kbuild-3149/0000755000175000017500000000000013252530251012702 5ustar locutuslocutuskbuild-3149/Makefile.kmk0000644000175000017500000000515213252530251015126 0ustar locutuslocutus# $Id: Makefile.kmk 2674 2013-01-31 13:28:27Z bird $ ## @file # Top-Level Sub-Makefile for kBuild. # # # Copyright (c) 2005-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # SUB_DEPTH = . include $(KBUILD_PATH)/subheader.kmk include $(PATH_SUB_CURRENT)/src/Makefile.kmk ifdef NIX_INSTALL_DIR # # When doing a unix install, install all the kBuild scripts and docs. # TODO: Make this default and make it possible to disable it for in-tree development. # INSTALLS += kBuild-data kBuild-data_TEMPLATE = DATA kBuild-data_SOURCES := \ $(wildcard \ kBuild/*.kmk \ ) \ $(foreach src,\ $(wildcard \ kBuild/tools/*.kmk \ kBuild/sdks/*.kmk \ kBuild/units/*.kmk \ kBuild/msgstyles/*.kmk \ kBuild/templates/*.kmk),\ $(src)=>$(subst kBuild/,,$(src))) INSTALLS += kBuild-doc kBuild-doc_TEMPLATE = DOC kBuild-doc_SOURCES := $(wildcard \ kBuild/doc/*.txt \ kBuild/doc/*.html \ ) endif # # And install any binary only tools and dlls. # TODO: Ship env.sh and envos2.cmd / envwin.cmd where applicable. # INSTALLS += kBuild_bin kBuild_bin_INST = $(TEMPLATE_BIN_INST) kBuild_bin_SOURCES = kBuild_bin_SOURCES.os2 = \ kBuild/bin/$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)/libc06.dll=>libc06.dll \ kBuild/bin/$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)/libc061.dll=>libc061.dll \ kBuild/bin/$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)/libc062.dll=>libc062.dll \ kBuild/bin/$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)/libc063.dll=>libc063.dll \ kBuild/bin/$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)/libc064.dll=>libc064.dll \ kBuild/bin/$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)/libc065.dll=>libc065.dll if1of ($(KBUILD_TARGET), nt win) kBuild_bin_SOURCES.$(KBUILD_TARGET) = \ kBuild/bin/$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)/msvcr100.dll kBuild_bin_SOURCES.profile = \ D:/coding/kStuff/svn/trunk/out/win.$(KBUILD_TARGET_ARCH)/release/kStuff/bin/kPrf2.dll \ D:/coding/kStuff/svn/trunk/out/win.$(KBUILD_TARGET_ARCH)/release/kStuff/bin/kPrf2WinApiWrappers.dll endif include $(FILE_KBUILD_SUB_FOOTER) kbuild-3149/COPYING0000644000175000017500000010451313252530251013741 0ustar locutuslocutus GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . kbuild-3149/tests/0000755000175000017500000000000013252530251014044 5ustar locutuslocutuskbuild-3149/tests/Makefile.kmk0000644000175000017500000000204113252530251016262 0ustar locutuslocutus# $Id: Makefile.kmk 2420 2010-10-17 00:33:38Z bird $ ## @file # Tests - Top Level Makefile. # # # Copyright (c) 2008-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # include $(PATH_KBUILD)/header.kmk SUBDIRS = \ inherit-target \ inherit-bld \ inherit-misc \ SUBDIRS.os2 = \ os2-impdef include $(FILE_KBUILD_FOOTER) kbuild-3149/tests/inherit-misc/0000755000175000017500000000000013252530251016437 5ustar locutuslocutuskbuild-3149/tests/inherit-misc/Makefile.kmk0000644000175000017500000000302313252530251020656 0ustar locutuslocutus# $Id: Makefile.kmk 2413 2010-09-11 17:43:04Z bird $ ## @file # Test - Misc Inheritance. # # # Copyright (c) 2008-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # DEPTH = ../.. include $(PATH_KBUILD)/header.kmk # # Search for SDKs in the current directory. # KBUILD_SDK_PATHS := $(PATH_SUB_CURRENT) # # Tests for checking that prepending and appending of properties # that have been defined as simple variables work. Ticket #51. # (This is a little bit out of place, but so what.) # PROGRAMS += inherit-misc51a inherit-misc51a_TEMPLATE := tmpl51a inherit-misc51a_SDKS := sdk51a-xz inherit-misc51a_DEFS := X=z inherit-misc51a_SOURCES := ../dummy_defined_X.c TEMPLATE_tmpl51a = inherit-misc51 template TEMPLATE_tmpl51a_EXTENDS = TST TEMPLATE_tmpl51a_DEFS = $(SDK_sdk51a-xz_SPECIAL_DEFS) include $(FILE_KBUILD_FOOTER) kbuild-3149/tests/inherit-misc/sdk51a-xz.kmk0000644000175000017500000000171713252530251020700 0ustar locutuslocutus# $Id: sdk51a-xz.kmk 2413 2010-09-11 17:43:04Z bird $ ## @file # Test - Misc Inheritance Issues. # # # Copyright (c) 2008-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # SDK_sdk51a-xz = for inherit-misc51a SDK_sdk51a-xz_SPECIAL_DEFS = z=42 kbuild-3149/tests/os2-implib/0000755000175000017500000000000013252530251016021 5ustar locutuslocutuskbuild-3149/tests/os2-implib/Makefile.kmk0000644000175000017500000000211513252530251020241 0ustar locutuslocutus# $Id: Makefile.kmk 2413 2010-09-11 17:43:04Z bird $ ## @file # Tests - OS/2 import library. # # # Copyright (c) 2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # DEPTH = ../.. include $(PATH_KBUILD)/header.kmk ifeq ($(KBUILD_HOST),os2) LIBRARIES = os2-implib-1 os2-implib-1_TOOL = GCC3OMF os2-implib-1_SOURCES = os2-implib.def endif include $(FILE_KBUILD_FOOTER) kbuild-3149/tests/os2-implib/os2-implib.def0000644000175000017500000000170613252530251020462 0ustar locutuslocutus; $Id: Makefile.kmk 2413 2010-09-11 17:43:04Z bird $ ;; @file ; Tests - OS/2 import library definitions. ; ; ; Copyright (c) 2010 knut st. osmundsen ; ; This file is part of kBuild. ; ; kBuild is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 2 of the License, or ; (at your option) any later version. ; ; kBuild 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 kBuild; if not, write to the Free Software ; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ; LIBRARY os2dll EXPORTS SomeFunction1 SomeFunction2 kbuild-3149/tests/dummy.c0000644000175000017500000000167113252530251015350 0ustar locutuslocutus/* $Id: dummy.c 2413 2010-09-11 17:43:04Z bird $ */ /** @file * Tests - Dummy test program. */ /* * Copyright (c) 2008-2010 knut st. osmundsen * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * kBuild 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 kBuild; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ int main() { return 0; } kbuild-3149/tests/hello.c0000644000175000017500000000176113252530251015320 0ustar locutuslocutus/* $Id: hello.c 2413 2010-09-11 17:43:04Z bird $ */ /** @file * Tests - Hello world test program. */ /* * Copyright (c) 2008-2010 knut st. osmundsen * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * kBuild 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 kBuild; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include int main() { printf("hello world\n"); return 0; } kbuild-3149/tests/dummy_defined_Y.c0000644000175000017500000000210113252530251017303 0ustar locutuslocutus/* $Id: dummy_defined_Y.c 2413 2010-09-11 17:43:04Z bird $ */ /** @file * Tests - Dummy test program checking that Y == 42. */ /* * Copyright (c) 2008-2010 knut st. osmundsen * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * kBuild 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 kBuild; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef Y # error "Y isn't defined, test the is busted." #endif #if Y != 42 # error "Y != 42" #endif int main() { return 0; } kbuild-3149/tests/Config.kmk0000644000175000017500000000612313252530251015757 0ustar locutuslocutus# $Id: Config.kmk 2413 2010-09-11 17:43:04Z bird $ ## @file # Tests - Configuration. # # # Copyright (c) 2008-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # # # Template for building commandline tools. # TEMPLATE_TST = Commandline binary TEMPLATE_TST_INST = tests/ ifeq ($(BUILD_TARGET),os2) TEMPLATE_TST_TOOL = GCC3OMF TEMPLATE_TST_CFLAGS.profile = -pg TEMPLATE_TST_CFLAGS.release = -O3 TEMPLATE_TST_LDFLAGS = -Zhigh-mem -Zstack=1024 endif ifeq ($(BUILD_TARGET),darwin) TEMPLATE_TST_TOOL = GCC4MACHO TEMPLATE_TST_CFLAGS.profile = TEMPLATE_TST_CFLAGS.release = -O3 TEMPLATE_TST_LDFLAGS = endif ifeq ($(filter-out win nt,$(BUILD_TARGET)),) ifeq ($(BUILD_TARGET_ARCH),x86) include $(PATH_KBUILD)/tools/VCC70.kmk # fixme! template expanding does something bad to _LIBS /me thinks. TEMPLATE_TST_TOOL = VCC70 else ifeq ($(BUILD_TARGET_ARCH),amd64) TEMPLATE_TST_TOOL = VCC80AMD64 TEMPLATE_TST_DEFS = _CRT_SECURE_NO_DEPRECATE _CRT_NONSTDC_NO_WARNINGS endif TEMPLATE_TST_SDKS = WINPSDK TEMPLATE_TST_CFLAGS = -W3 -Zi -Zl TEMPLATE_TST_CFLAGS.release = -O2 TEMPLATE_TST_CFLAGS.profile = -O2 -GH -Gh TEMPLATE_TST_LDFLAGS = /SUBSYSTEM:console /INCREMENTAL:no /NOD /DEBUG TEMPLATE_TST_CFLAGS += -MD TEMPLATE_TST_LIBS = \ $(PATH_TOOL_$(TEMPLATE_TST_TOOL)_LIB)/oldnames.lib \ $(PATH_TOOL_$(TEMPLATE_TST_TOOL)_LIB)/msvcrt.lib TEMPLATE_TST_LIBS.profile = Y:/coding/libc/svn/trunk/out/win.$(BUILD_TARGET_ARCH)/debug/kStuff/lib/kPrf2.lib endif ifndef TEMPLATE_TST_TOOL # Use GCC3 when we're certain that the system is using GNU ld and ar. ifeq ($(filter-out linux freebsd openbsd netbsd,$(BUILD_TARGET)),) TEMPLATE_TST_TOOL = GCC3 else TEMPLATE_TST_TOOL = GCC3PLAIN endif TEMPLATE_TST_CFLAGS.release = -O3 ifeq ($(BUILD_TARGET),solaris) TEMPLATE_TST_CFLAGS.x86 += -m32 TEMPLATE_TST_CFLAGS.amd64 += -m64 TEMPLATE_TST_CXXFLAGS.x86 += -m32 TEMPLATE_TST_CXXFLAGS.amd64 += -m64 TEMPLATE_TST_LDFLAGS.x86 += -m32 TEMPLATE_TST_LDFLAGS.amd64 += -m64 TEMPLATE_TST_LDFLAGS += -Wl,-i endif endif # # Template for building libraries for the tools. # TEMPLATE_TSTLIB = Library for Commandline binary TEMPLATE_TSTLIB_EXTENDS = BIN TEMPLATE_TSTLIB_INST = lib/ kbuild-3149/tests/inherit-target/0000755000175000017500000000000013252530251016772 5ustar locutuslocutuskbuild-3149/tests/inherit-target/Makefile.kmk0000644000175000017500000000466713252530251021230 0ustar locutuslocutus# $Id: Makefile.kmk 2413 2010-09-11 17:43:04Z bird $ ## @file # Test - Target Inheritance. # # # Copyright (c) 2008-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # DEPTH = ../.. include $(PATH_KBUILD)/header.kmk PROGRAMS += inherit-target1 inherit-target1_TEMPLATE = TST inherit-target1_SOURCES = ../dummy_defined_X.c inherit-target1_DEFS = X=y PROGRAMS += inherit-target2 inherit-target2_EXTENDS = inherit-target1 PROGRAMS += inherit-target3 inherit-target3_EXTENDS = inherit-target2 PROGRAMS += inherit-target4 inherit-target4_EXTENDS = inherit-target3 PROGRAMS += inherit-target5 inherit-target5_EXTENDS = inherit-target3 # out of target order. PROGRAMS += inherit-target6 inherit-target6_EXTENDS = inherit-target9 PROGRAMS += inherit-target7 inherit-target7_EXTENDS = inherit-target1 PROGRAMS += inherit-target8 inherit-target8_EXTENDS = inherit-target7 PROGRAMS += inherit-target9 inherit-target9_EXTENDS = inherit-target8 # More complicated, with a couple of SDKs and TEMPLATES. SDK_inh1 = target inherit test sdk 1 SDK_inh1_DEFS = Z=42 SDK_inh2 = target inherit test sdk 2 SDK_inh2_DEFS = Y=128 SDK_inh3 = target inherit test sdk 3 SDK_inh3_DEFS = P=42 TEMPLATE_inh1 = target inherit test template 1 TEMPLATE_inh1_EXTENDS = TST TEMPLATE_inh1_DEFS = Q=256 PROGRAMS += inherit-target10 inherit-target10_TEMPLATE = inh1 inherit-target10_SOURCES = ../dummy_defined_X.c inherit-target10_SDKS = inh1 inh2 inherit-target10_DEFS = X=Z PROGRAMS += inherit-target11 inherit-target11_EXTENDS = inherit-target10 inherit-target11_SOURCES = ../dummy_defined_Y.c inherit-target11_SDKS = inh3 inherit-target11_DEFS = Y=P include $(FILE_KBUILD_FOOTER) kbuild-3149/tests/inherit-bld/0000755000175000017500000000000013252530251016245 5ustar locutuslocutuskbuild-3149/tests/inherit-bld/Makefile.kmk0000644000175000017500000000724613252530251020477 0ustar locutuslocutus# $Id: Makefile.kmk 2413 2010-09-11 17:43:04Z bird $ ## @file # Test - Build Type Inheritance. # # # Copyright (c) 2008-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # DEPTH = ../.. include $(PATH_KBUILD)/header.kmk # Plain setup just for a reality check. PROGRAMS += inherit-bld1 inherit-bld1_TEMPLATE = TST inherit-bld1_DEFS = X=y inherit-bld1_SOURCES = ../dummy_defined_X.c # Test that the BLD_TYPE feature works. PROGRAMS += inherit-bld2 inherit-bld2_TEMPLATE = TST inherit-bld2_BLD_TYPE = debug inherit-bld2_DEFS.debug = X=y inherit-bld2_SOURCES = ../dummy_defined_X.c # Test that an simple alternative build type works. PROGRAMS += inherit-bld3 inherit-bld3_TEMPLATE = TST inherit-bld3_BLD_TYPE = dbgbld3 inherit-bld3_DEFS.dbgbld3 = X=y inherit-bld3_SOURCES = ../dummy_defined_X.c # Test that default build type inheritance works - dbgbld4 extends dbgbld3. PROGRAMS += inherit-bld4 inherit-bld4_TEMPLATE = TST inherit-bld4_BLD_TYPE = dbgbld4 inherit-bld4_DEFS.dbgbld3 = X=y inherit-bld4_SOURCES = ../dummy_defined_X.c # Test that appending build type inheritance works - dbgbld5 extends dbgbld3. PROGRAMS += inherit-bld5 inherit-bld5_TEMPLATE = TST inherit-bld5_BLD_TYPE = dbgbld5 inherit-bld5_DEFS.dbgbld3 = X=y y=0 inherit-bld5_DEFS.dbgbld5 = y=42 inherit-bld5_SOURCES = ../dummy_defined_X.c # Test that prepending build type inheritance works - dbgbld6 extends dbgbld3. PROGRAMS += inherit-bld6 inherit-bld6_TEMPLATE = TST inherit-bld6_BLD_TYPE = dbgbld6 inherit-bld6_DEFS.dbgbld3 = X=y y=42 inherit-bld6_DEFS.dbgbld6 = y=0 inherit-bld6_SOURCES = ../dummy_defined_X.c # # Tests where we inherit from a target and force build type which # relies on inheritance. These are the fine points... # PROGRAMS += inherit-bld10 inherit-bld10_TEMPLATE = TST inherit-bld10_BLD_TYPE = dbgbld11 inherit-bld10_DEFS = X=y inherit-bld10_DEFS.dbgbld10 = y=42 inherit-bld10_SOURCES = ../dummy_defined_X.c # Tests that target and build inheriting works together. PROGRAMS += inherit-bld11 inherit-bld11_EXTENDS = inherit-bld10 # Tests that dbgbld11 is picked from the target rather than the parent. PROGRAMS += inherit-bld12 inherit-bld12_EXTENDS = inherit-bld10 inherit-bld12_DEFS = y=0 inherit-bld12_DEFS.dbgbld11 = X=z z=42 # Tests that prepending works. PROGRAMS += inherit-bld20 inherit-bld20_TEMPLATE = TST inherit-bld20_BLD_TYPE = dbgbld21 inherit-bld20_DEFS = X=y inherit-bld20_DEFS.dbgbld20 = y=42 inherit-bld20_DEFS.dbgbld21 = y=0 #inherit-bld20_DEFS.dbgbld21 = y=0 y=42 <-- expected result. inherit-bld20_SOURCES = ../dummy_defined_X.c # Tests that prepending + target inheritance works as expected. funky! PROGRAMS += inherit-bld21 inherit-bld21_EXTENDS = inherit-bld20 inherit-bld21_DEFS.dbgbld20 = Y=y #inherit-bld21_DEFS.dbgbld21 = y=0 y=42 Y=y <-- expected result; dbgbld21 from parent + our dbgbld20. inherit-bld21_SOURCES = ../dummy_defined_Y.c include $(FILE_KBUILD_FOOTER) kbuild-3149/tests/inherit-bld/Config.kmk0000644000175000017500000000372513252530251020165 0ustar locutuslocutus# $Id: Config.kmk 2413 2010-09-11 17:43:04Z bird $ ## @file # Tests - Build Type Inheritance. # # Just to set up some additional build types the correct way. # # # Copyright (c) 2008-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # # # Include our parent Config.kmk # include $(PATH_ROOT)/tests/Config.kmk # # For inherit-bld3 - no inheritance. # KBUILD_BLD_TYPES += dbgbld3 # # For inherit-bld4 - default inheritance (override). # KBUILD_BLD_TYPES += dbgbld4 BLD_TYPE_dbgbld4_EXTENDS = dbgbld3 # # For inherit-bld5 - appending inheritance. # KBUILD_BLD_TYPES += dbgbld5 BLD_TYPE_dbgbld5_EXTENDS = dbgbld3 BLD_TYPE_dbgbld5_EXTENDS_BY = appending # # For inherit-bld6 - prepending inheritance. # KBUILD_BLD_TYPES += dbgbld6 BLD_TYPE_dbgbld6_EXTENDS = dbgbld3 BLD_TYPE_dbgbld6_EXTENDS_BY = prepending # # For inherit-bld7 - overriding inheritance. # KBUILD_BLD_TYPES += dbgbld7 BLD_TYPE_dbgbld7_EXTENDS = dbgbld3 BLD_TYPE_dbgbld7_EXTENDS_BY = overriding # # For inherit-bld10 thru 19 - overriding inheritance. # KBUILD_BLD_TYPES += dbgbld10 dbgbld11 BLD_TYPE_dbgbld11_EXTENDS = dbgbld10 # # For inherit-bld20 thru 29 - prepending inheritance. # KBUILD_BLD_TYPES += dbgbld20 dbgbld21 BLD_TYPE_dbgbld21_EXTENDS = dbgbld20 BLD_TYPE_dbgbld21_EXTENDS_BY = prepending kbuild-3149/tests/dummy_defined_X.c0000644000175000017500000000217413252530251017314 0ustar locutuslocutus/* $Id: dummy_defined_X.c 2413 2010-09-11 17:43:04Z bird $ */ /** @file * Tests - Dummy test program checking that X == 42, possibly doing this via y. */ /* * Copyright (c) 2008-2010 knut st. osmundsen * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * kBuild 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 kBuild; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef X # error "X isn't defined, test the is busted." #endif #ifndef y # define y 42 #endif #if X != 42 # error "X != 42" #endif int main() { return 0; } kbuild-3149/bootstrap.gmk0000644000175000017500000002364413252530224015430 0ustar locutuslocutus# $Id: bootstrap.gmk 3143 2018-03-14 23:00:29Z bird $ ## @file # GNU Make Compatible bootstrap Makefile. # # # Copyright (c) 2007-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # # # ASSUMES: # - KBUILD_TARGET, KBUILD_HOST, KBUILD_HOST_ARCH, and KBUILD_TYPE in the env. # - KBUILD_PATH points to ./kBuild with an absolute path. # - KBUILD_BIN_PATH and PATH_KBUILD_BIN must *NOT* be defined anywhere. # - Current directory == bootstrap.gmk directory. # - mkdir -p works. # - ln -s works # - cp -f works # - cd somedir && command works. # - echo done > some-file works. # - Recent GNU make that implements CURDIR, $(error) and ifdef. # # Tip: kBuild/env.sh --full (g(nu))make -f bootstrap.gmk # # Note to self on bootstrapping solaris.sparc64: # SED_MAKE_DEFS="SED=gsed" AUTOPOINT=true ACLOCAL=aclocal-1.10 AUTOMAKE=automake-1.10 nice ./kBuild/env.sh --full gmake -f bootstrap.gmk # # Note to self on bootstrapping openbsd: # AUTOCONF_VERSION=2.59 AUTOMAKE_VERSION=1.9 ./kBuild/env.sh --full gmake -f bootstrap.gmk # # # OPTIONAL: # Set env.var. NIX_INSTALL_DIR to /usr/local or /usr # (see Config.kmk and wiki for details) # # # Deal with legacy env.vars. - no niceties here. # ifndef KBUILD_HOST KBUILD_HOST := $(BUILD_PLATFORM) endif ifndef KBUILD_HOST_ARCH KBUILD_HOST_ARCH := $(BUILD_PLATFORM_ARCH) endif ifndef KBUILD_HOST_CPU KBUILD_HOST_CPU := $(BUILD_PLATFORM_CPU) endif ifndef KBUILD_TARGET KBUILD_TARGET := $(BUILD_TARGET) endif ifndef KBUILD_TARGET_ARCH KBUILD_TARGET_ARCH := $(BUILD_TARGET_ARCH) endif ifndef KBUILD_TARGET_CPU KBUILD_TARGET_CPU := $(BUILD_TARGET_CPU) endif ifndef KBUILD_TYPE KBUILD_TYPE := $(BUILD_TYPE) endif ifndef KBUILD_PATH KBUILD_PATH := $(PATH_KBUILD) endif # # Check (some of) the assumptions. # ifndef KBUILD_TARGET $(error KBUILD_TARGET not set) endif ifndef KBUILD_HOST $(error KBUILD_HOST not set) endif ifndef KBUILD_HOST_ARCH $(error KBUILD_HOST_ARCH not set) endif ifndef KBUILD_TYPE $(error KBUILD_TYPE not set) endif ifndef KBUILD_TYPE $(error KBUILD_TYPE not set) endif ifndef KBUILD_PATH $(error KBUILD_PATH not set) endif ifdef KBUILD_BIN_PATH $(error KBUILD_BIN_PATH is set) endif ifdef PATH_KBUILD_BIN $(error PATH_KBUILD_BIN is set) endif # # Globals # SRCDIR = $(CURDIR) OUTDIR = $(SRCDIR)/out/$(KBUILD_HOST).$(KBUILD_HOST_ARCH)/$(KBUILD_TYPE)/bootstrap SVN = svn # Override this on the make commandline if you need to (FreeBSD). AUTORECONF = autoreconf all: stage1 stage2 # # Stage 1 - Build bootstrap kmk, kmk_redirect and sed, refresh config.h caches, link # up kmk_ash so $(OUTDIR)/kmk can serve as kBuild bin dir. # stage1: \ $(OUTDIR)/kmk/kmk \ $(OUTDIR)/kmk/kmk_ash \ $(OUTDIR)/kmk/kmk_sed \ $(OUTDIR)/kmk/kmk_echo \ $(SRCDIR)/src/kmk/config.h.$(KBUILD_TARGET) \ $(SRCDIR)/src/sed/config.h.$(KBUILD_TARGET) # kmk $(OUTDIR)/kmk/ts-autoreconf: mkdir -p $(@D) cd $(SRCDIR)/src/kmk && $(AUTORECONF) -i -v echo done > $@ $(OUTDIR)/kmk/ts-configured: \ $(OUTDIR)/kmk/ts-autoreconf \ $(OUTDIR)/kmk/fts.h cd $(OUTDIR)/kmk && $(SRCDIR)/src/kmk/configure --disable-load --without-guile echo done > $@ ifeq ($(KBUILD_HOST),solaris) $(OUTDIR)/kmk/ts-configured: $(OUTDIR)/kmk/paths.h $(OUTDIR)/kmk/paths.h: echo > $@ endif $(OUTDIR)/kmk/fts.h: ln -s $(SRCDIR)/src/kmk/kmkbuiltin/ftsfake.h $@ $(OUTDIR)/kmk/config.h: $(OUTDIR)/kmk/ts-configured $(SRCDIR)/src/kmk/config.h.$(KBUILD_TARGET): $(OUTDIR)/kmk/config.h cp -f $(OUTDIR)/kmk/config.h $(SRCDIR)/src/kmk/config.h.$(KBUILD_TARGET) echo "" >> $@ echo '#include "inlined_memchr.h"' >> $@ $(OUTDIR)/kmk/kmk: $(OUTDIR)/kmk/ts-configured $(MAKE) -C $(@D) # sed $(OUTDIR)/sed/ts-autoreconf: mkdir -p $(@D) @cd $(SRCDIR)/src/sed && $(AUTORECONF) -i -v --force echo done > $@ $(OUTDIR)/sed/ts-configured: $(OUTDIR)/sed/ts-autoreconf cd $(OUTDIR)/sed && $(SRCDIR)/src/sed/configure --without-libintl --disable-nls echo done > $@ $(OUTDIR)/sed/config.h: $(OUTDIR)/sed/ts-configured $(SRCDIR)/src/sed/config.h.$(KBUILD_TARGET): $(OUTDIR)/sed/config.h cp -f $< $@ $(OUTDIR)/sed/sed/sed: $(OUTDIR)/sed/ts-configured $(MAKE) $(SED_MAKE_DEFS) -C $(@D)/.. $(OUTDIR)/kmk/kmk_sed: $(OUTDIR)/sed/sed/sed cp -f $< $@ $(OUTDIR)/kmk/kmk_ash: ifeq ($(KBUILD_TARGET),solaris) ln -s /usr/bin/bash $@ else ln -s /bin/sh $@ endif $(OUTDIR)/kmk/kmk_echo: ln -s /bin/echo $@ # # Stage 2 - Build kBuild using the bootstrap tools from the previous step # and install it to kBuild/bin/x.y. # stage2: \ $(OUTDIR)/ts-stage2-build \ $(OUTDIR)/ts-stage2-install $(OUTDIR)/ts-stage2-build: \ $(SRCDIR)/src/kmk/config.h.$(KBUILD_TARGET) \ $(SRCDIR)/src/sed/config.h.$(KBUILD_TARGET) \ $(OUTDIR)/kmk/kmk KBUILD_BIN_PATH=$(OUTDIR)/kmk $(OUTDIR)/kmk/kmk -C $(SRCDIR) KBUILD_BOOTSTRAP=1 echo done > $@ $(OUTDIR)/ts-stage2-install: $(OUTDIR)/ts-stage2-build KBUILD_BIN_PATH=$(OUTDIR)/kmk $(OUTDIR)/kmk/kmk -C $(SRCDIR) KBUILD_BOOTSTRAP=1 PATH_INS=$(SRCDIR) install echo done > $@ # # Clean the output files... Very enjoyable exercise. # clean: rm -Rf $(SRCDIR)/out/ \ $(SRCDIR)/src/kmk/autom4te.cache/ \ $(SRCDIR)/src/sed/autom4te.cache/ rm -f $(SRCDIR)/src/kmk/Makefile.in \ $(SRCDIR)/src/kmk/config.h.in \ $(SRCDIR)/src/kmk/configure \ $(SRCDIR)/src/kmk/aclocal.m4 \ $(SRCDIR)/src/kmk/glob/Makefile.in \ $(SRCDIR)/src/kmk/config/Makefile.in \ $(SRCDIR)/src/kmk/config/depcomp \ $(SRCDIR)/src/kmk/config/compile \ $(SRCDIR)/src/kmk/config/missing \ $(SRCDIR)/src/kmk/config/config.guess \ $(SRCDIR)/src/kmk/config/config.sub \ $(SRCDIR)/src/kmk/config/install-sh \ $(SRCDIR)/src/kmk/w32/Makefile.in \ $(SRCDIR)/src/sed/config_h.in~ \ $(SRCDIR)/src/sed/intl/printf-args.h \ $(SRCDIR)/src/sed/intl/printf.c \ $(SRCDIR)/src/sed/intl/localcharset.h \ $(SRCDIR)/src/sed/intl/libgnuintl.h.in \ $(SRCDIR)/src/sed/intl/vasnwprintf.h \ $(SRCDIR)/src/sed/intl/vasnprintf.c \ $(SRCDIR)/src/sed/intl/vasnprintf.h \ $(SRCDIR)/src/sed/intl/wprintf-parse.h \ $(SRCDIR)/src/sed/intl/relocatable.c \ $(SRCDIR)/src/sed/intl/relocatable.h \ $(SRCDIR)/src/sed/intl/xsize.h \ $(SRCDIR)/src/sed/intl/printf-parse.c \ $(SRCDIR)/src/sed/intl/printf-parse.h \ $(SRCDIR)/src/sed/intl/log.c \ $(SRCDIR)/src/sed/intl/printf-args.c \ $(SRCDIR)/src/sed/po/remove-potcdate.sin \ $(SRCDIR)/src/sed/po/Makevars.template \ $(SRCDIR)/src/sed/config/printf-posix.m4 \ $(SRCDIR)/src/sed/config/uintmax_t.m4 \ $(SRCDIR)/src/sed/config/signed.m4 \ $(SRCDIR)/src/sed/config/longlong.m4 \ $(SRCDIR)/src/sed/config/inttypes.m4 \ $(SRCDIR)/src/sed/config/inttypes_h.m4 \ $(SRCDIR)/src/sed/config/longdouble.m4 \ $(SRCDIR)/src/sed/config/nls.m4 \ $(SRCDIR)/src/sed/config/intmax.m4 \ $(SRCDIR)/src/sed/config/mkinstalldirs \ $(SRCDIR)/src/sed/config/xsize.m4 \ $(SRCDIR)/src/sed/config/ulonglong.m4 \ $(SRCDIR)/src/sed/config/wint_t.m4 \ $(SRCDIR)/src/sed/config/inttypes-pri.m4 \ $(SRCDIR)/src/sed/config/stdint_h.m4 \ $(SRCDIR)/src/sed/config/intdiv0.m4 \ $(SRCDIR)/src/sed/config/isc-posix.m4 \ $(SRCDIR)/src/sed/config/po.m4 \ $(SRCDIR)/src/sed/config/size_max.m4 \ $(SRCDIR)/src/sed/config/wchar_t.m4 \ $(SRCDIR)/src/sed/*~ \ $(SRCDIR)/src/sed/config/*~ \ $(SRCDIR)/src/sed/intl/*~ \ $(SRCDIR)/src/sed/po/*~ \ distclean: clean $(SVN) revert \ src/sed/configure \ src/sed/Makefile.in \ src/sed/doc/Makefile.in \ src/sed/doc/stamp-vti \ src/sed/doc/sed.info \ src/sed/doc/sed.info-1 \ src/sed/doc/sed.info-2 \ src/sed/doc/version.texi \ src/sed/INSTALL \ src/sed/lib/Makefile.in \ src/sed/sed/Makefile.in \ src/sed/config_h.in \ src/sed/testsuite/Makefile.in \ src/sed/config/depcomp \ src/sed/config/config.guess \ src/sed/config/config.sub \ src/sed/config/mdate-sh \ src/sed/config/missing \ src/sed/config/texinfo.tex \ src/sed/config/install-sh \ src/sed/aclocal.m4 \ src/sed/ABOUT-NLS \ src/sed/doc/sed.1 \ src/sed/intl/plural-exp.h \ src/sed/intl/Makefile.in \ src/sed/intl/explodename.c \ src/sed/intl/localcharset.c \ src/sed/intl/VERSION \ src/sed/intl/dcigettext.c \ src/sed/intl/dngettext.c \ src/sed/intl/localealias.c \ src/sed/intl/textdomain.c \ src/sed/intl/bindtextdom.c \ src/sed/intl/ref-del.sin \ src/sed/intl/intl-compat.c \ src/sed/intl/dgettext.c \ src/sed/intl/dcgettext.c \ src/sed/intl/plural.c \ src/sed/intl/loadinfo.h \ src/sed/intl/localename.c \ src/sed/intl/ngettext.c \ src/sed/intl/ChangeLog \ src/sed/intl/locale.alias \ src/sed/intl/os2compat.c \ src/sed/intl/finddomain.c \ src/sed/intl/ref-add.sin \ src/sed/intl/gettextP.h \ src/sed/intl/dcngettext.c \ src/sed/intl/osdep.c \ src/sed/intl/config.charset \ src/sed/intl/l10nflist.c \ src/sed/intl/os2compat.h \ src/sed/intl/loadmsgcat.c \ src/sed/intl/gettext.c \ src/sed/intl/plural.y \ src/sed/intl/gmo.h \ src/sed/intl/plural-exp.c \ src/sed/intl/eval-plural.h \ src/sed/intl/hash-string.h \ src/sed/config.h.darwin \ src/sed/po/Makefile.in.in \ src/sed/po/Rules-quot \ src/sed/config/lib-prefix.m4 \ src/sed/config/lib-link.m4 \ src/sed/config/lib-ld.m4 \ src/sed/config/lcmessage.m4 \ src/sed/config/config.rpath \ src/sed/config/progtest.m4 \ src/sed/config/iconv.m4 \ src/sed/config/gettext.m4 $(SVN) revert \ src/kmk/config.h.solaris \ src/sed/config.h.solaris $(SVN) status --no-ignore # can't hurt... .NOTPARALLEL: kbuild-3149/ChangeLog0000644000175000017500000003241113252530251014455 0ustar locutuslocutus/* $Id: ChangeLog 855 2007-02-26 21:59:05Z bird $ */ The change log has been discontinued. check the trac timeline instead: http://svn.netlabs.org/kbuild/timeline 2006-12-03: - kBuild/bin/x86.win32: o Rebuild and cleaned out dlls that mv and sed required. - sed: o Fixed parsing of single quoted arguments on windows. 2006-12-02: - kmk: o Fixed bugs dealing with the order SDK properties was applied to sources. 2006-12-01: - kBuild: o Added support for compiling resource files. o Fixed bug causing object files take from the SOURCES to be cleaned up. 2006-11-25: - kmk, kBuild: o Added mv as builtin command. o Added cat as builtin command. o Added GNU sed version 4.1.5 and ported it to MSC. o Added rmdir as builtin and external command. o Made mkdir not modify the argument strings. o Made mkdir deal properly with DOS slashes on OS/2 and Windows. 2006-11-24: - kBuild/bin/x86.win32/kmk.exe, kBuild/bin/x86.linux/kmk: o Rebuilt with current code. - kBuild/footer.kmk: o Fixed some issues with SDKS and linking. - kmk: o Fixed bug in the sdk walking in kbuild_collect_source_prop. o Added --pretty-command-printing for simplifying makefile debugging. 2006-11-23: - dist/portage: o Hacked together two ebuilds for the Gentoo Portage. - Config.kmk, Makefile.kmk: o #6: Hacking *nix install build for Gentoo. - src/gmake/Makefile.kmk, src/lib/Makefile: o Always include header.kmk when testing BUILD_TARGET*. - kBuild/header.kmk: o BUILD_TYPE defaults to 'release'. - kBuild/tools/GCC*.kmk: o Cleaned up the -s and -g usage. - kBuild/bin/x86.win32, kBuild/bin/x86.linux: o Rebuilt with current code. - kBuild/footer.kmk: o #3: Clean link output files. - kBuild/header.kmk, kmk: o #6: Did code changes for unix installation. Will do install goals when creating the gentoo ebuild. o #5: Proper versioning. (#5) - kmk: o Support SDK.$(BUILD_TARGET_ARCH) too (only bug). o Fixed a bug when gather SDKs. 2006-09-28: - kBuild/header.kmk, kBuild/env.sh, kBuild/tools/GCC4MACH.kmk, kBuild/bin/x86.darwin/, src/gmake, Config.kmk: o Initial Mac OS X / Darwin bootstrapping. 2006-09-23: - kBuild/footer.kmk: o Recursive template inheritance. - kBuild/header.kmk, kBuild/footer.kmk: o Removed some checks for features which are present in both gmake 3.81 and kmk. Anyone trying to bootstrap kBuild will have to build gmake 3.81 first. - Config.kmk, src/gmake, src/lib, src/kDepPre, src/kDepIDB: o Allow all kinds of ways of saying Windows in BUILD_TARGET. - kBuild/bin/x86.win32/: o Rebuilt kmk.exe. - kBuild/bin/x86.os2/: o Added kDepPre.exe and kDepIDB.exe. o Rebuilt kmk.exe and kmk_gmake.exe. - src/gmake: o Update KMK_FEATURES to include the optimizations from earlier this week. o Regenerated config.h.os2 and make adjustments to make it all build quietly on OS/2. - kBuild/envos2.cmd: o Environment script (REXX) for OS/2. 2006-09-19: - kBuild/bin/x86.win32/: o Rebuilt kmk.exe and kmk_gmake.exe. - src/gmake: o Fixed some optimization bugs in kbuild.c. 2006-09-18: - kBuild/gmake: o Don't send put j1 in MAKEFLAGS on windows, somehow that doesn't work. o Fixed some variable name typos in kbuild.c. o Fixed missing expansion in kbuild_lookup_variable. o A real attempt at fixing the double quoting problem on windows. ash seems to want a space between a double quote enclosing the last argument on the commandline and the double quote enclosing the commandline (the -c argument). o Fixed a newline escape problem when using batch_mode_shell on windows with kmk_ash. 2006-09-17: - kBuild/gmake: o Optimization summary: libc from ~21 seconds -> 7-8 seconds (os2/nt). o Optimized appending new stuff to variables. (major win) o Optimized variable memory value allocation avoiding a bunch of unnecessary copying and allocating. o Added kBuild specific functions for speeding up source processing. o Fixed assertion in w32_fixcase when shell doesn't have a full path and some other case. 2006-09-16: - kBuild/header.kmk: o Turn off command dependencies when using vanilla GNU Make. - kBuild/footer.kmk: o Made up my mind about the command depency blocker variables; NO_LINK_CMDS_DEPS and NO_COMPILE_CMDS_DEPS. - src/gmake: o Added kmk_gmake which is (almost) vanilla GNU Make. o kmk_ash wants batch files on windows or the double quotes will get screwed up. o Make sure kmk_builtin commands don't get batch files and odd weird stuff. o Cleaning up the modifications. Changes are now either configurable or marked, and dead stuff has been removed (dll shell). 2006-09-15: - kBuild/bin/x86.win32/kmk.exe: o Built new code. - kBuild/header.kmk: o DIRDEP is now the same on all platforms (fixed with 3.81 merge). - kBuild/bin/x86.linux/kmk: o Built new code on system360. - src/gmake: o Some parallel job fixes. o Regenerated config.h.linux on system360. o Fixed stat("dir/", &st) on windows and some warnings. o Merge with GNU Make v3.81 (vendor/gnumake/2005-05-16 -> vendor/gnumake/current). 2006-03-26: - kBuild/bin/x86.os2/: o Rebuilt the OS/2 tools. - src/gmake/variable.c, src/gmake/variable.h, src/gmake/make.h: o Attempt at speeding up performance on OS/2. - src/gmake/kmkbuiltin/rm.c: o OS/2 wants -R. - src/gmake/read.c: o Don't call glob() unless there is a wildcard pattern in the name. This speed things up a bit, at least on FreeBSD and especially on OS/2. - Config.kmk: o Added -pg for profile builds on OS/2. 2006-02-22: bird - kBuild/tools/MINGW32.kmk: o Corrected dependencies to match those generated by GCC3. 2006-02-09: bird - kBuild/tools/YASM.kmk: o Initial config. 2006-01-20: bird - kBuild/footer.kmk, kBuild/header.kmk: o Check for PACKING.$(BUILD_TARGET) as well. Added a quick evaluation of PACKING[.*] in the footer. 2006-01-18: bird - kBuild/footer.kmk, kBuild/header.kmk: o Packing pass change - uses PACKING var instead of packing::. - kBuild/footer.kmk: o Added mode,uid and gid to file INSTALLS. o Implemented template inheritance (_EXTENDS). 2006-01-14: bird - kBuild/env.sh: o Corrected the tool list. - kBuild/bin/x86.linux/: o Rebuild with current tree and static linage. (rhel3) - kBuild/tools/VCC70.kmk: o Enabled new dependcies. o Must use PDB macro to get the case correct on the idb file passed to kDepIDB. - src/lib/kDep.c: o Fixed missing slash fixing o Changed kDepPre error prefix to kDep. 2006-01-12: bird - kBuild/tools/VCC70.kmk: o Use DEP_IDB on win32. - kBuild/header.kmk: o Added DEP_IDB and DEP_IDB_EXT. - kBuild/bin/x86.win32/: o Rebuild with current source, adding kDepIDB. - src/kDepIDB/kDepIDB.c: o Initial coding. (This is a VC++ dependency extractor.) - src/kDepPre/kDepPre.c, src/lib/kDep.h, src/lib/kDep.c, Config.kmk: o Created a library for the dep*() functions. o Removed the IDB hacks from kDepPre. 2006-01-11: bird - kBuild/tools/vcc70.kmk: o Prepared for new IDB based dependencies.s - kBuild/footer.kmk: o Parallel build fixing. - src/gmake/job.c: o Fixed bad parallel bug. - src/gmake/main.c: o Enabled multiple jobs for recursive kmk processes on win32 despite the problems. - src/kDepPre/kDepPre.c: o Added extremely rough support for VC++ IDB files (/FD + /Fd). 2005-12-18: bird - kBuild/*.kmk, kBuild/tools/*.kmk: o Finally I've got around to implement command dependencies. o Use $(INSTALL) instead of $(RM) + $(CP). o More install features. - kBuild/bin/x86.[linux|win32|os2]/: o Rebuilt all the utils. o Renamed all unix utilites so they start with a kmk_ prefix and don't override any local unix utils. - src/gmake/kmkbuiltin/*, src/gmake/kmkbuiltin.c, src/gmake/kmkbuiltin.h, src/gmake/variables.c, src/gmake/Makefile.kmk: o Ported all the builtins to windows - now rebuild works again! o Fixed a few error case bugs in the builtins. o Disabled the -R and -r options for rm and cp. o Added kmk_install / kmk_builtin_install from BSD. 2005-12-13: bird - kBuild/bin/x86.linux/kmk, kBuild/bin/x86.linux/kmk_append, kBuild/bin/x86.linux/kmk_cp, kBuild/bin/x86.linux/kmk_echo, kBuild/bin/x86.linux/kmk_mkdir, kBuild/bin/x86.linux/kmk_rm: o Rebuild with current sources. - src/gmake/Makefile: o Prefixed external tools with kmk_. 2005-12-12: bird - kBuild/footer.kmk, kBuild/header.kmk: o Generic pass stuff. o Enabled and weeded out the new target install method. o Added separate install target type. o Added separate installs pass. o Fixed those $$$$(PATH_) problems. o General clean up removing lot's of duplicate stuff. - kBuild/tools/ALP.kmk, kBuild/tools/GCC.kmk, kBuild/tools/GCC3.kmk, kBuild/tools/GCC3OMF.kmk, kBuild/tools/MINGW32.kmk, kBuild/tools/NASM.kmk, kBuild/tools/VCC70.kmk: o Adjusted to new parameters for the link rules. o List all output files as targets for the rules. - kBuild/config.kmk, kBuild/cfg/x86.win32.va2003.kmk: o Removed early attempts which isn't used anylonger. - src/gmake/remake.c, src/gmake/commands.c, src/gmake/commands.h: o Fixed not parallel assertion on targets with no commands. 2005-12-11: bird - src/gmake/kmkbuiltin/append.c, src/gmake/kmkbuiltin.h, src/gmake/kmkbuiltin.c, src/gmake/Makefile.kmk, src/gmake/variables.c: o New command 'append' which appends text to a file, creating the file if necessary. o KMK_BUILTIN is listing the supported commands (used to be "1"). - src/gmake/kmkbuiltin/cp_utils.c: o Add O_BINARY to all open calls. - src/gmake/function.c: o Fixed abspath on OS/2. - src/kDepPre/kDepPre.c: o Killed some warnings and made it build on OS/2 and FreeBSD. 2005-11-07: bird - kBuild/tools/VCC70.kmk: o Use the new -s option for dependencies. - src/kDepPre/kDepPre.c, kBuild/bin/x86.linux/kDepPre, kBuild/bin/x86.win32/kDepPre.exe: o Added new option -s for generating stub dependencies just like -Wp,-MP. - kBuild/tools/GCC3.kmk, kBuild/tools/GCC3OMF.kmk: o Added -Wp,-MP to compile jobs for better dependencies. 2005-10-31: bird - kBuild/tools/VCC70.kmk: o Use the -f option with kDepPre to make sure nt/wine/cl doesn't screw up the path casing anywhere. - kBuild/bin/x86.linux/kDepPre, kBuild/bin/x86.win32/kDepPre.exe: o Rebuild with latest code. 2005-10-30: bird - kBuild/env.sh: o amd64. o kDepCCxx -> kDepPre. Ash. - kBuild/bin/amd64.linux/kDepPre, src/kDepPre/kDepPre.c: o Fix case option - need it on unix for cl.exe with wine. 2005-10-29: bird - kBuild/bin/amd64.linux/kDepPre, src/kDepPre/kDepPre.c: o Strip drive letters on non-PC OSes. 2005-10-28: bird - kBuild/footer.h: o Fixed a couple of defaults so it all works right on amd64. - kBuild/bin/amd64.linux/: o Added binaries. ash is 32-bit! 2005-10-14: bird - src/kDepPre/kDepPre.c, kBuild/bin/x86.win32/kDepPre.exe: o Corrected bug in line skipping where two lines would be skipped. o Corrected slashes on win32. 2005-10-03: bird - src/kDepPre/kDepPre.c, kBuild/bin/x86.win32/kDepPre.exe: o Fixed stupid stupid bug in the win32 case correcting code. Rebuilt the win32 binary. 2005-08-11: bird - kBuild/footer.kmk: o Enh. the _OBJECT_BASE hack for stripping of source paths within the project. - kBuild/tools/VCC70.kmk: o Use $(tolower ) to construct the right .pdb names for cleanup. - src/gmake/read.c: o print target name 'target pattern' errors. - kBuild/header.kmk: o Use $(abspath ). - src/gmake/variable.c: o Added KMK_FEATURES which indicates what's present+working and what's not. - src/gmake/w32/pathstuff.c, src/kDepPre/kDepPre.c, src/kDepPre/Makefile.kmk: o Fixed casing paths on win32. - src/gmake/function.c, src/gmake/Makefile.kmk: o Fixed $(abspath ) on Win32 and OS/2. o Added $(tolower ) and $(toupper ). 2005-06-16: bird - ALL: o Bootstrap and ported to FreeBSD 5.x on AMD64. 2005-05-06: bird - ALL: o Working on the build system of the build system. :-) o Ported the kmkbuiltin stuff to OS/2 as a prep to the win32 effort. [missing a lot!] 2002-10-15: bird - ALL: o Created a somewhat rought directory structure. - src/fastdep: o Imported current sources from ODIN32. - src/kmk: o Imported current sources from the freebsd tree. 2002-10-15: ktk - ALL: Create repository. kbuild-3149/kBuild/0000755000175000017500000000000013252530251014114 5ustar locutuslocutuskbuild-3149/kBuild/tools/0000755000175000017500000000000013252530251015254 5ustar locutuslocutuskbuild-3149/kBuild/tools/WATCOMC11C.kmk0000644000175000017500000002310513252530251017323 0ustar locutuslocutus# $Id: WATCOMC11C.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - Watcom C v11.0c # # # Copyright (c) 2008-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_WATCOMC11C = Watcom C/C++ v11.0c (generic) ifeq ($(PATH_TOOL_WATCOMC11C),) ifeq ($(PATH_TOOL_WATCOMC11C),) PATH_TOOL_WATCOMC11C := $(wildcard $(KBUILD_DEVTOOLS_HST)/watcom/v11.0c*) endif ifeq ($(PATH_TOOL_WATCOMC11C),) PATH_TOOL_WATCOMC11C := $(wildcard $(KBUILD_DEVTOOLS_TRG)/watcom/v11.0c*) endif ifeq ($(PATH_TOOL_WATCOMC11C),) PATH_TOOL_WATCOMC11C := $(wildcard $(KBUILD_DEVTOOLS)/common/watcom/v11.0c*) endif ifeq ($(PATH_TOOL_WATCOMC11C)$(KBUILD_HOST),os2) if1of ($(USER) $(USERNAME) $(LOGNAME), bird) PATH_TOOL_WATCOMC11C := $(wildcard d:/dev/Watcom/v11.0c*) endif endif PATH_TOOL_WATCOMC11C := $(firstword $(sort $(PATH_TOOL_WATCOMC11C))) # if not found, we'll enter 'pathless' mode. else # Resolve any fancy stuff once and for all. PATH_TOOL_WATCOMC11C := $(PATH_TOOL_WATCOMC11C) endif ifneq ($(PATH_TOOL_WATCOMC11C),) TOOL_WATCOMC11C_PATHLESS := no ifeq ($(KBUILD_HOST),os2) PATH_TOOL_WATCOMC11C_BIN = $(PATH_TOOL_WATCOMC11C)/binp PATH_TOOL_WATCOMC11C_BIN2 = $(PATH_TOOL_WATCOMC11C)/binw TOOL_WATCOMC11C_ENV_SETUP ?= $(REDIRECT) \ -E 'BEGINLIBPATH=$(PATH_TOOL_WATCOMC11C)/binp/dll;$(BEGINLIBPATH)' \ -E 'LIBPATHSTRICT=T' \ -E 'PATH=$(PATH_TOOL_WATCOMC11C_BIN);$(PATH_TOOL_WATCOMC11C_BIN2)' \ -E 'WATCOM=$(PATH_TOOL_WATCOMC11C)' \ -E 'EDPATH=$(PATH_TOOL_WATCOMC11C)/EDDAT' \ -E 'LIB=$1' \ -E 'INCLUDE=' \ $2 -- else PATH_TOOL_WATCOMC11C_BIN = $(PATH_TOOL_WATCOMC11C)/binnt PATH_TOOL_WATCOMC11C_BIN2 = $(PATH_TOOL_WATCOMC11C_BIN) TOOL_WATCOMC11C_ENV_SETUP ?= $(REDIRECT) \ -E 'PATH=$(PATH_TOOL_WATCOMC11C_BIN);$(PATH_TOOL_WATCOMC11C)/binw' \ -E 'WATCOM=$(PATH_TOOL_WATCOMC11C)' \ -E 'EDPATH=$(PATH_TOOL_WATCOMC11C)/EDDAT' \ -E 'LIB=$1' \ -E 'INCLUDE=' \ $2 -- endif TOOL_WATCOMC11C_CC ?= $(PATH_TOOL_WATCOMC11C_BIN)/wcc386$(HOSTSUFF_EXE) TOOL_WATCOMC11C_CC16 ?= $(PATH_TOOL_WATCOMC11C_BIN)/wcc$(HOSTSUFF_EXE) TOOL_WATCOMC11C_CXX ?= $(PATH_TOOL_WATCOMC11C_BIN)/wpp386$(HOSTSUFF_EXE) TOOL_WATCOMC11C_CXX16 ?= $(PATH_TOOL_WATCOMC11C_BIN)/wpp$(HOSTSUFF_EXE) TOOL_WATCOMC11C_AS ?= $(PATH_TOOL_WATCOMC11C_BIN)/wasm$(HOSTSUFF_EXE) TOOL_WATCOMC11C_AR ?= $(PATH_TOOL_WATCOMC11C_BIN)/wlib$(HOSTSUFF_EXE) TOOL_WATCOMC11C_RC ?= $(PATH_TOOL_WATCOMC11C_BIN2)/wrc$(HOSTSUFF_EXE) TOOL_WATCOMC11C_LD ?= $(PATH_TOOL_WATCOMC11C_BIN2)/wcl386$(HOSTSUFF_EXE) TOOL_WATCOMC11C_LD16 ?= $(PATH_TOOL_WATCOMC11C_BIN2)/wcl$(HOSTSUFF_EXE) TOOL_WATCOMC11C_WLINK ?= $(PATH_TOOL_WATCOMC11C_BIN2)/wlink$(HOSTSUFF_EXE) else # Pathless, relies on the environment. TOOL_WATCOMC11C_PATHLESS := TOOL_WATCOMC11C_ENV_SETUP ?= $(REDIRECT) \ -E 'LIB=$1' \ -E 'INCLUDE=' \ $2 -- TOOL_WATCOMC11C_CC ?= wcc386$(HOSTSUFF_EXE) TOOL_WATCOMC11C_CC16 ?= wcc$(HOSTSUFF_EXE) TOOL_WATCOMC11C_CXX ?= wpp386$(HOSTSUFF_EXE) TOOL_WATCOMC11C_CXX16 ?= wpp$(HOSTSUFF_EXE) TOOL_WATCOMC11C_AS ?= wasm$(HOSTSUFF_EXE) TOOL_WATCOMC11C_AR ?= wlib$(HOSTSUFF_EXE) TOOL_WATCOMC11C_RC ?= wrc$(HOSTSUFF_EXE) TOOL_WATCOMC11C_LD ?= wcl386$(HOSTSUFF_EXE) TOOL_WATCOMC11C_LD16 ?= wcl$(HOSTSUFF_EXE) TOOL_WATCOMC11C_WLINK ?= wcl$(HOSTSUFF_EXE) endif if $(KBUILD_KMK_REVISION) >= 2747 TOOL_WATCOMC11C_ENV_SETUP_BD ?= $(call TOOL_WATCOMC11C_ENV_SETUP,$1,$2 --wcc-brain-damage) else TOOL_WATCOMC11C_ENV_SETUP_BD ?= $(call TOOL_WATCOMC11C_ENV_SETUP,$1,$2) endif # General Properties used by kBuild TOOL_WATCOMC11C_COBJSUFF ?= .obj TOOL_WATCOMC11C_CFLAGS ?= -zq TOOL_WATCOMC11C_CFLAGS.dos ?= -bt=dos TOOL_WATCOMC11C_CFLAGS.os2 ?= -bt=os2 TOOL_WATCOMC11C_CFLAGS.win ?= -bt=nt ifdef PATH_TOOL_WATCOMC11C TOOL_WATCOMC11C_CINCS ?= $(PATH_TOOL_WATCOMC11C)/h endif TOOL_WATCOMC11C_CXXOBJSUFF ?= .obj TOOL_WATCOMC11C_CXXFLAGS ?= -zq TOOL_WATCOMC11C_CXXFLAGS.dos ?= -bt=dos TOOL_WATCOMC11C_CXXFLAGS.os2 ?= -bt=os2 TOOL_WATCOMC11C_CXXFLAGS.win ?= -bt=nt ifdef PATH_TOOL_WATCOMC11C TOOL_WATCOMC11C_CXXINCS ?= $(PATH_TOOL_WATCOMC11C)/h endif TOOL_WATCOMC11C_RCOBJSUFF ?= .res TOOL_WATCOMC11C_RCFLAGS ?= -r ifdef PATH_TOOL_WATCOMC11C TOOL_WATCOMC11C_RCINCS ?= $(PATH_TOOL_WATCOMC11C)/h endif TOOL_WATCOMC11C_ARFLAGS ?= -q TOOL_WATCOMC11C_ARLIBSUFF ?= .lib TOOL_WATCOMC11C_LDFLAGS ?= -zq -y TOOL_WATCOMC11C_LDFLAGS.dos ?= -bt=dos TOOL_WATCOMC11C_LDFLAGS.os2 ?= -bt=os2 TOOL_WATCOMC11C_LDFLAGS.win ?= -bt=nt TOOL_WATCOMC11C_COMPILE_C_DEPEND = TOOL_WATCOMC11C_COMPILE_C_DEPORD = TOOL_WATCOMC11C_COMPILE_C_OUTPUT = $(obj).err define TOOL_WATCOMC11C_COMPILE_C_CMDS $(QUIET) $(call TOOL_WATCOMC11C_ENV_SETUP_BD) $(TOOL_WATCOMC11C_CC) \ $(flags) \ $(addsuffix , $(addprefix -i=, $(subst /,\\,$(incs)))) \ $(addprefix -d, $(defs)) \ -fo=$(subst /,\\,$(obj)) \ -fr=$(subst /,\\,$(obj)).err \ $(subst /,\\,$(abspath $(source))) $(QUIET)$(APPEND) -n $(obj).err ## @todo dependencies endef TOOL_WATCOMC11C_COMPILE_CXX_DEPEND = TOOL_WATCOMC11C_COMPILE_CXX_DEPORD = TOOL_WATCOMC11C_COMPILE_CXX_OUTPUT = $(obj).err define TOOL_WATCOMC11C_COMPILE_CXX_CMDS $(QUIET) $(call TOOL_WATCOMC11C_ENV_SETUP_BD) $(TOOL_WATCOMC11C_CXX) \ $(flags) \ $(addsuffix , $(addprefix -i=, $(subst /,\\,$(incs)))) \ $(addprefix -d, $(defs)) \ -fo=$(subst /,\\,$(obj)) \ -fr=$(subst /,\\,$(obj)).err \ $(subst /,\\,$(abspath $(source))) $(QUIET)$(APPEND) -n $(obj).err ## @todo dependencies endef TOOL_WATCOMC11C_COMPILE_RC_OUTPUT = TOOL_WATCOMC11C_COMPILE_RC_DEPEND = TOOL_WATCOMC11C_COMPILE_RC_DEPORD = define TOOL_WATCOMC11C_COMPILE_RC_CMDS $(QUIET) $(call TOOL_WATCOMC11C_ENV_SETUP) \ $(TOOL_WATCOMC11C_RC) -r\ $(flags) \ $(addprefix -i=, $(subst /,\\,$(incs))) \ $(addprefix -d, $(defs))\ -fo=$(subst /,\\,$(obj)) \ $(subst /,\\,$(abspath $(source))) endef TOOL_WATCOMC11C_LINK_LIBRARY_OUTPUT = $(outbase).rsp TOOL_WATCOMC11C_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_WATCOMC11C_LINK_LIBRARY_DEPORD = define TOOL_WATCOMC11C_LINK_LIBRARY_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp $(foreach obj,$(subst /,\,$(objs) $(othersrc)),'+"$(obj)"') $(QUIET)$(TOOL_WATCOMC11C_ENV_SETUP_BD) $(TOOL_WATCOMC11C_AR) $(flags) $(subst /,\\,$(out)) @$(outbase).rsp endef TOOL_WATCOMC11C_LINK_PROGRAM_OUTPUT = $(outbase).map TOOL_WATCOMC11C_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_WATCOMC11C_LINK_PROGRAM_DEPORD = define TOOL_WATCOMC11C_LINK_PROGRAM_CMDS $(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP_BD,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \ $(TOOL_WATCOMC11C_LD) \ $(flags) \ -fe=$(subst /,\\,$(out)) \ -fm=$(subst /,\\,$(outbase).map) \ $(subst /,\\,$(filter-out %.res,$(objs))) \ $(subst /,\\,$(libs)) \ $(subst /,\\,$(othersrc)) $(if $(filter %.res,$(objs)), $(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP) \ $(TOOL_WATCOMC11C_RC) \ $(filter -bt=%,$(flags)) \ /fe=$(subst /,\\,$(out)) \ $(subst /,\\,$(filter %.res,$(objs)))) endef TOOL_WATCOMC11C_LINK_DLL_OUTPUT = $(outbase).map TOOL_WATCOMC11C_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_WATCOMC11C_LINK_DLL_DEPORD = define TOOL_WATCOMC11C_LINK_DLL_CMDS $(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP_BD,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \ $(TOOL_WATCOMC11C_LD) \ $(flags) \ -fe=$(subst /,\\,$(out)) \ -fm=$(subst /,\\,$(outbase).map) \ $(subst /,\\,$(filter-out %.res,$(objs))) \ $(subst /,\\,$(libs)) \ $(subst /,\\,$(othersrc)) $(if $(filter %.res,$(objs)), $(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP) \ $(TOOL_WATCOMC11C_RC) \ $(filter -bt=%,$(flags)) \ /fe=$(subst /,\\,$(out)) \ $(subst /,\\,$(filter %.res,$(objs)))) endef TOOL_WATCOMC11C_LINK_SYSMOD_OUTPUT = $(outbase).map TOOL_WATCOMC11C_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_WATCOMC11C_LINK_SYSMOD_DEPORD = define TOOL_WATCOMC11C_LINK_SYSMOD_CMDS $(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP_BD,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \ $(TOOL_WATCOMC11C_LD) \ $(flags) \ -fe=$(subst /,\\,$(out)) \ -fm=$(subst /,\\,$(outbase).map) \ $(subst /,\\,$(filter-out %.res,$(objs))) \ $(subst /,\\,$(libs)) \ $(subst /,\\,$(othersrc)) $(if $(filter %.res,$(objs)), $(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP) \ $(TOOL_WATCOMC11C_RC) \ $(filter -bt=%,$(flags)) \ /fe=$(subst /,\\,$(out)) \ $(subst /,\\,$(filter %.res,$(objs)))) endef kbuild-3149/kBuild/tools/LLVMGCC42MACHO.kmk0000644000175000017500000004714213252530251017775 0ustar locutuslocutus# $Id: LLVMGCC42MACHO.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - LLVM GCC v4.2.x targeting Darwin (Mac OS X) Mach-O. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_LLVMGCC42MACHO := LLVM GCC v4.2.x targeting Darwin (Mac OS X) Mach-O. # Tool Specific Properties TOOL_LLVMGCC42MACHO_PREFIX ?= llvm- TOOL_LLVMGCC42MACHO_SUFFIX ?= -4.2$(HOSTSUFF_EXE) TOOL_LLVMGCC42MACHO_CC ?= $(TOOL_LLVMGCC42MACHO_PREFIX)gcc$(TOOL_LLVMGCC42MACHO_SUFFIX) TOOL_LLVMGCC42MACHO_CXX ?= $(TOOL_LLVMGCC42MACHO_PREFIX)g++$(TOOL_LLVMGCC42MACHO_SUFFIX) TOOL_LLVMGCC42MACHO_OBJC ?= $(TOOL_LLVMGCC42MACHO_PREFIX)gcc$(TOOL_LLVMGCC42MACHO_SUFFIX) TOOL_LLVMGCC42MACHO_OBJCXX ?= $(TOOL_LLVMGCC42MACHO_PREFIX)gcc$(TOOL_LLVMGCC42MACHO_SUFFIX) TOOL_LLVMGCC42MACHO_AS ?= $(TOOL_LLVMGCC42MACHO_PREFIX)gcc$(TOOL_LLVMGCC42MACHO_SUFFIX) TOOL_LLVMGCC42MACHO_LD ?= $(TOOL_LLVMGCC42MACHO_PREFIX)gcc$(TOOL_LLVMGCC42MACHO_SUFFIX) TOOL_LLVMGCC42MACHO_LD_SYSMOD ?= $(TOOL_LLVMGCC42MACHO_PREFIX)gcc$(TOOL_LLVMGCC42MACHO_SUFFIX) ifndef TOOL_LLVMGCC42MACHO_LDFLAGS.$(KBUILD_TARGET) TOOL_LLVMGCC42MACHO_LDFLAGS.dll ?= -dynamiclib else TOOL_LLVMGCC42MACHO_LDFLAGS.dll ?= $(TOOL_LLVMGCC42MACHO_LDFLAGS.$(KBUILD_TARGET)) endif TOOL_LLVMGCC42MACHO_LDFLAGS.sysmod ?= -r #TOOL_LLVMGCC42MACHO_LD_SONAME = -Wl,-dylib_install_name $(firstword $($(1)_SONAME.$(KBUILD_TARGET).$(KBUILD_TYPE)) $($(1)_SONAME.$(KBUILD_TARGET)) $($(1)_SONAME.$(KBUILD_TYPE)) $($(1)_SONAME) $(notdir $(2))) TOOL_LLVMGCC42MACHO_DSYMUTIL ?= dsymutil ifdef SLKRUNS TOOL_LLVMGCC42MACHO_CC += -fmessage-length=0 TOOL_LLVMGCC42MACHO_CXX += -fmessage-length=0 TOOL_LLVMGCC42MACHO_OBJC += -fmessage-length=0 TOOL_LLVMGCC42MACHO_OBJCXX += -fmessage-length=0 endif # General Properties used by kBuild TOOL_LLVMGCC42MACHO_COBJSUFF ?= .o TOOL_LLVMGCC42MACHO_CFLAGS ?= TOOL_LLVMGCC42MACHO_CFLAGS.debug ?= -g TOOL_LLVMGCC42MACHO_CFLAGS.profile ?= -g -O2 #-pg TOOL_LLVMGCC42MACHO_CFLAGS.release ?= -O2 TOOL_LLVMGCC42MACHO_CINCS ?= TOOL_LLVMGCC42MACHO_CDEFS ?= TOOL_LLVMGCC42MACHO_CXXOBJSUFF ?= .o TOOL_LLVMGCC42MACHO_CXXFLAGS ?= TOOL_LLVMGCC42MACHO_CXXFLAGS.debug ?= -g TOOL_LLVMGCC42MACHO_CXXFLAGS.profile ?= -g -O2 #-pg TOOL_LLVMGCC42MACHO_CXXFLAGS.release ?= -O2 TOOL_LLVMGCC42MACHO_CXXINCS ?= TOOL_LLVMGCC42MACHO_CXXDEFS ?= TOOL_LLVMGCC42MACHO_OBJCOBJSUFF ?= .o TOOL_LLVMGCC42MACHO_OBJCFLAGS ?= TOOL_LLVMGCC42MACHO_OBJCFLAGS.debug ?= -g TOOL_LLVMGCC42MACHO_OBJCFLAGS.profile?= -O2 #-g -pg TOOL_LLVMGCC42MACHO_OBJCFLAGS.release?= -O2 TOOL_LLVMGCC42MACHO_OBJCINCS ?= TOOL_LLVMGCC42MACHO_OBJCDEFS ?= TOOL_LLVMGCC42MACHO_OBJCXXOBJSUFF ?= .o TOOL_LLVMGCC42MACHO_OBJCXXFLAGS ?= TOOL_LLVMGCC42MACHO_OBJCXXFLAGS.debug ?= -g TOOL_LLVMGCC42MACHO_OBJCXXFLAGS.profile ?= -O2 #-g -pg TOOL_LLVMGCC42MACHO_OBJCXXFLAGS.release ?= -O2 TOOL_LLVMGCC42MACHO_OBJCXXINCS ?= TOOL_LLVMGCC42MACHO_OBJCXXDEFS ?= TOOL_LLVMGCC42MACHO_ASFLAGS ?= -x assembler-with-cpp TOOL_LLVMGCC42MACHO_ASFLAGS.debug ?= -g TOOL_LLVMGCC42MACHO_ASFLAGS.profile ?= -g TOOL_LLVMGCC42MACHO_ASOBJSUFF ?= .o TOOL_LLVMGCC42MACHO_AR ?= ar$(HOSTSUFF_EXE) TOOL_LLVMGCC42MACHO_ARFLAGS ?= -c -rs TOOL_LLVMGCC42MACHO_ARLIBSUFF ?= .a TOOL_LLVMGCC42MACHO_LDFLAGS ?= TOOL_LLVMGCC42MACHO_LDFLAGS.debug ?= -g TOOL_LLVMGCC42MACHO_LDFLAGS.profile ?= -g TOOL_LLVMGCC42MACHO_STRIP_PROGRAM ?= strip -SXxru TOOL_LLVMGCC42MACHO_STRIP_DLL ?= strip -Sxru TOOL_LLVMGCC42MACHO_STRIP_SYSMOD ?= strip -Sru ## # Calculate the files in the debug bundle. # @param 1 The whole output filename. # @param 2 The output filename sans suffix. TOOL_LLVMGCC42MACHO_DEBUG_BUNDLE_FN = \ $(1).dSYM/ \ $(1).dSYM/Contents/ \ $(1).dSYM/Contents/Resources/ \ $(1).dSYM/Contents/Resources/DWARF/ \ $(1).dSYM/Contents/Info.plist \ $(1).dSYM/Contents/Resources/DWARF/$(notdir $(1)) ## # Calculate the files in the debug bundle. # @param 1 The whole linker output filename. # @param 2 The linker output filename sans suffix. # @param 3 The desired install name (no dir slash). # @remarks The Info.plist has some reference to the original name, but gdb # does not care and only check for a symbol file in the DWARF # directory with the same name as the debugged module. TOOL_LLVMGCC42MACHO_DEBUG_INSTALL_FN= \ $(3).dSYM/ \ $(3).dSYM/Contents/ \ $(3).dSYM/Contents/Resources/ \ $(3).dSYM/Contents/Resources/DWARF/ \ $(1).dSYM/Contents/Info.plist=>$(3).dSYM/Contents/Info.plist \ $(1).dSYM/Contents/Resources/DWARF/$(notdir $(1))=>$(3).dSYM/Contents/Resources/DWARF/$(notdir $(3)) ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_LLVMGCC42MACHO_COMPILE_C_DEPEND = TOOL_LLVMGCC42MACHO_COMPILE_C_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_LLVMGCC42MACHO_COMPILE_C_USES_KOBJCACHE = 1 TOOL_LLVMGCC42MACHO_COMPILE_C_OUTPUT = $(outbase).i define TOOL_LLVMGCC42MACHO_COMPILE_C_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).i\ $(TOOL_LLVMGCC42MACHO_CC) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_LLVMGCC42MACHO_CC) -c\ $(flags) -fpreprocessed -x c\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_LLVMGCC42MACHO_COMPILE_C_OUTPUT = define TOOL_LLVMGCC42MACHO_COMPILE_C_CMDS $(QUIET)$(TOOL_LLVMGCC42MACHO_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KUSE_OBJCACHE ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_LLVMGCC42MACHO_COMPILE_CXX_DEPEND = TOOL_LLVMGCC42MACHO_COMPILE_CXX_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_LLVMGCC42MACHO_COMPILE_CXX_USES_KOBJCACHE = 1 TOOL_LLVMGCC42MACHO_COMPILE_CXX_OUTPUT = $(outbase).ii define TOOL_LLVMGCC42MACHO_COMPILE_CXX_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).ii\ $(TOOL_LLVMGCC42MACHO_CXX) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_LLVMGCC42MACHO_CXX) -c\ $(flags) -fpreprocessed -x c++\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_LLVMGCC42MACHO_COMPILE_CXX_OUTPUT = define TOOL_LLVMGCC42MACHO_COMPILE_CXX_CMDS $(QUIET)$(TOOL_LLVMGCC42MACHO_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile Objective-C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_LLVMGCC42MACHO_COMPILE_OBJC_DEPEND = TOOL_LLVMGCC42MACHO_COMPILE_OBJC_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_LLVMGCC42MACHO_COMPILE_OBJC_USES_KOBJCACHE = 1 TOOL_LLVMGCC42MACHO_COMPILE_OBJC_OUTPUT = $(outbase).mi define TOOL_LLVMGCC42MACHO_COMPILE_OBJC_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).ii\ $(TOOL_LLVMGCC42MACHO_OBJC) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_LLVMGCC42MACHO_OBJC) -c\ $(flags) -fpreprocessed -x cbjective-c\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_LLVMGCC42MACHO_COMPILE_OBJC_OUTPUT = define TOOL_LLVMGCC42MACHO_COMPILE_OBJC_CMDS $(QUIET)$(TOOL_LLVMGCC42MACHO_OBJC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile Objective-C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_LLVMGCC42MACHO_COMPILE_OBJCXX_DEPEND = TOOL_LLVMGCC42MACHO_COMPILE_OBJCXX_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_LLVMGCC42MACHO_COMPILE_OBJCXX_USES_KOBJCACHE = 1 TOOL_LLVMGCC42MACHO_COMPILE_OBJCXX_OUTPUT = $(outbase).mii define TOOL_LLVMGCC42MACHO_COMPILE_OBJCXX_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).mii\ $(TOOL_LLVMGCC42MACHO_OBJCXX) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_LLVMGCC42MACHO_OBJCXX) -c\ $(flags) -fpreprocessed -x objective-c++\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_LLVMGCC42MACHO_COMPILE_OBJCXX_OUTPUT = define TOOL_LLVMGCC42MACHO_COMPILE_OBJCXX_CMDS $(QUIET)$(TOOL_LLVMGCC42MACHO_OBJCXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile Assembly source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. # TOOL_LLVMGCC42MACHO_COMPILE_AS_OUTPUT = TOOL_LLVMGCC42MACHO_COMPILE_AS_DEPEND = TOOL_LLVMGCC42MACHO_COMPILE_AS_DEPORD = define TOOL_LLVMGCC42MACHO_COMPILE_AS_CMDS $(QUIET)$(TOOL_LLVMGCC42MACHO_AS) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_LLVMGCC42MACHO_LINK_LIBRARY_OUTPUT = TOOL_LLVMGCC42MACHO_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_LLVMGCC42MACHO_LINK_LIBRARY_DEPORD = define TOOL_LLVMGCC42MACHO_LINK_LIBRARY_CMDS $(if $(strip $(objs)),$(call xargs,$(QUIET)$(TOOL_LLVMGCC42MACHO_AR) $(flags) $(out),$(objs))) $(foreach lib,$(othersrc)\ ,$(NL)$(TAB)$(call MSG_AR_MERGE,$(target),$(out),$(lib)) \ $(NL)$(TAB)$(QUIET)$(RM_EXT) -f $(dir $(outbase))ar.tmp.dir/* \ $(NL)$(TAB)$(QUIET)$(MKDIR) -p $(dir $(outbase))/ar.tmp.dir/ \ $(NL)$(TAB)$(QUIET)(cd $(dir $(outbase))ar.tmp.dir/ \ && $(TOOL_LLVMGCC42MACHO_AR) -x $(abspath $(lib)) \ && $(RM_EXT) -f ./__.SYMDEF* \ && $(TOOL_LLVMGCC42MACHO_AR) $(flags) $(out) *) \ $(NL)$(TAB)$(QUIET)$(RM_EXT) -f $(dir $(outbase))/ar.tmp.dir/* \ $(NL)$(TAB)$(QUIET)$(RMDIR) $(dir $(outbase))ar.tmp.dir/) endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_LLVMGCC42MACHO_LINK_PROGRAM_OUTPUT = $(outbase).rsp TOOL_LLVMGCC42MACHO_LINK_PROGRAM_OUTPUT_DEBUG = $(call TOOL_LLVMGCC42MACHO_DEBUG_BUNDLE_FN,$(out)) TOOL_LLVMGCC42MACHO_LINK_PROGRAM_DEBUG_INSTALL_FN = $(TOOL_LLVMGCC42MACHO_DEBUG_INSTALL_FN) TOOL_LLVMGCC42MACHO_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_LLVMGCC42MACHO_LINK_PROGRAM_DEPORD = define TOOL_LLVMGCC42MACHO_LINK_PROGRAM_CMDS $(QUIET)$(APPEND) -n $(outbase).rsp $(objs) $(QUIET)$(TOOL_LLVMGCC42MACHO_LD) $(flags) -o $(out)\ -filelist $(outbase).rsp\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib))) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_LLVMGCC42MACHO_DSYMUTIL) -o $(out).dSYM/ $(out) $(QUIET)$(TOOL_LLVMGCC42MACHO_STRIP_PROGRAM) $(out) endif endef ## Link DLL # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_LLVMGCC42MACHO_LINK_DLL_OUTPUT = $(outbase).rsp TOOL_LLVMGCC42MACHO_LINK_DLL_OUTPUT_DEBUG = $(call TOOL_LLVMGCC42MACHO_DEBUG_BUNDLE_FN,$(out)) TOOL_LLVMGCC42MACHO_LINK_DLL_DEBUG_INSTALL_FN = $(TOOL_LLVMGCC42MACHO_DEBUG_INSTALL_FN) TOOL_LLVMGCC42MACHO_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_LLVMGCC42MACHO_LINK_DLL_DEPORD = define TOOL_LLVMGCC42MACHO_LINK_DLL_CMDS $(QUIET)$(APPEND) -n $(outbase).rsp $(objs) $(QUIET)$(TOOL_LLVMGCC42MACHO_LD) $(TOOL_LLVMGCC42MACHO_LDFLAGS.dll) $(flags) -o $(out)\ $(call TOOL_LLVMGCC42MACHO_LD_SONAME,$(target),$(out))\ -filelist $(outbase).rsp\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib))) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_LLVMGCC42MACHO_DSYMUTIL) -o $(out).dSYM/ $(out) $(QUIET)$(TOOL_LLVMGCC42MACHO_STRIP_DLL) $(out) endif endef ## Link system module (windows aka driver, linux aka kernel module) # @param $(target) Normalized main target name. # @param $(out) System module name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_LLVMGCC42MACHO_LINK_SYSMOD_OUTPUT = $(outbase).rsp TOOL_LLVMGCC42MACHO_LINK_SYSMOD_OUTPUT_DEBUG = $(call TOOL_LLVMGCC42MACHO_DEBUG_BUNDLE_FN,$(out)) TOOL_LLVMGCC42MACHO_LINK_SYSMOD_DEBUG_INSTALL_FN = $(TOOL_LLVMGCC42MACHO_DEBUG_INSTALL_FN) TOOL_LLVMGCC42MACHO_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_LLVMGCC42MACHO_LINK_SYSMOD_DEPORD = define TOOL_LLVMGCC42MACHO_LINK_SYSMOD_CMDS $(QUIET)$(APPEND) -n $(outbase).rsp $(objs) $(QUIET)$(TOOL_LLVMGCC42MACHO_LD_SYSMOD) $(TOOL_LLVMGCC42MACHO_LDFLAGS.sysmod) $(flags) -o $(out)\ -filelist $(outbase).rsp\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib))) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_LLVMGCC42MACHO_DSYMUTIL) -o $(out).dSYM/ $(out) $(QUIET)$(TOOL_LLVMGCC42MACHO_STRIP_SYSMOD) $(out) endif endef kbuild-3149/kBuild/tools/GCC3.kmk0000644000175000017500000003316013252530251016442 0ustar locutuslocutus# $Id: GCC3.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - Generic GCC v3.2.x or later Using The System GCC and Binutils. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_GCC3 := Generic GCC v3.2.x or later Using The System GCC and Binutils. # Tool Specific Properties TOOL_GCC3_CC ?= gcc$(HOSTSUFF_EXE) TOOL_GCC3_CXX ?= g++$(HOSTSUFF_EXE) TOOL_GCC3_AS ?= gcc$(HOSTSUFF_EXE) ifeq ($(KBUILD_TARGET),solaris) ## @todo drop the MRI script! TOOL_GCC3_AR ?= gar$(HOSTSUFF_EXE) else TOOL_GCC3_AR ?= ar$(HOSTSUFF_EXE) endif ifeq ($(KBUILD_TARGET),os2) TOOL_GCC3_AR_IMP ?= emximp$(HOSTSTUFF_EXE) else TOOL_GCC3_AR_IMP ?= $(ECHO) not supported! endif TOOL_GCC3_LD ?= gcc$(HOSTSUFF_EXE) TOOL_GCC3_LD_SYSMOD ?= ld$(HOSTSUFF_EXE) ifndef TOOL_GCC3_LDFLAGS.$(KBUILD_TARGET) TOOL_GCC3_LDFLAGS.dll ?= -shared else TOOL_GCC3_LDFLAGS.dll ?= $(TOOL_GCC3_LDFLAGS.$(KBUILD_TARGET)) endif TOOL_GCC3_LDFLAGS.sysmod ?= -r TOOL_GCC3_LD_SONAME ?= -Wl,-soname=$(firstword $($(1)_SONAME.$(KBUILD_TARGET).$(KBUILD_TYPE)) $($(1)_SONAME.$(KBUILD_TARGET)) $($(1)_SONAME.$(KBUILD_TYPE)) $($(1)_SONAME) $(notdir $(2))) ifeq ($(KBUILD_TARGET),os2) TOOL_GCC3_LD_MAP ?= -Zmap=$(1) TOOL_GCC3_LD_SYSMOD_MAP ?= -Zmap=$(1) else TOOL_GCC3_LD_MAP ?= TOOL_GCC3_LD_SYSMOD_MAP ?= endif if1of ($(KBUILD_HOST), solaris) TOOL_GCC3_OBJCOPY ?= gobjcopy$(HOSTSUFF_EXE) else TOOL_GCC3_OBJCOPY ?= objcopy$(HOSTSUFF_EXE) endif ifdef SLKRUNS TOOL_GCC3_CC += -fmessage-length=0 TOOL_GCC3_CXX += -fmessage-length=0 endif # General Properties used by kBuild TOOL_GCC3_COBJSUFF ?= .o TOOL_GCC3_CFLAGS ?= TOOL_GCC3_CFLAGS.debug ?= -g TOOL_GCC3_CFLAGS.profile ?= -O2 #-g -pg TOOL_GCC3_CFLAGS.release ?= -O2 TOOL_GCC3_CINCS ?= TOOL_GCC3_CDEFS ?= TOOL_GCC3_CXXOBJSUFF ?= .o TOOL_GCC3_CXXOBJSUFF ?= .o TOOL_GCC3_CXXFLAGS ?= TOOL_GCC3_CXXFLAGS.debug ?= -g TOOL_GCC3_CXXFLAGS.profile ?= -O2 #-g -pg TOOL_GCC3_CXXFLAGS.release ?= -O2 TOOL_GCC3_CXXINCS ?= TOOL_GCC3_CXXDEFS ?= TOOL_GCC3_ASFLAGS ?= -x assembler-with-cpp TOOL_GCC3_ASFLAGS.debug ?= -g TOOL_GCC3_ASFLAGS.profile ?= -g TOOL_GCC3_ASOBJSUFF ?= .o TOOL_GCC3_ARFLAGS ?= cr TOOL_GCC3_ARLIBSUFF ?= .a TOOL_GCC3_LDFLAGS ?= TOOL_GCC3_LDFLAGS.debug ?= -g TOOL_GCC3_LDFLAGS.profile ?= -g ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GCC3_COMPILE_C_DEPEND = TOOL_GCC3_COMPILE_C_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GCC3_COMPILE_C_USES_KOBJCACHE = 1 TOOL_GCC3_COMPILE_C_OUTPUT = $(outbase).i define TOOL_GCC3_COMPILE_C_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).i\ $(TOOL_GCC3_CC) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GCC3_CC) -c\ $(flags) -fpreprocessed -x c\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GCC3_COMPILE_C_OUTPUT = define TOOL_GCC3_COMPILE_C_CMDS $(QUIET)$(TOOL_GCC3_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GCC3_COMPILE_CXX_DEPEND = TOOL_GCC3_COMPILE_CXX_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GCC3_COMPILE_CXX_USES_KOBJCACHE = 1 TOOL_GCC3_COMPILE_CXX_OUTPUT = $(outbase).ii define TOOL_GCC3_COMPILE_CXX_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).ii\ $(TOOL_GCC3_CXX) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GCC3_CXX) -c\ $(flags) -fpreprocessed -x c++\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GCC3_COMPILE_CXX_OUTPUT = define TOOL_GCC3_COMPILE_CXX_CMDS $(QUIET)$(TOOL_GCC3_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile Assembly source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. # TOOL_GCC3_COMPILE_AS_OUTPUT = TOOL_GCC3_COMPILE_AS_DEPEND = TOOL_GCC3_COMPILE_AS_DEPORD = define TOOL_GCC3_COMPILE_AS_CMDS $(QUIET)$(TOOL_GCC3_AS) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC3_LINK_LIBRARY_OUTPUT = $(out).ar-script TOOL_GCC3_LINK_LIBRARY_OUTPUT_MAYBE = $(outbase).imp.a TOOL_GCC3_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_GCC3_LINK_LIBRARY_DEPORD = define TOOL_GCC3_LINK_LIBRARY_CMDS $(QUIET)$(APPEND) $(out).ar-script 'CREATE $(out)' $(QUIET)$(APPEND) -n $(out).ar-script \ $(foreach o,$(objs), 'ADDMOD $(o)') \ $(foreach o,$(filter-out %.def %.imp %.dll,$(othersrc)), 'ADDLIB $(o)') $(if $(filter %.def %.imp %.dll,$(othersrc))\ ,$(TOOL_GCC3_AR_IMP) -o $(outbase).imp.a $(filter %.def %.imp %.dll,$(othersrc))\ $(NL)$(TAB)$(QUIET)$(APPEND) $(out).ar-script 'ADDLIB $(outbase).imp.a') $(QUIET)$(APPEND) $(out).ar-script 'SAVE' $(QUIET)$(APPEND) $(out).ar-script 'END' $(QUIET)$(REDIRECT) -rti $(out).ar-script -- $(TOOL_GCC3_AR) -M endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC3_LINK_PROGRAM_OUTPUT = TOOL_GCC3_LINK_PROGRAM_OUTPUT_MAYBE = $(outbase).map TOOL_GCC3_LINK_PROGRAM_OUTPUT_DEBUG = $(outbase).debug TOOL_GCC3_LINK_PROGRAM_DEBUG_INSTALL_FN = $(2).debug=>$(basename $(3)).debug TOOL_GCC3_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib)))\ $(filter %.def, $(othersrc)) TOOL_GCC3_LINK_PROGRAM_DEPORD = define TOOL_GCC3_LINK_PROGRAM_CMDS $(QUIET)$(TOOL_GCC3_LD) $(flags) -o $(out) $(objs)\ $(filter %.def, $(othersrc))\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\ $(call TOOL_GCC3_LD_MAP,$(outbase).map) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GCC3_OBJCOPY) --only-keep-debug $(out) $(outbase).debug $(QUIET)$(CHMOD) a-x $(outbase).debug $(QUIET)$(TOOL_GCC3_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out) endif endef ## Link DLL # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC3_LINK_DLL_OUTPUT = TOOL_GCC3_LINK_DLL_OUTPUT_MAYBE = $(outbase).map TOOL_GCC3_LINK_DLL_OUTPUT_DEBUG = $(outbase).debug TOOL_GCC3_LINK_DLL_DEBUG_INSTALL_FN = $(2).debug=>$(basename $(3)).debug TOOL_GCC3_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib)))\ $(filter %.def, $(othersrc)) TOOL_GCC3_LINK_DLL_DEPORD = define TOOL_GCC3_LINK_DLL_CMDS $(QUIET)$(TOOL_GCC3_LD) $(TOOL_GCC3_LDFLAGS.dll) $(flags) -o $(out)\ $(if $(filter-out win os2, $(KBUILD_TARGET)),$(call TOOL_GCC3_LD_SONAME,$(target),$(out)))\ $(objs)\ $(filter %.def, $(othersrc))\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\ $(call TOOL_GCC3_LD_MAP,$(outbase).map) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GCC3_OBJCOPY) --only-keep-debug $(out) $(outbase).debug $(QUIET)$(CHMOD) a-x $(outbase).debug $(QUIET)$(TOOL_GCC3_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out) endif endef ## Link system module (windows aka driver, linux aka kernel module) # @param $(target) Normalized main target name. # @param $(out) System module name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC3_LINK_SYSMOD_OUTPUT = TOOL_GCC3_LINK_SYSMOD_OUTPUT_MAYBE = $(outbase).map TOOL_GCC3_LINK_SYSMOD_OUTPUT_DEBUG = $(outbase).debug TOOL_GCC3_LINK_SYSMOD_DEBUG_INSTALL_FN = $(2).debug=>$(basename $(3)).debug TOOL_GCC3_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib)))\ $(filter %.def, $(othersrc)) TOOL_GCC3_LINK_SYSMOD_DEPORD = define TOOL_GCC3_LINK_SYSMOD_CMDS $(QUIET)$(TOOL_GCC3_LD_SYSMOD) $(TOOL_GCC3_LDFLAGS.sysmod) $(flags) -o $(out) $(objs)\ $(filter %.def, $(othersrc))\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\ $(call TOOL_GCC3_LD_SYSMOD_MAP,$(outbase).map) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GCC3_OBJCOPY) --only-keep-debug $(out) $(outbase).debug $(QUIET)$(CHMOD) a-x $(outbase).debug $(QUIET)$(TOOL_GCC3_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out) endif endef kbuild-3149/kBuild/tools/TARGZ.kmk0000644000175000017500000000251713252530251016654 0ustar locutuslocutus# $Id: TARGZ.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - tar.gz unpacker. # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_TARGZ := tar.gz unpacker. TOOL_TARGZ_EXTENDS = TAR TOOL_TARGZ_UNPACKFLAGS ?= -z kbuild-3149/kBuild/tools/MASM6PLUS.kmk0000644000175000017500000000474013252530251017314 0ustar locutuslocutus# $Id: MASM6PLUS.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - MASM v6 and later. # # # Copyright (c) 2008-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_MASM6PLUS := Microsoft Macro Assembler v6 and later. # Tool Specific Properties ifndef TOOL_MASM6PLUS_AS TOOL_MASM6PLUS_AS := $(firstword $(rsort $(wildcard \ $(KBUILD_DEVTOOLS_HST)/masm/*/bin$(if $(eq $(KBUILD_HOST),os2),p,)/ml$(HOSTSUFF_EXE)\ ))) ifeq ($(TOOL_MASM6PLUS_AS),) TOOL_MASM6PLUS_AS := $(firstword $(rsort $(wildcard \ $(KBUILD_DEVTOOLS_HST)/vcc/*/bin/ml$(HOSTSUFF_EXE) \ ))) endif ifeq ($(TOOL_MASM6PLUS_AS),) TOOL_MASM6PLUS_AS := $(firstword $(rsort $(wildcard \ $(KBUILD_DEVTOOLS)/win.x86/vcc/*/bin/ml$(HOSTSUFF_EXE) \ ))) endif endif ifeq ($(TOOL_MASM6PLUS_AS),) TOOL_MASM6PLUS_AS := $(firstword $(which ml$(HOSTSUFF_EXE)) path/notfound/ml$(HOSTSUFF_EXE)) endif # General Properties used by kBuild TOOL_MASM6PLUS_ASFLAGS ?= /nologo TOOL_MASM6PLUS_COMPILE_AS_OUTPUT = $(outbase).lst TOOL_MASM6PLUS_COMPILE_AS_DEPEND = TOOL_MASM6PLUS_COMPILE_AS_DEPORD = define TOOL_MASM6PLUS_COMPILE_AS_CMDS $(QUIET)$(REDIRECT) \ -E 'INCLUDE=$(subst $(SP),,$(addsuffix ;,$(subst /,\,$(incs))))' \ -E 'MASM=' -E 'ML=' \ -- \ $(subst /,\\,$(TOOL_MASM6PLUS_AS)) -c \ $(strip $(flags)) \ $(addprefix -D,$(defs)) \ -Fo$(subst /,\\,$(obj)) \ -Fl$(subst /,\\,$(outbase).lst) \ $(subst /,\\,$(source)) endef kbuild-3149/kBuild/tools/MINGW32.kmk0000644000175000017500000002514413252530251017014 0ustar locutuslocutus# $Id: MINGW32.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - MinGW32 GCC v3.3+. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # ifdef TOOL_MINGW32 $(error Already included (TOOL_MINGW32=$(TOOL_MINGW32))) endif TOOL_MINGW32 := MinGW32 GCC v3.3+. # Tool Specific Properties ifndef PATH_TOOL_MINGW32 PATH_TOOL_MINGW32 := $(wildcard $(KBUILD_DEVTOOLS_HST)/mingw32/v*.*) ifeq ($(PATH_TOOL_MINGW32),) PATH_TOOL_MINGW32 := $(wildcard $(KBUILD_DEVTOOLS)/win.x86/mingw32/v*.*) endif ifeq ($(PATH_TOOL_MINGW32),) PATH_TOOL_MINGW32 := $(wildcard $(KBUILD_DEVTOOLS)/x86.win32/mingw32/v*.*) endif ifneq ($(PATH_TOOL_MINGW32),) PATH_TOOL_MINGW32 := $(lastword $(sort $(PATH_TOOL_MINGW32))) endif else # Resolve any fancy stuff once and for all. PATH_TOOL_MINGW32 := $(PATH_TOOL_MINGW32) endif # figure out if it's native or needs a win32 launcher TOOL_MINGW32_HOSTSUFF_EXE ?= $(HOSTSUFF_EXE) ifndef TOOL_MINGW32_PREFIX ifneq ($(PATH_TOOL_MINGW32),) TOOL_MINGW32_PREFIX := $(PATH_TOOL_MINGW32)/bin/ else TOOL_MINGW32_PREFIX := endif ifneq ($(KBUILD_HOST),win) # we're cross compiling either using an emulator (wine/odin) or a cross compiler. ifneq ($(PATH_TOOL_MINGW32),$(subst /win.x86,,$(subst /x86.win,,$(PATH_TOOL_MINGW32)))) TOOL_MINGW32_PREFIX := $(EXEC_X86_WIN32) $(TOOL_MINGW32_PREFIX) TOOL_MINGW32_HOSTSUFF_EXE := .exe else TOOL_MINGW32_PREFIX := $(TOOL_MINGW32_PREFIX)i386-mingw32msvc- TOOL_MINGW32_HOSTSUFF_EXE := TOOL_MINGW32_XCOMPILE := 1 endif endif else # Resolve any fancy stuff once and for all. TOOL_MINGW32_PREFIX := $(TOOL_MINGW32_PREFIX) endif TOOL_MINGW32_CC ?= $(TOOL_MINGW32_PREFIX)gcc$(TOOL_MINGW32_HOSTSUFF_EXE) TOOL_MINGW32_CXX ?= $(TOOL_MINGW32_PREFIX)g++$(TOOL_MINGW32_HOSTSUFF_EXE) TOOL_MINGW32_AS ?= $(TOOL_MINGW32_PREFIX)gcc$(TOOL_MINGW32_HOSTSUFF_EXE) TOOL_MINGW32_AR ?= $(TOOL_MINGW32_PREFIX)ar$(TOOL_MINGW32_HOSTSUFF_EXE) ifndef TOOL_MINGW32_XCOMPILE# The gentoo package doesn't have g++. TOOL_MINGW32_LD ?= $(TOOL_MINGW32_PREFIX)g++$(TOOL_MINGW32_HOSTSUFF_EXE) else TOOL_MINGW32_LD ?= $(TOOL_MINGW32_PREFIX)gcc$(TOOL_MINGW32_HOSTSUFF_EXE) endif TOOL_MINGW32_DLLWRAP ?= $(TOOL_MINGW32_PREFIX)dllwrap$(TOOL_MINGW32_HOSTSUFF_EXE) TOOL_MINGW32_DLLTOOL ?= $(TOOL_MINGW32_PREFIX)dlltool$(TOOL_MINGW32_HOSTSUFF_EXE) # General Properties used by kBuild TOOL_MINGW32_COBJSUFF ?= .o TOOL_MINGW32_CFLAGS ?= -g TOOL_MINGW32_CFLAGS.debug ?= -O0 TOOL_MINGW32_CFLAGS.release ?= -O2 TOOL_MINGW32_CFLAGS.profile ?= -O2 #-pg TOOL_MINGW32_CINCS ?= TOOL_MINGW32_CDEFS ?= TOOL_MINGW32_CXXOBJSUFF ?= .o TOOL_MINGW32_CXXOBJSUFF ?= .o TOOL_MINGW32_CXXFLAGS ?= -g TOOL_MINGW32_CXXFLAGS.debug ?= -O0 TOOL_MINGW32_CXXFLAGS.release ?= -O2 TOOL_MINGW32_CXXFLAGS.profile ?= -O2 #-pg TOOL_MINGW32_CXXINCS ?= TOOL_MINGW32_CXXDEFS ?= TOOL_MINGW32_ASFLAGS ?= -g -x assembler-with-cpp TOOL_MINGW32_ASOBJSUFF ?= .o TOOL_MINGW32_ARFLAGS ?= cr TOOL_MINGW32_ARLIBSUFF ?= .a TOOL_MINGW32_LDFLAGS ?= TOOL_MINGW32_LDFLAGS.debug ?= -g TOOL_MINGW32_LDFLAGS.release ?= -s ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_MINGW32_COMPILE_C_OUTPUT = TOOL_MINGW32_COMPILE_C_DEPEND = TOOL_MINGW32_COMPILE_C_DEPORD = define TOOL_MINGW32_COMPILE_C_CMDS $(QUIET)$(TOOL_MINGW32_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) endef ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_MINGW32_COMPILE_CXX_OUTPUT = TOOL_MINGW32_COMPILE_CXX_DEPEND = TOOL_MINGW32_COMPILE_CXX_DEPORD = define TOOL_MINGW32_COMPILE_CXX_CMDS $(QUIET)$(TOOL_MINGW32_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) endef ## Compile Assembly source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. # TOOL_MINGW32_COMPILE_AS_OUTPUT = TOOL_MINGW32_COMPILE_AS_DEPEND = TOOL_MINGW32_COMPILE_AS_DEPORD = define TOOL_MINGW32_COMPILE_AS_CMDS $(QUIET)$(TOOL_MINGW32_AS) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_MINGW32_LINK_LIBRARY_OUTPUT = $(out).ar-script TOOL_MINGW32_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_MINGW32_LINK_LIBRARY_DEPORD = define TOOL_MINGW32_LINK_LIBRARY_CMDS $(QUIET)$(APPEND) $(out).ar-script 'CREATE $(out)' $(QUIET)$(APPEND) -n $(out).ar-script \ $(foreach o,$(objs), 'ADDMOD $(o)') \ $(foreach o,$(othersrc), 'ADDLIB $(o)') $(QUIET)$(APPEND) $(out).ar-script 'SAVE' $(QUIET)$(APPEND) $(out).ar-script 'END' $(QUIET)$(TOOL_MINGW32_AR) -M < $(out).ar-script endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_MINGW32_LINK_PROGRAM_OUTPUT = TOOL_MINGW32_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_MINGW32_LINK_PROGRAM_DEPORD = define TOOL_MINGW32_LINK_PROGRAM_CMDS $(QUIET)$(TOOL_MINGW32_LD) $(flags) -o $(out) $(objs)\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(basename $(lib))), $(lib))) endef ## Link DLL. # @param $(target) Normalized main target name. # @param $(out) DLL name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_MINGW32_LINK_DLL_OUTPUT = TOOL_MINGW32_LINK_DLL_OUTPUT_MAYBE = $(outbase).a $(outbase).exp $(PATH_STAGE_LIB)/$(notdir $(outbase)).exp $(PATH_STAGE_LIB)/$(notdir $(outbase)).a ## @todo Find a better solution for installing the extra files (.a, .exp, .pdb, etc). TOOL_MINGW32_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib)))\ $(filter %.def %.res,$(othersrc)) TOOL_MINGW32_LINK_DLL_DEPORD = $(call DIRDEP,$(PATH_STAGE_LIB)) define TOOL_MINGW32_LINK_DLL_CMDS $(QUIET)$(TOOL_MINGW32_DLLWRAP) $(flags)\ --dllname=$(out)\ --output-exp=$(outbase).exp\ --output-lib=$(outbase).a\ $(foreach def,$(filter %.def,$(othersrc)), --def $(def))\ $(filter %.res,$(othersrc))\ $(objs)\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(basename $(lib))), $(lib))) $(QUIET)$(CP) $(outbase).exp $(outbase).a $(PATH_STAGE_LIB)/ endef ## @todo separate install stuff! kbuild-3149/kBuild/tools/MINGWW64.kmk0000644000175000017500000002545013252530251017150 0ustar locutuslocutus# $Id: MINGWW64.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - MinGW-W64. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # ifdef TOOL_MINGWW64 $(error Already included (TOOL_MINGWW64=$(TOOL_MINGWW64))) endif TOOL_MINGWW64 := MinGW-W64 - The incomprehensible 64-bit GCC port to Windows. # Tool Specific Properties ifndef PATH_TOOL_MINGWW64 PATH_TOOL_MINGWW64 := $(wildcard $(KBUILD_DEVTOOLS_HST)/mingw-w64/r*) ifeq ($(PATH_TOOL_MINGWW64),) PATH_TOOL_MINGWW64 := $(wildcard $(KBUILD_DEVTOOLS)/win.amd64/mingw-w64/r*) endif ifeq ($(PATH_TOOL_MINGWW64),) PATH_TOOL_MINGWW64 := $(wildcard $(KBUILD_DEVTOOLS)/win.x86/mingw-w64/r*) endif ifneq ($(PATH_TOOL_MINGWW64),) PATH_TOOL_MINGWW64 := $(lastword $(sort $(PATH_TOOL_MINGWW64))) endif else # Resolve any fancy stuff once and for all. PATH_TOOL_MINGWW64 := $(PATH_TOOL_MINGWW64) endif # figure out if it's native or needs a win32 launcher TOOL_MINGWW64_HOSTSUFF_EXE ?= $(HOSTSUFF_EXE) ifndef TOOL_MINGWW64_PREFIX ifneq ($(PATH_TOOL_MINGWW64),) TOOL_MINGWW64_PREFIX := $(PATH_TOOL_MINGWW64)/bin/ else TOOL_MINGWW64_PREFIX := endif ifneq ($(KBUILD_HOST),win) # # we're cross compiling either using an emulator (wine/odin) or a cross compiler. # ifneq ($(PATH_TOOL_MINGWW64),$(subst /win.x86,,$(subst /x86.win,,$(PATH_TOOL_MINGWW64)))) TOOL_MINGWW64_PREFIX := $(EXEC_X86_WIN32) $(TOOL_MINGWW64_PREFIX) TOOL_MINGWW64_HOSTSUFF_EXE := .exe # else # TOOL_MINGWW64_PREFIX := $(TOOL_MINGWW64_PREFIX)i386-mingw32msvc- # TOOL_MINGWW64_HOSTSUFF_EXE := # TOOL_MINGWW64_XCOMPILE := 1 # endif endif else # Resolve any fancy stuff once and for all. TOOL_MINGWW64_PREFIX := $(TOOL_MINGWW64_PREFIX) endif TOOL_MINGWW64_CC ?= $(TOOL_MINGWW64_PREFIX)gcc$(TOOL_MINGWW64_HOSTSUFF_EXE) TOOL_MINGWW64_CXX ?= $(TOOL_MINGWW64_PREFIX)g++$(TOOL_MINGWW64_HOSTSUFF_EXE) TOOL_MINGWW64_AS ?= $(TOOL_MINGWW64_PREFIX)gcc$(TOOL_MINGWW64_HOSTSUFF_EXE) TOOL_MINGWW64_AR ?= $(TOOL_MINGWW64_PREFIX)ar$(TOOL_MINGWW64_HOSTSUFF_EXE) ifndef TOOL_MINGWW64_XCOMPILE# The gentoo package doesn't have g++. TOOL_MINGWW64_LD ?= $(TOOL_MINGWW64_PREFIX)g++$(TOOL_MINGWW64_HOSTSUFF_EXE) else TOOL_MINGWW64_LD ?= $(TOOL_MINGWW64_PREFIX)gcc$(TOOL_MINGWW64_HOSTSUFF_EXE) endif TOOL_MINGWW64_DLLWRAP ?= $(TOOL_MINGWW64_PREFIX)dllwrap$(TOOL_MINGWW64_HOSTSUFF_EXE) TOOL_MINGWW64_DLLTOOL ?= $(TOOL_MINGWW64_PREFIX)dlltool$(TOOL_MINGWW64_HOSTSUFF_EXE) # General Properties used by kBuild TOOL_MINGWW64_COBJSUFF ?= .o TOOL_MINGWW64_CFLAGS ?= -g TOOL_MINGWW64_CFLAGS.debug ?= -O0 TOOL_MINGWW64_CFLAGS.release ?= -O2 TOOL_MINGWW64_CFLAGS.profile ?= -O2 #-pg TOOL_MINGWW64_CINCS ?= TOOL_MINGWW64_CDEFS ?= TOOL_MINGWW64_CXXOBJSUFF ?= .o TOOL_MINGWW64_CXXOBJSUFF ?= .o TOOL_MINGWW64_CXXFLAGS ?= -g TOOL_MINGWW64_CXXFLAGS.debug ?= -O0 TOOL_MINGWW64_CXXFLAGS.release ?= -O2 TOOL_MINGWW64_CXXFLAGS.profile ?= -O2 #-pg TOOL_MINGWW64_CXXINCS ?= TOOL_MINGWW64_CXXDEFS ?= TOOL_MINGWW64_ASFLAGS ?= -g -x assembler-with-cpp TOOL_MINGWW64_ASOBJSUFF ?= .o TOOL_MINGWW64_ARFLAGS ?= cr TOOL_MINGWW64_ARLIBSUFF ?= .a TOOL_MINGWW64_LDFLAGS ?= TOOL_MINGWW64_LDFLAGS.debug ?= -g TOOL_MINGWW64_LDFLAGS.release ?= -s ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_MINGWW64_COMPILE_C_OUTPUT = TOOL_MINGWW64_COMPILE_C_DEPEND = TOOL_MINGWW64_COMPILE_C_DEPORD = define TOOL_MINGWW64_COMPILE_C_CMDS $(QUIET)$(TOOL_MINGWW64_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) endef ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_MINGWW64_COMPILE_CXX_OUTPUT = TOOL_MINGWW64_COMPILE_CXX_DEPEND = TOOL_MINGWW64_COMPILE_CXX_DEPORD = define TOOL_MINGWW64_COMPILE_CXX_CMDS $(QUIET)$(TOOL_MINGWW64_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) endef ## Compile Assembly source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. # TOOL_MINGWW64_COMPILE_AS_OUTPUT = TOOL_MINGWW64_COMPILE_AS_DEPEND = TOOL_MINGWW64_COMPILE_AS_DEPORD = define TOOL_MINGWW64_COMPILE_AS_CMDS $(QUIET)$(TOOL_MINGWW64_AS) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_MINGWW64_LINK_LIBRARY_OUTPUT = $(out).ar-script TOOL_MINGWW64_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_MINGWW64_LINK_LIBRARY_DEPORD = define TOOL_MINGWW64_LINK_LIBRARY_CMDS $(QUIET)$(APPEND) $(out).ar-script 'CREATE $(out)' $(QUIET)$(APPEND) -n $(out).ar-script \ $(foreach o,$(objs), 'ADDMOD $(o)') \ $(foreach o,$(othersrc), 'ADDLIB $(o)') $(QUIET)$(APPEND) $(out).ar-script 'SAVE' $(QUIET)$(APPEND) $(out).ar-script 'END' $(QUIET)$(TOOL_MINGWW64_AR) -M < $(out).ar-script endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_MINGWW64_LINK_PROGRAM_OUTPUT = TOOL_MINGWW64_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_MINGWW64_LINK_PROGRAM_DEPORD = define TOOL_MINGWW64_LINK_PROGRAM_CMDS $(QUIET)$(TOOL_MINGWW64_LD) $(flags) -o $(out) $(objs)\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(basename $(lib))), $(lib))) endef ## Link DLL. # @param $(target) Normalized main target name. # @param $(out) DLL name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_MINGWW64_LINK_DLL_OUTPUT = TOOL_MINGWW64_LINK_DLL_OUTPUT_MAYBE = $(outbase).a $(outbase).exp $(PATH_STAGE_LIB)/$(notdir $(outbase)).exp $(PATH_STAGE_LIB)/$(notdir $(outbase)).a ## @todo Find a better solution for installing the extra files (.a, .exp, .pdb, etc). TOOL_MINGWW64_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib)))\ $(filter %.def %.res,$(othersrc)) TOOL_MINGWW64_LINK_DLL_DEPORD = $(call DIRDEP,$(PATH_STAGE_LIB)) define TOOL_MINGWW64_LINK_DLL_CMDS $(QUIET)$(REDIRECT) -C "$(dir $(out))" -- $(TOOL_MINGWW64_DLLWRAP) $(flags)\ --dllname=$(notdir $(out))\ --output-exp=$(outbase).exp\ --output-lib=$(outbase).a\ $(foreach def,$(filter %.def,$(othersrc)), --def $(def))\ $(filter %.res,$(othersrc))\ $(objs)\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(basename $(lib))), $(lib))) $(QUIET)$(CP) $(outbase).exp $(outbase).a $(PATH_STAGE_LIB)/ endef ## @todo separate install stuff! kbuild-3149/kBuild/tools/GCC3OMF.kmk0000644000175000017500000003212313252530251017002 0ustar locutuslocutus# $Id: GCC3OMF.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - GCC v3 targeting OS/2 OMF. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_GCC3OMF := GCC v3 targeting OS/2 OMF. # Tool Specific Properties TOOL_GCC3OMF_CC ?= gcc$(HOSTSUFF_EXE) TOOL_GCC3OMF_CXX ?= g++$(HOSTSUFF_EXE) TOOL_GCC3OMF_AS ?= gcc$(HOSTSUFF_EXE) TOOL_GCC3OMF_AR ?= emxomfar$(HOSTSUFF_EXE) TOOL_GCC3OMF_AR_IMP ?= emximp$(HOSTSUFF_EXE) TOOL_GCC3OMF_LD ?= gcc$(HOSTSUFF_EXE) TOOL_GCC3OMF_LD_SYSMOD ?= gcc$(HOSTSUFF_EXE) ifndef TOOL_GCC3OMF_LDFLAGS.$(KBUILD_TARGET) TOOL_GCC3OMF_LDFLAGS.dll ?= -shared -Zdll else TOOL_GCC3OMF_LDFLAGS.dll ?= $(TOOL_GCC3OMF_LDFLAGS.$(KBUILD_TARGET)) endif TOOL_GCC3OMF_LDFLAGS.sysmod ?= -nostdlib TOOL_GCC3OMF_LD_MAP ?= -Zmap=$(1) TOOL_GCC3OMF_LD_SYSMOD_MAP ?= -Zmap=$(1) TOOL_GCC3OMF_RC = rc$(HOSTSUFF_EXE) ifdef SLKRUNS TOOL_GCC3OMF_CC += -fmessage-length=0 TOOL_GCC3OMF_CXX += -fmessage-length=0 endif # General Properties used by kBuild TOOL_GCC3OMF_COBJSUFF ?= .o TOOL_GCC3OMF_CFLAGS ?= -Zomf TOOL_GCC3OMF_CFLAGS.debug ?= -g TOOL_GCC3OMF_CFLAGS.profile ?= -O2 #-g -pg TOOL_GCC3OMF_CFLAGS.release ?= -O2 TOOL_GCC3OMF_CINCS ?= TOOL_GCC3OMF_CDEFS ?= TOOL_GCC3OMF_CXXOBJSUFF ?= .o TOOL_GCC3OMF_CXXOBJSUFF ?= .o TOOL_GCC3OMF_CXXFLAGS ?= -Zomf TOOL_GCC3OMF_CXXFLAGS.debug ?= -g TOOL_GCC3OMF_CXXFLAGS.profile ?= -O2 #-g -pg TOOL_GCC3OMF_CXXFLAGS.release ?= -O2 TOOL_GCC3OMF_CXXINCS ?= TOOL_GCC3OMF_CXXDEFS ?= TOOL_GCC3OMF_ASFLAGS ?= -x assembler-with-cpp -Zomf TOOL_GCC3OMF_ASFLAGS.debug ?= -g TOOL_GCC3OMF_ASFLAGS.profile ?= -g TOOL_GCC3OMF_ASOBJSUFF ?= .obj TOOL_GCC3OMF_RCOBJSUFF ?= .res TOOL_GCC3OMF_RCFLAGS ?= -n TOOL_GCC3OMF_RCINCS ?= $(shell $(TOOL_GCC3OMF_CXX) -E -x c++ - 2>&1 < /dev/null \ | $(SED_EXT) -e "/search starts here/,/[Ee]nd of search list/!d" -e "/^ /!d") TOOL_GCC3OMF_ARFLAGS ?= cr TOOL_GCC3OMF_ARLIBSUFF ?= .lib TOOL_GCC3OMF_LDFLAGS ?= -Zomf TOOL_GCC3OMF_LDFLAGS.debug ?= -g TOOL_GCC3OMF_LDFLAGS.profile ?= -g ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GCC3OMF_COMPILE_C_DEPEND = TOOL_GCC3OMF_COMPILE_C_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GCC3OMF_COMPILE_C_USES_KOBJCACHE = 1 TOOL_GCC3OMF_COMPILE_C_OUTPUT = $(outbase).i define TOOL_GCC3OMF_COMPILE_C_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).i\ $(TOOL_GCC3OMF_CC) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GCC3OMF_CC) -c\ $(flags) -fpreprocessed -x c\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GCC3OMF_COMPILE_C_OUTPUT = define TOOL_GCC3OMF_COMPILE_C_CMDS $(QUIET)$(TOOL_GCC3OMF_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP \ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GCC3OMF_COMPILE_CXX_DEPEND = TOOL_GCC3OMF_COMPILE_CXX_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GCC3OMF_COMPILE_CXX_USES_KOBJCACHE = 1 TOOL_GCC3OMF_COMPILE_CXX_OUTPUT = $(outbase).ii define TOOL_GCC3OMF_COMPILE_CXX_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).ii\ $(TOOL_GCC3OMF_CXX) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GCC3OMF_CXX) -c\ $(flags) -fpreprocessed -x c++\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GCC3OMF_COMPILE_CXX_OUTPUT = define TOOL_GCC3OMF_COMPILE_CXX_CMDS $(QUIET)$(TOOL_GCC3OMF_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP \ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile Assembly source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. # TOOL_GCC3OMF_COMPILE_AS_OUTPUT = TOOL_GCC3OMF_COMPILE_AS_DEPEND = TOOL_GCC3OMF_COMPILE_AS_DEPORD = define TOOL_GCC3OMF_COMPILE_AS_CMDS $(QUIET)$(TOOL_GCC3OMF_AS) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef ## Compile resource source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GCC3OMF_COMPILE_RC_OUTPUT = TOOL_GCC3OMF_COMPILE_RC_DEPEND = TOOL_GCC3OMF_COMPILE_RC_DEPORD = define TOOL_GCC3OMF_COMPILE_RC_CMDS $(QUIET)$(REDIRECT) -E 'INCLUDE=' -- $(TOOL_GCC3OMF_RC) -r \ $(flags) $(addprefix -i, $(subst /,\\,$(subst /@unixroot,$(UNIXROOT),$(incs)))) $(addprefix -d, $(defs))\ $(subst /,\\,$(abspath $(source))) \ $(obj) endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC3OMF_LINK_LIBRARY_OUTPUT = $(outbase).rsp TOOL_GCC3OMF_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_GCC3OMF_LINK_LIBRARY_DEPORD = define TOOL_GCC3OMF_LINK_LIBRARY_CMDS $(if $(filter %.def %.imp %.dll,$(othersrc))\ ,$(QUIET)$(APPEND) -n $(outbase).rsp $(filter %.def %.imp %.dll,$(othersrc))\ $(NL)$(TAB)$(QUIET)$(QUIET)$(TOOL_GCC3OMF_AR_IMP) -o $(out) @$(outbase).rsp\ $(NL)$(TAB)$(QUIET)$(RM) -f $(outbase).rsp) $(QUIET)$(APPEND) -n $(outbase).rsp $(flags) $(out) $(objs) $(filter-out %.def %.imp %.dll,$(othersrc)) $(QUIET)$(TOOL_GCC3OMF_AR) @$(outbase).rsp endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC3OMF_LINK_PROGRAM_OUTPUT = $(outbase).map $(outbase).rsp TOOL_GCC3OMF_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_GCC3OMF_LINK_PROGRAM_DEPORD = define TOOL_GCC3OMF_LINK_PROGRAM_CMDS $(QUIET)$(APPEND) -n $(outbase).rsp\ $(flags)\ -o $(out)\ $(objs)\ $(foreach p,$(libpath), -L$(p))\ $(othersrc)\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\ -Zmap=$(outbase).map $(QUIET)$(TOOL_GCC3OMF_LD) @$(outbase).rsp endef ## Link DLL # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC3OMF_LINK_DLL_OUTPUT = $(outbase).map $(outbase).rsp TOOL_GCC3OMF_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_GCC3OMF_LINK_DLL_DEPORD = define TOOL_GCC3OMF_LINK_DLL_CMDS $(QUIET)$(APPEND) -n $(outbase).rsp\ $(TOOL_GCC3OMF_LDFLAGS.dll)\ $(flags)\ -o $(out)\ $(objs)\ $(foreach p,$(libpath), -L$(p))\ $(othersrc)\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\ -Zmap=$(outbase).map $(QUIET)$(TOOL_GCC3OMF_LD) @$(outbase).rsp endef ## Link system module (windows aka driver, linux aka kernel module) # @param $(target) Normalized main target name. # @param $(out) System module name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC3OMF_LINK_SYSMOD_OUTPUT = $(outbase).map $(outbase).rsp TOOL_GCC3OMF_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_GCC3OMF_LINK_SYSMOD_DEPORD = define TOOL_GCC3OMF_LINK_SYSMOD_CMDS $(QUIET)$(APPEND) -n $(outbase).rsp\ $(TOOL_GCC3OMF_LDFLAGS.sysmod)\ $(flags)\ -o $(out)\ $(objs)\ $(foreach p,$(libpath), -L$(p))\ $(othersrc)\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\ -Zmap=$(outbase).map $(QUIET)$(TOOL_GCC3OMF_LD_SYSMOD) @$(outbase).rsp endef kbuild-3149/kBuild/tools/VCC100AMD64.kmk0000644000175000017500000004757213252530251017327 0ustar locutuslocutus# $Id: VCC100AMD64.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - Visual C++ 10.0 (aka Visual 2010 and MSC v16), targeting AMD64. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_VCC100AMD64 := Visual C++ 10.0 (aka Visual 2010 and MSC v16), targeting AMD64 # Tool Specific Properties ifndef PATH_TOOL_VCC100AMD64 PATH_TOOL_VCC100AMD64 := $(wildcard $(KBUILD_DEVTOOLS)/win.x86/vcc/v10*) ifeq ($(PATH_TOOL_VCC100AMD64),) PATH_TOOL_VCC100AMD64 := $(PATH_TOOL_VCC100) endif ifeq ($(PATH_TOOL_VCC100AMD64),) PATH_TOOL_VCC100AMD64 := $(PATH_TOOL_VCC100X86) endif ifeq ($(PATH_TOOL_VCC100AMD64),) PATH_TOOL_VCC100AMD64 := $(wildcard $(KBUILD_DEVTOOLS)/win.x86/vcc/v10*) endif ifneq ($(PATH_TOOL_VCC100AMD64),) PATH_TOOL_VCC100AMD64 := $(lastword $(sort $(PATH_TOOL_VCC100AMD64))) else $(warning kBuild: PATH_TOOL_VCC100AMD64 cannot be determined!) PATH_TOOL_VCC100AMD64 := $(KBUILD_DEVTOOLS)/win.x86/vcc/v10 endif else # Resolve any fancy stuff once and for all. PATH_TOOL_VCC100AMD64 := $(PATH_TOOL_VCC100AMD64) endif ifeq ($(KBUILD_HOST).$(KBUILD_HOST_ARCH),win.amd64) PATH_TOOL_VCC100AMD64_BIN ?= $(PATH_TOOL_VCC100AMD64)/bin/amd64 else PATH_TOOL_VCC100AMD64_BIN ?= $(PATH_TOOL_VCC100AMD64)/bin/x86_amd64 endif PATH_TOOL_VCC100AMD64_LIB ?= $(PATH_TOOL_VCC100AMD64)/lib/amd64 PATH_TOOL_VCC100AMD64_INC ?= $(PATH_TOOL_VCC100AMD64)/include PATH_TOOL_VCC100AMD64_ATLMFC ?= $(PATH_TOOL_VCC100AMD64)/atlmfc PATH_TOOL_VCC100AMD64_ATLMFC_INC ?= $(PATH_TOOL_VCC100AMD64_ATLMFC)/include PATH_TOOL_VCC100AMD64_ATLMFC_LIB ?= $(PATH_TOOL_VCC100AMD64_ATLMFC)/lib/amd64 TOOL_VCC100AMD64_CC ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100AMD64_BIN)/cl.exe TOOL_VCC100AMD64_CXX ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100AMD64_BIN)/cl.exe TOOL_VCC100AMD64_AS ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100AMD64_BIN)/ml64.exe #TOOL_VCC100AMD64_AR ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100AMD64_BIN)/lib.exe - just an exec wrapper for the below TOOL_VCC100AMD64_AR ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100AMD64_BIN)/link.exe /LIB TOOL_VCC100AMD64_LD ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100AMD64_BIN)/link.exe TOOL_VCC100AMD64_DUMPBIN ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100AMD64_BIN)/dumpbin.exe TOOL_VCC100AMD64_EDITBIN ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100AMD64_BIN)/editbin.exe TOOL_VCC100AMD64_RC ?= $(EXEC_X86_WIN32) $(call TOOL_VCC100_FN_FIND_SDK_TOOL,rc.exe,[Rr][Cc].[Ee][Xx][Ee],TOOL_VCC100_RC_CACHED) TOOL_VCC100AMD64_MT ?= $(EXEC_X86_WIN32) $(call TOOL_VCC100_FN_FIND_SDK_TOOL,mt.exe,[Mm][Tt].[Ee][Xx][Ee],TOOL_VCC100_MT_CACHED) ifdef TOOL_VCC100AMD64_USE_KSUBMIT ifeq ($(KBUILD_HOST),win) ifneq ($(substr $(PATH_TOOL_VCC100AMD64_BIN),-9),x86_amd64) TOOL_VCC100AMD64_KSUBMIT ?= kmk_builtin_kSubmit --64-bit TOOL_VCC100AMD64_KSUBMIT_DD = $(TOOL_VCC100AMD64_KSUBMIT) -- else # "fatal error C1902: Program database manager mismatch; please check your installation" when mixing with the 32-bit compiler. #TOOL_VCC100AMD64_KSUBMIT ?= kmk_builtin_kSubmit --32-bit #TOOL_VCC100AMD64_KSUBMIT_DD = $(TOOL_VCC100AMD64_KSUBMIT) -- endif endif endif # The following in duplicated in VCC100.kmk and VCC100X86.kmk. TOOL_VCC100_FN_FIND_SDK_TOOL_SUB = $(eval $3 := $(firstword \ $(if-expr defined(PATH_SDK_WINPSDK71_BIN), $(wildcard $(PATH_SDK_WINPSDK71_BIN)/$2)) \ $(if-expr defined(PATH_SDK_WINPSDK_BIN) , $(wildcard $(PATH_SDK_WINPSDK_BIN)/$2)) \ $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST)/sdk/*/[Bb][Ii][Nn]/$2)) \ $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST_ALT)/sdk/*/[Bb][Ii][Nn]/$2)) \ $1)) TOOL_VCC100_FN_FIND_SDK_TOOL = $(if-expr !defined($3),$(TOOL_VCC100_FN_FIND_SDK_TOOL_SUB),)$($3) ## Disabled fast DEP_IDB based dependencies. #VCC100AMD64_OLD_DEPS = 1 ## Constructs the correct .pdb name (the name is lowercased). # @param $(1) Base name, no extention. # @param $(2) The extension. TOOL_VCC100AMD64_PDB = $(dir $(1))$(tolower $(notdir $(1))).$(2) # General Properties used by kBuild TOOL_VCC100AMD64_COBJSUFF ?= .obj TOOL_VCC100AMD64_CFLAGS ?= -TC -nologo -Zi TOOL_VCC100AMD64_CFLAGS.debug ?= TOOL_VCC100AMD64_CFLAGS.dbgopt ?= -O2 TOOL_VCC100AMD64_CFLAGS.release ?= -O2 TOOL_VCC100AMD64_CFLAGS.profile ?= -O2 TOOL_VCC100AMD64_CINCS ?= $(PATH_TOOL_VCC100AMD64_INC) TOOL_VCC100AMD64_CDEFS ?= TOOL_VCC100AMD64_CXXOBJSUFF ?= .obj TOOL_VCC100AMD64_CXXFLAGS ?= -TP -nologo -Zi TOOL_VCC100AMD64_CXXFLAGS.debug ?= TOOL_VCC100AMD64_CXXFLAGS.dbgopt ?= -O2 TOOL_VCC100AMD64_CXXFLAGS.release ?= -O2 TOOL_VCC100AMD64_CXXFLAGS.profile ?= -O2 TOOL_VCC100AMD64_CXXINCS ?= $(PATH_TOOL_VCC100AMD64_INC) $(PATH_TOOL_VCC100AMD64_ATLMFC_INC) TOOL_VCC100AMD64_CXXDEFS ?= TOOL_VCC100AMD64_ASOBJSUFF ?= .obj TOOL_VCC100AMD64_RCOBJSUFF ?= .res TOOL_VCC100AMD64_RCINCS ?= $(PATH_TOOL_VCC100AMD64_INC) $(PATH_TOOL_VCC100AMD64_ATLMFC_INC) TOOL_VCC100AMD64_ARFLAGS ?= -nologo -machine:amd64 TOOL_VCC100AMD64_ARLIBSUFF ?= .lib TOOL_VCC100AMD64_LDFLAGS ?= -nologo -machine:amd64 TOOL_VCC100AMD64_LDFLAGS.debug ?= -debug TOOL_VCC100AMD64_LDFLAGS.dbgopt ?= -debug TOOL_VCC100AMD64_LDFLAGS.profile ?= -debug TOOL_VCC100AMD64_LDFLAGS.release ?= ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC100AMD64_COMPILE_C_DEPEND = TOOL_VCC100AMD64_COMPILE_C_DEPORD = TOOL_VCC100AMD64_COMPILE_C_OUTPUT = TOOL_VCC100AMD64_COMPILE_C_OUTPUT_MAYBE = $(call TOOL_VCC100AMD64_PDB, $(outbase)-obj,pdb) $(call TOOL_VCC100AMD64_PDB, $(outbase)-obj,idb) ifdef TOOL_VCC100AMD64_KSUBMIT TOOL_VCC100AMD64_COMPILE_C_DONT_PURGE_OUTPUT := 1 # speed define TOOL_VCC100AMD64_COMPILE_C_CMDS $(QUIET)$(TOOL_VCC100AMD64_KSUBMIT) -P $(DEP_OBJ_INT) -f -s -q -o $(dep) -t $(obj) $(obj)\ -- $(TOOL_VCC100AMD64_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fd$(outbase)-obj.pdb \ -Fo$(obj)\ $(subst /,\\,$(abspath $(source))) endef else define TOOL_VCC100AMD64_COMPILE_C_CMDS $(QUIET)$(TOOL_VCC100AMD64_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fd$(outbase)-obj.pdb \ -Fo$(obj)\ $(subst /,\\,$(abspath $(source))) $(QUIET)$(DEP_OBJ) -f -s -q -o $(dep) -t $(obj) $(obj) endef endif # !TOOL_VCC100AMD64_KSUBMIT ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC100AMD64_COMPILE_CXX_DEPEND = $($(target)_1_VCC_PCH_FILE) TOOL_VCC100AMD64_COMPILE_CXX_DEPORD = TOOL_VCC100AMD64_COMPILE_CXX_OUTPUT = TOOL_VCC100AMD64_COMPILE_CXX_OUTPUT_MAYBE = $(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB)\ ,,$(call TOOL_VCC100AMD64_PDB, $(outbase)-obj,pdb) $(call TOOL_VCC100AMD64_PDB, $(outbase)-obj,idb)) ifdef TOOL_VCC100AMD64_KSUBMIT TOOL_VCC100AMD64_COMPILE_CXX_DONT_PURGE_OUTPUT := 1 # speed define TOOL_VCC100AMD64_COMPILE_CXX_CMDS $(QUIET)$(TOOL_VCC100AMD64_KSUBMIT) -P $(DEP_OBJ_INT) -f -s -q -o $(dep) -t $(obj) $(obj)\ -- $(TOOL_VCC100AMD64_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ $(if-expr defined($(target)_PCH_HDR)\ ,-FI$($(target)_PCH_HDR) -Yu$($(target)_PCH_HDR) -Fp$($(target)_1_VCC_PCH_FILE),)\ -Fd$(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB),$($(target)_1_VCC_COMMON_OBJ_PDB),$(outbase)-obj.pdb) \ -Fo$(obj)\ $(subst /,\\,$(abspath $(source))) endef else define TOOL_VCC100AMD64_COMPILE_CXX_CMDS $(QUIET)$(TOOL_VCC100AMD64_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ $(if-expr defined($(target)_PCH_HDR)\ ,-FI$($(target)_PCH_HDR) -Yu$($(target)_PCH_HDR) -Fp$($(target)_1_VCC_PCH_FILE),)\ -Fd$(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB),$($(target)_1_VCC_COMMON_OBJ_PDB),$(outbase)-obj.pdb) \ -Fo$(obj)\ $(subst /,\\,$(abspath $(source))) $(QUIET)$(DEP_OBJ) -f -s -q -o $(dep) -t $(obj) $(obj) endef endif # !TOOL_VCC100AMD64_KSUBMIT # # Helper tool for creating the precompiled C++ header. # # It only have the C++ compile bits and it's purpose is to skip bits # related _1_VCC_PCH_FILE and add -Yc. # TOOL_VCC100AMD64-PCH := Helper for creating precompiled header using CXX handling. TOOL_VCC100AMD64-PCH_EXTENDS := VCC100AMD64 TOOL_VCC100AMD64-PCH_CXXOBJSUFF := .obj TOOL_VCC100AMD64-PCH_CXXINCS = $(TOOL_VCC100AMD64_CXXINCS) TOOL_VCC100AMD64-PCH_CXXFLAGS.debug = $(TOOL_VCC100AMD64_CXXFLAGS.debug) TOOL_VCC100AMD64-PCH_CXXFLAGS.dbgopt = $(TOOL_VCC100AMD64_CXXFLAGS.dbgopt) TOOL_VCC100AMD64-PCH_CXXFLAGS.release = $(TOOL_VCC100AMD64_CXXFLAGS.release) TOOL_VCC100AMD64-PCH_CXXFLAGS.profile = $(TOOL_VCC100AMD64_CXXFLAGS.profile) TOOL_VCC100AMD64-PCH_COMPILE_CXX_DEPEND = $(NO_SUCH_VARIABLE) TOOL_VCC100AMD64-PCH_COMPILE_CXX_DEPORD = $(NO_SUCH_VARIABLE) TOOL_VCC100AMD64-PCH_COMPILE_CXX_OUTPUT = $($(target)_1_VCC_PCH_FILE) $($(target)_1_VCC_COMMON_OBJ_PDB) TOOL_VCC100AMD64-PCH_COMPILE_CXX_OUTPUT_MAYBE = $(NO_SUCH_VARIABLE) ifdef TOOL_VCC100AMD64_KSUBMIT define TOOL_VCC100AMD64-PCH_COMPILE_CXX_CMDS $(QUIET)$(RM) -f -- $($(target)_1_VCC_PCH_FILE) $($(target)_1_VCC_COMMON_OBJ_PDB) $(QUIET)$(TOOL_VCC100AMD64_KSUBMIT) --no-pch-caching -P $(DEP_OBJ_INT) -f -s -q -e .pch -o $(dep) -t $(obj) $(obj)\ -- $(TOOL_VCC100AMD64_CXX) -c -Yc\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fp$($(target)_1_VCC_PCH_FILE) \ -Fd$($(target)_1_VCC_COMMON_OBJ_PDB) \ -Fo$(obj)\ -TP \ $(subst /,\\,$(abspath $(source))) endef else define TOOL_VCC100AMD64-PCH_COMPILE_CXX_CMDS $(QUIET)$(RM) -f -- $($(target)_1_VCC_PCH_FILE) $($(target)_1_VCC_COMMON_OBJ_PDB) $(QUIET)$(TOOL_VCC100AMD64_CXX) -c -Yc\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fp$($(target)_1_VCC_PCH_FILE) \ -Fd$($(target)_1_VCC_COMMON_OBJ_PDB) \ -Fo$(obj)\ -TP \ $(subst /,\\,$(abspath $(source))) $(QUIET)$(DEP_OBJ) -f -s -q -e .pch -o $(dep) -t $(obj) $(obj) endef endif # !TOOL_VCC100AMD64_KSUBMIT ## @todo configure the assembler template. ## Compile resource source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC100AMD64_COMPILE_RC_DEPEND = TOOL_VCC100AMD64_COMPILE_RC_DEPORD = TOOL_VCC100AMD64_COMPILE_RC_OUTPUT = define TOOL_VCC100AMD64_COMPILE_RC_CMDS $(QUIET)$(TOOL_VCC100AMD64_RC) \ $(flags) $(addprefix /i, $(subst /,\\,$(incs))) $(addprefix /d, $(defs))\ /fo$(obj)\ $(subst /,\\,$(abspath $(source))) endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_VCC100AMD64_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_VCC100AMD64_LINK_LIBRARY_DEPORD = TOOL_VCC100AMD64_LINK_LIBRARY_OUTPUT = $(outbase).rsp TOOL_VCC100AMD64_LINK_LIBRARY_OUTPUT_MAYBE = $(outbase).lst $(outbase).exp $(outbase).pdb define TOOL_VCC100AMD64_LINK_LIBRARY_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs) \ $(filter-out %.def,$(othersrc))) \ $(addprefix /DEF:,$(filter %.def,$(othersrc))) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC100AMD64_KSUBMIT_DD) $(TOOL_VCC100AMD64_AR) $(flags) /OUT:$(out) @$(outbase).rsp endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_VCC100AMD64_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC100AMD64_LINK_PROGRAM_DEPORD = TOOL_VCC100AMD64_LINK_PROGRAM_OUTPUT = $(outbase).map $(outbase).rsp TOOL_VCC100AMD64_LINK_PROGRAM_OUTPUT_MAYBE = $(outbase).lib $(outbase).exp $(outbase).ilk $(out).manifest TOOL_VCC100AMD64_LINK_PROGRAM_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC100AMD64_LINK_PROGRAM_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb define TOOL_VCC100AMD64_LINK_PROGRAM_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC100AMD64_KSUBMIT_DD) $(TOOL_VCC100AMD64_LD) $(flags) \ /OUT:$(out) \ /MAPINFO:EXPORTS /INCREMENTAL:NO \ /MAP:$(outbase).map \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp ifndef TOOL_VCC100AMD64_NO_AUTO_MANIFEST $(QUIET)$(TEST) -f $(out).manifest -- \ $(TOOL_VCC100AMD64_MT) -manifest $(subst /,\\,$(out)).manifest -outputresource:$(subst /,\\,$(out)) endif endef ## Link DLL. # @param $(target) Normalized main target name. # @param $(out) DLL name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_VCC100AMD64_LINK_DLL_DEPEND = $(objs) $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC100AMD64_LINK_DLL_DEPORD = $(call DIRDEP,$(PATH_STAGE_LIB)) TOOL_VCC100AMD64_LINK_DLL_OUTPUT = $(outbase).map $(outbase).lib $(outbase).exp $(outbase).rsp TOOL_VCC100AMD64_LINK_DLL_OUTPUT_MAYBE = $(outbase).ilk $(out).manifest $(PATH_STAGE_LIB)/$(notdir $(outbase)).exp TOOL_VCC100AMD64_LINK_DLL_OUTPUT_MAYBE_PRECIOUS = $(PATH_STAGE_LIB)/$(notdir $(outbase)).lib TOOL_VCC100AMD64_LINK_DLL_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC100AMD64_LINK_DLL_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb define TOOL_VCC100AMD64_LINK_DLL_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC100AMD64_KSUBMIT_DD) $(TOOL_VCC100AMD64_LD) $(flags) \ /OUT:$(out) \ /IMPLIB:$(outbase).lib \ /MAPINFO:EXPORTS /INCREMENTAL:NO \ /MAP:$(outbase).map \ /DLL \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp ifndef TOOL_VCC100AMD64_NO_AUTO_MANIFEST $(QUIET)$(TEST) -f $(out).manifest -- \ $(TOOL_VCC100AMD64_MT) -manifest $(subst /,\\,$(out)).manifest '-outputresource:$(subst /,\\,$(out));#2' endif $(QUIET)$(TEST) -f $(outbase).lib -- $(KLIBTWEAKER_EXT) --clear-timestamps $(outbase).lib $(QUIET)$(CP) --changed -v --ignore-non-existing $(outbase).exp $(outbase).lib $(PATH_STAGE_LIB)/ $(eval _DIRS += $(PATH_STAGE_LIB)) endef ## Link system module (windows aka driver, linux aka kernel module) # @param $(target) Normalized main target name. # @param $(out) System module name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_VCC100AMD64_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC100AMD64_LINK_SYSMOD_DEPORD = TOOL_VCC100AMD64_LINK_SYSMOD_OUTPUT = $(outbase).map $(outbase).rsp TOOL_VCC100AMD64_LINK_SYSMOD_OUTPUT_MAYBE = $(outbase).lib $(outbase).exp $(outbase).ilk $(out).manifest TOOL_VCC100AMD64_LINK_SYSMOD_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC100AMD64_LINK_SYSMOD_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb define TOOL_VCC100AMD64_LINK_SYSMOD_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC100AMD64_KSUBMIT_DD) $(TOOL_VCC100AMD64_LD) $(flags) \ /OUT:$(out) \ /MAPINFO:EXPORTS /INCREMENTAL:NO \ /MAP:$(outbase).map \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp ifndef TOOL_VCC100AMD64_NO_AUTO_MANIFEST $(QUIET)$(TEST) -f $(out).manifest -- \ $(TOOL_VCC100AMD64_MT) -manifest $(subst /,\\,$(out)).manifest '-outputresource:$(subst /,\\,$(out));#2' endif endef kbuild-3149/kBuild/tools/NASM.kmk0000644000175000017500000000637513252530251016531 0ustar locutuslocutus# $Id: NASM.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - Netwide Assembler v0.98+. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_NASM := Netwide Assembler v0.98+ # Tool Specific Properties ifndef PATH_TOOL_NASM PATH_TOOL_NASM := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST)/nasm/v*.*))) if "$(PATH_TOOL_NASM)" == "" && "$(KBUILD_DEVTOOLS_HST_ALT)" != "" PATH_TOOL_NASM := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST_ALT)/nasm/v*.*))) endif else # Resolve any fancy stuff once and for all. PATH_TOOL_NASM := $(PATH_TOOL_NASM) endif ifneq ($(PATH_TOOL_NASM),) TOOL_NASM_AS ?= $(PATH_TOOL_NASM)/nasm$(HOSTSUFF_EXE) else TOOL_NASM_AS ?= nasm$(HOSTSUFF_EXE) endif # kSubmit ifdef TOOL_NASM_USE_KSUBMIT ifeq ($(KBUILD_HOST),win) TOOL_NASM_KSUBMIT ?= kmk_builtin_kSubmit $1 -- endif endif # General Properties used by kBuild TOOL_NASM_ASFLAGS ?= ## Compile Assembly source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. # TOOL_NASM_COMPILE_AS_OUTPUT = $(outbase).lst TOOL_NASM_COMPILE_AS_DEPEND = TOOL_NASM_COMPILE_AS_DEPORD = define TOOL_NASM_COMPILE_AS_CMDS ifdef TOOL_NASM_KSUBMIT $(QUIET)$(call TOOL_NASM_KSUBMIT, -C $(PATH_OUT_BASE)) $(TOOL_NASM_AS)\ $(flags) $(addsuffix /,$(addprefix -i, $(incs))) $(addprefix -D, $(defs))\ -l $(outbase).lst\ -o $(obj)\ -MD "$(dep)" -MP\ $(abspath $(source)) else $(QUIET)$(REDIRECT) -C $(PATH_OUT_BASE) -- $(TOOL_NASM_AS)\ $(flags) $(addsuffix /,$(addprefix -i, $(incs))) $(addprefix -D, $(defs))\ -l $(outbase).lst\ -o $(obj)\ -MD "$(dep)" -MP\ $(abspath $(source)) endif endef kbuild-3149/kBuild/tools/XGCCAMD64LINUX.kmk0000644000175000017500000003065213252530251020026 0ustar locutuslocutus# $Id: XGCCAMD64LINUX.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - GCC Cross compiler for AMD64+Linux. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_XGCCAMD64LINUX := GCC Cross compiler for AMD64+Linux. # Tool Specific Properties TOOL_XGCCAMD64LINUX_HOSTSUFF_EXE ?= $(HOSTSUFF_EXE) ifeq ($(KBUILD_HOST).$(KBUILD_HOST_ARCH),linux.amd64) # not x-compile, use the default gcc. TOOL_XGCCAMD64LINUX_PREFIX := $(TOOL_XGCCAMD64LINUX_PREFIX) else # x-compile: # find the latest xgcc build. ifndef TOOL_XGCCAMD64LINUX_PREFIX TOOL_XGCCAMD64LINUX_PREFIX := x86_64-unknown-linux-gnu- ifndef PATH_TOOL_XGCCAMD64LINUX PATH_TOOL_XGCCAMD64LINUX := $(sort $(wildcard $(KBUILD_DEVTOOLS_HST)/x86_64-unknown-linux-gnu/*)) ifeq ($(PATH_TOOL_XGCCAMD64LINUX),) ifeq ($(filter-out win.amd64,$(KBUILD_HOST).$(KBUILD_HOST_ARCH)),) # these can use the windows build. TOOL_XGCCAMD64LINUX_EXEC_PREFIX ?= $(EXEC_X86_WIN32) TOOL_XGCCAMD64LINUX_HOSTSUFF_EXE := .exe PATH_TOOL_XGCCAMD64LINUX := $(sort $(wildcard $(KBUILD_DEVTOOLS)/win.x86/x86_64-unknown-linux-gnu/*)) ifeq ($(PATH_TOOL_XGCCAMD64LINUX),) PATH_TOOL_XGCCAMD64LINUX := $(sort $(wildcard $(KBUILD_DEVTOOLS)/x86.win32/x86_64-unknown-linux-gnu/*)) endif endif endif ifneq ($(PATH_TOOL_XGCCAMD64LINUX),) PATH_TOOL_XGCCAMD64LINUX := $(call lastword,$(PATH_TOOL_XGCCAMD64LINUX)) endif endif # !PATH_TOOL_XGCCAMD64LINUX ifneq ($(PATH_TOOL_XGCCAMD64LINUX),) TOOL_XGCCAMD64LINUX_PREFIX := $(TOOL_XGCCAMD64LINUX_EXEC_PREFIX) $(PATH_TOOL_XGCCAMD64LINUX)/bin/$(TOOL_XGCCAMD64LINUX_PREFIX) endif else # Resolve any fancy stuff once and for all. TOOL_XGCCAMD64LINUX_PREFIX := $(TOOL_XGCCAMD64LINUX_PREFIX) endif endif TOOL_XGCCAMD64LINUX_CC ?= $(TOOL_XGCCAMD64LINUX_PREFIX)gcc$(TOOL_XGCCAMD64LINUX_HOSTSUFF_EXE) TOOL_XGCCAMD64LINUX_CXX ?= $(TOOL_XGCCAMD64LINUX_PREFIX)g++$(TOOL_XGCCAMD64LINUX_HOSTSUFF_EXE) TOOL_XGCCAMD64LINUX_AS ?= $(TOOL_XGCCAMD64LINUX_PREFIX)gcc$(TOOL_XGCCAMD64LINUX_HOSTSUFF_EXE) TOOL_XGCCAMD64LINUX_AR ?= $(TOOL_XGCCAMD64LINUX_PREFIX)ar$(TOOL_XGCCAMD64LINUX_HOSTSUFF_EXE) TOOL_XGCCAMD64LINUX_LD ?= $(TOOL_XGCCAMD64LINUX_PREFIX)g++$(TOOL_XGCCAMD64LINUX_HOSTSUFF_EXE) TOOL_XGCCAMD64LINUX_LD_SYSMOD ?= $(TOOL_XGCCAMD64LINUX_PREFIX)ld$(TOOL_XGCCAMD64LINUX_HOSTSUFF_EXE) TOOL_XGCCAMD64LINUX_LD_SONAME ?= -Wl,-soname=$(firstword $($(1)_SONAME.$(KBUILD_TARGET).$(KBUILD_TYPE)) $($(1)_SONAME.$(KBUILD_TARGET)) $($(1)_SONAME.$(KBUILD_TYPE)) $($(1)_SONAME) $(notdir $(2))) TOOL_XGCCAMD64LINUX_LD_MAP ?= -Wl,-Map -Wl,$(1) -Wl,--cref TOOL_XGCCAMD64LINUX_LD_SYSMOD_MAP ?= -Map $(1) --cref TOOL_XGCCAMD64LINUX_LDFLAGS.dll ?= -shared TOOL_XGCCAMD64LINUX_LDFLAGS.sysmod ?= -r ifdef SLKRUNS TOOL_XGCCAMD64LINUX_CC += -fmessage-length=0 TOOL_XGCCAMD64LINUX_CXX += -fmessage-length=0 endif # General Properties used by kBuild TOOL_XGCCAMD64LINUX_COBJSUFF ?= .o TOOL_XGCCAMD64LINUX_CFLAGS ?= -g TOOL_XGCCAMD64LINUX_CFLAGS.debug ?= -O0 TOOL_XGCCAMD64LINUX_CFLAGS.release ?= -O2 TOOL_XGCCAMD64LINUX_CFLAGS.profile ?= -O2 #-pg TOOL_XGCCAMD64LINUX_CINCS ?= TOOL_XGCCAMD64LINUX_CDEFS ?= TOOL_XGCCAMD64LINUX_CXXOBJSUFF ?= .o TOOL_XGCCAMD64LINUX_CXXOBJSUFF ?= .o TOOL_XGCCAMD64LINUX_CXXFLAGS ?= -g TOOL_XGCCAMD64LINUX_CXXFLAGS.debug ?= -O0 TOOL_XGCCAMD64LINUX_CXXFLAGS.release ?= -O2 TOOL_XGCCAMD64LINUX_CXXFLAGS.profile ?= -O2 #-pg TOOL_XGCCAMD64LINUX_CXXINCS ?= TOOL_XGCCAMD64LINUX_CXXDEFS ?= TOOL_XGCCAMD64LINUX_ASFLAGS ?= -g -x assembler-with-cpp TOOL_XGCCAMD64LINUX_ASOBJSUFF ?= .o TOOL_XGCCAMD64LINUX_ARFLAGS ?= cr TOOL_XGCCAMD64LINUX_ARLIBSUFF ?= .a TOOL_XGCCAMD64LINUX_LDFLAGS ?= TOOL_XGCCAMD64LINUX_LDFLAGS.debug ?= -g TOOL_XGCCAMD64LINUX_LDFLAGS.release ?= -s ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_XGCCAMD64LINUX_COMPILE_C_OUTPUT = TOOL_XGCCAMD64LINUX_COMPILE_C_DEPEND = TOOL_XGCCAMD64LINUX_COMPILE_C_DEPORD = define TOOL_XGCCAMD64LINUX_COMPILE_C_CMDS $(QUIET)$(TOOL_XGCCAMD64LINUX_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) endef ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_XGCCAMD64LINUX_COMPILE_CXX_OUTPUT = TOOL_XGCCAMD64LINUX_COMPILE_CXX_DEPEND = TOOL_XGCCAMD64LINUX_COMPILE_CXX_DEPORD = define TOOL_XGCCAMD64LINUX_COMPILE_CXX_CMDS $(QUIET)$(TOOL_XGCCAMD64LINUX_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) endef ## Compile Assembly source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. # TOOL_XGCCAMD64LINUX_COMPILE_AS_OUTPUT = TOOL_XGCCAMD64LINUX_COMPILE_AS_DEPEND = TOOL_XGCCAMD64LINUX_COMPILE_AS_DEPORD = define TOOL_XGCCAMD64LINUX_COMPILE_AS_CMDS $(QUIET)$(TOOL_XGCCAMD64LINUX_AS) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_XGCCAMD64LINUX_LINK_LIBRARY_OUTPUT = $(out).ar-script TOOL_XGCCAMD64LINUX_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_XGCCAMD64LINUX_LINK_LIBRARY_DEPORD = define TOOL_XGCCAMD64LINUX_LINK_LIBRARY_CMDS $(QUIET)$(APPEND) $(out).ar-script 'CREATE $(out)' $(QUIET)$(APPEND) -n $(out).ar-script \ $(foreach o,$(objs), 'ADDMOD $(o)') \ $(foreach o,$(othersrc), 'ADDLIB $(o)') $(QUIET)$(APPEND) $(out).ar-script 'SAVE' $(QUIET)$(APPEND) $(out).ar-script 'END' $(QUIET)$(REDIRECT) -rti $(out).ar-script -- $(TOOL_XGCCAMD64LINUX_AR) -M endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_XGCCAMD64LINUX_LINK_PROGRAM_OUTPUT = $(outbase).map TOOL_XGCCAMD64LINUX_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_XGCCAMD64LINUX_LINK_PROGRAM_DEPORD = define TOOL_XGCCAMD64LINUX_LINK_PROGRAM_CMDS $(QUIET)$(TOOL_XGCCAMD64LINUX_LD) $(flags) -o $(out) $(objs)\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(basename $(lib))), $(lib)))\ $(call TOOL_XGCCAMD64LINUX_LD_MAP,$(outbase).map) endef ## Link DLL # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_XGCCAMD64LINUX_LINK_DLL_OUTPUT = $(outbase).map TOOL_XGCCAMD64LINUX_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_XGCCAMD64LINUX_LINK_DLL_DEPORD = define TOOL_XGCCAMD64LINUX_LINK_DLL_CMDS $(QUIET)$(TOOL_XGCCAMD64LINUX_LD) $(TOOL_XGCCAMD64LINUX_LDFLAGS.dll) $(flags) -o $(out)\ $(if $(filter-out win32 os2, $(KBUILD_TARGET)),$(call TOOL_XGCCAMD64LINUX_LD_SONAME,$(target),$(out)))\ $(objs)\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(basename $(lib))), $(lib)))\ $(call TOOL_XGCCAMD64LINUX_LD_MAP,$(outbase).map) endef ## Link system module (windows aka driver, linux aka kernel module) # @param $(target) Normalized main target name. # @param $(out) System module name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_XGCCAMD64LINUX_LINK_SYSMOD_OUTPUT = $(outbase).map TOOL_XGCCAMD64LINUX_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_XGCCAMD64LINUX_LINK_SYSMOD_DEPORD = define TOOL_XGCCAMD64LINUX_LINK_SYSMOD_CMDS $(QUIET)$(TOOL_XGCCAMD64LINUX_LD_SYSMOD) $(TOOL_XGCCAMD64LINUX_LDFLAGS.sysmod) $(flags) -o $(out) $(objs)\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(basename $(lib))), $(lib)))\ $(call TOOL_XGCCAMD64LINUX_LD_SYSMOD_MAP,$(outbase).map) endef kbuild-3149/kBuild/tools/GXX3PLAIN.kmk0000644000175000017500000003216713252530251017306 0ustar locutuslocutus# $Id: GXX3PLAIN.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - Generic GCC v3.2.x or later using the system GCC, any Unix linker and Unix archiver to build C++ code. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_GXX3PLAIN := Generic GCC v3.2.x or later using the system GCC, any Unix linker and Unix archiver to build C++ code. # Tool Specific Properties TOOL_GXX3PLAIN_CC ?= gcc$(HOSTSUFF_EXE) TOOL_GXX3PLAIN_CXX ?= g++$(HOSTSUFF_EXE) TOOL_GXX3PLAIN_AS ?= gcc$(HOSTSUFF_EXE) TOOL_GXX3PLAIN_AR ?= ar$(HOSTSUFF_EXE) TOOL_GXX3PLAIN_RANLIB ?= ranlib$(HOSTSUFF_EXE) TOOL_GXX3PLAIN_LD ?= g++$(HOSTSUFF_EXE) TOOL_GXX3PLAIN_LD_SYSMOD ?= ld$(HOSTSUFF_EXE) TOOL_GXX3PLAIN_LD_SYSMOD.os2 ?= g++$(HOSTSUFF_EXE) TOOL_GXX3PLAIN_LDFLAGS.dll.os2 ?= -Zdll TOOL_GXX3PLAIN_LDFLAGS.dll.darwin ?= -dynamiclib ifndef TOOL_GXX3PLAIN_LDFLAGS.$(KBUILD_TARGET) TOOL_GXX3PLAIN_LDFLAGS.dll ?= -shared else TOOL_GXX3PLAIN_LDFLAGS.dll ?= $(TOOL_GXX3PLAIN_LDFLAGS.$(KBUILD_TARGET)) endif TOOL_GXX3PLAIN_LD_SONAME.darwin ?= $(NO_SUCH_VARIABLE) TOOL_GXX3PLAIN_LD_SONAME.os2 ?= $(NO_SUCH_VARIABLE) TOOL_GXX3PLAIN_LD_SONAME.solaris ?= -Wl,-h,$(firstword $($(1)_SONAME.$(KBUILD_TARGET).$(KBUILD_TYPE)) $($(1)_SONAME.$(KBUILD_TARGET)) $($(1)_SONAME.$(KBUILD_TYPE)) $($(1)_SONAME) $(notdir $(2))) TOOL_GXX3PLAIN_LD_SONAME.win ?= $(NO_SUCH_VARIABLE) ifndef TOOL_GXX3PLAIN_LD_SONAME.$(KBUILD_TARGET) TOOL_GXX3PLAIN_LD_SONAME ?= -Wl,-soname=$(firstword $($(1)_SONAME.$(KBUILD_TARGET).$(KBUILD_TYPE)) $($(1)_SONAME.$(KBUILD_TARGET)) $($(1)_SONAME.$(KBUILD_TYPE)) $($(1)_SONAME) $(notdir $(2))) else TOOL_GXX3PLAIN_LD_SONAME ?= $(TOOL_GXX3PLAIN_LD_SONAME.$(KBUILD_TARGET)) endif ifdef SLKRUNS TOOL_GXX3PLAIN_CC += -fmessage-length=0 TOOL_GXX3PLAIN_CXX += -fmessage-length=0 endif # General Properties used by kBuild TOOL_GXX3PLAIN_COBJSUFF ?= .o TOOL_GXX3PLAIN_CFLAGS ?= TOOL_GXX3PLAIN_CFLAGS.debug ?= -g TOOL_GXX3PLAIN_CFLAGS.profile ?= -O2 #-g -pg TOOL_GXX3PLAIN_CFLAGS.release ?= -O2 TOOL_GXX3PLAIN_CINCS ?= TOOL_GXX3PLAIN_CDEFS ?= TOOL_GXX3PLAIN_CXXOBJSUFF ?= .o TOOL_GXX3PLAIN_CXXOBJSUFF ?= .o TOOL_GXX3PLAIN_CXXFLAGS ?= TOOL_GXX3PLAIN_CXXFLAGS.debug ?= -g TOOL_GXX3PLAIN_CXXFLAGS.profile ?= -O2 #-g -pg TOOL_GXX3PLAIN_CXXFLAGS.release ?= -O2 TOOL_GXX3PLAIN_CXXINCS ?= TOOL_GXX3PLAIN_CXXDEFS ?= TOOL_GXX3PLAIN_ASFLAGS ?= -x assembler-with-cpp TOOL_GXX3PLAIN_ASFLAGS.debug ?= -g TOOL_GXX3PLAIN_ASFLAGS.profile ?= -g TOOL_GXX3PLAIN_ASOBJSUFF ?= .o TOOL_GXX3PLAIN_ARFLAGS ?= cr TOOL_GXX3PLAIN_ARLIBSUFF ?= .a TOOL_GXX3PLAIN_LDFLAGS ?= ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GXX3PLAIN_COMPILE_C_DEPEND = TOOL_GXX3PLAIN_COMPILE_C_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GXX3PLAIN_COMPILE_C_USES_KOBJCACHE = 1 TOOL_GXX3PLAIN_COMPILE_C_OUTPUT = $(outbase).i define TOOL_GXX3PLAIN_COMPILE_C_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).i\ $(TOOL_GXX3PLAIN_CC) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GXX3PLAIN_CC) -c\ $(flags) -fpreprocessed -x c\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GXX3PLAIN_COMPILE_C_OUTPUT = define TOOL_GXX3PLAIN_COMPILE_C_CMDS $(QUIET)$(TOOL_GXX3PLAIN_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GXX3PLAIN_COMPILE_CXX_DEPEND = TOOL_GXX3PLAIN_COMPILE_CXX_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GXX3PLAIN_COMPILE_CXX_USES_KOBJCACHE = 1 TOOL_GXX3PLAIN_COMPILE_CXX_OUTPUT = $(outbase).ii define TOOL_GXX3PLAIN_COMPILE_CXX_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).ii\ $(TOOL_GXX3PLAIN_CXX) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GXX3PLAIN_CXX) -c\ $(flags) -fpreprocessed -x c++\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GXX3PLAIN_COMPILE_CXX_OUTPUT = define TOOL_GXX3PLAIN_COMPILE_CXX_CMDS $(QUIET)$(TOOL_GXX3PLAIN_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile Assembly source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. # TOOL_GXX3PLAIN_COMPILE_AS_OUTPUT = TOOL_GXX3PLAIN_COMPILE_AS_DEPEND = TOOL_GXX3PLAIN_COMPILE_AS_DEPORD = define TOOL_GXX3PLAIN_COMPILE_AS_CMDS $(QUIET)$(TOOL_GXX3PLAIN_AS) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX3PLAIN_LINK_LIBRARY_OUTPUT = TOOL_GXX3PLAIN_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_GXX3PLAIN_LINK_LIBRARY_DEPORD = define TOOL_GXX3PLAIN_LINK_LIBRARY_CMDS $(call xargs,$(QUIET)$(TOOL_GXX3PLAIN_AR) $(flags) $(out),$(objs)) $(foreach lib,$(othersrc)\ ,$(NL)$(TAB)$(call MSG_AR_MERGE,$(target),$(out),$(lib)) \ $(NL)$(TAB)$(QUIET)$(RM_EXT) -f $(dir $(outbase))ar.tmp.dir/* \ $(NL)$(TAB)$(QUIET)$(MKDIR) -p $(dir $(outbase))/ar.tmp.dir/ \ $(NL)$(TAB)$(QUIET)(cd $(dir $(outbase))ar.tmp.dir/ \ && $(TOOL_GXX3PLAIN_AR) x $(abspath $(lib)) \ && $(TOOL_GXX3PLAIN_AR) $(flags) $(out) *) \ $(NL)$(TAB)$(QUIET)$(RM_EXT) -f $(dir $(outbase))/ar.tmp.dir/* \ $(NL)$(TAB)$(QUIET)$(RMDIR) $(dir $(outbase))ar.tmp.dir/) $(QUIET)$(TOOL_GXX3PLAIN_RANLIB) $(out) endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX3PLAIN_LINK_PROGRAM_OUTPUT = TOOL_GXX3PLAIN_LINK_PROGRAM_OUTPUT_MAYBE = $(outbase).map TOOL_GXX3PLAIN_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib)))\ $(filter %.def, $(othersrc)) TOOL_GXX3PLAIN_LINK_PROGRAM_DEPORD = define TOOL_GXX3PLAIN_LINK_PROGRAM_CMDS $(QUIET)$(TOOL_GXX3PLAIN_LD) $(flags) -o $(out) $(objs)\ $(filter %.def, $(othersrc))\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib))) endef ## Link DLL # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX3PLAIN_LINK_DLL_OUTPUT = TOOL_GXX3PLAIN_LINK_DLL_OUTPUT_MAYBE = $(outbase).map TOOL_GXX3PLAIN_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib)))\ $(filter %.def, $(othersrc)) TOOL_GXX3PLAIN_LINK_DLL_DEPORD = define TOOL_GXX3PLAIN_LINK_DLL_CMDS $(QUIET)$(TOOL_GXX3PLAIN_LD) $(TOOL_GXX3PLAIN_LDFLAGS.dll) $(flags) -o $(out)\ $(if $(filter-out win32 os2, $(KBUILD_TARGET)),$(call TOOL_GXX3PLAIN_LD_SONAME,$(target),$(out)))\ $(objs)\ $(filter %.def, $(othersrc))\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib))) endef ## Link system module (windows aka driver, linux aka kernel module) # This tool target might not work everywhere, but is provided for the # platforms where it works (Solaris, etc). # # @param $(target) Normalized main target name. # @param $(out) System module name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX3PLAIN_LINK_SYSMOD_OUTPUT = TOOL_GXX3PLAIN_LINK_SYSMOD_OUTPUT_MAYBE = $(outbase).map TOOL_GXX3PLAIN_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib)))\ $(filter %.def, $(othersrc)) TOOL_GXX3PLAIN_LINK_SYSMOD_DEPORD = define TOOL_GXX3PLAIN_LINK_SYSMOD_CMDS $(QUIET)$(if $(TOOL_GXX3PLAIN_LD_SYSMOD.$(bld_trg)),$(TOOL_GXX3PLAIN_LD_SYSMOD.$(bld_trg)),$(TOOL_GXX3PLAIN_LD_SYSMOD))\ $(TOOL_GXX3PLAIN_LDFLAGS_SYSMOD.$(bld_trg)) $(flags) -o $(out) \ $(objs)\ $(filter %.def, $(othersrc))\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib))) endef kbuild-3149/kBuild/tools/VCC80.kmk0000644000175000017500000003554113252530251016553 0ustar locutuslocutus# $Id: VCC80.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - Visual C++ 8.0 (aka Visual .NET 2005, or MSC v14), targeting $(KBUILD_TARGET). # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_VCC80 := Visual C++ 8.0 (aka Visual .NET 2005, or MSC v14), targeting $(KBUILD_TARGET). # Tool Specific Properties ifndef PATH_TOOL_VCC80 PATH_TOOL_VCC80 := $(wildcard $(KBUILD_DEVTOOLS_TRG)/vcc/v8*) ifeq ($(PATH_TOOL_VCC80),) PATH_TOOL_VCC80 := $(wildcard $(KBUILD_DEVTOOLS)/win.x86/vcc/v8*) endif ifeq ($(PATH_TOOL_VCC80),) PATH_TOOL_VCC80 := $(wildcard $(KBUILD_DEVTOOLS)/x86.win32/vcc/v8*) endif ifeq ($(PATH_TOOL_VCC80),) PATH_TOOL_VCC80 := $(wildcard $(KBUILD_DEVTOOLS)/win.amd64/vcc/v8*) endif ifeq ($(PATH_TOOL_VCC80),) PATH_TOOL_VCC80 := $(lastword $(sort $(PATH_TOOL_VCC80))) endif # if not found, we'll enter 'pathless' mode. else # Resolve any fancy stuff once and for all. PATH_TOOL_VCC80 := $(PATH_TOOL_VCC80) endif ifneq ($(PATH_TOOL_VCC80),) ifeq ($(KBUILD_HOST).$(KBUILD_HOST_ARCH),win.amd64) PATH_TOOL_VCC80_BIN.amd64 ?= $(PATH_TOOL_VCC80)/bin/amd64 else PATH_TOOL_VCC80_BIN.amd64 ?= $(PATH_TOOL_VCC80)/bin/x86_amd64 endif PATH_TOOL_VCC80_BIN.x86 ?= $(PATH_TOOL_VCC80)/bin PATH_TOOL_VCC80_BIN ?= $(PATH_TOOL_VCC80_BIN.$(KBUILD_TARGET_ARCH)) PATH_TOOL_VCC80_LIB.amd64 ?= $(PATH_TOOL_VCC80)/lib/amd64 PATH_TOOL_VCC80_LIB.x86 ?= $(PATH_TOOL_VCC80)/lib PATH_TOOL_VCC80_LIB ?= $(PATH_TOOL_VCC80_LIB.$(KBUILD_TARGET_ARCH)) PATH_TOOL_VCC80_INC ?= $(PATH_TOOL_VCC80)/include PATH_TOOL_VCC80_ATLMFC ?= $(PATH_TOOL_VCC80X86)/atlmfc PATH_TOOL_VCC80_ATLMFC_INC ?= $(PATH_TOOL_VCC80_ATLMFC)/include PATH_TOOL_VCC80_ATLMFC_LIB.amd64 ?= $(PATH_TOOL_VCC80_ATLMFC)/lib PATH_TOOL_VCC80_ATLMFC_LIB.x86 ?= $(PATH_TOOL_VCC80_ATLMFC)/lib/amd64 PATH_TOOL_VCC80_ATLMFC_LIB ?= $(PATH_TOOL_VCC80_ATLMFC_LIB.$(KBUILD_TARGET_ARCH)) TOOL_VCC80_CC ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC80_BIN)/cl.exe TOOL_VCC80_CXX ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC80_BIN)/cl.exe TOOL_VCC80_AS ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC80_BIN)/ml64.exe TOOL_VCC80_RC ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC80_BIN.x86)/rc.exe TOOL_VCC80_AR ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC80_BIN)/lib.exe TOOL_VCC80_LD ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC80_BIN)/link.exe TOOL_VCC80_MT ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC80_BIN.x86)/mt.exe else # Pathless, relies on the environment. TOOL_VCC80_CC ?= $(EXEC_X86_WIN32) cl.exe TOOL_VCC80_CXX ?= $(EXEC_X86_WIN32) cl.exe TOOL_VCC80_AS ?= $(EXEC_X86_WIN32) ml64.exe TOOL_VCC80_RC ?= $(EXEC_X86_WIN32) rc.exe TOOL_VCC80_AR ?= $(EXEC_X86_WIN32) lib.exe TOOL_VCC80_LD ?= $(EXEC_X86_WIN32) link.exe TOOL_VCC80_MT ?= $(EXEC_X86_WIN32) mt.exe endif ## Disabled fast DEP_IDB based dependencies. #VCC80_OLD_DEPS = 1 ## Constructs the correct .pdb name (the name is lowercased). # @param $(1) Base name, no extention. # @param $(2) The extension. TOOL_VCC80_PDB = $(dir $(1))$(tolower $(notdir $(1))).$(2) TOOL_VCC80_COBJSUFF ?= .obj TOOL_VCC80_CFLAGS ?= -TC -c -nologo TOOL_VCC80_CFLAGS.debug ?= -Od -Zi TOOL_VCC80_CFLAGS.release ?= -O2 TOOL_VCC80_CFLAGS.profile ?= -O2 TOOL_VCC80_CINCS ?= $(PATH_TOOL_VCC80_INC) TOOL_VCC80_CDEFS ?= TOOL_VCC80_CXXOBJSUFF ?= .obj TOOL_VCC80_CXXFLAGS ?= -TP -c -nologo TOOL_VCC80_CXXFLAGS.debug ?= -Od -Zi TOOL_VCC80_CXXFLAGS.release ?= -O2 TOOL_VCC80_CXXFLAGS.profile ?= -O2 TOOL_VCC80_CXXINCS ?= $(PATH_TOOL_VCC80_INC) $(PATH_TOOL_VCC80_ATLMFC_INC) TOOL_VCC80_CXXDEFS ?= TOOL_VCC80_ASOBJSUFF ?= .obj TOOL_VCC80_RCOBJSUFF ?= .res TOOL_VCC80_RCINCS ?= $(PATH_TOOL_VCC80_INC) $(PATH_TOOL_VCC80_ATLMFC_INC) TOOL_VCC80_ARFLAGS.amd64 ?= -machine:amd64 TOOL_VCC80_ARFLAGS.x86 ?= -machine:x86 TOOL_VCC80_ARFLAGS ?= -nologo TOOL_VCC80_ARLIBSUFF ?= .lib TOOL_VCC80_LDFLAGS.amd64 ?= -machine:amd64 TOOL_VCC80_LDFLAGS.x86 ?= -machine:x86 TOOL_VCC80_LDFLAGS ?= -nologo TOOL_VCC80_LDFLAGS.debug ?= -debug TOOL_VCC80_LDFLAGS.release ?= TOOL_VCC80_LIBPATH.amd64 ?= $(PATH_TOOL_VCC80_LIB.amd64) $(PATH_TOOL_VCC80_ATLMFC_LIB.amd64) TOOL_VCC80_LIBPATH.x86 ?= $(PATH_TOOL_VCC80_LIB.x86) $(PATH_TOOL_VCC80_ATLMFC_LIB.x86) ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC80_COMPILE_C_DEPEND = TOOL_VCC80_COMPILE_C_DEPORD = TOOL_VCC80_COMPILE_C_OUTPUT = $(call TOOL_VCC80_PDB, $(outbase)-obj,idb) TOOL_VCC80_COMPILE_C_OUTPUT_MAYBE = $(call TOOL_VCC80_PDB, $(outbase)-obj,pdb) define TOOL_VCC80_COMPILE_C_CMDS $(QUIET)$(TOOL_VCC80_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fd$(outbase)-obj.pdb \ -FD\ -Fo$(obj)\ $(subst /,\\,$(abspath $(source))) $(QUIET)$(DEP_IDB) -f -s -q -o $(dep) -t $(obj) $(call TOOL_VCC80_PDB,$(outbase)-obj,idb) endef ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC80_COMPILE_CXX_DEPEND = TOOL_VCC80_COMPILE_CXX_DEPORD = TOOL_VCC80_COMPILE_CXX_OUTPUT = $(call TOOL_VCC80_PDB, $(outbase)-obj,idb) TOOL_VCC80_COMPILE_CXX_OUTPUT_MAYBE = $(call TOOL_VCC80_PDB, $(outbase)-obj,pdb) define TOOL_VCC80_COMPILE_CXX_CMDS $(QUIET)$(TOOL_VCC80_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fd$(outbase)-obj.pdb \ -FD\ -Fo$(obj)\ $(subst /,\\,$(abspath $(source))) $(QUIET)$(DEP_IDB) -f -s -q -o $(dep) -t $(obj) $(call TOOL_VCC80_PDB,$(outbase)-obj,idb) endef ## Compile resource source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC80_COMPILE_RC_OUTPUT = TOOL_VCC80_COMPILE_RC_DEPEND = TOOL_VCC80_COMPILE_RC_DEPORD = define TOOL_VCC80_COMPILE_RC_CMDS $(QUIET)$(TOOL_VCC80_RC) \ $(flags) $(addprefix /i, $(subst /,\\,$(incs))) $(addprefix /d, $(defs))\ /fo$(obj)\ $(subst /,\\,$(abspath $(source))) endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_VCC80_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_VCC80_LINK_LIBRARY_DEPORD = TOOL_VCC80_LINK_LIBRARY_OUTPUT = $(outbase).rsp TOOL_VCC80_LINK_LIBRARY_OUTPUT_MAYBE = $(outbase).lst $(outbase).exp $(outbase).pdb define TOOL_VCC80_LINK_LIBRARY_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs) \ $(filter-out %.def,$(othersrc))) \ $(addprefix /DEF:,$(filter %.def,$(othersrc))) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC80_AR) $(flags) /OUT:$(out) @$(outbase).rsp endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_VCC80_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC80_LINK_PROGRAM_DEPORD = TOOL_VCC80_LINK_PROGRAM_OUTPUT = $(outbase).map $(outbase).rsp TOOL_VCC80_LINK_PROGRAM_OUTPUT_MAYBE = $(outbase).map $(outbase).lib $(outbase).exp $(outbase).ilk $(out).manifest TOOL_VCC80_LINK_PROGRAM_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC80_LINK_PROGRAM_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb define TOOL_VCC80_LINK_PROGRAM_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC80_LD) $(flags) \ /OUT:$(out) \ /MAPINFO:EXPORTS /INCREMENTAL:NO \ /MAP:$(outbase).map \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp $(QUIET)$(TEST) -f $(out).manifest -- \ $(TOOL_VCC80_MT) -manifest $(subst /,\\,$(out)).manifest -outputresource:$(subst /,\\,$(out)) endef ## Link DLL. # @param $(target) Normalized main target name. # @param $(out) DLL name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_VCC80_LINK_DLL_DEPEND = $(objs) $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC80_LINK_DLL_DEPORD = $(call DIRDEP,$(PATH_STAGE_LIB)) TOOL_VCC80_LINK_DLL_OUTPUT = $(outbase).map $(outbase).lib $(outbase).exp $(outbase).rsp TOOL_VCC80_LINK_DLL_OUTPUT_MAYBE = $(outbase).ilk $(out).manifest $(PATH_STAGE_LIB)/$(notdir $(outbase)).lib $(PATH_STAGE_LIB)/$(notdir $(outbase)).exp TOOL_VCC80_LINK_DLL_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC80_LINK_DLL_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb define TOOL_VCC80_LINK_DLL_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC80_LD) $(flags) \ /OUT:$(out) \ /IMPLIB:$(outbase).lib \ /MAPINFO:EXPORTS /INCREMENTAL:NO \ /MAP:$(outbase).map \ /DLL \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp $(QUIET)$(TEST) -f $(out).manifest -- \ $(TOOL_VCC80_MT) -manifest $(subst /,\\,$(out)).manifest '-outputresource:$(subst /,\\,$(out));#2' $(QUIET)$(CP) --changed --ignore-non-existing $(outbase).exp $(outbase).lib $(PATH_STAGE_LIB)/ $(eval _DIRS += $(PATH_STAGE_LIB)) endef ## Link system module (windows aka driver, linux aka kernel module) # @param $(target) Normalized main target name. # @param $(out) System module name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_VCC80_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC80_LINK_SYSMOD_DEPORD = TOOL_VCC80_LINK_SYSMOD_OUTPUT = $(outbase).map $(outbase).rsp TOOL_VCC80_LINK_SYSMOD_OUTPUT_MAYBE = $(outbase).lib $(outbase).exp $(outbase).ilk $(out).manifest TOOL_VCC80_LINK_SYSMOD_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC80_LINK_SYSMOD_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb define TOOL_VCC80_LINK_SYSMOD_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC80_LD) $(flags) \ /OUT:$(out) \ /MAPINFO:EXPORTS /INCREMENTAL:NO \ /MAP:$(outbase).map \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp $(QUIET)$(TEST) -f $(out).manifest -- \ $(TOOL_VCC80_MT) -manifest $(subst /,\\,$(out)).manifest '-outputresource:$(subst /,\\,$(out));#2' endef kbuild-3149/kBuild/tools/YASM.kmk0000644000175000017500000000775513252530251016547 0ustar locutuslocutus# $Id: YASM.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - YASM 0.4.0 or later. # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_YASM := YASM v0.4.0+ # Tool Specific Properties ifndef PATH_TOOL_YASM PATH_TOOL_YASM := $(sort $(wildcard $(KBUILD_DEVTOOLS_HST)/yasm/v*.*)) ifneq ($(PATH_TOOL_YASM),) PATH_TOOL_YASM := $(call lastword,$(PATH_TOOL_YASM)) endif else # Resolve any fancy stuff once and for all. PATH_TOOL_YASM := $(PATH_TOOL_YASM) endif ifneq ($(PATH_TOOL_YASM),) TOOL_YASM_AS ?= $(PATH_TOOL_YASM)/yasm$(HOSTSUFF_EXE) else TOOL_YASM_AS ?= yasm$(HOSTSUFF_EXE) endif # kSubmit ifdef TOOL_YASM_USE_KSUBMIT ifeq ($(KBUILD_HOST),win) TOOL_YASM_KSUBMIT ?= kmk_builtin_kSubmit -- endif endif # General Properties used by kBuild TOOL_YASM_ASFLAGS ?= ## Compile Assembly source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. # TOOL_YASM_COMPILE_AS_OUTPUT = $(outbase).lst TOOL_YASM_COMPILE_AS_OUTPUT_MAYBE = $(obj).map TOOL_YASM_COMPILE_AS_DEPEND = TOOL_YASM_COMPILE_AS_DEPORD = define TOOL_YASM_COMPILE_AS_CMDS ifdef TOOL_YASM_KSUBMIT # yasm 1.3.0 w/ patches. $(QUIET)$(TOOL_YASM_KSUBMIT) $(TOOL_YASM_AS)\ $(patsubst --mapfile%,--mapfile=$(obj).map,$(flags))\ $(addsuffix /,$(addprefix -I, $(incs))) $(addprefix -D, $(defs))\ -l $(outbase).lst\ -o $(obj)\ -MD="$(dep)" -MP --makedep-dos2unix-slash\ $(abspath $(source)) else $(QUIET)$(TOOL_YASM_AS)\ $(patsubst --mapfile%,--mapfile=$(obj).map,$(flags))\ $(addsuffix /,$(addprefix -I, $(incs))) $(addprefix -D, $(defs))\ -l $(outbase).lst\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(REDIRECT) -wo $(dep) -- $(TOOL_YASM_AS) -DKBUILD_GENERATING_MAKEFILE_DEPENDENCIES\ $(patsubst --mapfile%,--mapfile=$(obj).map,$(flags))\ $(addsuffix /,$(addprefix -I, $(incs))) $(addprefix -D, $(defs))\ -o $(obj) \ $(abspath $(source)) \ -M if1of ($(KBUILD_HOST), win nt os2) $(QUIET)$(SED) -e 's/\\\(.\)/\/\1/g' --output "$(dep).tmp" "$(dep)" else $(QUIET)$(CP) -f -- "$(dep)" "$(dep).tmp" endif $(QUIET)$(APPEND) -n "$(dep).tmp" "" "" $(QUIET)$(SED) $(if $(intersects $(KBUILD_HOST), win nt os2), -e 's/\\\(.\)/\/\1/g',)\ -e 's/^[^ ]*: / /'\ -e 's/ *\\$$(DOLLAR)//'\ -e 's/^ *//'\ -e 's/ */\n/g'\ -e 's/ *\([^ \n][^ \n]*\)/\1:\n/g'\ --append "$(dep).tmp"\ "$(dep)" $(QUIET)$(MV) -f -- "$(dep).tmp" "$(dep)" endif endef kbuild-3149/kBuild/tools/JWASM.kmk0000644000175000017500000000411213252530251016637 0ustar locutuslocutus# $Id: JWASM.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - JWasm # # # Copyright (c) 2012-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_JWASM := JWasm - MASM clone based on the Open Watcom assembler. # Tool Specific Properties ifndef TOOL_JWASM_AS TOOL_JWASM_AS := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST)/jwasm/*/jwasm$(HOSTSUFF_EXE)))) ifeq ($(TOOL_JWASM_AS),) TOOL_JWASM_AS := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_TRG)/jwasm/*/jwasm$(HOSTSUFF_EXE)))) endif endif ifeq ($(TOOL_JWASM_AS),) TOOL_JWASM_AS := $(firstword $(which ml$(HOSTSUFF_EXE)) jwasm$(HOSTSUFF_EXE)) endif # General Properties used by kBuild TOOL_JWASM_ASFLAGS ?= -X -nologo TOOL_JWASM_COMPILE_AS_OUTPUT = $(outbase).lst TOOL_JWASM_COMPILE_AS_DEPEND = TOOL_JWASM_COMPILE_AS_DEPORD = define TOOL_JWASM_COMPILE_AS_CMDS $(QUIET)$(TOOL_JWASM_AS) -c \ $(strip $(flags)) \ $(addprefix -D,$(defs)) \ $(addprefix -I,$(incs)) \ -Fo$(obj) \ -Fl$(outbase).lst \ $(source) endef kbuild-3149/kBuild/tools/GCC4MACHO.kmk0000644000175000017500000004540313252530251017216 0ustar locutuslocutus# $Id: GCC4MACHO.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - GCC v4 targeting Darwin (Mac OS X) Mach-O. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_GCC4MACHO := GCC v4 targeting Darwin (Mac OS X) Mach-O. # Tool Specific Properties TOOL_GCC4MACHO_PREFIX ?= TOOL_GCC4MACHO_SUFFIX ?= $(HOSTSUFF_EXE) TOOL_GCC4MACHO_CC ?= $(TOOL_GCC4MACHO_PREFIX)gcc$(TOOL_GCC4MACHO_SUFFIX) TOOL_GCC4MACHO_CXX ?= $(TOOL_GCC4MACHO_PREFIX)g++$(TOOL_GCC4MACHO_SUFFIX) TOOL_GCC4MACHO_OBJC ?= $(TOOL_GCC4MACHO_PREFIX)gcc$(TOOL_GCC4MACHO_SUFFIX) TOOL_GCC4MACHO_OBJCXX ?= $(TOOL_GCC4MACHO_PREFIX)gcc$(TOOL_GCC4MACHO_SUFFIX) TOOL_GCC4MACHO_AS ?= $(TOOL_GCC4MACHO_PREFIX)gcc$(TOOL_GCC4MACHO_SUFFIX) TOOL_GCC4MACHO_LD ?= $(TOOL_GCC4MACHO_PREFIX)gcc$(TOOL_GCC4MACHO_SUFFIX) TOOL_GCC4MACHO_LD_SYSMOD ?= $(TOOL_GCC4MACHO_PREFIX)gcc$(TOOL_GCC4MACHO_SUFFIX) ifndef TOOL_GCC4MACHO_LDFLAGS.$(KBUILD_TARGET) TOOL_GCC4MACHO_LDFLAGS.dll ?= -dynamiclib else TOOL_GCC4MACHO_LDFLAGS.dll ?= $(TOOL_GCC4MACHO_LDFLAGS.$(KBUILD_TARGET)) endif TOOL_GCC4MACHO_LDFLAGS.sysmod ?= -r #TOOL_GCC4MACHO_LD_SONAME = -Wl,-dylib_install_name $(firstword $($(1)_SONAME.$(KBUILD_TARGET).$(KBUILD_TYPE)) $($(1)_SONAME.$(KBUILD_TARGET)) $($(1)_SONAME.$(KBUILD_TYPE)) $($(1)_SONAME) $(notdir $(2))) TOOL_GCC4MACHO_DSYMUTIL ?= dsymutil ifdef SLKRUNS TOOL_GCC4MACHO_CC += -fmessage-length=0 TOOL_GCC4MACHO_CXX += -fmessage-length=0 TOOL_GCC4MACHO_OBJC += -fmessage-length=0 TOOL_GCC4MACHO_OBJCXX += -fmessage-length=0 endif # General Properties used by kBuild TOOL_GCC4MACHO_COBJSUFF ?= .o TOOL_GCC4MACHO_CFLAGS ?= TOOL_GCC4MACHO_CFLAGS.debug ?= -g TOOL_GCC4MACHO_CFLAGS.profile ?= -g -O2 #-pg TOOL_GCC4MACHO_CFLAGS.release ?= -O2 TOOL_GCC4MACHO_CINCS ?= TOOL_GCC4MACHO_CDEFS ?= TOOL_GCC4MACHO_CXXOBJSUFF ?= .o TOOL_GCC4MACHO_CXXFLAGS ?= TOOL_GCC4MACHO_CXXFLAGS.debug ?= -g TOOL_GCC4MACHO_CXXFLAGS.profile ?= -g -O2 #-pg TOOL_GCC4MACHO_CXXFLAGS.release ?= -O2 TOOL_GCC4MACHO_CXXINCS ?= TOOL_GCC4MACHO_CXXDEFS ?= TOOL_GCC4MACHO_OBJCOBJSUFF ?= .o TOOL_GCC4MACHO_OBJCFLAGS ?= TOOL_GCC4MACHO_OBJCFLAGS.debug ?= -g TOOL_GCC4MACHO_OBJCFLAGS.profile?= -O2 #-g -pg TOOL_GCC4MACHO_OBJCFLAGS.release?= -O2 TOOL_GCC4MACHO_OBJCINCS ?= TOOL_GCC4MACHO_OBJCDEFS ?= TOOL_GCC4MACHO_OBJCXXOBJSUFF ?= .o TOOL_GCC4MACHO_OBJCXXFLAGS ?= TOOL_GCC4MACHO_OBJCXXFLAGS.debug ?= -g TOOL_GCC4MACHO_OBJCXXFLAGS.profile ?= -O2 #-g -pg TOOL_GCC4MACHO_OBJCXXFLAGS.release ?= -O2 TOOL_GCC4MACHO_OBJCXXINCS ?= TOOL_GCC4MACHO_OBJCXXDEFS ?= TOOL_GCC4MACHO_ASFLAGS ?= -x assembler-with-cpp TOOL_GCC4MACHO_ASFLAGS.debug ?= -g TOOL_GCC4MACHO_ASFLAGS.profile ?= -g TOOL_GCC4MACHO_ASOBJSUFF ?= .o TOOL_GCC4MACHO_AR ?= ar$(HOSTSUFF_EXE) TOOL_GCC4MACHO_ARFLAGS ?= -c -rs TOOL_GCC4MACHO_ARLIBSUFF ?= .a TOOL_GCC4MACHO_LDFLAGS ?= TOOL_GCC4MACHO_LDFLAGS.debug ?= -g TOOL_GCC4MACHO_LDFLAGS.profile ?= -g TOOL_GCC4MACHO_STRIP_PROGRAM ?= strip -SXxru TOOL_GCC4MACHO_STRIP_DLL ?= strip -Sxru TOOL_GCC4MACHO_STRIP_SYSMOD ?= strip -Sru ## # Calculate the files in the debug bundle. # @param 1 The whole output filename. # @param 2 The output filename sans suffix. TOOL_GCC4MACHO_DEBUG_BUNDLE_FN = \ $(1).dSYM/ \ $(1).dSYM/Contents/ \ $(1).dSYM/Contents/Resources/ \ $(1).dSYM/Contents/Resources/DWARF/ \ $(1).dSYM/Contents/Info.plist \ $(1).dSYM/Contents/Resources/DWARF/$(notdir $(1)) ## # Calculate the files in the debug bundle. # @param 1 The whole linker output filename. # @param 2 The linker output filename sans suffix. # @param 3 The desired install name (no dir slash). # @remarks The Info.plist has some reference to the original name, but gdb # does not care and only check for a symbol file in the DWARF # directory with the same name as the debugged module. TOOL_GCC4MACHO_DEBUG_INSTALL_FN= \ $(3).dSYM/ \ $(3).dSYM/Contents/ \ $(3).dSYM/Contents/Resources/ \ $(3).dSYM/Contents/Resources/DWARF/ \ $(1).dSYM/Contents/Info.plist=>$(3).dSYM/Contents/Info.plist \ $(1).dSYM/Contents/Resources/DWARF/$(notdir $(1))=>$(3).dSYM/Contents/Resources/DWARF/$(notdir $(3)) ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GCC4MACHO_COMPILE_C_DEPEND = TOOL_GCC4MACHO_COMPILE_C_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GCC4MACHO_COMPILE_C_USES_KOBJCACHE = 1 TOOL_GCC4MACHO_COMPILE_C_OUTPUT = $(outbase).i define TOOL_GCC4MACHO_COMPILE_C_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).i\ $(TOOL_GCC4MACHO_CC) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GCC4MACHO_CC) -c\ $(flags) -fpreprocessed -x c\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GCC4MACHO_COMPILE_C_OUTPUT = define TOOL_GCC4MACHO_COMPILE_C_CMDS $(QUIET)$(TOOL_GCC4MACHO_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KUSE_OBJCACHE ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GCC4MACHO_COMPILE_CXX_DEPEND = TOOL_GCC4MACHO_COMPILE_CXX_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GCC4MACHO_COMPILE_CXX_USES_KOBJCACHE = 1 TOOL_GCC4MACHO_COMPILE_CXX_OUTPUT = $(outbase).ii define TOOL_GCC4MACHO_COMPILE_CXX_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).ii\ $(TOOL_GCC4MACHO_CXX) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GCC4MACHO_CXX) -c\ $(flags) -fpreprocessed -x c++\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GCC4MACHO_COMPILE_CXX_OUTPUT = define TOOL_GCC4MACHO_COMPILE_CXX_CMDS $(QUIET)$(TOOL_GCC4MACHO_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile Objective-C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GCC4MACHO_COMPILE_OBJC_DEPEND = TOOL_GCC4MACHO_COMPILE_OBJC_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GCC4MACHO_COMPILE_OBJC_USES_KOBJCACHE = 1 TOOL_GCC4MACHO_COMPILE_OBJC_OUTPUT = $(outbase).mi define TOOL_GCC4MACHO_COMPILE_OBJC_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).ii\ $(TOOL_GCC4MACHO_OBJC) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GCC4MACHO_OBJC) -c\ $(flags) -fpreprocessed -x cbjective-c\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GCC4MACHO_COMPILE_OBJC_OUTPUT = define TOOL_GCC4MACHO_COMPILE_OBJC_CMDS $(QUIET)$(TOOL_GCC4MACHO_OBJC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile Objective-C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GCC4MACHO_COMPILE_OBJCXX_DEPEND = TOOL_GCC4MACHO_COMPILE_OBJCXX_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GCC4MACHO_COMPILE_OBJCXX_USES_KOBJCACHE = 1 TOOL_GCC4MACHO_COMPILE_OBJCXX_OUTPUT = $(outbase).mii define TOOL_GCC4MACHO_COMPILE_OBJCXX_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).mii\ $(TOOL_GCC4MACHO_OBJCXX) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GCC4MACHO_OBJCXX) -c\ $(flags) -fpreprocessed -x objective-c++\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GCC4MACHO_COMPILE_OBJCXX_OUTPUT = define TOOL_GCC4MACHO_COMPILE_OBJCXX_CMDS $(QUIET)$(TOOL_GCC4MACHO_OBJCXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile Assembly source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. # TOOL_GCC4MACHO_COMPILE_AS_OUTPUT = TOOL_GCC4MACHO_COMPILE_AS_DEPEND = TOOL_GCC4MACHO_COMPILE_AS_DEPORD = define TOOL_GCC4MACHO_COMPILE_AS_CMDS $(QUIET)$(TOOL_GCC4MACHO_AS) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC4MACHO_LINK_LIBRARY_OUTPUT = TOOL_GCC4MACHO_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_GCC4MACHO_LINK_LIBRARY_DEPORD = define TOOL_GCC4MACHO_LINK_LIBRARY_CMDS $(if $(strip $(objs)),$(call xargs,$(QUIET)$(TOOL_GCC4MACHO_AR) $(flags) $(out),$(objs))) $(foreach lib,$(othersrc)\ ,$(NL)$(TAB)$(call MSG_AR_MERGE,$(target),$(out),$(lib)) \ $(NL)$(TAB)$(QUIET)$(RM_EXT) -f $(dir $(outbase))ar.tmp.dir/* \ $(NL)$(TAB)$(QUIET)$(MKDIR) -p $(dir $(outbase))/ar.tmp.dir/ \ $(NL)$(TAB)$(QUIET)(cd $(dir $(outbase))ar.tmp.dir/ \ && $(TOOL_GCC4MACHO_AR) -x $(abspath $(lib)) \ && $(RM_EXT) -f ./__.SYMDEF* \ && $(TOOL_GCC4MACHO_AR) $(flags) $(out) *) \ $(NL)$(TAB)$(QUIET)$(RM_EXT) -f $(dir $(outbase))/ar.tmp.dir/* \ $(NL)$(TAB)$(QUIET)$(RMDIR) $(dir $(outbase))ar.tmp.dir/) endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC4MACHO_LINK_PROGRAM_OUTPUT = $(outbase).rsp TOOL_GCC4MACHO_LINK_PROGRAM_OUTPUT_DEBUG = $(call TOOL_GCC4MACHO_DEBUG_BUNDLE_FN,$(out)) TOOL_GCC4MACHO_LINK_PROGRAM_DEBUG_INSTALL_FN = $(TOOL_GCC4MACHO_DEBUG_INSTALL_FN) TOOL_GCC4MACHO_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_GCC4MACHO_LINK_PROGRAM_DEPORD = define TOOL_GCC4MACHO_LINK_PROGRAM_CMDS $(QUIET)$(APPEND) -n $(outbase).rsp $(objs) $(QUIET)$(TOOL_GCC4MACHO_LD) $(flags) -o $(out)\ -filelist $(outbase).rsp\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib))) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GCC4MACHO_DSYMUTIL) -o $(out).dSYM/ $(out) $(QUIET)$(TOOL_GCC4MACHO_STRIP_PROGRAM) $(out) endif endef ## Link DLL # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC4MACHO_LINK_DLL_OUTPUT = $(outbase).rsp TOOL_GCC4MACHO_LINK_DLL_OUTPUT_DEBUG = $(call TOOL_GCC4MACHO_DEBUG_BUNDLE_FN,$(out)) TOOL_GCC4MACHO_LINK_DLL_DEBUG_INSTALL_FN = $(TOOL_GCC4MACHO_DEBUG_INSTALL_FN) TOOL_GCC4MACHO_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_GCC4MACHO_LINK_DLL_DEPORD = define TOOL_GCC4MACHO_LINK_DLL_CMDS $(QUIET)$(APPEND) -n $(outbase).rsp $(objs) $(QUIET)$(TOOL_GCC4MACHO_LD) $(TOOL_GCC4MACHO_LDFLAGS.dll) $(flags) -o $(out)\ $(call TOOL_GCC4MACHO_LD_SONAME,$(target),$(out))\ -filelist $(outbase).rsp\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib))) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GCC4MACHO_DSYMUTIL) -o $(out).dSYM/ $(out) $(QUIET)$(TOOL_GCC4MACHO_STRIP_DLL) $(out) endif endef ## Link system module (windows aka driver, linux aka kernel module) # @param $(target) Normalized main target name. # @param $(out) System module name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC4MACHO_LINK_SYSMOD_OUTPUT = $(outbase).rsp TOOL_GCC4MACHO_LINK_SYSMOD_OUTPUT_DEBUG = $(call TOOL_GCC4MACHO_DEBUG_BUNDLE_FN,$(out)) TOOL_GCC4MACHO_LINK_SYSMOD_DEBUG_INSTALL_FN = $(TOOL_GCC4MACHO_DEBUG_INSTALL_FN) TOOL_GCC4MACHO_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_GCC4MACHO_LINK_SYSMOD_DEPORD = define TOOL_GCC4MACHO_LINK_SYSMOD_CMDS $(QUIET)$(APPEND) -n $(outbase).rsp $(objs) $(QUIET)$(TOOL_GCC4MACHO_LD_SYSMOD) $(TOOL_GCC4MACHO_LDFLAGS.sysmod) $(flags) -o $(out)\ -filelist $(outbase).rsp\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib))) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GCC4MACHO_DSYMUTIL) -o $(out).dSYM/ $(out) $(QUIET)$(TOOL_GCC4MACHO_STRIP_SYSMOD) $(out) endif endef kbuild-3149/kBuild/tools/FLEX.kmk0000644000175000017500000000312413252530250016515 0ustar locutuslocutus# $Id: FLEX.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # flex tool # # # Copyright (c) 2008-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_FLEX = flex TOOL_FLEX_LEX ?= flex$(HOSTSUFF_EXE) #TOOL_FLEX_LEXFLAGS ?= TOOL_FLEX_LEX_OUT_FILE = $(evalcall KB_FN_OPT_TEST_SHORT_LONG,+,--c++,$(flags),$(outbase).cpp,$(outbase).c) TOOL_FLEX_LEX_OUTPUT = TOOL_FLEX_LEX_OUTPUT_MAYBE = TOOL_FLEX_LEX_DEPEND = TOOL_FLEX_LEX_DEPORD = define TOOL_FLEX_LEX_CMDS $(QUIET)$(TOOL_FLEX_LEX) $(flags) -o$(out) $(source) endef kbuild-3149/kBuild/tools/LLVMGXX42MACHO.kmk0000644000175000017500000004720513252530251020047 0ustar locutuslocutus# $Id: LLVMGXX42MACHO.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - LLVM GCC v4.2.x targeting Darwin (Mac OS X) Mach-O, for building C++ code. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_LLVMGXX42MACHO := LLVM GCC v4.2.x targeting Darwin (Mac OS X) Mach-O, for building C++ code. # Tool Specific Properties TOOL_LLVMGXX42MACHO_PREFIX ?= llvm- TOOL_LLVMGXX42MACHO_SUFFIX ?= -4.2$(HOSTSUFF_EXE) TOOL_LLVMGXX42MACHO_CC ?= $(TOOL_LLVMGXX42MACHO_PREFIX)gcc$(TOOL_LLVMGXX42MACHO_SUFFIX) TOOL_LLVMGXX42MACHO_CXX ?= $(TOOL_LLVMGXX42MACHO_PREFIX)g++$(TOOL_LLVMGXX42MACHO_SUFFIX) TOOL_LLVMGXX42MACHO_OBJC ?= $(TOOL_LLVMGXX42MACHO_PREFIX)gcc$(TOOL_LLVMGXX42MACHO_SUFFIX) TOOL_LLVMGXX42MACHO_OBJCXX ?= $(TOOL_LLVMGXX42MACHO_PREFIX)gcc$(TOOL_LLVMGXX42MACHO_SUFFIX) TOOL_LLVMGXX42MACHO_AS ?= $(TOOL_LLVMGXX42MACHO_PREFIX)gcc$(TOOL_LLVMGXX42MACHO_SUFFIX) TOOL_LLVMGXX42MACHO_LD ?= $(TOOL_LLVMGXX42MACHO_PREFIX)g++$(TOOL_LLVMGXX42MACHO_SUFFIX) TOOL_LLVMGXX42MACHO_LD_SYSMOD ?= $(TOOL_LLVMGXX42MACHO_PREFIX)g++$(TOOL_LLVMGXX42MACHO_SUFFIX) ifndef TOOL_LLVMGXX42MACHO_LDFLAGS.$(KBUILD_TARGET) TOOL_LLVMGXX42MACHO_LDFLAGS.dll ?= -dynamiclib else TOOL_LLVMGXX42MACHO_LDFLAGS.dll ?= $(TOOL_LLVMGXX42MACHO_LDFLAGS.$(KBUILD_TARGET)) endif TOOL_LLVMGXX42MACHO_LDFLAGS.sysmod ?= -r #TOOL_LLVMGXX42MACHO_LD_SONAME = -Wl,-dylib_install_name $(firstword $($(1)_SONAME.$(KBUILD_TARGET).$(KBUILD_TYPE)) $($(1)_SONAME.$(KBUILD_TARGET)) $($(1)_SONAME.$(KBUILD_TYPE)) $($(1)_SONAME) $(notdir $(2))) TOOL_LLVMGXX42MACHO_DSYMUTIL ?= dsymutil ifdef SLKRUNS TOOL_LLVMGXX42MACHO_CC += -fmessage-length=0 TOOL_LLVMGXX42MACHO_CXX += -fmessage-length=0 TOOL_LLVMGXX42MACHO_OBJC += -fmessage-length=0 TOOL_LLVMGXX42MACHO_OBJCXX += -fmessage-length=0 endif # General Properties used by kBuild TOOL_LLVMGXX42MACHO_COBJSUFF ?= .o TOOL_LLVMGXX42MACHO_CFLAGS ?= TOOL_LLVMGXX42MACHO_CFLAGS.debug ?= -g TOOL_LLVMGXX42MACHO_CFLAGS.profile ?= -O2 #-g -pg TOOL_LLVMGXX42MACHO_CFLAGS.release ?= -O2 TOOL_LLVMGXX42MACHO_CINCS ?= TOOL_LLVMGXX42MACHO_CDEFS ?= TOOL_LLVMGXX42MACHO_CXXOBJSUFF ?= .o TOOL_LLVMGXX42MACHO_CXXFLAGS ?= TOOL_LLVMGXX42MACHO_CXXFLAGS.debug ?= -g TOOL_LLVMGXX42MACHO_CXXFLAGS.profile ?= -O2 #-g -pg TOOL_LLVMGXX42MACHO_CXXFLAGS.release ?= -O2 TOOL_LLVMGXX42MACHO_CXXINCS ?= TOOL_LLVMGXX42MACHO_CXXDEFS ?= TOOL_LLVMGXX42MACHO_OBJCOBJSUFF ?= .o TOOL_LLVMGXX42MACHO_OBJCFLAGS ?= TOOL_LLVMGXX42MACHO_OBJCFLAGS.debug ?= -g TOOL_LLVMGXX42MACHO_OBJCFLAGS.profile?= -O2 #-g -pg TOOL_LLVMGXX42MACHO_OBJCFLAGS.release?= -O2 TOOL_LLVMGXX42MACHO_OBJCINCS ?= TOOL_LLVMGXX42MACHO_OBJCDEFS ?= TOOL_LLVMGXX42MACHO_OBJCXXOBJSUFF ?= .o TOOL_LLVMGXX42MACHO_OBJCXXFLAGS ?= TOOL_LLVMGXX42MACHO_OBJCXXFLAGS.debug ?= -g TOOL_LLVMGXX42MACHO_OBJCXXFLAGS.profile ?= -O2 #-g -pg TOOL_LLVMGXX42MACHO_OBJCXXFLAGS.release ?= -O2 TOOL_LLVMGXX42MACHO_OBJCXXINCS ?= TOOL_LLVMGXX42MACHO_OBJCXXDEFS ?= TOOL_LLVMGXX42MACHO_ASFLAGS ?= -x assembler-with-cpp TOOL_LLVMGXX42MACHO_ASFLAGS.debug ?= -g TOOL_LLVMGXX42MACHO_ASFLAGS.profile ?= -g TOOL_LLVMGXX42MACHO_ASOBJSUFF ?= .o TOOL_LLVMGXX42MACHO_AR ?= ar$(HOSTSUFF_EXE) TOOL_LLVMGXX42MACHO_ARFLAGS ?= -c -rs TOOL_LLVMGXX42MACHO_ARLIBSUFF ?= .a TOOL_LLVMGXX42MACHO_LDFLAGS ?= TOOL_LLVMGXX42MACHO_LDFLAGS.debug ?= -g TOOL_LLVMGXX42MACHO_LDFLAGS.profile ?= -g TOOL_LLVMGXX42MACHO_STRIP_PROGRAM ?= strip -SXxru TOOL_LLVMGXX42MACHO_STRIP_DLL ?= strip -Sxru TOOL_LLVMGXX42MACHO_STRIP_SYSMOD ?= strip -Sru ## # Calculate the files in the debug bundle. # @param 1 The whole output filename. # @param 2 The output filename sans suffix. TOOL_LLVMGXX42MACHO_DEBUG_BUNDLE_FN = \ $(1).dSYM/ \ $(1).dSYM/Contents/ \ $(1).dSYM/Contents/Resources/ \ $(1).dSYM/Contents/Resources/DWARF/ \ $(1).dSYM/Contents/Info.plist \ $(1).dSYM/Contents/Resources/DWARF/$(notdir $(1)) ## # Calculate the files in the debug bundle. # @param 1 The whole linker output filename. # @param 2 The linker output filename sans suffix. # @param 3 The desired install name (no dir slash). # @remarks The Info.plist has some reference to the original name, but gdb # does not care and only check for a symbol file in the DWARF # directory with the same name as the debugged module. TOOL_LLVMGXX42MACHO_DEBUG_INSTALL_FN= \ $(3).dSYM/ \ $(3).dSYM/Contents/ \ $(3).dSYM/Contents/Resources/ \ $(3).dSYM/Contents/Resources/DWARF/ \ $(1).dSYM/Contents/Info.plist=>$(3).dSYM/Contents/Info.plist \ $(1).dSYM/Contents/Resources/DWARF/$(notdir $(1))=>$(3).dSYM/Contents/Resources/DWARF/$(notdir $(3)) ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_LLVMGXX42MACHO_COMPILE_C_DEPEND = TOOL_LLVMGXX42MACHO_COMPILE_C_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_LLVMGXX42MACHO_COMPILE_C_USES_KOBJCACHE = 1 TOOL_LLVMGXX42MACHO_COMPILE_C_OUTPUT = $(outbase).i define TOOL_LLVMGXX42MACHO_COMPILE_C_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).i\ $(TOOL_LLVMGXX42MACHO_CC) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_LLVMGXX42MACHO_CC) -c\ $(flags) -fpreprocessed -x c\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_LLVMGXX42MACHO_COMPILE_C_OUTPUT = define TOOL_LLVMGXX42MACHO_COMPILE_C_CMDS $(QUIET)$(TOOL_LLVMGXX42MACHO_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KUSE_OBJCACHE ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_LLVMGXX42MACHO_COMPILE_CXX_DEPEND = TOOL_LLVMGXX42MACHO_COMPILE_CXX_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_LLVMGXX42MACHO_COMPILE_CXX_USES_KOBJCACHE = 1 TOOL_LLVMGXX42MACHO_COMPILE_CXX_OUTPUT = $(outbase).ii define TOOL_LLVMGXX42MACHO_COMPILE_CXX_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).ii\ $(TOOL_LLVMGXX42MACHO_CXX) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_LLVMGXX42MACHO_CXX) -c\ $(flags) -fpreprocessed -x c++\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_LLVMGXX42MACHO_COMPILE_CXX_OUTPUT = define TOOL_LLVMGXX42MACHO_COMPILE_CXX_CMDS $(QUIET)$(TOOL_LLVMGXX42MACHO_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile Objective-C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_LLVMGXX42MACHO_COMPILE_OBJC_DEPEND = TOOL_LLVMGXX42MACHO_COMPILE_OBJC_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_LLVMGXX42MACHO_COMPILE_OBJC_USES_KOBJCACHE = 1 TOOL_LLVMGXX42MACHO_COMPILE_OBJC_OUTPUT = $(outbase).mi define TOOL_LLVMGXX42MACHO_COMPILE_OBJC_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).ii\ $(TOOL_LLVMGXX42MACHO_OBJC) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_LLVMGXX42MACHO_OBJC) -c\ $(flags) -fpreprocessed -x objective-c \ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_LLVMGXX42MACHO_COMPILE_OBJC_OUTPUT = define TOOL_LLVMGXX42MACHO_COMPILE_OBJC_CMDS $(QUIET)$(TOOL_LLVMGXX42MACHO_OBJC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile Objective-C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_LLVMGXX42MACHO_COMPILE_OBJCXX_DEPEND = TOOL_LLVMGXX42MACHO_COMPILE_OBJCXX_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_LLVMGXX42MACHO_COMPILE_OBJCXX_USES_KOBJCACHE = 1 TOOL_LLVMGXX42MACHO_COMPILE_OBJCXX_OUTPUT = $(outbase).mii define TOOL_LLVMGXX42MACHO_COMPILE_OBJCXX_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).mii\ $(TOOL_LLVMGXX42MACHO_OBJCXX) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_LLVMGXX42MACHO_OBJCXX) -c\ $(flags) -fpreprocessed -x objective-c++ \ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_LLVMGXX42MACHO_COMPILE_OBJCXX_OUTPUT = define TOOL_LLVMGXX42MACHO_COMPILE_OBJCXX_CMDS $(QUIET)$(TOOL_LLVMGXX42MACHO_OBJCXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile Assembly source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. # TOOL_LLVMGXX42MACHO_COMPILE_AS_OUTPUT = TOOL_LLVMGXX42MACHO_COMPILE_AS_DEPEND = TOOL_LLVMGXX42MACHO_COMPILE_AS_DEPORD = define TOOL_LLVMGXX42MACHO_COMPILE_AS_CMDS $(QUIET)$(TOOL_LLVMGXX42MACHO_AS) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_LLVMGXX42MACHO_LINK_LIBRARY_OUTPUT = TOOL_LLVMGXX42MACHO_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_LLVMGXX42MACHO_LINK_LIBRARY_DEPORD = define TOOL_LLVMGXX42MACHO_LINK_LIBRARY_CMDS $(if $(strip $(objs)),$(call xargs,$(QUIET)$(TOOL_LLVMGXX42MACHO_AR) $(flags) $(out),$(objs))) $(foreach lib,$(othersrc)\ ,$(NL)$(TAB)$(call MSG_AR_MERGE,$(target),$(out),$(lib)) \ $(NL)$(TAB)$(QUIET)$(RM_EXT) -f $(dir $(outbase))ar.tmp.dir/* \ $(NL)$(TAB)$(QUIET)$(MKDIR) -p $(dir $(outbase))/ar.tmp.dir/ \ $(NL)$(TAB)$(QUIET)(cd $(dir $(outbase))ar.tmp.dir/ \ && $(TOOL_LLVMGXX42MACHO_AR) -x $(abspath $(lib)) \ && $(RM_EXT) -f ./__.SYMDEF* \ && $(TOOL_LLVMGXX42MACHO_AR) $(flags) $(out) *) \ $(NL)$(TAB)$(QUIET)$(RM_EXT) -f $(dir $(outbase))/ar.tmp.dir/* \ $(NL)$(TAB)$(QUIET)$(RMDIR) $(dir $(outbase))ar.tmp.dir/) endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_LLVMGXX42MACHO_LINK_PROGRAM_OUTPUT = $(outbase).rsp TOOL_LLVMGXX42MACHO_LINK_PROGRAM_OUTPUT_DEBUG = $(call TOOL_LLVMGXX42MACHO_DEBUG_BUNDLE_FN,$(out)) TOOL_LLVMGXX42MACHO_LINK_PROGRAM_DEBUG_INSTALL_FN = $(TOOL_LLVMGXX42MACHO_DEBUG_INSTALL_FN) TOOL_LLVMGXX42MACHO_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_LLVMGXX42MACHO_LINK_PROGRAM_DEPORD = define TOOL_LLVMGXX42MACHO_LINK_PROGRAM_CMDS $(QUIET)$(APPEND) -n $(outbase).rsp $(objs) $(QUIET)$(TOOL_LLVMGXX42MACHO_LD) $(flags) -o $(out)\ -filelist $(outbase).rsp\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib))) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_LLVMGXX42MACHO_DSYMUTIL) -o $(out).dSYM/ $(out) $(QUIET)$(TOOL_LLVMGXX42MACHO_STRIP_PROGRAM) $(out) endif endef ## Link DLL # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_LLVMGXX42MACHO_LINK_DLL_OUTPUT = $(outbase).rsp TOOL_LLVMGXX42MACHO_LINK_DLL_OUTPUT_DEBUG = $(call TOOL_LLVMGXX42MACHO_DEBUG_BUNDLE_FN,$(out)) TOOL_LLVMGXX42MACHO_LINK_DLL_DEBUG_INSTALL_FN = $(TOOL_LLVMGXX42MACHO_DEBUG_INSTALL_FN) TOOL_LLVMGXX42MACHO_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_LLVMGXX42MACHO_LINK_DLL_DEPORD = define TOOL_LLVMGXX42MACHO_LINK_DLL_CMDS $(QUIET)$(APPEND) -n $(outbase).rsp $(objs) $(QUIET)$(TOOL_LLVMGXX42MACHO_LD) $(TOOL_LLVMGXX42MACHO_LDFLAGS.dll) $(flags) -o $(out)\ $(call TOOL_LLVMGXX42MACHO_LD_SONAME,$(target),$(out))\ -filelist $(outbase).rsp\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib))) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_LLVMGXX42MACHO_DSYMUTIL) -o $(out).dSYM/ $(out) $(QUIET)$(TOOL_LLVMGXX42MACHO_STRIP_DLL) $(out) endif endef ## Link system module (windows aka driver, linux aka kernel module) # @param $(target) Normalized main target name. # @param $(out) System module name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_LLVMGXX42MACHO_LINK_SYSMOD_OUTPUT = $(outbase).rsp TOOL_LLVMGXX42MACHO_LINK_SYSMOD_OUTPUT_DEBUG = $(call TOOL_LLVMGXX42MACHO_DEBUG_BUNDLE_FN,$(out)) TOOL_LLVMGXX42MACHO_LINK_SYSMOD_DEBUG_INSTALL_FN = $(TOOL_LLVMGXX42MACHO_DEBUG_INSTALL_FN) TOOL_LLVMGXX42MACHO_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_LLVMGXX42MACHO_LINK_SYSMOD_DEPORD = define TOOL_LLVMGXX42MACHO_LINK_SYSMOD_CMDS $(QUIET)$(APPEND) -n $(outbase).rsp $(objs) $(QUIET)$(TOOL_LLVMGXX42MACHO_LD_SYSMOD) $(TOOL_LLVMGXX42MACHO_LDFLAGS.sysmod) $(flags) -o $(out)\ -filelist $(outbase).rsp\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib))) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_LLVMGXX42MACHO_DSYMUTIL) -o $(out).dSYM/ $(out) $(QUIET)$(TOOL_LLVMGXX42MACHO_STRIP_SYSMOD) $(out) endif endef kbuild-3149/kBuild/tools/GXX3.kmk0000644000175000017500000003316713252530251016523 0ustar locutuslocutus# $Id: GXX3.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - Generic GCC v3.2.x using the system GCC and Binutils, for building C++ code. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_GXX3 := Generic GCC v3.2.x or later using the system GCC and Binutils, for building C++ code. # Tool Specific Properties TOOL_GXX3_CC ?= gcc$(HOSTSUFF_EXE) TOOL_GXX3_CXX ?= g++$(HOSTSUFF_EXE) TOOL_GXX3_AS ?= gcc$(HOSTSUFF_EXE) ifeq ($(KBUILD_TARGET),solaris) TOOL_GXX3_AR ?= gar$(HOSTSUFF_EXE) else TOOL_GXX3_AR ?= ar$(HOSTSUFF_EXE) endif ifeq ($(KBUILD_TARGET),os2) TOOL_GXX3_AR_IMP ?= emximp$(HOSTSTUFF_EXE) else TOOL_GXX3_AR_IMP ?= $(ECHO) not supported! endif TOOL_GXX3_LD ?= g++$(HOSTSUFF_EXE) TOOL_GXX3_LD_SYSMOD ?= ld$(HOSTSUFF_EXE) ifndef TOOL_GXX3_LDFLAGS.$(KBUILD_TARGET) TOOL_GXX3_LDFLAGS.dll ?= -shared else TOOL_GXX3_LDFLAGS.dll ?= $(TOOL_GXX3_LDFLAGS.$(KBUILD_TARGET)) endif TOOL_GXX3_LDFLAGS.sysmod ?= -r TOOL_GXX3_LD_SONAME ?= -Wl,-soname=$(firstword $($(1)_SONAME.$(KBUILD_TARGET).$(KBUILD_TYPE)) $($(1)_SONAME.$(KBUILD_TARGET)) $($(1)_SONAME.$(KBUILD_TYPE)) $($(1)_SONAME) $(notdir $(2))) ifeq ($(KBUILD_TARGET),os2) TOOL_GXX3_LD_MAP ?= -Zmap=$(1) TOOL_GXX3_LD_SYSMOD_MAP ?= -Zmap=$(1) else TOOL_GXX3_LD_MAP ?= TOOL_GXX3_LD_SYSMOD_MAP ?= endif if1of ($(KBUILD_HOST), solaris) TOOL_GXX3_OBJCOPY ?= gobjcopy$(HOSTSUFF_EXE) else TOOL_GXX3_OBJCOPY ?= objcopy$(HOSTSUFF_EXE) endif ifdef SLKRUNS TOOL_GXX3_CC += -fmessage-length=0 TOOL_GXX3_CXX += -fmessage-length=0 endif # General Properties used by kBuild TOOL_GXX3_COBJSUFF ?= .o TOOL_GXX3_CFLAGS ?= TOOL_GXX3_CFLAGS.debug ?= -g TOOL_GXX3_CFLAGS.profile ?= -O2 #-g -pg TOOL_GXX3_CFLAGS.release ?= -O2 TOOL_GXX3_CINCS ?= TOOL_GXX3_CDEFS ?= TOOL_GXX3_CXXOBJSUFF ?= .o TOOL_GXX3_CXXOBJSUFF ?= .o TOOL_GXX3_CXXFLAGS ?= TOOL_GXX3_CXXFLAGS.debug ?= -g TOOL_GXX3_CXXFLAGS.profile ?= -O2 #-g -pg TOOL_GXX3_CXXFLAGS.release ?= -O2 TOOL_GXX3_CXXINCS ?= TOOL_GXX3_CXXDEFS ?= TOOL_GXX3_ASFLAGS ?= -x assembler-with-cpp TOOL_GXX3_ASFLAGS.debug ?= -g TOOL_GXX3_ASFLAGS.profile ?= -g TOOL_GXX3_ASOBJSUFF ?= .o TOOL_GXX3_ARFLAGS ?= cr TOOL_GXX3_ARLIBSUFF ?= .a TOOL_GXX3_LDFLAGS ?= TOOL_GXX3_LDFLAGS.debug ?= -g TOOL_GXX3_LDFLAGS.profile ?= -g ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GXX3_COMPILE_C_DEPEND = TOOL_GXX3_COMPILE_C_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GXX3_COMPILE_C_USES_KOBJCACHE = 1 TOOL_GXX3_COMPILE_C_OUTPUT = $(outbase).i define TOOL_GXX3_COMPILE_C_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).i\ $(TOOL_GXX3_CC) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GXX3_CC) -c\ $(flags) -fpreprocessed -x c\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GXX3_COMPILE_C_OUTPUT = define TOOL_GXX3_COMPILE_C_CMDS $(QUIET)$(TOOL_GXX3_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GXX3_COMPILE_CXX_DEPEND = TOOL_GXX3_COMPILE_CXX_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GXX3_COMPILE_CXX_USES_KOBJCACHE = 1 TOOL_GXX3_COMPILE_CXX_OUTPUT = $(outbase).ii define TOOL_GXX3_COMPILE_CXX_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).ii\ $(TOOL_GXX3_CXX) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GXX3_CXX) -c\ $(flags) -fpreprocessed -x c++\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GXX3_COMPILE_CXX_OUTPUT = define TOOL_GXX3_COMPILE_CXX_CMDS $(QUIET)$(TOOL_GXX3_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile Assembly source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. # TOOL_GXX3_COMPILE_AS_OUTPUT = TOOL_GXX3_COMPILE_AS_DEPEND = TOOL_GXX3_COMPILE_AS_DEPORD = define TOOL_GXX3_COMPILE_AS_CMDS $(QUIET)$(TOOL_GXX3_AS) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX3_LINK_LIBRARY_OUTPUT = $(out).ar-script TOOL_GXX3_LINK_LIBRARY_OUTPUT_MAYBE = $(outbase).imp.a TOOL_GXX3_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_GXX3_LINK_LIBRARY_DEPORD = define TOOL_GXX3_LINK_LIBRARY_CMDS $(QUIET)$(APPEND) $(out).ar-script 'CREATE $(out)' $(QUIET)$(APPEND) -n $(out).ar-script \ $(foreach o,$(objs), 'ADDMOD $(o)') \ $(foreach o,$(filter-out %.def %.imp %.dll,$(othersrc)), 'ADDLIB $(o)') $(if $(filter %.def %.imp %.dll,$(othersrc))\ ,$(TOOL_GXX3_AR_IMP) -o $(outbase).imp.a $(filter %.def %.imp %.dll,$(othersrc))\ $(NL)$(TAB)$(QUIET)$(APPEND) $(out).ar-script 'ADDLIB $(outbase).imp.a') $(QUIET)$(APPEND) $(out).ar-script 'SAVE' $(QUIET)$(APPEND) $(out).ar-script 'END' $(QUIET)$(REDIRECT) -rti $(out).ar-script -- $(TOOL_GXX3_AR) -M endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX3_LINK_PROGRAM_OUTPUT = TOOL_GXX3_LINK_PROGRAM_OUTPUT_MAYBE = $(outbase).map TOOL_GXX3_LINK_PROGRAM_OUTPUT_DEBUG = $(outbase).debug TOOL_GXX3_LINK_PROGRAM_DEBUG_INSTALL_FN = $(2).debug=>$(basename $(3)).debug TOOL_GXX3_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib)))\ $(filter %.def, $(othersrc)) TOOL_GXX3_LINK_PROGRAM_DEPORD = define TOOL_GXX3_LINK_PROGRAM_CMDS $(QUIET)$(TOOL_GXX3_LD) $(flags) -o $(out) $(objs)\ $(filter %.def, $(othersrc))\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\ $(call TOOL_GXX3_LD_MAP,$(outbase).map) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GXX3_OBJCOPY) --only-keep-debug $(out) $(outbase).debug $(QUIET)$(CHMOD) a-x $(outbase).debug $(QUIET)$(TOOL_GXX3_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out) endif endef ## Link DLL # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX3_LINK_DLL_OUTPUT = TOOL_GXX3_LINK_DLL_OUTPUT_MAYBE = $(outbase).map TOOL_GXX3_LINK_DLL_OUTPUT_DEBUG = $(outbase).debug TOOL_GXX3_LINK_DLL_DEBUG_INSTALL_FN = $(2).debug=>$(basename $(3)).debug TOOL_GXX3_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib)))\ $(filter %.def, $(othersrc)) TOOL_GXX3_LINK_DLL_DEPORD = define TOOL_GXX3_LINK_DLL_CMDS $(QUIET)$(TOOL_GXX3_LD) $(TOOL_GXX3_LDFLAGS.dll) $(flags) -o $(out)\ $(if $(filter-out win os2, $(KBUILD_TARGET)),$(call TOOL_GXX3_LD_SONAME,$(target),$(out)))\ $(objs)\ $(filter %.def, $(othersrc))\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\ $(call TOOL_GXX3_LD_MAP,$(outbase).map) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GXX3_OBJCOPY) --only-keep-debug $(out) $(outbase).debug $(QUIET)$(CHMOD) a-x $(outbase).debug $(QUIET)$(TOOL_GXX3_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out) endif endef ## Link system module (windows aka driver, linux aka kernel module) # @param $(target) Normalized main target name. # @param $(out) System module name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX3_LINK_SYSMOD_OUTPUT = TOOL_GXX3_LINK_SYSMOD_OUTPUT_MAYBE = $(outbase).map TOOL_GXX3_LINK_SYSMOD_OUTPUT_DEBUG = $(outbase).debug TOOL_GXX3_LINK_SYSMOD_DEBUG_INSTALL_FN = $(2).debug=>$(basename $(3)).debug TOOL_GXX3_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib)))\ $(filter %.def, $(othersrc)) TOOL_GXX3_LINK_SYSMOD_DEPORD = define TOOL_GXX3_LINK_SYSMOD_CMDS $(QUIET)$(TOOL_GXX3_LD_SYSMOD) $(TOOL_GXX3_LDFLAGS.sysmod) $(flags) -o $(out) $(objs)\ $(filter %.def, $(othersrc))\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\ $(call TOOL_GXX3_LD_SYSMOD_MAP,$(outbase).map) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GXX3_OBJCOPY) --only-keep-debug $(out) $(outbase).debug $(QUIET)$(CHMOD) a-x $(outbase).debug $(QUIET)$(TOOL_GXX3_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out) endif endef kbuild-3149/kBuild/tools/MASM600.kmk0000644000175000017500000000536413252530251016753 0ustar locutuslocutus# $Id: MASM600.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - MASM v6.00 # # # Copyright (c) 2008-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_MASM600 := Microsoft Macro Assembler v6.00 # Tool Specific Properties ifndef TOOL_MASM600_AS TOOL_MASM600_AS := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST)/masm/v6.00*/binp/ml$(HOSTSUFF_EXE)))) ifeq ($(TOOL_MASM600_AS),) TOOL_MASM600_AS := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_TRG)/masm/v6.00*/binp/ml$(HOSTSUFF_EXE)))) endif ifeq ($(TOOL_MASM600_AS),) TOOL_MASM600_AS := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS)/os2.x86/ddk/*/toolkits/masm60/binp/ml$(HOSTSUFF_EXE)))) endif ifeq ($(TOOL_MASM600_AS),) if1of ($(USER) $(USERNAME) $(LOGNAME), bird) TOOL_MASM600_AS := $(wildcard D:/dev/DDK/*/toolkits/masm60/binp/ML.EXE) endif endif endif ifeq ($(TOOL_MASM600_AS),) TOOL_MASM600_AS := $(firstword $(which ml$(HOSTSUFF_EXE)) path/notfound/ml$(HOSTSUFF_EXE)) endif # General Properties used by kBuild TOOL_MASM600_ASFLAGS ?= /nologo ## # @remarks MASM v5.10 has serious trouble, so play safe with v6.00 as well. # See MASM510.kmk for details. TOOL_MASM600_COMPILE_AS_OUTPUT = $(outbase).lst TOOL_MASM600_COMPILE_AS_DEPEND = TOOL_MASM600_COMPILE_AS_DEPORD = define TOOL_MASM600_COMPILE_AS_CMDS $(QUIET)$(REDIRECT) \ -c3 -c4 -c5 -c6 -c7 -c8 -c9 -c10 -c11 -c12 -c13 -c14 -c15 -c16 -c17 -c18 -c19 -Z \ -E 'INCLUDE=$(subst $(SP),,$(addsuffix ;,$(subst /,\,$(incs))))' \ -- \ $(subst /,\\,$(TOOL_MASM600_AS)) -c \ $(strip $(flags)) \ $(addprefix -D,$(defs)) \ -Fo$(subst /,\\,$(obj)) \ -Fl$(subst /,\\,$(outbase).lst) \ $(subst /,\\,$(source)) endef kbuild-3149/kBuild/tools/VCC100X86.kmk0000644000175000017500000004574613252530251017142 0ustar locutuslocutus# $Id: VCC100X86.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - Visual C++ 10.0 (aka Visual 2010 and MSC v16), targeting x86. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_VCC100X86 := Visual C++ 10.0 (aka Visual 2010 and MSC v16), targeting x86. # Tool Specific Properties ifndef PATH_TOOL_VCC100X86 PATH_TOOL_VCC100X86 := $(wildcard $(KBUILD_DEVTOOLS)/win.x86/vcc/v10*) ifeq ($(PATH_TOOL_VCC100X86),) PATH_TOOL_VCC100X86 := $(PATH_TOOL_VCC100) endif ifeq ($(PATH_TOOL_VCC100X86),) PATH_TOOL_VCC100X86 := $(PATH_TOOL_VCC100AMD64) endif ifeq ($(PATH_TOOL_VCC100X86),) PATH_TOOL_VCC100X86 := $(wildcard $(KBUILD_DEVTOOLS)/x86.win32/vcc/v10*) endif ifeq ($(PATH_TOOL_VCC100X86),) PATH_TOOL_VCC100X86 := $(wildcard $(KBUILD_DEVTOOLS)/win.amd64/vcc/v10*) endif ifneq ($(PATH_TOOL_VCC100X86),) PATH_TOOL_VCC100X86 := $(lastword $(sort $(PATH_TOOL_VCC100X86))) else $(warning kBuild: PATH_TOOL_VCC100X86 cannot be determined!) PATH_TOOL_VCC100X86 := $(KBUILD_DEVTOOLS)/x86.win/vcc/v10 endif else # Resolve any fancy stuff once and for all. PATH_TOOL_VCC100X86 := $(PATH_TOOL_VCC100X86) endif PATH_TOOL_VCC100X86_BIN ?= $(PATH_TOOL_VCC100X86)/bin PATH_TOOL_VCC100X86_LIB ?= $(PATH_TOOL_VCC100X86)/lib PATH_TOOL_VCC100X86_INC ?= $(PATH_TOOL_VCC100X86)/include PATH_TOOL_VCC100X86_ATLMFC ?= $(PATH_TOOL_VCC100X86)/atlmfc PATH_TOOL_VCC100X86_ATLMFC_INC ?= $(PATH_TOOL_VCC100X86_ATLMFC)/include PATH_TOOL_VCC100X86_ATLMFC_LIB ?= $(PATH_TOOL_VCC100X86_ATLMFC)/lib TOOL_VCC100X86_CC ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100X86_BIN)/cl.exe TOOL_VCC100X86_CXX ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100X86_BIN)/cl.exe TOOL_VCC100X86_AS ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100X86_BIN)/ml.exe #TOOL_VCC100X86_AR ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100X86_BIN)/lib.exe - just an exec wrapper for the below TOOL_VCC100X86_AR ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100X86_BIN)/link.exe /LIB TOOL_VCC100X86_LD ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100X86_BIN)/link.exe TOOL_VCC100X86_DUMPBIN ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100X86_BIN)/dumpbin.exe TOOL_VCC100X86_EDITBIN ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100X86_BIN)/editbin.exe TOOL_VCC100X86_RC ?= $(EXEC_X86_WIN32) $(call TOOL_VCC100_FN_FIND_SDK_TOOL,rc.exe,[Rr][Cc].[Ee][Xx][Ee],TOOL_VCC100_RC_CACHED) TOOL_VCC100X86_MT ?= $(EXEC_X86_WIN32) $(call TOOL_VCC100_FN_FIND_SDK_TOOL,mt.exe,[Mm][Tt].[Ee][Xx][Ee],TOOL_VCC100_MT_CACHED) ifdef TOOL_VCC100X86_USE_KSUBMIT ifeq ($(KBUILD_HOST),win) TOOL_VCC100X86_KSUBMIT ?= kmk_builtin_kSubmit --32-bit TOOL_VCC100X86_KSUBMIT_DD = $(TOOL_VCC100X86_KSUBMIT) -- endif endif # The following in duplicated in VCC100.kmk and VCC100X86.kmk. TOOL_VCC100_FN_FIND_SDK_TOOL_SUB = $(eval $3 := $(firstword \ $(if-expr defined(PATH_SDK_WINPSDK71_BIN), $(wildcard $(PATH_SDK_WINPSDK71_BIN)/$2)) \ $(if-expr defined(PATH_SDK_WINPSDK_BIN) , $(wildcard $(PATH_SDK_WINPSDK_BIN)/$2)) \ $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST)/sdk/*/[Bb][Ii][Nn]/$2)) \ $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST_ALT)/sdk/*/[Bb][Ii][Nn]/$2)) \ $1)) TOOL_VCC100_FN_FIND_SDK_TOOL = $(if-expr !defined($3),$(TOOL_VCC100_FN_FIND_SDK_TOOL_SUB),)$($3) ## Disabled fast DEP_IDB based dependencies. #VCC100X86_OLD_DEPS = 1 ## Constructs the correct .pdb name (the name is lowercased). # @param $(1) Base name, no extention. # @param $(2) The extension. TOOL_VCC100X86_PDB = $(dir $(1))$(tolower $(notdir $(1))).$(2) # General Properties used by kBuild TOOL_VCC100X86_COBJSUFF ?= .obj TOOL_VCC100X86_CFLAGS ?= -TC -nologo -Zi TOOL_VCC100X86_CFLAGS.debug ?= TOOL_VCC100X86_CFLAGS.dbgopt ?= -O2 TOOL_VCC100X86_CFLAGS.release ?= -O2 TOOL_VCC100X86_CFLAGS.profile ?= -O2 TOOL_VCC100X86_CINCS ?= $(PATH_TOOL_VCC100X86_INC) TOOL_VCC100X86_CDEFS ?= TOOL_VCC100X86_CXXOBJSUFF ?= .obj TOOL_VCC100X86_CXXFLAGS ?= -TP -nologo -Zi TOOL_VCC100X86_CXXFLAGS.debug ?= TOOL_VCC100X86_CXXFLAGS.dbgopt ?= -O2 TOOL_VCC100X86_CXXFLAGS.release ?= -O2 TOOL_VCC100X86_CXXFLAGS.profile ?= -O2 TOOL_VCC100X86_CXXINCS ?= $(PATH_TOOL_VCC100X86_INC) $(PATH_TOOL_VCC100X86_ATLMFC_INC) TOOL_VCC100X86_CXXDEFS ?= TOOL_VCC100X86_ASOBJSUFF ?= .obj TOOL_VCC100X86_RCOBJSUFF ?= .res TOOL_VCC100X86_RCINCS ?= $(PATH_TOOL_VCC100X86_INC) $(PATH_TOOL_VCC100X86_ATLMFC_INC) TOOL_VCC100X86_ARFLAGS ?= -nologo TOOL_VCC100X86_ARLIBSUFF ?= .lib TOOL_VCC100X86_LDFLAGS ?= -nologo -machine:x86 TOOL_VCC100X86_LDFLAGS.debug ?= -debug TOOL_VCC100X86_LDFLAGS.dbgopt ?= -debug TOOL_VCC100X86_LDFLAGS.profile ?= -debug TOOL_VCC100X86_LDFLAGS.release ?= ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC100X86_COMPILE_C_DEPEND = TOOL_VCC100X86_COMPILE_C_DEPORD = TOOL_VCC100X86_COMPILE_C_OUTPUT = TOOL_VCC100X86_COMPILE_C_OUTPUT_MAYBE = $(call TOOL_VCC100X86_PDB, $(outbase)-obj,pdb) $(call TOOL_VCC100X86_PDB, $(outbase)-obj,idb) ifdef TOOL_VCC100X86_KSUBMIT TOOL_VCC100X86_COMPILE_C_DONT_PURGE_OUTPUT = 1 # speed define TOOL_VCC100X86_COMPILE_C_CMDS $(QUIET)$(TOOL_VCC100X86_KSUBMIT) -P $(DEP_OBJ_INT) -f -s -q -o $(dep) -t $(obj) $(obj)\ -- $(TOOL_VCC100X86_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fd$(outbase)-obj.pdb \ -Fo$(obj)\ $(subst /,\\,$(abspath $(source))) endef else define TOOL_VCC100X86_COMPILE_C_CMDS $(QUIET)$(TOOL_VCC100X86_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fd$(outbase)-obj.pdb \ -Fo$(obj)\ $(subst /,\\,$(abspath $(source))) $(QUIET)$(DEP_OBJ) -f -s -q -o $(dep) -t $(obj) $(obj) endef endif # !TOOL_VCC100X86_KSUBMIT ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC100X86_COMPILE_CXX_DEPEND = $($(target)_1_VCC_PCH_FILE) TOOL_VCC100X86_COMPILE_CXX_DEPORD = TOOL_VCC100X86_COMPILE_CXX_OUTPUT = TOOL_VCC100X86_COMPILE_CXX_OUTPUT_MAYBE = $(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB)\ ,,$(call TOOL_VCC100X86_PDB, $(outbase)-obj,pdb) $(call TOOL_VCC100X86_PDB, $(outbase)-obj,idb)) ifdef TOOL_VCC100X86_KSUBMIT TOOL_VCC100X86_COMPILE_CXX_DONT_PURGE_OUTPUT = 1 # speed define TOOL_VCC100X86_COMPILE_CXX_CMDS $(QUIET)$(TOOL_VCC100X86_KSUBMIT) -P $(DEP_OBJ_INT) -f -s -q -o $(dep) -t $(obj) $(obj)\ -- $(TOOL_VCC100X86_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ $(if-expr defined($(target)_PCH_HDR)\ ,-FI$($(target)_PCH_HDR) -Yu$($(target)_PCH_HDR) -Fp$($(target)_1_VCC_PCH_FILE),)\ -Fd$(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB),$($(target)_1_VCC_COMMON_OBJ_PDB),$(outbase)-obj.pdb) \ -Fo$(obj)\ $(subst /,\\,$(abspath $(source))) endef else define TOOL_VCC100X86_COMPILE_CXX_CMDS $(QUIET)$(TOOL_VCC100X86_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ $(if-expr defined($(target)_PCH_HDR)\ ,-FI$($(target)_PCH_HDR) -Yu$($(target)_PCH_HDR) -Fp$($(target)_1_VCC_PCH_FILE),)\ -Fd$(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB),$($(target)_1_VCC_COMMON_OBJ_PDB),$(outbase)-obj.pdb) \ -Fo$(obj)\ $(subst /,\\,$(abspath $(source))) $(QUIET)$(DEP_OBJ) -f -s -q -o $(dep) -t $(obj) $(obj) endef endif # !TOOL_VCC100X86_KSUBMIT # # Helper tool for creating the precompiled C++ header. # # It only have the C++ compile bits and it's purpose is to skip bits # related _1_VCC_PCH_FILE and add -Yc. # TOOL_VCC100X86-PCH := Helper for creating precompiled header using CXX handling. TOOL_VCC100X86-PCH_EXTENDS := VCC100X86 TOOL_VCC100X86-PCH_CXXOBJSUFF := .obj TOOL_VCC100X86-PCH_CXXINCS = $(TOOL_VCC100X86_CXXINCS) TOOL_VCC100X86-PCH_CXXFLAGS.debug = $(TOOL_VCC100X86_CXXFLAGS.debug) TOOL_VCC100X86-PCH_CXXFLAGS.dbgopt = $(TOOL_VCC100X86_CXXFLAGS.dbgopt) TOOL_VCC100X86-PCH_CXXFLAGS.release = $(TOOL_VCC100X86_CXXFLAGS.release) TOOL_VCC100X86-PCH_CXXFLAGS.profile = $(TOOL_VCC100X86_CXXFLAGS.profile) TOOL_VCC100X86-PCH_COMPILE_CXX_DEPEND = $(NO_SUCH_VARIABLE) TOOL_VCC100X86-PCH_COMPILE_CXX_DEPORD = $(NO_SUCH_VARIABLE) TOOL_VCC100X86-PCH_COMPILE_CXX_OUTPUT = $($(target)_1_VCC_PCH_FILE) $($(target)_1_VCC_COMMON_OBJ_PDB) TOOL_VCC100X86-PCH_COMPILE_CXX_OUTPUT_MAYBE = $(NO_SUCH_VARIABLE) ifdef TOOL_VCC100X86_KSUBMIT define TOOL_VCC100X86-PCH_COMPILE_CXX_CMDS $(QUIET)$(TOOL_VCC100X86_KSUBMIT) --no-pch-caching -P $(DEP_OBJ_INT) -f -s -q -e .pch -o $(dep) -t $(obj) $(obj)\ -- $(TOOL_VCC100X86_CXX) -c -Yc\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fp$($(target)_1_VCC_PCH_FILE) \ -Fd$($(target)_1_VCC_COMMON_OBJ_PDB) \ -Fo$(obj)\ -TP \ $(subst /,\\,$(abspath $(source))) endef else define TOOL_VCC100X86-PCH_COMPILE_CXX_CMDS $(QUIET)$(TOOL_VCC100X86_CXX) -c -Yc\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fp$($(target)_1_VCC_PCH_FILE) \ -Fd$($(target)_1_VCC_COMMON_OBJ_PDB) \ -Fo$(obj)\ -TP \ $(subst /,\\,$(abspath $(source))) $(QUIET)$(DEP_OBJ) -f -s -q -e .pch -o $(dep) -t $(obj) $(obj) endef endif # !TOOL_VCC100X86_KSUBMIT ## @todo configure the assembler template. ## Compile resource source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC100X86_COMPILE_RC_DEPEND = TOOL_VCC100X86_COMPILE_RC_DEPORD = TOOL_VCC100X86_COMPILE_RC_OUTPUT = define TOOL_VCC100X86_COMPILE_RC_CMDS $(QUIET)$(TOOL_VCC100X86_RC) \ $(flags) $(addprefix /i, $(subst /,\\,$(incs))) $(addprefix /d, $(defs))\ /fo$(obj)\ $(subst /,\\,$(abspath $(source))) endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_VCC100X86_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_VCC100X86_LINK_LIBRARY_DEPORD = TOOL_VCC100X86_LINK_LIBRARY_OUTPUT = $(outbase).rsp TOOL_VCC100X86_LINK_LIBRARY_OUTPUT_MAYBE = $(outbase).lst $(outbase).exp $(outbase).pdb define TOOL_VCC100X86_LINK_LIBRARY_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs) \ $(filter-out %.def,$(othersrc))) \ $(addprefix /DEF:,$(filter %.def,$(othersrc))) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC100X86_KSUBMIT_DD) $(TOOL_VCC100X86_AR) $(flags) /OUT:$(out) @$(outbase).rsp endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_VCC100X86_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC100X86_LINK_PROGRAM_DEPORD = TOOL_VCC100X86_LINK_PROGRAM_OUTPUT = $(outbase).map $(outbase).rsp TOOL_VCC100X86_LINK_PROGRAM_OUTPUT_MAYBE = $(outbase).lib $(outbase).exp $(outbase).ilk $(out).manifest TOOL_VCC100X86_LINK_PROGRAM_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC100X86_LINK_PROGRAM_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb define TOOL_VCC100X86_LINK_PROGRAM_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC100X86_KSUBMIT_DD) $(TOOL_VCC100X86_LD) $(flags) \ /OUT:$(out) \ /MAPINFO:EXPORTS /INCREMENTAL:NO \ /MAP:$(outbase).map \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp ifndef TOOL_VCC100X86_NO_AUTO_MANIFEST $(QUIET)$(TEST) -f $(out).manifest -- \ $(TOOL_VCC100X86_MT) -manifest $(subst /,\\,$(out)).manifest -outputresource:$(subst /,\\,$(out)) endif endef ## Link DLL. # @param $(target) Normalized main target name. # @param $(out) DLL name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_VCC100X86_LINK_DLL_DEPEND = $(objs) $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC100X86_LINK_DLL_DEPORD = $(call DIRDEP,$(PATH_STAGE_LIB)) TOOL_VCC100X86_LINK_DLL_OUTPUT = $(outbase).map $(outbase).lib $(outbase).exp $(outbase).rsp TOOL_VCC100X86_LINK_DLL_OUTPUT_MAYBE = $(outbase).ilk $(out).manifest $(PATH_STAGE_LIB)/$(notdir $(outbase)).exp TOOL_VCC100X86_LINK_DLL_OUTPUT_MAYBE_PRECIOUS = $(PATH_STAGE_LIB)/$(notdir $(outbase)).lib TOOL_VCC100X86_LINK_DLL_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC100X86_LINK_DLL_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb define TOOL_VCC100X86_LINK_DLL_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC100X86_KSUBMIT_DD) $(TOOL_VCC100X86_LD) $(flags) \ /OUT:$(out) \ /IMPLIB:$(outbase).lib \ /MAPINFO:EXPORTS /INCREMENTAL:NO \ /MAP:$(outbase).map \ /DLL \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp ifndef TOOL_VCC100X86_NO_AUTO_MANIFEST $(QUIET)$(TEST) -f $(out).manifest -- \ $(TOOL_VCC100X86_MT) -manifest $(subst /,\\,$(out)).manifest '-outputresource:$(subst /,\\,$(out));#2' endif $(QUIET)$(TEST) -f $(outbase).lib -- $(KLIBTWEAKER_EXT) --clear-timestamps $(outbase).lib $(QUIET)$(CP) --changed --ignore-non-existing $(outbase).exp $(outbase).lib $(PATH_STAGE_LIB)/ $(eval _DIRS += $(PATH_STAGE_LIB)) endef ## Link system module (windows aka driver, linux aka kernel module) # @param $(target) Normalized main target name. # @param $(out) System module name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_VCC100X86_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC100X86_LINK_SYSMOD_DEPORD = TOOL_VCC100X86_LINK_SYSMOD_OUTPUT = $(outbase).map $(outbase).rsp TOOL_VCC100X86_LINK_SYSMOD_OUTPUT_MAYBE = $(outbase).lib $(outbase).exp $(outbase).ilk $(out).manifest TOOL_VCC100X86_LINK_SYSMOD_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC100X86_LINK_SYSMOD_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb define TOOL_VCC100X86_LINK_SYSMOD_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC100X86_KSUBMIT_DD) $(TOOL_VCC100X86_LD) $(flags) \ /OUT:$(out) \ /MAPINFO:EXPORTS /INCREMENTAL:NO \ /MAP:$(outbase).map \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp ifndef TOOL_VCC100X86_NO_AUTO_MANIFEST $(QUIET)$(TEST) -f $(out).manifest -- \ $(TOOL_VCC100X86_MT) -manifest $(subst /,\\,$(out)).manifest '-outputresource:$(subst /,\\,$(out));#2' endif endef kbuild-3149/kBuild/tools/WGET.kmk0000644000175000017500000000427013252530251016531 0ustar locutuslocutus# $Id: WGET.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - wget fetchers. # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_WGET := wget fetcher. # Tool Specific Properties ifndef TOOL_WGET_FETCH TOOL_WGET_FETCH := $(wildcard $(KBUILD_DEVTOOLS_HST)/wget/v*/wget$(HOSTSUFF_EXE)) ifneq ($(TOOL_WGET_FETCH),) TOOL_WGET_FETCH := $(wildcard $(KBUILD_DEVTOOLS_HST)/bin/wget$(HOSTSUFF_EXE)) endif ifneq ($(TOOL_WGET_FETCH),) TOOL_WGET_FETCH := $(lastword $(sort $(TOOL_WGET_FETCH))) else TOOL_WGET_FETCH := wget$(HOSTSUFF_EXE) endif else # Resolve any fancy stuff once and for all. TOOL_WGET_FETCH := $(TOOL_WGET_FETCH) endif # General Properties used by kBuild TOOL_WGET_FETCHFLAGS ?= --passive-ftp -t 5 -T 60 ## Fetch one file. # @param $(target) Normalized main target name. # @param $(source) The URI of the file. # @param $(flags) Flags. # @param $(out) The output file TOOL_WGET_FETCH_OUTPUT = TOOL_WGET_FETCH_DEPEND = TOOL_WGET_FETCH_DEPORD = define TOOL_WGET_FETCH_CMDS $(QUIET)$(TOOL_WGET_FETCH) $(flags) -P $(dir $(out)) $(source) endef kbuild-3149/kBuild/tools/GXX4MACHO.kmk0000644000175000017500000004544613252530251017277 0ustar locutuslocutus# $Id: GXX4MACHO.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - GCC v4 targeting Darwin (Mac OS X) Mach-O, for building C++ code. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_GXX4MACHO := GCC v4 targeting Darwin (Mac OS X) Mach-O, for building C++ code. # Tool Specific Properties TOOL_GXX4MACHO_PREFIX ?= TOOL_GXX4MACHO_SUFFIX ?= $(HOSTSUFF_EXE) TOOL_GXX4MACHO_CC ?= $(TOOL_GXX4MACHO_PREFIX)gcc$(TOOL_GXX4MACHO_SUFFIX) TOOL_GXX4MACHO_CXX ?= $(TOOL_GXX4MACHO_PREFIX)g++$(TOOL_GXX4MACHO_SUFFIX) TOOL_GXX4MACHO_OBJC ?= $(TOOL_GXX4MACHO_PREFIX)gcc$(TOOL_GXX4MACHO_SUFFIX) TOOL_GXX4MACHO_OBJCXX ?= $(TOOL_GXX4MACHO_PREFIX)gcc$(TOOL_GXX4MACHO_SUFFIX) TOOL_GXX4MACHO_AS ?= $(TOOL_GXX4MACHO_PREFIX)gcc$(TOOL_GXX4MACHO_SUFFIX) TOOL_GXX4MACHO_LD ?= $(TOOL_GXX4MACHO_PREFIX)g++$(TOOL_GXX4MACHO_SUFFIX) TOOL_GXX4MACHO_LD_SYSMOD ?= $(TOOL_GXX4MACHO_PREFIX)g++$(TOOL_GXX4MACHO_SUFFIX) ifndef TOOL_GXX4MACHO_LDFLAGS.$(KBUILD_TARGET) TOOL_GXX4MACHO_LDFLAGS.dll ?= -dynamiclib else TOOL_GXX4MACHO_LDFLAGS.dll ?= $(TOOL_GXX4MACHO_LDFLAGS.$(KBUILD_TARGET)) endif TOOL_GXX4MACHO_LDFLAGS.sysmod ?= -r #TOOL_GXX4MACHO_LD_SONAME = -Wl,-dylib_install_name $(firstword $($(1)_SONAME.$(KBUILD_TARGET).$(KBUILD_TYPE)) $($(1)_SONAME.$(KBUILD_TARGET)) $($(1)_SONAME.$(KBUILD_TYPE)) $($(1)_SONAME) $(notdir $(2))) TOOL_GXX4MACHO_DSYMUTIL ?= dsymutil ifdef SLKRUNS TOOL_GXX4MACHO_CC += -fmessage-length=0 TOOL_GXX4MACHO_CXX += -fmessage-length=0 TOOL_GXX4MACHO_OBJC += -fmessage-length=0 TOOL_GXX4MACHO_OBJCXX += -fmessage-length=0 endif # General Properties used by kBuild TOOL_GXX4MACHO_COBJSUFF ?= .o TOOL_GXX4MACHO_CFLAGS ?= TOOL_GXX4MACHO_CFLAGS.debug ?= -g TOOL_GXX4MACHO_CFLAGS.profile ?= -O2 #-g -pg TOOL_GXX4MACHO_CFLAGS.release ?= -O2 TOOL_GXX4MACHO_CINCS ?= TOOL_GXX4MACHO_CDEFS ?= TOOL_GXX4MACHO_CXXOBJSUFF ?= .o TOOL_GXX4MACHO_CXXFLAGS ?= TOOL_GXX4MACHO_CXXFLAGS.debug ?= -g TOOL_GXX4MACHO_CXXFLAGS.profile ?= -O2 #-g -pg TOOL_GXX4MACHO_CXXFLAGS.release ?= -O2 TOOL_GXX4MACHO_CXXINCS ?= TOOL_GXX4MACHO_CXXDEFS ?= TOOL_GXX4MACHO_OBJCOBJSUFF ?= .o TOOL_GXX4MACHO_OBJCFLAGS ?= TOOL_GXX4MACHO_OBJCFLAGS.debug ?= -g TOOL_GXX4MACHO_OBJCFLAGS.profile?= -O2 #-g -pg TOOL_GXX4MACHO_OBJCFLAGS.release?= -O2 TOOL_GXX4MACHO_OBJCINCS ?= TOOL_GXX4MACHO_OBJCDEFS ?= TOOL_GXX4MACHO_OBJCXXOBJSUFF ?= .o TOOL_GXX4MACHO_OBJCXXFLAGS ?= TOOL_GXX4MACHO_OBJCXXFLAGS.debug ?= -g TOOL_GXX4MACHO_OBJCXXFLAGS.profile ?= -O2 #-g -pg TOOL_GXX4MACHO_OBJCXXFLAGS.release ?= -O2 TOOL_GXX4MACHO_OBJCXXINCS ?= TOOL_GXX4MACHO_OBJCXXDEFS ?= TOOL_GXX4MACHO_ASFLAGS ?= -x assembler-with-cpp TOOL_GXX4MACHO_ASFLAGS.debug ?= -g TOOL_GXX4MACHO_ASFLAGS.profile ?= -g TOOL_GXX4MACHO_ASOBJSUFF ?= .o TOOL_GXX4MACHO_AR ?= ar$(HOSTSUFF_EXE) TOOL_GXX4MACHO_ARFLAGS ?= -c -rs TOOL_GXX4MACHO_ARLIBSUFF ?= .a TOOL_GXX4MACHO_LDFLAGS ?= TOOL_GXX4MACHO_LDFLAGS.debug ?= -g TOOL_GXX4MACHO_LDFLAGS.profile ?= -g TOOL_GXX4MACHO_STRIP_PROGRAM ?= strip -SXxru TOOL_GXX4MACHO_STRIP_DLL ?= strip -Sxru TOOL_GXX4MACHO_STRIP_SYSMOD ?= strip -Sru ## # Calculate the files in the debug bundle. # @param 1 The whole output filename. # @param 2 The output filename sans suffix. TOOL_GXX4MACHO_DEBUG_BUNDLE_FN = \ $(1).dSYM/ \ $(1).dSYM/Contents/ \ $(1).dSYM/Contents/Resources/ \ $(1).dSYM/Contents/Resources/DWARF/ \ $(1).dSYM/Contents/Info.plist \ $(1).dSYM/Contents/Resources/DWARF/$(notdir $(1)) ## # Calculate the files in the debug bundle. # @param 1 The whole linker output filename. # @param 2 The linker output filename sans suffix. # @param 3 The desired install name (no dir slash). # @remarks The Info.plist has some reference to the original name, but gdb # does not care and only check for a symbol file in the DWARF # directory with the same name as the debugged module. TOOL_GXX4MACHO_DEBUG_INSTALL_FN= \ $(3).dSYM/ \ $(3).dSYM/Contents/ \ $(3).dSYM/Contents/Resources/ \ $(3).dSYM/Contents/Resources/DWARF/ \ $(1).dSYM/Contents/Info.plist=>$(3).dSYM/Contents/Info.plist \ $(1).dSYM/Contents/Resources/DWARF/$(notdir $(1))=>$(3).dSYM/Contents/Resources/DWARF/$(notdir $(3)) ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GXX4MACHO_COMPILE_C_DEPEND = TOOL_GXX4MACHO_COMPILE_C_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GXX4MACHO_COMPILE_C_USES_KOBJCACHE = 1 TOOL_GXX4MACHO_COMPILE_C_OUTPUT = $(outbase).i define TOOL_GXX4MACHO_COMPILE_C_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).i\ $(TOOL_GXX4MACHO_CC) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GXX4MACHO_CC) -c\ $(flags) -fpreprocessed -x c\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GXX4MACHO_COMPILE_C_OUTPUT = define TOOL_GXX4MACHO_COMPILE_C_CMDS $(QUIET)$(TOOL_GXX4MACHO_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KUSE_OBJCACHE ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GXX4MACHO_COMPILE_CXX_DEPEND = TOOL_GXX4MACHO_COMPILE_CXX_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GXX4MACHO_COMPILE_CXX_USES_KOBJCACHE = 1 TOOL_GXX4MACHO_COMPILE_CXX_OUTPUT = $(outbase).ii define TOOL_GXX4MACHO_COMPILE_CXX_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).ii\ $(TOOL_GXX4MACHO_CXX) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GXX4MACHO_CXX) -c\ $(flags) -fpreprocessed -x c++\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GXX4MACHO_COMPILE_CXX_OUTPUT = define TOOL_GXX4MACHO_COMPILE_CXX_CMDS $(QUIET)$(TOOL_GXX4MACHO_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile Objective-C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GXX4MACHO_COMPILE_OBJC_DEPEND = TOOL_GXX4MACHO_COMPILE_OBJC_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GXX4MACHO_COMPILE_OBJC_USES_KOBJCACHE = 1 TOOL_GXX4MACHO_COMPILE_OBJC_OUTPUT = $(outbase).mi define TOOL_GXX4MACHO_COMPILE_OBJC_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).ii\ $(TOOL_GXX4MACHO_OBJC) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GXX4MACHO_OBJC) -c\ $(flags) -fpreprocessed -x objective-c \ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GXX4MACHO_COMPILE_OBJC_OUTPUT = define TOOL_GXX4MACHO_COMPILE_OBJC_CMDS $(QUIET)$(TOOL_GXX4MACHO_OBJC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile Objective-C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GXX4MACHO_COMPILE_OBJCXX_DEPEND = TOOL_GXX4MACHO_COMPILE_OBJCXX_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GXX4MACHO_COMPILE_OBJCXX_USES_KOBJCACHE = 1 TOOL_GXX4MACHO_COMPILE_OBJCXX_OUTPUT = $(outbase).mii define TOOL_GXX4MACHO_COMPILE_OBJCXX_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).mii\ $(TOOL_GXX4MACHO_OBJCXX) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GXX4MACHO_OBJCXX) -c\ $(flags) -fpreprocessed -x objective-c++ \ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GXX4MACHO_COMPILE_OBJCXX_OUTPUT = define TOOL_GXX4MACHO_COMPILE_OBJCXX_CMDS $(QUIET)$(TOOL_GXX4MACHO_OBJCXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile Assembly source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. # TOOL_GXX4MACHO_COMPILE_AS_OUTPUT = TOOL_GXX4MACHO_COMPILE_AS_DEPEND = TOOL_GXX4MACHO_COMPILE_AS_DEPORD = define TOOL_GXX4MACHO_COMPILE_AS_CMDS $(QUIET)$(TOOL_GXX4MACHO_AS) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX4MACHO_LINK_LIBRARY_OUTPUT = TOOL_GXX4MACHO_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_GXX4MACHO_LINK_LIBRARY_DEPORD = define TOOL_GXX4MACHO_LINK_LIBRARY_CMDS $(if $(strip $(objs)),$(call xargs,$(QUIET)$(TOOL_GXX4MACHO_AR) $(flags) $(out),$(objs))) $(foreach lib,$(othersrc)\ ,$(NL)$(TAB)$(call MSG_AR_MERGE,$(target),$(out),$(lib)) \ $(NL)$(TAB)$(QUIET)$(RM_EXT) -f $(dir $(outbase))ar.tmp.dir/* \ $(NL)$(TAB)$(QUIET)$(MKDIR) -p $(dir $(outbase))/ar.tmp.dir/ \ $(NL)$(TAB)$(QUIET)(cd $(dir $(outbase))ar.tmp.dir/ \ && $(TOOL_GXX4MACHO_AR) -x $(abspath $(lib)) \ && $(RM_EXT) -f ./__.SYMDEF* \ && $(TOOL_GXX4MACHO_AR) $(flags) $(out) *) \ $(NL)$(TAB)$(QUIET)$(RM_EXT) -f $(dir $(outbase))/ar.tmp.dir/* \ $(NL)$(TAB)$(QUIET)$(RMDIR) $(dir $(outbase))ar.tmp.dir/) endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX4MACHO_LINK_PROGRAM_OUTPUT = $(outbase).rsp TOOL_GXX4MACHO_LINK_PROGRAM_OUTPUT_DEBUG = $(call TOOL_GXX4MACHO_DEBUG_BUNDLE_FN,$(out)) TOOL_GXX4MACHO_LINK_PROGRAM_DEBUG_INSTALL_FN = $(TOOL_GXX4MACHO_DEBUG_INSTALL_FN) TOOL_GXX4MACHO_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_GXX4MACHO_LINK_PROGRAM_DEPORD = define TOOL_GXX4MACHO_LINK_PROGRAM_CMDS $(QUIET)$(APPEND) -n $(outbase).rsp $(objs) $(QUIET)$(TOOL_GXX4MACHO_LD) $(flags) -o $(out)\ -filelist $(outbase).rsp\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib))) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GXX4MACHO_DSYMUTIL) -o $(out).dSYM/ $(out) $(QUIET)$(TOOL_GXX4MACHO_STRIP_PROGRAM) $(out) endif endef ## Link DLL # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX4MACHO_LINK_DLL_OUTPUT = $(outbase).rsp TOOL_GXX4MACHO_LINK_DLL_OUTPUT_DEBUG = $(call TOOL_GXX4MACHO_DEBUG_BUNDLE_FN,$(out)) TOOL_GXX4MACHO_LINK_DLL_DEBUG_INSTALL_FN = $(TOOL_GXX4MACHO_DEBUG_INSTALL_FN) TOOL_GXX4MACHO_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_GXX4MACHO_LINK_DLL_DEPORD = define TOOL_GXX4MACHO_LINK_DLL_CMDS $(QUIET)$(APPEND) -n $(outbase).rsp $(objs) $(QUIET)$(TOOL_GXX4MACHO_LD) $(TOOL_GXX4MACHO_LDFLAGS.dll) $(flags) -o $(out)\ $(call TOOL_GXX4MACHO_LD_SONAME,$(target),$(out))\ -filelist $(outbase).rsp\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib))) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GXX4MACHO_DSYMUTIL) -o $(out).dSYM/ $(out) $(QUIET)$(TOOL_GXX4MACHO_STRIP_DLL) $(out) endif endef ## Link system module (windows aka driver, linux aka kernel module) # @param $(target) Normalized main target name. # @param $(out) System module name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX4MACHO_LINK_SYSMOD_OUTPUT = $(outbase).rsp TOOL_GXX4MACHO_LINK_SYSMOD_OUTPUT_DEBUG = $(call TOOL_GXX4MACHO_DEBUG_BUNDLE_FN,$(out)) TOOL_GXX4MACHO_LINK_SYSMOD_DEBUG_INSTALL_FN = $(TOOL_GXX4MACHO_DEBUG_INSTALL_FN) TOOL_GXX4MACHO_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_GXX4MACHO_LINK_SYSMOD_DEPORD = define TOOL_GXX4MACHO_LINK_SYSMOD_CMDS $(QUIET)$(APPEND) -n $(outbase).rsp $(objs) $(QUIET)$(TOOL_GXX4MACHO_LD_SYSMOD) $(TOOL_GXX4MACHO_LDFLAGS.sysmod) $(flags) -o $(out)\ -filelist $(outbase).rsp\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib))) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GXX4MACHO_DSYMUTIL) -o $(out).dSYM/ $(out) $(QUIET)$(TOOL_GXX4MACHO_STRIP_SYSMOD) $(out) endif endef kbuild-3149/kBuild/tools/OPENWATCOM-WL.kmk0000644000175000017500000001027613252530251017762 0ustar locutuslocutus# $Id: OPENWATCOM-WL.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - Open Watcom v1.4 and later, using wlink. # # @remarks wrc is untested, so are DLLs, and programs. # # Copyright (c) 2008-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_OPENWATCOM-WL = Open Watcom v1.4 and later, using wlink. TOOL_OPENWATCOM-WL_EXTENDS = OPENWATCOM TOOL_OPENWATCOM-WL_LDFLAGS ?= Option Quiet TOOL_OPENWATCOM-WL_LDFLAGS.dos ?= $(NO_SUCH_VARIABLE) TOOL_OPENWATCOM-WL_LDFLAGS.linux ?= $(NO_SUCH_VARIABLE) TOOL_OPENWATCOM-WL_LDFLAGS.nt ?= $(NO_SUCH_VARIABLE) TOOL_OPENWATCOM-WL_LDFLAGS.os2 ?= $(NO_SUCH_VARIABLE) TOOL_OPENWATCOM-WL_LDFLAGS.win ?= $(NO_SUCH_VARIABLE) TOOL_OPENWATCOM-WL_LINK_PROGRAM_OUTPUT = $(outbase).map $(outbase).rsp TOOL_OPENWATCOM-WL_LINK_PROGRAM_OUTPUT_MAYBE = $(outbase).sym TOOL_OPENWATCOM-WL_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_OPENWATCOM-WL_LINK_PROGRAM_DEPORD = define TOOL_OPENWATCOM-WL_LINK_PROGRAM_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(if $(flags),'$(flags)',) \ 'Name $(call TOOL_OPENWATCOM_FIX_SLASHES_SQ,$(out)$(if $(suffix $(out)),,.))' \ 'Option Map=$(call TOOL_OPENWATCOM_FIX_SLASHES_SQ,$(outbase)).map' \ $(foreach p,$(call TOOL_OPENWATCOM_FIX_SLASHES_SQ,$(libpath)),'LIBPath $p') \ $(foreach o,$(call TOOL_OPENWATCOM_FIX_SLASHES_SQ,$(filter-out %.res,$(objs)) $(othersrc)),'$(if $(filter %.lib %.a,$l),LIB,)File $o') \ $(foreach l,$(call TOOL_OPENWATCOM_FIX_SLASHES_SQ,$(libs)),'Library $l') $(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP_BD) \ $(TOOL_OPENWATCOM_WLINK) @$(outbase).rsp $(if $(filter %.res,$(objs)), $(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP) \ $(TOOL_OPENWATCOM_RC) \ $(filter -bt=%,$(flags)) \ /fe=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(out)) \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(filter %.res,$(objs)))) endef TOOL_OPENWATCOM-WL_LINK_DLL_OUTPUT = $(TOOL_OPENWATCOM-WL_LINK_PROGRAM_OUTPUT) TOOL_OPENWATCOM-WL_LINK_DLL_OUTPUT_MAYBE = $(TOOL_OPENWATCOM-WL_LINK_PROGRAM_OUTPUT_MAYBE) TOOL_OPENWATCOM-WL_LINK_DLL_DEPEND = $(TOOL_OPENWATCOM-WL_LINK_PROGRAM_DEPEND) TOOL_OPENWATCOM-WL_LINK_DLL_DEPORD = $(TOOL_OPENWATCOM-WL_LINK_PROGRAM_DEPORD) TOOL_OPENWATCOM-WL_LINK_DLL_CMDS = $(TOOL_OPENWATCOM-WL_LINK_PROGRAM_CMDS) TOOL_OPENWATCOM-WL_LINK_SYSMOD_OUTPUT = $(TOOL_OPENWATCOM-WL_LINK_PROGRAM_OUTPUT) TOOL_OPENWATCOM-WL_LINK_SYSMOD_OUTPUT_MAYBE = $(TOOL_OPENWATCOM-WL_LINK_PROGRAM_OUTPUT_MAYBE) TOOL_OPENWATCOM-WL_LINK_SYSMOD_DEPEND = $(TOOL_OPENWATCOM-WL_LINK_PROGRAM_DEPEND) TOOL_OPENWATCOM-WL_LINK_SYSMOD_DEPORD = $(TOOL_OPENWATCOM-WL_LINK_PROGRAM_DEPORD) TOOL_OPENWATCOM-WL_LINK_SYSMOD_CMDS = $(TOOL_OPENWATCOM-WL_LINK_PROGRAM_CMDS) TOOL_OPENWATCOM-WL_LINK_MISCBIN_OUTPUT = $(TOOL_OPENWATCOM-WL_LINK_PROGRAM_OUTPUT) TOOL_OPENWATCOM-WL_LINK_MISCBIN_OUTPUT_MAYBE = $(TOOL_OPENWATCOM-WL_LINK_PROGRAM_OUTPUT_MAYBE) TOOL_OPENWATCOM-WL_LINK_MISCBIN_DEPEND = $(TOOL_OPENWATCOM-WL_LINK_PROGRAM_DEPEND) TOOL_OPENWATCOM-WL_LINK_MISCBIN_DEPORD = $(TOOL_OPENWATCOM-WL_LINK_PROGRAM_DEPORD) TOOL_OPENWATCOM-WL_LINK_MISCBIN_CMDS = $(TOOL_OPENWATCOM-WL_LINK_PROGRAM_CMDS) kbuild-3149/kBuild/tools/OPENWATCOM.kmk0000644000175000017500000003617413252530251017447 0ustar locutuslocutus# $Id: OPENWATCOM.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - Open Watcom v1.4 and later. # # # Copyright (c) 2008-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_OPENWATCOM = Open Watcom v1.4 and later (generic) ifeq ($(PATH_TOOL_OPENWATCOM),) ifeq ($(PATH_TOOL_OPENWATCOM),) PATH_TOOL_OPENWATCOM := $(wildcard $(KBUILD_DEVTOOLS_HST)/openwatcom/v*) endif ifeq ($(PATH_TOOL_OPENWATCOM),) PATH_TOOL_OPENWATCOM := $(wildcard $(KBUILD_DEVTOOLS_TRG)/openwatcom/v*) endif ifeq ($(PATH_TOOL_OPENWATCOM),) PATH_TOOL_OPENWATCOM := $(wildcard $(KBUILD_DEVTOOLS)/common/openwatcom/v*) endif ifeq ($(PATH_TOOL_OPENWATCOM)$(KBUILD_HOST),os2) if1of ($(USER) $(USERNAME) $(LOGNAME), bird) PATH_TOOL_OPENWATCOM := $(wildcard d:/dev/Watcom/v1.*) endif endif PATH_TOOL_OPENWATCOM := $(firstword $(sort $(PATH_TOOL_OPENWATCOM))) # if not found, we'll enter 'pathless' mode. else # Resolve any fancy stuff once and for all. PATH_TOOL_OPENWATCOM := $(PATH_TOOL_OPENWATCOM) endif # Clear the feature indicator if not available on the current host. ifdef TOOL_OPENWATCOM_USE_KSUBMIT ifneq ($(KBUILD_HOST),win) override TOOL_OPENWATCOM_USE_KSUBMIT := endif endif ifneq ($(PATH_TOOL_OPENWATCOM),) TOOL_OPENWATCOM_PATHLESS := no ifeq ($(KBUILD_HOST),darwin) PATH_TOOL_OPENWATCOM_BIN = $(PATH_TOOL_OPENWATCOM)/binosx TOOL_OPENWATCOM_ENV_SETUP ?= $(REDIRECT) \ -E 'PATH=$(PATH_TOOL_OPENWATCOM_BIN):$(PATH_TOOL_OPENWATCOM)/binl:$(PATH_TOOL_OPENWATCOM)/binw:$(PATH)' \ -E 'WATCOM=$(PATH_TOOL_OPENWATCOM)' \ -E 'EDPATH=$(PATH_TOOL_OPENWATCOM)/EDDAT' \ -E 'LIB=$1' \ -E 'INCLUDE=' \ $2 -- else ifeq ($(KBUILD_HOST),freebsd) PATH_TOOL_OPENWATCOM_BIN = $(PATH_TOOL_OPENWATCOM)/binfbsd TOOL_OPENWATCOM_ENV_SETUP ?= $(REDIRECT) \ -E 'PATH=$(PATH_TOOL_OPENWATCOM_BIN):$(PATH_TOOL_OPENWATCOM)/binl:$(PATH_TOOL_OPENWATCOM)/binw:$(PATH)' \ -E 'WATCOM=$(PATH_TOOL_OPENWATCOM)' \ -E 'EDPATH=$(PATH_TOOL_OPENWATCOM)/EDDAT' \ -E 'LIB=$1' \ -E 'INCLUDE=' \ $2 -- else ifeq ($(KBUILD_HOST),linux) PATH_TOOL_OPENWATCOM_BIN = $(PATH_TOOL_OPENWATCOM)/binl TOOL_OPENWATCOM_ENV_SETUP ?= $(REDIRECT) \ -E 'PATH=$(PATH_TOOL_OPENWATCOM_BIN):$(PATH_TOOL_OPENWATCOM)/binw:$(PATH)' \ -E 'WATCOM=$(PATH_TOOL_OPENWATCOM)' \ -E 'EDPATH=$(PATH_TOOL_OPENWATCOM)/EDDAT' \ -E 'LIB=$1' \ -E 'INCLUDE=' \ $2 -- else ifeq ($(KBUILD_HOST),os2) PATH_TOOL_OPENWATCOM_BIN = $(PATH_TOOL_OPENWATCOM)/binp TOOL_OPENWATCOM_ENV_SETUP ?= $(REDIRECT) \ -E 'BEGINLIBPATH=$(PATH_TOOL_OPENWATCOM)/binp/dll;$(BEGINLIBPATH)' \ -E 'LIBPATHSTRICT=T' \ -E 'PATH=$(PATH_TOOL_OPENWATCOM_BIN);$(PATH_TOOL_OPENWATCOM)/binw;$(PATH)' \ -E 'WATCOM=$(PATH_TOOL_OPENWATCOM)' \ -E 'EDPATH=$(PATH_TOOL_OPENWATCOM)/EDDAT' \ -E 'LIB=$1' \ -E 'INCLUDE=' \ $2 -- else ifeq ($(KBUILD_HOST),solaris) PATH_TOOL_OPENWATCOM_BIN = $(PATH_TOOL_OPENWATCOM)/binsol TOOL_OPENWATCOM_ENV_SETUP ?= $(REDIRECT) \ -E 'PATH=$(PATH_TOOL_OPENWATCOM_BIN):$(PATH_TOOL_OPENWATCOM)/binl:$(PATH_TOOL_OPENWATCOM)/binw:$(PATH)' \ -E 'WATCOM=$(PATH_TOOL_OPENWATCOM)' \ -E 'EDPATH=$(PATH_TOOL_OPENWATCOM)/EDDAT' \ -E 'LIB=$1' \ -E 'INCLUDE=' \ $2 -- else PATH_TOOL_OPENWATCOM_BIN = $(PATH_TOOL_OPENWATCOM)/binnt TOOL_OPENWATCOM_ENV_SETUP ?= $(if-expr defined(TOOL_OPENWATCOM_USE_KSUBMIT),kmk_builtin_kSubmit --32-bit,$(REDIRECT)) \ -E 'PATH=$(PATH_TOOL_OPENWATCOM_BIN);$(PATH_TOOL_OPENWATCOM)/binw;$(PATH)' \ -E 'WATCOM=$(PATH_TOOL_OPENWATCOM)' \ -E 'EDPATH=$(PATH_TOOL_OPENWATCOM)/EDDAT' \ -E 'LIB=$1' \ -E 'INCLUDE=' \ $2 -- endif TOOL_OPENWATCOM_CC ?= $(PATH_TOOL_OPENWATCOM_BIN)/wcc386$(HOSTSUFF_EXE) TOOL_OPENWATCOM_CC16 ?= $(PATH_TOOL_OPENWATCOM_BIN)/wcc$(HOSTSUFF_EXE) TOOL_OPENWATCOM_CXX ?= $(PATH_TOOL_OPENWATCOM_BIN)/wpp386$(HOSTSUFF_EXE) TOOL_OPENWATCOM_CXX16 ?= $(PATH_TOOL_OPENWATCOM_BIN)/wpp$(HOSTSUFF_EXE) TOOL_OPENWATCOM_AS ?= $(PATH_TOOL_OPENWATCOM_BIN)/wasm$(HOSTSUFF_EXE) TOOL_OPENWATCOM_AR ?= $(PATH_TOOL_OPENWATCOM_BIN)/wlib$(HOSTSUFF_EXE) TOOL_OPENWATCOM_RC ?= $(PATH_TOOL_OPENWATCOM_BIN)/wrc$(HOSTSUFF_EXE) TOOL_OPENWATCOM_LD ?= $(PATH_TOOL_OPENWATCOM_BIN)/wcl386$(HOSTSUFF_EXE) TOOL_OPENWATCOM_LD16 ?= $(PATH_TOOL_OPENWATCOM_BIN)/wcl$(HOSTSUFF_EXE) TOOL_OPENWATCOM_WLINK ?= $(PATH_TOOL_OPENWATCOM_BIN)/wlink$(HOSTSUFF_EXE) else # Pathless, relies on the environment. TOOL_OPENWATCOM_PATHLESS := TOOL_OPENWATCOM_ENV_SETUP ?= $(REDIRECT) \ -E 'LIB=$1' \ -E 'INCLUDE=' \ $2 -- TOOL_OPENWATCOM_CC ?= wcc386$(HOSTSUFF_EXE) TOOL_OPENWATCOM_CC16 ?= wcc$(HOSTSUFF_EXE) TOOL_OPENWATCOM_CXX ?= wpp386$(HOSTSUFF_EXE) TOOL_OPENWATCOM_CXX16 ?= wpp$(HOSTSUFF_EXE) TOOL_OPENWATCOM_AS ?= wasm$(HOSTSUFF_EXE) TOOL_OPENWATCOM_AR ?= wlib$(HOSTSUFF_EXE) TOOL_OPENWATCOM_RC ?= wrc$(HOSTSUFF_EXE) TOOL_OPENWATCOM_LD ?= wcl386$(HOSTSUFF_EXE) TOOL_OPENWATCOM_LD16 ?= wcl$(HOSTSUFF_EXE) TOOL_OPENWATCOM_WLINK ?= wlink$(HOSTSUFF_EXE) endif if $(KBUILD_KMK_REVISION) >= 2747 TOOL_OPENWATCOM_ENV_SETUP_BD ?= $(call TOOL_OPENWATCOM_ENV_SETUP,$1, --wcc-brain-damage $2) else TOOL_OPENWATCOM_ENV_SETUP_BD ?= $(call TOOL_OPENWATCOM_ENV_SETUP,$1,$2) endif # Functions for changing slashes (SQ = single quoted). if1of ($(KBUILD_HOST), os2 win) TOOL_OPENWATCOM_FIX_SLASHES = $(subst /,\\,$1) TOOL_OPENWATCOM_FIX_SLASHES_SQ = $(subst /,\,$1) else TOOL_OPENWATCOM_FIX_SLASHES = $1 TOOL_OPENWATCOM_FIX_SLASHES_SQ = $1 endif # General Properties used by kBuild TOOL_OPENWATCOM_ASOBJSUFF ?= .obj TOOL_OPENWATCOM_ASFLAGS ?= -zq TOOL_OPENWATCOM_ASFLAGS.dos ?= -bt=dos TOOL_OPENWATCOM_ASFLAGS.os2 ?= -bt=os2 TOOL_OPENWATCOM_ASFLAGS.win ?= -bt=nt TOOL_OPENWATCOM_COBJSUFF ?= .obj TOOL_OPENWATCOM_CFLAGS ?= -zq TOOL_OPENWATCOM_CFLAGS.dos ?= -bt=dos TOOL_OPENWATCOM_CFLAGS.os2 ?= -bt=os2 TOOL_OPENWATCOM_CFLAGS.win ?= -bt=nt ifdef PATH_TOOL_OPENWATCOM TOOL_OPENWATCOM_CINCS ?= $(PATH_TOOL_OPENWATCOM)/h endif TOOL_OPENWATCOM_CXXOBJSUFF ?= .obj TOOL_OPENWATCOM_CXXFLAGS ?= -zq TOOL_OPENWATCOM_CXXFLAGS.dos ?= -bt=dos TOOL_OPENWATCOM_CXXFLAGS.os2 ?= -bt=os2 TOOL_OPENWATCOM_CXXFLAGS.win ?= -bt=nt ifdef PATH_TOOL_OPENWATCOM TOOL_OPENWATCOM_CXXINCS ?= $(PATH_TOOL_OPENWATCOM)/h endif TOOL_OPENWATCOM_RCOBJSUFF ?= .res TOOL_OPENWATCOM_RCFLAGS ?= -r TOOL_OPENWATCOM_RCFLAGS.os2 ?= -bt=os2 TOOL_OPENWATCOM_RCFLAGS.win ?= -bt=nt ifdef PATH_TOOL_OPENWATCOM TOOL_OPENWATCOM_RCINCS ?= $(PATH_TOOL_OPENWATCOM)/h endif TOOL_OPENWATCOM_ARFLAGS ?= -q TOOL_OPENWATCOM_ARLIBSUFF ?= .lib TOOL_OPENWATCOM_LDFLAGS ?= -zq -y TOOL_OPENWATCOM_LDFLAGS.dos ?= -bt=dos TOOL_OPENWATCOM_LDFLAGS.os2 ?= -bt=os2 TOOL_OPENWATCOM_LDFLAGS.win ?= -bt=nt TOOL_OPENWATCOM_COMPILE_AS_DEPEND = TOOL_OPENWATCOM_COMPILE_AS_DEPORD = TOOL_OPENWATCOM_COMPILE_AS_OUTPUT = TOOL_OPENWATCOM_COMPILE_AS_OUTPUT_MAYBE = $(obj).err ifdef TOOL_OPENWATCOM_USE_KSUBMIT define TOOL_OPENWATCOM_COMPILE_AS_CMDS $(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP_BD,, -P $(DEP_OBJ_INT) -s -f -q -o "$(dep)" -t "$(obj)" "$(obj)") \ $(TOOL_OPENWATCOM_AS) \ $(flags) \ $(addsuffix , $(addprefix -i=, $(call TOOL_OPENWATCOM_FIX_SLASHES,$(incs)))) \ $(addprefix -d, $(defs)) \ -fo=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(obj)) \ -fr=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(obj)).err \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(abspath $(source))) endef else define TOOL_OPENWATCOM_COMPILE_AS_CMDS $(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP_BD) $(TOOL_OPENWATCOM_AS) \ $(flags) \ $(addsuffix , $(addprefix -i=, $(call TOOL_OPENWATCOM_FIX_SLASHES,$(incs)))) \ $(addprefix -d, $(defs)) \ -fo=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(obj)) \ -fr=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(obj)).err \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(abspath $(source))) $(QUIET)$(DEP_OBJ) -s -f -q -o "$(dep)" -t "$(obj)" "$(obj)" endef endif TOOL_OPENWATCOM_COMPILE_C_DEPEND = TOOL_OPENWATCOM_COMPILE_C_DEPORD = TOOL_OPENWATCOM_COMPILE_C_OUTPUT = TOOL_OPENWATCOM_COMPILE_C_OUTPUT_MAYBE = $(obj).err ifdef TOOL_OPENWATCOM_USE_KSUBMIT define TOOL_OPENWATCOM_COMPILE_C_CMDS $(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP_BD,, -P $(DEP_OBJ_INT) -s -f -q -o "$(dep)" -t "$(obj)" "$(obj)") \ $(TOOL_OPENWATCOM_CC) \ $(flags) \ $(addsuffix , $(addprefix -i=, $(call TOOL_OPENWATCOM_FIX_SLASHES,$(incs)))) \ $(addprefix -d, $(defs)) \ -fo=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(obj)) \ -fr=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(obj)).err \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(abspath $(source))) endef else define TOOL_OPENWATCOM_COMPILE_C_CMDS $(QUIET) $(call TOOL_OPENWATCOM_ENV_SETUP_BD) $(TOOL_OPENWATCOM_CC) \ $(flags) \ $(addsuffix , $(addprefix -i=, $(call TOOL_OPENWATCOM_FIX_SLASHES,$(incs)))) \ $(addprefix -d, $(defs)) \ -fo=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(obj)) \ -fr=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(obj)).err \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(abspath $(source))) $(QUIET)$(DEP_OBJ) -s -f -q -o "$(dep)" -t "$(obj)" "$(obj)" endef endif TOOL_OPENWATCOM_COMPILE_CXX_DEPEND = TOOL_OPENWATCOM_COMPILE_CXX_DEPORD = TOOL_OPENWATCOM_COMPILE_CXX_OUTPUT = TOOL_OPENWATCOM_COMPILE_CXX_OUTPUT_MAYBE = $(obj).err ifdef TOOL_OPENWATCOM_USE_KSUBMIT define TOOL_OPENWATCOM_COMPILE_CXX_CMDS $(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP_BD,, -P $(DEP_OBJ_INT) -s -f -q -o "$(dep)" -t "$(obj)" "$(obj)") \ $(TOOL_OPENWATCOM_CXX) \ $(flags) \ $(addsuffix , $(addprefix -i=, $(call TOOL_OPENWATCOM_FIX_SLASHES,$(incs)))) \ $(addprefix -d, $(defs)) \ -fo=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(obj)) \ -fr=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(obj)).err \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(abspath $(source))) endef else define TOOL_OPENWATCOM_COMPILE_CXX_CMDS $(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP_BD) $(TOOL_OPENWATCOM_CXX) \ $(flags) \ $(addsuffix , $(addprefix -i=, $(call TOOL_OPENWATCOM_FIX_SLASHES,$(incs)))) \ $(addprefix -d, $(defs)) \ -fo=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(obj)) \ -fr=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(obj)).err \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(abspath $(source))) $(QUIET)$(DEP_OBJ) -s -f -q -o "$(dep)" -t "$(obj)" "$(obj)" endef endif TOOL_OPENWATCOM_COMPILE_RC_OUTPUT = TOOL_OPENWATCOM_COMPILE_RC_DEPEND = TOOL_OPENWATCOM_COMPILE_RC_DEPORD = define TOOL_OPENWATCOM_COMPILE_RC_CMDS $(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP) \ $(TOOL_OPENWATCOM_RC) -r\ $(flags) \ $(addprefix -i=, $(call TOOL_OPENWATCOM_FIX_SLASHES,$(incs))) \ $(addprefix -d, $(defs))\ -fo=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(obj)) \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(abspath $(source))) endef TOOL_OPENWATCOM_LINK_LIBRARY_OUTPUT = ## @todo $(outbase).rsp TOOL_OPENWATCOM_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_OPENWATCOM_LINK_LIBRARY_DEPORD = define TOOL_OPENWATCOM_LINK_LIBRARY_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp $(foreach obj,$(call TOOL_OPENWATCOM_FIX_SLASHES,$(objs) $(filter-out %.imp,$(othersrc))),'+"$(obj)"') $(if $(filter %.imp,$(othersrc)),$(SED) \ -e 's/;.*$(DOLLAR)$(DOLLAR)//g' \ -e 's/^[[:space:]][[:space:]]*//g' \ -e 's/[[:space:]][[:space:]]*$(DOLLAR)$(DOLLAR)//g' \ -e '/^[[:space:]]*$(DOLLAR)$(DOLLAR)/d' \ -e 's/[[:space:]][[:space:]]*/ /g' \ -e 's/\([^ ][^ ]*\) \([^ ][^ ]*\) \([^ ][^ ]*\) \([^ ][^ ]*\).*/++\1.\2.\3/' \ $(filter %.imp,$(othersrc)) \ --append $(outbase).rsp \ ) $(QUIET)$(TOOL_OPENWATCOM_ENV_SETUP_BD) $(TOOL_OPENWATCOM_AR) $(flags) $(call TOOL_OPENWATCOM_FIX_SLASHES,$(out)) @$(outbase).rsp endef TOOL_OPENWATCOM_LINK_PROGRAM_OUTPUT = $(outbase).map TOOL_OPENWATCOM_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_OPENWATCOM_LINK_PROGRAM_DEPORD = define TOOL_OPENWATCOM_LINK_PROGRAM_CMDS $(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP_BD,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \ $(TOOL_OPENWATCOM_LD) \ $(flags) \ -fe=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(out)) \ -fm=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(outbase).map) \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(filter-out %.res,$(objs))) \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(libs)) \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(othersrc)) $(if $(filter %.res,$(objs)), $(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP) \ $(TOOL_OPENWATCOM_RC) \ $(filter -bt=%,$(flags)) \ /fe=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(out)) \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(filter %.res,$(objs)))) endef TOOL_OPENWATCOM_LINK_DLL_OUTPUT = $(outbase).map TOOL_OPENWATCOM_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_OPENWATCOM_LINK_DLL_DEPORD = define TOOL_OPENWATCOM_LINK_DLL_CMDS $(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP_BD,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \ $(TOOL_OPENWATCOM_LD) \ $(flags) \ -fe=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(out)) \ -fm=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(outbase).map) \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(filter-out %.res,$(objs))) \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(libs)) \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(othersrc)) $(if $(filter %.res,$(objs)), $(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP) \ $(TOOL_OPENWATCOM_RC) \ $(filter -bt=%,$(flags)) \ /fe=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(out)) \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(filter %.res,$(objs)))) endef TOOL_OPENWATCOM_LINK_SYSMOD_OUTPUT = $(outbase).map TOOL_OPENWATCOM_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_OPENWATCOM_LINK_SYSMOD_DEPORD = define TOOL_OPENWATCOM_LINK_SYSMOD_CMDS $(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP_BD,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \ $(TOOL_OPENWATCOM_LD) \ $(flags) \ -fe=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(out)) \ -fm=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(outbase).map) \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(filter-out %.res,$(objs))) \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(libs)) \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(othersrc)) $(if $(filter %.res,$(objs)), $(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP) \ $(TOOL_OPENWATCOM_RC) \ $(filter -bt=%,$(flags)) \ /fe=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(out)) \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(filter %.res,$(objs)))) endef kbuild-3149/kBuild/tools/MASM510.kmk0000644000175000017500000001027013252530251016743 0ustar locutuslocutus# $Id: MASM510.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - MASM v5.10 # # # Copyright (c) 2008-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_MASM510 := Microsoft Macro Assembler v5.10 # Tool Specific Properties ifndef TOOL_MASM510_AS TOOL_MASM510_AS := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST)/masm/v5.10*/masm$(HOSTSUFF_EXE)))) ifeq ($(TOOL_MASM510_AS),) TOOL_MASM510_AS := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_TRG)/masm/v5.10*/masm$(HOSTSUFF_EXE)))) endif ifeq ($(TOOL_MASM510_AS),) TOOL_MASM510_AS := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS)/os2.x86/ddk/*/base/tools/masm$(HOSTSUFF_EXE)))) endif ifeq ($(TOOL_MASM510_AS),) TOOL_MASM510_AS := $(firstword $(rsort $(wildcard \ $(KBUILD_DEVTOOLS)/os2.x86/ddk/*/video/tools/os2.386/lx.386/bin/masm$(HOSTSUFF_EXE) \ $(KBUILD_DEVTOOLS)/os2.x86/ddk/*/base32/tools/os2.386/bin/masm$(HOSTSUFF_EXE) \ $(KBUILD_DEVTOOLS)/os2.x86/ddk/*/base32/tools/os2.386/lx.386/bin/masm$(HOSTSUFF_EXE) \ $(KBUILD_DEVTOOLS)/os2.x86/ddk/*/print/tools/os2.386/lx.386/bin/masm$(HOSTSUFF_EXE) \ $(KBUILD_DEVTOOLS)/os2.x86/ddk/*/wpshell/tools/os2.386/lx.386/bin/masm$(HOSTSUFF_EXE) \ $(KBUILD_DEVTOOLS)/os2.x86/ddk/*/mme/tools/os2.386/lx.386/bin/masm$(HOSTSUFF_EXE) \ ))) endif ifneq ($(TOOL_MASM510_AS),) TOOL_MASM510_AS := $(TOOL_MASM510_AS) endif endif ifeq ($(TOOL_MASM510_AS),) TOOL_MASM510_AS := $(firstword $(which masm$(HOSTSUFF_EXE)) path/notfound/masm$(HOSTSUFF_EXE)) endif # General Properties used by kBuild TOOL_MASM510_ASFLAGS ?= -t -z -Zd -Zi -t ## Compile Assembly source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. # # @remarks MASM v5.10 has severe length limitations in several places and will respond with # crashing when these are exceeded. Thus, we use MASM and INCLUDE to avoid exceeding # the command line length (and the MASM length). # The closing of file handles and zapping of environment is to make sure it doesn't # mess up due handles left behind by some device init or because the env is too big. TOOL_MASM510_COMPILE_AS_OUTPUT = $(outbase).lst TOOL_MASM510_COMPILE_AS_DEPEND = TOOL_MASM510_COMPILE_AS_DEPORD = define TOOL_MASM510_COMPILE_AS_CMDS $(QUIET)$(REDIRECT) \ -c3 -c4 -c5 -c6 -c7 -c8 -c9 -c10 -c11 -c12 -c13 -c14 -c15 -c16 -c17 -c18 -c19 -Z \ -E 'MASM=$(addprefix -D, $(subst /,\,$(defs)))' \ -E 'INCLUDE=$(subst $(SP),,$(addsuffix ;,$(subst /,\,$(incs))))' \ -- \ $(subst /,\\,$(TOOL_MASM510_AS)) $(strip $(flags)) '$(subst /,\,$(source),$(obj),$(outbase).lst);' endef kbuild-3149/kBuild/tools/YACC.kmk0000644000175000017500000000377513252530251016513 0ustar locutuslocutus# $Id: YACC.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # yacc tool # # # Copyright (c) 2009-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_YACC = yacc ifndef TOOL_YACC_YACC TOOL_YACC_YACC := $(firstword $(which byacc$(HOSTSUFF_EXE)) $(which yacc$(HOSTSUFF_EXE)) yacc$(HOSTSUFF_EXE)) endif #TOOL_YACC_YACCFLAGS ?= TOOL_YACC_YACC_OUTPUT = $(evalcall KB_FN_OPT_TEST_SHORT,d,$(flags),$(outbase).h$(substr $(suffix $(source)),3),) TOOL_YACC_YACC_OUTPUT_MAYBE = $(outbase).tab.c$(substr $(suffix $(source)),3) $(outbase).tab.h$(substr $(suffix $(source)),3) TOOL_YACC_YACC_DEPEND = TOOL_YACC_YACC_DEPORD = define TOOL_YACC_YACC_CMDS $(QUIET)$(TOOL_YACC_YACC) $(flags) -b $(outbase) $(source) $(QUIET)$(evalcall KB_FN_OPT_TEST_SHORT,d,$(flags),$(MV) -f -- $(outbase).tab.h$(substr $(suffix $(source)),3) $(outbase).h$(substr $(suffix $(source)),3),) $(QUIET)$(MV) -f -- $(outbase).tab.c$(substr $(suffix $(source)),3) $(out) endef kbuild-3149/kBuild/tools/GXX64.kmk0000644000175000017500000003235413252530251016607 0ustar locutuslocutus# $Id: GXX64.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - Generic 64-bit GCC v3.2.x or later using the system GCC, for building C++ code. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_GXX64 := Generic 64-bit GCC v3.2.x or later using the system GCC, for building C++ code. \ More or less Linux/ELF specfic. # Tool Specific Properties TOOL_GXX64_CC ?= gcc$(HOSTSUFF_EXE) -m64 TOOL_GXX64_CXX ?= g++$(HOSTSUFF_EXE) -m64 TOOL_GXX64_AS ?= gcc$(HOSTSUFF_EXE) -m64 TOOL_GXX64_AR ?= ar$(HOSTSUFF_EXE) TOOL_GXX64_LD ?= g++$(HOSTSUFF_EXE) -m64 TOOL_GXX64_LD_SYSMOD ?= ld$(HOSTSUFF_EXE) ifndef TOOL_GXX64_LDFLAGS.$(KBUILD_TARGET) TOOL_GXX64_LDFLAGS.dll ?= -shared else TOOL_GXX64_LDFLAGS.dll ?= $(TOOL_GXX64_LDFLAGS.$(KBUILD_TARGET)) endif TOOL_GXX64_LDFLAGS.sysmod ?= -r -m elf_x86_64$(if-expr "$(KBUILD_TARGET)" == "freebsd" || "$(KBUILD_TARGET)" == "gnukfbsd",_fbsd,) TOOL_GXX64_LD_SONAME ?= -Wl,-soname=$(firstword $($(1)_SONAME.$(KBUILD_TARGET).$(KBUILD_TYPE)) $($(1)_SONAME.$(KBUILD_TARGET)) $($(1)_SONAME.$(KBUILD_TYPE)) $($(1)_SONAME) $(notdir $(2))) ifeq ($(KBUILD_TARGET),os2) TOOL_GXX64_LD_MAP ?= -Zmap=$(1) else TOOL_GXX64_LD_MAP ?= endif ifeq ($(KBUILD_TARGET),os2) TOOL_GXX64_LD_SYSMOD_MAP ?= -Zmap=$(1) else TOOL_GXX64_LD_SYSMOD_MAP ?= endif if1of ($(KBUILD_HOST), solaris) TOOL_GXX64_OBJCOPY ?= gobjcopy$(HOSTSUFF_EXE) else TOOL_GXX64_OBJCOPY ?= objcopy$(HOSTSUFF_EXE) endif ifdef SLKRUNS TOOL_GXX64_CC += -fmessage-length=0 TOOL_GXX64_CXX += -fmessage-length=0 endif # General Properties used by kBuild TOOL_GXX64_COBJSUFF ?= .o TOOL_GXX64_CFLAGS ?= TOOL_GXX64_CFLAGS.debug ?= -g TOOL_GXX64_CFLAGS.profile ?= -O2 #-g -pg TOOL_GXX64_CFLAGS.release ?= -O2 TOOL_GXX64_CINCS ?= TOOL_GXX64_CDEFS ?= TOOL_GXX64_CXXOBJSUFF ?= .o TOOL_GXX64_CXXOBJSUFF ?= .o TOOL_GXX64_CXXFLAGS ?= TOOL_GXX64_CXXFLAGS.debug ?= -g TOOL_GXX64_CXXFLAGS.profile ?= -O2 #-g -pg TOOL_GXX64_CXXFLAGS.release ?= -O2 TOOL_GXX64_CXXINCS ?= TOOL_GXX64_CXXDEFS ?= TOOL_GXX64_ASFLAGS ?= -x assembler-with-cpp TOOL_GXX64_ASFLAGS.debug ?= -g TOOL_GXX64_ASFLAGS.profile ?= -g TOOL_GXX64_ASOBJSUFF ?= .o TOOL_GXX64_ARFLAGS ?= cr TOOL_GXX64_ARLIBSUFF ?= .a TOOL_GXX64_LDFLAGS ?= TOOL_GXX64_LDFLAGS.debug ?= -g TOOL_GXX64_LDFLAGS.profile ?= -g ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GXX64_COMPILE_C_DEPEND = TOOL_GXX64_COMPILE_C_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GXX64_COMPILE_C_USES_KOBJCACHE = 1 TOOL_GXX64_COMPILE_C_OUTPUT = $(outbase).i define TOOL_GXX64_COMPILE_C_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).i\ $(TOOL_GXX64_CC) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GXX64_CC) -c\ $(flags) -fpreprocessed -x c\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GXX64_COMPILE_C_OUTPUT = define TOOL_GXX64_COMPILE_C_CMDS $(QUIET)$(TOOL_GXX64_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GXX64_COMPILE_CXX_DEPEND = TOOL_GXX64_COMPILE_CXX_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GXX64_COMPILE_CXX_USES_KOBJCACHE = 1 TOOL_GXX64_COMPILE_CXX_OUTPUT = $(outbase).ii define TOOL_GXX64_COMPILE_CXX_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).ii\ $(TOOL_GXX64_CXX) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GXX64_CXX) -c\ $(flags) -fpreprocessed -x c++\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GXX64_COMPILE_CXX_OUTPUT = define TOOL_GXX64_COMPILE_CXX_CMDS $(QUIET)$(TOOL_GXX64_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile Assembly source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. # TOOL_GXX64_COMPILE_AS_OUTPUT = TOOL_GXX64_COMPILE_AS_DEPEND = TOOL_GXX64_COMPILE_AS_DEPORD = define TOOL_GXX64_COMPILE_AS_CMDS $(QUIET)$(TOOL_GXX64_AS) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX64_LINK_LIBRARY_OUTPUT = $(out).ar-script TOOL_GXX64_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_GXX64_LINK_LIBRARY_DEPORD = define TOOL_GXX64_LINK_LIBRARY_CMDS $(QUIET)$(APPEND) $(out).ar-script 'CREATE $(out)' $(QUIET)$(APPEND) -n $(out).ar-script \ $(foreach o,$(objs), 'ADDMOD $(o)') \ $(foreach o,$(othersrc), 'ADDLIB $(o)') $(QUIET)$(APPEND) $(out).ar-script 'SAVE' $(QUIET)$(APPEND) $(out).ar-script 'END' $(QUIET)$(REDIRECT) -rti $(out).ar-script -- $(TOOL_GXX64_AR) -M endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX64_LINK_PROGRAM_OUTPUT = TOOL_GXX64_LINK_PROGRAM_OUTPUT_MAYBE = $(outbase).map TOOL_GXX64_LINK_PROGRAM_OUTPUT_DEBUG = $(outbase).debug TOOL_GXX64_LINK_PROGRAM_DEBUG_INSTALL_FN = $(2).debug=>$(basename $(3)).debug TOOL_GXX64_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_GXX64_LINK_PROGRAM_DEPORD = define TOOL_GXX64_LINK_PROGRAM_CMDS $(QUIET)$(TOOL_GXX64_LD) $(flags) -o $(out) $(objs)\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\ $(call TOOL_GXX64_LD_MAP,$(outbase).map) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GXX64_OBJCOPY) --only-keep-debug $(out) $(outbase).debug $(QUIET)$(CHMOD) a-x $(outbase).debug $(QUIET)$(TOOL_GXX64_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out) endif endef ## Link DLL # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX64_LINK_DLL_OUTPUT = TOOL_GXX64_LINK_DLL_OUTPUT_MAYBE = $(outbase).map TOOL_GXX64_LINK_DLL_OUTPUT_DEBUG = $(outbase).debug TOOL_GXX64_LINK_DLL_DEBUG_INSTALL_FN = $(2).debug=>$(basename $(3)).debug TOOL_GXX64_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_GXX64_LINK_DLL_DEPORD = define TOOL_GXX64_LINK_DLL_CMDS $(QUIET)$(TOOL_GXX64_LD) $(TOOL_GXX64_LDFLAGS.dll) $(flags) -o $(out)\ $(if $(filter-out win os2, $(KBUILD_TARGET)),$(call TOOL_GXX64_LD_SONAME,$(target),$(out)))\ $(objs)\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\ $(call TOOL_GXX64_LD_MAP,$(outbase).map) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GXX64_OBJCOPY) --only-keep-debug $(out) $(outbase).debug $(QUIET)$(CHMOD) a-x $(outbase).debug $(QUIET)$(TOOL_GXX64_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out) endif endef ## Link system module (windows aka driver, linux aka kernel module) # @param $(target) Normalized main target name. # @param $(out) System module name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX64_LINK_SYSMOD_OUTPUT = TOOL_GXX64_LINK_SYSMOD_OUTPUT_MAYBE = $(outbase).map TOOL_GXX64_LINK_SYSMOD_OUTPUT_DEBUG = $(outbase).debug TOOL_GXX64_LINK_SYSMOD_DEBUG_INSTALL_FN = $(2).debug=>$(basename $(3)).debug TOOL_GXX64_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_GXX64_LINK_SYSMOD_DEPORD = define TOOL_GXX64_LINK_SYSMOD_CMDS $(QUIET)$(TOOL_GXX64_LD_SYSMOD) $(TOOL_GXX64_LDFLAGS.sysmod) $(flags) -o $(out) $(objs)\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\ $(call TOOL_GXX64_LD_SYSMOD_MAP,$(outbase).map) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GXX64_OBJCOPY) --only-keep-debug $(out) $(outbase).debug $(QUIET)$(CHMOD) a-x $(outbase).debug $(QUIET)$(TOOL_GXX64_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out) endif endef kbuild-3149/kBuild/tools/WATCOMC11C-16.kmk0000644000175000017500000001336513252530251017556 0ustar locutuslocutus# $Id: WATCOMC11C-16.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - Watcom C v11.0c, 16-bit targets. # # @remarks wrc is untested, so are DLLs, and programs. # # Copyright (c) 2008-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_WATCOMC11C-16 = Watcom C/C++ v11.0c - 16-bit targets. TOOL_WATCOMC11C-16_EXTENDS = WATCOMC11C TOOL_WATCOMC11C-16_ASFLAGS.win ?= -bt=windows TOOL_WATCOMC11C-16_CFLAGS.win ?= -bt=windows TOOL_WATCOMC11C-16_CXXFLAGS.win ?= -bt=windows TOOL_WATCOMC11C-16_RCFLAGS.win ?= -bt=windows TOOL_WATCOMC11C-16_LDFLAGS.win ?= -bt=windows TOOL_WATCOMC11C-16_COMPILE_C_DEPEND = TOOL_WATCOMC11C-16_COMPILE_C_DEPORD = TOOL_WATCOMC11C-16_COMPILE_C_OUTPUT = $(obj).err define TOOL_WATCOMC11C-16_COMPILE_C_CMDS $(QUIET) $(call TOOL_WATCOMC11C_ENV_SETUP_BD) $(TOOL_WATCOMC11C_CC16) \ $(flags) \ $(addsuffix , $(addprefix -i=, $(subst /,\\,$(incs)))) \ $(addprefix -d, $(defs)) \ -fo=$(subst /,\\,$(obj)) \ -fr=$(subst /,\\,$(obj)).err \ $(subst /,\\,$(abspath $(source))) $(QUIET)$(APPEND) -n $(obj).err ## @todo dependencies endef TOOL_WATCOMC11C-16_COMPILE_CXX_DEPEND = TOOL_WATCOMC11C-16_COMPILE_CXX_DEPORD = TOOL_WATCOMC11C-16_COMPILE_CXX_OUTPUT = $(obj).err define TOOL_WATCOMC11C-16_COMPILE_CXX_CMDS $(QUIET) $(call TOOL_WATCOMC11C_ENV_SETUP_BD) $(TOOL_WATCOMC11C_CXX16) \ $(flags) \ $(addsuffix , $(addprefix -i=, $(subst /,\\,$(incs)))) \ $(addprefix -d, $(defs)) \ -fo=$(subst /,\\,$(obj)) \ -fr=$(subst /,\\,$(obj)).err \ $(subst /,\\,$(abspath $(source))) $(QUIET)$(APPEND) -n $(obj).err ## @todo dependencies endef TOOL_WATCOMC11C-16_COMPILE_RC_OUTPUT = TOOL_WATCOMC11C-16_COMPILE_RC_DEPEND = TOOL_WATCOMC11C-16_COMPILE_RC_DEPORD = define TOOL_WATCOMC11C-16_COMPILE_RC_CMDS $(QUIET) $(call TOOL_WATCOMC11C_ENV_SETUP) \ $(TOOL_WATCOMC11C_RC) -r\ $(flags) \ $(addprefix -i=, $(subst /,\\,$(incs))) \ $(addprefix -d, $(defs))\ -fo=$(subst /,\\,$(obj)) \ $(subst /,\\,$(abspath $(source))) endef TOOL_WATCOMC11C-16_LINK_LIBRARY_OUTPUT = ## @todo $(outbase).rsp TOOL_WATCOMC11C-16_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_WATCOMC11C-16_LINK_LIBRARY_DEPORD = define TOOL_WATCOMC11C-16_LINK_LIBRARY_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp $(foreach obj,$(subst /,\,$(objs) $(othersrc)),'+"$(obj)"') $(QUIET)$(TOOL_WATCOMC11C_ENV_SETUP_BD) $(TOOL_WATCOMC11C_AR) $(flags) $(subst /,\\,$(out)) @$(outbase).rsp endef TOOL_WATCOMC11C-16_LINK_PROGRAM_OUTPUT = $(outbase).map TOOL_WATCOMC11C-16_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_WATCOMC11C-16_LINK_PROGRAM_DEPORD = define TOOL_WATCOMC11C-16_LINK_PROGRAM_CMDS $(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP_BD,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \ $(TOOL_WATCOMC11C_LD16) \ $(flags) \ -fe=$(subst /,\\,$(out)) \ -fm=$(subst /,\\,$(outbase).map) \ $(subst /,\\,$(filter-out %.res,$(objs))) \ $(subst /,\\,$(libs)) \ $(subst /,\\,$(othersrc)) $(if $(filter %.res,$(objs)), $(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP) \ $(TOOL_WATCOMC11C_RC) \ $(filter -bt=%,$(flags)) \ /fe=$(subst /,\\,$(out)) \ $(subst /,\\,$(filter %.res,$(objs)))) endef TOOL_WATCOMC11C-16_LINK_DLL_OUTPUT = $(outbase).map TOOL_WATCOMC11C-16_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_WATCOMC11C-16_LINK_DLL_DEPORD = define TOOL_WATCOMC11C-16_LINK_DLL_CMDS $(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP_BD,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \ $(TOOL_WATCOMC11C_LD16) \ $(flags) \ -fe=$(subst /,\\,$(out)) \ -fm=$(subst /,\\,$(outbase).map) \ $(subst /,\\,$(filter-out %.res,$(objs))) \ $(subst /,\\,$(libs)) \ $(subst /,\\,$(othersrc)) $(if $(filter %.res,$(objs)), $(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP) \ $(TOOL_WATCOMC11C_RC) \ $(filter -bt=%,$(flags)) \ /fe=$(subst /,\\,$(out)) \ $(subst /,\\,$(filter %.res,$(objs)))) endef TOOL_WATCOMC11C-16_LINK_SYSMOD_OUTPUT = $(outbase).map TOOL_WATCOMC11C-16_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_WATCOMC11C-16_LINK_SYSMOD_DEPORD = define TOOL_WATCOMC11C-16_LINK_SYSMOD_CMDS $(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP_BD,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \ $(TOOL_WATCOMC11C_LD16) \ $(flags) \ -fe=$(subst /,\\,$(out)) \ -fm=$(subst /,\\,$(outbase).map) \ $(subst /,\\,$(filter-out %.res,$(objs))) \ $(subst /,\\,$(libs)) \ $(subst /,\\,$(othersrc)) $(if $(filter %.res,$(objs)), $(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP) \ $(TOOL_WATCOMC11C_RC) \ $(filter -bt=%,$(flags)) \ /fe=$(subst /,\\,$(out)) \ $(subst /,\\,$(filter %.res,$(objs)))) endef kbuild-3149/kBuild/tools/VCC120AMD64.kmk0000644000175000017500000005216713252530251017325 0ustar locutuslocutus# $Id: VCC120AMD64.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - Visual C++ 12.0 (aka Visual 2013 and MSC v18), targeting AMD64. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_VCC120AMD64 := Visual C++ 12.0 (aka Visual 2013 and MSC v18), targeting AMD64 # Tool Specific Properties ifndef PATH_TOOL_VCC120AMD64 PATH_TOOL_VCC120AMD64 := $(wildcard $(KBUILD_DEVTOOLS)/win.x86/vcc/v12*) ifeq ($(PATH_TOOL_VCC120AMD64),) PATH_TOOL_VCC120AMD64 := $(PATH_TOOL_VCC120) endif ifeq ($(PATH_TOOL_VCC120AMD64),) PATH_TOOL_VCC120AMD64 := $(PATH_TOOL_VCC120X86) endif ifeq ($(PATH_TOOL_VCC120AMD64),) PATH_TOOL_VCC120AMD64 := $(wildcard $(KBUILD_DEVTOOLS)/win.x86/vcc/v12*) endif ifneq ($(PATH_TOOL_VCC120AMD64),) PATH_TOOL_VCC120AMD64 := $(lastword $(sort $(PATH_TOOL_VCC120AMD64))) else $(warning kBuild: PATH_TOOL_VCC120AMD64 cannot be determined!) PATH_TOOL_VCC120AMD64 := $(KBUILD_DEVTOOLS)/win.x86/vcc/v12 endif else # Resolve any fancy stuff once and for all. PATH_TOOL_VCC120AMD64 := $(PATH_TOOL_VCC120AMD64) endif if "$(KBUILD_HOST).$(KBUILD_HOST_ARCH)" == "win.amd64" && exists("$(PATH_TOOL_VCC120AMD64)/bin/amd64") # Missing in express edition. PATH_TOOL_VCC120AMD64_BIN ?= $(PATH_TOOL_VCC120AMD64)/bin/amd64 #$(error works now: $(PATH_TOOL_VCC120AMD64)/bin/amd64) else #$(error no joy: $(PATH_TOOL_VCC120AMD64)/bin/amd64) PATH_TOOL_VCC120AMD64_BIN_DLL ?= $(PATH_TOOL_VCC120AMD64)/bin PATH_TOOL_VCC120AMD64_BIN ?= $(PATH_TOOL_VCC120AMD64)/bin/x86_amd64 endif PATH_TOOL_VCC120AMD64_LIB ?= $(PATH_TOOL_VCC120AMD64)/lib/amd64 PATH_TOOL_VCC120AMD64_INC ?= $(PATH_TOOL_VCC120AMD64)/include PATH_TOOL_VCC120AMD64_ATLMFC ?= $(PATH_TOOL_VCC120AMD64)/atlmfc PATH_TOOL_VCC120AMD64_ATLMFC_INC ?= $(PATH_TOOL_VCC120AMD64_ATLMFC)/include PATH_TOOL_VCC120AMD64_ATLMFC_LIB ?= $(PATH_TOOL_VCC120AMD64_ATLMFC)/lib/amd64 TOOL_VCC120AMD64_CC ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC120AMD64_BIN)/cl.exe TOOL_VCC120AMD64_CXX ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC120AMD64_BIN)/cl.exe TOOL_VCC120AMD64_AS ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC120AMD64_BIN)/ml64.exe #TOOL_VCC120AMD64_AR ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC120AMD64_BIN)/lib.exe - just an exec wrapper for the below TOOL_VCC120AMD64_AR ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC120AMD64_BIN)/link.exe /LIB TOOL_VCC120AMD64_LD ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC120AMD64_BIN)/link.exe TOOL_VCC120AMD64_DUMPBIN ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC120AMD64_BIN)/dumpbin.exe TOOL_VCC120AMD64_EDITBIN ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC120AMD64_BIN)/editbin.exe TOOL_VCC120AMD64_RC ?= $(EXEC_X86_WIN32) $(call TOOL_VCC120_FN_FIND_SDK_TOOL,rc.exe,[Rr][Cc].[Ee][Xx][Ee],TOOL_VCC120_RC_CACHED) TOOL_VCC120AMD64_MT ?= $(EXEC_X86_WIN32) $(call TOOL_VCC120_FN_FIND_SDK_TOOL,mt.exe,[Mm][Tt].[Ee][Xx][Ee],TOOL_VCC120_MT_CACHED) ifdef TOOL_VCC120AMD64_USE_KSUBMIT ifeq ($(KBUILD_HOST),win) ifneq ($(substr $(PATH_TOOL_VCC120AMD64_BIN),-9),x86_amd64) TOOL_VCC120AMD64_KSUBMIT ?= kmk_builtin_kSubmit --64-bit ifdef PATH_TOOL_VCC120AMD64_BIN_DLL TOOL_VCC120AMD64_KSUBMIT += --prepend 'PATH=$(PATH_TOOL_VCC120AMD64_BIN_DLL)$(HOST_PATH_SEP)' endif TOOL_VCC120AMD64_KSUBMIT_DD = $(TOOL_VCC120AMD64_KSUBMIT) -- else # "fatal error C1902: Program database manager mismatch; please check your installation" when mixing with the 32-bit compiler. #TOOL_VCC120AMD64_KSUBMIT ?= kmk_builtin_kSubmit --32-bit #TOOL_VCC120AMD64_KSUBMIT_DD = $(TOOL_VCC120AMD64_KSUBMIT) -- endif endif else ifdef PATH_TOOL_VCC120AMD64_BIN_DLL TOOL_VCC120AMD64_KSUBMIT_DD = $(REDIRECT) --prepend 'PATH=$(PATH_TOOL_VCC120AMD64_BIN_DLL)$(HOST_PATH_SEP)' -- endif # The following in duplicated in VCC120.kmk and VCC120X86.kmk. TOOL_VCC120_FN_FIND_SDK_TOOL_SUB = $(eval $3 := $(firstword \ $(if-expr defined(PATH_SDK_WINPSDK71_BIN), $(wildcard $(PATH_SDK_WINPSDK71_BIN)/$2)) \ $(if-expr defined(PATH_SDK_WINPSDK_BIN) , $(wildcard $(PATH_SDK_WINPSDK_BIN)/$2)) \ $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST)/sdk/*/[Bb][Ii][Nn]/$2)) \ $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST_ALT)/sdk/*/[Bb][Ii][Nn]/$2)) \ $1)) TOOL_VCC120_FN_FIND_SDK_TOOL = $(if-expr !defined($3),$(TOOL_VCC120_FN_FIND_SDK_TOOL_SUB),)$($3) ## Disabled fast DEP_IDB based dependencies. #VCC120AMD64_OLD_DEPS = 1 ## Constructs the correct .pdb name (the name is lowercased). # @param $(1) Base name, no extention. # @param $(2) The extension. TOOL_VCC120AMD64_PDB = $(dir $(1))$(tolower $(notdir $(1))).$(2) # General Properties used by kBuild TOOL_VCC120AMD64_COBJSUFF ?= .obj TOOL_VCC120AMD64_CFLAGS ?= -TC -nologo -Zi TOOL_VCC120AMD64_CFLAGS.debug ?= TOOL_VCC120AMD64_CFLAGS.dbgopt ?= -O2 TOOL_VCC120AMD64_CFLAGS.release ?= -O2 TOOL_VCC120AMD64_CFLAGS.profile ?= -O2 TOOL_VCC120AMD64_CINCS ?= $(PATH_TOOL_VCC120AMD64_INC) TOOL_VCC120AMD64_CDEFS ?= TOOL_VCC120AMD64_CXXOBJSUFF ?= .obj TOOL_VCC120AMD64_CXXFLAGS ?= -TP -nologo -Zi TOOL_VCC120AMD64_CXXFLAGS.debug ?= TOOL_VCC120AMD64_CXXFLAGS.dbgopt ?= -O2 TOOL_VCC120AMD64_CXXFLAGS.release ?= -O2 TOOL_VCC120AMD64_CXXFLAGS.profile ?= -O2 TOOL_VCC120AMD64_CXXINCS ?= $(PATH_TOOL_VCC120AMD64_INC) $(PATH_TOOL_VCC120AMD64_ATLMFC_INC) TOOL_VCC120AMD64_CXXDEFS ?= TOOL_VCC120AMD64_ASOBJSUFF ?= .obj TOOL_VCC120AMD64_RCOBJSUFF ?= .res TOOL_VCC120AMD64_RCINCS ?= $(PATH_TOOL_VCC120AMD64_INC) $(PATH_TOOL_VCC120AMD64_ATLMFC_INC) TOOL_VCC120AMD64_ARFLAGS ?= -nologo -machine:amd64 TOOL_VCC120AMD64_ARLIBSUFF ?= .lib TOOL_VCC120AMD64_LDFLAGS ?= -nologo -machine:amd64 TOOL_VCC120AMD64_LDFLAGS.debug ?= -debug TOOL_VCC120AMD64_LDFLAGS.dbgopt ?= -debug TOOL_VCC120AMD64_LDFLAGS.profile ?= -debug TOOL_VCC120AMD64_LDFLAGS.release ?= ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC120AMD64_COMPILE_C_DEPEND = TOOL_VCC120AMD64_COMPILE_C_DEPORD = TOOL_VCC120AMD64_COMPILE_C_OUTPUT = TOOL_VCC120AMD64_COMPILE_C_OUTPUT_MAYBE = $(call TOOL_VCC120AMD64_PDB, $(outbase)-obj,pdb) $(call TOOL_VCC120AMD64_PDB, $(outbase)-obj,idb) ifdef TOOL_VCC120AMD64_KSUBMIT TOOL_VCC120AMD64_COMPILE_C_DONT_PURGE_OUTPUT := 1 # speed define TOOL_VCC120AMD64_COMPILE_C_CMDS $(QUIET)$(TOOL_VCC120AMD64_KSUBMIT) -P $(DEP_OBJ_INT) -f -s -q -o $(dep) -t $(obj) $(obj)\ -- $(TOOL_VCC120AMD64_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fd$(outbase)-obj.pdb \ -Fo$(obj)\ $(subst /,\\,$(abspath $(source))) endef else define TOOL_VCC120AMD64_COMPILE_C_CMDS $(QUIET)$(if-expr defined(PATH_TOOL_VCC120AMD64_BIN_DLL)\ ,$(REDIRECT) --prepend 'PATH=$(PATH_TOOL_VCC120AMD64_BIN_DLL)$(HOST_PATH_SEP)' -- ,)$(TOOL_VCC120AMD64_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fd$(outbase)-obj.pdb \ -Fo$(obj)\ $(subst /,\\,$(abspath $(source))) $(QUIET)$(DEP_OBJ) -f -s -q -o $(dep) -t $(obj) $(obj) endef endif # !TOOL_VCC120AMD64_KSUBMIT ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC120AMD64_COMPILE_CXX_DEPEND = $($(target)_1_VCC_PCH_FILE) TOOL_VCC120AMD64_COMPILE_CXX_DEPORD = TOOL_VCC120AMD64_COMPILE_CXX_OUTPUT = TOOL_VCC120AMD64_COMPILE_CXX_OUTPUT_MAYBE = $(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB)\ ,,$(call TOOL_VCC120AMD64_PDB, $(outbase)-obj,pdb) $(call TOOL_VCC120AMD64_PDB, $(outbase)-obj,idb)) ifdef TOOL_VCC120AMD64_KSUBMIT TOOL_VCC120AMD64_COMPILE_CXX_DONT_PURGE_OUTPUT := 1 # speed define TOOL_VCC120AMD64_COMPILE_CXX_CMDS $(QUIET)$(TOOL_VCC120AMD64_KSUBMIT) -P $(DEP_OBJ_INT) -f -s -q -o $(dep) -t $(obj) $(obj)\ -- $(TOOL_VCC120AMD64_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ $(if-expr defined($(target)_PCH_HDR)\ ,-FI$($(target)_PCH_HDR) -Yu$($(target)_PCH_HDR) -Fp$($(target)_1_VCC_PCH_FILE) -FS,)\ -Fd$(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB),$($(target)_1_VCC_COMMON_OBJ_PDB),$(outbase)-obj.pdb) \ -Fo$(obj)\ $(subst /,\\,$(abspath $(source))) endef else define TOOL_VCC120AMD64_COMPILE_CXX_CMDS $(QUIET)$(if-expr defined(PATH_TOOL_VCC120AMD64_BIN_DLL)\ ,$(REDIRECT) --prepend 'PATH=$(PATH_TOOL_VCC120AMD64_BIN_DLL)$(HOST_PATH_SEP)' -- ,)$(TOOL_VCC120AMD64_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ $(if-expr defined($(target)_PCH_HDR)\ ,-FI$($(target)_PCH_HDR) -Yu$($(target)_PCH_HDR) -Fp$($(target)_1_VCC_PCH_FILE) -FS,)\ -Fd$(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB),$($(target)_1_VCC_COMMON_OBJ_PDB),$(outbase)-obj.pdb) \ -Fo$(obj)\ $(subst /,\\,$(abspath $(source))) $(QUIET)$(DEP_OBJ) -f -s -q -o $(dep) -t $(obj) $(obj) endef endif # !TOOL_VCC120AMD64_KSUBMIT # # Helper tool for creating the precompiled C++ header. # # It only have the C++ compile bits and it's purpose is to skip bits # related _1_VCC_PCH_FILE and add -Yc. # TOOL_VCC120AMD64-PCH := Helper for creating precompiled header using CXX handling. TOOL_VCC120AMD64-PCH_EXTENDS := VCC120AMD64 TOOL_VCC120AMD64-PCH_CXXOBJSUFF := .obj TOOL_VCC120AMD64-PCH_CXXINCS = $(TOOL_VCC120AMD64_CXXINCS) TOOL_VCC120AMD64-PCH_CXXFLAGS = $(TOOL_VCC120AMD64_CXXFLAGS) -FS TOOL_VCC120AMD64-PCH_CXXFLAGS.debug = $(TOOL_VCC120AMD64_CXXFLAGS.debug) TOOL_VCC120AMD64-PCH_CXXFLAGS.dbgopt = $(TOOL_VCC120AMD64_CXXFLAGS.dbgopt) TOOL_VCC120AMD64-PCH_CXXFLAGS.release = $(TOOL_VCC120AMD64_CXXFLAGS.release) TOOL_VCC120AMD64-PCH_CXXFLAGS.profile = $(TOOL_VCC120AMD64_CXXFLAGS.profile) TOOL_VCC120AMD64-PCH_COMPILE_CXX_DEPEND = $(NO_SUCH_VARIABLE) TOOL_VCC120AMD64-PCH_COMPILE_CXX_DEPORD = $(NO_SUCH_VARIABLE) TOOL_VCC120AMD64-PCH_COMPILE_CXX_OUTPUT = $($(target)_1_VCC_PCH_FILE) $($(target)_1_VCC_COMMON_OBJ_PDB) TOOL_VCC120AMD64-PCH_COMPILE_CXX_OUTPUT_MAYBE = $(NO_SUCH_VARIABLE) ifdef TOOL_VCC120AMD64_KSUBMIT define TOOL_VCC120AMD64-PCH_COMPILE_CXX_CMDS $(QUIET)$(RM) -f -- $($(target)_1_VCC_PCH_FILE) $($(target)_1_VCC_COMMON_OBJ_PDB) $(QUIET)$(TOOL_VCC120AMD64_KSUBMIT) --no-pch-caching -P $(DEP_OBJ_INT) -f -s -q -e .pch -o $(dep) -t $(obj) $(obj)\ -- $(TOOL_VCC120AMD64_CXX) -c -Yc\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fp$($(target)_1_VCC_PCH_FILE) \ -Fd$($(target)_1_VCC_COMMON_OBJ_PDB) \ -Fo$(obj)\ -TP \ $(subst /,\\,$(abspath $(source))) endef else define TOOL_VCC120AMD64-PCH_COMPILE_CXX_CMDS $(QUIET)$(RM) -f -- $($(target)_1_VCC_PCH_FILE) $($(target)_1_VCC_COMMON_OBJ_PDB) $(QUIET)$(if-expr defined(PATH_TOOL_VCC120AMD64_BIN_DLL)\ ,$(REDIRECT) --prepend 'PATH=$(PATH_TOOL_VCC120AMD64_BIN_DLL)$(HOST_PATH_SEP)' -- ,)$(TOOL_VCC120AMD64_CXX) -c -Yc\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fp$($(target)_1_VCC_PCH_FILE) \ -Fd$($(target)_1_VCC_COMMON_OBJ_PDB) \ -Fo$(obj)\ -TP \ $(subst /,\\,$(abspath $(source))) $(QUIET)$(DEP_OBJ) -f -s -q -e .pch -o $(dep) -t $(obj) $(obj) endef endif # !TOOL_VCC120AMD64_KSUBMIT ## @todo configure the assembler template. ## Compile resource source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC120AMD64_COMPILE_RC_DEPEND = TOOL_VCC120AMD64_COMPILE_RC_DEPORD = TOOL_VCC120AMD64_COMPILE_RC_OUTPUT = ## @todo Fix kmk_redirect so we can use it for setting PATH without spawning a shell or two define TOOL_VCC120AMD64_COMPILE_RC_CMDS $(QUIET)$(if-expr defined(PATH_TOOL_VCC120AMD64_BIN_DLL)\ ,$(REDIRECT) --prepend 'PATH=$(PATH_TOOL_VCC120AMD64_BIN_DLL)$(HOST_PATH_SEP)' -- ,)$(TOOL_VCC120AMD64_RC) \ $(flags) $(addprefix /i, $(subst /,\\,$(incs))) $(addprefix /d, $(defs))\ /fo$(obj)\ $(subst /,\\,$(abspath $(source))) endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_VCC120AMD64_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_VCC120AMD64_LINK_LIBRARY_DEPORD = TOOL_VCC120AMD64_LINK_LIBRARY_OUTPUT = $(outbase).rsp TOOL_VCC120AMD64_LINK_LIBRARY_OUTPUT_MAYBE = $(outbase).lst $(outbase).exp $(outbase).pdb define TOOL_VCC120AMD64_LINK_LIBRARY_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs) \ $(filter-out %.def,$(othersrc))) \ $(addprefix /DEF:,$(filter %.def,$(othersrc))) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC120AMD64_KSUBMIT_DD) $(TOOL_VCC120AMD64_AR) $(flags) /OUT:$(out) @$(outbase).rsp endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_VCC120AMD64_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC120AMD64_LINK_PROGRAM_DEPORD = TOOL_VCC120AMD64_LINK_PROGRAM_OUTPUT = $(outbase).map $(outbase).rsp TOOL_VCC120AMD64_LINK_PROGRAM_OUTPUT_MAYBE = $(outbase).lib $(outbase).exp $(outbase).ilk $(out).manifest TOOL_VCC120AMD64_LINK_PROGRAM_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC120AMD64_LINK_PROGRAM_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb define TOOL_VCC120AMD64_LINK_PROGRAM_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC120AMD64_KSUBMIT_DD) $(TOOL_VCC120AMD64_LD) $(flags) \ /OUT:$(out) \ /MAPINFO:EXPORTS /INCREMENTAL:NO \ /MAP:$(outbase).map \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp ifndef TOOL_VCC120AMD64_NO_AUTO_MANIFEST $(QUIET)$(TEST) -f $(out).manifest -- \ $(TOOL_VCC120AMD64_MT) -manifest $(subst /,\\,$(out)).manifest -outputresource:$(subst /,\\,$(out)) endif endef ## Link DLL. # @param $(target) Normalized main target name. # @param $(out) DLL name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_VCC120AMD64_LINK_DLL_DEPEND = $(objs) $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC120AMD64_LINK_DLL_DEPORD = $(call DIRDEP,$(PATH_STAGE_LIB)) TOOL_VCC120AMD64_LINK_DLL_OUTPUT = $(outbase).map $(outbase).lib $(outbase).exp $(outbase).rsp TOOL_VCC120AMD64_LINK_DLL_OUTPUT_MAYBE = $(outbase).ilk $(out).manifest $(PATH_STAGE_LIB)/$(notdir $(outbase)).exp TOOL_VCC120AMD64_LINK_DLL_OUTPUT_MAYBE_PRECIOUS = $(PATH_STAGE_LIB)/$(notdir $(outbase)).lib TOOL_VCC120AMD64_LINK_DLL_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC120AMD64_LINK_DLL_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb define TOOL_VCC120AMD64_LINK_DLL_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC120AMD64_KSUBMIT_DD) $(TOOL_VCC120AMD64_LD) $(flags) \ /OUT:$(out) \ /IMPLIB:$(outbase).lib \ /MAPINFO:EXPORTS /INCREMENTAL:NO \ /MAP:$(outbase).map \ /DLL \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp ifndef TOOL_VCC120AMD64_NO_AUTO_MANIFEST $(QUIET)$(TEST) -f $(out).manifest -- \ $(TOOL_VCC120AMD64_MT) -manifest $(subst /,\\,$(out)).manifest '-outputresource:$(subst /,\\,$(out));#2' endif $(QUIET)$(TEST) -f $(outbase).lib -- $(KLIBTWEAKER_EXT) --clear-timestamps $(outbase).lib $(QUIET)$(CP) --changed -v --ignore-non-existing $(outbase).exp $(outbase).lib $(PATH_STAGE_LIB)/ $(eval _DIRS += $(PATH_STAGE_LIB)) endef ## Link system module (windows aka driver, linux aka kernel module) # @param $(target) Normalized main target name. # @param $(out) System module name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_VCC120AMD64_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC120AMD64_LINK_SYSMOD_DEPORD = TOOL_VCC120AMD64_LINK_SYSMOD_OUTPUT = $(outbase).map $(outbase).rsp TOOL_VCC120AMD64_LINK_SYSMOD_OUTPUT_MAYBE = $(outbase).lib $(outbase).exp $(outbase).ilk $(out).manifest TOOL_VCC120AMD64_LINK_SYSMOD_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC120AMD64_LINK_SYSMOD_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb define TOOL_VCC120AMD64_LINK_SYSMOD_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC120AMD64_KSUBMIT_DD) $(TOOL_VCC120AMD64_LD) $(flags) \ /OUT:$(out) \ /MAPINFO:EXPORTS /INCREMENTAL:NO \ /MAP:$(outbase).map \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp ifndef TOOL_VCC120AMD64_NO_AUTO_MANIFEST $(QUIET)$(TEST) -f $(out).manifest -- \ $(TOOL_VCC120AMD64_MT) -manifest $(subst /,\\,$(out)).manifest '-outputresource:$(subst /,\\,$(out));#2' endif endef kbuild-3149/kBuild/tools/VCC120.kmk0000644000175000017500000004471513252530251016631 0ustar locutuslocutus# $Id: VCC120.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - Visual C++ 12.0 (aka Visual 2013 and MSC v18), targeting $(KBUILD_TARGET). # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_VCC120 := Visual C++ 12.0 (aka Visual 2013 and MSC v18), targeting $(KBUILD_TARGET). # Tool Specific Properties ifndef PATH_TOOL_VCC120 PATH_TOOL_VCC120 := $(wildcard $(KBUILD_DEVTOOLS_TRG)/vcc/v12*) ifeq ($(PATH_TOOL_VCC120),) PATH_TOOL_VCC120 := $(wildcard $(KBUILD_DEVTOOLS)/win.x86/vcc/v12*) endif ifeq ($(PATH_TOOL_VCC120),) PATH_TOOL_VCC120 := $(wildcard $(KBUILD_DEVTOOLS)/x86.win32/vcc/v12*) endif ifeq ($(PATH_TOOL_VCC120),) PATH_TOOL_VCC120 := $(wildcard $(KBUILD_DEVTOOLS)/win.amd64/vcc/v12*) endif ifeq ($(PATH_TOOL_VCC120),) PATH_TOOL_VCC120 := $(lastword $(sort $(PATH_TOOL_VCC120))) endif # if not found, we'll enter 'pathless' mode. else # Resolve any fancy stuff once and for all. PATH_TOOL_VCC120 := $(PATH_TOOL_VCC120) endif ifneq ($(PATH_TOOL_VCC120),) if "$(KBUILD_HOST).$(KBUILD_HOST_ARCH)" == "win.amd64" && exists("$(PATH_TOOL_VCC120AMD64)/bin/amd64") # Missing in express edition. PATH_TOOL_VCC120_BIN.amd64 ?= $(PATH_TOOL_VCC120)/bin/amd64 else PATH_TOOL_VCC120_BIN.amd64 ?= $(PATH_TOOL_VCC120)/bin/x86_amd64 endif PATH_TOOL_VCC120_BIN.x86 ?= $(PATH_TOOL_VCC120)/bin PATH_TOOL_VCC120_BIN ?= $(PATH_TOOL_VCC120_BIN.$(KBUILD_TARGET_ARCH)) PATH_TOOL_VCC120_LIB.amd64 ?= $(PATH_TOOL_VCC120)/lib/amd64 PATH_TOOL_VCC120_LIB.x86 ?= $(PATH_TOOL_VCC120)/lib PATH_TOOL_VCC120_LIB ?= $(PATH_TOOL_VCC120_LIB.$(KBUILD_TARGET_ARCH)) PATH_TOOL_VCC120_INC ?= $(PATH_TOOL_VCC120)/include PATH_TOOL_VCC120_ATLMFC ?= $(PATH_TOOL_VCC120X86)/atlmfc PATH_TOOL_VCC120_ATLMFC_INC ?= $(PATH_TOOL_VCC120_ATLMFC)/include PATH_TOOL_VCC120_ATLMFC_LIB.amd64 ?= $(PATH_TOOL_VCC120_ATLMFC)/lib PATH_TOOL_VCC120_ATLMFC_LIB.x86 ?= $(PATH_TOOL_VCC120_ATLMFC)/lib/amd64 PATH_TOOL_VCC120_ATLMFC_LIB ?= $(PATH_TOOL_VCC120_ATLMFC_LIB.$(KBUILD_TARGET_ARCH)) TOOL_VCC120_CC ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC120_BIN)/cl.exe TOOL_VCC120_CXX ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC120_BIN)/cl.exe TOOL_VCC120_AS ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC120_BIN)/ml64.exe TOOL_VCC120_AR ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC120_BIN)/lib.exe TOOL_VCC120_LD ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC120_BIN)/link.exe TOOL_VCC120_DUMPBIN ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC120_BIN)/dumpbin.exe TOOL_VCC120_EDITBIN ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC120_BIN)/editbin.exe else # Pathless, relies on the environment. TOOL_VCC120_CC ?= $(EXEC_X86_WIN32) cl.exe TOOL_VCC120_CXX ?= $(EXEC_X86_WIN32) cl.exe TOOL_VCC120_AS ?= $(EXEC_X86_WIN32) ml64.exe TOOL_VCC120_AR ?= $(EXEC_X86_WIN32) lib.exe TOOL_VCC120_LD ?= $(EXEC_X86_WIN32) link.exe TOOL_VCC120_DUMPBIN ?= $(EXEC_X86_WIN32) dumpbin.exe TOOL_VCC120_EDITBIN ?= $(EXEC_X86_WIN32) editbin.exe endif TOOL_VCC120_RC ?= $(EXEC_X86_WIN32) $(call TOOL_VCC120_FN_FIND_SDK_TOOL,rc.exe,[Rr][Cc].[Ee][Xx][Ee],TOOL_VCC120_RC_CACHED) TOOL_VCC120_MT ?= $(EXEC_X86_WIN32) $(call TOOL_VCC120_FN_FIND_SDK_TOOL,mt.exe,[Mm][Tt].[Ee][Xx][Ee],TOOL_VCC120_MT_CACHED) # The following in duplicated in VCC120.kmk and VCC120X86.kmk. TOOL_VCC120_FN_FIND_SDK_TOOL_SUB = $(eval $3 := $(firstword \ $(if-expr defined(PATH_SDK_WINPSDK71_BIN), $(wildcard $(PATH_SDK_WINPSDK71_BIN)/$2)) \ $(if-expr defined(PATH_SDK_WINPSDK_BIN) , $(wildcard $(PATH_SDK_WINPSDK_BIN)/$2)) \ $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST)/sdk/*/[Bb][Ii][Nn]/$2)) \ $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST_ALT)/sdk/*/[Bb][Ii][Nn]/$2)) \ $1)) TOOL_VCC120_FN_FIND_SDK_TOOL = $(if-expr !defined($3),$(TOOL_VCC120_FN_FIND_SDK_TOOL_SUB),)$($3) ## Disabled fast DEP_IDB based dependencies. #VCC120_OLD_DEPS = 1 ## Constructs the correct .pdb name (the name is lowercased). # @param $(1) Base name, no extention. # @param $(2) The extension. TOOL_VCC120_PDB = $(dir $(1))$(tolower $(notdir $(1))).$(2) # General Properties used by kBuild TOOL_VCC120_COBJSUFF ?= .obj TOOL_VCC120_CFLAGS ?= -TC -nologo -Zi TOOL_VCC120_CFLAGS.debug ?= TOOL_VCC120_CFLAGS.dbgopt ?= -O2 TOOL_VCC120_CFLAGS.release ?= -O2 TOOL_VCC120_CFLAGS.profile ?= -O2 TOOL_VCC120_CINCS ?= $(PATH_TOOL_VCC120_INC) TOOL_VCC120_CDEFS ?= TOOL_VCC120_CXXOBJSUFF ?= .obj TOOL_VCC120_CXXFLAGS ?= -TP -nologo -Zi TOOL_VCC120_CXXFLAGS.debug ?= TOOL_VCC120_CXXFLAGS.dbgopt ?= -O2 TOOL_VCC120_CXXFLAGS.release ?= -O2 TOOL_VCC120_CXXFLAGS.profile ?= -O2 TOOL_VCC120_CXXINCS ?= $(PATH_TOOL_VCC120_INC) $(PATH_TOOL_VCC120_ATLMFC_INC) TOOL_VCC120_CXXDEFS ?= TOOL_VCC120_ASOBJSUFF ?= .obj TOOL_VCC120_RCOBJSUFF ?= .res TOOL_VCC120_RCINCS ?= $(PATH_TOOL_VCC120_INC) $(PATH_TOOL_VCC120_ATLMFC_INC) TOOL_VCC120_ARFLAGS.amd64 ?= -machine:amd64 TOOL_VCC120_ARFLAGS.x86 ?= -machine:x86 TOOL_VCC120_ARFLAGS ?= -nologo TOOL_VCC120_ARLIBSUFF ?= .lib TOOL_VCC120_LDFLAGS.amd64 ?= -machine:amd64 TOOL_VCC120_LDFLAGS.x86 ?= -machine:x86 TOOL_VCC120_LDFLAGS ?= -nologo TOOL_VCC120_LDFLAGS.debug ?= -debug TOOL_VCC120_LDFLAGS.dbgopt ?= -debug TOOL_VCC120_LDFLAGS.profile ?= -debug TOOL_VCC120_LDFLAGS.release ?= TOOL_VCC120_LIBPATH.amd64 ?= $(PATH_TOOL_VCC120_LIB.amd64) $(PATH_TOOL_VCC120_ATLMFC_LIB.amd64) TOOL_VCC120_LIBPATH.x86 ?= $(PATH_TOOL_VCC120_LIB.x86) $(PATH_TOOL_VCC120_ATLMFC_LIB.x86) ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC120_COMPILE_C_DEPEND = TOOL_VCC120_COMPILE_C_DEPORD = TOOL_VCC120_COMPILE_C_OUTPUT = TOOL_VCC120_COMPILE_C_OUTPUT_MAYBE = $(call TOOL_VCC120_PDB, $(outbase)-obj,pdb) $(call TOOL_VCC120_PDB, $(outbase)-obj,idb) define TOOL_VCC120_COMPILE_C_CMDS $(QUIET)$(TOOL_VCC120_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fd$(outbase)-obj.pdb \ -Fo$(obj)\ $(subst /,\\,$(abspath $(source))) $(QUIET)$(DEP_OBJ) -f -s -q -o $(dep) -t $(obj) $(obj) endef ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC120_COMPILE_CXX_DEPEND = $($(target)_1_VCC_PCH_FILE) TOOL_VCC120_COMPILE_CXX_DEPORD = TOOL_VCC120_COMPILE_CXX_OUTPUT = TOOL_VCC120_COMPILE_CXX_OUTPUT_MAYBE = $(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB)\ ,,$(call TOOL_VCC120_PDB, $(outbase)-obj,pdb) $(call TOOL_VCC120_PDB, $(outbase)-obj,idb)) define TOOL_VCC120_COMPILE_CXX_CMDS $(QUIET)$(TOOL_VCC120_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ $(if-expr defined($(target)_PCH_HDR)\ ,-FI$($(target)_PCH_HDR) -Yu$($(target)_PCH_HDR) -Fp$($(target)_1_VCC_PCH_FILE) -FS,)\ -Fd$(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB),$($(target)_1_VCC_COMMON_OBJ_PDB),$(outbase)-obj.pdb) \ -Fo$(obj)\ $(subst /,\\,$(abspath $(source))) $(QUIET)$(DEP_OBJ) -f -s -q -o $(dep) -t $(obj) $(obj) endef # # Helper tool for creating the precompiled C++ header. # # It only have the C++ compile bits and it's purpose is to skip bits # related _1_VCC_PCH_FILE and add -Yc. # TOOL_VCC120-PCH := Helper for creating precompiled header using CXX handling. TOOL_VCC120-PCH_EXTENDS := VCC120 TOOL_VCC120-PCH_CXXOBJSUFF := .obj TOOL_VCC120-PCH_CXXINCS = $(TOOL_VCC120_CXXINCS) TOOL_VCC120-PCH_CXXFLAGS = $(TOOL_VCC120_CXXFLAGS) -FS TOOL_VCC120-PCH_CXXFLAGS.debug = $(TOOL_VCC120_CXXFLAGS.debug) TOOL_VCC120-PCH_CXXFLAGS.dbgopt = $(TOOL_VCC120_CXXFLAGS.dbgopt) TOOL_VCC120-PCH_CXXFLAGS.release = $(TOOL_VCC120_CXXFLAGS.release) TOOL_VCC120-PCH_CXXFLAGS.profile = $(TOOL_VCC120_CXXFLAGS.profile) TOOL_VCC120-PCH_COMPILE_CXX_DEPEND = $(NO_SUCH_VARIABLE) TOOL_VCC120-PCH_COMPILE_CXX_DEPORD = $(NO_SUCH_VARIABLE) TOOL_VCC120-PCH_COMPILE_CXX_OUTPUT = $($(target)_1_VCC_PCH_FILE) $($(target)_1_VCC_COMMON_OBJ_PDB) TOOL_VCC120-PCH_COMPILE_CXX_OUTPUT_MAYBE = $(NO_SUCH_VARIABLE) ifdef TOOL_VCC120_KSUBMIT define TOOL_VCC120-PCH_COMPILE_CXX_CMDS $(QUIET)$(TOOL_VCC120_KSUBMIT) --no-pch-caching -P $(DEP_OBJ_INT) -f -s -q -e .pch -o $(dep) -t $(obj) $(obj)\ -- $(TOOL_VCC120_CXX) -c -Yc\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fp$($(target)_1_VCC_PCH_FILE) \ -Fd$($(target)_1_VCC_COMMON_OBJ_PDB) \ -Fo$(obj)\ -TP \ $(subst /,\\,$(abspath $(source))) endef else define TOOL_VCC120-PCH_COMPILE_CXX_CMDS $(QUIET)$(TOOL_VCC120_CXX) -c -Yc\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fp$($(target)_1_VCC_PCH_FILE) \ -Fd$($(target)_1_VCC_COMMON_OBJ_PDB) \ -Fo$(obj)\ -TP \ $(subst /,\\,$(abspath $(source))) $(QUIET)$(DEP_OBJ) -f -s -q -e .pch -o $(dep) -t $(obj) $(obj) endef endif # !TOOL_VCC120_KSUBMIT ## @todo configure the assembler template. ## Compile resource source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC120_COMPILE_RC_OUTPUT = TOOL_VCC120_COMPILE_RC_DEPEND = TOOL_VCC120_COMPILE_RC_DEPORD = define TOOL_VCC120_COMPILE_RC_CMDS $(QUIET)$(TOOL_VCC120_RC) \ $(flags) $(addprefix /i, $(subst /,\\,$(incs))) $(addprefix /d, $(defs))\ /fo$(obj)\ $(subst /,\\,$(abspath $(source))) endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_VCC120_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_VCC120_LINK_LIBRARY_DEPORD = TOOL_VCC120_LINK_LIBRARY_OUTPUT = $(outbase).rsp TOOL_VCC120_LINK_LIBRARY_OUTPUT_MAYBE = $(outbase).lst $(outbase).exp $(outbase).pdb define TOOL_VCC120_LINK_LIBRARY_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs) \ $(filter-out %.def,$(othersrc))) \ $(addprefix /DEF:,$(filter %.def,$(othersrc))) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC120_AR) $(flags) /OUT:$(out) @$(outbase).rsp endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_VCC120_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC120_LINK_PROGRAM_DEPORD = TOOL_VCC120_LINK_PROGRAM_OUTPUT = $(outbase).map $(outbase).rsp TOOL_VCC120_LINK_PROGRAM_OUTPUT_MAYBE = $(outbase).lib $(outbase).exp $(outbase).ilk $(out).manifest TOOL_VCC120_LINK_PROGRAM_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC120_LINK_PROGRAM_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb define TOOL_VCC120_LINK_PROGRAM_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC120_LD) $(flags) \ /OUT:$(out) \ /MAPINFO:EXPORTS /INCREMENTAL:NO \ /MAP:$(outbase).map \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp ifndef TOOL_VCC120_NO_AUTO_MANIFEST $(QUIET)$(TEST) -f $(out).manifest -- \ $(TOOL_VCC120_MT) -manifest $(subst /,\\,$(out)).manifest -outputresource:$(subst /,\\,$(out)) endif endef ## Link DLL. # @param $(target) Normalized main target name. # @param $(out) DLL name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_VCC120_LINK_DLL_DEPEND = $(objs) $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC120_LINK_DLL_DEPORD = $(call DIRDEP,$(PATH_STAGE_LIB)) TOOL_VCC120_LINK_DLL_OUTPUT = $(outbase).map $(outbase).lib $(outbase).exp $(outbase).rsp TOOL_VCC120_LINK_DLL_OUTPUT_MAYBE = $(outbase).ilk $(out).manifest $(PATH_STAGE_LIB)/$(notdir $(outbase)).exp TOOL_VCC120_LINK_DLL_OUTPUT_MAYBE_PRECIOUS = $(PATH_STAGE_LIB)/$(notdir $(outbase)).lib TOOL_VCC120_LINK_DLL_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC120_LINK_DLL_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb define TOOL_VCC120_LINK_DLL_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC120_LD) $(flags) \ /OUT:$(out) \ /IMPLIB:$(outbase).lib \ /MAPINFO:EXPORTS /INCREMENTAL:NO \ /MAP:$(outbase).map \ /DLL \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp ifndef TOOL_VCC120_NO_AUTO_MANIFEST $(QUIET)$(TEST) -f $(out).manifest -- \ $(TOOL_VCC120_MT) -manifest $(subst /,\\,$(out)).manifest '-outputresource:$(subst /,\\,$(out));#2' endif $(QUIET)$(TEST) -f $(outbase).lib -- $(KLIBTWEAKER_EXT) --clear-timestamps $(outbase).lib $(QUIET)$(CP) --changed --ignore-non-existing $(outbase).exp $(outbase).lib $(PATH_STAGE_LIB)/ $(eval _DIRS += $(PATH_STAGE_LIB)) endef ## Link system module (windows aka driver, linux aka kernel module) # @param $(target) Normalized main target name. # @param $(out) System module name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_VCC120_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC120_LINK_SYSMOD_DEPORD = TOOL_VCC120_LINK_SYSMOD_OUTPUT = $(outbase).map $(outbase).rsp TOOL_VCC120_LINK_SYSMOD_OUTPUT_MAYBE = $(outbase).lib $(outbase).exp $(outbase).ilk $(out).manifest TOOL_VCC120_LINK_SYSMOD_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC120_LINK_SYSMOD_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb define TOOL_VCC120_LINK_SYSMOD_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC120_LD) $(flags) \ /OUT:$(out) \ /MAPINFO:EXPORTS /INCREMENTAL:NO \ /MAP:$(outbase).map \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp ifndef TOOL_VCC120_NO_AUTO_MANIFEST $(QUIET)$(TEST) -f $(out).manifest -- \ $(TOOL_VCC120_MT) -manifest $(subst /,\\,$(out)).manifest '-outputresource:$(subst /,\\,$(out));#2' endif endef kbuild-3149/kBuild/tools/TARBZ2.kmk0000644000175000017500000000252513252530251016730 0ustar locutuslocutus# $Id: TARBZ2.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - tar.bz2 unpacker. # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_TARBZ2 := tar.bz2 unpacker. TOOL_TARBZ2_EXTENDS = TAR TOOL_TARBZ2_UNPACKFLAGS ?= -j kbuild-3149/kBuild/tools/VCC120X86.kmk0000644000175000017500000005072113252530251017131 0ustar locutuslocutus# $Id: VCC120X86.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - Visual C++ 12.0 (aka Visual 2013 and MSC v18), targeting x86. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_VCC120X86 := Visual C++ 12.0 (aka Visual 2013 and MSC v18), targeting x86. # Tool Specific Properties ifndef PATH_TOOL_VCC120X86 PATH_TOOL_VCC120X86 := $(wildcard $(KBUILD_DEVTOOLS)/win.x86/vcc/v12*) ifeq ($(PATH_TOOL_VCC120X86),) PATH_TOOL_VCC120X86 := $(PATH_TOOL_VCC120) endif ifeq ($(PATH_TOOL_VCC120X86),) PATH_TOOL_VCC120X86 := $(PATH_TOOL_VCC120AMD64) endif ifeq ($(PATH_TOOL_VCC120X86),) PATH_TOOL_VCC120X86 := $(wildcard $(KBUILD_DEVTOOLS)/x86.win32/vcc/v12*) endif ifeq ($(PATH_TOOL_VCC120X86),) PATH_TOOL_VCC120X86 := $(wildcard $(KBUILD_DEVTOOLS)/win.amd64/vcc/v12*) endif ifneq ($(PATH_TOOL_VCC120X86),) PATH_TOOL_VCC120X86 := $(lastword $(sort $(PATH_TOOL_VCC120X86))) else $(warning kBuild: PATH_TOOL_VCC120X86 cannot be determined!) PATH_TOOL_VCC120X86 := $(KBUILD_DEVTOOLS)/x86.win/vcc/v12 endif else # Resolve any fancy stuff once and for all. PATH_TOOL_VCC120X86 := $(PATH_TOOL_VCC120X86) endif if "$(KBUILD_HOST).$(KBUILD_HOST_ARCH)" == "win.amd64" && exists("$(PATH_TOOL_VCC120AMD64)/bin/amd64_x86") # Missing in express edition. PATH_TOOL_VCC120X86_BIN_DLL ?= $(PATH_TOOL_VCC120X86)/bin/amd64 PATH_TOOL_VCC120X86_BIN ?= $(PATH_TOOL_VCC120X86)/bin/amd64_x86 else PATH_TOOL_VCC120X86_BIN_DLL ?= PATH_TOOL_VCC120X86_BIN ?= $(PATH_TOOL_VCC120X86)/bin endif PATH_TOOL_VCC120X86_BIN ?= $(PATH_TOOL_VCC120X86)/bin PATH_TOOL_VCC120X86_LIB ?= $(PATH_TOOL_VCC120X86)/lib PATH_TOOL_VCC120X86_INC ?= $(PATH_TOOL_VCC120X86)/include PATH_TOOL_VCC120X86_ATLMFC ?= $(PATH_TOOL_VCC120X86)/atlmfc PATH_TOOL_VCC120X86_ATLMFC_INC ?= $(PATH_TOOL_VCC120X86_ATLMFC)/include PATH_TOOL_VCC120X86_ATLMFC_LIB ?= $(PATH_TOOL_VCC120X86_ATLMFC)/lib TOOL_VCC120X86_CC ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC120X86_BIN)/cl.exe TOOL_VCC120X86_CXX ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC120X86_BIN)/cl.exe TOOL_VCC120X86_AS ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC120X86_BIN)/ml.exe #TOOL_VCC120X86_AR ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC120X86_BIN)/lib.exe - just an exec wrapper for the below TOOL_VCC120X86_AR ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC120X86_BIN)/link.exe /LIB TOOL_VCC120X86_LD ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC120X86_BIN)/link.exe TOOL_VCC120X86_DUMPBIN ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC120X86_BIN)/dumpbin.exe TOOL_VCC120X86_EDITBIN ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC120X86_BIN)/editbin.exe TOOL_VCC120X86_RC ?= $(EXEC_X86_WIN32) $(call TOOL_VCC120_FN_FIND_SDK_TOOL,rc.exe,[Rr][Cc].[Ee][Xx][Ee],TOOL_VCC120_RC_CACHED) TOOL_VCC120X86_MT ?= $(EXEC_X86_WIN32) $(call TOOL_VCC120_FN_FIND_SDK_TOOL,mt.exe,[Mm][Tt].[Ee][Xx][Ee],TOOL_VCC120_MT_CACHED) ifdef TOOL_VCC120X86_USE_KSUBMIT ifeq ($(KBUILD_HOST),win) if "$(substr $(PATH_TOOL_VCC120X86_BIN),-10)" == "/amd64_x86" TOOL_VCC120X86_KSUBMIT ?= kmk_builtin_kSubmit --64-bit else TOOL_VCC120X86_KSUBMIT ?= kmk_builtin_kSubmit --32-bit endif ifdef PATH_TOOL_VCC120X86_BIN_DLL TOOL_VCC120X86_KSUBMIT += --prepend 'PATH=$(PATH_TOOL_VCC120X86_BIN_DLL)$(HOST_PATH_SEP)' endif TOOL_VCC120X86_KSUBMIT_DD = $(TOOL_VCC120X86_KSUBMIT) -- endif else ifdef PATH_TOOL_VCC120X86_BIN_DLL TOOL_VCC120X86_KSUBMIT_DD = $(REDIRECT) --prepend 'PATH=$(PATH_TOOL_VCC120X86_BIN_DLL)$(HOST_PATH_SEP)' -- endif # The following in duplicated in VCC120.kmk and VCC120X86.kmk. TOOL_VCC120_FN_FIND_SDK_TOOL_SUB = $(eval $3 := $(firstword \ $(if-expr defined(PATH_SDK_WINPSDK71_BIN), $(wildcard $(PATH_SDK_WINPSDK71_BIN)/$2)) \ $(if-expr defined(PATH_SDK_WINPSDK_BIN) , $(wildcard $(PATH_SDK_WINPSDK_BIN)/$2)) \ $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST)/sdk/*/[Bb][Ii][Nn]/$2)) \ $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST_ALT)/sdk/*/[Bb][Ii][Nn]/$2)) \ $1)) TOOL_VCC120_FN_FIND_SDK_TOOL = $(if-expr !defined($3),$(TOOL_VCC120_FN_FIND_SDK_TOOL_SUB),)$($3) ## Disabled fast DEP_IDB based dependencies. #VCC120X86_OLD_DEPS = 1 ## Constructs the correct .pdb name (the name is lowercased). # @param $(1) Base name, no extention. # @param $(2) The extension. TOOL_VCC120X86_PDB = $(dir $(1))$(tolower $(notdir $(1))).$(2) # General Properties used by kBuild TOOL_VCC120X86_COBJSUFF ?= .obj TOOL_VCC120X86_CFLAGS ?= -TC -nologo -Zi TOOL_VCC120X86_CFLAGS.debug ?= TOOL_VCC120X86_CFLAGS.dbgopt ?= -O2 TOOL_VCC120X86_CFLAGS.release ?= -O2 TOOL_VCC120X86_CFLAGS.profile ?= -O2 TOOL_VCC120X86_CINCS ?= $(PATH_TOOL_VCC120X86_INC) TOOL_VCC120X86_CDEFS ?= TOOL_VCC120X86_CXXOBJSUFF ?= .obj TOOL_VCC120X86_CXXFLAGS ?= -TP -nologo -Zi TOOL_VCC120X86_CXXFLAGS.debug ?= TOOL_VCC120X86_CXXFLAGS.dbgopt ?= -O2 TOOL_VCC120X86_CXXFLAGS.release ?= -O2 TOOL_VCC120X86_CXXFLAGS.profile ?= -O2 TOOL_VCC120X86_CXXINCS ?= $(PATH_TOOL_VCC120X86_INC) $(PATH_TOOL_VCC120X86_ATLMFC_INC) TOOL_VCC120X86_CXXDEFS ?= TOOL_VCC120X86_ASOBJSUFF ?= .obj TOOL_VCC120X86_RCOBJSUFF ?= .res TOOL_VCC120X86_RCINCS ?= $(PATH_TOOL_VCC120X86_INC) $(PATH_TOOL_VCC120X86_ATLMFC_INC) TOOL_VCC120X86_ARFLAGS ?= -nologo -machine:x86 TOOL_VCC120X86_ARLIBSUFF ?= .lib TOOL_VCC120X86_LDFLAGS ?= -nologo -machine:x86 TOOL_VCC120X86_LDFLAGS.debug ?= -debug TOOL_VCC120X86_LDFLAGS.dbgopt ?= -debug TOOL_VCC120X86_LDFLAGS.profile ?= -debug TOOL_VCC120X86_LDFLAGS.release ?= ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC120X86_COMPILE_C_DEPEND = TOOL_VCC120X86_COMPILE_C_DEPORD = TOOL_VCC120X86_COMPILE_C_OUTPUT = TOOL_VCC120X86_COMPILE_C_OUTPUT_MAYBE = $(call TOOL_VCC120X86_PDB, $(outbase)-obj,pdb) $(call TOOL_VCC120X86_PDB, $(outbase)-obj,idb) ifdef TOOL_VCC120X86_KSUBMIT TOOL_VCC120X86_COMPILE_C_DONT_PURGE_OUTPUT = 1 # speed define TOOL_VCC120X86_COMPILE_C_CMDS $(QUIET)$(TOOL_VCC120X86_KSUBMIT) -P $(DEP_OBJ_INT) -f -s -q -o $(dep) -t $(obj) $(obj)\ -- $(TOOL_VCC120X86_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fd$(outbase)-obj.pdb \ -Fo$(obj)\ $(subst /,\\,$(abspath $(source))) endef else define TOOL_VCC120X86_COMPILE_C_CMDS $(QUIET)$(if-expr defined(PATH_TOOL_VCC120X86_BIN_DLL)\ ,$(REDIRECT) --prepend 'PATH=$(PATH_TOOL_VCC120X86_BIN_DLL)$(HOST_PATH_SEP)' -- ,)$(TOOL_VCC120X86_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fd$(outbase)-obj.pdb \ -Fo$(obj)\ $(subst /,\\,$(abspath $(source))) $(QUIET)$(DEP_OBJ) -f -s -q -o $(dep) -t $(obj) $(obj) endef endif # !TOOL_VCC120X86_KSUBMIT ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC120X86_COMPILE_CXX_DEPEND = $($(target)_1_VCC_PCH_FILE) TOOL_VCC120X86_COMPILE_CXX_DEPORD = TOOL_VCC120X86_COMPILE_CXX_OUTPUT = TOOL_VCC120X86_COMPILE_CXX_OUTPUT_MAYBE = $(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB)\ ,,$(call TOOL_VCC120X86_PDB, $(outbase)-obj,pdb) $(call TOOL_VCC120X86_PDB, $(outbase)-obj,idb)) ifdef TOOL_VCC120X86_KSUBMIT TOOL_VCC120X86_COMPILE_CXX_DONT_PURGE_OUTPUT = 1 # speed define TOOL_VCC120X86_COMPILE_CXX_CMDS $(QUIET)$(TOOL_VCC120X86_KSUBMIT) -P $(DEP_OBJ_INT) -f -s -q -o $(dep) -t $(obj) $(obj)\ -- $(TOOL_VCC120X86_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ $(if-expr defined($(target)_PCH_HDR)\ ,-FI$($(target)_PCH_HDR) -Yu$($(target)_PCH_HDR) -Fp$($(target)_1_VCC_PCH_FILE) -FS,)\ -Fd$(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB),$($(target)_1_VCC_COMMON_OBJ_PDB),$(outbase)-obj.pdb) \ -Fo$(obj)\ $(subst /,\\,$(abspath $(source))) endef else define TOOL_VCC120X86_COMPILE_CXX_CMDS $(QUIET)$(if-expr defined(PATH_TOOL_VCC120X86_BIN_DLL)\ ,$(REDIRECT) --prepend 'PATH=$(PATH_TOOL_VCC120X86_BIN_DLL)$(HOST_PATH_SEP)' -- ,)$(TOOL_VCC120X86_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ $(if-expr defined($(target)_PCH_HDR)\ ,-FI$($(target)_PCH_HDR) -Yu$($(target)_PCH_HDR) -Fp$($(target)_1_VCC_PCH_FILE) -FS,)\ -Fd$(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB),$($(target)_1_VCC_COMMON_OBJ_PDB),$(outbase)-obj.pdb) \ -Fo$(obj)\ $(subst /,\\,$(abspath $(source))) $(QUIET)$(DEP_OBJ) -f -s -q -o $(dep) -t $(obj) $(obj) endef endif # !TOOL_VCC120X86_KSUBMIT # # Helper tool for creating the precompiled C++ header. # # It only have the C++ compile bits and it's purpose is to skip bits # related _1_VCC_PCH_FILE and add -Yc. # TOOL_VCC120X86-PCH := Helper for creating precompiled header using CXX handling. TOOL_VCC120X86-PCH_EXTENDS := VCC120X86 TOOL_VCC120X86-PCH_CXXOBJSUFF := .obj TOOL_VCC120X86-PCH_CXXINCS = $(TOOL_VCC120X86_CXXINCS) TOOL_VCC120X86-PCH_CXXFLAGS = $(TOOL_VCC120X86_CXXFLAGS) -FS TOOL_VCC120X86-PCH_CXXFLAGS.debug = $(TOOL_VCC120X86_CXXFLAGS.debug) TOOL_VCC120X86-PCH_CXXFLAGS.dbgopt = $(TOOL_VCC120X86_CXXFLAGS.dbgopt) TOOL_VCC120X86-PCH_CXXFLAGS.release = $(TOOL_VCC120X86_CXXFLAGS.release) TOOL_VCC120X86-PCH_CXXFLAGS.profile = $(TOOL_VCC120X86_CXXFLAGS.profile) TOOL_VCC120X86-PCH_COMPILE_CXX_DEPEND = $(NO_SUCH_VARIABLE) TOOL_VCC120X86-PCH_COMPILE_CXX_DEPORD = $(NO_SUCH_VARIABLE) TOOL_VCC120X86-PCH_COMPILE_CXX_OUTPUT = $($(target)_1_VCC_PCH_FILE) $($(target)_1_VCC_COMMON_OBJ_PDB) TOOL_VCC120X86-PCH_COMPILE_CXX_OUTPUT_MAYBE = $(NO_SUCH_VARIABLE) ifdef TOOL_VCC120X86_KSUBMIT define TOOL_VCC120X86-PCH_COMPILE_CXX_CMDS $(QUIET)$(TOOL_VCC120X86_KSUBMIT) --no-pch-caching -P $(DEP_OBJ_INT) -f -s -q -e .pch -o $(dep) -t $(obj) $(obj)\ -- $(TOOL_VCC120X86_CXX) -c -Yc\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fp$($(target)_1_VCC_PCH_FILE) \ -Fd$($(target)_1_VCC_COMMON_OBJ_PDB) \ -Fo$(obj)\ -TP \ $(subst /,\\,$(abspath $(source))) endef else define TOOL_VCC120X86-PCH_COMPILE_CXX_CMDS $(QUIET)$(if-expr defined(PATH_TOOL_VCC120X86_BIN_DLL)\ ,$(REDIRECT) --prepend 'PATH=$(PATH_TOOL_VCC120X86_BIN_DLL)$(HOST_PATH_SEP)' -- ,)$(TOOL_VCC120X86_CXX) -c -Yc\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fp$($(target)_1_VCC_PCH_FILE) \ -Fd$($(target)_1_VCC_COMMON_OBJ_PDB) \ -Fo$(obj)\ -TP \ $(subst /,\\,$(abspath $(source))) $(QUIET)$(DEP_OBJ) -f -s -q -e .pch -o $(dep) -t $(obj) $(obj) endef endif # !TOOL_VCC120X86_KSUBMIT ## @todo configure the assembler template. ## Compile resource source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC120X86_COMPILE_RC_DEPEND = TOOL_VCC120X86_COMPILE_RC_DEPORD = TOOL_VCC120X86_COMPILE_RC_OUTPUT = ## @todo Fix kmk_redirect so we can use it for setting PATH without spawning a shell or two define TOOL_VCC120X86_COMPILE_RC_CMDS $(QUIET)$(if-expr defined(PATH_TOOL_VCC120X86_BIN_DLL)\ ,$(REDIRECT) --prepend 'PATH=$(PATH_TOOL_VCC120X86_BIN_DLL)$(HOST_PATH_SEP)' -- ,) $(TOOL_VCC120X86_RC) \ $(flags) $(addprefix /i, $(subst /,\\,$(incs))) $(addprefix /d, $(defs))\ /fo$(obj)\ $(subst /,\\,$(abspath $(source))) endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_VCC120X86_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_VCC120X86_LINK_LIBRARY_DEPORD = TOOL_VCC120X86_LINK_LIBRARY_OUTPUT = $(outbase).rsp TOOL_VCC120X86_LINK_LIBRARY_OUTPUT_MAYBE = $(outbase).lst $(outbase).exp $(outbase).pdb define TOOL_VCC120X86_LINK_LIBRARY_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs) \ $(filter-out %.def,$(othersrc))) \ $(addprefix /DEF:,$(filter %.def,$(othersrc))) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC120X86_KSUBMIT_DD) $(TOOL_VCC120X86_AR) $(flags) /OUT:$(out) @$(outbase).rsp endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_VCC120X86_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC120X86_LINK_PROGRAM_DEPORD = TOOL_VCC120X86_LINK_PROGRAM_OUTPUT = $(outbase).map $(outbase).rsp TOOL_VCC120X86_LINK_PROGRAM_OUTPUT_MAYBE = $(outbase).lib $(outbase).exp $(outbase).ilk $(out).manifest TOOL_VCC120X86_LINK_PROGRAM_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC120X86_LINK_PROGRAM_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb define TOOL_VCC120X86_LINK_PROGRAM_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC120X86_KSUBMIT_DD) $(TOOL_VCC120X86_LD) $(flags) \ /OUT:$(out) \ /MAPINFO:EXPORTS /INCREMENTAL:NO \ /MAP:$(outbase).map \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp ifndef TOOL_VCC120X86_NO_AUTO_MANIFEST $(QUIET)$(TEST) -f $(out).manifest -- \ $(TOOL_VCC120X86_MT) -manifest $(subst /,\\,$(out)).manifest -outputresource:$(subst /,\\,$(out)) endif endef ## Link DLL. # @param $(target) Normalized main target name. # @param $(out) DLL name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_VCC120X86_LINK_DLL_DEPEND = $(objs) $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC120X86_LINK_DLL_DEPORD = $(call DIRDEP,$(PATH_STAGE_LIB)) TOOL_VCC120X86_LINK_DLL_OUTPUT = $(outbase).map $(outbase).lib $(outbase).exp $(outbase).rsp TOOL_VCC120X86_LINK_DLL_OUTPUT_MAYBE = $(outbase).ilk $(out).manifest $(PATH_STAGE_LIB)/$(notdir $(outbase)).exp TOOL_VCC120X86_LINK_DLL_OUTPUT_MAYBE_PRECIOUS = $(PATH_STAGE_LIB)/$(notdir $(outbase)).lib TOOL_VCC120X86_LINK_DLL_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC120X86_LINK_DLL_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb define TOOL_VCC120X86_LINK_DLL_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC120X86_KSUBMIT_DD) $(TOOL_VCC120X86_LD) $(flags) \ /OUT:$(out) \ /IMPLIB:$(outbase).lib \ /MAPINFO:EXPORTS /INCREMENTAL:NO \ /MAP:$(outbase).map \ /DLL \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp ifndef TOOL_VCC120X86_NO_AUTO_MANIFEST $(QUIET)$(TEST) -f $(out).manifest -- \ $(TOOL_VCC120X86_MT) -manifest $(subst /,\\,$(out)).manifest '-outputresource:$(subst /,\\,$(out));#2' endif $(QUIET)$(TEST) -f $(outbase).lib -- $(KLIBTWEAKER_EXT) --clear-timestamps $(outbase).lib $(QUIET)$(CP) --changed --ignore-non-existing $(outbase).exp $(outbase).lib $(PATH_STAGE_LIB)/ $(eval _DIRS += $(PATH_STAGE_LIB)) endef ## Link system module (windows aka driver, linux aka kernel module) # @param $(target) Normalized main target name. # @param $(out) System module name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_VCC120X86_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC120X86_LINK_SYSMOD_DEPORD = TOOL_VCC120X86_LINK_SYSMOD_OUTPUT = $(outbase).map $(outbase).rsp TOOL_VCC120X86_LINK_SYSMOD_OUTPUT_MAYBE = $(outbase).lib $(outbase).exp $(outbase).ilk $(out).manifest TOOL_VCC120X86_LINK_SYSMOD_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC120X86_LINK_SYSMOD_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb define TOOL_VCC120X86_LINK_SYSMOD_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC120X86_KSUBMIT_DD) $(TOOL_VCC120X86_LD) $(flags) \ /OUT:$(out) \ /MAPINFO:EXPORTS /INCREMENTAL:NO \ /MAP:$(outbase).map \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp ifndef TOOL_VCC120X86_NO_AUTO_MANIFEST $(QUIET)$(TEST) -f $(out).manifest -- \ $(TOOL_VCC120X86_MT) -manifest $(subst /,\\,$(out)).manifest '-outputresource:$(subst /,\\,$(out));#2' endif endef kbuild-3149/kBuild/tools/GCC32.kmk0000644000175000017500000003305513252530251016527 0ustar locutuslocutus# $Id: GCC32.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - Generic 32-bit GCC v3.2.x or later Using The System GCC. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_GCC32 := Generic 32-bit GCC v3.2.x or later Using The System GCC. \ More or less Linux/ELF specfic. # Tool Specific Properties TOOL_GCC32_CC ?= gcc$(HOSTSUFF_EXE) -m32 TOOL_GCC32_CXX ?= g++$(HOSTSUFF_EXE) -m32 TOOL_GCC32_AS ?= gcc$(HOSTSUFF_EXE) -m32 TOOL_GCC32_AR ?= ar$(HOSTSUFF_EXE) TOOL_GCC32_LD ?= gcc$(HOSTSUFF_EXE) -m32 TOOL_GCC32_LD_SYSMOD ?= ld$(HOSTSUFF_EXE) ifndef TOOL_GCC32_LDFLAGS.$(KBUILD_TARGET) TOOL_GCC32_LDFLAGS.dll ?= -shared else TOOL_GCC32_LDFLAGS.dll ?= $(TOOL_GCC32_LDFLAGS.$(KBUILD_TARGET)) endif TOOL_GCC32_LDFLAGS.sysmod ?= -r -m elf_i386$(if-expr "$(KBUILD_TARGET)" == "freebsd" || "$(KBUILD_TARGET)" == "gnukfbsd",_fbsd,) TOOL_GCC32_LD_SONAME ?= -Wl,-soname=$(firstword $($(1)_SONAME.$(KBUILD_TARGET).$(KBUILD_TYPE)) $($(1)_SONAME.$(KBUILD_TARGET)) $($(1)_SONAME.$(KBUILD_TYPE)) $($(1)_SONAME) $(notdir $(2))) ifeq ($(KBUILD_TARGET),os2) TOOL_GCC32_LD_MAP ?= -Zmap=$(1) else TOOL_GCC32_LD_MAP ?= endif ifeq ($(KBUILD_TARGET),os2) TOOL_GCC32_LD_SYSMOD_MAP ?= -Zmap=$(1) else TOOL_GCC32_LD_SYSMOD_MAP ?= endif if1of ($(KBUILD_HOST), solaris) TOOL_GCC32_OBJCOPY ?= gobjcopy$(HOSTSUFF_EXE) else TOOL_GCC32_OBJCOPY ?= objcopy$(HOSTSUFF_EXE) endif ifdef SLKRUNS TOOL_GCC32_CC += -fmessage-length=0 TOOL_GCC32_CXX += -fmessage-length=0 endif # General Properties used by kBuild TOOL_GCC32_COBJSUFF ?= .o TOOL_GCC32_CFLAGS ?= TOOL_GCC32_CFLAGS.debug ?= -g TOOL_GCC32_CFLAGS.profile ?= -O2 #-g -pg TOOL_GCC32_CFLAGS.release ?= -O2 TOOL_GCC32_CINCS ?= TOOL_GCC32_CDEFS ?= TOOL_GCC32_CXXOBJSUFF ?= .o TOOL_GCC32_CXXOBJSUFF ?= .o TOOL_GCC32_CXXFLAGS ?= TOOL_GCC32_CXXFLAGS.debug ?= -g TOOL_GCC32_CXXFLAGS.profile ?= -O2 #-g -pg TOOL_GCC32_CXXFLAGS.release ?= -O2 TOOL_GCC32_CXXINCS ?= TOOL_GCC32_CXXDEFS ?= TOOL_GCC32_ASFLAGS ?= -x assembler-with-cpp TOOL_GCC32_ASFLAGS.debug ?= -g TOOL_GCC32_ASFLAGS.profile ?= -g TOOL_GCC32_ASOBJSUFF ?= .o TOOL_GCC32_ARFLAGS ?= cr TOOL_GCC32_ARLIBSUFF ?= .a TOOL_GCC32_LDFLAGS ?= TOOL_GCC32_LDFLAGS.debug ?= -g TOOL_GCC32_LDFLAGS.profile ?= -g ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GCC32_COMPILE_C_DEPEND = TOOL_GCC32_COMPILE_C_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GCC32_COMPILE_C_USES_KOBJCACHE = 1 TOOL_GCC32_COMPILE_C_OUTPUT = $(outbase).i define TOOL_GCC32_COMPILE_C_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).i\ $(TOOL_GCC32_CC) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GCC32_CC) -c\ $(flags) -fpreprocessed -x c\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GCC32_COMPILE_C_OUTPUT = define TOOL_GCC32_COMPILE_C_CMDS $(QUIET)$(TOOL_GCC32_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GCC32_COMPILE_CXX_DEPEND = TOOL_GCC32_COMPILE_CXX_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GCC32_COMPILE_CXX_USES_KOBJCACHE = 1 TOOL_GCC32_COMPILE_CXX_OUTPUT = $(outbase).ii define TOOL_GCC32_COMPILE_CXX_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).ii\ $(TOOL_GCC32_CXX) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GCC32_CXX) -c\ $(flags) -fpreprocessed -x c++\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GCC32_COMPILE_CXX_OUTPUT = define TOOL_GCC32_COMPILE_CXX_CMDS $(QUIET)$(TOOL_GCC32_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile Assembly source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. # TOOL_GCC32_COMPILE_AS_OUTPUT = TOOL_GCC32_COMPILE_AS_DEPEND = TOOL_GCC32_COMPILE_AS_DEPORD = define TOOL_GCC32_COMPILE_AS_CMDS $(QUIET)$(TOOL_GCC32_AS) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC32_LINK_LIBRARY_OUTPUT = $(out).ar-script TOOL_GCC32_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_GCC32_LINK_LIBRARY_DEPORD = define TOOL_GCC32_LINK_LIBRARY_CMDS $(QUIET)$(APPEND) $(out).ar-script 'CREATE $(out)' $(QUIET)$(APPEND) -n $(out).ar-script \ $(foreach o,$(objs), 'ADDMOD $(o)') \ $(foreach o,$(filter-out %.def %.imp %.dll,$(othersrc)), 'ADDLIB $(o)') $(if $(filter %.def %.imp %.dll,$(othersrc))\ ,$(TOOL_GCC32_AR_IMP) -o $(outbase).imp.a $(filter %.def %.imp %.dll,$(othersrc))\ $(NL)$(TAB)$(QUIET)$(APPEND) $(out).ar-script 'ADDLIB $(outbase).imp.a') $(QUIET)$(APPEND) $(out).ar-script 'SAVE' $(QUIET)$(APPEND) $(out).ar-script 'END' $(QUIET)$(REDIRECT) -rti $(out).ar-script -- $(TOOL_GCC32_AR) -M endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC32_LINK_PROGRAM_OUTPUT = TOOL_GCC32_LINK_PROGRAM_OUTPUT_MAYBE = $(outbase).map TOOL_GCC32_LINK_PROGRAM_OUTPUT_DEBUG = $(outbase).debug TOOL_GCC32_LINK_PROGRAM_DEBUG_INSTALL_FN = $(2).debug=>$(basename $(3)).debug TOOL_GCC32_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib)))\ $(filter %.def, $(othersrc)) TOOL_GCC32_LINK_PROGRAM_DEPORD = define TOOL_GCC32_LINK_PROGRAM_CMDS $(QUIET)$(TOOL_GCC32_LD) $(flags) -o $(out) $(objs)\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\ $(call TOOL_GCC32_LD_MAP,$(outbase).map) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GCC32_OBJCOPY) --only-keep-debug $(out) $(outbase).debug $(QUIET)$(CHMOD) a-x $(outbase).debug $(QUIET)$(TOOL_GCC32_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out) endif endef ## Link DLL # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC32_LINK_DLL_OUTPUT = TOOL_GCC32_LINK_DLL_OUTPUT_MAYBE = $(outbase).map TOOL_GCC32_LINK_DLL_OUTPUT_DEBUG = $(outbase).debug TOOL_GCC32_LINK_DLL_DEBUG_INSTALL_FN = $(2).debug=>$(basename $(3)).debug TOOL_GCC32_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib)))\ $(filter %.def, $(othersrc)) TOOL_GCC32_LINK_DLL_DEPORD = define TOOL_GCC32_LINK_DLL_CMDS $(QUIET)$(TOOL_GCC32_LD) $(TOOL_GCC32_LDFLAGS.dll) $(flags) -o $(out)\ $(if $(filter-out win os2, $(KBUILD_TARGET)),$(call TOOL_GCC32_LD_SONAME,$(target),$(out)))\ $(objs)\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\ $(call TOOL_GCC32_LD_MAP,$(outbase).map) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GCC32_OBJCOPY) --only-keep-debug $(out) $(outbase).debug $(QUIET)$(CHMOD) a-x $(outbase).debug $(QUIET)$(TOOL_GCC32_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out) endif endef ## Link system module (windows aka driver, linux aka kernel module) # @param $(target) Normalized main target name. # @param $(out) System module name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC32_LINK_SYSMOD_OUTPUT = TOOL_GCC32_LINK_SYSMOD_OUTPUT_MAYBE = $(outbase).map TOOL_GCC32_LINK_SYSMOD_OUTPUT_DEBUG = $(outbase).debug TOOL_GCC32_LINK_SYSMOD_DEBUG_INSTALL_FN = $(2).debug=>$(basename $(3)).debug TOOL_GCC32_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib)))\ $(filter %.def, $(othersrc)) TOOL_GCC32_LINK_SYSMOD_DEPORD = define TOOL_GCC32_LINK_SYSMOD_CMDS $(QUIET)$(TOOL_GCC32_LD_SYSMOD) $(TOOL_GCC32_LDFLAGS.sysmod) $(flags) -o $(out) $(objs)\ $(filter %.def, $(othersrc))\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\ $(call TOOL_GCC32_LD_SYSMOD_MAP,$(outbase).map) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GCC32_OBJCOPY) --only-keep-debug $(out) $(outbase).debug $(QUIET)$(CHMOD) a-x $(outbase).debug $(QUIET)$(TOOL_GCC32_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out) endif endef kbuild-3149/kBuild/tools/GXX.kmk0000644000175000017500000002121513252530251016427 0ustar locutuslocutus# $Id: GXX.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - Generic GCC using the system GCC, for building C++ code. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_GXX := Generic GCC using the system GCC, for building C++ code. # Tool Specific Properties TOOL_GXX_CC ?= gcc$(HOSTSUFF_EXE) TOOL_GXX_CXX ?= g++$(HOSTSUFF_EXE) TOOL_GXX_AS ?= gcc$(HOSTSUFF_EXE) TOOL_GXX_AR ?= ar$(HOSTSUFF_EXE) TOOL_GXX_RANLIB ?= ranlib$(HOSTSUFF_EXE) TOOL_GXX_LD ?= g++$(HOSTSUFF_EXE) TOOL_GXX_LDFLAGS.dll.os2 ?= -Zdll TOOL_GXX_LDFLAGS.dll.darwin ?= -dynamiclib ifndef TOOL_GXX_LDFLAGS.$(KBUILD_TARGET) TOOL_GXX_LDFLAGS.dll ?= -shared else TOOL_GXX_LDFLAGS.dll ?= $(TOOL_GXX_LDFLAGS.$(KBUILD_TARGET)) endif # General Properties used by kBuild TOOL_GXX_COBJSUFF ?= .o TOOL_GXX_CFLAGS ?= TOOL_GXX_CFLAGS.debug ?= -g TOOL_GXX_CFLAGS.profile ?= -g -O2 #-pg TOOL_GXX_CFLAGS.release ?= -O2 TOOL_GXX_CINCS ?= TOOL_GXX_CDEFS ?= TOOL_GXX_CXXOBJSUFF ?= .o TOOL_GXX_CXXOBJSUFF ?= .o TOOL_GXX_CXXFLAGS ?= TOOL_GXX_CXXFLAGS.debug ?= -g -O0 TOOL_GXX_CXXFLAGS.profile ?= -g -O2 #-pg TOOL_GXX_CXXFLAGS.release ?= -O2 TOOL_GXX_CXXINCS ?= TOOL_GXX_CXXDEFS ?= TOOL_GXX_ASFLAGS ?= -x assembler-with-cpp TOOL_GXX_ASFLAGS.debug ?= -g TOOL_GXX_ASFLAGS.profile ?= -g TOOL_GXX_ASOBJSUFF ?= .o TOOL_GXX_ARFLAGS ?= cr TOOL_GXX_ARLIBSUFF ?= .a TOOL_GXX_LDFLAGS ?= TOOL_GXX_LDFLAGS.debug ?= -g TOOL_GXX_LDFLAGS.profile ?= -g ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. # TOOL_GXX_COMPILE_C_OUTPUT = TOOL_GXX_COMPILE_C_DEPEND = TOOL_GXX_COMPILE_C_DEPORD = define TOOL_GXX_COMPILE_C_CMDS $(QUIET)$(TOOL_GXX_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) \ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GXX_COMPILE_CXX_OUTPUT = TOOL_GXX_COMPILE_CXX_DEPEND = TOOL_GXX_COMPILE_CXX_DEPORD = define TOOL_GXX_COMPILE_CXX_CMDS $(QUIET)$(TOOL_GXX_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) \ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef ## Compile Assembly source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. # TOOL_GXX_COMPILE_AS_OUTPUT = TOOL_GXX_COMPILE_AS_DEPEND = TOOL_GXX_COMPILE_AS_DEPORD = define TOOL_GXX_COMPILE_AS_CMDS $(QUIET)$(TOOL_GXX_AS) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) \ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX_LINK_LIBRARY_OUTPUT = TOOL_GXX_LINK_LIBRARY_DEPEND = TOOL_GXX_LINK_LIBRARY_DEPORD = define TOOL_GXX_LINK_LIBRARY_CMDS $(QUIET)$(TOOL_GXX_AR) $(flags) $(out) $(objs) $(call xargs,$(QUIET)$(TOOL_GXX_AR) $(flags) $(out),$(objs)) $(foreach lib,$(othersrc)\ ,$(NL)$(TAB)$(call MSG_AR_MERGE,$(target),$(out),$(lib)) \ $(NL)$(TAB)$(QUIET)$(RM_EXT) -f $(dir $(outbase))ar.tmp.dir/* \ $(NL)$(TAB)$(QUIET)$(MKDIR) -p $(dir $(outbase))/ar.tmp.dir/ \ $(NL)$(TAB)$(QUIET)(cd $(dir $(outbase))ar.tmp.dir/ \ && $(TOOL_GXX_AR) x $(abspath $(lib)) \ && $(TOOL_GXX_AR) $(flags) $(out) *) \ $(NL)$(TAB)$(QUIET)$(RM_EXT) -f $(dir $(outbase))/ar.tmp.dir/* \ $(NL)$(TAB)$(QUIET)$(RMDIR) $(dir $(outbase))ar.tmp.dir/) $(QUIET)$(TOOL_GXX_RANLIB) $(out) endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX_LINK_PROGRAM_OUTPUT = TOOL_GXX_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_GXX_LINK_PROGRAM_DEPORD = define TOOL_GXX_LINK_PROGRAM_CMDS $(QUIET)$(TOOL_GXX_LD) $(flags) -o $(out) $(objs) \ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib))) endef ## Link DLL # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX_LINK_DLL_OUTPUT = TOOL_GXX_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_GXX_LINK_DLL_DEPORD = define TOOL_GXX_LINK_DLL_CMDS $(QUIET)$(TOOL_GXX_LD) $(TOOL_GXX_LDFLAGS.dll) $(flags) -o $(out) $(objs) \ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib))) endef kbuild-3149/kBuild/tools/MASM710.kmk0000644000175000017500000000461213252530251016750 0ustar locutuslocutus# $Id: MASM710.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - MASM v7.10 # # # Copyright (c) 2008-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_MASM710 := Microsoft Macro Assembler v7.10 # Tool Specific Properties ifndef TOOL_MASM710_AS TOOL_MASM710_AS := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST)/masm/v7.10*/binp/ml$(HOSTSUFF_EXE)))) ifeq ($(TOOL_MASM710_AS),) TOOL_MASM710_AS := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_TRG)/masm/v7.10*/binp/ml$(HOSTSUFF_EXE)))) endif ifeq ($(TOOL_MASM710_AS),) TOOL_MASM710_AS := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS)/win.x86/vcc/v7*/bin/ml$(HOSTSUFF_EXE)))) endif endif ifeq ($(TOOL_MASM710_AS),) TOOL_MASM710_AS := $(firstword $(which ml$(HOSTSUFF_EXE)) path/notfound/ml$(HOSTSUFF_EXE)) endif # General Properties used by kBuild TOOL_MASM710_ASFLAGS ?= /nologo TOOL_MASM710_COMPILE_AS_OUTPUT = $(outbase).lst TOOL_MASM710_COMPILE_AS_DEPEND = TOOL_MASM710_COMPILE_AS_DEPORD = define TOOL_MASM710_COMPILE_AS_CMDS $(QUIET)$(REDIRECT) \ -E 'INCLUDE=$(subst $(SP),,$(addsuffix ;,$(subst /,\,$(incs))))' \ -E 'MASM=' -E 'ML=' \ -- \ $(subst /,\\,$(TOOL_MASM710_AS)) -c \ $(strip $(flags)) \ $(addprefix -D,$(defs)) \ -Fo$(subst /,\\,$(obj)) \ -Fl$(subst /,\\,$(outbase).lst) \ $(subst /,\\,$(source)) endef kbuild-3149/kBuild/tools/GCC.kmk0000644000175000017500000002113713252530250016357 0ustar locutuslocutus# $Id: GCC.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - Generic GCC Using The System GCC. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_GCC := Generic GCC Using The System GCC. # Tool Specific Properties TOOL_GCC_CC ?= gcc$(HOSTSUFF_EXE) TOOL_GCC_CXX ?= g++$(HOSTSUFF_EXE) TOOL_GCC_AS ?= gcc$(HOSTSUFF_EXE) TOOL_GCC_AR ?= ar$(HOSTSUFF_EXE) TOOL_GCC_RANLIB ?= ranlib$(HOSTSUFF_EXE) TOOL_GCC_LD ?= gcc$(HOSTSUFF_EXE) TOOL_GCC_LDFLAGS.dll.os2 ?= -Zdll TOOL_GCC_LDFLAGS.dll.darwin ?= -dynamiclib ifndef TOOL_GCC_LDFLAGS.$(KBUILD_TARGET) TOOL_GCC_LDFLAGS.dll ?= -shared else TOOL_GCC_LDFLAGS.dll ?= $(TOOL_GCC_LDFLAGS.$(KBUILD_TARGET)) endif # General Properties used by kBuild TOOL_GCC_COBJSUFF ?= .o TOOL_GCC_CFLAGS ?= TOOL_GCC_CFLAGS.debug ?= -g TOOL_GCC_CFLAGS.profile ?= -g -O2 #-pg TOOL_GCC_CFLAGS.release ?= -O2 TOOL_GCC_CINCS ?= TOOL_GCC_CDEFS ?= TOOL_GCC_CXXOBJSUFF ?= .o TOOL_GCC_CXXOBJSUFF ?= .o TOOL_GCC_CXXFLAGS ?= TOOL_GCC_CXXFLAGS.debug ?= -g -O0 TOOL_GCC_CXXFLAGS.profile ?= -g -O2 #-pg TOOL_GCC_CXXFLAGS.release ?= -O2 TOOL_GCC_CXXINCS ?= TOOL_GCC_CXXDEFS ?= TOOL_GCC_ASFLAGS ?= -x assembler-with-cpp TOOL_GCC_ASFLAGS.debug ?= -g TOOL_GCC_ASFLAGS.profile ?= -g TOOL_GCC_ASOBJSUFF ?= .o TOOL_GCC_ARFLAGS ?= cr TOOL_GCC_ARLIBSUFF ?= .a TOOL_GCC_LDFLAGS ?= TOOL_GCC_LDFLAGS.debug ?= -g TOOL_GCC_LDFLAGS.profile ?= -g ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. # TOOL_GCC_COMPILE_C_OUTPUT = TOOL_GCC_COMPILE_C_DEPEND = TOOL_GCC_COMPILE_C_DEPORD = define TOOL_GCC_COMPILE_C_CMDS $(QUIET)$(TOOL_GCC_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) \ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GCC_COMPILE_CXX_OUTPUT = TOOL_GCC_COMPILE_CXX_DEPEND = TOOL_GCC_COMPILE_CXX_DEPORD = define TOOL_GCC_COMPILE_CXX_CMDS $(QUIET)$(TOOL_GCC_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) \ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef ## Compile Assembly source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. # TOOL_GCC_COMPILE_AS_OUTPUT = TOOL_GCC_COMPILE_AS_DEPEND = TOOL_GCC_COMPILE_AS_DEPORD = define TOOL_GCC_COMPILE_AS_CMDS $(QUIET)$(TOOL_GCC_AS) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) \ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC_LINK_LIBRARY_OUTPUT = TOOL_GCC_LINK_LIBRARY_DEPEND = TOOL_GCC_LINK_LIBRARY_DEPORD = define TOOL_GCC_LINK_LIBRARY_CMDS $(QUIET)$(TOOL_GCC_AR) $(flags) $(out) $(objs) $(call xargs,$(QUIET)$(TOOL_GCC_AR) $(flags) $(out),$(objs)) $(foreach lib,$(othersrc)\ ,$(NL)$(TAB)$(call MSG_AR_MERGE,$(target),$(out),$(lib)) \ $(NL)$(TAB)$(QUIET)$(RM_EXT) -f $(dir $(outbase))ar.tmp.dir/* \ $(NL)$(TAB)$(QUIET)$(MKDIR) -p $(dir $(outbase))/ar.tmp.dir/ \ $(NL)$(TAB)$(QUIET)(cd $(dir $(outbase))ar.tmp.dir/ \ && $(TOOL_GCC_AR) x $(abspath $(lib)) \ && $(TOOL_GCC_AR) $(flags) $(out) *) \ $(NL)$(TAB)$(QUIET)$(RM_EXT) -f $(dir $(outbase))/ar.tmp.dir/* \ $(NL)$(TAB)$(QUIET)$(RMDIR) $(dir $(outbase))ar.tmp.dir/) $(QUIET)$(TOOL_GCC_RANLIB) $(out) endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC_LINK_PROGRAM_OUTPUT = TOOL_GCC_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_GCC_LINK_PROGRAM_DEPORD = define TOOL_GCC_LINK_PROGRAM_CMDS $(QUIET)$(TOOL_GCC_LD) $(flags) -o $(out) $(objs) \ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib))) endef ## Link DLL # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC_LINK_DLL_OUTPUT = TOOL_GCC_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_GCC_LINK_DLL_DEPORD = define TOOL_GCC_LINK_DLL_CMDS $(QUIET)$(TOOL_GCC_LD) $(TOOL_GCC_LDFLAGS.dll) $(flags) -o $(out) $(objs) \ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib))) endef kbuild-3149/kBuild/tools/GXX3OMF.kmk0000644000175000017500000003220313252530251017053 0ustar locutuslocutus# $Id: GXX3OMF.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - GCC v3 targeting OS/2 OMF, for building C++ code. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_GXX3OMF := GCC v3 targeting OS/2 OMF, for building C++ code. # Tool Specific Properties TOOL_GXX3OMF_CC ?= gcc$(HOSTSUFF_EXE) TOOL_GXX3OMF_CXX ?= g++$(HOSTSUFF_EXE) TOOL_GXX3OMF_AS ?= gcc$(HOSTSUFF_EXE) TOOL_GXX3OMF_AR ?= emxomfar$(HOSTSUFF_EXE) TOOL_GXX3OMF_AR_IMP ?= emximp$(HOSTSUFF_EXE) TOOL_GXX3OMF_LD ?= g++$(HOSTSUFF_EXE) TOOL_GXX3OMF_LD_SYSMOD ?= g++$(HOSTSUFF_EXE) ifndef TOOL_GXX3OMF_LDFLAGS.$(KBUILD_TARGET) TOOL_GXX3OMF_LDFLAGS.dll ?= -shared -Zdll else TOOL_GXX3OMF_LDFLAGS.dll ?= $(TOOL_GXX3OMF_LDFLAGS.$(KBUILD_TARGET)) endif TOOL_GXX3OMF_LDFLAGS.sysmod ?= -nostdlib TOOL_GXX3OMF_LD_MAP ?= -Zmap=$(1) TOOL_GXX3OMF_LD_SYSMOD_MAP ?= -Zmap=$(1) TOOL_GXX3OMF_RC = rc$(HOSTSUFF_EXE) ifdef SLKRUNS TOOL_GXX3OMF_CC += -fmessage-length=0 TOOL_GXX3OMF_CXX += -fmessage-length=0 endif # General Properties used by kBuild TOOL_GXX3OMF_COBJSUFF ?= .o TOOL_GXX3OMF_CFLAGS ?= -Zomf TOOL_GXX3OMF_CFLAGS.debug ?= -g TOOL_GXX3OMF_CFLAGS.profile ?= -O2 #-g -pg TOOL_GXX3OMF_CFLAGS.release ?= -O2 TOOL_GXX3OMF_CINCS ?= TOOL_GXX3OMF_CDEFS ?= TOOL_GXX3OMF_CXXOBJSUFF ?= .o TOOL_GXX3OMF_CXXOBJSUFF ?= .o TOOL_GXX3OMF_CXXFLAGS ?= -Zomf TOOL_GXX3OMF_CXXFLAGS.debug ?= -g TOOL_GXX3OMF_CXXFLAGS.profile ?= -O2 #-g -pg TOOL_GXX3OMF_CXXFLAGS.release ?= -O2 TOOL_GXX3OMF_CXXINCS ?= TOOL_GXX3OMF_CXXDEFS ?= TOOL_GXX3OMF_ASFLAGS ?= -x assembler-with-cpp -Zomf TOOL_GXX3OMF_ASFLAGS.debug ?= -g TOOL_GXX3OMF_ASFLAGS.profile ?= -g TOOL_GXX3OMF_ASOBJSUFF ?= .obj TOOL_GXX3OMF_RCOBJSUFF ?= .res TOOL_GXX3OMF_RCFLAGS ?= -n TOOL_GXX3OMF_RCINCS ?= $(shell $(TOOL_GXX3OMF_CXX) -E -x c++ - 2>&1 < /dev/null \ | $(SED_EXT) -e "/search starts here/,/[Ee]nd of search list/!d" -e "/^ /!d") TOOL_GXX3OMF_ARFLAGS ?= cr TOOL_GXX3OMF_ARLIBSUFF ?= .lib TOOL_GXX3OMF_LDFLAGS ?= -Zomf TOOL_GXX3OMF_LDFLAGS.debug ?= -g TOOL_GXX3OMF_LDFLAGS.profile ?= -g ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GXX3OMF_COMPILE_C_DEPEND = TOOL_GXX3OMF_COMPILE_C_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GXX3OMF_COMPILE_C_USES_KOBJCACHE = 1 TOOL_GXX3OMF_COMPILE_C_OUTPUT = $(outbase).i define TOOL_GXX3OMF_COMPILE_C_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).i\ $(TOOL_GXX3OMF_CC) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GXX3OMF_CC) -c\ $(flags) -fpreprocessed -x c\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GXX3OMF_COMPILE_C_OUTPUT = define TOOL_GXX3OMF_COMPILE_C_CMDS $(QUIET)$(TOOL_GXX3OMF_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP \ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GXX3OMF_COMPILE_CXX_DEPEND = TOOL_GXX3OMF_COMPILE_CXX_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GXX3OMF_COMPILE_CXX_USES_KOBJCACHE = 1 TOOL_GXX3OMF_COMPILE_CXX_OUTPUT = $(outbase).ii define TOOL_GXX3OMF_COMPILE_CXX_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).ii\ $(TOOL_GXX3OMF_CXX) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GXX3OMF_CXX) -c\ $(flags) -fpreprocessed -x c++\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GXX3OMF_COMPILE_CXX_OUTPUT = define TOOL_GXX3OMF_COMPILE_CXX_CMDS $(QUIET)$(TOOL_GXX3OMF_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP \ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile Assembly source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. # TOOL_GXX3OMF_COMPILE_AS_OUTPUT = TOOL_GXX3OMF_COMPILE_AS_DEPEND = TOOL_GXX3OMF_COMPILE_AS_DEPORD = define TOOL_GXX3OMF_COMPILE_AS_CMDS $(QUIET)$(TOOL_GXX3OMF_AS) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef ## Compile resource source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GXX3OMF_COMPILE_RC_OUTPUT = TOOL_GXX3OMF_COMPILE_RC_DEPEND = TOOL_GXX3OMF_COMPILE_RC_DEPORD = define TOOL_GXX3OMF_COMPILE_RC_CMDS $(QUIET)$(REDIRECT) -E 'INCLUDE=' -- $(TOOL_GXX3OMF_RC) -r \ $(flags) $(addprefix -i, $(subst /,\\,$(subst /@unixroot,$(UNIXROOT),$(incs)))) $(addprefix -d, $(defs))\ $(subst /,\\,$(abspath $(source))) \ $(obj) endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX3OMF_LINK_LIBRARY_OUTPUT = $(outbase).rsp TOOL_GXX3OMF_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_GXX3OMF_LINK_LIBRARY_DEPORD = define TOOL_GXX3OMF_LINK_LIBRARY_CMDS $(if $(filter %.def %.imp %.dll,$(othersrc))\ ,$(QUIET)$(APPEND) -n $(outbase).rsp $(filter %.def %.imp %.dll,$(othersrc))\ $(NL)$(TAB)$(QUIET)$(QUIET)$(TOOL_GXX3OMF_AR_IMP) -o $(out) @$(outbase).rsp\ $(NL)$(TAB)$(QUIET)$(RM) -f $(outbase).rsp) $(QUIET)$(APPEND) -n $(outbase).rsp $(flags) $(out) $(objs) $(filter-out %.def %.imp %.dll,$(othersrc)) $(QUIET)$(TOOL_GXX3OMF_AR) @$(outbase).rsp endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX3OMF_LINK_PROGRAM_OUTPUT = $(outbase).map $(outbase).rsp TOOL_GXX3OMF_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_GXX3OMF_LINK_PROGRAM_DEPORD = define TOOL_GXX3OMF_LINK_PROGRAM_CMDS $(QUIET)$(APPEND) -n $(outbase).rsp\ $(flags)\ -o $(out)\ $(objs)\ $(foreach p,$(libpath), -L$(p))\ $(othersrc)\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\ -Zmap=$(outbase).map $(QUIET)$(TOOL_GXX3OMF_LD) @$(outbase).rsp endef ## Link DLL # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX3OMF_LINK_DLL_OUTPUT = $(outbase).map $(outbase).rsp TOOL_GXX3OMF_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_GXX3OMF_LINK_DLL_DEPORD = define TOOL_GXX3OMF_LINK_DLL_CMDS $(QUIET)$(APPEND) -n $(outbase).rsp\ $(TOOL_GXX3OMF_LDFLAGS.dll)\ $(flags)\ -o $(out)\ $(objs)\ $(foreach p,$(libpath), -L$(p))\ $(othersrc)\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\ -Zmap=$(outbase).map $(QUIET)$(TOOL_GXX3OMF_LD) @$(outbase).rsp endef ## Link system module (windows aka driver, linux aka kernel module) # @param $(target) Normalized main target name. # @param $(out) System module name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX3OMF_LINK_SYSMOD_OUTPUT = $(outbase).map $(outbase).rsp TOOL_GXX3OMF_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_GXX3OMF_LINK_SYSMOD_DEPORD = define TOOL_GXX3OMF_LINK_SYSMOD_CMDS $(QUIET)$(APPEND) -n $(outbase).rsp\ $(TOOL_GXX3OMF_LDFLAGS.sysmod)\ $(flags)\ -o $(out)\ $(objs)\ $(foreach p,$(libpath), -L$(p))\ $(othersrc)\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\ -Zmap=$(outbase).map $(QUIET)$(TOOL_GXX3OMF_LD_SYSMOD) @$(outbase).rsp endef kbuild-3149/kBuild/tools/WATCOMC11C-WL.kmk0000644000175000017500000000725313252530251017651 0ustar locutuslocutus# $Id: WATCOMC11C-WL.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - Watcom C/C++ v11.0c, using wlink. # # @remarks wrc is untested, so are DLLs, and programs. # # Copyright (c) 2008-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_WATCOMC11C-WL = Watcom C/C++ v11.0c, using wlink. TOOL_WATCOMC11C-WL_EXTENDS = WATCOMC11C TOOL_WATCOMC11C-WL_LDFLAGS ?= Option Quiet TOOL_WATCOMC11C-WL_LDFLAGS.dos ?= $(NO_SUCH_VARIABLE) TOOL_WATCOMC11C-WL_LDFLAGS.linux ?= $(NO_SUCH_VARIABLE) TOOL_WATCOMC11C-WL_LDFLAGS.nt ?= $(NO_SUCH_VARIABLE) TOOL_WATCOMC11C-WL_LDFLAGS.os2 ?= $(NO_SUCH_VARIABLE) TOOL_WATCOMC11C-WL_LDFLAGS.win ?= $(NO_SUCH_VARIABLE) TOOL_WATCOMC11C-WL_LINK_PROGRAM_OUTPUT = $(outbase).map $(outbase).rsp TOOL_WATCOMC11C-WL_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_WATCOMC11C-WL_LINK_PROGRAM_DEPORD = define TOOL_WATCOMC11C-WL_LINK_PROGRAM_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(if $(flags),'$(flags)',) \ 'Name $(subst /,\,$(out)$(if $(suffix $(out)),,.))' \ 'Option Map=$(subst /,\,$(outbase)).map' \ $(foreach p,$(subst /,\,$(libpath)),'LIBPath $p') \ $(foreach o,$(subst /,\,$(filter-out %.res,$(objs)) $(othersrc)),'$(if $(filter %.lib %.a,$l),LIB,)File $o') \ $(foreach l,$(subst /,\,$(libs)),'Library $l') $(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP_BD) \ $(TOOL_WATCOMC11C_WLINK) @$(outbase).rsp $(if $(filter %.res,$(objs)), $(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP) \ $(TOOL_WATCOMC11C_RC) \ $(filter -bt=%,$(flags)) \ /fe=$(subst /,\\,$(out)) \ $(subst /,\\,$(filter %.res,$(objs)))) endef TOOL_WATCOMC11C-WL_LINK_DLL_OUTPUT = $(TOOL_WATCOMC11C-WL_LINK_PROGRAM_OUTPUT) TOOL_WATCOMC11C-WL_LINK_DLL_DEPEND = $(TOOL_WATCOMC11C-WL_LINK_PROGRAM_DEPEND) TOOL_WATCOMC11C-WL_LINK_DLL_DEPORD = $(TOOL_WATCOMC11C-WL_LINK_PROGRAM_DEPORD) TOOL_WATCOMC11C-WL_LINK_DLL_CMDS = $(TOOL_WATCOMC11C-WL_LINK_PROGRAM_CMDS) TOOL_WATCOMC11C-WL_LINK_SYSMOD_OUTPUT = $(TOOL_WATCOMC11C-WL_LINK_PROGRAM_OUTPUT) TOOL_WATCOMC11C-WL_LINK_SYSMOD_DEPEND = $(TOOL_WATCOMC11C-WL_LINK_PROGRAM_DEPEND) TOOL_WATCOMC11C-WL_LINK_SYSMOD_DEPORD = $(TOOL_WATCOMC11C-WL_LINK_PROGRAM_DEPORD) TOOL_WATCOMC11C-WL_LINK_SYSMOD_CMDS = $(TOOL_WATCOMC11C-WL_LINK_PROGRAM_CMDS) TOOL_WATCOMC11C-WL_LINK_MISCBIN_OUTPUT = $(TOOL_WATCOMC11C-WL_LINK_PROGRAM_OUTPUT) TOOL_WATCOMC11C-WL_LINK_MISCBIN_DEPEND = $(TOOL_WATCOMC11C-WL_LINK_PROGRAM_DEPEND) TOOL_WATCOMC11C-WL_LINK_MISCBIN_DEPORD = $(TOOL_WATCOMC11C-WL_LINK_PROGRAM_DEPORD) TOOL_WATCOMC11C-WL_LINK_MISCBIN_CMDS = $(TOOL_WATCOMC11C-WL_LINK_PROGRAM_CMDS) kbuild-3149/kBuild/tools/GCC64.kmk0000644000175000017500000003227613252530251016540 0ustar locutuslocutus# $Id: GCC64.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - Generic 64-bit GCC v3.2.x or later Using The System GCC. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_GCC64 := Generic 64-bit GCC v3.2.x or later Using The System GCC. \ More or less Linux/ELF specfic. # Tool Specific Properties TOOL_GCC64_CC ?= gcc$(HOSTSUFF_EXE) -m64 TOOL_GCC64_CXX ?= g++$(HOSTSUFF_EXE) -m64 TOOL_GCC64_AS ?= gcc$(HOSTSUFF_EXE) -m64 TOOL_GCC64_AR ?= ar$(HOSTSUFF_EXE) TOOL_GCC64_LD ?= gcc$(HOSTSUFF_EXE) -m64 TOOL_GCC64_LD_SYSMOD ?= ld$(HOSTSUFF_EXE) ifndef TOOL_GCC64_LDFLAGS.$(KBUILD_TARGET) TOOL_GCC64_LDFLAGS.dll ?= -shared else TOOL_GCC64_LDFLAGS.dll ?= $(TOOL_GCC64_LDFLAGS.$(KBUILD_TARGET)) endif TOOL_GCC64_LDFLAGS.sysmod ?= -r -m elf_x86_64$(if-expr "$(KBUILD_TARGET)" == "freebsd" || "$(KBUILD_TARGET)" == "gnukfbsd",_fbsd,) TOOL_GCC64_LD_SONAME ?= -Wl,-soname=$(firstword $($(1)_SONAME.$(KBUILD_TARGET).$(KBUILD_TYPE)) $($(1)_SONAME.$(KBUILD_TARGET)) $($(1)_SONAME.$(KBUILD_TYPE)) $($(1)_SONAME) $(notdir $(2))) ifeq ($(KBUILD_TARGET),os2) TOOL_GCC64_LD_MAP ?= -Zmap=$(1) else TOOL_GCC64_LD_MAP ?= endif ifeq ($(KBUILD_TARGET),os2) TOOL_GCC64_LD_SYSMOD_MAP ?= -Zmap=$(1) else TOOL_GCC64_LD_SYSMOD_MAP ?= endif if1of ($(KBUILD_HOST), solaris) TOOL_GCC64_OBJCOPY ?= gobjcopy$(HOSTSUFF_EXE) else TOOL_GCC64_OBJCOPY ?= objcopy$(HOSTSUFF_EXE) endif ifdef SLKRUNS TOOL_GCC64_CC += -fmessage-length=0 TOOL_GCC64_CXX += -fmessage-length=0 endif # General Properties used by kBuild TOOL_GCC64_COBJSUFF ?= .o TOOL_GCC64_CFLAGS ?= TOOL_GCC64_CFLAGS.debug ?= -g TOOL_GCC64_CFLAGS.profile ?= -O2 #-g -pg TOOL_GCC64_CFLAGS.release ?= -O2 TOOL_GCC64_CINCS ?= TOOL_GCC64_CDEFS ?= TOOL_GCC64_CXXOBJSUFF ?= .o TOOL_GCC64_CXXOBJSUFF ?= .o TOOL_GCC64_CXXFLAGS ?= TOOL_GCC64_CXXFLAGS.debug ?= -g TOOL_GCC64_CXXFLAGS.profile ?= -O2 #-g -pg TOOL_GCC64_CXXFLAGS.release ?= -O2 TOOL_GCC64_CXXINCS ?= TOOL_GCC64_CXXDEFS ?= TOOL_GCC64_ASFLAGS ?= -x assembler-with-cpp TOOL_GCC64_ASFLAGS.debug ?= -g TOOL_GCC64_ASFLAGS.profile ?= -g TOOL_GCC64_ASOBJSUFF ?= .o TOOL_GCC64_ARFLAGS ?= cr TOOL_GCC64_ARLIBSUFF ?= .a TOOL_GCC64_LDFLAGS ?= TOOL_GCC64_LDFLAGS.debug ?= -g TOOL_GCC64_LDFLAGS.profile ?= -g ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GCC64_COMPILE_C_DEPEND = TOOL_GCC64_COMPILE_C_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GCC64_COMPILE_C_USES_KOBJCACHE = 1 TOOL_GCC64_COMPILE_C_OUTPUT = $(outbase).i define TOOL_GCC64_COMPILE_C_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).i\ $(TOOL_GCC64_CC) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GCC64_CC) -c\ $(flags) -fpreprocessed -x c\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GCC64_COMPILE_C_OUTPUT = define TOOL_GCC64_COMPILE_C_CMDS $(QUIET)$(TOOL_GCC64_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GCC64_COMPILE_CXX_DEPEND = TOOL_GCC64_COMPILE_CXX_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GCC64_COMPILE_CXX_USES_KOBJCACHE = 1 TOOL_GCC64_COMPILE_CXX_OUTPUT = $(outbase).ii define TOOL_GCC64_COMPILE_CXX_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).ii\ $(TOOL_GCC64_CXX) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GCC64_CXX) -c\ $(flags) -fpreprocessed -x c++\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GCC64_COMPILE_CXX_OUTPUT = define TOOL_GCC64_COMPILE_CXX_CMDS $(QUIET)$(TOOL_GCC64_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile Assembly source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. # TOOL_GCC64_COMPILE_AS_OUTPUT = TOOL_GCC64_COMPILE_AS_DEPEND = TOOL_GCC64_COMPILE_AS_DEPORD = define TOOL_GCC64_COMPILE_AS_CMDS $(QUIET)$(TOOL_GCC64_AS) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC64_LINK_LIBRARY_OUTPUT = $(out).ar-script TOOL_GCC64_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_GCC64_LINK_LIBRARY_DEPORD = define TOOL_GCC64_LINK_LIBRARY_CMDS $(QUIET)$(APPEND) $(out).ar-script 'CREATE $(out)' $(QUIET)$(APPEND) -n $(out).ar-script \ $(foreach o,$(objs), 'ADDMOD $(o)') \ $(foreach o,$(othersrc), 'ADDLIB $(o)') $(QUIET)$(APPEND) $(out).ar-script 'SAVE' $(QUIET)$(APPEND) $(out).ar-script 'END' $(QUIET)$(REDIRECT) -rti $(out).ar-script -- $(TOOL_GCC64_AR) -M endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC64_LINK_PROGRAM_OUTPUT = TOOL_GCC64_LINK_PROGRAM_OUTPUT_MAYBE = $(outbase).map TOOL_GCC64_LINK_PROGRAM_OUTPUT_DEBUG = $(outbase).debug TOOL_GCC64_LINK_PROGRAM_DEBUG_INSTALL_FN = $(2).debug=>$(basename $(3)).debug TOOL_GCC64_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_GCC64_LINK_PROGRAM_DEPORD = define TOOL_GCC64_LINK_PROGRAM_CMDS $(QUIET)$(TOOL_GCC64_LD) $(flags) -o $(out) $(objs)\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\ $(call TOOL_GCC64_LD_MAP,$(outbase).map) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GCC64_OBJCOPY) --only-keep-debug $(out) $(outbase).debug $(QUIET)$(CHMOD) a-x $(outbase).debug $(QUIET)$(TOOL_GCC64_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out) endif endef ## Link DLL # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC64_LINK_DLL_OUTPUT = TOOL_GCC64_LINK_DLL_OUTPUT_MAYBE = $(outbase).map TOOL_GCC64_LINK_DLL_OUTPUT_DEBUG = $(outbase).debug TOOL_GCC64_LINK_DLL_DEBUG_INSTALL_FN = $(2).debug=>$(basename $(3)).debug TOOL_GCC64_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_GCC64_LINK_DLL_DEPORD = define TOOL_GCC64_LINK_DLL_CMDS $(QUIET)$(TOOL_GCC64_LD) $(TOOL_GCC64_LDFLAGS.dll) $(flags) -o $(out)\ $(if $(filter-out win os2, $(KBUILD_TARGET)),$(call TOOL_GCC64_LD_SONAME,$(target),$(out)))\ $(objs)\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\ $(call TOOL_GCC64_LD_MAP,$(outbase).map) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GCC64_OBJCOPY) --only-keep-debug $(out) $(outbase).debug $(QUIET)$(CHMOD) a-x $(outbase).debug $(QUIET)$(TOOL_GCC64_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out) endif endef ## Link system module (windows aka driver, linux aka kernel module) # @param $(target) Normalized main target name. # @param $(out) System module name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC64_LINK_SYSMOD_OUTPUT = TOOL_GCC64_LINK_SYSMOD_OUTPUT_MAYBE = $(outbase).map TOOL_GCC64_LINK_SYSMOD_OUTPUT_DEBUG = $(outbase).debug TOOL_GCC64_LINK_SYSMOD_DEBUG_INSTALL_FN = $(2).debug=>$(basename $(3)).debug TOOL_GCC64_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_GCC64_LINK_SYSMOD_DEPORD = define TOOL_GCC64_LINK_SYSMOD_CMDS $(QUIET)$(TOOL_GCC64_LD_SYSMOD) $(TOOL_GCC64_LDFLAGS.sysmod) $(flags) -o $(out) $(objs)\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\ $(call TOOL_GCC64_LD_SYSMOD_MAP,$(outbase).map) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GCC64_OBJCOPY) --only-keep-debug $(out) $(outbase).debug $(QUIET)$(CHMOD) a-x $(outbase).debug $(QUIET)$(TOOL_GCC64_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out) endif endef kbuild-3149/kBuild/tools/ZIP.kmk0000644000175000017500000000571413252530251016431 0ustar locutuslocutus# $Id: ZIP.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - The zip/unzip packer/unpacker. # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_ZIP := The zip/unzip packer/unpacker. # Tool Specific Properties ifndef TOOL_ZIP_UNPACK TOOL_ZIP_UNPACK := $(wildcard $(KBUILD_DEVTOOLS_HST)/unzip/v*/unzip$(HOSTSUFF_EXE)) ifeq ($(TOOL_ZIP_UNPACK),) TOOL_ZIP_UNPACK := $(wildcard $(KBUILD_DEVTOOLS_HST)/zip/v*/unzip$(HOSTSUFF_EXE)) endif ifeq ($(TOOL_ZIP_UNPACK),) TOOL_ZIP_UNPACK := $(wildcard $(KBUILD_DEVTOOLS_HST)/bin/unzip$(HOSTSUFF_EXE)) endif ifneq ($(TOOL_ZIP_UNPACK),) TOOL_ZIP_UNPACK := $(lastword $(sort $(TOOL_ZIP_UNPACK))) else TOOL_ZIP_UNPACK := unzip$(HOSTSUFF_EXE) endif else TOOL_ZIP_UNPACK := $(TOOL_ZIP_UNPACK) endif #ifndef TOOL_ZIP_PACK # TOOL_ZIP_PACK := $(wildcard $(KBUILD_DEVTOOLS_HST)/zip/v*/zip$(HOSTSUFF_EXE)) # ifeq ($(TOOL_ZIP_PACK),) # TOOL_ZIP_PACK := $(wildcard $(KBUILD_DEVTOOLS_HST)/unzip/v*/zip$(HOSTSUFF_EXE)) # endif # ifeq ($(TOOL_ZIP_PACK),) # TOOL_ZIP_PACK := $(wildcard $(KBUILD_DEVTOOLS_HST)/bin/zip$(HOSTSUFF_EXE)) # endif # ifneq ($(TOOL_ZIP_PACK),) # TOOL_ZIP_PACK := $(lastword $(sort $(TOOL_ZIP_PACK))) # else # TOOL_ZIP_PACK := zip$(HOSTSUFF_EXE) # endif #else # TOOL_ZIP_PACK := $(TOOL_ZIP_PACK) #endif # General Properties used by kBuild TOOL_ZIP_UNPACKFLAGS ?= ## UNPACK one file. # @param $(zipget) Normalized main zipget name. # @param $(archive) The file to unpack. # @param $(flags) Flags. # @param $(inst) Where to unpack it. # @param $(out) Where to write the file list. TOOL_ZIP_UNPACK_OUTPUT = TOOL_ZIP_UNPACK_DEPEND = TOOL_ZIP_UNPACK_DEPORD = define TOOL_ZIP_UNPACK_CMDS $(QUIET)$(TOOL_ZIP_UNPACK) $(flags) $(archive) -d "$(inst)" $(QUIET)$(TOOL_ZIP_UNPACK) -l $(archive) | $(SED) \ -e '/ [0-2][0-9]:[0-6][0-9]/!d' \ -e 's/^.* [0-2][0-9]:[0-6][0-9] //' \ > $(out) endef kbuild-3149/kBuild/tools/VCC80X86.kmk0000644000175000017500000003407313252530251017060 0ustar locutuslocutus# $Id: VCC80X86.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - Visual C++ 8.0 (aka Visual .NET 2005, or MSC v14), targeting x86. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_VCC80X86 := Visual C++ 8.0 (aka Visual .NET 2005, or MSC v14), targeting x86. # Tool Specific Properties ifndef PATH_TOOL_VCC80X86 PATH_TOOL_VCC80X86 := $(wildcard $(KBUILD_DEVTOOLS)/win.x86/vcc/v8*) ifeq ($(PATH_TOOL_VCC80X86),) PATH_TOOL_VCC80X86 := $(PATH_TOOL_VCC80) endif ifeq ($(PATH_TOOL_VCC80X86),) PATH_TOOL_VCC80X86 := $(PATH_TOOL_VCC80AMD64) endif ifeq ($(PATH_TOOL_VCC80X86),) PATH_TOOL_VCC80X86 := $(wildcard $(KBUILD_DEVTOOLS)/x86.win32/vcc/v8*) endif ifeq ($(PATH_TOOL_VCC80X86),) PATH_TOOL_VCC80X86 := $(wildcard $(KBUILD_DEVTOOLS)/win.amd64/vcc/v8*) endif ifneq ($(PATH_TOOL_VCC80X86),) PATH_TOOL_VCC80X86 := $(lastword $(sort $(PATH_TOOL_VCC80X86))) else $(warning kBuild: PATH_TOOL_VCC80X86 cannot be determined!) PATH_TOOL_VCC80X86 := $(KBUILD_DEVTOOLS)/x86.win/vcc/v8 endif else # Resolve any fancy stuff once and for all. PATH_TOOL_VCC80X86 := $(PATH_TOOL_VCC80X86) endif PATH_TOOL_VCC80X86_BIN ?= $(PATH_TOOL_VCC80X86)/bin PATH_TOOL_VCC80X86_LIB ?= $(PATH_TOOL_VCC80X86)/lib PATH_TOOL_VCC80X86_INC ?= $(PATH_TOOL_VCC80X86)/include PATH_TOOL_VCC80X86_ATLMFC ?= $(PATH_TOOL_VCC80X86)/atlmfc PATH_TOOL_VCC80X86_ATLMFC_INC ?= $(PATH_TOOL_VCC80X86_ATLMFC)/include PATH_TOOL_VCC80X86_ATLMFC_LIB ?= $(PATH_TOOL_VCC80X86_ATLMFC)/lib TOOL_VCC80X86_CC ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC80X86_BIN)/cl.exe TOOL_VCC80X86_CXX ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC80X86_BIN)/cl.exe TOOL_VCC80X86_AS ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC80X86_BIN)/ml.exe TOOL_VCC80X86_RC ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC80X86_BIN)/rc.exe TOOL_VCC80X86_AR ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC80X86_BIN)/lib.exe TOOL_VCC80X86_LD ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC80X86_BIN)/link.exe TOOL_VCC80X86_MT ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC80X86_BIN)/mt.exe ## Disabled fast DEP_IDB based dependencies. #VCC80X86_OLD_DEPS = 1 ## Constructs the correct .pdb name (the name is lowercased). # @param $(1) Base name, no extention. # @param $(2) The extension. TOOL_VCC80X86_PDB = $(dir $(1))$(tolower $(notdir $(1))).$(2) # General Properties used by kBuild TOOL_VCC80X86_COBJSUFF ?= .obj TOOL_VCC80X86_CFLAGS ?= -TC -c -nologo TOOL_VCC80X86_CFLAGS.debug ?= -Zi TOOL_VCC80X86_CFLAGS.release ?= -O2 TOOL_VCC80X86_CFLAGS.profile ?= -O2 TOOL_VCC80X86_CINCS ?= $(PATH_TOOL_VCC80X86_INC) TOOL_VCC80X86_CDEFS ?= TOOL_VCC80X86_CXXOBJSUFF ?= .obj TOOL_VCC80X86_CXXFLAGS ?= -TP -c -nologo TOOL_VCC80X86_CXXFLAGS.debug ?= -Zi TOOL_VCC80X86_CXXFLAGS.release ?= -O2 TOOL_VCC80X86_CXXFLAGS.profile ?= -O2 TOOL_VCC80X86_CXXINCS ?= $(PATH_TOOL_VCC80X86_INC) $(PATH_TOOL_VCC80X86_ATLMFC_INC) TOOL_VCC80X86_CXXDEFS ?= TOOL_VCC80X86_ASOBJSUFF ?= .obj TOOL_VCC80X86_RCOBJSUFF ?= .res TOOL_VCC80X86_RCINCS ?= $(PATH_TOOL_VCC80X86_INC) $(PATH_TOOL_VCC80X86_ATLMFC_INC) TOOL_VCC80X86_ARFLAGS ?= -nologo TOOL_VCC80X86_ARLIBSUFF ?= .lib TOOL_VCC80X86_LDFLAGS ?= -nologo -machine:x86 TOOL_VCC80X86_LDFLAGS.debug ?= -debug TOOL_VCC80X86_LDFLAGS.release ?= ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC80X86_COMPILE_C_DEPEND = TOOL_VCC80X86_COMPILE_C_DEPORD = TOOL_VCC80X86_COMPILE_C_OUTPUT = $(call TOOL_VCC80X86_PDB, $(outbase)-obj,idb) TOOL_VCC80X86_COMPILE_C_OUTPUT_MAYBE = $(call TOOL_VCC80X86_PDB, $(outbase)-obj,pdb) define TOOL_VCC80X86_COMPILE_C_CMDS $(QUIET)$(TOOL_VCC80X86_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fd$(outbase)-obj.pdb \ -FD\ -Fo$(obj)\ $(subst /,\\,$(abspath $(source))) $(QUIET)$(DEP_IDB) -f -s -q -o $(dep) -t $(obj) $(call TOOL_VCC80X86_PDB,$(outbase)-obj,idb) endef ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC80X86_COMPILE_CXX_DEPEND = TOOL_VCC80X86_COMPILE_CXX_DEPORD = TOOL_VCC80X86_COMPILE_CXX_OUTPUT = $(call TOOL_VCC80X86_PDB, $(outbase)-obj,idb) TOOL_VCC80X86_COMPILE_CXX_OUTPUT_MAYBE = $(call TOOL_VCC80X86_PDB, $(outbase)-obj,pdb) define TOOL_VCC80X86_COMPILE_CXX_CMDS $(QUIET)$(TOOL_VCC80X86_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fd$(outbase)-obj.pdb \ -FD\ -Fo$(obj)\ $(subst /,\\,$(abspath $(source))) $(QUIET)$(DEP_IDB) -f -s -q -o $(dep) -t $(obj) $(call TOOL_VCC80X86_PDB,$(outbase)-obj,idb) endef ## @todo configure the assembler template. ## Compile resource source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC80X86_COMPILE_RC_DEPEND = TOOL_VCC80X86_COMPILE_RC_DEPORD = TOOL_VCC80X86_COMPILE_RC_OUTPUT = define TOOL_VCC80X86_COMPILE_RC_CMDS $(QUIET)$(TOOL_VCC80X86_RC) \ $(flags) $(addprefix /i, $(subst /,\\,$(incs))) $(addprefix /d, $(defs))\ /fo$(obj)\ $(subst /,\\,$(abspath $(source))) endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_VCC80X86_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_VCC80X86_LINK_LIBRARY_DEPORD = TOOL_VCC80X86_LINK_LIBRARY_OUTPUT = $(outbase).rsp TOOL_VCC80X86_LINK_LIBRARY_OUTPUT_MAYBE = $(outbase).lst $(outbase).exp $(outbase).pdb define TOOL_VCC80X86_LINK_LIBRARY_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs) \ $(filter-out %.def,$(othersrc))) \ $(addprefix /DEF:,$(filter %.def,$(othersrc))) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC80X86_AR) $(flags) /OUT:$(out) @$(outbase).rsp endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_VCC80X86_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC80X86_LINK_PROGRAM_DEPORD = TOOL_VCC80X86_LINK_PROGRAM_OUTPUT = $(outbase).map $(outbase).rsp TOOL_VCC80X86_LINK_PROGRAM_OUTPUT_MAYBE = $(outbase).lib $(outbase).exp $(outbase).ilk $(out).manifest TOOL_VCC80X86_LINK_PROGRAM_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC80X86_LINK_PROGRAM_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb define TOOL_VCC80X86_LINK_PROGRAM_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC80X86_LD) $(flags) \ /OUT:$(out) \ /MAPINFO:EXPORTS /INCREMENTAL:NO \ /MAP:$(outbase).map \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp $(QUIET)$(TEST) -f $(out).manifest -- \ $(TOOL_VCC80X86_MT) -manifest $(subst /,\\,$(out)).manifest -outputresource:$(subst /,\\,$(out)) endef ## Link DLL. # @param $(target) Normalized main target name. # @param $(out) DLL name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_VCC80X86_LINK_DLL_DEPEND = $(objs) $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC80X86_LINK_DLL_DEPORD = $(call DIRDEP,$(PATH_STAGE_LIB)) TOOL_VCC80X86_LINK_DLL_OUTPUT = $(outbase).map $(outbase).lib $(outbase).exp $(outbase).rsp TOOL_VCC80X86_LINK_DLL_OUTPUT_MAYBE = $(outbase).ilk $(out).manifest $(PATH_STAGE_LIB)/$(notdir $(outbase)).lib $(PATH_STAGE_LIB)/$(notdir $(outbase)).exp TOOL_VCC80X86_LINK_DLL_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC80X86_LINK_DLL_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb define TOOL_VCC80X86_LINK_DLL_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC80X86_LD) $(flags) \ /OUT:$(out) \ /IMPLIB:$(outbase).lib \ /MAPINFO:EXPORTS /INCREMENTAL:NO \ /MAP:$(outbase).map \ /DLL \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp $(QUIET)$(TEST) -f $(out).manifest -- \ $(TOOL_VCC80X86_MT) -manifest $(subst /,\\,$(out)).manifest '-outputresource:$(subst /,\\,$(out));#2' $(QUIET)$(CP) --changed --ignore-non-existing $(outbase).exp $(outbase).lib $(PATH_STAGE_LIB)/ $(eval _DIRS += $(PATH_STAGE_LIB)) endef ## Link system module (windows aka driver, linux aka kernel module) # @param $(target) Normalized main target name. # @param $(out) System module name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_VCC80X86_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC80X86_LINK_SYSMOD_DEPORD = TOOL_VCC80X86_LINK_SYSMOD_OUTPUT = $(outbase).map $(outbase).rsp TOOL_VCC80X86_LINK_SYSMOD_OUTPUT_MAYBE = $(outbase).lib $(outbase).exp $(outbase).ilk $(out).manifest TOOL_VCC80X86_LINK_SYSMOD_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC80X86_LINK_SYSMOD_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb define TOOL_VCC80X86_LINK_SYSMOD_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC80X86_LD) $(flags) \ /OUT:$(out) \ /MAPINFO:EXPORTS /INCREMENTAL:NO \ /MAP:$(outbase).map \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp $(QUIET)$(TEST) -f $(out).manifest -- \ $(TOOL_VCC80X86_MT) -manifest $(subst /,\\,$(out)).manifest '-outputresource:$(subst /,\\,$(out));#2' endef kbuild-3149/kBuild/tools/VCC70.kmk0000644000175000017500000003512713252530251016552 0ustar locutuslocutus# $Id: VCC70.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - Visual C++ 7.0 (aka Visual Studio .NET), targeting x86. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_VCC70 := Visual C++ 7.0 (aka Visual Studio .NET), targeting x86. # Tool Specific Properties ifndef PATH_TOOL_VCC70 PATH_TOOL_VCC70 := $(firstword $(wildcard \ $(KBUILD_DEVTOOLS)/win.x86/vcc/v7 \ $(KBUILD_DEVTOOLS)/x86.win32/vcc/v7 \ $(KBUILD_DEVTOOLS)/x86.win32/vcc70) ) # if not found, we'll enter 'pathless' mode. else # Resolve any fancy stuff once and for all. PATH_TOOL_VCC70 := $(PATH_TOOL_VCC70) endif ifneq ($(PATH_TOOL_VCC70),) PATH_TOOL_VCC70_BIN ?= $(PATH_TOOL_VCC70)/bin PATH_TOOL_VCC70_LIB ?= $(PATH_TOOL_VCC70)/lib PATH_TOOL_VCC70_INC ?= $(PATH_TOOL_VCC70)/include PATH_TOOL_VCC70_ATLMFC ?= $(PATH_TOOL_VCC70)/atlmfc PATH_TOOL_VCC70_ATLMFC_INC ?= $(PATH_TOOL_VCC70_ATLMFC)/include PATH_TOOL_VCC70_ATLMFC_LIB ?= $(PATH_TOOL_VCC70_ATLMFC)/lib TOOL_VCC70_CC ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC70_BIN)/cl.exe TOOL_VCC70_CXX ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC70_BIN)/cl.exe TOOL_VCC70_AS ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC70_BIN)/ml.exe TOOL_VCC70_RC ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC70_BIN)/rc.exe TOOL_VCC70_AR ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC70_BIN)/lib.exe TOOL_VCC70_LD ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC70_BIN)/link.exe else # Pathless, relies on the environment. TOOL_VCC70_CC ?= $(EXEC_X86_WIN32) cl.exe TOOL_VCC70_CXX ?= $(EXEC_X86_WIN32) cl.exe TOOL_VCC70_AS ?= $(EXEC_X86_WIN32) ml.exe TOOL_VCC70_RC ?= $(EXEC_X86_WIN32) rc.exe TOOL_VCC70_AR ?= $(EXEC_X86_WIN32) lib.exe TOOL_VCC70_LD ?= $(EXEC_X86_WIN32) link.exe endif ## Disabled fast DEP_IDB based dependencies. #VCC70_OLD_DEPS = 1 ## Constructs the correct .pdb name (the name is lowercased). # @param $(1) Base name, no extention. # @param $(2) The extension. TOOL_VCC70_PDB = $(dir $(1))$(tolower $(notdir $(1))).$(2) # General Properties used by kBuild TOOL_VCC70_COBJSUFF ?= .obj TOOL_VCC70_CFLAGS ?= -TC -c -nologo TOOL_VCC70_CFLAGS.debug ?= -Od -Zi TOOL_VCC70_CFLAGS.release ?= -O2 TOOL_VCC70_CFLAGS.profile ?= -O2 TOOL_VCC70_CINCS ?= $(PATH_TOOL_VCC70_INC) TOOL_VCC70_CDEFS ?= TOOL_VCC70_CXXOBJSUFF ?= .obj TOOL_VCC70_CXXFLAGS ?= -TP -c -nologo TOOL_VCC70_CXXFLAGS.debug ?= -Od -Zi TOOL_VCC70_CXXFLAGS.release ?= -O2 TOOL_VCC70_CXXFLAGS.profile ?= -O2 TOOL_VCC70_CXXINCS ?= $(PATH_TOOL_VCC70_INC) $(PATH_TOOL_VCC70_ATLMFC_INC) TOOL_VCC70_CXXDEFS ?= TOOL_VCC70_ASOBJSUFF ?= .obj TOOL_VCC70_RCOBJSUFF ?= .res TOOL_VCC70_RCINCS ?= $(PATH_TOOL_VCC70_INC) $(PATH_TOOL_VCC70_ATLMFC_INC) TOOL_VCC70_ARFLAGS ?= -nologo TOOL_VCC70_ARLIBSUFF ?= .lib TOOL_VCC70_LDFLAGS ?= -nologo TOOL_VCC70_LDFLAGS.debug ?= -debug TOOL_VCC70_LDFLAGS.release ?= ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC70_COMPILE_C_DONT_PURGE_OUTPUT = TOOL_VCC70_COMPILE_C_DEPEND = TOOL_VCC70_COMPILE_C_DEPORD = #ifdef KBUILD_USE_KOBJCACHE #TOOL_VCC70_COMPILE_C_OUTPUT = $(call TOOL_VCC70_PDB, $(outbase)-obj,pdb) $(call TOOL_VCC70_PDB, $(outbase)-obj,idb) $(outbase).i #TOOL_VCC70_COMPILE_C_USESES_KOBJCACHE = 1 #define TOOL_VCC70_COMPILE_C_CMDS # $(QUIET)$(KOBJCACHE) -f $(outbase).koc -r --kObjCache-cpp $(outbase).i \ # $(TOOL_VCC70_CC) -E \ # $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ # $(subst /,\\,$(abspath $(source))) \ # --kObjCache-cc $(obj) \ # $(TOOL_VCC70_CC) -c -TC\ # $(flags) \ # -Fd$(outbase)-obj.pdb \ # -FD\ # -Fo$(obj)\ # $(subst /,\\,$(outbase).i) # $(QUIET)$(DEP_IDB) -f -s -q -o $(dep) -t $(obj) $(call TOOL_VCC70_PDB,$(outbase)-obj,idb) #endef #else # !KBUILD_USE_KOBJCACHE TOOL_VCC70_COMPILE_C_OUTPUT = $(call TOOL_VCC70_PDB, $(outbase)-obj,idb) TOOL_VCC70_COMPILE_C_OUTPUT_MAYBE = $(call TOOL_VCC70_PDB, $(outbase)-obj,pdb) define TOOL_VCC70_COMPILE_C_CMDS $(QUIET)$(TOOL_VCC70_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fd$(outbase)-obj.pdb \ -FD\ -Fo$(obj)\ $(subst /,\\,$(abspath $(source))) $(QUIET)$(DEP_IDB) -f -s -q -o $(dep) -t $(obj) $(call TOOL_VCC70_PDB,$(outbase)-obj,idb) endef #endif # !KBUILD_USE_KOBJCACHE ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC70_COMPILE_CXX_DONT_PURGE_OUTPUT = TOOL_VCC70_COMPILE_CXX_DEPEND = TOOL_VCC70_COMPILE_CXX_DEPORD = #ifdef KBUILD_USE_KOBJCACHE #TOOL_VCC70_COMPILE_CXX_OUTPUT = $(call TOOL_VCC70_PDB, $(outbase)-obj,pdb) $(call TOOL_VCC70_PDB, $(outbase)-obj,idb) $(outbase).ii #TOOL_VCC70_COMPILE_CXX_USES_KOBJCACHE = 1 #define TOOL_VCC70_COMPILE_CXX_CMDS # $(QUIET)$(KOBJCACHE) -f $(outbase).koc -r --kObjCache-cpp $(outbase).ii \ # $(TOOL_VCC70_CC) -E \ # $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ # $(subst /,\\,$(abspath $(source))) \ # --kObjCache-cc $(obj) \ # $(TOOL_VCC70_CC) -c -TP\ # $(flags) \ # -Fd$(outbase)-obj.pdb \ # -FD\ # -Fo$(obj)\ # $(subst /,\\,$(outbase).ii) # $(QUIET)$(DEP_IDB) -f -s -q -o $(dep) -t $(obj) $(call TOOL_VCC70_PDB,$(outbase)-obj,idb) #endef #else # !KBUILD_USE_KOBJCACHE TOOL_VCC70_COMPILE_CXX_OUTPUT = $(call TOOL_VCC70_PDB, $(outbase)-obj,idb) TOOL_VCC70_COMPILE_CXX_OUTPUT_MAYBE = $(call TOOL_VCC70_PDB, $(outbase)-obj,pdb) define TOOL_VCC70_COMPILE_CXX_CMDS $(QUIET)$(TOOL_VCC70_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fd$(outbase)-obj.pdb \ -FD\ -Fo$(obj)\ $(subst /,\\,$(abspath $(source))) $(QUIET)$(DEP_IDB) -f -s -q -o $(dep) -t $(obj) $(call TOOL_VCC70_PDB,$(outbase)-obj,idb) endef #endif # !KBUILD_USE_KOBJCACHE ## Compile resource source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC70_COMPILE_RC_OUTPUT = TOOL_VCC70_COMPILE_RC_DEPEND = TOOL_VCC70_COMPILE_RC_DEPORD = define TOOL_VCC70_COMPILE_RC_CMDS $(QUIET)$(TOOL_VCC70_RC) \ $(flags) $(addprefix /i, $(subst /,\\,$(incs))) $(addprefix /d, $(defs))\ /fo$(obj)\ $(subst /,\\,$(abspath $(source))) endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_VCC70_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_VCC70_LINK_LIBRARY_DEPORD = TOOL_VCC70_LINK_LIBRARY_OUTPUT = $(outbase).rsp TOOL_VCC70_LINK_LIBRARY_OUTPUT_MAYBE = $(outbase).lst $(outbase).exp $(outbase).pdb define TOOL_VCC70_LINK_LIBRARY_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs) \ $(filter-out %.def,$(othersrc))) \ $(addprefix /DEF:,$(filter %.def,$(othersrc))) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC70_AR) $(flags) /OUT:$(out) @$(outbase).rsp endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_VCC70_LINK_PROGRAM_OUTPUT = $(outbase).rsp TOOL_VCC70_LINK_PROGRAM_OUTPUT_MAYBE = $(outbase).map $(outbase).lib $(outbase).exp $(outbase).ilk TOOL_VCC70_LINK_PROGRAM_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC70_LINK_PROGRAM_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb TOOL_VCC70_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC70_LINK_PROGRAM_DEPORD = define TOOL_VCC70_LINK_PROGRAM_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC70_LD) $(flags) \ /OUT:$(out) \ /MAPINFO:EXPORTS /INCREMENTAL:NO /MAPINFO:LINES \ /MAP:$(outbase).map \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp endef ## Link DLL. # @param $(target) Normalized main target name. # @param $(out) DLL name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_VCC70_LINK_DLL_OUTPUT = $(outbase).map $(outbase).lib $(outbase).exp $(outbase).rsp TOOL_VCC70_LINK_DLL_OUTPUT_MAYBE = $(outbase).ilk $(PATH_STAGE_LIB)/$(notdir $(outbase)).lib $(PATH_STAGE_LIB)/$(notdir $(outbase)).exp TOOL_VCC70_LINK_DLL_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC70_LINK_DLL_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb TOOL_VCC70_LINK_DLL_DEPEND = $(objs) $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC70_LINK_DLL_DEPORD = $(call DIRDEP,$(PATH_STAGE_LIB)) define TOOL_VCC70_LINK_DLL_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC70_LD) $(flags) \ /OUT:$(out) \ /IMPLIB:$(outbase).lib \ /MAPINFO:EXPORTS /INCREMENTAL:NO /MAPINFO:LINES \ /MAP:$(outbase).map \ /DLL \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp $(QUIET)$(CP) --changed --ignore-non-existing $(outbase).exp $(outbase).lib $(PATH_STAGE_LIB)/ $(eval _DIRS += $(PATH_STAGE_LIB)) endef ## Link system module (windows aka driver, linux aka kernel module) # @param $(target) Normalized main target name. # @param $(out) System module name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_VCC70_LINK_SYSMOD_OUTPUT = $(outbase).map $(outbase).rsp TOOL_VCC70_LINK_SYSMOD_OUTPUT_MAYBE = $(outbase).lib $(outbase).exp $(outbase).ilk TOOL_VCC70_LINK_SYSMOD_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC70_LINK_SYSMOD_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb TOOL_VCC70_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC70_LINK_SYSMOD_DEPORD = define TOOL_VCC70_LINK_SYSMOD_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC70_LD) $(flags) \ /OUT:$(out) \ /MAPINFO:EXPORTS /INCREMENTAL:NO /MAPINFO:LINES \ /MAP:$(outbase).map \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp endef kbuild-3149/kBuild/tools/ALP.kmk0000644000175000017500000000520413252530251016375 0ustar locutuslocutus# $Id: ALP.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - ALP or later. # # # Copyright (c) 2005-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_ALP := The IBM Assembly Language Processor # Tool Specific Properties ifndef PATH_TOOL_ALP PATH_TOOL_ALP := $(sort $(wildcard $(KBUILD_DEVTOOLS_HST)/alp/v*.*)) ifneq ($(PATH_TOOL_ALP),) PATH_TOOL_ALP := $(call lastword,$(PATH_TOOL_ALP)) endif endif ifneq ($(PATH_TOOL_ALP),) TOOL_ALP_AS ?= $(PATH_TOOL_ALP)/alp$(HOSTSUFF_EXE) else TOOL_ALP_AS ?= alp$(HOSTSUFF_EXE) endif # General Properties used by kBuild TOOL_ALP_ASFLAGS ?= -Mb ## Compile Assembly source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_ALP_COMPILE_AS_OUTPUT = $(outbase).lst TOOL_ALP_COMPILE_AS_DEPEND = TOOL_ALP_COMPILE_AS_DEPORD = define TOOL_ALP_COMPILE_AS_CMDS $(QUIET)$(TOOL_ALP_AS)\ $(flags) $(addsuffix /,$(addprefix -I:, $(incs))) $(addprefix -D:, $(defs))\ $(source)\ -Fl:$(outbase).lst\ -Fd:$(dep)\ -Fo:$(obj) endef kbuild-3149/kBuild/tools/VCC80AMD64.kmk0000644000175000017500000003447113252530251017250 0ustar locutuslocutus# $Id: VCC80AMD64.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - Visual C++ 8.0 (aka Visual .NET 2005, or MSC v14), targeting AMD64. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_VCC80AMD64 := Visual C++ 8.0 (aka Visual .NET 2005, or MSC v14), targeting AMD64. # Tool Specific Properties ifndef PATH_TOOL_VCC80AMD64 PATH_TOOL_VCC80AMD64 := $(wildcard $(KBUILD_DEVTOOLS)/win.x86/vcc/v8*) ifeq ($(PATH_TOOL_VCC80AMD64),) PATH_TOOL_VCC80AMD64 := $(PATH_TOOL_VCC80) endif ifeq ($(PATH_TOOL_VCC80AMD64),) PATH_TOOL_VCC80AMD64 := $(PATH_TOOL_VCC80X86) endif ifeq ($(PATH_TOOL_VCC80AMD64),) PATH_TOOL_VCC80AMD64 := $(wildcard $(KBUILD_DEVTOOLS)/win.x86/vcc/v8*) endif ifneq ($(PATH_TOOL_VCC80AMD64),) PATH_TOOL_VCC80AMD64 := $(lastword $(sort $(PATH_TOOL_VCC80AMD64))) else $(warning kBuild: PATH_TOOL_VCC80AMD64 cannot be determined!) PATH_TOOL_VCC80AMD64 := $(KBUILD_DEVTOOLS)/win.x86/vcc/v8 endif else # Resolve any fancy stuff once and for all. PATH_TOOL_VCC80AMD64 := $(PATH_TOOL_VCC80AMD64) endif ifeq ($(KBUILD_HOST).$(KBUILD_HOST_ARCH),win.amd64) PATH_TOOL_VCC80AMD64_BIN ?= $(PATH_TOOL_VCC80AMD64)/bin/amd64 else PATH_TOOL_VCC80AMD64_BIN ?= $(PATH_TOOL_VCC80AMD64)/bin/x86_amd64 endif PATH_TOOL_VCC80AMD64_LIB ?= $(PATH_TOOL_VCC80AMD64)/lib/amd64 PATH_TOOL_VCC80AMD64_INC ?= $(PATH_TOOL_VCC80AMD64)/include PATH_TOOL_VCC80AMD64_ATLMFC ?= $(PATH_TOOL_VCC80AMD64)/atlmfc PATH_TOOL_VCC80AMD64_ATLMFC_INC ?= $(PATH_TOOL_VCC80AMD64_ATLMFC)/include PATH_TOOL_VCC80AMD64_ATLMFC_LIB ?= $(PATH_TOOL_VCC80AMD64_ATLMFC)/lib/amd64 TOOL_VCC80AMD64_CC ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC80AMD64_BIN)/cl.exe TOOL_VCC80AMD64_CXX ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC80AMD64_BIN)/cl.exe TOOL_VCC80AMD64_AS ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC80AMD64_BIN)/ml64.exe TOOL_VCC80AMD64_RC ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC80AMD64_BIN)/../rc.exe TOOL_VCC80AMD64_AR ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC80AMD64_BIN)/lib.exe TOOL_VCC80AMD64_LD ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC80AMD64_BIN)/link.exe TOOL_VCC80AMD64_MT ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC80AMD64_BIN)/../mt.exe ## Disabled fast DEP_IDB based dependencies. #VCC80AMD64_OLD_DEPS = 1 ## Constructs the correct .pdb name (the name is lowercased). # @param $(1) Base name, no extention. # @param $(2) The extension. TOOL_VCC80AMD64_PDB = $(dir $(1))$(tolower $(notdir $(1))).$(2) TOOL_VCC80AMD64_COBJSUFF ?= .obj TOOL_VCC80AMD64_CFLAGS ?= -TC -c -nologo TOOL_VCC80AMD64_CFLAGS.debug ?= -Od -Zi TOOL_VCC80AMD64_CFLAGS.release ?= -O2 TOOL_VCC80AMD64_CFLAGS.profile ?= -O2 TOOL_VCC80AMD64_CINCS ?= $(PATH_TOOL_VCC80AMD64_INC) TOOL_VCC80AMD64_CDEFS ?= TOOL_VCC80AMD64_CXXOBJSUFF ?= .obj TOOL_VCC80AMD64_CXXFLAGS ?= -TP -c -nologo TOOL_VCC80AMD64_CXXFLAGS.debug ?= -Od -Zi TOOL_VCC80AMD64_CXXFLAGS.release ?= -O2 TOOL_VCC80AMD64_CXXFLAGS.profile ?= -O2 TOOL_VCC80AMD64_CXXINCS ?= $(PATH_TOOL_VCC80AMD64_INC) $(PATH_TOOL_VCC80AMD64_ATLMFC_INC) TOOL_VCC80AMD64_CXXDEFS ?= TOOL_VCC80AMD64_ASOBJSUFF ?= .obj TOOL_VCC80AMD64_RCOBJSUFF ?= .res TOOL_VCC80AMD64_RCINCS ?= $(PATH_TOOL_VCC80AMD64_INC) $(PATH_TOOL_VCC80AMD64_ATLMFC_INC) TOOL_VCC80AMD64_ARFLAGS ?= -nologo -machine:amd64 TOOL_VCC80AMD64_ARLIBSUFF ?= .lib TOOL_VCC80AMD64_LDFLAGS ?= -nologo -machine:amd64 TOOL_VCC80AMD64_LDFLAGS.debug ?= -debug TOOL_VCC80AMD64_LDFLAGS.release ?= ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC80AMD64_COMPILE_C_DEPEND = TOOL_VCC80AMD64_COMPILE_C_DEPORD = TOOL_VCC80AMD64_COMPILE_C_OUTPUT = $(call TOOL_VCC80AMD64_PDB, $(outbase)-obj,idb) TOOL_VCC80AMD64_COMPILE_C_OUTPUT_MAYBE = $(call TOOL_VCC80AMD64_PDB, $(outbase)-obj,pdb) define TOOL_VCC80AMD64_COMPILE_C_CMDS $(QUIET)$(TOOL_VCC80AMD64_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fd$(outbase)-obj.pdb \ -FD\ -Fo$(obj)\ $(subst /,\\,$(abspath $(source))) $(QUIET)$(DEP_IDB) -f -s -q -o $(dep) -t $(obj) $(call TOOL_VCC80AMD64_PDB,$(outbase)-obj,idb) endef ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC80AMD64_COMPILE_CXX_DEPEND = TOOL_VCC80AMD64_COMPILE_CXX_DEPORD = TOOL_VCC80AMD64_COMPILE_CXX_OUTPUT = $(call TOOL_VCC80AMD64_PDB, $(outbase)-obj,idb) TOOL_VCC80AMD64_COMPILE_CXX_OUTPUT_MAYBE = $(call TOOL_VCC80AMD64_PDB, $(outbase)-obj,pdb) define TOOL_VCC80AMD64_COMPILE_CXX_CMDS $(QUIET)$(TOOL_VCC80AMD64_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fd$(outbase)-obj.pdb \ -FD\ -Fo$(obj)\ $(subst /,\\,$(abspath $(source))) $(QUIET)$(DEP_IDB) -f -s -q -o $(dep) -t $(obj) $(call TOOL_VCC80AMD64_PDB,$(outbase)-obj,idb) endef ## Compile resource source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC80AMD64_COMPILE_RC_DEPEND = TOOL_VCC80AMD64_COMPILE_RC_DEPORD = TOOL_VCC80AMD64_COMPILE_RC_OUTPUT = define TOOL_VCC80AMD64_COMPILE_RC_CMDS $(QUIET)$(TOOL_VCC80AMD64_RC) \ $(flags) $(addprefix /i, $(subst /,\\,$(incs))) $(addprefix /d, $(defs))\ /fo$(obj)\ $(subst /,\\,$(abspath $(source))) endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_VCC80AMD64_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_VCC80AMD64_LINK_LIBRARY_DEPORD = TOOL_VCC80AMD64_LINK_LIBRARY_OUTPUT = $(outbase).rsp TOOL_VCC80AMD64_LINK_LIBRARY_OUTPUT_MAYBE = $(outbase).lst $(outbase).exp $(outbase).pdb define TOOL_VCC80AMD64_LINK_LIBRARY_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs) \ $(filter-out %.def,$(othersrc))) \ $(addprefix /DEF:,$(filter %.def,$(othersrc))) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC80AMD64_AR) $(flags) /OUT:$(out) @$(outbase).rsp endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_VCC80AMD64_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC80AMD64_LINK_PROGRAM_DEPORD = TOOL_VCC80AMD64_LINK_PROGRAM_OUTPUT = $(outbase).map $(outbase).rsp TOOL_VCC80AMD64_LINK_PROGRAM_OUTPUT_MAYBE = $(outbase).lib $(outbase).exp $(outbase).ilk $(out).manifest TOOL_VCC80AMD64_LINK_PROGRAM_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC80AMD64_LINK_PROGRAM_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb define TOOL_VCC80AMD64_LINK_PROGRAM_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC80AMD64_LD) $(flags) \ /OUT:$(out) \ /MAPINFO:EXPORTS /INCREMENTAL:NO \ /MAP:$(outbase).map \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp $(QUIET)$(TEST) -f $(out).manifest -- \ $(TOOL_VCC80AMD64_MT) -manifest $(subst /,\\,$(out)).manifest -outputresource:$(subst /,\\,$(out)) endef ## Link DLL. # @param $(target) Normalized main target name. # @param $(out) DLL name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_VCC80AMD64_LINK_DLL_DEPEND = $(objs) $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC80AMD64_LINK_DLL_DEPORD = $(call DIRDEP,$(PATH_STAGE_LIB)) TOOL_VCC80AMD64_LINK_DLL_OUTPUT = $(outbase).map $(outbase).lib $(outbase).exp $(outbase).rsp TOOL_VCC80AMD64_LINK_DLL_OUTPUT_MAYBE = $(outbase).ilk $(out).manifest $(PATH_STAGE_LIB)/$(notdir $(outbase)).lib $(PATH_STAGE_LIB)/$(notdir $(outbase)).exp TOOL_VCC80AMD64_LINK_DLL_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC80AMD64_LINK_DLL_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb define TOOL_VCC80AMD64_LINK_DLL_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC80AMD64_LD) $(flags) \ /OUT:$(out) \ /IMPLIB:$(outbase).lib \ /MAPINFO:EXPORTS /INCREMENTAL:NO \ /MAP:$(outbase).map \ /DLL \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp $(QUIET)$(TEST) -f $(out).manifest -- \ $(TOOL_VCC80AMD64_MT) -manifest $(subst /,\\,$(out)).manifest '-outputresource:$(subst /,\\,$(out));#2' $(QUIET)$(CP) --changed --ignore-non-existing $(outbase).exp $(outbase).lib $(PATH_STAGE_LIB)/ $(eval _DIRS += $(PATH_STAGE_LIB)) endef ## Link system module (windows aka driver, linux aka kernel module) # @param $(target) Normalized main target name. # @param $(out) System module name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_VCC80AMD64_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC80AMD64_LINK_SYSMOD_DEPORD = TOOL_VCC80AMD64_LINK_SYSMOD_OUTPUT = $(outbase).map $(outbase).rsp TOOL_VCC80AMD64_LINK_SYSMOD_OUTPUT_MAYBE = $(outbase).lib $(outbase).exp $(outbase).ilk $(out).manifest TOOL_VCC80AMD64_LINK_SYSMOD_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC80AMD64_LINK_SYSMOD_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb define TOOL_VCC80AMD64_LINK_SYSMOD_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC80AMD64_LD) $(flags) \ /OUT:$(out) \ /MAPINFO:EXPORTS /INCREMENTAL:NO \ /MAP:$(outbase).map \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp $(QUIET)$(TEST) -f $(out).manifest -- \ $(TOOL_VCC80AMD64_MT) -manifest $(subst /,\\,$(out)).manifest '-outputresource:$(subst /,\\,$(out));#2' endef kbuild-3149/kBuild/tools/GCC42MACHO.kmk0000644000175000017500000004566613252530251017313 0ustar locutuslocutus# $Id: GCC42MACHO.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - GCC v4.2.x targeting Darwin (Mac OS X) Mach-O. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_GCC42MACHO := GCC v4.2.x targeting Darwin (Mac OS X) Mach-O. # Tool Specific Properties TOOL_GCC42MACHO_PREFIX ?= TOOL_GCC42MACHO_SUFFIX ?= -4.2$(HOSTSUFF_EXE) TOOL_GCC42MACHO_CC ?= $(TOOL_GCC42MACHO_PREFIX)gcc$(TOOL_GCC42MACHO_SUFFIX) TOOL_GCC42MACHO_CXX ?= $(TOOL_GCC42MACHO_PREFIX)g++$(TOOL_GCC42MACHO_SUFFIX) TOOL_GCC42MACHO_OBJC ?= $(TOOL_GCC42MACHO_PREFIX)gcc$(TOOL_GCC42MACHO_SUFFIX) TOOL_GCC42MACHO_OBJCXX ?= $(TOOL_GCC42MACHO_PREFIX)gcc$(TOOL_GCC42MACHO_SUFFIX) TOOL_GCC42MACHO_AS ?= $(TOOL_GCC42MACHO_PREFIX)gcc$(TOOL_GCC42MACHO_SUFFIX) TOOL_GCC42MACHO_LD ?= $(TOOL_GCC42MACHO_PREFIX)gcc$(TOOL_GCC42MACHO_SUFFIX) TOOL_GCC42MACHO_LD_SYSMOD ?= $(TOOL_GCC42MACHO_PREFIX)gcc$(TOOL_GCC42MACHO_SUFFIX) ifndef TOOL_GCC42MACHO_LDFLAGS.$(KBUILD_TARGET) TOOL_GCC42MACHO_LDFLAGS.dll ?= -dynamiclib else TOOL_GCC42MACHO_LDFLAGS.dll ?= $(TOOL_GCC42MACHO_LDFLAGS.$(KBUILD_TARGET)) endif TOOL_GCC42MACHO_LDFLAGS.sysmod ?= -r #TOOL_GCC42MACHO_LD_SONAME = -Wl,-dylib_install_name $(firstword $($(1)_SONAME.$(KBUILD_TARGET).$(KBUILD_TYPE)) $($(1)_SONAME.$(KBUILD_TARGET)) $($(1)_SONAME.$(KBUILD_TYPE)) $($(1)_SONAME) $(notdir $(2))) TOOL_GCC42MACHO_DSYMUTIL ?= dsymutil ifdef SLKRUNS TOOL_GCC42MACHO_CC += -fmessage-length=0 TOOL_GCC42MACHO_CXX += -fmessage-length=0 TOOL_GCC42MACHO_OBJC += -fmessage-length=0 TOOL_GCC42MACHO_OBJCXX += -fmessage-length=0 endif # General Properties used by kBuild TOOL_GCC42MACHO_COBJSUFF ?= .o TOOL_GCC42MACHO_CFLAGS ?= TOOL_GCC42MACHO_CFLAGS.debug ?= -g TOOL_GCC42MACHO_CFLAGS.profile ?= -g -O2 #-pg TOOL_GCC42MACHO_CFLAGS.release ?= -O2 TOOL_GCC42MACHO_CINCS ?= TOOL_GCC42MACHO_CDEFS ?= TOOL_GCC42MACHO_CXXOBJSUFF ?= .o TOOL_GCC42MACHO_CXXFLAGS ?= TOOL_GCC42MACHO_CXXFLAGS.debug ?= -g TOOL_GCC42MACHO_CXXFLAGS.profile ?= -g -O2 #-pg TOOL_GCC42MACHO_CXXFLAGS.release ?= -O2 TOOL_GCC42MACHO_CXXINCS ?= TOOL_GCC42MACHO_CXXDEFS ?= TOOL_GCC42MACHO_OBJCOBJSUFF ?= .o TOOL_GCC42MACHO_OBJCFLAGS ?= TOOL_GCC42MACHO_OBJCFLAGS.debug ?= -g TOOL_GCC42MACHO_OBJCFLAGS.profile?= -O2 #-g -pg TOOL_GCC42MACHO_OBJCFLAGS.release?= -O2 TOOL_GCC42MACHO_OBJCINCS ?= TOOL_GCC42MACHO_OBJCDEFS ?= TOOL_GCC42MACHO_OBJCXXOBJSUFF ?= .o TOOL_GCC42MACHO_OBJCXXFLAGS ?= TOOL_GCC42MACHO_OBJCXXFLAGS.debug ?= -g TOOL_GCC42MACHO_OBJCXXFLAGS.profile ?= -O2 #-g -pg TOOL_GCC42MACHO_OBJCXXFLAGS.release ?= -O2 TOOL_GCC42MACHO_OBJCXXINCS ?= TOOL_GCC42MACHO_OBJCXXDEFS ?= TOOL_GCC42MACHO_ASFLAGS ?= -x assembler-with-cpp TOOL_GCC42MACHO_ASFLAGS.debug ?= -g TOOL_GCC42MACHO_ASFLAGS.profile ?= -g TOOL_GCC42MACHO_ASOBJSUFF ?= .o TOOL_GCC42MACHO_AR ?= ar$(HOSTSUFF_EXE) TOOL_GCC42MACHO_ARFLAGS ?= -c -rs TOOL_GCC42MACHO_ARLIBSUFF ?= .a TOOL_GCC42MACHO_LDFLAGS ?= TOOL_GCC42MACHO_LDFLAGS.debug ?= -g TOOL_GCC42MACHO_LDFLAGS.profile ?= -g TOOL_GCC42MACHO_STRIP_PROGRAM ?= strip -SXxru TOOL_GCC42MACHO_STRIP_DLL ?= strip -Sxru TOOL_GCC42MACHO_STRIP_SYSMOD ?= strip -Sru ## # Calculate the files in the debug bundle. # @param 1 The whole output filename. # @param 2 The output filename sans suffix. TOOL_GCC42MACHO_DEBUG_BUNDLE_FN = \ $(1).dSYM/ \ $(1).dSYM/Contents/ \ $(1).dSYM/Contents/Resources/ \ $(1).dSYM/Contents/Resources/DWARF/ \ $(1).dSYM/Contents/Info.plist \ $(1).dSYM/Contents/Resources/DWARF/$(notdir $(1)) ## # Calculate the files in the debug bundle. # @param 1 The whole linker output filename. # @param 2 The linker output filename sans suffix. # @param 3 The desired install name (no dir slash). # @remarks The Info.plist has some reference to the original name, but gdb # does not care and only check for a symbol file in the DWARF # directory with the same name as the debugged module. TOOL_GCC42MACHO_DEBUG_INSTALL_FN= \ $(3).dSYM/ \ $(3).dSYM/Contents/ \ $(3).dSYM/Contents/Resources/ \ $(3).dSYM/Contents/Resources/DWARF/ \ $(1).dSYM/Contents/Info.plist=>$(3).dSYM/Contents/Info.plist \ $(1).dSYM/Contents/Resources/DWARF/$(notdir $(1))=>$(3).dSYM/Contents/Resources/DWARF/$(notdir $(3)) ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GCC42MACHO_COMPILE_C_DEPEND = TOOL_GCC42MACHO_COMPILE_C_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GCC42MACHO_COMPILE_C_USES_KOBJCACHE = 1 TOOL_GCC42MACHO_COMPILE_C_OUTPUT = $(outbase).i define TOOL_GCC42MACHO_COMPILE_C_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).i\ $(TOOL_GCC42MACHO_CC) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GCC42MACHO_CC) -c\ $(flags) -fpreprocessed -x c\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GCC42MACHO_COMPILE_C_OUTPUT = define TOOL_GCC42MACHO_COMPILE_C_CMDS $(QUIET)$(TOOL_GCC42MACHO_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KUSE_OBJCACHE ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GCC42MACHO_COMPILE_CXX_DEPEND = TOOL_GCC42MACHO_COMPILE_CXX_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GCC42MACHO_COMPILE_CXX_USES_KOBJCACHE = 1 TOOL_GCC42MACHO_COMPILE_CXX_OUTPUT = $(outbase).ii define TOOL_GCC42MACHO_COMPILE_CXX_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).ii\ $(TOOL_GCC42MACHO_CXX) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GCC42MACHO_CXX) -c\ $(flags) -fpreprocessed -x c++\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GCC42MACHO_COMPILE_CXX_OUTPUT = define TOOL_GCC42MACHO_COMPILE_CXX_CMDS $(QUIET)$(TOOL_GCC42MACHO_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile Objective-C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GCC42MACHO_COMPILE_OBJC_DEPEND = TOOL_GCC42MACHO_COMPILE_OBJC_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GCC42MACHO_COMPILE_OBJC_USES_KOBJCACHE = 1 TOOL_GCC42MACHO_COMPILE_OBJC_OUTPUT = $(outbase).mi define TOOL_GCC42MACHO_COMPILE_OBJC_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).ii\ $(TOOL_GCC42MACHO_OBJC) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GCC42MACHO_OBJC) -c\ $(flags) -fpreprocessed -x cbjective-c\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GCC42MACHO_COMPILE_OBJC_OUTPUT = define TOOL_GCC42MACHO_COMPILE_OBJC_CMDS $(QUIET)$(TOOL_GCC42MACHO_OBJC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile Objective-C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GCC42MACHO_COMPILE_OBJCXX_DEPEND = TOOL_GCC42MACHO_COMPILE_OBJCXX_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GCC42MACHO_COMPILE_OBJCXX_USES_KOBJCACHE = 1 TOOL_GCC42MACHO_COMPILE_OBJCXX_OUTPUT = $(outbase).mii define TOOL_GCC42MACHO_COMPILE_OBJCXX_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).mii\ $(TOOL_GCC42MACHO_OBJCXX) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GCC42MACHO_OBJCXX) -c\ $(flags) -fpreprocessed -x objective-c++\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GCC42MACHO_COMPILE_OBJCXX_OUTPUT = define TOOL_GCC42MACHO_COMPILE_OBJCXX_CMDS $(QUIET)$(TOOL_GCC42MACHO_OBJCXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile Assembly source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. # TOOL_GCC42MACHO_COMPILE_AS_OUTPUT = TOOL_GCC42MACHO_COMPILE_AS_DEPEND = TOOL_GCC42MACHO_COMPILE_AS_DEPORD = define TOOL_GCC42MACHO_COMPILE_AS_CMDS $(QUIET)$(TOOL_GCC42MACHO_AS) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC42MACHO_LINK_LIBRARY_OUTPUT = TOOL_GCC42MACHO_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_GCC42MACHO_LINK_LIBRARY_DEPORD = define TOOL_GCC42MACHO_LINK_LIBRARY_CMDS $(if $(strip $(objs)),$(call xargs,$(QUIET)$(TOOL_GCC42MACHO_AR) $(flags) $(out),$(objs))) $(foreach lib,$(othersrc)\ ,$(NL)$(TAB)$(call MSG_AR_MERGE,$(target),$(out),$(lib)) \ $(NL)$(TAB)$(QUIET)$(RM_EXT) -f $(dir $(outbase))ar.tmp.dir/* \ $(NL)$(TAB)$(QUIET)$(MKDIR) -p $(dir $(outbase))/ar.tmp.dir/ \ $(NL)$(TAB)$(QUIET)(cd $(dir $(outbase))ar.tmp.dir/ \ && $(TOOL_GCC42MACHO_AR) -x $(abspath $(lib)) \ && $(RM_EXT) -f ./__.SYMDEF* \ && $(TOOL_GCC42MACHO_AR) $(flags) $(out) *) \ $(NL)$(TAB)$(QUIET)$(RM_EXT) -f $(dir $(outbase))/ar.tmp.dir/* \ $(NL)$(TAB)$(QUIET)$(RMDIR) $(dir $(outbase))ar.tmp.dir/) endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC42MACHO_LINK_PROGRAM_OUTPUT = $(outbase).rsp TOOL_GCC42MACHO_LINK_PROGRAM_OUTPUT_DEBUG = $(call TOOL_GCC42MACHO_DEBUG_BUNDLE_FN,$(out)) TOOL_GCC42MACHO_LINK_PROGRAM_DEBUG_INSTALL_FN = $(TOOL_GCC42MACHO_DEBUG_INSTALL_FN) TOOL_GCC42MACHO_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_GCC42MACHO_LINK_PROGRAM_DEPORD = define TOOL_GCC42MACHO_LINK_PROGRAM_CMDS $(QUIET)$(APPEND) -n $(outbase).rsp $(objs) $(QUIET)$(TOOL_GCC42MACHO_LD) $(flags) -o $(out)\ -filelist $(outbase).rsp\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib))) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GCC42MACHO_DSYMUTIL) -o $(out).dSYM/ $(out) $(QUIET)$(TOOL_GCC42MACHO_STRIP_PROGRAM) $(out) endif endef ## Link DLL # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC42MACHO_LINK_DLL_OUTPUT = $(outbase).rsp TOOL_GCC42MACHO_LINK_DLL_OUTPUT_DEBUG = $(call TOOL_GCC42MACHO_DEBUG_BUNDLE_FN,$(out)) TOOL_GCC42MACHO_LINK_DLL_DEBUG_INSTALL_FN = $(TOOL_GCC42MACHO_DEBUG_INSTALL_FN) TOOL_GCC42MACHO_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_GCC42MACHO_LINK_DLL_DEPORD = define TOOL_GCC42MACHO_LINK_DLL_CMDS $(QUIET)$(APPEND) -n $(outbase).rsp $(objs) $(QUIET)$(TOOL_GCC42MACHO_LD) $(TOOL_GCC42MACHO_LDFLAGS.dll) $(flags) -o $(out)\ $(call TOOL_GCC42MACHO_LD_SONAME,$(target),$(out))\ -filelist $(outbase).rsp\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib))) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GCC42MACHO_DSYMUTIL) -o $(out).dSYM/ $(out) $(QUIET)$(TOOL_GCC42MACHO_STRIP_DLL) $(out) endif endef ## Link system module (windows aka driver, linux aka kernel module) # @param $(target) Normalized main target name. # @param $(out) System module name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC42MACHO_LINK_SYSMOD_OUTPUT = $(outbase).rsp TOOL_GCC42MACHO_LINK_SYSMOD_OUTPUT_DEBUG = $(call TOOL_GCC42MACHO_DEBUG_BUNDLE_FN,$(out)) TOOL_GCC42MACHO_LINK_SYSMOD_DEBUG_INSTALL_FN = $(TOOL_GCC42MACHO_DEBUG_INSTALL_FN) TOOL_GCC42MACHO_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_GCC42MACHO_LINK_SYSMOD_DEPORD = define TOOL_GCC42MACHO_LINK_SYSMOD_CMDS $(QUIET)$(APPEND) -n $(outbase).rsp $(objs) $(QUIET)$(TOOL_GCC42MACHO_LD_SYSMOD) $(TOOL_GCC42MACHO_LDFLAGS.sysmod) $(flags) -o $(out)\ -filelist $(outbase).rsp\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib))) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GCC42MACHO_DSYMUTIL) -o $(out).dSYM/ $(out) $(QUIET)$(TOOL_GCC42MACHO_STRIP_SYSMOD) $(out) endif endef kbuild-3149/kBuild/tools/MSLINK510.kmk0000644000175000017500000001177513252530251017216 0ustar locutuslocutus# $Id: MSLINK510.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - Microsoft Link v5.10 # # # Copyright (c) 2008-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_MSLINK510 := Microsoft Segmented-Executable Linker Version 5.10 # Tool Specific Properties ifndef TOOL_MSLINK510_LD TOOL_MSLINK510_LD := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS)/os2.x86/ddk/*/base/tools/link$(HOSTSUFF_EXE)))) ifeq ($(TOOL_MSLINK510_LD),) TOOL_MSLINK510_LD := $(firstword $(rsort $(wildcard \ $(KBUILD_DEVTOOLS)/os2.x86/ddk/*/video/tools/os2.386/lx.386/bin/link$(HOSTSUFF_EXE) \ $(KBUILD_DEVTOOLS)/os2.x86/ddk/*/base32/tools/os2.386/bin/link$(HOSTSUFF_EXE) \ $(KBUILD_DEVTOOLS)/os2.x86/ddk/*/base32/tools/os2.386/lx.386/bin/link$(HOSTSUFF_EXE) \ $(KBUILD_DEVTOOLS)/os2.x86/ddk/*/print/tools/os2.386/lx.386/bin/link$(HOSTSUFF_EXE) \ $(KBUILD_DEVTOOLS)/os2.x86/ddk/*/wpshell/tools/os2.386/lx.386/bin/link$(HOSTSUFF_EXE) \ $(KBUILD_DEVTOOLS)/os2.x86/ddk/*/mme/tools/os2.386/lx.386/bin/link$(HOSTSUFF_EXE) \ ))) endif ifneq ($(TOOL_MSLINK510_LD),) TOOL_MSLINK510_LD := $(TOOL_MSLINK510_LD) endif endif ifeq ($(TOOL_MSLINK510_LD),) TOOL_MSLINK510_LD := $(firstword $(which link$(HOSTSUFF_EXE)) path/notfound/link$(HOSTSUFF_EXE)) endif TOOL_MSLINK510_ENV_SETUP = $(REDIRECT) \ -Z -E 'LIB=$1' \ -- # General Properties used by kBuild TOOL_MSLINK510_LDFLAGS ?= /nologo /map:full /linenumbers TOOL_MSLINK510_LINK_PROGRAM_OUTPUT = $(outbase).map $(outbase).rsp TOOL_MSLINK510_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_MSLINK510_LINK_PROGRAM_DEPORD = define TOOL_MSLINK510_LINK_PROGRAM_CMDS $(QUIET)$(APPEND) -n $(outbase).rsp '$(subst $(SP),+' ',$(strip $(subst /,\,$(objs)))),' $(QUIET)$(APPEND) $(outbase).rsp '$(subst /,\,$(out)),' $(QUIET)$(APPEND) $(outbase).rsp '$(subst /,\,$(outbase)).map,' $(QUIET)$(APPEND) -n $(outbase).rsp '$(subst $(SP),+' ',$(strip $(subst /,\,$(libs))))$(if $(filter %.def,$(othersrc)),$(COMMA),;)' $(if $(filter %.def,$(othersrc)),$(QUIET)$(APPEND) $(outbase).rsp '$(subst /,\,$(filter %.def,$(othersrc)));',) $(QUIET)$(call TOOL_MSLINK510_ENV_SETUP,$(subst $(SP),;,$(libpath))) \ $(TOOL_MSLINK510_LD) $(flags) '@$(subst /,\,$(outbase).rsp)' endef TOOL_MSLINK510_LINK_DLL_OUTPUT = $(outbase).map $(outbase).rsp TOOL_MSLINK510_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_MSLINK510_LINK_DLL_DEPORD = define TOOL_MSLINK510_LINK_DLL_CMDS $(QUIET)$(APPEND) -n $(outbase).rsp '$(subst $(SP),+' ',$(strip $(subst /,\,$(objs)))),' $(QUIET)$(APPEND) $(outbase).rsp '$(subst /,\,$(out)),' $(QUIET)$(APPEND) $(outbase).rsp '$(subst /,\,$(outbase)).map,' $(QUIET)$(APPEND) -n $(outbase).rsp '$(subst $(SP),+' ',$(strip $(subst /,\,$(libs))))$(if $(filter %.def,$(othersrc)),$(COMMA),;)' $(if $(filter %.def,$(othersrc)),$(QUIET)$(APPEND) $(outbase).rsp '$(subst /,\,$(filter %.def,$(othersrc)));',) $(QUIET)$(call TOOL_MSLINK510_ENV_SETUP,$(subst $(SP),;,$(libpath))) \ $(TOOL_MSLINK510_LD) $(flags) '@$(subst /,\,$(outbase).rsp)' endef TOOL_MSLINK510_LINK_SYSMOD_OUTPUT = $(outbase).map $(outbase).rsp TOOL_MSLINK510_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_MSLINK510_LINK_SYSMOD_DEPORD = define TOOL_MSLINK510_LINK_SYSMOD_CMDS $(QUIET)$(APPEND) -n $(outbase).rsp '$(subst $(SP),+' ',$(strip $(subst /,\,$(objs)))),' $(QUIET)$(APPEND) $(outbase).rsp '$(subst /,\,$(out)),' $(QUIET)$(APPEND) $(outbase).rsp '$(subst /,\,$(outbase)).map,' $(QUIET)$(APPEND) -n $(outbase).rsp '$(subst $(SP),+' ',$(strip $(subst /,\,$(libs))))$(if $(filter %.def,$(othersrc)),$(COMMA),;)' $(if $(filter %.def,$(othersrc)),$(QUIET)$(APPEND) $(outbase).rsp '$(subst /,\,$(filter %.def,$(othersrc)));',) $(QUIET)$(call TOOL_MSLINK510_ENV_SETUP,$(subst $(SP),;,$(libpath))) \ $(TOOL_MSLINK510_LD) $(flags) '@$(subst /,\,$(outbase).rsp)' endef kbuild-3149/kBuild/tools/GXX42MACHO.kmk0000644000175000017500000004573113252530251017356 0ustar locutuslocutus# $Id: GXX42MACHO.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - GCC v4.2.x targeting Darwin (Mac OS X) Mach-O, for building C++ code. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_GXX42MACHO := GCC v4.2.x targeting Darwin (Mac OS X) Mach-O, for building C++ code. # Tool Specific Properties TOOL_GXX42MACHO_PREFIX ?= TOOL_GXX42MACHO_SUFFIX ?= -4.2$(HOSTSUFF_EXE) TOOL_GXX42MACHO_CC ?= $(TOOL_GXX42MACHO_PREFIX)gcc$(TOOL_GXX42MACHO_SUFFIX) TOOL_GXX42MACHO_CXX ?= $(TOOL_GXX42MACHO_PREFIX)g++$(TOOL_GXX42MACHO_SUFFIX) TOOL_GXX42MACHO_OBJC ?= $(TOOL_GXX42MACHO_PREFIX)gcc$(TOOL_GXX42MACHO_SUFFIX) TOOL_GXX42MACHO_OBJCXX ?= $(TOOL_GXX42MACHO_PREFIX)gcc$(TOOL_GXX42MACHO_SUFFIX) TOOL_GXX42MACHO_AS ?= $(TOOL_GXX42MACHO_PREFIX)gcc$(TOOL_GXX42MACHO_SUFFIX) TOOL_GXX42MACHO_LD ?= $(TOOL_GXX42MACHO_PREFIX)g++$(TOOL_GXX42MACHO_SUFFIX) TOOL_GXX42MACHO_LD_SYSMOD ?= $(TOOL_GXX42MACHO_PREFIX)g++$(TOOL_GXX42MACHO_SUFFIX) ifndef TOOL_GXX42MACHO_LDFLAGS.$(KBUILD_TARGET) TOOL_GXX42MACHO_LDFLAGS.dll ?= -dynamiclib else TOOL_GXX42MACHO_LDFLAGS.dll ?= $(TOOL_GXX42MACHO_LDFLAGS.$(KBUILD_TARGET)) endif TOOL_GXX42MACHO_LDFLAGS.sysmod ?= -r #TOOL_GXX42MACHO_LD_SONAME = -Wl,-dylib_install_name $(firstword $($(1)_SONAME.$(KBUILD_TARGET).$(KBUILD_TYPE)) $($(1)_SONAME.$(KBUILD_TARGET)) $($(1)_SONAME.$(KBUILD_TYPE)) $($(1)_SONAME) $(notdir $(2))) TOOL_GXX42MACHO_DSYMUTIL ?= dsymutil ifdef SLKRUNS TOOL_GXX42MACHO_CC += -fmessage-length=0 TOOL_GXX42MACHO_CXX += -fmessage-length=0 TOOL_GXX42MACHO_OBJC += -fmessage-length=0 TOOL_GXX42MACHO_OBJCXX += -fmessage-length=0 endif # General Properties used by kBuild TOOL_GXX42MACHO_COBJSUFF ?= .o TOOL_GXX42MACHO_CFLAGS ?= TOOL_GXX42MACHO_CFLAGS.debug ?= -g TOOL_GXX42MACHO_CFLAGS.profile ?= -O2 #-g -pg TOOL_GXX42MACHO_CFLAGS.release ?= -O2 TOOL_GXX42MACHO_CINCS ?= TOOL_GXX42MACHO_CDEFS ?= TOOL_GXX42MACHO_CXXOBJSUFF ?= .o TOOL_GXX42MACHO_CXXFLAGS ?= TOOL_GXX42MACHO_CXXFLAGS.debug ?= -g TOOL_GXX42MACHO_CXXFLAGS.profile ?= -O2 #-g -pg TOOL_GXX42MACHO_CXXFLAGS.release ?= -O2 TOOL_GXX42MACHO_CXXINCS ?= TOOL_GXX42MACHO_CXXDEFS ?= TOOL_GXX42MACHO_OBJCOBJSUFF ?= .o TOOL_GXX42MACHO_OBJCFLAGS ?= TOOL_GXX42MACHO_OBJCFLAGS.debug ?= -g TOOL_GXX42MACHO_OBJCFLAGS.profile?= -O2 #-g -pg TOOL_GXX42MACHO_OBJCFLAGS.release?= -O2 TOOL_GXX42MACHO_OBJCINCS ?= TOOL_GXX42MACHO_OBJCDEFS ?= TOOL_GXX42MACHO_OBJCXXOBJSUFF ?= .o TOOL_GXX42MACHO_OBJCXXFLAGS ?= TOOL_GXX42MACHO_OBJCXXFLAGS.debug ?= -g TOOL_GXX42MACHO_OBJCXXFLAGS.profile ?= -O2 #-g -pg TOOL_GXX42MACHO_OBJCXXFLAGS.release ?= -O2 TOOL_GXX42MACHO_OBJCXXINCS ?= TOOL_GXX42MACHO_OBJCXXDEFS ?= TOOL_GXX42MACHO_ASFLAGS ?= -x assembler-with-cpp TOOL_GXX42MACHO_ASFLAGS.debug ?= -g TOOL_GXX42MACHO_ASFLAGS.profile ?= -g TOOL_GXX42MACHO_ASOBJSUFF ?= .o TOOL_GXX42MACHO_AR ?= ar$(HOSTSUFF_EXE) TOOL_GXX42MACHO_ARFLAGS ?= -c -rs TOOL_GXX42MACHO_ARLIBSUFF ?= .a TOOL_GXX42MACHO_LDFLAGS ?= TOOL_GXX42MACHO_LDFLAGS.debug ?= -g TOOL_GXX42MACHO_LDFLAGS.profile ?= -g TOOL_GXX42MACHO_STRIP_PROGRAM ?= strip -SXxru TOOL_GXX42MACHO_STRIP_DLL ?= strip -Sxru TOOL_GXX42MACHO_STRIP_SYSMOD ?= strip -Sru ## # Calculate the files in the debug bundle. # @param 1 The whole output filename. # @param 2 The output filename sans suffix. TOOL_GXX42MACHO_DEBUG_BUNDLE_FN = \ $(1).dSYM/ \ $(1).dSYM/Contents/ \ $(1).dSYM/Contents/Resources/ \ $(1).dSYM/Contents/Resources/DWARF/ \ $(1).dSYM/Contents/Info.plist \ $(1).dSYM/Contents/Resources/DWARF/$(notdir $(1)) ## # Calculate the files in the debug bundle. # @param 1 The whole linker output filename. # @param 2 The linker output filename sans suffix. # @param 3 The desired install name (no dir slash). # @remarks The Info.plist has some reference to the original name, but gdb # does not care and only check for a symbol file in the DWARF # directory with the same name as the debugged module. TOOL_GXX42MACHO_DEBUG_INSTALL_FN= \ $(3).dSYM/ \ $(3).dSYM/Contents/ \ $(3).dSYM/Contents/Resources/ \ $(3).dSYM/Contents/Resources/DWARF/ \ $(1).dSYM/Contents/Info.plist=>$(3).dSYM/Contents/Info.plist \ $(1).dSYM/Contents/Resources/DWARF/$(notdir $(1))=>$(3).dSYM/Contents/Resources/DWARF/$(notdir $(3)) ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GXX42MACHO_COMPILE_C_DEPEND = TOOL_GXX42MACHO_COMPILE_C_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GXX42MACHO_COMPILE_C_USES_KOBJCACHE = 1 TOOL_GXX42MACHO_COMPILE_C_OUTPUT = $(outbase).i define TOOL_GXX42MACHO_COMPILE_C_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).i\ $(TOOL_GXX42MACHO_CC) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GXX42MACHO_CC) -c\ $(flags) -fpreprocessed -x c\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GXX42MACHO_COMPILE_C_OUTPUT = define TOOL_GXX42MACHO_COMPILE_C_CMDS $(QUIET)$(TOOL_GXX42MACHO_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KUSE_OBJCACHE ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GXX42MACHO_COMPILE_CXX_DEPEND = TOOL_GXX42MACHO_COMPILE_CXX_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GXX42MACHO_COMPILE_CXX_USES_KOBJCACHE = 1 TOOL_GXX42MACHO_COMPILE_CXX_OUTPUT = $(outbase).ii define TOOL_GXX42MACHO_COMPILE_CXX_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).ii\ $(TOOL_GXX42MACHO_CXX) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GXX42MACHO_CXX) -c\ $(flags) -fpreprocessed -x c++\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GXX42MACHO_COMPILE_CXX_OUTPUT = define TOOL_GXX42MACHO_COMPILE_CXX_CMDS $(QUIET)$(TOOL_GXX42MACHO_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile Objective-C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GXX42MACHO_COMPILE_OBJC_DEPEND = TOOL_GXX42MACHO_COMPILE_OBJC_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GXX42MACHO_COMPILE_OBJC_USES_KOBJCACHE = 1 TOOL_GXX42MACHO_COMPILE_OBJC_OUTPUT = $(outbase).mi define TOOL_GXX42MACHO_COMPILE_OBJC_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).ii\ $(TOOL_GXX42MACHO_OBJC) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GXX42MACHO_OBJC) -c\ $(flags) -fpreprocessed -x objective-c \ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GXX42MACHO_COMPILE_OBJC_OUTPUT = define TOOL_GXX42MACHO_COMPILE_OBJC_CMDS $(QUIET)$(TOOL_GXX42MACHO_OBJC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile Objective-C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GXX42MACHO_COMPILE_OBJCXX_DEPEND = TOOL_GXX42MACHO_COMPILE_OBJCXX_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GXX42MACHO_COMPILE_OBJCXX_USES_KOBJCACHE = 1 TOOL_GXX42MACHO_COMPILE_OBJCXX_OUTPUT = $(outbase).mii define TOOL_GXX42MACHO_COMPILE_OBJCXX_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).mii\ $(TOOL_GXX42MACHO_OBJCXX) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GXX42MACHO_OBJCXX) -c\ $(flags) -fpreprocessed -x objective-c++ \ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GXX42MACHO_COMPILE_OBJCXX_OUTPUT = define TOOL_GXX42MACHO_COMPILE_OBJCXX_CMDS $(QUIET)$(TOOL_GXX42MACHO_OBJCXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile Assembly source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. # TOOL_GXX42MACHO_COMPILE_AS_OUTPUT = TOOL_GXX42MACHO_COMPILE_AS_DEPEND = TOOL_GXX42MACHO_COMPILE_AS_DEPORD = define TOOL_GXX42MACHO_COMPILE_AS_CMDS $(QUIET)$(TOOL_GXX42MACHO_AS) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX42MACHO_LINK_LIBRARY_OUTPUT = TOOL_GXX42MACHO_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_GXX42MACHO_LINK_LIBRARY_DEPORD = define TOOL_GXX42MACHO_LINK_LIBRARY_CMDS $(if $(strip $(objs)),$(call xargs,$(QUIET)$(TOOL_GXX42MACHO_AR) $(flags) $(out),$(objs))) $(foreach lib,$(othersrc)\ ,$(NL)$(TAB)$(call MSG_AR_MERGE,$(target),$(out),$(lib)) \ $(NL)$(TAB)$(QUIET)$(RM_EXT) -f $(dir $(outbase))ar.tmp.dir/* \ $(NL)$(TAB)$(QUIET)$(MKDIR) -p $(dir $(outbase))/ar.tmp.dir/ \ $(NL)$(TAB)$(QUIET)(cd $(dir $(outbase))ar.tmp.dir/ \ && $(TOOL_GXX42MACHO_AR) -x $(abspath $(lib)) \ && $(RM_EXT) -f ./__.SYMDEF* \ && $(TOOL_GXX42MACHO_AR) $(flags) $(out) *) \ $(NL)$(TAB)$(QUIET)$(RM_EXT) -f $(dir $(outbase))/ar.tmp.dir/* \ $(NL)$(TAB)$(QUIET)$(RMDIR) $(dir $(outbase))ar.tmp.dir/) endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX42MACHO_LINK_PROGRAM_OUTPUT = $(outbase).rsp TOOL_GXX42MACHO_LINK_PROGRAM_OUTPUT_DEBUG = $(call TOOL_GXX42MACHO_DEBUG_BUNDLE_FN,$(out)) TOOL_GXX42MACHO_LINK_PROGRAM_DEBUG_INSTALL_FN = $(TOOL_GXX42MACHO_DEBUG_INSTALL_FN) TOOL_GXX42MACHO_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_GXX42MACHO_LINK_PROGRAM_DEPORD = define TOOL_GXX42MACHO_LINK_PROGRAM_CMDS $(QUIET)$(APPEND) -n $(outbase).rsp $(objs) $(QUIET)$(TOOL_GXX42MACHO_LD) $(flags) -o $(out)\ -filelist $(outbase).rsp\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib))) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GXX42MACHO_DSYMUTIL) -o $(out).dSYM/ $(out) $(QUIET)$(TOOL_GXX42MACHO_STRIP_PROGRAM) $(out) endif endef ## Link DLL # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX42MACHO_LINK_DLL_OUTPUT = $(outbase).rsp TOOL_GXX42MACHO_LINK_DLL_OUTPUT_DEBUG = $(call TOOL_GXX42MACHO_DEBUG_BUNDLE_FN,$(out)) TOOL_GXX42MACHO_LINK_DLL_DEBUG_INSTALL_FN = $(TOOL_GXX42MACHO_DEBUG_INSTALL_FN) TOOL_GXX42MACHO_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_GXX42MACHO_LINK_DLL_DEPORD = define TOOL_GXX42MACHO_LINK_DLL_CMDS $(QUIET)$(APPEND) -n $(outbase).rsp $(objs) $(QUIET)$(TOOL_GXX42MACHO_LD) $(TOOL_GXX42MACHO_LDFLAGS.dll) $(flags) -o $(out)\ $(call TOOL_GXX42MACHO_LD_SONAME,$(target),$(out))\ -filelist $(outbase).rsp\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib))) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GXX42MACHO_DSYMUTIL) -o $(out).dSYM/ $(out) $(QUIET)$(TOOL_GXX42MACHO_STRIP_DLL) $(out) endif endef ## Link system module (windows aka driver, linux aka kernel module) # @param $(target) Normalized main target name. # @param $(out) System module name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX42MACHO_LINK_SYSMOD_OUTPUT = $(outbase).rsp TOOL_GXX42MACHO_LINK_SYSMOD_OUTPUT_DEBUG = $(call TOOL_GXX42MACHO_DEBUG_BUNDLE_FN,$(out)) TOOL_GXX42MACHO_LINK_SYSMOD_DEBUG_INSTALL_FN = $(TOOL_GXX42MACHO_DEBUG_INSTALL_FN) TOOL_GXX42MACHO_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) TOOL_GXX42MACHO_LINK_SYSMOD_DEPORD = define TOOL_GXX42MACHO_LINK_SYSMOD_CMDS $(QUIET)$(APPEND) -n $(outbase).rsp $(objs) $(QUIET)$(TOOL_GXX42MACHO_LD_SYSMOD) $(TOOL_GXX42MACHO_LDFLAGS.sysmod) $(flags) -o $(out)\ -filelist $(outbase).rsp\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib))) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GXX42MACHO_DSYMUTIL) -o $(out).dSYM/ $(out) $(QUIET)$(TOOL_GXX42MACHO_STRIP_SYSMOD) $(out) endif endef kbuild-3149/kBuild/tools/MASM610.kmk0000644000175000017500000000436713252530251016756 0ustar locutuslocutus# $Id: MASM610.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - MASM v6.10 # # # Copyright (c) 2008-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_MASM610 := Microsoft Macro Assembler v6.10 # Tool Specific Properties ifndef TOOL_MASM610_AS TOOL_MASM610_AS := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST)/masm/v6.10*/binp/ml$(HOSTSUFF_EXE)))) ifeq ($(TOOL_MASM610_AS),) TOOL_MASM610_AS := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_TRG)/masm/v6.10*/binp/ml$(HOSTSUFF_EXE)))) endif endif ifeq ($(TOOL_MASM610_AS),) TOOL_MASM610_AS := $(firstword $(which ml$(HOSTSUFF_EXE)) path/notfound/ml$(HOSTSUFF_EXE)) endif # General Properties used by kBuild TOOL_MASM610_ASFLAGS ?= /nologo TOOL_MASM610_COMPILE_AS_OUTPUT = $(outbase).lst TOOL_MASM610_COMPILE_AS_DEPEND = TOOL_MASM610_COMPILE_AS_DEPORD = define TOOL_MASM610_COMPILE_AS_CMDS $(QUIET)$(REDIRECT) \ -E 'INCLUDE=$(subst $(SP),,$(addsuffix ;,$(subst /,\,$(incs))))' \ -E 'MASM=' -E 'ML=' \ -- \ $(subst /,\\,$(TOOL_MASM610_AS)) -c \ $(strip $(flags)) \ $(addprefix -D,$(defs)) \ -Fo$(subst /,\\,$(obj)) \ -Fl$(subst /,\\,$(outbase).lst) \ $(subst /,\\,$(source)) endef kbuild-3149/kBuild/tools/GXX32.kmk0000644000175000017500000003313113252530251016574 0ustar locutuslocutus# $Id: GXX32.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - Generic 32-bit GCC v3.2.x or later using the system GCC, for building C++ code. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_GXX32 := Generic 32-bit GCC v3.2.x or later using the system GCC, for building C++ code. \ More or less Linux/ELF specfic. # Tool Specific Properties TOOL_GXX32_CC ?= gcc$(HOSTSUFF_EXE) -m32 TOOL_GXX32_CXX ?= g++$(HOSTSUFF_EXE) -m32 TOOL_GXX32_AS ?= gcc$(HOSTSUFF_EXE) -m32 TOOL_GXX32_AR ?= ar$(HOSTSUFF_EXE) TOOL_GXX32_LD ?= g++$(HOSTSUFF_EXE) -m32 TOOL_GXX32_LD_SYSMOD ?= ld$(HOSTSUFF_EXE) ifndef TOOL_GXX32_LDFLAGS.$(KBUILD_TARGET) TOOL_GXX32_LDFLAGS.dll ?= -shared else TOOL_GXX32_LDFLAGS.dll ?= $(TOOL_GXX32_LDFLAGS.$(KBUILD_TARGET)) endif TOOL_GXX32_LDFLAGS.sysmod ?= -r -m elf_i386$(if-expr "$(KBUILD_TARGET)" == "freebsd" || "$(KBUILD_TARGET)" == "gnukfbsd",_fbsd,) TOOL_GXX32_LD_SONAME ?= -Wl,-soname=$(firstword $($(1)_SONAME.$(KBUILD_TARGET).$(KBUILD_TYPE)) $($(1)_SONAME.$(KBUILD_TARGET)) $($(1)_SONAME.$(KBUILD_TYPE)) $($(1)_SONAME) $(notdir $(2))) ifeq ($(KBUILD_TARGET),os2) TOOL_GXX32_LD_MAP ?= -Zmap=$(1) else TOOL_GXX32_LD_MAP ?= endif ifeq ($(KBUILD_TARGET),os2) TOOL_GXX32_LD_SYSMOD_MAP ?= -Zmap=$(1) else TOOL_GXX32_LD_SYSMOD_MAP ?= endif if1of ($(KBUILD_HOST), solaris) TOOL_GXX32_OBJCOPY ?= gobjcopy$(HOSTSUFF_EXE) else TOOL_GXX32_OBJCOPY ?= objcopy$(HOSTSUFF_EXE) endif ifdef SLKRUNS TOOL_GXX32_CC += -fmessage-length=0 TOOL_GXX32_CXX += -fmessage-length=0 endif # General Properties used by kBuild TOOL_GXX32_COBJSUFF ?= .o TOOL_GXX32_CFLAGS ?= TOOL_GXX32_CFLAGS.debug ?= -g TOOL_GXX32_CFLAGS.profile ?= -O2 #-g -pg TOOL_GXX32_CFLAGS.release ?= -O2 TOOL_GXX32_CINCS ?= TOOL_GXX32_CDEFS ?= TOOL_GXX32_CXXOBJSUFF ?= .o TOOL_GXX32_CXXOBJSUFF ?= .o TOOL_GXX32_CXXFLAGS ?= TOOL_GXX32_CXXFLAGS.debug ?= -g TOOL_GXX32_CXXFLAGS.profile ?= -O2 #-g -pg TOOL_GXX32_CXXFLAGS.release ?= -O2 TOOL_GXX32_CXXINCS ?= TOOL_GXX32_CXXDEFS ?= TOOL_GXX32_ASFLAGS ?= -x assembler-with-cpp TOOL_GXX32_ASFLAGS.debug ?= -g TOOL_GXX32_ASFLAGS.profile ?= -g TOOL_GXX32_ASOBJSUFF ?= .o TOOL_GXX32_ARFLAGS ?= cr TOOL_GXX32_ARLIBSUFF ?= .a TOOL_GXX32_LDFLAGS ?= TOOL_GXX32_LDFLAGS.debug ?= -g TOOL_GXX32_LDFLAGS.profile ?= -g ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GXX32_COMPILE_C_DEPEND = TOOL_GXX32_COMPILE_C_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GXX32_COMPILE_C_USES_KOBJCACHE = 1 TOOL_GXX32_COMPILE_C_OUTPUT = $(outbase).i define TOOL_GXX32_COMPILE_C_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).i\ $(TOOL_GXX32_CC) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GXX32_CC) -c\ $(flags) -fpreprocessed -x c\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GXX32_COMPILE_C_OUTPUT = define TOOL_GXX32_COMPILE_C_CMDS $(QUIET)$(TOOL_GXX32_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GXX32_COMPILE_CXX_DEPEND = TOOL_GXX32_COMPILE_CXX_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GXX32_COMPILE_CXX_USES_KOBJCACHE = 1 TOOL_GXX32_COMPILE_CXX_OUTPUT = $(outbase).ii define TOOL_GXX32_COMPILE_CXX_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).ii\ $(TOOL_GXX32_CXX) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GXX32_CXX) -c\ $(flags) -fpreprocessed -x c++\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GXX32_COMPILE_CXX_OUTPUT = define TOOL_GXX32_COMPILE_CXX_CMDS $(QUIET)$(TOOL_GXX32_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile Assembly source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. # TOOL_GXX32_COMPILE_AS_OUTPUT = TOOL_GXX32_COMPILE_AS_DEPEND = TOOL_GXX32_COMPILE_AS_DEPORD = define TOOL_GXX32_COMPILE_AS_CMDS $(QUIET)$(TOOL_GXX32_AS) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX32_LINK_LIBRARY_OUTPUT = $(out).ar-script TOOL_GXX32_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_GXX32_LINK_LIBRARY_DEPORD = define TOOL_GXX32_LINK_LIBRARY_CMDS $(QUIET)$(APPEND) $(out).ar-script 'CREATE $(out)' $(QUIET)$(APPEND) -n $(out).ar-script \ $(foreach o,$(objs), 'ADDMOD $(o)') \ $(foreach o,$(filter-out %.def %.imp %.dll,$(othersrc)), 'ADDLIB $(o)') $(if $(filter %.def %.imp %.dll,$(othersrc))\ ,$(TOOL_GXX3_AR_IMP) -o $(outbase).imp.a $(filter %.def %.imp %.dll,$(othersrc))\ $(NL)$(TAB)$(QUIET)$(APPEND) $(out).ar-script 'ADDLIB $(outbase).imp.a') $(QUIET)$(APPEND) $(out).ar-script 'SAVE' $(QUIET)$(APPEND) $(out).ar-script 'END' $(QUIET)$(REDIRECT) -rti $(out).ar-script -- $(TOOL_GXX32_AR) -M endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX32_LINK_PROGRAM_OUTPUT = TOOL_GXX32_LINK_PROGRAM_OUTPUT_MAYBE = $(outbase).map TOOL_GXX32_LINK_PROGRAM_OUTPUT_DEBUG = $(outbase).debug TOOL_GXX32_LINK_PROGRAM_DEBUG_INSTALL_FN = $(2).debug=>$(basename $(3)).debug TOOL_GXX32_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib)))\ $(filter %.def, $(othersrc)) TOOL_GXX32_LINK_PROGRAM_DEPORD = define TOOL_GXX32_LINK_PROGRAM_CMDS $(QUIET)$(TOOL_GXX32_LD) $(flags) -o $(out) $(objs)\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\ $(call TOOL_GXX32_LD_MAP,$(outbase).map) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GXX32_OBJCOPY) --only-keep-debug $(out) $(outbase).debug $(QUIET)$(CHMOD) a-x $(outbase).debug $(QUIET)$(TOOL_GXX32_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out) endif endef ## Link DLL # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX32_LINK_DLL_OUTPUT = TOOL_GXX32_LINK_DLL_OUTPUT_MAYBE = $(outbase).map TOOL_GXX32_LINK_DLL_OUTPUT_DEBUG = $(outbase).debug TOOL_GXX32_LINK_DLL_DEBUG_INSTALL_FN = $(2).debug=>$(basename $(3)).debug TOOL_GXX32_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib)))\ $(filter %.def, $(othersrc)) TOOL_GXX32_LINK_DLL_DEPORD = define TOOL_GXX32_LINK_DLL_CMDS $(QUIET)$(TOOL_GXX32_LD) $(TOOL_GXX32_LDFLAGS.dll) $(flags) -o $(out)\ $(if $(filter-out win os2, $(KBUILD_TARGET)),$(call TOOL_GXX32_LD_SONAME,$(target),$(out)))\ $(objs)\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\ $(call TOOL_GXX32_LD_MAP,$(outbase).map) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GXX32_OBJCOPY) --only-keep-debug $(out) $(outbase).debug $(QUIET)$(CHMOD) a-x $(outbase).debug $(QUIET)$(TOOL_GXX32_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out) endif endef ## Link system module (windows aka driver, linux aka kernel module) # @param $(target) Normalized main target name. # @param $(out) System module name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GXX32_LINK_SYSMOD_OUTPUT = TOOL_GXX32_LINK_SYSMOD_OUTPUT_MAYBE = $(outbase).map TOOL_GXX32_LINK_SYSMOD_OUTPUT_DEBUG = $(outbase).debug TOOL_GXX32_LINK_SYSMOD_DEBUG_INSTALL_FN = $(2).debug=>$(basename $(3)).debug TOOL_GXX32_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib)))\ $(filter %.def, $(othersrc)) TOOL_GXX32_LINK_SYSMOD_DEPORD = define TOOL_GXX32_LINK_SYSMOD_CMDS $(QUIET)$(TOOL_GXX32_LD_SYSMOD) $(TOOL_GXX32_LDFLAGS.sysmod) $(flags) -o $(out) $(objs)\ $(filter %.def, $(othersrc))\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\ $(call TOOL_GXX32_LD_SYSMOD_MAP,$(outbase).map) ifeq ($(ld_debug),split) $(QUIET)$(TOOL_GXX32_OBJCOPY) --only-keep-debug $(out) $(outbase).debug $(QUIET)$(CHMOD) a-x $(outbase).debug $(QUIET)$(TOOL_GXX32_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out) endif endef kbuild-3149/kBuild/tools/GCC3PLAIN.kmk0000644000175000017500000003212313252530251017224 0ustar locutuslocutus# $Id: GCC3PLAIN.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - Generic GCC v3.2.x or later Using The System GCC, any Unix Linker and Unix Archiver. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_GCC3PLAIN := Generic GCC v3.2.x or later Using The System GCC, any Unix Linker and Unix Archiver. # Tool Specific Properties TOOL_GCC3PLAIN_CC ?= gcc$(HOSTSUFF_EXE) TOOL_GCC3PLAIN_CXX ?= g++$(HOSTSUFF_EXE) TOOL_GCC3PLAIN_AS ?= gcc$(HOSTSUFF_EXE) TOOL_GCC3PLAIN_AR ?= ar$(HOSTSUFF_EXE) TOOL_GCC3PLAIN_RANLIB ?= ranlib$(HOSTSUFF_EXE) TOOL_GCC3PLAIN_LD ?= gcc$(HOSTSUFF_EXE) TOOL_GCC3PLAIN_LD_SYSMOD ?= ld$(HOSTSUFF_EXE) TOOL_GCC3PLAIN_LD_SYSMOD.os2 ?= g++$(HOSTSUFF_EXE) TOOL_GCC3PLAIN_LDFLAGS.dll.os2 ?= -Zdll TOOL_GCC3PLAIN_LDFLAGS.dll.darwin ?= -dynamiclib ifndef TOOL_GCC3PLAIN_LDFLAGS.$(KBUILD_TARGET) TOOL_GCC3PLAIN_LDFLAGS.dll ?= -shared else TOOL_GCC3PLAIN_LDFLAGS.dll ?= $(TOOL_GCC3PLAIN_LDFLAGS.$(KBUILD_TARGET)) endif TOOL_GCC3PLAIN_LD_SONAME.darwin ?= $(NO_SUCH_VARIABLE) TOOL_GCC3PLAIN_LD_SONAME.os2 ?= $(NO_SUCH_VARIABLE) TOOL_GCC3PLAIN_LD_SONAME.solaris ?= -Wl,-h,$(firstword $($(1)_SONAME.$(KBUILD_TARGET).$(KBUILD_TYPE)) $($(1)_SONAME.$(KBUILD_TARGET)) $($(1)_SONAME.$(KBUILD_TYPE)) $($(1)_SONAME) $(notdir $(2))) TOOL_GCC3PLAIN_LD_SONAME.win ?= $(NO_SUCH_VARIABLE) ifndef TOOL_GCC3PLAIN_LD_SONAME.$(KBUILD_TARGET) TOOL_GCC3PLAIN_LD_SONAME ?= -Wl,-soname=$(firstword $($(1)_SONAME.$(KBUILD_TARGET).$(KBUILD_TYPE)) $($(1)_SONAME.$(KBUILD_TARGET)) $($(1)_SONAME.$(KBUILD_TYPE)) $($(1)_SONAME) $(notdir $(2))) else TOOL_GCC3PLAIN_LD_SONAME ?= $(TOOL_GCC3PLAIN_LD_SONAME.$(KBUILD_TARGET)) endif ifdef SLKRUNS TOOL_GCC3PLAIN_CC += -fmessage-length=0 TOOL_GCC3PLAIN_CXX += -fmessage-length=0 endif # General Properties used by kBuild TOOL_GCC3PLAIN_COBJSUFF ?= .o TOOL_GCC3PLAIN_CFLAGS ?= TOOL_GCC3PLAIN_CFLAGS.debug ?= -g TOOL_GCC3PLAIN_CFLAGS.profile ?= -O2 #-g -pg TOOL_GCC3PLAIN_CFLAGS.release ?= -O2 TOOL_GCC3PLAIN_CINCS ?= TOOL_GCC3PLAIN_CDEFS ?= TOOL_GCC3PLAIN_CXXOBJSUFF ?= .o TOOL_GCC3PLAIN_CXXOBJSUFF ?= .o TOOL_GCC3PLAIN_CXXFLAGS ?= TOOL_GCC3PLAIN_CXXFLAGS.debug ?= -g TOOL_GCC3PLAIN_CXXFLAGS.profile ?= -O2 #-g -pg TOOL_GCC3PLAIN_CXXFLAGS.release ?= -O2 TOOL_GCC3PLAIN_CXXINCS ?= TOOL_GCC3PLAIN_CXXDEFS ?= TOOL_GCC3PLAIN_ASFLAGS ?= -x assembler-with-cpp TOOL_GCC3PLAIN_ASFLAGS.debug ?= -g TOOL_GCC3PLAIN_ASFLAGS.profile ?= -g TOOL_GCC3PLAIN_ASOBJSUFF ?= .o TOOL_GCC3PLAIN_ARFLAGS ?= cr TOOL_GCC3PLAIN_ARLIBSUFF ?= .a TOOL_GCC3PLAIN_LDFLAGS ?= ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GCC3PLAIN_COMPILE_C_DEPEND = TOOL_GCC3PLAIN_COMPILE_C_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GCC3PLAIN_COMPILE_C_USES_KOBJCACHE = 1 TOOL_GCC3PLAIN_COMPILE_C_OUTPUT = $(outbase).i define TOOL_GCC3PLAIN_COMPILE_C_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).i\ $(TOOL_GCC3PLAIN_CC) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GCC3PLAIN_CC) -c\ $(flags) -fpreprocessed -x c\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GCC3PLAIN_COMPILE_C_OUTPUT = define TOOL_GCC3PLAIN_COMPILE_C_CMDS $(QUIET)$(TOOL_GCC3PLAIN_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_GCC3PLAIN_COMPILE_CXX_DEPEND = TOOL_GCC3PLAIN_COMPILE_CXX_DEPORD = ifdef KBUILD_USE_KOBJCACHE TOOL_GCC3PLAIN_COMPILE_CXX_USES_KOBJCACHE = 1 TOOL_GCC3PLAIN_COMPILE_CXX_OUTPUT = $(outbase).ii define TOOL_GCC3PLAIN_COMPILE_CXX_CMDS $(QUIET)$(KOBJCACHE) -f $(outbase).koc -d $(PATH_OBJCACHE) -t $(bld_trg).$(bld_trg_arch) -p\ --kObjCache-cpp $(outbase).ii\ $(TOOL_GCC3PLAIN_CXX) -E -o -\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ $(abspath $(source))\ --kObjCache-cc $(obj)\ $(TOOL_GCC3PLAIN_CXX) -c\ $(flags) -fpreprocessed -x c++\ -o $(obj)\ - $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef else # !KBUILD_USE_KOBJCACHE TOOL_GCC3PLAIN_COMPILE_CXX_OUTPUT = define TOOL_GCC3PLAIN_COMPILE_CXX_CMDS $(QUIET)$(TOOL_GCC3PLAIN_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef endif # !KBUILD_USE_KOBJCACHE ## Compile Assembly source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. # TOOL_GCC3PLAIN_COMPILE_AS_OUTPUT = TOOL_GCC3PLAIN_COMPILE_AS_DEPEND = TOOL_GCC3PLAIN_COMPILE_AS_DEPORD = define TOOL_GCC3PLAIN_COMPILE_AS_CMDS $(QUIET)$(TOOL_GCC3PLAIN_AS) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ -o $(obj)\ $(abspath $(source)) $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC3PLAIN_LINK_LIBRARY_OUTPUT = TOOL_GCC3PLAIN_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_GCC3PLAIN_LINK_LIBRARY_DEPORD = define TOOL_GCC3PLAIN_LINK_LIBRARY_CMDS $(call xargs,$(QUIET)$(TOOL_GCC3PLAIN_AR) $(flags) $(out),$(objs)) $(foreach lib,$(othersrc)\ ,$(NL)$(TAB)$(call MSG_AR_MERGE,$(target),$(out),$(lib)) \ $(NL)$(TAB)$(QUIET)$(RM_EXT) -f $(dir $(outbase))ar.tmp.dir/* \ $(NL)$(TAB)$(QUIET)$(MKDIR) -p $(dir $(outbase))/ar.tmp.dir/ \ $(NL)$(TAB)$(QUIET)(cd $(dir $(outbase))ar.tmp.dir/ \ && $(TOOL_GCC3PLAIN_AR) x $(abspath $(lib)) \ && $(TOOL_GCC3PLAIN_AR) $(flags) $(out) *) \ $(NL)$(TAB)$(QUIET)$(RM_EXT) -f $(dir $(outbase))/ar.tmp.dir/* \ $(NL)$(TAB)$(QUIET)$(RMDIR) $(dir $(outbase))ar.tmp.dir/) $(QUIET)$(TOOL_GCC3PLAIN_RANLIB) $(out) endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC3PLAIN_LINK_PROGRAM_OUTPUT = TOOL_GCC3PLAIN_LINK_PROGRAM_OUTPUT_MAYBE = $(outbase).map TOOL_GCC3PLAIN_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib)))\ $(filter %.def, $(othersrc)) TOOL_GCC3PLAIN_LINK_PROGRAM_DEPORD = define TOOL_GCC3PLAIN_LINK_PROGRAM_CMDS $(QUIET)$(TOOL_GCC3PLAIN_LD) $(flags) -o $(out) $(objs)\ $(filter %.def, $(othersrc))\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib))) endef ## Link DLL # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC3PLAIN_LINK_DLL_OUTPUT = TOOL_GCC3PLAIN_LINK_DLL_OUTPUT_MAYBE = $(outbase).map TOOL_GCC3PLAIN_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib)))\ $(filter %.def, $(othersrc)) TOOL_GCC3PLAIN_LINK_DLL_DEPORD = define TOOL_GCC3PLAIN_LINK_DLL_CMDS $(QUIET)$(TOOL_GCC3PLAIN_LD) $(TOOL_GCC3PLAIN_LDFLAGS.dll) $(flags) -o $(out)\ $(if $(filter-out win32 os2, $(KBUILD_TARGET)),$(call TOOL_GCC3PLAIN_LD_SONAME,$(target),$(out)))\ $(objs)\ $(filter %.def, $(othersrc))\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib))) endef ## Link system module (windows aka driver, linux aka kernel module) # This tool target might not work everywhere, but is provided for the # platforms where it works (Solaris, etc). # # @param $(target) Normalized main target name. # @param $(out) System module name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_GCC3PLAIN_LINK_SYSMOD_OUTPUT = TOOL_GCC3PLAIN_LINK_SYSMOD_OUTPUT_MAYBE = $(outbase).map TOOL_GCC3PLAIN_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib)))\ $(filter %.def, $(othersrc)) TOOL_GCC3PLAIN_LINK_SYSMOD_DEPORD = define TOOL_GCC3PLAIN_LINK_SYSMOD_CMDS $(QUIET)$(if $(TOOL_GCC3PLAIN_LD_SYSMOD.$(bld_trg)),$(TOOL_GCC3PLAIN_LD_SYSMOD.$(bld_trg)),$(TOOL_GCC3PLAIN_LD_SYSMOD))\ $(TOOL_GCC3PLAIN_LDFLAGS_SYSMOD.$(bld_trg)) $(flags) -o $(out)\ $(objs)\ $(filter %.def, $(othersrc))\ $(foreach p,$(libpath), -L$(p))\ $(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib))) endef kbuild-3149/kBuild/tools/VAC308.kmk0000644000175000017500000001730613252530251016633 0ustar locutuslocutus# $Id: VAC308.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - VisualAge for C++ v3.08. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_VAC308 := VisualAge for C++ v3.08 # Determin VAC308 location. ifndef PATH_TOOL_VAC308 PATH_TOOL_VAC308 := $(wildcard $(KBUILD_DEVTOOLS_HST)/vac/v3.0.8*) ifeq ($(PATH_TOOL_VAC308),) PATH_TOOL_VAC308 := $(wildcard $(KBUILD_DEVTOOLS_HST)/vac/v308*) endif ifeq ($(PATH_TOOL_VAC308),) PATH_TOOL_VAC308 := $(wildcard $(KBUILD_DEVTOOLS_TRG)/vac/v3.0.8*) ifeq ($(PATH_TOOL_VAC308),) PATH_TOOL_VAC308 := $(wildcard $(KBUILD_DEVTOOLS_TRG)/vac/v308*) endif endif ifeq ($(PATH_TOOL_VAC308),) PATH_TOOL_VAC308 := $(firstword $(rsort $(PATH_TOOL_VAC308))) endif # if not found, we'll enter 'pathless' mode. else # Resolve any fancy stuff once and for all. PATH_TOOL_VAC308 := $(PATH_TOOL_VAC308) endif ifneq ($(PATH_TOOL_VAC308),) TOOL_VAC308_PATHLESS := PATH_TOOL_VAC308_BIN ?= $(PATH_TOOL_VAC308)/bin PATH_TOOL_VAC308_LIB ?= $(PATH_TOOL_VAC308)/lib PATH_TOOL_VAC308_INC ?= $(PATH_TOOL_VAC308)/include PATH_TOOL_VAC308_DLL ?= $(PATH_TOOL_VAC308)/dll PATH_TOOL_VAC308_HELP ?= $(PATH_TOOL_VAC308)/help PATH_TOOL_VAC308_LOCALE ?= $(PATH_TOOL_VAC308)/locale TOOL_VAC308_ENV_SETUP ?= $(REDIRECT) \ -E 'BEGINLIBPATH=$(PATH_TOOL_VAC308_DLL);$(BEGINLIBPATH)' \ -E 'DPATH=$(PATH_TOOL_VAC308_LOCALE);$(PATH_TOOL_VAC308_HELP);$(DPATH)' \ -E 'LIB=$1' \ -E 'INCLUDE=' \ $2 \ -- TOOL_VAC308_CC ?= $(PATH_TOOL_VAC308_BIN)/icc$(HOSTSUFF_EXE) TOOL_VAC308_CXX ?= $(PATH_TOOL_VAC308_BIN)/icc$(HOSTSUFF_EXE) TOOL_VAC308_AR ?= $(PATH_TOOL_VAC308_BIN)/ilib$(HOSTSUFF_EXE) TOOL_VAC308_LD ?= $(PATH_TOOL_VAC308_BIN)/icc$(HOSTSUFF_EXE) TOOL_VAC308_RC ?= $(PATH_TOOL_VAC308_BIN)/rc$(HOSTSUFF_EXE) else # Pathless, relies on the environment. TOOL_VAC308_PATHLESS := yes TOOL_VAC308_ENV_SETUP ?= $(REDIRECT) \ -E 'LIB=$1' \ -E 'INCLUDE=' \ $2 \ -- TOOL_VAC308_CC ?= icc$(HOSTSUFF_EXE) TOOL_VAC308_CXX ?= icc$(HOSTSUFF_EXE) TOOL_VAC308_AR ?= ilib$(HOSTSUFF_EXE) TOOL_VAC308_LD ?= icc$(HOSTSUFF_EXE) TOOL_VAC308_RC ?= rc$(HOSTSUFF_EXE) endif # More tool specific properties. # Note: implib isn't really a part of VAC308. TOOL_VAC308_IMP ?= implib$(HOSTSUFF_EXE) TOOL_VAC308_IMPFLAGS ?= /nologo /noignorecase # General Properties used by kBuild TOOL_VAC308_COBJSUFF ?= .obj TOOL_VAC308_CFLAGS ?= -Q+ TOOL_VAC308_CFLAGS.debug ?= -Ti+ TOOL_VAC308_CFLAGS.release ?= -O TOOL_VAC308_CINCS ?= $(PATH_TOOL_VAC308_INC) TOOL_VAC308_CDEFS ?= TOOL_VAC308_CXXOBJSUFF ?= .obj TOOL_VAC308_CXXFLAGS ?= -Q+ TOOL_VAC308_CXXFLAGS.debug ?= -Ti TOOL_VAC308_CXXFLAGS.release ?= -O TOOL_VAC308_CXXINCS ?= $(PATH_TOOL_VAC308_INC) TOOL_VAC308_CXXDEFS ?= TOOL_VAC308_RCOBJSUFF ?= .res TOOL_VAC308_RCFLAGS ?= -n TOOL_VAC308_RCINCS ?= TOOL_VAC308_RCDEFS ?= TOOL_VAC308_ARFLAGS ?= /nologo /noignorecase TOOL_VAC308_ARLIBSUFF ?= .lib TOOL_VAC308_LDFLAGS ?= -Q+ TOOL_VAC308_LDFLAGS.debug ?= -Ti+ TOOL_VAC308_COMPILE_C_DEPEND = TOOL_VAC308_COMPILE_C_DEPORD = TOOL_VAC308_COMPILE_C_OUTPUT = $(obj).ii define TOOL_VAC308_COMPILE_C_CMDS $(QUIET) $(call TOOL_VAC308_ENV_SETUP) $(TOOL_VAC308_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fo$(obj)\ $(abspath $(source)) $(QUIET) $(call TOOL_VAC308_ENV_SETUP,,-wo $(obj).ii) $(TOOL_VAC308_CC) -P+ -Pd+ \ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ $(abspath $(source)) $(QUIET)$(DEP_PRE) -f -s -o $(dep) -t $(obj) $(obj).ii endef TOOL_VAC308_COMPILE_CXX_DEPEND = TOOL_VAC308_COMPILE_CXX_DEPORD = TOOL_VAC308_COMPILE_CXX_OUTPUT = $(obj).ii define TOOL_VAC308_COMPILE_CXX_CMDS $(QUIET) $(call TOOL_VAC308_ENV_SETUP) $(TOOL_VAC308_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fo$(obj)\ $(abspath $(source)) $(QUIET) $(call TOOL_VAC308_ENV_SETUP,,-wo $(obj).ii) $(TOOL_VAC308_CXX) -P+ -Pd+ \ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ $(abspath $(source)) $(QUIET)$(DEP_PRE) -f -s -o $(dep) -t $(obj) $(obj).ii endef TOOL_VAC308_COMPILE_RC_OUTPUT = TOOL_VAC308_COMPILE_RC_DEPEND = TOOL_VAC308_COMPILE_RC_DEPORD = define TOOL_VAC308_COMPILE_RC_CMDS $(QUIET) $(call TOOL_VAC308_ENV_SETUP) $(TOOL_VAC308_RC) -r\ $(flags) $(addprefix -i, $(subst /,\\,$(incs))) $(addprefix -D, $(defs))\ $(subst /,\\,$(abspath $(source))) \ $(obj) endef TOOL_VAC308_LINK_LIBRARY_OUTPUT = ## @todo $(outbase).rsp TOOL_VAC308_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_VAC308_LINK_LIBRARY_DEPORD = define TOOL_VAC308_LINK_LIBRARY_CMDS $(if $(strip $(othersrc)),\ $(QUIET)$(call TOOL_VAC308_ENV_SETUP) \ $(TOOL_VAC308_IMP) $(TOOL_VAC308_IMPFLAGS) $(subst /,\\,$(out)) $(subst /,\\,$(othersrc)) ) $(if $(strip $(objs)),$(QUIET)$(call TOOL_VAC308_ENV_SETUP) \ $(TOOL_VAC308_AR) $(flags) $(subst /,\\,$(out)) $(foreach obj,$(subst /,\\,$(objs)),+"$(obj)") ";" ) endef TOOL_VAC308_LINK_PROGRAM_OUTPUT = $(outbase).map TOOL_VAC308_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VAC308_LINK_PROGRAM_DEPORD = define TOOL_VAC308_LINK_PROGRAM_CMDS $(QUIET)$(call TOOL_VAC308_ENV_SETUP,$(subst ;$(SP),;,$(foreach one,$(libpath),$(one);))) \ $(TOOL_VAC308_LD) $(flags) -Fe$(out) -Fm$(outbase).map $(filter-out %.res,$(objs)) $(libs) $(othersrc) $(if $(filter %.res,$(objs)), $(QUIET)$(call TOOL_VAC308_ENV_SETUP) \ $(TOOL_VAC308_RC) $(filter %.res,$(objs)) $(out)) endef TOOL_VAC308_LINK_DLL_OUTPUT = $(outbase).map TOOL_VAC308_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VAC308_LINK_DLL_DEPORD = define TOOL_VAC308_LINK_DLL_CMDS $(QUIET)$(call TOOL_VAC308_ENV_SETUP,$(subst ;$(SP),;,$(foreach one,$(libpath),$(one);))) \ $(TOOL_VAC308_LD) /B"/DLL" $(flags) -Fe$(out) -Fm$(outbase).map $(filter-out %.res,$(objs)) $(libs) $(othersrc) $(if $(filter %.res,$(objs)), $(QUIET)$(call TOOL_VAC308_ENV_SETUP) \ $(TOOL_VAC308_RC) $(filter %.res,$(objs)) $(out)) endef TOOL_VAC308_LINK_SYSMOD_OUTPUT = $(outbase).map TOOL_VAC308_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VAC308_LINK_SYSMOD_DEPORD = define TOOL_VAC308_LINK_SYSMOD_CMDS $(QUIET)$(call TOOL_VAC308_ENV_SETUP,$(subst ;$(SP),;,$(foreach one,$(libpath),$(one);))) \ $(TOOL_VAC308_LD) $(flags) -Fe$(out) -Fm$(outbase).map $(filter-out %.res,$(objs)) $(libs) $(othersrc) $(if $(filter %.res,$(objs)), $(QUIET)$(call TOOL_VAC308_ENV_SETUP) \ $(TOOL_VAC308_RC) $(filter %.res,$(objs)) $(out)) endef kbuild-3149/kBuild/tools/StandardDTrace.kmk0000644000175000017500000000355613252530251020614 0ustar locutuslocutus# $Id: StandardDTrace.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # Standard DTrace tool. # # # Copyright (c) 2012-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_StandardDTrace := Standard DTrace or similar. TOOL_StandardDTrace_DTRACE := dtrace TOOL_StandardDTrace_DTRACE_HDR_FLAGS := -h define TOOL_StandardDTrace_DTRACE_HDR_CMDS $(QUIET)$(TOOL_StandardDTrace_DTRACE) $(flags) \ -o "$(out)" -s "$(source)" endef TOOL_StandardDTrace_DTRACE_OBJ_NOT_NEEDED := darwin TOOL_StandardDTrace_DTRACE_OBJ_FLAGS := -G define TOOL_StandardDTrace_DTRACE_OBJ_CMDS $(QUIET)$(TOOL_StandardDTrace_DTRACE) \ $(if-expr $(intersects $(bld_trg_arch),$(KBUILD_ARCHES_64)),-64,-32) \ $(flags) \ -o "$(out)" -s "$(source)" \ $$(filter-out %-dtrace-object-format.o, $$($(target)_2_OBJS)) endef kbuild-3149/kBuild/tools/TAR.kmk0000644000175000017500000000506213252530251016411 0ustar locutuslocutus# $Id: TAR.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - tar unpacker. # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_TAR := tar unpacker. # Tool Specific Properties ifndef TOOL_TAR_TAR TOOL_TAR_TAR := $(wildcard $(KBUILD_DEVTOOLS_HST)/tar/v*/tar$(HOSTSUFF_EXE)) ifeq ($(TOOL_TAR_TAR),) TOOL_TAR_TAR := $(wildcard $(KBUILD_DEVTOOLS_HST)/bin/tar$(HOSTSUFF_EXE)) endif ifneq ($(TOOL_TAR_TAR),) TOOL_TAR_TAR := $(lastword $(sort $(TOOL_TAR_TAR))) else TOOL_TAR_TAR := tar$(HOSTSUFF_EXE) endif else TOOL_TAR_TAR := $(TOOL_TAR_TAR) endif TOOL_TAR_UNPACK ?= $(TOOL_TAR_TAR) # General Properties used by kBuild TOOL_TAR_UNPACKFLAGS ?= ## UNPACK one file. # @param $(target) Normalized main target name. # @param $(archive) The file to unpack. # @param $(flags) Flags. # @param $(inst) Where to unpack it. # @param $(out) Where to write the file list. TOOL_TAR_UNPACK_OUTPUT = TOOL_TAR_UNPACK_DEPEND = TOOL_TAR_UNPACK_DEPORD = ifeq ($(KBUILD_HOST),win) # hacking with buggy unxutils on windows. it doesn't like driver letters. define TOOL_TAR_UNPACK_CMDS $(QUIET)$(TOOL_TAR_UNPACK) -x $(flags) -C $(subst G:,,$(inst)) -f $(archive) $(QUIET)$(TOOL_TAR_UNPACK) -t $(filter-out -v --verbose,$(flags)) -f $(archive) > $(out) endef else define TOOL_TAR_UNPACK_CMDS $(QUIET)$(TOOL_TAR_UNPACK) -x $(flags) -C $(inst) -f $(archive) $(QUIET)$(TOOL_TAR_UNPACK) -t $(filter-out -v --verbose,$(flags)) -f $(archive) > $(out) endef endif kbuild-3149/kBuild/tools/VCC100.kmk0000644000175000017500000004446113252530251016625 0ustar locutuslocutus# $Id: VCC100.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - Visual C++ 10.0 (aka Visual 2010 and MSC v16), targeting $(KBUILD_TARGET). # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_VCC100 := Visual C++ 10.0 (aka Visual 2010 and MSC v16), targeting $(KBUILD_TARGET). # Tool Specific Properties ifndef PATH_TOOL_VCC100 PATH_TOOL_VCC100 := $(wildcard $(KBUILD_DEVTOOLS_TRG)/vcc/v10*) ifeq ($(PATH_TOOL_VCC100),) PATH_TOOL_VCC100 := $(wildcard $(KBUILD_DEVTOOLS)/win.x86/vcc/v10*) endif ifeq ($(PATH_TOOL_VCC100),) PATH_TOOL_VCC100 := $(wildcard $(KBUILD_DEVTOOLS)/x86.win32/vcc/v10*) endif ifeq ($(PATH_TOOL_VCC100),) PATH_TOOL_VCC100 := $(wildcard $(KBUILD_DEVTOOLS)/win.amd64/vcc/v10*) endif ifeq ($(PATH_TOOL_VCC100),) PATH_TOOL_VCC100 := $(lastword $(sort $(PATH_TOOL_VCC100))) endif # if not found, we'll enter 'pathless' mode. else # Resolve any fancy stuff once and for all. PATH_TOOL_VCC100 := $(PATH_TOOL_VCC100) endif ifneq ($(PATH_TOOL_VCC100),) ifeq ($(KBUILD_HOST).$(KBUILD_HOST_ARCH),win.amd64) PATH_TOOL_VCC100_BIN.amd64 ?= $(PATH_TOOL_VCC100)/bin/amd64 else PATH_TOOL_VCC100_BIN.amd64 ?= $(PATH_TOOL_VCC100)/bin/x86_amd64 endif PATH_TOOL_VCC100_BIN.x86 ?= $(PATH_TOOL_VCC100)/bin PATH_TOOL_VCC100_BIN ?= $(PATH_TOOL_VCC100_BIN.$(KBUILD_TARGET_ARCH)) PATH_TOOL_VCC100_LIB.amd64 ?= $(PATH_TOOL_VCC100)/lib/amd64 PATH_TOOL_VCC100_LIB.x86 ?= $(PATH_TOOL_VCC100)/lib PATH_TOOL_VCC100_LIB ?= $(PATH_TOOL_VCC100_LIB.$(KBUILD_TARGET_ARCH)) PATH_TOOL_VCC100_INC ?= $(PATH_TOOL_VCC100)/include PATH_TOOL_VCC100_ATLMFC ?= $(PATH_TOOL_VCC100X86)/atlmfc PATH_TOOL_VCC100_ATLMFC_INC ?= $(PATH_TOOL_VCC100_ATLMFC)/include PATH_TOOL_VCC100_ATLMFC_LIB.amd64 ?= $(PATH_TOOL_VCC100_ATLMFC)/lib PATH_TOOL_VCC100_ATLMFC_LIB.x86 ?= $(PATH_TOOL_VCC100_ATLMFC)/lib/amd64 PATH_TOOL_VCC100_ATLMFC_LIB ?= $(PATH_TOOL_VCC100_ATLMFC_LIB.$(KBUILD_TARGET_ARCH)) TOOL_VCC100_CC ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100_BIN)/cl.exe TOOL_VCC100_CXX ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100_BIN)/cl.exe TOOL_VCC100_AS ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100_BIN)/ml64.exe TOOL_VCC100_AR ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100_BIN)/lib.exe TOOL_VCC100_LD ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100_BIN)/link.exe TOOL_VCC100_DUMPBIN ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100_BIN)/dumpbin.exe TOOL_VCC100_EDITBIN ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100_BIN)/editbin.exe else # Pathless, relies on the environment. TOOL_VCC100_CC ?= $(EXEC_X86_WIN32) cl.exe TOOL_VCC100_CXX ?= $(EXEC_X86_WIN32) cl.exe TOOL_VCC100_AS ?= $(EXEC_X86_WIN32) ml64.exe TOOL_VCC100_AR ?= $(EXEC_X86_WIN32) lib.exe TOOL_VCC100_LD ?= $(EXEC_X86_WIN32) link.exe TOOL_VCC100_DUMPBIN ?= $(EXEC_X86_WIN32) dumpbin.exe TOOL_VCC100_EDITBIN ?= $(EXEC_X86_WIN32) editbin.exe endif TOOL_VCC100_RC ?= $(EXEC_X86_WIN32) $(call TOOL_VCC100_FN_FIND_SDK_TOOL,rc.exe,[Rr][Cc].[Ee][Xx][Ee],TOOL_VCC100_RC_CACHED) TOOL_VCC100_MT ?= $(EXEC_X86_WIN32) $(call TOOL_VCC100_FN_FIND_SDK_TOOL,mt.exe,[Mm][Tt].[Ee][Xx][Ee],TOOL_VCC100_MT_CACHED) # The following in duplicated in VCC100.kmk and VCC100X86.kmk. TOOL_VCC100_FN_FIND_SDK_TOOL_SUB = $(eval $3 := $(firstword \ $(if-expr defined(PATH_SDK_WINPSDK71_BIN), $(wildcard $(PATH_SDK_WINPSDK71_BIN)/$2)) \ $(if-expr defined(PATH_SDK_WINPSDK_BIN) , $(wildcard $(PATH_SDK_WINPSDK_BIN)/$2)) \ $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST)/sdk/*/[Bb][Ii][Nn]/$2)) \ $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST_ALT)/sdk/*/[Bb][Ii][Nn]/$2)) \ $1)) TOOL_VCC100_FN_FIND_SDK_TOOL = $(if-expr !defined($3),$(TOOL_VCC100_FN_FIND_SDK_TOOL_SUB),)$($3) ## Disabled fast DEP_IDB based dependencies. #VCC100_OLD_DEPS = 1 ## Constructs the correct .pdb name (the name is lowercased). # @param $(1) Base name, no extention. # @param $(2) The extension. TOOL_VCC100_PDB = $(dir $(1))$(tolower $(notdir $(1))).$(2) # General Properties used by kBuild TOOL_VCC100_COBJSUFF ?= .obj TOOL_VCC100_CFLAGS ?= -TC -nologo -Zi TOOL_VCC100_CFLAGS.debug ?= TOOL_VCC100_CFLAGS.dbgopt ?= -O2 TOOL_VCC100_CFLAGS.release ?= -O2 TOOL_VCC100_CFLAGS.profile ?= -O2 TOOL_VCC100_CINCS ?= $(PATH_TOOL_VCC100_INC) TOOL_VCC100_CDEFS ?= TOOL_VCC100_CXXOBJSUFF ?= .obj TOOL_VCC100_CXXFLAGS ?= -TP -nologo -Zi TOOL_VCC100_CXXFLAGS.debug ?= TOOL_VCC100_CXXFLAGS.dbgopt ?= -O2 TOOL_VCC100_CXXFLAGS.release ?= -O2 TOOL_VCC100_CXXFLAGS.profile ?= -O2 TOOL_VCC100_CXXINCS ?= $(PATH_TOOL_VCC100_INC) $(PATH_TOOL_VCC100_ATLMFC_INC) TOOL_VCC100_CXXDEFS ?= TOOL_VCC100_ASOBJSUFF ?= .obj TOOL_VCC100_RCOBJSUFF ?= .res TOOL_VCC100_RCINCS ?= $(PATH_TOOL_VCC100_INC) $(PATH_TOOL_VCC100_ATLMFC_INC) TOOL_VCC100_ARFLAGS.amd64 ?= -machine:amd64 TOOL_VCC100_ARFLAGS.x86 ?= -machine:x86 TOOL_VCC100_ARFLAGS ?= -nologo TOOL_VCC100_ARLIBSUFF ?= .lib TOOL_VCC100_LDFLAGS.amd64 ?= -machine:amd64 TOOL_VCC100_LDFLAGS.x86 ?= -machine:x86 TOOL_VCC100_LDFLAGS ?= -nologo TOOL_VCC100_LDFLAGS.debug ?= -debug TOOL_VCC100_LDFLAGS.dbgopt ?= -debug TOOL_VCC100_LDFLAGS.profile ?= -debug TOOL_VCC100_LDFLAGS.release ?= TOOL_VCC100_LIBPATH.amd64 ?= $(PATH_TOOL_VCC100_LIB.amd64) $(PATH_TOOL_VCC100_ATLMFC_LIB.amd64) TOOL_VCC100_LIBPATH.x86 ?= $(PATH_TOOL_VCC100_LIB.x86) $(PATH_TOOL_VCC100_ATLMFC_LIB.x86) ## Compile C source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC100_COMPILE_C_DEPEND = TOOL_VCC100_COMPILE_C_DEPORD = TOOL_VCC100_COMPILE_C_OUTPUT = TOOL_VCC100_COMPILE_C_OUTPUT_MAYBE = $(call TOOL_VCC100_PDB, $(outbase)-obj,pdb) $(call TOOL_VCC100_PDB, $(outbase)-obj,idb) define TOOL_VCC100_COMPILE_C_CMDS $(QUIET)$(TOOL_VCC100_CC) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fd$(outbase)-obj.pdb \ -Fo$(obj)\ $(subst /,\\,$(abspath $(source))) $(QUIET)$(DEP_OBJ) -f -s -q -o $(dep) -t $(obj) $(obj) endef ## Compile C++ source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC100_COMPILE_CXX_DEPEND = $($(target)_1_VCC_PCH_FILE) TOOL_VCC100_COMPILE_CXX_DEPORD = TOOL_VCC100_COMPILE_CXX_OUTPUT = TOOL_VCC100_COMPILE_CXX_OUTPUT_MAYBE = $(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB)\ ,,$(call TOOL_VCC100_PDB, $(outbase)-obj,pdb) $(call TOOL_VCC100_PDB, $(outbase)-obj,idb)) define TOOL_VCC100_COMPILE_CXX_CMDS $(QUIET)$(TOOL_VCC100_CXX) -c\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ $(if-expr defined($(target)_PCH_HDR)\ ,-FI$($(target)_PCH_HDR) -Yu$($(target)_PCH_HDR) -Fp$($(target)_1_VCC_PCH_FILE),)\ -Fd$(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB),$($(target)_1_VCC_COMMON_OBJ_PDB),$(outbase)-obj.pdb) \ -Fo$(obj)\ $(subst /,\\,$(abspath $(source))) $(QUIET)$(DEP_OBJ) -f -s -q -o $(dep) -t $(obj) $(obj) endef # # Helper tool for creating the precompiled C++ header. # # It only have the C++ compile bits and it's purpose is to skip bits # related _1_VCC_PCH_FILE and add -Yc. # TOOL_VCC100-PCH := Helper for creating precompiled header using CXX handling. TOOL_VCC100-PCH_EXTENDS := VCC100 TOOL_VCC100-PCH_CXXOBJSUFF := .obj TOOL_VCC100-PCH_CXXINCS = $(TOOL_VCC100_CXXINCS) TOOL_VCC100-PCH_CXXFLAGS.debug = $(TOOL_VCC100_CXXFLAGS.debug) TOOL_VCC100-PCH_CXXFLAGS.dbgopt = $(TOOL_VCC100_CXXFLAGS.dbgopt) TOOL_VCC100-PCH_CXXFLAGS.release = $(TOOL_VCC100_CXXFLAGS.release) TOOL_VCC100-PCH_CXXFLAGS.profile = $(TOOL_VCC100_CXXFLAGS.profile) TOOL_VCC100-PCH_COMPILE_CXX_DEPEND = $(NO_SUCH_VARIABLE) TOOL_VCC100-PCH_COMPILE_CXX_DEPORD = $(NO_SUCH_VARIABLE) TOOL_VCC100-PCH_COMPILE_CXX_OUTPUT = $($(target)_1_VCC_PCH_FILE) $($(target)_1_VCC_COMMON_OBJ_PDB) TOOL_VCC100-PCH_COMPILE_CXX_OUTPUT_MAYBE = $(NO_SUCH_VARIABLE) ifdef TOOL_VCC100_KSUBMIT define TOOL_VCC100-PCH_COMPILE_CXX_CMDS $(QUIET)$(TOOL_VCC100_KSUBMIT) --no-pch-caching -P $(DEP_OBJ_INT) -f -s -q -e .pch -o $(dep) -t $(obj) $(obj)\ -- $(TOOL_VCC100_CXX) -c -Yc\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fp$($(target)_1_VCC_PCH_FILE) \ -Fd$($(target)_1_VCC_COMMON_OBJ_PDB) \ -Fo$(obj)\ -TP \ $(subst /,\\,$(abspath $(source))) endef else define TOOL_VCC100-PCH_COMPILE_CXX_CMDS $(QUIET)$(TOOL_VCC100_CXX) -c -Yc\ $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ -Fp$($(target)_1_VCC_PCH_FILE) \ -Fd$($(target)_1_VCC_COMMON_OBJ_PDB) \ -Fo$(obj)\ -TP \ $(subst /,\\,$(abspath $(source))) $(QUIET)$(DEP_OBJ) -f -s -q -e .pch -o $(dep) -t $(obj) $(obj) endef endif # !TOOL_VCC100_KSUBMIT ## @todo configure the assembler template. ## Compile resource source. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(obj) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This shall be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. No -D or something. # @param $(incs) Includes. No -I or something. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # # @param $(outbase) Output basename (full). Use this for list files and such. # @param $(objsuff) Object suffix. TOOL_VCC100_COMPILE_RC_OUTPUT = TOOL_VCC100_COMPILE_RC_DEPEND = TOOL_VCC100_COMPILE_RC_DEPORD = define TOOL_VCC100_COMPILE_RC_CMDS $(QUIET)$(TOOL_VCC100_RC) \ $(flags) $(addprefix /i, $(subst /,\\,$(incs))) $(addprefix /d, $(defs))\ /fo$(obj)\ $(subst /,\\,$(abspath $(source))) endef ## Link library # @param $(target) Normalized main target name. # @param $(out) Library name. # @param $(objs) Object files to put in the library. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_VCC100_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_VCC100_LINK_LIBRARY_DEPORD = TOOL_VCC100_LINK_LIBRARY_OUTPUT = $(outbase).rsp TOOL_VCC100_LINK_LIBRARY_OUTPUT_MAYBE = $(outbase).lst $(outbase).exp $(outbase).pdb define TOOL_VCC100_LINK_LIBRARY_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs) \ $(filter-out %.def,$(othersrc))) \ $(addprefix /DEF:,$(filter %.def,$(othersrc))) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC100_AR) $(flags) /OUT:$(out) @$(outbase).rsp endef ## Link program # @param $(target) Normalized main target name. # @param $(out) Program name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_VCC100_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC100_LINK_PROGRAM_DEPORD = TOOL_VCC100_LINK_PROGRAM_OUTPUT = $(outbase).map $(outbase).rsp TOOL_VCC100_LINK_PROGRAM_OUTPUT_MAYBE = $(outbase).lib $(outbase).exp $(outbase).ilk $(out).manifest TOOL_VCC100_LINK_PROGRAM_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC100_LINK_PROGRAM_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb define TOOL_VCC100_LINK_PROGRAM_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC100_LD) $(flags) \ /OUT:$(out) \ /MAPINFO:EXPORTS /INCREMENTAL:NO \ /MAP:$(outbase).map \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp ifndef TOOL_VCC100_NO_AUTO_MANIFEST $(QUIET)$(TEST) -f $(out).manifest -- \ $(TOOL_VCC100_MT) -manifest $(subst /,\\,$(out)).manifest -outputresource:$(subst /,\\,$(out)) endif endef ## Link DLL. # @param $(target) Normalized main target name. # @param $(out) DLL name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_VCC100_LINK_DLL_DEPEND = $(objs) $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC100_LINK_DLL_DEPORD = $(call DIRDEP,$(PATH_STAGE_LIB)) TOOL_VCC100_LINK_DLL_OUTPUT = $(outbase).map $(outbase).lib $(outbase).exp $(outbase).rsp TOOL_VCC100_LINK_DLL_OUTPUT_MAYBE = $(outbase).ilk $(out).manifest $(PATH_STAGE_LIB)/$(notdir $(outbase)).exp TOOL_VCC100_LINK_DLL_OUTPUT_MAYBE_PRECIOUS = $(PATH_STAGE_LIB)/$(notdir $(outbase)).lib TOOL_VCC100_LINK_DLL_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC100_LINK_DLL_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb define TOOL_VCC100_LINK_DLL_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC100_LD) $(flags) \ /OUT:$(out) \ /IMPLIB:$(outbase).lib \ /MAPINFO:EXPORTS /INCREMENTAL:NO \ /MAP:$(outbase).map \ /DLL \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp ifndef TOOL_VCC100_NO_AUTO_MANIFEST $(QUIET)$(TEST) -f $(out).manifest -- \ $(TOOL_VCC100_MT) -manifest $(subst /,\\,$(out)).manifest '-outputresource:$(subst /,\\,$(out));#2' endif $(QUIET)$(TEST) -f $(outbase).lib -- $(KLIBTWEAKER_EXT) --clear-timestamps $(outbase).lib $(QUIET)$(CP) --changed --ignore-non-existing $(outbase).exp $(outbase).lib $(PATH_STAGE_LIB)/ $(eval _DIRS += $(PATH_STAGE_LIB)) endef ## Link system module (windows aka driver, linux aka kernel module) # @param $(target) Normalized main target name. # @param $(out) System module name. # @param $(objs) Object files to link together. # @param $(libs) Libraries to search. # @param $(libpath) Library search paths. # @param $(flags) Flags. # @param $(dirdep) Directory creation dependency. # @param $(deps) Other dependencies. # @param $(othersrc) Unhandled sources. # @param $(custom_pre) Custom step invoked before linking. # @param $(custom_post) Custom step invoked after linking. # # @param $(outbase) Output basename (full). Use this for list files and such. TOOL_VCC100_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_VCC100_LINK_SYSMOD_DEPORD = TOOL_VCC100_LINK_SYSMOD_OUTPUT = $(outbase).map $(outbase).rsp TOOL_VCC100_LINK_SYSMOD_OUTPUT_MAYBE = $(outbase).lib $(outbase).exp $(outbase).ilk $(out).manifest TOOL_VCC100_LINK_SYSMOD_OUTPUT_DEBUG = $(outbase).pdb TOOL_VCC100_LINK_SYSMOD_DEBUG_INSTALL_FN = $(2).pdb=>$(basename $(3)).pdb define TOOL_VCC100_LINK_SYSMOD_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp \ $(foreach arg,\ $(subst /,\\,$(objs)) \ $(subst /,\\,$(libs)) \ ,\"$(arg)\") $(QUIET)$(TOOL_VCC100_LD) $(flags) \ /OUT:$(out) \ /MAPINFO:EXPORTS /INCREMENTAL:NO \ /MAP:$(outbase).map \ $(foreach def,$(filter %.def,$(othersrc)), /DEF:$(def)) \ $(subst /,\\,$(filter %.exp %.res,$(othersrc))) \ $(foreach p,$(libpath), /LIBPATH:$(p)) \ @$(outbase).rsp ifndef TOOL_VCC100_NO_AUTO_MANIFEST $(QUIET)$(TEST) -f $(out).manifest -- \ $(TOOL_VCC100_MT) -manifest $(subst /,\\,$(out)).manifest '-outputresource:$(subst /,\\,$(out));#2' endif endef kbuild-3149/kBuild/tools/OPENWATCOM-16.kmk0000644000175000017500000002163513252530251017667 0ustar locutuslocutus# $Id: OPENWATCOM-16.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Tool Config - Open Watcom v1.4 and later, 16-bit targets. # # @remarks wrc is untested, so are DLLs, and programs. # # Copyright (c) 2008-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_OPENWATCOM-16 = Open Watcom v1.4 and later - 16-bit targets. TOOL_OPENWATCOM-16_EXTENDS = OPENWATCOM TOOL_OPENWATCOM-16_ASFLAGS.win ?= -bt=windows TOOL_OPENWATCOM-16_CFLAGS.win ?= -bt=windows TOOL_OPENWATCOM-16_CXXFLAGS.win ?= -bt=windows TOOL_OPENWATCOM-16_RCFLAGS.win ?= -bt=windows TOOL_OPENWATCOM-16_LDFLAGS.win ?= -bt=windows TOOL_OPENWATCOM-16_COMPILE_AS_DEPEND = TOOL_OPENWATCOM-16_COMPILE_AS_DEPORD = TOOL_OPENWATCOM-16_COMPILE_AS_OUTPUT = TOOL_OPENWATCOM-16_COMPILE_AS_OUTPUT_MAYBE = $(obj).err ifdef TOOL_OPENWATCOM_USE_KSUBMIT define TOOL_OPENWATCOM-16_COMPILE_AS_CMDS $(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP_BD,, -P $(DEP_OBJ_INT) -s -f -q -o "$(dep)" -t "$(obj)" "$(obj)") \ $(TOOL_OPENWATCOM_AS) \ $(flags) \ $(addsuffix , $(addprefix -i=, $(call TOOL_OPENWATCOM_FIX_SLASHES,$(incs)))) \ $(addprefix -d, $(defs)) \ -fo=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(obj)) \ -fr=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(obj)).err \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(abspath $(source))) endef else define TOOL_OPENWATCOM-16_COMPILE_AS_CMDS $(QUIET) $(call TOOL_OPENWATCOM_ENV_SETUP_BD) $(TOOL_OPENWATCOM_AS) \ $(flags) \ $(addsuffix , $(addprefix -i=, $(call TOOL_OPENWATCOM_FIX_SLASHES,$(incs)))) \ $(addprefix -d, $(defs)) \ -fo=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(obj)) \ -fr=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(obj)).err \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(abspath $(source))) $(QUIET)$(DEP_OBJ) -s -f -q -o "$(dep)" -t "$(obj)" "$(obj)" endef endif TOOL_OPENWATCOM-16_COMPILE_C_DEPEND = TOOL_OPENWATCOM-16_COMPILE_C_DEPORD = TOOL_OPENWATCOM-16_COMPILE_C_OUTPUT = TOOL_OPENWATCOM-16_COMPILE_C_OUTPUT_MAYBE = $(obj).err ifdef TOOL_OPENWATCOM_USE_KSUBMIT define TOOL_OPENWATCOM-16_COMPILE_C_CMDS $(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP_BD,, -P $(DEP_OBJ_INT) -s -f -q -o "$(dep)" -t "$(obj)" "$(obj)") \ $(TOOL_OPENWATCOM_CC16) \ $(flags) \ $(addsuffix , $(addprefix -i=, $(call TOOL_OPENWATCOM_FIX_SLASHES,$(incs)))) \ $(addprefix -d, $(defs)) \ -fo=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(obj)) \ -fr=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(obj)).err \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(abspath $(source))) endef else define TOOL_OPENWATCOM-16_COMPILE_C_CMDS $(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP_BD) $(TOOL_OPENWATCOM_CC16) \ $(flags) \ $(addsuffix , $(addprefix -i=, $(call TOOL_OPENWATCOM_FIX_SLASHES,$(incs)))) \ $(addprefix -d, $(defs)) \ -fo=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(obj)) \ -fr=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(obj)).err \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(abspath $(source))) $(QUIET)$(DEP_OBJ) -s -f -q -o "$(dep)" -t "$(obj)" "$(obj)" endef endif TOOL_OPENWATCOM-16_COMPILE_CXX_DEPEND = TOOL_OPENWATCOM-16_COMPILE_CXX_DEPORD = TOOL_OPENWATCOM-16_COMPILE_CXX_OUTPUT = TOOL_OPENWATCOM-16_COMPILE_CXX_OUTPUT_MAYBE = $(obj).err ifdef TOOL_OPENWATCOM_USE_KSUBMIT define TOOL_OPENWATCOM-16_COMPILE_CXX_CMDS $(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP_BD,, -P $(DEP_OBJ_INT) -s -f -q -o "$(dep)" -t "$(obj)" "$(obj)") \ $(TOOL_OPENWATCOM_CXX16) \ $(flags) \ $(addsuffix , $(addprefix -i=, $(call TOOL_OPENWATCOM_FIX_SLASHES,$(incs)))) \ $(addprefix -d, $(defs)) \ -fo=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(obj)) \ -fr=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(obj)).err \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(abspath $(source))) endef else define TOOL_OPENWATCOM-16_COMPILE_CXX_CMDS $(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP_BD) $(TOOL_OPENWATCOM_CXX16) \ $(flags) \ $(addsuffix , $(addprefix -i=, $(call TOOL_OPENWATCOM_FIX_SLASHES,$(incs)))) \ $(addprefix -d, $(defs)) \ -fo=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(obj)) \ -fr=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(obj)).err \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(abspath $(source))) $(QUIET)$(DEP_OBJ) -s -f -q -o "$(dep)" -t "$(obj)" "$(obj)" endef endif TOOL_OPENWATCOM-16_COMPILE_RC_OUTPUT = TOOL_OPENWATCOM-16_COMPILE_RC_DEPEND = TOOL_OPENWATCOM-16_COMPILE_RC_DEPORD = define TOOL_OPENWATCOM-16_COMPILE_RC_CMDS $(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP) \ $(TOOL_OPENWATCOM_RC) -r\ $(flags) \ $(addprefix -i=, $(call TOOL_OPENWATCOM_FIX_SLASHES,$(incs))) \ $(addprefix -d, $(defs))\ -fo=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(obj)) \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(abspath $(source))) endef TOOL_OPENWATCOM-16_LINK_LIBRARY_OUTPUT = $(outbase).rsp TOOL_OPENWATCOM-16_LINK_LIBRARY_DEPEND = $(othersrc) TOOL_OPENWATCOM-16_LINK_LIBRARY_DEPORD = define TOOL_OPENWATCOM-16_LINK_LIBRARY_CMDS $(QUIET)$(APPEND) -tn $(outbase).rsp $(foreach obj,$(call TOOL_OPENWATCOM_FIX_SLASHES,$(objs) $(othersrc)),'+"$(obj)"') $(QUIET)$(TOOL_OPENWATCOM_ENV_SETUP_BD) $(TOOL_OPENWATCOM_AR) $(flags) $(call TOOL_OPENWATCOM_FIX_SLASHES,$(out)) @$(outbase).rsp endef TOOL_OPENWATCOM-16_LINK_PROGRAM_OUTPUT = $(outbase).map TOOL_OPENWATCOM-16_LINK_PROGRAM_OUTPUT_MAYBE = $(outbase).sym TOOL_OPENWATCOM-16_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_OPENWATCOM-16_LINK_PROGRAM_DEPORD = define TOOL_OPENWATCOM-16_LINK_PROGRAM_CMDS $(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP_BD,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \ $(TOOL_OPENWATCOM_LD16) \ $(flags) \ -fe=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(out)) \ -fm=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(outbase).map) \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(filter-out %.res,$(objs))) \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(libs)) \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(othersrc)) $(if $(filter %.res,$(objs)), $(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP) \ $(TOOL_OPENWATCOM_RC) \ $(filter -bt=%,$(flags)) \ /fe=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(out)) \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(filter %.res,$(objs)))) endef TOOL_OPENWATCOM-16_LINK_DLL_OUTPUT = $(outbase).map TOOL_OPENWATCOM-16_LINK_DLL_OUTPUT_MAYBE = $(outbase).sym TOOL_OPENWATCOM-16_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_OPENWATCOM-16_LINK_DLL_DEPORD = define TOOL_OPENWATCOM-16_LINK_DLL_CMDS $(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP_BD,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \ $(TOOL_OPENWATCOM_LD16) \ $(flags) \ -fe=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(out)) \ -fm=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(outbase).map) \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(filter-out %.res,$(objs))) \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(libs)) \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(othersrc)) $(if $(filter %.res,$(objs)), $(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP) \ $(TOOL_OPENWATCOM_RC) \ $(filter -bt=%,$(flags)) \ /fe=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(out)) \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(filter %.res,$(objs)))) endef TOOL_OPENWATCOM-16_LINK_SYSMOD_OUTPUT = $(outbase).map TOOL_OPENWATCOM-16_LINK_SYSMOD_OUTPUT_MAYBE = $(outbase).sym TOOL_OPENWATCOM-16_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc) TOOL_OPENWATCOM-16_LINK_SYSMOD_DEPORD = define TOOL_OPENWATCOM-16_LINK_SYSMOD_CMDS $(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP_BD,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \ $(TOOL_OPENWATCOM_LD16) \ $(flags) \ -fe=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(out)) \ -fm=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(outbase).map) \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(filter-out %.res,$(objs))) \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(libs)) \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(othersrc)) $(if $(filter %.res,$(objs)), $(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP) \ $(TOOL_OPENWATCOM_RC) \ $(filter -bt=%,$(flags)) \ /fe=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(out)) \ $(call TOOL_OPENWATCOM_FIX_SLASHES,$(filter %.res,$(objs)))) endef kbuild-3149/kBuild/tools/BISON.kmk0000644000175000017500000000321413252530251016632 0ustar locutuslocutus# $Id: BISON.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # GNU bison tool # # # Copyright (c) 2009-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TOOL_BISON = GNU bison ifndef TOOL_BISON_YACC TOOL_BISON_YACC := bison$(HOSTSUFF_EXE) endif #TOOL_BISON_YACCFLAGS ?= TOOL_BISON_YACC_OUTPUT = $(evalcall KB_FN_OPT_TEST_SHORT_LONG,d,--defines,$(flags),$(outbase).h$(substr $(suffix $(source)),3),) TOOL_BISON_YACC_OUTPUT_MAYBE = TOOL_BISON_YACC_DEPEND = TOOL_BISON_YACC_DEPORD = define TOOL_BISON_YACC_CMDS $(QUIET)$(TOOL_BISON_YACC) $(flags) -o $(out) $(source) endef kbuild-3149/kBuild/footer-pass2-patches.kmk0000644000175000017500000000332513252530251020574 0ustar locutuslocutus# $Id: footer-pass2-patches.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild - Footer - Target lists - Pass 2 - Patches. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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 source of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # ## ## Patching. ## ## #define def_patch_src # #endef # # ## Deal with one patch target. #define def_patch # #$(foreach source,$($(target)_SOURCES) $($(target)_SOURCES.$(KBUILD_TYPE)) $($(target)_SOURCES.$(KBUILD_TARGET)) $($(target)_SOURCES.$(KBUILD_TARGET_ARCH)) $($(target)_SOURCES.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)),\ # $(evalval def_patch_src)) # #_PATCHES += #endef # #$(foreach target, $(_ALL_PATCHES), \ # $(evalval def_patch)) # kbuild-3149/kBuild/footer-pass2-fetches.kmk0000644000175000017500000003541313252530250020570 0ustar locutuslocutus# $Id: footer-pass2-fetches.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild - Footer - Target lists - Pass 2 - Fetches. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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 source of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # ## @page pg_fetches Fetching Tools, Sources and Similar. # # The targets listed in the the FETCHES target list have the following attributes: # SOURCES # INST # FETCHTOOL # FETCHFLAGS # FETCHDIR # UNPACKTOOL # UNPACKFLAGS # # As usual the target name is an alias for 'creating' the target. Other # aliases are: # pass_fetches # fetch # unfetch # download # unpack # # @remark # # This is a little bit complex because we must guarantee that if a source file # changes only sligtly we must refetch it and to a proper unpacking of it. It # is also a desire that fetched archives and unpacked files can be deleted to # save space. # # Thus, we must be able to cleanup what we've unpacked should any of the # sources be removed. We do this by maintaining a file listing the files # and directories that was unpacked. This operation is named 'unfetch'. # # We make use of the SIZE and MD5 attributes for each of the sources to # create a digest that is stored in the primary target file. Subsequent # runswill compare their digest with it to decide if a refetch is required. # When a refetch is found necessary, an 'unfetch' is performed first to # clean out old files and directores. Note even changes in source order # will cause a refetch due to the way the digest is constructed and # evaluated. # # By not depending directly on the archives (nor on any unpacked files) # but on a goal made up from the archive name, size and md5, we allow # the user to delete the archives. Naturally, this means we'll have to # check and fetch missing archives before attempting to unpack them. # # @remark # # This feature will *NOT* work correctly with vanilla GNU make becuase # it makes use of includedep to avoid too many unnecessary files. # # @todo # 0. Move the fetches out into a unit. # 1. Download corruption / continuation. # 2. It's quite possible that there is one too many indirect dependency now... # ## generates the fetch rule define def_fetch_src_fetch_rule # Indirect goal for downloading something. .PRECIOUS: $(out) $(out) + $($(target)_$(srcname)_FETCH_2_OUTPUT) +| $($(target)_$(srcname)_FETCH_2_OUTPUT_MAYBE) : \ | $($(target)_$(srcname)_FETCH_2_DEPORD) %$$(call MSG_FETCH_DL,$(target),$(source),$(out)) @## @todo do fancy stuff like download continuation. $$(QUIET)$$(RM) -f -- $(out) $(cmds) $$(QUIET)$(if $(md5),$$(MD5SUM_EXT) -b -C $(md5) $(out)) # Intermediate goal for making sure the md5 and size matches. it will (re) fetch the archive if necessary. $(out).checked_$(md5)_$(size): $($(target)_$(srcname)_FETCH_2_DEPEND) | $($(target)_$(srcname)_FETCH_2_DEPORD) %$$(call MSG_FETCH_CHK,$(target),$(source),$(out)) $$(QUIET)$$(RM) -f -- $$@ @# (re)fetch the file if it doesn't exist or if it doesn't matches the md5. @## @todo do fancy stuff like download continuation. $$(QUIET)( test -f $(out) && $(if $(md5),$$(MD5SUM_EXT) -b -C $(md5) $(out), true) ) \ || ( $$(RM_EXT) -f $(out) \ && $$(MAKE) $(out) -f $(MAKEFILE) --no-print-directory ) $$(QUIET2)$$(APPEND) $$@ _TARGET_$(target)_FETCHED += $(out) $(out).checked_$(md5)_$(size) # Just a little precaution. .NOTPARALLEL: $(out) $(out).checked_$(md5)_$(size) endef # def_fetch_src_fetch_rule $(eval-opt-var def_fetch_src_fetch_rule) ## generates the unpack rule define def_fetch_src_unpack_rule # This is the unpack rule. it has an order-only dependency on the download check. $(out) + $($(target)_$(srcname)_UNPACK_2_OUTPUT) +| $($(target)_$(srcname)_UNPACK_2_OUTPUT_MAYBE) : \ $($(target)_$(srcname)_UNPACK_2_DEPEND) \ | $($(target)_$(srcname)_UNPACK_2_DEPORD) \ $(archive).checked_$(md5)_$(size) \ $(dir $(out)) %$$(call MSG_FETCH_UP,$(target),$(archive),$(inst)) $$(QUIET)$$(RM) -f -- $(out) $$(QUIET)$$(MKDIR) -p -- $(dir $(out)) @# if the source archive doesn't exist fetch it (may have been deleted to save space). $$(QUIET)test -f $(archive) \ || ( $$(RM_EXT) -f $(archive).checked_$(md5)_$(size) \ && $$(MAKE) $(archive).checked_$(md5)_$(size) -f $(MAKEFILE) --no-print-directory ) $(cmds) $$(QUIET2)$$(APPEND) $(out) $(notdir $(archive).checked_$(md5)_$(size)) $$(QUIET2)$$(APPEND) $(out) $(notdir $(out)) $(eval _TARGET_$(target)_UNPACKED += $(out)) _TARGET_$(target)_DIGEST := $(_TARGET_$(target)_DIGEST)-$(srcname)_$(md5)_$(size) .NOTPARALLEL: $(out) endef # def_fetch_src_unpack_rule $(eval-opt-var def_fetch_src_unpack_rule) ## Processes a fetch source # define def_fetch_src #$ (warning dbg: def_fetch_src: source='$(source)' target='$(target)') # common local srcname := $(notdir $(source)) local inst := $(firstword \ $($(target)_$(source)_INST)\ $($(target)_$(srcname)_INST)\ $($(source)_INST)\ $($(srcname)_INST)\ $($(target)_INST)\ ) ifneq ($(patsubst %/,ok,$(inst)),ok) $(error kBuild: Bad or missing INST property for source '$(source)' in target '$(target)': $(inst)) endif ## @todo Install-revamp: FIXME INSTARGET_$(target)_$(srcname) := $(inst) local fetchdir := $(firstword \ $($(target)_$(source)_FETCHDIR)\ $($(target)_$(srcname)_FETCHDIR)\ $($(source)_FETCHDIR)\ $($(srcname)_FETCHDIR)\ $($(target)_FETCHDIR)\ $(FETCHDIR)\ $(PATH_TARGET)\ ) local deps := \ $($(target)_$(source)_DEPS)\ $($(target)_$(srcname)_DEPS)\ $($(source)_DEPS)\ $($(srcname)_DEPS)\ $($(target)_DEPS) local orderdeps := \ $($(target)_$(source)_ORDERDEPS)\ $($(target)_$(srcname)_ORDERDEPS)\ $($(source)_ORDERDEPS)\ $($(srcname)_ORDERDEPS)\ $($(target)_ORDERDEPS) local md5 := $(firstword \ $($(target)_$(source)_MD5)\ $($(target)_$(srcname)_MD5)\ $($(source)_MD5)\ $($(srcname)_MD5)\ $($(target)_MD5)\ ) local size := $(firstword \ $($(target)_$(source)_SIZE)\ $($(target)_$(srcname)_SIZE)\ $($(source)_SIZE)\ $($(srcname)_SIZE)\ $($(target)_SIZE)\ ) clean_files += \ $($(target)_$(source)_CLEAN)\ $($(target)_$(srcname)_CLEAN)\ $($(source)_CLEAN)\ $($(srcname)_CLEAN) local dep := # not legal for fetch and unpack tools # # The fetching. # local out := $(fetchdir)/$(srcname) local archive := $(out) $(target)_$(srcname)_1_TARGET = $(TARGET_$(target)_$(srcname)) $(call KB_FN_ASSIGN_DEPRECATED,TARGET_$(target)_$(srcname),$(TARGET_$(target)_$(srcname)),TARGET_$(target)_$(srcname)) local dirdep := $(call DIRDEP,$(fetchdir)) local tool := $(firstword \ $($(target)_$(source)_FETCHTOOL)\ $($(target)_$(srcname)_FETCHTOOL)\ $($(target)_$(source)_TOOL)\ $($(target)_$(srcname)_TOOL)\ $($(source)_FETCHTOOL)\ $($(srcname)_FETCHTOOL)\ $($(source)_TOOL)\ $($(srcname)_TOOL)\ $($(target)_FETCHTOOL)\ $($(target)_TOOL)\ ) local flags :=\ $(TOOL_$(tool)_FETCHFLAGS)\ $(FETCHFLAGS)\ $($(target)_FETCHFLAGS)\ $($(srcname)_FETCHFLAGS)\ $($(source)_FETCHFLAGS)\ $($(target)_$(srcname)_FETCHFLAGS)\ $($(target)_$(source)_FETCHFLAGS) #$ (warning dbg: target=$(target) source=$(source) $(srcname)=$(srcname) tool=$(tool) out=$(out) flags=$(flags) dirdep=$(dirdep) fetchdir=$(fetchdir) md5=$(md5) size=$(size)) ifndef TOOL_$(tool)_FETCH_CMDS $(warning kBuild: tools: \ 1 $($(target)_$(source)_FETCHTOOL)\ 2 $($(target)_$(srcname)_FETCHTOOL)\ 3 $($(target)_$(source)_TOOL)\ 4 $($(target)_$(srcname)_TOOL)\ 5 $($(source)_FETCHTOOL)\ 6 $($(srcname)_FETCHTOOL)\ 7 $($(source)_TOOL)\ 8 $($(srcname)_TOOL)\ 9 $($(target)_FETCHTOOL)\ 10 $($(target)_TOOL) ) $(error kBuild: TOOL_$(tool)_FETCH_CMDS is not defined. source=$(source) target=$(target) ) endif # call the tool local cmds := $(TOOL_$(tool)_FETCH_CMDS) $(target)_$(srcname)_FETCH_2_OUTPUT := $(TOOL_$(tool)_FETCH_OUTPUT) $(target)_$(srcname)_FETCH_2_OUTPUT_MAYBE := $(TOOL_$(tool)_FETCH_OUTPUT_MAYBE) $(target)_$(srcname)_FETCH_2_DEPEND := $(TOOL_$(tool)_FETCH_DEPEND) $(deps) $(target)_$(srcname)_FETCH_2_DEPORD := $(TOOL_$(tool)_FETCH_DEPORD) $(dirdep) $(orderdeps) # generate the fetch rule. $(eval $(def_fetch_src_fetch_rule)) # # The unpacking / installing. # local out := $(inst)_kBuild_$(target)_$(srcname)_unpacked.lst local dirdep := $(call DIRDEP,$(inst)) local tool := $(firstword \ $($(target)_$(source)_UNPACKTOOL)\ $($(target)_$(srcname)_UNPACKTOOL)\ $($(target)_$(source)_TOOL)\ $($(target)_$(srcname)_TOOL)\ $($(source)_UNPACKTOOL)\ $($(srcname)_UNPACKTOOL)\ $($(source)_TOOL)\ $($(srcname)_TOOL)\ $($(target)_UNPACKTOOL)\ $($(target)_TOOL) \ ) ifeq ($(tool),) local tool := $(toupper $(subst .,,$(suffix $(subst tar.,TAR,$(srcname))))) $(evalval def_tools_include) endif local flags :=\ $(TOOL_$(tool)_UNPACKFLAGS)\ $(UNPACKFLAGS)\ $($(target)_UNPACKFLAGS)\ $($(srcname)_UNPACKFLAGS)\ $($(source)_UNPACKFLAGS)\ $($(target)_$(srcname)_UNPACKFLAGS)\ $($(target)_$(source)_UNPACKFLAGS) #$ (warning dbg: target=$(target) source=$(source) $(srcname)=$(srcname) tool=$(tool) out=$(out) flags=$(flags) dirdep=$(dirdep) inst=$(inst) md5=$(md5) size=$(size)) ifndef TOOL_$(tool)_UNPACK_CMDS $(warning kBuild: tools: \ 1 $($(target)_$(source)_UNPACKTOOL)\ 2 $($(target)_$(srcname)_UNPACKTOOL)\ 3 $($(target)_$(source)_TOOL)\ 4 $($(target)_$(srcname)_TOOL)\ 5 $($(source)_UNPACKTOOL)\ 6 $($(srcname)_UNPACKTOOL)\ 7 $($(source)_TOOL)\ 8 $($(srcname)_TOOL)\ 9 $($(target)_UNPACKTOOL)\ 10 $($(target)_TOOL) \ 11 $(toupper $(subst tar.,TAR,$(ext $(srcname)))) \ ) $(error kBuild: TOOL_$(tool)_UNPACK_CMDS is not defined. source=$(source) target=$(target) ) endif # call the tool local cmds := $(TOOL_$(tool)_UNPACK_CMDS) $(target)_$(srcname)_UNPACK_2_OUTPUT := $(TOOL_$(tool)_UNPACK_OUTPUT) $(target)_$(srcname)_UNPACK_2_OUTPUT_MAYBE := $(TOOL_$(tool)_UNPACK_OUTPUT_MAYBE) $(target)_$(srcname)_UNPACK_2_DEPEND := $(TOOL_$(tool)_UNPACK_DEPEND) $(deps) $(target)_$(srcname)_UNPACK_2_DEPORD := $(TOOL_$(tool)_UNPACK_DEPORD) $(dirdep) $(orderdeps) # generate the fetch rule. $(eval $(def_fetch_src_unpack_rule)) _DIRS += $(inst) $(fetchdir) endef # def_fetch_src $(eval-opt-var def_fetch_src) ## # Define the target level rules for a fetch. # @param target # @param out # @param inst # @param _TARGET_$(target)_UNPACKED # @param _TARGET_$(target)_DIGEST # @param bld_trg # @param bld_trg_arch define def_fetch_rules $(out).lst: $(_TARGET_$(target)_UNPACKED) | $(call DIRDEP,$(inst)) %$$(call MSG_FETCH_OK,$(target)) $$(QUIET)$$(RM) -f -- $$@ $$@.tmp $$(QUIET2)$$(APPEND) $$@.tmp '$(notdir $(out))' $$(QUIET)$(if $(_TARGET_$(target)_UNPACKED),$$(CAT_EXT) $(_TARGET_$(target)_UNPACKED) >> $$@.tmp) $$(QUIET)$$(MV) -f -- $$@.tmp $$@ $(out)_unfetched: %$$(call MSG_UNFETCH,$(target)) $$(QUIET)$$(RM) -f -- $$(addprefix $(inst),$$(shell $$(CAT_EXT) $(out).lst 2> /dev/null | $$(SED) -e '/\/$$$$/d')) $$(QUIET)$$(RMDIR) -p --ignore-fail-on-non-empty --ignore-fail-on-not-exist -- $$(dir $$@) \ $$(addprefix $(inst),$$(sort $$(dir $$(shell $$(CAT_EXT) $(out).lst 2> /dev/null)))) $$(QUIET)$$(RM) -f -- $(out).lst $(out) $$(QUIET)$$(RMDIR) -p --ignore-fail-on-non-empty --ignore-fail-on-not-exist -- $$(dir $$@) $(out): $(comp-vars _TARGET_$(target)_DIGEST_PREV,_TARGET_$(target)_DIGEST,FORCE) | $(call DIRDEP,$(inst)) $$(QUIET)$$(RM) -f -- $$@ %$$(if $$(_TARGET_$(target)_DIGEST),$$(if $$(eq $$(file-size $(out).lst),-1)\ ,$$(call MSG_REFETCH,$(target)),$$(call MSG_FETCH,$(target))),$$(call MSG_UNFETCH,$(target))) $$(QUIET)$(TEST_EXT) -f $(out).lst -- $$(MAKE) -f $(MAKEFILE) --no-print-directory $(out)_unfetched if $(KBUILD_KMK_REVISION) > 2911 $$(QUIET)kmk_builtin_dircache deleted "$(dir $(out))" endif $$(QUIET)$$(if $$(_TARGET_$(target)_DIGEST),$$(MAKE) -f $(MAKEFILE) --no-print-directory $(out).lst,$$(RMDIR) -p --ignore-fail-on-non-empty --ignore-fail-on-not-exist -- $$(dir $$@)) $$(QUIET2)$$(if $$(_TARGET_$(target)_DIGEST),$$(APPEND) $$@ "_TARGET_$(target)_DIGEST_PREV := $(_TARGET_$(target)_DIGEST)") .NOTPARALLEL: $(out).lst $(out)_unfetched $(out) endef ## # Deal with one fetch target. # @param target # @param bld_trg # @param bld_trg_arch define def_fetch # common ## @todo Install-revamp: FIXME INSTARGET_$(target) := $($(target)_INST) ifneq ($(patsubst %/,ok,$(INSTARGET_$(target))),ok) $(error kBuild: Bad or missing INST property for target '$(target)'. \ $(target)_INST='$($(target)_INST)' ($(origin $(target)_INST))) endif _TARGET_$(target)_FETCHED := _TARGET_$(target)_UNPACKED := _TARGET_$(target)_DIGEST := local clean_files := $($(target)_CLEAN) $($(target)_CLEAN.$(bld_trg)) $($(target)_CLEAN.$(bld_trg).$(bld_trg_arch)) $($(target)_CLEAN.$(bld_trg_arch)) $($(target)_CLEAN.$(KBUILD_TYPE)) # The 'sources'. #$ (warning dbg fetch: target=$(target) sources=$($(target)_SOURCES) $($(target)_SOURCES.$(KBUILD_TYPE)) $($(target)_SOURCES.$(KBUILD_TARGET)) $($(target)_SOURCES.$(bld_trg_arch)) $($(target)_SOURCES.$(KBUILD_TARGET).$(bld_trg_arch))) $(foreach source,$($(target)_SOURCES) $($(target)_SOURCES.$(KBUILD_TYPE)) $($(target)_SOURCES.$(bld_trg)) $($(target)_SOURCES.$(bld_trg_arch)) $($(target)_SOURCES.$(bld_trg).$(bld_trg_arch)),\ $(evalval def_fetch_src)) # The target. local inst := $(INSTARGET_$(target)) local out := $(inst)_kBuild_fetch_$(target) $(eval includedep $(out)) $(eval $(def_fetch_rules)) # Define the aliases here (doesn't work if defined in def_fetch_rules, just like includedep). $(target): $(out) $(target)_unfetch: $(out)_unfetched _FETCHES += $(out) _DOWNLOADS += $(_TARGET_$(target)_FETCHED) _UNPACKS += $(_TARGET_$(target)_UNPACKED) _UNFETCHES += $(out)_unfetched _DIRS += $(inst) _CLEAN_FILES += $(clean_files) endef $(eval-opt-var def_fetch) # Walk the FETCH target lists. bld_trg := $(KBUILD_TARGET) bld_trg_arch := $(KBUILD_TARGET_ARCH) $(foreach target, $(_ALL_FETCHES), \ $(evalvalctx def_fetch)) # some aliases. download: $(_DOWNLOADS) unpack: $(_UNPACKS) fetch: $(_FETCHES) unfetch: $(_UNFETCHES) ifdef KBUILD_PROFILE_SELF $(evalcall def_profile_self, done fetching targets) endif kbuild-3149/kBuild/templates/0000755000175000017500000000000013252530250016111 5ustar locutuslocutuskbuild-3149/kBuild/templates/DUMMY.kmk0000644000175000017500000000245113252530250017512 0ustar locutuslocutus# $Id: DUMMY.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Template Config - Empty dummy template. # # # Copyright (c) 2008-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # TEMPLATE_DUMMY = Empty dummy template kbuild-3149/kBuild/COPYING0000644000175000017500000004310313252530251015150 0ustar locutuslocutus GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. 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 convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision 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, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This 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. kbuild-3149/kBuild/rules.kmk0000644000175000017500000000271013252530250015751 0ustar locutuslocutus# $Id: rules.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild - File included at top of makefile. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # ifdef PATH_KBUILD # Usual location. include $(PATH_KBUILD)/header.kmk else # Default location. include $(DEPTH)/kBuild/header.kmk endif # PATH_KBUILD is defined now. include $(PATH_KBUILD)/footer.kmk kbuild-3149/kBuild/header.kmk0000644000175000017500000015412413252530250016056 0ustar locutuslocutus# $Id: header.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild - File included at top of a makefile. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # ifndef __header_kmk__ # start-of-file-content ifdef KBUILD_PROFILE_SELF _KBUILD_TS_HEADER_START := $(nanots ) # just a dummy warm up query $(info prof: since start - since previous -- event description) ifeq ($(KBUILD_PROFILE_SELF),2) $(info stat: $(make-stats )) endif _KBUILD_TS_HEADER_START := $(nanots ) _KBUILD_TS_PREV := $(_KBUILD_TS_HEADER_START) _KBUILD_FMT_ELAPSED_EX = $(int-div $(int-add $(int-sub $1, $2),500000),1000000)ms _KBUILD_FMT_ELAPSED = $(call _KBUILD_FMT_ELAPSED_EX,$(_KBUILD_TS_NOW),$1) define def_profile_self _KBUILD_TS_NOW := $(nanots ) $(info prof: $(call _KBUILD_FMT_ELAPSED,$(_KBUILD_TS_HEADER_START)) - $(call _KBUILD_FMT_ELAPSED, $(_KBUILD_TS_PREV)) -- $(strip $1)) ifeq ($(KBUILD_PROFILE_SELF),2) $(info stat: $(make-stats )) endif _KBUILD_TS_PREV := $(_KBUILD_TS_NOW) endef endif # # Check make version before we do anything else. # ifndef KMK_VERSION $(error kBuild: The kmk default variable KMK_VERSION isn't defined! Make sure you are using 'kmk' and not 'make', 'gmake', 'kmk_gmake', 'dmake' or any other make program) endif ifneq ($(KBUILD_VERSION_MAJOR).$(KBUILD_VERSION_MINOR),0.1) ifneq ($(KBUILD_VERSION_MAJOR),0) $(warning kBuild: kmk major version mismatch! Expected '0' but found '$(KBUILD_VERSION_MAJOR)'!) else $(warning kBuild: kmk minor version mismatch! Expected '1' but found '$(KBUILD_VERSION_MINOR)'!) endif else if $(KBUILD_VERSION_PATCH) < 999 $(error kBuild: kmk version mismatch! Expected 0.1.999 or later. Actual version is $(KBUILD_VERSION).) endif endif # # The revision in which this file was last modified. # This can be useful when using development versions of kBuild. # KMK_REVISION := $(patsubst %:,, $Rev: 3121 $ ) # # Define the default goal. # .PHONY: all all_recursive all: all_recursive # # The phony FORCE target. # .PHONY: FORCE FORCE: # # Enable delete on error and second expansion of prerequisites and targets. # .DELETE_ON_ERROR: .SECONDEXPANSION: .SECONDTARGETEXPANSION: # # General purpose macros. # ## # Newline character(s). define NL endef ## # Tab character. TAB := $(subst ., ,.) ## # Newline + tab characters (for generating commands). NLTAB = $(NL)$(TAB) ## # Space character. SP := $(subst ., ,.) ## # Hash character. define HASH # endef ## # Colon character. COLON := : ## # Semicolon character. SEMICOLON := ; ## # Comma character. COMMA := , ## # Dot character. DOT := . ## # Dollar character. DOLLAR := $$ ## # Equal character. EQUAL := = ## # Percent character. PERCENT := % ## # Single quote character. SQUOTE := ' ## # Double quote character. DQUOTE := " ## # Opening parenthesis. OPENPAR := ( ## # Closing parenthesis. CLOSEPAR := ) # # The list of standard build types in kBuild. # # This list can be extended in Config.kmk and it's possible to extend # (inherit) another build type. # KBUILD_BLD_TYPES := release profile debug # # The OSes, Architectures and CPUs that kBuild recognizes. # # When kBuild is ported to a new OS or architecture a unique keyword needs # to be assigned to it and added here. This strictness is required because # this keyword namespace is shared between OSes, architectures, cpus and # build types. (PORTME) # KBUILD_OSES := darwin dos dragonfly freebsd gnuhurd gnukfbsd gnuknbsd haiku l4 linux netbsd nt openbsd os2 solaris win os-agnostic KBUILD_ARCHES := x86 amd64 noarch alpha arm32 arm64 hppa32 hppa64 ia64 m68k mips32 mips64 ppc32 ppc64 s390 s390x sh32 sh64 sparc32 sparc64 x32 KBUILD_ARCHES_64 := amd64 alpha arm64 hppa64 ia64 mips64 ppc64 s390x sh64 sparc64 x32 KBUILD_ARCHES_32 := x86 arm32 hppa32 m68k mips32 ppc32 s390 sh32 sparc32 # # Mapping of kBuild OS + ARCH to GNU system type wildcards. # For use with the foreach/append/prepend and wildcard functions. # KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.darwin.x86 = i?86-apple-darwin* KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.darwin.amd64 = x86_64-apple-darwin* amd64-apple-darwin* KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.freebsd.x86 = i?86-*freebsd* KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.freebsd.amd64 = x86_64-*freebsd* amd64-*freebsd* KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.linux.x86 = i?86-*linux-gnu KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.linux.amd64 = x86_64-*linux-gnu amd64-*linux-gnu KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.netbsd.x86 = i?86-*netbsd* KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.netbsd.amd64 = x86_64-*netbsd* amd64-*netbsd* KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.os2.x86 = i?86-*os2* KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.solaris.x86 = i?86-*solaris2* KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.solaris.amd64 = amd64-*solaris2* x86_64-*solaris2* KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.solaris.sparc32 = sparc-*solaris2* KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.solaris.sparc64 = sparc64-*solaris2* sparcv9-*solaris2* KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.win.x86 = i?86-*mingw32* i?86-*msys* i?86-*cygwin* KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.win.amd64 = x86_64-*mingw64* amd64-*mingw64* x86_64-*msys* amd64-*msys* x86_64-*cygwin* amd64-*cygwin* # # Set default build type. # ifndef KBUILD_TYPE ifdef BUILD_TYPE KBUILD_TYPE := $(BUILD_TYPE) endif else ifdef BUILD_TYPE ifneq ($(KBUILD_TYPE),$(BUILD_TYPE)) ifeq ($(origin KBUILD_TYPE):$(origin BUILD_TYPE),environment:command line) KBUILD_TYPE := $(BUILD_TYPE) else ifneq ($(origin KBUILD_TYPE):$(origin BUILD_TYPE),command line:environment) $(error kBuild: KBUILD_TYPE and BUILD_TYPE disagree.) endif endif endif override BUILD_TYPE = $(KBUILD_TYPE) ifndef KBUILD_TYPE KBUILD_TYPE := release else if1of ($(KBUILD_TYPE), $(KBUILD_OSES) $(KBUILD_ARCHES)) $(error kBuild: The KBUILD_TYPE value '$(KBUILD_TYPE)' is an OS or architecture!) endif ifneq (.$(words $(KBUILD_TYPE)).$(KBUILD_TYPE).,.1.$(strip $(KBUILD_TYPE)).) $(error kBuild: The KBUILD_TYPE value '$(KBUILD_TYPE)' contains spaces/tabs!) endif endif # # Host platform legacy # kmk deals with this, so this is only temporary until I've rebuilt everything. # ifndef KBUILD_HOST KBUILD_HOST := $(BUILD_PLATFORM) endif ifndef KBUILD_HOST_ARCH KBUILD_HOST_ARCH := $(BUILD_PLATFORM_ARCH) endif ifndef KBUILD_HOST_CPU KBUILD_HOST_CPU := $(BUILD_PLATFORM_CPU) endif # # Assert valid build platform variables. # # All these are set by kmk so they shouldn't be any trouble # unless the user starts messing about with environment variables. # ifneq (.$(words $(KBUILD_HOST)).$(KBUILD_HOST).,.1.$(strip $(KBUILD_HOST)).) $(error kBuild: The KBUILD_HOST value '$(KBUILD_HOST)' contains spaces/tabs!) endif ifneq ($(words $(filter $(KBUILD_HOST),$(KBUILD_OSES))),1) $(error kBuild: KBUILD_HOST value '$(KBUILD_HOST)' is not recognized (valid: $(KBUILD_OSES))) endif ifneq (.$(words $(KBUILD_HOST_ARCH)).$(KBUILD_HOST_ARCH).,.1.$(strip $(KBUILD_HOST_ARCH)).) $(error kBuild: The KBUILD_HOST_ARCH value '$(KBUILD_HOST_ARCH)' contains spaces/tabs!) endif ifneq ($(words $(filter $(KBUILD_HOST_ARCH),$(KBUILD_ARCHES))),1) $(error kBuild: KBUILD_HOST_ARCH value '$(KBUILD_HOST_ARCH)' is not recognized (valid: $(KBUILD_ARCHES))) endif ifeq ($(strip $(KBUILD_HOST_CPU)),) KBUILD_HOST_CPU := blend else ifneq (.$(words $(KBUILD_HOST_CPU)).$(KBUILD_HOST_CPU).,.1.$(strip $(KBUILD_HOST_CPU)).) $(error kBuild: The KBUILD_HOST_CPU value '$(KBUILD_HOST_CPU)' contains spaces/tabs!) endif if1of ($(KBUILD_HOST_CPU), $(KBUILD_OSES) $(KBUILD_ARCHES)) $(error kBuild: The KBUILD_HOST_CPU value '$(KBUILD_HOST_CPU)' was found in the OS or architecture keywords!) endif ifeq ($(KBUILD_HOST_CPU),$(KBUILD_TYPE)) $(error kBuild: The KBUILD_HOST_CPU value '$(KBUILD_HOST_CPU)' is the same as the KBUILD_TYPE!) endif endif # # Deal with target platform legacy. # ifndef KBUILD_TARGET ifdef BUILD_TARGET KBUILD_TARGET := $(BUILD_TARGET) endif else ifdef BUILD_TARGET ifneq ($(KBUILD_TARGET),$(BUILD_TARGET)) ifeq ($(origin KBUILD_TARGET):$(origin BUILD_TARGET),environment:command line) KBUILD_TARGET := $(BUILD_TARGET) else ifneq ($(origin KBUILD_TARGET):$(origin BUILD_TARGET),command line:environment) $(error kBuild: KBUILD_TARGET and BUILD_TARGET disagree) endif endif endif override BUILD_TARGET = $(KBUILD_TARGET) ifndef KBUILD_TARGET_ARCH ifdef BUILD_TARGET_ARCH KBUILD_TARGET_ARCH := $(BUILD_TARGET_ARCH) endif else ifdef BUILD_TARGET_ARCH ifneq ($(KBUILD_TARGET_ARCH),$(BUILD_TARGET_ARCH)) ifeq ($(origin KBUILD_TARGET_ARCH):$(origin BUILD_TARGET_ARCH),environment:command line) KBUILD_TARGET_ARCH := $(BUILD_TARGET_ARCH) else ifneq ($(origin KBUILD_TARGET_ARCH):$(origin BUILD_TARGET_ARCH),command line:environment) $(error kBuild: KBUILD_TARGET_ARCH and BUILD_TARGET_ARCH disagree) endif endif endif override BUILD_TARGET_ARCH = $(KBUILD_TARGET_ARCH) ifndef KBUILD_TARGET_CPU ifdef BUILD_TARGET_CPU KBUILD_TARGET_CPU := $(BUILD_TARGET_CPU) endif else ifdef BUILD_TARGET_CPU ifneq ($(KBUILD_TARGET_CPU),$(BUILD_TARGET_CPU)) ifeq ($(origin KBUILD_TARGET_CPU):$(origin BUILD_TARGET_CPU),environment:command line) KBUILD_TARGET_CPU := $(BUILD_TARGET_CPU) else ifneq ($(origin KBUILD_TARGET_CPU):$(origin BUILD_TARGET_CPU),command line:environment) $(error kBuild: KBUILD_TARGET_CPU and BUILD_TARGET_CPU disagree) endif endif endif override BUILD_TARGET_CPU = $(KBUILD_TARGET_CPU) # # Assert or set default target platform. # When not defined use the corresponding KBUILD_HOST value. # ifndef KBUILD_TARGET KBUILD_TARGET := $(KBUILD_HOST) else ifneq (.$(words $(KBUILD_TARGET)).$(KBUILD_TARGET).,.1.$(strip $(KBUILD_TARGET)).) $(error kBuild: The KBUILD_TARGET value '$(KBUILD_TARGET)' contains spaces/tabs!) endif ifneq ($(words $(filter $(KBUILD_TARGET),$(KBUILD_OSES))),1) $(error kBuild: KBUILD_TARGET value '$(KBUILD_TARGET)' is not recognized (valid: $(KBUILD_OSES))) endif endif ifndef KBUILD_TARGET_ARCH KBUILD_TARGET_ARCH := $(KBUILD_HOST_ARCH) else ifneq (.$(words $(KBUILD_TARGET_ARCH)).$(KBUILD_TARGET_ARCH).,.1.$(strip $(KBUILD_TARGET_ARCH)).) $(error kBuild: The KBUILD_TARGET_ARCH value '$(KBUILD_TARGET_ARCH)' contains spaces/tabs!) endif ifneq ($(words $(filter $(KBUILD_TARGET_ARCH),$(KBUILD_ARCHES))),1) $(error kBuild: KBUILD_TARGET_ARCH value '$(KBUILD_TARGET_ARCH)' is not recognized (valid: $(KBUILD_ARCHES))) endif endif ifndef KBUILD_TARGET_CPU KBUILD_TARGET_CPU := $(KBUILD_HOST_CPU) else ifeq ($(strip $(KBUILD_TARGET_CPU)),) ifeq ($(KBUILD_TARGET_ARCH),$(KBUILD_HOST_ARCH)) KBUILD_TARGET_CPU := $(KBUILD_HOST_CPU) else KBUILD_TARGET_CPU := blend endif else ifneq (.$(words $(KBUILD_TARGET_CPU)).$(KBUILD_TARGET_CPU).,.1.$(strip $(KBUILD_TARGET_CPU)).) $(error kBuild: The KBUILD_TARGET_CPU value '$(KBUILD_TARGET_CPU)' contains spaces/tabs!) endif if1of ($(KBUILD_TARGET_CPU), $(KBUILD_OSES) $(KBUILD_ARCHES)) $(error kBuild: The KBUILD_TARGET_CPU value was found in the OS or architecture keywords!) endif ifeq ($(KBUILD_TARGET_CPU),$(KBUILD_TYPE)) $(error kBuild: The KBUILD_TARGET_CPU value '$(KBUILD_TARGET_CPU)' is the same as the KBUILD_TYPE!) endif endif # Short hand for $(KBUILD_TARGET).$(KBUILD_TARGET_ARCH). KBUILD_TARGET_DOT_ARCH = $(KBUILD_TARGET).$(KBUILD_TARGET_ARCH) KBUILD_HOST_DOT_ARCH = $(KBUILD_HOST).$(KBUILD_TARGET_ARCH) # # Paths and stuff. # # Adjust DEPTH first. DEPTH := $(strip $(DEPTH)) ifeq ($(DEPTH),) DEPTH := . endif ## PATH_CURRENT is the current directory (getcwd). PATH_CURRENT := $(abspath $(CURDIR)) ## PATH_SUB_CURRENT points to current directory of the current makefile. # Meaning that it will change value as we enter and exit sub-makefiles. PATH_SUB_CURRENT := $(PATH_CURRENT) ## PATH_ROOT points to the project root directory. PATH_ROOT := $(abspath $(PATH_CURRENT)/$(DEPTH)) ## PATH_SUB_ROOT points to the directory of the top-level makefile. ifneq ($(strip $(SUB_DEPTH)),) SUB_DEPTH := $(strip $(SUB_DEPTH)) PATH_SUB_ROOT := $(abspath $(PATH_CURRENT)/$(SUB_DEPTH)) else PATH_SUB_ROOT := $(PATH_CURRENT) endif ## CURSUBDIR is PATH_SUB_ROOT described relative to PATH_ROOT. # This variable is used to determin where the object files and other output goes. ifneq ($(PATH_ROOT),$(PATH_SUB_ROOT)) CURSUBDIR := $(patsubst $(PATH_ROOT)/%,%,$(PATH_SUB_ROOT)) else CURSUBDIR := . endif # Install directory layout. Relative to PATH_INS. KBUILD_INST_PATHS := BIN DLL SYS LIB DOC DEBUG SBIN LIBEXEC SHARE INST_BIN = bin/ if1of ($(KBUILD_TARGET), win) INST_DLL = bin/ else INST_DLL = lib/ endif if1of ($(KBUILD_TARGET), os2 win) INST_SYS = drivers/ else INST_SYS = kernel/ endif INST_LIB = lib/ INST_DOC = share/doc/ INST_DEBUG = debug/ INST_SBIN = sbin/ INST_LIBEXEC = libexec/ INST_SHARE = share/ # Staging directory layout. Relative to PATH_STAGE. STAGE_BIN = $(INST_BIN) STAGE_DLL = $(INST_DLL) STAGE_SYS = $(INST_SYS) STAGE_LIB = $(INST_LIB) STAGE_DOC = $(INST_DOC) STAGE_DEBUG = $(INST_DEBUG) STAGE_SBIN = $(INST_SBIN) STAGE_LIBEXEC = $(INST_LIBEXEC) STAGE_SHARE = $(INST_SHARE) # Install and staging directory paths. $(foreach path, $(KBUILD_INST_PATHS), \ $(eval PATH_STAGE_$(path) = $$(patsubst %/,%,$$(PATH_STAGE)/$$(STAGE_$(path)))) \ $(eval PATH_INST_$(path) = $$(patsubst %/,%,$$(PATH_INS)/$$(INST_$(path)))) \ ) # Output directories. ifndef PATH_OUT_BASE PATH_OUT_BASE := $(PATH_ROOT)/out endif ifndef PATH_OUT ifdef BUILD_TARGET_SUB # (BUILD_TARGET_SUB is not currently recognized by kBuild in any other places - obsolete) PATH_OUT = $(PATH_OUT_BASE)/$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH).$(BUILD_TARGET_SUB)/$(KBUILD_TYPE) else PATH_OUT = $(PATH_OUT_BASE)/$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)/$(KBUILD_TYPE) endif endif # !define PATH_OUT PATH_OBJCACHE = $(PATH_OUT_BASE)/kObjCache PATH_OBJ = $(PATH_OUT)/obj PATH_TARGET = $(PATH_OBJ)/$(CURSUBDIR) PATH_STAGE = $(PATH_OUT)/stage ifndef PATH_INS ifdef DESTROOT PATH_INS = $(DESTROOT) else PATH_INS = $(PATH_OUT)/dist endif endif # Tripwire obsolete PATH defines. PATH_BIN = $(error kBuild: PATH_BIN is obsoleted in kBuild 0.1.2. Use PATH_STAGE_BIN or PATH_INST_BIN instead) PATH_DLL = $(error kBuild: PATH_LIB is obsoleted in kBuild 0.1.2. Use PATH_STAGE_DLL or PATH_INST_DLL instead) PATH_LIB = $(error kBuild: PATH_LIB is obsoleted in kBuild 0.1.2. Use PATH_STAGE_LIB or PATH_INST_LIB instead) PATH_SYS = $(error kBuild: PATH_SYS is obsoleted in kBuild 0.1.2. Use PATH_STAGE_SYS or PATH_INST_SYS instead) PATH_DOC = $(error kBuild: PATH_DOC is obsoleted in kBuild 0.1.2. Use PATH_STAGE_DOC or PATH_INST_DOC instead) # Development tool tree. ifndef KBUILD_DEVTOOLS ifeq ($(PATH_DEVTOOLS),) KBUILD_DEVTOOLS = $(PATH_ROOT)/tools else KBUILD_DEVTOOLS := $(PATH_DEVTOOLS) endif endif KBUILD_DEVTOOLS_TRG ?= $(KBUILD_DEVTOOLS)/$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH) KBUILD_DEVTOOLS_HST ?= $(KBUILD_DEVTOOLS)/$(KBUILD_HOST).$(KBUILD_HOST_ARCH) if1of ($(KBUILD_TARGET_ARCH), amd64 hppa64 mips64 ppc64 s390x sparc64) ifeq ($(KBUILD_TARGET_ARCH),amd64) KBUILD_DEVTOOLS_TRG_ALT ?= $(KBUILD_DEVTOOLS)/$(KBUILD_TARGET).x86 else ifeq ($(KBUILD_TARGET_ARCH),hppa64) KBUILD_DEVTOOLS_TRG_ALT ?= $(KBUILD_DEVTOOLS)/$(KBUILD_TARGET).hppa32 else ifeq ($(KBUILD_TARGET_ARCH),mips64) KBUILD_DEVTOOLS_TRG_ALT ?= $(KBUILD_DEVTOOLS)/$(KBUILD_TARGET).mips32 else ifeq ($(KBUILD_TARGET_ARCH),ppc64) KBUILD_DEVTOOLS_TRG_ALT ?= $(KBUILD_DEVTOOLS)/$(KBUILD_TARGET).ppc32 else ifeq ($(KBUILD_TARGET_ARCH),s390x) KBUILD_DEVTOOLS_TRG_ALT ?= $(KBUILD_DEVTOOLS)/$(KBUILD_TARGET).s390 else ifeq ($(KBUILD_TARGET_ARCH),sparc64) KBUILD_DEVTOOLS_TRG_ALT ?= $(KBUILD_DEVTOOLS)/$(KBUILD_TARGET).sparc32 endif endif if1of ($(KBUILD_HOST_ARCH), amd64 hppa64 mips64 ppc64 s390x sparc64) ifeq ($(KBUILD_HOST_ARCH),amd64) KBUILD_DEVTOOLS_HST_ALT ?= $(KBUILD_DEVTOOLS)/$(KBUILD_HOST).x86 else ifeq ($(KBUILD_HOST_ARCH),hppa64) KBUILD_DEVTOOLS_HST_ALT ?= $(KBUILD_DEVTOOLS)/$(KBUILD_HOST).hppa32 else ifeq ($(KBUILD_HOST_ARCH),mips64) KBUILD_DEVTOOLS_HST_ALT ?= $(KBUILD_DEVTOOLS)/$(KBUILD_HOST).mips32 else ifeq ($(KBUILD_HOST_ARCH),ppc64) KBUILD_DEVTOOLS_HST_ALT ?= $(KBUILD_DEVTOOLS)/$(KBUILD_HOST).ppc32 else ifeq ($(KBUILD_HOST_ARCH),s390x) KBUILD_DEVTOOLS_HST_ALT ?= $(KBUILD_DEVTOOLS)/$(KBUILD_HOST).s390 else ifeq ($(KBUILD_HOST_ARCH),sparc64) KBUILD_DEVTOOLS_HST_ALT ?= $(KBUILD_DEVTOOLS)/$(KBUILD_HOST).sparc32 endif endif # Deprecated legacy names. PATH_DEVTOOLS ?= $(KBUILD_DEVTOOLS) PATH_DEVTOOLS_TRG ?= $(KBUILD_DEVTOOLS_TRG) PATH_DEVTOOLS_BLD ?= $(KBUILD_DEVTOOLS_TRG) PATH_DEVTOOLS_TRG_ALT ?= $(KBUILD_DEVTOOLS_TRG_ALT) PATH_DEVTOOLS_HST ?= $(KBUILD_DEVTOOLS_HST) PATH_DEVTOOLS_HST_ALT ?= $(KBUILD_DEVTOOLS_HST_ALT) # KBUILD_PATH / PATH_KBUILD is determined by kmk. ifndef KBUILD_PATH KBUILD_PATH := $(PATH_KBUILD) endif ifeq ($(strip $(KBUILD_PATH)),) $(error kBuild: KBUILD_PATH is missing or empty! kmk is supposed to set it.) endif # KBUILD_BIN_PATH / PATH_KBUILD_BIN is determined by kmk. ifndef KBUILD_BIN_PATH KBUILD_BIN_PATH := $(PATH_KBUILD_BIN) endif ifeq ($(strip $(KBUILD_BIN_PATH)),) $(error kBuild: KBUILD_BIN_PATH is missing or empty! kmk is supposed to set it.) endif # kBuild files which might be of interest. FILE_KBUILD_HEADER := $(KBUILD_PATH)/header.kmk #FILE_KBUILD_CONFIG := $(KBUILD_PATH)/config.kmk FILE_KBUILD_FOOTER := $(KBUILD_PATH)/footer.kmk FILE_KBUILD_SUB_HEADER := $(KBUILD_PATH)/subheader.kmk FILE_KBUILD_SUB_FOOTER := $(KBUILD_PATH)/subfooter.kmk ## MAKEFILE is the name of the main makefile. MAKEFILE := $(firstword $(MAKEFILE_LIST)) ## MAKEFILE_CURRENT is the name of the current makefile. # This is updated everything a sub-makefile is included. MAKEFILE_CURRENT := $(MAKEFILE) ## @todo this should be done via SUFF_XYZ.target/host... # # Build platform setup. # (PORTME) # if1of ($(KBUILD_HOST), win nt) # Win, Win32, Win64, NT. EXEC_X86_WIN32 := HOSTSUFF_EXE := .exe HOST_PATH_SEP := $(SEMICOLON) # OS/2. else ifeq ($(KBUILD_HOST),os2) EXEC_X86_WIN32 := innopec.exe HOSTSUFF_EXE := .exe HOST_PATH_SEP := $(SEMICOLON) else if1of ($(KBUILD_HOST), dragonfly freebsd gnukfbsd gnuknbsd linux openbsd netbsd) # Unix (like) systems with wine. EXEC_X86_WIN32 := wine HOSTSUFF_EXE := HOST_PATH_SEP := $(COLON) else # Unix (like) systems without wine. EXEC_X86_WIN32 := false HOSTSUFF_EXE := HOST_PATH_SEP := $(COLON) endif # # Build target setup. # (PORTME) # SUFF_DEP := .dep SUFF_BIN := if1of ($(KBUILD_TARGET), win nt os2) SUFF_OBJ := .obj SUFF_LIB := .lib SUFF_DLL := .dll SUFF_EXE := .exe SUFF_SYS := .sys SUFF_RES := .res else ifeq ($(KBUILD_TARGET),l4) SUFF_OBJ := .o SUFF_LIB := .a SUFF_DLL := .s.so SUFF_EXE := SUFF_SYS := .a SUFF_RES := else ifeq ($(KBUILD_TARGET),darwin) SUFF_OBJ := .o SUFF_LIB := .a SUFF_DLL := .dylib SUFF_EXE := SUFF_SYS := SUFF_RES := else SUFF_OBJ := .o SUFF_LIB := .a SUFF_DLL := .so SUFF_EXE := if1of ($(KBUILD_TARGET), dragonfly freebsd gnukfbsd gnuknbsd linux netbsd openbsd) ## @todo check netbsd, gnuknbsd and openbsd. SUFF_SYS := .ko else SUFF_SYS := endif SUFF_RES := endif # # Standard kBuild tools. # ifeq ($(KMK),kmk) KMK := $(KBUILD_BIN_PATH)/kmk$(HOSTSUFF_EXE) endif MAKE := $(KMK) GMAKE := $(KBUILD_BIN_PATH)/kmk_gmake$(HOSTSUFF_EXE) #DEP_EXT := $(KBUILD_BIN_PATH)/kDep$(HOSTSUFF_EXE) #DEP_INT := $(KBUILD_BIN_PATH)/kDep$(HOSTSUFF_EXE) #DEP := $(DEP_INT) DEP_IDB_EXT := $(KBUILD_BIN_PATH)/kDepIDB$(HOSTSUFF_EXE) DEP_IDB_INT := kmk_builtin_kDepIDB DEP_IDB := $(DEP_IDB_INT) DEP_OBJ_EXT := $(KBUILD_BIN_PATH)/kDepObj$(HOSTSUFF_EXE) DEP_OBJ_INT := kmk_builtin_kDepObj DEP_OBJ := $(DEP_OBJ_INT) DEP_PRE := $(KBUILD_BIN_PATH)/kDepPre$(HOSTSUFF_EXE) KOBJCACHE_EXT := $(KBUILD_BIN_PATH)/kObjCache$(HOSTSUFF_EXE) KOBJCACHE := $(KOBJCACHE_EXT) KLIBTWEAKER_EXT := $(KBUILD_BIN_PATH)/kLibTweaker$(HOSTSUFF_EXE) KLIBTWEAKER := $(KLIBTWEAKER_EXT) APPEND_EXT := $(KBUILD_BIN_PATH)/kmk_append$(HOSTSUFF_EXE) APPEND_INT := kmk_builtin_append APPEND := $(APPEND_INT) CAT_EXT := $(KBUILD_BIN_PATH)/kmk_cat$(HOSTSUFF_EXE) CAT_INT := kmk_builtin_cat CAT := $(CAT_INT) CHMOD_EXT := $(KBUILD_BIN_PATH)/kmk_chmod$(HOSTSUFF_EXE) CHMOD_INT := kmk_builtin_chmod CHMOD := $(CHMOD_INT) CMP_EXT := $(KBUILD_BIN_PATH)/kmk_cmp$(HOSTSUFF_EXE) CMP_INT := kmk_builtin_cmp CMP := $(CMP_INT) CP_EXT := $(KBUILD_BIN_PATH)/kmk_cp$(HOSTSUFF_EXE) CP_INT := kmk_builtin_cp CP := $(CP_INT) ECHO_EXT := $(KBUILD_BIN_PATH)/kmk_echo$(HOSTSUFF_EXE) ECHO_INT := kmk_builtin_echo ECHO := $(ECHO_INT) EXPR_EXT := $(KBUILD_BIN_PATH)/kmk_expr$(HOSTSUFF_EXE) EXPR_INT := kmk_builtin_expr EXPR := $(EXPR_INT) INSTALL_EXT := $(KBUILD_BIN_PATH)/kmk_install$(HOSTSUFF_EXE) INSTALL_INT := kmk_builtin_install INSTALL := $(INSTALL_INT) LN_EXT := $(KBUILD_BIN_PATH)/kmk_ln$(HOSTSUFF_EXE) LN_INT := kmk_builtin_ln LN := $(LN_INT) MD5SUM_EXT := $(KBUILD_BIN_PATH)/kmk_md5sum$(HOSTSUFF_EXE) MD5SUM_INT := kmk_builtin_md5sum MD5SUM := $(MD5SUM_INT) MKDIR_EXT := $(KBUILD_BIN_PATH)/kmk_mkdir$(HOSTSUFF_EXE) MKDIR_INT := kmk_builtin_mkdir MKDIR := $(MKDIR_INT) MV_EXT := $(KBUILD_BIN_PATH)/kmk_mv$(HOSTSUFF_EXE) MV_INT := kmk_builtin_mv MV := $(MV_INT) PRINTF_EXT := $(KBUILD_BIN_PATH)/kmk_printf$(HOSTSUFF_EXE) PRINTF_INT := kmk_builtin_printf PRINTF := $(PRINTF_INT) REDIRECT_EXT:= $(KBUILD_BIN_PATH)/kmk_redirect$(HOSTSUFF_EXE) if $(KBUILD_KMK_REVISION) > 2911 REDIRECT_INT:= kmk_builtin_redirect else REDIRECT_INT:= $(REDIRECT_EXT) endif REDIRECT := $(REDIRECT_INT) RM_EXT := $(KBUILD_BIN_PATH)/kmk_rm$(HOSTSUFF_EXE) RM_INT := kmk_builtin_rm RM := $(RM_INT) RMDIR_EXT := $(KBUILD_BIN_PATH)/kmk_rmdir$(HOSTSUFF_EXE) RMDIR_INT := kmk_builtin_rmdir RMDIR := $(RMDIR_INT) SED_EXT := $(KBUILD_BIN_PATH)/kmk_sed$(HOSTSUFF_EXE) SED_INT := $(SED_EXT) SED := $(SED_EXT) SLEEP_INT := kmk_builtin_sleep SLEEP_EXT := $(KBUILD_BIN_PATH)/kmk_sleep$(HOSTSUFF_EXE) SLEEP := $(SLEEP_EXT) TEST_EXT := $(KBUILD_BIN_PATH)/kmk_test$(HOSTSUFF_EXE) TEST_INT := kmk_builtin_test TEST := $(TEST_INT) TIME_EXT := $(KBUILD_BIN_PATH)/kmk_time$(HOSTSUFF_EXE) TIME_INT := $(TIME_EXT) TIME := $(TIME_INT) TOUCH_EXT := $(KBUILD_BIN_PATH)/kmk_touch$(HOSTSUFF_EXE) if $(KBUILD_KMK_REVISION) >= 3060 TOUCH_INT := kmk_builtin_touch else TOUCH_INT := $(TOUCH_EXT) endif TOUCH := $(TOUCH_INT) # Our default shell is the Almquist shell from *BSD. ASH := $(KBUILD_BIN_PATH)/kmk_ash$(HOSTSUFF_EXE) MAKESHELL := $(ASH) SHELL := $(ASH) export SHELL MAKESHELL # Symlinking is problematic on some platforms... LN_SYMLINK := $(LN) -s # When copying to the staging area, use hard links to save time and space. ifndef KBUILD_NO_HARD_LINKING INSTALL_STAGING := $(INSTALL) --hard-link-files-when-possible else INSTALL_STAGING := $(INSTALL) endif # # Some Functions. # The lower cased ones are either fallbacks or candidates for functions.c. # ## ABSPATH - make paths absolute. # This implementation is clumsy and doesn't resolve '..' and '.' components. # # @param $1 The paths to make absolute. # @obsolete Use the GNU make function $(abspath) directly now. ABSPATH = $(abspath $(1))$(warning ABSPATH is deprecated, use abspath directly!) ## DIRDEP - make create directory dependencies. # # @param $1 The paths to the directories which must be created. DIRDEP = $(foreach path,$(patsubst %/,%,$(1)),$(path)/) ## Cygwin kludge. # This converts /cygdrive/x/% to x:%. # # @param $1 The paths to make native. # @remark This macro is pretty much obsolete since we don't use cygwin base make. ifneq ($(patsubst /cygdrive/%,%,$(CURDIR)),$(CURDIR)) CYGPATHMIXED = $(foreach path,$(1)\ ,$(if $(patsubst /cygdrive/%,,$(path)),$(path),$(patsubst $(strip $(firstword $(subst /, ,$(patsubst /cygdrive/%,%,$(path)))))/%,$(strip $(firstword $(subst /, ,$(patsubst /cygdrive/%,%,$(path))))):/%,$(patsubst /cygdrive/%,%,$(path))))) else CYGPATHMIXED = $(1) endif ## Removes the drive letter from a path (if it has one) # @param $1 the path no-drive = $(word $(words $(subst :, ,$(1))),$(subst :, ,$(1))) ## Removes the root slash from a path (if it has one) # @param $1 the path no-root-slash = $(patsubst /%,%,$(1)) ## # Similar to firstword, except it returns the value of first defined variable. # @param $1 list of variables to probe. define FIRST-DEFINED-VAR local .RETURN := $(strip $(firstdefined $1, value)) endef ## Figure out where to put object files. # @param $1 real target name. # @param $2 normalized main target TARGET_BASE = $(PATH_TARGET)/$(2)/$(call no-root-slash,$(call no-drive,$(1))) ## Figure out where to put object files. # @param $1 normalized main target TARGET_PATH = $(PATH_TARGET)/$(1) ## # Checks if the specified short option ($1) is found in the flags ($2), # assuming getopt style options. # # @returns $3 if present, $4 not. # # @param $1 The option (single char!). # @param $2 The option arguments. # @param $3 Eval and return if present. # @param $4 Eval and return if not present. # # @todo May confuse option values starting with '-' for options. # @remarks Invoke like this: $(evalcall KB_FN_OPT_TEST_SHORT,d,$(flags),present,not-present) # define KB_FN_OPT_TEST_SHORT local options := $(translate $(strip $(filter -%,$(filter-out --%,$2))),$(SP)-,) local .RETURN := $(if-expr $(pos $1,$(options)) != 0,$3,$4) endef ## # Checks if the specified long option ($1) is found in the flags ($2), # assuming getopt style options. # # @returns $3 if present, $4 not. # # @param $1 The long option, dashes included. No % chars. # @param $2 The option arguments. # @param $3 Eval and return if present. # @param $4 Eval and return if not present. # # @todo May confuse option values starting with '--' for options. # @remarks Invoke like this: $(evalcall KBFN_OPT_TEST_SHORT,--defined,$(flags),present,not-present) # define KB_FN_OPT_TEST_LONG local options := $(filter-out =delete=%,$(subst :, =delete=,$(subst =, =delete=,$2))) local .RETURN := $(if-expr "$(filter $1,$(options))" != "",$3,$4) endef ## # Checks if the specified short ($1) or long ($2) option is found in the flags ($2), # assuming getopt style options. # # @returns $4 if present, $5 not. # # @param $1 The short option (single char!). # @param $2 The long option, dashes included. No % chars. # @param $3 The option arguments. # @param $4 Eval and return if present. # @param $5 Eval and return if not present. # # @todo May confuse option values starting with '--' for options. # @remarks Invoke like this: $(evalcall KB_FN_OPT_TEST_SHORT_LONG,d,--defined,$(flags),present,not-present) # define KB_FN_OPT_TEST_SHORT_LONG local short_options := $(translate $(strip $(filter -%,$(filter-out --%,$3))),$(SP)-,) local long_options := $(filter-out =delete=%,$(subst :, =delete=,$(subst =, =delete=,$3))) local .RETURN := $(if-expr $(pos $1,$(short_options)) != 0 || "$(filter $2,$(long_options))" != "",$4,$5) endef ## # Make an assignment to a deprecated variable. # # @param $1 The variable name. # @param $2 The value. # @param $3 The variable to use instead. # ifdef KBUILD_WITH_DEPREATED_AS_ERROR KB_FN_ASSIGN_DEPRECATED = $(eval $(subst :,$$(COLON),$1) = $2$$(error $1 is deprecated, use $3 instead)) else KB_FN_ASSIGN_DEPRECATED = $(eval $(subst :,$$(COLON),$1) = $2$$(warning $1 is deprecated, use $3 instead)) endif ## # Show an assertion message. # # @param $1 The assertion name. # @param $2 The details. # define KB_FN_ASSERT_MSG $(info !! kBuild $1 Assertion Failed !!) ifdef target $(info !! target: $(target)) local varloc := $(where $(target)) if "$(varloc)" == "undefined" local varloc := $(where $(target)_TEMPLATE) endif if "$(varloc)" == "undefined" local varloc := $(where $(target)_SOURCES) endif if "$(varloc)" == "undefined" local varloc := $(where $(target)_EXTENDS) endif if "$(varloc)" == "undefined" local varloc := $(where target) endif ifneq ($(varloc),) $(info !! location: $(varloc)) else $(info !! probable location: $($(target)_DEFPATH)/Makefile.kmk) endif endif $(info !! $2) $(error fixme) endef ## # Throw an error if the given path $1 isn't absolute and assertions are enabled. # # @param $1 The name of the path variable to check. # ifdef KBUILD_INTERNAL_STRICT KB_FN_ASSERT_ABSPATH = $(if-expr "$(abspath $($(strip $1)))" != "$(strip $($(strip $1)))",\ $(evalcall KB_FN_ASSERT_MSG,abspath,$1 is:$(NLTAB)'$($(strip $1))'$(NLTAB)expected:$(NLTAB)'$(abspath $($(strip $1)))')) else KB_FN_ASSERT_ABSPATH := endif # # Somewhat simple solution for automatic command dependencies. # ## # Advanced version of KB_FN_AUTO_CMD_DEPS_COMMANDS_EX where you set # the dependency file name yourself. # # After or before the recipe do $(call KB_FN_AUTO_CMD_DEPS_EX,,). # # @param 1 dep file. define KB_FN_AUTO_CMD_DEPS_COMMANDS_EX %$(QUIET2)$(RM) -f -- "$1" %$(QUIET2)$(APPEND) "$1" 'define AUTO_CMD_DEP_$(translate $@,:,_)_PREV_CMDS' %$(QUIET2)$(APPEND) -c "$1" '$@' %$(QUIET2)$(APPEND) "$1" 'endef' endef ## # Advanced version of KB_FN_AUTO_CMD_DEPS # # @param 1 recipe name # @param 2 dep file. KB_FN_AUTO_CMD_DEPS_EX = $(eval includedep $2)$(eval _DEPFILES_INCLUDED += $2)$1: .MUST_MAKE = $$(comp-cmds-ex $$(AUTO_CMD_DEP_$(translate $1,:,_)_PREV_CMDS),$$(commands $1),FORCE) ## # $(call KB_FN_AUTO_CMD_DEPS_COMMANDS) as the first command in a recipe to # automatically generate command dependencies. # After or before the recipe do $(call KB_FN_AUTO_CMD_DEPS,). define KB_FN_AUTO_CMD_DEPS_COMMANDS %$(QUIET2)$(RM) -f -- "$@.auto-dep" %$(QUIET2)$(APPEND) "$@.auto-dep" 'define AUTO_CMD_DEP_$(translate $@,:,_)_PREV_CMDS' %$(QUIET2)$(APPEND) -c "$@.auto-dep" '$@' %$(QUIET2)$(APPEND) "$@.auto-dep" 'endef' endef ## # Call before or after defining a recipe that you want automatic command # dependencies on. The recipe must start off by $(call KB_FN_AUTO_CMD_DEPS_COMMANDS). # # @param 1 recipe name KB_FN_AUTO_CMD_DEPS = $(call KB_FN_AUTO_CMD_DEPS_EX,$1,$1.auto-dep) # # Initialize some of the globals which the Config.kmk and # others can add stuff to if they like for processing in the footer. # ## KBUILD_TEMPLATE_PATHS # List a paths (separated by space) where templates can be found. KBUILD_TEMPLATE_PATHS := ## KBUILD_TOOL_PATHS # List of paths (separated by space) where tools can be found. KBUILD_TOOL_PATHS := ## KBUILD_SDK_PATHS # List of paths (separated by space) where SDKs can be found. KBUILD_SDK_PATHS := ## KBUILD_UNIT_PATHS # List of paths (separated by space) where units (USES) can be found. KBUILD_UNIT_PATHS := ## KBUILD_DEFAULT_PATHS # List of paths (separated by space) to search for stuff as a last resort. KBUILD_DEFAULT_PATHS := ## Proritized list of the default makefile when walking subdirectories. # The user can overload this list. DEFAULT_MAKEFILE := Makefile.kmk makefile.kmk Makefile makefile ## KBUILD_SRC_HANDLERS # The list of source handlers, pair of extension and handler. # The user can overload this list to provide additional or custom # handlers. On a per-target/template see SRC_HANDLERS. KBUILD_SRC_HANDLERS := \ .c:def_src_handler_c \ .C:def_src_handler_c \ .cxx:def_src_handler_cxx \ .CXX:def_src_handler_cxx \ .cpp:def_src_handler_cxx \ .CPP:def_src_handler_cxx \ .cc:def_src_handler_cxx \ .CC:def_src_handler_cxx \ .m:def_src_handler_objc \ .M:def_src_handler_objcxx \ .mm:def_src_handler_objcxx \ .asm:def_src_handler_asm \ .ASM:def_src_handler_asm \ .s:def_src_handler_asm \ .S:def_src_handler_asm \ .rc:def_src_handler_rc \ .obj:def_src_handler_obj \ .o:def_src_handler_obj \ .res:def_src_handler_obj ## PROPS_TOOLS # This is a subset of PROPS_SINGLE. PROPS_TOOLS := TOOL CTOOL CXXTOOL OBJCTOOL OBJCXXTOOL ASTOOL RCTOOL ARTOOL LDTOOL FETCHTOOL UNPACKTOOL PATCHTOOL ## PROPS_SINGLE # The list of non-accumulative target properties. # A Config.kmk file can add it's own properties to this list and kBuild # will do the necessary inheritance for templates, sdks, tools and targets. PROPS_SINGLE := $(PROPS_TOOLS) TEMPLATE INSTTYPE INST STAGE NOINST BLD_TYPE BLD_TRG BLD_TRG_ARCH BLD_TRG_CPU FETCHDIR \ OBJSUFF COBJSUFF CXXOBJSUFF OBJCOBJSUFF OBJCXXOBJSUFF ASOBJSUFF RCOBJSUFF SYSSUFF BINSUFF EXESUFF DLLSUFF LIBSUFF ARLIBSUFF \ MODE UID GID LD_DEBUG DEBUG_INSTTYPE DEBUG_INST DEBUG_STAGE ## PROPS_SINGLE_LNK # Subset of PROPS_SINGLE which applies to all linkable targets. PROPS_SINGLE_LNK := $(filter-out FETCHTOOL UNPACKTOOL PATCHTOOL FETCHDIR, $(PROPS_SINGLE)) ## PROPS_DEFERRED # This list of non-accumulative target properties which are or may be # functions, and thus should not be expanded until the very last moment. PROPS_DEFERRED := INSTFUN INSTALLER PRE_CMDS POST_CMDS PRE_INST_CMDS POST_INST_CMDS \ PRE_FILE_CMDS POST_FILE_CMDS PRE_SYMLINK_CMDS POST_SYMLINK_CMDS PRE_DIRECTORY_CMDS POST_DIRECTORY_CMDS \ NAME SONAME ## PROPS_ACCUMULATE_R # The list of accumulative target properties where the right most value/flag # is the 'most significant'. # A Config.kmk file can add it's own properties to this list and kBuild # will do the necessary inheritance from templates to targets. PROPS_ACCUMULATE_R := \ DEPS LNK_DEPS ORDERDEPS LNK_ORDERDEPS DEFS \ ARFLAGS \ CFLAGS CDEFS \ CXXFLAGS CXXDEFS \ OBJCFLAGS OBJCDEFS \ OBJCXXFLAGS OBJCXXDEFS \ ASFLAGS ASDEFS \ RCFLAGS RCDEFS \ LDFLAGS \ IDFLAGS IFFLAGS EXEC_IFFLAGS ISFLAGS \ FETCHFLAGS UNPACKFLAGS PATCHFLAGS ## PROPS_ACCUMULATE_R_LNK # Subset of PROPS_ACCUMULATE_R which applies to all linkable targets. PROPS_ACCUMULATE_R_LNK := $(filter-out ARFLAGS LDFLAGS EXEC_IFFLAGS FETCHFLAGS UNPACKFLAGS PATCHFLAGS, $(PROPS_ACCUMULATE_R)) ## PROPS_ACCUMULATE # The list of accumulative target properties where the left most value/flag # is the 'most significant'. # A Config.kmk file can add it's own properties to this list and kBuild # will do the necessary inheritance from templates to targets. PROPS_ACCUMULATE_L := \ SDKS USES SOURCES EXEC_SOURCES SRC_HANDLERS INTERMEDIATES \ INCS CINCS CXXINCS OBJCINCS OBJCXXINCS ASINCS RCINCS \ LIBS LIBPATH \ DIRS BLDDIRS CLEAN ## PROPS_ACCUMULATE_L_LNK # Subset of PROPS_ACCUMULATE_L which applies to all linkable targets. PROPS_ACCUMULATE_L_LNK := $(filter-out LIBS LIBPATH EXEC_SOURCES DIRS, $(PROPS_ACCUMULATE_L)) ## PROPS_ALL # List of all the properties. PROPS_ALL = $(PROPS_SINGLE) $(PROPS_DEFERRED) $(PROPS_ACCUMULATE_L) $(PROPS_ACCUMULATE_R) ## @name Properties valid on programs (BLDPROGS and PROGRAMS) ## @{ PROPS_PROGRAMS_SINGLE := $(PROPS_SINGLE_LNK) LDTOOL EXESUFF PROPS_PROGRAMS_DEFERRED := $(PROPS_DEFERRED) PROPS_PROGRAMS_ACCUMULATE_R := $(PROPS_ACCUMULATE_R_LNK) LDFLAGS PROPS_PROGRAMS_ACCUMULATE_L := $(PROPS_ACCUMULATE_L_LNK) LIBS LIBPATH ## @} ## @name Properties valid on libraries (LIBRARIES and IMPORT_LIBS) ## @{ PROPS_LIBRARIES_SINGLE := $(PROPS_SINGLE_LNK) ARTOOL LIBSUFF ARLIBSUFF LIBSUFF PROPS_LIBRARIES_DEFERRED := $(filter-out SONAME,$(PROPS_DEFERRED)) PROPS_LIBRARIES_ACCUMULATE_R := $(PROPS_ACCUMULATE_R_LNK) ARFLAGS PROPS_LIBRARIES_ACCUMULATE_L := $(PROPS_ACCUMULATE_L_LNK) ## @} ## @name Properties valid on dlls (DLLS) ## @{ PROPS_DLLS_SINGLE := $(PROPS_SINGLE_LNK) LDTOOL DLLSUFF LIBSUFF PROPS_DLLS_DEFERRED := $(PROPS_DEFERRED) PROPS_DLLS_ACCUMULATE_R := $(PROPS_ACCUMULATE_R_LNK) LDFLAGS PROPS_DLLS_ACCUMULATE_L := $(PROPS_ACCUMULATE_L_LNK) LIBS LIBPATH ## @} ## @name Properties valid on system modules (SYSMODS) ## @{ PROPS_SYSMODS_SINGLE := $(PROPS_SINGLE_LNK) LDTOOL SYSSUFF PROPS_SYSMODS_DEFERRED := $(PROPS_DEFERRED) PROPS_SYSMODS_ACCUMULATE_R := $(PROPS_ACCUMULATE_R_LNK) LDFLAGS PROPS_SYSMODS_ACCUMULATE_L := $(PROPS_ACCUMULATE_L_LNK) LIBS LIBPATH ## @} ## @name Properties valid on misc binaries (MISCBINS) ## @{ PROPS_MISCBINS_SINGLE := $(PROPS_SINGLE_LNK) LDTOOL BINSUFF PROPS_MISCBINS_DEFERRED := $(PROPS_DEFERRED) PROPS_MISCBINS_ACCUMULATE_R := $(PROPS_ACCUMULATE_R_LNK) LDFLAGS PROPS_MISCBINS_ACCUMULATE_L := $(PROPS_ACCUMULATE_L_LNK) LIBS LIBPATH ## @} ## @name Properties valid on installs (INSTALLS) ## @{ PROPS_INSTALLS_SINGLE := TOOL TEMPLATE INSTTYPE INST STAGE NOINST BLD_TYPE BLD_TRG BLD_TRG_ARCH BLD_TRG_CPU MODE UID GID PROPS_INSTALLS_DEFERRED := INSTFUN INSTALLER PRE_FILE_CMDS POST_FILE_CMDS PRE_SYMLINK_CMDS POST_SYMLINK_CMDS \ PRE_DIRECTORY_CMDS POST_DIRECTORY_CMDS PROPS_INSTALLS_ACCUMULATE_R := DEPS ORDERDEPS GOALS INST_ONLY_GOALS STAGE_ONLY_GOALS IFFLAGS EXEC_IFFLAGS PROPS_INSTALLS_ACCUMULATE_L := SOURCES EXEC_SOURCES DIRS CLEAN ## @} ## @name Properties valid on fetches (FETCHES) ## @{ PROPS_FETCHES_SINGLE := TOOL TEMPLATE FETCHTOOL UNPACKTOOL PATCHTOOL INST FETCHDIR PROPS_FETCHES_DEFERRED := PROPS_FETCHES_ACCUMULATE_R := FETCHFLAGS UNPACKFLAGS PATCHFLAGS PROPS_FETCHES_ACCUMULATE_L := SOURCES CLEAN ## @} ## KBUILD_COMPILE_CATEGTORIES # Tools categories for compiling. KBUILD_COMPILE_CATEGTORIES := AS C CXX OBJC OBJCXX RC ## KBUILD_GENERIC_CATEGORIES # Generic tool categories. KBUILD_GENERIC_CATEGORIES := FETCH UNPACK PATCH $(addprefix LINK_,LIBRARY PROGRAM DLL SYSMOD MISCBIN) ## PROPS_TOOLS_ONLY # Properties found only on tools. # This is expanded in a deferred manner, so it will pick up changes made to # KBUILD_COMPILE_CATEGTORIES and KBUILD_GENERIC_CATEGORIES made by units. PROPS_TOOLS_ONLY = \ $(foreach cat, $(KBUILD_COMPILE_CATEGTORIES), \ COMPILE_$(cat)_CMDS \ COMPILE_$(cat)_OUTPUT \ COMPILE_$(cat)_OUTPUT_MAYBE \ COMPILE_$(cat)_DEPEND \ COMPILE_$(cat)_DEPORD \ COMPILE_$(cat)_USES_KOBJCACHE ) \ $(foreach cat, $(KBUILD_GENERIC_CATEGORIES), \ $(cat)_CMDS \ $(cat)_OUTPUT \ $(cat)_OUTPUT_MAYBE \ $(cat)_DEPEND \ $(cat)_DEPORD )) # # Here is a special 'hack' to prevent innocent environment variables being # picked up and treated as properties. (The most annoying example of why # this is necessary is the Visual C++ commandline with it's LIBPATH.) # # Define KBUILD_DONT_KILL_ENV_PROPS in the env. or on the commandline to # disable this 'hack'. # ifndef KBUILD_DONT_KILL_ENV_PROPS define def_nuke_environment_prop ifeq ($(origin $(prop)),environment) $(prop) = endif endef $(foreach prop, $(PROPS_ALL) \ FETCHES PATCHES BLDPROGS LIBRARIES IMPORT_LIBS DLLS PROGRAMS SYSMODS MISCBINS INSTALLS OTHERS \ SUBDIRS MAKEFILES BLDDIRS \ ,$(eval $(value def_nuke_environment_prop))) endif # KBUILD_DONT_KILL_ENV_PROPS # # Pass configuration. # # The PASS__trgs variable is listing the targets. # The PASS__vars variable is listing the target variables. # The PASS__pass variable is the lowercased passname. # ## PASS: fetches # This pass fetches and unpacks things needed to complete the build. PASS_FETCHES := Fetches PASS_FETCHES_trgs := PASS_FETCHES_vars := _FETCHES PASS_FETCHES_pass := fetches ## PASS: patches # This pass applies patches. PASS_PATCHES := Patches PASS_PATCHES_trgs := PASS_PATCHES_vars := _PATCHES PASS_PATCHES_pass := patches ## PASS: bldprogs # This pass builds targets which are required for building the rest. PASS_BLDPROGS := Build Programs PASS_BLDPROGS_trgs := PASS_BLDPROGS_vars := _BLDPROGS PASS_BLDPROGS_pass := bldprogs ## PASS: libraries # This pass builds library targets. PASS_LIBRARIES := Libraries PASS_LIBRARIES_trgs := PASS_LIBRARIES_vars := _LIBS _IMPORT_LIBS _OTHER_LIBRARIES PASS_LIBRARIES_pass := libraries ## PASS: binaries # This pass builds dll targets. PASS_DLLS := DLLs PASS_DLLS_trgs := PASS_DLLS_vars := _DLLS _OTHER_DLLS PASS_DLLS_pass := dlls ## PASS: binaries # This pass builds binary targets, i.e. programs, system modules and stuff. PASS_BINARIES := Programs PASS_BINARIES_trgs := PASS_BINARIES_vars := _PROGRAMS _SYSMODS _MISC_BINS _OTHER_BINARIES PASS_BINARIES_pass := binaries ## PASS: others # This pass builds other targets. PASS_OTHERS := Other Stuff PASS_OTHERS_trgs := PASS_OTHERS_vars := _OTHERS PASS_OTHERS_pass := others ## PASS: staging # This pass installs the built entities to a sandbox area. ## @todo split this up into build install (to sandbox) and real installation. PASS_STAGING := Staging PASS_STAGING_trgs := PASS_STAGING_vars := _STAGE_DIRS _INSTALLS _STAGE_FILES _DEBUG_STAGE_DIRS _DEBUG_STAGE_FILES PASS_STAGING_pass := staging ## PASS: install # This pass installs the built entities to where they will be used (using # DESTROOT or PATH_INS to indicate where this is). PASS_INSTALLS := Install PASS_INSTALLS_trgs := PASS_INSTALLS_vars := _INSTALLS_DIRS _INSTALLS_FILES _DEBUG_INSTALL_DIRS _DEBUG_INSTALL_FILES PASS_INSTALLS_pass := installs ## PASS: testing # This pass processes custom rules for executing tests. PASS_TESTING := Tests PASS_TESTING_trgs := PASS_TESTING_vars := _TESTING PASS_TESTING_pass := testing ## PASS: packing # This pass processes custom packing rules. PASS_PACKING := Packing PASS_PACKING_trgs := PASS_PACKING_vars := _PACKING PASS_PACKING_pass := packing ## PASS: clean # This pass removes all generated files. PASS_CLEAN := Clean PASS_CLEAN_trgs := do-clean PASS_CLEAN_vars := PASS_CLEAN_pass := clean ## PASS: nothing # This pass just walks the tree. PASS_NOTHING := Nothing PASS_NOTHING_trgs := do-nothing PASS_NOTHING_vars := PASS_NOTHING_pass := nothing ## DEFAULT_PASSES # The default passes and their order. DEFAULT_PASSES := BLDPROGS LIBRARIES DLLS BINARIES OTHERS STAGING ## PASSES # The passes that should be defined. This must include # all passes mentioned by DEFAULT_PASSES. PASSES := FETCHES PATCHES $(DEFAULT_PASSES) INSTALLS TESTING PACKING CLEAN NOTHING # # Check for --pretty-command-printing before including the Config.kmk # so that anyone overriding the message macros can take the implied # verbosity level change into account. # ifndef KBUILD_VERBOSE ifndef KBUILD_QUIET ifeq ($(KMK_OPTS_PRETTY_COMMAND_PRINTING),1) export KBUILD_VERBOSE := 2 endif endif endif # # Legacy variable translation. # These will be eliminated when switching to the next version. # ifdef USE_KOBJCACHE ifndef KBUILD_USE_KOBJCACHE export KBUILD_USE_KOBJCACHE := $(USE_KOBJCACHE) endif endif # # Library path searching hints (target OS + arch). # # KBUILD_LIB_SEARCH_SUBS - Subdirs typically containing the right libraries. # KBUILD_LIB_SEARCH_ROOTS - Roots to search for library subdirs. # KBUILD_LIB_SEARCH_PATHS - ROOTS + SUBS. # ifeq ($(KBUILD_TARGET),darwin) KBUILD_LIB_SEARCH_ROOTS := \ /usr/ \ /Developer/usr/ KBUILD_LIB_SEARCH_SUBS := lib/ else if1of ($(KBUILD_TARGET), freebsd openbsd dragonfly) KBUILD_LIB_SEARCH_ROOTS := \ / \ /usr/ \ /usr/local/ KBUILD_LIB_SEARCH_SUBS := lib/ else ifeq ($(KBUILD_TARGET),netbsd) KBUILD_LIB_SEARCH_ROOTS := \ / \ /usr/ \ /usr/pkg/ \ /usr/local/ KBUILD_LIB_SEARCH_SUBS := lib/ else if1of ($(KBUILD_TARGET), gnukfbsd gnuknbsd linux) ifeq ($(realpath /bin),/usr/bin) KBUILD_LIB_SEARCH_ROOTS := \ /usr/ \ / \ /usr/local/ else KBUILD_LIB_SEARCH_ROOTS := \ / \ /usr/ \ /usr/local/ endif ifeq ($(KBUILD_TARGET_ARCH),amd64) KBUILD_LIB_SEARCH_SUBS := \ lib/x86_64-linux-gnu/ \ lib64/ \ lib/ else ifeq ($(KBUILD_TARGET_ARCH),x86) KBUILD_LIB_SEARCH_SUBS := \ lib/i686-linux-gnu/ \ lib/i386-linux-gnu/ \ lib32/ \ lib/ else KBUILD_LIB_SEARCH_SUBS := lib/ endif else ifeq ($(KBUILD_TARGET),solaris) KBUILD_LIB_SEARCH_ROOTS := \ / \ /usr/ \ /usr/sfw/ \ /usr/local/ \ /sw/ ifeq ($(KBUILD_TARGET_ARCH),amd64) KBUILD_LIB_SEARCH_SUBS := lib/amd64/ lib/ else ifeq ($(KBUILD_TARGET_ARCH),sparc64) KBUILD_LIB_SEARCH_SUBS := lib/sparcv9/ lib/ else KBUILD_LIB_SEARCH_SUBS := lib/ endif else KBUILD_LIB_SEARCH_SUBS := KBUILD_LIB_SEARCH_ROOTS := endif KBUILD_LIB_SEARCH_PATHS := $(foreach root, $(KBUILD_LIB_SEARCH_ROOTS), $(addprefix $(root),$(KBUILD_LIB_SEARCH_SUBS))) # # This is how we find the closest config.kmk. # It's a little hacky but I think it works fine. # _CFGDIR := . _CFGFILES := ./Config.kmk ./config.kmk define def_include_config $(eval _CFGDIR := $(_CFGDIR)/$(dir)) _CFGFILES += $(_CFGDIR)/Config.kmk $(_CFGDIR)/config.kmk endef # walk down the _RELATIVE_ path specified by DEPTH. $(foreach dir,$(subst /, ,$(DEPTH)), $(eval $(def_include_config)) ) # add the default config file. _CFGFILE := $(firstword $(wildcard $(_CFGFILES) $(FILE_KBUILD_CONFIG))) _CFGFILES := _CFGDIR := ifeq ($(_CFGFILE),) $(error kBuild: no Config.kmk file found! Check the DEPTH: DEPTH='$(DEPTH)' PATH_CURRENT='$(PATH_CURRENT)') endif # Include the config.kmk we found file (or the default one). ifdef KBUILD_PROFILE_SELF $(evalcall def_profile_self, including $(_CFGFILE)) include $(_CFGFILE) $(evalcall def_profile_self, included $(_CFGFILE)) else include $(_CFGFILE) endif # # Finalize a the central path variables now that we've included the Config.kmk file. # # This prevents some trouble when users override the defaults for these # variables and uses relative paths or paths with incorrect case. # PATH_OUT_BASE := $(abspath $(PATH_OUT_BASE)) PATH_OUT := $(abspath $(PATH_OUT)) PATH_OBJ := $(abspath $(PATH_OBJ)) PATH_TARGET := $(abspath $(PATH_TARGET)) PATH_INS := $(abspath $(PATH_INS)) PATH_STAGE := $(abspath $(PATH_STAGE)) # Finalize the install and staging directory layouts. define def_kbuild_finalize_inst local val := $(strip $($(y)_$(x))) ifeq ($(val),) $(error kBuild: '$(y)_$(x)' is set to an empty value.) endif ifneq ($(words $(val)),1) $(error kBuild: The '$(y)_$(x)' value '$(val)' should not contain spaces.) endif ifneq ($(pos \,$(val)), 0) $(error kBuild: The '$(y)_$(x)' value '$(val)' contains DOS slashes: not allowed.) endif ifneq ($(pos $(COLON),$(val)), 0) $(error kBuild: The '$(y)_$(x)' value '$(val)' contains colon: not allowed.) endif ifneq ($(substr $(val),-1), /) $(error kBuild: The '$(y)_$(x)' value '$(val)' has no trailing slash.) endif if $(pos /../,$(val)) != 0 || "$(substr $(val), 3)" == "../" $(error kBuild: The '$(y)_$(x)' value '$(val)' contains dot-dot escape.) endif $($(y)_$(x) := $(val) local val := $(strip $(PATH_$(y)_$(x))) ifeq ($(val),) $(error kBuild: 'PATH_$(y)_$(x)' is set to an empty value.) endif PATH_$(y)_$(x) := $(val) endef $(foreach y, INST STAGE, $(foreach x, $(KBUILD_INST_PATHS), $(evalcall def_kbuild_finalize_inst))) # No abspath for devtools since they might've been referenced already and we # don't want conflicting variable expansions. KBUILD_DEVTOOLS := $(KBUILD_DEVTOOLS) KBUILD_DEVTOOLS_TRG := $(KBUILD_DEVTOOLS_TRG) KBUILD_DEVTOOLS_TRG_ALT := $(KBUILD_DEVTOOLS_TRG_ALT) KBUILD_DEVTOOLS_HST := $(KBUILD_DEVTOOLS_HST) KBUILD_DEVTOOLS_HST_ALT := $(KBUILD_DEVTOOLS_HST_ALT) # # Setup the message style. The default one is inlined. # # See kBuild/msgstyles for more styles or use KBUILD_MSG_STYLE_PATHS # to create your own message style. # KBUILD_MSG_STYLE ?= default ifeq ($(KBUILD_MSG_STYLE),default) # # The 'default' style. # ## Fetch starting. # @param 1 Target name. MSG_FETCH ?= $(call MSG_L1,Fetching $1...) ## Re-fetch starting. # @param 1 Target name. MSG_REFETCH ?= $(call MSG_L1,Re-fetching $1...) ## Downloading a fetch component. # @param 1 Target name. # @param 2 The source URL. # @param 3 The destination file name. MSG_FETCH_DL ?= $(call MSG_L1,Downloading $1 - $2,=> $3) ## Checking a fetch component. # @param 1 Target name. # @param 2 The source URL. # @param 3 The destination file name. MSG_FETCH_CHK?= $(call MSG_L1,Checking $1 - $3, ($2)) ## Unpacking a fetch component. # @param 1 Target name. # @param 2 The archive file name. # @param 3 The target directory. MSG_FETCH_UP ?= $(call MSG_L1,Unpacking $1 - $2 => $3) ## Fetch completed. # @param 1 Target name. MSG_FETCH_OK ?= $(call MSG_L1,Successfully fetched $1) ## Unfetch a fetch target. # @param 1 Target name. MSG_UNFETCH ?= $(call MSG_L1,Unfetching $1...) ## Compiling a source file. # @param 1 Target name. # @param 2 The source filename. # @param 3 The primary link output file name. # @param 4 The source type (C,CXX,OBJC,AS,RC,++). MSG_COMPILE ?= $(call MSG_L1,Compiling $1 - $2,=> $3) ## Tool # @param 1 The tool name (bin2c,...) # @param 2 Target name. # @param 3 The source filename. # @param 4 The primary output file name. MSG_TOOL ?= $(call MSG_L1,$1 $2 - $3,=> $4) ## Generate a file, typically a source file. # @param 1 Target name if applicable. # @param 2 Output file name. # @param 3 What it's generated from MSG_GENERATE ?= $(call MSG_L1,Generating $(if $1,$1 - )$2,$(if $3,from $3)) ## Linking a bldprog/dll/program/sysmod target. # @param 1 Target name. # @param 2 The primary link output file name. # @param 3 The link tool operation (LINK_LIBRARY,LINK_PROGRAM,LINK_DLL,LINK_SYSMOD,++). MSG_LINK ?= $(call MSG_L1,Linking $1,=> $2) ## Merging a library into the target (during library linking). # @param 1 Target name. # @param 2 The output library name. # @param 3 The input library name. MSG_AR_MERGE ?= $(call MSG_L1,Merging $3 into $1, ($2)) ## Creating a directory (build). # @param 1 Directory name. MSG_MKDIR ?= $(call MSG_L2,Creating directory $1) ## Cleaning. MSG_CLEAN ?= $(call MSG_L1,Cleaning...) ## Nothing. MSG_NOTHING ?= $(call MSG_L1,Did nothing in $(CURDIR)) ## Pass # @param 1 The pass name. MSG_PASS ?= $(call MSG_L1,Pass - $1) ## Installing a bldprog/lib/dll/program/sysmod target. # @param 1 Target name. # @param 2 The source filename. # @param 3 The destination file name. MSG_INST_TRG ?= $(call MSG_L1,Installing $1 => $3) ## Installing a file (install target). # @param 1 The source filename. # @param 2 The destination filename. MSG_INST_FILE?= $(call MSG_L1,Installing $2,(<= $1)) ## Installing a symlink. # @param 1 Symlink # @param 2 Link target MSG_INST_SYM ?= $(call MSG_L1,Installing symlink $1,=> $2) ## Installing a directory. # @param 1 Directory name. MSG_INST_DIR ?= $(call MSG_L1,Installing directory $1) else _KBUILD_MSG_STYLE_FILE := $(firstword $(foreach path, $(KBUILD_MSG_STYLE_PATHS) $(KBUILD_PATH)/msgstyles, $(wildcard $(path)/$(KBUILD_MSG_STYLE).kmk))) ifneq ($(_KBUILD_MSG_STYLE_FILE),) include $(_KBUILD_MSG_STYLE_FILE) else $(error kBuild: Can't find the style setup file for KBUILD_MSG_STYLE '$(KBUILD_MSG_STYLE)') endif endif # # Message macros. # # This is done after including Config.kmk as to allow for # KBUILD_QUIET and KBUILD_VERBOSE to be configurable. # ifdef KBUILD_QUIET # No output QUIET := @ QUIET2:= @ MSG_L1 = MSG_L2 = else ifndef KBUILD_VERBOSE # Default output level. QUIET := @ QUIET2 := @ MSG_L1 ?= %@$(ECHO) "kBuild: $1" MSG_L2 = else ifeq ($(KBUILD_VERBOSE),1) # A bit more output QUIET := @ QUIET2 := @ MSG_L1 ?= %@$(ECHO) "kBuild: $1 $2" MSG_L2 = else ifeq ($(KBUILD_VERBOSE),2) # Lot more output QUIET := QUIET2 := @ MSG_L1 ?= %@$(ECHO) "kBuild: $1 $2" MSG_L2 ?= %@$(ECHO) "kBuild: $1" else # maximal output. QUIET := QUIET2 := MSG_L1 ?= %@$(ECHO) "kBuild: $1 $2" MSG_L2 ?= %@$(ECHO) "kBuild: $1" endif endif ## # An internal define used by subheader.kmk, subfooter.kmk, and # KB_FN_PASS_0_ON_TARGET. # # @param target The target to process. # define def_subfooter_header_target_pass ifndef $(target)_PATH ifndef $(target)_DEFPATH $(target)_DEFPATH := $(PATH_SUB_CURRENT) endif $(call KB_FN_ASSIGN_DEPRECATED,$(target)_PATH,$($(target)_DEFPATH), $(target)_DEFPATH) else ifndef $(target)_DEFPATH $(target)_DEFPATH := $($(target)_PATH) endif ifndef $(target)_MAKEFILE $(target)_MAKEFILE := $(MAKEFILE_CURRENT) endif ifndef $(target)_0_OUTDIR $(target)_0_OUTDIR := $(call TARGET_PATH,$(target)) $(call KB_FN_ASSIGN_DEPRECATED,PATH_$(target),$($(target)_0_OUTDIR), $(target)_0_OUTDIR) endif endef ## # Function to call to set _0_OUTDIR, _DEFPATH, and _MAKEFILE earlier than subfooter. # Can be used to avoid exploiting double expansion. # # @param 1 The target name. KB_FN_DO_PASS0_ON_TARGET = $(foreach target,$1,$(if-expr defined($(target)_0_OUTDIR),,$(evalval def_subfooter_header_target_pass))) # # Validate any KBUILD_BLD_TYPES additions and finally the KBUILD_TYPE. # if1of ($(KBUILD_BLD_TYPES), $(KBUILD_OSES)) $(error kBuild: found KBUILD_BLD_TYPES in KBUILD_OSES!) endif if1of ($(KBUILD_BLD_TYPES), $(KBUILD_ARCHES)) $(error kBuild: found KBUILD_BLD_TYPES in KBUILD_ARCHES!) endif if1of ($(KBUILD_OSES), $(KBUILD_ARCHES)) $(error kBuild: found KBUILD_OSES in KBUILD_ARCHES!) endif ifn1of ($(KBUILD_TYPE), $(KBUILD_BLD_TYPES)) $(error kBuild: KBUILD_TYPE(=$(KBUILD_TYPE)) is not found in KBUILD_BLD_TYPES(=$(KBUILD_BLD_TYPES))!) endif # # Mark the output and temporary directories as volatile on windows. # # This automatically means the directories not listed here are considered # static and won't be invalidated once we start running compile jobs. # ifeq ($(KBUILD_HOST),win) if $(KBUILD_KMK_REVISION) >= 2886 $(dircache-ctl volatile, $(PATH_OUT_BASE), $(PATH_OUT), $(TEMP), $(TMP), $(TMPDIR), $(TMP)) endif endif ifdef KBUILD_PROFILE_SELF $(evalcall def_profile_self, end of header.kmk) _KBUILD_TS_HEADER_END := $(_KBUILD_TS_PREV) endif # end-of-file-content __header_kmk__ := 1 endif # !__header_kmk__ kbuild-3149/kBuild/footer-pass2-installs.kmk0000644000175000017500000005452213252530250021002 0ustar locutuslocutus# $Id: footer-pass2-installs.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild - Footer - Target lists - Pass 2 - Installs. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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 source of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # # # INSTALLS # ## # Generate the staging rules. # define def_install_src_rule_staging $$(call KB_FN_ASSERT_ABSPATH, stagedst) $$(call KB_FN_ASSERT_ABSPATH, srcsrc) $(stagedst) : $(srcsrc) $(top_deps) | $(dir $(stagedst)) $(top_orderdeps) %$$(call MSG_INST_FILE,$(srcsrc),$(stagedst)) $(top_pre_file_cmds) $$(QUIET)$(stagecmd) $(top_post_file_cmds) endef $(eval-opt-var def_install_src_rule_staging) define def_install_src_rule_installing $$(call KB_FN_ASSERT_ABSPATH, instdst) $$(call KB_FN_ASSERT_ABSPATH, srcsrc) $(instdst) : $(srcsrc) $(top_deps) | $(dir $(instdst)) $(top_orderdeps) %$$(call MSG_INST_FILE,$(srcsrc),$(instdst)) $(top_pre_file_cmds) $$(QUIET)$(instcmd) $(top_post_file_cmds) endef $(eval-opt-var def_install_src_rule_installing) ## # Install one file. # define def_install_src # deal with '=>' in the source file name. ifeq ($(src),=>) $(error kBuild: Install target '$(target)' has a bad source specifier containing '=>' without any file names) endif ifeq ($(substr $(src),1,2),=>) $(warning kBuild: Install target '$(target)' has a bad source specifier: $(src)) endif ifeq ($(substr $(src),-2),=>) $(warning kBuild: Install target '$(target)' has a bad source specifier: $(src)) endif local srcdst := $(subst =>, ,$(src)) local srcsrc := $(firstword $(srcdst)) local srcdstdir := $(dir $(word 2,$(srcdst))) ifeq ($(srcdstdir),./) local srcdstdir:= endif local srcdst := $(word $(words $(srcdst)),$(srcdst)) # instfun, mode, uid and gid. ifdef $(srcsrc)_INSTFUN local instfun := $(srcsrc)_INSTFUN else local instfun := $(top_instfun) endif local mode := $(firstword \ $($(target)_$(srcsrc)$(source_type_prefix)_MODE.$(bld_trg).$(bld_trg_arch)) \ $($(target)_$(srcsrc)$(source_type_prefix)_MODE.$(bld_trg)) \ $($(target)_$(srcsrc)$(source_type_prefix)_MODE) \ $($(target)_$(srcdst)$(source_type_prefix)_MODE.$(bld_trg).$(bld_trg_arch)) \ $($(target)_$(srcdst)$(source_type_prefix)_MODE.$(bld_trg)) \ $($(target)_$(srcdst)$(source_type_prefix)_MODE) \ $($(srcsrc)$(source_type_prefix)_MODE.$(bld_trg).$(bld_trg_arch)) \ $($(srcsrc)$(source_type_prefix)_MODE.$(bld_trg)) \ $($(srcsrc)$(source_type_prefix)_MODE) \ $($(srcdst)$(source_type_prefix)_MODE.$(bld_trg).$(bld_trg_arch)) \ $($(srcdst)$(source_type_prefix)_MODE.$(bld_trg)) \ $($(srcdst)$(source_type_prefix)_MODE) \ $(source_type_mode)) local uid := $(firstword \ $($(target)_$(srcsrc)_UID.$(bld_trg).$(bld_trg_arch)) \ $($(target)_$(srcsrc)_UID.$(bld_trg)) \ $($(target)_$(srcsrc)_UID) \ $($(target)_$(srcdst)_UID.$(bld_trg).$(bld_trg_arch)) \ $($(target)_$(srcdst)_UID.$(bld_trg)) \ $($(target)_$(srcdst)_UID) \ $($(srcsrc)_UID.$(bld_trg).$(bld_trg_arch)) \ $($(srcsrc)_UID.$(bld_trg)) \ $($(srcsrc)_UID) \ $($(srcdst)_UID.$(bld_trg).$(bld_trg_arch)) \ $($(srcdst)_UID.$(bld_trg)) \ $($(srcdst)_UID) \ $(top_uid)) local gid := $(firstword \ $($(target)_$(srcsrc)_GID.$(bld_trg).$(bld_trg_arch)) \ $($(target)_$(srcsrc)_GID.$(bld_trg)) \ $($(target)_$(srcsrc)_GID) \ $($(target)_$(srcdst)_GID.$(bld_trg).$(bld_trg_arch)) \ $($(target)_$(srcdst)_GID.$(bld_trg)) \ $($(target)_$(srcdst)_GID) \ $($(srcsrc)_GID.$(bld_trg).$(bld_trg_arch)) \ $($(srcsrc)_GID.$(bld_trg)) \ $($(srcsrc)_GID) \ $($(srcdst)_GID.$(bld_trg).$(bld_trg_arch)) \ $($(srcdst)_GID.$(bld_trg)) \ $($(srcdst)_GID) \ $(top_gid)) local flags := \ $(top_ifflags) \ $($(srcdst)$(source_type_prefix)_IFFLAGS) \ $($(srcdst)$(source_type_prefix)_IFFLAGS.$(bld_trg)) \ $($(srcdst)$(source_type_prefix)_IFFLAGS.$(bld_trg).$(bld_trg_arch)) \ $($(srcsrc)$(source_type_prefix)_IFFLAGS) \ $($(srcsrc)$(source_type_prefix)_IFFLAGS.$(bld_trg)) \ $($(srcsrc)$(source_type_prefix)_IFFLAGS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_$(srcdst)$(source_type_prefix)_IFFLAGS) \ $($(target)_$(srcdst)$(source_type_prefix)_IFFLAGS.$(bld_trg)) \ $($(target)_$(srcdst)$(source_type_prefix)_IFFLAGS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_$(srcsrc)$(source_type_prefix)_IFFLAGS) \ $($(target)_$(srcsrc)$(source_type_prefix)_IFFLAGS.$(bld_trg)) \ $($(target)_$(srcsrc)$(source_type_prefix)_IFFLAGS.$(bld_trg).$(bld_trg_arch)) clean_files += \ $($(srcdst)_CLEAN) \ $($(srcdst)_CLEAN.$(bld_trg)) \ $($(srcdst)_CLEAN.$(bld_trg).$(bld_trg_arch)) \ $($(srcsrc)_CLEAN) \ $($(srcsrc)_CLEAN.$(bld_trg)) \ $($(srcsrc)_CLEAN.$(bld_trg).$(bld_trg_arch)) \ $($(target)_$(srcdst)_CLEAN) \ $($(target)_$(srcdst)_CLEAN.$(bld_trg)) \ $($(target)_$(srcdst)_CLEAN.$(bld_trg).$(bld_trg_arch)) \ $($(target)_$(srcsrc)_CLEAN) \ $($(target)_$(srcsrc)_CLEAN.$(bld_trg)) \ $($(target)_$(srcsrc)_CLEAN.$(bld_trg).$(bld_trg_arch)) # Adjust the source if we got a default PATH. (This must be done this late!) ifdef $(target)_DEFPATH local defpath := $($(target)_DEFPATH) else ifdef $(target)_PATH local defpath := $($(target)_PATH) else local defpath := endif ifneq ($(defpath),) local srcsrc := $(abspathex $(srcsrc),$(defpath)) endif # Generate the staging rule (requires double evaluation). local stage := $(strip $(firstdefined $(srcsrc)_STAGE $(srcsrc)_INST $(target)_1_STAGE,value)) if "$(substr $(stage),-1)" != "/" && "$(stage)" != "" $(warning kBuild: File $(srcsrc) in install target $(target) has a STAGE/INST property without a trailing slash: '$(stage)') local stage := $(stage)/ endif local stage := $(stage)$(dir $(srcdstdir)) ifeq ($(root $(stage)),) local stagedst := $(call $(instfun),$(srcdst),$(target),$(stage),$(PATH_STAGE)) else local stage := $(abspath $(stage))/ ifeq ($(pos $(PATH_OBJ),$(stage)),1) local stage := $(substr $(stage), $(expr $(length-var PATH_OBJ) + 2)) local stagedst := $(call $(instfun),$(srcdst),$(target),$(stage),$(PATH_OBJ)) else $(error kBuild: File $(srcsrc) in install target $(target) has a STAGE/INST property with an absolute path outside PATH_OBJ: '$(stage)') endif endif ifdef $(srcsrc)_INSTALLER local stagecmd := $(call $(srcsrc)_INSTALLER,$(srcsrc),$(stagedst),$(target),$(flags),stage) else ifdef $(target)_INSTALLER local stagecmd := $(call $(target)_INSTALLER,$(srcsrc),$(stagedst),$(target),$(flags),stage) else local stagecmd := $$(INSTALL_STAGING)\ $(if $(uid),-o $(uid))\ $(if $(gid),-g $(gid))\ $(if $(mode),-m $(mode))\ $(flags) -- \ $(srcsrc) $(stagedst) endif $(eval $(def_install_src_rule_staging)) $(target)_2_STAGE_TARGETS += $(stagedst) # Generate the install rule ifeq ($(insttype),both) local inst := $(strip $(firstdefined $(srcsrc)_INST $(target)_1_INST,value)) if "$(substr $(inst),-1)" != "/" && "$(inst)" != "" $(warning kBuild: File $(srcsrc) in install target $(target) has a INST property without a trailing slash: '$(inst)') local inst := $(inst)/ endif local inst := $(inst)$(dir $(srcdstdir)) ifneq ($(root $(inst)),) $(error kBuild: File $(srcsrc) in install target $(target) has a INST property with an absolute path: '$(inst)') endif local instdst := $(call $(instfun),$(srcdst),$(target),$(inst),$(PATH_INS)) ifdef $(srcsrc)_INSTALLER local instcmd := $(call $(srcsrc)_INSTALLER,$(srcsrc),$(instdst),$(target),$(flags),install) else ifdef $(target)_INSTALLER local instcmd := $(call $(target)_INSTALLER,$(srcsrc),$(instdst),$(target),$(flags),install) else local instcmd := $$(INSTALL)\ $(if $(uid),-o $(uid))\ $(if $(gid),-g $(gid))\ $(if $(mode),-m $(mode))\ $(flags) -- \ $(srcsrc) $(instdst) endif $(eval $(def_install_src_rule_installing)) $(target)_2_INST_TARGETS += $(instdst) endif #$(warning instfun=$(instfun) srcdst=$(srcdst) target=$(target) inst=$(inst) => instdst=$(instdst); stage=$(stage) => stagedst=$(stagedst)) endef # def_install_src $(eval-opt-var def_install_src) ## # Generate the symlink rules. # define def_install_symlink_rule_staging $$(call KB_FN_ASSERT_ABSPATH, stagedst) $(stagedst) : $(top_deps) | $(dir $(stagedst)) $(top_orderdeps) %$$(call MSG_INST_SYM,$(stagedst),$(symdst)) $$(QUIET)$$(RM) -f -- $$@ $(top_pre_sym_cmds) $$(QUIET)$$(LN_SYMLINK) $(symdst) $(stagedst) $(top_post_sym_cmds) endef $(eval-opt-var def_install_symlink_rule_staging) define def_install_symlink_rule_installing $$(call KB_FN_ASSERT_ABSPATH, instdst) $(instdst) : $(top_deps) | $(dir $(instdst)) $(top_orderdeps) %$$(call MSG_INST_SYM,$(instdst),$(symdst)) $$(QUIET)$$(RM) -f -- $$@ $(top_pre_sym_cmds) $$(QUIET)$$(LN_SYMLINK) $(symdst) $(instdst) $(top_post_sym_cmds) endef $(eval-opt-var def_install_symlink_rule_installing) ## # Create one symlink. # define def_install_symlink # deal with '=>' in the source file name. local symdst := $(subst =>, ,$(src)) local symlnk := $(firstword $(symdst)) local symdst := $(word $(words $(symdst)),$(symdst)) local symlnkdir := $(dir $(symlnk)) ifeq ($(symlnkdir),./) local symlnkdir := endif # Figure which install function to use below. ifdef $(symlnk)_INSTFUN local instfun := $(symlnk)_INSTFUN else local instfun := $(top_instfun) endif # Calc stage destination and generate the rule (requires double evaluation). local stage := $(strip $(firstdefined $(symlnk)_STAGE $(symlnk)_INST $(target)_1_STAGE,value)) if "$(substr $(stage),-1)" != "/" && "$(stage)" != "" $(warning kBuild: Symlink $(symlnk) in install target $(target) has a STAGE/INST property without a trailing slash: '$(stage)') local stage := $(stage)/ endif local stage := $(stage)$(symlnkdir) ifeq ($(root $(stage)),) local stagedst := $(call $(instfun),$(symlnk),$(target),$(stage),$(PATH_STAGE)) else local stage := $(abspath $(stage))/ ifeq ($(pos $(PATH_OBJ),$(stage)),1) local stage := $(substr $(stage), $(expr $(length-var PATH_OBJ) + 2)) local stagedst := $(call $(instfun),$(symlnk),$(target),$(stage),$(PATH_OBJ)) else $(error kBuild: Symlink $(symlnk) in install target $(target) has a STAGE/INST property with an absolute path outside PATH_OBJ: '$(stage)') endif endif $(eval $(def_install_symlink_rule_staging)) $(target)_2_STAGE_TARGETS += $(stagedst) # Calcuate the install destiation and generate the rule (if necessary). ifeq ($(instmode),both) local inst := $(strip $(firstdefined $(symlnk)_INST $(target)_1_INST,value)) if "$(substr $(inst),-1)" != "/" && "$(inst)" != "" $(warning kBuild: Symlink $(symlnk) in install target $(target) has a INST property without a trailing slash: '$(inst)') local inst := $(inst)/ endif ifneq ($(root $(inst)),) $(error kBuild: Symlink $(symlnk) in install target $(target) has a INST property with an absolute path: '$(inst)') endif local inst := $(inst)$(symlnkdir) local instdst := $(call $(instfun),$(symlnk),$(target),$(inst),$(PATH_INS)) $(eval $(def_install_symlink_rule_installing)) $(target)_2_INST_TARGETS += $(instdst) endif #$(warning symlnk=$(symlnk) symdst=$(symdst) instdst=$(instdst) stagedst=$(stagedst) instfun=$(instfun) inst=$(inst) stage='$(stage)') endef # def_install_symlink $(optmize def_install_symlink) ## # Generate an directory installtion rule. # Note. Used both for staging and real install rules. # define def_install_directory_rule $$(call KB_FN_ASSERT_ABSPATH, insdst) $(insdst): $(top_deps) | $(top_orderdeps) %$$(call MSG_INST_DIR,$(insdst)) $(top_pre_dir_cmds) $$(QUIET)$$(INSTALL) -d \ $(if $(uid),-o $(uid))\ $(if $(gid),-g $(gid))\ $(if $(mode),-m $(mode))\ $(flags) -- \ $(insdst) $(top_post_dir_cmds) .NOTPARALLEL: $(insdst) endef # def_install_directory_rule $(eval-opt-var def_install_directory_rule) ## # Create one directory. # define def_install_directory # gather common properties. local mode := $(firstword \ $($(target)_$(directory)_MODE.$(bld_trg).$(bld_trg_arch)) \ $($(target)_$(directory)_MODE.$(bld_trg)) \ $($(target)_$(directory)_MODE) \ $($(directory)_MODE.$(bld_trg).$(bld_trg_arch)) \ $($(directory)_MODE.$(bld_trg)) \ $($(directory)_MODE) \ $(top_mode) ) local uid := $(firstword \ $($(target)_$(directory)_UID.$(bld_trg).$(bld_trg_arch)) \ $($(target)_$(directory)_UID.$(bld_trg)) \ $($(target)_$(directory)_UID) \ $($(directory)_UID.$(bld_trg).$(bld_trg_arch)) \ $($(directory)_UID.$(bld_trg)) \ $($(directory)_UID) \ $(top_uid) ) local gid := $(firstword \ $($(target)_$(directory)_GID.$(bld_trg).$(bld_trg_arch)) \ $($(target)_$(directory)_GID.$(bld_trg)) \ $($(target)_$(directory)_GID) \ $($(directory)_GID.$(bld_trg).$(bld_trg_arch)) \ $($(directory)_GID.$(bld_trg)) \ $($(directory)_GID) \ $(top_gid) ) local flags := \ $(top_idflags) \ $($(directory)_IDFLAGS) \ $($(directory)_IDFLAGS.$(bld_trg)) \ $($(directory)_IDFLAGS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_$(directory)_IDFLAGS) \ $($(target)_$(directory)_IDFLAGS.$(bld_trg)) \ $($(target)_$(directory)_IDFLAGS.$(bld_trg).$(bld_trg_arch)) \ # The staging rule (requires double evaluation). local stage := $(strip $(firstdefined $(directory)_STAGE $(directory)_INST $(target)_1_STAGE,value)) if "$(substr $(stage),-1)" != "/" && "$(stage)" != "" $(warning kBuild: Directory $(directory) in install target $(target) has a STAGE/INST property without a trailing slash: '$(stage)') local stage := $(stage)/ endif ifeq ($(root $(stage)),) local insdst := $(PATH_STAGE)/$(stage)$(directory)/ else local stage := $(abspath $(stage))/ ifeq ($(pos $(PATH_OBJ),$(stage)),1) local insdst := $(stage)$(directory)/ else $(error kBuild: Directory $(directory) in install target $(target) has a STAGE/INST property with an absolute path outside PATH_OBJ: '$(stage)') endif endif $(target)_2_STAGE_DIR_TARGETS += $(insdst) $(eval $(def_install_directory_rule)) # The install rule. ifeq ($(insttype),both) local inst := $(strip $(firstdefined $(directory)_INST $(target)_1_INST,value)) ifneq ($(substr $(inst),-1),/) $(warning kBuild: Directory $(directory) in install target $(target) has a INST property without a trailing slash: '$(inst)') local inst := $(inst)/ endif ifneq ($(root $(stage)),) $(error kBuild: Directory $(directory) in install target $(target) has a INST property with an absolute path: '$(inst)') endif local insdst := $(PATH_INS)/$(inst)$(directory)/ $(target)_2_INST_DIR_TARGETS += $(insdst) $(eval $(def_install_directory_rule)) endif #$(warning directory=$(directory) inst=$(inst) stage=$(stage) mode=$(mode) gid=$(gid) uid=$(uid)) endef # def_install_directory $(eval-opt-var def_install_directory) ## # Process one install target. # define def_install # the basics. local bld_type := $(firstword $($(target)_BLD_TYPE) $(KBUILD_TYPE)) local bld_trg := $(firstword $($(target)_BLD_TRG) $(KBUILD_TARGET)) local bld_trg_arch := $(firstword $($(target)_BLD_TRG_ARCH) $(KBUILD_TARGET_ARCH)) local bld_trg_cpu := $(firstword $($(target)_BLD_TRG_CPU) $(KBUILD_TARGET_CPU)) local insttype := $($(target)_1_INSTTYPE) ifneq ($(insttype),none) $(target)_2_STAGE_TARGETS := $($(target)_GOALS) $($(target)_STAGE_ONLY_GOALS) else $(target)_2_STAGE_TARGETS := endif $(target)_2_STAGE_DIR_TARGETS := ifeq ($(insttype),both) $(target)_2_INST_TARGETS := $($(target)_GOALS) $($(target)_INST_ONLY_GOALS) else $(target)_2_INST_TARGETS := endif $(target)_2_INST_DIR_TARGETS := local outbase := $(call TARGET_BASE,$(target),$(target)) $(target)_0_OUTDIR := $(patsubst %/,%,$(dir $(outbase))) $(call KB_FN_ASSIGN_DEPRECATED,PATH_$(target),$($(target)_0_OUTDIR), $(target)_0_OUTDIR) ifneq ($(insttype),none) # Cache top level target properties. local top_mode := $(firstword \ $($(target)_MODE.$(bld_trg).$(bld_trg_arch)) \ $($(target)_MODE.$(bld_trg)) \ $($(target)_MODE) ) local top_exec_mode := $(firstword \ $($(target)_EXEC_MODE.$(bld_trg).$(bld_trg_arch)) \ $($(target)_EXEC_MODE.$(bld_trg)) \ $($(target)_EXEC_MODE) ) local top_uid := $(firstword \ $($(target)_UID.$(bld_trg).$(bld_trg_arch)) \ $($(target)_UID.$(bld_trg)) \ $($(target)_UID) ) local top_gid := $(firstword \ $($(target)_GID.$(bld_trg).$(bld_trg_arch)) \ $($(target)_GID.$(bld_trg)) \ $($(target)_GID) ) local top_ifflags := \ $($(target)_IFFLAGS) \ $($(target)_IFFLAGS.$(bld_trg)) \ $($(target)_IFFLAGS.$(bld_trg).$(bld_trg_arch)) local top_idflags := \ $($(target)_IDFLAGS) \ $($(target)_IDFLAGS.$(bld_trg)) \ $($(target)_IDFLAGS.$(bld_trg).$(bld_trg_arch)) ifdef $(target)_INSTFUN local top_instfun := $(target)_INSTFUN else local top_instfun := _INSTALL_FILE endif local top_deps := \ $($(target)_DEPS.$(bld_trg_cpu)) \ $($(target)_DEPS.$(bld_trg).$(bld_trg_arch).$(bld_type)) \ $($(target)_DEPS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_DEPS.$(bld_trg).$(bld_type)) \ $($(target)_DEPS.$(bld_trg_arch)) \ $($(target)_DEPS.$(bld_trg)) \ $($(target)_DEPS.$(bld_type)) \ $($(target)_DEPS) local top_orderdeps := \ $($(target)_ORDERDEPS.$(bld_trg_cpu)) \ $($(target)_ORDERDEPS.$(bld_trg).$(bld_trg_arch).$(bld_type)) \ $($(target)_ORDERDEPS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_ORDERDEPS.$(bld_trg).$(bld_type)) \ $($(target)_ORDERDEPS.$(bld_trg_arch)) \ $($(target)_ORDERDEPS.$(bld_trg)) \ $($(target)_ORDERDEPS.$(bld_type)) \ $($(target)_ORDERDEPS) ifdef $(target)_DEFPATH local top_defpath := $($(target)_DEFPATH) else ifdef $(target)_PATH local top_defpath := $($(target)_PATH) else local top_defpath := endif ifneq ($(top_defpath),) local top_deps := $(abspathex $(top_deps),$(top_defpath)) local top_orderdeps := $(abspathex $(top_orderdeps),$(top_defpath)) endif # The user have to use double expansion and can only use the above locals. Not 100% optimal... local top_pre_file_cmds := $(evalcall def_fn_prop_get_first_defined,PRE_XFILE_CMDS) local top_post_file_cmds := $(evalcall def_fn_prop_get_first_defined,POST_XFILE_CMDS) local top_pre_sym_cmds := $(evalcall def_fn_prop_get_first_defined,PRE_SYMLINK_CMDS) local top_post_sym_cmds := $(evalcall def_fn_prop_get_first_defined,POST_SYMLINK_CMDS) local top_pre_dir_cmds := $(evalcall def_fn_prop_get_first_defined,PRE_DIRECTORY_CMDS) local top_post_dir_cmds := $(evalcall def_fn_prop_get_first_defined,POST_DIRECTORY_CMDS) $(foreach directory, \ $($(target)_DIRS) \ $($(target)_DIRS.$(bld_trg)) \ $($(target)_DIRS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_DIRS.$(bld_trg_arch)) \ $($(target)_DIRS.$(bld_trg_cpu)) \ $($(target)_DIRS.$(bld_type)), \ $(evalval def_install_directory)) local clean_files := \ $($(target)_CLEAN) \ $($(target)_CLEAN.$(bld_trg)) \ $($(target)_CLEAN.$(bld_trg).$(bld_trg_arch)) \ $($(target)_CLEAN.$(bld_trg_arch)) \ $($(target)_CLEAN.$(bld_trg_cpu)) \ $($(target)_CLEAN.$(bld_type)) local source_type_prefix := local source_type_mode := $(firstword $(top_mode) a+r,u+w) $(foreach src,\ $($(target)_SOURCES) \ $($(target)_SOURCES.$(bld_trg)) \ $($(target)_SOURCES.$(bld_trg).$(bld_trg_arch)) \ $($(target)_SOURCES.$(bld_trg_arch)) \ $($(target)_SOURCES.$(bld_trg_cpu)) \ $($(target)_SOURCES.$(bld_type)), \ $(evalval def_install_src)) local source_type_prefix := EXEC_ local source_type_mode := $(firstword $(top_exec_mode) a+xr,u+w) $(foreach src,\ $($(target)_EXEC_SOURCES) \ $($(target)_EXEC_SOURCES.$(bld_trg)) \ $($(target)_EXEC_SOURCES.$(bld_trg).$(bld_trg_arch)) \ $($(target)_EXEC_SOURCES.$(bld_trg_arch)) \ $($(target)_EXEC_SOURCES.$(bld_trg_cpu)) \ $($(target)_EXEC_SOURCES.$(bld_type)), \ $(evalval def_install_src)) $(foreach src,\ $($(target)_SYMLINKS) \ $($(target)_SYMLINKS.$(bld_trg)) \ $($(target)_SYMLINKS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_SYMLINKS.$(bld_trg_arch)) \ $($(target)_SYMLINKS.$(bld_trg_cpu)) \ $($(target)_SYMLINKS.$(bld_type)), \ $(evalval def_install_symlink)) else # none local clean_files := endif # The collection targets (staging only). local clean_files += $($(target)_1_TARGET) $($(target)_1_TARGET): $$($(target)_2_STAGE_TARGETS) | $$($(target)_2_STAGE_DIR_TARGETS) $$(dir $$@) @$(QUIET2)$(APPEND) $@ $(target): $$($(target)_1_TARGET) # Update Global lists. _INSTALLS += $($(target)_1_TARGET) _STAGE_FILES += $($(target)_2_STAGE_TARGETS) _STAGE_DIRS += $($(target)_2_STAGE_DIR_TARGETS) _INSTALLS_FILES += $($(target)_2_INST_TARGETS) _INSTALLS_DIRS += $($(target)_2_INST_DIR_TARGETS) _CLEAN_FILES += $(clean_files) _DIRS += \ $($(target)_0_OUTDIR) \ $($(target)_BLDDIRS) \ $($(target)_BLDDIRS.$(bld_trg)) \ $($(target)_BLDDIRS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_BLDDIRS.$(bld_trg_arch)) \ $($(target)_BLDDIRS.$(bld_trg_cpu)) \ $($(target)_BLDDIRS.$(bld_type)) # Deprecated properties. INSTARGET_$(target) := $($(target)_2_STAGE_TARGETS) INSTARGET_DIRS_$(target) := $($(target)_2_STAGE_DIR_TARGETS) endef # def_install $(eval-opt-var def_install) ## Do pass 1 on the implicit targets and add them to the list. $(foreach target, $(_ALL_INSTALLS_IMPLICIT), \ $(evalval def_pass1_install)) _ALL_INSTALLS += $(_ALL_INSTALLS_IMPLICIT) ## Do pass 2 on all install targets. $(foreach target, $(_ALL_INSTALLS), \ $(evalvalctx def_install)) ifdef KBUILD_PROFILE_SELF $(evalcall def_profile_self, done install targets) endif # # Some introspection targets that can be useful for package maintainers. # .PHONY: kbuild-show-install-files kbuild-show-install-dirs kbuild-show-install-files:: $(addprefix $(NL)$(TAB)$(QUIET)$(ECHO) , $(subst $(PATH_INS)/,,$(_INSTALLS_FILES))) kbuild-show-install-dirs:: $(addprefix $(NL)$(TAB)$(QUIET)$(ECHO) , $(subst $(PATH_INS)/,,$(_INSTALLS_DIRS))) kbuild-show-stage-files:: $(addprefix $(NL)$(TAB)$(QUIET)$(ECHO) , $(subst $(PATH_STAGE)/,,$(_STAGE_FILES))) kbuild-show-stage-dirs:: $(addprefix $(NL)$(TAB)$(QUIET)$(ECHO) , $(subst $(PATH_STAGE)/,,$(_STAGE_DIRS))) kbuild-3149/kBuild/envos2.cmd0000644000175000017500000006434713252530251016033 0ustar locutuslocutus/* echo this is a rexx script! cancel & quit & exit */ /* $Id: envos2.cmd 2413 2010-09-11 17:43:04Z bird $ */ /** @file * Environment setup script for OS/2. */ /* * * Copyright (c) 1999-2010 knut st. osmundsen * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * kBuild 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 kBuild; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /* * Setup the usual suspects. */ Address CMD '@echo off'; signal on novalue name NoValueHandler if (RxFuncQuery('SysLoadFuncs') = 1) then do call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs'; call SysLoadFuncs; end /* * Apply the CMD.EXE workaround. */ call FixCMDEnv; /* * Globals */ skBuildPath = EnvGet("KBUILD_PATH"); skBuildBinPath = EnvGet("KBUILD_BIN_PATH"); skBuildType = EnvGet("KBUILD_TYPE"); skBuildTarget = EnvGet("KBUILD_TARGET"); skBuildTargetArch = EnvGet("KBUILD_TARGET_ARCH"); skBuildTargetCpu = EnvGet("KBUILD_TARGET_CPU"); skBuildHost = EnvGet("KBUILD_HOST"); skBuildHostArch = EnvGet("KBUILD_HOST_ARCH"); skBuildHostCpu = EnvGet("KBUILD_HOST_CPU"); /* * Process arguments. */ fOptFull = 0 fOptLegacy = 0 fOptDbg = 0 fOptQuiet = 0 sOptVars = "" fOptValueOnly = 0 sShowVarPrefix = ""; fOptOverrideAll = 0 fOptOverrideType = 0; fSetType = 0; fOptOverrideTarget = 0; fOptOverrideTargetArch = 0; fOptDefault = 0; parse arg sArgs do while (sArgs <> '') parse value sArgs with sArg sRest say 'sArgs='sArgs';' say ' sArg='sArg';' say 'sRest='sRest';' select when (sArg = "--debug-script") then do fOptDbg = 1; end when (sArg = "--no-debug-script") then do fOptDbg = 0; end when (sArg = "--quiet") then do fOptQuiet = 1; end when (sArg = "--verbose") then do fOptQuiet = 0; end when (sArg = "--full") then do fOptFull = 1; end when (sArg = "--normal") then do fOptFull = 0; end when (sArg = "--legacy") then do fOptLegacy = 1; end when (sArg = "--no-legacy") then do fOptLegacy = 0; end when (sArg = "--eval") then do say "error: --eval is not supported on OS/2." end when (sArg = "--var") then do parse value sRest with sVar sRest2 sRest = sRest2; if (sVar = '') then do say "syntax error: --var is missing the variable name"; call SysSleep 1 exit 1; end if (sVar = "all" | sOptVars = "all") then sOptVars = "all"; else sOptVars = sOptVars || " " || sVar; end when (sArg = "--set") then do sShowVarPrefix = "SET "; end when (sArg = "--no-set") then do sShowVarPrefix = ""; end when (sArg = "--value-only") then do fOptValueOnly = 1; end when (sArg = "--name-and-value") then do fOptValueOnly = 0; end when (sArg = "--release") then do fOptOverrideType = 1; fSetType = 1; skBuildType = 'release'; end when (sArg = "--debug") then do fOptOverrideType = 1; fSetType = 1; skBuildType = 'debug'; end when (sArg = "--profile") then do fOptOverrideType = 1; fSetType = 1; skBuildType = 'profile'; end when (sArg = "--defaults") then do fOptOverrideAll = 1; skBuildType = ""; skBuildTarget = ""; skBuildTargetArch = ""; skBuildTargetCpu = ""; skBuildHost = ""; skBuildHostArch = ""; skBuildHostCpu = ""; skBuildPath = ""; skBuildBinPath = ""; end when (sArg = "--help" | sArg = "-h" | sArg = "-?" | sArg = "/?" | sArg = "/h") then do say "kBuild Environment Setup Script, v0.1.4" say "" say "syntax: envos2.cmd [options] [command [args]]" say " or: envos2.cmd [options] --var " say "" say "The first form will execute the command, or if no command is given" say "modify the current invoking shell." say "The second form will print the specfified variable(s)." say "" say "Options:" say " --debug, --release, --profile" say " Alternative way of specifying KBUILD_TYPE." say " --defaults" say " Enforce defaults for all the KBUILD_* values." say " --debug-script, --no-debug-script" say " Controls debug output. Default: --no-debug-script" say " --quiet, --verbose" say " Controls informational output. Default: --verbose" say " --full, --normal" say " Controls the variable set. Default: --normal" say " --legacy, --no-legacy" say " Include legacy variables in result. Default: --no-legacy" say " --value-only, --name-and-value" say " Controls what the result of a --var query. Default: --name-and-value" say " --set, --no-set" say " Whether to prefix the variable output with 'SET'." say " Default: --no-set" say "" exit 1 end when (sArg = "--") then do sArgs = sRest; leave; end when (left(sArg, 2) = '--') then do say 'syntax error: unknown option: '||sArg call SysSleep 1 exit 1 end otherwise do leave end end sArgs = sRest; end sCommand = strip(sArgs); /* * Deal with legacy environment variables. */ if (\fOptOverrideAll) then do if (EnvGet("PATH_KBUILD") <> '') then do if (skBuildPath <> '' & skBuildPath <> EnvGet("PATH_KBUILD")) then do say "error: KBUILD_PATH ("||skBuildPath||") and PATH_KBUILD ("||EnvGet("PATH_KBUILD")||") disagree." call SysSleep 1; exit 1; end skBuildPath = EnvGet("PATH_KBUILD"); end if (EnvGet("PATH_KBUILD_BIN") <> '') then do if (skBuildPath <> '' & skBuildBinPath <> EnvGet("PATH_KBUILD_BIN")) then do say "error: KBUILD_BIN_PATH ("||skBuildBinPath||") and PATH_KBUILD_BIN ("||EnvGet("PATH_KBUILD_BIN")||") disagree." call SysSleep 1; exit 1; end skBuildBinPath = EnvGet("PATH_KBUILD_BIN"); end if (EnvGet("BUILD_TYPE") <> '') then do if (skBuildType <> '' & skBuildType <> EnvGet("BUILD_TYPE")) then do say "error: KBUILD_TYPE ("||skBuildType||") and BUILD_TYPE ("||EnvGet("BUILD_TYPE")||") disagree." call SysSleep 1; exit 1; end skBuildType = EnvGet("BUILD_TYPE"); end if (EnvGet("BUILD_TARGET") <> '') then do if (skBuildTarget <> '' & skBuildTarget <> EnvGet("BUILD_TARGET")) then do say "error: KBUILD_TARGET ("||skBuildTarget||") and BUILD_TARGET ("||EnvGet("BUILD_TARGET")||") disagree." call SysSleep 1; exit 1; end skBuildTarget = EnvGet("BUILD_TARGET"); end if (EnvGet("BUILD_TARGET_ARCH") <> '') then do if (skBuildTargetArch <> '' & skBuildTargetArch <> EnvGet("BUILD_TARGET_ARCH")) then do say "error: KBUILD_TARGET_ARCH ("||skBuildTargetArch ||") and BUILD_TARGET_ARCH ("||EnvGet("BUILD_TARGET_ARCH")||") disagree." call SysSleep 1; exit 1; end skBuildTargetArch = EnvGet("BUILD_TARGET_ARCH"); end if (EnvGet("BUILD_TARGET_CPU") <> '') then do if (skBuildTargetCpu <> '' & skBuildTargetCpu <> EnvGet("BUILD_TARGET_CPU")) then do say "error: KBUILD_TARGET_CPU ("||skBuildTargetCpu ||") and BUILD_TARGET_CPU ("||EnvGet("BUILD_TARGET_CPU")||") disagree." call SysSleep 1; exit 1; end skBuildTargetCpu = EnvGet("BUILD_TARGET_CPU"); end if (EnvGet("BUILD_PLATFORM") <> '') then do if (skBuildHost <> '' & skBuildHost <> EnvGet("BUILD_PLATFORM")) then do say "error: KBUILD_HOST ("||skBuildHost||") and BUILD_PLATFORM ("||EnvGet("BUILD_PLATFORM")||") disagree." call SysSleep 1; exit 1; end if (skBuildHost = '' & EnvGet("BUILD_PLATFORM") = "OS2") then do say "error: BUILD_PLATFORM=OS2! Please unset it or change it to 'os2'." call SysSleep 1; exit 1; end skBuildHost = EnvGet("BUILD_PLATFORM"); end if (EnvGet("BUILD_PLATFORM_ARCH") <> '') then do if (skBuildHostArch <> '' & skBuildHostArch <> EnvGet("BUILD_PLATFORM_ARCH")) then do say "error: KBUILD_HOST_ARCH ("||skBuildHostArch ||") and BUILD_PLATFORM_ARCH ("||EnvGet("BUILD_PLATFORM_ARCH")||") disagree." call SysSleep 1; exit 1; end skBuildHostArch = EnvGet("BUILD_PLATFORM_ARCH"); end if (EnvGet("BUILD_PLATFORM_CPU") <> '') then do if (skBuildHostCpu <> '' & skBuildHostCpu <> EnvGet("BUILD_PLATFORM_CPU")) then do say "error: KBUILD_HOST_CPU ("||skBuildHostCpu ||") and BUILD_PLATFORM_CPU ("||EnvGet("BUILD_PLATFORM_CPU")||") disagree." call SysSleep 1; exit 1; end skBuildHostCpu = EnvGet("BUILD_PLATFORM_CPU"); end end /* * Set default build type. */ if (skBuildType = '') then skBuildType = 'release'; if (fOptDbg <> 0) then say "dbg: KBUILD_TYPE="||skBuildType /* * Determin the host platform (OS/2) */ if (skBuildHost = '') then skBuildHost = 'os2'; if (fOptDbg <> 0) then say "dbg: KBUILD_HOST="||skBuildHost if (skBuildHostArch = '') then do select when (skBuildHostCpu = 'i386', | skBuildHostCpu = 'i486', | skBuildHostCpu = 'i586', | skBuildHostCpu = 'i686', | skBuildHostCpu = 'i786', | skBuildHostCpu = 'i886', | skBuildHostCpu = 'i986') then do skBuildHostArch = "x86"; end otherwise do skBuildHostArch = "x86"; end end end if (fOptDbg <> 0) then say "dbg: KBUILD_HOST_ARCH="||skBuildHostArch if (skBuildHostCpu = '') then skBuildHostCpu = 'blend'; if (fOptDbg <> 0) then say "dbg: KBUILD_HOST_CPU="||skBuildHostCpu /* * The target platform. * Defaults to the host when not specified. */ if (skBuildTarget = '') then skBuildTarget = skBuildHost; if (fOptDbg <> 0) then say "dbg: KBUILD_TARGET="||skBuildTarget if (skBuildTargetArch = '') then skBuildTargetArch = skBuildHostArch; if (fOptDbg <> 0) then say "dbg: KBUILD_TARGET_ARCH="||skBuildTargetArch if (skBuildTargetCpu = '') then do if (skBuildTargetArch = skBuildHostArch) then skBuildTargetCpu = skBuildHostCpu; else skBuildTargetCpu = "blend"; end if (fOptDbg <> 0) then say "dbg: KBUILD_TARGET_CPU="||skBuildTargetCpu /* * Determin KBUILD_PATH from the script location and calc KBUILD_BIN_PATH from there. */ if (skBuildPath = '') then do skBuildPath = GetScriptDir() end skBuildPath = translate(skBuildPath, '/', '\') if ( FileExists(skBuildPath||"/footer.kmk") = 0, | FileExists(skBuildPath||"/header.kmk") = 0, | FileExists(skBuildPath||"/rules.kmk") = 0) then do say "error: KBUILD_PATH ("skBuildPath||") is not pointing to a popluated kBuild directory." call SysSleep 1 exit 1 end if (fOptDbg <> 0) then say "dbg: KBUILD_PATH="||skBuildPath; if (skBuildBinPath = '') then do skBuildBinPath = skBuildPath||'/bin/'||skBuildHost||'.'||skBuildHostArch; end skBuildBinPath = translate(skBuildBinPath, '/', '\') if (fOptDbg <> 0) then say "dbg: KBUILD_BIN_PATH="||skBuildBinPath; /* * Add the bin/x.y/ directory to the PATH and BEGINLIBPATH. * NOTE! Once bootstrapped this is the only thing that is actually necessary. */ sOldPath = EnvGet("PATH"); call EnvAddFront 0, "PATH", translate(skBuildBinPath, '\', '/'); sNewPath = EnvGet("PATH"); call EnvSet 0, "PATH", sOldPath; if (fOptDbg <> 0) then say "dbg: PATH="||sNewPath; sOldBeginLibPath = EnvGet("BEGINLIBPATH"); call EnvAddFront 0, "BEGINLIBPATH", translate(skBuildBinPath, '\', '/'); sNewBeginLibPath = EnvGet("BEGINLIBPATH"); call EnvSet 0, "BEGINLIBPATH", sOldBeginLibPath; if (fOptDbg <> 0) then say "dbg: BEGINLIBPATH="||sNewBeginLibPath; /* * Sanity check */ if (DirExists(skBuildBinPath) = 0) then say "warning: The bin directory for the build platform doesn't exist. ("||skBuildBinPath||")"; else do sPrograms = "kmk kDepPre kDepIDB kmk_append kmk_ash kmk_cat kmk_cp kmk_echo kmk_install kmk_ln kmk_mkdir kmk_mv kmk_redirect kmk_rm kmk_rmdir kmk_sed"; do i = 1 to words(sPrograms) sProgram = word(sPrograms, i); if (FileExists(skBuildBinPath||"\"||sProgram||".exe") = 0) then say "warning: The "||sProgram||" program doesn't exit for this platform. ("||skBuildBinPath||")"; end end /* * The environment is in place, now take the requested action. */ iRc = 0; if (sOptVars <> '') then do if (sOptVars = "all") then sOptVars = "KBUILD_PATH KBUILD_BIN_PATH KBUILD_TYPE ", || "KBUILD_TARGET KBUILD_TARGET_ARCH KBUILD_TARGET_CPU ", || "KBUILD_HOST KBUILD_HOST_ARCH KBUILD_HOST_CPU "; /* Echo variable values or variable export statements. */ do i = 1 to words(sOptVars) sVar = word(sOptVars, i) sVal = ''; select when (sVar = "PATH") then sVal = sNewPath; when (sVar = "BEGINLIBPATH") then sVal = sNewBeginLibPath; when (sVar = "KBUILD_PATH") then sVal = skBuildPath; when (sVar = "KBUILD_BIN_PATH") then sVal = skBuildBinPath; when (sVar = "KBUILD_TYPE") then sVal = skBuildType; when (sVar = "KBUILD_HOST") then sVal = skBuildHost; when (sVar = "KBUILD_HOST_ARCH") then sVal = skBuildHostArch; when (sVar = "KBUILD_HOST_CPU") then sVal = skBuildHostCpu; when (sVar = "KBUILD_TARGET") then sVal = skBuildTarget; when (sVar = "KBUILD_TARGET_ARCH") then sVal = skBuildTargetArch; when (sVar = "KBUILD_TARGET_CPU") then sVal = skBuildTargetCpu; otherwise do say "error: Unknown variable "||sVar||" specified in --var request." call SysSleep 1 exit 1 end end if (fOptValueOnly <> 0) then say sVal else say sShowVarPrefix||sVar||"="||sVal; end end else do /* Wipe out all variables - legacy included - with --default. */ if (fOptOverrideAll <> 0) then do call EnvSet 0, KBUILD_PATH, '' call EnvSet 0, KBUILD_BIN_PATH, '' call EnvSet 0, KBUILD_HOST, '' call EnvSet 0, KBUILD_HOST_ARCH, '' call EnvSet 0, KBUILD_HOST_CPU, '' call EnvSet 0, KBUILD_TARGET, '' call EnvSet 0, KBUILD_TARGET_ARCH, '' call EnvSet 0, KBUILD_TARGET_CPU, '' call EnvSet 0, PATH_KBUILD, '' call EnvSet 0, PATH_KBUILD_BIN, '' call EnvSet 0, BUILD_PLATFORM, '' call EnvSet 0, BUILD_PLATFORM_ARCH, '' call EnvSet 0, BUILD_PLATFORM_CPU, '' call EnvSet 0, BUILD_TARGET, '' call EnvSet 0, BUILD_TARGET_ARCH, '' call EnvSet 0, BUILD_TARGET_CPU, '' end /* Export the variables. */ call EnvSet 0, "PATH", sNewPath call EnvSet 0, "BEGINLIBPATH", sNewBeginLibPath if (fOptOverrideType <> 0) then call EnvSet 0, "KBUILD_TYPE", skBuildType if (fOptFull <> 0) then do call EnvSet 0, KBUILD_PATH, skBuildPath call EnvSet 0, KBUILD_HOST, skBuildHost call EnvSet 0, KBUILD_HOST_ARCH, skBuildHostArch call EnvSet 0, KBUILD_HOST_CPU, skBuildHostCpu call EnvSet 0, KBUILD_TARGET, skBuildTarget call EnvSet 0, KBUILD_TARGET_ARCH, skBuildTargetArch call EnvSet 0, KBUILD_TARGET_CPU, skBuildTargetCpu if (fOptLegacy <> 0) then do call EnvSet 0, PATH_KBUILD, skBuildPath call EnvSet 0, BUILD_PLATFORM, skBuildHost call EnvSet 0, BUILD_PLATFORM_ARCH, skBuildHostArch call EnvSet 0, BUILD_PLATFORM_CPU, skBuildHostCpu call EnvSet 0, BUILD_TARGET, skBuildTarget call EnvSet 0, BUILD_TARGET_ARCH, skBuildTargetArch call EnvSet 0, BUILD_TARGET_CPU, skBuildTargetCpu end end /* * Execute left over arguments. */ if (strip(sCommand) <> '') then do if (fOptQuiet <> 0) then say "info: Executing command: "|| sCommand address CMD sCommand iRc = rc; if (fOptQuiet <> 0 & iRc <> 0) then say "info: rc="||iRc||": "|| sCommand end end if (fOptDbg <> 0) then say "dbg: finished (rc="||rc||")" exit (iRc); /******************************************************************************* * Procedure Section * *******************************************************************************/ /** * Give the script syntax */ syntax: procedure say 'syntax: envos2.cmd [command to be executed and its arguments]' say '' return 0; /** * No value handler */ NoValueHandler: say 'NoValueHandler: line 'SIGL; exit(16); /** * Add sToAdd in front of sEnvVar. * Note: sToAdd now is allowed to be alist! * * Known features: Don't remove sToAdd from original value if sToAdd * is at the end and don't end with a ';'. */ EnvAddFront: procedure parse arg fRM, sEnvVar, sToAdd, sSeparator /* sets default separator if not specified. */ if (sSeparator = '') then sSeparator = ';'; /* checks that sToAdd ends with an ';'. Adds one if not. */ if (substr(sToAdd, length(sToAdd), 1) <> sSeparator) then sToAdd = sToAdd || sSeparator; /* check and evt. remove ';' at start of sToAdd */ if (substr(sToAdd, 1, 1) = ';') then sToAdd = substr(sToAdd, 2); /* loop thru sToAdd */ rc = 0; i = length(sToAdd); do while i > 1 & rc = 0 j = lastpos(sSeparator, sToAdd, i-1); rc = EnvAddFront2(fRM, sEnvVar, substr(sToAdd, j+1, i - j), sSeparator); i = j; end return rc; /** * Add sToAdd in front of sEnvVar. * * Known features: Don't remove sToAdd from original value if sToAdd * is at the end and don't end with a ';'. */ EnvAddFront2: procedure parse arg fRM, sEnvVar, sToAdd, sSeparator /* sets default separator if not specified. */ if (sSeparator = '') then sSeparator = ';'; /* checks that sToAdd ends with a separator. Adds one if not. */ if (substr(sToAdd, length(sToAdd), 1) <> sSeparator) then sToAdd = sToAdd || sSeparator; /* check and evt. remove the separator at start of sToAdd */ if (substr(sToAdd, 1, 1) = sSeparator) then sToAdd = substr(sToAdd, 2); /* Get original variable value */ sOrgEnvVar = EnvGet(sEnvVar); /* Remove previously sToAdd if exists. (Changing sOrgEnvVar). */ i = pos(translate(sToAdd), translate(sOrgEnvVar)); if (i > 0) then sOrgEnvVar = substr(sOrgEnvVar, 1, i-1) || substr(sOrgEnvVar, i + length(sToAdd)); /* set environment */ if (fRM) then return EnvSet(0, sEnvVar, sOrgEnvVar); return EnvSet(0, sEnvVar, sToAdd||sOrgEnvVar); /** * Add sToAdd as the end of sEnvVar. * Note: sToAdd now is allowed to be alist! * * Known features: Don't remove sToAdd from original value if sToAdd * is at the end and don't end with a ';'. */ EnvAddEnd: procedure parse arg fRM, sEnvVar, sToAdd, sSeparator /* sets default separator if not specified. */ if (sSeparator = '') then sSeparator = ';'; /* checks that sToAdd ends with a separator. Adds one if not. */ if (substr(sToAdd, length(sToAdd), 1) <> sSeparator) then sToAdd = sToAdd || sSeparator; /* check and evt. remove ';' at start of sToAdd */ if (substr(sToAdd, 1, 1) = sSeparator) then sToAdd = substr(sToAdd, 2); /* loop thru sToAdd */ rc = 0; i = length(sToAdd); do while i > 1 & rc = 0 j = lastpos(sSeparator, sToAdd, i-1); rc = EnvAddEnd2(fRM, sEnvVar, substr(sToAdd, j+1, i - j), sSeparator); i = j; end return rc; /** * Add sToAdd as the end of sEnvVar. * * Known features: Don't remove sToAdd from original value if sToAdd * is at the end and don't end with a ';'. */ EnvAddEnd2: procedure parse arg fRM, sEnvVar, sToAdd, sSeparator /* sets default separator if not specified. */ if (sSeparator = '') then sSeparator = ';'; /* checks that sToAdd ends with a separator. Adds one if not. */ if (substr(sToAdd, length(sToAdd), 1) <> sSeparator) then sToAdd = sToAdd || sSeparator; /* check and evt. remove separator at start of sToAdd */ if (substr(sToAdd, 1, 1) = sSeparator) then sToAdd = substr(sToAdd, 2); /* Get original variable value */ sOrgEnvVar = EnvGet(sEnvVar); if (sOrgEnvVar <> '') then do /* Remove previously sToAdd if exists. (Changing sOrgEnvVar). */ i = pos(translate(sToAdd), translate(sOrgEnvVar)); if (i > 0) then sOrgEnvVar = substr(sOrgEnvVar, 1, i-1) || substr(sOrgEnvVar, i + length(sToAdd)); /* checks that sOrgEnvVar ends with a separator. Adds one if not. */ if (sOrgEnvVar = '') then if (right(sOrgEnvVar,1) <> sSeparator) then sOrgEnvVar = sOrgEnvVar || sSeparator; end /* set environment */ if (fRM) then return EnvSet(0, sEnvVar, sOrgEnvVar); return EnvSet(0, sEnvVar, sOrgEnvVar||sToAdd); /** * Sets sEnvVar to sValue. */ EnvSet: procedure parse arg fRM, sEnvVar, sValue /* if we're to remove this, make valuestring empty! */ if (fRM) then sValue = ''; sEnvVar = translate(sEnvVar); /* * Begin/EndLibpath fix: * We'll have to set internal these using both commandline 'SET' * and internal VALUE in order to export it and to be able to * get it (with EnvGet) again. */ if ((sEnvVar = 'BEGINLIBPATH') | (sEnvVar = 'ENDLIBPATH')) then do if (length(sValue) >= 1024) then say 'Warning: 'sEnvVar' is too long,' length(sValue)' char.'; return SysSetExtLibPath(sValue, substr(sEnvVar, 1, 1)); end if (length(sValue) >= 1024) then do say 'Warning: 'sEnvVar' is too long,' length(sValue)' char.'; say ' This may make CMD.EXE unstable after a SET operation to print the environment.'; end sRc = VALUE(sEnvVar, sValue, 'OS2ENVIRONMENT'); return 0; /** * Gets the value of sEnvVar. */ EnvGet: procedure parse arg sEnvVar if ((translate(sEnvVar) = 'BEGINLIBPATH') | (translate(sEnvVar) = 'ENDLIBPATH')) then return SysQueryExtLibPath(substr(sEnvVar, 1, 1)); return value(sEnvVar,, 'OS2ENVIRONMENT'); /** * Checks if a file exists. * @param sFile Name of the file to look for. * @param sComplain Complaint text. Complain if non empty and not found. * @returns TRUE if file exists. * FALSE if file doesn't exists. */ FileExists: procedure parse arg sFile, sComplain rc = stream(sFile, 'c', 'query exist'); if ((rc = '') & (sComplain <> '')) then say sComplain ''''sFile'''.'; return rc <> ''; /** * Checks if a directory exists. * @param sDir Name of the directory to look for. * @param sComplain Complaint text. Complain if non empty and not found. * @returns TRUE if file exists. * FALSE if file doesn't exists. */ DirExists: procedure parse arg sDir, sComplain rc = SysFileTree(sDir, 'sDirs', 'DO'); if (rc = 0 & sDirs.0 = 1) then return 1; if (sComplain <> '') then say sComplain ''''sDir'''.'; return 0; /** * Workaround for bug in CMD.EXE. * It messes up when REXX have expanded the environment. */ FixCMDEnv: procedure /* do this anyway /* check for 4OS2 first */ Address CMD 'set 4os2test_env=%@eval[2 + 2]'; if (value('4os2test_env',, 'OS2ENVIRONMENT') = '4') then return 0; */ /* force environment expansion by setting a lot of variables and freeing them. * ~6600 (bytes) */ do i = 1 to 100 Address CMD '@set dummyenvvar'||i'=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; end do i = 1 to 100 Address CMD '@set dummyenvvar'||i'='; end return 0; /** * Translate a string to lower case. */ ToLower: procedure parse arg sString return translate(sString, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'); /** * Gets the script directory. */ GetScriptDir: procedure /* * Assuming this script is in the root directory, we can determing * the abs path to it by using the 'parse source' feature in rexx. */ parse source . . sScript sScriptDir = filespec('drive', sScript) || strip(filespec('path', sScript), 'T', '\'); return ToLower(sScriptDir); kbuild-3149/kBuild/footer-pass1.kmk0000644000175000017500000003522113252530251017146 0ustar locutuslocutus# $Id: footer-pass1.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild - Footer - Target lists - Pass 1. # # This pass is for defining variables that might be referenced in # properties of other targets. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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 source of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # # Don't do anything for fetch targets (yet). ## # Link prolog for Pass 1. # # @param $(target) Normalized target name. # @param $(EXT) EXE,DLL,SYS,LIB. # @param $(EXTPRE) HOST or nothing. # @param $(definst) The default _INST value. # @param $(tool_prefix) LD or AR. # @param $(bld_trg_base_var) TARGET or PLATFORM. define def_pass1_link_common local bld_type := $(firstword $($(target)_BLD_TYPE) $(KBUILD_TYPE)) local bld_trg := $(firstword $($(target)_BLD_TRG) $(BUILD_$(bld_trg_base_var))) local bld_trg_arch:= $(firstword $($(target)_BLD_TRG_ARCH) $(BUILD_$(bld_trg_base_var)_ARCH)) local bld_trg_cpu := $(firstword $($(target)_BLD_TRG_CPU) $(BUILD_$(bld_trg_base_var)_CPU)) local tool := $(call _TARGET_TOOL,$(target),$(tool_prefix)) local name := $(firstword\ $($(target)_NAME.$(bld_trg).$(bld_trg_arch).$(bld_type))\ $($(target)_NAME.$(bld_trg).$(bld_trg_arch))\ $($(target)_NAME.$(bld_trg).$(bld_type))\ $($(target)_NAME.$(bld_trg_arch))\ $($(target)_NAME.$(bld_trg))\ $($(target)_NAME.$(bld_type))\ $($(target)_NAME)\ $(target)) local outbase := $(call TARGET_BASE,$(name),$(target)) $(target)_0_OUTDIR:= $(patsubst %/,%,$(dir $(outbase))) $(call KB_FN_ASSIGN_DEPRECATED,PATH_$(target),$($(target)_0_OUTDIR), $(target)_0_OUTDIR) ## @todo fix the fun at the last line (AR != LIB => mess). local suff := $(firstword \ $($(target)_$(EXT)SUFF.$(bld_trg).$(bld_trg_arch))\ $($(target)_$(EXT)SUFF.$(bld_trg))\ $($(target)_$(EXT)SUFF)\ $(TOOL_$(tool)_$(tool_prefix)$(EXT)SUFF.$(bld_trg).$(bld_trg_arch))\ $(TOOL_$(tool)_$(tool_prefix)$(EXT)SUFF.$(bld_trg))\ $(TOOL_$(tool)_$(tool_prefix)$(EXT)SUFF)\ $(if $(eq $(tool_prefix),AR),$(SUFF_LIB),$($(EXTPRE)SUFF_$(EXT))) ) local out := $(outbase)$(suff) # Object directory target variable. $(target)_1_TARGET := $(out) $(call KB_FN_ASSIGN_DEPRECATED,TARGET_$(target),$($(target)_1_TARGET), $(target)_1_TARGET) # Staging and install directory target variables. local insttype := $(firstword \ $($(target)_INSTTYPE.$(bld_trg).$(bld_trg_arch).$(bld_type)) \ $($(target)_INSTTYPE.$(bld_trg).$(bld_trg_arch)) \ $($(target)_INSTTYPE.$(bld_trg).$(bld_type)) \ $($(target)_INSTTYPE.$(bld_trg_arch)) \ $($(target)_INSTTYPE.$(bld_trg_cpu)) \ $($(target)_INSTTYPE.$(bld_trg)) \ $($(target)_INSTTYPE.$(bld_type)) \ $($(target)_INSTTYPE) \ ) ifeq ($(insttype),) ifneq ($(firstword \ $($(target)_NOINST) \ $($(target)_NOINST.$(bld_trg)) \ $($(target)_NOINST.$(bld_trg).$(bld_trg_arch)) \ $($(target)_NOINST.$(bld_trg).$(bld_trg_arch).$(bld_type)) \ $($(target)_NOINST.$(bld_trg_arch)) \ $($(target)_NOINST.$(bld_trg_cpu)) \ $($(target)_NOINST.$(bld_type)) ),) local insttype := none else local insttype := both endif endif $(target)_1_INSTTYPE := $(insttype) local inst := $(strip $(firstdefined \ $(target)_INST.$(bld_trg).$(bld_trg_arch).$(bld_type) \ $(target)_INST.$(bld_trg).$(bld_trg_arch) \ $(target)_INST.$(bld_trg).$(bld_type) \ $(target)_INST.$(bld_trg_arch) \ $(target)_INST.$(bld_trg_cpu) \ $(target)_INST.$(bld_trg) \ $(target)_INST.$(bld_type) \ $(target)_INST \ definst \ ,value)) local stage := $(strip $(firstdefined \ $(target)_STAGE.$(bld_trg).$(bld_trg_arch).$(bld_type) \ $(target)_STAGE.$(bld_trg).$(bld_trg_arch) \ $(target)_STAGE.$(bld_trg).$(bld_type) \ $(target)_STAGE.$(bld_trg_arch) \ $(target)_STAGE.$(bld_trg_cpu) \ $(target)_STAGE.$(bld_trg) \ $(target)_STAGE.$(bld_type) \ $(target)_STAGE \ inst \ ,value)) if1of ($(insttype), stage both) $(target)_1_STAGE := $(stage) if "$(substr $(stage),-1,1)" == "/" # Multicast support requires addprefix/suffix. $(target)_1_STAGE_TARGET := $(addprefix $(PATH_STAGE)/,$(addsuffix $(notdir $(out)),$(stage))) else if "$(stage)" == "" $(target)_1_STAGE_TARGET := $(PATH_STAGE)/$(notdir $(out)) else $(target)_1_STAGE_TARGET := $(addprefix $(PATH_STAGE)/,$(stage)) endif else if1of ($(insttype), none) $(target)_1_STAGE := $(target)_1_STAGE_TARGET := else $(error kBuild: Unknown value '$(insttype)' for '$(target)_INSTTYPE'. Valid values are 'none', 'both' and 'stage'.) endif INSTARGET_$(target) := $($(target)_1_STAGE_TARGET) if1of ($(insttype), both) $(target)_1_INST := $(inst) if "$(substr $(inst),-1,1)" == "/" # Multicast support requires addprefix/suffix. $(target)_1_INST_TARGET := $(addprefix $(PATH_INS)/,$(addsuffix $(notdir $(out)),$(inst))) else if "$(inst)" == "" $(target)_1_INST_TARGET := $(PATH_INS)/$(notdir $(out)) else $(target)_1_INST_TARGET := $(addprefix $(PATH_INS)/,$(inst)) endif else $(target)_1_INST := $(target)_1_INST_TARGET := endif # Debug info related stuff. local debug_insttype := $(firstword \ $($(target)_DEBUG_INSTTYPE.$(bld_trg).$(bld_trg_arch).$(bld_type)) \ $($(target)_DEBUG_INSTTYPE.$(bld_trg).$(bld_trg_arch)) \ $($(target)_DEBUG_INSTTYPE.$(bld_trg).$(bld_type)) \ $($(target)_DEBUG_INSTTYPE.$(bld_trg_arch)) \ $($(target)_DEBUG_INSTTYPE.$(bld_trg_cpu)) \ $($(target)_DEBUG_INSTTYPE.$(bld_trg)) \ $($(target)_DEBUG_INSTTYPE.$(bld_type)) \ $($(target)_DEBUG_INSTTYPE) \ $(insttype) ) $(target)_1_DEBUG_INSTTYPE := $(debug_insttype) if1of ($(debug_insttype), stage both) local debug_stage := $(firstdefined \ $(target)_DEBUG_STAGE.$(bld_trg).$(bld_trg_arch).$(bld_type) \ $(target)_DEBUG_STAGE.$(bld_trg).$(bld_trg_arch) \ $(target)_DEBUG_STAGE.$(bld_trg).$(bld_type) \ $(target)_DEBUG_STAGE.$(bld_trg_arch) \ $(target)_DEBUG_STAGE.$(bld_trg_cpu) \ $(target)_DEBUG_STAGE.$(bld_trg) \ $(target)_DEBUG_STAGE.$(bld_type) \ $(target)_DEBUG_STAGE \ $(target)_DEBUG_INST.$(bld_trg).$(bld_trg_arch).$(bld_type) \ $(target)_DEBUG_INST.$(bld_trg).$(bld_trg_arch) \ $(target)_DEBUG_INST.$(bld_trg).$(bld_type) \ $(target)_DEBUG_INST.$(bld_trg_arch) \ $(target)_DEBUG_INST.$(bld_trg_cpu) \ $(target)_DEBUG_INST.$(bld_trg) \ $(target)_DEBUG_INST.$(bld_type) \ $(target)_DEBUG_INST) ifneq ($(debug_stage),) $(target)_1_DEBUG_STAGE := $($(debug_stage)) else $(target)_1_DEBUG_STAGE := $(addprefix $(STAGE_DEBUG),$(stage)) endif ifndef $(target)_1_DEBUG_STAGE $(target)_1_DEBUG_STAGE := ./ endif else if1of ($(debug_insttype), none) $(target)_1_DEBUG_STAGE := else $(error kBuild: Unknown value '$(debug_insttype)' for '$(target)_DEBUG_INSTTYPE'. Valid values are 'none', 'both' and 'stage'.) endif if1of ($(debug_insttype), both) local debug_inst := $(firstdefined \ $(target)_DEBUG_INST.$(bld_trg).$(bld_trg_arch).$(bld_type) \ $(target)_DEBUG_INST.$(bld_trg).$(bld_trg_arch) \ $(target)_DEBUG_INST.$(bld_trg).$(bld_type) \ $(target)_DEBUG_INST.$(bld_trg_arch) \ $(target)_DEBUG_INST.$(bld_trg_cpu) \ $(target)_DEBUG_INST.$(bld_trg) \ $(target)_DEBUG_INST.$(bld_type) \ $(target)_DEBUG_INST) ifneq ($(debug_inst),) $(target)_1_DEBUG_INST := $($(debug_inst)) else $(target)_1_DEBUG_INST := $(addprefix $(INST_DEBUG),$(inst)) endif ifndef $(target)_1_DEBUG_INST $(target)_1_DEBUG_INST := ./ endif else $(target)_1_DEBUG_INST := endif #$(warning $(NLTAB)$(target)_1_DEBUG_INST=$($(target)_1_DEBUG_INST)$(NLTAB)$(target)_1_DEBUG_STAGE=$($(target)_1_DEBUG_STAGE)$(NLTAB)insttype=$(insttype)$(NLTAB)debug_insttype=$(debug_insttype)) endef # def_pass1_link_common $(eval-opt-var def_pass1_link_common) # # BLDPROGS (Pass 1) # define def_pass1_bldprog # set NOINST if not forced installation before doing the usual stuff. ifndef $(target)_INST $(target)_INSTTYPE := none endif $(evalvalctx def_pass1_link_common) endef EXT := EXE EXTPRE := HOST definst := $(INST_BIN) tool_prefix := LD bld_trg_base_var := PLATFORM $(foreach target, $(_ALL_BLDPROGS), \ $(evalvalctx def_pass1_bldprog)) # # LIBRARIES (Pass 1) # EXT := LIB EXTPRE := definst := $(INST_LIB) tool_prefix := AR bld_trg_base_var := TARGET $(foreach target, $(_ALL_LIBRARIES), \ $(evalvalctx def_pass1_link_common)) # # DLLS (Pass 1) # EXT := DLL EXTPRE := definst := $(INST_DLL) tool_prefix := LD bld_trg_base_var := TARGET $(foreach target, $(_ALL_DLLS), \ $(evalvalctx def_pass1_link_common)) # # IMPORT LIBRARIES (Pass 1) # # - On OS/2 and windows these are libraries. # - On other platforms they are fake DLLs. # if1of ($(KBUILD_TARGET), nt os2 win win64 win32) EXT := LIB EXTPRE := definst := $(INST_LIB) tool_prefix := AR bld_trg_base_var := TARGET $(foreach target, $(_ALL_IMPORT_LIBS), \ $(evalvalctx def_pass1_link_common)) else EXT := DLL EXTPRE := definst := $(INST_DLL) tool_prefix := LD bld_trg_base_var := TARGET $(foreach target, $(_ALL_IMPORT_LIBS), \ $(evalvalctx def_pass1_link_common)) endif # # PROGRAMS (Pass 1) # EXT := EXE EXTPRE := definst := $(INST_BIN) tool_prefix := LD bld_trg_base_var := TARGET $(foreach target, $(_ALL_PROGRAMS), \ $(evalvalctx def_pass1_link_common)) # # SYSMODS (Pass 1) # EXT := SYS EXTPRE := definst := $(INST_SYS) tool_prefix := LD bld_trg_base_var := TARGET $(foreach target, $(_ALL_SYSMODS), \ $(evalvalctx def_pass1_link_common)) # # MISCBINS (Pass 1) # EXT := BIN EXTPRE := definst := $(INST_BIN) tool_prefix := LD bld_trg_base_var := TARGET $(foreach target, $(_ALL_MISCBINS), \ $(evalvalctx def_pass1_link_common)) # # INSTALLS (Pass 1) # Note! INSTARGET_* for INSTALLS aren't available until later. # define def_pass1_install local bld_type := $(firstword $($(target)_BLD_TYPE) $(KBUILD_TYPE)) local bld_trg := $(firstword $($(target)_BLD_TRG) $(KBUILD_TARGET)) local bld_trg_arch := $(firstword $($(target)_BLD_TRG_ARCH) $(KBUILD_TARGET_ARCH)) local bld_trg_cpu := $(firstword $($(target)_BLD_TRG_CPU) $(KBUILD_TARGET_CPU)) # _1_TARGET $(target)_1_TARGET := $(PATH_TARGET)/$(target).ins $(call KB_FN_ASSIGN_DEPRECATED,TARGET_$(target),$($(target)_1_TARGET), $(target)_1_TARGET) # Determine and set 1_INSTTYPE. local insttype := $(firstword \ $($(target)_INSTTYPE.$(bld_trg).$(bld_trg_arch).$(bld_type)) \ $($(target)_INSTTYPE.$(bld_trg).$(bld_trg_arch)) \ $($(target)_INSTTYPE.$(bld_trg).$(bld_type)) \ $($(target)_INSTTYPE.$(bld_trg_arch)) \ $($(target)_INSTTYPE.$(bld_trg_cpu)) \ $($(target)_INSTTYPE.$(bld_trg)) \ $($(target)_INSTTYPE.$(bld_type)) \ $($(target)_INSTTYPE) \ ) ifeq ($(insttype),) ifneq ($(firstword \ $($(target)_NOINST) \ $($(target)_NOINST.$(bld_trg)) \ $($(target)_NOINST.$(bld_trg).$(bld_trg_arch)) \ $($(target)_NOINST.$(bld_trg).$(bld_trg_arch).$(bld_type)) \ $($(target)_NOINST.$(bld_trg_arch)) \ $($(target)_NOINST.$(bld_trg_cpu)) \ $($(target)_NOINST.$(bld_type)) ),) local insttype := none else local insttype := both endif endif ifn1of ($(insttype), none both stage) $(error kBuild: Unknown value '$(insttype)' for '$(target)_INSTTYPE'. Valid values are 'none', 'both' and 'stage'.) endif $(target)_1_INSTTYPE := $(insttype) # Determine the actual INST and STAGE sub-dirs to use for this target. if1of ($(insttype), stage both) local stage := $(strip $(firstdefined \ $(target)_STAGE.$(bld_trg).$(bld_trg_arch).$(bld_type) \ $(target)_STAGE.$(bld_trg).$(bld_trg_arch) \ $(target)_STAGE.$(bld_trg).$(bld_type) \ $(target)_STAGE.$(bld_trg_arch) \ $(target)_STAGE.$(bld_trg_cpu) \ $(target)_STAGE.$(bld_trg) \ $(target)_STAGE.$(bld_type) \ $(target)_STAGE \ $(target)_INST.$(bld_trg).$(bld_trg_arch).$(bld_type) \ $(target)_INST.$(bld_trg).$(bld_trg_arch) \ $(target)_INST.$(bld_trg).$(bld_type) \ $(target)_INST.$(bld_trg_arch) \ $(target)_INST.$(bld_trg_cpu) \ $(target)_INST.$(bld_trg) \ $(target)_INST.$(bld_type) \ $(target)_INST \ definst \ ,value)) if $(words $(stage)) > 1 $(warning kBuild: The STAGE/INST property of install '$(target)' specifies multiple location, that is not supported.) local stage := $(word 1, $(stage)) endif $(target)_1_STAGE := $(stage) else $(target)_1_STAGE = $(error _1_STAGE not used) endif if1of ($(insttype), both) local inst := $(strip $(firstdefined \ $(target)_INST.$(bld_trg).$(bld_trg_arch).$(bld_type) \ $(target)_INST.$(bld_trg).$(bld_trg_arch) \ $(target)_INST.$(bld_trg).$(bld_type) \ $(target)_INST.$(bld_trg_arch) \ $(target)_INST.$(bld_trg_cpu) \ $(target)_INST.$(bld_trg) \ $(target)_INST.$(bld_type) \ $(target)_INST \ definst \ ,value)) if $(words $(inst)) > 1 $(warning kBuild: The INST property of install '$(target)' specifies multiple location, that is not supported.) local inst := $(word 1, $(inst)) endif ifneq ($(root $(stage)),) $(error kBuild: The effective INST property of install '$(target)' should not start with a root specification) endif $(target)_1_INST := $(inst) else $(target)_1_INST = $(error _1_INST not used) endif # Block properties that we put off setting until pass 2 for INSTALLS. $(target)_1_STAGE_TARGET = $(error The '_1_STAGE_TARGET' property is not present on install targets. Use '_2_STAGE_TARGETS' instead (set by pass 2!).) $(target)_1_INST_TARGET = $(error The '_1_INST_TARGET' property is not present on install targets. Use '_2_INST_TARGETS' instead (set by pass 2!).) INSTARGET_$(target) = $(error The 'INSTARGET_' is deprecated and besides, it is being accessed to early. Consider '_2_STAGE_TARGETS' or '_2_INST_TARGETS'.) # INSTARGET_ later. # PATH_* local outbase := $(call TARGET_BASE,$(target),$(target)) $(target)_0_OUTDIR := $(patsubst %/,%,$(dir $(outbase))) $(call KB_FN_ASSIGN_DEPRECATED,PATH_$(target),$($(target)_0_OUTDIR), $(target)_0_OUTDIR) endef # def_pass1_install $(eval-opt-var def_pass1_install) $(foreach target, $(_ALL_INSTALLS), \ $(evalvalctx def_pass1_install)) ifdef KBUILD_PROFILE_SELF $(evalcall def_profile_self, done pass 1) endif kbuild-3149/kBuild/footer-passes.kmk0000644000175000017500000002440013252530251017412 0ustar locutuslocutus# $Id: footer-passes.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild - Footer - Target lists - Pass 2 - Passes. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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 source of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # # # PASSES (including directory and makefile walking) # # # First, check whether we need to order the passes explicitly or not. # This depends on whether we're a leaf makefile or not. A leaf will # know all its dependencies, while a recursive one relies on the # order sub-directories and other makefiles are executed it. # ## Setup a pass and check for optimizations. # @param $(PASS) Uppercase pass name. define def_pass_setup_and_optimize # The setup. ## @todo This is looks a bit weird... ifndef SUBDIRS_$(PASS) SUBDIRS_$(PASS) := $(SUBDIRS) $(SUBDIRS.$(KBUILD_TARGET)) $(SUBDIRS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) endif ifndef SUBDIRS_AFTER_$(PASS) SUBDIRS_AFTER_$(PASS) := $(SUBDIRS_AFTER) $(SUBDIRS_AFTER.$(KBUILD_TARGET)) $(SUBDIRS_AFTER.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) endif ifndef MAKEFILES_BEFORE_$(PASS) MAKEFILES_BEFORE_$(PASS) := $(MAKEFILES_BEFORE) $(MAKEFILES_BEFORE.$(KBUILD_TARGET)) $(MAKEFILES_BEFORE.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) endif ifndef MAKEFILES_AFTER_$(PASS) MAKEFILES_AFTER_$(PASS) := $(MAKEFILES_AFTER) $(MAKEFILES_AFTER.$(KBUILD_TARGET)) $(MAKEFILES_AFTER.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) endif # The check. ifeq ($(_KBUILD_STRICT_PASS_ORDER),nonstrict) ifneq ($(strip \ $(SUBDIRS_$(PASS)) $(SUBDIRS_$(PASS).$(KBUILD_TARGET)) $(SUBDIRS_$(PASS).$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) \ $(MAKEFILES_BEFORE_$(PASS)) $(MAKEFILES_BEFORE_$(PASS).$(KBUILD_TARGET)) $(MAKEFILES_BEFORE_$(PASS).$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) \ $(SUBDIRS_AFTER_$(PASS)) $(SUBDIRS_AFTER_$(PASS).$(KBUILD_TARGET)) $(SUBDIRS_AFTER_$(PASS).$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) \ $(MAKEFILES_AFTER_$(PASS)) $(MAKEFILES_AFTER_$(PASS).$(KBUILD_TARGET)) $(MAKEFILES_AFTER_$(PASS).$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) \ ),) _KBUILD_STRICT_PASS_ORDER := strict endif endif # _KBUILD_STRICT_PASS_ORDER == nonstrict endef # def_pass_setup_and_optimize $(eval-opt-var def_pass_setup_and_optimize) ## PASS: Setup & optimization. # Check if we can apply the non-strict pass order optimzation (no SUBDIRS_* and MAKEFILES_*), # and set up the pass specific variables as we go along. _KBUILD_STRICT_PASS_ORDER := nonstrict $(foreach PASS, $(PASSES), $(evalval def_pass_setup_and_optimize)) #$ (error _KBUILD_STRICT_PASS_ORDER=$(_KBUILD_STRICT_PASS_ORDER)) ifeq ($(_KBUILD_STRICT_PASS_ORDER),strict) if !defined(KBUILD_SAFE_PARALLEL) || "$(KMK_OPT_JOBS)" == "1" _KBUILD_STRICT_PASS_ORDER := strict_unsafe endif endif ## Subdir # @param $(pass) Lowercase pass name. # @param $(PASS) Uppercase pass name. # @param $(subdir) Subdirectory # @param $(tag) tag to attach to the rule name. define def_pass_subdir pass_$(pass)$(tag):: $(dep) + $$(QUIET)$$(MAKE) -C $(subdir) -f $$(notdir $$(firstword $$(wildcard $$(addprefix $(subdir)/,$$(DEFAULT_MAKEFILE))))) pass_$(pass) endef ## Submakefile # @param $(pass) Lowercase pass name. # @param $(PASS) Uppercase pass name. # @param $(makefile) Makefile. # @param $(tag) tag to attach to the rule name. define def_pass_makefile pass_$(pass)$(tag):: $(dep) + $$(QUIET)$$(MAKE) -C $(patsubst %/,%,$(dir $(makefile))) -f $(notdir $(makefile)) pass_$(pass) endef ## Execute a pass, strict order. # @param $(pass) Lowercase pass name. # @param $(PASS) Uppercase pass name. define def_pass_strict $(eval tag:=_before) $(eval dep:= ) $(foreach subdir, $(SUBDIRS_$(PASS)) $(SUBDIRS_$(PASS).$(KBUILD_TARGET)) $(SUBDIRS_$(PASS).$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) ,$(eval $(def_pass_subdir))) $(foreach makefile,$(MAKEFILES_BEFORE_$(PASS)) $(MAKEFILES_BEFORE_$(PASS).$(KBUILD_TARGET)) $(MAKEFILES_BEFORE_$(PASS).$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)),$(eval $(def_pass_makefile))) $(eval tag:=_after) $(eval dep:=pass_$(pass)_doit) $(foreach subdir, $(SUBDIRS_AFTER_$(PASS)) $(SUBDIRS_AFTER_$(PASS).$(KBUILD_TARGET)) $(SUBDIRS_AFTER_$(PASS).$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) ,$(eval $(def_pass_subdir))) $(foreach makefile,$(MAKEFILES_AFTER_$(PASS)) $(MAKEFILES_AFTER_$(PASS).$(KBUILD_TARGET)) $(MAKEFILES_AFTER_$(PASS).$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) ,$(eval $(def_pass_makefile))) .NOTPARALLEL: pass_$(pass) pass_$(pass)_before pass_$(pass)_after pass_$(pass)_this .PHONY: pass_$(pass) pass_$(pass)_before pass_$(pass)_after pass_$(pass)_this pass_$(pass)_doit pass_$(pass)_doit: $(PASS_$(PASS)_trgs) $(foreach var,$(PASS_$(PASS)_vars),$($(var))) pass_$(pass)_this: pass_$(pass)_before + $$(QUIET)$$(MAKE) -f $$(MAKEFILE) pass_$(pass)_doit pass_$(pass)_after:: pass_$(pass)_this pass_$(pass): pass_$(pass)_after #$ (warning pass=$(pass) PASS=$(PASS): $(PASS_$(PASS)_trgs) $(PASS_$(PASS)_trgs) $(foreach var,$(PASS_$(PASS)_vars),$($(var)))) endef # def_pass_strict $(eval-opt-var def_pass_strict) ## Execute a pass, strict order. # @param $(pass) Lowercase pass name. # @param $(PASS) Uppercase pass name. define def_pass_strict_unsafe $(eval tag:=_before) $(eval dep:= ) $(foreach subdir, $(SUBDIRS_$(PASS)) $(SUBDIRS_$(PASS).$(KBUILD_TARGET)) $(SUBDIRS_$(PASS).$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) ,$(eval $(def_pass_subdir))) $(foreach makefile,$(MAKEFILES_BEFORE_$(PASS)) $(MAKEFILES_BEFORE_$(PASS).$(KBUILD_TARGET)) $(MAKEFILES_BEFORE_$(PASS).$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)),$(eval $(def_pass_makefile))) $(eval tag:=_after) $(eval dep:=pass_$(pass)_doit) $(foreach subdir, $(SUBDIRS_AFTER_$(PASS)) $(SUBDIRS_AFTER_$(PASS).$(KBUILD_TARGET)) $(SUBDIRS_AFTER_$(PASS).$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) ,$(eval $(def_pass_subdir))) $(foreach makefile,$(MAKEFILES_AFTER_$(PASS)) $(MAKEFILES_AFTER_$(PASS).$(KBUILD_TARGET)) $(MAKEFILES_AFTER_$(PASS).$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) ,$(eval $(def_pass_makefile))) .PHONY: pass_$(pass) pass_$(pass)_before pass_$(pass)_after pass_$(pass)_doit .NOTPARALLEL: pass_$(pass) pass_$(pass)_before pass_$(pass)_after pass_$(pass)_doit pass_$(pass)_doit: pass_$(pass)_before \ $(PASS_$(PASS)_trgs) $(foreach var,$(PASS_$(PASS)_vars),$($(var))) pass_$(pass): \ pass_$(pass)_before \ pass_$(pass)_doit \ pass_$(pass)_after #$ (warning pass=$(pass) PASS=$(PASS): $(PASS_$(PASS)_trgs) $(PASS_$(PASS)_trgs) $(foreach var,$(PASS_$(PASS)_vars),$($(var)))) endef # def_pass_strict_unsafe $(eval-opt-var def_pass_strict_unsafe) ## Execute a pass, non-strict pass ordering. # @param $(pass) Lowercase pass name. # @param $(PASS) Uppercase pass name. define def_pass_nonstrict .PHONY: pass_$(pass) pass_$(pass)_before pass_$(pass)_after pass_$(pass)_doit pass_$(pass)_doit: $(PASS_$(PASS)_trgs) $(foreach var,$(PASS_$(PASS)_vars),$$$$($(var))) pass_$(pass): pass_$(pass)_doit endef # def_pass_nonstrict ## PASS: rules # Generate the rules for the defined passes. $(foreach PASS, $(PASSES), \ $(eval pass := $(PASS_$(PASS)_pass)) \ $(eval $(def_pass_$(_KBUILD_STRICT_PASS_ORDER)))) ## Pass order, strict. # @param $(pass) Current pass name. # @param $(prev_pass) The previous pass name. define def_pass_order_strict .PHONY: pass_$(pass)_order .NOTPARALLEL: pass_$(pass)_order pass_$(pass)_order: $(pass_prev) %$$(call MSG_PASS,$$(if $$(PASS_$(PASS)),$$(PASS_$(PASS)),$(pass))) + $$(QUIET)$$(MAKE) -f $$(MAKEFILE) pass_$(pass) $(eval pass_prev := pass_$(pass)_order) endef # def_pass_order_strict $(eval-opt-var def_pass_order_strict) ## Pass order, strict unsafe. # @param $(pass) Current pass name. # @param $(prev_pass) The previous pass name. define def_pass_order_strict_unsafe .NOTPARALLEL: pass_$(pass)_order pass_$(pass)_banner .PHONY: pass_$(pass)_order pass_$(pass)_banner pass_$(pass)_banner: $(pass_prev) %$$(call MSG_PASS,$$(if $$(PASS_$(PASS)),$$(PASS_$(PASS)),$(pass))) pass_$(pass)_order: $(pass_prev) \ pass_$(pass)_banner \ pass_$(pass) $(eval pass_prev := pass_$(pass)_order) endef # def_pass_order_strict_unsafe $(eval-opt-var def_pass_order_strict_unsafe) ## Pass order, non-strict. # @param $(pass) Current pass name. # @param $(prev_pass) The previous pass name. define def_pass_order_nonstrict .PHONY: pass_$(pass)_order pass_$(pass)_banner pass_$(pass)_banner: %$$(call MSG_PASS,$$(if $$(PASS_$(PASS)),$$(PASS_$(PASS)),$(pass))) pass_$(pass)_order: \ $(pass_prev) \ pass_$(pass)_banner \ pass_$(pass) $(eval pass_prev := pass_$(pass)_order) endef # def_pass_order_nonstrict $(eval-opt-var def_pass_order_nonstrict) ## PASS: order # Use dependencies to ensure correct pass order. pass_prev := $(foreach PASS,$(DEFAULT_PASSES),\ $(eval pass := $(PASS_$(PASS)_pass)) \ $(eval $(def_pass_order_$(_KBUILD_STRICT_PASS_ORDER)))) ifdef KBUILD_PROFILE_SELF $(evalcall def_profile_self, done passes) endif # Some common pass aliases ifndef KBUILD_NO_PASS_ALIASES .PHONY: clean clean: pass_clean .PHONY: nothing nothing: pass_nothing .PHONY: staging staging: pass_staging .PHONY: packing packing: pass_packing ifndef KBUILD_NO_TESTING_PASS_ALIASES .PHONY: check check:: pass_testing .PHONY: test test:: pass_testing endif # KBUILD_NO_TESTING_PASS_ALIASES endif # KBUILD_NO_PASS_ALIASES kbuild-3149/kBuild/footer-misc.kmk0000644000175000017500000000654513252530251017061 0ustar locutuslocutus# $Id: footer-misc.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild - Footer - Target lists - Pass 2 - Misc. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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 source of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # # # OTHERS # _OTHERS = $(OTHERS) $(OTHERS.$(KBUILD_TARGET)) $(OTHERS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) # # TESTING # _TESTING += $(TESTING) \ $(TESTING.$(KBUILD_TARGET)) \ $(TESTING.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) \ $(TESTING.$(KBUILD_TARGET_ARCH)) \ $(TESTING.$(KBUILD_TARGET_CPU)) # # PACKING # _PACKING += $(PACKING) \ $(PACKING.$(KBUILD_TARGET)) \ $(PACKING.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) \ $(PACKING.$(KBUILD_TARGET_ARCH)) \ $(PACKING.$(KBUILD_TARGET_CPU)) # # DOCS # # # DIRECTORIES # _DIR_ALL := $(sort \ $(addsuffix /,$(patsubst %/,%,$(_DIRS) )) \ $(dir $(_OUT_FILES) $(_OBJS) $(_INSTALLS_FILES) $(_DEBUG_INSTALL_FILES) $(_STAGE_FILES) $(_DEBUG_STAGE_FILES) ) \ $(foreach path, $(KBUILD_INST_PATHS), $(PATH_INS)/$(INST_$(path)) $(PATH_STAGE)/$(STAGE_$(path)) ) \ $(dir $(patsubst %/,%, $(_INSTALLS_DIRS) $(_STAGE_DIRS) $(_DEBUG_INSTALL_DIRS) $(_DEBUG_STAGE_DIRS)) ) \ ) $(foreach directory, \ $(_INSTALLS_DIRS) \ $(_STAGE_DIRS) \ $(_DEBUG_INSTALL_DIRS) \ $(_DEBUG_STAGE_DIRS) \ , $(eval _DIR_ALL := $(filter-out $(directory),$(_DIR_ALL))) ) define def_mkdir_rule $(directory): %$$(call MSG_MKDIR,$$@) $$(QUIET)$$(MKDIR) -p -- $$@ endef $(foreach directory,$(_DIR_ALL),$(eval $(def_mkdir_rule))) ifdef KBUILD_PROFILE_SELF $(evalcall def_profile_self, done directories) endif # # NOTHING # do-nothing: %$(call MSG_NOTHING) ifdef KBUILD_PROFILE_SELF @$(ECHO) 'prof: $(call _KBUILD_FMT_ELAPSED_EX, $(nanots ), $(_KBUILD_TS_HEADER_START)) - $(call _KBUILD_FMT_ELAPSED_EX, $(nanots ), $(_KBUILD_TS_PREV)) - executing $@' ifeq ($(KBUILD_PROFILE_SELF),2) @$(ECHO) 'stat: $(make-stats )' endif endif # # CLEAN UP # do-clean: %$(call MSG_CLEAN) $(QUIET)$(RM) -f -- \ $(_OUT_FILES) \ $(_OBJS) \ $(_DEPFILES) \ $(_DEPFILES_INCLUDED) \ $(_CLEAN_FILES) \ $(OTHER_CLEAN) \ $(_STAGE_FILES) $(QUIET)$(RMDIR) -p --ignore-fail-on-non-empty --ignore-fail-on-not-exist -- \ $(rsort $(dir $(_OUT_FILES) \ $(_OBJS) \ $(_DEPFILES) \ $(_DEPFILES_INCLUDED) \ $(_CLEAN_FILES) \ $(OTHER_CLEAN))\ $(_STAGE_DIRS) ) kbuild-3149/kBuild/envwin.cmd0000644000175000017500000006270613252530251016122 0ustar locutuslocutus@echo off REM $Id: envwin.cmd 3113 2017-10-29 17:16:03Z bird $ REM REM @file REM Environment setup script. REM REM REM Copyright (c) 2005-2010 knut st. osmundsen REM REM This file is part of kBuild. REM REM kBuild is free software; you can redistribute it and/or modify REM it under the terms of the GNU General Public License as published by REM the Free Software Foundation; either version 2 of the License, or REM (at your option) any later version. REM REM kBuild is distributed in the hope that it will be useful, REM but WITHOUT ANY WARRANTY; without even the implied warranty of REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the REM GNU General Public License for more details. REM REM You should have received a copy of the GNU General Public License REM along with kBuild; if not, write to the Free Software REM Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA REM REM REM Globals REM set _KBUILD_CURDIR=%CD% for /f "tokens=*" %%d in ('cd') do set _KBUILD_CURDIR=%%d set _KBUILD_PATH=%KBUILD_PATH% set _KBUILD_BIN_PATH=%KBUILD_BIN_PATH% set _KBUILD_TYPE=%KBUILD_TYPE% set _KBUILD_TARGET=%KBUILD_TARGET% set _KBUILD_TARGET_ARCH=%KBUILD_TARGET_ARCH% set _KBUILD_TARGET_CPU=%KBUILD_TARGET_CPU% set _KBUILD_HOST=%KBUILD_HOST% set _KBUILD_HOST_ARCH=%KBUILD_HOST_ARCH% set _KBUILD_HOST_CPU=%KBUILD_HOST_CPU% set _KBUILD_OVERRIDE_TYPE=0 set _KBUILD_OVERRIDE_TARGET=0 set _KBUILD_OVERRIDE_TARGET_ARCH=0 REM REM Parse the arguments. REM REM Note: The 0 argument must be saved as it is also shifted. REM set _KBUILD_SELF=%0 set _KBUILD_OPT_FULL=0 set _KBUILD_OPT_LEGACY=0 set _KBUILD_OPT_VAR= set _KBUILD_OPT_VALUE_ONLY=0 set _KBUILD_SHOW_VAR_PREFIX= set _KBUILD_OPT_DBG=1 set _KBUILD_OPT_OVERRIDE_ALL=0 :argument_loop if ".%1" == ".-h" goto do_help if ".%1" == "./h" goto do_help if ".%1" == "./H" goto do_help if ".%1" == ".-h" goto do_help if ".%1" == ".-help" goto do_help if ".%1" == ".--help" goto do_help if ".%1" == ".--win" goto want_win if ".%1" == ".-win" goto want_win if ".%1" == ".--win32" goto want_win32_bit if ".%1" == ".-win32" goto want_win32_bit if ".%1" == ".-win64" goto want_win64_bit if ".%1" == ".--win64" goto want_win64_bit if ".%1" == ".--nt" goto want_nt if ".%1" == ".-nt" goto want_nt if ".%1" == ".--nt32" goto want_nt32_bit if ".%1" == ".-nt32" goto want_nt32_bit if ".%1" == ".--nt64" goto want_nt64_bit if ".%1" == ".-nt64" goto want_nt64_bit if ".%1" == ".--release" goto want_release if ".%1" == ".--profile" goto want_profile if ".%1" == ".--debug" goto want_debug if ".%1" == ".--full" goto opt_full if ".%1" == ".--normal" goto opt_normal if ".%1" == ".--legacy" goto opt_legacy if ".%1" == ".--no-legacy" goto opt_no_legacy if ".%1" == ".--debug-script" goto opt_debug_script if ".%1" == ".--no-debug-script" goto opt_no_debug_script if ".%1" == ".--var" goto opt_var if ".%1" == ".--value-only" goto opt_value_only if ".%1" == ".--name-and-value" goto opt_name_and_value if ".%1" == ".--set" goto opt_set if ".%1" == ".--no-set" goto opt_no_set goto done_arguments :want_win shift set _KBUILD_TARGET=win set _KBUILD_OVERRIDE_TARGET=1 goto argument_loop :want_win32_bit shift set _KBUILD_TARGET=win set _KBUILD_TARGET_ARCH=x86 set _KBUILD_OVERRIDE_TARGET=1 set _KBUILD_OVERRIDE_TARGET_ARCH=1 goto argument_loop :want_win64_bit shift set _KBUILD_TARGET=win set _KBUILD_TARGET_ARCH=amd64 set _KBUILD_OVERRIDE_TARGET=1 set _KBUILD_OVERRIDE_TARGET_ARCH=1 goto argument_loop :want_nt shift set _KBUILD_TARGET=nt set _KBUILD_OVERRIDE_TARGET=1 goto argument_loop :want_nt32_bit shift set _KBUILD_TARGET=nt set _KBUILD_TARGET_ARCH=x86 set _KBUILD_OVERRIDE_TARGET=1 set _KBUILD_OVERRIDE_TARGET_ARCH=1 goto argument_loop :want_nt64_bit shift set _KBUILD_TARGET=nt set _KBUILD_TARGET_ARCH=amd64 set _KBUILD_OVERRIDE_TARGET=1 set _KBUILD_OVERRIDE_TARGET_ARCH=1 goto argument_loop :want_release shift set _KBUILD_TYPE=release set _KBUILD_OVERRIDE_TYPE=1 goto argument_loop :want_profile shift set _KBUILD_TYPE=profile set _KBUILD_OVERRIDE_TYPE=1 goto argument_loop :want_debug shift set _KBUILD_TYPE=debug set _KBUILD_OVERRIDE_TYPE=1 goto argument_loop :opt_full shift set _KBUILD_OPT_FULL=1 goto argument_loop :opt_normal shift set _KBUILD_OPT_FULL=0 goto argument_loop :opt_legacy shift set _KBUILD_OPT_LEGACY=1 goto argument_loop :opt_no_legacy shift set _KBUILD_OPT_LEGACY=0 goto argument_loop :opt_debug_script shift set _KBUILD_OPT_DBG=1 goto argument_loop :opt_no_debug_script shift set _KBUILD_OPT_DBG=0 goto argument_loop :opt_var shift if ".%1" == "." echo syntax error: --var is missing it's variable name. if ".%1" == "." goto failure set _KBUILD_OPT_VAR=%_KBUILD_OPT_VAR% %1 shift goto argument_loop :opt_value_only shift set _KBUILD_OPT_VALUE_ONLY=1 goto argument_loop :opt_name_and_value shift set _KBUILD_OPT_VALUE_ONLY=0 goto argument_loop :opt_set shift set _KBUILD_SHOW_VAR_PREFIX=SET %_KBUILD_NON_EXISTING_VAR% goto argument_loop :opt_no_set shift set _KBUILD_SHOW_VAR_PREFIX= goto argument_loop REM # REM # Syntax REM # :do_help echo kBuild environment setup script for Windows NT. echo Syntax: envwin.cmd [options] [command to be executed] echo or: envwin.cmd [options] --var varname echo . echo Options: echo --win echo Force windows target and host platform. echo --win32 echo Force x86 32-bit windows target platform. echo --win64 echo Force AMD64 64-bit windows target platform. echo --nt echo Force NT target and host platform. echo --nt32 echo Force x86 32-bit NT target platform. echo --nt64 echo Force AMD64 64-bit NT target platform. echo --debug, --release, --profile echo Alternative way of specifying KBUILD_TYPE. echo --full, --normal echo Controls the variable set. Default: --normal echo --legacy, --no-legacy echo Include legacy variables in result. Default: --legacy echo --value-only, --name-and-value echo Controls what the result of a --var query. Default: --name-and-value echo --set, --no-set echo Whether to prefix the variable output with 'SET' or not. echo Default: --no-set goto end :done_arguments REM REM Convert legacy variable names. REM if ".%_KBUILD_OPT_OVERRIDE_ALL%" == ".1" goto legacy_convertion_done set _KBUILD_VARS=KBUILD_HOST (%_KBUILD_HOST%) and BUILD_PLATFORM (%BUILD_PLATFORM%) if not ".%BUILD_PLATFORM%" == "." if not ".%_KBUILD_HOST%" == "." if ".%_KBUILD_HOST%" == ".%BUILD_PLATFORM%" goto legacy_mismatch if not ".%BUILD_PLATFORM%" == "." set _KBUILD_HOST=%BUILD_PLATFORM% set _KBUILD_VARS=KBUILD_HOST_ARCH (%_KBUILD_HOST_ARCH%) and BUILD_PLATFORM_ARCH (%BUILD_PLATFORM_ARCH%) if not ".%BUILD_PLATFORM_ARCH%" == "." if not ".%_KBUILD_HOST_ARCH%" == "." if ".%_KBUILD_HOST_ARCH%" == ".%BUILD_PLATFORM_ARCH%" goto legacy_mismatch if not ".%BUILD_PLATFORM_ARCH%" == "." set _KBUILD_HOST_ARCH=%BUILD_PLATFORM_ARCH% set _KBUILD_VARS=KBUILD_HOST_CPU (%_KBUILD_HOST_CPU%) and BUILD_PLATFORM_CPU (%BUILD_PLATFORM_CPU%) if not ".%BUILD_PLATFORM_CPU%" == "." if not ".%_KBUILD_HOST_CPU%" == "." if ".%_KBUILD_HOST_CPU%" == ".%BUILD_PLATFORM_CPU%" goto legacy_mismatch if not ".%BUILD_PLATFORM_CPU%" == "." set _KBUILD_HOST_CPU=%BUILD_PLATFORM_CPU% if ".%_KBUILD_OVERRIDE_TARGET%" == ".1" goto legacy_skip_target set _KBUILD_VARS=KBUILD_TARGET (%_KBUILD_TARGET%) and BUILD_TARGET (%BUILD_TARGET%) if not ".%BUILD_TARGET%" == "." if not ".%_KBUILD_TARGET%" == "." if ".%_KBUILD_TARGET%" == ".%BUILD_TARGET%" goto legacy_mismatch if not ".%BUILD_TARGET%" == "." set _KBUILD_TARGET=%BUILD_TARGET% :legacy_skip_target if ".%_KBUILD_OVERRIDE_TARGET%" == ".1" goto legacy_skip_target_arch set _KBUILD_VARS=KBUILD_TARGET_ARCH (%_KBUILD_TARGET_ARCH%) and BUILD_TARGET_ARCH (%BUILD_TARGET_ARCH%) if not ".%BUILD_TARGET_ARCH%" == "." if not ".%_KBUILD_TARGET_ARCH%" == "." if ".%_KBUILD_TARGET_ARCH%" == ".%BUILD_TARGET_ARCH%" goto legacy_mismatch if not ".%BUILD_TARGET_ARCH%" == "." set _KBUILD_TARGET_ARCH=%BUILD_TARGET_ARCH% :legacy_skip_target_arch if ".%_KBUILD_OVERRIDE_TARGET%" == ".1" goto legacy_skip_target_cpu set _KBUILD_VARS=KBUILD_TARGET_CPU (%_KBUILD_TARGET_CPU%) and BUILD_TARGET_CPU (%BUILD_TARGET_CPU%) if not ".%BUILD_TARGET_CPU%" == "." if not ".%_KBUILD_TARGET_CPU%" == "." if ".%_KBUILD_TARGET_CPU%" == ".%BUILD_TARGET_CPU%" goto legacy_mismatch if not ".%BUILD_TARGET_CPU%" == "." set _KBUILD_TARGET_CPU=%BUILD_TARGET_CPU% :legacy_skip_target_cpu if ".%_KBUILD_OVERRIDE_TARGET%" == ".1" goto legacy_skip_type set _KBUILD_VARS=KBUILD_TYPE (%_KBUILD_TYPE%) and BUILD_TYPE (%BUILD_TYPE%) if not ".%BUILD_TYPE%" == "." if not ".%_KBUILD_TYPE%" == "." if ".%_KBUILD_TYPE%" == ".%BUILD_TYPE%" goto legacy_mismatch if not ".%BUILD_TYPE%" == "." set _KBUILD_TYPE=%BUILD_TYPE% :legacy_skip_type set _KBUILD_VARS=KBUILD_PATH (%_KBUILD_PATH%) and PATH_KBUILD (%PATH_KBUILD%) if not ".%PATH_KBUILD%" == "." if not ".%_KBUILD_PATH%" == "." if ".%_KBUILD_PATH%" == ".%PATH_KBUILD%" goto legacy_mismatch if not ".%PATH_KBUILD%" == "." set _KBUILD_PATH=%PATH_KBUILD% goto legacy_convertion_done :legacy_mismatch echo error: %_KBUILD_VARS% disagree. goto failed :legacy_convertion_done REM REM Check for illegal target/platforms. REM :target_and_platform if "%_KBUILD_TARGET" == "win32" goto illegal_target if "%_KBUILD_TARGET" == "win64" goto illegal_target if "%_KBUILD_HOST" == "win32" goto illegal_host if "%_KBUILD_HOST" == "win64" goto illegal_host goto target_and_platform_ok :illegal_target echo error: KBUILD_TARGET=%KBUILD_TARGET% is no longer valid. echo Only 'win' and 'nt' are permitted for targeting microsoft windows. goto failed :illegal_host echo error: KBUILD_HOST=%KBUILD_HOST is no longer valid. echo Only 'win' and 'nt' are permitted for building on microsoft windows. goto failed :target_and_platform_ok REM REM Find kBuild. REM REM We'll try determin the location of this script first and use that REM as a starting point for guessing the kBuild directory. REM REM Check if set via KBUILD_PATH. if not ".%_KBUILD_PATH%" == "." if exist %_KBUILD_PATH%\footer.kmk goto found_kbuild REM Determin a correct self - by %0 if exist "%_KBUILD_SELF%" goto found_self set _KBUILD_SELF=%_KBUILD_SELF%.cmd if exist "%_KBUILD_SELF%" goto found_self REM Determin a correct self - by the PATH REM This is very verbose because nested for loops didn't work out. for /f "tokens=1 delims=;" %%d in ("%PATH%") do set _KBUILD_SELF=%%d\envwin.cmd if exist "%_KBUILD_SELF%" goto found_self for /f "tokens=2 delims=;" %%d in ("%PATH%") do set _KBUILD_SELF=%%d\envwin.cmd if exist "%_KBUILD_SELF%" goto found_self for /f "tokens=3 delims=;" %%d in ("%PATH%") do set _KBUILD_SELF=%%d\envwin.cmd if exist "%_KBUILD_SELF%" goto found_self for /f "tokens=4 delims=;" %%d in ("%PATH%") do set _KBUILD_SELF=%%d\envwin.cmd if exist "%_KBUILD_SELF%" goto found_self for /f "tokens=5 delims=;" %%d in ("%PATH%") do set _KBUILD_SELF=%%d\envwin.cmd if exist "%_KBUILD_SELF%" goto found_self for /f "tokens=6 delims=;" %%d in ("%PATH%") do set _KBUILD_SELF=%%d\envwin.cmd if exist "%_KBUILD_SELF%" goto found_self for /f "tokens=7 delims=;" %%d in ("%PATH%") do set _KBUILD_SELF=%%d\envwin.cmd if exist "%_KBUILD_SELF%" goto found_self for /f "tokens=8 delims=;" %%d in ("%PATH%") do set _KBUILD_SELF=%%d\envwin.cmd if exist "%_KBUILD_SELF%" goto found_self for /f "tokens=9 delims=;" %%d in ("%PATH%") do set _KBUILD_SELF=%%d\envwin.cmd if exist "%_KBUILD_SELF%" goto found_self for /f "tokens=10 delims=;" %%d in ("%PATH%") do set _KBUILD_SELF=%%d\envwin.cmd if exist "%_KBUILD_SELF%" goto found_self for /f "tokens=11 delims=;" %%d in ("%PATH%") do set _KBUILD_SELF=%%d\envwin.cmd if exist "%_KBUILD_SELF%" goto found_self for /f "tokens=12 delims=;" %%d in ("%PATH%") do set _KBUILD_SELF=%%d\envwin.cmd if exist "%_KBUILD_SELF%" goto found_self for /f "tokens=13 delims=;" %%d in ("%PATH%") do set _KBUILD_SELF=%%d\envwin.cmd if exist "%_KBUILD_SELF%" goto found_self for /f "tokens=14 delims=;" %%d in ("%PATH%") do set _KBUILD_SELF=%%d\envwin.cmd if exist "%_KBUILD_SELF%" goto found_self for /f "tokens=15 delims=;" %%d in ("%PATH%") do set _KBUILD_SELF=%%d\envwin.cmd if exist "%_KBUILD_SELF%" goto found_self for /f "tokens=16 delims=;" %%d in ("%PATH%") do set _KBUILD_SELF=%%d\envwin.cmd if exist "%_KBUILD_SELF%" goto found_self for /f "tokens=17 delims=;" %%d in ("%PATH%") do set _KBUILD_SELF=%%d\envwin.cmd if exist "%_KBUILD_SELF%" goto found_self for /f "tokens=18 delims=;" %%d in ("%PATH%") do set _KBUILD_SELF=%%d\envwin.cmd if exist "%_KBUILD_SELF%" goto found_self for /f "tokens=19 delims=;" %%d in ("%PATH%") do set _KBUILD_SELF=%%d\envwin.cmd if exist "%_KBUILD_SELF%" goto found_self for /f "tokens=20 delims=;" %%d in ("%PATH%") do set _KBUILD_SELF=%%d\envwin.cmd if exist "%_KBUILD_SELF%" goto found_self goto try_by_pwd :found_self cd "%_KBUILD_SELF%\.." for /f "tokens=*" %%d in ('cd') do set _KBUILD_PATH=%%d cd "%_KBUILD_CURDIR%" if exist "%_KBUILD_PATH%\footer.kmk" goto found_kbuild REM Try relative to the current directory. :try_by_pwd if exist "%_KBUILD_PATH%\footer.kmk" goto found_kbuild set _KBUILD_PATH=%_KBUILD_CURDIR% if exist "%_KBUILD_PATH%\footer.kmk" goto found_kbuild set _KBUILD_PATH=%_KBUILD_CURDIR%\kBuild if exist "%_KBUILD_PATH%\footer.kmk" goto found_kbuild set _KBUILD_PATH=%_KBUILD_CURDIR%\..\kBuild if exist "%_KBUILD_PATH%\footer.kmk" goto found_kbuild set _KBUILD_PATH=%_KBUILD_CURDIR%\..\..\kBuild if exist "%_KBUILD_PATH%\footer.kmk" goto found_kbuild set _KBUILD_PATH=%_KBUILD_CURDIR%\..\..\..\kBuild if exist "%_KBUILD_PATH%\footer.kmk" goto found_kbuild set _KBUILD_PATH=%_KBUILD_CURDIR%\..\..\..\..\kBuild if exist "%_KBUILD_PATH%\footer.kmk" goto found_kbuild echo kBuild: Can't find the kBuild directory! set CURDIR= goto failed :found_kbuild cd "%_KBUILD_PATH%" for /f "tokens=*" %%d in ('cd') do set _KBUILD_PATH=%%d cd "%_KBUILD_CURDIR%" if ".%_KBUILD_OPT_DBG%" == ".1" echo dbg: _KBUILD_PATH=%_KBUILD_PATH% REM REM Type - release is the default. REM if not ".%_KBUILD_TYPE%" == "." goto have_type set _KBUILD_TYPE=release :have_type if ".%_KBUILD_OPT_DBG%" == ".1" echo dbg: _KBUILD_TYPE=%_KBUILD_TYPE% REM REM Host platform - windows REM if not ".%_KBUILD_HOST%" == "." goto have_host set _KBUILD_HOST=win if ".%_KBUILD_OPT_DBG%" == ".1" echo dbg: _KBUILD_HOST=%_KBUILD_HOST% :have_host if not ".%_KBUILD_HOST_ARCH%" == "." goto have_host_arch REM try guess from _KBUILD_HOST_CPU if ".%KBUILD_HOST_CPU%" == ".i386" set _KBUILD_HOST_ARCH=x86 if ".%KBUILD_HOST_CPU%" == ".i486" set _KBUILD_HOST_ARCH=x86 if ".%KBUILD_HOST_CPU%" == ".i586" set _KBUILD_HOST_ARCH=x86 if ".%KBUILD_HOST_CPU%" == ".i686" set _KBUILD_HOST_ARCH=x86 if ".%KBUILD_HOST_CPU%" == ".i786" set _KBUILD_HOST_ARCH=x86 if ".%KBUILD_HOST_CPU%" == ".i886" set _KBUILD_HOST_ARCH=x86 if ".%KBUILD_HOST_CPU%" == ".i986" set _KBUILD_HOST_ARCH=x86 if ".%KBUILD_HOST_CPU%" == ".k8" set _KBUILD_HOST_ARCH=amd64 if ".%KBUILD_HOST_CPU%" == ".k9" set _KBUILD_HOST_ARCH=amd64 if ".%KBUILD_HOST_CPU%" == ".k10" set _KBUILD_HOST_ARCH=amd64 if not ".%_KBUILD_HOST_ARCH%" == "." goto have_host_arch REM try guess from PROCESSOR_ARCHITEW6432 and PROCESSOR_ARCHITECTURE set _KBUILD_TMP=%PROCESSOR_ARCHITECTURE% if not ".%PROCESSOR_ARCHITEW6432%" == "." set _KBUILD_TMP=%PROCESSOR_ARCHITEW6432% if "%_KBUILD_TMP%" == "x86" set _KBUILD_HOST_ARCH=x86 if "%_KBUILD_TMP%" == "X86" set _KBUILD_HOST_ARCH=x86 if "%_KBUILD_TMP%" == "amd64" set _KBUILD_HOST_ARCH=amd64 if "%_KBUILD_TMP%" == "Amd64" set _KBUILD_HOST_ARCH=amd64 if "%_KBUILD_TMP%" == "AMD64" set _KBUILD_HOST_ARCH=amd64 if "%_KBUILD_TMP%" == "x64" set _KBUILD_HOST_ARCH=amd64 if "%_KBUILD_TMP%" == "X64" set _KBUILD_HOST_ARCH=amd64 if not ".%_KBUILD_HOST_ARCH%" == "." goto have_host_arch echo error: Cannot figure KBUILD_HOST_ARCH! goto failed :have_host_arch if ".%_KBUILD_OPT_DBG%" == ".1" echo dbg: _KBUILD_HOST_ARCH=%_KBUILD_HOST_ARCH% if not ".%_KBUILD_HOST_CPU%" == "." goto have_host_cpu set _KBUILD_HOST_CPU=blend :have_host_cpu if ".%_KBUILD_OPT_DBG%" == ".1" echo dbg: _KBUILD_HOST_CPU=%_KBUILD_HOST_CPU% REM REM The target platform. REM Defaults to the host when not specified. REM if not ".%_KBUILD_TARGET%" == "." goto have_target set _KBUILD_TARGET=%_KBUILD_HOST% :have_target if ".%_KBUILD_OPT_DBG%" == ".1" echo dbg: _KBUILD_TARGET=%_KBUILD_TARGET% if not ".%_KBUILD_TARGET_ARCH%" == "." goto have_target_arch set _KBUILD_TARGET_ARCH=%_KBUILD_HOST_ARCH% :have_target_arch if ".%_KBUILD_OPT_DBG%" == ".1" echo dbg: _KBUILD_TARGET_ARCH=%_KBUILD_TARGET_ARCH% if not ".%_KBUILD_TARGET_CPU%" == "." goto have_target_cpu if ".%_KBUILD_TARGET_ARCH%" == ".%_KBUILD_HOST_ARCH%" set _KBUILD_TARGET_CPU=%_KBUILD_HOST_CPU% if not ".%_KBUILD_TARGET_CPU%" == "." goto have_target_cpu set _KBUILD_TARGET_CPU=%_KBUILD_HOST_CPU% :have_target_cpu if ".%_KBUILD_OPT_DBG%" == ".1" echo dbg: _KBUILD_TARGET_CPU=%_KBUILD_TARGET_CPU% REM REM Calc KBUILD_BIN_PATH and the new PATH value. REM if not ".%_KBUILD_BIN_PATH%" == "." goto have_kbuild_bin_path set _KBUILD_BIN_PATH=%_KBUILD_PATH%\bin\win.%_KBUILD_HOST_ARCH% :have_kbuild_bin_path if ".%_KBUILD_OPT_DBG%" == ".1" echo dbg: _KBUILD_BIN_PATH=%_KBUILD_BIN_PATH% set _KBUILD_NEW_PATH=%_KBUILD_BIN_PATH%;%PATH% if ".%_KBUILD_OPT_DBG%" == ".1" echo dbg: _KBUILD_NEW_PATH=%_KBUILD_NEW_PATH% REM REM Sanity check. REM if not exist "%_KBUILD_BIN_PATH%" goto missing_bin_path if not exist "%_KBUILD_BIN_PATH%" goto done_chekcing_for_tools set _KBUILD_TMP=kmk kDepPre kDepIDB kmk_append kmk_ash kmk_cat kmk_cp kmk_echo kmk_install kmk_ln kmk_mkdir kmk_mv kmk_rm kmk_rmdir kmk_sed for %%i in ( %_KBUILD_TMP% ) do if not exist "%_KBUILD_BIN_PATH%\%%i.exe" echo warning: The %%i program doesn't exist for this platform. (%_KBUILD_BIN_PATH%\%%i.exe)" goto done_chekcing_for_tools :missing_bin_path echo warning: The bin directory for this platform doesn't exist. (%_KBUILD_BIN_PATH%) :done_chekcing_for_tools REM REM The environment is in place, now take the requested action. REM if ".%_KBUILD_OPT_VAR%" == "." goto exec_or_setup_env goto show_variable REM REM Show a set of variables. REM REM Note: 4nt doesn't grok the setlocal delayed expansion option. REM So, we'll have to identify which shell we're running. REM :show_variable for %%i in ( %_KBUILD_OPT_VAR% ) do if "%%i" == "all" goto show_all_variables if not ".%_4VER%" == "." goto 4nt setlocal ENABLEDELAYEDEXPANSION if errorlevel 1 goto no_delay_expansion for %%i in ( %_KBUILD_OPT_VAR% ) do ( set _KBUILD_VAR=%%i set _KBUILD_TMP= if "%%i" == "KBUILD_PATH" set _KBUILD_TMP=%_KBUILD_PATH% if "%%i" == "KBUILD_BIN_PATH" set _KBUILD_TMP=%_KBUILD_BIN_PATH% if "%%i" == "KBUILD_TYPE" set _KBUILD_TMP=%_KBUILD_TYPE% if "%%i" == "KBUILD_HOST" set _KBUILD_TMP=%_KBUILD_HOST% if "%%i" == "KBUILD_HOST_ARCH" set _KBUILD_TMP=%_KBUILD_HOST_ARCH% if "%%i" == "KBUILD_HOST_CPU" set _KBUILD_TMP=%_KBUILD_HOST_CPU% if "%%i" == "KBUILD_TARGET" set _KBUILD_TMP=%_KBUILD_TARGET% if "%%i" == "KBUILD_TARGET_ARCH" set _KBUILD_TMP=%_KBUILD_TARGET_ARCH% if "%%i" == "KBUILD_TARGET_CPU" set _KBUILD_TMP=%_KBUILD_TARGET_CPU% if ".!_KBUILD_TMP!" == "." goto varible_not_found if not ".%_KBUILD_OPT_VALUE_ONLY%" == ".1" echo %_KBUILD_SHOW_VAR_PREFIX%%%i=!_KBUILD_TMP! if ".%_KBUILD_OPT_VALUE_ONLY%" == ".1" echo !_KBUILD_TMP! ) endlocal goto end :no_delay_expansion echo error: Unable to enable delayed expansion in the shell. :4nt for %%i in ( %_KBUILD_OPT_VAR% ) do ( set _KBUILD_VAR=%%i set _KBUILD_TMP= if "%%i" == "KBUILD_PATH" set _KBUILD_TMP=%_KBUILD_PATH% if "%%i" == "KBUILD_BIN_PATH" set _KBUILD_TMP=%_KBUILD_BIN_PATH% if "%%i" == "KBUILD_TYPE" set _KBUILD_TMP=%_KBUILD_TYPE% if "%%i" == "KBUILD_HOST" set _KBUILD_TMP=%_KBUILD_HOST% if "%%i" == "KBUILD_HOST_ARCH" set _KBUILD_TMP=%_KBUILD_HOST_ARCH% if "%%i" == "KBUILD_HOST_CPU" set _KBUILD_TMP=%_KBUILD_HOST_CPU% if "%%i" == "KBUILD_TARGET" set _KBUILD_TMP=%_KBUILD_TARGET% if "%%i" == "KBUILD_TARGET_ARCH" set _KBUILD_TMP=%_KBUILD_TARGET_ARCH% if "%%i" == "KBUILD_TARGET_CPU" set _KBUILD_TMP=%_KBUILD_TARGET_CPU% if ".%_KBUILD_TMP%" == "." goto varible_not_found if not ".%_KBUILD_OPT_VALUE_ONLY%" == ".1" echo %_KBUILD_SHOW_VAR_PREFIX%%i=%_KBUILD_TMP% if ".%_KBUILD_OPT_VALUE_ONLY%" == ".1" echo %_KBUILD_TMP% ) goto end :varible_not_found echo error: Unknown variable %_KBUILD_VAR% specified in --var request. goto failed :show_all_variables echo %_KBUILD_SHOW_VAR_PREFIX%KBUILD_PATH=%_KBUILD_PATH% echo %_KBUILD_SHOW_VAR_PREFIX%KBUILD_BIN_PATH=%_KBUILD_BIN_PATH% echo %_KBUILD_SHOW_VAR_PREFIX%KBUILD_TYPE=%_KBUILD_TYPE% echo %_KBUILD_SHOW_VAR_PREFIX%KBUILD_HOST=%_KBUILD_HOST% echo %_KBUILD_SHOW_VAR_PREFIX%KBUILD_HOST_ARCH=%_KBUILD_HOST_ARCH% echo %_KBUILD_SHOW_VAR_PREFIX%KBUILD_HOST_CPU=%_KBUILD_HOST_CPU% echo %_KBUILD_SHOW_VAR_PREFIX%KBUILD_TARGET=%_KBUILD_TARGET% echo %_KBUILD_SHOW_VAR_PREFIX%KBUILD_TARGET_ARCH=%_KBUILD_TARGET_ARCH% echo %_KBUILD_SHOW_VAR_PREFIX%KBUILD_TARGET_CPU=%_KBUILD_TARGET_CPU% goto end REM REM Setup environment for the current shell or execute a command. REM REM Note: We use setlocal if we're going to execute a command as we REM don't want the environment of the invoking shell to be changed. REM :exec_or_setup_env if not ".%1" == "." setlocal REM The PATH is always set. set PATH=%_KBUILD_NEW_PATH% REM Clear up anything that should be overridden. if not "%_KBUILD_OPT_OVERRIDE_ALL%" == "1" goto skip_override_all set KBUILD_TYPE= set KBUILD_HOST= set KBUILD_HOST_ARCH= set KBUILD_HOST_CPU= set KBUILD_TARGET= set KBUILD_TARGET_ARCH= set KBUILD_TARGET_CPU= set KBUILD_PATH= set KBUILD_BIN_PATH= if not "%_KBUILD_OPT_LEGACY%" == "1" goto skip_override_all set BUILD_TYPE= set BUILD_PLATFORM= set BUILD_PLATFORM_ARCH= set BUILD_PLATFORM_CPU= set BUILD_TARGET= set BUILD_TARGET_ARCH= set BUILD_TARGET_CPU= set PATH_KBUILD= set PATH_KBUILD_BIN= :skip_override_all REM Specific overrides, these implicitly deletes the legacy variable. if "%_KBUILD_OVERRIDE_TARGET%" == "1" set KBUILD_TARGET=%_KBUILD_TARGET% if "%_KBUILD_OVERRIDE_TARGET%" == "1" set BUILD_TARGET= if "%_KBUILD_OVERRIDE_TARGET_ARCH%" == "1" set KBUILD_TARGET_ARCH=%_KBUILD_TARGET_ARCH% if "%_KBUILD_OVERRIDE_TARGET_ARCH%" == "1" set BUILD_TARGET_ARCH= if "%_KBUILD_OVERRIDE_TYPE%" == "1" set KBUILD_TYPE=%_KBUILD_TYPE% if "%_KBUILD_OVERRIDE_TYPE%" == "1" set BUILD_TYPE= if not "%_KBUILD_OPT_FULL%" == "1" goto env_setup_done set KBUILD_PATH=%_KBUILD_PATH% set KBUILD_BIN_PATH=%_KBUILD_BIN_PATH% set KBUILD_TYPE=%_KBUILD_TYPE% set KBUILD_HOST=%_KBUILD_HOST% set KBUILD_HOST_ARCH=%_KBUILD_HOST_ARCH% set KBUILD_HOST_CPU=%_KBUILD_HOST_CPU% set KBUILD_TARGET=%_KBUILD_TARGET% set KBUILD_TARGET_ARCH=%_KBUILD_TARGET_ARCH% set KBUILD_TARGET_CPU=%_KBUILD_TARGET_CPU% if not "%_KBUILD_OPT_LEGACY%" == "1" goto env_setup_done set PATH_KBUILD=%_KBUILD_PATH% set PATH_KBUILD_BIN=%_KBUILD_BIN_PATH% set BUILD_TYPE=%_KBUILD_TYPE% set BUILD_PLATFORM=%_KBUILD_HOST% set BUILD_PLATFORM_ARCH=%_KBUILD_HOST_ARCH% set BUILD_PLATFORM_CPU=%_KBUILD_HOST_CPU% set BUILD_TARGET=%_KBUILD_TARGET% set BUILD_TARGET_ARCH=%_KBUILD_TARGET_ARCH% set BUILD_TARGET_CPU=%_KBUILD_TARGET_CPU% :env_setup_done if ".%1" == "." goto end REM Execute the specified command if ".%_KBUILD_OPT_DBG%" == ".1" echo dbg: Executing: %1 %2 %3 %4 %5 %6 %7 %8 %9 set _KBUILD_CLEAN_GOTO=exec_command & goto cleanup :exec_command SET _KBUILD_CLEAN_GOTO= %1 %2 %3 %4 %5 %6 %7 %8 %9 endlocal goto end_no_exit REM REM All exit paths leads to 'end' or 'failed' depending on REM which exit code is desire. This is required as we're manually REM performing environment cleanup (setlocal/endlocal is crap). REM :cleanup set _KBUILD_CURDIR= set _KBUILD_PATH= set _KBUILD_BIN_PATH= set _KBUILD_NEW_PATH= set _KBUILD_TYPE= set _KBUILD_TARGET= set _KBUILD_TARGET_ARCH= set _KBUILD_TARGET_CPU= set _KBUILD_HOST= set _KBUILD_HOST_ARCH= set _KBUILD_HOST_CPU= set _KBUILD_OPT_OVERRIDE_ALL= set _KBUILD_OVERRIDE_TYPE= set _KBUILD_OVERRIDE_TARGET= set _KBUILD_OVERRIDE_TARGET_ARCH= set _KBUILD_SELF= set _KBUILD_OPT_FULL= set _KBUILD_OPT_LEGACY= set _KBUILD_OPT_VAR= set _KBUILD_OPT_VALUE_ONLY= set _KBUILD_SHOW_VAR_PREFIX= set _KBUILD_OPT_DBG= set _KBUILD_OPT_OVERRIDE_ALL= set _KBUILD_TMP= set _KBUILD_VAR= set _KBUILD_VARS= goto %_KBUILD_CLEAN_GOTO% :failed set _KBUILD_CLEAN_GOTO=failed_done & goto cleanup :failed_done set _KBUILD_CLEAN_GOTO= exit /b 1 :end set _KBUILD_CLEAN_GOTO=end_done & goto cleanup :end_done set _KBUILD_CLEAN_GOTO= exit /b 0 :end_no_exit kbuild-3149/kBuild/footer-inherit-uses-tools.kmk0000644000175000017500000011273613252530250021702 0ustar locutuslocutus# $Id: footer-inherit-uses-tools.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild - Footer - Target lists - Pass 2 - Template & Target Inheritance, Uses and Tools. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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 source of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # ## Converts a variable from simple to recursive flavor. # This is used by def_inherit_template_one_accumulate_l and def_inherit_template_one_accumulate_r. # @param $1 The variable name. define def_simple_2_recursive $1_DEFERRED := $$($1) $1 = $$($1_DEFERRED) endef ## Inherit one keyword in a non-accumulative manner. # @param $(trg) Target object. # @param $(prop) The property. # @param $(src_key) Source keyword. # @param $(trg_key) Target keyword. define def_inherit_one_keyword ifdef $(trg)_$(prop).$(src_key) ifndef $(trg)_$(prop).$(trg_key) $(trg)_$(prop).$(trg_key) = $($(trg)_$(prop).$(src_key)) endif endif endef # EXPAND_BY = overriding ## Inherit one keyword in a non-accumulative manner. # @param $(trg) Target object. # @param $(prop) The property. # @param $(src_key) Source keyword. # @param $(trg_key) Target keyword. define def_inherit_one_keyword_overriding_now_l ifdef $(trg)_$(prop).$(src_key) ifndef $(trg)_$(prop).$(trg_key) $(trg)_$(prop).$(trg_key) := $($(trg)_$(prop).$(src_key)) endif endif endef ## @copydoc def_inherit_one_overriding_now_l define def_inherit_one_keyword_overriding_now_r ifdef $(trg)_$(prop).$(src_key) ifndef $(trg)_$(prop).$(trg_key) $(trg)_$(prop).$(trg_key) := $($(trg)_$(prop).$(src_key)) endif endif endef ## Inherit one keyword in a non-accumulative manner, deferred expansion. # @param $(trg) Target object. # @param $(prop) The property. # @param $(src_key) Source keyword. # @param $(trg_key) Target keyword. # @remark This define relies on double evaluation define def_inherit_one_keyword_overriding_deferred ifdef $(trg)_$(prop).$(src_key) ifndef $(trg)_$(prop).$(trg_key) $(trg)_$(prop).$(trg_key) = $$($(trg)_$(prop).$(src_key)) endif endif endef ## @copydoc def_inherit_one_overriding_deferred define def_inherit_one_keyword_overriding_deferred_l ifdef $(trg)_$(prop).$(src_key) ifndef $(trg)_$(prop).$(trg_key) $(trg)_$(prop).$(trg_key) = $$($(trg)_$(prop).$(src_key)) endif endif endef ## @copydoc def_inherit_one_overriding_deferred define def_inherit_one_keyword_overriding_deferred_r ifdef $(trg)_$(prop).$(src_key) ifndef $(trg)_$(prop).$(trg_key) $(trg)_$(prop).$(trg_key) = $$($(trg)_$(prop).$(src_key)) endif endif endef # EXPAND_BY = prepending ## Inherit one keyword in a prepending manner. # @param $(trg) Target object. # @param $(prop) The property. # @param $(src_key) Source keyword. # @param $(trg_key) Target keyword. define def_inherit_one_keyword_prepending_now_l ifdef $(trg)_$(prop).$(src_key) $(trg)_$(prop).$(trg_key) := $($(trg)_$(prop).$(src_key)) $($(trg)_$(prop).$(trg_key)) endif endef ## @copydoc def_inherit_one_prepending_now_l define def_inherit_one_keyword_prepending_now_r ifdef $(trg)_$(prop).$(src_key) $(trg)_$(prop).$(trg_key) := $($(trg)_$(prop).$(trg_key)) $($(trg)_$(prop).$(src_key)) endif endef ## Inherit one keyword in a non-accumulative manner, deferred expansion. # @param $(trg) Target object. # @param $(prop) The property. # @param $(src_key) Source keyword. # @param $(trg_key) Target keyword. # @remark This define relies on double evaluation define def_inherit_one_keyword_prepending_deferred ifdef $(trg)_$(prop).$(src_key) ifndef $(trg)_$(prop).$(trg_key) $(trg)_$(prop).$(trg_key) = $$($(trg)_$(prop).$(src_key)) endif endif endef ## Inherit one keyword in a prepending manner, deferred expansion. # @param $(trg) Target object. # @param $(prop) The property. # @param $(src_key) Source keyword. # @param $(trg_key) Target keyword. define def_inherit_one_keyword_prepending_deferred_l ifdef $(trg)_$(prop).$(src_key) ifeq ($$(flavor $(trg)_$(prop).$(trg_key)),simple) $$(evalcall2 def_simple_2_recursive,$(trg)_$(prop).$(trg_key)) endif $(trg)_$(prop).$(trg_key) <= $$($(trg)_$(prop).$(src_key)) endif endef ## @copydoc def_inherit_one_prepending_deferred_l define def_inherit_one_keyword_prepending_deferred_r ifdef $(trg)_$(prop).$(src_key) ifeq ($$(flavor $(trg)_$(prop).$(trg_key)),simple) $$(evalcall2 def_simple_2_recursive,$(trg)_$(prop).$(trg_key)) endif $(trg)_$(prop).$(trg_key) += $$($(trg)_$(prop).$(src_key)) endif endef # EXPAND_BY = appending ## Inherit one keyword in an appending manner. # @param $(trg) Target object. # @param $(prop) The property. # @param $(src_key) Source keyword. # @param $(trg_key) Target keyword. define def_inherit_one_keyword_appending_now_l ifdef $(trg)_$(prop).$(src_key) $(trg)_$(prop).$(trg_key) := $($(trg)_$(prop).$(trg_key)) $($(trg)_$(prop).$(src_key)) endif endef ## @copydoc def_inherit_one_appending_now_l define def_inherit_one_keyword_appending_now_r ifdef $(trg)_$(prop).$(src_key) $(trg)_$(prop).$(trg_key) := $($(trg)_$(prop).$(src_key)) $($(trg)_$(prop).$(trg_key)) endif endef ## Inherit one keyword in a non-accumulative manner, deferred expansion. # @param $(trg) Target object. # @param $(prop) The property. # @param $(src_key) Source keyword. # @param $(trg_key) Target keyword. # @remark This define relies on double evaluation define def_inherit_one_keyword_appending_deferred ifdef $(trg)_$(prop).$(src_key) ifndef $(trg)_$(prop).$(trg_key) $(trg)_$(prop).$(trg_key) = $$($(trg)_$(prop).$(src_key)) endif endif endef ## Inherit one keyword in an appending manner, deferred expansion. # @param $(trg) Target object. # @param $(prop) The property. # @param $(src_key) Source keyword. # @param $(trg_key) Target keyword. define def_inherit_one_keyword_appending_deferred_l ifdef $(trg)_$(prop).$(src_key) ifeq ($$(flavor $(trg)_$(prop).$(trg_key)),simple) $$(evalcall2 def_simple_2_recursive,$(trg)_$(prop).$(trg_key)) endif $(trg)_$(prop).$(trg_key) += $$($(trg)_$(prop).$(src_key)) endif endef ## @copydoc def_inherit_one_appending_deferred_l define def_inherit_one_keyword_appending_deferred_r ifdef $(trg)_$(prop).$(src_key) ifeq ($$(flavor $(trg)_$(prop).$(trg_key)),simple) $$(evalcall2 def_simple_2_recursive,$(trg)_$(prop).$(trg_key)) endif $(trg)_$(prop).$(trg_key) <= $$($(trg)_$(prop).$(src_key)) endif endef ## Worker for def_inherit that deals with one keyword that makes # use of inheritance. # @param prefix_keyword key_prefix:keyword. The cool join/split game as usual. # @param trg Object to consider for inheriting. # @param properties List of the properties with straight expansion. # @param properties_now_l List of the properties with immediate expansion, accumulating on the left side. # @param properties_now_r List of the properties with immediate expansion, accumulating on the right side. # @param properties_deferred List of the properties with deferred expansion (e.g. function), non-accumulative . # @param properties_deferred_l List of the properties with deferred expansion (e.g. function), accumulating on the left side. # @param properties_deferred_r List of the properties with deferred expansion (e.g. function), accumulating on the right side. define def_inherit_keyword local prefix := $(word 1,$(subst :, ,$(prefix_keyword))) local trg_key := $(word 2,$(subst :, ,$(prefix_keyword))) local src_key := $($(prefix)_$(trg_key)_EXTENDS) local by := $($(prefix)_$(trg_key)_EXTENDS_BY) # Inherit the properties. $(foreach prop, $(properties), $(eval $(def_inherit_one_keyword))) $(foreach prop, $(properties_now_l), $(eval $(def_inherit_one_keyword_$(by)_now_l))) $(foreach prop, $(properties_now_r), $(eval $(def_inherit_one_keyword_$(by)_now_r))) $(foreach prop, $(properties_deferred), $(eval $(def_inherit_one_keyword_$(by)_deferred))) $(foreach prop, $(properties_deferred_l), $(eval $(def_inherit_one_keyword_$(by)_deferred_l))) $(foreach prop, $(properties_deferred_r), $(eval $(def_inherit_one_keyword_$(by)_deferred_r))) endef # def_inherit_keyword ## Inherit one template property in a non-accumulative manner. # @param $(prop) Property name # @param $(src) Source (parent) object. # @param $(trg) Target (child) object. define def_inherit_one ifdef $(src)_$(prop) ifndef $(trg)_$(prop) $(trg)_$(prop) = $($(src)_$(prop)) endif endif endef # EXPAND_BY = overriding ## Inherit one template property in a non-accumulative manner. # @param $(prop) Property name # @param $(src) Source (parent) object. # @param $(trg) Target (child) object. define def_inherit_one_overriding_now_l ifdef $(src)_$(prop) ifndef $(trg)_$(prop) $(trg)_$(prop) := $($(src)_$(prop)) endif endif endef ## @copydoc def_inherit_one_overriding_now_l define def_inherit_one_overriding_now_r ifdef $(src)_$(prop) ifndef $(trg)_$(prop) $(trg)_$(prop) := $($(src)_$(prop)) endif endif endef ## Inherit one template property in a non-accumulative manner, deferred expansion. # @param $(prop) Property name # @param $(src) Source # @param $(trg) Target # @remark This define relies on double evaluation define def_inherit_one_overriding_deferred ifdef $(src)_$(prop) ifndef $(trg)_$(prop) $(trg)_$(prop) = $$($(src)_$(prop)) endif endif endef ## @copydoc def_inherit_one_overriding_deferred define def_inherit_one_overriding_deferred_l ifdef $(src)_$(prop) ifndef $(trg)_$(prop) $(trg)_$(prop) = $$($(src)_$(prop)) endif endif endef ## @copydoc def_inherit_one_overriding_deferred define def_inherit_one_overriding_deferred_r ifdef $(src)_$(prop) ifndef $(trg)_$(prop) $(trg)_$(prop) = $$($(src)_$(prop)) endif endif endef # EXPAND_BY = prepending ## Inherit one template property in a prepending manner. # @param $(prop) Property name # @param $(src) Source (parent) object. # @param $(trg) Target (child) object. define def_inherit_one_prepending_now_l ifdef $(src)_$(prop) $(trg)_$(prop) := $($(src)_$(prop)) $($(trg)_$(prop)) endif endef ## @copydoc def_inherit_one_prepending_now_l define def_inherit_one_prepending_now_r ifdef $(src)_$(prop) $(trg)_$(prop) := $($(trg)_$(prop)) $($(src)_$(prop)) endif endef ## Inherit one template property in a non-accumulative manner, deferred expansion. # @param $(prop) Property name # @param $(src) Source # @param $(trg) Target # @remark This define relies on double evaluation define def_inherit_one_prepending_deferred ifdef $(src)_$(prop) ifndef $(trg)_$(prop) $(trg)_$(prop) = $$($(src)_$(prop)) endif endif endef ## Inherit one template property in a prepending manner, deferred expansion. # @param $(prop) Property name # @param $(src) Source (parent) object. # @param $(trg) Target (child) object. define def_inherit_one_prepending_deferred_l ifdef $(src)_$(prop) ifeq ($$(flavor $(trg)_$(prop)),simple) $$(evalcall2 def_simple_2_recursive,$(trg)_$(prop)) endif $(trg)_$(prop) <= $$($(src)_$(prop)) endif endef ## @copydoc def_inherit_one_prepending_deferred_l define def_inherit_one_prepending_deferred_r ifdef $(src)_$(prop) ifeq ($$(flavor $(trg)_$(prop)),simple) $$(evalcall2 def_simple_2_recursive,$(trg)_$(prop)) endif $(trg)_$(prop) += $$($(src)_$(prop)) endif endef # EXPAND_BY = appending ## Inherit one template property in an appending manner. # @param $(prop) Property name # @param $(src) Source (parent) object. # @param $(trg) Target (child) object. define def_inherit_one_appending_now_l ifdef $(src)_$(prop) $(trg)_$(prop) := $($(trg)_$(prop)) $($(src)_$(prop)) endif endef ## @copydoc def_inherit_one_appending_now_l define def_inherit_one_appending_now_r ifdef $(src)_$(prop) $(trg)_$(prop) := $($(src)_$(prop)) $($(trg)_$(prop)) endif endef ## Inherit one template property in a non-accumulative manner, deferred expansion. # @param $(prop) Property name # @param $(src) Source # @param $(trg) Target # @remark This define relies on double evaluation define def_inherit_one_appending_deferred ifdef $(src)_$(prop) ifndef $(trg)_$(prop) $(trg)_$(prop) = $$($(src)_$(prop)) endif endif endef ## Inherit one template property in an appending manner, deferred expansion. # @param $(prop) Property name # @param $(src) Source (parent) object. # @param $(trg) Target (child) object. define def_inherit_one_appending_deferred_l ifdef $(src)_$(prop) ifeq ($$(flavor $(trg)_$(prop)),simple) $$(evalcall2 def_simple_2_recursive,$(trg)_$(prop)) endif $(trg)_$(prop) += $$($(src)_$(prop)) endif endef ## @copydoc def_inherit_one_appending_deferred_l define def_inherit_one_appending_deferred_r ifdef $(src)_$(prop) ifeq ($$(flavor $(trg)_$(prop)),simple) $$(evalcall2 def_simple_2_recursive,$(trg)_$(prop)) endif $(trg)_$(prop) <= $$($(src)_$(prop)) endif endef ## combines the specified properties $(1) with the $(_KEYWORDS) list. _INHERIT_JOIN_KEYWORDS = $(1) $(foreach keyword,$(_KEYWORDS), $(addsuffix .$(keyword), $(1))) ## Generic inheritance for use with targets templates and tools. # @param trg Object to consider for inheriting. # @param src_prefix What to prefix the value found in EXTENDS with to get the object. # @param load_function Load function for stuff that needs # @param properties List of the properties with straight expansion. # @param properties_now_l List of the properties with immediate expansion, accumulating on the left side. # @param properties_now_r List of the properties with immediate expansion, accumulating on the right side. # @param properties_deferred List of the properties with deferred expansion (e.g. function), non-accumulative . # @param properties_deferred_l List of the properties with deferred expansion (e.g. function), accumulating on the left side. # @param properties_deferred_r List of the properties with deferred expansion (e.g. function), accumulating on the right side. define def_inherit # Load it - loading is a mess, fix. ifneq ($(load_function),) local loading := $(patsubst $(src_prefix)%,%,$(trg)) $(evalvalctx $(load_function)) endif local src := $(strip $($(trg)_EXTENDS)) ifneq ($(src),) ifndef $(trg)_EXTENDS_STATUS_ $(trg)_EXTENDS_STATUS_ := 0 # Load the source. ifneq ($(load_function),) local loading := $(src) $(evalvalctx $(load_function)) endif # less typing. local src := $(src_prefix)$(src) # Recursivly process the parent (src) if it's inherting from somebody too. ifdef $(src)_EXTENDS ifneq ($($(src)_EXTENDS_STATUS_),42) # 'foreach' will create 'trg' in a new variable context hiding # out current variable. 'src' OTOH will be overwritten. $(foreach trg, $(src), $(evalval def_inherit)) local src := $(src_prefix)$(strip $($(trg)_EXTENDS)) endif endif # Get & check EXTENDS_BY. local by = $(strip $($(trg)_EXTENDS_BY)) ifeq ($(by),) local by = overriding else ifn1of ($(by), overriding appending prepending) $(error kBuild: Invalid EXTENDS_BY value '$(by)' on '$(trg)'!) endif # Inherit the properties. $(foreach prop, $(call _INHERIT_JOIN_KEYWORDS,$(properties)), $(eval $(def_inherit_one))) $(foreach prop, $(call _INHERIT_JOIN_KEYWORDS,$(properties_now_l)), $(eval $(def_inherit_one_$(by)_now_l))) $(foreach prop, $(call _INHERIT_JOIN_KEYWORDS,$(properties_now_r)), $(eval $(def_inherit_one_$(by)_now_r))) $(foreach prop, $(call _INHERIT_JOIN_KEYWORDS,$(properties_deferred)), $(eval $(def_inherit_one_$(by)_deferred))) $(foreach prop, $(call _INHERIT_JOIN_KEYWORDS,$(properties_deferred_l)), $(eval $(def_inherit_one_$(by)_deferred_l))) $(foreach prop, $(call _INHERIT_JOIN_KEYWORDS,$(properties_deferred_r)), $(eval $(def_inherit_one_$(by)_deferred_r))) # Mark the target as done. $(trg)_EXTENDS_STATUS_ := 42 else # Check for inheritance loops. ifneq ($($(trg)_EXTENDS_STATUS_),42) $(error kBuild: Target inheritance loop! target=$(trg) $(trg)_EXTENDS_STATUS_=$($(trg)_EXTENDS_STATUS_)) endif endif endif # Keyword inheritance. $(foreach prefix_keyword, $(join $(_KEYWORDS_PREFIX), $(addprefix :,$(_KEYWORDS_EXTENDS))), $(evalval def_inherit_keyword)) endef # def_inherit # # Load global units before doing any inheriting so they can add new properties. # # This only applies to the guys listed in the global USES since there is # no reliable way to deal with things on a target level without first # applying templates. So, to avoid having USES mess up all targets, # we'll make the global and per-target USES property work differently: # The global USES does not apply to targets, just globally. # ## Unit load function. # @param loading The unit name define def_unit_load_function ifndef UNIT_$(loading) UNIT_$(loading)_KMK_FILE := $(firstword $(foreach path, $(KBUILD_UNIT_PATHS) $(KBUILD_PATH)/units $(KBUILD_DEFAULT_PATHS), $(wildcard $(path)/$(loading).kmk))) ifeq ($(UNIT_$(loading)_KMK_FILE),) $(error kBuild: Cannot find include file for the unit '$(loading)'! Searched: $(KBUILD_UNIT_PATHS) $(KBUILD_PATH)/units $(KBUILD_DEFAULT_PATHS)) endif include $(UNIT_$(loading)_KMK_FILE) ifndef UNIT_$(loading) $(warning kBuild: UNIT_$(loading) was not defined by $(UNIT_$(loading)_KMK_FILE)!) endif endif endef # def_unit_load_function $(foreach loading, \ $(USES.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) \ $(USES.$(KBUILD_TARGET_CPU)) \ $(USES.$(KBUILD_TARGET_ARCH)) \ $(USES.$(KBUILD_TARGET)) \ $(USES.$(KBUILD_HOST).$(KBUILD_HOST_ARCH)) \ $(USES.$(KBUILD_HOST_CPU)) \ $(USES.$(KBUILD_HOST_ARCH)) \ $(USES.$(KBUILD_TARGET)) \ $(USES.$(KBUILD_TYPE)) \ $(USES),$(evalval def_unit_load_function)) # # Determin all the templates that is being used and make # sure they are present before we try collect keywords. # _TEMPLATES := $(TEMPLATE) define def_templates ifdef $(target)_TEMPLATE ifneq ("$($(target)_TEMPLATE)","$(strip $($(target)_TEMPLATE))") $$(error kBuild: The template name of target '$(target)' contains tabs ($($(target)_TEMPLATE))). Please remove them) endif _TEMPLATES += $($(target)_TEMPLATE) endif endef # def_templates $(foreach target, $(_ALL_TARGETS), $(eval $(def_templates))) _TEMPLATES := $(sort $(_TEMPLATES)) ## Template load function. # @param loading The template name. This is prefixed. define def_templates_load_function ifndef TEMPLATE_$(loading) TEMPLATE_$(loading)_KMK_FILE := $(firstword $(foreach path, $(KBUILD_TEMPLATE_PATHS) $(KBUILD_PATH)/templates $(KBUILD_DEFAULT_PATHS), $(wildcard $(path)/$(loading).kmk))) ifeq ($(TEMPLATE_$(loading)_KMK_FILE),) $(error kBuild: Cannot find include file for the template '$(loading)'! Searched: $(KBUILD_TEMPLATE_PATHS) $(KBUILD_PATH)/templates $(KBUILD_DEFAULT_PATHS)) endif include $(TEMPLATE_$(loading)_KMK_FILE) ifndef TEMPLATE_$(loading) $(warning kBuild: TEMPLATE_$(loading) was not defined by $(TEMPLATE_$(loading)_KMK_FILE)!) endif endif endef # def_templates_load_function $(foreach loading, $(_TEMPLATES), $(evalval def_templates_load_function)) # # Determin the keywords required for correct inherting and setup keyword inheritance. # # This means walking all the lists of immediate template and targets and # pick up all the BLD_T* keywords. Since templates that are referenced # indirectly in the inheritance hierarchy, the result from this exercise # might not be 100% accurate... :-/ # _BLD_TYPES := $(KBUILD_TYPE) _BLD_TARGETS := $(KBUILD_TARGET) $(KBUILD_HOSTS) _BLD_ARCHES := $(KBUILD_TARGET_ARCH) $(KBUILD_HOST_ARCH) _BLD_CPUS := $(KBUILD_TARGET_CPU) $(KBUILD_HOST_CPU) define def_collect_bld_xyz ifdef $(src)_BLD_TYPE ifn1of ($($(src)_BLD_TYPE), $(KBUILD_BLD_TYPES)) $(error kBuild: $(src)_BLD_TYPE=$($(src)_BLD_TYPE) not in KBUILD_BLD_TYPES={$(KBUILD_BLD_TYPES)}!) endif _BLD_TYPES += $($(src)_BLD_TYPE) endif ifdef $(src)_BLD_TRG ifn1of ($($(src)_BLD_TRG), $(KBUILD_OSES)) $(error kBuild: $(src)_BLD_TRG=$($(src)_BLD_TRG) not in KBUILD_OSES={$(KBUILD_OSES)}!) endif _BLD_TARGETS += $($(src)_BLD_TRG) endif ifdef $(src)_BLD_TRG_ARCH ifn1of ($($(src)_BLD_TRG_ARCH), $(KBUILD_ARCHES)) $(error kBuild: $(src)_BLD_TRG_ARCH=$($(src)_BLD_TRG_ARCH) not in KBUILD_ARCHES={$(KBUILD_ARCHES)}!) endif _BLD_ARCHES += $($(src)_BLD_TRG_ARCH) endif ifdef $(src)_BLD_TRG_CPU if1of ($($(src)_BLD_CPU), $(KBUILD_ARCHES) $(KBUILD_OSES) $(KBUILD_BLD_TYPES)) $(error kBuild: $(src)_BLD_TRG_CPU=$($(src)_BLD_TRG_CPU) found in KBUILD_ARCHES, KBUILD_OSES or KBUILD_BLD_TYPES!) endif _BLD_CPUS += $($(src)_BLD_TRG_CPU) endif endef # def_collect_bld_xyz $(foreach src, $(addprefix TEMPLATE_, $(_TEMPLATES)) $(_ALL_TARGETS) \ ,$(evalval def_collect_bld_xyz)) # Drop duplicate values. # WARNING! These list might not include keywords only involved in inheritance. _BLD_TYPES := $(sort $(_BLD_TYPES)) _BLD_TARGETS := $(sort $(_BLD_TARGETS)) _BLD_ARCHES := $(sort $(_BLD_ARCHES)) _BLD_CPUS := $(sort $(_BLD_CPUS)) ## Look for keywords which extends others and order them. # @param keyword # @param prefix # @param valid define def_keyword_ordering # Check for EXTENDS, fix and validate it if found. local src := $(strip $($(prefix)_$(keyword)_EXTENDS)) ifneq ($(src),) ifndef $(prefix)_$(keyword)_EXTENDS_STATUS_ ifn1of ($(src), $(valid)) $(error kBuild: $(keyword) tries to extend unknown keyword '$(src)'! (known = $(valid))) endif # Recursivly process the parent (src). ifneq ($($(prefix)_$(src)_EXTENDS_STATUS_),42) $(prefix)_$(keyword)_EXTENDS_STATUS_ := 0 # 'foreach' will create 'keyword' in a new variable context hiding # out current variable. 'src' OTOH will be overwritten. $(foreach keyword, $(src), $(evalval def_keyword_ordering)) local src := $(strip $($(prefix)_$(keyword)_EXTENDS)) endif # Check and strip EXTENDS_BY. local by = $(strip $($(prefix)_$(keyword)_EXTENDS_BY)) ifeq ($(by),) local by = overriding else ifn1of ($(by), overriding appending prepending) $(error kBuild: Invalid EXTENDS_BY value '$(by)' on '$(keyword)'!) endif # Update the attributes with stripped $(prefix)_$(keyword)_EXTENDS_BY := $(by) $(prefix)_$(keyword)_EXTENDS := $(src) # Add it to the list and mark it as done. _KEYWORDS_EXTENDS += $(keyword) _KEYWORDS_PREFIX += $(prefix) $(prefix)_$(keyword)_EXTENDS_STATUS_ := 42 else # Check for inheritance loops. ifneq ($($(trg)_EXTENDS_STATUS_),42) $(error kBuild: Keyword inheritance loop! keyword=$(keyword) $(prefix)_$(keyword)_EXTENDS_STATUS_=$($(prefix)_$(keyword)_EXTENDS_STATUS_)) endif endif else # Add it to the ordered list and mark it as done. _KEYWORDS_ORDERED += $(keyword) $(prefix)_$(src)_EXTENDS_STATUS_ := 42 endif endef # def_keyword_ordering $(eval-opt-var def_keyword_ordering) # Look for keywords which extends others and their parents, and from this # construct two lists. _KEYWORDS_ORDERED := _KEYWORDS_EXTENDS := _KEYWORDS_PREFIX := prefix := BLD_TYPE valid := $(KBUILD_BLD_TYPES) $(foreach keyword, $(_BLD_TYPES) , $(evalval def_keyword_ordering)) prefix := BLD_TRG valid := $(KBUILD_OSES) $(foreach keyword, $(_BLD_TARGETS), $(evalval def_keyword_ordering)) prefix := BLD_ARCH valid := $(KBUILD_ARCHES) $(foreach keyword, $(_BLD_ARCHES) , $(evalval def_keyword_ordering)) prefix := BLD_CPU valid := $(KBUILD_CPUS) $(foreach keyword, $(_BLD_CPUS) , $(evalval def_keyword_ordering)) ## @todo Inherit bld_trg.bld_arch for too? # Construct all the possible keywords. _KEYWORDS := $(_KEYWORDS_ORDERED) $(_KEYWORDS_EXTENDS) \ $(foreach bld_trg,$(_BLD_TARGETS),$(addprefix $(bld_trg).,$(_BLD_ARCHES))) ifdef KBUILD_PROFILE_SELF $(evalcall def_profile_self, done keywords) endif # # Target inheritance. # # This has to be done on a per target list basis as to avoid adding # incorrect properties that will wast memory, time, and may confuse # later strictness checks. This also has to be done *before* templates # are applied to the targets. Since we're doing that part rather # early on, the target inheritance feature is a bit restricted at # the moment. However, this will be addressed in a little(?) while. # src_prefix := load_function := properties_deferred_l := properties_deferred_r := # Fetches. properties := $(PROPS_FETCHES_SINGLE) properties_now_l := $(PROPS_FETCHES_ACCUMULATE_L) properties_now_r := $(PROPS_FETCHES_ACCUMULATE_R) properties_deferred := $(PROPS_FETCHES_DEFERRED) $(foreach trg, $(_ALL_FETCHES),$(evalval def_inherit)) ## Patches. - not implemented yet. #properties := $(PROPS_PATCHES_SINGLE) #properties_now_l := $(PROPS_PATCHES_ACCUMULATE_L) #properties_now_r := $(PROPS_PATCHES_ACCUMULATE_R) #properties_deferred := $(PROPS_PATCHES_DEFERRED) #$(foreach trg, $(_ALL_PATCHES),$(evalval def_inherit)) # Programs and build programs. properties := $(PROPS_PROGRAMS_SINGLE) properties_now_l := $(PROPS_PROGRAMS_ACCUMULATE_L) properties_now_r := $(PROPS_PROGRAMS_ACCUMULATE_R) properties_deferred := $(PROPS_PROGRAMS_DEFERRED) $(foreach trg, $(_ALL_BLDPROGS) $(_ALL_PROGRAMS),$(evalval def_inherit)) # Libraries and import libraries. properties := $(PROPS_LIBRARIES_SINGLE) properties_now_l := $(PROPS_LIBRARIES_ACCUMULATE_L) properties_now_r := $(PROPS_LIBRARIES_ACCUMULATE_R) properties_deferred := $(PROPS_LIBRARIES_DEFERRED) if1of ($(KBUILD_TARGET), nt os2 win) $(foreach trg, $(_ALL_LIBRARIES) $(_ALL_IMPORT_LIBS),$(evalval def_inherit)) else $(foreach trg, $(_ALL_LIBRARIES),$(evalval def_inherit)) endif # DLLs. properties := $(PROPS_DLLS_SINGLE) properties_now_l := $(PROPS_DLLS_ACCUMULATE_L) properties_now_r := $(PROPS_DLLS_ACCUMULATE_R) properties_deferred := $(PROPS_DLLS_DEFERRED) if1of ($(KBUILD_TARGET), nt os2 win) $(foreach trg, $(_ALL_DLLS),$(evalval def_inherit)) else $(foreach trg, $(_ALL_DLLS) $(_ALL_IMPORT_LIBS),$(evalval def_inherit)) endif # System modules. properties := $(PROPS_SYSMODS_SINGLE) properties_now_l := $(PROPS_SYSMODS_ACCUMULATE_L) properties_now_r := $(PROPS_SYSMODS_ACCUMULATE_R) properties_deferred := $(PROPS_SYSMODS_DEFERRED) $(foreach trg, $(_ALL_SYSMODS),$(evalval def_inherit)) # Misc binaries. properties := $(PROPS_MISCBINS_SINGLE) properties_now_l := $(PROPS_MISCBINS_ACCUMULATE_L) properties_now_r := $(PROPS_MISCBINS_ACCUMULATE_R) properties_deferred := $(PROPS_MISCBINS_DEFERRED) $(foreach trg, $(_ALL_MISCBINS),$(evalval def_inherit)) # Installs. properties := $(PROPS_INSTALLS_SINGLE) properties_now_l := $(PROPS_INSTALLS_ACCUMULATE_L) properties_now_r := $(PROPS_INSTALLS_ACCUMULATE_R) properties_deferred := $(PROPS_INSTALLS_DEFERRED) $(foreach trg, $(_ALL_INSTALLS),$(evalval def_inherit)) ifdef KBUILD_PROFILE_SELF $(evalcall def_profile_self, done target inheritance) endif # # Template Inheritance. # # This is much the same as with target inheritance, except we cannot # restrict the properties involved since we haven't got a clue which # target platforms/archs are using them. But, we can drop the instance # expansion we're doing for targets since there won't be any more # changes to either the source nor the target templates beyond this # exercise. # src_prefix := TEMPLATE_ load_function := def_templates_load_function properties := properties_now_l := properties_now_r := properties_deferred := $(PROPS_SINGLE) $(PROPS_DEFERRED) properties_deferred_l := $(PROPS_ACCUMULATE_L) properties_deferred_r := $(PROPS_ACCUMULATE_R) $(foreach trg, $(addprefix TEMPLATE_,$(_TEMPLATES)),$(evalval def_inherit)) # done inheriting. src_prefix := load_function := properties := properties_now_l := properties_now_r := properties_deferred := properties_deferred_l := properties_deferred_r := ifdef KBUILD_PROFILE_SELF $(evalcall def_profile_self, done template inheritance) endif # # Template/Target Expansion. # # Extend all targets with the values from the template. Doing this up front # allows more generic code and less mess down in the pass 2 target handling. # However it does eat a good deal of memory. # define def_inherit_template_workaround_target local _tmpl := $(firstword $($(target)_TEMPLATE) $(TEMPLATE)) local _bld_type := $(firstword $($(target)_BLD_TYPE) $(TEMPLATE_$(_tmpl)_BLD_TYPE) $(KBUILD_TYPE)) local _bld_trg := $(firstword $($(target)_BLD_TRG) $(TEMPLATE_$(_tmpl)_BLD_TRG) $(KBUILD_TARGET)) local _bld_trg_arch := $(firstword $($(target)_BLD_TRG_ARCH) $(TEMPLATE_$(_tmpl)_BLD_TRG_ARCH) $(KBUILD_TARGET_ARCH)) local _bld_trg_cpu := $(firstword $($(target)_BLD_TRG_CPU) $(TEMPLATE_$(_tmpl)_BLD_TRG_CPU) $(KBUILD_TARGET_CPU)) $(kb-exp-tmpl 1,$(target),$(_bld_trg),$(_bld_trg_arch),$(_bld_trg_cpu),$(_bld_type)) endef # def_inherit_template_workaround_target #$(kb-exp-tmpl 1,$(_ALL_TARGET_TARGETS),$(KBUILD_TARGET),$(KBUILD_TARGET_ARCH),$(KBUILD_TARGET_CPU),$(KBUILD_TYPE)) $(foreach target,$(_ALL_TARGET_TARGETS),$(evalval def_inherit_template_workaround_target)) define def_inherit_template_workaround_host local _tmpl := $(firstword $($(target)_TEMPLATE) $(TEMPLATE)) local _bld_type := $(firstword $($(target)_BLD_TYPE) $(TEMPLATE_$(_tmpl)_BLD_TYPE) $(KBUILD_TYPE)) local _bld_trg := $(firstword $($(target)_BLD_TRG) $(TEMPLATE_$(_tmpl)_BLD_TRG) $(KBUILD_HOST)) local _bld_trg_arch := $(firstword $($(target)_BLD_TRG_ARCH) $(TEMPLATE_$(_tmpl)_BLD_TRG_ARCH) $(KBUILD_HOST_ARCH)) local _bld_trg_cpu := $(firstword $($(target)_BLD_TRG_CPU) $(TEMPLATE_$(_tmpl)_BLD_TRG_CPU) $(KBUILD_HOST_CPU)) $(kb-exp-tmpl 1,$(target),$(_bld_trg),$(_bld_trg_arch),$(_bld_trg_cpu),$(_bld_type)) endef # def_inherit_template_workaround_target #$(kb-exp-tmpl 1,$(_ALL_HOST_TARGETS),$(KBUILD_HOST),$(KBUILD_HOST_ARCH),$(KBUILD_HOST_CPU),$(KBUILD_TYPE)) $(foreach target,$(_ALL_HOST_TARGETS),$(evalval def_inherit_template_workaround_host)) ifdef KBUILD_PROFILE_SELF $(evalcall def_profile_self, done template/target expansion) endif # # Include tools, sdks and units. # # The first part of this exercise is to figure out which TOOLS and SDKS # that should be included. # _TOOLS := $(TOOL.$(KBUILD_TARGET)) $(TOOL.$(KBUILD_TARGET_ARCH)) $(TOOL.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) \ $(TOOL.$(KBUILD_HOST)) $(TOOL.$(KBUILD_HOST_ARCH)) $(TOOL.$(KBUILD_HOST).$(KBUILD_HOST_ARCH)) \ $(TOOL) _SDKS := $(SDKS.$(KBUILD_TARGET)) $(SDKS.$(KBUILD_TARGET_ARCH)) $(SDKS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) \ $(SDKS.$(KBUILD_HOST)) $(SDKS.$(KBUILD_HOST_ARCH)) $(SDKS.$(KBUILD_HOST).$(KBUILD_HOST_ARCH)) \ $(SDKS.$(KBUILD_TYPE)) \ $(SDKS) _USES := $(USES.$(KBUILD_TARGET)) $(USES.$(KBUILD_TARGET_ARCH)) $(USES.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) \ $(USES.$(KBUILD_HOST)) $(USES.$(KBUILD_HOST_ARCH)) $(USES.$(KBUILD_HOST).$(KBUILD_HOST_ARCH)) \ $(USES.$(KBUILD_TYPE)) \ $(USES) define def_tools_sdks_target_source $(eval _TOOLS += $(foreach prop, $(PROPS_TOOLS), \ $($(source)_$(prop).$(_bld_trg)) \ $($(target)_$(source)_$(prop).$(_bld_trg)) \ $($(source)_$(prop).$(_bld_trg).$(_bld_trg_arch)) \ $($(target)_$(source)_$(prop).$(_bld_trg).$(_bld_trg_arch)) \ $($(source)_$(prop).$(_bld_trg_arch)) \ $($(target)_$(source)_$(prop).$(_bld_trg_arch)) \ $($(source)_$(prop)) \ $($(target)_$(source)_$(prop)))) $(eval _SDKS += \ $($(source)_SDKS.$(_bld_trg)) \ $($(target)_$(source)_SDKS.$(_bld_trg)) \ $($(source)_SDKS.$(_bld_trg).$(_bld_trg_arch)) \ $($(target)_$(source)_SDKS.$(_bld_trg).$(_bld_trg_arch)) \ $($(source)_SDKS.$(_bld_trg_arch)) \ $($(target)_$(source)_SDKS.$(_bld_trg_arch)) \ $($(source)_SDKS.$(KBUILD_TYPE)) \ $($(target)_$(source)_SDKS.$(KBUILD_TYPE)) \ $($(source)_SDKS) \ $($(target)_$(source)_SDKS)) $(eval _USES += \ $($(source)_USES.$(_bld_trg)) \ $($(target)_$(source)_USES.$(_bld_trg)) \ $($(source)_USES.$(_bld_trg).$(_bld_trg_arch)) \ $($(target)_$(source)_USES.$(_bld_trg).$(_bld_trg_arch)) \ $($(source)_USES.$(_bld_trg_arch)) \ $($(target)_$(source)_USES.$(_bld_trg_arch)) \ $($(source)_USES.$(KBUILD_TYPE)) \ $($(target)_$(source)_USES.$(KBUILD_TYPE)) \ $($(source)_USES) \ $($(target)_$(source)_USES)) endef # def_tools_sdks_target_source $(eval-opt-var def_tools_sdks_target_source) define def_tools_sdks_target local _bld_type := $(firstword $($(target)_BLD_TYPE) $(KBUILD_TYPE)) local _bld_trg := $(firstword $($(target)_BLD_TRG) $(bld_trg)) local _bld_trg_arch := $(firstword $($(target)_BLD_TRG_ARCH) $(bld_trg_arch)) local _bld_trg_cpu := $(firstword $($(target)_BLD_TRG_CPU) $(bld_trg_cpu)) $(eval _TOOLS += $(foreach prop, $(PROPS_TOOLS), \ $($(target)_$(prop).$(_bld_trg)) \ $($(target)_$(prop).$(_bld_trg_arch)) \ $($(target)_$(prop).$(_bld_trg).$(_bld_trg_arch)) \ $($(target)_$(prop)))) $(eval _SDKS += \ $($(target)_SDKS.$(_bld_trg)) \ $($(target)_SDKS.$(_bld_trg_arch)) \ $($(target)_SDKS.$(_bld_trg).$(_bld_trg_arch)) \ $($(target)_SDKS)) $(eval _USES += \ $($(target)_USES.$(_bld_trg)) \ $($(target)_USES.$(_bld_trg_arch)) \ $($(target)_USES.$(_bld_trg).$(_bld_trg_arch)) \ $($(target)_USES)) $(foreach source, \ $($(target)_SOURCES.$(_bld_trg)) \ $($(target)_SOURCES.$(_bld_trg_arch)) \ $($(target)_SOURCES.$(_bld_trg).$(_bld_trg_arch)) \ $($(target)_SOURCES.$(_bld_trg_cpu)) \ $($(target)_SOURCES.$(_bld_type)) \ $($(target)_SOURCES) \ , $(evalval def_tools_sdks_target_source)) endef # def_tools_sdks_target $(eval-opt-var def_tools_sdks_target) define def_tools_srcname_target local _bld_type := $(firstword $($(target)_BLD_TYPE) $(KBUILD_TYPE)) local _bld_trg := $(firstword $($(target)_BLD_TRG) $(bld_trg)) local _bld_trg_arch := $(firstword $($(target)_BLD_TRG_ARCH) $(bld_trg_arch)) local _bld_trg_cpu := $(firstword $($(target)_BLD_TRG_CPU) $(bld_trg_cpu)) $(foreach source, $(notdir\ $($(target)_SOURCES.$(_bld_trg)) \ $($(target)_SOURCES.$(_bld_trg_arch)) \ $($(target)_SOURCES.$(_bld_trg).$(_bld_trg_arch)) \ $($(target)_SOURCES.$(_bld_trg_cpu)) \ $($(target)_SOURCES.$(_bld_type)) \ $($(target)_SOURCES) \ ), $(evalval def_tools_sdks_target_source)) endef # def_tools_srcname_target $(eval-opt-var def_tools_srcname_target) bld_trg := $(KBUILD_TARGET) bld_trg_arch := $(KBUILD_TARGET_ARCH) bld_trg_cpu := $(KBUILD_TARGET_CPU) $(foreach target, $(_ALL_TARGET_TARGETS), $(evalval def_tools_sdks_target)) $(foreach target, $(_ALL_SRCNAME_TARGETS), $(evalval def_tools_srcname_target)) bld_trg := $(KBUILD_HOST) bld_trg_arch := $(KBUILD_HOST_ARCH) bld_trg_cpu := $(KBUILD_HOST_CPU) $(foreach target, $(_ALL_HOST_TARGETS), $(evalval def_tools_sdks_target)) _TOOLS := $(sort $(_TOOLS)) _SDKS := $(sort $(_SDKS)) ## Tool load function. # @param loading The tool name define def_tools_load_function ifndef TOOL_$(loading) TOOL_$(loading)_KMK_FILE := $(firstword $(foreach path, $(KBUILD_TOOL_PATHS) $(KBUILD_PATH)/tools $(KBUILD_DEFAULT_PATHS), $(wildcard $(path)/$(loading).kmk))) ifeq ($(TOOL_$(loading)_KMK_FILE),) $(error kBuild: Cannot find include file for the tool '$(loading)'! Searched: $(KBUILD_TOOL_PATHS) $(KBUILD_PATH)/tools $(KBUILD_DEFAULT_PATHS)) endif include $(TOOL_$(loading)_KMK_FILE) ifndef TOOL_$(loading) $(warning kBuild: TOOL_$(loading) was not defined by $(TOOL_$(loading)_KMK_FILE)!) endif endif endef # def_tools_include ## SDK load function. # @param loading The tool name define def_sdk_load_function ifndef SDK_$(loading) SDK_$(loading)_KMK_FILE := $(firstword $(foreach path, $(KBUILD_SDK_PATHS) $(KBUILD_PATH)/sdks $(KBUILD_DEFAULT_PATHS), $(wildcard $(path)/$(loading).kmk))) ifeq ($(SDK_$(loading)_KMK_FILE),) $(error kBuild: Cannot find include file for the SDK '$(loading)'! Searched: $(KBUILD_SDK_PATHS) $(KBUILD_PATH)/sdks $(KBUILD_DEFAULT_PATHS)) endif include $(SDK_$(loading)_KMK_FILE) ifndef SDK_$(loading) $(warning kBuild: SDK_$(loading) was not defined by $(SDK_$(loading)_KMK_FILE)!) endif endif endef # def_sdk_load_function properties := properties_now_l := properties_now_r := properties_deferred := $(PROPS_SINGLE) $(PROPS_DEFERRED) properties_deferred_l := $(PROPS_ACCUMULATE_L) properties_deferred_r := $(PROPS_ACCUMULATE_R) src_prefix := SDK_ load_function := def_sdk_load_function $(foreach trg, $(addprefix SDK_,$(_SDKS)), $(evalval def_inherit)) properties_deferred := $(PROPS_SINGLE) $(PROPS_DEFERRED) $(PROPS_TOOLS_ONLY) src_prefix := TOOL_ load_function := def_tools_load_function $(foreach trg, $(addprefix TOOL_,$(_TOOLS)), $(evalval def_inherit)) # done inheriting. src_prefix := load_function := properties := properties_now_l := properties_now_r := properties_deferred := properties_deferred_l := properties_deferred_r := # No inheriting for the uses, they're just global 'code'. $(foreach loading, $(_USES), $(evalval def_unit_load_function)) ifdef KBUILD_PROFILE_SELF $(evalcall def_profile_self, done tools + sdks + units) endif kbuild-3149/kBuild/footer.kmk0000644000175000017500000004050013252530224016115 0ustar locutuslocutus# $Id: footer.kmk 3128 2017-12-25 13:33:14Z bird $ ## @file # kBuild - File included at bottom of a makefile. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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 source of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # ifndef __footer_kmk__ # start-of-file-content ifdef KBUILD_PROFILE_SELF $(evalcall def_profile_self, start of footer.kmk) _KBUILD_TS_FOOTER_START := $(_KBUILD_TS_PREV) endif # # Variables. # (Some of these need initialization before including definitions using them.) # # All targets of each types. _ALL_BLDPROGS := $(BLDPROGS) $(BLDPROGS.$(KBUILD_HOST)) $(BLDPROGS.$(KBUILD_HOST).$(KBUILD_HOST_ARCH)) $(BLDPROGS.$(KBUILD_HOST_ARCH)) $(BLDPROGS.$(KBUILD_HOST_CPU)) $(BLDPROGS.$(KBUILD_TYPE)) _ALL_LIBRARIES := $(LIBRARIES) $(LIBRARIES.$(KBUILD_TARGET)) $(LIBRARIES.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(LIBRARIES.$(KBUILD_TARGET_ARCH)) $(LIBRARIES.$(KBUILD_TARGET_CPU)) $(LIBRARIES.$(KBUILD_TYPE)) _ALL_IMPORT_LIBS := $(IMPORT_LIBS) $(IMPORT_LIBS.$(KBUILD_TARGET)) $(IMPORT_LIBS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(IMPORT_LIBS.$(KBUILD_TARGET_ARCH)) $(IMPORT_LIBS.$(KBUILD_TARGET_CPU)) $(IMPORT_LIBS.$(KBUILD_TYPE)) _ALL_DLLS := $(DLLS) $(DLLS.$(KBUILD_TARGET)) $(DLLS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(DLLS.$(KBUILD_TARGET_ARCH)) $(DLLS.$(KBUILD_TARGET_CPU)) $(DLLS.$(KBUILD_TYPE)) _ALL_PROGRAMS := $(PROGRAMS) $(PROGRAMS.$(KBUILD_TARGET)) $(PROGRAMS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(PROGRAMS.$(KBUILD_TARGET_ARCH)) $(PROGRAMS.$(KBUILD_TARGET_CPU)) $(PROGRAMS.$(KBUILD_TYPE)) _ALL_SYSMODS := $(SYSMODS) $(SYSMODS.$(KBUILD_TARGET)) $(SYSMODS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(SYSMODS.$(KBUILD_TARGET_ARCH)) $(SYSMODS.$(KBUILD_TARGET_CPU)) $(SYSMODS.$(KBUILD_TYPE)) _ALL_MISCBINS := $(MISCBINS) $(MISCBINS.$(KBUILD_TARGET)) $(MISCBINS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(MISCBINS.$(KBUILD_TARGET_ARCH)) $(MISCBINS.$(KBUILD_TARGET_CPU)) $(MISCBINS.$(KBUILD_TYPE)) _ALL_OTHERS := $(OTHERS) $(OTHERS.$(KBUILD_TARGET)) $(OTHERS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(OTHERS.$(KBUILD_TARGET_ARCH)) $(OTHERS.$(KBUILD_TARGET_CPU)) $(OTHERS.$(KBUILD_TYPE)) _ALL_INSTALLS := $(INSTALLS) $(INSTALLS.$(KBUILD_TARGET)) $(INSTALLS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(INSTALLS.$(KBUILD_TARGET_ARCH)) $(INSTALLS.$(KBUILD_TARGET_CPU)) $(INSTALLS.$(KBUILD_TYPE)) _ALL_FETCHES := $(FETCHES) $(FETCHES.$(KBUILD_TARGET)) $(FETCHES.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(FETCHES.$(KBUILD_TARGET_ARCH)) $(FETCHES.$(KBUILD_TARGET_CPU)) $(FETCHES.$(KBUILD_TYPE)) _ALL_PATCHES := $(PATCHES) $(PATCHES.$(KBUILD_TARGET)) $(PATCHES.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(PATCHES.$(KBUILD_TARGET_ARCH)) $(PATCHES.$(KBUILD_TARGET_CPU)) $(PATCHES.$(KBUILD_TYPE)) # all targets. _ALL_TARGETS = \ $(_ALL_FETCHES) \ $(_ALL_PATCHES) \ $(_ALL_BLDPROGS) \ $(_ALL_LIBRARIES) \ $(_ALL_IMPORT_LIBS) \ $(_ALL_DLLS) \ $(_ALL_PROGRAMS) \ $(_ALL_SYSMODS) \ $(_ALL_MISCBINS) \ $(_ALL_INSTALLS) \ $(_ALL_OTHERS) # all $(KBUILD_TARGET) targets. _ALL_TARGET_TARGETS = \ $(_ALL_FETCHES) \ $(_ALL_PATCHES) \ $(_ALL_LIBRARIES) \ $(_ALL_IMPORT_LIBS) \ $(_ALL_DLLS) \ $(_ALL_PROGRAMS) \ $(_ALL_SYSMODS) \ $(_ALL_MISCBINS) \ $(_ALL_INSTALLS) \ $(_ALL_OTHERS) # all $(KBUILD_HOST) targets. _ALL_HOST_TARGETS = \ $(_ALL_BLDPROGS) # all targets making use of srcname. _ALL_SRCNAME_TARGETS = \ $(_ALL_FETCHES) \ $(_ALL_PATCHES) # Dependency files. (currently not on target level, only this global stuff) _DEPFILES := $(DEPFILES) $(DEPFILES.$(KBUILD_TARGET)) $(DEPFILES.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(DEPFILES.$(KBUILD_TARGET_ARCH)) $(DEPFILES.$(KBUILD_TARGET_CPU)) $(DEPFILES.$(KBUILD_TYPE)) # included dependency files. _DEPFILES_INCLUDED := # All kind of output files except for _OBJS and _DEPFILES. # Compiling or linking definition outputting other things that $@ and any # required dependency file must add those output files to this variable. _OUT_FILES := # Files which only requires cleaning up. _CLEAN_FILES := # all of a type _OBJS := _FETCHES := _DOWNLOADS:= _UNPACKS := _PATCHES := _UNFETCHES:= _BLDPROGS := _LIBS := _DLLS := _PROGRAMS := _SYSMODS := _MISCBINS := _STAGE_FILES := _STAGE_DIRS := _INSTALLS := _INSTALLS_FILES := _INSTALLS_DIRS := _DEBUG_STAGE_FILES := _DEBUG_STAGE_DIRS := _DEBUG_INSTALL_FILES := _DEBUG_INSTALL_DIRS := _OTHERS := _PACKING := _DIRS := $(PATH_TARGET)/ $(PATH_TARGET) $(BLDDIRS) _IMPORT_LIBS := # Implicit targets added while processing other targets (usually by units). _ALL_INSTALLS_IMPLICIT := # misc pass_prev := # # Footer macros # ## Figure out the tool for a target. # @param $1 normalized target. # @param $2 tooltype. # @param bld_trg build target. # @param bld_trg_arch build target architecture. # @param bld_type build target type. if 0 _TARGET_TOOL = $(strip $(firstword \ $($(1)_$(2)TOOL.$(bld_trg).$(bld_trg_arch)) \ $($(1)_$(2)TOOL.$(bld_trg)) \ $($(1)_$(2)TOOL) \ $($(1)_TOOL.$(bld_trg).$(bld_trg_arch)) \ $($(1)_TOOL.$(bld_trg)) \ $($(1)_TOOL) \ $($(2)TOOL.$(bld_trg).$(bld_trg_arch)) \ $($(2)TOOL.$(bld_trg)) \ $($(2)TOOL) \ $(TOOL.$(bld_trg).$(bld_trg_arch)) \ $(TOOL.$(bld_trg)) \ $(TOOL) \ )) else _TARGET_TOOL = $(strip $(firstword \ $($(1)_$(2)TOOL.$(bld_trg).$(bld_trg_arch).$(bld_type)) \ $($(1)_$(2)TOOL.$(bld_trg).$(bld_trg_arch)) \ $($(1)_$(2)TOOL.$(bld_trg).$(bld_type)) \ $($(1)_$(2)TOOL.$(bld_trg_arch)) \ $($(1)_$(2)TOOL.$(bld_trg)) \ $($(1)_$(2)TOOL.$(bld_type)) \ $($(1)_$(2)TOOL) \ $($(1)_TOOL.$(bld_trg).$(bld_trg_arch).$(bld_type)) \ $($(1)_TOOL.$(bld_trg).$(bld_trg_arch)) \ $($(1)_TOOL.$(bld_trg).$(bld_type)) \ $($(1)_TOOL.$(bld_trg_arch)) \ $($(1)_TOOL.$(bld_trg)) \ $($(1)_TOOL.$(bld_type)) \ $($(1)_TOOL) \ $($(2)TOOL.$(bld_trg).$(bld_trg_arch).$(bld_type)) \ $($(2)TOOL.$(bld_trg).$(bld_trg_arch)) \ $($(2)TOOL.$(bld_trg).$(bld_type)) \ $($(2)TOOL.$(bld_trg_arch)) \ $($(2)TOOL.$(bld_trg)) \ $($(2)TOOL.$(bld_type)) \ $($(2)TOOL) \ $(TOOL.$(bld_trg).$(bld_trg_arch).$(bld_type)) \ $(TOOL.$(bld_trg).$(bld_trg_arch)) \ $(TOOL.$(bld_trg).$(bld_type)) \ $(TOOL.$(bld_trg_arch)) \ $(TOOL.$(bld_trg)) \ $(TOOL.$(bld_type)) \ $(TOOL) \ )) endif ## Figure out the actual name of an installed file. # @param $1 The file to install. # @param $2 The target name. # @param $3 The _INST value (can be empty). # @param $4 The installation root directory. _INSTALL_FILE = $(patsubst %/,%/$(notdir $(1)),$(if $(3),$(4)/$(3),$(4)/)) ## # Function for getting the first defined propert value. # # @param 1 The property name. # @param 2 The default property name, empty if none. # @param 3 What to return if all variables are empty. (optional) # @note Implicit parameters: target, bld_trg, bld_trg_arch, bld_trg_cpu, bld_type. # @returns Expanded property value. # define def_fn_prop_get_first_defined local .RETURN := $(firstdefined \ $(target)_$(1).$(bld_trg).$(bld_trg_arch).$(bld_type) \ $(target)_$(1).$(bld_trg).$(bld_trg_arch) \ $(target)_$(1).$(bld_trg).$(bld_type) \ $(target)_$(1).$(bld_trg_cpu) \ $(target)_$(1).$(bld_trg_arch) \ $(target)_$(1).$(bld_trg) \ $(target)_$(1).$(bld_type) \ $(target)_$(1) \ ) ifeq ($(.RETURN),) ifneq ($(2),) local .RETURN := $(firstdefined \ $(2).$(bld_trg).$(bld_trg_arch).$(bld_type) \ $(2).$(bld_trg).$(bld_trg_arch) \ $(2).$(bld_trg).$(bld_type) \ $(2).$(bld_trg_cpu) \ $(2).$(bld_trg_arch) \ $(2).$(bld_trg) \ $(2).$(bld_type) \ $(2) \ 3 \ ) else local .RETURN := $(firstdefined \ kBuildGlobalDefaults_$(1).$(bld_trg).$(bld_trg_arch).$(bld_type) \ kBuildGlobalDefaults_$(1).$(bld_trg).$(bld_trg_arch) \ kBuildGlobalDefaults_$(1).$(bld_trg).$(bld_type) \ kBuildGlobalDefaults_$(1).$(bld_trg_cpu) \ kBuildGlobalDefaults_$(1).$(bld_trg_arch) \ kBuildGlobalDefaults_$(1).$(bld_trg) \ kBuildGlobalDefaults_$(1).$(bld_type) \ kBuildGlobalDefaults_$(1) \ 3 \ ) endif endif local .RETURN := $(strip $($(.RETURN))) endef # def_fn_prop_get_first_defined ## # Function for getting the first property value (ignoring empty defines). # # @param 1 The property name. # @param 2 The default property name, empty if none. # @param 3 What to return if all variables are empty. (optional) # @note Implicit parameters: target, bld_trg, bld_trg_arch, bld_trg_cpu, bld_type. # @returns First word. # define def_fn_prop_get_first_word local .RETURN := $(firstword \ $($(target)_$(1).$(bld_trg).$(bld_trg_arch).$(bld_type)) \ $($(target)_$(1).$(bld_trg).$(bld_trg_arch)) \ $($(target)_$(1).$(bld_trg).$(bld_type)) \ $($(target)_$(1).$(bld_trg_cpu)) \ $($(target)_$(1).$(bld_trg_arch)) \ $($(target)_$(1).$(bld_trg)) \ $($(target)_$(1).$(bld_type)) \ $($(target)_$(1)) \ ) ifeq ($(.RETURN),) ifneq ($(2),) local .RETURN := $(firstword \ $($(2).$(bld_trg).$(bld_trg_arch).$(bld_type)) \ $($(2).$(bld_trg).$(bld_trg_arch)) \ $($(2).$(bld_trg).$(bld_type)) \ $($(2).$(bld_trg_cpu)) \ $($(2).$(bld_trg_arch)) \ $($(2).$(bld_trg)) \ $($(2).$(bld_type)) \ $($(2)) \ $(3) \ ) else local .RETURN := $(firstword \ $(kBuildGlobalDefaults_$(1).$(bld_trg).$(bld_trg_arch).$(bld_type)) \ $(kBuildGlobalDefaults_$(1).$(bld_trg).$(bld_trg_arch)) \ $(kBuildGlobalDefaults_$(1).$(bld_trg).$(bld_type)) \ $(kBuildGlobalDefaults_$(1).$(bld_trg_cpu)) \ $(kBuildGlobalDefaults_$(1).$(bld_trg_arch)) \ $(kBuildGlobalDefaults_$(1).$(bld_trg)) \ $(kBuildGlobalDefaults_$(1).$(bld_type)) \ $(kBuildGlobalDefaults_$(1)) \ $(3) \ ) endif endif endef # def_fn_prop_get_first_word ## # Function for collecting properties, priority ones last. # # @param 1 The property name. # @param 2 The default property name, empty if none. # @note Implicit parameters: target, bld_trg, bld_trg_arch, bld_trg_cpu, bld_type. # @returns All properties. # define def_fn_prop_get_all_priority_last local .RETURN := \ $($(target)_$(1)) \ $($(target)_$(1).$(bld_type)) \ $($(target)_$(1).$(bld_trg)) \ $($(target)_$(1).$(bld_trg_arch)) \ $($(target)_$(1).$(bld_trg_cpu)) \ $($(target)_$(1).$(bld_trg).$(bld_type)) \ $($(target)_$(1).$(bld_trg).$(bld_trg_arch)) \ $($(target)_$(1).$(bld_trg).$(bld_trg_arch).$(bld_type)) endef # def_fn_prop_get_all_priority_last ## # Function for collecting properties with prefixing, priority ones last. # # @param 1 The property name. # @param 2 Something like $(NLTAB). # @note Implicit parameters: target, bld_trg, bld_trg_arch, bld_trg_cpu, bld_type. # @returns All properties. # define def_fn_prop_get_all_prefixed_priority_last local .RETURN := \ $(if $($(target)_$(1)),$(2),)$($(target)_$(1)) \ $(if $($(target)_$(1).$(bld_type)),$(2),)$($(target)_$(1).$(bld_type)) \ $(if $($(target)_$(1).$(bld_trg)),$(2),)$($(target)_$(1).$(bld_trg)) \ $(if $($(target)_$(1).$(bld_trg_arch)),$(2),)$($(target)_$(1).$(bld_trg_arch)) \ $(if $($(target)_$(1).$(bld_trg_cpu)),$(2),)$($(target)_$(1).$(bld_trg_cpu)) \ $(if $($(target)_$(1).$(bld_trg).$(bld_type)),$(2),)$($(target)_$(1).$(bld_trg).$(bld_type)) \ $(if $($(target)_$(1).$(bld_trg).$(bld_trg_arch)),$(2),)$($(target)_$(1).$(bld_trg).$(bld_trg_arch)) \ $(if $($(target)_$(1).$(bld_trg).$(bld_trg_arch).$(bld_type)),$(2),)$($(target)_$(1).$(bld_trg).$(bld_trg_arch).$(bld_type)) endef # def_fn_prop_get_all_prefixed_priority_last # # The main body. # include $(KBUILD_PATH)/footer-inherit-uses-tools.kmk include $(KBUILD_PATH)/footer-pass1.kmk include $(KBUILD_PATH)/footer-pass2-fetches.kmk include $(KBUILD_PATH)/footer-pass2-patches.kmk include $(KBUILD_PATH)/footer-pass2-compiling-targets.kmk include $(KBUILD_PATH)/footer-pass2-installs.kmk include $(KBUILD_PATH)/footer-misc.kmk include $(KBUILD_PATH)/footer-passes.kmk # # THE MAIN RULES # all_recursive: $(pass_prev) rebuild: clean + $(MAKE) -f $(firstword $(MAKEFILE_LIST)) all_recursive # @todo make this a non-default pass! uninstall:: $(RM) -f -- $(_INSTALLS_FILES) install:: pass_installs # misc shortcuts (use secondary expansion here to save strcache[file] space). targets: bldprogs libraries dlls programs sysmods miscbins others installs objects: $$(_OBJS) bldprogs: $$(_BLDPROGS) libraries: $$(_LIBS) $$(_IMPORT_LIBS) $$(_OTHER_LIBRARIES) dlls: $$(_DLLS) programs: $$(_PROGRAMS) sysmods: $$(_SYSMODS) miscbins: $$(_MISCBINS) others: $$(_OTHERS) stagings: $$(_INSTALLS) $$(_STAGE_DIRS) $$(_STAGE_FILES) installs: $$(_INSTALLS_DIRS) $$(_INSTALLS_FILES) install-debug: $$(_DEBUG_INSTALL_DIRS) $$(_DEBUG_INSTALL_FILES) # # kBuild debugging stuff. # ## @todo this doesn't work. Move to a debug unit and expand it. show_targets: @$(foreach target, $(_ALL_TARGETS),\ @$(ECHO) "target: $(target)" $(NLTAB)\ @$(ECHO) " $(target)_0_OUTDIR=$($(target)_0_OUTDIR)" $(NLTAB)\ @$(ECHO) " $(target)_1_TARGET=$($(target)_1_TARGET)" $(NLTAB)\ @$(ECHO) " INSTARGET_$(target)=$(INSTARGET_$(target))" $(NLTAB)\ $(foreach prop,$(PROPS_SINGLE) $(PROPS_ACCUMULATE_L) $(PROPS_ACCUMULATE_R) 2_OBJS CLEAN, \ $(eval _tmp:=$(firstword $($(target)_BLD_TRG) $(KBUILD_TARGET))) \ $(if $($(target)_$(prop).$(_tmp)),\ @$(ECHO) " $(target)_$(prop).$(_tmp)=$($(target)_$(prop).$(_tmp))" $(NLTAB)) \ $(if $($(target)_$(prop)), $(NLTAB)@$(ECHO) " $(target)_$(prop)=$($(target)_$(prop))" $(NLTAB)) \ )\ $(foreach prop,$(PROPS_DEFERRED), \ $(eval _tmp:=$(firstword $($(target)_BLD_TRG) $(KBUILD_TARGET))) \ $(if $(value $(target)_$(prop).$(_tmp)),\ @$(ECHO) ' $(target)_$(prop).$(_tmp)=$(value $(TARGET)_$(prop).$(_tmp))' $(NLTAB)) \ $(if $(value $(target)_$(prop)), $(NLTAB)@$(ECHO) ' $(target)_$(prop)=$(value $(target)_$(prop))' $(NLTAB)) \ )) # # Include dependency files. # ifdef _DEPFILES # TODO: first works the second doesn't, provided _KB_INCLUDE_DEPS is undefined: # if "$(_KB_INCLUDE_DEPS)" == "1" # if $(_KB_INCLUDE_DEPS) == "1" ifdef KB_HAVE_INCLUDEDEP_QUEUE includedep-queue $(_DEPFILES) else $(foreach dep, $(_DEPFILES), $(eval includedep $(dep))) endif endif ifdef KBUILD_PROFILE_SELF $(evalcall def_profile_self, end of footer.kmk) _KBUILD_TS_FOOTER_END := $(_KBUILD_TS_PREV) ifneq ($(KBUILD_PROFILE_SELF),0) $(info prof: ALL=$(words $(_ALL_TARGETS)) BLDPROGS=$(words $(_ALL_BLDPROGS)) LIBRARIES=$(words $(_ALL_LIBRARIES)) IMPORT_LIBS=$(words $(IMPORT_LIBS)) DLLS=$(words $(DLLS)) PROGRAMS=$(words $(_ALL_PROGRAMS)) ) $(info prof: SYSMODS=$(words $(_ALL_SYSMODS)) MISCBINS=$(words $(_ALL_MISCBINS)) OTHERS=$(words $(_ALL_OTHERS)) INSTALLS=$(words $(_ALL_INSTALLS)) FETCHES=$(words $(_ALL_FETCHES)) PACKING=$(words $(_PACKING)) TESTING=$(words $(TESTING)) ) $(info prof: DIRS=$(words $(_DIR_ALL)) TOOLS=$(words $(_TOOLS)) SDKS=$(words $(_SDKS)) USES=$(words $(_USES)) OUT_FILES=$(words $(_OUT_FILES)) OBJS=$(words $(_OBJS)) CLEAN_FILES=$(words $(CLEAN_FILES) $(OTHER_CLEAN)) ) $(info prof: DEPFILES_INCLUDED=$(words $(_DEPFILES_INCLUDED)) DEPFILES=$(words $(_DEPFILES)) MAKEFILES=$(words $(MAKEFILE_LIST)) ) endif endif # end-of-file-content __footer_kmk__ := target endif # !defined(__footer_kmk__) kbuild-3149/kBuild/up.kmk0000644000175000017500000000357013252530251015251 0ustar locutuslocutus# $Id: up.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild - File included at top of a up forwarder makefile. # This method is DEPRECATED. Use Makefile.kup files instead. # # # Copyright (c) 2005-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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 source of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite typetype0, Boston, MA 0sourcetargettargettarget-targettype07 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # include the header to get the right MAKE and to include config.kmk # files since these may contain global goals. include $(PATH_KBUILD)/header.kmk UP_TO ?= .. # typical kbuild goals. all_recursive \ binaries \ clean \ dlls \ libraries \ needed \ nothing \ objects \ others \ packing \ pass_binaries \ pass_clean \ pass_dlls \ pass_needed \ pass_nothing \ pass_others \ pass_packing \ programs \ rebuild \ sysmods \ target \ : $(MAKE) -C $(UP_TO) $@ # the syntax checkers. %.o %.obj: $(MAKE) -C $(UP_TO) $@ kbuild-3149/kBuild/doc/0000755000175000017500000000000013252530251014661 5ustar locutuslocutuskbuild-3149/kBuild/doc/Makefile.kmk0000644000175000017500000000366613252530251017115 0ustar locutuslocutusDEPTH = ../.. include ../header.kmk TXTFILES = \ QuickReference-kmk.txt \ QuickReference-kBuild.txt define genrule all: $(name).html clean:: kmk_rm -f $(name).html $(name).html: $(name).txt LC_ALL=C rst2html.py --no-generator $$< $$@ $(name).o: $(name).html .PHONY: $(name).o endef $(foreach name, $(basename $(TXTFILES)), $(eval $(genrule))) # # For generating the basis for the target properties table. # my_tp.1 = BLDPROGS PROGRAMS my_tp.2 = LIBRARIES my_tp.3 = IMPORT_LIBS DLLS my_tp.4 = DLLS my_tp.5 = PROGRAMS my_tp.6 = SYSMODS my_tp.7 = MISCBINS my_tp.8 = INSTALLS my_tp.9 = FETCHES my_tp.a = OTHERS my_tp = 1 2 3 4 5 6 7 8 9 a tpc := $(translate $(my_tp),$(SP)) define def_target_prop_rule target-properties:: @$$(PRINTF) '|%-2s| %-18s| %-6s|%$(expr 79-33)s|\n' "$(kind)" "``$(prop)``" "$(my_tmp_which)" "" @$$(ECHO) '+--+-------------------+-------+----------------------------------------------+' endef define def_target_prop_doit my_tmp_which := $(foreach x,$(my_tp),$(if $(intersects \ $(prop),\ $(foreach nm,$(my_tp.$(x)),$(foreach suff,SINGLE DEFERRED ACCUMULATE_R ACCUMULATE_L,$(PROPS_$(nm)_$(suff)))))\ ,$(x),)) my_tmp_which := $(translate $(my_tmp_which),$(SP)) $(for local i = 1, $i < 10, local i := $(expr $i + 1),$(for local l = $(expr 10 - $i + 1), $l > 3, local l := $(expr $l - 1), \ $(eval my_tmp_which:=$(subst $(substr $(tpc), $i, $l),$i-$(substr $(tpc),$(expr $i + $l - 1),1),$(my_tmp_which)))\ ) ) $(eval $(def_target_prop_rule)) endef kind := S $(foreach prop,$(sort $(PROPS_SINGLE)),$(evalcall def_target_prop_doit)) kind := D $(foreach prop,$(sort $(PROPS_DEFERRED)),$(evalcall def_target_prop_doit)) kind := Ar $(foreach prop,$(sort $(PROPS_ACCUMULATE_R)),$(evalcall def_target_prop_doit)) kind := Al $(foreach prop,$(sort $(PROPS_ACCUMULATE_L)),$(evalcall def_target_prop_doit)) #kind := To #$(foreach prop,$(sort $(PROPS_TOOLS_ONLY)),$(evalcall def_target_prop_doit)) kbuild-3149/kBuild/doc/QuickReference-kmk.html0000644000175000017500000022062213252530251021226 0ustar locutuslocutus kmk Quick Reference

kmk Quick Reference

This is an attempt at summarizing all directives, functions, special variables, special targets, built-in commands, external commands, and kmk-expressions. Since all the features are included, the quickness of this reference can be disputed. ;-)

Directives

Here is a summary of the directives kmk recognizes:

Define a multi-line, recursively-expanded variable:

define variable
endef

Conditionally evaluate part of the makefile:

ifdef variable
ifndef variable
ifeq (a,b)
ifeq "a" "b"
ifeq 'a' 'b'
ifneq (a,b)
ifneq "a" "b"
ifneq 'a' 'b'
if1of (set-a,set-b)             [1]
ifn1of (set-a,set-b)            [1]
if expression                   [1]
else
endif

Include another makefile:

include file
-include file
sinclude file

Include another dependency file [1]:

includedep file

Define a variable, overriding any previous definition, even one from the command line:

override variable = value
override variable := value
override variable += value
override variable <= value      [1]
override variable ?= value
override define variable
endef

Tell kmk to export all variables to child processes by default:

export

Tell kmk whether or not to export a particular variable to child processes:

export variable
export variable = value
export variable := value
export variable += value
export variable <= value        [1]
export variable ?= value
unexport variable

Define a variable in the local context instead of the global one [1]:

local variable = value
local variable := value
local variable += value
local variable <= value
local variable ?= value
local define variable
endef

Specify a search path for files matching a % pattern:

vpath pattern path

Remove all search paths previously specified for pattern:

vpath pattern

Remove all search paths previously specified in any vpath directive:

vpath

Automatic variables

Here is a summary of the automatic variables.

Variable Description
$@ The file name of the target.
$< The name of the first prerequisite.
$? The names of all the prerequisites that are newer than the target, with spaces between them.
$^ The names of all the prerequisites, duplicates omitted.
$+ The names of all the prerequisites, duplicates and order preserved
$* The stem with which an implicit rule matches.
$| The name of all the order only prerequisites.
$(@D) The directory part of $@.
$(<D) The directory part of $<.
$(?D) The directory part of $?.
$(^D) The directory part of %^.
$(+D) The directory part of $+.
$(*D) The directory part of $*.
$(|D) The directory part of $|.
$(@F) The file-within-directory part of $@.
$(<F) The file-within-directory part of $<.
$(?F) The file-within-directory part of $?.
$(^F) The file-within-directory part of $^.
$(+F) The file-within-directory part of $+.
$(*F) The file-within-directory part of $*.
$(|F) The file-within-directory part of $|.

Special variables

All variables starting with a . is reserved by kmk. The following variables are specially used or/and defined by kmk:

Variable Description
.DEFAULT_GOAL The makefile default goal. You can set this in the makefile, if you don't it will default to the first target that is encountered.
.FEATURES List of GNU make features. Do not set this.
.INCLUDE_DIRS List of include directories, -I arguments and defaults. Do not set this.
.RECIPEPREFIX Recipe prefix, defaults to tab.
.VARIABLES Special variable which exands to the list of variable. Do not set this.
CURDIR Set to the pathname of the current working directory (after all -C options are processed, if any). Do not set this.
KBUILD_VERSION, KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH, KBUILD_KMK_REVISION The kBuild version string and the break down into individual components. [1]
KBUILD_HOST [1] The host operating system.
KBUILD_HOST_ARCH [1] The host architecture.
KBUILD_HOST_CPU [1] The host CPU kmk is built for, set to blend if not any particular CPU.
KBUILD_PATH [1] Where the kBuild scripts are.
KBUILD_BIN_PATH [1] Where the host specific kBuild binaries are.
KMK [1], MAKE The name with which kmk was invoked. Using this variable in recipes has special meaning.
KMK_BUILTIN [1] List of built-in commands.
KMK_FEATURES [1] List of kmk specific features.
KMK_FLAGS [1]

The flags given to kmk. You can set this in the environment or a makefile to set flags.

It is never appropriate to use KMK_FLAGS directly in a recipe line: its contents may not be quoted correctly for use in the shell. Always allow recursive kmk's to obtain these values through the environment from its parent.

KMK_LEVEL [1] The number of levels of recursion (sub-makes).
KMK_VERSION [1] The GNU make version number.
MAKECMDGOALS The targets given to kmk on the command line. Do not set this.
MAKEFILES Makefiles to be read on every invocation of kmk.
MAKEFILE_LIST List of the makefiles that kmk has opened.
MAKESHELL OS/2 and MS-DOS only, the name of the command interpreter that is to be used by kmk. This value takes precedence over the value of SHELL.
SHELL The name of the default command interpreter, kmk_ash. You can set SHELL in the makefile to change the shell used to run recipes. The SHELL variable is handled specially when importing from and exporting to the environment.
SUFFIXES The default list of suffixes before kmk reads any makefiles (always empty).
VPATH Directory search path for files not found in the current directory.

The following variables reflects kmk options. Do not set these. [1]

Variable Description
KMK_OPTS_JOBS -j slots, 0 if not given.
KMK_OPTS_KEEP_GOING -k indictor (0/1).
KMK_OPTS_JUST_PRINT -n indicator (0/1).
KMK_OPTS_PRORITY --priority level, 0 if not given.
KMK_OPTS_AFFINITY --affinity mask, 0 if not given.
KMK_OPTS_STATISTICS --statistics indicator (0/1).
KMK_OPTS_PRINT_TIME The --print-time value.
KMK_OPTS_PRETTY_COMMAND_PRINTING --pretty-command-printing indicator.

Special Targets

Certain names have special meanings if they appear as targets.

Target Description
.DEFAULT The recipe is used for any target for which no rules are found.
.DELETE_ON_ERROR If mentioned, kmk will delete the targets of a rule if it has changed and its recipe fails or is interrupted.
.EXPORT_ALL_VARIABLES If mentioned, all variables will by default be exported to child processes.
.IGNORE Ignore errors in the execution of the recipe for the targets .IGNORE depends on, if no prequisites all targets are affected.
.INTERMEDIATE The prerequisites are treated as intermediate files (implicite rules).
.LOW_RESOLUTION_TIME kmk will assume prerequisite files are created with low resolution time stamps.
.NOTPARALLEL If mentioned without any prerequisites, kmk will run serially as if -j1 was given. If it has prerequisites kmk [1] will only do this for the targets among them.
.PHONY The prerequisites are considered phony and will be rebuilt unconditionally.
.PRECIOUS The targets which .PRECIOUS depends will to be deleted if kmk is killed or interrupted while their building.
.SECONDARY The prerequisites are treated as intermediate files, except that they are never automatically deleted. If used with no prerequisites all targets gets this treatement.
.SECONDEXPANSION If mentioned, all prerequisite lists after it will be expanded a second time after all makefiles have been read.
.SECONDTARGETEXPANSION [1] If mentioned, all targets after it will be expanded a second time after all makefiles have been read.
.SILENT kmk will not print the recipe for targets listed as prerequisites, if none then it applies to all targets.
.SUFFIXES The prerequisites are the list of suffixes used in checking for suffix rules. If it appears without prerequisites it the suffix will be cleared.

Commands

Builtin commands [1] all start with kmk_builtin_, so in order to save space this prefix has been omitted in the table below. All commands comes in an external edition that can be used by/in the shell, these are prefixed kmk_.

Command Description
append Append text to a file. The builtin version can output the value of a variable or the commands of a target.
cat The BSD cat command.
chmod The BSD chmod command.
cmp The BSD cmp command.
cp The BSD cp command with some twaking.
echo The BSD echo command.
expr The BSD expr command.
install The BSD install command with some tweaking.
kDepIDB Extract dependencies from a Visual C++ .IDB file.
ln The BSD ln command.
md5sum Typical MD5 sum program, custom kBuild version.
mkdir The BSD mkdir command.
mv The BSD mv command with some tweaking.
printf The BSD printf command.
rm The BSD rm command with some tweaking.
rmdir The BSD rmdir command with some tweaking.
sleep Typical sleep program, custom kBuild version.
test The BSD test program with some tweaking.

Some additional external commands are available in the kmk / kBuild environment (kSomething command are not prefixed with kmk_):

Command Description
kDepPre Extract dependencies from the C/C++ preprocessor output.
kObjCache Simple object file cache program.
ash Almquist's shell (NetBSD variant).
gmake Vanilla GNU make from same sources as kmk.
redirect Shell avoidance tool. Sets up file descriptors, environment variables and current directory before kicking of program.
sed GNU sed with some tweaks to avoid involving the shell.
time Stopwatch utility for measuring program execution time(s).

kmk-expression

kmk-expressions [1] are related to the C/C++ preprocessor in some ways as well as nmake and BSD make. There are however some peculiarities because of the way GNU make choose to represent booleans in its function library, so, strings can be turned into boolean by taking any non-empty string as true.

Quoting using single quotes results in hard strings, while double quotes and unquoted string results in soft strings that can be converted to number or boolean to fit the situation.

Here's the operator table in decending precedence order:

Operator Type Description
defined Unary Checks if the following variable exists.
exists Checks if the following file exists.
target Checks if the following target exists.
bool Casts the following value to boolean.
num Casts the following value to a number.
str Casts the following value to a string.
! Unary Logical NOT.
+ Pluss prefix.
- Minus prefix.
~ Bitwise one's complement.
* Binary Multiplication (product).
/ Division (quotient).
% Modulus (remainder).
+ Binary Addition (sum).
- Subtraction (difference).
<< Binary Bitwise left shift.
>> Bitwise right shift.
<= Binary Less or equal than.
< Less than.
>= Greater or equal than.
> Greater than.
== Binary Equal to.
!= Not equal to.
& Binary Bitwise AND.
^ Binary Bitwise XOR.
| Binary Bitwise OR.
&& Binary Logical AND.
|| Binary Logical OR.

Built-in functions

String Manipulation Functions:

Replace from with to in text:

$(subst from,to,text)

Replace words matching pattern with replacement in text:

$(patsubst pattern,replacement,text)

Remove excess whitespace characters from string:

$(strip string)

Locate find in text, returning find if found:

$(findstring find,text)

Select words in text that match one of the pattern words:

$(filter pattern...,text)

Select words in text that do not match any of the pattern words:

$(filter-out pattern...,text)

Sort the words in list lexicographically, removing duplicates:

$(sort list)

Sort the words in list lexicographically in reserve order, removing duplicates [1]:

$(rsort list)

Count the number of words in text:

$(words text)

Extract the nth word (one-origin) of text:

$(word n,text)

Returns the list of words in text from s to e (one-origin):

$(wordlist s,e,text)

Extract the first word of names:

$(firstword names...)

Extract the last word of names:

$(lastword names...)

Join two parallel lists of words:

$(join list1,list2)

Fold text to upper case [1]:

$(toupper text)

Fold text to lower case [1]:

$(tolower text)

String formatting a la the unix printf command [1]:

$(printf fmt, arg...)

Return the length of a string or a (unexpanded) variable [1]:

$(length string)
$(length-var var)

Find the position of needle in haystack, returns 0 if not found. Negative start indices are relative to the end of haystack, while positive ones are one based [1]:

$(pos needle, haystack[, start])
$(lastpos needle, haystack[, start])

Returns the specified substring. The start works like with $(pos ). If the substring is partially outside the string the result will be padded with pad if present [1]:

$(substr string, start[, length[, pad]])

Insert in into str at the specified position. n works like with $(pos ), except that 0 is the end of the string [1]:

$(insert in, str[, n[, length[, pad]]])

Translate string exchanging characters in from-set with to-set, optionally completing to-set with pad-char if specified. If no pad-char characters absent in to-set will be deleted [1]:

$(translate string, from-set[, to-set[, pad-char]])

Functions for file names:

Extract the directory part of each file name:

$(dir names...)

Extract the non-directory part of each file name:

$(notdir names...)

Extract the suffix (the last . and following characters) of each file name:

$(suffix names...)

Extract the base name (name without suffix) of each file name:

$(basename names...)

Extract the root specification of each file name (a bit complicated on Windows & OS/2) [1]:

$(root names...)

Append suffix to each word in names:

$(addsuffix suffix,names...)

Prepend prefix to each word in names:

$(addprefix prefix,names...)

Find file names matching a shell file name pattern (not a % pattern):

$(wildcard pattern...)

For each file name in names, expand to an absolute name that does not contain any ., .., nor symlinks:

$(realpath names...)

For each file name in names, expand to an absolute name that does not contain any . or .. components, but preserves symlinks:

$(abspath names...)

Same as $(abspath ) except that the current directory can be specified as curdir [1]:

$(abspathex names...[, curdir])

Arithmetic Functions:

Returns the sum of the arguments [1]:

$(int-add addend1, addend2[, addendN])

Returns the difference between the first argument and the sum of the rest [1]:

$(int-sub minuend, subtrahend[, subtrahendN])

Returns the product of the arguments [1]:

$(int-mul factor1, factor2[, factorN])

Returns the quotient of first argument and the rest [1]:

$(int-div dividend, divisor[, divisorN])

Returns the modulus of the two arguments [1]:

$(int-mod dividend, divisor)

Returns the bitwise two-complement of argument [1]:

$(int-not val)

Returns the result of a bitwise AND of the arguments [1]:

$(int-and val1, val2[, valN])

Returns the result of a bitwise OR of the arguments [1]:

$(int-or val1, val2[, valN])

Returns the result of a bitwise XOR of the arguments [1]:

$(int-xor val1, val2[, valN])

Returns the kmk boolean (true = non-empty, false = empty) result of val1 == val2 [1]:

$(int-eq val1, val2)

Returns the kmk boolean result of val1 != val2 [1]:

$(int-ne val1, val2)

Returns the kmk boolean result of val1 > val2 [1]:

$(int-gt val1, val2)

Returns the kmk boolean result of val1 >= val2 [1]:

$(int-ge val1, val2)

Returns the kmk boolean result of val1 < val2 [1]:

$(int-lt val1, val2)

Returns the kmk boolean result of val1 <= val2 [1]:

$(int-le val1, val2)

Boolean and Conditional Functions:

Condition is false if the condition evaluates to an empty string (stripped). Evaluate the true-part if the condition is true, otherwise the false-part:

$(if condition,true-part[,false-part])

Test if any of the conditions evalues to non-empty string, returning the first one:

$(or condition1[,condition2[,condition3[...]]])

Test if all of the conditions evaluates to non-empty strings, returning the last one:

$(and condition1[,condition2[,condition3[...]]])

Test if the two strings are identical, returning kmk boolean (true = non-empty, false = empty) [2]:

$(eq str1, str2)

Invert a kmk boolean value [2]:

$(not val)

Test if variable is defined, returning a kmk boolean value [1]:

$(defined variable)

Test if set-a and set-b intersects, returning a kmk boolean value [1]:

$(intersects set-a, set-b)

Same as $(if ) execpt that the condition is a kmk-expression [1]:

$(if-expr kmk-expression,true-part[,false-part])

Select the first true condition (kmk-expression) and expand the following body. Special condition strings default and otherwise [1]:

$(select when1-cond, when1-body[, whenN-cond, whenN-body])

Evalutate the kmk-expression returning what it evalues as. This is the preferred way of doing arithmentic now [1]:

$(expr kmk-expression)

Stack Fuctions:

Push item onto the stack-var, returning the empty string [1]:

$(stack-push stack-var, item)

Pop the top item off the stack-var [1]:

$(stack-pop stack-var)

Pop the top item off the stack-var, returning the empty string [1]:

$(stack-popv stack-var)

Get the top item of the stack-var, returning the empty string [1]:

$(stack-top stack-var)

Advanced Functions:

Evaluates to the contents of the variable var, with no expansion performed on it:

$(value var)

Evaluate body with var bound to each word in words, and concatenate the results (spaced):

$(foreach var,words,body)

C-style for-loop. Start by evaluating init. Each iteration will first check whether the condition (kmk-expression) is true, then expand body concatenating the result to the previous iterations (spaced), and finally evaluate next [1]:

$(for init,conditions,next,body)

C-style while-loop. Each iteration will check whether the condition (kmk-expression) is true, then expand body concatenating the result to the previous iterations [1]:

$(while conditions,body)

Evaluate the variable var replacing any references to $(1), $(2) with the first, second, etc. param values:

$(call var,param,...)

Evaluate text then read the results as makefile commands. Expands to the empty string:

$(eval text)

Same as $(eval text) except that the text is expanded in its own variable context [1]:

$(evalctx text)

Same as $(eval $(value var)) [1]:

$(evalval var)

Same as $(evalctx $(value var)) [1]:

$(evalvalctx var)

A combination of $(eval ), $(call ) and $(value ) [1]:

$(evalcall var)

A combination of $(eval ) and $(call ) [1]:

$(evalcall var)

Remove comments and blank lines from the variable var. Expands to the empty string [1]:

$(eval-opt-var var)

Returns accessing $< of target, either retriving the whole thing or the file at pos (one-origin) [1]:

$(deps target[, pos])

Returns accessing $+ (order + duplicates) of target, either retriving the whole thing or the file at pos (one-origin) [1]:

$(deps-all target[, pos])

Returns accessing $? of target, either retriving the whole thing or the file at pos (one-origin) [1]:

$(deps-newer target[, pos])

Returns accessing $| (order only) of target, either retriving the whole thing or the file at pos (one-origin) [1]:

$(deps-oo target[, pos])

Command Functions:

Create one or more command lines avoiding the max argument length restriction of the host OS [1]:

$(xargs ar cas mylib.a,$(objects))
$(xargs ar cas mylib.a,ar as mylib.a,$(objects))

Returns the commands for the specified target separated by new-line, space, or a user defined string. Note that this might not produce the 100% correct result if any of the prerequisite automatic variables are used [1]:

$(commands target)
$(commands-sc target)
$(commands-usr target,sep)

Compares two commands returning the empty string if equal and the 3rd argument if not. This differs from $(comp-vars v1,v2,ne) in that line by line is stripped of leading spaces, command prefixes and trailing spaces before comparing [1]:

$(comp-cmds cmds-var1, cmds-var2, ne)
$(comp-cmds-ex cmds1, cmd2, ne)

Compares the values of the two variables returning the empty string if equal and the 3rd argument if not. Leading and trailing spaces is ignored [1]:

$(comp-var var1, var2, ne)

Utility functions:

When this function is evaluated, kmk generates a fatal error with the message text:

$(error text...)

When this function is evaluated, kmk generates a warning with the message text:

$(warning text...)

When this function is evaluated, kmk generates a info with the message text:

$(info text...)

Execute a shell command and return its output:

$(shell command)

Return a string describing how the kmk variable variable was defined:

$(origin variable)

Return a string describing the flavor of the kmk variable variable:

$(flavor variable)

Returns the current local time and date formatted in the strftime style specifier fmt. fmt defaults to %Y-%m-%dT%H:%M:%S when not specified [1]:

$(date fmt)

Returns the current UTC time and date formatted in the strftime style specifier fmt. fmt defaults to %Y-%m-%dT%H:%M:%SZ when not specified [1]:

$(date-utc fmt)

Reformats the in time and date using fmt. The in-fmt defaults to fmt if not specified. While fmt defaults to %Y-%m-%dT%H:%M:%SZ if not specified [1]:

$(date-utc fmt,time,in-fmt)

Returns the current nanosecond timestamp (monotonic when possible) [1]:

$(nanots )

Returns the size of the specified file, or -1 if the size could not be obtained. This can be used to check if a file exist or not [1]:

$(file-size file)

Searches the PATH kmk variable for the specified files [1]:

$(which files...)

OS/2: Returns the specified LIBPATH variable value [1]:

$(libpath var)

OS/2: Sets the specified LIBPATH variable value, returning the empty string [1]:

$(libpath var,value)

Debugging Functions:

Returns various make statistics, if no item is specified a default selection is returned [1]:

$(make-stats item[,itemN])

Raise a debug breakpoint. Used for debugging kmk makefile parsing [1]:

$(breakpoint )

Recipes

A typical recipe takes one of the two following forms:

targets : normal-prerequisites | order-only-prerequisites
        command
        ...

targets : normal-prerequisites | order-only-prerequisites ; command
        command
        ...

Specifying more than one file in the targets lists is the same as repeating the recipe for each of the files.

Use + and +| in the list of targets to tell kmk that the recipe has more than one output. [1] The files after a + will always be remade, while the files after a +| don't have to be remade. The latter is frequently employed to update files which prerequisites change wihtout the output files necessarily changing. See also kmk_cp --changed.

Double colon recipes

Double colon recipes are written with :: instead of : and are handled differently from ordinary recipes if the target appears in more than one recipe. First, all the recipes must be of the double colon type. Second, the recipes are executed individually and may be omitted depending on the state of their prerequisites. Double colon recipes without any prerequisites will always be executed.

Pattern rules

A couple of examples:

%.o : %.c
        gcc -o $@ $<
%.tab.c %.tab.h : %.y
        bison -d $<

The latter has two outputs.


[1](1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81) kmk only feature.
[2](1, 2) Experimental GNU make feature that is not enabled by default.

Status:

$Id: QuickReference-kmk.html 2340 2009-04-18 12:05:47Z bird $

Copyright:

Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.

Copyright (c) 2008-2009 knut st. osmundsen

kbuild-3149/kBuild/doc/QuickReference-kmk.txt0000644000175000017500000013051713252530251021104 0ustar locutuslocutus kmk Quick Reference =================== This is an attempt at summarizing all directives, functions, special variables, special targets, built-in commands, external commands, and ``kmk``-expressions. Since *all* the features are included, the quickness of this reference can be disputed. ;-) Directives ---------- Here is a summary of the directives ``kmk`` recognizes: Define a multi-line, recursively-expanded variable:: define variable endef Conditionally evaluate part of the makefile:: ifdef variable ifndef variable ifeq (a,b) ifeq "a" "b" ifeq 'a' 'b' ifneq (a,b) ifneq "a" "b" ifneq 'a' 'b' if1of (set-a,set-b) [1] ifn1of (set-a,set-b) [1] if expression [1] else endif Include another makefile:: include file -include file sinclude file Include another dependency file [1]_:: includedep file Define a variable, overriding any previous definition, even one from the command line:: override variable = value override variable := value override variable += value override variable <= value [1] override variable ?= value override define variable endef Tell ``kmk`` to export all variables to child processes by default:: export Tell ``kmk`` whether or not to export a particular variable to child processes:: export variable export variable = value export variable := value export variable += value export variable <= value [1] export variable ?= value unexport variable Define a variable in the local context instead of the global one [1]_:: local variable = value local variable := value local variable += value local variable <= value local variable ?= value local define variable endef Specify a search path for files matching a ``%`` pattern:: vpath pattern path Remove all search paths previously specified for pattern:: vpath pattern Remove all search paths previously specified in any vpath directive:: vpath Automatic variables ------------------- Here is a summary of the automatic variables. +-----------+-----------------------------------------------------------------+ | Variable | Description | +===========+=================================================================+ | ``$@`` | The file name of the target. | +-----------+-----------------------------------------------------------------+ | ``$<`` | The name of the first prerequisite. | +-----------+-----------------------------------------------------------------+ | ``$?`` | The names of all the prerequisites that are newer than the | | | target, with spaces between them. | +-----------+-----------------------------------------------------------------+ | ``$^`` | The names of all the prerequisites, duplicates omitted. | +-----------+-----------------------------------------------------------------+ | ``$+`` | The names of all the prerequisites, duplicates and order | | | preserved | +-----------+-----------------------------------------------------------------+ | ``$*`` | The stem with which an implicit rule matches. | +-----------+-----------------------------------------------------------------+ | ``$|`` | The name of all the order only prerequisites. | +-----------+-----------------------------------------------------------------+ | ``$(@D)`` | The directory part of ``$@``. | +-----------+-----------------------------------------------------------------+ | ``$(>`` | | Bitwise right shift. | +---------------+--------+-----------------------------------------------------+ | ``<=`` | Binary | Less or equal than. | +---------------+ +-----------------------------------------------------+ | ``<`` | | Less than. | +---------------+ +-----------------------------------------------------+ | ``>=`` | | Greater or equal than. | +---------------+ +-----------------------------------------------------+ | ``>`` | | Greater than. | +---------------+--------+-----------------------------------------------------+ | ``==`` | Binary | Equal to. | +---------------+ +-----------------------------------------------------+ | ``!=`` | | Not equal to. | +---------------+--------+-----------------------------------------------------+ | ``&`` | Binary | Bitwise AND. | +---------------+--------+-----------------------------------------------------+ | ``^`` | Binary | Bitwise XOR. | +---------------+--------+-----------------------------------------------------+ | ``|`` | Binary | Bitwise OR. | +---------------+--------+-----------------------------------------------------+ | ``&&`` | Binary | Logical AND. | +---------------+--------+-----------------------------------------------------+ | ``||`` | Binary | Logical OR. | +---------------+--------+-----------------------------------------------------+ Built-in functions ------------------ String Manipulation Functions: Replace ``from`` with ``to`` in ``text``:: $(subst from,to,text) Replace words matching ``pattern`` with ``replacement`` in ``text``:: $(patsubst pattern,replacement,text) Remove excess whitespace characters from ``string``:: $(strip string) Locate ``find`` in ``text``, returning ``find`` if found:: $(findstring find,text) Select words in ``text`` that match one of the ``pattern`` words:: $(filter pattern...,text) Select words in ``text`` that do not match any of the ``pattern`` words:: $(filter-out pattern...,text) Sort the words in ``list`` lexicographically, removing duplicates:: $(sort list) Sort the words in ``list`` lexicographically in reserve order, removing duplicates [1]_:: $(rsort list) Count the number of words in ``text``:: $(words text) Extract the ``n``\th word (one-origin) of ``text``:: $(word n,text) Returns the list of words in ``text`` from ``s`` to ``e`` (one-origin):: $(wordlist s,e,text) Extract the first word of ``names``:: $(firstword names...) Extract the last word of ``names``:: $(lastword names...) Join two parallel lists of words:: $(join list1,list2) Extract the first defined variable from ``variables``, returning its name (default) or value:: $(firstdefined variables[, name|value]) Extract the last defined variable from ``variables``, returning its name (default) or value:: $(lastdefined variables[, name|value]) Fold ``text`` to upper case [1]_:: $(toupper text) Fold ``text`` to lower case [1]_:: $(tolower text) String formatting a la the unix ``printf`` command [1]_:: $(printf fmt, arg...) Return the length of a string or a (unexpanded) variable [1]_:: $(length string) $(length-var var) Find the position of ``needle`` in ``haystack``, returns 0 if not found. Negative ``start`` indices are relative to the end of ``haystack``, while positive ones are one based [1]_:: $(pos needle, haystack[, start]) $(lastpos needle, haystack[, start]) Returns the specified substring. The ``start`` works like with ``$(pos )``. If the substring is partially outside the ``string`` the result will be padded with ``pad`` if present [1]_:: $(substr string, start[, length[, pad]]) Insert ``in`` into ``str`` at the specified position. ``n`` works like with ``$(pos )``, except that ``0`` is the end of the string [1]_:: $(insert in, str[, n[, length[, pad]]]) Translate ``string`` exchanging characters in ``from-set`` with ``to-set``, optionally completing ``to-set`` with ``pad-char`` if specified. If no ``pad-char`` characters absent in ``to-set`` will be deleted [1]_:: $(translate string, from-set[, to-set[, pad-char]]) Functions for file names: Extract the directory part of each file ``name``:: $(dir names...) Extract the non-directory part of each file ``name``:: $(notdir names...) Extract the suffix (the last ``.`` and following characters) of each file ``name``:: $(suffix names...) Extract the base name (name without suffix) of each file name:: $(basename names...) Extract the root specification of each file name (a bit complicated on Windows & OS/2) [1]_:: $(root names...) Extract the non-root part of each file name (a bit complicated on Windows & OS/2) [1]_:: $(notroot names...) Append ``suffix`` to each word in ``names``:: $(addsuffix suffix,names...) Prepend ``prefix`` to each word in ``names``:: $(addprefix prefix,names...) Find file names matching a shell file name ``pattern`` (not a ``%`` pattern):: $(wildcard pattern...) For each file name in ``names``, expand to an absolute name that does not contain any ``.``, ``..``, nor symlinks:: $(realpath names...) For each file name in ``names``, expand to an absolute name that does not contain any ``.`` or ``..`` components, but preserves symlinks:: $(abspath names...) Same as ``$(abspath )`` except that the current directory can be specified as ``curdir`` [1]_:: $(abspathex names...[, curdir]) Arithmetic Functions: Returns the sum of the arguments [1]_:: $(int-add addend1, addend2[, addendN]) Returns the difference between the first argument and the sum of the rest [1]_:: $(int-sub minuend, subtrahend[, subtrahendN]) Returns the product of the arguments [1]_:: $(int-mul factor1, factor2[, factorN]) Returns the quotient of first argument and the rest [1]_:: $(int-div dividend, divisor[, divisorN]) Returns the modulus of the two arguments [1]_:: $(int-mod dividend, divisor) Returns the bitwise two-complement of argument [1]_:: $(int-not val) Returns the result of a bitwise AND of the arguments [1]_:: $(int-and val1, val2[, valN]) Returns the result of a bitwise OR of the arguments [1]_:: $(int-or val1, val2[, valN]) Returns the result of a bitwise XOR of the arguments [1]_:: $(int-xor val1, val2[, valN]) Returns the ``kmk`` boolean (true = non-empty, false = empty) result of ``val1 == val2`` [1]_:: $(int-eq val1, val2) Returns the ``kmk`` boolean result of ``val1 != val2`` [1]_:: $(int-ne val1, val2) Returns the ``kmk`` boolean result of ``val1 > val2`` [1]_:: $(int-gt val1, val2) Returns the ``kmk`` boolean result of ``val1 >= val2`` [1]_:: $(int-ge val1, val2) Returns the ``kmk`` boolean result of ``val1 < val2`` [1]_:: $(int-lt val1, val2) Returns the ``kmk`` boolean result of ``val1 <= val2`` [1]_:: $(int-le val1, val2) Boolean and Conditional Functions: Condition is false if the ``condition`` evaluates to an empty string (stripped). Evaluate the ``true-part`` if the condition is true, otherwise the ``false-part``:: $(if condition,true-part[,false-part]) Test if any of the conditions evalues to non-empty string, returning the first one:: $(or condition1[,condition2[,condition3[...]]]) Test if all of the conditions evaluates to non-empty strings, returning the last one:: $(and condition1[,condition2[,condition3[...]]]) Test if the two strings are identical, returning ``kmk`` boolean (true = non-empty, false = empty) [2]_:: $(eq str1, str2) Invert a ``kmk`` boolean value [2]_:: $(not val) Test if ``variable`` is defined, returning a ``kmk`` boolean value [1]_:: $(defined variable) Test if ``set-a`` and ``set-b`` intersects, returning a ``kmk`` boolean value [1]_:: $(intersects set-a, set-b) Same as ``$(if )`` execpt that the condition is a ``kmk``-expression [1]_:: $(if-expr kmk-expression,true-part[,false-part]) Select the first true condition (``kmk``-expression) and expand the following body. Special condition strings ``default`` and ``otherwise`` [1]_:: $(select when1-cond, when1-body[, whenN-cond, whenN-body]) Evalutate the ``kmk-expression`` returning what it evalues as. This is the preferred way of doing arithmentic now [1]_:: $(expr kmk-expression) Stack Fuctions: Push ``item`` onto the ``stack-var``, returning the empty string [1]_:: $(stack-push stack-var, item) Pop the top item off the ``stack-var`` [1]_:: $(stack-pop stack-var) Pop the top item off the ``stack-var``, returning the empty string [1]_:: $(stack-popv stack-var) Get the top item of the ``stack-var``, returning the empty string [1]_:: $(stack-top stack-var) Advanced Functions: Evaluates to the contents of the variable ``var``, with no expansion performed on it:: $(value var) Evaluate ``body`` with ``var`` bound to each word in ``words``, and concatenate the results (spaced):: $(foreach var,words,body) C-style for-loop. Start by evaluating ``init``. Each iteration will first check whether the ``condition`` (``kmk``-expression) is true, then expand ``body`` concatenating the result to the previous iterations (spaced), and finally evaluate ``next`` [1]_:: $(for init,conditions,next,body) C-style while-loop. Each iteration will check whether the ``condition`` (``kmk``-expression) is true, then expand ``body`` concatenating the result to the previous iterations [1]_:: $(while conditions,body) Evaluate the variable ``var`` replacing any references to ``$(1)``, ``$(2)`` with the first, second, etc. ``param`` values:: $(call var,param,...) Evaluate ``text`` then read the results as makefile commands. Expands to the empty string:: $(eval text) Same as ``$(eval text)`` except that the ``text`` is expanded in its own variable context [1]_:: $(evalctx text) Same as ``$(eval $(value var))`` [1]_:: $(evalval var) Same as ``$(evalctx $(value var))`` [1]_:: $(evalvalctx var) A combination of ``$(eval )``, ``$(call )`` and ``$(value )`` [1]_:: $(evalcall var) A combination of ``$(eval )`` and ``$(call )`` [1]_:: $(evalcall2 var) Remove comments and blank lines from the variable ``var``. Expands to the empty string [1]_:: $(eval-opt-var var) Returns accessing ``$<`` of ``target``, either retriving the whole thing or the file at ``pos`` (one-origin) [1]_:: $(deps target[, pos]) Returns accessing ``$+`` (order + duplicates) of ``target``, either retriving the whole thing or the file at ``pos`` (one-origin) [1]_:: $(deps-all target[, pos]) Returns accessing ``$?`` of ``target``, either retriving the whole thing or the file at ``pos`` (one-origin) [1]_:: $(deps-newer target[, pos]) Returns accessing ``$|`` (order only) of ``target``, either retriving the whole thing or the file at ``pos`` (one-origin) [1]_:: $(deps-oo target[, pos]) Command Functions: Create one or more command lines avoiding the max argument length restriction of the host OS [1]_:: $(xargs ar cas mylib.a,$(objects)) $(xargs ar cas mylib.a,ar as mylib.a,$(objects)) Returns the commands for the specified target separated by new-line, space, or a user defined string. Note that this might not produce the 100% correct result if any of the prerequisite automatic variables are used [1]_:: $(commands target) $(commands-sc target) $(commands-usr target,sep) Compares two commands returning the empty string if equal and the 3rd argument if not. This differs from ``$(comp-vars v1,v2,ne)`` in that line by line is stripped of leading spaces, command prefixes and trailing spaces before comparing [1]_:: $(comp-cmds cmds-var1, cmds-var2, ne) $(comp-cmds-ex cmds1, cmd2, ne) Compares the values of the two variables returning the empty string if equal and the 3rd argument if not. Leading and trailing spaces is ignored [1]_:: $(comp-var var1, var2, ne) Utility functions: When this function is evaluated, ``kmk`` generates a fatal error with the message ``text``:: $(error text...) When this function is evaluated, ``kmk`` generates a warning with the message ``text``:: $(warning text...) When this function is evaluated, ``kmk`` generates a info with the message ``text``:: $(info text...) Execute a shell ``command`` and return its output:: $(shell command) Return a string with the location where the ``kmk`` variable ``variable`` was defined:: $(where variable) Return a string describing how the ``kmk`` variable ``variable`` was defined:: $(origin variable) Return a string describing the flavor of the ``kmk`` variable ``variable``:: $(flavor variable) Returns the current local time and date formatted in the ``strftime`` style specifier ``fmt``. ``fmt`` defaults to ``%Y-%m-%dT%H:%M:%S`` when not specified [1]_:: $(date fmt) Returns the current UTC time and date formatted in the ``strftime`` style specifier ``fmt``. ``fmt`` defaults to ``%Y-%m-%dT%H:%M:%SZ`` when not specified [1]_:: $(date-utc fmt) Reformats the ``in`` time and date using ``fmt``. The ``in-fmt`` defaults to ``fmt`` if not specified. While ``fmt`` defaults to ``%Y-%m-%dT%H:%M:%SZ`` if not specified [1]_:: $(date-utc fmt,time,in-fmt) Returns the current nanosecond timestamp (monotonic when possible) [1]_:: $(nanots ) Returns the size of the specified file, or -1 if the size could not be obtained. This can be used to check if a file exist or not [1]_:: $(file-size file) Searches the ``PATH`` ``kmk`` variable for the specified ``files`` [1]_:: $(which files...) OS/2: Returns the specified LIBPATH variable value [1]_:: $(libpath var) OS/2: Sets the specified LIBPATH variable value, returning the empty string [1]_:: $(libpath var,value) Debugging Functions: Returns various make statistics, if no item is specified a default selection is returned [1]_:: $(make-stats item[,itemN]) Raise a debug breakpoint. Used for debugging ``kmk`` makefile parsing [1]_:: $(breakpoint ) Recipes ------- A typical recipe takes one of the two following forms:: targets : normal-prerequisites | order-only-prerequisites command ... targets : normal-prerequisites | order-only-prerequisites ; command command ... Specifying more than one file in the ``targets`` lists is the same as repeating the recipe for each of the files. Use ``+`` and ``+|`` in the list of ``targets`` to tell ``kmk`` that the recipe has more than one output. [1]_ The files after a ``+`` will always be remade, while the files after a ``+|`` don't have to be remade. The latter is frequently employed to update files which prerequisites change wihtout the output files necessarily changing. See also ``kmk_cp --changed``. Double colon recipes Double colon recipes are written with ``::`` instead of ``:`` and are handled differently from ordinary recipes if the target appears in more than one recipe. First, all the recipes must be of the double colon type. Second, the recipes are executed individually and may be omitted depending on the state of their prerequisites. Double colon recipes without any prerequisites will always be executed. Pattern rules A couple of examples:: %.o : %.c gcc -o $@ $< %.tab.c %.tab.h : %.y bison -d $< The latter has two outputs. ----- .. [1] ``kmk`` only feature. .. [2] Experimental GNU ``make`` feature that is not enabled by default. ----- :Status: $Id: QuickReference-kmk.txt 2532 2011-08-02 13:05:37Z bird $ :Copyright: Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. Copyright (c) 2008-2009 knut st. osmundsen kbuild-3149/kBuild/doc/example1/0000755000175000017500000000000013252530251016375 5ustar locutuslocutuskbuild-3149/kBuild/doc/example1/Makefile.kmk0000644000175000017500000000146413252530251020623 0ustar locutuslocutus# $Id: Makefile.kmk 2343 2009-04-19 21:44:50Z bird $ ## @file # kBuild Example no. 1 - Makefile.kmk - The top-level makefile. # # # The author disclaims copyright to this example script and places # it in the public domain. # # include full-legal-disclaimer.kmk # SUB_DEPTH = . include $(KBUILD_PATH)/subheader.kmk # # Include sub-makefiles. # include $(PATH_CURRENT)/libhello/Makefile.kmk # # The targets. # PROGRAMS += \ hello \ hellolib # # Hello world program. # hello_TEMPLATE = ExampleNo1Exe hello_SOURCES = hello.c # # A hello world variant that has some of the code in the libhello directory, # i.e. linking with a library built by the sub-makefile included above. # hellolib_TEMPLATE = ExampleNo1Exe hellolib_SOURCES = hellolib.c hellolib_LIBS = $(libhello_1_TARGET) include $(FILE_KBUILD_SUB_FOOTER) kbuild-3149/kBuild/doc/example1/hello.c0000644000175000017500000000052713252530251017650 0ustar locutuslocutus/* $Id: hello.c 2343 2009-04-19 21:44:50Z bird $ */ /** @file * Example no. 1 - hello.c - Hello world program. */ /* * The author disclaims copyright to this example code and places * it in the public domain. * * #include * */ #include int main() { printf("Hello world!\n"); return 0; } kbuild-3149/kBuild/doc/example1/Config.kmk0000644000175000017500000000132413252530251020306 0ustar locutuslocutus# $Id: Config.kmk 2343 2009-04-19 21:44:50Z bird $ ## @file # kBuild Example no. 1 - Config.kmk - The global configuration file. # # # The author disclaims copyright to this example script and places # it in the public domain. # # include full-legal-disclaimer.kmk # # # Some templates. # TEMPLATE_ExampleNo1Exe = For creating a program or static library for linking into a program. TEMPLATE_ExampleNo1Exe_TOOL = GCC TEMPLATE_ExampleNo1Exe_DEFS = MY_DEFINE=42 MY_OTHER_DEFINE TEMPLATE_ExampleNo1Dll = For creating a DLL/SO/DYLIB or static library for linking into a DLL/SO/DYLIB TEMPLATE_ExampleNo1Dll_EXTENDS = ExampleNo1Exe TEMPLATE_ExampleNo1Dll_EXTENDS_BY = appending TEMPLATE_ExampleNo1Dll_DEFS = MY_DLL_INDICATOR kbuild-3149/kBuild/doc/example1/libhello/0000755000175000017500000000000013252530251020167 5ustar locutuslocutuskbuild-3149/kBuild/doc/example1/libhello/Makefile.kmk0000644000175000017500000000103013252530251022402 0ustar locutuslocutus# $Id: Makefile.kmk 2343 2009-04-19 21:44:50Z bird $ ## @file # kBuild Example no. 1 - libhello/Makefile.kmk - The libhello sub-makefile. # # # The author disclaims copyright to this example script and places # it in the public domain. # # include full-legal-disclaimer.kmk # SUB_DEPTH = .. include $(KBUILD_PATH)/subheader.kmk # # The targets. # LIBRARIES += libhello # # The hello world library. # libhello_TEMPLATE = ExampleNo1Exe libhello_SOURCES = libhello.c ## @todo Create a DLL variant. include $(FILE_KBUILD_SUB_FOOTER) kbuild-3149/kBuild/doc/example1/libhello/libhello.c0000644000175000017500000000063413252530251022130 0ustar locutuslocutus/* $Id: libhello.c 2343 2009-04-19 21:44:50Z bird $ */ /** @file * Example no. 1 - libhello.c - Hello world library. */ /* * The author disclaims copyright to this example code and places * it in the public domain. * * #include * */ #include extern int print_hello_world(void); int print_hello_world(void) { printf("Hello library world!\n"); return 0; } kbuild-3149/kBuild/doc/example1/hellolib.c0000644000175000017500000000055113252530251020334 0ustar locutuslocutus/* $Id: hellolib.c 2343 2009-04-19 21:44:50Z bird $ */ /** @file * Example no. 1 - hellolib.c - Hello world program w/ lib. */ /* * The author disclaims copyright to this example code and places * it in the public domain. * * #include * */ extern int print_hello_world(void); int main() { return print_hello_world(); } kbuild-3149/kBuild/doc/QuickReference-kBuild.txt0000644000175000017500000004006313252530251021530 0ustar locutuslocutus kBuild Quick Reference ====================== This is an attempt at summarizing the magic of kBuild makefiles. The anatomy of a kBuild Makefile -------------------------------- A typical makefile:: # $Id: QuickReference-kBuild.txt 2345 2009-04-19 23:47:42Z bird $ ## @file # Makefile description. # # # Copyright (c) year name # License, disclaimer and other legal text. # SUB_DEPTH = ../.. include $(KBUILD_PATH)/subheader.kmk # # Include sub-makefiles. # include $(PATH_CURRENT)/subdir1/Makefile.kmk include $(PATH_CURRENT)/subdir2/Makefile.kmk # # Global variables. # MYPREFIX_SOMETHING = or another # # Target lists. # DLLS += mydll PROGRAMS += myprogs # # mydll - description. # mydll_TEMPLATE = MYDLL mydll_SOURCES = mydll.c mydll_SOURCES.win = $(mydll_0_OUTDIR)/mydll.def # # myprog - description. # myprog_TEMPLATE = MYPROG myprog_SOURCES = myprog.c # # Custom rules (optional of course). # $$(mydll_0_OUTDIR)/mydll.def: $(APPEND) -t $@ LIBRARY mydll.dll $(APPEND) $@ EXPORTS $(APPEND) $@ ' myfunction' include $(FILE_KBUILD_SUB_FOOTER) Target lists ------------ +-+-------------------+-------------------------------------------------------+ |#| Name | Description | +=+===================+=======================================================+ |1| ``BLDPROGS`` | Build programs, targets the host platform. | +-+-------------------+-------------------------------------------------------+ |2| ``LIBRARIES`` | Libraries (not shared). | +-+-------------------+-------------------------------------------------------+ |3| ``IMPORT_LIBS`` | Import libraries or stub shared libraries. | +-+-------------------+-------------------------------------------------------+ |4| ``DLLS`` | DLLs, Shared Libraries, DYLIBs, etc. | +-+-------------------+-------------------------------------------------------+ |5| ``PROGRAMS`` | Executable programs. | +-+-------------------+-------------------------------------------------------+ |6| ``SYSMODS`` | System modules (kexts, kernel modules, drivers, etc). | +-+-------------------+-------------------------------------------------------+ |7| ``MISCBINS`` | Miscellanceous binaries like BIOS images and such. | +-+-------------------+-------------------------------------------------------+ |8| ``INSTALLS`` | Things to install. [1]_ | +-+-------------------+-------------------------------------------------------+ |9| ``FETCHES`` | Things to fetch. [1]_ | +-+-------------------+-------------------------------------------------------+ |a| ``OTHERS`` | List of targets made during the others pass. | +-+-------------------+-------------------------------------------------------+ Target properties ----------------- The first column indicates the kind of property, S=Single, D=Deferred, Ar=Accumlate-Right and Al=Accumulate-Left. The third column should be cross referenced with the first column in the target list table above. +--+-------------------+-------+----------------------------------------------+ |K | Name | Which | Description | +==+===================+=======+==============================================+ |S | ``ARLIBSUFF`` | 2 | | +--+-------------------+-------+----------------------------------------------+ |S | ``ARTOOL`` | 2 | | +--+-------------------+-------+----------------------------------------------+ |S | ``ASOBJSUFF`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |S | ``ASTOOL`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |S | ``BINSUFF`` | 7 | | +--+-------------------+-------+----------------------------------------------+ |S | ``BLD_TRG`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |S | ``BLD_TRG_ARCH`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |S | ``BLD_TRG_CPU`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |S | ``BLD_TYPE`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |S | ``COBJSUFF`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |S | ``CTOOL`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |S | ``CXXOBJSUFF`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |S | ``CXXTOOL`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |S | ``DLLSUFF`` | 34 | | +--+-------------------+-------+----------------------------------------------+ |S | ``EXESUFF`` | 15 | | +--+-------------------+-------+----------------------------------------------+ |S | ``FETCHDIR`` | 9 | | +--+-------------------+-------+----------------------------------------------+ |S | ``FETCHTOOL`` | 9 | | +--+-------------------+-------+----------------------------------------------+ |S | ``GID`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |S | ``INST`` | 1-9 | | +--+-------------------+-------+----------------------------------------------+ |S | ``LDTOOL`` | 13-7 | | +--+-------------------+-------+----------------------------------------------+ |S | ``LIBSUFF`` | 234 | | +--+-------------------+-------+----------------------------------------------+ |S | ``MODE`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |S | ``NOINST`` | 1-8 | | +--+-------------------+-------+----------------------------------------------+ |S | ``OBJCOBJSUFF`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |S | ``OBJCTOOL`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |S | ``OBJSUFF`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |S | ``PATCHTOOL`` | 9 | | +--+-------------------+-------+----------------------------------------------+ |S | ``RCOBJSUFF`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |S | ``RCTOOL`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |S | ``SYSSUFF`` | 6 | | +--+-------------------+-------+----------------------------------------------+ |S | ``TEMPLATE`` | 1-9 | | +--+-------------------+-------+----------------------------------------------+ |S | ``TOOL`` | 1-9 | | +--+-------------------+-------+----------------------------------------------+ |S | ``UID`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |S | ``UNPACKTOOL`` | 9 | | +--+-------------------+-------+----------------------------------------------+ |D | ``INSTALLER`` | 1-8 | | +--+-------------------+-------+----------------------------------------------+ |D | ``INSTFUN`` | 1-8 | | +--+-------------------+-------+----------------------------------------------+ |D | ``NAME`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |D | ``POST_CMDS`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |D | ``PRE_CMDS`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |D | ``SONAME`` | 13-7 | | +--+-------------------+-------+----------------------------------------------+ |Ar| ``ARFLAGS`` | 2 | | +--+-------------------+-------+----------------------------------------------+ |Ar| ``ASDEFS`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |Ar| ``ASFLAGS`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |Ar| ``CDEFS`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |Ar| ``CFLAGS`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |Ar| ``CXXDEFS`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |Ar| ``CXXFLAGS`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |Ar| ``DEFS`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |Ar| ``DEPS`` | 1-8 | | +--+-------------------+-------+----------------------------------------------+ |Ar| ``FETCHFLAGS`` | 9 | | +--+-------------------+-------+----------------------------------------------+ |Ar| ``IDFLAGS`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |Ar| ``IFDLAGS`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |Ar| ``ISFLAGS`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |Ar| ``LDFLAGS`` | 13-7 | | +--+-------------------+-------+----------------------------------------------+ |Ar| ``LNK_DEPS`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |Ar| ``LNK_ORDERDEPS`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |Ar| ``OBJCDEFS`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |Ar| ``OBJCFLAGS`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |Ar| ``ORDERDEPS`` | 1-8 | | +--+-------------------+-------+----------------------------------------------+ |Ar| ``PATCHFLAGS`` | 9 | | +--+-------------------+-------+----------------------------------------------+ |Ar| ``RCDEFS`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |Ar| ``RCFLAGS`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |Ar| ``UNPACKFLAGS`` | 9 | | +--+-------------------+-------+----------------------------------------------+ |Al| ``ASINCS`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |Al| ``BLDDIRS`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |Al| ``CINCS`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |Al| ``CLEAN`` | 1-9 | | +--+-------------------+-------+----------------------------------------------+ |Al| ``CXXINCS`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |Al| ``DIRS`` | 8 | | +--+-------------------+-------+----------------------------------------------+ |Al| ``INCS`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |Al| ``INTERMEDIATES`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |Al| ``LIBPATH`` | 13-7 | | +--+-------------------+-------+----------------------------------------------+ |Al| ``LIBS`` | 13-7 | | +--+-------------------+-------+----------------------------------------------+ |Al| ``OBJCINCS`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |Al| ``RCINCS`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |Al| ``SDKS`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |Al| ``SOURCES`` | 1-9 | | +--+-------------------+-------+----------------------------------------------+ |Al| ``SRC_HANDLERS`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ |Al| ``USES`` | 1-7 | | +--+-------------------+-------+----------------------------------------------+ ----- .. [1] Normally not one of the default passes. ----- :Status: $Id: QuickReference-kBuild.txt 2345 2009-04-19 23:47:42Z bird $ :Copyright: Copyright (c) 2009 knut st. osmundsen kbuild-3149/kBuild/doc/COPYING-FDL-1.30000644000175000017500000005466213252530251016633 0ustar locutuslocutus GNU Free Documentation License Version 1.3, 3 November 2008 Copyright (C) 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. 0. PREAMBLE The purpose of this License is to make a manual, textbook, or other functional and useful document "free" in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others. This License is a kind of "copyleft", which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software. We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference. 1. APPLICABILITY AND DEFINITIONS This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The "Document", below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as "you". You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law. A "Modified Version" of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language. A "Secondary Section" is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them. The "Invariant Sections" are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none. The "Cover Texts" are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words. A "Transparent" copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not "Transparent" is called "Opaque". Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only. The "Title Page" means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, "Title Page" means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text. The "publisher" means any person or entity that distributes copies of the Document to the public. A section "Entitled XYZ" means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as "Acknowledgements", "Dedications", "Endorsements", or "History".) To "Preserve the Title" of such a section when you modify the Document means that it remains a section "Entitled XYZ" according to this definition. The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License. 2. VERBATIM COPYING You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3. You may also lend copies, under the same conditions stated above, and you may publicly display copies. 3. COPYING IN QUANTITY If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects. If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages. If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public. It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document. 4. MODIFICATIONS You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version: A. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission. B. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement. C. State on the Title page the name of the publisher of the Modified Version, as the publisher. D. Preserve all the copyright notices of the Document. E. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices. F. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below. G. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice. H. Include an unaltered copy of this License. I. Preserve the section Entitled "History", Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled "History" in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence. J. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the "History" section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission. K. For any section Entitled "Acknowledgements" or "Dedications", Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein. L. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles. M. Delete any section Entitled "Endorsements". Such a section may not be included in the Modified Version. N. Do not retitle any existing section to be Entitled "Endorsements" or to conflict in title with any Invariant Section. O. Preserve any Warranty Disclaimers. If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles. You may add a section Entitled "Endorsements", provided it contains nothing but endorsements of your Modified Version by various parties--for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard. You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one. The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version. 5. COMBINING DOCUMENTS You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers. The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work. In the combination, you must combine any sections Entitled "History" in the various original documents, forming one section Entitled "History"; likewise combine any sections Entitled "Acknowledgements", and any sections Entitled "Dedications". You must delete all sections Entitled "Endorsements". 6. COLLECTIONS OF DOCUMENTS You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects. You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document. 7. AGGREGATION WITH INDEPENDENT WORKS A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an "aggregate" if the copyright resulting from the compilation is not used to limit the legal rights of the compilation's users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document. If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document's Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate. 8. TRANSLATION Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail. If a section in the Document is Entitled "Acknowledgements", "Dedications", or "History", the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title. 9. TERMINATION You may not copy, modify, sublicense, or distribute the Document except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, or distribute it is void, and will automatically terminate your rights under this License. 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, receipt of a copy of some or all of the same material does not give you any rights to use it. 10. FUTURE REVISIONS OF THIS LICENSE The Free Software Foundation may publish new, revised versions of the GNU Free Documentation 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. See http://www.gnu.org/copyleft/. Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License "or any later version" applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. If the Document specifies that a proxy can decide which future versions of this License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Document. 11. RELICENSING "Massive Multiauthor Collaboration Site" (or "MMC Site") means any World Wide Web server that publishes copyrightable works and also provides prominent facilities for anybody to edit those works. A public wiki that anybody can edit is an example of such a server. A "Massive Multiauthor Collaboration" (or "MMC") contained in the site means any set of copyrightable works thus published on the MMC site. "CC-BY-SA" means the Creative Commons Attribution-Share Alike 3.0 license published by Creative Commons Corporation, a not-for-profit corporation with a principal place of business in San Francisco, California, as well as future copyleft versions of that license published by that same organization. "Incorporate" means to publish or republish a Document, in whole or in part, as part of another Document. An MMC is "eligible for relicensing" if it is licensed under this License, and if all works that were first published under this License somewhere other than this MMC, and subsequently incorporated in whole or in part into the MMC, (1) had no cover texts or invariant sections, and (2) were thus incorporated prior to November 1, 2008. The operator of an MMC Site may republish an MMC contained in the site under CC-BY-SA on the same site at any time before August 1, 2009, provided the MMC is eligible for relicensing. ADDENDUM: How to use this License for your documents To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page: Copyright (c) YEAR YOUR NAME. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License". If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the "with...Texts." line with this: with the Invariant Sections being LIST THEIR TITLES, with the Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation. If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software. kbuild-3149/kBuild/units/0000755000175000017500000000000013252530251015256 5ustar locutuslocutuskbuild-3149/kBuild/units/qt5.kmk0000644000175000017500000011656213252530251016506 0ustar locutuslocutus# $Id: qt5.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # Qt 5 unit. # # # Copyright (c) 2008-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # ifdef UNIT_qt5 $(error kBuild: The qt5 unit was included twice!) endif UNIT_qt5 = qt5 if !defined(UNIT_qt3) && !defined(UNIT_qt4) # Add our target properties (same as qt3 & qt4). PROPS_SINGLE += QTTOOL MOCTOOL UICTOOL LRCTOOL QT_TRANSLATIONS_INST QT_TRANSLATIONS_TEMPLATE QT_PREFIX PROPS_ACCUMULATE_R += MOCDEFS MOCFLAGS UICFLAGS LRCFLAGS QT_TRANSLATIONS QT_MOCSRCS QT_MOCHDRS endif PROPS_SINGLE += RCCTOOL QT_INFIX PROPS_ACCUMULATE_R += RCCFLAGS QT_MODULES ## @todo use pkg-config? # # The QT5 SDK. # # This is implemented here rather than in sdks/QT5.kmk to enforce the global USES. # It also makes things easier to develop, with fewer files I mean. # ## @todo the SDK might actually not be necessary as it turns out... For now it servers # a purpose if the host differs from the target, in theory at least. SDK_QT5 = Qt5 # SDK Specific Properties # PATH_SDK_QT5 - The general Qt5 root directory. # PATH_SDK_QT5_INC - The include directory. # PATH_SDK_QT5_LIB.amd64 - The lib directory for AMD64. # PATH_SDK_QT5_LIB.x86 - The lib directory for X86. # PATH_SDK_QT5_LIB - The lib directory for KBUILD_TARGET. ifndef PATH_SDK_QT5 PATH_SDK_QT5 := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_TRG)/qt/v5*))) ifeq ($(PATH_SDK_QT5),) # If target == host, try look for Qt in the various platform specific places. ifeq ($(KBUILD_TARGET),$(KBUILD_HOST)) ifeq ($(KBUILD_TARGET),darwin) PATH_SDK_QT5 := $(patsubst %/Frameworks/QtCore.framework/Versions/5,%,$(firstword $(wildcard /Library/Frameworks/QtCore.framework/Versions/5))) else ifeq ($(KBUILD_TARGET),win) # No idea here yet... else ifeq ($(KBUILD_TARGET),ose) # No port... else # The Unices. Includes and esp. libs are tricky, so override the PATH_SDK_QT5_LIB* stuff if it doesn't work. # Try find the general root of thing by looking for the qt4to5 program, if not found, then look for rcc. PATH_SDK_QT5 := $(patsubst %/bin/qt4to5-qt5,%,$(firstword $(wildcard \ /usr/bin/qt4to5-qt5 \ /usr/local/bin/qt4to5-qt5 \ /usr/qt/5/bin/qt4to5-qt5 \ /usr/share/qt5/bin/qt4to5-qt5 \ ))) ifeq ($(PATH_SDK_QT5),) PATH_SDK_QT5 := $(patsubst %/bin/qt4to5,%,$(firstword $(wildcard \ /usr/bin/qt4to5 \ /usr/local/bin/qt4to5 \ /usr/qt/5/bin/qt4to5 \ /usr/share/qt5/bin/qt4to5 \ ))) endif ifeq ($(PATH_SDK_QT5),) PATH_SDK_QT5 := $(patsubst %/bin/rcc-qt5,%,$(firstword $(wildcard \ /usr/bin/rcc-qt5 \ /usr/local/bin/rcc-qt5 \ /usr/qt/5/bin/rcc-qt5 \ /usr/share/qt5/bin/rcc-qt5 \ ))) endif ifeq ($(PATH_SDK_QT5),) PATH_SDK_QT5 := $(patsubst %/bin/rcc,%,$(firstword $(wildcard \ /usr/lib/*/qt5/bin/rcc \ /usr/bin/rcc \ /usr/local/bin/rcc \ /usr/qt/5/bin/rcc \ /usr/share/qt5/bin/rcc \ ))) endif ifneq ($(PATH_SDK_QT5),) export PATH_SDK_QT5 # Locate the include files. Check for qglobalstatic.h (since 5.1) first. ifeq ($(PATH_SDK_QT5_INC),) PATH_SDK_QT5_INC := $(patsubst %/QtCore/qglobalstatic.h,%,$(firstword $(wildcard \ $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET_DOT_ARCH)),/usr/include/$(type)/qt5/QtCore/qglobalstatic.h) \ $(PATH_SDK_QT5)/include/qt5/QtCore/qglobalstatic.h \ /usr/include/qt5/QtCore/qtglobalstatic.h \ /usr/local/include/qt5/QtCore/qtglobalstatic.h \ $(PATH_SDK_QT5)/include/QtCore/qglobalstatic.h \ /usr/include/qt/QtCore/qglobalstatic.h \ /usr/local/include/qt/QtCore/qglobalstatic.h \ ))) ifeq ($(PATH_SDK_QT5_INC),) PATH_SDK_QT5_INC := $(patsubst %/QtCore/qglobal.h,%,$(firstword $(wildcard \ $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET_DOT_ARCH)),/usr/include/$(type)/qt5/QtCore/qglobal.h) \ $(PATH_SDK_QT5)/include/qt5/QtCore/qglobal.h \ /usr/include/qt5/QtCore/qtglobal.h \ /usr/local/include/qt5/QtCore/qtglobal.h \ $(PATH_SDK_QT5)/include/QtCore/qglobal.h \ ))) endif ifneq ($(PATH_SDK_QT5_INC),) export PATH_SDK_QT5_INC endif endif # Now for the libraries (mostly for helping out finding the KBUILD_TARGET libs). ifeq ($(PATH_SDK_QT5_LIB.x86),) PATH_SDK_QT5_LIB.x86 := $(patsubst %/libQt5Core$(SUFF_DLL),%,$(firstword $(wildcard \ $(PATH_SDK_QT5)/lib32/libQt5Core$(SUFF_DLL) \ $(PATH_SDK_QT5)/lib32/qt5/libQt5Core$(SUFF_DLL) \ /usr/lib32/libQt5Core$(SUFF_DLL) \ /usr/lib32/qt5/libQt5Core$(SUFF_DLL) \ $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET).x86),/usr/lib/$(type)/libQt5Core$(SUFF_DLL)) \ /usr/local/lib32/libQt5Core$(SUFF_DLL) \ /usr/local/lib32/qt5/libQt5Core$(SUFF_DLL) \ $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET).x86),/usr/local/lib/$(type)/libQt5Core$(SUFF_DLL)) \ $(PATH_SDK_QT5)/lib/libQt5Core$(SUFF_DLL) \ $(PATH_SDK_QT5)/lib/qt5/libQt5Core$(SUFF_DLL) \ $(PATH_SDK_QT5)/lib/i386-linux-gnu/libQt5Core$(SUFF_DLL) \ ))) ifneq ($(PATH_SDK_QT5_LIB.x86),) export PATH_SDK_QT5_LIB.x86 endif endif ifeq ($(PATH_SDK_QT5_LIB.amd64),) PATH_SDK_QT5_LIB.amd64 := $(patsubst %/libQt5Core$(SUFF_DLL),%,$(firstword $(wildcard \ $(PATH_SDK_QT5)/lib64/libQt5Core$(SUFF_DLL) \ $(PATH_SDK_QT5)/lib64/qt5/libQt5Core$(SUFF_DLL) \ $(PATH_SDK_QT5)/lib/amd64/libQt5Core$(SUFF_DLL) \ /usr/lib64/libQt5Core$(SUFF_DLL) \ /usr/lib64/qt5/libQt5Core$(SUFF_DLL) \ /usr/lib/amd64/libQt5Core$(SUFF_DLL) \ $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET).amd64),/usr/lib/$(type)/libQt5Core$(SUFF_DLL)) \ /usr/local/lib64/libQt5Core$(SUFF_DLL) \ /usr/local/lib64/qt5/libQt5Core$(SUFF_DLL) \ /usr/local/lib/amd64/libQt5Core$(SUFF_DLL) \ $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET).amd64),/usr/local/lib/$(type)/libQt5Core$(SUFF_DLL)) \ $(PATH_SDK_QT5)/lib/libQt5Core$(SUFF_DLL) \ $(PATH_SDK_QT5)/lib/qt5/libQt5Core$(SUFF_DLL) \ $(PATH_SDK_QT5)/lib/x86_64-linux-gnu/libQt5Core$(SUFF_DLL) \ ))) ifneq ($(PATH_SDK_QT5_LIB.amd64),) export PATH_SDK_QT5_LIB.amd64 endif endif # And finally, the library path for KBUILD_TARGET. ifeq ($(PATH_SDK_QT5_LIB),) PATH_SDK_QT5_LIB := $(PATH_SDK_QT5_LIB.$(KBUILD_TARGET_ARCH)) ifeq ($(PATH_SDK_QT5_LIB),) PATH_SDK_QT5_LIB := $(patsubst %/libQt5Core$(SUFF_DLL),%,$(firstword $(wildcard \ $(PATH_SDK_QT5)/lib/libQt5Core$(SUFF_DLL) \ $(PATH_SDK_QT5)/lib/qt5/libQt5Core$(SUFF_DLL) \ /usr/lib/libQt5Core$(SUFF_DLL) \ /usr/lib/qt5/libQt5Core$(SUFF_DLL) \ $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET_DOT_ARCH)),/usr/lib/$(type)/libQt5Core$(SUFF_DLL)) \ /usr/local/lib/libQt5Core$(SUFF_DLL) \ /usr/local/lib/qt5/libQt5Core$(SUFF_DLL) \ $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET_DOT_ARCH)),/usr/local/lib/$(type)/libQt5Core$(SUFF_DLL)) \ ))) endif ifneq ($(PATH_SDK_QT5_LIB),) export PATH_SDK_QT5_LIB endif endif endif endif # Unices endif # Found it? ifeq ($(PATH_SDK_QT5),) $(warning kBuild: Couldn't find the Qt5 headers and libaries...) PATH_SDK_QT5 := $(KBUILD_DEVTOOLS_TRG)/qt/not-found endif endif else # Resolve any fancy stuff once and for all. PATH_SDK_QT5 := $(PATH_SDK_QT5) endif # Libraries can be in either Frameworks or lib depending on how you # build it on the mac. The .dmg installs into Frameworks but builds into lib. ifeq ($(KBUILD_TARGET),darwin) ifndef PATH_SDK_QT5_LIB ifneq ($(wildcard $(PATH_SDK_QT5)/Frameworks),) PATH_SDK_QT5_LIB ?= $(PATH_SDK_QT5)/Frameworks else PATH_SDK_QT5_LIB ?= $(PATH_SDK_QT5)/lib endif endif else PATH_SDK_QT5_LIB ?= $(PATH_SDK_QT5)/lib PATH_SDK_QT5_INC ?= $(PATH_SDK_QT5)/include endif # The bits that kBuild picks up. # (nothing here) # # The QT5 tool. # # This is implemented here rather than in tools/QT5.kmk to enforce the global USES. # It also makes things easier to develop, with fewer files I mean. # TOOL_QT5 = Qt5 # Tool Specific Properties # PATH_TOOL_QT5 - Obsolete. # PATH_TOOL_QT5_BIN - The # TOOL_QT5_BIN_SUFF - if !defined(PATH_TOOL_QT5_BIN) && defined(PATH_TOOL_QT5) PATH_TOOL_QT5_BIN := $(PATH_TOOL_QT5)/bin endif ifndef PATH_TOOL_QT5_BIN PATH_TOOL_QT5_BIN := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST)/qt/v5*/bin))) if "$(PATH_TOOL_QT5_BIN)" == "" && "$(KBUILD_DEVTOOLS_HST_ALT)" != "" PATH_TOOL_QT5_BIN := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST_ALT)/qt/v5*/bin))) endif ifeq ($(PATH_TOOL_QT5_BIN),) ifdef TOOL_QT5_BIN_SUFF TOOL_QT5_BIN_SUFF := $(TOOL_QT5_BIN_SUFF) endif # Try looking for moc-qt5 / moc-$(suffix) first. ifneq ($(TOOL_QT5_BIN_SUFF),) PATH_TOOL_QT5_BIN := $(patsubst %/moc$(TOOL_QT5_BIN_SUFF),%,$(firstword $(wildcard \ $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt5/bin/moc$(TOOL_QT5_BIN_SUFF)) \ /usr/lib/qt5/bin/moc$(TOOL_QT5_BIN_SUFF) \ /usr/qt/5/bin/moc$(TOOL_QT5_BIN_SUFF) \ /usr/share/qt5/bin/moc$(TOOL_QT5_BIN_SUFF) \ /usr/local/bin/moc$(TOOL_QT5_BIN_SUFF) \ /usr/bin/moc$(TOOL_QT5_BIN_SUFF) \ ))) else # No suffix given, so before we check out -qt5 look at qt5 specific locations to avoid choosers and symlinks. PATH_TOOL_QT5_BIN := $(patsubst %/moc,%,$(firstword $(wildcard \ $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt5/bin/moc) \ $(if $(intersects $(KBUILD_HOST_ARCH), $(KBUILD_ARCHES_64)),/usr/lib64/qt5/bin/moc,) \ /usr/lib/qt5/bin/moc \ /usr/local/lib/qt5/bin/moc \ /usr/qt/5/bin/moc \ /usr/local/qt/5/bin/moc \ /usr/share/qt5/bin/moc \ /usr/local/share/qt5/bin/moc \ ))) ifeq ($(PATH_TOOL_QT5_BIN),) PATH_TOOL_QT5_BIN := $(patsubst %/moc-qt5,%,$(firstword $(wildcard \ $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt5/bin/moc-qt5) \ /usr/lib/qt5/bin/moc-qt5 \ /usr/qt/5/bin/moc-qt5 \ /usr/share/qt5/bin/moc-qt5 \ /usr/local/bin/moc-qt5 \ /usr/bin/moc-qt5 \ ))) ifneq ($(PATH_TOOL_QT5_BIN),) TOOL_QT5_BIN_SUFF := -qt5 endif endif endif # If still no go, try looking for qt4to5 and rcc. ifeq ($(PATH_TOOL_QT5_BIN),) PATH_TOOL_QT5_BIN := $(patsubst %/qt4to5,%,$(firstword $(wildcard \ $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt5/bin/qt4to5) \ /usr/lib/qt5/bin/qt4to5 \ /usr/qt/5/bin/qt4to5 \ /usr/share/qt5/bin/qt4to5 \ /usr/local/bin/qt4to5 \ /usr/bin/qt4to5 \ ))) endif ifeq ($(PATH_TOOL_QT5_BIN),) PATH_TOOL_QT5_BIN := $(patsubst %/rcc$(TOOL_QT5_BIN_SUFF),%,$(firstword $(wildcard \ $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt5/bin/rcc$(TOOL_QT5_BIN_SUFF)) \ /usr/lib/qt5/bin/rcc$(TOOL_QT5_BIN_SUFF) \ /usr/qt/5/bin/rcc$(TOOL_QT5_BIN_SUFF) \ /usr/share/qt5/bin/rcc$(TOOL_QT5_BIN_SUFF) \ /usr/local/bin/rcc$(TOOL_QT5_BIN_SUFF) \ /usr/bin/rcc$(TOOL_QT5_BIN_SUFF) \ ))) endif if "$(PATH_TOOL_QT5_BIN)" == "" && "$(TOOL_QT5_BIN_SUFF)" != "" PATH_TOOL_QT5_BIN := $(patsubst %/rcc,%,$(firstword $(wildcard \ $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt5/bin/rcc) \ /usr/lib/qt5/bin/rcc \ /usr/qt/5/bin/rcc \ /usr/share/qt5/bin/rcc \ /usr/local/bin/rcc \ /usr/bin/rcc \ ))) endif ifneq ($(PATH_TOOL_QT5_BIN),) export PATH_TOOL_QT5_BIN endif endif # If not found, we'll enter the 'pathless' mode. else # Resolve any fancy stuff once and for all. PATH_TOOL_QT5_BIN := $(PATH_TOOL_QT5_BIN) endif ifneq ($(PATH_TOOL_QT5_BIN),) TOOL_QT5_MOC ?= $(PATH_TOOL_QT5_BIN)/moc$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE) TOOL_QT5_UIC ?= $(PATH_TOOL_QT5_BIN)/uic$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE) ifndef TOOL_QT5_RCC TOOL_QT5_RCC := $(PATH_TOOL_QT5_BIN)/rcc$(HOSTSUFF_EXE) ifeq ($(wildcard $(TOOL_QT5_RCC)),) TOOL_QT5_RCC := $(PATH_TOOL_QT5_BIN)/rcc$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE) endif endif TOOL_QT5_LRC ?= $(PATH_TOOL_QT5_BIN)/lrelease$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE) TOOL_QT5_LUPDATE ?= $(PATH_TOOL_QT5_BIN)/lupdate$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE) else # Pathless, relies on the environment. TOOL_QT5_MOC ?= moc$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE) TOOL_QT5_UIC ?= uic$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE) TOOL_QT5_RCC ?= rcc$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE) TOOL_QT5_LRC ?= lrelease$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE) TOOL_QT5_LUPDATE ?= lupdate$(TOOL_QT5_BIN_SUFF)$(HOSTSUFF_EXE) endif ifdef TOOL_QT5_USE_KSUBMIT ifeq ($(KBUILD_HOST),win) TOOL_QT5_MOC_KSUBMIT ?= kmk_builtin_kSubmit --$(SP) endif endif # General Properties used by kBuild and/or units/qt.kmk TOOL_QT5_MOCFLAGS ?= TOOL_QT5_MOCINCS ?= TOOL_QT5_MOCDEFS ?= TOOL_QT5_MOCDEFS.darwin ?= __APPLE__ __GNUC__ TOOL_QT5_MOCDEFS.solaris ?= __sun TOOL_QT5_MOCDEFS.win.amd64 ?= WIN64 TOOL_QT5_MOCDEFS.win.x86 ?= WIN32 ## MOC a C++ source file. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(out) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This may be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. # @param $(incs) Includes. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_QT5_MOC_CPP_DEPEND = TOOL_QT5_MOC_CPP_DEPORD = TOOL_QT5_MOC_CPP_OUTPUT = TOOL_QT5_MOC_CPP_OUTPUT_MAYBE = define TOOL_QT5_MOC_CPP_CMDS $(QUIET)$(TOOL_QT5_MOC_KSUBMIT)$(TOOL_QT5_MOC)\ $(flags)\ $(addprefix -I, $(incs))\ $(addprefix -D, $(defs))\ -o $(out)\ $(source) endef ## MOC a C++ header file. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(out) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This may be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. # @param $(incs) Includes. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_QT5_MOC_HPP_DEPEND = TOOL_QT5_MOC_HPP_DEPORD = TOOL_QT5_MOC_HPP_OUTPUT = TOOL_QT5_MOC_HPP_OUTPUT_MAYBE = define TOOL_QT5_MOC_HPP_CMDS $(QUIET)$(TOOL_QT5_MOC_KSUBMIT)$(TOOL_QT5_MOC)\ $(flags)\ $(addprefix -I, $(incs))\ $(addprefix -D, $(defs))\ -o $(out)\ $(source) endef ## Compile a Qt user interface file (.ui). # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(out) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This may be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. # @param $(incs) Includes. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_QT5_UIC_UI_DEPEND = TOOL_QT5_UIC_UI_DEPORD = TOOL_QT5_UIC_UI_OUTPUT = TOOL_QT5_UIC_UI_OUTPUT_MAYBE = define TOOL_QT5_UIC_UI_CMDS $(QUIET)$(TOOL_QT5_UIC)\ $(flags)\ -o $(out)\ $(source) endef ## Compile a Qt resource file (.qrc). # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(out) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This may be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. # @param $(incs) Includes. # @param $(outbase) Output basename (full). Use this for list files and such. # # @remarks The sed script generating the dependency file is a bit naive. TOOL_QT5_RCC_QRC_DEPEND = TOOL_QT5_RCC_QRC_DEPORD = TOOL_QT5_RCC_QRC_OUTPUT = TOOL_QT5_RCC_QRC_OUTPUT_MAYBE = define TOOL_QT5_RCC_QRC_CMDS $(QUIET)$(TOOL_QT5_RCC)\ $(flags)\ -o $(out)\ $(source) $(QUIET2)$(APPEND) $(dep) '\' $(QUIET2)$(APPEND) $(dep) '$(out): \' $(QUIET2)$(APPEND) $(dep) '$(source) \' $(QUIET2)$(SED) \ -e '/^[[:blank:]]*]*>/!d' \ -e 's/^.*]*>\([^<]*\)<\/file>.*$$$$/\1/' \ -e 's|^[^/][^:]|$(abspathex $(dir $(source)),$(defpath))/&|' \ -e 's|$$$$| \\|' \ --append $(dep) \ $(source) $(QUIET2)$(APPEND) $(dep) $(QUIET2)$(SED) \ -e '/^[[:blank:]]*]*>/!d' \ -e 's/^.*]*>\([^<]*\)<\/file>.*$$$$/\1/' \ -e 's|^[^/][^:]|$(abspathex $(dir $(source)),$(defpath))/&|' \ -e 's|$$$$|:\n|' \ --append $(dep) \ $(source) $(QUIET2)$(APPEND) $(dep) endef ## Compile a Qt translation file (.ts). # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(out) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This may be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. # @param $(incs) Includes. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_QT5_LRC_TS_DEPEND = TOOL_QT5_LRC_TS_DEPORD = TOOL_QT5_LRC_TS_OUTPUT = TOOL_QT5_LRC_TS_OUTPUT_MAYBE = define TOOL_QT5_LRC_TS_CMDS $(QUIET)$(TOOL_QT5_LRC)\ $(flags)\ $(source)\ -qm $(out) endef # # # Back to the Qt5 unit. # # ## wrapper for the lrelease (LRC) command dependencies. ifndef NO_COMPILE_CMDS_DEPS _UNIT_QT5_LRC_CMDS_DEP = $$(comp-cmds-ex $$($(target)_$(subst :,_,$(source))_QT5_LRC_CMDS_PREV_),$$(commands $(out)),FORCE) else _UNIT_QT5_LRC_CMDS_DEP = endif ## # def_unit_qt5_target_pre_handle_translation helper that is expanded before evaluation. # # This is necessary to resolve reference to local variables before doing # assignments and setting up commands. They would otherwise be resolved # later in a different context and the result would be completely wrong. # define def_unit_qt5_target_pre_handle_translation_dx $(out) + $(more_output) +| $(maybe_output): \ $(deps) \ $(value _UNIT_QT5_LRC_CMDS_DEP) \ | \ $(orderdeps) %$$(call MSG_TOOL,lrelease,$(target),$(source),$$@) $(QUIET2)$(RM) -f $(out) $(more_output) $(maybe_output) $(dep) $(cmds) ifndef NO_COMPILE_CMDS_DEPS %$$(QUIET2)$$(APPEND) '$(dep)' %$$(QUIET2)$$(APPEND) '$(dep)' 'define $(target)_$(subst :,_,$(source))_QT5_LRC_CMDS_PREV_' %$$(QUIET2)$$(APPEND) -c '$(dep)' '$(out)' %$$(QUIET2)$$(APPEND) '$(dep)' 'endef' endif $(target)_CLEAN += $(out) $(more_output) $(maybe_output) $(dep) $(target)-inst-nls_SOURCES += $(out) endef # def_unit_qt5_target_pre_handle_translation_dx ## # Handle a source file listed in QT_TRANSLATIONS. # # The files listed in QT_TRANSLATIONS are translation files (.ts) which needs # to be translated into .qm files that are loadble by Qt. # # @remarks Invoked via $(evalvalctx ). define def_unit_qt5_target_pre_handle_translation local type := LRC # fetch the properties. local tool := $(kb-src-tool dummy_var) local qtnlsdir := $($(target)_0_OUTDIR)/qtnls local outbase := $(qtnlsdir)/$(notdir $(basename $(source))) local out := $(outbase).qm local dep := $(out).dep local flags := $(kb-src-prop FLAGS,dummy_var,right-to-left) local deps := $(kb-src-prop DEPS,dummy_var,left-to-right) local orderdeps := $(call DIRDEP,$(dir $(outbase))) $(kb-src-prop ORDERDEPS,dummy_var,left-to-right) # default path + source dep. ifneq ($(defpath),) local source := $(abspathex $(source),$(defpath)) local deps := $(abspathex $(deps),$(defpath)) $(source) local incs := $(abspathex $(incs),$(defpath)) else local deps += $(source) endif # call the tool ifndef TOOL_$(tool)_LRC_TS_CMDS $(error kBuild: qt lrelease tool not found: TOOL_$(tool)_LRC_TS_CMDS) endif local cmds := $(TOOL_$(tool)_LRC_TS_CMDS) local more_output := $(TOOL_$(tool)_LRC_TS_OUTPUT) local maybe_output := $(TOOL_$(tool)_LRC_TS_OUTPUT_MAYBE) local deps += $(TOOL_$(tool)_LRC_TS_DEPEND) local orderdeps += $(TOOL_$(tool)_LRC_TS_DEPORD) # generate the link rule and update some source and target variables. ifndef NO_COMPILE_CMDS_DEPS $(eval includedep $(dep)) endif $(eval $(def_unit_qt5_target_pre_handle_translation_dx)) endef # def_unit_qt5_target_pre_handle_translation ## wrapper for the UIC command dependencies. ifndef NO_COMPILE_CMDS_DEPS _UNIT_QT5_RCC_CMDS_DEP = $$(comp-cmds-ex $$($(target)_$(subst :,_,$(source))_QT5_RCC_CMDS_PREV_),$$(commands $(out)),FORCE) else _UNIT_QT5_RCC_CMDS_DEP = endif ## # def_unit_qt5_target_pre_handle_qrc helper that is expanded before evaluation. # # This is necessary to resolve reference to local variables before doing # assignments and setting up commands. They would otherwise be resolved # later in a different context and the result would be completely wrong. # define def_unit_qt5_target_pre_handle_rcc_dx $(out) +| $(realout) $(more_output) $(maybe_output): \ $(deps) \ $(value _UNIT_QT5_RCC_CMDS_DEP) \ | \ $(orderdeps) %$$(call MSG_TOOL,rcc,$(target),$(source),$$@) $(QUIET2)$(RM) -f $(out) $(more_output) $(maybe_output) $(dep) $(cmds) $(QUIET)$(CP) --changed -f $(out) $(realout) ifndef NO_COMPILE_CMDS_DEPS %$$(QUIET2)$$(APPEND) '$(dep)' %$$(QUIET2)$$(APPEND) '$(dep)' 'define $(target)_$(subst :,_,$(source))_QT5_RCC_CMDS_PREV_' %$$(QUIET2)$$(APPEND) -c '$(dep)' '$(out)' %$$(QUIET2)$$(APPEND) '$(dep)' 'endef' endif $(target)_INTERMEDIATES += $(realout) $(target)_GEN_SOURCES_ += $(realout) $(target)_CLEAN += $(out) $(realout) $(more_output) $(maybe_output) $(dep) endef # def_unit_qt5_target_pre_handle_rcc_dx ## # Source handler for .qrc sources (Qt resource files). # # @remarks $(evalvalctx me). define def_unit_qt5_src_handler_qrc local type := RCC # fetch the properties. local tool := $(kb-src-tool dummy_var) local qtrccdir := $($(target)_0_OUTDIR)/qtrcc local outbase := $(qtrccdir)/$(notdir $(basename $(source))) local out := $(outbase).tmp.gen.cpp local realout := $(outbase).gen.cpp local dep := $(realout).dep local flags := $(kb-src-prop FLAGS,dummy_var,right-to-left) local deps := $(kb-src-prop DEPS,dummy_var,left-to-right) local orderdeps := $(call DIRDEP,$(dir $(outbase))) $(kb-src-prop ORDERDEPS,dummy_var,left-to-right) # default path + source dep. ifneq ($(defpath),) local source := $(abspathex $(source),$(defpath)) local deps := $(abspathex $(deps),$(defpath)) $(source) local incs := $(abspathex $(incs),$(defpath)) else local deps += $(source) endif # call the tool ifndef TOOL_$(tool)_RCC_QRC_CMDS $(error kBuild: qt rcc tool not found: TOOL_$(tool)_RCC_QRC_CMDS) endif local cmds := $(TOOL_$(tool)_RCC_QRC_CMDS) local more_output := $(TOOL_$(tool)_RCC_QRC_OUTPUT) local maybe_output := $(TOOL_$(tool)_RCC_QRC_OUTPUT_MAYBE) local deps += $(TOOL_$(tool)_RCC_QRC_DEPEND) local orderdeps += $(TOOL_$(tool)_RCC_QRC_DEPORD) # generate the link rule and update some source and target variables. ifndef NO_COMPILE_CMDS_DEPS $(eval includedep $(dep)) endif $(eval $(def_unit_qt5_target_pre_handle_rcc_dx)) endef # def_unit_qt5_src_handler_qrc ## wrapper for the UIC command dependencies. ifndef NO_COMPILE_CMDS_DEPS _UNIT_QT5_UIC_CMDS_DEP = $$(comp-cmds-ex $$($(target)_$(subst :,_,$(source))_QT5_UIC_CMDS_PREV_),$$(commands $(out)),FORCE) else _UNIT_QT5_UIC_CMDS_DEP = endif ## # def_unit_qt5_src_handler_ui helper that is expanded before evaluation. # # This is necessary to resolve reference to local variables before doing # assignments and setting up commands. They would otherwise be resolved # later in a different context and the result would be completely wrong. # define def_unit_qt5_target_pre_handle_ui_dx $(out) +| $(realout) $(more_output) $(maybe_output): \ $(deps) \ $(value _UNIT_QT5_UIC_CMDS_DEP) \ | \ $(orderdeps) %$$(call MSG_TOOL,uic,$(target),$(source),$$@) $(QUIET2)$(RM) -f $(out) $(more_output) $(maybe_output) $(dep) $(cmds) $(QUIET)$(CP) --changed -f $(out) $(realout) ifndef NO_COMPILE_CMDS_DEPS %$$(QUIET2)$$(APPEND) '$(dep)' %$$(QUIET2)$$(APPEND) '$(dep)' 'define $(target)_$(subst :,_,$(source))_QT5_UIC_CMDS_PREV_' %$$(QUIET2)$$(APPEND) -c '$(dep)' '$(out)' %$$(QUIET2)$$(APPEND) '$(dep)' 'endef' endif $(target)_INTERMEDIATES += $(realout) $(target)_CLEAN += $(out) $(realout) $(more_output) $(maybe_output) $(dep) endef # def_unit_qt5_target_pre_handle_ui_dx ## # Source handler for .ui sources. # # @remarks $(evalvalctx me). define def_unit_qt5_src_handler_ui local type := UIC # fetch the properties. local tool := $(kb-src-tool dummy_var) local qtuicdir := $($(target)_0_OUTDIR)/qtuic local outbase := $(qtuicdir)/$(notdir $(basename $(source))) local out := $(outbase).tmp.gen.h local realout := $(outbase).gen.h local dep := $(realout).dep local flags := $(kb-src-prop FLAGS,dummy_var,right-to-left) local deps := $(kb-src-prop DEPS,dummy_var,left-to-right) local orderdeps := $(call DIRDEP,$(dir $(outbase))) $(kb-src-prop ORDERDEPS,dummy_var,left-to-right) # default path + source dep. ifneq ($(defpath),) local source := $(abspathex $(source),$(defpath)) local deps := $(abspathex $(deps),$(defpath)) $(source) local incs := $(abspathex $(incs),$(defpath)) else local deps += $(source) endif # call the tool ifndef TOOL_$(tool)_UIC_UI_CMDS $(error kBuild: qt uic tool not found: TOOL_$(tool)_UIC_UI_CMDS) endif local cmds := $(TOOL_$(tool)_UIC_UI_CMDS) local more_output := $(TOOL_$(tool)_UIC_UI_OUTPUT) local maybe_output := $(TOOL_$(tool)_UIC_UI_OUTPUT_MAYBE) local deps += $(TOOL_$(tool)_UIC_UI_DEPEND) local orderdeps += $(TOOL_$(tool)_UIC_UI_DEPORD) # generate the link rule and update some source and target variables. ifndef NO_COMPILE_CMDS_DEPS $(eval includedep $(dep)) endif $(eval $(def_unit_qt5_target_pre_handle_ui_dx)) endef # def_unit_qt5_src_handler_ui ## wrapper for the MOC command dependencies. ifndef NO_COMPILE_CMDS_DEPS _UNIT_QT5_MOC_HPP_CMDS_DEP = $$(comp-cmds-ex $$($(target)_$(subst :,_,$(source))_QT5_MOC_HPP_CMDS_PREV_),$$(commands $(out)),FORCE) else _UNIT_QT5_MOC_HPP_CMDS_DEP = endif ## # def_unit_qt5_target_pre_handle_moc_hdr helper that is expanded before evaluation. # # This is necessary to resolve reference to local variables before doing # assignments and setting up commands. They would otherwise be resolved # later in a different context and the result would be completely wrong. # define def_unit_qt5_target_pre_handle_moc_hdr_dx $(out) +| $(realout) $(more_output) $(maybe_output): \ $(deps) \ $(value _UNIT_QT5_MOC_HPP_CMDS_DEP) \ | \ $(orderdeps) %$$(call MSG_TOOL,moc,$(target),$(source),$$@) $(QUIET2)$(RM) -f $(out) $(more_output) $(maybe_output) $(dep) $(cmds) $(QUIET)$(CP) --changed -f $(out) $(realout) ifndef NO_COMPILE_CMDS_DEPS %$$(QUIET2)$$(APPEND) '$(dep)' %$$(QUIET2)$$(APPEND) '$(dep)' 'define $(target)_$(subst :,_,$(source))_QT5_MOC_HPP_CMDS_PREV_' %$$(QUIET2)$$(APPEND) -c '$(dep)' '$(out)' %$$(QUIET2)$$(APPEND) '$(dep)' 'endef' endif $(target)_INTERMEDIATES += $(realout) $(target)_GEN_SOURCES_ += $(realout) $(target)_CLEAN += $(out) $(realout) $(more_output) $(maybe_output) $(dep) endef ## # Handle a source file listed in QT_MOCHDRS. # # The files listed in QT_MOCHDRS uses the Q_OBJECT macro and we will # generate a .cpp file for each of them and add it to the generated # sources so that it's compiled and linked. (There is an alternative # way to do this where the .cpp file is included, this isn't currently # supported by this unit.) # # @remarks Invoked via $(evalvalctx ). define def_unit_qt5_target_pre_handle_moc_hdr local type := MOC # fetch the properties. local tool := $(kb-src-tool dummy_var) local outbase := $(qtmocdir)/$(notdir $(basename $(source))) local out := $(outbase).tmp.cpp local realout := $(outbase).cpp local dep := $(realout).dep local defs := $(kb-src-prop DEFS,dummy_var,left-to-right) local incs := $(kb-src-prop INCS,dummy_var,right-to-left) local flags := $(kb-src-prop FLAGS,dummy_var,right-to-left) local deps := $(kb-src-prop DEPS,dummy_var,left-to-right) local orderdeps := $(call DIRDEP,$(dir $(outbase))) $(kb-src-prop ORDERDEPS,dummy_var,left-to-right) # default path + source dep. ifneq ($(defpath),) local source := $(abspathex $(source),$(defpath)) local deps := $(abspathex $(deps),$(defpath)) $(source) local incs := $(abspathex $(incs),$(defpath)) else local deps += $(source) endif # call the tool ifndef TOOL_$(tool)_MOC_HPP_CMDS $(error kBuild: qt moc tool not found: TOOL_$(tool)_MOC_HPP_CMDS) endif local cmds := $(TOOL_$(tool)_MOC_HPP_CMDS) local more_output := $(TOOL_$(tool)_MOC_HPP_OUTPUT) local maybe_output := $(TOOL_$(tool)_MOC_HPP_OUTPUT_MAYBE) local deps += $(TOOL_$(tool)_MOC_HPP_DEPEND) local orderdeps += $(TOOL_$(tool)_MOC_HPP_DEPORD) # generate the link rule and update some source and target variables. ifndef NO_COMPILE_CMDS_DEPS $(eval includedep $(dep)) endif $(eval $(def_unit_qt5_target_pre_handle_moc_hdr_dx)) endef # def_unit_qt5_target_pre_handle_moc_hdr ## wrapper for the MOC command dependencies. ifndef NO_COMPILE_CMDS_DEPS _UNIT_QT5_MOC_CPP_CMDS_DEP = $$(comp-cmds-ex $$($(target)_$(subst :,_,$(source))_QT5_MOC_CPP_CMDS_PREV_),$$(commands $(out)),FORCE) else _UNIT_QT5_MOC_CPP_CMDS_DEP = endif ## # def_unit_qt5_target_pre_handle_moc_src helper that is expanded before evaluation. # # This is necessary to resolve reference to local variables before doing # assignments and setting up commands. They would otherwise be resolved # later in a different context and the result would be completely wrong. # define def_unit_qt5_target_pre_handle_moc_src_dx $(out) +| $(realout) $(more_output) $(maybe_output): \ $(deps) \ $(value _UNIT_QT5_MOC_CPP_CMDS_DEP) \ | \ $(orderdeps) %$$(call MSG_TOOL,moc,$(target),$(source),$$@) $(QUIET2)$(RM) -f $(out) $(more_output) $(maybe_output) $(dep) $(cmds) $(QUIET)$(CP) --changed -f $(out) $(realout) ifndef NO_COMPILE_CMDS_DEPS %$$(QUIET2)$$(APPEND) '$(dep)' %$$(QUIET2)$$(APPEND) '$(dep)' 'define $(target)_$(subst :,_,$(source))_QT5_MOC_CPP_CMDS_PREV_' %$$(QUIET2)$$(APPEND) -c '$(dep)' '$(out)' %$$(QUIET2)$$(APPEND) '$(dep)' 'endef' endif $(target)_INTERMEDIATES += $(realout) $(target)_CLEAN += $(out) $(realout) $(more_output) $(maybe_output) $(dep) endef ## # Handle a source file listed in QT_MOCSRCS. # # The files listed in QT_MOCSRCS uses the Q_OBJECT macro and will include # a .moc file that we're expected to generate here. # # @remarks Invoked via $(evalvalctx ). define def_unit_qt5_target_pre_handle_moc_src local type := MOC # fetch the properties. local tool := $(kb-src-tool dummy_var) local outbase := $(qtmocdir)/$(notdir $(basename $(source))) local out := $(outbase).tmp.moc local realout := $(outbase).moc local dep := $(realout).dep local defs := $(kb-src-prop DEFS,dummy_var,left-to-right) local incs := $(kb-src-prop INCS,dummy_var,right-to-left) local flags := $(kb-src-prop FLAGS,dummy_var,right-to-left) local deps := $(kb-src-prop DEPS,dummy_var,left-to-right) local orderdeps := $(call DIRDEP,$(dir $(outbase))) $(kb-src-prop ORDERDEPS,dummy_var,left-to-right) # default path + source dep. ifneq ($(defpath),) local source := $(abspathex $(source),$(defpath)) local deps := $(abspathex $(deps),$(defpath)) $(source) local incs := $(abspathex $(incs),$(defpath)) else local deps += $(source) endif # call the tool ifndef TOOL_$(tool)_MOC_CPP_CMDS $(error kBuild: qt moc tool not found: TOOL_$(tool)_MOC_CPP_CMDS) endif local cmds := $(TOOL_$(tool)_MOC_CPP_CMDS) local more_output := $(TOOL_$(tool)_MOC_CPP_OUTPUT) local maybe_output := $(TOOL_$(tool)_MOC_CPP_OUTPUT_MAYBE) local deps += $(TOOL_$(tool)_MOC_CPP_DEPEND) local orderdeps += $(TOOL_$(tool)_MOC_CPP_DEPORD) # generate the link rule and update some source and target variables. ifndef NO_COMPILE_CMDS_DEPS $(eval includedep $(dep)) endif $(eval $(def_unit_qt5_target_pre_handle_moc_src_dx)) endef # def_unit_qt5_target_pre_handle_moc_src ## # Adds sources containing Q_OBJECT to QT_MOCSRCS. define def_unit_qt5_target_pre_cpp_source ifneq ($(file-size $(source)),-1) ifneq ($(strip $(shell $(SED) -f $(KBUILD_PATH)/units/qt-Q_OBJECT.sed $(source))),) $(eval $(target)_QT_MOCSRCS += $(source)) endif endif endef # def_unit_qt5_target_pre_cpp_source ## # Invoked early in the processing of a target that uses the Qt unit. # # It will append the qt source handlers to the target (.h, .ui, .ts, # .png, .bmp, .gif). # # It will then check all the C++ sources and check which needs # a .moc files and generate rules and dependencies fofor these # define def_unit_qt5_target_pre # Make QTTOOL the default for the specific Qt tools instead of TOOL. ifneq ($($(target)_QTTOOL),) ifeq ($($(target)_MOCTOOL),) $(target)_MOCTOOL := $($(target)_QTTOOL) endif ifeq ($($(target)_UICTOOL),) $(target)_UICTOOL := $($(target)_QTTOOL) endif ifeq ($($(target)_RCCTOOL),) $(target)_RCCTOOL := $($(target)_QTTOOL) endif ifeq ($($(target)_LRCTOOL),) $(target)_LRCTOOL := $($(target)_QTTOOL) endif endif # Deal with QT_MODULES, QT_PREFIX and QT_INFIX. local qt_modules := \ $($(target)_QT_MODULES.$(bld_trg)) \ $($(target)_QT_MODULES.$(bld_trg_arch)) \ $($(target)_QT_MODULES.$(bld_trg).$(bld_trg_arch)) \ $($(target)_QT_MODULES.$(bld_trg_cpu)) \ $($(target)_QT_MODULES.$(bld_type)) \ $($(target)_QT_MODULES) local qt_prefix := $(firstword \ $($(target)_QT_PREFIX.$(bld_trg)) \ $($(target)_QT_PREFIX.$(bld_trg_arch)) \ $($(target)_QT_PREFIX.$(bld_trg).$(bld_trg_arch)) \ $($(target)_QT_PREFIX.$(bld_trg_cpu)) \ $($(target)_QT_PREFIX.$(bld_type)) \ $($(target)_QT_PREFIX)) local qt_infix := $(firstword \ $($(target)_QT_INFIX.$(bld_trg)) \ $($(target)_QT_INFIX.$(bld_trg_arch)) \ $($(target)_QT_INFIX.$(bld_trg).$(bld_trg_arch)) \ $($(target)_QT_INFIX.$(bld_trg_cpu)) \ $($(target)_QT_INFIX.$(bld_type)) \ $($(target)_QT_INFIX)) ifeq ($(bld_trg),darwin) # Adding -F to CXXFLAGS is necessary to make #include stuff work... $(eval $(target)_CXXFLAGS += -F$(PATH_SDK_QT5_LIB) ) $(eval $(target)_OBJCXXFLAGS += -F$(PATH_SDK_QT5_LIB) ) $(eval $(target)_LDFLAGS += -F$(PATH_SDK_QT5_LIB) $(foreach module,$(qt_modules), -framework $(qt_prefix)Qt$(module)$(qt_infix)) ) $(eval $(target)_INCS += $(foreach module,$(qt_modules), $(PATH_SDK_QT5_LIB)/$(qt_prefix)Qt$(module)$(qt_infix).framework/Versions/5/Headers) ) else ifeq ($(bld_trg),win) $(eval $(target)_LIBS += $(foreach module,$(qt_modules), $(PATH_SDK_QT5_LIB)/$(qt_prefix)Qt5$(module)$(qt_infix)$(SUFF_LIB)) ) ifeq ($(tool_do),LINK_PROGRAM) $(eval $(target)_LIBS += $(PATH_SDK_QT5_LIB)/$(qt_prefix)qtmain$(qt_infix)$(SUFF_LIB) ) endif else $(eval $(target)_LIBS += $(foreach module,$(qt_modules), $(PATH_SDK_QT5_LIB)/lib$(qt_prefix)Qt5$(module)$(qt_infix)$(SUFF_DLL)) ) endif $(eval $(target)_INCS += $(addprefix $(PATH_SDK_QT5_INC)/Qt,$(qt_modules)) $(PATH_SDK_QT5_INC) ) endif $(eval $(target)_DEFS += $(foreach module,$(toupper $(qt_modules)), QT_$(module)_LIB) ) # Autodetect source files with Q_OBJECT references if QT_MOCSRCS is undefined. (slow) # Tip: Use target_QT_MOCSRCS = $(NO_SUCH_VARIABLE) to avoid this. ifndef $(target)_QT_MOCSRCS $(foreach source, $(filter %.cxx %.CXX %.cpp %.CPP %.cc %.CC,\ $($(target)_SOURCES.$(bld_trg)) \ $($(target)_SOURCES.$(bld_trg_arch)) \ $($(target)_SOURCES.$(bld_trg).$(bld_trg_arch)) \ $($(target)_SOURCES.$(bld_trg_cpu)) \ $($(target)_SOURCES.$(bld_type)) \ $($(target)_SOURCES) \ ), $(evalval def_unit_qt5_target_pre_cpp_source)) endif # Install source handlers for .ui files. $(target)_SRC_HANDLERS += \ .ui:def_unit_qt5_src_handler_ui \ .UI:def_unit_qt5_src_handler_ui \ .qrc:def_unit_qt5_src_handler_qrc \ .qrc:def_unit_qt5_src_handler_qrc # Calc the MOC and UI output directories and add them to BLDDIRS and INCS. local qtmocdir := $($(target)_0_OUTDIR)/qtmoc local qtuicdir := $($(target)_0_OUTDIR)/qtuic local qtrccdir := $($(target)_0_OUTDIR)/qtrcc local qtnlsdir := $($(target)_0_OUTDIR)/qtnls $(eval $(target)_BLDDIRS += $(qtmocdir) $(qtuicdir) $(qtrccdir) $(qtnlsdir)) $(eval $(target)_INCS += $(qtmocdir) $(qtuicdir)) # Deal with QT_MOCSRCS. $(foreach source, \ $($(target)_QT_MOCSRCS.$(bld_trg)) \ $($(target)_QT_MOCSRCS.$(bld_trg_arch)) \ $($(target)_QT_MOCSRCS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_QT_MOCSRCS.$(bld_trg_cpu)) \ $($(target)_QT_MOCSRCS.$(bld_type)) \ $($(target)_QT_MOCSRCS) \ , $(evalvalctx def_unit_qt5_target_pre_handle_moc_src)) # Deal with QT_MOCHDRS. $(foreach source, \ $($(target)_QT_MOCHDRS.$(bld_trg)) \ $($(target)_QT_MOCHDRS.$(bld_trg_arch)) \ $($(target)_QT_MOCHDRS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_QT_MOCHDRS.$(bld_trg_cpu)) \ $($(target)_QT_MOCHDRS.$(bld_type)) \ $($(target)_QT_MOCHDRS) \ , $(evalvalctx def_unit_qt5_target_pre_handle_moc_hdr)) # Deal with QT_TRANSLATIONS. # ASSUMES (_ALL_)INSTALLS is processed after the targets using this unit. local translations := \ $($(target)_QT_TRANSLATIONS.$(bld_trg)) \ $($(target)_QT_TRANSLATIONS.$(bld_trg_arch)) \ $($(target)_QT_TRANSLATIONS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_QT_TRANSLATIONS.$(bld_trg_cpu)) \ $($(target)_QT_TRANSLATIONS.$(bld_type)) \ $($(target)_QT_TRANSLATIONS) ifneq ($(strip $(translations)),) local expr := _ALL_INSTALLS_IMPLICIT += $(target)-inst-nls $(eval $(expr)) ifdef $(target)_QT_TRANSLATIONS_TEMPLATE $(target)-inst-nls_TEMPLATE := $($(target)_QT_TRANSLATIONS_TEMPLATE) else $(target)-inst-nls_MODE := 0644 endif ifdef $(target)_QT_TRANSLATIONS_INST $(target)-inst-nls_INST := $($(target)_QT_TRANSLATIONS_INST) endif $(target)-inst-nls_SOURCES := $(foreach source, $(translations)\ , $(evalvalctx def_unit_qt5_target_pre_handle_translation)) endif endef # def_unit_qt5_target_pre # # Rule for debugging. # unit-qt5-show-vars: @$(ECHO) 'The Qt5 SDK variables:' @$(ECHO) ' PATH_SDK_QT5 = "$(PATH_SDK_QT5)"' @$(ECHO) ' PATH_SDK_QT5_INC = "$(PATH_SDK_QT5_INC)"' @$(ECHO) ' PATH_SDK_QT5_LIB = "$(PATH_SDK_QT5_LIB)"' @$(ECHO) ' PATH_SDK_QT5_LIB.amd64 = "$(PATH_SDK_QT5_LIB.amd64)"' @$(ECHO) ' PATH_SDK_QT5_LIB.x86 = "$(PATH_SDK_QT5_LIB.x86)"' @$(ECHO) 'The Qt5 TOOL variables:' @$(ECHO) ' PATH_TOOL_QT5_BIN = "$(PATH_TOOL_QT5_BIN)"' @$(ECHO) ' TOOL_QT5_BIN_SUFF = "$(TOOL_QT5_BIN_SUFF)"' @$(ECHO) ' TOOL_QT5_MOC = "$(TOOL_QT5_MOC)"' @$(ECHO) ' TOOL_QT5_UIC = "$(TOOL_QT5_UIC)"' @$(ECHO) ' TOOL_QT5_RCC = "$(TOOL_QT5_RCC)"' @$(ECHO) ' TOOL_QT5_LRC = "$(TOOL_QT5_LRC)"' @$(ECHO) ' TOOL_QT5_LUPDATE = "$(TOOL_QT5_LUPDATE)"' kbuild-3149/kBuild/units/lex.kmk0000644000175000017500000001041313252530251016551 0ustar locutuslocutus# $Id: lex.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # lex unit. # # # Copyright (c) 2008-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # ifdef UNIT_lex $(error kBuild: The lex unit was included twice!) endif UNIT_lex = lex # Add our target properties. PROPS_TOOLS += LEXTOOL PROPS_SINGLE += LEXTOOL PROPS_ACCUMULATE_R += LEXFLAGS # Add ourselves to the default source handlers. KBUILD_SRC_HANDLERS += \ .l:def_src_handler_lex ## wrapper the compile command dependency check. ifndef NO_COMPILE_CMDS_DEPS _DEP_LEX_CMDS = $$(comp-cmds-ex $$($(target)_$(subst :,_,$(source))_LEX_CMDS_PREV_),$$(commands $(out)),FORCE) else _DEP_LEX_CMDS = endif ## # Generates the rules for running flex on a specific source file. # # @param $(obj) The object file. # @param lots more define def_lex_rule $(out) + $(output_extra) +| $(output_maybe) : \ $(deps) \ $(value _DEP_LEX_CMDS) \ | \ $(orderdeps) %$$(call MSG_COMPILE,$(target),$(source),$$@,$(type)) $$(QUIET)$$(RM) -f -- $(dep) $(out) $(output_extra) $(output_maybe) $(cmds) ifndef NO_COMPILE_CMDS_DEPS %$$(QUIET2)$$(APPEND) '$(dep)' %$$(QUIET2)$$(APPEND) '$(dep)' 'define $(target)_$(subst :,_,$(source))_LEX_CMDS_PREV_' %$$(QUIET2)$$(APPEND) -c '$(dep)' '$(out)' %$$(QUIET2)$$(APPEND) '$(dep)' 'endef' endif # update globals _OUT_FILES += $(out) $(output_extra) $(output_maybe) $(target)_GEN_SOURCES_ += $(out) $(target)_INTERMEDIATES += $(intermediates) endef # def_lex_rule ## # Handler for .l files listed in the SOURCES properties. # # .l files are transformed into .c files that then gets compiled by # the C compiler. # # @param target The target file. # @param source The source file. # @param lots more # @returns quite a bit. define def_src_handler_lex # Figure out all the props. local type := LEX local tmp := $(kb-src-tool tool) ifeq ($(tool),) $(error kBuild: $(target) / $(sources) does not a (lex) tool defined!) endif ifndef TOOL_$(tool)_LEX_CMDS $(error kBuild: TOOL_$(tool)_LEX_CMDS isn't defined! target=$(target) source=$(source) ) endif local out := $(kb-obj-base outbase).c local tmp := $(kb-src-prop LEXFLAGS,flags,left-to-right,) local tmp := $(kb-src-prop DEPS,deps,left-to-right,$(defpath)) local tmp := $(kb-src-prop ORDERDEPS,orderdeps,left-to-right,$(defpath)) ifdef TOOL_$(tool)_LEX_OUT_FILE # .c/.cpp output depends on flags. local out := $(strip $(TOOL_$(tool)_LEX_OUT_FILE)) ifeq ($(out),) local out := $(outbase).c endif endif local dirdep := $(call DIRDEP,$(dir $(out))) # Adjust paths if we got a default path. ifneq ($(defpath),) local source := $(abspathex $(source),$(defpath)) endif # dependency file. local dep := $(out)$(SUFF_DEP) ifndef NO_COMPILE_CMDS_DEPS _DEPFILES_INCLUDED += $(dep) $(eval includedep $(dep)) endif # call the tool local cmds := $(TOOL_$(tool)_LEX_CMDS) local output_extra := $(TOOL_$(tool)_LEX_OUTPUT) local output_maybe := $(TOOL_$(tool)_LEX_OUTPUT_MAYBE) local deps += $(TOOL_$(tool)_LEX_DEPEND) $(source) local orderdeps += $(TOOL_$(tool)_LEX_DEPORD) $(dirdep) # Whether it generates a header file depends on the tool / flags. local intermediates := $(filter %.h %.hpp %.h++ %.H,$(output_extra)) # generate the rule. $(eval $(def_lex_rule)) endef # def_src_handler_lex kbuild-3149/kBuild/units/qt-Q_OBJECT.sed0000644000175000017500000000222113252530251017620 0ustar locutuslocutus# $Id: qt-Q_OBJECT.sed 2413 2010-09-11 17:43:04Z bird $ ## @file # Qt unit - sed script for checking for Q_OBJECT in a file. # # This is not very sophisticated, but it helps avoid generating # files we don't need. It outputs '1' when Q_OBJECT is found # and then quits, allowing us to do $(if $(shell ...),moc_...). # is # # # Copyright (c) 2008-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # /Q_OBJECT/!b skip s/^.*$/1/ q 0 :skip d kbuild-3149/kBuild/units/qt3.kmk0000644000175000017500000010220613252530251016472 0ustar locutuslocutus# $Id: qt3.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # Qt 3.3.x unit. # # # Copyright (c) 2008-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # ifdef UNIT_qt3 $(error kBuild: The qt3 unit was included twice!) endif UNIT_qt3 = qt3 if !defined(UNIT_qt4) && !defined(UNIT_qt5) # Add our target properties (same as qt4 & qt5). PROPS_SINGLE += QTTOOL MOCTOOL UICTOOL LRCTOOL QT_TRANSLATIONS_INST QT_TRANSLATIONS_TEMPLATE QT_PREFIX PROPS_ACCUMULATE_R += MOCDEFS MOCFLAGS UICFLAGS LRCFLAGS QT_TRANSLATIONS QT_MOCSRCS QT_MOCHDRS endif PROPS_SINGLE += PROPS_ACCUMULATE_R += QT_IMAGES # # The QT3 SDK. # # This is implemented here rather than in sdks/QT3.kmk to enforce the global USES. # It also makes things easier to develop, with fewer files I mean. # ## @todo the SDK might actually not be necessary as it turns out... For now it servers # a purpose if the host differs from the target, in theory at least. SDK_QT3 = Qt3 # SDK Specific Properties # PATH_SDK_QT3 - the general location of the Qt3 SDK stuff. # PATH_SDK_QT3_INC - the Qt3 include directory. # PATH_SDK_QT3_LIB - the Qt3 library directory for KBUILD_TARGET. # PATH_SDK_QT3_LIB.amd64 - the Qt3 library directory for AMD64. # PATH_SDK_QT3_LIB.x86 - the Qt3 library directory for X86. ifndef PATH_SDK_QT3 PATH_SDK_QT3 := $(firstword $(rsort $(wildcard $(PATH_DEVTOOLS_TRG)/qt/v3*))) ifeq ($(PATH_SDK_QT3),) # If target == host, try look for Qt in the various platform specific places. ifeq ($(KBUILD_TARGET),$(KBUILD_HOST)) ifeq ($(KBUILD_TARGET),darwin) # No idea here yet... else ifeq ($(KBUILD_TARGET),os2) # No idea here yet... Check QTDIR perhaps, but for now users have toset PATH_SDK_QT3. else ifeq ($(KBUILD_TARGET),win) # No idea here yet... Check QTDIR perhaps, but for now users have toset PATH_SDK_QT3. else # The Unices. Includes and esp. libs are tricky, so override the PATH_SDK_QT3_LIB* stuff if it doesn't work. # Try find the general location of the thing by looking for the qm2ts program, then try looking for # the moc program in likely and unlikely places save /usr[/local]/bin to avoid mistaking it with Qt4. PATH_SDK_QT3 := $(patsubst %/bin/qm2ts,%,$(firstword $(wildcard \ /usr/lib/qt-3.3/bin/qm2ts \ /usr/lib64/qt-3.3/bin/qm2ts \ /usr/qt/3/bin/qm2ts \ $(if $(QTDIR),$(QTDIR)/bin/qm2ts) \ /usr/bin/qm2ts \ /usr/local/bin/qm2ts \ /usr/share/qt3/bin/qm2ts \ ))) ifeq ($(PATH_SDK_QT3),) # Try with moc, but not in /usr/bin and /usr/local/bin. PATH_SDK_QT3 := $(patsubst %/bin/moc,%,$(firstword $(wildcard \ /usr/lib/qt-3.3/bin/moc \ /usr/lib64/qt-3.3/bin/moc \ /usr/qt/3/bin/moc \ /usr/share/qt3/bin/moc \ $(if $(QTDIR),$(QTDIR)/bin/moc) \ ))) endif ifneq ($(PATH_SDK_QT3),) # Found something! Export the variable for the benefit of recursive make instances. export PATH_SDK_QT3 # Determin the include directory. ifeq ($(PATH_SDK_QT3_INC),) PATH_SDK_QT3_INC := $(patsubst %/private/qfiledefs_p.h,%,$(firstword $(wildcard \ $(PATH_SDK_QT3)/include/private/qfiledefs_p.h \ $(PATH_SDK_QT3)/include/qt3/private/qfiledefs_p.h \ /usr/include/qt3/private/qfiledefs_p.h))) ifneq ($(PATH_SDK_QT3_INC),) export PATH_SDK_QT3_INC endif endif # Determin the most likely x86 and AMD64 lib directories (only used for making PATH_SDK_QT3_LIB). ifeq ($(PATH_SDK_QT3_LIB.x86),) PATH_SDK_QT3_LIB.x86 := $(patsubst %/libqt-mt$(SUFF_DLL),%,$(firstword $(wildcard \ $(PATH_SDK_QT3)/lib32/libqt-mt$(SUFF_DLL) \ $(PATH_SDK_QT3)/lib32/qt3/libqt-mt$(SUFF_DLL) \ $(PATH_SDK_QT3)/lib32/qt3-3/lib/libqt-mt$(SUFF_DLL) \ /usr/lib32/libqt-mt$(SUFF_DLL) \ /usr/lib32/qt3/libqt-mt$(SUFF_DLL) \ /usr/lib/i386-linux-gnu/libqt-mt$(SUFF_DLL) \ /usr/local/lib32/libqt-mt$(SUFF_DLL) \ /usr/local/lib32/qt3/libqt-mt$(SUFF_DLL) \ /usr/local/lib32/qt3-3/lib/libqt-mt$(SUFF_DLL) \ /usr/local/lib/i386-linux-gnu/libqt-mt$(SUFF_DLL) \ $(PATH_SDK_QT3)/lib/libqt-mt$(SUFF_DLL) \ $(PATH_SDK_QT3)/lib/qt3/libqt-mt$(SUFF_DLL) \ $(PATH_SDK_QT3)/lib/qt3-3/lib/libqt-mt$(SUFF_DLL) \ $(PATH_SDK_QT3)/lib/i386-linux-gnu/libqt-mt$(SUFF_DLL) \ ))) ifneq ($(PATH_SDK_QT3_LIB.x86),) export PATH_SDK_QT3_LIB.x86 endif endif ifeq ($(PATH_SDK_QT3_LIB.amd64),) PATH_SDK_QT3_LIB.amd64 := $(patsubst %/libqt-mt$(SUFF_DLL),%,$(firstword $(wildcard \ $(PATH_SDK_QT3)/lib64/libqt-mt$(SUFF_DLL) \ $(PATH_SDK_QT3)/lib64/qt3/libqt-mt$(SUFF_DLL) \ $(PATH_SDK_QT3)/lib64/qt3-3/lib/libqt-mt$(SUFF_DLL) \ $(PATH_SDK_QT3)/lib/amd64/libqt-mt$(SUFF_DLL) \ $(PATH_SDK_QT3)/lib/64/libqt-mt$(SUFF_DLL) \ /usr/lib64/libqt-mt$(SUFF_DLL) \ /usr/lib64/qt3/libqt-mt$(SUFF_DLL) \ /usr/lib64/qt3-3/lib/libqt-mt$(SUFF_DLL) \ /usr/lib/amd64/libqt-mt$(SUFF_DLL) \ /usr/lib/64/libqt-mt$(SUFF_DLL) \ /usr/lib/x86_64-linux-gnu/libqt-mt$(SUFF_DLL) \ /usr/local/lib64/libqt-mt$(SUFF_DLL) \ /usr/local/lib64/qt3/libqt-mt$(SUFF_DLL) \ /usr/local/lib64/qt3-3/lib/libqt-mt$(SUFF_DLL) \ /usr/local/lib/amd64/libqt-mt$(SUFF_DLL) \ /usr/local/lib/64/libqt-mt$(SUFF_DLL) \ /usr/local/lib/x86_64-linux-gnu/libqt-mt$(SUFF_DLL) \ $(PATH_SDK_QT3)/lib/libqt-mt$(SUFF_DLL) \ $(PATH_SDK_QT3)/lib/qt3/libqt-mt$(SUFF_DLL) \ $(PATH_SDK_QT3)/lib/qt3-3/lib/libqt-mt$(SUFF_DLL) \ $(PATH_SDK_QT3)/lib/x86_64-linux-gnu/libqt-mt$(SUFF_DLL) \ ))) ifneq ($(PATH_SDK_QT3_LIB.amd64),) export PATH_SDK_QT3_LIB.amd64 endif endif # Determin the KBUILD_TARGET lib directory. ifeq ($(PATH_SDK_QT3_LIB),) PATH_SDK_QT3_LIB := $(PATH_SDK_QT3_LIB.$(KBUILD_TARGET_ARCH)) ifeq ($(PATH_SDK_QT3_LIB),) PATH_SDK_QT3_LIB := $(patsubst %/libqt-mt$(SUFF_DLL),%,$(firstword $(wildcard \ $(PATH_SDK_QT3)/lib/libqt-mt$(SUFF_DLL) \ $(PATH_SDK_QT3)/lib/qt3/libqt-mt$(SUFF_DLL) \ $(PATH_SDK_QT3)/lib/qt3-3/lib/libqt-mt$(SUFF_DLL) \ /usr/lib/libqt-mt$(SUFF_DLL) \ /usr/lib/qt3/libqt-mt$(SUFF_DLL) \ /usr/lib/qt3-3/lib/libqt-mt$(SUFF_DLL) \ /usr/local/lib/libqt-mt$(SUFF_DLL) \ /usr/local/lib/qt3/libqt-mt$(SUFF_DLL) \ /usr/local/lib/qt3-3/lib/libqt-mt$(SUFF_DLL) \ ))) ifneq ($(PATH_SDK_QT3_LIB),) export PATH_SDK_QT3_LIB endif endif endif endif endif # Unices endif # Found it? ifeq ($(PATH_SDK_QT3),) $(warning kBuild: Couldn't find the Qt3 headers and libaries...) PATH_SDK_QT3 := $(PATH_DEVTOOLS_TRG)/qt/not-found endif endif else # Resolve any fancy stuff once and for all. PATH_SDK_QT3 := $(PATH_SDK_QT3) endif # Libraries can be in either Frameworks or lib depending on how you # build it on the mac. The .dmg installs into Frameworks but builds into lib. PATH_SDK_QT3_LIB ?= $(PATH_SDK_QT3)/lib PATH_SDK_QT3_INC ?= $(PATH_SDK_QT3)/include # The bits that kBuild picks up. # (nothing here) # # The QT3 tool. # # This is implemented here rather than in tools/QT3.kmk to enforce the global USES. # It also makes things easier to develop, with fewer files I mean. # TOOL_QT3 = Qt3 # Tool Specific Properties (PATH_TOOL_QT3_BIN and TOOL_QT3_BIN_SUFF) # TOOL_QT3_BIN_SUFF - the '-qt3' bit found on debian. # PATH_TOOL_QT3_BIN - the directory containing moc, uic, lrelease, lupdate and qm2ts. ifndef PATH_TOOL_QT3_BIN PATH_TOOL_QT3_BIN := $(firstword $(rsort $(wildcard $(PATH_DEVTOOLS_BLD)/qt/v3*/bin))) ifeq ($(PATH_TOOL_QT3_BIN),) if1of ($(KBUILD_HOST), win os2) # Sorry, no joy here. Check QTDIR perhaps, but for now users have to set PATH_TOOL_QT3_BIN. else ifdef TOOL_QT3_BIN_SUFF TOOL_QT3_BIN_SUFF := $(TOOL_QT3_BIN_SUFF) endif PATH_TOOL_QT3_BIN := $(patsubst %/qm2ts$(TOOL_QT3_BIN_SUFF),%,$(firstword $(wildcard \ /usr/lib/qt-3.3/bin/qm2ts$(TOOL_QT3_BIN_SUFF) \ /usr/lib64/qt-3.3/bin/qm2ts$(TOOL_QT3_BIN_SUFF) \ /usr/qt/3/bin/qm2ts$(TOOL_QT3_BIN_SUFF) \ $(if $(QTDIR),$(QTDIR)/bin/qm2ts$(TOOL_QT3_BIN_SUFF)) \ /usr/bin/qm2ts$(TOOL_QT3_BIN_SUFF) \ /usr/local/bin/qm2ts$(TOOL_QT3_BIN_SUFF) \ /usr/share/qt3/bin/qm2ts$(TOOL_QT3_BIN_SUFF) \ ))) ifeq ($(PATH_TOOL_QT3_BIN),) # If we couldn't find the qt3 specific tool qm2ts, debian and other skip # this (thanks a bundle). Try with look for 'moc' with a '-qt3' extension, # then for just moc. In the latter case don't search /usr[/local]/bin to # void finding the qt4 tools and messing up. ifeq ($(TOOL_QT3_BIN_SUFF),) PATH_TOOL_QT3_BIN := $(patsubst %/moc-qt3,%,$(firstword $(wildcard \ /usr/bin/moc-qt3 \ /usr/local/bin/moc-qt3 \ /usr/lib/qt-3.3/bin/moc-qt3 \ /usr/lib64/qt-3.3/bin/moc-qt3 \ /usr/qt/3/bin/moc-qt3 \ /usr/share/qt3/bin/moc-qt3 \ $(if $(QTDIR),$(QTDIR)/bin/moc-qt3) \ ))) endif ifneq ($(PATH_TOOL_QT3_BIN),) export TOOL_QT3_BIN_SUFF := -qt3 else PATH_TOOL_QT3_BIN := $(patsubst %/moc$(TOOL_QT3_BIN_SUFF),%,$(firstword $(wildcard \ /usr/lib/qt-3.3/bin/moc$(TOOL_QT3_BIN_SUFF) \ /usr/lib64/qt-3.3/bin/moc$(TOOL_QT3_BIN_SUFF) \ /usr/qt/3/bin/moc$(TOOL_QT3_BIN_SUFF) \ /usr/share/qt3/bin/moc$(TOOL_QT3_BIN_SUFF) \ $(if $(QTDIR),$(QTDIR)/bin/moc$(TOOL_QT3_BIN_SUFF)) \ ))) endif endif ifneq ($(PATH_TOOL_QT3_BIN),) export PATH_TOOL_QT3_BIN endif endif endif # If not found, we'll enter the 'pathless' mode. else # Resolve any fancy stuff once and for all. PATH_TOOL_QT3_BIN := $(PATH_TOOL_QT3_BIN) TOOL_QT3_BIN_SUFF := $(TOOL_QT3_BIN_SUFF) endif ifneq ($(PATH_TOOL_QT3_BIN),) ifeq ($(KBUILD_HOST),os2) TOOL_QT3_ENV_SETUP ?= $(REDIRECT) -E 'BEGINLIBPATH=$(PATH_TOOL_QT3_BIN);$(libpath BEGINLIBPATH)' -- endif TOOL_QT3_MOC ?= $(TOOL_QT3_ENV_SETUP) $(PATH_TOOL_QT3_BIN)/moc$(TOOL_QT3_BIN_SUFF)$(HOST_SUFF_EXE) TOOL_QT3_UIC ?= $(TOOL_QT3_ENV_SETUP) $(PATH_TOOL_QT3_BIN)/uic$(TOOL_QT3_BIN_SUFF)$(HOST_SUFF_EXE) TOOL_QT3_LRC ?= $(TOOL_QT3_ENV_SETUP) $(PATH_TOOL_QT3_BIN)/lrelease$(TOOL_QT3_BIN_SUFF)$(HOST_SUFF_EXE) TOOL_QT3_LUPDATE ?= $(TOOL_QT3_ENV_SETUP) $(PATH_TOOL_QT3_BIN)/lupdate$(TOOL_QT3_BIN_SUFF)$(HOST_SUFF_EXE) else # Pathless, relies on the environment. TOOL_QT3_MOC ?= moc$(TOOL_QT3_BIN_SUFF)$(HOST_SUFF_EXE) TOOL_QT3_UIC ?= uic$(TOOL_QT3_BIN_SUFF)$(HOST_SUFF_EXE) TOOL_QT3_LRC ?= lrelease$(TOOL_QT3_BIN_SUFF)$(HOST_SUFF_EXE) TOOL_QT3_LUPDATE ?= lupdate$(TOOL_QT3_BIN_SUFF)$(HOST_SUFF_EXE) endif # General Properties used by kBuild and/or units/qt.kmk TOOL_QT3_MOCFLAGS ?= TOOL_QT3_UICFLAGS ?= TOOL_QT3_LRCFLAGS ?= ## MOC a C++ source file. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(out) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This may be (re)created by the compilation. # @param $(flags) Flags. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_QT3_MOC_CPP_DEPEND = TOOL_QT3_MOC_CPP_DEPORD = TOOL_QT3_MOC_CPP_OUTPUT = TOOL_QT3_MOC_CPP_OUTPUT_MAYBE = define TOOL_QT3_MOC_CPP_CMDS $(QUIET)$(TOOL_QT3_MOC)\ $(flags)\ -o $(out)\ -i \ $(source) endef ## MOC a C++ header file. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(out) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This may be (re)created by the compilation. # @param $(flags) Flags. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_QT3_MOC_HPP_DEPEND = TOOL_QT3_MOC_HPP_DEPORD = TOOL_QT3_MOC_HPP_OUTPUT = TOOL_QT3_MOC_HPP_OUTPUT_MAYBE = define TOOL_QT3_MOC_HPP_CMDS $(QUIET)$(TOOL_QT3_MOC)\ $(flags)\ -o $(out)\ $(source) endef ## Compile a Qt user interface file (.ui). # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(out.cpp) The C++ source file to be generated. # @param $(out.h) The C++ header file to be generated. # @param $(dep) Dependcy file. This may be (re)created by the compilation. # @param $(flags) Flags. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_QT3_UIC_UI_DEPEND = TOOL_QT3_UIC_UI_DEPORD = TOOL_QT3_UIC_UI_OUTPUT = TOOL_QT3_UIC_UI_OUTPUT_MAYBE = define TOOL_QT3_UIC_UI_CMDS $(QUIET)$(TOOL_QT3_UIC)\ $(flags)\ -o $(out.h)\ $(source) $(QUIET)$(TOOL_QT3_UIC)\ $(flags)\ -i $(out.h) \ -o $(out.cpp)\ $(source) endef ## Compile a Qt translation file (.ts). # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(out) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This may be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. # @param $(incs) Includes. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_QT3_LRC_TS_DEPEND = TOOL_QT3_LRC_TS_DEPORD = TOOL_QT3_LRC_TS_OUTPUT = TOOL_QT3_LRC_TS_OUTPUT_MAYBE = define TOOL_QT3_LRC_TS_CMDS $(QUIET)$(TOOL_QT3_LRC)\ $(flags)\ $(source)\ -qm $(out) endef # # # Back to the Qt3 unit. # # ## wrapper for the lrelease (LRC) command dependencies. ifndef NO_COMPILE_CMDS_DEPS _UNIT_QT3_LRC_CMDS_DEP = $$(comp-cmds-ex $$($(target)_$(subst :,_,$(source))_QT3_LRC_CMDS_PREV_),$$(commands $(out)),FORCE) else _UNIT_QT3_LRC_CMDS_DEP = endif ## # def_unit_qt3_target_pre_handle_translation helper that is expanded before evaluation. # # This is necessary to resolve reference to local variables before doing # assignments and setting up commands. They would otherwise be resolved # later in a different context and the result would be completely wrong. # define def_unit_qt3_target_pre_handle_translation_dx $(out) + $(more_output) +| $(maybe_output): \ $(deps) \ $(value _UNIT_QT3_LRC_CMDS_DEP) \ | \ $(orderdeps) %$$(call MSG_TOOL,lrelease,$(target),$(source),$$@) $(QUIET2)$(RM) -f $(out) $(more_output) $(maybe_output) $(dep) $(cmds) ifndef NO_COMPILE_CMDS_DEPS %$$(QUIET2)$$(APPEND) '$(dep)' %$$(QUIET2)$$(APPEND) '$(dep)' 'define $(target)_$(subst :,_,$(source))_QT3_LRC_CMDS_PREV_' %$$(QUIET2)$$(APPEND) -c '$(dep)' '$(out)' %$$(QUIET2)$$(APPEND) '$(dep)' 'endef' endif $(target)_CLEAN += $(out) $(more_output) $(maybe_output) $(dep) $(target)-inst-nls_SOURCES += $(out) endef # def_unit_qt3_target_pre_handle_translation_dx ## # Handle a source file listed in QT_TRANSLATIONS. # # The files listed in QT_TRANSLATIONS are translation files (.ts) which needs # to be translated into .qm files that are loadble by Qt. # # @remarks Invoked via $(evalvalctx ). define def_unit_qt3_target_pre_handle_translation local type := LRC # fetch the properties. local tool := $(kb-src-tool dummy_var) local qtnlsdir := $($(target)_0_OUTDIR)/qtnls local outbase := $(qtnlsdir)/$(notdir $(basename $(source))) local out := $(outbase).qm local dep := $(out).dep local flags := $(kb-src-prop FLAGS,dummy_var,right-to-left) local deps := $(kb-src-prop DEPS,dummy_var,left-to-right) local orderdeps := $(call DIRDEP,$(dir $(outbase))) $(kb-src-prop ORDERDEPS,dummy_var,left-to-right) # default path + source dep. ifneq ($(defpath),) local source := $(abspathex $(source),$(defpath)) local deps := $(abspathex $(deps),$(defpath)) $(source) local incs := $(abspathex $(incs),$(defpath)) else local deps += $(source) endif # call the tool ifndef TOOL_$(tool)_LRC_TS_CMDS $(error kBuild: qt lrelease tool not found: TOOL_$(tool)_LRC_TS_CMDS) endif local cmds := $(TOOL_$(tool)_LRC_TS_CMDS) local more_output := $(TOOL_$(tool)_LRC_TS_OUTPUT) local maybe_output := $(TOOL_$(tool)_LRC_TS_OUTPUT_MAYBE) local deps += $(TOOL_$(tool)_LRC_TS_DEPEND) local orderdeps += $(TOOL_$(tool)_LRC_TS_DEPORD) # generate the link rule and update some source and target variables. ifndef NO_COMPILE_CMDS_DEPS $(eval includedep $(dep)) endif $(eval $(def_unit_qt3_target_pre_handle_translation_dx)) endef # def_unit_qt3_target_pre_handle_translation ## wrapper for the UIC command dependencies. ifndef NO_COMPILE_CMDS_DEPS _UNIT_QT3_UIC_CMDS_DEP = $$(comp-cmds-ex $$($(target)_$(subst :,_,$(source))_QT3_UIC_CMDS_PREV_),$$(commands $(out.h)),FORCE) else _UNIT_QT3_UIC_CMDS_DEP = endif ## # def_unit_qt3_src_handler_ui helper that is expanded before evaluation. # # This is necessary to resolve reference to local variables before doing # assignments and setting up commands. They would otherwise be resolved # later in a different context and the result would be completely wrong. # define def_unit_qt3_target_pre_handle_ui_dx $(out.h) + $(out.cpp) +| $(realout.h) $(realout.cpp) $(more_output) $(maybe_output): \ $(deps) \ $(value _UNIT_QT3_UIC_CMDS_DEP) \ | \ $(orderdeps) %$$(call MSG_TOOL,uic,$(target),$(source),$(out.h) $(out.cpp)) $(QUIET2)$(RM) -f $(out.h) $(out.cpp) $(more_output) $(maybe_output) $(dep) $(cmds) $(QUIET)$(CP) --changed -f $(out.h) $(realout.h) $(QUIET)$(CP) --changed -f $(out.cpp) $(realout.cpp) ifndef NO_COMPILE_CMDS_DEPS %$$(QUIET2)$$(APPEND) '$(dep)' %$$(QUIET2)$$(APPEND) '$(dep)' 'define $(target)_$(subst :,_,$(source))_QT3_UIC_CMDS_PREV_' %$$(QUIET2)$$(APPEND) -c '$(dep)' '$(out.h)' %$$(QUIET2)$$(APPEND) '$(dep)' 'endef' endif $(target)_INTERMEDIATES += $(realout.h) $(target)_GEN_SOURCES_ += $(realout.cpp) $(target)_CLEAN += $(out.h) $(out.cpp) $(realout.h) $(realout.cpp) $(more_output) $(maybe_output) $(dep) endef # def_unit_qt3_target_pre_handle_ui_dx ## # Source handler for .ui sources. # # @remarks $(evalvalctx me). define def_unit_qt3_src_handler_ui local type := UIC # fetch the properties. local tool := $(kb-src-tool dummy_var) local qtuicdir := $($(target)_0_OUTDIR)/qtuic local outbase := $(qtuicdir)/$(notdir $(basename $(source))) local out.h := $(outbase).tmp.h local out.cpp := $(outbase).tmp.cpp local realout.h := $(outbase).h local realout.cpp:=$(outbase).cpp local dep := $(realout.h).dep local flags := $(kb-src-prop FLAGS,dummy_var,right-to-left) local deps := $(kb-src-prop DEPS,dummy_var,left-to-right) local orderdeps := $(call DIRDEP,$(dir $(outbase))) $(kb-src-prop ORDERDEPS,dummy_var,left-to-right) # default path + source dep. ifneq ($(defpath),) local source := $(abspathex $(source),$(defpath)) local deps := $(abspathex $(deps),$(defpath)) $(source) local incs := $(abspathex $(incs),$(defpath)) else local deps += $(source) endif # call the tool ifndef TOOL_$(tool)_UIC_UI_CMDS $(error kBuild: qt uic tool not found: TOOL_$(tool)_UIC_UI_CMDS) endif local cmds := $(TOOL_$(tool)_UIC_UI_CMDS) local more_output := $(TOOL_$(tool)_UIC_UI_OUTPUT) local maybe_output := $(TOOL_$(tool)_UIC_UI_OUTPUT_MAYBE) local deps += $(TOOL_$(tool)_UIC_UI_DEPEND) local orderdeps += $(TOOL_$(tool)_UIC_UI_DEPORD) # generate the link rule and update some source and target variables. ifndef NO_COMPILE_CMDS_DEPS $(eval includedep $(dep)) endif $(eval $(def_unit_qt3_target_pre_handle_ui_dx)) endef # def_unit_qt3_src_handler_ui ## wrapper for the MOC command dependencies. ifndef NO_COMPILE_CMDS_DEPS _UNIT_QT3_MOC_HPP_CMDS_DEP = $$(comp-cmds-ex $$($(target)_$(subst :,_,$(source))_QT3_MOC_HPP_CMDS_PREV_),$$(commands $(out)),FORCE) else _UNIT_QT3_MOC_HPP_CMDS_DEP = endif ## # def_unit_qt3_target_pre_handle_moc_hdr helper that is expanded before evaluation. # # This is necessary to resolve reference to local variables before doing # assignments and setting up commands. They would otherwise be resolved # later in a different context and the result would be completely wrong. # define def_unit_qt3_target_pre_handle_moc_hdr_dx $(out) +| $(realout) $(more_output) $(maybe_output): \ $(deps) \ $(value _UNIT_QT3_MOC_HPP_CMDS_DEP) \ | \ $(orderdeps) %$$(call MSG_TOOL,moc,$(target),$(source),$(realout)) $(QUIET2)$(RM) -f $(out) $(more_output) $(maybe_output) $(dep) $(cmds) $(QUIET)$(CP) --changed -f $(out) $(realout) ifndef NO_COMPILE_CMDS_DEPS %$$(QUIET2)$$(APPEND) '$(dep)' %$$(QUIET2)$$(APPEND) '$(dep)' 'define $(target)_$(subst :,_,$(source))_QT3_MOC_HPP_CMDS_PREV_' %$$(QUIET2)$$(APPEND) -c '$(dep)' '$(out)' %$$(QUIET2)$$(APPEND) '$(dep)' 'endef' endif $(target)_INTERMEDIATES += $(realout) $(target)_GEN_SOURCES_ += $(realout) $(target)_CLEAN += $(out) $(realout) $(more_output) $(maybe_output) $(dep) endef ## # Handle a source file listed in QT_MOCHDRS. # # The files listed in QT_MOCHDRS uses the Q_OBJECT macro and we will # generate a .cpp file for each of them and add it to the generated # sources so that it's compiled and linked. (There is an alternative # way to do this where the .cpp file is included, this isn't currently # supported by this unit.) # # @remarks Invoked via $(evalvalctx ). define def_unit_qt3_target_pre_handle_moc_hdr local type := MOC # fetch the properties. local tool := $(kb-src-tool dummy_var) local outbase := $(qtmocdir)/$(notdir $(basename $(source))) local out := $(outbase).tmp.cpp local realout := $(outbase).cpp local dep := $(realout).dep local flags := $(kb-src-prop FLAGS,dummy_var,right-to-left) local deps := $(kb-src-prop DEPS,dummy_var,left-to-right) local orderdeps := $(call DIRDEP,$(dir $(outbase))) $(kb-src-prop ORDERDEPS,dummy_var,left-to-right) # default path + source dep. ifneq ($(defpath),) local source := $(abspathex $(source),$(defpath)) local deps := $(abspathex $(deps),$(defpath)) $(source) else local deps += $(source) endif # call the tool ifndef TOOL_$(tool)_MOC_HPP_CMDS $(error kBuild: qt moc tool not found: TOOL_$(tool)_MOC_HPP_CMDS) endif local cmds := $(TOOL_$(tool)_MOC_HPP_CMDS) local more_output := $(TOOL_$(tool)_MOC_HPP_OUTPUT) local maybe_output := $(TOOL_$(tool)_MOC_HPP_OUTPUT_MAYBE) local deps += $(TOOL_$(tool)_MOC_HPP_DEPEND) local orderdeps += $(TOOL_$(tool)_MOC_HPP_DEPORD) # generate the link rule and update some source and target variables. ifndef NO_COMPILE_CMDS_DEPS $(eval includedep $(dep)) endif $(eval $(def_unit_qt3_target_pre_handle_moc_hdr_dx)) endef # def_unit_qt3_target_pre_handle_moc_hdr ## wrapper for the MOC command dependencies. ifndef NO_COMPILE_CMDS_DEPS _UNIT_QT3_MOC_CPP_CMDS_DEP = $$(comp-cmds-ex $$($(target)_$(subst :,_,$(source))_QT3_MOC_CPP_CMDS_PREV_),$$(commands $(out)),FORCE) else _UNIT_QT3_MOC_CPP_CMDS_DEP = endif ## # def_unit_qt3_target_pre_handle_moc_src helper that is expanded before evaluation. # # This is necessary to resolve reference to local variables before doing # assignments and setting up commands. They would otherwise be resolved # later in a different context and the result would be completely wrong. # define def_unit_qt3_target_pre_handle_moc_src_dx $(out) +| $(realout) $(more_output) $(maybe_output): \ $(deps) \ $(value _UNIT_QT3_MOC_CPP_CMDS_DEP) \ | \ $(orderdeps) %$$(call MSG_TOOL,moc,$(target),$(source),$(realout)) $(QUIET2)$(RM) -f $(out) $(more_output) $(maybe_output) $(dep) $(cmds) $(QUIET)$(CP) --changed -f $(out) $(realout) ifndef NO_COMPILE_CMDS_DEPS %$$(QUIET2)$$(APPEND) '$(dep)' %$$(QUIET2)$$(APPEND) '$(dep)' 'define $(target)_$(subst :,_,$(source))_QT3_MOC_CPP_CMDS_PREV_' %$$(QUIET2)$$(APPEND) -c '$(dep)' '$(out)' %$$(QUIET2)$$(APPEND) '$(dep)' 'endef' endif $(target)_INTERMEDIATES += $(realout) $(target)_CLEAN += $(out) $(realout) $(more_output) $(maybe_output) $(dep) endef ## # Handle a source file listed in QT_MOCSRCS. # # The files listed in QT_MOCSRCS uses the Q_OBJECT macro and will include # a .moc file that we're expected to generate here. # # @remarks Invoked via $(evalvalctx ). define def_unit_qt3_target_pre_handle_moc_src local type := MOC # fetch the properties. local tool := $(kb-src-tool dummy_var) local outbase := $(qtmocdir)/$(notdir $(basename $(source))) local out := $(outbase).tmp.moc local realout := $(outbase).moc local dep := $(realout).dep local flags := $(kb-src-prop FLAGS,dummy_var,right-to-left) local deps := $(kb-src-prop DEPS,dummy_var,left-to-right) local orderdeps := $(call DIRDEP,$(dir $(outbase))) $(kb-src-prop ORDERDEPS,dummy_var,left-to-right) # default path + source dep. ifneq ($(defpath),) local source := $(abspathex $(source),$(defpath)) local deps := $(abspathex $(deps),$(defpath)) $(source) local incs := $(abspathex $(incs),$(defpath)) else local deps += $(source) endif # call the tool ifndef TOOL_$(tool)_MOC_CPP_CMDS $(error kBuild: qt moc tool not found: TOOL_$(tool)_MOC_CPP_CMDS) endif local cmds := $(TOOL_$(tool)_MOC_CPP_CMDS) local more_output := $(TOOL_$(tool)_MOC_CPP_OUTPUT) local maybe_output := $(TOOL_$(tool)_MOC_CPP_OUTPUT_MAYBE) local deps += $(TOOL_$(tool)_MOC_CPP_DEPEND) local orderdeps += $(TOOL_$(tool)_MOC_CPP_DEPORD) # generate the link rule and update some source and target variables. ifndef NO_COMPILE_CMDS_DEPS $(eval includedep $(dep)) endif $(eval $(def_unit_qt3_target_pre_handle_moc_src_dx)) endef # def_unit_qt3_target_pre_handle_moc_src ## # Adds sources containing Q_OBJECT to QT_MOCSRCS. define def_unit_qt3_target_pre_cpp_source ifneq ($(file-size $(source)),-1) ifneq ($(strip $(shell $(SED) -f $(KBUILD_PATH)/units/qt-Q_OBJECT.sed $(source))),) $(eval $(target)_QT_MOCSRCS += $(source)) endif endif endef # def_unit_qt3_target_pre_cpp_source ## # Invoked early in the processing of a target that uses the Qt unit. # # It will append the qt source handlers to the target (.h, .ui, .ts, # .png, .bmp, .gif). # # It will then check all the C++ sources and check which needs # a .moc files and generate rules and dependencies fofor these # define def_unit_qt3_target_pre # Make QTTOOL the default for the specific Qt tools instead of TOOL. ifneq ($($(target)_QTTOOL),) ifeq ($($(target)_MOCTOOL),) $(target)_MOCTOOL := $($(target)_QTTOOL) endif ifeq ($($(target)_UICTOOL),) $(target)_UICTOOL := $($(target)_QTTOOL) endif ifeq ($($(target)_LRCTOOL),) $(target)_LRCTOOL := $($(target)_QTTOOL) endif endif # Deal with QT_MODULES and QT_PREFIX. local qt_prefix := $(firstword \ $($(target)_QT_PREFIX.$(bld_trg)) \ $($(target)_QT_PREFIX.$(bld_trg_arch)) \ $($(target)_QT_PREFIX.$(bld_trg).$(bld_trg_arch)) \ $($(target)_QT_PREFIX.$(bld_trg_cpu)) \ $($(target)_QT_PREFIX.$(bld_type)) \ $($(target)_QT_PREFIX)) ifeq ($(bld_trg),win) local qt_lib := $(firstword $(wildcard \ $(PATH_SDK_QT3_LIB)/dynamic/$(qt_prefix)qt-mt3*$(SUFF_LIB) \ $(PATH_SDK_QT3_LIB)/$(qt_prefix)qt-mt3*$(SUFF_LIB) \ $(PATH_SDK_QT3_LIB)/dynamic/$(qt_prefix)qt-mt$(SUFF_LIB) \ $(PATH_SDK_QT3_LIB)/$(qt_prefix)qt-mt$(SUFF_LIB) \ $(PATH_SDK_QT3_LIB)/dynamic/$(qt_prefix)Qt3*$(SUFF_LIB) \ $(PATH_SDK_QT3_LIB)/$(qt_prefix)Qt3*$(SUFF_LIB) \ $(PATH_SDK_QT3_LIB)/dynamic/$(qt_prefix)Qt*$(SUFF_LIB) \ $(PATH_SDK_QT3_LIB)/$(qt_prefix)Qt*$(SUFF_LIB) \ ) $(PATH_SDK_QT3_LIB)/$(qt_prefix)qt-mt$(SUFF_LIB) ) $(eval $(target)_LIBS += $(qt_lib) ) ifeq ($(tool_do),LINK_PROGRAM) local qt_main_lib := $(firstword $(wildcard \ $(PATH_SDK_QT3_LIB)/$(qt_prefix)qtmain$(SUFF_LIB) \ $(PATH_SDK_QT3_LIB)/qtmain$(SUFF_LIB) \ ) $(PATH_SDK_QT3_LIB)/$(qt_prefix)qtmain$(SUFF_LIB) ) $(eval $(target)_LIBS += $(qt_main_lib) ) endif else ifeq ($(bld_trg),os2) # This is a real PITA since the dll/lib can be called (almost) anything. :-( local qt_lib := $(firstword $(wildcard \ $(PATH_SDK_QT3_LIB)/$(qt_prefix)*qt3*$(SUFF_LIB) \ $(PATH_SDK_QT3_LIB)/$(qt_prefix)*qt*$(SUFF_LIB) \ )) ifeq ($(qt_lib),) local qt_prls := $(basename $(wildcard $(PATH_SDK_QT3_LIB)/$(qt_prefix)*.prl)) local qt_defs := $(basename $(wildcard $(PATH_SDK_QT3_LIB)/$(qt_prefix)*.def)) local qt_dlls := $(basename $(wildcard $(PATH_SDK_QT3_LIB)/$(qt_prefix)*.dll)) local qt_libs := $(basename $(wildcard $(PATH_SDK_QT3_LIB)/$(qt_prefix)*.lib)) local qt_lib := $(firstword \ $(addsuffix .lib,$(filter $(qt_prls), $(filter $(qt_defs), $(filter $(qt_dlls), $(qt_libs))))) \ $(PATH_SDK_QT3_LIB)/myqt.lib ) endif $(eval $(target)_LIBS += $(qt_lib) ) else local qt_lib := $(PATH_SDK_QT3_LIB)/lib$(qt_prefix)qt-mt$(SUFF_DLL) $(eval $(target)_LIBS += $(qt_lib) ) endif $(eval $(target)_INCS += $(PATH_SDK_QT3_INC) ) # On Qt3 we will try pickup the QMAKE_PRL_DEFINES listed in the .prl file (in libs). local qt_prl := $(firstword $(wildcard \ $(patsubst %$(SUFF_DLL),%,$(patsubst %$(SUFF_LIB),%,$(qt_lib))).prl \ $(dir $(qt_lib))/$(qt_prefix)qt-mt.prl \ $(dir $(qt_lib))/*qt-mt*.prl \ $(dir $(qt_lib))/*qt*.prl \ )) ifneq ($(qt_prl),) include $(qt_prl) $(eval $(target)_DEFS += $(QMAKE_PRL_DEFINES)) endif # Autodetect source files with Q_OBJECT references if QT_MOCSRCS is undefined. (slow) # Tip: Use target_QT_MOCSRCS = $(NO_SUCH_VARIABLE) to avoid this. ifndef $(target)_QT_MOCSRCS $(foreach source, $(filter %.cxx %.CXX %.cpp %.CPP %.cc %.CC,\ $($(target)_SOURCES.$(bld_trg)) \ $($(target)_SOURCES.$(bld_trg_arch)) \ $($(target)_SOURCES.$(bld_trg).$(bld_trg_arch)) \ $($(target)_SOURCES.$(bld_trg_cpu)) \ $($(target)_SOURCES.$(bld_type)) \ $($(target)_SOURCES) \ ), $(evalval def_unit_qt3_target_pre_cpp_source)) endif # Install source handlers for .ui files. $(target)_SRC_HANDLERS += \ .ui:def_unit_qt3_src_handler_ui \ .UI:def_unit_qt3_src_handler_ui # Calc the MOC and UI output directories and add them to BLDDIRS and INCS. local qtmocdir := $($(target)_0_OUTDIR)/qtmoc local qtuicdir := $($(target)_0_OUTDIR)/qtuic local qtnlsdir := $($(target)_0_OUTDIR)/qtnls $(eval $(target)_BLDDIRS += $(qtmocdir) $(qtuicdir) $(qtnlsdir) ) $(eval $(target)_INCS += $(qtmocdir) $(qtuicdir) ) # Calc .ui sources so we can add them to the QT_MOCSRCS and QT_MOCHDRS. local ui_sources := $(notdir $(basename $(filter %.ui %.UI, \ $($(target)_SOURCES.$(bld_trg)) \ $($(target)_SOURCES.$(bld_trg_arch)) \ $($(target)_SOURCES.$(bld_trg).$(bld_trg_arch)) \ $($(target)_SOURCES.$(bld_trg_cpu)) \ $($(target)_SOURCES.$(bld_type)) \ $($(target)_SOURCES) \ ))) #$(error ui_sources:=$(ui_sources)) # Deal with QT_MOCSRCS. $(foreach source, \ $($(target)_QT_MOCSRCS.$(bld_trg)) \ $($(target)_QT_MOCSRCS.$(bld_trg_arch)) \ $($(target)_QT_MOCSRCS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_QT_MOCSRCS.$(bld_trg_cpu)) \ $($(target)_QT_MOCSRCS.$(bld_type)) \ $($(target)_QT_MOCSRCS) \ $(addsuffix .h,$(addprefix $(qtuicdir)/,$(notdir $(basename $(ui_sources))))) \ , $(evalvalctx def_unit_qt3_target_pre_handle_moc_src)) # Deal with QT_MOCHDRS. $(foreach source, \ $($(target)_QT_MOCHDRS.$(bld_trg)) \ $($(target)_QT_MOCHDRS.$(bld_trg_arch)) \ $($(target)_QT_MOCHDRS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_QT_MOCHDRS.$(bld_trg_cpu)) \ $($(target)_QT_MOCHDRS.$(bld_type)) \ $($(target)_QT_MOCHDRS) \ $(addsuffix .h,$(addprefix $(qtuicdir)/,$(notdir $(basename $(ui_sources))))) \ , $(evalvalctx def_unit_qt3_target_pre_handle_moc_hdr)) # Deal with QT_TRANSLATIONS. # ASSUMES (_ALL_)INSTALLS is processed after the targets using this unit. local translations := \ $($(target)_QT_TRANSLATIONS.$(bld_trg)) \ $($(target)_QT_TRANSLATIONS.$(bld_trg_arch)) \ $($(target)_QT_TRANSLATIONS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_QT_TRANSLATIONS.$(bld_trg_cpu)) \ $($(target)_QT_TRANSLATIONS.$(bld_type)) \ $($(target)_QT_TRANSLATIONS) ifneq ($(strip $(translations)),) local expr := _ALL_INSTALLS_IMPLICIT += $(target)-inst-nls $(eval $(expr)) ifdef $(target)_QT_TRANSLATIONS_TEMPLATE $(target)-inst-nls_TEMPLATE := $($(target)_QT_TRANSLATIONS_TEMPLATE) else $(target)-inst-nls_MODE := 0644 endif ifdef $(target)_QT_TRANSLATIONS_INST $(target)-inst-nls_INST := $($(target)_QT_TRANSLATIONS_INST) endif $(target)-inst-nls_SOURCES := $(foreach source, $(translations)\ , $(evalvalctx def_unit_qt3_target_pre_handle_translation)) endif endef # def_unit_qt3_target_pre # # Rule for debugging. # unit-qt3-show-vars: @$(ECHO) 'The Qt3 SDK variables:' @$(ECHO) ' PATH_SDK_QT3 = "$(PATH_SDK_QT3)"' @$(ECHO) ' PATH_SDK_QT3_INC = "$(PATH_SDK_QT3_INC)"' @$(ECHO) ' PATH_SDK_QT3_LIB = "$(PATH_SDK_QT3_LIB)"' @$(ECHO) ' PATH_SDK_QT3_LIB.amd64 = "$(PATH_SDK_QT3_LIB.amd64)"' @$(ECHO) ' PATH_SDK_QT3_LIB.x86 = "$(PATH_SDK_QT3_LIB.x86)"' @$(ECHO) 'The Qt3 TOOL variables:' @$(ECHO) ' PATH_TOOL_QT3_BIN = "$(PATH_TOOL_QT3_BIN)"' @$(ECHO) ' TOOL_QT3_BIN_SUFF = "$(TOOL_QT3_BIN_SUFF)"' @$(ECHO) ' TOOL_QT3_MOC = "$(TOOL_QT3_MOC)"' @$(ECHO) ' TOOL_QT3_UIC = "$(TOOL_QT3_UIC)"' @$(ECHO) ' TOOL_QT3_LRC = "$(TOOL_QT3_LRC)"' @$(ECHO) ' TOOL_QT3_LUPDATE = "$(TOOL_QT3_LUPDATE)"' kbuild-3149/kBuild/units/qt4.kmk0000644000175000017500000011511413252530251016475 0ustar locutuslocutus# $Id: qt4.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # Qt 4 unit. # # # Copyright (c) 2008-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # ifdef UNIT_qt4 $(error kBuild: The qt4 unit was included twice!) endif UNIT_qt4 = qt4 if !defined(UNIT_qt3) && !defined(UNIT_qt5) # Add our target properties (same as qt3 & qt5). PROPS_SINGLE += QTTOOL MOCTOOL UICTOOL LRCTOOL QT_TRANSLATIONS_INST QT_TRANSLATIONS_TEMPLATE QT_PREFIX PROPS_ACCUMULATE_R += MOCDEFS MOCFLAGS UICFLAGS LRCFLAGS QT_TRANSLATIONS QT_MOCSRCS QT_MOCHDRS endif PROPS_SINGLE += RCCTOOL QT_INFIX PROPS_ACCUMULATE_R += RCCFLAGS QT_MODULES ## @todo use pkg-config? # # The QT4 SDK. # # This is implemented here rather than in sdks/QT4.kmk to enforce the global USES. # It also makes things easier to develop, with fewer files I mean. # ## @todo the SDK might actually not be necessary as it turns out... For now it servers # a purpose if the host differs from the target, in theory at least. SDK_QT4 = Qt4 # SDK Specific Properties # PATH_SDK_QT4 - The general Qt4 root directory. # PATH_SDK_QT4_INC - The include directory. # PATH_SDK_QT4_LIB.amd64 - The lib directory for AMD64. # PATH_SDK_QT4_LIB.x86 - The lib directory for X86. # PATH_SDK_QT4_LIB - The lib directory for KBUILD_TARGET. ifndef PATH_SDK_QT4 PATH_SDK_QT4 := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_TRG)/qt/v4*))) ifeq ($(PATH_SDK_QT4),) # If target == host, try look for Qt in the various platform specific places. ifeq ($(KBUILD_TARGET),$(KBUILD_HOST)) ifeq ($(KBUILD_TARGET),darwin) PATH_SDK_QT4 := $(patsubst %/Frameworks/QtCore.framework/Versions/4,%,$(firstword $(wildcard /Library/Frameworks/QtCore.framework/Versions/4))) else ifeq ($(KBUILD_TARGET),win) # No idea here yet... else ifeq ($(KBUILD_TARGET),ose) # No port... else # The Unices. Includes and esp. libs are tricky, so override the PATH_SDK_QT4_LIB* stuff if it doesn't work. # Try find the general root of thing by looking for the qt3to4 program, if not found, then look for rcc. PATH_SDK_QT4 := $(patsubst %/bin/qt3to4-qt4,%,$(firstword $(wildcard \ /usr/bin/qt3to4-qt4 \ /usr/local/bin/qt3to4-qt4 \ /usr/qt/4/bin/qt3to4-qt4 \ /usr/share/qt4/bin/qt3to4-qt4 \ ))) ifeq ($(PATH_SDK_QT4),) PATH_SDK_QT4 := $(patsubst %/bin/qt3to4,%,$(firstword $(wildcard \ /usr/bin/qt3to4 \ /usr/local/bin/qt3to4 \ /usr/qt/4/bin/qt3to4 \ /usr/share/qt4/bin/qt3to4 \ ))) endif ifeq ($(PATH_SDK_QT4),) PATH_SDK_QT4 := $(patsubst %/bin/rcc-qt4,%,$(firstword $(wildcard \ /usr/bin/rcc-qt4 \ /usr/local/bin/rcc-qt4 \ /usr/qt/4/bin/rcc-qt4 \ /usr/share/qt4/bin/rcc-qt4 \ ))) endif ifeq ($(PATH_SDK_QT4),) PATH_SDK_QT4 := $(patsubst %/bin/rcc,%,$(firstword $(wildcard \ /usr/lib/*/qt4/bin/rcc \ /usr/bin/rcc \ /usr/local/bin/rcc \ /usr/qt/4/bin/rcc \ /usr/share/qt4/bin/rcc \ ))) endif ifneq ($(PATH_SDK_QT4),) export PATH_SDK_QT4 # Locate the include files. ifeq ($(PATH_SDK_QT4_INC),) PATH_SDK_QT4_INC := $(patsubst %/QtCore/qglobal.h,%,$(firstword $(wildcard \ $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET_DOT_ARCH)),/usr/include/$(type)/qt4/QtCore/qglobal.h) \ $(PATH_SDK_QT4)/include/QtCore/qglobal.h \ $(PATH_SDK_QT4)/include/qt4/QtCore/qglobal.h \ /usr/include/qt4/QtCore/qtglobal.h \ /usr/local/include/qt4/QtCore/qtglobal.h \ ))) ifneq ($(PATH_SDK_QT4_INC),) export PATH_SDK_QT4_INC endif endif # Now for the libraries (mostly for helping out finding the KBUILD_TARGET libs). ifeq ($(PATH_SDK_QT4_LIB.x86),) PATH_SDK_QT4_LIB.x86 := $(patsubst %/libQtCore$(SUFF_DLL),%,$(firstword $(wildcard \ $(PATH_SDK_QT4)/lib32/libQtCore$(SUFF_DLL) \ $(PATH_SDK_QT4)/lib32/qt4/libQtCore$(SUFF_DLL) \ /usr/lib32/libQtCore$(SUFF_DLL) \ /usr/lib32/qt4/libQtCore$(SUFF_DLL) \ $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET).x86),/usr/lib/$(type)/libQtCore$(SUFF_DLL)) \ /usr/local/lib32/libQtCore$(SUFF_DLL) \ /usr/local/lib32/qt4/libQtCore$(SUFF_DLL) \ $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET).x86),/usr/local/lib/$(type)/libQtCore$(SUFF_DLL)) \ $(PATH_SDK_QT4)/lib/libQtCore$(SUFF_DLL) \ $(PATH_SDK_QT4)/lib/qt4/libQtCore$(SUFF_DLL) \ $(PATH_SDK_QT4)/lib/i386-linux-gnu/libQtCore$(SUFF_DLL) \ ))) ifneq ($(PATH_SDK_QT4_LIB.x86),) export PATH_SDK_QT4_LIB.x86 endif endif ifeq ($(PATH_SDK_QT4_LIB.amd64),) PATH_SDK_QT4_LIB.amd64 := $(patsubst %/libQtCore$(SUFF_DLL),%,$(firstword $(wildcard \ $(PATH_SDK_QT4)/lib64/libQtCore$(SUFF_DLL) \ $(PATH_SDK_QT4)/lib64/qt4/libQtCore$(SUFF_DLL) \ $(PATH_SDK_QT4)/lib/amd64/libQtCore$(SUFF_DLL) \ /usr/lib64/libQtCore$(SUFF_DLL) \ /usr/lib64/qt4/libQtCore$(SUFF_DLL) \ /usr/lib/amd64/libQtCore$(SUFF_DLL) \ $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET).amd64),/usr/lib/$(type)/libQtCore$(SUFF_DLL)) \ /usr/local/lib64/libQtCore$(SUFF_DLL) \ /usr/local/lib64/qt4/libQtCore$(SUFF_DLL) \ /usr/local/lib/amd64/libQtCore$(SUFF_DLL) \ $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET).amd64),/usr/local/lib/$(type)/libQtCore$(SUFF_DLL)) \ $(PATH_SDK_QT4)/lib/libQtCore$(SUFF_DLL) \ $(PATH_SDK_QT4)/lib/qt4/libQtCore$(SUFF_DLL) \ $(PATH_SDK_QT4)/lib/x86_64-linux-gnu/libQtCore$(SUFF_DLL) \ ))) ifneq ($(PATH_SDK_QT4_LIB.amd64),) export PATH_SDK_QT4_LIB.amd64 endif endif # And finally, the library path for KBUILD_TARGET. ifeq ($(PATH_SDK_QT4_LIB),) PATH_SDK_QT4_LIB := $(PATH_SDK_QT4_LIB.$(KBUILD_TARGET_ARCH)) ifeq ($(PATH_SDK_QT4_LIB),) PATH_SDK_QT4_LIB := $(patsubst %/libQtCore$(SUFF_DLL),%,$(firstword $(wildcard \ $(PATH_SDK_QT4)/lib/libQtCore$(SUFF_DLL) \ $(PATH_SDK_QT4)/lib/qt4/libQtCore$(SUFF_DLL) \ /usr/lib/libQtCore$(SUFF_DLL) \ /usr/lib/qt4/libQtCore$(SUFF_DLL) \ $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET_DOT_ARCH)),/usr/lib/$(type)/libQtCore$(SUFF_DLL)) \ /usr/local/lib/libQtCore$(SUFF_DLL) \ /usr/local/lib/qt4/libQtCore$(SUFF_DLL) \ $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_TARGET_DOT_ARCH)),/usr/local/lib/$(type)/libQtCore$(SUFF_DLL)) \ ))) endif ifneq ($(PATH_SDK_QT4_LIB),) export PATH_SDK_QT4_LIB endif endif endif endif # Unices endif # Found it? ifeq ($(PATH_SDK_QT4),) $(warning kBuild: Couldn't find the Qt4 headers and libaries...) PATH_SDK_QT4 := $(KBUILD_DEVTOOLS_TRG)/qt/not-found endif endif else # Resolve any fancy stuff once and for all. PATH_SDK_QT4 := $(PATH_SDK_QT4) endif # Libraries can be in either Frameworks or lib depending on how you # build it on the mac. The .dmg installs into Frameworks but builds into lib. ifeq ($(KBUILD_TARGET),darwin) ifndef PATH_SDK_QT4_LIB ifneq ($(wildcard $(PATH_SDK_QT4)/Frameworks),) PATH_SDK_QT4_LIB ?= $(PATH_SDK_QT4)/Frameworks else PATH_SDK_QT4_LIB ?= $(PATH_SDK_QT4)/lib endif endif else PATH_SDK_QT4_LIB ?= $(PATH_SDK_QT4)/lib PATH_SDK_QT4_INC ?= $(PATH_SDK_QT4)/include endif # The bits that kBuild picks up. # (nothing here) # # The QT4 tool. # # This is implemented here rather than in tools/QT4.kmk to enforce the global USES. # It also makes things easier to develop, with fewer files I mean. # TOOL_QT4 = Qt4 # Tool Specific Properties # PATH_TOOL_QT4 - Obsolete. # PATH_TOOL_QT4_BIN - The # TOOL_QT4_BIN_SUFF - if !defined(PATH_TOOL_QT4_BIN) && defined(PATH_TOOL_QT4) PATH_TOOL_QT4_BIN := $(PATH_TOOL_QT4)/bin endif ifndef PATH_TOOL_QT4_BIN PATH_TOOL_QT4_BIN := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST)/qt/v4*/bin))) if "$(PATH_TOOL_QT4_BIN)" == "" && "$(KBUILD_DEVTOOLS_HST_ALT)" != "" PATH_TOOL_QT4_BIN := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST_ALT)/qt/v4*/bin))) endif ifeq ($(PATH_TOOL_QT4_BIN),) ifdef TOOL_QT4_BIN_SUFF TOOL_QT4_BIN_SUFF := $(TOOL_QT4_BIN_SUFF) endif # Try looking for moc-$(suffix) first, if specified. ifneq ($(TOOL_QT4_BIN_SUFF),) PATH_TOOL_QT4_BIN := $(patsubst %/moc$(TOOL_QT4_BIN_SUFF),%,$(firstword $(wildcard \ $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt4/bin/moc$(TOOL_QT4_BIN_SUFF)) \ /usr/lib/qt4/bin/moc$(TOOL_QT4_BIN_SUFF) \ /usr/qt/4/bin/moc$(TOOL_QT4_BIN_SUFF) \ /usr/share/qt4/bin/moc$(TOOL_QT4_BIN_SUFF) \ /usr/local/bin/moc$(TOOL_QT4_BIN_SUFF) \ /usr/bin/moc$(TOOL_QT4_BIN_SUFF) \ ))) else # No suffix given, so before we check out -qt4 look at qt4 specific locations to avoid choosers and symlinks. PATH_TOOL_QT4_BIN := $(patsubst %/moc,%,$(firstword $(wildcard \ $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt4/bin/moc) \ $(if $(intersects $(KBUILD_HOST_ARCH), $(KBUILD_ARCHES_64)),/usr/lib64/qt4/bin/moc,) \ /usr/lib/qt4/bin/moc \ /usr/local/lib/qt4/bin/moc \ /usr/qt/4/bin/moc \ /usr/local/qt/4/bin/moc \ /usr/share/qt4/bin/moc \ /usr/local/share/qt4/bin/moc \ ))) ifeq ($(PATH_TOOL_QT4_BIN),) PATH_TOOL_QT4_BIN := $(patsubst %/moc-qt4,%,$(firstword $(wildcard \ $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt4/bin/moc-qt4) \ /usr/lib/qt4/bin/moc-qt4 \ /usr/qt/4/bin/moc-qt4 \ /usr/share/qt4/bin/moc-qt4 \ /usr/local/bin/moc-qt4 \ /usr/bin/moc-qt4 \ ))) ifneq ($(PATH_TOOL_QT4_BIN),) TOOL_QT4_BIN_SUFF := -qt4 endif endif endif # If still no go, try looking for qt3to4 and rcc. ifeq ($(PATH_TOOL_QT4_BIN),) PATH_TOOL_QT4_BIN := $(patsubst %/qt3to4,%,$(firstword $(wildcard \ $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt4/bin/qt3to4) \ /usr/lib/qt4/bin/qt3to4 \ /usr/qt/4/bin/qt3to4 \ /usr/share/qt4/bin/qt3to4 \ /usr/local/bin/qt3to4 \ /usr/bin/qt3to4 \ ))) endif ifeq ($(PATH_TOOL_QT4_BIN),) PATH_TOOL_QT4_BIN := $(patsubst %/rcc$(TOOL_QT4_BIN_SUFF),%,$(firstword $(wildcard \ $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt4/bin/rcc$(TOOL_QT4_BIN_SUFF)) \ /usr/lib/qt4/bin/rcc$(TOOL_QT4_BIN_SUFF) \ /usr/qt/4/bin/rcc$(TOOL_QT4_BIN_SUFF) \ /usr/share/qt4/bin/rcc$(TOOL_QT4_BIN_SUFF) \ /usr/local/bin/rcc$(TOOL_QT4_BIN_SUFF) \ /usr/bin/rcc$(TOOL_QT4_BIN_SUFF) \ ))) endif if "$(PATH_TOOL_QT4_BIN)" == "" && "$(TOOL_QT4_BIN_SUFF)" != "" PATH_TOOL_QT4_BIN := $(patsubst %/rcc,%,$(firstword $(wildcard \ $(foreach type,$(KBUILD_OSARCH_2_GNU_SYSTEM_TYPES.$(KBUILD_HOST_DOT_ARCH)),/usr/lib/$(type)/qt4/bin/rcc) \ /usr/lib/qt4/bin/rcc \ /usr/qt/4/bin/rcc \ /usr/share/qt4/bin/rcc \ /usr/local/bin/rcc \ /usr/bin/rcc \ ))) endif ifneq ($(PATH_TOOL_QT4_BIN),) export PATH_TOOL_QT4_BIN endif endif # If not found, we'll enter the 'pathless' mode. else # Resolve any fancy stuff once and for all. PATH_TOOL_QT4_BIN := $(PATH_TOOL_QT4_BIN) endif ifneq ($(PATH_TOOL_QT4_BIN),) TOOL_QT4_MOC ?= $(PATH_TOOL_QT4_BIN)/moc$(TOOL_QT4_BIN_SUFF)$(HOST_SUFF_EXE) TOOL_QT4_UIC ?= $(PATH_TOOL_QT4_BIN)/uic$(TOOL_QT4_BIN_SUFF)$(HOST_SUFF_EXE) ifndef TOOL_QT4_RCC TOOL_QT4_RCC := $(PATH_TOOL_QT4_BIN)/rcc$(HOST_SUFF_EXE) ifeq ($(wildcard $(TOOL_QT4_RCC)),) TOOL_QT4_RCC := $(PATH_TOOL_QT4_BIN)/rcc$(TOOL_QT4_BIN_SUFF)$(HOST_SUFF_EXE) endif endif TOOL_QT4_LRC ?= $(PATH_TOOL_QT4_BIN)/lrelease$(TOOL_QT4_BIN_SUFF)$(HOST_SUFF_EXE) TOOL_QT4_LUPDATE ?= $(PATH_TOOL_QT4_BIN)/lupdate$(TOOL_QT4_BIN_SUFF)$(HOST_SUFF_EXE) else # Pathless, relies on the environment. TOOL_QT4_MOC ?= moc$(TOOL_QT4_BIN_SUFF)$(HOST_SUFF_EXE) TOOL_QT4_UIC ?= uic$(TOOL_QT4_BIN_SUFF)$(HOST_SUFF_EXE) TOOL_QT4_RCC ?= rcc$(TOOL_QT4_BIN_SUFF)$(HOST_SUFF_EXE) TOOL_QT4_LRC ?= lrelease$(TOOL_QT4_BIN_SUFF)$(HOST_SUFF_EXE) TOOL_QT4_LUPDATE ?= lupdate$(TOOL_QT4_BIN_SUFF)$(HOST_SUFF_EXE) endif # General Properties used by kBuild and/or units/qt.kmk TOOL_QT4_MOCFLAGS ?= TOOL_QT4_MOCINCS ?= TOOL_QT4_MOCDEFS ?= TOOL_QT4_MOCDEFS.darwin ?= __APPLE__ __GNUC__ TOOL_QT4_MOCDEFS.solaris ?= __sun TOOL_QT4_MOCDEFS.win.amd64 ?= WIN64 TOOL_QT4_MOCDEFS.win.x86 ?= WIN32 ## MOC a C++ source file. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(out) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This may be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. # @param $(incs) Includes. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_QT4_MOC_CPP_DEPEND = TOOL_QT4_MOC_CPP_DEPORD = TOOL_QT4_MOC_CPP_OUTPUT = TOOL_QT4_MOC_CPP_OUTPUT_MAYBE = define TOOL_QT4_MOC_CPP_CMDS $(QUIET)$(TOOL_QT4_MOC)\ $(flags)\ $(addprefix -I, $(incs))\ $(addprefix -D, $(defs))\ -o $(out)\ $(source) endef ## MOC a C++ header file. # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(out) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This may be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. # @param $(incs) Includes. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_QT4_MOC_HPP_DEPEND = TOOL_QT4_MOC_HPP_DEPORD = TOOL_QT4_MOC_HPP_OUTPUT = TOOL_QT4_MOC_HPP_OUTPUT_MAYBE = define TOOL_QT4_MOC_HPP_CMDS $(QUIET)$(TOOL_QT4_MOC)\ $(flags)\ $(addprefix -I, $(incs))\ $(addprefix -D, $(defs))\ -o $(out)\ $(source) endef ## Compile a Qt user interface file (.ui). # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(out) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This may be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. # @param $(incs) Includes. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_QT4_UIC_UI_DEPEND = TOOL_QT4_UIC_UI_DEPORD = TOOL_QT4_UIC_UI_OUTPUT = TOOL_QT4_UIC_UI_OUTPUT_MAYBE = define TOOL_QT4_UIC_UI_CMDS $(QUIET)$(TOOL_QT4_UIC)\ $(flags)\ -o $(out)\ $(source) endef ## Compile a Qt resource file (.qrc). # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(out) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This may be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. # @param $(incs) Includes. # @param $(outbase) Output basename (full). Use this for list files and such. # # @remarks The sed script generating the dependency file is a bit naive. TOOL_QT4_RCC_QRC_DEPEND = TOOL_QT4_RCC_QRC_DEPORD = TOOL_QT4_RCC_QRC_OUTPUT = TOOL_QT4_RCC_QRC_OUTPUT_MAYBE = define TOOL_QT4_RCC_QRC_CMDS $(QUIET)$(TOOL_QT4_RCC)\ $(flags)\ -o $(out)\ $(source) $(QUIET2)$(APPEND) $(dep) '\' $(QUIET2)$(APPEND) $(dep) '$(out): \' $(QUIET2)$(APPEND) $(dep) '$(source) \' $(QUIET2)$(SED) \ -e '/^[[:blank:]]*]*>/!d' \ -e 's/^.*]*>\([^<]*\)<\/file>.*$$$$/\1/' \ -e 's|^[^/][^:]|$(abspathex $(dir $(source)),$(defpath))/&|' \ -e 's|$$$$| \\|' \ --append $(dep) \ $(source) $(QUIET2)$(APPEND) $(dep) $(QUIET2)$(SED) \ -e '/^[[:blank:]]*]*>/!d' \ -e 's/^.*]*>\([^<]*\)<\/file>.*$$$$/\1/' \ -e 's|^[^/][^:]|$(abspathex $(dir $(source)),$(defpath))/&|' \ -e 's|$$$$|:\n|' \ --append $(dep) \ $(source) $(QUIET2)$(APPEND) $(dep) endef ## Compile a Qt translation file (.ts). # @param $(target) Normalized main target name. # @param $(source) Source filename (relative). # @param $(out) Object file name. This shall be (re)created by the compilation. # @param $(dep) Dependcy file. This may be (re)created by the compilation. # @param $(flags) Flags. # @param $(defs) Definitions. # @param $(incs) Includes. # @param $(outbase) Output basename (full). Use this for list files and such. # TOOL_QT4_LRC_TS_DEPEND = TOOL_QT4_LRC_TS_DEPORD = TOOL_QT4_LRC_TS_OUTPUT = TOOL_QT4_LRC_TS_OUTPUT_MAYBE = define TOOL_QT4_LRC_TS_CMDS $(QUIET)$(TOOL_QT4_LRC)\ $(flags)\ $(source)\ -qm $(out) endef # # # Back to the Qt4 unit. # # ## wrapper for the lrelease (LRC) command dependencies. ifndef NO_COMPILE_CMDS_DEPS _UNIT_QT4_LRC_CMDS_DEP = $$(comp-cmds-ex $$($(target)_$(subst :,_,$(source))_QT4_LRC_CMDS_PREV_),$$(commands $(out)),FORCE) else _UNIT_QT4_LRC_CMDS_DEP = endif ## # def_unit_qt4_target_pre_handle_translation helper that is expanded before evaluation. # # This is necessary to resolve reference to local variables before doing # assignments and setting up commands. They would otherwise be resolved # later in a different context and the result would be completely wrong. # define def_unit_qt4_target_pre_handle_translation_dx $(out) + $(more_output) +| $(maybe_output): \ $(deps) \ $(value _UNIT_QT4_LRC_CMDS_DEP) \ | \ $(orderdeps) %$$(call MSG_TOOL,lrelease,$(target),$(source),$$@) $(QUIET2)$(RM) -f $(out) $(more_output) $(maybe_output) $(dep) $(cmds) ifndef NO_COMPILE_CMDS_DEPS %$$(QUIET2)$$(APPEND) '$(dep)' %$$(QUIET2)$$(APPEND) '$(dep)' 'define $(target)_$(subst :,_,$(source))_QT4_LRC_CMDS_PREV_' %$$(QUIET2)$$(APPEND) -c '$(dep)' '$(out)' %$$(QUIET2)$$(APPEND) '$(dep)' 'endef' endif $(target)_CLEAN += $(out) $(more_output) $(maybe_output) $(dep) $(target)-inst-nls_SOURCES += $(out) endef # def_unit_qt4_target_pre_handle_translation_dx ## # Handle a source file listed in QT_TRANSLATIONS. # # The files listed in QT_TRANSLATIONS are translation files (.ts) which needs # to be translated into .qm files that are loadble by Qt. # # @remarks Invoked via $(evalvalctx ). define def_unit_qt4_target_pre_handle_translation local type := LRC # fetch the properties. local tool := $(kb-src-tool dummy_var) local qtnlsdir := $($(target)_0_OUTDIR)/qtnls local outbase := $(qtnlsdir)/$(notdir $(basename $(source))) local out := $(outbase).qm local dep := $(out).dep local flags := $(kb-src-prop FLAGS,dummy_var,right-to-left) local deps := $(kb-src-prop DEPS,dummy_var,left-to-right) local orderdeps := $(call DIRDEP,$(dir $(outbase))) $(kb-src-prop ORDERDEPS,dummy_var,left-to-right) # default path + source dep. ifneq ($(defpath),) local source := $(abspathex $(source),$(defpath)) local deps := $(abspathex $(deps),$(defpath)) $(source) local incs := $(abspathex $(incs),$(defpath)) else local deps += $(source) endif # call the tool ifndef TOOL_$(tool)_LRC_TS_CMDS $(error kBuild: qt lrelease tool not found: TOOL_$(tool)_LRC_TS_CMDS) endif local cmds := $(TOOL_$(tool)_LRC_TS_CMDS) local more_output := $(TOOL_$(tool)_LRC_TS_OUTPUT) local maybe_output := $(TOOL_$(tool)_LRC_TS_OUTPUT_MAYBE) local deps += $(TOOL_$(tool)_LRC_TS_DEPEND) local orderdeps += $(TOOL_$(tool)_LRC_TS_DEPORD) # generate the link rule and update some source and target variables. ifndef NO_COMPILE_CMDS_DEPS $(eval includedep $(dep)) endif $(eval $(def_unit_qt4_target_pre_handle_translation_dx)) endef # def_unit_qt4_target_pre_handle_translation ## wrapper for the UIC command dependencies. ifndef NO_COMPILE_CMDS_DEPS _UNIT_QT4_RCC_CMDS_DEP = $$(comp-cmds-ex $$($(target)_$(subst :,_,$(source))_QT4_RCC_CMDS_PREV_),$$(commands $(out)),FORCE) else _UNIT_QT4_RCC_CMDS_DEP = endif ## # def_unit_qt4_target_pre_handle_qrc helper that is expanded before evaluation. # # This is necessary to resolve reference to local variables before doing # assignments and setting up commands. They would otherwise be resolved # later in a different context and the result would be completely wrong. # define def_unit_qt4_target_pre_handle_rcc_dx $(out) +| $(realout) $(more_output) $(maybe_output): \ $(deps) \ $(value _UNIT_QT4_RCC_CMDS_DEP) \ | \ $(orderdeps) %$$(call MSG_TOOL,rcc,$(target),$(source),$$@) $(QUIET2)$(RM) -f $(out) $(more_output) $(maybe_output) $(dep) $(cmds) $(QUIET)$(CP) --changed -f $(out) $(realout) ifndef NO_COMPILE_CMDS_DEPS %$$(QUIET2)$$(APPEND) '$(dep)' %$$(QUIET2)$$(APPEND) '$(dep)' 'define $(target)_$(subst :,_,$(source))_QT4_RCC_CMDS_PREV_' %$$(QUIET2)$$(APPEND) -c '$(dep)' '$(out)' %$$(QUIET2)$$(APPEND) '$(dep)' 'endef' endif $(target)_INTERMEDIATES += $(realout) $(target)_GEN_SOURCES_ += $(realout) $(target)_CLEAN += $(out) $(realout) $(more_output) $(maybe_output) $(dep) endef # def_unit_qt4_target_pre_handle_rcc_dx ## # Source handler for .qrc sources (Qt resource files). # # @remarks $(evalvalctx me). define def_unit_qt4_src_handler_qrc local type := RCC # fetch the properties. local tool := $(kb-src-tool dummy_var) local qtrccdir := $($(target)_0_OUTDIR)/qtrcc local outbase := $(qtrccdir)/$(notdir $(basename $(source))) local out := $(outbase).tmp.gen.cpp local realout := $(outbase).gen.cpp local dep := $(realout).dep local flags := $(kb-src-prop FLAGS,dummy_var,right-to-left) local deps := $(kb-src-prop DEPS,dummy_var,left-to-right) local orderdeps := $(call DIRDEP,$(dir $(outbase))) $(kb-src-prop ORDERDEPS,dummy_var,left-to-right) # default path + source dep. ifneq ($(defpath),) local source := $(abspathex $(source),$(defpath)) local deps := $(abspathex $(deps),$(defpath)) $(source) local incs := $(abspathex $(incs),$(defpath)) else local deps += $(source) endif # call the tool ifndef TOOL_$(tool)_RCC_QRC_CMDS $(error kBuild: qt rcc tool not found: TOOL_$(tool)_RCC_QRC_CMDS) endif local cmds := $(TOOL_$(tool)_RCC_QRC_CMDS) local more_output := $(TOOL_$(tool)_RCC_QRC_OUTPUT) local maybe_output := $(TOOL_$(tool)_RCC_QRC_OUTPUT_MAYBE) local deps += $(TOOL_$(tool)_RCC_QRC_DEPEND) local orderdeps += $(TOOL_$(tool)_RCC_QRC_DEPORD) # generate the link rule and update some source and target variables. ifndef NO_COMPILE_CMDS_DEPS $(eval includedep $(dep)) endif $(eval $(def_unit_qt4_target_pre_handle_rcc_dx)) endef # def_unit_qt4_src_handler_qrc ## wrapper for the UIC command dependencies. ifndef NO_COMPILE_CMDS_DEPS _UNIT_QT4_UIC_CMDS_DEP = $$(comp-cmds-ex $$($(target)_$(subst :,_,$(source))_QT4_UIC_CMDS_PREV_),$$(commands $(out)),FORCE) else _UNIT_QT4_UIC_CMDS_DEP = endif ## # def_unit_qt4_src_handler_ui helper that is expanded before evaluation. # # This is necessary to resolve reference to local variables before doing # assignments and setting up commands. They would otherwise be resolved # later in a different context and the result would be completely wrong. # define def_unit_qt4_target_pre_handle_ui_dx $(out) +| $(realout) $(more_output) $(maybe_output): \ $(deps) \ $(value _UNIT_QT4_UIC_CMDS_DEP) \ | \ $(orderdeps) %$$(call MSG_TOOL,uic,$(target),$(source),$$@) $(QUIET2)$(RM) -f $(out) $(more_output) $(maybe_output) $(dep) $(cmds) $(QUIET)$(CP) --changed -f $(out) $(realout) ifndef NO_COMPILE_CMDS_DEPS %$$(QUIET2)$$(APPEND) '$(dep)' %$$(QUIET2)$$(APPEND) '$(dep)' 'define $(target)_$(subst :,_,$(source))_QT4_UIC_CMDS_PREV_' %$$(QUIET2)$$(APPEND) -c '$(dep)' '$(out)' %$$(QUIET2)$$(APPEND) '$(dep)' 'endef' endif $(target)_INTERMEDIATES += $(realout) $(target)_CLEAN += $(out) $(realout) $(more_output) $(maybe_output) $(dep) endef # def_unit_qt4_target_pre_handle_ui_dx ## # Source handler for .ui sources. # # @remarks $(evalvalctx me). define def_unit_qt4_src_handler_ui local type := UIC # fetch the properties. local tool := $(kb-src-tool dummy_var) local qtuicdir := $($(target)_0_OUTDIR)/qtuic local outbase := $(qtuicdir)/$(notdir $(basename $(source))) local out := $(outbase).tmp.gen.h local realout := $(outbase).gen.h local dep := $(realout).dep local flags := $(kb-src-prop FLAGS,dummy_var,right-to-left) local deps := $(kb-src-prop DEPS,dummy_var,left-to-right) local orderdeps := $(call DIRDEP,$(dir $(outbase))) $(kb-src-prop ORDERDEPS,dummy_var,left-to-right) # default path + source dep. ifneq ($(defpath),) local source := $(abspathex $(source),$(defpath)) local deps := $(abspathex $(deps),$(defpath)) $(source) local incs := $(abspathex $(incs),$(defpath)) else local deps += $(source) endif # call the tool ifndef TOOL_$(tool)_UIC_UI_CMDS $(error kBuild: qt uic tool not found: TOOL_$(tool)_UIC_UI_CMDS) endif local cmds := $(TOOL_$(tool)_UIC_UI_CMDS) local more_output := $(TOOL_$(tool)_UIC_UI_OUTPUT) local maybe_output := $(TOOL_$(tool)_UIC_UI_OUTPUT_MAYBE) local deps += $(TOOL_$(tool)_UIC_UI_DEPEND) local orderdeps += $(TOOL_$(tool)_UIC_UI_DEPORD) # generate the link rule and update some source and target variables. ifndef NO_COMPILE_CMDS_DEPS $(eval includedep $(dep)) endif $(eval $(def_unit_qt4_target_pre_handle_ui_dx)) endef # def_unit_qt4_src_handler_ui ## wrapper for the MOC command dependencies. ifndef NO_COMPILE_CMDS_DEPS _UNIT_QT4_MOC_HPP_CMDS_DEP = $$(comp-cmds-ex $$($(target)_$(subst :,_,$(source))_QT4_MOC_HPP_CMDS_PREV_),$$(commands $(out)),FORCE) else _UNIT_QT4_MOC_HPP_CMDS_DEP = endif ## # def_unit_qt4_target_pre_handle_moc_hdr helper that is expanded before evaluation. # # This is necessary to resolve reference to local variables before doing # assignments and setting up commands. They would otherwise be resolved # later in a different context and the result would be completely wrong. # define def_unit_qt4_target_pre_handle_moc_hdr_dx $(out) +| $(realout) $(more_output) $(maybe_output): \ $(deps) \ $(value _UNIT_QT4_MOC_HPP_CMDS_DEP) \ | \ $(orderdeps) %$$(call MSG_TOOL,moc,$(target),$(source),$$@) $(QUIET2)$(RM) -f $(out) $(more_output) $(maybe_output) $(dep) $(cmds) $(QUIET)$(CP) --changed -f $(out) $(realout) ifndef NO_COMPILE_CMDS_DEPS %$$(QUIET2)$$(APPEND) '$(dep)' %$$(QUIET2)$$(APPEND) '$(dep)' 'define $(target)_$(subst :,_,$(source))_QT4_MOC_HPP_CMDS_PREV_' %$$(QUIET2)$$(APPEND) -c '$(dep)' '$(out)' %$$(QUIET2)$$(APPEND) '$(dep)' 'endef' endif $(target)_INTERMEDIATES += $(realout) $(target)_GEN_SOURCES_ += $(realout) $(target)_CLEAN += $(out) $(realout) $(more_output) $(maybe_output) $(dep) endef ## # Handle a source file listed in QT_MOCHDRS. # # The files listed in QT_MOCHDRS uses the Q_OBJECT macro and we will # generate a .cpp file for each of them and add it to the generated # sources so that it's compiled and linked. (There is an alternative # way to do this where the .cpp file is included, this isn't currently # supported by this unit.) # # @remarks Invoked via $(evalvalctx ). define def_unit_qt4_target_pre_handle_moc_hdr local type := MOC # fetch the properties. local tool := $(kb-src-tool dummy_var) local outbase := $(qtmocdir)/$(notdir $(basename $(source))) local out := $(outbase).tmp.cpp local realout := $(outbase).cpp local dep := $(realout).dep local defs := $(kb-src-prop DEFS,dummy_var,left-to-right) local incs := $(kb-src-prop INCS,dummy_var,right-to-left) local flags := $(kb-src-prop FLAGS,dummy_var,right-to-left) local deps := $(kb-src-prop DEPS,dummy_var,left-to-right) local orderdeps := $(call DIRDEP,$(dir $(outbase))) $(kb-src-prop ORDERDEPS,dummy_var,left-to-right) # default path + source dep. ifneq ($(defpath),) local source := $(abspathex $(source),$(defpath)) local deps := $(abspathex $(deps),$(defpath)) $(source) local incs := $(abspathex $(incs),$(defpath)) else local deps += $(source) endif # call the tool ifndef TOOL_$(tool)_MOC_HPP_CMDS $(error kBuild: qt moc tool not found: TOOL_$(tool)_MOC_HPP_CMDS) endif local cmds := $(TOOL_$(tool)_MOC_HPP_CMDS) local more_output := $(TOOL_$(tool)_MOC_HPP_OUTPUT) local maybe_output := $(TOOL_$(tool)_MOC_HPP_OUTPUT_MAYBE) local deps += $(TOOL_$(tool)_MOC_HPP_DEPEND) local orderdeps += $(TOOL_$(tool)_MOC_HPP_DEPORD) # generate the link rule and update some source and target variables. ifndef NO_COMPILE_CMDS_DEPS $(eval includedep $(dep)) endif $(eval $(def_unit_qt4_target_pre_handle_moc_hdr_dx)) endef # def_unit_qt4_target_pre_handle_moc_hdr ## wrapper for the MOC command dependencies. ifndef NO_COMPILE_CMDS_DEPS _UNIT_QT4_MOC_CPP_CMDS_DEP = $$(comp-cmds-ex $$($(target)_$(subst :,_,$(source))_QT4_MOC_CPP_CMDS_PREV_),$$(commands $(out)),FORCE) else _UNIT_QT4_MOC_CPP_CMDS_DEP = endif ## # def_unit_qt4_target_pre_handle_moc_src helper that is expanded before evaluation. # # This is necessary to resolve reference to local variables before doing # assignments and setting up commands. They would otherwise be resolved # later in a different context and the result would be completely wrong. # define def_unit_qt4_target_pre_handle_moc_src_dx $(out) +| $(realout) $(more_output) $(maybe_output): \ $(deps) \ $(value _UNIT_QT4_MOC_CPP_CMDS_DEP) \ | \ $(orderdeps) %$$(call MSG_TOOL,moc,$(target),$(source),$$@) $(QUIET2)$(RM) -f $(out) $(more_output) $(maybe_output) $(dep) $(cmds) $(QUIET)$(CP) --changed -f $(out) $(realout) ifndef NO_COMPILE_CMDS_DEPS %$$(QUIET2)$$(APPEND) '$(dep)' %$$(QUIET2)$$(APPEND) '$(dep)' 'define $(target)_$(subst :,_,$(source))_QT4_MOC_CPP_CMDS_PREV_' %$$(QUIET2)$$(APPEND) -c '$(dep)' '$(out)' %$$(QUIET2)$$(APPEND) '$(dep)' 'endef' endif $(target)_INTERMEDIATES += $(realout) $(target)_CLEAN += $(out) $(realout) $(more_output) $(maybe_output) $(dep) endef ## # Handle a source file listed in QT_MOCSRCS. # # The files listed in QT_MOCSRCS uses the Q_OBJECT macro and will include # a .moc file that we're expected to generate here. # # @remarks Invoked via $(evalvalctx ). define def_unit_qt4_target_pre_handle_moc_src local type := MOC # fetch the properties. local tool := $(kb-src-tool dummy_var) local outbase := $(qtmocdir)/$(notdir $(basename $(source))) local out := $(outbase).tmp.moc local realout := $(outbase).moc local dep := $(realout).dep local defs := $(kb-src-prop DEFS,dummy_var,left-to-right) local incs := $(kb-src-prop INCS,dummy_var,right-to-left) local flags := $(kb-src-prop FLAGS,dummy_var,right-to-left) local deps := $(kb-src-prop DEPS,dummy_var,left-to-right) local orderdeps := $(call DIRDEP,$(dir $(outbase))) $(kb-src-prop ORDERDEPS,dummy_var,left-to-right) # default path + source dep. ifneq ($(defpath),) local source := $(abspathex $(source),$(defpath)) local deps := $(abspathex $(deps),$(defpath)) $(source) local incs := $(abspathex $(incs),$(defpath)) else local deps += $(source) endif # call the tool ifndef TOOL_$(tool)_MOC_CPP_CMDS $(error kBuild: qt moc tool not found: TOOL_$(tool)_MOC_CPP_CMDS) endif local cmds := $(TOOL_$(tool)_MOC_CPP_CMDS) local more_output := $(TOOL_$(tool)_MOC_CPP_OUTPUT) local maybe_output := $(TOOL_$(tool)_MOC_CPP_OUTPUT_MAYBE) local deps += $(TOOL_$(tool)_MOC_CPP_DEPEND) local orderdeps += $(TOOL_$(tool)_MOC_CPP_DEPORD) # generate the link rule and update some source and target variables. ifndef NO_COMPILE_CMDS_DEPS $(eval includedep $(dep)) endif $(eval $(def_unit_qt4_target_pre_handle_moc_src_dx)) endef # def_unit_qt4_target_pre_handle_moc_src ## # Adds sources containing Q_OBJECT to QT_MOCSRCS. define def_unit_qt4_target_pre_cpp_source ifneq ($(file-size $(source)),-1) ifneq ($(strip $(shell $(SED) -f $(KBUILD_PATH)/units/qt-Q_OBJECT.sed $(source))),) $(eval $(target)_QT_MOCSRCS += $(source)) endif endif endef # def_unit_qt4_target_pre_cpp_source ## # Invoked early in the processing of a target that uses the Qt unit. # # It will append the qt source handlers to the target (.h, .ui, .ts, # .png, .bmp, .gif). # # It will then check all the C++ sources and check which needs # a .moc files and generate rules and dependencies fofor these # define def_unit_qt4_target_pre # Make QTTOOL the default for the specific Qt tools instead of TOOL. ifneq ($($(target)_QTTOOL),) ifeq ($($(target)_MOCTOOL),) $(target)_MOCTOOL := $($(target)_QTTOOL) endif ifeq ($($(target)_UICTOOL),) $(target)_UICTOOL := $($(target)_QTTOOL) endif ifeq ($($(target)_RCCTOOL),) $(target)_RCCTOOL := $($(target)_QTTOOL) endif ifeq ($($(target)_LRCTOOL),) $(target)_LRCTOOL := $($(target)_QTTOOL) endif endif # Deal with QT_MODULES, QT_PREFIX and QT_INFIX. local qt_modules := \ $($(target)_QT_MODULES.$(bld_trg)) \ $($(target)_QT_MODULES.$(bld_trg_arch)) \ $($(target)_QT_MODULES.$(bld_trg).$(bld_trg_arch)) \ $($(target)_QT_MODULES.$(bld_trg_cpu)) \ $($(target)_QT_MODULES.$(bld_type)) \ $($(target)_QT_MODULES) local qt_prefix := $(firstword \ $($(target)_QT_PREFIX.$(bld_trg)) \ $($(target)_QT_PREFIX.$(bld_trg_arch)) \ $($(target)_QT_PREFIX.$(bld_trg).$(bld_trg_arch)) \ $($(target)_QT_PREFIX.$(bld_trg_cpu)) \ $($(target)_QT_PREFIX.$(bld_type)) \ $($(target)_QT_PREFIX)) local qt_infix := $(firstword \ $($(target)_QT_INFIX.$(bld_trg)) \ $($(target)_QT_INFIX.$(bld_trg_arch)) \ $($(target)_QT_INFIX.$(bld_trg).$(bld_trg_arch)) \ $($(target)_QT_INFIX.$(bld_trg_cpu)) \ $($(target)_QT_INFIX.$(bld_type)) \ $($(target)_QT_INFIX)) ifeq ($(bld_trg),darwin) # Adding -F to CXXFLAGS is necessary to make #include stuff work... $(eval $(target)_CXXFLAGS += -F$(PATH_SDK_QT4_LIB) ) $(eval $(target)_OBJCXXFLAGS += -F$(PATH_SDK_QT4_LIB) ) $(eval $(target)_LDFLAGS += -F$(PATH_SDK_QT4_LIB) $(foreach module,$(qt_modules), -framework $(qt_prefix)Qt$(module)$(qt_infix)) ) $(eval $(target)_INCS += $(foreach module,$(qt_modules), $(PATH_SDK_QT4_LIB)/$(qt_prefix)Qt$(module)$(qt_infix).framework/Versions/4/Headers) ) else ifeq ($(bld_trg),win) $(eval $(target)_LIBS += $(foreach module,$(qt_modules), $(PATH_SDK_QT4_LIB)/$(qt_prefix)Qt$(module)$(qt_infix)4$(SUFF_LIB)) ) ifeq ($(tool_do),LINK_PROGRAM) $(eval $(target)_LIBS += $(PATH_SDK_QT4_LIB)/$(qt_prefix)qtmain$(qt_infix)$(SUFF_LIB) ) endif else $(eval $(target)_LIBS += $(foreach module,$(qt_modules), $(PATH_SDK_QT4_LIB)/lib$(qt_prefix)Qt$(module)$(qt_infix)$(SUFF_DLL)) ) endif $(eval $(target)_INCS += $(addprefix $(PATH_SDK_QT4_INC)/Qt,$(qt_modules)) $(PATH_SDK_QT4_INC) ) endif $(eval $(target)_DEFS += $(foreach module,$(toupper $(qt_modules)), QT_$(module)_LIB) ) # Autodetect source files with Q_OBJECT references if QT_MOCSRCS is undefined. (slow) # Tip: Use target_QT_MOCSRCS = $(NO_SUCH_VARIABLE) to avoid this. ifndef $(target)_QT_MOCSRCS $(foreach source, $(filter %.cxx %.CXX %.cpp %.CPP %.cc %.CC,\ $($(target)_SOURCES.$(bld_trg)) \ $($(target)_SOURCES.$(bld_trg_arch)) \ $($(target)_SOURCES.$(bld_trg).$(bld_trg_arch)) \ $($(target)_SOURCES.$(bld_trg_cpu)) \ $($(target)_SOURCES.$(bld_type)) \ $($(target)_SOURCES) \ ), $(evalval def_unit_qt4_target_pre_cpp_source)) endif # Install source handlers for .ui files. $(target)_SRC_HANDLERS += \ .ui:def_unit_qt4_src_handler_ui \ .UI:def_unit_qt4_src_handler_ui \ .qrc:def_unit_qt4_src_handler_qrc \ .qrc:def_unit_qt4_src_handler_qrc # Calc the MOC and UI output directories and add them to BLDDIRS and INCS. local qtmocdir := $($(target)_0_OUTDIR)/qtmoc local qtuicdir := $($(target)_0_OUTDIR)/qtuic local qtrccdir := $($(target)_0_OUTDIR)/qtrcc local qtnlsdir := $($(target)_0_OUTDIR)/qtnls $(eval $(target)_BLDDIRS += $(qtmocdir) $(qtuicdir) $(qtrccdir) $(qtnlsdir)) $(eval $(target)_INCS += $(qtmocdir) $(qtuicdir)) # Deal with QT_MOCSRCS. $(foreach source, \ $($(target)_QT_MOCSRCS.$(bld_trg)) \ $($(target)_QT_MOCSRCS.$(bld_trg_arch)) \ $($(target)_QT_MOCSRCS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_QT_MOCSRCS.$(bld_trg_cpu)) \ $($(target)_QT_MOCSRCS.$(bld_type)) \ $($(target)_QT_MOCSRCS) \ , $(evalvalctx def_unit_qt4_target_pre_handle_moc_src)) # Deal with QT_MOCHDRS. $(foreach source, \ $($(target)_QT_MOCHDRS.$(bld_trg)) \ $($(target)_QT_MOCHDRS.$(bld_trg_arch)) \ $($(target)_QT_MOCHDRS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_QT_MOCHDRS.$(bld_trg_cpu)) \ $($(target)_QT_MOCHDRS.$(bld_type)) \ $($(target)_QT_MOCHDRS) \ , $(evalvalctx def_unit_qt4_target_pre_handle_moc_hdr)) # Deal with QT_TRANSLATIONS. # ASSUMES (_ALL_)INSTALLS is processed after the targets using this unit. local translations := \ $($(target)_QT_TRANSLATIONS.$(bld_trg)) \ $($(target)_QT_TRANSLATIONS.$(bld_trg_arch)) \ $($(target)_QT_TRANSLATIONS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_QT_TRANSLATIONS.$(bld_trg_cpu)) \ $($(target)_QT_TRANSLATIONS.$(bld_type)) \ $($(target)_QT_TRANSLATIONS) ifneq ($(strip $(translations)),) local expr := _ALL_INSTALLS_IMPLICIT += $(target)-inst-nls $(eval $(expr)) ifdef $(target)_QT_TRANSLATIONS_TEMPLATE $(target)-inst-nls_TEMPLATE := $($(target)_QT_TRANSLATIONS_TEMPLATE) else $(target)-inst-nls_MODE := 0644 endif ifdef $(target)_QT_TRANSLATIONS_INST $(target)-inst-nls_INST := $($(target)_QT_TRANSLATIONS_INST) endif $(target)-inst-nls_SOURCES := $(foreach source, $(translations)\ , $(evalvalctx def_unit_qt4_target_pre_handle_translation)) endif endef # def_unit_qt4_target_pre # # Rule for debugging. # unit-qt4-show-vars: @$(ECHO) 'The Qt4 SDK variables:' @$(ECHO) ' PATH_SDK_QT4 = "$(PATH_SDK_QT4)"' @$(ECHO) ' PATH_SDK_QT4_INC = "$(PATH_SDK_QT4_INC)"' @$(ECHO) ' PATH_SDK_QT4_LIB = "$(PATH_SDK_QT4_LIB)"' @$(ECHO) ' PATH_SDK_QT4_LIB.amd64 = "$(PATH_SDK_QT4_LIB.amd64)"' @$(ECHO) ' PATH_SDK_QT4_LIB.x86 = "$(PATH_SDK_QT4_LIB.x86)"' @$(ECHO) 'The Qt4 TOOL variables:' @$(ECHO) ' PATH_TOOL_QT4_BIN = "$(PATH_TOOL_QT4_BIN)"' @$(ECHO) ' TOOL_QT4_BIN_SUFF = "$(TOOL_QT4_BIN_SUFF)"' @$(ECHO) ' TOOL_QT4_MOC = "$(TOOL_QT4_MOC)"' @$(ECHO) ' TOOL_QT4_UIC = "$(TOOL_QT4_UIC)"' @$(ECHO) ' TOOL_QT4_RCC = "$(TOOL_QT4_RCC)"' @$(ECHO) ' TOOL_QT4_LRC = "$(TOOL_QT4_LRC)"' @$(ECHO) ' TOOL_QT4_LUPDATE = "$(TOOL_QT4_LUPDATE)"' kbuild-3149/kBuild/units/dtrace.kmk0000644000175000017500000001576513252530251017242 0ustar locutuslocutus# $Id: dtrace.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # DTrace unit. # # # Copyright (c) 2012-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # ifdef UNIT_dtrace $(error kBuild: The lex unit was included twice!) endif UNIT_dtrace = dtrace # Add our target properties. PROPS_TOOLS += DTRACETOOL PROPS_SINGLE += DTRACETOOL PROPS_ACCUMULATE_R += DTRACE_HDR_FLAGS DTRACE_OBJ_FLAGS # Add ourselves to the default source handlers. KBUILD_SRC_HANDLERS += \ .d:def_src_handler_dtrace ## wrapper the compile command dependency check. ifndef NO_COMPILE_CMDS_DEPS _DEP_DTRACE_HDR_CMDS = $$(comp-cmds-ex $$($(target)_$(subst :,_,$(source))_DTRACE_HDR_CMDS_PREV_),$$(commands $(out)),FORCE) _DEP_DTRACE_OBJ_CMDS = $$(comp-cmds-ex $$($(target)_$(subst :,_,$(source))_DTRACE_OBJ_CMDS_PREV_),$$(commands $(out)),FORCE) else _DEP_DTRACE_HDR_CMDS = _DEP_DTRACE_OBJ_CMDS = endif ## # Generates the rule for creating a DTrace header from a D source file. # # @param out The output file. # @param cmds The dtrace command(s). # @param lots more # define def_dtrace_hdr_rule $(out): \ $(deps) \ $(value _DEP_DTRACE_HDR_CMDS) \ | \ $(orderdeps) %$$(call MSG_GENERATE,$(target),$$@,$(source)) $$(QUIET)$$(RM) -f -- $(dep) $(out) $(cmds) ifndef NO_COMPILE_CMDS_DEPS %$$(QUIET2)$$(APPEND) '$(dep)' %$$(QUIET2)$$(APPEND) '$(dep)' 'define $(target)_$(subst :,_,$(source))_DTRACE_HDR_CMDS_PREV_' %$$(QUIET2)$$(APPEND) -c '$(dep)' '$(out)' %$$(QUIET2)$$(APPEND) '$(dep)' 'endef' endif # update globals _OUT_FILES += $(out) $(target)_INTERMEDIATES += $(out) endef # def_dtrace_hdr_rule ## # Generates the rule for creating a DTrace object file from a D source file # and a bunch of object files. # # @param out The output file. # @param cmds The dtrace command(s). # @param lots more # define def_dtrace_obj_rule $(out): \ $(deps) \ $$$$(filter-out %-dtrace-object-format.o, $$$$($(target)_2_OBJS)) \ $(value _DEP_DTRACE_OBJ_CMDS) \ | \ $(orderdeps) %$$(call MSG_GENERATE,$(target),$$@,$(source) ++) $$(QUIET)$$(RM) -f -- $(dep) $(out) $(cmds) ifndef NO_COMPILE_CMDS_DEPS %$$(QUIET2)$$(APPEND) '$(dep)' %$$(QUIET2)$$(APPEND) '$(dep)' 'define $(target)_$(subst :,_,$(source))_DTRACE_OBJ_CMDS_PREV_' %$$(QUIET2)$$(APPEND) -c '$(dep)' '$(out)' %$$(QUIET2)$$(APPEND) '$(dep)' 'endef' endif # update globals _OUT_FILES += $(out) $(target)_2_OBJS <= $(out) endef # def_dtrace_hdr_rule ## # Handler for .d files listed in the SOURCES properties. # # .d files are transformed into .h that is used when compiling, thus needing # to be generated before anything is compiled, and into object files that needs # to go into the linking. Mac does not create object files. # # The step producing the object file requires all the object files with dtrace # probes in them as input/output as well, because it adjusts the dtrace symbols # from UNDEF to IGNORE. This is really ugly and cannot be expressed in make # syntax (prerequisite object files being modified). Fortunately, it works # fine because the object files won't be used by anyone else before the dtrace # object file exists. # # @param target The target file. # @param source The source file. # @param lots more # @returns quite a bit. define def_src_handler_dtrace local type := DTRACE local tmp := $(kb-src-tool tool) ifeq ($(tool),) $ (error kBuild: $(target) / $(sources) does not have a (DTRACE) tool defined!) endif local dtracedir := $($(target)_0_OUTDIR)/dtrace # # The header file first. # # Figure out all the props. ifndef TOOL_$(tool)_DTRACE_HDR_CMDS $(error kBuild: TOOL_$(tool)_DTRACE_HDR_CMDS isn't defined! target=$(target) source=$(source) ) endif ## @todo put the header in a subdir and add this to INCS? Do we have a early per-target hook for this?? local outbase := $(dtracedir)/dtrace/$(basename $(notdir $(source))) local out := $(outbase).h local tmp := $(kb-src-prop DTRACE_HDR_FLAGS,flags,left-to-right,) local tmp := $(kb-src-prop DEPS,deps,left-to-right,$(defpath)) local tmp := $(kb-src-prop ORDERDEPS,orderdeps,left-to-right,$(defpath)) local dirdep := $(call DIRDEP,$(dir $(out))) # Adjust paths if we got a default path. ifneq ($(defpath),) local source := $(abspathex $(source),$(defpath)) endif # dependency file. local dep := $(out)$(SUFF_DEP) ifndef NO_COMPILE_CMDS_DEPS _DEPFILES_INCLUDED += $(dep) $(eval includedep $(dep)) endif # call the tool local cmds := $(TOOL_$(tool)_DTRACE_HDR_CMDS) local deps += $(TOOL_$(tool)_DTRACE_DEPEND) $(source) local orderdeps += $(TOOL_$(tool)_DTRACE_DEPORD) $(dirdep) # generate the rule. $(eval $(def_dtrace_hdr_rule)) # # Adjust the object files and generate one from the D source, if needed. # ifn1of ($(bld_trg), $(TOOL_$(tool)_DTRACE_OBJ_NOT_NEEDED)) # Figure out all the props. ifndef TOOL_$(tool)_DTRACE_OBJ_CMDS $(error kBuild: TOOL_$(tool)_DTRACE_OBJ_CMDS isn't defined! target=$(target) source=$(source) ) endif local outbase := $(dtracedir)/$(basename $(notdir $(source))) local out := $(outbase)-dtrace-object-format.o local tmp := $(kb-src-prop DTRACE_OBJ_FLAGS,flags,left-to-right,) local tmp := $(kb-src-prop DEPS,deps,left-to-right,$(defpath)) local tmp := $(kb-src-prop ORDERDEPS,orderdeps,left-to-right,$(defpath)) local dirdep := $(call DIRDEP,$(dir $(out))) # Adjust paths if we got a default path. ifneq ($(defpath),) local source := $(abspathex $(source),$(defpath)) endif # dependency file. local dep := $(out)$(SUFF_DEP) ifndef NO_COMPILE_CMDS_DEPS _DEPFILES_INCLUDED += $(dep) $(eval includedep $(dep)) endif # call the tool local cmds := $(TOOL_$(tool)_DTRACE_OBJ_CMDS) local deps += $(TOOL_$(tool)_DTRACE_DEPEND) $(source) local orderdeps += $(TOOL_$(tool)_DTRACE_DEPORD) $(dirdep) # generate the rule. $(eval $(def_dtrace_obj_rule)) endif endef # def_src_handler_dtrace # # The pre-target hook. # define def_unit_dtrace_target_pre local dtracedir := $($(target)_0_OUTDIR)/dtrace $(eval $(target)_INCS += $(dtracedir)) endef #def_unit_dtrace_target_pre kbuild-3149/kBuild/units/vccprecomp.kmk0000644000175000017500000000464013252530251020127 0ustar locutuslocutus# $Id: vccprecomp.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild Unit - Target Level Precompiled Headers for Visual C++. # # # Copyright (c) 2016-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # UNIT_vccprecomp = Target level precompiled Headers for Visual C++ # # Early target processing pass #1. # # This set the internal _VCC_PCH_FILE and VCC_COMMON_OBJ_PDB properties, # which will be picked up by the VCCxxx tool. # define def_unit_vccprecomp_target_pre $(target)_1_VCC_PCH_FILE := $(outbase)-pch.pch $(target)_1_VCC_COMMON_OBJ_PDB := $(outbase)-common-obj.pdb endef # # Early target processing pass #2. # # This sets up a rule for creating the .pch file after qt5 and similar units # are done modifying INCS, DEFS and company. The 'tool' variable is defined by # footer-pass2-compiling-targets.kmk and is really the LD tool, but that'll # have to do for now. The '-PCH' variant of the VCC tool, is defined together # with $(tool) and allow us to bypass the options and dependencies triggered # by _1_VCC_PCH_FILE, _1_VCC_COMMON_OBJ_PDB and _PCH_HDR, and also make sure we # don't get circular dependencies by way of kDepObj and the debug info. # define def_unit_vccprecomp_target_pre_2 local source := $($(target)_PCH_HDR) $(source)_TOOL := $(tool)-PCH local suff := $(suffix $(source)) local type := CXX $(kb-src-one 2) endef kbuild-3149/kBuild/units/yacc.kmk0000644000175000017500000001361613252530251016710 0ustar locutuslocutus# $Id: yacc.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # yacc/bison unit. # # # Copyright (c) 2008-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # ifdef UNIT_yacc $(error kBuild: The yacc unit was included twice!) endif UNIT_yacc = yacc # Add our target properties. PROPS_TOOLS += YACCTOOL PROPS_SINGLE += YACCTOOL PROPS_ACCUMULATE_R += YACCFLAGS # Add ourselves to the default source handlers. KBUILD_SRC_HANDLERS += \ .y:def_src_handler_yacc_y \ .ypp:def_src_handler_yacc_ypp \ .y++:def_src_handler_yacc_ypp ## wrapper the compile command dependency check. ifndef NO_COMPILE_CMDS_DEPS _DEP_YACC_CMDS = $$(comp-cmds-ex $$($(target)_$(subst :,_,$(source))_YACC_CMDS_PREV_),$$(commands $(out)),FORCE) else _DEP_YACC_CMDS = endif ## # Generates the rules for running flex on a specific source file. # # @param $(obj) The object file. # @param lots more define def_yacc_rule $(out) + $(output_extra) +| $(output_maybe) : \ $(deps) \ $(value _DEP_YACC_CMDS) \ | \ $(orderdeps) %$$(call MSG_COMPILE,$(target),$(source),$$@,$(type)) $$(QUIET)$$(RM) -f -- $(dep) $(out) $(output_extra) $(output_maybe) $(cmds) ifndef NO_COMPILE_CMDS_DEPS %$$(QUIET2)$$(APPEND) '$(dep)' %$$(QUIET2)$$(APPEND) '$(dep)' 'define $(target)_$(subst :,_,$(source))_YACC_CMDS_PREV_' %$$(QUIET2)$$(APPEND) -c '$(dep)' '$(out)' %$$(QUIET2)$$(APPEND) '$(dep)' 'endef' endif # update globals and target properties. _OUT_FILES += $(out) $(output_extra) $(output_maybe) $(target)_GEN_SOURCES_ += $(out) $(target)_INTERMEDIATES += $(intermediates) endef # def_yacc_rule ## # Handler for .y files listed in the SOURCES properties. # # .y files are transformed into .c (and maybe .h) files that then gets # compiled by the C compiler. # # @param target The target file. # @param source The source file. # @param lots more # @returns quite a bit. # define def_src_handler_yacc_y # Figure out all the props. local type := YACC local tmp := $(kb-src-tool tool) ifeq ($(tool),) $(error kBuild: $(target) / $(sources) does not a (yacc) tool defined!) endif ifndef TOOL_$(tool)_YACC_CMDS $(error kBuild: TOOL_$(tool)_YACC_CMDS isn't defined! target=$(target) source=$(source) ) endif local out := $(kb-obj-base outbase).c local tmp := $(kb-src-prop YACCFLAGS,flags,left-to-right,) local tmp := $(kb-src-prop DEPS,deps,left-to-right,$(defpath)) local tmp := $(kb-src-prop ORDERDEPS,orderdeps,left-to-right,$(defpath)) local dirdep := $(call DIRDEP,$(dir $(out))) # Adjust paths if we got a default path. ifneq ($(defpath),) local source := $(abspathex $(source),$(defpath)) endif # dependency file. local dep := $(out)$(SUFF_DEP) ifndef NO_COMPILE_CMDS_DEPS _DEPFILES_INCLUDED += $(dep) $(eval includedep $(dep)) endif # Call the tool. local cmds := $(TOOL_$(tool)_YACC_CMDS) local output_extra := $(TOOL_$(tool)_YACC_OUTPUT) local output_maybe := $(TOOL_$(tool)_YACC_OUTPUT_MAYBE) local deps += $(TOOL_$(tool)_YACC_DEPEND) $(source) local orderdeps += $(TOOL_$(tool)_YACC_DEPORD) $(dirdep) # Whether it generates a header file depends on flags. local intermediates := $(filter %.h %.hpp %.h++ %.H,$(output_extra)) # Generate the rule. $(eval $(def_yacc_rule)) endef # def_src_handler_yacc_y ## # Handler for .ypp/.y++ files listed in the SOURCES properties. # # .ypp/++ files are transformed into .cpp/++ (and maybe .hpp/++) files that then gets # compiled by the C++ compiler. # # @param target The target file. # @param source The source file. # @param lots more # @returns quite a bit. # define def_src_handler_yacc_ypp # Figure out all the props. local type := YACC local tmp := $(kb-src-tool tool) ifeq ($(tool),) $(error kBuild: $(target) / $(sources) does not a (yacc) tool defined!) endif ifndef TOOL_$(tool)_YACC_CMDS $(error kBuild: TOOL_$(tool)_YACC_CMDS isn't defined! target=$(target) source=$(source) ) endif local out := $(kb-obj-base outbase).c$(substr $(suffix $(source),3)) local tmp := $(kb-src-prop YACCFLAGS,flags,left-to-right,) local tmp := $(kb-src-prop DEPS,deps,left-to-right,$(defpath)) local tmp := $(kb-src-prop ORDERDEPS,orderdeps,left-to-right,$(defpath)) local dirdep := $(call DIRDEP,$(dir $(out))) # Adjust paths if we got a default path. ifneq ($(defpath),) local source := $(abspathex $(source),$(defpath)) endif # dependency file. local dep := $(out)$(SUFF_DEP) ifndef NO_COMPILE_CMDS_DEPS _DEPFILES_INCLUDED += $(dep) $(eval includedep $(dep)) endif # Call the tool. local cmds := $(TOOL_$(tool)_YACC_CMDS) local output_extra := $(TOOL_$(tool)_YACC_OUTPUT) local output_maybe := $(TOOL_$(tool)_YACC_OUTPUT_MAYBE) local deps += $(TOOL_$(tool)_YACC_DEPEND) $(source) local orderdeps += $(TOOL_$(tool)_YACC_DEPORD) $(dirdep) # Whether it generates a header file depends on flags. local intermediates := $(filter %.h %.hpp %.h++ %.H,$(output_extra)) # Generate the rule. $(eval $(def_yacc_rule)) endef # def_src_handler_yacc_ypp kbuild-3149/kBuild/env.sh0000755000175000017500000004724413252530215015256 0ustar locutuslocutus#!/bin/sh # $Id: env.sh 3127 2017-11-22 20:15:12Z bird $ ## @file # Environment setup script. # # # Copyright (c) 2005-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # #set -x # # Check if we're in eval mode or not. # ERR_REDIR=1 DBG_REDIR=1 EVAL_OPT= EVAL_EXPORT="export " DBG_OPT= QUIET_OPT= FULL_OPT= FULL_WITH_BIN_OPT= LEGACY_OPT= VAR_OPT= VALUE_ONLY_OPT= EXP_TYPE_OPT= while test $# -gt 0; do case "$1" in "--debug-script") DBG_OPT="true" ;; "--no-debug-script") DBG_OPT= ;; "--quiet") QUIET_OPT="true" ;; "--verbose") QUIET_OPT= ;; "--full") FULL_OPT="true" ;; "--full-with-bin") FULL_OPT="true" FULL_WITH_BIN_OPT="true" ;; "--normal") FULL_OPT= ;; "--legacy") LEGACY_OPT="true" ;; "--no-legacy") LEGACY_OPT= ;; "--eval") EVAL_OPT="true" ERR_REDIR=2 DBG_REDIR=2 ;; "--set") EVAL_OPT="true" EVAL_EXPORT="" ERR_REDIR=2 DBG_REDIR=2 ;; "--var") shift VAR_OPT="${VAR_OPT} $1" ERR_REDIR=2 DBG_REDIR=2 ;; "--value-only") VALUE_ONLY_OPT="true" ;; "--name-and-value") VALUE_ONLY_OPT= ;; "--release") EXP_TYPE_OPT=1 KBUILD_TYPE=release BUILD_TYPE= ;; "--debug") EXP_TYPE_OPT=1 KBUILD_TYPE=debug BUILD_TYPE= ;; "--profile") EXP_TYPE_OPT=1 KBUILD_TYPE=profile BUILD_TYPE= ;; "--help") echo "kBuild Environment Setup Script, v0.2.0-pre" echo "" echo "syntax: $0 [options] [command [args]]" echo " or: $0 [options] --var " echo " or: $0 [options] --eval" echo " or: $0 [options] --eval --var " echo "" echo "The first form will execute the command, or if no command is given start" echo "an interactive shell." echo "The second form will print the specfified variable(s)." echo "The third form will print all exported variables suitable for bourne shell" echo "evaluation." echo "The forth form will only print the specified variable(s)." echo "" echo "Options:" echo " --debug, --release, --profile" echo " Alternative way of specifying KBUILD_TYPE." echo " --debug-script, --no-debug-script" echo " Controls debug output. Default: --no-debug-script" echo " --quiet, --verbose" echo " Controls informational output. Default: --verbose" echo " --full, --full-with-bin, --normal" echo " Controls the variable set. Default: --normal" echo " --legacy, --no-legacy" echo " Include legacy variables in result. Default: --no-legacy" echo " --value-only, --name-and-value" echo " Controls what the result of a --var query. Default: --name-and-value" echo " --set, --export" echo " Whether --eval explicitly export the variables. --set is useful for" echo " getting a list of environment vars for a commandline, while --eval" echo ' is useful for eval `env.sh`. Default: --export' echo "" exit 1 ;; *) break ;; esac shift done # # Deal with legacy environment variables. # if test -n "$PATH_KBUILD"; then if test -n "$KBUILD_PATH" -a "$KBUILD_PATH" != "$PATH_KBUILD"; then echo "$0: error: KBUILD_PATH ($KBUILD_PATH) and PATH_KBUILD ($PATH_KBUILD) disagree." 1>&${ERR_REDIR} sleep 1 exit 1 fi KBUILD_PATH=$PATH_KBUILD fi if test -n "$PATH_KBUILD_BIN"; then if test -n "$KBUILD_BIN_PATH" -a "$KBUILD_BIN_PATH" != "$PATH_KBUILD_BIN"; then echo "$0: error: KBUILD_BIN_PATH ($KBUILD_BIN_PATH) and PATH_KBUILD_BIN ($PATH_KBUILD_BIN) disagree." 1>&${ERR_REDIR} sleep 1 exit 1 fi KBUILD_BIN_PATH=$PATH_KBUILD_BIN fi if test -n "$BUILD_TYPE"; then if test -n "$KBUILD_TYPE" -a "$KBUILD_TYPE" != "$BUILD_TYPE"; then echo "$0: error: KBUILD_TYPE ($KBUILD_TYPE) and BUILD_TYPE ($BUILD_TYPE) disagree." 1>&${ERR_REDIR} sleep 1 exit 1 fi KBUILD_TYPE=$BUILD_TYPE fi if test -n "$BUILD_PLATFORM"; then if test -n "$KBUILD_HOST" -a "$KBUILD_HOST" != "$BUILD_PLATFORM"; then echo "$0: error: KBUILD_HOST ($KBUILD_HOST) and BUILD_PLATFORM ($BUILD_PLATFORM) disagree." 1>&${ERR_REDIR} sleep 1 exit 1 fi KBUILD_HOST=$BUILD_PLATFORM fi if test -n "$BUILD_PLATFORM_ARCH"; then if test -n "$KBUILD_HOST_ARCH" -a "$KBUILD_HOST_ARCH" != "$BUILD_PLATFORM_ARCH"; then echo "$0: error: KBUILD_HOST_ARCH ($KBUILD_HOST_ARCH) and BUILD_PLATFORM_ARCH ($BUILD_PLATFORM_ARCH) disagree." 1>&${ERR_REDIR} sleep 1 exit 1 fi KBUILD_HOST_ARCH=$BUILD_PLATFORM_ARCH fi if test -n "$BUILD_PLATFORM_CPU"; then if test -n "$KBUILD_HOST_CPU" -a "$KBUILD_HOST_CPU" != "$BUILD_PLATFORM_CPU"; then echo "$0: error: KBUILD_HOST_CPU ($KBUILD_HOST_CPU) and BUILD_PLATFORM_CPU ($BUILD_PLATFORM_CPU) disagree." 1>&${ERR_REDIR} sleep 1 exit 1 fi KBUILD_HOST_CPU=$BUILD_PLATFORM_CPU fi if test -n "$BUILD_TARGET"; then if test -n "$KBUILD_TARGET" -a "$KBUILD_TARGET" != "$BUILD_TARGET"; then echo "$0: error: KBUILD_TARGET ($KBUILD_TARGET) and BUILD_TARGET ($BUILD_TARGET) disagree." 1>&${ERR_REDIR} sleep 1 exit 1 fi KBUILD_TARGET=$BUILD_TARGET fi if test -n "$BUILD_TARGET_ARCH"; then if test -n "$KBUILD_TARGET_ARCH" -a "$KBUILD_TARGET_ARCH" != "$BUILD_TARGET_ARCH"; then echo "$0: error: KBUILD_TARGET_ARCH ($KBUILD_TARGET_ARCH) and BUILD_TARGET_ARCH ($BUILD_TARGET_ARCH) disagree." 1>&${ERR_REDIR} sleep 1 exit 1 fi KBUILD_TARGET_ARCH=$BUILD_TARGET_ARCH fi if test -n "$BUILD_TARGET_CPU"; then if test -n "$KBUILD_TARGET_CPU" -a "$KBUILD_TARGET_CPU" != "$BUILD_TARGET_CPU"; then echo "$0: error: KBUILD_TARGET_CPU ($KBUILD_TARGET_CPU) and BUILD_TARGET_CPU ($BUILD_TARGET_CPU) disagree." 1>&${ERR_REDIR} sleep 1 exit 1 fi KBUILD_TARGET_CPU=$BUILD_TARGET_CPU fi # # Set default build type. # if test -z "$KBUILD_TYPE"; then KBUILD_TYPE=release fi test -n "$DBG_OPT" && echo "dbg: KBUILD_TYPE=$KBUILD_TYPE" 1>&${DBG_REDIR} # # Determin the host platform. # # The CPU isn't important, only the other two are. But, since the cpu, # arch and platform (and build type) share a common key space, try make # sure any new additions are unique. (See header.kmk, KBUILD_OSES/ARCHES.) # if test -z "$KBUILD_HOST"; then KBUILD_HOST=`uname` case "$KBUILD_HOST" in Darwin|darwin) KBUILD_HOST=darwin ;; DragonFly) KBUILD_HOST=dragonfly ;; freebsd|FreeBSD|FREEBSD) KBUILD_HOST=freebsd ;; GNU) KBUILD_HOST=gnuhurd ;; GNU/kFreeBSD) KBUILD_HOST=gnukfbsd ;; GNU/kNetBSD|GNU/NetBSD) KBUILD_HOST=gnuknbsd ;; Haiku) KBUILD_HOST=haiku ;; linux|Linux|GNU/Linux|LINUX) KBUILD_HOST=linux ;; netbsd|NetBSD|NETBSD) KBUILD_HOST=netbsd ;; openbsd|OpenBSD|OPENBSD) KBUILD_HOST=openbsd ;; os2|OS/2|OS2) KBUILD_HOST=os2 ;; SunOS) KBUILD_HOST=solaris ;; WindowsNT|CYGWIN_NT-*) KBUILD_HOST=win ;; *) echo "$0: unknown os $KBUILD_HOST" 1>&${ERR_REDIR} sleep 1 exit 1 ;; esac fi test -n "$DBG_OPT" && echo "dbg: KBUILD_HOST=$KBUILD_HOST" 1>&${DBG_REDIR} if test -z "$KBUILD_HOST_ARCH"; then # Try deduce it from the cpu if given. if test -n "$KBUILD_HOST_CPU"; then case "$KBUILD_HOST_CPU" in i[3456789]86) KBUILD_HOST_ARCH='x86' ;; k8|k8l|k9|k10) KBUILD_HOST_ARCH='amd64' ;; esac fi fi if test -z "$KBUILD_HOST_ARCH"; then # Use uname -m or isainfo (lots of guesses here, please help clean this up...) if test "$KBUILD_HOST" = "solaris"; then KBUILD_HOST_ARCH=`isainfo | cut -f 1 -d ' '` else KBUILD_HOST_ARCH=`uname -m` fi case "$KBUILD_HOST_ARCH" in x86_64|AMD64|amd64|k8|k8l|k9|k10) KBUILD_HOST_ARCH='amd64' # Try detect debian x32. if test "$KBUILD_HOST" = "linux"; then if test -z "${DEB_HOST_ARCH}"; then DEB_HOST_ARCH=`dpkg-architecture -qDEB_HOST_ARCH 2> /dev/null`; if test -z "${DEB_HOST_ARCH}"; then DEB_HOST_ARCH=`dpkg --print-architecture 2> /dev/null`; fi fi case "${DEB_HOST_ARCH}" in "x32") KBUILD_HOST_ARCH=x32 ;; "") case "`uname -v`" in *Debian*+x32+*) KBUILD_HOST_ARCH=x32 ;; esac ;; esac fi ;; x86|i86pc|ia32|i[3456789]86|BePC|i[3456789]86-AT[3456789]86) KBUILD_HOST_ARCH='x86' ;; alpha) KBUILD_HOST_ARCH='alpha' ;; aarch32|arm|arm1|arm2|arm3|arm6|armv1|armv2|armv3*|armv4*|armv5*|armv6*|armv7*) KBUILD_HOST_ARCH='arm32' ;; aarch64*) KBUILD_HOST_ARCH='arm64' ;; hppa32|parisc32|parisc) KBUILD_HOST_ARCH='hppa32' ;; hppa64|parisc64) KBUILD_HOST_ARCH='hppa64' ;; ia64) KBUILD_HOST_ARCH='ia64' ;; ppc32|ppc|powerpc) KBUILD_HOST_ARCH='ppc32' ;; ppc64|ppc64le|powerpc64|powerpc64le) KBUILD_HOST_ARCH='ppc64' ;; m68k) KBUILD_HOST_ARCH='m68k' ;; mips32|mips) KBUILD_HOST_ARCH='mips32' ;; mips64) KBUILD_HOST_ARCH='mips64' ;; s390) KBUILD_HOST_ARCH='s390' ;; s390x) KBUILD_HOST_ARCH='s390x' ;; sh|sh2|sh2a|sh3|sh3|sh4|sh4a|sh4al|sh4al-dsp|shmedia) KBUILD_HOST_ARCH='sh32' ;; sh64) KBUILD_HOST_ARCH='sh64' ;; sparc32|sparc|sparcv8|sparcv7|sparcv8e) KBUILD_HOST_ARCH='sparc32' ;; sparc64|sparcv9) KBUILD_HOST_ARCH='sparc64' ;; *) echo "$0: unknown cpu/arch - $KBUILD_HOST_ARCH" 1>&${ERR_REDIR} sleep 1 exit 1 ;; esac fi test -n "$DBG_OPT" && echo "dbg: KBUILD_HOST_ARCH=$KBUILD_HOST_ARCH" 1>&${DBG_REDIR} if test -z "$KBUILD_HOST_CPU"; then KBUILD_HOST_CPU="blend" fi test -n "$DBG_OPT" && echo "dbg: KBUILD_HOST_CPU=$KBUILD_HOST_CPU" 1>&${DBG_REDIR} # # The target platform. # Defaults to the host when not specified. # if test -z "$KBUILD_TARGET"; then KBUILD_TARGET="$KBUILD_HOST" fi test -n "$DBG_OPT" && echo "dbg: KBUILD_TARGET=$KBUILD_TARGET" 1>&${DBG_REDIR} if test -z "$KBUILD_TARGET_ARCH"; then KBUILD_TARGET_ARCH="$KBUILD_HOST_ARCH" fi test -n "$DBG_OPT" && echo "dbg: KBUILD_TARGET_ARCH=$KBUILD_TARGET_ARCH" 1>&${DBG_REDIR} if test -z "$KBUILD_TARGET_CPU"; then if test "$KBUILD_TARGET_ARCH" = "$KBUILD_HOST_ARCH"; then KBUILD_TARGET_CPU="$KBUILD_HOST_CPU" else KBUILD_TARGET_CPU="blend" fi fi test -n "$DBG_OPT" && echo "dbg: KBUILD_TARGET_CPU=$KBUILD_TARGET_CPU" 1>&${DBG_REDIR} # # Determin executable extension and path separator. # _SUFF_EXE= _PATH_SEP=":" case "$KBUILD_HOST" in os2|win|nt) _SUFF_EXE=".exe" _PATH_SEP=";" ;; esac # # Determin KBUILD_PATH from the script location and calc KBUILD_BIN_PATH from there. # if test -z "$KBUILD_PATH"; then KBUILD_PATH=`dirname "$0"` KBUILD_PATH=`cd "$KBUILD_PATH" ; /bin/pwd` fi if test ! -f "$KBUILD_PATH/footer.kmk" -o ! -f "$KBUILD_PATH/header.kmk" -o ! -f "$KBUILD_PATH/rules.kmk"; then echo "$0: error: KBUILD_PATH ($KBUILD_PATH) is not pointing to a popluated kBuild directory." 1>&${ERR_REDIR} sleep 1 exit 1 fi test -n "$DBG_OPT" && echo "dbg: KBUILD_PATH=$KBUILD_PATH" 1>&${DBG_REDIR} if test -z "$KBUILD_BIN_PATH"; then KBUILD_BIN_PATH="${KBUILD_PATH}/bin/${KBUILD_HOST}.${KBUILD_HOST_ARCH}" fi test -n "$DBG_OPT" && echo "dbg: KBUILD_BIN_PATH=${KBUILD_BIN_PATH}" 1>&${DBG_REDIR} # # Add the bin/x.y/ directory to the PATH. # NOTE! Once bootstrapped this is the only thing that is actually necessary. # PATH="${KBUILD_BIN_PATH}${_PATH_SEP}$PATH" test -n "$DBG_OPT" && echo "dbg: PATH=$PATH" 1>&${DBG_REDIR} # # Sanity and x bits. # if test ! -d "${KBUILD_BIN_PATH}/"; then echo "$0: warning: The bin directory for this platform doesn't exist. (${KBUILD_BIN_PATH}/)" 1>&${ERR_REDIR} else for prog in kmk kDepPre kDepIDB kmk_append kmk_ash kmk_cat kmk_cp kmk_echo kmk_install kmk_ln kmk_mkdir kmk_mv kmk_rm kmk_rmdir kmk_sed; do chmod a+x ${KBUILD_BIN_PATH}/${prog} > /dev/null 2>&1 if test ! -f "${KBUILD_BIN_PATH}/${prog}${_SUFF_EXE}"; then echo "$0: warning: The ${prog} program doesn't exist for this platform. (${KBUILD_BIN_PATH}/${prog}${_SUFF_EXE})" 1>&${ERR_REDIR} fi done fi # # The environment is in place, now take the requested action. # MY_RC=0 if test -n "${VAR_OPT}"; then # Echo variable values or variable export statements. for var in ${VAR_OPT}; do val= case "$var" in PATH) val=$PATH ;; KBUILD_PATH) val=$KBUILD_PATH ;; KBUILD_BIN_PATH) val=$KBUILD_BIN_PATH ;; KBUILD_HOST) val=$KBUILD_HOST ;; KBUILD_HOST_ARCH) val=$KBUILD_HOST_ARCH ;; KBUILD_HOST_CPU) val=$KBUILD_HOST_CPU ;; KBUILD_TARGET) val=$KBUILD_TARGET ;; KBUILD_TARGET_ARCH) val=$KBUILD_TARGET_ARCH ;; KBUILD_TARGET_CPU) val=$KBUILD_TARGET_CPU ;; KBUILD_TYPE) val=$KBUILD_TYPE ;; *) echo "$0: error: Unknown variable $var specified in --var request." 1>&${ERR_REDIR} sleep 1 exit 1 ;; esac if test -n "$EVAL_OPT"; then echo "${EVAL_EXPORT} $var=$val" else if test -n "$VALUE_ONLY_OPT"; then echo "$val" else echo "$var=$val" fi fi done else if test -n "$EVAL_OPT"; then # Echo statements for the shell to evaluate. test -n "$DBG_OPT" && echo "dbg: echoing exported variables" 1>&${DBG_REDIR} echo "${EVAL_EXPORT} PATH=${PATH}" test -n "${FULL_OPT}" -o "${EXP_TYPE_OPT}" && echo "${EVAL_EXPORT} KBUILD_TYPE=${KBUILD_TYPE}" if test -n "${FULL_OPT}"; then echo "${EVAL_EXPORT} KBUILD_PATH=${KBUILD_PATH}" if test -n "{FULL_WITH_BIN_OPT}"; then echo "${EVAL_EXPORT} KBUILD_BIN_PATH=${KBUILD_BIN_PATH}" fi echo "${EVAL_EXPORT} KBUILD_HOST=${KBUILD_HOST}" echo "${EVAL_EXPORT} KBUILD_HOST_ARCH=${KBUILD_HOST_ARCH}" echo "${EVAL_EXPORT} KBUILD_HOST_CPU=${KBUILD_HOST_CPU}" echo "${EVAL_EXPORT} KBUILD_TARGET=${KBUILD_TARGET}" echo "${EVAL_EXPORT} KBUILD_TARGET_ARCH=${KBUILD_TARGET_ARCH}" echo "${EVAL_EXPORT} KBUILD_TARGET_CPU=${KBUILD_TARGET_CPU}" if test -n "${LEGACY_OPT}"; then echo "${EVAL_EXPORT} PATH_KBUILD=${KBUILD_PATH}" if test -n "${FULL_WITH_BIN_OPT}"; then echo "${EVAL_EXPORT} PATH_KBUILD_BIN=${KBUILD_PATH_BIN}" fi echo "${EVAL_EXPORT} BUILD_TYPE=${KBUILD_TYPE}" echo "${EVAL_EXPORT} BUILD_PLATFORM=${KBUILD_HOST}" echo "${EVAL_EXPORT} BUILD_PLATFORM_ARCH=${KBUILD_HOST_ARCH}" echo "${EVAL_EXPORT} BUILD_PLATFORM_CPU=${KBUILD_HOST_CPU}" echo "${EVAL_EXPORT} BUILD_TARGET=${KBUILD_TARGET}" echo "${EVAL_EXPORT} BUILD_TARGET_ARCH=${KBUILD_TARGET_ARCH}" echo "${EVAL_EXPORT} BUILD_TARGET_CPU=${KBUILD_TARGET_CPU}" fi fi else # Export variables. export PATH test -n "${FULL_OPT}" -o "${EXP_TYPE_OPT}" && export KBUILD_TYPE if test -n "${FULL_OPT}"; then export KBUILD_PATH if test -n "${FULL_WITH_BIN_OPT}"; then export KBUILD_BIN_PATH fi export KBUILD_HOST export KBUILD_HOST_ARCH export KBUILD_HOST_CPU export KBUILD_TARGET export KBUILD_TARGET_ARCH export KBUILD_TARGET_CPU if test -n "${LEGACY_OPT}"; then export PATH_KBUILD=$KBUILD_PATH if test -n "${FULL_WITH_BIN_OPT}"; then export PATH_KBUILD_BIN=$KBUILD_BIN_PATH fi export BUILD_TYPE=$KBUILD_TYPE export BUILD_PLATFORM=$KBUILD_HOST export BUILD_PLATFORM_ARCH=$KBUILD_HOST_ARCH export BUILD_PLATFORM_CPU=$KBUILD_HOST_CPU export BUILD_TARGET=$KBUILD_TARGET export BUILD_TARGET_ARCH=$KBUILD_TARGET_ARCH export BUILD_TARGET_CPU=$KBUILD_TARGET_CPU fi fi # Execute command or spawn shell. if test $# -eq 0; then test -z "${QUIET_OPT}" && echo "$0: info: Spawning work shell..." 1>&${ERR_REDIR} if test "$TERM" != 'dumb' -a -n "$BASH"; then export PS1='\[\033[01;32m\]\u@\h \[\033[01;34m\]\W \$ \[\033[00m\]' fi $SHELL -i MY_RC=$? else test -z "${QUIET_OPT}" && echo "$0: info: Executing command: $*" 1>&${ERR_REDIR} $* MY_RC=$? test -z "${QUIET_OPT}" -a "$MY_RC" -ne 0 && echo "$0: info: rc=$MY_RC: $*" 1>&${ERR_REDIR} fi fi fi test -n "$DBG_OPT" && echo "dbg: finished (rc=$MY_RC)" 1>&${DBG_REDIR} exit $MY_RC kbuild-3149/kBuild/sdks/0000755000175000017500000000000013252530251015060 5ustar locutuslocutuskbuild-3149/kBuild/sdks/WIN64SDK.kmk0000644000175000017500000000724413252530251016744 0ustar locutuslocutus# $Id: WIN64SDK.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - The Windows Platform SDK, targeting AMD64. # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_WIN64SDK := The Windows Platform SDK, targeting AMD64. # SDK Specific Properties ifndef PATH_SDK_WIN64SDK PATH_SDK_WIN64SDK := $(wildcard $(PATH_DEVTOOLS)/win.amd64/sdk/2*) ifeq ($(PATH_SDK_WIN64SDK),) PATH_SDK_WIN64SDK := $(PATH_SDK_WINPSDK) endif ifeq ($(PATH_SDK_WIN64SDK),) PATH_SDK_WIN64SDK := $(wildcard $(PATH_DEVTOOLS)/win.x86/sdk/2*) endif ifneq ($(PATH_SDK_WIN64SDK),) PATH_SDK_WIN64SDK := $(lastword $(sort $(PATH_SDK_WIN64SDK))) else $(warning kBuild: PATH_SDK_WIN64SDK couldn't be determined!) PATH_SDK_WIN64SDK := $(PATH_DEVTOOLS)/win.amd64/sdk/not/found endif else # Resolve any fancy stuff once and for all. PATH_SDK_WIN64SDK := $(PATH_SDK_WIN64SDK) endif ifndef PATH_SDK_WIN64SDK_INC PATH_SDK_WIN64SDK_INC := $(firstword $(wildcard $(PATH_SDK_WIN64SDK)/[Ii][Nn][Cc][Ll][Uu][Dd][Ee]) $(PATH_SDK_WIN64SDK)/Include) endif ifndef PATH_SDK_WIN64SDK_LIB PATH_SDK_WIN64SDK_LIB := $(firstword $(wildcard $(PATH_SDK_WIN64SDK)/[Ll][Ii][Bb]/[Aa][Mm][Dd]64 $(PATH_SDK_WIN64SDK)/[Ll][Ii][Bb]/[xX]64) $(PATH_SDK_WIN64SDK)/Lib/AMD64) endif ifndef PATH_SDK_WIN64SDK_BIN PATH_SDK_WIN64SDK_BIN := $(firstword $(wildcard $(PATH_SDK_WIN64SDK)/[Bb][Ii][Nn]) $(PATH_SDK_WIN64SDK)/Bin) endif ifndef PATH_SDK_WIN64SDK_BIN_AMD64 PATH_SDK_WIN64SDK_BIN_AMD64 := $(firstword $(wildcard $(PATH_SDK_WIN64SDK_BIN)/[Ww][Ii][Nn]64/[Xx]86/[Aa][Mm][Dd]64 $(PATH_SDK_WIN64SDK_BIN)/[Ww][Ii][Nn]64/[Xx]86) $(PATH_SDK_WIN64SDK_BIN)/win64/AMD64) endif # General Properties used by kBuild SDK_WIN64SDK_INCS ?= $(PATH_SDK_WIN64SDK_INC) SDK_WIN64SDK_LIBPATH ?= $(PATH_SDK_WIN64SDK_LIB) SDK_WIN64SDK_LIBS ?= \ $(PATH_SDK_WIN64SDK_LIB)/Kernel32.Lib \ $(PATH_SDK_WIN64SDK_LIB)/User32.Lib \ $(PATH_SDK_WIN64SDK_LIB)/Gdi32.Lib \ $(PATH_SDK_WIN64SDK_LIB)/AdvAPI32.Lib \ $(PATH_SDK_WIN64SDK_LIB)/Shell32.Lib \ $(PATH_SDK_WIN64SDK_LIB)/ShLwApi.Lib \ $(PATH_SDK_WIN64SDK_LIB)/SetupAPI.Lib \ $(PATH_SDK_WIN64SDK_LIB)/Uuid.Lib \ $(PATH_SDK_WIN64SDK_LIB)/Version.Lib \ $(PATH_SDK_WIN64SDK_LIB)/WS2_32.Lib \ \ $(PATH_SDK_WIN64SDK_LIB)/Ole32.Lib \ $(PATH_SDK_WIN64SDK_LIB)/OleAut32.Lib \ $(PATH_SDK_WIN64SDK_LIB)/OleDlg.Lib \ $(PATH_SDK_WIN64SDK_LIB)/RpcRT4.Lib \ \ $(PATH_SDK_WIN64SDK_LIB)/DbgHelp.Lib \ $(PATH_SDK_WIN64SDK_LIB)/ImageHlp.Lib \ $(PATH_SDK_WIN64SDK_LIB)/IPHlpApi.Lib \ $(PATH_SDK_WIN64SDK_LIB)/ComCtl32.Lib \ $(PATH_SDK_WIN64SDK_LIB)/ComDlg32.Lib \ $(PATH_SDK_WIN64SDK_LIB)/WinSpool.Lib \ $(PATH_SDK_WIN64SDK_LIB)/WinMM.Lib kbuild-3149/kBuild/sdks/ReorderCompilerIncs.kmk0000644000175000017500000000465413252530250021506 0ustar locutuslocutus# $Id: ReorderCompilerIncs.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - Pseudo SDK that inserts the compiler includes a bit earlier. # # Note! This SDK is using a number of internal kBuild variables as well as # making assumptions about expansion order and location. # Please, do NOT attempt anything like this in your own SDKs!! # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_ReorderCompilerIncs := Pseudo SDK that inserts the compiler includes a bit earlier. FN_SDK_ReorderCompilerIncs_GET_INCS = \ $(TOOL_$(tool)_$(1)INCS.$(2).$(3).$(5)) \ $(TOOL_$(tool)_$(1)INCS.$(2).$(3)) \ $(TOOL_$(tool)_$(1)INCS.$(2).$(5)) \ $(TOOL_$(tool)_$(1)INCS.$(4)) \ $(TOOL_$(tool)_$(1)INCS.$(3)) \ $(TOOL_$(tool)_$(1)INCS.$(2)) \ $(TOOL_$(tool)_$(1)INCS.$(5)) \ $(TOOL_$(tool)_$(1)INCS) \ $(TOOL_$(tool)_INCS.$(2).$(3).$(5)) \ $(TOOL_$(tool)_INCS.$(2).$(3)) \ $(TOOL_$(tool)_INCS.$(2).$(5)) \ $(TOOL_$(tool)_INCS.$(4)) \ $(TOOL_$(tool)_INCS.$(3)) \ $(TOOL_$(tool)_INCS.$(2)) \ $(TOOL_$(tool)_INCS.$(5)) \ $(TOOL_$(tool)_INCS) \ $(foreach os,$(KBUILD_OSES),$(foreach arch,$(KBUILD_ARCHES),$(foreach cat,$(KBUILD_COMPILE_CATEGTORIES) \ ,$(eval SDK_ReorderCompilerIncs_$(cat)INCS.$(os).$(arch) = \ $$(call FN_SDK_ReorderCompilerIncs_GET_INCS,CXX,win,amd64,$$(bld_trg_cpu),$$(bld_type))\ )\ ))) kbuild-3149/kBuild/sdks/NT4DDK.kmk0000644000175000017500000000421213252530251016513 0ustar locutuslocutus# $Id: NT4DDK.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - The Windows NT 4 DDK, targeting X86. # # # Copyright (c) 2005-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_NT4DDK := The MicroSoft NT 4 DDK, targeting X86 (free, not checked). # SDK Specific Properties ifndef PATH_SDK_NT4DDK PATH_SDK_NT4DDK := $(wildcard $(PATH_DEVTOOLS)/win.x86/ddknt4/1* $(PATH_DEVTOOLS)/win.x86/ddknt4/2*) ifeq ($(PATH_SDK_NT4DDK),) PATH_SDK_NT4DDK := $(wildcard $(PATH_DEVTOOLS)/x86.win32/ddknt4) endif ifneq ($(PATH_SDK_NT4DDK),) PATH_SDK_NT4DDK := $(lastword $(sort $(PATH_SDK_NT4DDK))) else $(warning kBuild: PATH_SDK_NT4DDK couldn't be determined!) PATH_SDK_NT4DDK := $(PATH_DEVTOOLS)/x86.win/ddknt4/not/found endif else # Resolve any fancy stuff once and for all. PATH_SDK_NT4DDK := $(PATH_SDK_NT4DDK) endif PATH_SDK_NT4DDK_INC ?= $(PATH_SDK_NT4DDK)/inc PATH_SDK_NT4DDK_LIB ?= $(PATH_SDK_NT4DDK)/lib/i386/free # General Properties used by kBuild SDK_NT4DDK_DEFS ?= _X86_ SDK_NT4DDK_INCS ?= $(PATH_SDK_NT4DDK_INC) SDK_NT4DDK_LIBPATH ?= $(PATH_SDK_NT4DDK_LIB) kbuild-3149/kBuild/sdks/WINDDK80.kmk0000644000175000017500000001033713252530250016717 0ustar locutuslocutus# $Id: WINDDK80.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - The Microsoft Windows 8 DDK. # Defaults to $(KBUILD_TARGET_ARCH). Base SDK. # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_WINDDK80 := The Microsoft Windows 8 DDK. \ Defaults to $(KBUILD_TARGET_ARCH). Base SDK. # SDK Specific Properties ifndef PATH_SDK_WINDDK80 PATH_SDK_WINDDK80 := $(wildcard $(PATH_DEVTOOLS_TRG)/ddk/v8*) ifeq ($(PATH_SDK_WINDDK80),) PATH_SDK_WINDDK80 := $(wildcard $(PATH_DEVTOOLS)/win.x86/ddk/v8*) endif ifeq ($(PATH_SDK_WINDDK80),) PATH_SDK_WINDDK80 := $(wildcard $(PATH_DEVTOOLS)/win.amd64/ddk/v8*) endif ifneq ($(PATH_SDK_WINDDK80),) PATH_SDK_WINDDK80 := $(lastword $(sort $(PATH_SDK_WINDDK80))) else $(warning kBuild: PATH_SDK_WINDDK80 couldn't be determined!) PATH_SDK_WINDDK80 := $(PATH_DEVTOOLS)/win.x86/ddk/v8.0/not/found endif else # Resolve any fancy stuff once and for all. PATH_SDK_WINDDK80 := $(PATH_SDK_WINDDK80) endif PATH_SDK_WINDDK80_INC ?= $(PATH_SDK_WINDDK80)/Include PATH_SDK_WINDDK80_INC_UM ?= $(PATH_SDK_WINDDK80_INC)/um PATH_SDK_WINDDK80_INC_KM ?= $(PATH_SDK_WINDDK80_INC)/km PATH_SDK_WINDDK80_INC_KM_CRT ?= $(PATH_SDK_WINDDK80_INC_KM)/crt PATH_SDK_WINDDK80_INC_SHARED ?= $(PATH_SDK_WINDDK80_INC)/Shared PATH_SDK_WINDDK80_LIB_ROOT ?= $(PATH_SDK_WINDDK80)/Lib PATH_SDK_WINDDK80_LIB_W8_ROOT ?= $(PATH_SDK_WINDDK80_LIB_ROOT)/win8 PATH_SDK_WINDDK80_LIB_W7_ROOT ?= $(PATH_SDK_WINDDK80_LIB_ROOT)/win7 PATH_SDK_WINDDK80_LIB_WLH_ROOT ?= $(PATH_SDK_WINDDK80_LIB_ROOT)/wlh PATH_SDK_WINDDK80_LIB_WDF_ROOT ?= $(PATH_SDK_WINDDK80_LIB_ROOT)/wdf PATH_SDK_WINDDK80_LIB_MFC_ROOT ?= $(PATH_SDK_WINDDK80_LIB_ROOT)/Mfc PATH_SDK_WINDDK80_LIB_ATL_ROOT ?= $(PATH_SDK_WINDDK80_LIB_ROOT)/Atl PATH_SDK_WINDDK80_LIB_W8.amd64 ?= $(PATH_SDK_WINDDK80_LIB_W8_ROOT)/km/x64 PATH_SDK_WINDDK80_LIB_W8.x86 ?= $(PATH_SDK_WINDDK80_LIB_W8_ROOT)/km/x86 PATH_SDK_WINDDK80_LIB_W8 ?= $(PATH_SDK_WINDDK80_LIB_W8.$(KBUILD_TARGET_ARCH)) PATH_SDK_WINDDK80_LIB_W7.amd64 ?= $(PATH_SDK_WINDDK80_LIB_W7_ROOT)/km/x64 PATH_SDK_WINDDK80_LIB_W7.x86 ?= $(PATH_SDK_WINDDK80_LIB_W7_ROOT)/km/x86 PATH_SDK_WINDDK80_LIB_W7 ?= $(PATH_SDK_WINDDK80_LIB_W7.$(KBUILD_TARGET_ARCH)) PATH_SDK_WINDDK80_LIB_WLH.amd64 ?= $(PATH_SDK_WINDDK80_LIB_WLH_ROOT)/km/x64 PATH_SDK_WINDDK80_LIB_WLH.x86 ?= $(PATH_SDK_WINDDK80_LIB_WLH_ROOT)/km/x86 PATH_SDK_WINDDK80_LIB_WLH ?= $(PATH_SDK_WINDDK80_LIB_WLH.$(KBUILD_TARGET_ARCH)) PATH_SDK_WINDDK80_LIB.amd64 ?= $(PATH_SDK_WINDDK80_LIB_WLH.amd64) PATH_SDK_WINDDK80_LIB.x86 ?= $(PATH_SDK_WINDDK80_LIB_WLH.x86) PATH_SDK_WINDDK80_LIB ?= $(PATH_SDK_WINDDK80_LIB.$(KBUILD_TARGET_ARCH)) # General Properties used by kBuild SDK_WINDDK80_DEFS.amd64 ?= _AMD64_ AMD64 _WIN64 SDK_WINDDK80_DEFS.x86 ?= _X86_=1 i386=1 STD_CALL SDK_WINDDK80_INCS ?= \ $(PATH_SDK_WINDDK80_INC_KM) \ $(PATH_SDK_WINDDK80_INC_UM) \ $(PATH_SDK_WINDDK80_INC_SHARED) \ # The compiler tool(s) will have to select the appropriate crt includes. SDK_WINDDK80_LIBPATH.amd64 ?= $(PATH_SDK_WINDDK80_LIB_WLH.amd64) SDK_WINDDK80_LIBPATH.x86 ?= $(PATH_SDK_WINDDK80_LIB_WLH.x86) kbuild-3149/kBuild/sdks/WINDDK71WLH.kmk0000644000175000017500000000426513252530251017276 0ustar locutuslocutus# $Id: WINDDK71WLH.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - The Microsoft Windows 7 DDKs, v7.1, Targeting Vista and 2008 (KBUILD_TARGET_ARCH). # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_WINDDK71WLH := The Microsoft Windows 7 DDKs, v7.1, Targeting Vista and 2008 (KBUILD_TARGET_ARCH). SDK_WINDDK71WLH_EXTENDS = WINDDK71 SDK_WINDDK71WLH_DEFS ?= WIN32=100 _WIN32_WINNT=0x0600 WINVER=0x0600 _WIN32_IE=0x0700 NTDDI_VERSION=0x06000000 KMDF_MAJOR_VERSION=01 KMDF_MINOR_VERSION=005 SDK_WINDDK71WLH_LIBPATH.amd64 ?= $(PATH_SDK_WINDDK71_LIB_WLH.amd64) SDK_WINDDK71WLH_LIBPATH.ia64 ?= $(PATH_SDK_WINDDK71_LIB_WLH.ia64) SDK_WINDDK71WLH_LIBPATH.x86 ?= $(PATH_SDK_WINDDK71_LIB_WLH.x86) # SDK Specific Properties. # Note! extends the WINDDK71 sdk, so use those variables where ever possible PATH_SDK_WINDDK71WLH_LIB.amd64?= $(PATH_SDK_WINDDK71_LIB_WLH.amd64) PATH_SDK_WINDDK71WLH_LIB.ia64 ?= $(PATH_SDK_WINDDK71_LIB_WLH.ia64) PATH_SDK_WINDDK71WLH_LIB.x86 ?= $(PATH_SDK_WINDDK71_LIB_WLH.x86) PATH_SDK_WINDDK71WLH_LIB ?= $(PATH_SDK_WINDDK71WLH_LIB.$(KBUILD_TARGET_ARCH)) kbuild-3149/kBuild/sdks/WINDDK.kmk0000644000175000017500000001742413252530250016553 0ustar locutuslocutus# $Id: WINDDK.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - The Microsoft Windows Vista and Server 2008 DDKs. # Defaults to $(KBUILD_TARGET_ARCH). Base SDK. # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_WINDDK := The Microsoft Windows Vista and Server 2008 DDKs. \ Defaults to $(KBUILD_TARGET_ARCH). Base SDK. # SDK Specific Properties ifndef PATH_SDK_WINDDK PATH_SDK_WINDDK := $(wildcard $(PATH_DEVTOOLS_TRG)/ddk/6*) ifeq ($(PATH_SDK_WINDDK),) PATH_SDK_WINDDK := $(wildcard $(PATH_DEVTOOLS)/win.x86/ddk/6*) endif ifeq ($(PATH_SDK_WINDDK),) PATH_SDK_WINDDK := $(wildcard $(PATH_DEVTOOLS)/win.amd64/ddk/6*) endif ifeq ($(PATH_SDK_WINDDK),) ifeq ($(KBUILD_HOST),win) PATH_SDK_WINDDK := $(wildcard C:/WinDDK/6*) endif endif ifneq ($(PATH_SDK_WINDDK),) PATH_SDK_WINDDK := $(lastword $(sort $(PATH_SDK_WINDDK))) else $(warning kBuild: PATH_SDK_WINDDK couldn't be determined!) PATH_SDK_WINDDK := $(PATH_DEVTOOLS)/win.x86/ddk/not/found endif else # Resolve any fancy stuff once and for all. PATH_SDK_WINDDK := $(PATH_SDK_WINDDK) endif PATH_SDK_WINDDK_INC ?= $(PATH_SDK_WINDDK)/inc PATH_SDK_WINDDK_INC_API ?= $(PATH_SDK_WINDDK_INC)/api PATH_SDK_WINDDK_INC_CRT ?= $(PATH_SDK_WINDDK_INC)/crt PATH_SDK_WINDDK_INC_DDK ?= $(PATH_SDK_WINDDK_INC)/ddk PATH_SDK_WINDDK_LIB_ROOT ?= $(PATH_SDK_WINDDK)/lib PATH_SDK_WINDDK_LIB_WLH_ROOT ?= $(PATH_SDK_WINDDK_LIB_ROOT)/wlh PATH_SDK_WINDDK_LIB_WNET_ROOT ?= $(PATH_SDK_WINDDK_LIB_ROOT)/wnet PATH_SDK_WINDDK_LIB_WXP_ROOT ?= $(PATH_SDK_WINDDK_LIB_ROOT)/wxp PATH_SDK_WINDDK_LIB_W2K_ROOT ?= $(PATH_SDK_WINDDK_LIB_ROOT)/w2k PATH_SDK_WINDDK_LIB_WDF_ROOT ?= $(PATH_SDK_WINDDK_LIB_ROOT)/w2k PATH_SDK_WINDDK_LIB_WLH.amd64 ?= $(PATH_SDK_WINDDK_LIB_WLH_ROOT)/amd64 PATH_SDK_WINDDK_LIB_WLH.ia64 ?= $(PATH_SDK_WINDDK_LIB_WLH_ROOT)/ia64 PATH_SDK_WINDDK_LIB_WLH.x86 ?= $(PATH_SDK_WINDDK_LIB_WLH_ROOT)/i386 PATH_SDK_WINDDK_LIB_WLH ?= $(PATH_SDK_WINDDK_LIB_WLH.$(KBUILD_TARGET_ARCH)) PATH_SDK_WINDDK_LIB_WNET.amd64?= $(PATH_SDK_WINDDK_LIB_WNET_ROOT)/amd64 PATH_SDK_WINDDK_LIB_WNET.ia64 ?= $(PATH_SDK_WINDDK_LIB_WNET_ROOT)/ia64 PATH_SDK_WINDDK_LIB_WNET.x86 ?= $(PATH_SDK_WINDDK_LIB_WNET_ROOT)/i386 PATH_SDK_WINDDK_LIB_WNET ?= $(PATH_SDK_WINDDK_LIB_WNET.$(KBUILD_TARGET_ARCH)) PATH_SDK_WINDDK_LIB_WXP.x86 ?= $(PATH_SDK_WINDDK_LIB_WXP_ROOT)/i386 PATH_SDK_WINDDK_LIB_WXP ?= $(PATH_SDK_WINDDK_LIB_WXP.$(KBUILD_TARGET_ARCH)) PATH_SDK_WINDDK_LIB_W2K.x86 ?= $(PATH_SDK_WINDDK_LIB_W2K_ROOT)/i386 PATH_SDK_WINDDK_LIB_W2K ?= $(PATH_SDK_WINDDK_LIB_W2K.$(KBUILD_TARGET_ARCH)) PATH_SDK_WINDDK_LIB.amd64 ?= $(PATH_SDK_WINDDK_LIB_WLH.amd64) PATH_SDK_WINDDK_LIB.ia64 ?= $(PATH_SDK_WINDDK_LIB_WLH.ia64) PATH_SDK_WINDDK_LIB.x86 ?= $(PATH_SDK_WINDDK_LIB_WLH.x86) PATH_SDK_WINDDK_LIB ?= $(PATH_SDK_WINDDK_LIB.$(KBUILD_TARGET_ARCH)) # General Properties used by kBuild SDK_WINDDK_DEFS.amd64 ?= _AMD64_ AMD64 _WIN64 SDK_WINDDK_DEFS.ia64 ?= _IA64_=1 IA64=1 _WIN64 _MSC_EXTENSIONS SDK_WINDDK_DEFS.x86 ?= _X86_=1 i386=1 STD_CALL SDK_WINDDK_INCS ?= \ $(PATH_SDK_WINDDK_INC_API) \ $(PATH_SDK_WINDDK_INC_DDK) # The compiler tool(s) will have to select the appropriate crt includes. SDK_WINDDK_LIBPATH.amd64 ?= $(PATH_SDK_WINDDK_LIB_WLH.amd64) SDK_WINDDK_LIBPATH.ia64 ?= $(PATH_SDK_WINDDK_LIB_WLH.ia64) SDK_WINDDK_LIBPATH.x86 ?= $(PATH_SDK_WINDDK_LIB_WLH.x86) # # CDFS defines for the various build environments. Just to give an idea what # you should put in your templates and target DEFS. # # Vista / Server Longhorn x64 Free: NT_INST=0 WIN32=100 _WIN32_WINNT=0x0600 WINVER=0x0600 _WIN32_IE=0x0700 NTDDI_VERSION=0x06000000 KMDF_MAJOR_VERSION=01 KMDF_MINOR_VERSION=005 WIN32_LEAN_AND_MEAN=1 CONDITION_HANDLING=1 DEVL=1 NDEBUG __BUILDMACHINE__=WinDDK _DLL # Vista / Server Longhorn ia64 Free: NT_INST=0 WIN32=100 _WIN32_WINNT=0x0600 WINVER=0x0600 _WIN32_IE=0x0700 NTDDI_VERSION=0x06000000 KMDF_MAJOR_VERSION=01 KMDF_MINOR_VERSION=005 WIN32_LEAN_AND_MEAN=1 CONDITION_HANDLING=1 DEVL=1 NDEBUG __BUILDMACHINE__=WinDDK _DLL NO_HW_DETECT _MSC_EXTENSIONS _MERCED_A0_=1 FPO=0 # Vista / Server Longhorn x86 Free: NT_INST=0 WIN32=100 _WIN32_WINNT=0x0600 WINVER=0x0600 _WIN32_IE=0x0700 NTDDI_VERSION=0x06000000 KMDF_MAJOR_VERSION=01 KMDF_MINOR_VERSION=005 WIN32_LEAN_AND_MEAN=1 CONDITION_HANDLING=1 DEVL=1 NDEBUG __BUILDMACHINE__=WinDDK _DLL STD_CALL FPO=0 # Windows Server 2003 amd64 Free: NT_INST=0 WIN32=100 _WIN32_WINNT=0x0502 WINVER=0x0502 _WIN32_IE=0x0603 NTDDI_VERSION=0x05020100 KMDF_MAJOR_VERSION=01 KMDF_MINOR_VERSION=005 WIN32_LEAN_AND_MEAN=1 CONDITION_HANDLING=1 DEVL=1 NDEBUG __BUILDMACHINE__=WinDDK _DLL # Windows Server 2003 ia64 Free: NT_INST=0 WIN32=100 _WIN32_WINNT=0x0502 WINVER=0x0502 _WIN32_IE=0x0603 NTDDI_VERSION=0x05020100 KMDF_MAJOR_VERSION=01 KMDF_MINOR_VERSION=005 WIN32_LEAN_AND_MEAN=1 CONDITION_HANDLING=1 DEVL=1 NDEBUG __BUILDMACHINE__=WinDDK _DLL NO_HW_DETECT _MSC_EXTENSIONS _MERCED_A0_=1 FPO=0 # Windows Server 2003 x86 Free: NT_INST=0 WIN32=100 _WIN32_WINNT=0x0502 WINVER=0x0502 _WIN32_IE=0x0603 NTDDI_VERSION=0x05020100 KMDF_MAJOR_VERSION=01 KMDF_MINOR_VERSION=005 WIN32_LEAN_AND_MEAN=1 CONDITION_HANDLING=1 DEVL=1 NDEBUG __BUILDMACHINE__=WinDDK _DLL STD_CALL FPO=0 # Windows XP Free: NT_INST=0 WIN32=100 _WIN32_WINNT=0x0501 WINVER=0x0501 _WIN32_IE=0x0603 NTDDI_VERSION=0x05010200 KMDF_MAJOR_VERSION=01 KMDF_MINOR_VERSION=005 WIN32_LEAN_AND_MEAN=1 CONDITION_HANDLING=1 DEVL=1 NDEBUG __BUILDMACHINE__=WinDDK _DLL STD_CALL FPO=0 # Windows 2000 Free: NT_INST=0 WIN32=100 _WIN32_WINNT=0x0500 WINVER=0x0500 _WIN32_IE=0x0501 NTDDI_VERSION=0x05000400 KMDF_MAJOR_VERSION=01 KMDF_MINOR_VERSION=005 WIN32_LEAN_AND_MEAN=1 CONDITION_HANDLING=1 DEVL=1 NDEBUG __BUILDMACHINE__=WinDDK _DLL STD_CALL FPO=0 # Windows 2000 Checked: NT_INST=0 WIN32=100 _WIN32_WINNT=0x0500 WINVER=0x0500 _WIN32_IE=0x0501 NTDDI_VERSION=0x05000400 KMDF_MAJOR_VERSION=01 KMDF_MINOR_VERSION=005 WIN32_LEAN_AND_MEAN=1 CONDITION_HANDLING=1 DEVL=1 NDEBUG __BUILDMACHINE__=WinDDK _DLL STD_CALL FPO=0 MSC_NOOPT # Some notes about the defines: # NTDDI_VERSION indicates the target NT version, looks kind of important to get right. # _WIN32_WINNT, WINVER and _WIN32_IE are used by a bunch of headers for selecting features. # WIN32_LEAN_AND_MEAN is used by api\WINDOWS.H to drop a bunch of includes. # WIN32 is just used for some ifdef'ing by a handful headers. # __BUILDMACHINE__ is used by api\common.ver (for resources it seems). # STD_CALL is used by ddk\stdcall.inc (masm). # DEVL governs the IF_NTOS_DEBUG() macro in ddk\wdm.h. # NDEBUG is used by crt\assert.h dictated by the standards. # CONDITION_HANDLING, FPO, KMDF_MAJOR_VERSION, KMDF_MINOR_VERSION, MSC_NOOPT and NT_INST are not referenced in any headers. kbuild-3149/kBuild/sdks/MACOSX105INCS.kmk0000644000175000017500000000333313252530250017462 0ustar locutuslocutus# $Id: MACOSX105INCS.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - Mac OS X v10.5 SDK, includes only. # # # Copyright (c) 2008-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_MACOSX105INCS := Mac OS X v10.5 SDK # SDK Specific Properties ifndef PATH_SDK_MACOSX105INCS ifdef PATH_SDK_MACOSX105 PATH_SDK_MACOSX105INCS := $(PATH_SDK_MACOSX105) else PATH_SDK_MACOSX105INCS := /Developer/SDKs/MacOSX10.5.sdk endif else # Resolve any fancy stuff once and for all. PATH_SDK_MACOSX105INCS := $(PATH_SDK_MACOSX105INCS) endif # General Properties (used by kBuild) SDK_MACOSX105INCS_INCS = $(PATH_SDK_MACOSX105INCS)/usr/include kbuild-3149/kBuild/sdks/LIBSDL.kmk0000644000175000017500000001357713252530250016551 0ustar locutuslocutus# $Id: LIBSDL.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - Simple DirectMedia Layer, targeting $(KBUILD_TARGET). # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_LIBSDL := Simple DirectMedia Layer, targeting $(KBUILD_TARGET). # SDK Specific Properties _SDK_LIBSDK_IS_FRAMEWORK := no ifndef PATH_SDK_LIBSDL PATH_SDK_LIBSDL := $(wildcard $(PATH_DEVTOOLS_TRG)/libsdl/v*) ifeq ($(PATH_SDK_LIBSDL),) PATH_SDK_LIBSDL := $(wildcard $(PATH_DEVTOOLS_BLD)/libsdl/v*) endif ifneq ($(PATH_SDK_LIBSDL),) PATH_SDK_LIBSDL := $(lastword $(sort $(PATH_SDK_LIBSDL))) else # Darwin might have a framework for it. ifeq ($(KBUILD_TARGET),darwin) PATH_SDK_LIBSDL := $(firstword $(wildcard \ /System/Library/Frameworks/SDL.framework/SDL \ /Library/Frameworks/SDL.framework/SDL \ ) ) ifneq ($(PATH_SDK_LIBSDL),) PATH_SDK_LIBSDL := $(patsubst %/,%,$(dir $(PATH_SDK_LIBSDL))) _SDK_LIBSDK_IS_FRAMEWORK := yes endif endif ifeq ($(PATH_SDK_LIBSDL),) PATH_SDK_LIBSDL := $(firstword $(foreach root,$(KBUILD_LIB_SEARCH_ROOTS) \ ,$(if $(wildcard $(addsuffix libSDL.*,$(addprefix $(root),$(KBUILD_LIB_SEARCH_SUBS)))),$(root),) )) ifeq ($(PATH_SDK_LIBSDL),/) PATH_SDK_LIBSDL := /. else ifneq ($(PATH_SDK_LIBSDL),) PATH_SDK_LIBSDL := $(patsubst %/,%,$(PATH_SDK_LIBSDL)) else $(warning kBuild: PATH_SDK_LIBSDL couldn't be determined!) PATH_SDK_LIBSDL := $(PATH_DEVTOOLS_TRG)/libsdl/not/found endif endif endif else PATH_SDK_LIBSDL := $(PATH_SDK_LIBSDL) ifeq ($(KBUILD_TARGET),darwin) # Check if it's the framework or not. _SDK_LIBSDK_IS_FRAMEWORK := $(if $(wildcard $(PATH_SDK_LIBSDL)/Headers/SDL.h),yes) endif endif # # The way libsdl is distributed on the different platforms # varies quite a bit, thus this kludge. # ifeq ($(KBUILD_TARGET),os2) LIB_SDK_LIBSDL_SDLMAIN ?= DLL_SDK_LIBSDL_SDL ?= $(PATH_SDK_LIBSDL)/SDL/SDL12.dll DLL_SDK_LIBSDL_FSLIB ?= $(PATH_SDK_LIBSDL)/SDL/FSLib.dll LIB_SDK_LIBSDL_SDL ?= $(PATH_SDK_LIBSDL)/SDL/SDL12.lib LIB_SDK_LIBSDL_SDLGFX ?= $(PATH_SDK_LIBSDL)/SDLGfx/SDLGFX.lib LIB_SDK_LIBSDL_SDLIMAGE ?= $(PATH_SDK_LIBSDL)/SDLImage/SDLIMAGE.lib LIB_SDK_LIBSDL_SDLMIXER ?= $(PATH_SDK_LIBSDL)/SDLMixer/SDLMIXER.lib LIB_SDK_LIBSDL_SDLNET ?= $(PATH_SDK_LIBSDL)/SDLNet/SDLNET.lib LIB_SDK_LIBSDL_SDLTTF ?= $(PATH_SDK_LIBSDL)/SDLTTF/SDLTTF.lib # General Properties used by kBuild SDK_LIBSDL_INCS ?= \ $(PATH_SDK_LIBSDL)/SDL/include \ $(PATH_SDK_LIBSDL)/SDLGfx \ $(PATH_SDK_LIBSDL)/SDLImage \ $(PATH_SDK_LIBSDL)/SDLMixer \ $(PATH_SDK_LIBSDL)/SDLNet \ $(PATH_SDK_LIBSDL)/SDLTTF SDK_LIBSDL_LIBS ?= \ $(LIB_SDK_LIBSDL_SDL) SDK_LIBSDL_LIBPATH ?= \ $(PATH_SDK_LIBSDL)/SDL \ $(PATH_SDK_LIBSDL)/SDLGfx \ $(PATH_SDK_LIBSDL)/SDLImage \ $(PATH_SDK_LIBSDL)/SDLMixer \ $(PATH_SDK_LIBSDL)/SDLNet \ $(PATH_SDK_LIBSDL)/SDLTTF else ifeq ($(KBUILD_TARGET),win) # ASSUMES VC++ on windows, sorry. LIB_SDK_LIBSDL_SDLMAIN ?= $(PATH_SDK_LIBSDL)/lib/SDLmain.lib LIB_SDK_LIBSDL_SDL ?= $(PATH_SDK_LIBSDL)/lib/SDL.lib DLL_SDK_LIBSDL_SDL ?= $(PATH_SDK_LIBSDL)/lib/SDL.dll LIB_SDK_LIBSDL_SDLGFX ?= $(PATH_SDK_LIBSDL)/lib/SDL_gfx.lib LIB_SDK_LIBSDL_SDLIMAGE ?= $(PATH_SDK_LIBSDL)/lib/SDL_image.lib LIB_SDK_LIBSDL_SDLMIXER ?= $(PATH_SDK_LIBSDL)/lib/SDL_mixer.lib LIB_SDK_LIBSDL_SDLNET ?= $(PATH_SDK_LIBSDL)/lib/SDL_net.lib LIB_SDK_LIBSDL_SDLTTF ?= $(PATH_SDK_LIBSDL)/lib/SDL_ttf.lib DLL_SDK_LIBSDL_SDLTTF ?= $(PATH_SDK_LIBSDL)/lib/SDL_ttf.dll # General Properties used by kBuild SDK_LIBSDL_INCS ?= \ $(PATH_SDK_LIBSDL)/include/SDL \ $(PATH_SDK_LIBSDL)/include SDK_LIBSDL_LIBS ?= \ $(LIB_SDK_LIBSDL_SDL) SDK_LIBSDL_LIBPATH ?= \ $(PATH_SDK_LIBSDL)/lib else ifeq ($(KBUILD_TARGET).$(_SDK_LIBSDK_IS_FRAMEWORK),darwin.yes) # darwin + framework LIB_SDK_LIBSDL_SDLMAIN ?= $(NO_SUCH_VARIABLE) LIB_SDK_LIBSDL_SDL ?= $(NO_SUCH_VARIABLE) LIB_SDK_LIBSDL_SDLGFX ?= $(NO_SUCH_VARIABLE) LIB_SDK_LIBSDL_SDLIMAGE ?= $(NO_SUCH_VARIABLE) LIB_SDK_LIBSDL_SDLMIXER ?= $(NO_SUCH_VARIABLE) LIB_SDK_LIBSDL_SDLNET ?= $(NO_SUCH_VARIABLE) LIB_SDK_LIBSDL_SDLTTF ?= $(NO_SUCH_VARIABLE) # General Properties used by kBuild SDK_LIBSDL_INCS ?= $(PATH_SDK_LIBSDL)/Headers SDK_LIBSDL_LDFLAGS ?= -framework SDL else # ASSUMES Unix like system LIB_SDK_LIBSDL_SDLMAIN ?= SDLmain LIB_SDK_LIBSDL_SDL ?= SDL LIB_SDK_LIBSDL_SDLGFX ?= SDL_gfx LIB_SDK_LIBSDL_SDLIMAGE ?= SDL_image LIB_SDK_LIBSDL_SDLMIXER ?= SDL_mixer LIB_SDK_LIBSDL_SDLNET ?= SDL_net LIB_SDK_LIBSDL_SDLTTF ?= SDL_ttf # General Properties used by kBuild ifndef SDK_LIBSDL_INCS ifneq ($(wildcard $(PATH_SDK_LIBSDL)/include/SDL/),) SDK_LIBSDL_INCS := $(PATH_SDK_LIBSDL)/include/SDL else SDK_LIBSDL_INCS := $(PATH_SDK_LIBSDL)/include endif endif SDK_LIBSDL_LIBS ?= \ $(LIB_SDK_LIBSDL_SDL) SDK_LIBSDL_LIBPATH ?= \ $(PATH_SDK_LIBSDL)/lib endif kbuild-3149/kBuild/sdks/DXSDKAMD64.kmk0000644000175000017500000000435613252530251017145 0ustar locutuslocutus# $Id: DXSDKAMD64.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - The Microsoft Direct X SDK, targeting AMD64. # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_DXSDKAMD64 := The Microsoft Direct X SDK, targeting AMD64. # SDK Specific Properties ifndef PATH_SDK_DXSDKAMD64 PATH_SDK_DXSDKAMD64 := $(wildcard $(PATH_DEVTOOLS)/win.amd64/dxsdk/2*) ifeq ($(PATH_SDK_DXSDKAMD64),) PATH_SDK_DXSDKAMD64 := $(PATH_SDK_DXSDK) endif ifeq ($(PATH_SDK_DXSDKAMD64),) PATH_SDK_DXSDKAMD64 := $(wildcard $(PATH_DEVTOOLS)/win.x86/dxsdk/2*) endif ifneq ($(PATH_SDK_DXSDKAMD64),) PATH_SDK_DXSDKAMD64 := $(lastword $(sort $(PATH_SDK_DXSDKAMD64))) else $(warning kBuild: PATH_SDK_DXSDKAMD64 couldn't be determined!) PATH_SDK_DXSDKAMD64 := $(PATH_DEVTOOLS)/win.amd64/dxsdk/not/found endif else # Resolve any fancy stuff once and for all. PATH_SDK_DXSDKAMD64 := $(PATH_SDK_DXSDKAMD64) endif PATH_SDK_DXSDKAMD64_INC ?= $(PATH_SDK_DXSDKAMD64)/Include PATH_SDK_DXSDKAMD64_LIB ?= $(PATH_SDK_DXSDKAMD64)/Lib/x64 # General Properties used by kBuild SDK_DXSDKAMD64_INCS ?= $(PATH_SDK_DXSDKAMD64_INC) SDK_DXSDKAMD64_LIBPATH ?= $(PATH_SDK_DXSDKAMD64_LIB) kbuild-3149/kBuild/sdks/WINDDK71WXP.kmk0000644000175000017500000000350013252530250017310 0ustar locutuslocutus# $Id: WINDDK71WXP.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - The Microsoft Windows 7 DDK, v7.1, Targeting Windows XP (x86). # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_WINDDK71WXP := The Microsoft Windows 7 DDK, v7.1, Targeting Windows XP (x86). SDK_WINDDK71WXP_EXTENDS = WINDDK71 SDK_WINDDK71WXP_DEFS ?= WIN32=100 _WIN32_WINNT=0x0501 WINVER=0x0501 _WIN32_IE=0x0603 NTDDI_VERSION=0x05010200 SDK_WINDDK71WXP_LIBPATH.x86 ?= $(PATH_SDK_WINDDK71_LIB_WXP.x86) # SDK Specific Properties. # Note! extends the WINDDK71 sdk, so use those variables where ever possible PATH_SDK_WINDDK71WXP_LIB.x86 ?= $(PATH_SDK_WINDDK71_LIB_WXP.x86) PATH_SDK_WINDDK71WXP_LIB ?= $(PATH_SDK_WINDDK71WXP_LIB.x86) kbuild-3149/kBuild/sdks/W2K3DDK.kmk0000644000175000017500000000577613252530250016613 0ustar locutuslocutus# $Id: W2K3DDK.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - The Microsoft Windows 2003 DDK, targeting $(KBUILD_TARGET). # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_W2K3DDK := The Microsoft Windows 2003 DDK, targeting $(KBUILD_TARGET). # SDK Specific Properties ifndef PATH_SDK_W2K3DDK PATH_SDK_W2K3DDK := $(wildcard $(PATH_DEVTOOLS_TRG)/ddkwin2k3/2*) ifeq ($(PATH_SDK_W2K3DDK),) PATH_SDK_W2K3DDK := $(wildcard $(PATH_DEVTOOLS_BLD)/ddkwin2k3/2*) endif ifeq ($(PATH_SDK_W2K3DDK),) PATH_SDK_W2K3DDK := $(wildcard $(PATH_DEVTOOLS)/win.x86/ddkwin2k3/2*) endif ifeq ($(PATH_SDK_W2K3DDK),) PATH_SDK_W2K3DDK := $(wildcard $(PATH_DEVTOOLS)/win.amd64/ddkwin2k3/2*) endif ifeq ($(PATH_SDK_W2K3DDK),) PATH_SDK_W2K3DDK := $(wildcard $(PATH_DEVTOOLS)/x86.win32/ddkwin2k3/2*) endif ifeq ($(PATH_SDK_W2K3DDK),) ifneq ($(wildcard $(PATH_DEVTOOLS)/x86.win32/ddkwin2k3/lib/wnet/i386/*.lib),) PATH_SDK_W2K3DDK := $(PATH_DEVTOOLS)/x86.win32/ddkwin2k3 endif endif ifneq ($(PATH_SDK_W2K3DDK),) PATH_SDK_W2K3DDK := $(lastword $(sort $(PATH_SDK_W2K3DDK))) else $(warning kBuild: PATH_SDK_W2K3DDK couldn't be determined!) PATH_SDK_W2K3DDK := $(PATH_DEVTOOLS)/win.x86/ddkwin2k3/not/found endif else # Resolve any fancy stuff once and for all. PATH_SDK_W2K3DDK := $(PATH_SDK_W2K3DDK) endif PATH_SDK_W2K3DDK_INC ?= $(PATH_SDK_W2K3DDK)/inc PATH_SDK_W2K3DDK_LIB.amd64 ?= $(PATH_SDK_W2K3DDK)/lib/wnet/AMD64 PATH_SDK_W2K3DDK_LIB.x86 ?= $(PATH_SDK_W2K3DDK)/lib/wnet/i386 PATH_SDK_W2K3DDK_LIB ?= $(PATH_SDK_W2K3DDK_LIB.$(KBUILD_TARGET_ARCH)) # General Properties used by kBuild SDK_W2K3DDK_DEFS.amd64 ?= _AMD64_ SDK_W2K3DDK_DEFS.x86 ?= _X86_ SDK_W2K3DDK_INCS ?= \ $(PATH_SDK_W2K3DDK_INC)/ddk \ $(PATH_SDK_W2K3DDK_INC)/ddk/wnet \ $(PATH_SDK_W2K3DDK_INC)/wnet \ $(PATH_SDK_W2K3DDK_INC)/ddk/wdm/wnet SDK_W2K3DDK_LIBPATH.amd64 ?= $(PATH_SDK_W2K3DDK_LIB.amd64) SDK_W2K3DDK_LIBPATH.x86 ?= $(PATH_SDK_W2K3DDK_LIB.x86) kbuild-3149/kBuild/sdks/WINDDK71.kmk0000644000175000017500000001120213252530250016707 0ustar locutuslocutus# $Id: WINDDK71.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - The Microsoft Windows 7 DDK, v7.1. # Defaults to $(KBUILD_TARGET_ARCH). Base SDK. # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_WINDDK71 := The Microsoft Windows 7 DDK, v7.1. \ Defaults to $(KBUILD_TARGET_ARCH). Base SDK. # SDK Specific Properties ifndef PATH_SDK_WINDDK71 PATH_SDK_WINDDK71 := $(wildcard $(PATH_DEVTOOLS_TRG)/ddk/7600.16385.1*) ifeq ($(PATH_SDK_WINDDK71),) PATH_SDK_WINDDK71 := $(wildcard $(PATH_DEVTOOLS)/win.x86/ddk/7600.16385.1*) endif ifeq ($(PATH_SDK_WINDDK71),) PATH_SDK_WINDDK71 := $(wildcard $(PATH_DEVTOOLS)/win.amd64/ddk/7600.16385.1*) endif ifeq ($(PATH_SDK_WINDDK71),) ifeq ($(KBUILD_HOST),win) PATH_SDK_WINDDK71 := $(wildcard C:/WinDDK/7600.16385.1*) endif endif ifneq ($(PATH_SDK_WINDDK71),) PATH_SDK_WINDDK71 := $(lastword $(sort $(PATH_SDK_WINDDK71))) else $(warning kBuild: PATH_SDK_WINDDK71 couldn't be determined!) PATH_SDK_WINDDK71 := $(PATH_DEVTOOLS)/win.x86/ddk/7600.16385.1-not-found endif else # Resolve any fancy stuff once and for all. PATH_SDK_WINDDK71 := $(PATH_SDK_WINDDK71) endif PATH_SDK_WINDDK71_INC ?= $(PATH_SDK_WINDDK71)/inc PATH_SDK_WINDDK71_INC_API ?= $(PATH_SDK_WINDDK71_INC)/api PATH_SDK_WINDDK71_INC_CRT ?= $(PATH_SDK_WINDDK71_INC)/crt PATH_SDK_WINDDK71_INC_DDK ?= $(PATH_SDK_WINDDK71_INC)/ddk PATH_SDK_WINDDK71_LIB_ROOT ?= $(PATH_SDK_WINDDK71)/lib PATH_SDK_WINDDK71_LIB_WLH_ROOT ?= $(PATH_SDK_WINDDK71_LIB_ROOT)/wlh PATH_SDK_WINDDK71_LIB_WNET_ROOT ?= $(PATH_SDK_WINDDK71_LIB_ROOT)/wnet PATH_SDK_WINDDK71_LIB_WXP_ROOT ?= $(PATH_SDK_WINDDK71_LIB_ROOT)/wxp PATH_SDK_WINDDK71_LIB_W2K_ROOT ?= $(PATH_SDK_WINDDK71_LIB_ROOT)/w2k PATH_SDK_WINDDK71_LIB_WDF_ROOT ?= $(PATH_SDK_WINDDK71_LIB_ROOT)/w2k PATH_SDK_WINDDK71_LIB_WLH.amd64 ?= $(PATH_SDK_WINDDK71_LIB_WLH_ROOT)/amd64 PATH_SDK_WINDDK71_LIB_WLH.ia64 ?= $(PATH_SDK_WINDDK71_LIB_WLH_ROOT)/ia64 PATH_SDK_WINDDK71_LIB_WLH.x86 ?= $(PATH_SDK_WINDDK71_LIB_WLH_ROOT)/i386 PATH_SDK_WINDDK71_LIB_WLH ?= $(PATH_SDK_WINDDK71_LIB_WLH.$(KBUILD_TARGET_ARCH)) PATH_SDK_WINDDK71_LIB_WNET.amd64?= $(PATH_SDK_WINDDK71_LIB_WNET_ROOT)/amd64 PATH_SDK_WINDDK71_LIB_WNET.ia64 ?= $(PATH_SDK_WINDDK71_LIB_WNET_ROOT)/ia64 PATH_SDK_WINDDK71_LIB_WNET.x86 ?= $(PATH_SDK_WINDDK71_LIB_WNET_ROOT)/i386 PATH_SDK_WINDDK71_LIB_WNET ?= $(PATH_SDK_WINDDK71_LIB_WNET.$(KBUILD_TARGET_ARCH)) PATH_SDK_WINDDK71_LIB_WXP.x86 ?= $(PATH_SDK_WINDDK71_LIB_WXP_ROOT)/i386 PATH_SDK_WINDDK71_LIB_WXP ?= $(PATH_SDK_WINDDK71_LIB_WXP.$(KBUILD_TARGET_ARCH)) PATH_SDK_WINDDK71_LIB_W2K.x86 ?= $(PATH_SDK_WINDDK71_LIB_W2K_ROOT)/i386 PATH_SDK_WINDDK71_LIB_W2K ?= $(PATH_SDK_WINDDK71_LIB_W2K.$(KBUILD_TARGET_ARCH)) PATH_SDK_WINDDK71_LIB.amd64 ?= $(PATH_SDK_WINDDK71_LIB_WLH.amd64) PATH_SDK_WINDDK71_LIB.ia64 ?= $(PATH_SDK_WINDDK71_LIB_WLH.ia64) PATH_SDK_WINDDK71_LIB.x86 ?= $(PATH_SDK_WINDDK71_LIB_WLH.x86) PATH_SDK_WINDDK71_LIB ?= $(PATH_SDK_WINDDK71_LIB.$(KBUILD_TARGET_ARCH)) # General Properties used by kBuild SDK_WINDDK71_DEFS.amd64 ?= _AMD64_ AMD64 _WIN64 SDK_WINDDK71_DEFS.ia64 ?= _IA64_=1 IA64=1 _WIN64 _MSC_EXTENSIONS SDK_WINDDK71_DEFS.x86 ?= _X86_=1 i386=1 STD_CALL SDK_WINDDK71_INCS ?= \ $(PATH_SDK_WINDDK71_INC_API) \ $(PATH_SDK_WINDDK71_INC_DDK) # The compiler tool(s) will have to select the appropriate crt includes. SDK_WINDDK71_LIBPATH.amd64 ?= $(PATH_SDK_WINDDK71_LIB_WLH.amd64) SDK_WINDDK71_LIBPATH.ia64 ?= $(PATH_SDK_WINDDK71_LIB_WLH.ia64) SDK_WINDDK71_LIBPATH.x86 ?= $(PATH_SDK_WINDDK71_LIB_WLH.x86) kbuild-3149/kBuild/sdks/WINPSDK71INCS.kmk0000644000175000017500000000737513252530250017543 0ustar locutuslocutus# $Id: WINPSDK71INCS.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - The Windows Platform SDK v7.1, targeting (KBUILD_TARGET) but # without any libraries or LIBPATH properties. # Basically for finding specstrings.h when using the DDK. # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_WINPSDK71INCS := The Windows Platform SDK v7.1, targeting (KBUILD_TARGET) but \ without any library or LIBPATH properties. \ Basically for finding specstrings.h when using the DDK. # SDK Specific Properties ifndef PATH_SDK_WINPSDK71INCS ifdef PATH_SDK_WINPSDK71 PATH_SDK_WINPSDK71INCS := $(PATH_SDK_WINPSDK71) else PATH_SDK_WINPSDK71INCS := $(wildcard $(PATH_DEVTOOLS_BLD)/sdk/v7.1*) ifeq ($(PATH_SDK_WINPSDK71INCS),) PATH_SDK_WINPSDK71INCS := $(wildcard $(PATH_DEVTOOLS_TRG)/sdk/v7.1*) endif ifeq ($(PATH_SDK_WINPSDK71INCS),) PATH_SDK_WINPSDK71INCS := $(wildcard $(PATH_DEVTOOLS)/win.x86/sdk/v7.1*) endif ifeq ($(PATH_SDK_WINPSDK71INCS),) PATH_SDK_WINPSDK71INCS := $(wildcard $(PATH_DEVTOOLS)/win.amd64/sdk/v7.1*) endif ifneq ($(PATH_SDK_WINPSDK71INCS),) PATH_SDK_WINPSDK71INCS := $(lastword $(sort $(PATH_SDK_WINPSDK71INCS))) else $(warning kBuild: PATH_SDK_WINPSDK71INCS couldn't be determined!) PATH_SDK_WINPSDK71INCS := $(PATH_DEVTOOLS_BLD)/sdk/v7.1-not-found endif endif else PATH_SDK_WINPSDK71INCS := $(PATH_SDK_WINPSDK71INCS) endif ifndef PATH_SDK_WINPSDK71INCS_INC PATH_SDK_WINPSDK71INCS_INC := $(firstword $(wildcard $(PATH_SDK_WINPSDK71INCS)/[Ii][Nn][Cc][Ll][Uu][Dd][Ee]) $(PATH_SDK_WINPSDK71INCS)/Include) endif ifndef PATH_SDK_WINPSDK71INCS_LIB.x86 PATH_SDK_WINPSDK71INCS_LIB.x86 := $(firstword $(wildcard $(PATH_SDK_WINPSDK71INCS)/[Ll][Ii][Bb]) $(PATH_SDK_WINPSDK71INCS)/Lib) endif ifndef PATH_SDK_WINPSDK71INCS_LIB.amd64 PATH_SDK_WINPSDK71INCS_LIB.amd64 := $(firstword $(wildcard $(PATH_SDK_WINPSDK71INCS)/[Ll][Ii][Bb]/[Aa][Mm][Dd]64) $(PATH_SDK_WINPSDK71INCS)/Lib/AMD64) endif PATH_SDK_WINPSDK71INCS_LIB ?= $(PATH_SDK_WINPSDK71INCS_LIB.$(KBUILD_TARGET_ARCH)) ifndef PATH_SDK_WINPSDK71INCS_BIN PATH_SDK_WINPSDK71INCS_BIN := $(firstword $(wildcard $(PATH_SDK_WINPSDK71INCS)/[Bb][Ii][Nn]) $(PATH_SDK_WINPSDK71INCS)/Bin) endif ifndef PATH_SDK_WINPSDK71INCS_BIN_AMD64 PATH_SDK_WINPSDK71INCS_BIN_AMD64 := $(firstword $(wildcard $(PATH_SDK_WINPSDK71INCS_BIN)/[Ww][Ii][Nn]64/[Xx]86/[Aa][Mm][Dd]64) $(PATH_SDK_WINPSDK71INCS_BIN)/win64/AMD64) endif ifndef PATH_SDK_WINPSDK71INCS_BIN_IA64 PATH_SDK_WINPSDK71INCS_BIN_IA64 := $(firstword $(wildcard $(PATH_SDK_WINPSDK71INCS_BIN)/[Ww][Ii][Nn]64) $(PATH_SDK_WINPSDK71INCS_BIN)/win64) endif # General Properties used by kBuild SDK_WINPSDK71INCS_INCS ?= $(PATH_SDK_WINPSDK71INCS_INC) kbuild-3149/kBuild/sdks/W32API.kmk0000644000175000017500000000405113252530250016470 0ustar locutuslocutus# $Id: W32API.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - w32api (MinGW), targeting x86. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_W32API := w32api (MinGW), targeting x86. # SDK Specific Properties ifndef PATH_SDK_W32API PATH_SDK_W32API := $(wildcard $(PATH_DEVTOOLS)/win.x86/w32api/v*) ifeq ($(PATH_SDK_W32API),) PATH_SDK_W32API := $(wildcard $(PATH_DEVTOOLS)/x86.win32/w32api/v*) endif ifneq ($(PATH_SDK_W32API),) PATH_SDK_W32API := $(lastword $(sort $(PATH_SDK_W32API))) else $(warning kBuild: PATH_SDK_W32API couldn't be determined!) PATH_SDK_W32API := $(PATH_DEVTOOLS)/x86.win/w32api/not/found endif else # Resolve any fancy stuff once and for all. PATH_SDK_W32API := $(PATH_SDK_W32API) endif PATH_SDK_W32API_INC ?= $(PATH_SDK_W32API)/include PATH_SDK_W32API_LIB ?= $(PATH_SDK_W32API)/lib # General Properties used by kBuild SDK_W32API_INCS ?= $(PATH_SDK_W32API_INC) SDK_W32API_LIBPATH ?= $(PATH_SDK_W32API_LIB) kbuild-3149/kBuild/sdks/WINDDKWLH.kmk0000644000175000017500000000425113252530250017120 0ustar locutuslocutus# $Id: WINDDKWLH.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - The Microsoft Windows Vista and Server 2008 DDKs, Targeting Vista and 2008 (KBUILD_TARGET_ARCH). # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_WINDDKWLH := The Microsoft Windows Vista and Server 2008 DDKs, Targeting Vista and 2008 (KBUILD_TARGET_ARCH). SDK_WINDDKWLH_EXTENDS = WINDDK SDK_WINDDKWLH_DEFS ?= WIN32=100 _WIN32_WINNT=0x0600 WINVER=0x0600 _WIN32_IE=0x0700 NTDDI_VERSION=0x06000000 KMDF_MAJOR_VERSION=01 KMDF_MINOR_VERSION=005 SDK_WINDDKWLH_LIBPATH.amd64 ?= $(PATH_SDK_WINDDK_LIB_WLH.amd64) SDK_WINDDKWLH_LIBPATH.ia64 ?= $(PATH_SDK_WINDDK_LIB_WLH.ia64) SDK_WINDDKWLH_LIBPATH.x86 ?= $(PATH_SDK_WINDDK_LIB_WLH.x86) # SDK Specific Properties. # Note! extends the WINDDK sdk, so use those variables where ever possible PATH_SDK_WINDDKWLH_LIB.amd64?= $(PATH_SDK_WINDDK_LIB_WLH.amd64) PATH_SDK_WINDDKWLH_LIB.ia64 ?= $(PATH_SDK_WINDDK_LIB_WLH.ia64) PATH_SDK_WINDDKWLH_LIB.x86 ?= $(PATH_SDK_WINDDK_LIB_WLH.x86) PATH_SDK_WINDDKWLH_LIB ?= $(PATH_SDK_WINDDKWLH_LIB.$(KBUILD_TARGET_ARCH)) kbuild-3149/kBuild/sdks/DXSDKX86.kmk0000644000175000017500000000427313252530250016754 0ustar locutuslocutus# $Id: DXSDKX86.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - The Microsoft Direct X SDK, targeting X86. # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_DXSDKX86 := The Microsoft Direct X SDK, targeting X86. # SDK Specific Properties ifndef PATH_SDK_DXSDKX86 PATH_SDK_DXSDKX86 := $(wildcard $(PATH_DEVTOOLS)/win.x86/dxsdk/2*) ifeq ($(PATH_SDK_DXSDKX86),) PATH_SDK_DXSDKX86 := $(PATH_SDK_DXSDK) endif ifeq ($(PATH_SDK_DXSDKX86),) PATH_SDK_DXSDKX86 := $(wildcard $(PATH_DEVTOOLS)/amd64.win/dxsdk/2*) endif ifneq ($(PATH_SDK_DXSDKX86),) PATH_SDK_DXSDKX86 := $(lastword $(sort $(PATH_SDK_DXSDKX86))) else $(warning kBuild: PATH_SDK_DXSDKX86 couldn't be determined!) PATH_SDK_DXSDKX86 := $(PATH_DEVTOOLS)/win.x86/dxsdk/not/found endif else # Resolve any fancy stuff once and for all. PATH_SDK_DXSDKX86 := $(PATH_SDK_DXSDKX86) endif PATH_SDK_DXSDKX86_INC ?= $(PATH_SDK_DXSDKX86)/Include PATH_SDK_DXSDKX86_LIB ?= $(PATH_SDK_DXSDKX86)/Lib/x86 # General Properties used by kBuild SDK_DXSDKX86_INCS ?= $(PATH_SDK_DXSDKX86_INC) SDK_DXSDKX86_LIBPATH ?= $(PATH_SDK_DXSDKX86_LIB) kbuild-3149/kBuild/sdks/WINPSDK.kmk0000644000175000017500000001451113252530251016705 0ustar locutuslocutus# $Id: WINPSDK.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - The Windows Platform SDK, targeting (KBUILD_TARGET). # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_WINPSDK := The Windows Platform SDK, targeting (KBUILD_TARGET). # SDK Specific Properties ifndef PATH_SDK_WINPSDK PATH_SDK_WINPSDK := $(wildcard $(PATH_DEVTOOLS_BLD)/sdk/2*) ifeq ($(PATH_SDK_WINPSDK),) PATH_SDK_WINPSDK := $(wildcard $(PATH_DEVTOOLS_TRG)/sdk/2*) endif ifeq ($(PATH_SDK_WINPSDK),) PATH_SDK_WINPSDK := $(wildcard $(PATH_DEVTOOLS)/win.x86/sdk/2*) endif ifeq ($(PATH_SDK_WINPSDK),) PATH_SDK_WINPSDK := $(wildcard $(PATH_DEVTOOLS)/win.amd64/sdk/2*) endif ifneq ($(PATH_SDK_WINPSDK),) PATH_SDK_WINPSDK := $(lastword $(sort $(PATH_SDK_WINPSDK))) else $(warning kBuild: PATH_SDK_WINPSDK couldn't be determined!) PATH_SDK_WINPSDK := $(PATH_DEVTOOLS_BLD)/sdk/not/found endif else PATH_SDK_WINPSDK := $(PATH_SDK_WINPSDK) endif ifndef PATH_SDK_WINPSDK_INC PATH_SDK_WINPSDK_INC := $(firstword $(wildcard $(PATH_SDK_WINPSDK)/[Ii][Nn][Cc][Ll][Uu][Dd][Ee]) $(PATH_SDK_WINPSDK)/Include) endif ifndef PATH_SDK_WINPSDK_LIB.x86 PATH_SDK_WINPSDK_LIB.x86 := $(firstword $(wildcard $(PATH_SDK_WINPSDK)/[Ll][Ii][Bb]) $(PATH_SDK_WINPSDK)/Lib) endif ifndef PATH_SDK_WINPSDK_LIB.amd64 PATH_SDK_WINPSDK_LIB.amd64 := $(firstword $(wildcard $(PATH_SDK_WINPSDK)/[Ll][Ii][Bb]/[Aa][Mm][Dd]64 $(PATH_SDK_WINPSDK)/[Ll][Ii][Bb]/[xX]64) $(PATH_SDK_WINPSDK)/Lib/AMD64) endif ifndef PATH_SDK_WINPSDK_LIB.ia64 PATH_SDK_WINPSDK_LIB.ia64 := $(firstword $(wildcard $(PATH_SDK_WINPSDK)/[Ll][Ii][Bb]/[Ii][Aa]64) $(PATH_SDK_WINPSDK)/Lib/IA64) endif PATH_SDK_WINPSDK_LIB ?= $(PATH_SDK_WINPSDK_LIB.$(KBUILD_TARGET_ARCH)) ifndef PATH_SDK_WINPSDK_BIN PATH_SDK_WINPSDK_BIN := $(firstword $(wildcard $(PATH_SDK_WINPSDK)/[Bb][Ii][Nn]) $(PATH_SDK_WINPSDK)/Bin) endif ifndef PATH_SDK_WINPSDK_BIN_AMD64 PATH_SDK_WINPSDK_BIN_AMD64 := $(firstword $(wildcard $(PATH_SDK_WINPSDK_BIN)/[Ww][Ii][Nn]64/[Xx]86/[Aa][Mm][Dd]64 $(PATH_SDK_WINPSDK_BIN)/[Ww][Ii][Nn]64/[Xx]86) $(PATH_SDK_WINPSDK_BIN)/win64/AMD64) endif ifndef PATH_SDK_WINPSDK_BIN_IA64 PATH_SDK_WINPSDK_BIN_IA64 := $(firstword $(wildcard $(PATH_SDK_WINPSDK_BIN)/[Ww][Ii][Nn]64) $(PATH_SDK_WINPSDK_BIN)/win64) endif # General Properties used by kBuild SDK_WINPSDK_INCS ?= $(PATH_SDK_WINPSDK_INC) SDK_WINPSDK_LIBPATH.x86 ?= $(PATH_SDK_WINPSDK_LIB.x86) SDK_WINPSDK_LIBPATH.amd64 ?= $(PATH_SDK_WINPSDK_LIB.amd64) SDK_WINPSDK_LIBPATH.ia64 ?= $(PATH_SDK_WINPSDK_LIB.ia64) SDK_WINPSDK_LIBS.x86 ?= \ $(PATH_SDK_WINPSDK_LIB.x86)/Kernel32.Lib \ $(PATH_SDK_WINPSDK_LIB.x86)/User32.Lib \ $(PATH_SDK_WINPSDK_LIB.x86)/Gdi32.Lib \ $(PATH_SDK_WINPSDK_LIB.x86)/AdvAPI32.Lib \ $(PATH_SDK_WINPSDK_LIB.x86)/shell32.lib \ $(PATH_SDK_WINPSDK_LIB.x86)/ShLwApi.Lib \ $(PATH_SDK_WINPSDK_LIB.x86)/SetupAPI.Lib \ $(PATH_SDK_WINPSDK_LIB.x86)/Uuid.Lib \ $(PATH_SDK_WINPSDK_LIB.x86)/Version.Lib \ $(PATH_SDK_WINPSDK_LIB.x86)/WS2_32.Lib \ \ $(PATH_SDK_WINPSDK_LIB.x86)/Ole32.Lib \ $(PATH_SDK_WINPSDK_LIB.x86)/OleAut32.Lib \ $(PATH_SDK_WINPSDK_LIB.x86)/OleDlg.Lib \ $(PATH_SDK_WINPSDK_LIB.x86)/RpcRT4.Lib \ \ $(PATH_SDK_WINPSDK_LIB.x86)/DbgHelp.Lib \ $(PATH_SDK_WINPSDK_LIB.x86)/ImageHlp.Lib \ $(PATH_SDK_WINPSDK_LIB.x86)/IPHlpApi.Lib \ $(PATH_SDK_WINPSDK_LIB.x86)/ComCtl32.Lib \ $(PATH_SDK_WINPSDK_LIB.x86)/ComDlg32.Lib \ $(PATH_SDK_WINPSDK_LIB.x86)/WinSpool.Lib \ $(PATH_SDK_WINPSDK_LIB.x86)/WinMM.Lib SDK_WINPSDK_LIBS.amd64 ?= \ $(PATH_SDK_WINPSDK_LIB.amd64)/Kernel32.Lib \ $(PATH_SDK_WINPSDK_LIB.amd64)/User32.Lib \ $(PATH_SDK_WINPSDK_LIB.amd64)/Gdi32.Lib \ $(PATH_SDK_WINPSDK_LIB.amd64)/AdvAPI32.Lib \ $(PATH_SDK_WINPSDK_LIB.amd64)/Shell32.Lib \ $(PATH_SDK_WINPSDK_LIB.amd64)/ShLwApi.Lib \ $(PATH_SDK_WINPSDK_LIB.amd64)/SetupAPI.Lib \ $(PATH_SDK_WINPSDK_LIB.amd64)/Uuid.Lib \ $(PATH_SDK_WINPSDK_LIB.amd64)/Version.Lib \ $(PATH_SDK_WINPSDK_LIB.amd64)/WS2_32.Lib \ \ $(PATH_SDK_WINPSDK_LIB.amd64)/Ole32.Lib \ $(PATH_SDK_WINPSDK_LIB.amd64)/OleAut32.Lib \ $(PATH_SDK_WINPSDK_LIB.amd64)/OleDlg.Lib \ $(PATH_SDK_WINPSDK_LIB.amd64)/RpcRT4.Lib \ \ $(PATH_SDK_WINPSDK_LIB.amd64)/DbgHelp.Lib \ $(PATH_SDK_WINPSDK_LIB.amd64)/ImageHlp.Lib \ $(PATH_SDK_WINPSDK_LIB.amd64)/IPHlpApi.Lib \ $(PATH_SDK_WINPSDK_LIB.amd64)/ComCtl32.Lib \ $(PATH_SDK_WINPSDK_LIB.amd64)/ComDlg32.Lib \ $(PATH_SDK_WINPSDK_LIB.amd64)/WinSpool.Lib \ $(PATH_SDK_WINPSDK_LIB.amd64)/WinMM.Lib SDK_WINPSDK_LIBS.ia64 ?= \ $(PATH_SDK_WINPSDK_LIB.ia64)/Kernel32.Lib \ $(PATH_SDK_WINPSDK_LIB.ia64)/User32.Lib \ $(PATH_SDK_WINPSDK_LIB.ia64)/Gdi32.Lib \ $(PATH_SDK_WINPSDK_LIB.ia64)/AdvAPI32.Lib \ $(PATH_SDK_WINPSDK_LIB.ia64)/Shell32.Lib \ $(PATH_SDK_WINPSDK_LIB.ia64)/ShLwApi.Lib \ $(PATH_SDK_WINPSDK_LIB.ia64)/SetupAPI.Lib \ $(PATH_SDK_WINPSDK_LIB.ia64)/Uuid.Lib \ $(PATH_SDK_WINPSDK_LIB.ia64)/Version.Lib \ $(PATH_SDK_WINPSDK_LIB.ia64)/WS2_32.Lib \ \ $(PATH_SDK_WINPSDK_LIB.ia64)/Ole32.Lib \ $(PATH_SDK_WINPSDK_LIB.ia64)/OleAut32.Lib \ $(PATH_SDK_WINPSDK_LIB.ia64)/OleDlg.Lib \ $(PATH_SDK_WINPSDK_LIB.ia64)/RpcRT4.Lib \ \ $(PATH_SDK_WINPSDK_LIB.ia64)/DbgHelp.Lib \ $(PATH_SDK_WINPSDK_LIB.ia64)/ImageHlp.Lib \ $(PATH_SDK_WINPSDK_LIB.ia64)/IPHlpApi.Lib \ $(PATH_SDK_WINPSDK_LIB.ia64)/ComCtl32.Lib \ $(PATH_SDK_WINPSDK_LIB.ia64)/ComDlg32.Lib \ $(PATH_SDK_WINPSDK_LIB.ia64)/WinSpool.Lib \ $(PATH_SDK_WINPSDK_LIB.ia64)/WinMM.Lib kbuild-3149/kBuild/sdks/MACOSX105.kmk0000644000175000017500000000400313252530250017000 0ustar locutuslocutus# $Id: MACOSX105.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - Mac OS X v10.5 SDK. # # # Copyright (c) 2008-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_MACOSX105 := Mac OS X v10.5 SDK # SDK Specific Properties ifndef PATH_SDK_MACOSX105 PATH_SDK_MACOSX105 := /Developer/SDKs/MacOSX10.5.sdk else # Resolve any fancy stuff once and for all. PATH_SDK_MACOSX105 := $(PATH_SDK_MACOSX105) endif # General Properties (used by kBuild) # Note: The MAC_OS_X_VERSION_MAX_ALLOWED is left free for the SDK user to define. SDK_MACOSX105_DEFS ?= MAC_OS_X_VERSION_MIN_REQUIRED=1050 SDK_MACOSX105_CFLAGS ?= -mmacosx-version-min=10.5 -isysroot $(PATH_SDK_MACOSX105) SDK_MACOSX105_CXXFLAGS ?= -mmacosx-version-min=10.5 -isysroot $(PATH_SDK_MACOSX105) SDK_MACOSX105_OBJCFLAGS ?= -mmacosx-version-min=10.5 -isysroot $(PATH_SDK_MACOSX105) SDK_MACOSX105_LDFLAGS ?= -mmacosx-version-min=10.5 -Wl,-syslibroot,$(PATH_SDK_MACOSX105) kbuild-3149/kBuild/sdks/W2K3DDKX86.kmk0000644000175000017500000000521413252530251017105 0ustar locutuslocutus# $Id: W2K3DDKX86.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - The Microsoft Windows 2003 DDK, targeting x86. # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_W2K3DDKX86 := The Microsoft Windows 2003 DDK, targeting x86. # SDK Specific Properties ifndef PATH_SDK_W2K3DDKX86 PATH_SDK_W2K3DDKX86 := $(wildcard $(PATH_DEVTOOLS)/win.x86/ddkwin2k3/2*) ifeq ($(PATH_SDK_W2K3DDKX86),) PATH_SDK_W2K3DDKX86 := $(PATH_SDK_W2K3DDK) endif ifeq ($(PATH_SDK_W2K3DDKX86),) PATH_SDK_W2K3DDKX86 := $(wildcard $(PATH_DEVTOOLS)/win.amd64/ddkwin2k3/2*) endif # legacy: ifeq ($(PATH_SDK_W2K3DDKX86),) PATH_SDK_W2K3DDKX86 := $(wildcard $(PATH_DEVTOOLS)/x86.win32/ddkwin2k3/2*) endif ifeq ($(PATH_SDK_W2K3DDKX86),) PATH_SDK_W2K3DDKX86 := $(wildcard $(PATH_DEVTOOLS)/x86.win32/ddkwin2k3) endif ifneq ($(PATH_SDK_W2K3DDKX86),) PATH_SDK_W2K3DDKX86 := $(lastword $(sort $(PATH_SDK_W2K3DDKX86))) else $(warning kBuild: PATH_SDK_W2K3DDKX86 couldn't be determined!) PATH_SDK_W2K3DDKX86 := $(PATH_DEVTOOLS)/x86.win/ddkwin2k3/not/found endif else # Resolve any fancy stuff once and for all. PATH_SDK_W2K3DDKX86 := $(PATH_SDK_W2K3DDKX86) endif PATH_SDK_W2K3DDKX86_INC ?= $(PATH_SDK_W2K3DDKX86)/inc PATH_SDK_W2K3DDKX86_LIB ?= $(PATH_SDK_W2K3DDKX86)/lib/wnet/i386 # General Properties used by kBuild SDK_W2K3DDKX86_DEFS ?= _X86_ SDK_W2K3DDKX86_INCS ?= \ $(PATH_SDK_W2K3DDKX86_INC)/ddk \ $(PATH_SDK_W2K3DDKX86_INC)/ddk/wnet \ $(PATH_SDK_W2K3DDKX86_INC)/wnet \ $(PATH_SDK_W2K3DDKX86_INC)/ddk/wdm/wnet SDK_W2K3DDKX86_LIBPATH ?= \ $(PATH_SDK_W2K3DDKX86_LIB) kbuild-3149/kBuild/sdks/OS2DDKBASE32.kmk0000644000175000017500000000443313252530251017316 0ustar locutuslocutus# $Id: OS2DDKBASE32.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # # kBuild SDK - The OS/2 DDK, 32-bit base headers and libraries. # # Copyright (c) 2007-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_OS2DDKBASE32 := The OS/2 DDK, 32-bit base headers and libraries. # SDK Specific Properties ifndef PATH_SDK_OS2DDKBASE32 PATH_SDK_OS2DDKBASE32 := $(wildcard $(PATH_DEVTOOLS)/os2.x86/ddk/2*/base32) ifeq ($(PATH_SDK_OS2DDKBASE32),) PATH_SDK_OS2DDKBASE32 := $(wildcard $(PATH_DDKBASE)/../base32) endif ifneq ($(PATH_SDK_OS2DDKBASE32),) PATH_SDK_OS2DDKBASE32 := $(lastword $(sort $(PATH_SDK_OS2DDKBASE32))) else $(warning kBuild: PATH_SDK_OS2DDKBASE32 couldn't be determined!) PATH_SDK_OS2DDKBASE32 := $(PATH_DEVTOOLS)/x86.win/ddknt4/not/found endif else # Resolve any fancy stuff once and for all. PATH_SDK_OS2DDKBASE32 := $(PATH_SDK_OS2DDKBASE32) endif PATH_SDK_OS2DDKBASE32_INC ?= PATH_SDK_OS2DDKBASE32_LIB ?= $(PATH_SDK_OS2DDKBASE32)/lib/i386/free # General Properties used by kBuild SDK_OS2DDKBASE32_INCS ?= $(PATH_SDK_OS2DDKBASE32)/rel/os2c/include/base/os2/16bit SDK_OS2DDKBASE32_ASINCS ?= $(PATH_SDK_OS2DDKBASE32)/rel/os2c/include/base/os2/inc SDK_OS2DDKBASE32_LIBPATH ?= $(PATH_SDK_OS2DDKBASE32_LIB) kbuild-3149/kBuild/sdks/DXSDK.kmk0000644000175000017500000000474513252530251016453 0ustar locutuslocutus# $Id: DXSDK.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - The Microsoft Direct X SDK, targeting $(KBUILD_TARGET). # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_DXSDK := The Microsoft Direct X SDK, targeting $(KBUILD_TARGET) # SDK Specific Properties ifndef PATH_SDK_DXSDK ## @todo which order is logical here, BLD and then TRG or the other way? PATH_SDK_DXSDK := $(sort $(wildcard $(PATH_DEVTOOLS_BLD)/dxsdk/2*)) ifeq ($(PATH_SDK_DXSDK),) PATH_SDK_DXSDK := $(sort $(wildcard $(PATH_DEVTOOLS_TRG)/dxsdk/2*)) endif ifeq ($(PATH_SDK_DXSDK),) PATH_SDK_DXSDK := $(sort $(wildcard $(PATH_DEVTOOLS)/win.x86/dxsdk/2*)) endif ifeq ($(PATH_SDK_DXSDK),) PATH_SDK_DXSDK := $(sort $(wildcard $(PATH_DEVTOOLS)/win.amd64/dxsdk/2*)) endif ifneq ($(PATH_SDK_DXSDK),) PATH_SDK_DXSDK := $(call lastword,$(PATH_SDK_DXSDK)) else $(warning kBuild: PATH_SDK_DXSDK couldn't be determined!) PATH_SDK_DXSDK := $(PATH_DEVTOOLS_TRG)/dxsdk/not/found endif else # Resolve any fancy stuff once and for all. PATH_SDK_DXSDK := $(PATH_SDK_DXSDK) endif PATH_SDK_DXSDK_INC ?= $(PATH_SDK_DXSDK)/Include PATH_SDK_DXSDK_LIB.x86 ?= $(PATH_SDK_DXSDK)/Lib/x86 PATH_SDK_DXSDK_LIB.amd64 ?= $(PATH_SDK_DXSDK)/Lib/x64 PATH_SDK_DXSDK_LIB ?= $(PATH_SDK_DXSDK_LIB.$(KBUILD_TARGET_ARCH)) # General Properties used by kBuild SDK_DXSDK_INCS ?= $(PATH_SDK_DXSDK_INC) SDK_DXSDK_LIBPATH ?= $(PATH_SDK_DXSDK_LIB) kbuild-3149/kBuild/sdks/WINDDKWXP.kmk0000644000175000017500000000350613252530251017147 0ustar locutuslocutus# $Id: WINDDKWXP.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - The Microsoft Windows Vista and Server 2008 DDKs, Targeting Windows XP (x86). # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_WINDDKWXP := The Microsoft Windows Vista and Server 2008 DDKs, Targeting Windows XP (x86). SDK_WINDDKWXP_EXTENDS = WINDDK SDK_WINDDKWXP_DEFS ?= WIN32=100 _WIN32_WINNT=0x0501 WINVER=0x0501 _WIN32_IE=0x0603 NTDDI_VERSION=0x05010200 SDK_WINDDKWXP_LIBPATH.x86 ?= $(PATH_SDK_WINDDK_LIB_WXP.x86) # SDK Specific Properties. # Note! extends the WINDDK sdk, so use those variables where ever possible PATH_SDK_WINDDKWXP_LIB.x86 ?= $(PATH_SDK_WINDDK_LIB_WXP.x86) PATH_SDK_WINDDKWXP_LIB ?= $(PATH_SDK_WINDDKWXP_LIB.x86) kbuild-3149/kBuild/sdks/WIN32SDK.kmk0000644000175000017500000000657113252530250016740 0ustar locutuslocutus# $Id: WIN32SDK.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - The Windows Platform SDK, targeting x86. # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_WIN32SDK := The Windows Platform SDK, targeting x86. # SDK Specific Properties ifndef PATH_SDK_WIN32SDK PATH_SDK_WIN32SDK := $(wildcard $(PATH_DEVTOOLS)/win.x86/sdk/2*) ifeq ($(PATH_SDK_WIN32SDK),) PATH_SDK_WIN32SDK := $(PATH_SDK_WINPSDK) endif ifeq ($(PATH_SDK_WIN32SDK),) PATH_SDK_WIN32SDK := $(wildcard $(PATH_DEVTOOLS)/x86.win32/sdk/2*) endif ifeq ($(PATH_SDK_WIN32SDK),) PATH_SDK_WIN32SDK := $(wildcard $(PATH_DEVTOOLS)/win.amd64/sdk/2*) endif ifneq ($(PATH_SDK_WIN32SDK),) PATH_SDK_WIN32SDK := $(lastword $(sort $(PATH_SDK_WIN32SDK))) else $(warning kBuild: PATH_SDK_WIN32SDK couldn't be determined!) PATH_SDK_WIN32SDK := $(PATH_DEVTOOLS)/win.x86/sdk/not/found endif endif ifndef PATH_SDK_WIN32SDK_INC PATH_SDK_WIN32SDK_INC := $(firstword $(wildcard $(PATH_SDK_WIN32SDK)/[Ii][Nn][Cc][Ll][Uu][Dd][Ee]) $(PATH_SDK_WIN32SDK)/Include) endif ifndef PATH_SDK_WIN32SDK_LIB PATH_SDK_WIN32SDK_LIB := $(firstword $(wildcard $(PATH_SDK_WIN32SDK)/[Ll][Ii][Bb]) $(PATH_SDK_WIN32SDK)/Lib) endif ifndef PATH_SDK_WIN32SDK_BIN PATH_SDK_WIN32SDK_BIN := $(firstword $(wildcard $(PATH_SDK_WIN32SDK)/[Bb][Ii][Nn]) $(PATH_SDK_WIN32SDK)/Bin) endif # General Properties used by kBuild SDK_WIN32SDK_INCS ?= $(PATH_SDK_WIN32SDK_INC) SDK_WIN32SDK_LIBPATH ?= $(PATH_SDK_WIN32SDK_LIB) SDK_WIN32SDK_LIBS ?= \ $(PATH_SDK_WIN32SDK_LIB)/Kernel32.Lib \ $(PATH_SDK_WIN32SDK_LIB)/User32.Lib \ $(PATH_SDK_WIN32SDK_LIB)/Gdi32.Lib \ $(PATH_SDK_WIN32SDK_LIB)/AdvAPI32.Lib \ $(PATH_SDK_WIN32SDK_LIB)/Shell32.Lib \ $(PATH_SDK_WIN32SDK_LIB)/ShLwApi.Lib \ $(PATH_SDK_WIN32SDK_LIB)/SetupAPI.Lib \ $(PATH_SDK_WIN32SDK_LIB)/Uuid.Lib \ $(PATH_SDK_WIN32SDK_LIB)/Version.Lib \ $(PATH_SDK_WIN32SDK_LIB)/WS2_32.Lib \ \ $(PATH_SDK_WIN32SDK_LIB)/Ole32.Lib \ $(PATH_SDK_WIN32SDK_LIB)/OleAut32.Lib \ $(PATH_SDK_WIN32SDK_LIB)/OleDlg.Lib \ $(PATH_SDK_WIN32SDK_LIB)/RpcRT4.Lib \ \ $(PATH_SDK_WIN32SDK_LIB)/DbgHelp.Lib \ $(PATH_SDK_WIN32SDK_LIB)/ImageHlp.Lib \ $(PATH_SDK_WIN32SDK_LIB)/IPHlpApi.Lib \ $(PATH_SDK_WIN32SDK_LIB)/ComCtl32.Lib \ $(PATH_SDK_WIN32SDK_LIB)/ComDlg32.Lib \ $(PATH_SDK_WIN32SDK_LIB)/WinSpool.Lib \ $(PATH_SDK_WIN32SDK_LIB)/WinMM.Lib \ kbuild-3149/kBuild/sdks/WINDDKW2K.kmk0000644000175000017500000000351213252530251017071 0ustar locutuslocutus# $Id: WINDDKW2K.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - The Microsoft Windows Vista and Server 2008 DDKs, Targeting Windows 2000 (x86). # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_WINDDKW2K := The Microsoft Windows Vista and Server 2008 DDKs, Targeting Windows 2000 (x86). SDK_WINDDKW2K_EXTENDS = WINDDK SDK_WINDDKW2K_DEFS ?= WIN32=100 _WIN32_WINNT=0x0500 WINVER=0x0500 _WIN32_IE=0x0501 NTDDI_VERSION=0x05000400 SDK_WINDDKW2K_LIBPATH.x86 ?= $(PATH_SDK_WINDDK_LIB_W2K.x86) # SDK Specific Properties. # Note! extends the WINDDK sdk, so use those variables where ever possible PATH_SDK_WINDDKW2K_LIB.x86 ?= $(PATH_SDK_WINDDK_LIB_W2K.x86) PATH_SDK_WINDDKW2K_LIB ?= $(PATH_SDK_WINDDKW2K_LIB.x86) kbuild-3149/kBuild/sdks/WINDDK80W8.kmk0000644000175000017500000000401613252530251017134 0ustar locutuslocutus# $Id: WINDDK80W8.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - The Microsoft Windows 8 DDKs, Targeting Windows 8 (KBUILD_TARGET_ARCH). # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_WINDDK80W8 := The Microsoft Windows 8 DDKs, Targeting Windows 8 (KBUILD_TARGET_ARCH). SDK_WINDDK80W8_EXTENDS = WINDDK80 SDK_WINDDK80W8_DEFS ?= WIN32=100 _WIN32_WINNT=0x0602 WINVER=0x0602 _WIN32_IE=0x0A00 NTDDI_VERSION=0x06020000 \ KMDF_MAJOR_VERSION=01 KMDF_MINOR_VERSION=005 SDK_WINDDK80W8_LIBPATH.amd64 ?= $(PATH_SDK_WINDDK80_LIB_W8.amd64) SDK_WINDDK80W8_LIBPATH.x86 ?= $(PATH_SDK_WINDDK80_LIB_W8.x86) # SDK Specific Properties. # Note! extends the WINDDK80 sdk, so use those variables where ever possible PATH_SDK_WINDDK80W8_LIB.amd64?= $(PATH_SDK_WINDDK80_LIB_W8.amd64) PATH_SDK_WINDDK80W8_LIB.x86 ?= $(PATH_SDK_WINDDK80_LIB_W8.x86) PATH_SDK_WINDDK80W8_LIB ?= $(PATH_SDK_WINDDK80W8_LIB.$(KBUILD_TARGET_ARCH)) kbuild-3149/kBuild/sdks/WINPSDKINCS.kmk0000644000175000017500000000736513252530251017373 0ustar locutuslocutus# $Id: WINPSDKINCS.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - The Windows Platform SDK, targeting (KBUILD_TARGET) but # without any libraries or LIBPATH properties. # Basically for finding specstrings.h when using the DDK. # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_WINPSDKINCS := The Windows Platform SDK, targeting (KBUILD_TARGET) but \ without any library or LIBPATH properties. \ Basically for finding specstrings.h when using the DDK. # SDK Specific Properties ifndef PATH_SDK_WINPSDKINCS ifdef PATH_SDK_WINPSDK PATH_SDK_WINPSDKINCS := $(PATH_SDK_WINPSDK) else PATH_SDK_WINPSDKINCS := $(wildcard $(PATH_DEVTOOLS_BLD)/sdk/2*) ifeq ($(PATH_SDK_WINPSDKINCS),) PATH_SDK_WINPSDKINCS := $(wildcard $(PATH_DEVTOOLS_TRG)/sdk/2*) endif ifeq ($(PATH_SDK_WINPSDKINCS),) PATH_SDK_WINPSDKINCS := $(wildcard $(PATH_DEVTOOLS)/win.x86/sdk/2*) endif ifeq ($(PATH_SDK_WINPSDKINCS),) PATH_SDK_WINPSDKINCS := $(wildcard $(PATH_DEVTOOLS)/x86.win32/sdk/2*) endif ifeq ($(PATH_SDK_WINPSDKINCS),) PATH_SDK_WINPSDKINCS := $(wildcard $(PATH_DEVTOOLS)/win.amd64/sdk/2*) endif ifneq ($(PATH_SDK_WINPSDKINCS),) PATH_SDK_WINPSDKINCS := $(lastword $(sort $(PATH_SDK_WINPSDKINCS))) else $(warning kBuild: PATH_SDK_WINPSDKINCS couldn't be determined!) PATH_SDK_WINPSDKINCS := $(PATH_DEVTOOLS_BLD)/sdk/not/found endif endif else PATH_SDK_WINPSDKINCS := $(PATH_SDK_WINPSDKINCS) endif ifndef PATH_SDK_WINPSDKINCS_INC PATH_SDK_WINPSDKINCS_INC := $(firstword $(wildcard $(PATH_SDK_WINPSDKINCS)/[Ii][Nn][Cc][Ll][Uu][Dd][Ee]) $(PATH_SDK_WINPSDKINCS)/Include) endif ifndef PATH_SDK_WINPSDKINCS_LIB.x86 PATH_SDK_WINPSDKINCS_LIB.x86 := $(firstword $(wildcard $(PATH_SDK_WINPSDKINCS)/[Ll][Ii][Bb]) $(PATH_SDK_WINPSDKINCS)/Lib) endif ifndef PATH_SDK_WINPSDKINCS_LIB.amd64 PATH_SDK_WINPSDKINCS_LIB.amd64 := $(firstword $(wildcard $(PATH_SDK_WINPSDKINCS)/[Ll][Ii][Bb]/[Aa][Mm][Dd]64) $(PATH_SDK_WINPSDKINCS)/Lib/AMD64) endif PATH_SDK_WINPSDKINCS_LIB ?= $(PATH_SDK_WINPSDKINCS_LIB.$(KBUILD_TARGET_ARCH)) ifndef PATH_SDK_WINPSDKINCS_BIN PATH_SDK_WINPSDKINCS_BIN := $(firstword $(wildcard $(PATH_SDK_WINPSDKINCS)/[Bb][Ii][Nn]) $(PATH_SDK_WINPSDKINCS)/Bin) endif ifndef PATH_SDK_WINPSDKINCS_BIN_AMD64 PATH_SDK_WINPSDKINCS_BIN_AMD64 := $(firstword $(wildcard $(PATH_SDK_WINPSDKINCS_BIN)/[Ww][Ii][Nn]64/[Xx]86/[Aa][Mm][Dd]64) $(PATH_SDK_WINPSDKINCS_BIN)/win64/AMD64) endif ifndef PATH_SDK_WINPSDKINCS_BIN_IA64 PATH_SDK_WINPSDKINCS_BIN_IA64 := $(firstword $(wildcard $(PATH_SDK_WINPSDKINCS_BIN)/[Ww][Ii][Nn]64) $(PATH_SDK_WINPSDKINCS_BIN)/win64) endif # General Properties used by kBuild SDK_WINPSDKINCS_INCS ?= $(PATH_SDK_WINPSDKINCS_INC) kbuild-3149/kBuild/sdks/W2K3DDKAMD64.kmk0000644000175000017500000000513613252530251017276 0ustar locutuslocutus# $Id: W2K3DDKAMD64.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - The Microsoft Windows 2003 DDK, targeting amd64. # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_W2K3DDKAMD64 := The Microsoft Windows 2003 DDK, targeting amd64. # SDK Specific Properties ifndef PATH_SDK_W2K3DDKAMD64 PATH_SDK_W2K3DDKAMD64 := $(wildcard $(PATH_DEVTOOLS)/win.amd64/ddkwin2k3/2*) ifeq ($(PATH_SDK_W2K3DDKAMD64),) PATH_SDK_W2K3DDKAMD64 := $(PATH_SDK_W2K3DDK) endif ifeq ($(PATH_SDK_W2K3DDKAMD64),) PATH_SDK_W2K3DDKAMD64 := $(wildcard $(PATH_DEVTOOLS)/win.x86/ddkwin2k3/2*) endif # legacy: ifeq ($(PATH_SDK_W2K3DDKAMD64),) PATH_SDK_W2K3DDKAMD64 := $(wildcard $(PATH_DEVTOOLS)/x86.win32/ddkwin2k3/2*) endif ifneq ($(PATH_SDK_W2K3DDKAMD64),) PATH_SDK_W2K3DDKAMD64 := $(lastword $(sort $(PATH_SDK_W2K3DDKAMD64))) else $(warning kBuild: PATH_SDK_W2K3DDKAMD64 couldn't be determined!) PATH_SDK_W2K3DDKAMD64 := $(PATH_DEVTOOLS)/win.amd64/ddkwin2k3/not/found endif else # Resolve any fancy stuff once and for all. PATH_SDK_W2K3DDKAMD64 := $(PATH_SDK_W2K3DDKAMD64) endif PATH_SDK_W2K3DDKAMD64_INC ?= $(PATH_SDK_W2K3DDKAMD64)/inc PATH_SDK_W2K3DDKAMD64_LIB ?= $(PATH_SDK_W2K3DDKAMD64)/lib/wnet/AMD64 # General Properties used by kBuild SDK_W2K3DDKAMD64_DEFS ?= _AMD64_ SDK_W2K3DDKAMD64_INCS ?= \ $(PATH_SDK_W2K3DDKAMD64_INC)/ddk \ $(PATH_SDK_W2K3DDKAMD64_INC)/ddk/wnet \ $(PATH_SDK_W2K3DDKAMD64_INC)/wnet \ $(PATH_SDK_W2K3DDKAMD64_INC)/ddk/wdm/wnet SDK_W2K3DDKAMD64_LIBPATH ?= \ $(PATH_SDK_W2K3DDKAMD64_LIB) kbuild-3149/kBuild/sdks/WINDDK71WNET.kmk0000644000175000017500000000424413252530251017416 0ustar locutuslocutus# $Id: WINDDK71WNET.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - The Microsoft Windows 7 DDKs, v7.1, Targeting Windows Server 2003 (KBUILD_TARGET_ARCH). # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_WINDDK71WNET := The Microsoft Windows 7 DDKs, v7.1, Targeting Windows Server 2003 (KBUILD_TARGET_ARCH). SDK_WINDDK71WNET_EXTENDS = WINDDK71 SDK_WINDDK71WNET_DEFS ?= WIN32=100 _WIN32_WINNT=0x0502 WINVER=0x0502 _WIN32_IE=0x0603 NTDDI_VERSION=0x05020100 SDK_WINDDK71WNET_LIBPATH.amd64 ?= $(PATH_SDK_WINDDK71_LIB_WNET.amd64) SDK_WINDDK71WNET_LIBPATH.ia64 ?= $(PATH_SDK_WINDDK71_LIB_WNET.ia64) SDK_WINDDK71WNET_LIBPATH.x86 ?= $(PATH_SDK_WINDDK71_LIB_WNET.x86) # SDK Specific Properties. # Note! extends the WINDDK71 sdk, so use those variables where ever possible PATH_SDK_WINDDK71WNET_LIB.amd64?= $(PATH_SDK_WINDDK71_LIB_WNET.amd64) PATH_SDK_WINDDK71WNET_LIB.ia64 ?= $(PATH_SDK_WINDDK71_LIB_WNET.ia64) PATH_SDK_WINDDK71WNET_LIB.x86 ?= $(PATH_SDK_WINDDK71_LIB_WNET.x86) PATH_SDK_WINDDK71WNET_LIB ?= $(PATH_SDK_WINDDK71WNET_LIB.$(KBUILD_TARGET_ARCH)) kbuild-3149/kBuild/sdks/WINDDKWNET.kmk0000644000175000017500000000423013252530250017240 0ustar locutuslocutus# $Id: WINDDKWNET.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - The Microsoft Windows Vista and Server 2008 DDKs, Targeting Windows Server 2003 (KBUILD_TARGET_ARCH). # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_WINDDKWNET := The Microsoft Windows Vista and Server 2008 DDKs, Targeting Windows Server 2003 (KBUILD_TARGET_ARCH). SDK_WINDDKWNET_EXTENDS = WINDDK SDK_WINDDKWNET_DEFS ?= WIN32=100 _WIN32_WINNT=0x0502 WINVER=0x0502 _WIN32_IE=0x0603 NTDDI_VERSION=0x05020100 SDK_WINDDKWNET_LIBPATH.amd64 ?= $(PATH_SDK_WINDDK_LIB_WNET.amd64) SDK_WINDDKWNET_LIBPATH.ia64 ?= $(PATH_SDK_WINDDK_LIB_WNET.ia64) SDK_WINDDKWNET_LIBPATH.x86 ?= $(PATH_SDK_WINDDK_LIB_WNET.x86) # SDK Specific Properties. # Note! extends the WINDDK sdk, so use those variables where ever possible PATH_SDK_WINDDKWNET_LIB.amd64?= $(PATH_SDK_WINDDK_LIB_WNET.amd64) PATH_SDK_WINDDKWNET_LIB.ia64 ?= $(PATH_SDK_WINDDK_LIB_WNET.ia64) PATH_SDK_WINDDKWNET_LIB.x86 ?= $(PATH_SDK_WINDDK_LIB_WNET.x86) PATH_SDK_WINDDKWNET_LIB ?= $(PATH_SDK_WINDDKWNET_LIB.$(KBUILD_TARGET_ARCH)) kbuild-3149/kBuild/sdks/MACOSX104.kmk0000644000175000017500000000400413252530251017001 0ustar locutuslocutus# $Id: MACOSX104.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - Mac OS X v10.4 SDK. # # # Copyright (c) 2008-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_MACOSX104 := Mac OS X v10.4 SDK # SDK Specific Properties ifndef PATH_SDK_MACOSX104 PATH_SDK_MACOSX104 := /Developer/SDKs/MacOSX10.4u.sdk else # Resolve any fancy stuff once and for all. PATH_SDK_MACOSX104 := $(PATH_SDK_MACOSX104) endif # General Properties (used by kBuild) # Note: The MAC_OS_X_VERSION_MAX_ALLOWED is left free for the SDK user to define. SDK_MACOSX104_DEFS ?= MAC_OS_X_VERSION_MIN_REQUIRED=1040 SDK_MACOSX104_CFLAGS ?= -mmacosx-version-min=10.4 -isysroot $(PATH_SDK_MACOSX104) SDK_MACOSX104_CXXFLAGS ?= -mmacosx-version-min=10.4 -isysroot $(PATH_SDK_MACOSX104) SDK_MACOSX104_OBJCFLAGS ?= -mmacosx-version-min=10.4 -isysroot $(PATH_SDK_MACOSX104) SDK_MACOSX104_LDFLAGS ?= -mmacosx-version-min=10.4 -Wl,-syslibroot,$(PATH_SDK_MACOSX104) kbuild-3149/kBuild/sdks/WINPSDK71.kmk0000644000175000017500000001513213252530250017054 0ustar locutuslocutus# $Id: WINPSDK71.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - The Windows Platform SDK v7.1, targeting (KBUILD_TARGET). # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_WINPSDK71 := The Windows Platform SDK v7.1, targeting (KBUILD_TARGET). # SDK Specific Properties ifndef PATH_SDK_WINPSDK71 PATH_SDK_WINPSDK71 := $(wildcard $(PATH_DEVTOOLS_BLD)/sdk/v7.1*) ifeq ($(PATH_SDK_WINPSDK71),) PATH_SDK_WINPSDK71 := $(wildcard $(PATH_DEVTOOLS_TRG)/sdk/v7.1*) endif ifeq ($(PATH_SDK_WINPSDK71),) PATH_SDK_WINPSDK71 := $(wildcard $(PATH_DEVTOOLS)/win.x86/sdk/v7.1*) endif ifeq ($(PATH_SDK_WINPSDK71),) PATH_SDK_WINPSDK71 := $(wildcard $(PATH_DEVTOOLS)/win.amd64/sdk/v7.1*) endif ifneq ($(PATH_SDK_WINPSDK71),) PATH_SDK_WINPSDK71 := $(lastword $(sort $(PATH_SDK_WINPSDK71))) else $(warning kBuild: PATH_SDK_WINPSDK71 couldn't be determined!) PATH_SDK_WINPSDK71 := $(PATH_DEVTOOLS_BLD)/sdk/v7.1-not-found endif else PATH_SDK_WINPSDK71 := $(PATH_SDK_WINPSDK71) endif ifndef PATH_SDK_WINPSDK71_INC PATH_SDK_WINPSDK71_INC := $(firstword $(wildcard $(PATH_SDK_WINPSDK71)/[Ii][Nn][Cc][Ll][Uu][Dd][Ee]) $(PATH_SDK_WINPSDK71)/Include) endif ifndef PATH_SDK_WINPSDK71_LIB.x86 PATH_SDK_WINPSDK71_LIB.x86 := $(firstword $(wildcard $(PATH_SDK_WINPSDK71)/[Ll][Ii][Bb]) $(PATH_SDK_WINPSDK71)/Lib) endif ifndef PATH_SDK_WINPSDK71_LIB.amd64 PATH_SDK_WINPSDK71_LIB.amd64 := $(firstword $(wildcard $(PATH_SDK_WINPSDK71)/[Ll][Ii][Bb]/[Aa][Mm][Dd]64 $(PATH_SDK_WINPSDK71)/[Ll][Ii][Bb]/[xX]64) $(PATH_SDK_WINPSDK71)/Lib/AMD64) endif ifndef PATH_SDK_WINPSDK71_LIB.ia64 PATH_SDK_WINPSDK71_LIB.ia64 := $(firstword $(wildcard $(PATH_SDK_WINPSDK71)/[Ll][Ii][Bb]/[Ii][Aa]64) $(PATH_SDK_WINPSDK71)/Lib/IA64) endif PATH_SDK_WINPSDK71_LIB ?= $(PATH_SDK_WINPSDK71_LIB.$(KBUILD_TARGET_ARCH)) ifndef PATH_SDK_WINPSDK71_BIN PATH_SDK_WINPSDK71_BIN := $(firstword $(wildcard $(PATH_SDK_WINPSDK71)/[Bb][Ii][Nn]) $(PATH_SDK_WINPSDK71)/Bin) endif ifndef PATH_SDK_WINPSDK71_BIN_AMD64 PATH_SDK_WINPSDK71_BIN_AMD64 := $(firstword $(wildcard $(PATH_SDK_WINPSDK71_BIN)/[Ww][Ii][Nn]64/[Xx]86/[Aa][Mm][Dd]64 $(PATH_SDK_WINPSDK71_BIN)/[Ww][Ii][Nn]64/[Xx]86) $(PATH_SDK_WINPSDK71_BIN)/win64/AMD64) endif ifndef PATH_SDK_WINPSDK71_BIN_IA64 PATH_SDK_WINPSDK71_BIN_IA64 := $(firstword $(wildcard $(PATH_SDK_WINPSDK71_BIN)/[Ww][Ii][Nn]64) $(PATH_SDK_WINPSDK71_BIN)/win64) endif # General Properties used by kBuild SDK_WINPSDK71_INCS ?= $(PATH_SDK_WINPSDK71_INC) SDK_WINPSDK71_LIBPATH.x86 ?= $(PATH_SDK_WINPSDK71_LIB.x86) SDK_WINPSDK71_LIBPATH.amd64 ?= $(PATH_SDK_WINPSDK71_LIB.amd64) SDK_WINPSDK71_LIBPATH.ia64 ?= $(PATH_SDK_WINPSDK71_LIB.ia64) SDK_WINPSDK71_LIBS.x86 ?= \ $(PATH_SDK_WINPSDK71_LIB.x86)/Kernel32.Lib \ $(PATH_SDK_WINPSDK71_LIB.x86)/User32.Lib \ $(PATH_SDK_WINPSDK71_LIB.x86)/Gdi32.Lib \ $(PATH_SDK_WINPSDK71_LIB.x86)/AdvAPI32.Lib \ $(PATH_SDK_WINPSDK71_LIB.x86)/shell32.lib \ $(PATH_SDK_WINPSDK71_LIB.x86)/ShLwApi.Lib \ $(PATH_SDK_WINPSDK71_LIB.x86)/SetupAPI.Lib \ $(PATH_SDK_WINPSDK71_LIB.x86)/Uuid.Lib \ $(PATH_SDK_WINPSDK71_LIB.x86)/Version.Lib \ $(PATH_SDK_WINPSDK71_LIB.x86)/WS2_32.Lib \ \ $(PATH_SDK_WINPSDK71_LIB.x86)/Ole32.Lib \ $(PATH_SDK_WINPSDK71_LIB.x86)/OleAut32.Lib \ $(PATH_SDK_WINPSDK71_LIB.x86)/OleDlg.Lib \ $(PATH_SDK_WINPSDK71_LIB.x86)/RpcRT4.Lib \ \ $(PATH_SDK_WINPSDK71_LIB.x86)/DbgHelp.Lib \ $(PATH_SDK_WINPSDK71_LIB.x86)/ImageHlp.Lib \ $(PATH_SDK_WINPSDK71_LIB.x86)/IPHlpApi.Lib \ $(PATH_SDK_WINPSDK71_LIB.x86)/ComCtl32.Lib \ $(PATH_SDK_WINPSDK71_LIB.x86)/ComDlg32.Lib \ $(PATH_SDK_WINPSDK71_LIB.x86)/WinSpool.Lib \ $(PATH_SDK_WINPSDK71_LIB.x86)/WinMM.Lib SDK_WINPSDK71_LIBS.amd64 ?= \ $(PATH_SDK_WINPSDK71_LIB.amd64)/Kernel32.Lib \ $(PATH_SDK_WINPSDK71_LIB.amd64)/User32.Lib \ $(PATH_SDK_WINPSDK71_LIB.amd64)/Gdi32.Lib \ $(PATH_SDK_WINPSDK71_LIB.amd64)/AdvAPI32.Lib \ $(PATH_SDK_WINPSDK71_LIB.amd64)/Shell32.Lib \ $(PATH_SDK_WINPSDK71_LIB.amd64)/ShLwApi.Lib \ $(PATH_SDK_WINPSDK71_LIB.amd64)/SetupAPI.Lib \ $(PATH_SDK_WINPSDK71_LIB.amd64)/Uuid.Lib \ $(PATH_SDK_WINPSDK71_LIB.amd64)/Version.Lib \ $(PATH_SDK_WINPSDK71_LIB.amd64)/WS2_32.Lib \ \ $(PATH_SDK_WINPSDK71_LIB.amd64)/Ole32.Lib \ $(PATH_SDK_WINPSDK71_LIB.amd64)/OleAut32.Lib \ $(PATH_SDK_WINPSDK71_LIB.amd64)/OleDlg.Lib \ $(PATH_SDK_WINPSDK71_LIB.amd64)/RpcRT4.Lib \ \ $(PATH_SDK_WINPSDK71_LIB.amd64)/DbgHelp.Lib \ $(PATH_SDK_WINPSDK71_LIB.amd64)/ImageHlp.Lib \ $(PATH_SDK_WINPSDK71_LIB.amd64)/IPHlpApi.Lib \ $(PATH_SDK_WINPSDK71_LIB.amd64)/ComCtl32.Lib \ $(PATH_SDK_WINPSDK71_LIB.amd64)/ComDlg32.Lib \ $(PATH_SDK_WINPSDK71_LIB.amd64)/WinSpool.Lib \ $(PATH_SDK_WINPSDK71_LIB.amd64)/WinMM.Lib SDK_WINPSDK71_LIBS.ia64 ?= \ $(PATH_SDK_WINPSDK71_LIB.ia64)/Kernel32.Lib \ $(PATH_SDK_WINPSDK71_LIB.ia64)/User32.Lib \ $(PATH_SDK_WINPSDK71_LIB.ia64)/Gdi32.Lib \ $(PATH_SDK_WINPSDK71_LIB.ia64)/AdvAPI32.Lib \ $(PATH_SDK_WINPSDK71_LIB.ia64)/Shell32.Lib \ $(PATH_SDK_WINPSDK71_LIB.ia64)/ShLwApi.Lib \ $(PATH_SDK_WINPSDK71_LIB.ia64)/SetupAPI.Lib \ $(PATH_SDK_WINPSDK71_LIB.ia64)/Uuid.Lib \ $(PATH_SDK_WINPSDK71_LIB.ia64)/Version.Lib \ $(PATH_SDK_WINPSDK71_LIB.ia64)/WS2_32.Lib \ \ $(PATH_SDK_WINPSDK71_LIB.ia64)/Ole32.Lib \ $(PATH_SDK_WINPSDK71_LIB.ia64)/OleAut32.Lib \ $(PATH_SDK_WINPSDK71_LIB.ia64)/OleDlg.Lib \ $(PATH_SDK_WINPSDK71_LIB.ia64)/RpcRT4.Lib \ \ $(PATH_SDK_WINPSDK71_LIB.ia64)/DbgHelp.Lib \ $(PATH_SDK_WINPSDK71_LIB.ia64)/ImageHlp.Lib \ $(PATH_SDK_WINPSDK71_LIB.ia64)/IPHlpApi.Lib \ $(PATH_SDK_WINPSDK71_LIB.ia64)/ComCtl32.Lib \ $(PATH_SDK_WINPSDK71_LIB.ia64)/ComDlg32.Lib \ $(PATH_SDK_WINPSDK71_LIB.ia64)/WinSpool.Lib \ $(PATH_SDK_WINPSDK71_LIB.ia64)/WinMM.Lib kbuild-3149/kBuild/sdks/WIN32SDK2002.kmk0000644000175000017500000000670413252530251017243 0ustar locutuslocutus# $Id: WIN32SDK2002.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - Windows Platform SDK (from ~2002), targeting x86. # Differs in that it has ddraw.lib and dxguid.lib. # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_WIN32SDK2002 := Windows Platform SDK (from ~2002), targeting x86. \ Differs in that it has ddraw.lib and dxguid.lib. # SDK Specific Properties ifndef PATH_SDK_WIN32SDK2002 PATH_SDK_WIN32SDK2002 := $(wildcard $(PATH_DEVTOOLS)/win.x86/sdk/2002*) ifeq ($(PATH_SDK_WIN32SDK2002),) PATH_SDK_WIN32SDK2002 := $(wildcard $(PATH_DEVTOOLS)/x86.win32/sdk/2002*) endif ifeq ($(PATH_SDK_WIN32SDK2002),) PATH_SDK_WIN32SDK2002 := $(wildcard $(PATH_DEVTOOLS)/x86.win32/sdk2002*) endif ifneq ($(PATH_SDK_WIN32SDK2002),) PATH_SDK_WIN32SDK2002 := $(lastword $(sort $(PATH_SDK_WIN32SDK2002))) else $(warning kBuild: PATH_SDK_WIN32SDK2002 couldn't be determined!) PATH_SDK_WIN32SDK2002 := $(PATH_DEVTOOLS)/win.x86/sdk/2002/not/found endif else # Resolve any fancy stuff once and for all. PATH_SDK_WIN32SDK2002 := $(PATH_SDK_WIN32SDK2002) endif PATH_SDK_WIN32SDK2002_INC ?= $(PATH_SDK_WIN32SDK2002)/include PATH_SDK_WIN32SDK2002_LIB ?= $(PATH_SDK_WIN32SDK2002)/lib # General Properties used by kBuild SDK_WIN32SDK2002_INCS ?= $(PATH_SDK_WIN32SDK2002_INC) SDK_WIN32SDK2002_LIBPATH ?= $(PATH_SDK_WIN32SDK2002_LIB) SDK_WIN32SDK2002_LIBS ?= \ $(PATH_SDK_WIN32SDK2002_LIB)/Kernel32.Lib \ $(PATH_SDK_WIN32SDK2002_LIB)/User32.Lib \ $(PATH_SDK_WIN32SDK2002_LIB)/Gdi32.Lib \ $(PATH_SDK_WIN32SDK2002_LIB)/AdvAPI32.Lib \ $(PATH_SDK_WIN32SDK2002_LIB)/Shell32.Lib \ $(PATH_SDK_WIN32SDK2002_LIB)/ShLwApi.Lib \ $(PATH_SDK_WIN32SDK2002_LIB)/SetupAPI.Lib \ $(PATH_SDK_WIN32SDK2002_LIB)/Uuid.Lib \ $(PATH_SDK_WIN32SDK2002_LIB)/Version.Lib \ $(PATH_SDK_WIN32SDK2002_LIB)/WS2_32.Lib \ \ $(PATH_SDK_WIN32SDK2002_LIB)/Ole32.Lib \ $(PATH_SDK_WIN32SDK2002_LIB)/OleAut32.Lib \ $(PATH_SDK_WIN32SDK2002_LIB)/OleDlg.Lib \ $(PATH_SDK_WIN32SDK2002_LIB)/RpcRT4.Lib \ \ $(PATH_SDK_WIN32SDK2002_LIB)/DbgHelp.Lib \ $(PATH_SDK_WIN32SDK2002_LIB)/ImageHlp.Lib \ $(PATH_SDK_WIN32SDK2002_LIB)/IPHlpApi.Lib \ $(PATH_SDK_WIN32SDK2002_LIB)/ddraw.lib \ $(PATH_SDK_WIN32SDK2002_LIB)/dxguid.lib \ $(PATH_SDK_WIN32SDK2002_LIB)/ComCtl32.Lib \ $(PATH_SDK_WIN32SDK2002_LIB)/ComDlg32.Lib \ $(PATH_SDK_WIN32SDK2002_LIB)/WinSpool.Lib \ $(PATH_SDK_WIN32SDK2002_LIB)/WinMM.Lib kbuild-3149/kBuild/sdks/MACOSX104INCS.kmk0000644000175000017500000000333413252530251017463 0ustar locutuslocutus# $Id: MACOSX104INCS.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild SDK - Mac OS X v10.4 SDK, includes only. # # # Copyright (c) 2008-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # SDK_MACOSX104INCS := Mac OS X v10.4 SDK # SDK Specific Properties ifndef PATH_SDK_MACOSX104INCS ifdef PATH_SDK_MACOSX104 PATH_SDK_MACOSX104INCS := $(PATH_SDK_MACOSX104) else PATH_SDK_MACOSX104INCS := /Developer/SDKs/MacOSX10.4u.sdk endif else # Resolve any fancy stuff once and for all. PATH_SDK_MACOSX104INCS := $(PATH_SDK_MACOSX104INCS) endif # General Properties (used by kBuild) SDK_MACOSX104INCS_INCS = $(PATH_SDK_MACOSX104INCS)/usr/include kbuild-3149/kBuild/footer-pass2-compiling-targets.kmk0000644000175000017500000011047013252530215022575 0ustar locutuslocutus# $Id: footer-pass2-compiling-targets.kmk 3135 2018-03-01 18:45:26Z bird $ ## @file # kBuild - Footer - Target lists - Pass 2 - Compiling Targets. # # # Copyright (c) 2004-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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 source of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # # # Object processing. # ## wrapper the compile command dependency check. ifndef NO_COMPILE_CMDS_DEPS if1of ($(KMK_FEATURES),dot-must-make) _DEP_COMPILE_CMDS = # for debugging: $$(warning MUST_MAKE=$$$$(comp-cmds-ex $$$$($(target)_$(subst :,_,$(source))_CMDS_PREV_), $$$$(commands $$@)) -> $$(comp-cmds-ex $$($(target)_$(subst :,_,$(source))_CMDS_PREV_),$$(commands $$@),FORCE)) else _DEP_COMPILE_CMDS = $$(comp-cmds-ex $$($(target)_$(subst :,_,$(source))_CMDS_PREV_),$$(commands $(obj)),FORCE) endif else _DEP_COMPILE_CMDS = endif ## Temporary for the compile rule below. if "$(KBUILD_KMK_REVISION)" >= 3134 KBUILD_HAVE_OPTIMIZED_APPEND := 1 endif ## Generates the rules for building a specific object, and the aliases # for building a source file. # @param $(obj) The object file. define def_target_source_rule ifndef NO_COMPILE_CMDS_DEPS $(obj): .MUST_MAKE = $$(comp-cmds-ex $$($(target)_$(subst :,_,$(source))_CMDS_PREV_),$$(commands $$@),FORCE) endif ifdef TOOL_$(tool)_COMPILE_$(type)_USES_KOBJCACHE _OUT_FILES += $(outbase).koc $(outbase).koc +| $(obj) $($(target)_$(source)_OUTPUT_) $($(target)_$(source)_OUTPUT_MAYBE_) : \ $($(target)_$(source)_DEPEND_) \ $(value _DEP_COMPILE_CMDS) \ | \ $($(target)_$(source)_DEPORD_) \ $$$$($(target)_INTERMEDIATES) \ $$$$($(target)_INTERMEDIATES.$(bld_trg)) \ $$$$($(target)_INTERMEDIATES.$(bld_trg).$(bld_trg_arch)) \ $$$$($(target)_INTERMEDIATES.$(bld_trg_arch)) \ $$$$($(target)_INTERMEDIATES.$(bld_trg_cpu)) \ $$$$($(target)_INTERMEDIATES.$(bld_type)) %$$(call MSG_COMPILE,$(target),$(source),$$@,$(type)) else $(obj) + $($(target)_$(source)_OUTPUT_) +| $($(target)_$(source)_OUTPUT_MAYBE_) : \ $($(target)_$(source)_DEPEND_) \ $(value _DEP_COMPILE_CMDS) \ | \ $($(target)_$(source)_DEPORD_) \ $$$$($(target)_INTERMEDIATES) \ $$$$($(target)_INTERMEDIATES.$(bld_trg)) \ $$$$($(target)_INTERMEDIATES.$(bld_trg).$(bld_trg_arch)) \ $$$$($(target)_INTERMEDIATES.$(bld_trg_arch)) \ $$$$($(target)_INTERMEDIATES.$(bld_trg_cpu)) \ $$$$($(target)_INTERMEDIATES.$(bld_type)) %$$(call MSG_COMPILE,$(target),$(source),$$@,$(type)) ifndef TOOL_$(tool)_COMPILE_$(type)_DONT_PURGE_OUTPUT $$(QUIET)$$(RM) -f -- $(dep) $(obj) $($(target)_$(source)_OUTPUT_) $($(target)_OUTPUT_MAYBE_) endif endif $($(target)_$(source)_CMDS_) ifndef NO_COMPILE_CMDS_DEPS ifdef KBUILD_HAVE_OPTIMIZED_APPEND %$$(QUIET2)$$(APPEND) -in '$(dep)' \ '' \ 'define $(target)_$(subst :,_,$(source))_CMDS_PREV_' \ '--insert-command=$(obj)' \ 'endef' else %$$(QUIET2)$$(APPEND) -n '$(dep)' '' 'define $(target)_$(subst :,_,$(source))_CMDS_PREV_' %$$(QUIET2)$$(APPEND) -c '$(dep)' '$(obj)' %$$(QUIET2)$$(APPEND) '$(dep)' 'endef' endif endif $(basename $(notdir $(obj))).o: $(obj) $(basename $(notdir $(obj))).obj: $(obj) ## @todo make this 'local cmds,output,output_maybe,depend and depord' in 0.2.x or when a new kb-src-one is added. $(target)_$(source)_CMDS_ := $(target)_$(source)_OUTPUT_ := $(target)_$(source)_OUTPUT_MAYBE_ := $(target)_$(source)_DEPEND_ := $(target)_$(source)_DEPORD_ := endef # def_target_source_rule $(eval-opt-var def_target_source_rule) ## wrapper the link command dependency check. ifndef NO_LINK_CMDS_DEPS if1of ($(KMK_FEATURES),dot-must-make) _DEP_LINK_CMDS = else _DEP_LINK_CMDS = $$(comp-cmds-ex $$($(target)_CMDS_PREV_),$$(commands $(out)),FORCE) endif else _DEP_LINK_CMDS = endif ## Generate the link rule for a target. # @param $(target) The normalized target name. # @param $(dirdep) Directories we depend upon begin created before linking. # @param $(dep) The name of the dependency file. # @param $(out) # @param $($(target)_2_OUTPUT) Output files from the link. # @param $($(target)_2_OUTPUT_MAYBE) Output files that the link may perhaps create. # @param $($(target)_2_OUTPUT_MAYBE_PRECIOUS) Output files that the link may perhaps create but shouldn't be deleted. # @param $($(target)_2_DEPEND) Dependencies. # @param $($(target)_2_DEPORD) Dependencies which should only affect build order. # @param $(cmds) The link commands. # @param $($(target)_CMDS_PREV_) The link commands from the previous run. define def_link_rule $$(call KB_FN_ASSERT_ABSPATH,out) ifndef NO_LINK_CMDS_DEPS $(out): .MUST_MAKE = $$(comp-cmds-ex $$($(target)_CMDS_PREV_),$$(commands $$@),FORCE) endif $(out) \ + $($(target)_2_OUTPUT) \ + $($(target)_2_OUTPUT_DEBUG_FILES) \ + $($(target)_2_OUTPUT_DEBUG_DIRS) \ +| $($(target)_2_OUTPUT_MAYBE) $($(target)_2_OUTPUT_MAYBE_PRECIOUS) : \ $$$$($(target)_2_DEPEND) \ $(value _DEP_LINK_CMDS) \ | \ $$$$($(target)_2_DEPORD) %$$(call MSG_LINK,$(target),$$@,$(tool_do)) $$(QUIET)$$(RM) -f -- $(dep) $(out) $($(target)_2_OUTPUT) $($(target)_2_OUTPUT_MAYBE) $($(target)_2_OUTPUT_DEBUG_FILES) ifdef $(target)_2_OUTPUT_DEBUG_DIRS $$(QUIET)$$(RM) -Rf -- $($(target)_2_OUTPUT_DEBUG_DIRS) endif $(cmds) ifndef NO_LINK_CMDS_DEPS %$$(QUIET2)$$(APPEND) '$(dep)' 'define $(target)_CMDS_PREV_' %$$(QUIET2)$$(APPEND) -c '$(dep)' '$(out)' %$$(QUIET2)$$(APPEND) '$(dep)' 'endef' endif $(basename $(notdir $(out))):: $(out) endef # def_link_rule $(eval-opt-var def_link_rule) ## Generate the link & lib install rule # Implicit parameters: target, out, $(target)_1_STAGE_TARGET, mode, # pre_install_cmds, post_install_cmds define def_link_install_rule $$(call KB_FN_ASSERT_ABSPATH,$(target)_1_INST_TARGET) $($(target)_1_INST_TARGET): $(out) | $$$$(dir $$$$@) %$$(call MSG_INST_TRG,$(target),$(out),$$@) $(pre_install_cmds) $$(QUIET)$$(INSTALL) $(if $(mode),-m $(mode)) $(if $(uid),-o $(uid)) $(if $(gid),-g $(gid)) -- $(out) $$@ $(post_install_cmds) endef ## Generate the link & lib stage installation rule # Implicit parameters: target, out, $(target)_1_STAGE_TARGET, mode, # pre_install_cmds, post_install_cmds define def_link_stage_rule $$(call KB_FN_ASSERT_ABSPATH,$(target)_1_STAGE_TARGET) $($(target)_1_STAGE_TARGET): $(out) | $$$$(dir $$$$@) %$$(call MSG_INST_TRG,$(target),$(out),$$@) $(pre_install_cmds) $$(QUIET)$$(INSTALL_STAGING) $(if $(mode),-m $(mode)) $(if $(uid),-o $(uid)) $(if $(gid),-g $(gid)) -- $(out) $$@ $(post_install_cmds) $(basename $(notdir $(out))):: $($(target)_1_STAGE_TARGET) endef ## def_src_handler_* # # @{ define def_src_handler_c local type := C $(kb-src-one 2) endef define def_src_handler_cxx local type := CXX $(kb-src-one 2) endef define def_src_handler_objc local type := OBJC $(kb-src-one 2) endef define def_src_handler_objcxx local type := OBJCXX $(kb-src-one 2) endef define def_src_handler_asm local type := AS $(kb-src-one 2) endef define def_src_handler_rc local type := RC $(kb-src-one 2) endef define def_src_handler_obj ifeq ($(defpath),) $(target)_2_OBJS += $(source) else $(target)_2_OBJS += $(abspathex $(source), $(defpath)) endif endef ## @} ## Handle one source. # . define def_src_handler_one local suff := $(suffix $(source)) local src_handler := $(firstword $(filter $(suff):%, $($(target)_$(source)_SRC_HANDLERS) $($(source)_SRC_HANDLERS) $(target_src_handlers) )) local handler := $(patsubst $(suff):%,%,$(src_handler)) ifneq ($(handler),) $(evalvalctx $(handler)) else othersrc += $(source) endif endef # def_src_handler_one ## Generic macro for processing all target sources. # @param $(target) Normalized target name. # @param $(defpath) # @param much-more... # @returns othersrc, $(target)_2_OBJS, ++ define def_target_sources local target_src_handlers := $($(target)_SRC_HANDLERS) $(KBUILD_SRC_HANDLERS) $(foreach source,\ $($(target)_SOURCES)\ $($(target)_SOURCES.$(bld_trg))\ $($(target)_SOURCES.$(bld_trg).$(bld_type))\ $($(target)_SOURCES.$(bld_trg).$(bld_trg_arch))\ $($(target)_SOURCES.$(bld_trg).$(bld_trg_arch).$(bld_type))\ $($(target)_SOURCES.$(bld_trg_arch))\ $($(target)_SOURCES.$(bld_trg_cpu))\ $($(target)_SOURCES.$(bld_type))\ ,$(evalvalctx def_src_handler_one) ) $(foreach source,\ $($(target)_GEN_SOURCES_)\ $($(target)_GEN_SOURCES_.$(bld_trg))\ $($(target)_GEN_SOURCES_.$(bld_trg).$(bld_type))\ $($(target)_GEN_SOURCES_.$(bld_trg).$(bld_trg_arch))\ $($(target)_GEN_SOURCES_.$(bld_trg).$(bld_trg_arch).$(bld_type))\ $($(target)_GEN_SOURCES_.$(bld_trg_arch))\ $($(target)_GEN_SOURCES_.$(bld_trg_cpu))\ $($(target)_GEN_SOURCES_.$(bld_type))\ ,$(evalvalctx def_src_handler_one) ) endef # def_target_sources $(eval-opt-var def_target_sources) ## # Install a debug directory. # @param debug_dir The directory name. define def_link_install_debug_dir_rule local dir := $(debug_inst_path)/$(debug_inst2)$(debug_dir) $$(call KB_FN_ASSERT_ABSPATH,dir) $$(dir): | $$$$(dir $$$$(patsubst %/,%,$$$$@)) %$$(call MSG_INST_DIR,$$@) $$(QUIET)$$(MKDIR) -p -- $$@ $(target)_2_DEBUG_$(debug_var)_TARGET_DIRS += $$(dir) endef # def_link_install_debug_dir_rule ## # Install a debug file. # @param debug_file Src=>Dst file pair. define def_link_install_debug_file_rule local dst := $(debug_inst_path)/$(debug_inst2)$(word 2, $(subst =>,$(SP),$(debug_file))) $$(call KB_FN_ASSERT_ABSPATH,dst) local src := $(word 1, $(subst =>,$(SP),$(debug_file))) $$(call KB_FN_ASSERT_ABSPATH,src) $$(dst): $$(src) | $$$$(dir $$$$@) %$$(call MSG_INST_FILE,$$<,$$@) $$(QUIET)$(debug_install_cmd) $(if $(mode),-m $(mode)) $(if $(uid),-o $(uid)) $(if $(gid),-g $(gid)) -- $$< $$@ $(target)_2_DEBUG_$(debug_var)_TARGET_FILES += $$(dst) endef # def_link_install_debug_file_rule ## # Install debug info to $(debug_inst), where debug_inst can be a directory or # file (just like $(inst) and $(stage). Used for both staging and installing. define def_target_install_only_debug if "$(substr $(debug_inst),-1,1)" == "/" if "$(debug_inst)" == "./" local debug_inst2 := else local debug_inst2 := $(debug_inst) endif local debug_dirs := $(patsubst $($(target)_0_OUTDIR)/%,%,$($(target)_2_OUTPUT_DEBUG_DIRS)) ifneq ($(strip $(root $(debug_dirs))),) $(error kBuild: Bad tool? debug_dirs='$(debug_dirs)', expected all to be under '$(outbase)') endif local debug_files := $(foreach file, $(patsubst $($(target)_0_OUTDIR)/%,%,$($(target)_2_OUTPUT_DEBUG_FILES)) \ ,$($(target)_0_OUTDIR)/$(file)=>$(file)) else local debug_notdir:= $(notdir $(debug_inst)) local debug_inst2 := $(dir $(debug_inst)) local debug_files := $(call TOOL_$(tool)_$(tool_do)_DEBUG_INSTALL_FN,$(out),$(outbase),$(debug_notdir)) local debug_dirs := $(filter %/,$(debug_files)) local debug_files := $(filter-out %/,$(debug_files)) endif $(foreach debug_dir, $(debug_dirs), $(eval $(def_link_install_debug_dir_rule))) $(foreach debug_file, $(debug_files), $(eval $(def_link_install_debug_file_rule))) endef ## Generic macro for generating the install rule(s) for a target. # # @param $(target) Normalized target name. # @param $(out) The output file. # @param $(typevar) The name of the variable with all the root targets of its type. # @param $(target_type_mode) The default file mode implied by the target type. define def_target_install_only if1of ($($(target)_1_INSTTYPE) $($(target)_1_DEBUG_INSTTYPE), both stage) # Determin common variables. local mode := $(firstword \ $($(target)_MODE.$(bld_trg).$(bld_trg_arch).$(bld_type)) \ $($(target)_MODE.$(bld_trg).$(bld_trg_arch)) \ $($(target)_MODE.$(bld_trg).$(bld_type)) \ $($(target)_MODE.$(bld_trg_arch)) \ $($(target)_MODE.$(bld_trg)) \ $($(target)_MODE.$(bld_type)) \ $($(target)_MODE) \ $(target_type_mode) ) local uid := $(firstword \ $($(target)_UID.$(bld_trg).$(bld_trg_arch).$(bld_type)) \ $($(target)_UID.$(bld_trg).$(bld_trg_arch)) \ $($(target)_UID.$(bld_trg).$(bld_type)) \ $($(target)_UID.$(bld_trg_arch)) \ $($(target)_UID.$(bld_trg)) \ $($(target)_UID.$(bld_type)) \ $($(target)_UID) ) local gid := $(firstword \ $($(target)_GID.$(bld_trg).$(bld_trg_arch).$(bld_type)) \ $($(target)_GID.$(bld_trg).$(bld_trg_arch)) \ $($(target)_GID.$(bld_trg).$(bld_type)) \ $($(target)_GID.$(bld_trg_arch)) \ $($(target)_GID.$(bld_trg)) \ $($(target)_GID.$(bld_type)) \ $($(target)_GID) ) local pre_install_cmds := $(evalcall def_fn_prop_get_first_defined,PRE_INST_CMDS) local post_install_cmds := $(evalcall def_fn_prop_get_first_defined,POST_INST_CMDS) endif ifneq ($($(target)_1_INSTTYPE),none) # Generate the rules ifeq ($($(target)_1_INSTTYPE),both) $(eval $(def_link_install_rule)) _INSTALLS_FILES += $($(target)_1_INST_TARGET) endif $(eval $(def_link_stage_rule)) _STAGE_FILES += $($(target)_1_STAGE_TARGET) $(typevar) += $($(target)_1_STAGE_TARGET) else # INSTTYPE == none $(typevar) += $(out) endif # INSTTYPE == none # Install debug info. $(target)_2_DEBUG_STAGE_TARGET_DIRS := $(target)_2_DEBUG_STAGE_TARGET_FILES := $(target)_2_DEBUG_INSTALL_TARGET_DIRS := $(target)_2_DEBUG_INSTALL_TARGET_FILES := if ( defined($(target)_2_OUTPUT_DEBUG_DIRS) \ || defined($(target)_2_OUTPUT_DEBUG_FILES) ) \ && "$($(target)_1_DEBUG_INSTTYPE)" != "none" local mode := $(if $(mode),$(mode)$(COMMA)a-x,0644) ifeq ($($(target)_1_DEBUG_INSTTYPE),both) local debug_inst_path := $(PATH_INS) local debug_install_cmd := $(INSTALL) local debug_var := INSTALL $(foreach debug_inst, $($(target)_1_DEBUG_INST), $(evalvalctx def_target_install_only_debug)) endif local debug_inst_path := $(PATH_STAGE) local debug_install_cmd := $(INSTALL_STAGING) local debug_var := STAGE if1of ($($(target)_1_DEBUG_INSTTYPE), stage both) $(foreach debug_inst, $($(target)_1_DEBUG_STAGE), $(evalvalctx def_target_install_only_debug)) endif if1of ($($(target)_1_INSTTYPE), stage both) ifndef debug_nostage $(foreach debug_inst,$($(target)_1_STAGE), $(evalvalctx def_target_install_only_debug)) endif endif _DEBUG_STAGE_DIRS += $($(target)_2_DEBUG_STAGE_TARGET_DIRS) _DEBUG_STAGE_FILES += $($(target)_2_DEBUG_STAGE_TARGET_FILES) _DEBUG_INSTALL_DIRS += $($(target)_2_DEBUG_INSTALL_TARGET_DIRS) _DEBUG_INSTALL_FILES += $($(target)_2_DEBUG_INSTALL_TARGET_FILES) $(basename $(notdir $(out))):: $($(target)_2_DEBUG_STAGE_TARGET_DIRS) $($(target)_2_DEBUG_STAGE_TARGET_FILES) endif endef # def_target_install_only # # LIBRARIES # ## Library (one). # @param $(target) Normalized library (target) name. define def_lib # library basics ## @todo prefix local bld_type := $(firstword $($(target)_BLD_TYPE) $(KBUILD_TYPE)) local bld_trg := $(firstword $($(target)_BLD_TRG) $(KBUILD_TARGET)) local bld_trg_arch:= $(firstword $($(target)_BLD_TRG_ARCH) $(KBUILD_TARGET_ARCH)) local bld_trg_cpu := $(firstword $($(target)_BLD_TRG_CPU) $(KBUILD_TARGET_CPU)) local tool := $(call _TARGET_TOOL,$(target),AR) ifeq ($(tool),) $(error kBuild: Library target $(target) does not have a tool defined!) endif local name := $(firstword\ $($(target)_NAME.$(bld_trg).$(bld_trg_arch).$(bld_type))\ $($(target)_NAME.$(bld_trg).$(bld_trg_arch))\ $($(target)_NAME.$(bld_trg).$(bld_type))\ $($(target)_NAME.$(bld_trg_arch))\ $($(target)_NAME.$(bld_trg))\ $($(target)_NAME.$(bld_type))\ $($(target)_NAME)\ $(target)) local outbase := $(call TARGET_BASE,$(name),$(target)) $(target)_0_OUTDIR:= $(patsubst %/,%,$(dir $(outbase))) $(call KB_FN_ASSIGN_DEPRECATED,PATH_$(target),$($(target)_0_OUTDIR), $(target)_0_OUTDIR) local suff := $(firstword\ $($(target)_LIBSUFF.$(bld_trg).$(bld_trg_arch))\ $($(target)_LIBSUFF.$(bld_trg))\ $($(target)_LIBSUFF)\ $(TOOL_$(tool)_ARLIBSUFF.$(bld_trg).$(bld_trg_arch))\ $(TOOL_$(tool)_ARLIBSUFF.$(bld_trg))\ $(TOOL_$(tool)_ARLIBSUFF)\ $(SUFF_LIB)) local out := $(outbase)$(suff) local defpath := $($(target)_DEFPATH) ifeq ($(defpath),) local defpath := $($(target)_PATH) endif $(target)_1_TARGET:= $(out) $(call KB_FN_ASSIGN_DEPRECATED,TARGET_$(target),$($(target)_1_TARGET), $(target)_1_TARGET) # no local here - must be writable across some foreachs. othersrc := $(target)_2_OBJS := # Do units pre source callouts. local units := \ $($(target)_USES.$(bld_trg).$(bld_trg_arch))\ $($(target)_USES.$(bld_trg_arch))\ $($(target)_USES.$(bld_trg))\ $($(target)_USES.$(bld_type))\ $($(target)_USES) $(foreach unit,$(units),$(evalvalctx def_unit_$(unit)_target_pre)) $(foreach unit,$(units),$(evalvalctx def_unit_$(unit)_target_pre_2)) # source -> object $(evalval def_target_sources) # library linking local tool := $(call _TARGET_TOOL,$(target),AR) local name := $(firstword\ $($(target)_NAME.$(bld_trg).$(bld_trg_arch).$(bld_type))\ $($(target)_NAME.$(bld_trg).$(bld_trg_arch))\ $($(target)_NAME.$(bld_trg).$(bld_type))\ $($(target)_NAME.$(bld_trg_arch))\ $($(target)_NAME.$(bld_trg))\ $($(target)_NAME.$(bld_type))\ $($(target)_NAME)\ $(target)) local outbase := $(call TARGET_BASE,$(name),$(target)) local flags :=\ $(TOOL_$(tool)_ARFLAGS)\ $(TOOL_$(tool)_ARFLAGS.$(bld_type))\ $(ARFLAGS)\ $(ARFLAGS.$(bld_type))\ $($(target)_ARFLAGS)\ $($(target)_ARFLAGS.$(bld_type)) \ $($(target)_ARFLAGS.$(bld_trg)) \ $($(target)_ARFLAGS.$(bld_trg_arch)) \ $($(target)_ARFLAGS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_ARFLAGS.$(bld_trg_cpu)) local dirdep := $(call DIRDEP,$(dir $(out))) local deps := \ $($(target)_DEPS.$(bld_trg_cpu)) \ $($(target)_DEPS.$(bld_trg).$(bld_trg_arch).$(bld_type)) \ $($(target)_DEPS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_DEPS.$(bld_trg).$(bld_type)) \ $($(target)_DEPS.$(bld_trg_arch)) \ $($(target)_DEPS.$(bld_trg)) \ $($(target)_DEPS.$(bld_type)) \ $($(target)_DEPS) \ $($(target)_LNK_DEPS.$(bld_trg_cpu)) \ $($(target)_LNK_DEPS.$(bld_trg).$(bld_trg_arch).$(bld_type)) \ $($(target)_LNK_DEPS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_LNK_DEPS.$(bld_trg).$(bld_type)) \ $($(target)_LNK_DEPS.$(bld_trg_arch)) \ $($(target)_LNK_DEPS.$(bld_trg)) \ $($(target)_LNK_DEPS.$(bld_type)) \ $($(target)_LNK_DEPS) local orderdeps := \ $($(target)_ORDERDEPS.$(bld_trg_cpu)) \ $($(target)_ORDERDEPS.$(bld_trg).$(bld_trg_arch).$(bld_type)) \ $($(target)_ORDERDEPS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_ORDERDEPS.$(bld_trg).$(bld_type)) \ $($(target)_ORDERDEPS.$(bld_trg_arch)) \ $($(target)_ORDERDEPS.$(bld_trg)) \ $($(target)_ORDERDEPS.$(bld_type)) \ $($(target)_ORDERDEPS) \ $($(target)_LNK_ORDERDEPS.$(bld_trg_cpu)) \ $($(target)_LNK_ORDERDEPS.$(bld_trg).$(bld_trg_arch).$(bld_type)) \ $($(target)_LNK_ORDERDEPS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_LNK_ORDERDEPS.$(bld_trg).$(bld_type)) \ $($(target)_LNK_ORDERDEPS.$(bld_trg_arch)) \ $($(target)_LNK_ORDERDEPS.$(bld_trg)) \ $($(target)_LNK_ORDERDEPS.$(bld_type)) \ $($(target)_LNK_ORDERDEPS) # Adjust paths if we got a default path. ifneq ($(defpath),) local deps := $(abspathex $(deps),$(defpath)) local orderdeps := $(abspathex $(orderdeps),$(defpath)) othersrc := $(abspathex $(othersrc),$(defpath)) endif # Custom pre-link actions. local pre_cmds := $(evalcall def_fn_prop_get_all_prefixed_priority_last,PRE_CMDS,$(NLTAB)) local post_cmds := $(evalcall def_fn_prop_get_all_prefixed_priority_last,POST_CMDS,$(NLTAB)) # eliminate this guy? local objs = $($(target)_2_OBJS) # dependency file local dep := $(out)$(SUFF_DEP) ifndef NO_LINK_CMDS_DEPS _DEPFILES_INCLUDED += $(dep) ifdef KB_HAVE_INCLUDEDEP_QUEUE includedep-queue $(dep) else includedep $(dep) endif endif # check that the tool is defined. ifndef TOOL_$(tool)_LINK_LIBRARY_CMDS $(warning kBuild: tools: \ 1 $($(target)_$(source)TOOL.$(bld_trg).$(bld_trg_arch)) \ 2 $($(target)_$(source)TOOL.$(bld_trg)) \ 3 $($(target)_$(source)TOOL) \ 4 $($(target)_TOOL.$(bld_trg).$(bld_trg_arch)) \ 5 $($(target)_TOOL.$(bld_trg)) \ 6 $($(target)_TOOL) \ 7 $($(source)TOOL) \ 8 $($(source)TOOL.$(bld_trg).$(bld_trg_arch)) \ 9 $($(source)TOOL.$(bld_trg)) \ 10 $(TOOL.$(bld_trg).$(bld_trg_arch)) \ 11 $(TOOL.$(bld_trg)) \ 12 $(TOOL) ) $(error kBuild: TOOL_$(tool)_LINK_LIBRARY_CMDS isn't defined! target=$(target) ) endif # call the tool local cmds := $(TOOL_$(tool)_LINK_LIBRARY_CMDS) ifneq ($(pre_cmds),) local cmds := $(TAB)$(pre_cmds)$(NL)$(TAB)$(cmds) endif ifneq ($(post_cmds),) local cmds := $(cmds)$(NL)$(TAB)$(post_cmds) endif $(target)_2_OUTPUT := $(TOOL_$(tool)_LINK_LIBRARY_OUTPUT) $(target)_2_OUTPUT_MAYBE := $(TOOL_$(tool)_LINK_LIBRARY_OUTPUT_MAYBE) $(target)_2_OUTPUT_MAYBE_PRECIOUS := $(TOOL_$(tool)_LINK_LIBRARY_OUTPUT_MAYBE_PRECIOUS) $(target)_2_DEPEND := $(TOOL_$(tool)_LINK_LIBRARY_DEPEND) $(deps) $($(target)_2_OBJS) $(target)_2_DEPORD := $(TOOL_$(tool)_LINK_LIBRARY_DEPORD) $(dirdep) $(orderdeps) # generate the link rule. $(eval $(def_link_rule)) # installing and globals. local target_type_mode := a+r,u+w $(evalval def_target_install_only) _OUT_FILES += $($(target)_2_OUTPUT) $($(target)_2_OUTPUT_MAYBE) $($(target)_2_OUTPUT_MAYBE_PRECIOUS) $(out) _CLEAN_FILES += $($(target)_CLEAN) $($(target)_CLEAN.$(bld_trg)) $($(target)_CLEAN.$(bld_trg).$(bld_trg_arch)) $($(target)_CLEAN.$(bld_trg_arch)) $($(target)_CLEAN.$(bld_trg_cpu)) $($(target)_CLEAN.$(bld_type)) _DIRS += $($(target)_BLDDIRS) $($(target)_BLDDIRS.$(bld_trg)) $($(target)_BLDDIRS.$(bld_trg).$(bld_trg_arch)) $($(target)_BLDDIRS.$(bld_trg_arch)) $($(target)_BLDDIRS.$(bld_trg_cpu)) $($(target)_BLDDIRS.$(bld_type)) _OBJS += $($(target)_2_OBJS) endef # def_lib $(eval-opt-var def_lib) # Process libraries typevar := _LIBS tool_do := LINK_LIBRARY mode := 0644 $(foreach target, $(_ALL_LIBRARIES), $(evalvalctx def_lib)) ifdef KBUILD_PROFILE_SELF $(evalcall def_profile_self, done library targets) endif # # Link operations. # ## # Link prolog # # @param $(target) Normalized target name. # @param $(EXT) EXE,DLL,SYS. # @param $(typevar) The name of the variable with all the root targets of its type. define def_link_common # basics local bld_type := $(firstword $($(target)_BLD_TYPE) $(KBUILD_TYPE)) local bld_trg := $(firstword $($(target)_BLD_TRG) $(BUILD_$(bld_trg_base_var))) local bld_trg_arch:= $(firstword $($(target)_BLD_TRG_ARCH) $(BUILD_$(bld_trg_base_var)_ARCH)) local bld_trg_cpu := $(firstword $($(target)_BLD_TRG_CPU) $(BUILD_$(bld_trg_base_var)_CPU)) local tool := $(call _TARGET_TOOL,$(target),LD) local name := $(firstword\ $($(target)_NAME.$(bld_trg).$(bld_trg_arch).$(bld_type))\ $($(target)_NAME.$(bld_trg).$(bld_trg_arch))\ $($(target)_NAME.$(bld_trg).$(bld_type))\ $($(target)_NAME.$(bld_trg_arch))\ $($(target)_NAME.$(bld_trg))\ $($(target)_NAME.$(bld_type))\ $($(target)_NAME)\ $(target)) local outbase := $(call TARGET_BASE,$(name),$(target)) $(target)_0_OUTDIR:= $(patsubst %/,%,$(dir $(outbase))) $(call KB_FN_ASSIGN_DEPRECATED,PATH_$(target),$($(target)_0_OUTDIR), $(target)_0_OUTDIR) local suff := $(firstword \ $($(target)_$(EXT)SUFF.$(bld_trg).$(bld_trg_arch))\ $($(target)_$(EXT)SUFF.$(bld_trg))\ $($(target)_$(EXT)SUFF)\ $(TOOL_$(tool)_LD$(EXT)SUFF.$(bld_trg).$(bld_trg_arch))\ $(TOOL_$(tool)_LD$(EXT)SUFF.$(bld_trg))\ $(TOOL_$(tool)_LD$(EXT)SUFF)\ $($(EXTPRE)SUFF_$(EXT)) ) local out := $(outbase)$(suff) $(target)_1_TARGET:= $(out) $(call KB_FN_ASSIGN_DEPRECATED,TARGET_$(target),$($(target)_1_TARGET), $(target)_1_TARGET) local defpath := $($(target)_DEFPATH) ifeq ($(defpath),) local defpath := $($(target)_PATH) endif # no local here - must be writable across some foreachs. othersrc := $(target)_2_OBJS := # Do units pre source callouts. local units := \ $($(target)_USES.$(bld_trg).$(bld_trg_arch))\ $($(target)_USES.$(bld_trg_arch))\ $($(target)_USES.$(bld_trg))\ $($(target)_USES.$(bld_type))\ $($(target)_USES) $(foreach unit,$(units),$(evalvalctx def_unit_$(unit)_target_pre)) $(foreach unit,$(units),$(evalvalctx def_unit_$(unit)_target_pre_2)) # source -> object $(evalval def_target_sources) # more link stuff. local tool := $(call _TARGET_TOOL,$(target),LD) local name := $(firstword\ $($(target)_NAME.$(bld_trg).$(bld_trg_arch).$(bld_type))\ $($(target)_NAME.$(bld_trg).$(bld_trg_arch))\ $($(target)_NAME.$(bld_trg).$(bld_type))\ $($(target)_NAME.$(bld_trg_arch))\ $($(target)_NAME.$(bld_trg))\ $($(target)_NAME.$(bld_type))\ $($(target)_NAME)\ $(target)) local outbase := $(call TARGET_BASE,$(name),$(target)) local flags :=\ $(TOOL_$(tool)_LDFLAGS)\ $(TOOL_$(tool)_LDFLAGS.$(bld_type))\ $(TOOL_$(tool)_LDFLAGS.$(bld_trg))\ $(TOOL_$(tool)_LDFLAGS.$(bld_trg_arch))\ $(TOOL_$(tool)_LDFLAGS.$(bld_trg).$(bld_trg_arch))\ $(TOOL_$(tool)_LDFLAGS.$(bld_trg_cpu))\ $(foreach sdk, $(SDKS) \ $(SDKS.$(bld_type)) \ $(SDKS.$(bld_trg)) \ $(SDKS.$(bld_trg_arch)) \ $(SDKS.$(bld_trg).$(bld_trg_arch)),\ $(SDK_$(sdk)_LDFLAGS)\ $(SDK_$(sdk)_LDFLAGS.$(bld_type))\ $(SDK_$(sdk)_LDFLAGS.$(bld_trg))\ $(SDK_$(sdk)_LDFLAGS.$(bld_trg_arch))\ $(SDK_$(sdk)_LDFLAGS.$(bld_trg).$(bld_trg_arch))\ $(SDK_$(sdk)_LDFLAGS.$(bld_trg_cpu)))\ $(LDFLAGS)\ $(LDFLAGS.$(bld_type))\ $(LDFLAGS.$(bld_trg))\ $(LDFLAGS.$(bld_trg_arch))\ $(LDFLAGS.$(bld_trg).$(bld_trg_arch))\ $(LDFLAGS.$(bld_trg_cpu))\ $(foreach sdk, $($(target)_SDKS) \ $($(target)_SDKS.$(bld_type)) \ $($(target)_SDKS.$(bld_trg)) \ $($(target)_SDKS.$(bld_trg_arch)) \ $($(target)_SDKS.$(bld_trg).$(bld_trg_arch)),\ $(SDK_$(sdk)_LDFLAGS)\ $(SDK_$(sdk)_LDFLAGS.$(bld_type))\ $(SDK_$(sdk)_LDFLAGS.$(bld_trg))\ $(SDK_$(sdk)_LDFLAGS.$(bld_trg_arch))\ $(SDK_$(sdk)_LDFLAGS.$(bld_trg).$(bld_trg_arch))\ $(SDK_$(sdk)_LDFLAGS.$(bld_trg_cpu)))\ $($(target)_LDFLAGS)\ $($(target)_LDFLAGS.$(bld_type))\ $($(target)_LDFLAGS.$(bld_trg))\ $($(target)_LDFLAGS.$(bld_trg_arch))\ $($(target)_LDFLAGS.$(bld_trg).$(bld_trg_arch))\ $($(target)_LDFLAGS.$(bld_trg_cpu)) local libs :=\ $($(target)_LIBS.$(bld_trg_cpu))\ $($(target)_LIBS.$(bld_trg).$(bld_trg_arch))\ $($(target)_LIBS.$(bld_trg_arch))\ $($(target)_LIBS.$(bld_trg))\ $($(target)_LIBS.$(bld_type))\ $($(target)_LIBS)\ $(foreach sdk, $($(target)_SDKS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_SDKS.$(bld_trg_arch)) \ $($(target)_SDKS.$(bld_trg)) \ $($(target)_SDKS.$(bld_type)) \ $($(target)_SDKS),\ $(SDK_$(sdk)_LIBS.$(bld_trg_cpu))\ $(SDK_$(sdk)_LIBS.$(bld_trg).$(bld_trg_arch))\ $(SDK_$(sdk)_LIBS.$(bld_trg_arch))\ $(SDK_$(sdk)_LIBS.$(bld_trg))\ $(SDK_$(sdk)_LIBS.$(bld_type))\ $(SDK_$(sdk)_LIBS))\ $(LIBS.$(bld_trg_cpu))\ $(LIBS.$(bld_trg).$(bld_trg_arch))\ $(LIBS.$(bld_trg_arch))\ $(LIBS.$(bld_trg))\ $(LIBS.$(bld_type))\ $(LIBS)\ $(foreach sdk, $(SDKS.$(bld_trg).$(bld_trg_arch)) \ $(SDKS.$(bld_trg_arch)) \ $(SDKS.$(bld_trg)) \ $(SDKS.$(bld_type)) \ $(SDKS),\ $(SDK_$(sdk)_LIBS.$(bld_trg_cpu))\ $(SDK_$(sdk)_LIBS.$(bld_trg).$(bld_trg_arch))\ $(SDK_$(sdk)_LIBS.$(bld_trg_arch))\ $(SDK_$(sdk)_LIBS.$(bld_trg))\ $(SDK_$(sdk)_LIBS.$(bld_type))\ $(SDK_$(sdk)_LIBS))\ $(TOOL_$(tool)_LIBS.$(bld_trg_cpu))\ $(TOOL_$(tool)_LIBS.$(bld_trg).$(bld_trg_arch))\ $(TOOL_$(tool)_LIBS.$(bld_trg_arch))\ $(TOOL_$(tool)_LIBS.$(bld_trg))\ $(TOOL_$(tool)_LIBS.$(bld_type))\ $(TOOL_$(tool)_LIBS) local libpath :=\ $($(target)_LIBPATH.$(bld_trg_cpu))\ $($(target)_LIBPATH.$(bld_trg).$(bld_trg_arch))\ $($(target)_LIBPATH.$(bld_trg_arch))\ $($(target)_LIBPATH.$(bld_trg))\ $($(target)_LIBPATH.$(bld_type))\ $($(target)_LIBPATH)\ $(foreach sdk, $($(target)_SDKS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_SDKS.$(bld_trg_arch)) \ $($(target)_SDKS.$(bld_trg)) \ $($(target)_SDKS.$(bld_type)) \ $($(target)_SDKS),\ $(SDK_$(sdk)_LIBPATH.$(bld_trg_cpu))\ $(SDK_$(sdk)_LIBPATH.$(bld_trg).$(bld_trg_arch))\ $(SDK_$(sdk)_LIBPATH.$(bld_trg_arch))\ $(SDK_$(sdk)_LIBPATH.$(bld_trg))\ $(SDK_$(sdk)_LIBPATH.$(bld_type))\ $(SDK_$(sdk)_LIBPATH))\ $(LIBPATH.$(bld_trg_cpu))\ $(LIBPATH.$(bld_trg).$(bld_trg_arch))\ $(LIBPATH.$(bld_trg_arch))\ $(LIBPATH.$(bld_trg))\ $(LIBPATH.$(bld_type))\ $(LIBPATH)\ $(foreach sdk, $(SDKS.$(bld_trg).$(bld_trg_arch)) \ $(SDKS.$(bld_trg_arch)) \ $(SDKS.$(bld_trg)) \ $(SDKS.$(bld_type)) \ $(SDKS),\ $(SDK_$(sdk)_LIBPATH.$(bld_trg_cpu))\ $(SDK_$(sdk)_LIBPATH.$(bld_trg).$(bld_trg_arch))\ $(SDK_$(sdk)_LIBPATH.$(bld_trg_arch))\ $(SDK_$(sdk)_LIBPATH.$(bld_trg))\ $(SDK_$(sdk)_LIBPATH.$(bld_type))\ $(SDK_$(sdk)_LIBPATH))\ $(TOOL_$(tool)_LIBPATH.$(bld_trg_cpu))\ $(TOOL_$(tool)_LIBPATH.$(bld_trg).$(bld_trg_arch))\ $(TOOL_$(tool)_LIBPATH.$(bld_trg_arch))\ $(TOOL_$(tool)_LIBPATH.$(bld_trg))\ $(TOOL_$(tool)_LIBPATH.$(bld_type))\ $(TOOL_$(tool)_LIBPATH) local dirdep := $(call DIRDEP,$(dir $(out))) local deps := \ $($(target)_DEPS.$(bld_trg_cpu)) \ $($(target)_DEPS.$(bld_trg).$(bld_trg_arch).$(bld_type)) \ $($(target)_DEPS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_DEPS.$(bld_trg).$(bld_type)) \ $($(target)_DEPS.$(bld_trg_arch)) \ $($(target)_DEPS.$(bld_trg)) \ $($(target)_DEPS.$(bld_type)) \ $($(target)_DEPS) \ $($(target)_LNK_DEPS.$(bld_trg_cpu)) \ $($(target)_LNK_DEPS.$(bld_trg).$(bld_trg_arch).$(bld_type)) \ $($(target)_LNK_DEPS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_LNK_DEPS.$(bld_trg).$(bld_type)) \ $($(target)_LNK_DEPS.$(bld_trg_arch)) \ $($(target)_LNK_DEPS.$(bld_trg)) \ $($(target)_LNK_DEPS.$(bld_type)) \ $($(target)_LNK_DEPS) local orderdeps := \ $($(target)_ORDERDEPS.$(bld_trg_cpu)) \ $($(target)_ORDERDEPS.$(bld_trg).$(bld_trg_arch).$(bld_type)) \ $($(target)_ORDERDEPS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_ORDERDEPS.$(bld_trg).$(bld_type)) \ $($(target)_ORDERDEPS.$(bld_trg_arch)) \ $($(target)_ORDERDEPS.$(bld_trg)) \ $($(target)_ORDERDEPS.$(bld_type)) \ $($(target)_ORDERDEPS) \ $($(target)_LNK_ORDERDEPS.$(bld_trg_cpu)) \ $($(target)_LNK_ORDERDEPS.$(bld_trg).$(bld_trg_arch).$(bld_type)) \ $($(target)_LNK_ORDERDEPS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_LNK_ORDERDEPS.$(bld_trg).$(bld_type)) \ $($(target)_LNK_ORDERDEPS.$(bld_trg_arch)) \ $($(target)_LNK_ORDERDEPS.$(bld_trg)) \ $($(target)_LNK_ORDERDEPS.$(bld_type)) \ $($(target)_LNK_ORDERDEPS) # Adjust paths if we got a default path. ifneq ($(defpath),) local libpath := $(abspathex $(libpath),$(defpath)) local deps := $(abspathex $(deps),$(defpath)) local orderdeps := $(abspathex $(orderdeps),$(defpath)) othersrc := $(abspathex $(othersrc),$(defpath)) # libs are not subject to this because of the the -l stuff. Use $(_DEFPATH)/lib if relative to current dir! endif # Debug info. local ld_debug := $(evalcall def_fn_prop_get_first_defined,LD_DEBUG) local debug_inst := $(evalcall def_fn_prop_get_first_defined,DEBUG_INST) local debug_stage := $(evalcall def_fn_prop_get_first_defined,DEBUG_STAGE) local debug_nostage := $(evalcall def_fn_prop_get_first_word,DEBUG_NOSTAGE) # Custom pre/post-link actions. local pre_cmds := $(evalcall def_fn_prop_get_all_prefixed_priority_last,PRE_CMDS,$(NLTAB)) local post_cmds := $(evalcall def_fn_prop_get_all_prefixed_priority_last,POST_CMDS,$(NLTAB)) # eliminate this guy? local objs = $($(target)_2_OBJS) # dependency file local dep := $(outbase)$(SUFF_DEP) ifndef NO_LINK_CMDS_DEPS _DEPFILES_INCLUDED += $(dep) ifdef KB_HAVE_INCLUDEDEP_QUEUE includedep-queue $(dep) else includedep $(dep) endif endif # check that the tool is defined. ifndef TOOL_$(tool)_$(tool_do)_CMDS $(warning kBuild: tools: \ 1 $($(target)_$(source)TOOL.$(bld_trg).$(bld_trg_arch)) \ 2 $($(target)_$(source)TOOL.$(bld_trg)) \ 3 $($(target)_$(source)TOOL) \ 4 $($(target)_TOOL.$(bld_trg).$(bld_trg_arch)) \ 5 $($(target)_TOOL.$(bld_trg)) \ 6 $($(target)_TOOL) \ 7 $($(source)TOOL.$(bld_trg).$(bld_trg_arch)) \ 8 $($(source)TOOL.$(bld_trg)) \ 9 $($(source)TOOL) \ 10 $(TOOL.$(bld_trg).$(bld_trg_arch)) \ 11 $(TOOL.$(bld_trg)) \ 12 $(TOOL) ) $(error kBuild: TOOL_$(tool)_$(tool_do)_CMDS isn't defined! target=$(target) ) endif # call the tool local cmds := $(TOOL_$(tool)_$(tool_do)_CMDS) ifneq ($(pre_cmds),) local cmds := $(TAB)$(pre_cmds)$(NL)$(TAB)$(cmds) endif ifneq ($(post_cmds),) local cmds := $(cmds)$(NL)$(TAB)$(post_cmds) endif $(target)_2_OUTPUT := $(TOOL_$(tool)_$(tool_do)_OUTPUT) $(target)_2_OUTPUT_MAYBE := $(TOOL_$(tool)_$(tool_do)_OUTPUT_MAYBE) $(target)_2_OUTPUT_MAYBE_PRECIOUS := $(TOOL_$(tool)_$(tool_do)_OUTPUT_MAYBE_PRECIOUS) if1of ($(ld_debug), split) $(target)_2_OUTPUT_DEBUG_FILES := $(filter-out %/,$(TOOL_$(tool)_$(tool_do)_OUTPUT_DEBUG)) $(target)_2_OUTPUT_DEBUG_DIRS := $(filter %/,$(TOOL_$(tool)_$(tool_do)_OUTPUT_DEBUG)) else $(target)_2_OUTPUT_DEBUG_FILES := $(target)_2_OUTPUT_DEBUG_DIRS := endif $(target)_2_DEPEND := $(TOOL_$(tool)_$(tool_do)_DEPEND) $(deps) $($(target)_2_OBJS) $(target)_2_DEPORD := $(TOOL_$(tool)_$(tool_do)_DEPORD) $(dirdep) $(orderdeps) # generate the link rule. $(eval $(def_link_rule)) # installation targets local target_type_mode := $(evalval def_target_install_only) # Update globals. _OBJS += $($(target)_2_OBJS) _OUT_FILES += $($(target)_2_OUTPUT) $($(target)_2_OUTPUT_MAYBE) $($(target)_2_OUTPUT_MAYBE_PRECIOUS) $(out) _CLEAN_FILES += $($(target)_CLEAN) $($(target)_CLEAN.$(bld_trg)) $($(target)_CLEAN.$(bld_trg).$(bld_trg_arch)) $($(target)_CLEAN.$(bld_trg_arch)) $($(target)_CLEAN.$(bld_trg_cpu)) $($(target)_CLEAN.$(bld_type)) _DIRS += $($(target)_BLDDIRS) $($(target)_BLDDIRS.$(bld_trg)) $($(target)_BLDDIRS.$(bld_trg).$(bld_trg_arch)) $($(target)_BLDDIRS.$(bld_trg_arch)) $($(target)_BLDDIRS.$(bld_trg_cpu)) $($(target)_BLDDIRS.$(bld_type)) _INSTALLS_FILES += $(INSTARGET_$(target)) endef # def_link_common $(eval-opt-var def_link_common) # # BLDPROGS # # Process build programs. EXT := EXE EXTPRE := HOST tool_do := LINK_PROGRAM typevar := _BLDPROGS mode := 0755 bld_trg_base_var := PLATFORM $(foreach target, $(_ALL_BLDPROGS), $(evalvalctx def_link_common)) ifdef KBUILD_PROFILE_SELF $(evalcall def_profile_self, done build program targets) endif # # DLLS # # Process dlls EXT := DLL EXTPRE := tool_do := LINK_DLL typevar := _DLLS mode := 0644 bld_trg_base_var := TARGET $(foreach target, $(_ALL_DLLS), $(evalvalctx def_link_common)) ifdef KBUILD_PROFILE_SELF $(evalcall def_profile_self, done dll targets) endif # # IMPORT LIBRARIES # # - On OS/2 and windows these are libraries. # - On other platforms they are fake DLLs. # EXTPRE := typevar := _IMPORT_LIBS mode := 0644 bld_trg_base_var := TARGET ifeq ($(filter-out nt os2 win win64 win32,$(KBUILD_TARGET)),) EXT := LIB tool_do := LINK_LIBRARY $(foreach target, $(_ALL_IMPORT_LIBS), $(evalvalctx def_lib)) else EXT := DLL tool_do := LINK_DLL $(foreach target, $(_ALL_IMPORT_LIBS), $(evalvalctx def_link_common)) endif ifdef KBUILD_PROFILE_SELF $(evalcall def_profile_self, done import library targets) endif # # PROGRAMS # # Process programs EXT := EXE EXTPRE := tool_do := LINK_PROGRAM typevar := _PROGRAMS mode := 0755 bld_trg_base_var := TARGET $(foreach target, $(_ALL_PROGRAMS), $(evalvalctx def_link_common)) ifdef KBUILD_PROFILE_SELF $(evalcall def_profile_self, done program targets) endif # # SYSMODS # # Process sysmods EXT := SYS EXTPRE := tool_do := LINK_SYSMOD typevar := _SYSMODS mode := 0644 bld_trg_base_var := TARGET $(foreach target, $(_ALL_SYSMODS), $(evalvalctx def_link_common)) ifdef KBUILD_PROFILE_SELF $(evalcall def_profile_self, done sysmod targets) endif # # MISCBINS # # Process MISCBINS EXT := BIN EXTPRE := tool_do := LINK_MISCBIN typevar := _MISCBINS mode := 0644 bld_trg_base_var := TARGET $(foreach target, $(_ALL_MISCBINS), $(evalvalctx def_link_common)) ifdef KBUILD_PROFILE_SELF $(evalcall def_profile_self, done misc binary targets) endif kbuild-3149/kBuild/subfooter.kmk0000644000175000017500000001034213252530251016630 0ustar locutuslocutus# $Id: subfooter.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild - File included at bottom of a makefile or sub-makefile. # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # # # Sanity check. # ifdef __footer_kmk__ $(error kBuild: footer.kmk has already been included. Fix your sub-makefiles! $(MAKEFILE_CURRENT)) endif # # Set the default path for all new targets. # ## @todo Wish there was an easy way of only enumerating only new targets... $(foreach target,\ $(ALL_TARGETS) \ $(FETCHES) $(FETCHES.$(KBUILD_TARGET)) $(FETCHES.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(FETCHES.$(KBUILD_TARGET_ARCH)) $(FETCHES.$(KBUILD_TARGET_CPU)) $(FETCHES.$(KBUILD_TYPE)) \ $(PATCHES) $(PATCHES.$(KBUILD_TARGET)) $(PATCHES.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(PATCHES.$(KBUILD_TARGET_ARCH)) $(PATCHES.$(KBUILD_TARGET_CPU)) $(PATCHES.$(KBUILD_TYPE)) \ $(BLDPROGS) $(BLDPROGS.$(KBUILD_HOST)) $(BLDPROGS.$(KBUILD_HOST).$(BUILD_PLATFORM_ARCH)) $(BLDPROGS.$(KBUILD_HOST_ARCH)) $(BLDPROGS.$(KBUILD_HOST_CPU)) $(BLDPROGS.$(KBUILD_TYPE)) \ $(LIBRARIES) $(LIBRARIES.$(KBUILD_TARGET)) $(LIBRARIES.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(LIBRARIES.$(KBUILD_TARGET_ARCH)) $(LIBRARIES.$(KBUILD_TARGET_CPU)) $(LIBRARIES.$(KBUILD_TYPE)) \ $(IMPORT_LIBS) $(IMPORT_LIBS.$(KBUILD_TARGET)) $(IMPORT_LIBS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(IMPORT_LIBS.$(KBUILD_TARGET_ARCH)) $(IMPORT_LIBS.$(KBUILD_TARGET_CPU)) $(IMPORT_LIBS.$(KBUILD_TYPE)) \ $(DLLS) $(DLLS.$(KBUILD_TARGET)) $(DLLS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(DLLS.$(KBUILD_TARGET_ARCH)) $(DLLS.$(KBUILD_TARGET_CPU)) $(DLLS.$(KBUILD_TYPE)) \ $(PROGRAMS) $(PROGRAMS.$(KBUILD_TARGET)) $(PROGRAMS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(PROGRAMS.$(KBUILD_TARGET_ARCH)) $(PROGRAMS.$(KBUILD_TARGET_CPU)) $(PROGRAMS.$(KBUILD_TYPE)) \ $(SYSMODS) $(SYSMODS.$(KBUILD_TARGET)) $(SYSMODS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(SYSMODS.$(KBUILD_TARGET_ARCH)) $(SYSMODS.$(KBUILD_TARGET_CPU)) $(SYSMODS.$(KBUILD_TYPE)) \ $(MISCBINS) $(MISCBINS.$(KBUILD_TARGET)) $(MISCBINS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(MISCBINS.$(KBUILD_TARGET_ARCH)) $(MISCBINS.$(KBUILD_TARGET_CPU)) $(MISCBINS.$(KBUILD_TYPE)) \ $(INSTALLS) $(INSTALLS.$(KBUILD_TARGET)) $(INSTALLS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(INSTALLS.$(KBUILD_TARGET_ARCH)) $(INSTALLS.$(KBUILD_TARGET_CPU)) $(INSTALLS.$(KBUILD_TYPE)) \ $(OTHERS) $(OTHERS.$(KBUILD_TARGET)) $(OTHERS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(OTHERS.$(KBUILD_TARGET_ARCH)) $(OTHERS.$(KBUILD_TARGET_CPU)) $(OTHERS.$(KBUILD_TYPE)) \ ,$(if-expr defined($(target)_0_OUTDIR),,$(evalval def_subfooter_header_target_pass))) ifneq ($(_SUB_MAKEFILE_STACK),) # # Switch back to the context of previous makefile on the stack. # MAKEFILE_CURRENT := $(stack-pop _SUB_MAKEFILE_STACK) PATH_SUB_CURRENT := $(abspath $(dir $(MAKEFILE_CURRENT))) else # # We've reached the end of the line, include the real footer. # include $(PATH_KBUILD)/footer.kmk endif kbuild-3149/kBuild/subheader.kmk0000644000175000017500000001074713252530250016572 0ustar locutuslocutus# $Id: subheader.kmk 3121 2017-10-31 10:58:59Z bird $ ## @file # kBuild - File included at top of a makefile or sub-makefile. # # # Copyright (c) 2006-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # # # Sanity check. # ifdef __footer_kmk__ $(error kBuild: footer.kmk has already been included. Fix your sub-makefiles! $(MAKEFILE_CURRENT)) endif ifndef _SUB_MAKEFILE_NOT_FIRST # # The first time we just take the makefile context set by header.kmk. # _SUB_MAKEFILE_NOT_FIRST := 1 DEPTH ?= $(SUB_DEPTH) include $(PATH_KBUILD)/header.kmk else # # Set the default path and makefile for all new targets. # ## @todo Wish there was an easy way of only enumerating only new targets... $(foreach target,\ $(ALL_TARGETS) \ $(FETCHES) $(FETCHES.$(KBUILD_TARGET)) $(FETCHES.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(FETCHES.$(KBUILD_TARGET_ARCH)) $(FETCHES.$(KBUILD_TARGET_CPU)) $(FETCHES.$(KBUILD_TYPE)) \ $(PATCHES) $(PATCHES.$(KBUILD_TARGET)) $(PATCHES.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(PATCHES.$(KBUILD_TARGET_ARCH)) $(PATCHES.$(KBUILD_TARGET_CPU)) $(PATCHES.$(KBUILD_TYPE)) \ $(BLDPROGS) $(BLDPROGS.$(KBUILD_HOST)) $(BLDPROGS.$(KBUILD_HOST).$(BUILD_PLATFORM_ARCH)) $(BLDPROGS.$(KBUILD_HOST_ARCH)) $(BLDPROGS.$(KBUILD_HOST_CPU)) $(BLDPROGS.$(KBUILD_TYPE)) \ $(LIBRARIES) $(LIBRARIES.$(KBUILD_TARGET)) $(LIBRARIES.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(LIBRARIES.$(KBUILD_TARGET_ARCH)) $(LIBRARIES.$(KBUILD_TARGET_CPU)) $(LIBRARIES.$(KBUILD_TYPE)) \ $(IMPORT_LIBS) $(IMPORT_LIBS.$(KBUILD_TARGET)) $(IMPORT_LIBS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(IMPORT_LIBS.$(KBUILD_TARGET_ARCH)) $(IMPORT_LIBS.$(KBUILD_TARGET_CPU)) $(IMPORT_LIBS.$(KBUILD_TYPE)) \ $(DLLS) $(DLLS.$(KBUILD_TARGET)) $(DLLS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(DLLS.$(KBUILD_TARGET_ARCH)) $(DLLS.$(KBUILD_TARGET_CPU)) $(DLLS.$(KBUILD_TYPE)) \ $(PROGRAMS) $(PROGRAMS.$(KBUILD_TARGET)) $(PROGRAMS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(PROGRAMS.$(KBUILD_TARGET_ARCH)) $(PROGRAMS.$(KBUILD_TARGET_CPU)) $(PROGRAMS.$(KBUILD_TYPE)) \ $(SYSMODS) $(SYSMODS.$(KBUILD_TARGET)) $(SYSMODS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(SYSMODS.$(KBUILD_TARGET_ARCH)) $(SYSMODS.$(KBUILD_TARGET_CPU)) $(SYSMODS.$(KBUILD_TYPE)) \ $(MISCBINS) $(MISCBINS.$(KBUILD_TARGET)) $(MISCBINS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(MISCBINS.$(KBUILD_TARGET_ARCH)) $(MISCBINS.$(KBUILD_TARGET_CPU)) $(MISCBINS.$(KBUILD_TYPE)) \ $(INSTALLS) $(INSTALLS.$(KBUILD_TARGET)) $(INSTALLS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(INSTALLS.$(KBUILD_TARGET_ARCH)) $(INSTALLS.$(KBUILD_TARGET_CPU)) $(INSTALLS.$(KBUILD_TYPE)) \ $(OTHERS) $(OTHERS.$(KBUILD_TARGET)) $(OTHERS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)) $(OTHERS.$(KBUILD_TARGET_ARCH)) $(OTHERS.$(KBUILD_TARGET_CPU)) $(OTHERS.$(KBUILD_TYPE)) \ ,$(if-expr defined($(target)_0_OUTDIR),,$(evalval def_subfooter_header_target_pass))) # # Switch context. # # push the current old makefile onto the stack. $(stack-push _SUB_MAKEFILE_STACK,$(MAKEFILE_CURRENT)) # the current makefile is the 2nd from the end of the MAKEFILE_LIST (we're the last one). __tmp := $(MAKEFILE_LIST) $(stack-popv __tmp) MAKEFILE_CURRENT := $(stack-top __tmp) PATH_SUB_CURRENT := $(abspath $(dir $(MAKEFILE_CURRENT))) endif kbuild-3149/kBuild/msgstyles/0000755000175000017500000000000013252530215016146 5ustar locutuslocutuskbuild-3149/kBuild/msgstyles/brief2.kmk0000644000175000017500000001145113252530215020025 0ustar locutuslocutus# $Id: brief2.kmk 3130 2018-01-31 19:28:35Z bird $ ## @file # kBuild Message Style - 'brief' # # # Copyright (c) 2007-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # # Indent the messages, drop the kBuild: prefix, and shorten paths. ifndef KBUILD_VERBOSE ifndef MSG_L1 MSG_L1 = %@$(PRINTF) " %-7s %s\n" \ "$(subst $(PATH_ROOT)/,{R}/,$(subst $(PATH_OUT)/,{O}/,$(subst $(CURDIR)/,{C}/,$(subst $(PATH_TARGET)/,{T}/,$1))))" \ "$(subst $(PATH_ROOT)/,{R}/,$(subst $(PATH_OUT)/,{O}/,$(subst $(CURDIR)/,{C}/,$(subst $(PATH_TARGET)/,{T}/,$2))))" endif ifndef MSG_L1I MSG_L1I = %@$(PRINTF) " %-7s %s\n" "$1" "$2" endif else MSG_L1 ?= %@$(ECHO) " $(subst $(PATH_ROOT)/,{R}/,$(subst $(PATH_OUT)/,{O}/,$(subst $(CURDIR)/,{C}/,$(subst $(PATH_TARGET)/,{T}/,$1 $2))))" MSG_L1I?= %@$(ECHO) " $1 $2" MSG_L2 ?= %@$(ECHO) " $(subst $(PATH_ROOT)/,{R}/,$(subst $(PATH_OUT)/,{O}/,$(subst $(CURDIR)/,{C}/,$(subst $(PATH_TARGET)/,{T}/,$1))))" endif ## Fetch starting. # @param 1 Target name. MSG_FETCH ?= $(call MSG_L1,FTCH,$1...) ## Re-fetch starting. # @param 1 Target name. MSG_REFETCH ?= $(call MSG_L1,RFTCH,$1...) ## Downloading a fetch component. # @param 1 Target name. # @param 2 The source URL. # @param 3 The destination file name. MSG_FETCH_DL ?= $(call MSG_L1,GET,$1 - $2,=> $3) ## Checking a fetch component. # @param 1 Target name. # @param 2 The source URL. # @param 3 The destination file name. MSG_FETCH_CHK?= $(call MSG_L1,CHK,$1 - $3, ($2)) ## Unpacking a fetch component. # @param 1 Target name. # @param 2 The archive file name. # @param 3 The target directory. MSG_FETCH_UP ?= $(call MSG_L1,UNPK,$1 - $2,=> $3) ## Fetch completed. # @param 1 Target name. MSG_FETCH_OK ?= $(call MSG_L1,DONE,$1) ## Unfetch a fetch target. # @param 1 Target name. MSG_UNFETCH ?= $(call MSG_L1,RM,$1...) ## Compiling a source file. # @param 1 Target name. # @param 2 The source filename. # @param 3 The primary link output file name. # @param 4 The source type (CXX,C,AS,RC,++). MSG_COMPILE ?= $(call MSG_L1,$4,$1 - $2,=> $3) ## Tool # @param 1 The tool name (bin2c,...) # @param 2 Target name. # @param 3 The source filename. # @param 4 The primary output file name. MSG_TOOL ?= $(call MSG_L1,$1,$2 - $3,=> $4) ## Generate a file, typically a source file. # @param 1 Target name if applicable. # @param 2 Output file name. # @param 3 What it's generated from MSG_GENERATE ?= $(call MSG_L1,GEN,$2) ## Linking a bldprog/dll/program/sysmod target. # @param 1 Target name. # @param 2 The primary link output file name. # @param 3 The link tool operation (LINK_LIBRARY,LINK_PROGRAM,LINK_DLL,LINK_SYSMOD,++). MSG_LINK ?= $(call MSG_L1I,$(if $(eq $3,LINK_LIBRARY),AR,LD),$1 => $2,) ## Merging a library into the target (during library linking). # @param 1 Target name. # @param 2 The output library name. # @param 3 The input library name. MSG_AR_MERGE ?= $(NO_SUCH_VARIABLE) ## Creating a directory (build). # @param 1 Directory name. MSG_MKDIR ?= $(call MSG_L2,DIR,$1) ## Cleaning. MSG_CLEAN ?= $(call MSG_L1,CLEAN) ## Nothing. MSG_NOTHING ?= $(call MSG_L1,NOTHING $(CURDIR)) ## Installing a bldprog/lib/dll/program/sysmod target. # @param 1 Target name. # @param 2 The source filename. # @param 3 The destination file name. MSG_INST_TRG ?= $(call MSG_L1I,INST,$1 => $3) ## Installing a file (install target). # @param 1 The source filename. # @param 2 The destination filename. MSG_INST_FILE?= $(call MSG_L1I,IFIL,$2,(<= $1)) ## Installing a symlink. # @param 1 Symlink # @param 2 Link target MSG_INST_SYM ?= $(call MSG_L1I,ISYM,$1,=> $2) ## Installing a directory. # @param 1 Directory name. MSG_INST_DIR ?= $(call MSG_L1I,IDIR,$1) kbuild-3149/kBuild/msgstyles/brief.kmk0000644000175000017500000001127413252530215017746 0ustar locutuslocutus# $Id: brief.kmk 3130 2018-01-31 19:28:35Z bird $ ## @file # kBuild Message Style - 'brief' # # # Copyright (c) 2007-2017 knut st. osmundsen # # This file is part of kBuild. # # kBuild is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # kBuild 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 kBuild; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # As a special exception you are granted permission to include this file, via # the kmk include directive, as you wish without this in itself causing the # resulting makefile, program or whatever to be covered by the GPL license. # This exception does not however invalidate any other reasons why the makefile, # program, whatever should not be covered the GPL. # # # Indent the messages, drop the kBuild: prefix, and shorten paths. ifndef KBUILD_VERBOSE ifndef MSG_L1 MSG_L1 = %@$(PRINTF) " %-7s %s\n" \ "$(subst $(PATH_ROOT)/,{R}/,$(subst $(PATH_OUT)/,{O}/,$(subst $(CURDIR)/,{C}/,$(subst $(PATH_TARGET)/,{T}/,$1))))" \ "$(subst $(PATH_ROOT)/,{R}/,$(subst $(PATH_OUT)/,{O}/,$(subst $(CURDIR)/,{C}/,$(subst $(PATH_TARGET)/,{T}/,$2))))" endif else MSG_L1 ?= %@$(ECHO) " $(subst $(PATH_ROOT)/,{R}/,$(subst $(PATH_OUT)/,{O}/,$(subst $(CURDIR)/,{C}/,$(subst $(PATH_TARGET)/,{T}/,$1 $2))))" MSG_L2 ?= %@$(ECHO) " $(subst $(PATH_ROOT)/,{R}/,$(subst $(PATH_OUT)/,{O}/,$(subst $(CURDIR)/,{C}/,$(subst $(PATH_TARGET)/,{T}/,$1))))" endif ## Fetch starting. # @param 1 Target name. MSG_FETCH ?= $(call MSG_L1,FTCH,$1...) ## Re-fetch starting. # @param 1 Target name. MSG_REFETCH ?= $(call MSG_L1,RFTCH,$1...) ## Downloading a fetch component. # @param 1 Target name. # @param 2 The source URL. # @param 3 The destination file name. MSG_FETCH_DL ?= $(call MSG_L1,GET,$1 - $2,=> $3) ## Checking a fetch component. # @param 1 Target name. # @param 2 The source URL. # @param 3 The destination file name. MSG_FETCH_CHK?= $(call MSG_L1,CHK,$1 - $3, ($2)) ## Unpacking a fetch component. # @param 1 Target name. # @param 2 The archive file name. # @param 3 The target directory. MSG_FETCH_UP ?= $(call MSG_L1,UNPK,$1 - $2,=> $3) ## Fetch completed. # @param 1 Target name. MSG_FETCH_OK ?= $(call MSG_L1,DONE,$1) ## Unfetch a fetch target. # @param 1 Target name. MSG_UNFETCH ?= $(call MSG_L1,RM,$1...) ## Compiling a source file. # @param 1 Target name. # @param 2 The source filename. # @param 3 The primary link output file name. # @param 4 The source type (CXX,C,AS,RC,++). MSG_COMPILE ?= $(call MSG_L1,$4,$1 - $2,=> $3) ## Tool # @param 1 The tool name (bin2c,...) # @param 2 Target name. # @param 3 The source filename. # @param 4 The primary output file name. MSG_TOOL ?= $(call MSG_L1,$1,$2 - $3,=> $4) ## Generate a file, typically a source file. # @param 1 Target name if applicable. # @param 2 Output file name. # @param 3 What it's generated from MSG_GENERATE ?= $(call MSG_L1,GEN,$2) ## Linking a bldprog/dll/program/sysmod target. # @param 1 Target name. # @param 2 The primary link output file name. # @param 3 The link tool operation (LINK_LIBRARY,LINK_PROGRAM,LINK_DLL,LINK_SYSMOD,++). MSG_LINK ?= $(call MSG_L1,$(if $(eq $3,LINK_LIBRARY),AR,LD),$1,=> $2) ## Merging a library into the target (during library linking). # @param 1 Target name. # @param 2 The output library name. # @param 3 The input library name. MSG_AR_MERGE ?= $(NO_SUCH_VARIABLE) ## Creating a directory (build). # @param 1 Directory name. MSG_MKDIR ?= $(call MSG_L2,DIR,$1) ## Cleaning. MSG_CLEAN ?= $(call MSG_L1,CLEAN) ## Nothing. MSG_NOTHING ?= $(call MSG_L1,NOTHING $(CURDIR)) ## Installing a bldprog/lib/dll/program/sysmod target. # @param 1 Target name. # @param 2 The source filename. # @param 3 The destination file name. MSG_INST_TRG ?= $(call MSG_L1,INST,$1 => $3) ## Installing a file (install target). # @param 1 The source filename. # @param 2 The destination filename. MSG_INST_FILE?= $(call MSG_L1,IFIL,$2,(<= $1)) ## Installing a symlink. # @param 1 Symlink # @param 2 Link target MSG_INST_SYM ?= $(call MSG_L1,ISYM,$1,=> $2) ## Installing a directory. # @param 1 Directory name. MSG_INST_DIR ?= $(call MSG_L1,IDIR,$1) kbuild-3149/Config.kmk0000644000175000017500000003506613252530251014625 0ustar locutuslocutus# $Id: Config.kmk 3111 2017-10-22 11:38:15Z bird $ ## @file # Build Configuration. # # # Copyright (c) 2005-2012 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # # Enable automatic installation of what's built. KBUILD_DO_AUTO_INSTALL := 1 # # The kBuild version. # KBUILD_VERSION_MAJOR = 0 KBUILD_VERSION_MINOR = 1 KBUILD_VERSION_PATCH = 9998 KBUILD_VERSION = 0.1.9998 DEFS += \ KBUILD_VERSION_MAJOR=$(KBUILD_VERSION_MAJOR) \ KBUILD_VERSION_MINOR=$(KBUILD_VERSION_MINOR) \ KBUILD_VERSION_PATCH=$(KBUILD_VERSION_PATCH) # # Get the svn version. # This is shipped with the tarballs in a SvnInfo.kmk in the root. # ifneq ($(wildcard $(PATH_ROOT)/SvnInfo.kmk),) # Shipped KBUILD_SVN_INFO_KMK := $(PATH_ROOT)/SvnInfo.kmk KBUILD_SVN_INFO_DEP := $(KBUILD_SVN_INFO_KMK) else ifneq ($(wildcard $(PATH_ROOT)/.svn/ $(PATH_ROOT)/../.svn/),) # Generate from svn info KBUILD_SVN_INFO_KMK := $(PATH_OBJ)/SvnInfo.kmk KBUILD_SVN_INFO_DEP := $(KBUILD_SVN_INFO_KMK) $(PATH_OBJ)/SvnInfo.ts +| $(KBUILD_SVN_INFO_KMK): $(wildcard $(addprefix $(PATH_ROOT)/.svn/ $(PATH_ROOT)/../.svn/,\ . \ pristine \ wc.db \ tmp \ entries \ all-wcprops \ format \ props \ prop-base ) ) $(call MSG_GENERATE,,$(KBUILD_SVN_INFO_KMK)) @$(RM) -f $@ $@.tmp @$(MKDIR) -p $(@D) @$(REDIRECT) -o $@.tmp -E 'LC_ALL=C' -- svn info $(DEPTH) @$(SED) \ -e 's/^URL: */KBUILD_SVN_URL := /' \ -e 's/Revision: */KBUILD_SVN_REV := /' \ -e '/KBUILD_SVN_/!d' \ --append $@ \ $@.tmp @$(RM) -f $@.tmp @$(CP) --changed -fv $@ $(KBUILD_SVN_INFO_KMK) ifeq ($(DEPTH),.) OTHER_CLEAN += $(KBUILD_SVN_INFO_KMK) $(PATH_OBJ)/SvnInfo.ts endif else # Some incomplete source export... KBUILD_SVN_INFO_KMK := $(PATH_OBJ)/SvnInfo.kmk KBUILD_SVN_INFO_DEP := $(KBUILD_SVN_INFO_KMK) $(warning Neither SvnInfo nor .svn/* was found in the root. Will have to cook up something too keep the build happy.) $(KBUILD_SVN_INFO_KMK): $(RM) -f $@ $(MKDIR) -p $(@D) $(APPEND) $@ 'KBUILD_SVN_REV := 0' $(APPEND) $@ 'KBUILD_SVN_URL := /dev/null' ifeq ($(DEPTH),.) OTHER_CLEAN += $(KBUILD_SVN_INFO_KMK) endif endif include $(KBUILD_SVN_INFO_KMK) # # Local config, optional. # ifneq ($(wildcard $(PATH_ROOT)/LocalConfig.kmk),) include $(PATH_ROOT)/LocalConfig.kmk endif # # Where to fine the GNU Make stuff (for FreeBSD and Windows). # PATH_GNUMAKE_SRC ?= $(PATH_ROOT)/src/kmk # # Various platform specific hacks. # ifn1of ($(KBUILD_TARGET), haiku openbsd) GCC_Wextra = -Wextra endif if1of ($(KBUILD_TARGET), openbsd) TOOL_FLEX_LEX = gflex endif # # The OS and Architecture indicators. # DEFS.darwin += KBUILD_OS_DARWIN DEFS.freebsd += KBUILD_OS_FREEBSD DEFS.linux += KBUILD_OS_LINUX DEFS.netbsd += KBUILD_OS_NETBSD DEFS.openbsd += KBUILD_OS_OPENBSD DEFS.os2 += KBUILD_OS_OS2 DEFS.solaris += KBUILD_OS_SOLARIS DEFS.win += KBUILD_OS_WINDOWS DEFS.x86 += KBUILD_ARCH_X86 DEFS.amd64 += KBUILD_ARCH_AMD64 # # Check if we're building a *nix installation. # # There are a few optional overrides here for customizing the install location # and how it is installed: # MY_INST_BIN - the bin/ directory (the trailing slash is mandatory). # MY_INST_DATA - the share/kBuild/ directory (the trailing slash is mandatory). # MY_INST_DOC - the share/doc/kBuild-x.y.z/ directory (the trailing slash is mandatory). # MY_INST_UID - the default install UID or user name. # MY_INST_GID - the default install GID or group name. # MY_INST_MODE - the default install mode mask, ",a+x" is added for executables and files. # MY_INST_DATA_UID - data specialization. # MY_INST_DATA_GID - data specialization. # MY_INST_DATA_MODE - data specialization. # MY_INST_DOC_UID - doc specialization. # MY_INST_DOC_GID - doc specialization. # MY_INST_DOC_MODE - doc specialization. # MY_INST_BIN_UID - binary (executable) specialization. # MY_INST_BIN_GID - binary (executable) specialization. # MY_INST_BIN_MODE - binary (executable) specialization. # # When running kmk install, you can use PATH_INS like you use DESTDIR in other makefile # systems. (These things will be improved in 0.2.x btw, so will be possible to enable a # mode where PREFIX and DESTDIR will.) # # ifdef NIX_INSTALL_DIR MY_INST_ROOT := $(patsubst /%,%,$(NIX_INSTALL_DIR))/ ifndef MY_INST_BIN MY_INST_BIN := $(MY_INST_ROOT)bin/ endif ifndef MY_INST_DATA MY_INST_DATA := $(MY_INST_ROOT)share/kBuild/ endif ifndef MY_INST_DOC MY_INST_DOC := $(MY_INST_ROOT)share/doc/kBuild-$(KBUILD_VERSION)/ endif if !defined(MY_INST_BIN_MODE) && defined(MY_INST_MODE) MY_INST_BIN_MODE := $(MY_INST_MODE),a+x endif DEFS += \ KBUILD_PATH=\"/$(patsubst %/,%,$(MY_INST_DATA))\" \ KBUILD_BIN_PATH=\"/$(patsubst %/,%,$(MY_INST_BIN))\" endif # # Templates for installing docs and make scripts. # TEMPLATE_DATA = Data installation template. TEMPLATE_DATA_INST = $(MY_INST_DATA) TEMPLATE_DATA_MODE ?= $(firstword $(MY_INST_DATA_MODE) $(MY_INST_MODE) a+r) TEMPLATE_DATA_UID ?= $(firstword $(MY_INST_DATA_UID) $(MY_INST_UID)) TEMPLATE_DATA_GID ?= $(firstword $(MY_INST_DATA_GID) $(MY_INST_GID)) TEMPLATE_DOC = Documentation installation template. TEMPLATE_DOC_INST = $(MY_INST_DOC) TEMPLATE_DOC_MODE ?= $(firstword $(MY_INST_DOC_MODE) $(MY_INST_MODE) a+r) TEMPLATE_DOC_UID ?= $(firstword $(MY_INST_DOC_UID) $(MY_INST_UID)) TEMPLATE_DOC_GID ?= $(firstword $(MY_INST_DOC_GID) $(MY_INST_GID)) # # Template for building commandline tools. # TEMPLATE_BIN = Command line binary TEMPLATE_BIN_INCS = \ $(PATH_ROOT)/src/lib \ $(PATH_ROOT)/src/lib/kStuff/include TEMPLATE_BIN_DEFS.profile = NDEBUG TEMPLATE_BIN_DEFS.release = NDEBUG if defined(NIX_INSTALL_DIR) && !defined(KBUILD_BOOTSTRAP) TEMPLATE_BIN_INST = $(MY_INST_BIN) TEMPLATE_BIN_MODE ?= $(firstword $(MY_INST_BIN_MODE) a+rx) TEMPLATE_BIN_UID ?= $(firstword $(MY_INST_BIN_UID) $(MY_INST_UID)) TEMPLATE_BIN_GID ?= $(firstword $(MY_INST_BIN_GID) $(MY_INST_GID)) else TEMPLATE_BIN_INST = kBuild/bin/$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)/ endif ifeq ($(KBUILD_TARGET),os2) TEMPLATE_BIN_TOOL = GCC3OMF TEMPLATE_BIN_CFLAGS = -g TEMPLATE_BIN_CFLAGS.profile = -pg TEMPLATE_BIN_CFLAGS.release = -O3 TEMPLATE_BIN_LDFLAGS = -Zhigh-mem -Zstack=1024 -g else if1of ($(KBUILD_TARGET), win nt) TEMPLATE_BIN_TOOL = VCC100 TEMPLATE_BIN_TOOL.x86 = VCC100X86 TEMPLATE_BIN_TOOL.amd64 = VCC100AMD64 TEMPLATE_BIN_DEFS = WINDOWS32 _CONSOLE __WIN__ _CRT_SECURE_NO_DEPRECATE _CRT_NONSTDC_NO_WARNINGS TEMPLATE_BIN_DEFS.x86 = WIN32 __WIN32__ TEMPLATE_BIN_DEFS.amd64 = WIN32 __WIN32__ __WIN64__ WIN64 TEMPLATE_BIN_CFLAGS = -W3 -Zi -Zl TEMPLATE_BIN_CFLAGS.release = -O2 TEMPLATE_BIN_CFLAGS.profile = -O2 -GH -Gh TEMPLATE_BIN_INCS += \ . \ $(PATH_GNUMAKE_SRC)/w32/include \ $(PATH_GNUMAKE_SRC)/glob TEMPLATE_BIN_LDFLAGS = /SUBSYSTEM:console /INCREMENTAL:no /NOD /DEBUG /OPT:REF /OPT:ICF /LargeAddressAware ifeq ($(KBUILD_TYPE),profile) TEMPLATE_BIN_SDKS = WINPSDKINCS TEMPLATE_BIN_CFLAGS += -MT TEMPLATE_BIN_LIBS = \ D:/coding/kStuff/svn/trunk/out/win.$(KBUILD_TARGET_ARCH)/release/kStuff/lib/kPrf2.lib \ D:/coding/kStuff/svn/trunk/out/win.$(KBUILD_TARGET_ARCH)/release/kStuff/lib/kPrf2WinApiWrappersImp.lib \ $(PATH_TOOL_$(TEMPLATE_BIN_TOOL)_LIB)/oldnames.lib \ $(PATH_TOOL_$(TEMPLATE_BIN_TOOL)_LIB)/libcmt.lib \ $(PATH_TOOL_$(TEMPLATE_BIN_TOOL)_LIB)/libcpmt.lib \ D:/coding/kStuff/svn/trunk/out/win.$(KBUILD_TARGET_ARCH)/release/kStuff/lib/kPrf2WinApiWrappersImp.lib \ $(PATH_SDK_WINPSDKINCS_LIB)/AdvAPI32.lib \ $(PATH_SDK_WINPSDKINCS_LIB)/User32.lib else TEMPLATE_BIN_SDKS = WINPSDK71 ifdef KBUILD_WITH_STATIC_MSVCRT TEMPLATE_BIN_CFLAGS += -MT TEMPLATE_BIN_LIBS = \ $(PATH_TOOL_$(TEMPLATE_BIN_TOOL)_LIB)/oldnames.lib \ $(PATH_TOOL_$(TEMPLATE_BIN_TOOL)_LIB)/libcmt.lib \ $(PATH_TOOL_$(TEMPLATE_BIN_TOOL)_LIB)/libcpmt.lib else TEMPLATE_BIN_CFLAGS += -MD TEMPLATE_BIN_LIBS = \ $(PATH_TOOL_$(TEMPLATE_BIN_TOOL)_LIB)/oldnames.lib \ $(PATH_TOOL_$(TEMPLATE_BIN_TOOL)_LIB)/msvcrt.lib endif endif else # !os2, !win, !nt ifeq ($(KBUILD_TARGET),darwin) ifndef KBUILD_MACOSX_VERSION export KBUILD_MACOSX_VERSION := $(expr $(firstword $(subst ., ,$(shell uname -r))) - 4) endif #ifndef KBUILD_XCODE_VERSION # export KBUILD_XCODE_VERSION := $(shell xcodebuild -version | kmk_sed -e '/Xcode/!d' -e 's/Xcode *//') #endif ifndef KBUILD_MACOSX_TARGET_VERSION if $(KBUILD_TARGET_ARCH) == amd64 KBUILD_MACOSX_TARGET_VERSION = 6 else KBUILD_MACOSX_TARGET_VERSION = 5 endif endif ifndef KBUILD_MACOSX_WHATEVER_MODE if $(KBUILD_MACOSX_TARGET_VERSION) == 4 TOOL_GCC4MACHO_SUFFIX = -4.0 TOOL_GXX4MACHO_SUFFIX = -4.0 else if $(KBUILD_MACOSX_TARGET_VERSION) >= 5 TOOL_GCC4MACHO_SUFFIX = -4.2 TOOL_GXX4MACHO_SUFFIX = -4.2 endif ifndef KBUILD_MACOSX_SDK KBUILD_MACOSX_SDK := /Developer/SDKs/MacOSX10.$(KBUILD_MACOSX_TARGET_VERSION)$(if-expr $(KBUILD_MACOSX_TARGET_VERSION)==4,u,).sdk ifeq ($(wildcard $(KBUILD_MACOSX_SDK)),) KBUILD_MACOSX_SDK := /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform$(KBUILD_MACOSX_SDK) endif endif ifeq ($(wildcard $(KBUILD_MACOSX_SDK)),) $(error SDK not found ($(KBUILD_MACOSX_SDK)), please adjust KBUILD_MACOSX_TARGET_VERSION or/and KBUILD_MACOSX_SDK in LocalConfig.kmk or simply use KBUILD_MACOSX_WHATEVER_MODE=1.) endif endif # !KBUILD_MACOSX_WHATEVER_MODE TEMPLATE_BIN_TOOL = GCC4MACHO TEMPLATE_BIN_CFLAGS = -g -mmacosx-version-min=10.$(KBUILD_MACOSX_TARGET_VERSION) $(if $(KBUILD_MACOSX_WHATEVER_MODE),,-isysroot $(KBUILD_MACOSX_SDK)) ifeq ($(USER),bird) TEMPLATE_BIN_CFLAGS += -Wall $(GCC_Wextra) -pedantic -Wno-unused-parameter -Wno-long-long -Wshadow TEMPLATE_BIN_DEFS += NO_ENUM_BITFIELDS endif TEMPLATE_BIN_CFLAGS.profile = -O3 -pg TEMPLATE_BIN_CFLAGS.release = -O3 TEMPLATE_BIN_LDFLAGS = -g -mmacosx-version-min=10.$(KBUILD_MACOSX_TARGET_VERSION) $(if $(KBUILD_MACOSX_WHATEVER_MODE),,-Wl,-syslibroot,$(KBUILD_MACOSX_SDK)) if $(KBUILD_MACOSX_TARGET_VERSION) == 4 && $(KBUILD_MACOSX_VERSION) >= 5 TEMPLATE_BIN_LDFLAGS += -classic_ld endif TEMPLATE_BIN_LDFLAGS.profile = -pg else # !darwin # Use GCC3 when we're certain that the system is using GNU ld and ar. ifeq ($(filter-out linux freebsd openbsd netbsd,$(KBUILD_TARGET)),) TEMPLATE_BIN_TOOL = GCC3 else TEMPLATE_BIN_TOOL = GCC3PLAIN endif TEMPLATE_BIN_CFLAGS = -g ifeq ($(USER),bird) TEMPLATE_BIN_CFLAGS += -Wall $(GCC_Wextra) -pedantic -Wno-unused-parameter -Wshadow TEMPLATE_BIN_DEFS += NO_ENUM_BITFIELDS endif TEMPLATE_BIN_LDFLAGS = -g TEMPLATE_BIN_LDFLAGS.profile = -pg -p TEMPLATE_BIN_CFLAGS.release = -O3 TEMPLATE_BIN_CFLAGS.profile = -O3 -pg -p ifeq ($(KBUILD_TARGET),freebsd) TEMPLATE_BIN_INCS += $(PATH_GNUMAKE_SRC)/glob /usr/local/include endif ifeq ($(KBUILD_TARGET),linux) TEMPLATE_BIN_LIBS += rt endif endif # Make sure we get the right bit count in the output. TEMPLATE_BIN_CFLAGS.x86 += -m32 TEMPLATE_BIN_CFLAGS.x32 += -mx32 TEMPLATE_BIN_CFLAGS.sparc32 += -m32 TEMPLATE_BIN_CFLAGS.amd64 += -m64 TEMPLATE_BIN_CFLAGS.sparc64 += -m64 TEMPLATE_BIN_CXXFLAGS.x86 += -m32 TEMPLATE_BIN_CXXFLAGS.x32 += -mx32 TEMPLATE_BIN_CXXFLAGS.sparc32 += -m32 TEMPLATE_BIN_CXXFLAGS.amd64 += -m64 TEMPLATE_BIN_CXXFLAGS.sparc64 += -m64 TEMPLATE_BIN_LDFLAGS.x86 += -m32 TEMPLATE_BIN_LDFLAGS.x32 += -mx32 TEMPLATE_BIN_LDFLAGS.sparc32 += -m32 TEMPLATE_BIN_LDFLAGS.amd64 += -m64 TEMPLATE_BIN_LDFLAGS.sparc64 += -m64 ifeq ($(KBUILD_TARGET),solaris) TEMPLATE_BIN_LIBS += rt dl TEMPLATE_BIN_LDFLAGS += -Wl,-i TEMPLATE_BIN_DEFS.x86 += _FILE_OFFSET_BITS=64 _LARGEFILE_SOURCE TEMPLATE_BIN_DEFS.sparc32 += _FILE_OFFSET_BITS=64 _LARGEFILE_SOURCE endif ifeq ($(KBUILD_TARGET),netbsd) TEMPLATE_BIN_LIBS += util endif endif # On systems where it's possible, do split out the debug info from the binaries. if1of ($(KBUILD_TARGET), darwin win) TEMPLATE_BIN_LD_DEBUG = split endif # # Template for building threaded binaries. # TEMPLATE_BIN-THREADED = Threaded command line binary TEMPLATE_BIN-THREADED_EXTENDS = BIN TEMPLATE_BIN-THREADED_EXTENDS_BY = appending if1of ($(KBUILD_TARGET), dragonfly freebsd gnuhurd gnukfbsd gnuknbsd linux netbsd openbsd) TEMPLATE_BIN-THREADED_LIBS = pthread endif # # Template for building libraries for the tools. # TEMPLATE_LIB = Library for Commandline binary TEMPLATE_LIB_EXTENDS = BIN TEMPLATE_LIB_INST = lib/ # for LIB_KDEP TEMPLATE_LIB_TOOL = $(TEMPLATE_BIN_TOOL) # # Template for static threaded binaries (windows). # TEMPLATE_BIN-STATIC-THREADED = Threaded command line binary TEMPLATE_BIN-STATIC-THREADED_EXTENDS = BIN-THREADED ifeq ($(filter-out win nt,$(KBUILD_TARGET)),) TEMPLATE_BIN-STATIC-THREADED_CFLAGS = $(filter-out -MD,$(TEMPLATE_BIN-THREADED_CFLAGS)) -MT TEMPLATE_BIN-STATIC-THREADED_LIBS = $(filter-out %/msvcrt.lib,$(TEMPLATE_BIN-THREADED_LIBS)) \ $(PATH_TOOL_$(TEMPLATE_BIN_TOOL)_LIB)/libcmt.lib \ $(PATH_TOOL_$(TEMPLATE_BIN_TOOL)_LIB)/libcpmt.lib else TEMPLATE_BIN-STATIC-THREADED_CFLAGS = $(TEMPLATE_BIN-THREADED_CFLAGS) -static TEMPLATE_BIN-STATIC-THREADED_LDFLAGS = $(TEMPLATE_BIN-THREADED_LDFLAGS) -static endif # # Template for static threaded libraries. # TEMPLATE_LIB-STATIC-THREADED = Threaded command line library TEMPLATE_LIB-STATIC-THREADED_EXTENDS = BIN-STATIC-THREADED TEMPLATE_LIB-STATIC-THREADED_INST = lib/ # # Library macros. # LIB_KDEP = $(PATH_OBJ)/kDep/$(TOOL_$(TEMPLATE_LIB_TOOL)_ARLIBPREF)kDep$(TOOL_$(TEMPLATE_LIB_TOOL)_ARLIBSUFF) LIB_KUTIL = $(PATH_OBJ)/kUtil/$(TOOL_$(TEMPLATE_LIB_TOOL)_ARLIBPREF)kUtil$(TOOL_$(TEMPLATE_LIB_TOOL)_ARLIBSUFF) kbuild-3149/dist/0000755000175000017500000000000013252530251013645 5ustar locutuslocutuskbuild-3149/dist/debian/0000755000175000017500000000000013252530251015067 5ustar locutuslocutuskbuild-3149/dist/debian/links0000644000175000017500000000305413252530251016134 0ustar locutuslocutus/usr/share/man/man1/kmk.1.gz /usr/share/man/man1/kmk_append.1.gz /usr/share/man/man1/kmk.1.gz /usr/share/man/man1/kmk_ash.1.gz /usr/share/man/man1/kmk.1.gz /usr/share/man/man1/kmk_cat.1.gz /usr/share/man/man1/kmk.1.gz /usr/share/man/man1/kmk_chmod.1.gz /usr/share/man/man1/kmk.1.gz /usr/share/man/man1/kmk_cmp.1.gz /usr/share/man/man1/kmk.1.gz /usr/share/man/man1/kmk_cp.1.gz /usr/share/man/man1/kmk.1.gz /usr/share/man/man1/kmk_echo.1.gz /usr/share/man/man1/kmk.1.gz /usr/share/man/man1/kmk_expr.1.gz /usr/share/man/man1/kmk.1.gz /usr/share/man/man1/kmk_gmake.1.gz /usr/share/man/man1/kmk.1.gz /usr/share/man/man1/kmk_install.1.gz /usr/share/man/man1/kmk.1.gz /usr/share/man/man1/kmk_ln.1.gz /usr/share/man/man1/kmk.1.gz /usr/share/man/man1/kmk_md5sum.1.gz /usr/share/man/man1/kmk.1.gz /usr/share/man/man1/kmk_mkdir.1.gz /usr/share/man/man1/kmk.1.gz /usr/share/man/man1/kmk_mv.1.gz /usr/share/man/man1/kmk.1.gz /usr/share/man/man1/kmk_printf.1.gz /usr/share/man/man1/kmk.1.gz /usr/share/man/man1/kmk_redirect.1.gz /usr/share/man/man1/kmk.1.gz /usr/share/man/man1/kmk_rm.1.gz /usr/share/man/man1/kmk.1.gz /usr/share/man/man1/kmk_rmdir.1.gz /usr/share/man/man1/kmk.1.gz /usr/share/man/man1/kmk_sed.1.gz /usr/share/man/man1/kmk.1.gz /usr/share/man/man1/kmk_sleep.1.gz /usr/share/man/man1/kmk.1.gz /usr/share/man/man1/kmk_test.1.gz /usr/share/man/man1/kmk.1.gz /usr/share/man/man1/kmk_time.1.gz /usr/share/man/man1/kmk.1.gz /usr/share/man/man1/kDepPre.1.gz /usr/share/man/man1/kmk.1.gz /usr/share/man/man1/kDepIDB.1.gz /usr/share/man/man1/kmk.1.gz /usr/share/man/man1/kObjCache.1.gz kbuild-3149/dist/debian/kbuild.doc-base0000644000175000017500000000041713252530251017742 0ustar locutuslocutusDocument: kBuild Title: kmk Quick Reference Author: Knut St. Osmundsen Abstract: Brief description of all the features of the make program. Section: Devel/Tools Format: HTML Index: /usr/share/doc/kbuild/kmk-QuickReference-kmk.html Files: /usr/share/doc/kbuild*.htmlkbuild-3149/dist/debian/changelog0000644000175000017500000001445713252530251016754 0ustar locutuslocutuskbuild (1:0.1.5-1) unstable; urgency=low * New upstream version. * Adopted for tarball use. -- bird Thu, 22 Jan 2009 01:05:00 +0100 kbuild (1:0.1.5svn2062-1) unstable; urgency=low * new upstream version * Remove patch lazy.diff that has been applied upstream. -- Torsten Werner Wed, 12 Nov 2008 21:54:38 +0100 kbuild (1:0.1.5svn2059-2) unstable; urgency=low * Create SvnInfo.kmk during build process because the upstream svn does not ship it anymore. -- Torsten Werner Sat, 08 Nov 2008 09:17:10 +0100 kbuild (1:0.1.5svn2059-1) unstable; urgency=low * new upstream version * Add patch lazy.diff to fix build process. * Add more manpage symlinks. -- Torsten Werner Fri, 07 Nov 2008 23:25:40 +0100 kbuild (1:0.1.4svn1804-1) unstable; urgency=low * new upstream version * Bump up Standards-Version: 3.8.0 (no changes). -- Torsten Werner Tue, 07 Oct 2008 20:50:48 +0200 kbuild (1:0.1.3svn1610-1) unstable; urgency=low * new upstream version (Closes: #479046, #480012) * Remove patch cpu.diff that has been applied upstream. -- Torsten Werner Thu, 08 May 2008 20:20:07 +0200 kbuild (1:0.1.3svn1587-1) unstable; urgency=low * new upstream version * Add support for armv5tejl. -- Torsten Werner Thu, 17 Apr 2008 22:08:34 +0200 kbuild (1:0.1.2svn1393-2) unstable; urgency=high * Add patch to fix build on parisc. * Set urgency to high because we are fixing a FTBFS bug on 1 arch. -- Torsten Werner Thu, 10 Apr 2008 22:42:26 +0200 kbuild (1:0.1.2svn1393-1) unstable; urgency=low * new upstream release * Remove our patch because it has been applied upstream. -- Torsten Werner Sun, 09 Mar 2008 22:29:26 +0100 kbuild (1:0.1.2svn1377-5) unstable; urgency=low * Add support for s390x. -- Torsten Werner Sun, 30 Dec 2007 23:54:18 +0100 kbuild (1:0.1.2svn1377-4) unstable; urgency=low * Add support for mips. -- Torsten Werner Sun, 30 Dec 2007 22:53:09 +0100 kbuild (1:0.1.2svn1377-3) unstable; urgency=low * Add support for armv5tel. -- Torsten Werner Fri, 28 Dec 2007 23:39:11 +0100 kbuild (1:0.1.2svn1377-2) unstable; urgency=low * Add support for PA-RISC. -- Torsten Werner Fri, 28 Dec 2007 13:20:11 +0100 kbuild (1:0.1.2svn1377-1) unstable; urgency=low * Use version number (KBUILD_VERSION) from file Config.kmk for our package. * Always bootstrap kBuild because it is required. * Add Build-Depends: autoconf, automake, cvs. * Remove Build-Depends: doxygen, kbuild. -- Torsten Werner Sat, 22 Dec 2007 11:53:03 +0100 kbuild (1377-2) unstable; urgency=low * Add patch cpu.diff to support Debian's architectures. * Set LDFLAGS to -Wl,--as-needed to avoid linking of unneeded libraries. * Use the freshly built kmk for the installation step instead of the old one used for the build step. Rationale: that is a very basic test that the new kmk is really working. -- Torsten Werner Fri, 21 Dec 2007 18:06:38 +0100 kbuild (1377-1) unstable; urgency=low * new upstream version * Add some debugging output (gcc macros). * Update Homepage and Vcs headers in debian/control. * Change Standards-Version: 3.7.3. * Add manpage symlinks for kmk_redirect and kmk_test. -- Torsten Werner Fri, 21 Dec 2007 12:30:37 +0100 kbuild (1366-1) unstable; urgency=low * new upstream version - Does not ship kBuild.Doxyfile any more. * Remove all references to the obsoleted documentation files. (Closes: #454038) * Remove Depends: autoconf, automake1.9. -- Torsten Werner Mon, 03 Dec 2007 18:59:04 +0100 kbuild (1258-1) unstable; urgency=low * new upstream release * Remove the last patch because it has been applied upstream. -- Torsten Werner Sun, 28 Oct 2007 23:05:09 +0100 kbuild (1173-1) unstable; urgency=low * new upstream release * Fix the get-orig-source target in debian/rules. * Removed all patches that have been applied upstream. * Add more man page symlinks (kmk_cmp and kmk_md5sum). -- Torsten Werner Tue, 02 Oct 2007 21:59:51 +0200 kbuild (1096-1) unstable; urgency=low * new upstream version * Add kbuild to Build-Depends. * Fix clean target. (Closes: #442611) * Comment the patches. -- Torsten Werner Sun, 16 Sep 2007 19:06:22 +0200 kbuild (1080-2) unstable; urgency=low * Add patch arm.diff to support armv4l too. -- Torsten Werner Sat, 21 Jul 2007 12:26:46 +0200 kbuild (1080-1) unstable; urgency=low * New upstream version * Add a patch debug.diff that fixes debugging output. -- Torsten Werner Sat, 21 Jul 2007 08:27:12 +0200 kbuild (1060-1) unstable; urgency=low * New upstream version * Bootstrap every architecture again because some binaries are buggy. -- Torsten Werner Sat, 9 Jun 2007 07:42:44 +0200 kbuild (894-5) unstable; urgency=low * Remove directory 'out' in clean target. (Closes: #424426) -- Torsten Werner Sat, 19 May 2007 23:25:17 +0200 kbuild (894-4) unstable; urgency=low * Add hppa, ia64, mips, mipsel, powerpc, s390 to already bootstrapped architectures. * Add patch unused.diff to fix a build problem on alpha. -- Torsten Werner Mon, 14 May 2007 05:30:43 +0200 kbuild (894-3) unstable; urgency=low * Add yet another fix for the missing architectures. -- Torsten Werner Sat, 12 May 2007 18:32:30 +0200 kbuild (894-2) unstable; urgency=low * Complete the last (incomplete) patch. -- Torsten Werner Sat, 12 May 2007 15:20:34 +0200 kbuild (894-1) unstable; urgency=low * New upstream revision. * Use the revision number from debian/changelog for debian/orig-tar.sh. * Add Build-Depends: kbuild [amd64 i386]. * Add a patch to support all Debian architectures. -- Torsten Werner Sat, 12 May 2007 14:38:49 +0200 kbuild (893-1) unstable; urgency=low * Initial release (Closes: #422367) -- Torsten Werner Fri, 4 May 2007 20:35:40 +0200 kbuild-3149/dist/debian/patches/0000755000175000017500000000000013252530251016516 5ustar locutuslocutuskbuild-3149/dist/debian/manpages0000644000175000017500000000001513252530251016601 0ustar locutuslocutusdebian/kmk.1 kbuild-3149/dist/debian/control0000644000175000017500000000263013252530251016473 0ustar locutuslocutusSource: kbuild Section: devel Priority: extra Maintainer: Torsten Werner Build-Depends: autoconf, automake, byacc, cdbs, cvs, debhelper (>= 5), flex, quilt Standards-Version: 3.8.0 Homepage: http://svn.netlabs.org/kbuild Vcs-Svn: https://bollin.googlecode.com/svn/kbuild/trunk Vcs-Browser: http://bollin.googlecode.com/svn/kbuild/trunk Package: kbuild Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: framework for writing simple makefiles for complex tasks The goals of the kBuild framework: - Similar behavior cross all supported platforms. - Flexibility, don't create unnecessary restrictions preventing ad-hoc solutions. - Makefile can very simple to write and maintain. . There are four concepts being tried out in the current kBuild incaration: - One configuration file for a subtree automatically included. - Target configuration templates as the primary mechanism for makefile simplification. - Tools and SDKs for helping out the templates with flexibility. - Non-recursive makefile method by using sub-makefiles. . kBuild does not provide any facilities for checking compiler/library/header configurations, that's not in its scope. If this is important for your project, check out the autoconf tool in the GNU build system. It is possible to use kBuild together with autoconf if you like, but you might just as well use the full GNU package. kbuild-3149/dist/debian/copyright0000644000175000017500000000330613252530251017024 0ustar locutuslocutusThis package was debianized by Torsten Werner on Sat May 5 14:23:24 CEST 2007. It was downloaded from http://svn.netlabs.org/kbuild Upstream Author: 2004-2010 knut st. osmundsen Copyright: (C) 2004-2010 knut st. osmundsen License: This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. On Debian systems, the complete text of the GNU General Public License can be found in `/usr/share/common-licenses/GPL'. kBuild ships modified sources of ash, make and sed. NetBSD ash is Copyright (C) 1993 The Regents of the University of California. ash is licensed under the BSD license, see `/usr/share/common-licenses/BSD'. GNU make is Copyright (C) 2007 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later GNU sed is Copyright (C) 2003 Free Software Foundation, Inc. licensed under the GPL, see `/usr/share/common-licenses/GPL`. The Debian packaging is (C) 2007, Torsten Werner and is licensed under the GPL, see `/usr/share/common-licenses/GPL'. kbuild-3149/dist/debian/rules0000755000175000017500000000322713252530251016153 0ustar locutuslocutus#!/usr/bin/make -f include /usr/share/cdbs/1/rules/debhelper.mk include /usr/share/cdbs/1/rules/patchsys-quilt.mk YACC := YACC=/usr/bin/byacc BOOTSTRAP := ASH=/bin/bash ECHO=/bin/echo MKDIR=/bin/mkdir CP=/bin/cp \ RM=/bin/rm INSTALL=/usr/bin/install $(YACC) ifdef KBUILD_FROM_SVN SVNROOT := http://svn.netlabs.org/repos/kbuild/trunk REVISION := $(shell echo $(DEB_UPSTREAM_VERSION) | sed -e's,.*svn,,') makebuilddir:: SvnInfo.kmk SvnInfo.kmk: echo "KBUILD_SVN_URL := $(SVNROOT)" > $@ echo "KBUILD_SVN_REV := $(REVISION)" >> $@ endif build/kbuild:: debian/stamp-build debian/stamp-build: $(info DEBUG: macros defined by gcc:) -gcc -dM -E - < /dev/null kBuild/env.sh --full make -f bootstrap.gmk SRCDIR=`pwd` $(BOOTSTRAP) kBuild/env.sh kmk rebuild PATH_INS=`pwd` $(YACC) pod2man -c 'kBuild for Debian GNU/Linux' \ -r kBuild-$(DEB_UPSTREAM_VERSION) debian/kmk.pod > debian/kmk.1 touch $@ install/kbuild:: kBuild/env.sh kmk install NIX_INSTALL_DIR=/usr \ MY_INST_DOC=share/doc/kbuild/ LDFLAGS=-Wl,--as-needed clean:: -kBuild/env.sh kmk uninstall $(RM) -r debian/stamp-* debian/kmk.1 out kBuild/bin/*/* ifdef KBUILD_FROM_SVN $(RM) SvnInfo.kmk endif ## @todo fetch from ftp://ftp.netlabs.org/pub/kbuild or ## ftp://ftp.netlabs.org/incoming/kbuild when KBUILD_FROM_SVN isn't ## defined... (fetch the kBuild-x.y.z-src.tar.gz file) ifdef KBUILD_FROM_SVN get-orig-info: svn info $(SVNROOT) get-orig-source: sh debian/orig-tar.sh $(SVNROOT) $(DEB_UPSTREAM_VERSION) $(REVISION) else get-orig-source: wget -O ../tarballs/kbuild_$(DEB_UPSTREAM_VERSION).orig.tar.gz \ ftp://ftp.netlabs.org/incoming/kbuild/kBuild-$(DEB_UPSTREAM_VERSION)-src.tar.gz endif kbuild-3149/dist/debian/install0000644000175000017500000000002713252530251016457 0ustar locutuslocutusout/*.*/release/usr / kbuild-3149/dist/debian/compat0000644000175000017500000000000213252530251016265 0ustar locutuslocutus5 kbuild-3149/dist/debian/orig-tar.sh0000755000175000017500000000057513252530251017161 0ustar locutuslocutus#!/bin/sh -e SVNROOT=$1 VERSION=$2 REVISION=$3 DIR=kbuild-$REVISION TAR=../kbuild_$VERSION.orig.tar.gz svn co -r $REVISION $SVNROOT $DIR tar -c -z --exclude '*/kBuild/bin*' --exclude '*/out/*' --exclude '*/.svn*' -f $TAR $DIR rm -rf $DIR # move to directory 'tarballs' if [ -r .svn/deb-layout ]; then . .svn/deb-layout mv $TAR $origDir echo "moved $TAR to $origDir" fi kbuild-3149/dist/debian/kmk.pod0000644000175000017500000000106613252530251016360 0ustar locutuslocutus=head1 NAME kmk - framework for writing simple makefiles for complex tasks =head1 SYNOPSIS B [S>] =head1 DESCRIPTION kmk and its helper tools are an extension to GNU make to ease writing portable Makefile. There is not a lot of documentation though. A starting point is L. On Debian systems the kBuild binaries can be found in F, its data files in F and its documentation in F. =head1 SEE ALSO L =head1 AUTHOR Torsten Werner kbuild-3149/dist/freebsd/0000755000175000017500000000000013252530251015257 5ustar locutuslocutuskbuild-3149/dist/freebsd/devel/0000755000175000017500000000000013252530251016356 5ustar locutuslocutuskbuild-3149/dist/freebsd/devel/kBuild/0000755000175000017500000000000013252530251017570 5ustar locutuslocutuskbuild-3149/dist/freebsd/devel/kBuild/pkg-plist0000644000175000017500000000556213252530251021435 0ustar locutuslocutusbin/kmk_sed bin/kmk bin/kmk_append bin/kmk_cat bin/kmk_chmod bin/kmk_cp bin/kmk_cmp bin/kmk_echo bin/kmk_expr bin/kmk_md5sum bin/kmk_mkdir bin/kmk_mv bin/kmk_install bin/kmk_ln bin/kmk_printf bin/kmk_redirect bin/kmk_rm bin/kmk_rmdir bin/kmk_sleep bin/kmk_test bin/kDepIDB bin/kmk_gmake bin/kmk_fgmake bin/kmk_ash bin/kDepPre bin/kObjCache bin/kmk_time %%DATADIR%%/footer.kmk %%DATADIR%%/header.kmk %%DATADIR%%/rules.kmk %%DATADIR%%/subfooter.kmk %%DATADIR%%/subheader.kmk %%DATADIR%%/up.kmk %%DATADIR%%/tools/ALP.kmk %%DATADIR%%/tools/BISON.kmk %%DATADIR%%/tools/FLEX.kmk %%DATADIR%%/tools/GCC.kmk %%DATADIR%%/tools/GCC3.kmk %%DATADIR%%/tools/GCC32.kmk %%DATADIR%%/tools/GCC3OMF.kmk %%DATADIR%%/tools/GCC3PLAIN.kmk %%DATADIR%%/tools/GCC4MACHO.kmk %%DATADIR%%/tools/GCC64.kmk %%DATADIR%%/tools/GXX.kmk %%DATADIR%%/tools/GXX3.kmk %%DATADIR%%/tools/GXX32.kmk %%DATADIR%%/tools/GXX3OMF.kmk %%DATADIR%%/tools/GXX3PLAIN.kmk %%DATADIR%%/tools/GXX4MACHO.kmk %%DATADIR%%/tools/GXX64.kmk %%DATADIR%%/tools/MASM510.kmk %%DATADIR%%/tools/MASM600.kmk %%DATADIR%%/tools/MASM610.kmk %%DATADIR%%/tools/MASM6PLUS.kmk %%DATADIR%%/tools/MASM710.kmk %%DATADIR%%/tools/MINGW32.kmk %%DATADIR%%/tools/MSLINK510.kmk %%DATADIR%%/tools/NASM.kmk %%DATADIR%%/tools/OPENWATCOM-16.kmk %%DATADIR%%/tools/OPENWATCOM-WL.kmk %%DATADIR%%/tools/OPENWATCOM.kmk %%DATADIR%%/tools/TAR.kmk %%DATADIR%%/tools/TARGZ.kmk %%DATADIR%%/tools/VAC308.kmk %%DATADIR%%/tools/VCC70.kmk %%DATADIR%%/tools/VCC80.kmk %%DATADIR%%/tools/VCC80AMD64.kmk %%DATADIR%%/tools/VCC80X86.kmk %%DATADIR%%/tools/WATCOMC11C-16.kmk %%DATADIR%%/tools/WATCOMC11C-WL.kmk %%DATADIR%%/tools/WATCOMC11C.kmk %%DATADIR%%/tools/WGET.kmk %%DATADIR%%/tools/XGCCAMD64LINUX.kmk %%DATADIR%%/tools/YACC.kmk %%DATADIR%%/tools/YASM.kmk %%DATADIR%%/tools/ZIP.kmk %%DATADIR%%/sdks/DXSDK.kmk %%DATADIR%%/sdks/DXSDKAMD64.kmk %%DATADIR%%/sdks/DXSDKX86.kmk %%DATADIR%%/sdks/LIBSDL.kmk %%DATADIR%%/sdks/MACOSX104.kmk %%DATADIR%%/sdks/MACOSX104INCS.kmk %%DATADIR%%/sdks/MACOSX105.kmk %%DATADIR%%/sdks/MACOSX105INCS.kmk %%DATADIR%%/sdks/NT4DDK.kmk %%DATADIR%%/sdks/OS2DDKBASE32.kmk %%DATADIR%%/sdks/W2K3DDK.kmk %%DATADIR%%/sdks/W2K3DDKAMD64.kmk %%DATADIR%%/sdks/W2K3DDKX86.kmk %%DATADIR%%/sdks/W32API.kmk %%DATADIR%%/sdks/WIN32SDK.kmk %%DATADIR%%/sdks/WIN32SDK2002.kmk %%DATADIR%%/sdks/WIN64SDK.kmk %%DATADIR%%/sdks/WINDDK.kmk %%DATADIR%%/sdks/WINDDKW2K.kmk %%DATADIR%%/sdks/WINDDKWLH.kmk %%DATADIR%%/sdks/WINDDKWNET.kmk %%DATADIR%%/sdks/WINDDKWXP.kmk %%DATADIR%%/sdks/WINPSDK.kmk %%DATADIR%%/sdks/WINPSDKINCS.kmk %%DATADIR%%/units/lex.kmk %%DATADIR%%/units/qt3.kmk %%DATADIR%%/units/qt4.kmk %%DATADIR%%/units/yacc.kmk %%DATADIR%%/msgstyles/brief.kmk %%DATADIR%%/templates/DUMMY.kmk %%DOCSDIR%%/QuickReference-kmk.txt %%DOCSDIR%%/QuickReference-kmk.html @dirrm %%DATADIR%%/msgstyles @dirrm %%DATADIR%%/sdks @dirrm %%DATADIR%%/templates @dirrm %%DATADIR%%/tools @dirrm %%DATADIR%%/units @dirrm %%DATADIR%% @dirrm %%DOCSDIR%% kbuild-3149/dist/freebsd/devel/kBuild/distinfo0000644000175000017500000000031613252530251021332 0ustar locutuslocutusMD5 (kBuild-0.1.5-src.tar.gz) = df7e0905232e67728643f97d63cbf3f3 SHA256 (kBuild-0.1.5-src.tar.gz) = db3b672da8f579949e4d8c41d023d6d1ca1ab5626a2e552970ba75e7a3af84b5 SIZE (kBuild-0.1.5-src.tar.gz) = 2431964 kbuild-3149/dist/freebsd/devel/kBuild/kBuild-files.mk0000644000175000017500000000411513252530251022434 0ustar locutuslocutus# Autogenerated by kbuild-generate-files in Makefile KBUILD_BIN_FILES = \ kmk_sed \ kmk \ kmk_append \ kmk_cat \ kmk_chmod \ kmk_cp \ kmk_cmp \ kmk_echo \ kmk_expr \ kmk_md5sum \ kmk_mkdir \ kmk_mv \ kmk_install \ kmk_ln \ kmk_printf \ kmk_redirect \ kmk_rm \ kmk_rmdir \ kmk_sleep \ kmk_test \ kDepIDB \ kmk_gmake \ kmk_fgmake \ kmk_ash \ kDepPre \ kObjCache \ kmk_time \ KBUILD_DATA_FILES = \ footer.kmk \ header.kmk \ rules.kmk \ subfooter.kmk \ subheader.kmk \ up.kmk \ tools/ALP.kmk \ tools/BISON.kmk \ tools/FLEX.kmk \ tools/GCC.kmk \ tools/GCC3.kmk \ tools/GCC32.kmk \ tools/GCC3OMF.kmk \ tools/GCC3PLAIN.kmk \ tools/GCC4MACHO.kmk \ tools/GCC64.kmk \ tools/GXX.kmk \ tools/GXX3.kmk \ tools/GXX32.kmk \ tools/GXX3OMF.kmk \ tools/GXX3PLAIN.kmk \ tools/GXX4MACHO.kmk \ tools/GXX64.kmk \ tools/MASM510.kmk \ tools/MASM600.kmk \ tools/MASM610.kmk \ tools/MASM6PLUS.kmk \ tools/MASM710.kmk \ tools/MINGW32.kmk \ tools/MSLINK510.kmk \ tools/NASM.kmk \ tools/OPENWATCOM-16.kmk \ tools/OPENWATCOM-WL.kmk \ tools/OPENWATCOM.kmk \ tools/TAR.kmk \ tools/TARGZ.kmk \ tools/VAC308.kmk \ tools/VCC70.kmk \ tools/VCC80.kmk \ tools/VCC80AMD64.kmk \ tools/VCC80X86.kmk \ tools/WATCOMC11C-16.kmk \ tools/WATCOMC11C-WL.kmk \ tools/WATCOMC11C.kmk \ tools/WGET.kmk \ tools/XGCCAMD64LINUX.kmk \ tools/YACC.kmk \ tools/YASM.kmk \ tools/ZIP.kmk \ sdks/DXSDK.kmk \ sdks/DXSDKAMD64.kmk \ sdks/DXSDKX86.kmk \ sdks/LIBSDL.kmk \ sdks/MACOSX104.kmk \ sdks/MACOSX104INCS.kmk \ sdks/MACOSX105.kmk \ sdks/MACOSX105INCS.kmk \ sdks/NT4DDK.kmk \ sdks/OS2DDKBASE32.kmk \ sdks/W2K3DDK.kmk \ sdks/W2K3DDKAMD64.kmk \ sdks/W2K3DDKX86.kmk \ sdks/W32API.kmk \ sdks/WIN32SDK.kmk \ sdks/WIN32SDK2002.kmk \ sdks/WIN64SDK.kmk \ sdks/WINDDK.kmk \ sdks/WINDDKW2K.kmk \ sdks/WINDDKWLH.kmk \ sdks/WINDDKWNET.kmk \ sdks/WINDDKWXP.kmk \ sdks/WINPSDK.kmk \ sdks/WINPSDKINCS.kmk \ units/lex.kmk \ units/qt3.kmk \ units/qt4.kmk \ units/yacc.kmk \ msgstyles/brief.kmk \ templates/DUMMY.kmk \ KBUILD_DOC_FILES = \ QuickReference-kmk.txt \ QuickReference-kmk.html \ kbuild-3149/dist/freebsd/devel/kBuild/pkg-descr0000644000175000017500000000011713252530251021371 0ustar locutuslocutuskBuild is a makefile framework for writing simple makefiles for complex tasks. kbuild-3149/dist/freebsd/devel/kBuild/Makefile0000644000175000017500000000663113252530251021236 0ustar locutuslocutus# New ports collection makefile for: kbuild # Date created: Mon Jul 28 14:34:33 BST 2008 # Whom: Bruce Simpson # # $FreeBSD: ports/devel/kBuild/Makefile,v 1.4 2008/12/02 23:14:19 gahr Exp $ # PORTNAME= kBuild PORTVERSION= 0.1.5 CATEGORIES= devel MASTER_SITES= ftp://ftp.netlabs.org/pub/kbuild/ DISTNAME= ${PORTNAME}-${PORTVERSION}-src MAINTAINER= que_deseja@hotmail.com COMMENT= Makefile framework USE_AUTOTOOLS= automake:19 autoconf:261 USE_GMAKE= yes WRKSRC= ${WRKDIR}/${PORTNAME}-${PORTVERSION} KBUILD_ARCH= ${MACHINE_ARCH:S/i386/x86/} KBUILD_ENV= ACLOCAL=${ACLOCAL} \ AUTOMAKE=${AUTOMAKE} \ AUTORECONF=${AUTORECONF} KBUILD_STAGE= ${WRKSRC}/out/freebsd.${KBUILD_ARCH}/release${PREFIX} # KBUILD_BINS, KBUILD_DATA_FILES and KBUILD_DOC_FILES (generated). .include "kBuild-files.mk" # Override autotools run-autotools: do-configure: do-build: cd ${WRKSRC} && ${SETENV} ${KBUILD_ENV} ./kBuild/env.sh --full \ ${GMAKE} NIX_INSTALL_DIR=${PREFIX} -f bootstrap.gmk ${WRKSRC}/kBuild/env.sh --full-with-bin \ kmk -C ${WRKSRC} NIX_INSTALL_DIR=${PREFIX} do-install: .for file in ${KBUILD_BIN_FILES} ${INSTALL_PROGRAM} ${KBUILD_STAGE}/bin/${file} ${PREFIX}/bin/${file} .endfor ${MKDIR} ${DATADIR} .for file in ${KBUILD_DATA_FILES} ${MKDIR} `dirname ${DATADIR}/${file}` ${INSTALL_DATA} ${KBUILD_STAGE}/share/kBuild/${file} ${DATADIR}/${file} .endfor ${MKDIR} ${DOCSDIR} .for file in ${KBUILD_DOC_FILES} ${MKDIR} `dirname ${DOCSDIR}/${file}` ${INSTALL_DATA} ${KBUILD_STAGE}/share/doc/kBuild-${PORTVERSION}/${file} ${DOCSDIR}/${file} .endfor .include # # Helper rule to generate kBuild-files.mk and pkg-plist when updating the port. # kbuild-generate-files: echo '# Autogenerated by kbuild-generate-files in Makefile' > kBuild-files.mk echo '' >> kBuild-files.mk echo 'KBUILD_BIN_FILES = \' >> kBuild-files.mk ${WRKSRC}/kBuild/env.sh --full-with-bin --quiet \ kmk --no-print-directory -sC ${WRKSRC} NIX_INSTALL_DIR=${PREFIX} \ MY_INST_BIN=_keep_/ MY_INST_DATA=_drop_/ MY_INST_DOC=_drop_/ \ kbuild-show-install-files \ | sed -e '/^_drop_/d' -e 's/^_keep_\// /' -e 's/$$/ \\/' \ >> kBuild-files.mk echo '' >> kBuild-files.mk echo 'KBUILD_DATA_FILES = \' >> kBuild-files.mk ${WRKSRC}/kBuild/env.sh --full-with-bin --quiet \ kmk --no-print-directory -sC ${WRKSRC} NIX_INSTALL_DIR=${PREFIX} \ MY_INST_BIN=_drop_/ MY_INST_DATA=_keep_/ MY_INST_DOC=_drop_/ \ kbuild-show-install-files \ | sed -e '/^_drop_/d' -e 's/^_keep_\// /' -e 's/$$/ \\/' \ >> kBuild-files.mk echo '' >> kBuild-files.mk echo 'KBUILD_DOC_FILES = \' >> kBuild-files.mk ${WRKSRC}/kBuild/env.sh --full-with-bin --quiet \ kmk --no-print-directory -sC ${WRKSRC} NIX_INSTALL_DIR=${PREFIX} \ MY_INST_BIN=_drop_/ MY_INST_DATA=_drop_/ MY_INST_DOC=_keep_/ \ kbuild-show-install-files \ | sed -e '/^_drop_/d' -e 's/^_keep_\// /' -e 's/$$/ \\/' \ >> kBuild-files.mk echo '' >> kBuild-files.mk ${WRKSRC}/kBuild/env.sh --full-with-bin --quiet \ kmk --no-print-directory -sC ${WRKSRC} NIX_INSTALL_DIR=${PREFIX} \ 'MY_INST_BIN=bin/' 'MY_INST_DATA=%%DATADIR%%/' \ 'MY_INST_DOC=%%DOCSDIR%%/' kbuild-show-install-files \ > pkg-plist echo '@dirrm %%DATADIR%%/msgstyles' >> pkg-plist echo '@dirrm %%DATADIR%%/sdks' >> pkg-plist echo '@dirrm %%DATADIR%%/templates' >> pkg-plist echo '@dirrm %%DATADIR%%/tools' >> pkg-plist echo '@dirrm %%DATADIR%%/units' >> pkg-plist echo '@dirrm %%DATADIR%%' >> pkg-plist echo '@dirrm %%DOCSDIR%%' >> pkg-plist kbuild-3149/dist/macports/0000755000175000017500000000000013252530251015475 5ustar locutuslocutuskbuild-3149/dist/macports/devel/0000755000175000017500000000000013252530251016574 5ustar locutuslocutuskbuild-3149/dist/macports/devel/kbuild-head/0000755000175000017500000000000013252530251020745 5ustar locutuslocutuskbuild-3149/dist/macports/devel/kbuild-head/Portfile0000644000175000017500000000172013252530251022454 0ustar locutuslocutus# $Id: Portfile 2413 2010-09-11 17:43:04Z bird $ # Very crude atm, everything is exec'ed. PortSystem 1.0 name kbuild-head version 9999 categories devel maintainers bird-kBuild-spamx@anduin.net description kBuild subversion trunk long_description \ See http://svn.netlabs.org/kbuild (I'm lazy). homepage http://svn.netlabs.org/kbuild platforms darwin fetch.type svn svn.url http://svn.netlabs.org/repos/kbuild/trunk #svn.url svn://system360/svn-mirrors/kbuild/trunk worksrcdir trunk test.run no configure {} build { system "cd ${workpath}/${worksrcdir} && ./kBuild/env.sh --full gnumake -f bootstrap.gmk NIX_INSTALL_DIR=${prefix} " } test { system "cd ${workpath}/${worksrcdir} && ./kBuild/env.sh --full-with-bin kmk -C tests nothing " } destroot { system "cd ${workpath}/${worksrcdir} && ./kBuild/env.sh --full-with-bin kmk NIX_INSTALL_DIR=${prefix} PATH_INS=${destroot}/ " } kbuild-3149/dist/macports/devel/kbuild/0000755000175000017500000000000013252530251020046 5ustar locutuslocutuskbuild-3149/dist/macports/devel/kbuild/Portfile0000644000175000017500000000204113252530251021552 0ustar locutuslocutus# $Id: Portfile 2413 2010-09-11 17:43:04Z bird $ # Very crude atm, everything is exec'ed. PortSystem 1.0 name kbuild version 0.1.5 categories devel maintainers bird-kBuild-spamx@anduin.net description kBuild long_description \ See http://svn.netlabs.org/kbuild (I'm lazy). homepage http://svn.netlabs.org/kbuild platforms darwin master_sites ftp://ftp.netlabs.org/pub/kbuild \ ftp://ftp.netlabs.org/incoming/kbuild distfiles kBuild-${version}-src.tar.gz checksums kBuild-${version}-src.tar.gz md5 df7e0905232e67728643f97d63cbf3f3 worksrcdir kBuild-${version} test.run no configure {} build { system "cd ${workpath}/${worksrcdir} && ./kBuild/env.sh --full gnumake -f bootstrap.gmk NIX_INSTALL_DIR=${prefix} " } test { system "cd ${workpath}/${worksrcdir} && ./kBuild/env.sh --full-with-bin kmk -C tests nothing " } destroot { system "cd ${workpath}/${worksrcdir} && ./kBuild/env.sh --full-with-bin kmk NIX_INSTALL_DIR=${prefix} PATH_INS=${destroot}/ " } kbuild-3149/dist/macports/PortIndex0000644000175000017500000000124113252530251017332 0ustar locutuslocutuskbuild 336 variants universal description kBuild portdir devel/kbuild homepage http://svn.netlabs.org/kbuild epoch 0 platforms darwin name kbuild long_description {See http://svn.netlabs.org/kbuild (I'm lazy). Stable version, well, soon to be stable anyways.} maintainers bird-kBuild-spam@anduin.net categories devel version 0.1.3-beta revision 0 kbuild-head 310 variants universal description {kBuild subversion trunk} portdir devel/kbuild-head homepage http://svn.netlabs.org/kbuild epoch 0 platforms darwin name kbuild-head long_description {See http://svn.netlabs.org/kbuild (I'm lazy).} maintainers bird-kBuild-spam@anduin.net categories devel version 9999 revision 0 kbuild-3149/dist/portage/0000755000175000017500000000000013252530251015306 5ustar locutuslocutuskbuild-3149/dist/portage/dev-util/0000755000175000017500000000000013252530251017037 5ustar locutuslocutuskbuild-3149/dist/portage/dev-util/kbuild/0000755000175000017500000000000013252530251020311 5ustar locutuslocutuskbuild-3149/dist/portage/dev-util/kbuild/kbuild-0.1.5.ebuild0000644000175000017500000000164213252530251023413 0ustar locutuslocutus# Copyright 1999-2008 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # $Header: /var/cvsroot/gentoo-x86/dev-util/kbuild/kbuild-0.1.4.ebuild,v 1.4 2008/10/28 18:11:02 jokey Exp $ EAPI=1 WANT_AUTOMAKE=1.9 inherit eutils autotools MY_P=kBuild-${PV}-src DESCRIPTION="A makefile framework for writing simple makefiles for complex tasks" HOMEPAGE="http://svn.netlabs.org/kbuild/wiki" SRC_URI="ftp://ftp.netlabs.org/pub/kbuild/${MY_P}.tar.gz" LICENSE="GPL-2 GPL-3 FDL-1.3" SLOT="0" KEYWORDS="amd64 x86" IUSE="" DEPEND="sys-devel/bison sys-devel/flex sys-devel/gettext" S=${WORKDIR}/${MY_P/-src} src_unpack() { unpack ${A} cd "${S}" } src_compile() { kBuild/env.sh --full \ make -f bootstrap.gmk NIX_INSTALL_DIR=/usr || die "bootstrap failed" } src_install() { kBuild/env.sh --full-with-bin kmk \ NIX_INSTALL_DIR=/usr \ PATH_INS="${D}" \ install || die "install failed" } kbuild-3149/SlickEdit/0000755000175000017500000000000013252530215014555 5ustar locutuslocutuskbuild-3149/SlickEdit/vusr_beautifier.xml0000644000175000017500000004215313252530215020502 0ustar locutuslocutus

kbuild-3149/SlickEdit/user.vlx0000644000175000017500000000172213252530215016270 0ustar locutuslocutus[kmk] idchars=a-zA-Z 0-9_ case-sensitive=y styles=dqbackslash sqbackslash punctuation= ( ) : ; [ ] { } operators= ! # $ % & * + , - . / < = > ? ^ ` | ~ := += >= |+ : :: keywords= export override libkeywords= abspath abspathex addprefix addsuffix and basename call comp-cmds comp-vars date date-utc dir eq error eval expr file-size filter filter-out findstring firstword flavor foreach if-expr info int-add int-and int-div int-eq int-ge int-gt int-le int-lt int-mod int-mul int-ne int-not int-or int-sub int-xor join kb-obj-base kb-obj-suff kb-src-one kb-src-prop kb-src-tool lastword nanots not notdir or origin patsubst realpath rsort shell sort stack-pop stack-popv stack-push stack-top strip subst suffix tolower toupper value warning which wildcard word wordlist words xargs ppkeywords= bool define defined else endif endef if if1of ifn1of ifdef ifndef ifeq ifneq include includedep num string target linecomment=# [def] idchars=a-zA-Z 0-9_ case-sensitive=n linecomment=; kbuild-3149/SlickEdit/usrprjtemplates.vpt0000644000175000017500000000233313252530215020555 0ustar locutuslocutus kbuild-3149/SlickEdit/uscheme.ini0000644000175000017500000001561713252530215016721 0ustar locutuslocutus[Solarized Dark] VERSION=22 ASSOCIATED_SYMBOL_SCHEME=(None) CFG_SELECTIONfg=0x969483 CFG_SELECTIONbg=0x423607 CFG_SELECTIONff=0x0 CFG_SELECTIONem=0x63510A CFG_WINDOW_TEXTfg=0x969483 CFG_WINDOW_TEXTbg=0x362B00 CFG_WINDOW_TEXTff=0x0 CFG_WINDOW_TEXTem=0x1A1400 CFG_CLINEfg=0xFFFFFF CFG_CLINEbg=0x605030 CFG_CLINEff=0x0 CFG_CLINEem=0x908060 CFG_SELECTED_CLINEfg=0xFFFF CFG_SELECTED_CLINEbg=0x80C400 CFG_SELECTED_CLINEff=0x0 CFG_SELECTED_CLINEem=0x509400 CFG_MESSAGEfg=0x80000008 CFG_MESSAGEbg=0x80000005 CFG_MESSAGEff=0x0 CFG_STATUSfg=0x80000008 CFG_STATUSbg=0xFFFFFF CFG_STATUSff=0x0 CFG_CURSORfg=0x0 CFG_CURSORbg=0xE8E8C0 CFG_CURSORff=0x0 CFG_CURSORem=0xB8B890 CFG_ERRORfg=0x8236D3 CFG_ERRORbg=0x362B00 CFG_ERRORff=0x2000 CFG_ERRORem=0x1A1400 CFG_MODIFIED_LINEfg=0xFFFFFF CFG_MODIFIED_LINEbg=0xFF CFG_MODIFIED_LINEff=0x0 CFG_MODIFIED_LINEem=0xCF CFG_INSERTED_LINEfg=0xFFFFFF CFG_INSERTED_LINEbg=0x80 CFG_INSERTED_LINEff=0x0 CFG_INSERTED_LINEem=0x3030B0 CFG_KEYWORDfg=0x1689B5 CFG_KEYWORDbg=0x362B00 CFG_KEYWORDff=0x2000 CFG_KEYWORDem=0x1A1400 CFG_LINENUMfg=0x969483 CFG_LINENUMbg=0x423607 CFG_LINENUMff=0x0 CFG_LINENUMem=0x303030 CFG_NUMBERfg=0x98A12A CFG_NUMBERbg=0x362B00 CFG_NUMBERff=0x2000 CFG_NUMBERem=0x1A1400 CFG_STRINGfg=0x9985 CFG_STRINGbg=0x362B00 CFG_STRINGff=0x2000 CFG_STRINGem=0x1A1400 CFG_COMMENTfg=0xA100 CFG_COMMENTbg=0x362B00 CFG_COMMENTff=0x2000 CFG_COMMENTem=0x1A1400 CFG_PPKEYWORDfg=0x164BCB CFG_PPKEYWORDbg=0x362B00 CFG_PPKEYWORDff=0x2001 CFG_PPKEYWORDem=0x1A1400 CFG_PUNCTUATIONfg=0x98A12A CFG_PUNCTUATIONbg=0x362B00 CFG_PUNCTUATIONff=0x2000 CFG_PUNCTUATIONem=0x1A1400 CFG_LIBRARY_SYMBOLfg=0xC0C000 CFG_LIBRARY_SYMBOLbg=0x362B00 CFG_LIBRARY_SYMBOLff=0x2000 CFG_LIBRARY_SYMBOLem=0x1A1400 CFG_OPERATORfg=0x2F32DC CFG_OPERATORbg=0x362B00 CFG_OPERATORff=0x2000 CFG_OPERATORem=0x1A1400 CFG_USER_DEFINEDfg=0xFF CFG_USER_DEFINEDbg=0x362B00 CFG_USER_DEFINEDff=0x2000 CFG_USER_DEFINEDem=0x1A1400 CFG_IMAGINARY_LINEfg=0xFFFFFF CFG_IMAGINARY_LINEbg=0xFF0000 CFG_IMAGINARY_LINEff=0x0 CFG_IMAGINARY_LINEem=0xCF0000 CFG_FUNCTIONfg=0xDB8B26 CFG_FUNCTIONbg=0x362B00 CFG_FUNCTIONff=0x2001 CFG_FUNCTIONem=0x1A1400 CFG_LINEPREFIXAREAfg=0xA1A193 CFG_LINEPREFIXAREAbg=0x423600 CFG_LINEPREFIXAREAff=0x1 CFG_FILENAMEfg=0x0 CFG_FILENAMEbg=0xFFFF00 CFG_FILENAMEff=0x0 CFG_FILENAMEem=0xCFCF00 CFG_HILIGHTfg=0xFFFFFF CFG_HILIGHTbg=0x808000 CFG_HILIGHTff=0x0 CFG_HILIGHTem=0x505000 CFG_ATTRIBUTEfg=0x9985 CFG_ATTRIBUTEbg=0x362B00 CFG_ATTRIBUTEff=0x2001 CFG_ATTRIBUTEem=0x1A1400 CFG_UNKNOWNXMLELEMENTfg=0x2F32DC CFG_UNKNOWNXMLELEMENTbg=0x362B00 CFG_UNKNOWNXMLELEMENTff=0x2001 CFG_UNKNOWNXMLELEMENTem=0x1A1400 CFG_XHTMLELEMENTINXSLfg=0x80FF CFG_XHTMLELEMENTINXSLbg=0x362B00 CFG_XHTMLELEMENTINXSLff=0x2001 CFG_XHTMLELEMENTINXSLem=0x1A1400 CFG_SPECIALCHARSfg=0xC0C0C0 CFG_SPECIALCHARSbg=0xFFFFFF CFG_SPECIALCHARSff=0x0 CFG_SPECIALCHARSem=0xCFCFCF CFG_CURRENT_LINE_BOXfg=0xFF8080 CFG_CURRENT_LINE_BOXbg=0xFF8080 CFG_CURRENT_LINE_BOXff=0x0 CFG_VERTICAL_COL_LINEfg=0x164BCB CFG_VERTICAL_COL_LINEbg=0x164BCB CFG_VERTICAL_COL_LINEff=0x0 CFG_MARGINS_COL_LINEfg=0x808080 CFG_MARGINS_COL_LINEbg=0x808080 CFG_MARGINS_COL_LINEff=0x0 CFG_TRUNCATION_COL_LINEfg=0xFF CFG_TRUNCATION_COL_LINEbg=0xFF CFG_TRUNCATION_COL_LINEff=0x0 CFG_PREFIX_AREA_LINEfg=0x808080 CFG_PREFIX_AREA_LINEbg=0x808080 CFG_PREFIX_AREA_LINEff=0x0 CFG_BLOCK_MATCHINGfg=0xFFFFFF CFG_BLOCK_MATCHINGbg=0x837B65 CFG_BLOCK_MATCHINGff=0x0 CFG_BLOCK_MATCHINGem=0xCF0000 CFG_INC_SEARCH_CURRENTfg=0x0 CFG_INC_SEARCH_CURRENTbg=0xFFFF80 CFG_INC_SEARCH_CURRENTff=0x0 CFG_INC_SEARCH_CURRENTem=0xCFCF50 CFG_INC_SEARCH_MATCHfg=0x0 CFG_INC_SEARCH_MATCHbg=0x80FFFF CFG_INC_SEARCH_MATCHff=0x0 CFG_INC_SEARCH_MATCHem=0x50CFCF CFG_HEX_MODE_COLORfg=0x2F32DC CFG_HEX_MODE_COLORbg=0xF0F0F0 CFG_HEX_MODE_COLORff=0x1 CFG_HEX_MODE_COLORem=0xC0C0C0 CFG_SYMBOL_HIGHLIGHTfg=0x98A12A CFG_SYMBOL_HIGHLIGHTbg=0x362B00 CFG_SYMBOL_HIGHLIGHTff=0x2000 CFG_SYMBOL_HIGHLIGHTem=0x1A1400 CFG_DOCUMENT_TAB_MODIFIEDfg=0xFF CFG_DOCUMENT_TAB_MODIFIEDbg=0xFFFFFF CFG_DOCUMENT_TAB_MODIFIEDff=0x0 CFG_LINE_COMMENTfg=0xA100 CFG_LINE_COMMENTbg=0x362B00 CFG_LINE_COMMENTff=0x2000 CFG_LINE_COMMENTem=0x1A1400 CFG_DOCUMENTATIONfg=0xA100 CFG_DOCUMENTATIONbg=0x362B00 CFG_DOCUMENTATIONff=0x2000 CFG_DOCUMENTATIONem=0x1A1400 CFG_DOC_KEYWORDfg=0xA197 CFG_DOC_KEYWORDbg=0x362B00 CFG_DOC_KEYWORDff=0x2001 CFG_DOC_KEYWORDem=0x1A1400 CFG_DOC_PUNCTUATIONfg=0xA100 CFG_DOC_PUNCTUATIONbg=0x362B00 CFG_DOC_PUNCTUATIONff=0x2001 CFG_DOC_PUNCTUATIONem=0x1A1400 CFG_DOC_ATTRIBUTEfg=0x97A100 CFG_DOC_ATTRIBUTEbg=0x362B00 CFG_DOC_ATTRIBUTEff=0x2001 CFG_DOC_ATTRIBUTEem=0x1A1400 CFG_DOC_ATTR_VALUEfg=0x97A100 CFG_DOC_ATTR_VALUEbg=0x362B00 CFG_DOC_ATTR_VALUEff=0x2000 CFG_DOC_ATTR_VALUEem=0x1A1400 CFG_IDENTIFIERfg=0x969483 CFG_IDENTIFIERbg=0x362B00 CFG_IDENTIFIERff=0x2000 CFG_IDENTIFIERem=0x1A1400 CFG_FLOATING_NUMBERfg=0x98A12A CFG_FLOATING_NUMBERbg=0x362B00 CFG_FLOATING_NUMBERff=0x2000 CFG_FLOATING_NUMBERem=0x1A1400 CFG_HEX_NUMBERfg=0x98A12A CFG_HEX_NUMBERbg=0x362B00 CFG_HEX_NUMBERff=0x2000 CFG_HEX_NUMBERem=0x1A1400 CFG_SINGLEQUOTED_STRINGfg=0x9985 CFG_SINGLEQUOTED_STRINGbg=0x362B00 CFG_SINGLEQUOTED_STRINGff=0x2000 CFG_SINGLEQUOTED_STRINGem=0x1A1400 CFG_BACKQUOTED_STRINGfg=0x9985 CFG_BACKQUOTED_STRINGbg=0x362B00 CFG_BACKQUOTED_STRINGff=0x2000 CFG_BACKQUOTED_STRINGem=0x1A1400 CFG_UNTERMINATED_STRINGfg=0x9985 CFG_UNTERMINATED_STRINGbg=0x362B00 CFG_UNTERMINATED_STRINGff=0x2000 CFG_UNTERMINATED_STRINGem=0x1A1400 CFG_INACTIVE_CODEfg=0xA100 CFG_INACTIVE_CODEbg=0x362B00 CFG_INACTIVE_CODEff=0x2000 CFG_INACTIVE_CODEem=0x1A1400 CFG_INACTIVE_KEYWORDfg=0xA100 CFG_INACTIVE_KEYWORDbg=0x362B00 CFG_INACTIVE_KEYWORDff=0x2001 CFG_INACTIVE_KEYWORDem=0x1A1400 CFG_IMAGINARY_SPACEfg=0xFFFFFF CFG_IMAGINARY_SPACEbg=0xFF0000 CFG_IMAGINARY_SPACEff=0x0 CFG_IMAGINARY_SPACEem=0xCF0000 CFG_INACTIVE_COMMENTfg=0xA100 CFG_INACTIVE_COMMENTbg=0x362B00 CFG_INACTIVE_COMMENTff=0x2002 CFG_INACTIVE_COMMENTem=0x1A1400 CFG_MODIFIED_ITEMfg=0xFF CFG_MODIFIED_ITEMbg=0xFFFFFF CFG_MODIFIED_ITEMff=0x0 CFG_NAVHINTfg=0x80FF CFG_NAVHINTbg=0x403010 CFG_NAVHINTff=0x0 CFG_XML_CHARACTER_REFfg=0x98A12A CFG_XML_CHARACTER_REFbg=0x362B00 CFG_XML_CHARACTER_REFff=0x2000 CFG_XML_CHARACTER_REFem=0x1A1400 CFG_SEARCH_RESULT_TRUNCATEDfg=0x969483 CFG_SEARCH_RESULT_TRUNCATEDbg=0x362B00 CFG_SEARCH_RESULT_TRUNCATEDff=0x0 CFG_MARKDOWN_HEADERfg=0x969483 CFG_MARKDOWN_HEADERbg=0x362B00 CFG_MARKDOWN_HEADERff=0x0 CFG_MARKDOWN_HEADERem=0x1A1400 CFG_MARKDOWN_CODEfg=0x969483 CFG_MARKDOWN_CODEbg=0x362B00 CFG_MARKDOWN_CODEff=0x0 CFG_MARKDOWN_CODEem=0x1A1400 CFG_MARKDOWN_BLOCKQUOTEfg=0x969483 CFG_MARKDOWN_BLOCKQUOTEbg=0x362B00 CFG_MARKDOWN_BLOCKQUOTEff=0x0 CFG_MARKDOWN_BLOCKQUOTEem=0x1A1400 CFG_MARKDOWN_LINKfg=0x969483 CFG_MARKDOWN_LINKbg=0x362B00 CFG_MARKDOWN_LINKff=0x0 CFG_MARKDOWN_LINKem=0x1A1400 CFG_DOCUMENT_TAB_ACTIVEfg=0x362B00 CFG_DOCUMENT_TAB_ACTIVEbg=0xA1A193 CFG_DOCUMENT_TAB_ACTIVEff=0x0 CFG_DOCUMENT_TAB_SELECTEDfg=0x362B00 CFG_DOCUMENT_TAB_SELECTEDbg=0x969483 CFG_DOCUMENT_TAB_SELECTEDff=0x0 CFG_DOCUMENT_TAB_UNSELECTEDfg=0x969483 CFG_DOCUMENT_TAB_UNSELECTEDbg=0x362B00 CFG_DOCUMENT_TAB_UNSELECTEDff=0x0 kbuild-3149/SlickEdit/lexer-kmk.cfg.xml0000644000175000017500000000526613252530215017745 0ustar locutuslocutus

kbuild-3149/SlickEdit/lexer-def.cfg.xml0000644000175000017500000000027513252530215017714 0ustar locutuslocutus

kbuild-3149/SlickEdit/kkeys.e0000644000175000017500000002312113252530215016050 0ustar locutuslocutus/* $Id: kkeys.e 3146 2018-03-15 17:01:15Z bird $ */ /** @file * Bird's key additions to Visual Slickedit. */ /* * Copyright (c) 2004-2010 knut st. osmundsen * * This file is part of kBuild. * * kBuild 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. * * kBuild 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 kBuild. If not, see * */ /******************************************************************************* * Header Files * *******************************************************************************/ #include 'slick.sh' /******************************************************************************* * Global Variables * *******************************************************************************/ defeventtab default_keys def 'A-UP' = find_prev def 'A-DOWN' = find_next def 'A-PGUP' = prev_proc def 'A-PGDN' = next_proc def 'A-d' = delete_line def 'A-o' = kkeys_duplicate_line def 'A-s' = kkeys_switch_lines def 'A-u' = undo_cursor /* will cursor movement in one undo step. */ def 'A-g' = goto_line def 'A-z' = kkeys_fullscreen def 'INS' = boxer_paste def 'S-INS' = insert_toggle def 'C-UP' = kkeys_scroll_down def 'C-DOWN' = kkeys_scroll_up def 'C-PGUP' = prev_window def 'C-PGDN' = next_window def 'C-DEL' = kkeys_delete_right #if __VERSION__ >= 15.0 def 'S-C-=' = svn_diff_with_base #endif #if __VERSION__ >= 22.0 def 'C-=' = diff; def 'C--' = nil; def 'S-A-C-=' = wfont_zoom_in; def 'S-A-C--' = wfont_zoom_out; #endif #if __VERSION__ >= 14.0 def 'C-/' = kkeys_push_ref def 'S-C-/' = push_ref def 'S-A-]' = next_buff_tab def 'S-A-[' = prev_buff_tab def 'S-A-U' = kkeys_gen_uuid #endif /* For the mac (A/M mix, all except A-z): */ def 'M-1' = cursor_error def 'M-UP' = find_prev def 'M-DOWN' = find_next def 'M-PGUP' = prev_proc def 'M-PGDN' = next_proc def 'M-d' = delete_line def 'M-f' = kkeys_open_file_menu def 'M-e' = kkeys_open_edit_menu def 'M-o' = kkeys_duplicate_line def 'M-s' = kkeys_switch_lines def 'M-t' = kkeys_open_tools_menu def 'M-u' = undo_cursor def 'M-g' = goto_line #if __VERSION__ >= 14.0 def 'S-M-]' = next_buff_tab def 'S-M-[' = prev_buff_tab def 'S-M-U' = kkeys_gen_uuid #endif #if __VERSION__ >= 22.0 def 'S-M-C-=' = wfont_zoom_in; def 'S-M-C--' = wfont_zoom_out; #endif /* Fixing brainfucked slickedit silliness: */ def 'M-v' = paste /** Saves the cursor position. */ static long kkeys_save_cur_pos() { long offset = _QROffset(); message(offset); return offset; } /** Restores a saved cursor position. */ static void kkeys_restore_cur_pos(long lSavedCurPos) { _GoToROffset(lSavedCurPos); } _command kkeys_switch_lines() { /* Allocate a selection for copying the current line. */ cursor_down(); mark_id= _alloc_selection(); if (mark_id>=0) { _select_line(mark_id); cursor_up(); cursor_up(); _move_to_cursor(mark_id); cursor_down(); _free_selection(mark_id); // This selection can be freed because it is not the active selection. } else message(get_message(mark_id)); } _command kkeys_duplicate_line() { /* Allocate a selection for copying the current line. */ mark_id= _alloc_selection(); if (mark_id>=0) { _select_line(mark_id); _copy_to_cursor(mark_id); // This selection can be freed because it is not the active selection. _free_selection(mark_id); cursor_down(); } else message(get_message(mark_id)); } _command kkeys_delete_right() { col=p_col; /* virtual space hack */ keyin(" "); left(); _delete_char(); /* are we in a word, delete it? */ ch = get_text(); if (ch != ' ' && ch != "\t" && ch != "\r" && ch != "\n") { /* Delete word and any trailing spaces, but stop at new line. */ delete_word(); ch = get_text(); if (ch == ' ' || ch == "\t" || ch == "\r" || ch == "\n") { if (search('[ \t]#','r+') == 0) { _nrseek(match_length('s')); _delete_text(match_length()); } } } else { /* delete spaces and newlines until the next word. */ if (search('[ \t\n\r]#','r+') == 0) { _nrseek(match_length('s')); _delete_text(match_length()); } } p_col=col //retrieve_command_results() } _command kkeys_scroll_up() { if (p_cursor_y == 0) down(); set_scroll_pos(p_left_edge, p_cursor_y-1); } _command kkeys_scroll_down() { if (p_cursor_y intdiv p_font_height == p_char_height-1) up() set_scroll_pos(p_left_edge, p_cursor_y+p_font_height); } _command boxer_paste() { long lSavedCurPos = kkeys_save_cur_pos() paste(); kkeys_restore_cur_pos(lSavedCurPos); } _command kkeys_fullscreen() { fullscreen(); } /* for later, not used yet. */ _command boxer_select() { if (command_state()) fSelected = (p_sel_length != 0); else fSelected = select_active(); key = last_event(); if (key :== name2event('s-down')) { if (!fSelected) select_line(); else cursor_down(); } else if (key :== name2event('s-up')) { if (!fSelected) select_line(); else cursor_up(); } else if (key :== name2event('s-left')) { if (!fSelected) select_char(); else cursor_left(); } else if (key :== name2event('s-right')) { if (!fSelected) select_char(); else cursor_right(); } else if (key :== name2event('s-home')) { if (!fSelected) select_char(); begin_line_text_toggle(); } else if (key :== name2event('s-end')) { if (!fSelected) select_char(); end_line(); if (p_col > 0) //this is not identical with boxer... cursor_left(); } else if (key :== name2event('c-s-home')) { if (!fSelected) select_char(); top_of_buffer(); } else if (key :== name2event('c-s-end')) { if (!fSelected) select_char(); bottom_of_buffer(); } else if (key :== name2event('c-s-left')) { if (!fSelected) { cursor_left(); select_char(); /* start this selection non-inclusive */ } prev_word(); } else if (key :== name2event('c-s-right')) { if (!fSelected) { select_char(); /* start this selection non-inclusive */ } /* temporary hack */ prevpos = p_col; prevline = p_line; p_col++; next_word(); if ((p_line == prevline && p_col > prevpos + 1) || (p_line != prevline && p_col > 0)) p_col--; } } #if __VERSION__ >= 14.0 /** * Search for references only in the current workspace. */ _command kkeys_push_ref() { if (_isEditorCtl()) { sProjTagFile = project_tags_filename(); sLangId = p_LangId; if (sProjTagFile != '') { # if __VERSION__ < 21.0 /** @todo fix me? */ /* HACK ALERT: Make sure gtag_filelist_last_ext has the right value. */ _update_tag_filelist_ext(sLangId); /* save */ boolean saved_gtag_filelist_cache_updated = gtag_filelist_cache_updated; _str saved_gtag_filelist_ext[] = gtag_filelist_ext; /* HACK ALERT: Replace the tag file list for this language. */ gtag_filelist_ext._makeempty(); gtag_filelist_ext[0] = sProjTagFile; gtag_filelist_cache_updated = true; # endif /* Do the reference searching. */ push_ref('-e ' :+ sLangId); # if __VERSION__ < 21.0 /* restore*/ gtag_filelist_cache_updated = saved_gtag_filelist_cache_updated; gtag_filelist_ext = saved_gtag_filelist_ext; # endif } else push_ref(); } else push_ref(); } _command kkeys_gen_uuid() { _str uuid = guid_create_string('G'); uuid = lowcase(uuid); long lSavedCurPos = kkeys_save_cur_pos(); _insert_text(uuid); kkeys_restore_cur_pos(lSavedCurPos); } #endif /* >= 14.0 */ /** @name Mac OS X Hacks: Alt+[fet] -> drop down menu * * This only works when the alt menu hotkeys are enabled in the * settings. Al * * @{ */ _command void kkeys_open_file_menu() { call_key(A_F) } _command void kkeys_open_edit_menu() { call_key(A_E) } _command void kkeys_open_tools_menu() { call_key(A_T) } /** @} */ void nop() { } #if __VERSION__ >= 14.0 /* * Some diff keyboard hacks for Mac OS X. */ defeventtab _diff_form def 'M-f' = kkeys_diffedit_find def 'M-n' = kkeys_diffedit_next def 'M-p' = kkeys_diffedit_prev _command kkeys_diffedit_find() { _nocheck _control _ctlfind; _ctlfind.call_event(_ctlfind, LBUTTON_UP); } _command kkeys_diffedit_next() { _nocheck _control _ctlfile1; _nocheck _control _ctlfile2; _DiffNextDifference(_ctlfile1, _ctlfile2); } _command kkeys_diffedit_prev() { _nocheck _control _ctlfile1; _nocheck _control _ctlfile2; _DiffNextDifference(_ctlfile1, _ctlfile2, '-'); } #endif /* >= 14.0 */ kbuild-3149/SlickEdit/kdev.e0000644000175000017500000034640413252530215015667 0ustar locutuslocutus/* $Id: kdev.e 3146 2018-03-15 17:01:15Z bird $ -*- tab-width: 4 c-indent-level: 4 -*- */ /** @file * Visual SlickEdit Documentation Macros. */ /* * Copyright (c) 1999-2010 knut st. osmundsen * * This file is part of kBuild. * * kBuild 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. * * kBuild 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 kBuild. If not, see * */ /*** * * This define the following keys: *--------------------------------- * Ctrl+Shift+C: Class description box. * Ctrl+Shift+F: Function/method description box. * Ctrl+Shift+M: Module(file) description box * Ctrl+Shift+O: One-liner (comment) * * Ctrl+Shift+G: Global box * Ctrl+Shift+H: Header box * Ctrl+Shift+E: Exported Symbols * Ctrl+Shift+I: Internal function box * Ctrl+Shift+K: Const/macro box * Ctrl+Shift+S: Struct/Typedef box * * Ctrl+Shift+A: Signature+Date marker * Ctrl+Shift+P: Mark line as change by me * * Ctrl+Shift+T: Update project tagfile. * Ctrl+Shift+L: Load document variables. * * Ctrl+Shift+B: KLOGENTRYX(..) * Ctrl+Shift+E: KLOGEXIT(..) * Ctrl+Shift+N: Do kLog stuff for the current file. No questions. * Ctrl+Shift+Q: Do kLog stuff for the current file. Ask a lot of questions. * * Remember to set the correct sOdin32UserName, sOdin32UserEmail and sOdin32UserInitials * before compiling and loading the macros into Visual SlickEdit. * * These macros are compatible with both 3.0(c) and 4.0(b). * */ defeventtab default_keys def 'C-S-A' = k_signature //def 'C-S-C' = k_javadoc_classbox def 'C-S-C' = k_calc def 'C-S-E' = k_box_exported def 'C-S-F' = k_javadoc_funcbox def 'C-S-G' = k_box_globals def 'C-S-H' = k_box_headers def 'C-S-I' = k_box_intfuncs def 'C-S-K' = k_box_consts def 'C-S-N' = k_noref def 'C-S-M' = k_javadoc_moduleheader def 'C-S-O' = k_oneliner def 'C-S-P' = k_mark_modified_line def 'C-S-S' = k_box_structs def 'C-S-T' = k_rebuild_tagfile def 'C-S-L' = k_style_load //optional stuff //def 'C-S-Q' = klib_klog_file_ask //def 'C-S-N' = klib_klog_file_no_ask //def 'C-S-1' = klib_klogentry //def 'C-S-3' = klib_klogexit //MARKER. Editor searches for this line! #pragma option(redeclvars, on) #include 'slick.sh' #ifndef VS_TAGDETAIL_context_args /* newer vslick version. */ #include 'tagsdb.sh' //#pragma option(strict,on) /*#else: Version 4.0 (OS/2) */ #endif #ifndef __MACOSX__ #define KDEV_WITH_MENU #endif /* Remeber to change these! */ static _str skUserInitials = "bird"; static _str skUserName = "knut st. osmundsen"; static _str skUserEmail = "bird-kBuild-spamx@anduin.net"; /******************************************************************************* * Global Variables * *******************************************************************************/ static _str skCodeStyle = 'Opt2Ind4'; /* coding style scheme. */ static _str skDocStyle = 'javadoc';/* options: javadoc, */ static _str skLicense = 'GPLv3'; /* options: GPL, LGPL, Odin32, Confidential, ++ */ static _str skCompany = ''; /* empty or company name for copyright */ static _str skProgram = ''; /* Current program name - used by [L]GPL */ static _str skChange = ''; /* Current change identifier. */ static int ikStyleWidth = 130; /* The page width of the style. */ static boolean fkStyleFullHeaders = false; /* false: omit some tags. */ static int ikStyleOneliner = 41; /* The oneline comment column. */ static int ikStyleModifyMarkColumn = 105; static boolean fkStyleBoxTag = false; /* true: Include tag in k_box_start. */ /******************************************************************************* * Internal Functions * *******************************************************************************/ /** * Gets iso date. * @returns ISO formatted date. */ static _str k_date() { int i,j; _str date; date = _date('U'); i = pos("/", date); j = pos("/", date, i+1); _str month = substr(date, 1, i-1); if (length(month) == 1) month = '0'month; _str day = substr(date, i+1, j-i-1); if (length(day) == 1) day = '0'day; _str year = substr(date, j+1); return year"-"month"-"day; } /** * Get the current year. * @returns Current year string. */ static _str k_year() { _str date = _date('U'); return substr(date, pos("/",date, pos("/",date)+1)+1, 4); } /** * Aligns a value up to a given alignment. */ static int k_alignup(int iValue, iAlign) { if (iAlign <= 0) { message('k_alignup: iValue='iValue ' iAlign='iAlign); iAlign = 4; } return ((iValue intdiv iAlign) + 1) * iAlign; } /** * Reads the comment setup for this lexer/extension . * * @returns Success indicator. * @param sLeft Left comment. (output) * @param sRight Right comment. (output) * @param iColumn Comment mark column. (1-based) (output) * @param sExt The extension to lookup defaults to the current one. * @param sLexer The lexer to lookup defaults to the current one. * @remark This should be exported from box.e, but unfortunately it isn't. */ static boolean k_commentconfig(_str &sLeft, _str &sRight, int &iColumn, _str sExt = p_extension, _str sLexer = p_lexer_name) { /* init returns */ sLeft = sRight = ''; iColumn = 0; /* * Get comment setup from the lexer. */ _str sLine = ''; if (sLexer) { /* multiline */ #if __VERSION__ >= 21.0 COMMENT_TYPE aComments[]; GetComments(aComments, "M", sLexer); for (i = 0; i < aComments._length(); i++) # if __VERSION__ >= 22.0 if (aComments[i].type != 'doc_comment') # else if (!aComments[i].isDocumentation) # endif { sLeft = aComments[i].delim1; sRight = aComments[i].delim2; iColumn = aComments[i].startcol; if (sLeft != '' && sRight != '') return true; } #else # if __VERSION__ >= 14.0 _str aComments[] = null; GetComments(aComments, "mlcomment", sLexer); for (i = 0; i < aComments._length(); i++) if (pos("documentation", aComments[i]) <= 0) { sLine = aComments[i]; break; } if (sLine != '') # else rc = _ini_get_value(slick_path_search("user.vlx"), sLexer, 'mlcomment', sLine); if (rc) rc = _ini_get_value(slick_path_search("vslick.vlx"), sLexer, 'mlcomment', sLine); if (!rc) # endif { sLeft = strip(word(sLine, 1)); sRight = strip(word(sLine, 2)); if (sLeft != '' && sRight != '') return true; } #endif /* failed, try single line. */ #if __VERSION__ >= 21.0 GetComments(aComments, "L", sLexer); for (i = 0; i < aComments._length(); i++) # if __VERSION__ >= 22.0 if (aComments[i].type != 'doc_comment') # else if (!aComments[i].isDocumentation) # endif { sLeft = aComments[i].delim1; sRight = ''; iColumn = aComments[i].startcol; if (sLeft != '') return true; } #else # if __VERSION__ >= 14.0 GetComments(aComments, "linecomment", sLexer) for (i = 0; i < aComments._length(); i++) if (pos("documentation", aComments[i]) <= 0) { sLine = aComments[i]; break; } if (sLine != '') # else rc = _ini_get_value(slick_path_search("user.vlx"), sLexer, 'linecomment', sLine); if (rc) rc = _ini_get_value(slick_path_search("vslick.vlx"), sLexer, 'linecomment', sLine); if (!rc) # endif { sLeft = strip(word(sLine, 1)); sRight = ''; iColumn = 0; _str sTmp = word(sLine, 2); if (isnumber(sTmp)) iColumn = (int)sTmp; if (sLeft != '') return true; } #endif } /* * Read the nonboxchars and determin user or default box.ini. */ _str sFile = slick_path_search("ubox.ini"); boolean frc = _ini_get_value(sFile, sExt, 'nonboxchars', sLine); if (frc) { sFile = slick_path_search("box.ini"); frc = _ini_get_value(sFile, sExt, 'nonboxchars', sLine); } if (!frc) { /* * Found extension. */ sLeft = strip(eq_name2value('left',sLine)); if (sLeft == '\e') sLeft = ''; sRight = strip(eq_name2value('right',sLine)); if (sRight == '\e') sRight = ''; /* Read comment column too */ frc = _ini_get_value(sFile, sExt, 'comment_col', sLine); if (frc) { iColumn = eq_name2value('comment_col', sLine); if (iColumn == '\e') iColumn = 0; } else iColumn = 0; return true; } /* failure */ sLeft = sRight = ''; iColumn = 0; return false; } /** * Checks if current file only support line comments. * @returns True / False. * @remark Use builtin extension stuff! */ static boolean k_line_comment() { _str sRight = ''; _str sLeft = ''; int iColumn; boolean fLineComment = false; if (k_commentconfig(sLeft, sRight, iColumn)) fLineComment = (sRight == '' || iColumn > 0); return fLineComment; } #define KIC_CURSOR_BEFORE 1 #define KIC_CURSOR_AFTER 2 #define KIC_CURSOR_AT_END 3 /** * Insert a comment at current or best fitting position in the text. * @param sStr The comment to insert. * @param iCursor Where to put the cursor. * @param iPosition Where to start the comment. * Doesn't apply to column based source. * -1 means at cursor position. (default) * >0 means at end of line, but not before this column (1-based). * This also implies a min of one space to EOL. */ void k_insert_comment(_str sStr, int iCursor, int iPosition = -1) { _str sLeft; _str sRight; int iColumn; if (!k_commentconfig(sLeft, sRight, iColumn)) { sLeft = '/*'; sRight = '*/'; iColumn = 0; } int iCol = 0; if (iColumn <= 0) { /* * not column based source */ /* position us first */ if (iPosition > 0) { end_line(); do { _insert_text(" "); } while (p_col < iPosition); } /* insert comment saving the position for _BEFORE. */ iCol = p_col; _insert_text(sLeft:+' ':+sStr); if (iCursor == KIC_CURSOR_AT_END) iCol = p_col; /* right comment delimiter? */ if (sRight != '') _insert_text(' ':+sRight); } else { if (p_col >= iColumn) _insert_text("\n"); do { _insert_text(" "); } while (p_col < iColumn); if (iCursor == KIC_CURSOR_BEFORE) iCol = p_col; _insert_text(sLeft:+' ':+sStr); if (iCursor == KIC_CURSOR_AT_END) iCol = p_col; } /* set cursor. */ if (iCursor != KIC_CURSOR_AFTER) p_col = iCol; } /** * Gets the comment prefix or postfix. * @returns Comment prefix or postfix. * @param fRight If clear left comment string - default. * If set right comment string. */ static _str k_comment(boolean fRight = false) { _str sLeft, sRight; int iColumn; _str sComment = '/*'; if (k_commentconfig(sLeft, sRight, iColumn)) sComment = (!fRight || iColumn > 0 ? sLeft : sRight); return strip(sComment); } /******************************************************************************* * BOXES * *******************************************************************************/ /** * Inserts the first line in a box. * @param sTag Not used - box tag. */ static void k_box_start(sTag) { _str sLeft, sRight; int iColumn; if (!k_commentconfig(sLeft, sRight, iColumn)) return; _begin_line(); if (iColumn >= 0) while (p_col < iColumn) _insert_text(" "); _str sText = sLeft; if (sTag != '' && fkStyleBoxTag) { if (substr(sText, length(sText)) != '*') sText = sText:+'*'; sText = sText:+sTag; } int i; for (i = length(sText); i <= ikStyleWidth - p_col; i++) sText = sText:+'*'; sText = sText:+"\n"; _insert_text(sText); } /** * Places a string, sStr, into a line started and ended by '*'. * @param sStr Text to have between the '*'s. */ static void k_box_line(_str sStr) { _str sLeft, sRight; int iColumn; if (!k_commentconfig(sLeft, sRight, iColumn)) return; if (iColumn >= 0) while (p_col < iColumn) _insert_text(" "); _str sText = ''; if (k_line_comment()) sText = sLeft; if (sText == '' || substr(sText, length(sText)) != '*') sText = sText:+'*'; sText = sText:+' '; int i; for (i = length(sText); i < p_SyntaxIndent; i++) sText = sText:+' '; sText = sText:+sStr; for (i = length(sText) + 1; i <= ikStyleWidth - p_col; i++) sText = sText:+' '; sText = sText:+"*\n"; _insert_text(sText); } /** * Inserts the last line in a box. */ static void k_box_end() { _str sLeft, sRight; int iColumn, i; if (!k_commentconfig(sLeft, sRight, iColumn)) return; if (iColumn >= 0) while (p_col < iColumn) _insert_text(" "); _str sText = ''; if (k_line_comment()) sText = sLeft; for (i = length(sText) + length(sRight); i <= ikStyleWidth - p_col; i++) sText = sText:+'*'; sText = sText:+sRight:+"\n"; _insert_text(sText); } /******************************************************************************* * FUNCTION AND CODE PARSERS * *******************************************************************************/ /** * Moves cursor to nearest function start. * @returns 0 if ok. * -1 on failure. */ static int k_func_goto_nearest_function() { boolean fFix = false; /* cursor at function fix. (last function) */ int cur_line = p_line; int prev_line = -1; int next_line = -1; typeless org_pos; _save_pos2(org_pos); if (!next_proc(1)) { next_line = p_line; if (!prev_proc(1) && p_line == cur_line) { _restore_pos2(org_pos); return 0; } _restore_pos2(org_pos); _save_pos2(org_pos); } else { p_col++; /* fixes problem with single function files. */ fFix = true; } if (!prev_proc(1)) { prev_line = p_line; if (!next_proc(1) && p_line == cur_line) { _restore_pos2(org_pos); return 0; } _restore_pos2(org_pos); _save_pos2(org_pos); } if (prev_line != -1 && (next_line == -1 || cur_line - prev_line <= next_line - cur_line)) { if (fFix) p_col++; prev_proc(1); return 0; } if (next_line != -1 && (prev_line == -1 || cur_line - prev_line > next_line - cur_line)) { next_proc(); return 0; } _restore_pos2(org_pos); return -1; } /** * Check if nearest function is a prototype. * @returns True if function prototype. * False if not function prototype. */ static boolean k_func_prototype() { /* * Check if this is a real function implementation. */ typeless procpos; _save_pos2(procpos); if (!k_func_goto_nearest_function()) { int proc_line = p_line; if (!k_func_searchcode("{")) { prev_proc(); if (p_line != proc_line) { _restore_pos2(procpos); return true; } } } _restore_pos2(procpos); return false; } /** * Gets the name fo the current function. * @returns The current function name. */ static _str k_func_getfunction_name() { _str sFunctionName = current_proc(); if (!sFunctionName) sFunctionName = ""; //say 'functionanme='sFunctionName; return sFunctionName; } /** * Goes to the neares function and gets its parameters. * @remark Should be reimplemented to use tags (if someone can figure out how to query that stuff). */ static _str k_func_getparams() { typeless org_pos; _save_pos2(org_pos); /* * Try use the tags first. */ _UpdateContext(true); int context_id = tag_current_context(); if (context_id <= 0) { k_func_goto_nearest_function(); context_id = tag_current_context(); } if (context_id > 0) { _str args = ''; _str type = ''; tag_get_detail2(VS_TAGDETAIL_context_args, context_id, args); tag_get_detail2(VS_TAGDETAIL_context_type, context_id, type); if (tag_tree_type_is_func(type)) return args //caption = tag_tree_make_caption_fast(VS_TAGMATCH_context,context_id,true,true,false); } /* * Go to nearest function. */ if ( !k_func_goto_nearest_function() && !k_func_searchcode("(") /* makes some assumptions. */ ) { /* * Get parameters. */ typeless posStart; _save_pos2(posStart); long offStart = _QROffset(); if (!find_matching_paren()) { long offEnd = _QROffset(); _restore_pos2(posStart); p_col++; _str sParamsRaw = strip(get_text((int)(offEnd - offStart - 1))); /* * Remove new lines and double spaces within params. */ _str sParams = ""; int i; _str chPrev; for (i = 1, chPrev = ' '; i <= length(sParamsRaw); i++) { _str ch = substr(sParamsRaw, i, 1); /* * Do fixups. */ if (ch == " " && chPrev == " ") continue; if ((ch :== "\n") || (ch :== "\r") || (ch :== "\t")) { if (chPrev == ' ') continue; ch = ' '; } if (ch == ',' && chPrev == ' ') { sParams = substr(sParams, 1, length(sParams) - 1); } if (ch == '*') { if (chPrev != ' ') sParams = sParams :+ ' * '; else sParams = sParams :+ '* '; chPrev = ' '; } else { sParams = sParams :+ ch; chPrev = ch; } } /* for */ sParams = strip(sParams); if (sParams == 'void' || sParams == 'VOID') sParams = ""; _restore_pos2(org_pos); return sParams; } else message("find_matchin_paren failed"); } _restore_pos2(org_pos); return false; } /** * Enumerates the parameters to the function. * @param sParams Parameter string from k_func_getparams. * @param iParam The index (0-based) of the parameter to get. * @param sType Type. (output) * @param sName Name. (output) * @param sDefault Default value. (output) * @remark Doesn't perhaps handle function pointers very well (I think)? * @remark Should be reimplemented to use tags (if someone can figure out how to query that stuff). */ static int k_func_enumparams(_str sParams, int iParam, _str &sType, _str &sName, _str &sDefault) { int i; int iParLevel; int iCurParam; int iStartParam; sType = sName = sDefault = ""; /* no use working on empty string! */ if (length(sParams) == 0) return -1; /* find the parameter in question */ for (iStartParam = i = 1, iParLevel = iCurParam = 0; i <= length(sParams); i++) { _str ch = substr(sParams, i, 1); if (ch == ',' && iParLevel == 0) { /* is it this parameter ? */ if (iParam == iCurParam) break; iCurParam++; iStartParam = i + 1; } else if (ch == '(') iParLevel++; else if (ch == ')') iParLevel--; } /* did we find the parameter? */ if (iParam == iCurParam) { /* (yeah, we did!) */ _str sArg = strip(substr(sParams, iStartParam, i - iStartParam)); /* remove M$ stuff */ sArg = stranslate(sArg, "", "IN", "E"); sArg = stranslate(sArg, "", "OUT", "E"); sArg = stranslate(sArg, "", "OPTIONAL", "E"); sArg = strip(sArg); /* lazy approach, which doens't support function types */ if (pos('=', sParams) > 0) /* default */ { sDefault = strip(substr(sParams, pos('=', sParams) + 1)); sArg = strip(substr(sArg, 1, pos('=', sParams) - 1)); } for (i = length(sArg); i > 1; i--) { _str ch = substr(sArg, i, 1); if ( !(ch >= 'a' && ch <= 'z') && !(ch >= 'A' && ch <= 'Z') && !(ch >= '0' && ch <= '9') && ch != '_' && ch != '$') break; } if (sArg == "...") i = 0; sName = strip(substr(sArg, i + 1)); sType = strip(substr(sArg, 1, i)); return 0; } return -1; } /** * Counts the parameters to the function. * @param sParams Parameter string from k_func_getparams. * @remark Should be reimplemented to use tags (if someone can figure out how to query that stuff). */ static int k_func_countparams(_str sParams) { int i; int iParLevel; int iCurParam; _str sType = "", sName = "", sDefault = ""; /* check for 0 parameters */ if (length(sParams) == 0) return 0; /* find the parameter in question */ for (i = 1, iParLevel = iCurParam = 0; i <= length(sParams); i++) { _str ch = substr(sParams, i, 1); if (ch == ',' && iParLevel == 0) { iCurParam++; } else if (ch == '(') iParLevel++; else if (ch == ')') iParLevel--; } return iCurParam + 1; } /** * Gets the return type. */ static _str k_func_getreturntype(boolean fPureType = false) { typeless org_pos; _save_pos2(org_pos); /* * Go to nearest function. */ if (!k_func_goto_nearest_function()) { /* * Return type is from function start to function name... */ typeless posStart; _save_pos2(posStart); long offStart = _QROffset(); if (!k_func_searchcode("(")) /* makes some assumptions. */ { prev_word(); long offEnd = _QROffset(); _restore_pos2(posStart); _str sTypeRaw = strip(get_text((int)(offEnd - offStart))); //say 'sTypeRaw='sTypeRaw; /* * Remove static, inline, _Optlink, stdcall, EXPENTRY etc. */ if (fPureType) { sTypeRaw = stranslate(sTypeRaw, "", "__static__", "I"); sTypeRaw = stranslate(sTypeRaw, "", "__static", "I"); sTypeRaw = stranslate(sTypeRaw, "", "static__", "I"); sTypeRaw = stranslate(sTypeRaw, "", "static", "I"); sTypeRaw = stranslate(sTypeRaw, "", "__inline__", "I"); sTypeRaw = stranslate(sTypeRaw, "", "__inline", "I"); sTypeRaw = stranslate(sTypeRaw, "", "inline__", "I"); sTypeRaw = stranslate(sTypeRaw, "", "inline", "I"); sTypeRaw = stranslate(sTypeRaw, "", "EXPENTRY", "I"); sTypeRaw = stranslate(sTypeRaw, "", "_Optlink", "I"); sTypeRaw = stranslate(sTypeRaw, "", "__stdcall", "I"); sTypeRaw = stranslate(sTypeRaw, "", "__cdecl", "I"); sTypeRaw = stranslate(sTypeRaw, "", "_cdecl", "I"); sTypeRaw = stranslate(sTypeRaw, "", "cdecl", "I"); sTypeRaw = stranslate(sTypeRaw, "", "__PASCAL", "I"); sTypeRaw = stranslate(sTypeRaw, "", "_PASCAL", "I"); sTypeRaw = stranslate(sTypeRaw, "", "PASCAL", "I"); sTypeRaw = stranslate(sTypeRaw, "", "__Far32__", "I"); sTypeRaw = stranslate(sTypeRaw, "", "__Far32", "I"); sTypeRaw = stranslate(sTypeRaw, "", "Far32__", "I"); sTypeRaw = stranslate(sTypeRaw, "", "_Far32_", "I"); sTypeRaw = stranslate(sTypeRaw, "", "_Far32", "I"); sTypeRaw = stranslate(sTypeRaw, "", "Far32_", "I"); sTypeRaw = stranslate(sTypeRaw, "", "Far32", "I"); sTypeRaw = stranslate(sTypeRaw, "", "__far", "I"); sTypeRaw = stranslate(sTypeRaw, "", "_far", "I"); sTypeRaw = stranslate(sTypeRaw, "", "far", "I"); sTypeRaw = stranslate(sTypeRaw, "", "__near", "I"); sTypeRaw = stranslate(sTypeRaw, "", "_near", "I"); sTypeRaw = stranslate(sTypeRaw, "", "near", "I"); sTypeRaw = stranslate(sTypeRaw, "", "__loadds__", "I"); sTypeRaw = stranslate(sTypeRaw, "", "__loadds", "I"); sTypeRaw = stranslate(sTypeRaw, "", "loadds__", "I"); sTypeRaw = stranslate(sTypeRaw, "", "_loadds_", "I"); sTypeRaw = stranslate(sTypeRaw, "", "_loadds", "I"); sTypeRaw = stranslate(sTypeRaw, "", "loadds_", "I"); sTypeRaw = stranslate(sTypeRaw, "", "loadds", "I"); sTypeRaw = stranslate(sTypeRaw, "", "__loades__", "I"); sTypeRaw = stranslate(sTypeRaw, "", "__loades", "I"); sTypeRaw = stranslate(sTypeRaw, "", "loades__", "I"); sTypeRaw = stranslate(sTypeRaw, "", "_loades_", "I"); sTypeRaw = stranslate(sTypeRaw, "", "_loades", "I"); sTypeRaw = stranslate(sTypeRaw, "", "loades_", "I"); sTypeRaw = stranslate(sTypeRaw, "", "loades", "I"); sTypeRaw = stranslate(sTypeRaw, "", "WIN32API", "I"); sTypeRaw = stranslate(sTypeRaw, "", "WINAPI", "I"); sTypeRaw = stranslate(sTypeRaw, "", "LDRCALL", "I"); sTypeRaw = stranslate(sTypeRaw, "", "KRNLCALL", "I"); sTypeRaw = stranslate(sTypeRaw, "", "__operator__", "I"); /* operator fix */ sTypeRaw = stranslate(sTypeRaw, "", "__operator", "I"); /* operator fix */ sTypeRaw = stranslate(sTypeRaw, "", "operator__", "I"); /* operator fix */ sTypeRaw = stranslate(sTypeRaw, "", "operator", "I"); /* operator fix */ sTypeRaw = stranslate(sTypeRaw, "", "IN", "E"); sTypeRaw = stranslate(sTypeRaw, "", "OUT", "E"); sTypeRaw = stranslate(sTypeRaw, "", "OPTIONAL", "E"); } /* * Remove new lines and double spaces within params. */ _str sType = ""; int i; _str chPrev; for (i = 1, chPrev = ' '; i <= length(sTypeRaw); i++) { _str ch = substr(sTypeRaw, i, 1); /* * Do fixups. */ if (ch == " " && chPrev == " ") continue; if ((ch :== "\n") || (ch :== "\r") || (ch :== "\t")) { if (chPrev == ' ') continue; ch = ' '; } if (ch == ',' && chPrev == ' ') { sType = substr(sType, 1, length(sType) - 1); } if (ch == '*') { if (chPrev != ' ') sType = sType :+ ' * '; else sType = sType :+ '* '; chPrev = ' '; } else { sType = sType :+ ch; chPrev = ch; } } /* for */ sType = strip(sType); _restore_pos2(org_pos); return sType; } else message('k_func_getreturntype: can''t find ''(''.'); } _restore_pos2(org_pos); return false; } /** * Search for some piece of code. */ static int k_func_searchcode(_str sSearchString, _str sOptions = "E+") { int rc; rc = search(sSearchString, sOptions); while (!rc && !k_func_in_code()) { p_col++; rc = search(sSearchString, sOptions); } return rc; } /** * Checks if cursor is in code or in comment. * @return True if cursor in code. */ static boolean k_func_in_code() { typeless searchsave; _save_pos2(searchsave); boolean fRc = !_in_comment(); _restore_pos2(searchsave); return fRc; } /* * Gets the next piece of code. */ static _str k_func_get_next_code_text() { typeless searchsave; _save_pos2(searchsave); _str ch = k_func_get_next_code_text2(); _restore_pos2(searchsave); return ch; } /** * Checks if there is more code on the line. */ static boolean k_func_more_code_on_line() { boolean fRc; int curline = p_line; typeless searchsave; _save_pos2(searchsave); k_func_get_next_code_text2(); fRc = curline == p_line; _restore_pos2(searchsave); return fRc; } /** * Gets the next piece of code. * Doesn't preserver cursor position. */ static _str k_func_get_next_code_text2() { _str ch; do { int curcol = ++p_col; end_line(); if (p_col <= curcol) { p_line++; p_col = 1; } else p_col = curcol; ch = get_text(); //say ch ' ('_asc(ch)')'; while (ch == "#") /* preprocessor stuff */ { p_col = 1; p_line++; ch = get_text(); //say ch ' ('_asc(ch)')'; continue; } } while (ch :== ' ' || ch :== "\t" || ch :== "\n" || ch :== "\r" || !k_func_in_code()); return ch; } /******************************************************************************* * JAVA DOC STYLED WORKERS * *******************************************************************************/ /** starts a javadoc documentation box. */ static void k_javadoc_box_start(_str sStr = '', boolean fDouble = true) { _str sLeft, sRight; int iColumn; if (!k_commentconfig(sLeft, sRight, iColumn)) return; _begin_line(); if (iColumn >= 0) while (p_col < iColumn) _insert_text(" "); _str sText = sLeft; if (fDouble) sText = sLeft:+substr(sLeft, length(sLeft), 1); if (sStr != '') sText = sText:+' ':+sStr; sText = sText:+"\n"; _insert_text(sText); } /** inserts a new line in a javadoc documentation box. */ static void k_javadoc_box_line(_str sStr = '', int iPadd = 0, _str sStr2 = '', int iPadd2 = 0, _str sStr3 = '') { _str sLeft, sRight; int iColumn; if (!k_commentconfig(sLeft, sRight, iColumn)) return; if (iColumn >= 0) while (p_col < iColumn) _insert_text(" "); _str sText; if (k_line_comment()) sText = sLeft; else { sText = sLeft; sText = ' ':+substr(sLeft, length(sLeft)); } if (sStr != '') sText = sText:+' ':+sStr; if (iPadd > 0) { int i; for (i = length(sText); i < iPadd; i++) sText = sText:+' '; if (sStr2 != '') sText = sText:+sStr2; if (iPadd2 > 0) { for (i = length(sText); i < iPadd2; i++) sText = sText:+' '; if (sStr3 != '') sText = sText:+sStr3; } } sText = sText:+"\n"; _insert_text(sText); } /** ends a javadoc documentation box. */ static void k_javadoc_box_end() { _str sLeft, sRight; int iColumn; if (!k_commentconfig(sLeft, sRight, iColumn)) return; if (iColumn >= 0) while (p_col < iColumn) _insert_text(" "); _str sText; if (k_line_comment()) sText = sLeft; else { sText = sRight; /*if (substr(sText, 1, 1) != '*') sText = '*':+sText;*/ sText = ' ':+sText; } sText = sText:+"\n"; _insert_text(sText); } /** * Write a Javadoc styled classbox. */ void k_javadoc_classbox() { int iCursorLine; int iPadd = k_alignup(12, p_SyntaxIndent); k_javadoc_box_start(); iCursorLine = p_RLine; k_javadoc_box_line(' '); if (fkStyleFullHeaders) { k_javadoc_box_line('@shortdesc', iPadd); k_javadoc_box_line('@dstruct', iPadd); k_javadoc_box_line('@version', iPadd); k_javadoc_box_line('@verdesc', iPadd); } k_javadoc_box_line('@author', iPadd, skUserName ' <' skUserEmail '>'); k_javadoc_box_line('@approval', iPadd); k_javadoc_box_end(); up(p_RLine - iCursorLine); end_line(); keyin(' '); } /** * Javadoc - functionbox(/header). */ void k_javadoc_funcbox() { int cArgs = 1; _str sArgs = ""; int iCursorLine; int iPadd = k_alignup(11, p_SyntaxIndent); /* look for parameters */ boolean fFoundFn = !k_func_goto_nearest_function(); if (fFoundFn) { sArgs = k_func_getparams(); cArgs = k_func_countparams(sArgs); } k_javadoc_box_start(); iCursorLine = p_RLine; k_javadoc_box_line(' '); if (file_eq(p_extension, 'asm') || file_eq(p_extension, 'masm')) k_javadoc_box_line('@cproto', iPadd); k_javadoc_box_line('@returns', iPadd); if (fFoundFn) { /* * Determin parameter description indent. */ int iPadd2 = 0; int i; for (i = 0; i < cArgs; i++) { _str sName, sType, sDefault; if ( !k_func_enumparams(sArgs, i, sType, sName, sDefault) && iPadd2 < length(sName)) iPadd2 = length(sName); } iPadd2 = k_alignup((iPadd + iPadd2), p_SyntaxIndent); if (iPadd2 < 28) iPadd2 = k_alignup(28, p_SyntaxIndent); /* * Insert parameter. */ for (i = 0; i < cArgs; i++) { _str sName, sType, sDefault; if (!k_func_enumparams(sArgs, i, sType, sName, sDefault)) { _str sStr3 = '.'; if (sDefault != "") sStr3 = '(default='sDefault')'; k_javadoc_box_line('@param', iPadd, sName, iPadd2, sStr3); } else k_javadoc_box_line('@param', iPadd); } } else k_javadoc_box_line('@param', iPadd); if (file_eq(p_extension, 'asm') || file_eq(p_extension, 'masm')) k_javadoc_box_line('@uses', iPadd); if (fkStyleFullHeaders) { k_javadoc_box_line('@equiv', iPadd); k_javadoc_box_line('@time', iPadd); k_javadoc_box_line('@sketch', iPadd); k_javadoc_box_line('@status', iPadd); k_javadoc_box_line('@author', iPadd, skUserName ' <' skUserEmail '>'); k_javadoc_box_line('@remark', iPadd); } k_javadoc_box_end(); up(p_RLine - iCursorLine); end_line(); keyin(' '); } /** * Javadoc module header. */ void k_javadoc_moduleheader() { int iCursorLine; int fSplit = 0; _insert_text("\n"); up(); _begin_line(); k_insert_comment('$':+'I':+'d: $', KIC_CURSOR_AT_END, -1); _end_line(); _insert_text("\n"); k_javadoc_box_start('@file'); fSplit = 1; iCursorLine = p_RLine; k_javadoc_box_line(); k_javadoc_box_end(); _insert_text("\n"); _insert_text(k_comment() "\n"); if (skLicense == 'Confidential') { k_javadoc_box_line(skCompany ' confidential'); k_javadoc_box_line(); } if (skCompany != '') { if (skLicense != 'Confidential') k_javadoc_box_line('Copyright (C) ' k_year() ' ' skCompany); else { k_javadoc_box_line('Copyright (c) ' k_year() ' ' skCompany); k_javadoc_box_line(); k_javadoc_box_line('Author: ' skUserName' <' skUserEmail '>'); } } else k_javadoc_box_line('Copyright (c) ' k_year() ' 'skUserName' <' skUserEmail '>'); k_javadoc_box_line(); _str sProg = skProgram; switch (skLicense) { case 'Odin32': k_javadoc_box_line('Project Odin Software License can be found in LICENSE.TXT.'); break; case 'GPL': if (!fSplit) k_javadoc_box_line(); if (sProg == '') sProg = 'This program'; else { k_javadoc_box_line('This file is part of ' sProg '.'); k_javadoc_box_line(); } k_javadoc_box_line(sProg ' is free software; you can redistribute it and/or modify'); k_javadoc_box_line('it under the terms of the GNU General Public License as published by'); k_javadoc_box_line('the Free Software Foundation; either version 2 of the License, or'); k_javadoc_box_line('(at your option) any later version.'); k_javadoc_box_line(); k_javadoc_box_line(sProg ' is distributed in the hope that it will be useful,'); k_javadoc_box_line('but WITHOUT ANY WARRANTY; without even the implied warranty of'); k_javadoc_box_line('MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the'); k_javadoc_box_line('GNU General Public License for more details.'); k_javadoc_box_line(); k_javadoc_box_line('You should have received a copy of the GNU General Public License'); k_javadoc_box_line('along with ' sProg '; if not, write to the Free Software'); k_javadoc_box_line('Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA'); break; case 'LGPL': if (!fSplit) k_javadoc_box_line(); if (sProg == '') sProg = 'This library'; else { k_javadoc_box_line('This file is part of ' sProg '.'); k_javadoc_box_line(); } k_javadoc_box_line(sProg ' is free software; you can redistribute it and/or'); k_javadoc_box_line('modify it under the terms of the GNU Lesser General Public'); k_javadoc_box_line('License as published by the Free Software Foundation; either'); k_javadoc_box_line('version 2.1 of the License, or (at your option) any later version.'); k_javadoc_box_line(); k_javadoc_box_line(sProg ' is distributed in the hope that it will be useful,'); k_javadoc_box_line('but WITHOUT ANY WARRANTY; without even the implied warranty of'); k_javadoc_box_line('MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU'); k_javadoc_box_line('Lesser General Public License for more details.'); k_javadoc_box_line(); k_javadoc_box_line('You should have received a copy of the GNU Lesser General Public'); k_javadoc_box_line('License along with ' sProg '; if not, write to the Free Software'); k_javadoc_box_line('Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA'); break; case 'GPLv3': if (!fSplit) k_javadoc_box_line(); if (sProg == '') sProg = 'This program'; else { k_javadoc_box_line('This file is part of ' sProg '.'); k_javadoc_box_line(); } k_javadoc_box_line(sProg ' is free software; you can redistribute it and/or modify'); k_javadoc_box_line('it under the terms of the GNU General Public License as published by'); k_javadoc_box_line('the Free Software Foundation; either version 3 of the License, or'); k_javadoc_box_line('(at your option) any later version.'); k_javadoc_box_line(); k_javadoc_box_line(sProg ' is distributed in the hope that it will be useful,'); k_javadoc_box_line('but WITHOUT ANY WARRANTY; without even the implied warranty of'); k_javadoc_box_line('MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the'); k_javadoc_box_line('GNU General Public License for more details.'); k_javadoc_box_line(); k_javadoc_box_line('You should have received a copy of the GNU General Public License'); k_javadoc_box_line('along with ' sProg '. If not, see '); break; case 'LGPLv3': if (!fSplit) k_javadoc_box_line(); if (sProg == '') sProg = 'This program'; else { k_javadoc_box_line('This file is part of ' sProg '.'); k_javadoc_box_line(); } k_javadoc_box_line(sProg ' is free software; you can redistribute it and/or'); k_javadoc_box_line('modify it under the terms of the GNU Lesser General Public'); k_javadoc_box_line('License as published by the Free Software Foundation; either'); k_javadoc_box_line('version 3 of the License, or (at your option) any later version.'); k_javadoc_box_line(); k_javadoc_box_line(sProg ' is distributed in the hope that it will be useful,'); k_javadoc_box_line('but WITHOUT ANY WARRANTY; without even the implied warranty of'); k_javadoc_box_line('MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the'); k_javadoc_box_line('GNU Lesser General Public License for more details.'); k_javadoc_box_line(); k_javadoc_box_line('You should have received a copy of the GNU Lesser General Public License'); k_javadoc_box_line('along with ' sProg '. If not, see '); break; case 'Confidential': k_javadoc_box_line('All Rights Reserved'); break; case 'ConfidentialNoAuthor': k_javadoc_box_line(skCompany ' confidential'); k_javadoc_box_line('All Rights Reserved'); break; case 'VirtualBox': k_javadoc_box_line('This file is part of VirtualBox Open Source Edition (OSE), as') k_javadoc_box_line('available from http://www.virtualbox.org. This file is free software;') k_javadoc_box_line('you can redistribute it and/or modify it under the terms of the GNU') k_javadoc_box_line('General Public License (GPL) as published by the Free Software') k_javadoc_box_line('Foundation, in version 2 as it comes in the "COPYING" file of the') k_javadoc_box_line('VirtualBox OSE distribution. VirtualBox OSE is distributed in the') k_javadoc_box_line('hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.') k_javadoc_box_line('') k_javadoc_box_line('Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa') k_javadoc_box_line('Clara, CA 95054 USA or visit http://www.sun.com if you need') k_javadoc_box_line('additional information or have any questions.') break; case 'VirtualBoxGPLAndCDDL': k_javadoc_box_line('This file is part of VirtualBox Open Source Edition (OSE), as') k_javadoc_box_line('available from http://www.virtualbox.org. This file is free software;') k_javadoc_box_line('you can redistribute it and/or modify it under the terms of the GNU') k_javadoc_box_line('General Public License (GPL) as published by the Free Software') k_javadoc_box_line('Foundation, in version 2 as it comes in the "COPYING" file of the') k_javadoc_box_line('VirtualBox OSE distribution. VirtualBox OSE is distributed in the') k_javadoc_box_line('hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.') k_javadoc_box_line('') k_javadoc_box_line('The contents of this file may alternatively be used under the terms') k_javadoc_box_line('of the Common Development and Distribution License Version 1.0') k_javadoc_box_line('(CDDL) only, as it comes in the "COPYING.CDDL" file of the') k_javadoc_box_line('VirtualBox OSE distribution, in which case the provisions of the') k_javadoc_box_line('CDDL are applicable instead of those of the GPL.') k_javadoc_box_line('') k_javadoc_box_line('You may elect to license modified versions of this file under the') k_javadoc_box_line('terms and conditions of either the GPL or the CDDL or both.') k_javadoc_box_line('') k_javadoc_box_line('Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa') k_javadoc_box_line('Clara, CA 95054 USA or visit http://www.sun.com if you need') k_javadoc_box_line('additional information or have any questions.') break; default: } k_javadoc_box_line(); k_javadoc_box_end(); up(p_RLine - iCursorLine); end_line(); keyin(' '); } /******************************************************************************* * Keyboard Shortcuts * *******************************************************************************/ /** Makes global box. */ void k_box_globals() { k_box_start('Global'); k_box_line('Global Variables'); k_box_end(); } /** Makes header box. */ void k_box_headers() { k_box_start("Header"); k_box_line("Header Files"); k_box_end(); } /** Makes internal function box. */ void k_box_intfuncs() { k_box_start("IntFunc"); k_box_line("Internal Functions"); k_box_end(); } /** Makes def/const box. */ void k_box_consts() { k_box_start("Const"); k_box_line("Defined Constants And Macros"); k_box_end(); } /** Structure box */ void k_box_structs() { k_box_start("Struct"); k_box_line("Structures and Typedefs"); k_box_end(); } /** Makes exported symbols box. */ void k_box_exported() { k_box_start('Exported'); k_box_line('Exported Symbols'); k_box_end(); } /** oneliner comment */ void k_oneliner() { _str sLeft, sRight; int iColumn; if ( k_commentconfig(sLeft, sRight, iColumn) && iColumn > 0) { /* column based needs some tricky repositioning. */ _end_line(); if (p_col > iColumn) { _begin_line(); _insert_text("\n\r"); up(); } } k_insert_comment("", KIC_CURSOR_AT_END, ikStyleOneliner); } /** mark line as modified. */ void k_mark_modified_line() { /* not supported for column based sources */ _str sLeft, sRight; int iColumn; if ( !k_commentconfig(sLeft, sRight, iColumn) || iColumn > 0) return; _str sStr; if (skChange != '') sStr = skChange ' (' skUserInitials ')'; else sStr = skUserInitials; k_insert_comment(sStr, KIC_CURSOR_BEFORE, ikStyleModifyMarkColumn); down(); } /** * Inserts a signature. Form: "//Initials ISO-date:" * @remark defeventtab */ void k_signature() { /* kso I5-10000 2002-09-10: */ _str sSig; if (skChange != '') sSig = skUserInitials ' ' skChange ' ' k_date() ': '; else sSig = skUserInitials ' ' k_date() ': '; k_insert_comment(sSig, KIC_CURSOR_AT_END); } /* Insert a list of NOREF() macro invocations. */ void k_noref() { typeless org_pos; _save_pos2(org_pos); _str sNoRefs = ''; boolean fFoundFn = !k_func_goto_nearest_function(); if (fFoundFn) { _str sArgs = k_func_getparams(); int cArgs = k_func_countparams(sArgs); int fVaArgs = 1; int i; int offLine = 4; for (i = 0; i < cArgs; i++) { _str sName, sType, sDefault; if (!k_func_enumparams(sArgs, i, sType, sName, sDefault)) { if (!fVaArgs) { sThis = 'NOREF(' sName ');'; if (length(sNoRefs) == 0) { sNoRefs = sThis; offLine += length(sThis); } else if (offLine + length(sThis) < 130) { sNoRefs = sNoRefs ' ' sThis; offLine += 1 + length(sThis); } else { sNoRefs = sNoRefs "\n " sThis; offLine = 4 + length(sThis); } } else if (length(sNoRefs) == 0) { sNoRefs = 'RT_NOREF(' sName; offLine = length(sNoRefs); } else if (offLine + 2 + length(sName) < 130) { sNoRefs = sNoRefs ', ' sName; offLine += 2 + length(sName); } else { sNoRefs = sNoRefs ',\n ' sName; offLine += 4 + length(sName); } } } if (length(sNoRefs) > 0 && fVaArgs != 0) sNoRefs = sNoRefs ');'; } _restore_pos2(org_pos); _insert_text(sNoRefs); } /******************************************************************************* * kLIB Logging * *******************************************************************************/ /** * Hot-Key: Inserts a KLOGENTRY statement at start of nearest function. */ void klib_klogentry() { typeless org_pos; _save_pos2(org_pos); /* * Go to nearest function. */ if (!k_func_goto_nearest_function()) { /* * Get parameters. */ _str sParams = k_func_getparams(); if (sParams) { _str sRetType = k_func_getreturntype(true); if (!sRetType || sRetType == "") sRetType = "void"; /* paranoia! */ /* * Insert text. */ if (!k_func_searchcode("{")) { p_col++; int cArgs = k_func_countparams(sParams); if (cArgs > 0) { _str sArgs = ""; int i; for (i = 0; i < cArgs; i++) { _str sType, sName, sDefault; if (!k_func_enumparams(sParams, i, sType, sName, sDefault)) sArgs = sArgs', 'sName; } _insert_text("\n KLOGENTRY"cArgs"(\""sRetType"\",\""sParams"\""sArgs");"); /* todo tab size.. or smart indent */ } else _insert_text("\n KLOGENTRY0(\""sRetType"\");"); /* todo tab size.. or smart indent */ /* * Check if the next word is KLOGENTRY. */ next_word(); if (def_next_word_style == 'E') prev_word(); int iIgnorePos = 0; if (substr(cur_word(iIgnorePos), 1, 9) == "KLOGENTRY") delete_line(); } else message("didn't find {"); } else message("k_func_getparams failed, sParams=" sParams); return; } _restore_pos2(org_pos); } /** * Hot-Key: Inserts a KLOGEXIT statement at cursor location. */ void klib_klogexit() { typeless org_pos; _save_pos2(org_pos); /* * Go to nearest function. */ if (!prev_proc()) { /* * Get parameters. */ _str sType = k_func_getreturntype(true); _restore_pos2(org_pos); if (sType) { boolean fReturn = true; /* true if an return statment is following the KLOGEXIT statement. */ /* * Insert text. */ int cur_col = p_col; if (sType == 'void' || sType == 'VOID') { /* procedure */ int iIgnorePos; fReturn = cur_word(iIgnorePos) == 'return'; if (!fReturn) { while (p_col <= p_SyntaxIndent) keyin(" "); } _insert_text("KLOGEXITVOID();\n"); if (fReturn) { int i; for (i = 1; i < cur_col; i++) _insert_text(" "); } search(")","E-"); } else { /* function */ _insert_text("KLOGEXIT();\n"); int i; for (i = 1; i < cur_col; i++) _insert_text(" "); search(")","E-"); /* * Insert value if possible. */ typeless valuepos; _save_pos2(valuepos); next_word(); if (def_next_word_style == 'E') prev_word(); int iIgnorePos; if (cur_word(iIgnorePos) == 'return') { p_col += length('return'); typeless posStart; _save_pos2(posStart); long offStart = _QROffset(); if (!k_func_searchcode(";", "E+")) { long offEnd = _QROffset(); _restore_pos2(posStart); _str sValue = strip(get_text((int)(offEnd - offStart))); //say 'sValue = 'sValue; _restore_pos2(valuepos); _save_pos2(valuepos); _insert_text(sValue); } } _restore_pos2(valuepos); } /* * Remove old KLOGEXIT statement on previous line if any. */ typeless valuepos; _save_pos2(valuepos); int newexitline = p_line; p_line--; p_col = 1; next_word(); if (def_next_word_style == 'E') prev_word(); int iIgnorePos; if (p_line == newexitline - 1 && substr(cur_word(iIgnorePos), 1, 8) == 'KLOGEXIT') delete_line(); _restore_pos2(valuepos); /* * Check for missing '{...}'. */ if (fReturn) { boolean fFound = false; _save_pos2(valuepos); p_col--; find_matching_paren(); p_col += 2; k_func_searchcode(';', 'E+'); /* places us at the ';' of the return. (hopefully) */ _str ch = k_func_get_next_code_text(); if (ch != '}') { _restore_pos2(valuepos); _save_pos2(valuepos); p_col--; find_matching_paren(); p_col += 2; k_func_searchcode(';', 'E+'); /* places us at the ';' of the return. (hopefully) */ p_col++; if (k_func_more_code_on_line()) _insert_text(' }'); else { typeless returnget; _save_pos2(returnget); k_func_searchcode("return", "E-"); int return_col = p_col; _restore_pos2(returnget); end_line(); _insert_text("\n"); while (p_col < return_col - p_SyntaxIndent) _insert_text(' '); _insert_text('}'); } _restore_pos2(valuepos); _save_pos2(valuepos); prev_word(); p_col -= p_SyntaxIndent; int codecol = p_col; _insert_text("{\n"); while (p_col < codecol) _insert_text(' '); } _restore_pos2(valuepos); } } else message("k_func_getreturntype failed, sType=" sType); return; } _restore_pos2(org_pos); } /** * Processes a file - ask user all the time. */ void klib_klog_file_ask() { klib_klog_file_int(true); } /** * Processes a file - no questions. */ void klib_klog_file_no_ask() { klib_klog_file_int(false); } /** * Processes a file. */ static void klib_klog_file_int(boolean fAsk) { show_all(); bottom(); _refresh_scroll(); /* ask question so we can get to the right position somehow.. */ if (fAsk && _message_box("kLog process this file?", "Visual SlickEdit", MB_YESNO | MB_ICONQUESTION) != IDYES) return; /* * Entries. */ while (!prev_proc()) { //say 'entry main loop: ' k_func_getfunction_name(); /* * Skip prototypes. */ if (k_func_prototype()) continue; /* * Ask user. */ center_line(); _refresh_scroll(); _str sFunction = k_func_getfunction_name(); rc = fAsk ? _message_box("Process this function ("sFunction")?", "Visual SlickEdit", MB_YESNOCANCEL | MB_ICONQUESTION) : IDYES; if (rc == IDYES) { typeless procpos; _save_pos2(procpos); klib_klogentry(); _restore_pos2(procpos); } else if (rc == IDNO) continue; else break; } /* * Exits. */ bottom(); _refresh_scroll(); boolean fUserCancel = false; while (!prev_proc() && !fUserCancel) { typeless procpos; _save_pos2(procpos); _str sCurFunction = k_func_getfunction_name(); //say 'exit main loop: ' sCurFunction /* * Skip prototypes. */ if (k_func_prototype()) continue; /* * Select procedure. */ while ( !k_func_searchcode("return", "WE<+") && k_func_getfunction_name() == sCurFunction) { //say 'exit sub loop: ' p_line /* * Ask User. */ center_line(); _refresh_scroll(); _str sFunction = k_func_getfunction_name(); rc = fAsk ? _message_box("Process this exit from "sFunction"?", "Visual SlickEdit", MB_YESNOCANCEL | MB_ICONQUESTION) : IDYES; deselect(); if (rc == IDYES) { typeless returnpos; _save_pos2(returnpos); klib_klogexit(); _restore_pos2(returnpos); p_line++; } else if (rc != IDNO) { fUserCancel = true; break; } p_line++; /* just so we won't hit it again. */ } /* * If void function we'll have to check if there is and return; prior to the ending '}'. */ _restore_pos2(procpos); _save_pos2(procpos); _str sType = k_func_getreturntype(true); if (!fUserCancel && sType && (sType == 'void' || sType == 'VOID')) { if ( !k_func_searchcode("{", "E+") && !find_matching_paren()) { typeless funcend; _save_pos2(funcend); prev_word(); int iIgnorePos; if (cur_word(iIgnorePos) != "return") { /* * Ask User. */ _restore_pos2(funcend); center_line(); _refresh_scroll(); _str sFunction = k_func_getfunction_name(); rc = fAsk ? _message_box("Process this exit from "sFunction"?", "Visual SlickEdit", MB_YESNOCANCEL | MB_ICONQUESTION) : IDYES; deselect(); if (rc == IDYES) { typeless returnpos; _save_pos2(returnpos); klib_klogexit(); _restore_pos2(returnpos); } } } } /* * Next proc. */ _restore_pos2(procpos); } } /** @todo move to kkeys.e */ _command void k_rebuild_tagfile() { #if 1 /*__VERSION__ < 14.0*/ if (file_match('-p 'maybe_quote_filename(strip_filename(_project_name,'e'):+TAG_FILE_EXT),1) != "") _project_update_files_retag(false, false, false, false); else _project_update_files_retag(true, false, false, true); #else _str sArgs = "-refs=on"; if (file_match('-p 'maybe_quote_filename(strip_filename(_project_name,'e'):+TAG_FILE_EXT),1) != "") sArgs = sArgs :+ " -retag"; sArgs = sArgs :+ " " :+ _workspace_filename; build_workspace_tagfiles(sArgs); #endif } /******************************************************************************* * Styles * *******************************************************************************/ static _str StyleLanguages[] = { "c", "e", "java" }; struct StyleScheme { _str name; _str settings[]; }; static StyleScheme StyleSchemes[] = { { "Opt2Ind4", { "orig_tabsize=4", "syntax_indent=4", "tabsize=4", "align_on_equal=1", "pad_condition_state=1", "indent_with_tabs=0", "nospace_before_paren=0", "indent_comments=1", "indent_case=1", "statement_comment_col=0", "disable_bestyle=0", "decl_comment_col=0", "bestyle_on_functions=0", "use_relative_indent=1", "nospace_before_brace=0", "indent_fl=1", "statement_comment_state=2", "indent_pp=1", "be_style=1", "parens_on_return=0", "eat_blank_lines=0", "brace_indent=0", "eat_pp_space=1", "align_on_parens=1", "continuation_indent=0", "cuddle_else=0", "nopad_condition=1", "pad_condition=0", "indent_col1_comments=0" } } , { "Opt2Ind3", { "orig_tabsize=3", "syntax_indent=3", "tabsize=3", "align_on_equal=1", "pad_condition_state=1", "indent_with_tabs=0", "nospace_before_paren=0", "indent_comments=1", "indent_case=1", "statement_comment_col=0", "disable_bestyle=0", "decl_comment_col=0", "bestyle_on_functions=0", "use_relative_indent=1", "nospace_before_brace=0", "indent_fl=1", "statement_comment_state=2", "indent_pp=1", "be_style=1", "parens_on_return=0", "eat_blank_lines=0", "brace_indent=0", "eat_pp_space=1", "align_on_parens=1", "continuation_indent=0", "cuddle_else=0", "nopad_condition=1", "pad_condition=0", "indent_col1_comments=0" } } , { "Opt2Ind8", { "orig_tabsize=8", "syntax_indent=8", "tabsize=8", "align_on_equal=1", "pad_condition_state=1", "indent_with_tabs=0", "nospace_before_paren=0", "indent_comments=1", "indent_case=1", "statement_comment_col=0", "disable_bestyle=0", "decl_comment_col=0", "bestyle_on_functions=0", "use_relative_indent=1", "nospace_before_brace=0", "indent_fl=1", "statement_comment_state=2", "indent_pp=1", "be_style=1", "parens_on_return=0", "eat_blank_lines=0", "brace_indent=0", "eat_pp_space=1", "align_on_parens=1", "continuation_indent=0", "cuddle_else=0", "nopad_condition=1", "pad_condition=0", "indent_col1_comments=0" } } , { "Opt3Ind4", { "orig_tabsize=4", "syntax_indent=4", "tabsize=4", "align_on_equal=1", "pad_condition_state=1", "indent_with_tabs=0", "nospace_before_paren=0", "indent_comments=1", "indent_case=1", "statement_comment_col=0", "disable_bestyle=0", "decl_comment_col=0", "bestyle_on_functions=0", "use_relative_indent=1", "nospace_before_brace=0", "indent_fl=1", "statement_comment_state=2", "indent_pp=1", "be_style=2", "parens_on_return=0", "eat_blank_lines=0", "brace_indent=0", "eat_pp_space=1", "align_on_parens=1", "continuation_indent=0", "cuddle_else=0", "nopad_condition=1", "pad_condition=0", "indent_col1_comments=0" } } , { "Opt3Ind3", { "orig_tabsize=3", "syntax_indent=3", "tabsize=3", "align_on_equal=1", "pad_condition_state=1", "indent_with_tabs=0", "nospace_before_paren=0", "indent_comments=1", "indent_case=1", "statement_comment_col=0", "disable_bestyle=0", "decl_comment_col=0", "bestyle_on_functions=0", "use_relative_indent=1", "nospace_before_brace=0", "indent_fl=1", "statement_comment_state=2", "indent_pp=1", "be_style=2", "parens_on_return=0", "eat_blank_lines=0", "brace_indent=0", "eat_pp_space=1", "align_on_parens=1", "continuation_indent=0", "cuddle_else=0", "nopad_condition=1", "pad_condition=0", "indent_col1_comments=0" } } }; static void k_styles_create() { /* * Find user format ini file. */ _str userini = maybe_quote_filename(_config_path():+'uformat.ini'); if (file_match('-p 'userini, 1) == '') { _str ini = maybe_quote_filename(slick_path_search('uformat.ini')); if (ini != '') userini = ini; } /* * Remove any old schemes. */ int i,j,tv; for (i = 0; i < StyleSchemes._length(); i++) for (j = 0; j < StyleLanguages._length(); j++) { _str sectionname = StyleLanguages[j]:+'-scheme-':+StyleSchemes[i].name; if (!_ini_get_section(userini, sectionname, tv)) { _ini_delete_section(userini, sectionname); _delete_temp_view(tv); //message("delete old scheme"); } } /* * Create the new schemes. */ for (i = 0; i < StyleSchemes._length(); i++) { for (j = 0; j < StyleLanguages._length(); j++) { _str sectionname = StyleLanguages[j]:+'-scheme-':+StyleSchemes[i].name; int temp_view_id, k; _str orig_view_id = _create_temp_view(temp_view_id); activate_view(temp_view_id); for (k = 0; k < StyleSchemes[i].settings._length(); k++) insert_line(StyleSchemes[i].settings[k]); /* Insert the scheme section. */ _ini_replace_section(userini, sectionname, temp_view_id); //message(userini) //bogus id - activate_view(orig_view_id); } } //last_scheme = last scheme name!!! } /* * Sets the last used beutify scheme. */ static k_styles_set(_str scheme) { /* * Find user format ini file. */ _str userini = maybe_quote_filename(_config_path():+'uformat.ini'); if (file_match('-p 'userini, 1) == '') { _str ini = maybe_quote_filename(slick_path_search('uformat.ini')); if (ini != '') userini = ini; } /* * Set the scheme for each language. */ int j; for (j = 0; j < StyleLanguages._length(); j++) { _ini_set_value(userini, StyleLanguages[j]:+'-scheme-Default', 'last_scheme', scheme); } } static _str defoptions[] = { "def-options-sas", "def-options-js", "def-options-bat", "def-options-c", "def-options-pas", "def-options-e", "def-options-java", "def-options-bourneshell", "def-options-csh", "def-options-vlx", "def-options-plsql", "def-options-sqlserver", "def-options-cmd" }; static _str defsetups[] = { "def-setup-sas", "def-setup-js", "def-setup-bat", "def-setup-fundamental", "def-setup-process", "def-setup-c", "def-setup-pas", "def-setup-e", "def-setup-asm", "def-setup-java", "def-setup-html", "def-setup-bourneshell", "def-setup-csh", "def-setup-vlx", "def-setup-fileman", "def-setup-plsql", "def-setup-sqlserver", "def-setup-s", "def-setup-cmd" }; static _str defsetupstab8[] = { "def-setup-c" }; static void k_styles_setindent(int indent, int iBraceStyle, boolean iWithTabs = false) { if (iBraceStyle < 1 || iBraceStyle > 3) { message('k_styles_setindent: iBraceStyle is bad (=' :+ iBraceStyle :+ ')'); iBraceStyle = 2; } /* * def-options for extentions known to have that info. */ int i; for (i = 0; i < defoptions._length(); i++) { int idx = find_index(defoptions[i], MISC_TYPE); if (!idx) continue; parse name_info(idx) with syntax_indent o2 o3 o4 flags indent_fl o7 indent_case rest; /* Begin/end style */ flags = flags & ~(1|2); flags = flags | (iBraceStyle - 1); /* Set style (0-based) */ flags = flags & ~(16); /* no scape before parent.*/ indent_fl = 1; /* Indent first level */ indent_case = 1; /* Indent case from switch */ sNewOptions = indent' 'o2' 'o3' 'o4' 'flags' 'indent_fl' 'o7' 'indent_case' 'rest; set_name_info(idx, sNewOptions); _config_modify |= CFGMODIFY_DEFDATA; } /* * def-setup for known extentions. */ for (i = 0; i < defsetups._length(); i++) { idx = find_index(defsetups[i], MISC_TYPE); if (!idx) continue; sExt = substr(defsetups[i], length('def-setup-') + 1); sSetup = name_info(idx); /* parse sSetup with 'MN=' mode_name ','\ 'TABS=' tabs ',' 'MA=' margins ',' 'KEYTAB=' keytab_name ','\ 'WW='word_wrap_style ',' 'IWT='indent_with_tabs ','\ 'ST='show_tabs ',' 'IN='indent_style ','\ 'WC='word_chars',' 'LN='lexer_name',' 'CF='color_flags','\ 'LNL='line_numbers_len','rest; indent_with_tabs = 0; /* Indent with tabs */ /* Make sure all the values are legal */ _ext_init_values(ext, lexer_name, color_flags); if (!isinteger(line_numbers_len)) line_numbers_len = 0; if (word_chars == '') word_chars = 'A-Za-z0-9_$'; if (word_wrap_style == '') word_wrap_style = 3; if (show_tabs == '') show_tabs = 0; if (indent_style == '') indent_style = INDENT_SMART; /* Set new indent */ tabs = '+'indent; */ sNewSetup = sSetup; /* Set new indent */ if (pos('TABS=', sNewSetup) > 0) { /* * If either in defoptions or defsetupstab8 use default tab of 8 * For those supporting separate syntax indent using the normal tabsize * helps us a lot when reading it... */ fTab8 = false; for (j = 0; !fTab8 && j < defsetupstab8._length(); j++) if (substr(defsetupstab8[j], lastpos('-', defsetupstab8[j]) + 1) == sExt) fTab8 = true; for (j = 0; !fTab8 && j < defoptions._length(); j++) if (substr(defoptions[j], lastpos('-', defoptions[j]) + 1) == sExt) fTab8 = true; parse sNewSetup with sPre 'TABS=' sValue ',' sPost; if (fTab8) sNewSetup = sPre 'TABS=+8,' sPost else sNewSetup = sPre 'TABS=+' indent ',' sPost } /* Set indent with tabs flag. */ if (pos('IWT=', sNewSetup) > 0) { parse sNewSetup with sPre 'IWT=' sValue ',' sPost; if (iWithTabs) sNewSetup = sPre 'IWT=1,' sPost else sNewSetup = sPre 'IWT=0,' sPost } /* Do the real changes */ set_name_info(idx, sNewSetup); _config_modify |= CFGMODIFY_DEFDATA; _update_buffers(sExt); } } /** * Takes necessary steps to convert a string to integer. */ static int k_style_emacs_var_integer(_str sVal) { int i = (int)sVal; //say 'k_style_emacs_var_integer('sVal') -> 'i; return (int)sVal; } /** * Sets a Emacs style variable. */ static int k_style_emacs_var(_str sVar, _str sVal) { /* check input. */ if (sVar == '' || sVal == '') return -1; //say 'k_style_emacs_var: 'sVar'='sVal; #if __VERSION__ >= 21.0 /** @todo figure out p_index. */ return 0; #else /* * Unpack the mode style parameters. */ _str sStyle = name_info(_edit_window().p_index); _str sStyleName = p_mode_name; typeless iIndentAmount, fExpansion, iMinAbbrivation, fIndentAfterOpenParen, iBeginEndStyle, fIndent1stLevel, iMainStyle, iSwitchStyle, sRest, sRes0, sRes1; if (sStyleName == 'Slick-C') { parse sStyle with iMinAbbrivation sRes0 iBeginEndStyle fIndent1stLevel sRes1 iSwitchStyle sRest; iIndentAmount = p_SyntaxIndent; } else /* C */ parse sStyle with iIndentAmount fExpansion iMinAbbrivation fIndentAfterOpenParen iBeginEndStyle fIndent1stLevel iMainStyle iSwitchStyle sRest; /* * Process the variable. */ switch (sVar) { case 'mode': case 'Mode': { switch (sVal) { case 'c': case 'C': case 'c++': case 'C++': case 'cpp': case 'CPP': case 'cxx': case 'CXX': p_extension = 'c'; p_mode_name = 'C'; break; case 'e': case 'slick-c': case 'Slick-c': case 'Slick-C': p_extension = 'e'; p_mode_name = 'Slick-C'; break; default: message('emacs mode "'sVal'" is not known to us'); return -3; } break; } /* relevant emacs code: (defconst c-style-alist '(("gnu" (c-basic-offset . 2) (c-comment-only-line-offset . (0 . 0)) (c-offsets-alist . ((statement-block-intro . +) (knr-argdecl-intro . 5) (substatement-open . +) (label . 0) (statement-case-open . +) (statement-cont . +) (arglist-intro . c-lineup-arglist-intro-after-paren) (arglist-close . c-lineup-arglist) (inline-open . 0) (brace-list-open . +) )) (c-special-indent-hook . c-gnu-impose-minimum) (c-block-comment-prefix . "") ) ("k&r" (c-basic-offset . 5) (c-comment-only-line-offset . 0) (c-offsets-alist . ((statement-block-intro . +) (knr-argdecl-intro . 0) (substatement-open . 0) (label . 0) (statement-cont . +) )) ) ("bsd" (c-basic-offset . 8) (c-comment-only-line-offset . 0) (c-offsets-alist . ((statement-block-intro . +) (knr-argdecl-intro . +) (substatement-open . 0) (label . 0) (statement-cont . +) (inline-open . 0) (inexpr-class . 0) )) ) ("stroustrup" (c-basic-offset . 4) (c-comment-only-line-offset . 0) (c-offsets-alist . ((statement-block-intro . +) (substatement-open . 0) (label . 0) (statement-cont . +) )) ) ("whitesmith" (c-basic-offset . 4) (c-comment-only-line-offset . 0) (c-offsets-alist . ((knr-argdecl-intro . +) (label . 0) (statement-cont . +) (substatement-open . +) (block-open . +) (statement-block-intro . c-lineup-whitesmith-in-block) (block-close . c-lineup-whitesmith-in-block) (inline-open . +) (defun-open . +) (defun-block-intro . c-lineup-whitesmith-in-block) (defun-close . c-lineup-whitesmith-in-block) (brace-list-open . +) (brace-list-intro . c-lineup-whitesmith-in-block) (brace-entry-open . c-indent-multi-line-block) (brace-list-close . c-lineup-whitesmith-in-block) (class-open . +) (inclass . c-lineup-whitesmith-in-block) (class-close . +) (inexpr-class . 0) (extern-lang-open . +) (inextern-lang . c-lineup-whitesmith-in-block) (extern-lang-close . +) (namespace-open . +) (innamespace . c-lineup-whitesmith-in-block) (namespace-close . +) )) ) ("ellemtel" (c-basic-offset . 3) (c-comment-only-line-offset . 0) (c-hanging-braces-alist . ((substatement-open before after))) (c-offsets-alist . ((topmost-intro . 0) (topmost-intro-cont . 0) (substatement . +) (substatement-open . 0) (case-label . +) (access-label . -) (inclass . ++) (inline-open . 0) )) ) ("linux" (c-basic-offset . 8) (c-comment-only-line-offset . 0) (c-hanging-braces-alist . ((brace-list-open) (brace-entry-open) (substatement-open after) (block-close . c-snug-do-while))) (c-cleanup-list . (brace-else-brace)) (c-offsets-alist . ((statement-block-intro . +) (knr-argdecl-intro . 0) (substatement-open . 0) (label . 0) (statement-cont . +) )) ) ("python" (indent-tabs-mode . t) (fill-column . 78) (c-basic-offset . 8) (c-offsets-alist . ((substatement-open . 0) (inextern-lang . 0) (arglist-intro . +) (knr-argdecl-intro . +) )) (c-hanging-braces-alist . ((brace-list-open) (brace-list-intro) (brace-list-close) (brace-entry-open) (substatement-open after) (block-close . c-snug-do-while) )) (c-block-comment-prefix . "") ) ("java" (c-basic-offset . 4) (c-comment-only-line-offset . (0 . 0)) ;; the following preserves Javadoc starter lines (c-offsets-alist . ((inline-open . 0) (topmost-intro-cont . +) (statement-block-intro . +) (knr-argdecl-intro . 5) (substatement-open . +) (label . +) (statement-case-open . +) (statement-cont . +) (arglist-intro . c-lineup-arglist-intro-after-paren) (arglist-close . c-lineup-arglist) (access-label . 0) (inher-cont . c-lineup-java-inher) (func-decl-cont . c-lineup-java-throws) )) ) ) */ case 'c-file-style': case 'c-indentation-style': switch (sVal) { case 'bsd': case '"bsd"': case 'BSD': iBeginEndStyle = 1 | (iBeginEndStyle & ~3); p_indent_with_tabs = true; iIndentAmount = 8; p_SyntaxIndent = 8; p_tabs = "+8"; //say 'bsd'; break; case 'k&r': case '"k&r"': case 'K&R': iBeginEndStyle = 0 | (iBeginEndStyle & ~3); p_indent_with_tabs = false; iIndentAmount = 4; p_SyntaxIndent = 4; p_tabs = "+4"; //say 'k&r'; break; case 'linux-c': case '"linux-c"': iBeginEndStyle = 0 | (iBeginEndStyle & ~3); p_indent_with_tabs = true; iIndentAmount = 4; p_SyntaxIndent = 4; p_tabs = "+4"; //say 'linux-c'; break; case 'yet-to-be-found': iBeginEndStyle = 2 | (iBeginEndStyle & ~3); p_indent_with_tabs = false; iIndentAmount = 4; p_SyntaxIndent = 4; p_tabs = "+4"; //say 'todo'; break; default: message('emacs "'sVar'" value "'sVal'" is not known to us.'); return -3; } break; case 'c-label-offset': { int i = k_style_emacs_var_integer(sVal); if (i >= -16 && i <= 16) { if (i == -p_SyntaxIndent) iSwitchStyle = 0; else iSwitchStyle = 1; } break; } case 'indent-tabs-mode': p_indent_with_tabs = sVal == 't'; break; case 'c-indent-level': case 'c-basic-offset': { int i = k_style_emacs_var_integer(sVal); if (i > 0 && i <= 16) { iIndentAmount = i; p_SyntaxIndent = i; } else { message('emacs "'sVar'" value "'sVal'" is out of range.'); return -4; } break; } case 'tab-width': { int i = k_style_emacs_var_integer(sVal); if (i > 0 && i <= 16) p_tabs = '+'i; else { message('emacs "'sVar'" value "'sVal'" is out of range.'); return -4; } break; } case 'nuke-trailing-whitespace-p': { #if 0 _str sName = 'def-koptions-'p_buf_id; int idx = insert_name(sName, MISC_TYPE, "kstyledoc"); if (!idx) idx = find_index(sName, MISC_TYPE); if (idx) { if (sVal == 't') set_name_info(idx, "saveoptions: +S"); else set_name_info(idx, "saveoptions: -S"); say 'sVal=' sVal; } #endif break; } default: message('emacs variable "'sVar'" (value "'sVal'") is unknown to us.'); return -5; } /* * Update the style? */ _str sNewStyle = ""; if (sStyleName == 'Slick-C') sNewStyle = iMinAbbrivation' 'sRes0' 'iBeginEndStyle' 'fIndent1stLevel' 'sRes1' 'iSwitchStyle' 'sRest; else sNewStyle = iIndentAmount' 'fExpansion' 'iMinAbbrivation' 'fIndentAfterOpenParen' 'iBeginEndStyle' 'fIndent1stLevel' 'iMainStyle' 'iSwitchStyle' 'sRest; if ( sNewStyle != "" && sNewStyle != sStyle && sStyleName == p_mode_name) { _str sName = name_name(_edit_window().p_index) //say ' sStyle='sStyle' p_mode_name='p_mode_name; //say 'sNewStyle='sNewStyle' sName='sName; if (pos('kstyledoc-', sName) <= 0) { sName = 'def-kstyledoc-'p_buf_id; int idx = insert_name(sName, MISC_TYPE, "kstyledoc"); if (!idx) idx = find_index(sName, MISC_TYPE); if (idx) { if (!set_name_info(idx, sNewStyle)) _edit_window().p_index = idx; } //say sName'='idx; } else set_name_info(_edit_window().p_index, sNewStyle); } return 0; #endif } /** * Parses a string with emacs variables. * * The variables are separated by new line. Junk at * the start and end of the line is ignored. */ static int k_style_emac_vars(_str sVars) { /* process them line by line */ int iLine = 0; while (sVars != '' && iLine++ < 20) { int iNext, iEnd; iEnd = iNext = pos("\n", sVars); if (iEnd <= 0) iEnd = iNext = length(sVars); else iEnd--; iNext++; sLine = strip(substr(sVars, 1, iEnd), 'B', " \t\n\r"); sVars = strip(substr(sVars, iNext), 'L', " \t\n\r"); //say 'iLine='iLine' sVars='sVars''; //say 'iLine='iLine' sLine='sLine''; if (sLine != '') { rc = pos('[^a-zA-Z0-9-_]*([a-zA-Z0-9-_]+)[ \t]*:[ \t]*([^ \t]*)', sLine, 1, 'U'); //say '0={'pos('S0')','pos('0')',"'substr(sLine,pos('S0'),pos('0'))'"' //say '1={'pos('S1')','pos('1')',"'substr(sLine,pos('S1'),pos('1'))'"' //say '2={'pos('S2')','pos('2')',"'substr(sLine,pos('S2'),pos('2'))'"' //say '3={'pos('S3')','pos('3')',"'substr(sLine,pos('S3'),pos('3'))'"' //say '4={'pos('S4')','pos('4')',"'substr(sLine,pos('S4'),pos('4'))'"' if (rc > 0) k_style_emacs_var(substr(sLine,pos('S1'),pos('1')), substr(sLine,pos('S2'),pos('2'))); } } return 0; } /** * Searches for Emacs style specification for the current document. */ void k_style_load() { /* save the position before we start looking around the file. */ typeless saved_pos; _save_pos2(saved_pos); int rc; /* Check first line. */ top_of_buffer(); _str sLine; get_line(sLine); strip(sLine); if (pos('-*-[ \t]+(.*:.*)[ \t]+-*-', sLine, 1, 'U')) { _str sVars; sVars = substr(sLine, pos('S1'), pos('1')); sVars = translate(sVars, "\n", ";"); k_style_emac_vars(sVars); } /* Look for the "Local Variables:" stuff from the end of the file. */ bottom_of_buffer(); rc = search('Local Variables:[ \t]*\n\om(.*)\ol\n.*End:.*\n', '-EU'); if (!rc) { /* copy the variables out to a buffer. */ _str sVars; sVars = get_text(match_length("1"), match_length("S1")); k_style_emac_vars(sVars); } _restore_pos2(saved_pos); } /** * Callback function for the event of a new buffer. * * This is used to make sure there are no left over per buffer options * hanging around. */ void _buffer_add_kdev(int buf_id) { _str sName = 'def-koptions-'buf_id; int idx = find_index(sName, MISC_TYPE); if (idx) delete_name(idx); //message("_buffer_add_kdev: " idx " name=" sName); sName = 'def-kstyledoc-'buf_id; idx = find_index(sName, MISC_TYPE); if (idx) delete_name(idx); //k_style_load(); } /** * Callback function for the event of quitting a buffer. * * This is used to make sure there are no left over per buffer options * hanging around. */ void _cbquit2_kdev(int buf_id) { _str sName = 'def-koptions-'buf_id; int idx = find_index(sName, MISC_TYPE); if (idx) delete_name(idx); //message("_cbquit2_kdev: " idx " " sName); sName = 'def-kstyledoc-'buf_id; idx = find_index(sName, MISC_TYPE); if (idx) delete_name(idx); } /** * Called to get save options for the current buffer. * * This requires a modified loadsave.e! */ _str _buffer_save_kdev(int buf_id) { _str sRet = "" _str sName = 'def-koptions-'buf_id; int idx = find_index(sName, MISC_TYPE); if (idx) { _str sOptions = strip(name_info(idx)); if (sOptions != "") parse sOptions with . "saveoptions:" sRet . message("_buffer_save_kdev: " idx " " sName " " sOptions); } return sRet; } /** * Command similar to the add() command in math.e, only this * produces hex and doesn't do the multi line stuff. */ _command int k_calc() { _str sLine; filter_init(); typeless rc = filter_get_string(sLine); if (rc == 0) { _str sResultHex; rc = eval_exp(sResultHex, sLine, 16); if (rc == 0) { _str sResultDec; rc = eval_exp(sResultDec, sLine, 10); if (rc == 0) { _end_select(); _insert_text(' = ' :+ sResultHex :+ ' (' :+ sResultDec :+ ')'); return 0; } } } if (isinteger(rc)) message(get_message(rc)); else message(rc); return 1; } /******************************************************************************* * Menu and Menu commands * *******************************************************************************/ #ifdef KDEV_WITH_MENU #if __VERSION__ < 18.0 /* Something with timers are busted, so excusing my code. */ static int iTimer = 0; #endif static int mhkDev = 0; static int mhCode = 0; static int mhDoc = 0; static int mhLic = 0; static int mhPre = 0; /* * Creates the kDev menu. */ static k_menu_create() { # if __VERSION__ < 18.0 /* Something with timers are busted, so excusing my code. */ if (arg(1) == 'timer') _kill_timer(iTimer); # endif menu_handle = _mdi.p_menu_handle; menu_index = find_index(_cur_mdi_menu,oi2type(OI_MENU)); /* * Remove any old menu. */ mhDelete = iPos = 0; index = _menu_find(menu_handle, "kDev", mhDelete, iPos, 'C'); //message("index="index " mhDelete="mhDelete " iPos="iPos); if (index == 0) _menu_delete(mhDelete, iPos); /* * Insert the "kDev" menu. */ mhkDev = _menu_insert(menu_handle, 9, MF_SUBMENU, "&kDev", "", "kDev"); mhCode=_menu_insert(mhkDev, -1, MF_ENABLED | MF_SUBMENU, "Coding &Style", "", "coding"); rc = _menu_insert(mhCode, -1, MF_ENABLED | MF_UNCHECKED, "Braces 2, Syntax Indent 4 (knut)", "k_menu_style Opt2Ind4", "Opt2Ind4"); rc = _menu_insert(mhCode, -1, MF_ENABLED | MF_UNCHECKED, "Braces 2, Syntax Indent 3", "k_menu_style Opt2Ind3", "Opt2Ind3"); rc = _menu_insert(mhCode, -1, MF_ENABLED | MF_UNCHECKED, "Braces 2, Syntax Indent 8", "k_menu_style Opt2Ind8", "Opt2Ind8"); rc = _menu_insert(mhCode, -1, MF_ENABLED | MF_UNCHECKED, "Braces 3, Syntax Indent 4 (giws)", "k_menu_style Opt3Ind4", "Opt3Ind4"); rc = _menu_insert(mhCode, -1, MF_ENABLED | MF_UNCHECKED, "Braces 3, Syntax Indent 3 (giws)", "k_menu_style Opt3Ind3", "Opt3Ind3"); mhDoc= _menu_insert(mhkDev, -1, MF_ENABLED | MF_SUBMENU, "&Documentation", "", "doc"); mhDSJ= _menu_insert(mhDoc, -1, MF_ENABLED | MF_UNCHECKED, "&Javadoc Style", "k_menu_doc_style javadoc", "javadoc"); mhDSL= _menu_insert(mhDoc, -1, MF_GRAYED | MF_UNCHECKED, "&Linux Kernel Style", "k_menu_doc_style linux", "linux"); mhLic= _menu_insert(mhkDev, -1, MF_ENABLED | MF_SUBMENU, "&License", "", "License"); rc = _menu_insert(mhLic, -1, MF_ENABLED | MF_UNCHECKED, "&Odin32", "k_menu_license Odin32", "Odin32"); rc = _menu_insert(mhLic, -1, MF_ENABLED | MF_UNCHECKED, "&GPL", "k_menu_license GPL", "GPL"); rc = _menu_insert(mhLic, -1, MF_ENABLED | MF_UNCHECKED, "&LGPL", "k_menu_license LGPL", "LGPL"); rc = _menu_insert(mhLic, -1, MF_ENABLED | MF_UNCHECKED, "&GPLv3", "k_menu_license GPLv3", "GPLv3"); rc = _menu_insert(mhLic, -1, MF_ENABLED | MF_UNCHECKED, "&LGPLv3", "k_menu_license LGPLv3", "LGPLv3"); rc = _menu_insert(mhLic, -1, MF_ENABLED | MF_UNCHECKED, "&VirtualBox", "k_menu_license VirtualBox", "VirtualBox"); rc = _menu_insert(mhLic, -1, MF_ENABLED | MF_UNCHECKED, "&VirtualBox GPL And CDDL","k_menu_license VirtualBoxGPLAndCDDL", "VirtualBoxGPLAndCDDL"); rc = _menu_insert(mhLic, -1, MF_ENABLED | MF_UNCHECKED, "&Confidential", "k_menu_license Confidential", "Confidential"); rc = _menu_insert(mhLic, -1, MF_ENABLED | MF_UNCHECKED, "&Confidential No Author", "k_menu_license ConfidentialNoAuthor", "ConfidentialNoAuthor"); rc = _menu_insert(mhkDev, -1, MF_ENABLED, "-", "", "dash vars"); rc = _menu_insert(mhkDev, -1, MF_ENABLED, skChange == '' ? '&Change...' : '&Change (' skChange ')...', "k_menu_change", ""); rc = _menu_insert(mhkDev, -1, MF_ENABLED, skProgram == '' ? '&Program...' : '&Program (' skProgram ')...', "k_menu_program", ""); rc = _menu_insert(mhkDev, -1, MF_ENABLED, skCompany == '' ? 'Co&mpany...' : 'Co&mpany (' skCompany ')...', "k_menu_company", ""); rc = _menu_insert(mhkDev, -1, MF_ENABLED, '&User Name (' skUserName ')...', "k_menu_user_name", "username"); rc = _menu_insert(mhkDev, -1, MF_ENABLED, 'User &e-mail (' skUserEmail ')...', "k_menu_user_email", "useremail"); rc = _menu_insert(mhkDev, -1, MF_ENABLED, 'User &Initials (' skUserInitials ')...', "k_menu_user_initials", "userinitials"); rc = _menu_insert(mhkDev, -1, MF_ENABLED, "-", "", "dash preset"); mhPre= _menu_insert(mhkDev, -1, MF_SUBMENU, "P&resets", "", ""); rc = _menu_insert(mhPre, -1, MF_ENABLED, "The Bird", "k_menu_preset javadoc, GPL, Opt2Ind4", "bird"); rc = _menu_insert(mhPre, -1, MF_ENABLED, "kLIBC", "k_menu_preset javadoc, GPL, Opt2Ind4,, kLIBC", "kLIBC"); rc = _menu_insert(mhPre, -1, MF_ENABLED, "kBuild", "k_menu_preset javadoc, GPLv3, Opt2Ind4,, kBuild", "kBuild"); rc = _menu_insert(mhPre, -1, MF_ENABLED, "kStuff", "k_menu_preset javadoc, GPL, Opt2Ind4,, kStuff", "kStuff"); rc = _menu_insert(mhPre, -1, MF_ENABLED, "sun", "k_menu_preset javadoc, ConfidentialNoAuthor, Opt2Ind4, sun", "sun"); rc = _menu_insert(mhPre, -1, MF_ENABLED, "VirtualBox", "k_menu_preset javadoc, VirtualBox, Opt2Ind4, sun", "VirtualBox"); k_menu_doc_style(); k_menu_license(); k_menu_style(); } /** * Change change Id. */ _command k_menu_change() { sRc = show("-modal k_form_simple_input", "Change ID", skChange); if (sRc != "\r") { skChange = sRc; k_menu_create(); } } /** * Change program name. */ _command k_menu_program() { sRc = show("-modal k_form_simple_input", "Program", skProgram); if (sRc != "\r") { skProgram = sRc; k_menu_create(); } } /** * Change company. */ _command k_menu_company() { if (skCompany == '') sRc = show("-modal k_form_simple_input", "Company", 'innotek GmbH'); else sRc = show("-modal k_form_simple_input", "Company", skCompany); if (sRc != "\r") { skCompany = sRc; k_menu_create(); } } /** * Change user name. */ _command k_menu_user_name() { sRc = show("-modal k_form_simple_input", "User Name", skUserName); if (sRc != "\r" && sRc != '') { skUserName = sRc; k_menu_create(); } } /** * Change user email. */ _command k_menu_user_email() { sRc = show("-modal k_form_simple_input", "User e-mail", skUserEmail); if (sRc != "\r" && sRc != '') { skUserEmail = sRc; k_menu_create(); } } /** * Change user initials. */ _command k_menu_user_initials() { sRc = show("-modal k_form_simple_input", "User e-mail", skUserInitials); if (sRc != "\r" && sRc != '') { skUserInitials = sRc; k_menu_create(); } } /** * Checks the correct menu item. */ _command void k_menu_doc_style(_str sNewDocStyle = '') { //say 'sNewDocStyle='sNewDocStyle; if (sNewDocStyle != '') skDocStyle = sNewDocStyle _menu_set_state(mhDoc, "javadoc", MF_UNCHECKED); _menu_set_state(mhDoc, "linux", MF_UNCHECKED | MF_GRAYED); _menu_set_state(mhDoc, skDocStyle, MF_CHECKED); } /** * Checks the correct menu item. */ _command void k_menu_license(_str sNewLicense = '') { //say 'sNewLicense='sNewLicense; if (sNewLicense != '') skLicense = sNewLicense _menu_set_state(mhLic, "Odin32", MF_UNCHECKED); _menu_set_state(mhLic, "GPL", MF_UNCHECKED); _menu_set_state(mhLic, "LGPL", MF_UNCHECKED); _menu_set_state(mhLic, "GPLv3", MF_UNCHECKED); _menu_set_state(mhLic, "LGPLv3", MF_UNCHECKED); _menu_set_state(mhLic, "VirtualBox", MF_UNCHECKED); _menu_set_state(mhLic, "VirtualBoxGPLAndCDDL", MF_UNCHECKED); _menu_set_state(mhLic, "Confidential", MF_UNCHECKED); _menu_set_state(mhLic, "ConfidentialNoAuthor", MF_UNCHECKED); _menu_set_state(mhLic, skLicense, MF_CHECKED); } /** * Check the correct style menu item. */ _command void k_menu_style(_str sNewStyle = '') { //say 'sNewStyle='sNewStyle; _menu_set_state(mhCode, "Opt1Ind4", MF_UNCHECKED); _menu_set_state(mhCode, "Opt1Ind3", MF_UNCHECKED); _menu_set_state(mhCode, "Opt1Ind8", MF_UNCHECKED); _menu_set_state(mhCode, "Opt2Ind4", MF_UNCHECKED); _menu_set_state(mhCode, "Opt2Ind3", MF_UNCHECKED); _menu_set_state(mhCode, "Opt2Ind8", MF_UNCHECKED); _menu_set_state(mhCode, "Opt3Ind4", MF_UNCHECKED); _menu_set_state(mhCode, "Opt3Ind3", MF_UNCHECKED); _menu_set_state(mhCode, "Opt3Ind8", MF_UNCHECKED); if (sNewStyle != '') { int iIndent = (int)substr(sNewStyle, 8, 1); int iBraceStyle = (int)substr(sNewStyle, 4, 1); skCodeStyle = sNewStyle; k_styles_setindent(iIndent, iBraceStyle); k_styles_set(sNewStyle); } _menu_set_state(mhCode, skCodeStyle, MF_CHECKED); } /** * Load a 'preset'. */ _command void k_menu_preset(_str sArgs = '') { parse sArgs with sNewDocStyle ',' sNewLicense ',' sNewStyle ',' sNewCompany ',' sNewProgram ',' sNewChange sNewDocStyle= strip(sNewDocStyle); sNewLicense = strip(sNewLicense); sNewStyle = strip(sNewStyle); sNewCompany = strip(sNewCompany); if (sNewCompany == 'sun') sNewCompany = 'Sun Microsystems, Inc.' sNewProgram = strip(sNewProgram); sNewChange = strip(sNewChange); //say 'k_menu_preset('sNewDocStyle',' sNewLicense',' sNewStyle',' sNewCompany',' sNewProgram')'; k_menu_doc_style(sNewDocStyle); k_menu_license(sNewLicense); k_menu_style(sNewStyle); skCompany = sNewCompany; skProgram = sNewProgram; skChange = sNewChange; k_menu_create(); } /* future ones.. _command k_menu_setcolor() { createMyColorSchemeAndUseIt(); } _command k_menu_setkeys() { rc = load("d:/knut/VSlickMacros/BoxerDef.e"); } _command k_menu_settings() { mySettings(); } */ #endif /* KDEV_WITH_MENU */ /******************************************************************************* * Dialogs * *******************************************************************************/ _form k_form_simple_input { p_backcolor=0x80000005 p_border_style=BDS_DIALOG_BOX p_caption='Simple Input' p_clip_controls=FALSE p_forecolor=0x80000008 p_height=1120 p_width=5020 p_x=6660 p_y=6680 _text_box entText { p_auto_size=TRUE p_backcolor=0x80000005 p_border_style=BDS_FIXED_SINGLE p_completion=NONE_ARG p_font_bold=FALSE p_font_italic=FALSE p_font_name='MS Sans Serif' p_font_size=8 p_font_underline=FALSE p_forecolor=0x80000008 p_height=270 p_tab_index=1 p_tab_stop=TRUE p_text='text' p_width=3180 p_x=1680 p_y=240 p_eventtab2=_ul2_textbox } _label lblLabel { p_alignment=AL_VCENTERRIGHT p_auto_size=FALSE p_backcolor=0x80000005 p_border_style=BDS_NONE p_caption='Label' p_font_bold=FALSE p_font_italic=FALSE p_font_name='MS Sans Serif' p_font_size=8 p_font_underline=FALSE p_forecolor=0x80000008 p_height=240 p_tab_index=2 p_width=1380 p_word_wrap=FALSE p_x=180 p_y=240 } _command_button btnOK { p_cancel=FALSE p_caption='&OK' p_default=TRUE p_font_bold=FALSE p_font_italic=FALSE p_font_name='MS Sans Serif' p_font_size=8 p_font_underline=FALSE p_height=360 p_tab_index=3 p_tab_stop=TRUE p_width=1020 p_x=180 p_y=660 } _command_button btnCancel { p_cancel=TRUE p_caption='Cancel' p_default=FALSE p_font_bold=FALSE p_font_italic=FALSE p_font_name='MS Sans Serif' p_font_size=8 p_font_underline=FALSE p_height=360 p_tab_index=4 p_tab_stop=TRUE p_width=840 p_x=1380 p_y=660 } } defeventtab k_form_simple_input btnOK.on_create(_str sLabel = '', _str sText = '') { p_active_form.p_caption = sLabel; lblLabel.p_caption = sLabel; entText.p_text = sText; } btnOK.lbutton_up() { sText = entText.p_text; p_active_form._delete_window(sText); } btnCancel.lbutton_up() { sText = entText.p_text; p_active_form._delete_window("\r"); } static _str aCLikeIncs[] = { "c", "ansic", "java", "rul", "vera", "cs", "js", "as", "idl", "asm", "s", "imakefile", "rc", "lex", "yacc", "antlr" }; static _str aMyLangIds[] = { "applescript", "ansic", "antlr", "as", #if __VERSION__ < 19.0 "asm", #endif "c", "cs", "csh", "css", "conf", "d", "docbook", "dtd", "e", "html", "idl", "imakefile", "ini", "java", "js", "lex", "mak", "masm", "pas", "phpscript", "powershell", "py", "rexx", "rc", "rul", "tcl", #if __VERSION__ < 19.0 "s", #endif "unixasm", "vbs", "xhtml", "xml", "xmldoc", "xsd", "yacc" }; #if __VERSION__ >= 17.0 # require "se/lang/api/LanguageSettings.e" using se.lang.api.LanguageSettings; #endif #if __VERSION__ >= 16.0 int def_auto_unsurround_block; #endif #if __VERSION__ >= 21.0 int def_gui_find_default; #endif /** * Loads the standard bird settings. */ _command void kdev_load_settings() { typeless nt1; typeless nt2; typeless nt3; typeless nt4; typeless nt5; typeless nt6; typeless i7; _str sRest; _str sTmp; #if __VERSION__ >= 21.0 /* * Load the color profile (was lexer). */ int rc = cload(_strip_filename(__FILE__, 'N') '/user.vlx'); if (rc != 0) messageNwait('cload of user.vlx failed: ' rc); #endif /* * General stuff. */ _default_option('A', '0'); /* ALT menu */ def_alt_menu = 0; _default_option('R', '130'); /* Vertical line in column 130. */ def_mfsearch_init_flags = 2 | 4; /* MFSEARCH_INIT_CURWORD | MFSEARCH_INIT_SELECTION */ def_line_insert = 'B'; /* insert before */ def_updown_col=0; /* cursor movement */ def_cursorwrap=0; /* ditto. */ def_click_past_end=1; /* ditto */ def_start_on_first=1; /* vs A B C; view A. */ def_vc_system='Subversion' /* svn is default version control */ #if __VERSION__ >= 16.0 def_auto_unsurround_block=0; /* Delete line, not block. */ #endif _config_modify_flags(CFGMODIFY_DEFDATA); #if __VERSION__ < 21.0 /* I think this is obsolete... */ def_file_types='All Files (*),' /** @todo make this prettier */ 'C/C++ Files (*.c;*.cc;*.cpp;*.cp;*.cxx;*.c++;*.h;*.hh;*.hpp;*.hxx;*.inl;*.xpm),' 'Assembler (*.s;*.asm;*.mac;*.S),' 'Makefiles (*;*.mak;*.kmk)' 'C# Files (*.cs),' 'Ch Files (*.ch;*.chf;*.chs;*.cpp;*.h),' 'D Files (*.d),' 'Java Files (*.java),' 'HTML Files (*.htm;*.html;*.shtml;*.asp;*.jsp;*.php;*.php3;*.rhtml;*.css),' 'CFML Files (*.cfm;*.cfml;*.cfc),' 'XML Files (*.xml;*.dtd;*.xsd;*.xmldoc;*.xsl;*.xslt;*.ent;*.tld;*.xhtml;*.build;*.plist),' 'XML/SGML DTD Files (*.xsd;*.dtd),' 'XML/JSP TagLib Files (*.tld;*.xml),' 'Objective-C (*.m;*.mm;*.h),' 'IDL Files (*.idl),' 'Ada Files (*.ada;*.adb;*.ads),' 'Applescript Files (*.applescript),' 'Basic Files (*.vb;*.vbs;*.bas;*.frm),' 'Cobol Files (*.cob;*.cbl;*.ocb),' 'JCL Files (*.jcl),' 'JavaScript (*.js;*.ds),' 'ActionScript (*.as),' 'Pascal Files (*.pas;*.dpr),' 'Fortran Files (*.for;*.f),' 'PL/I Files (*.pl1),' 'InstallScript (*.rul),' 'Perl Files (*.pl;*.pm;*.perl;*.plx),' 'Python Files (*.py),' 'Ruby Files (*.rb;*.rby),' 'Java Properties (*.properties),' 'Lua Files (*.lua),' 'Tcl Files (*.tcl;*.tlib;*.itk;*.itcl;*.exp),' 'PV-WAVE (*.pro),' 'Slick-C (*.e;*.sh),' 'SQL Files (*.sql;*.pgsql),' 'SAS Files (*.sas),' 'Text Files (*.txt),' 'Verilog Files (*.v),' 'VHDL Files (*.vhd),' 'SystemVerilog Files (*.sv;*.svh;*.svi),' 'Vera Files (*.vr;*.vrh),' 'Erlang Files (*.erl;*.hrl),' ; #endif /* Make it grok: # include */ for (i = 0; i < aCLikeIncs._length(); i++) replace_def_data("def-":+aCLikeIncs[i]:+"-include", '^[ \t]*(\#[ \t]*include|include|\#[ \t]*line)[ \t]#({#1:i}[ \t]#|)(<{#0[~>]#}>|"{#0[~"]#}")'); replace_def_data("def-m-include", '^[ \t]*(\#[ \t]*include|\#[ \t]*import|include|\#[ \t]*line)[ \t]#({#1:i}[ \t]#|)(<{#0[~>]#}>|"{#0[~"]#}")'); replace_def_data("def-e-include", '^[ \t]*(\#[ \t]*include|\#[ \t]*import|\#[ \t]*require|include)[ \t]#(''{#0[~'']#}''|"{#0[~"]#}")'); /* Replace the default unicode proportional font with the fixed oned. */ _str sCodeFont = _default_font(CFG_SBCS_DBCS_SOURCE_WINDOW); _str sUnicodeFont = _default_font(CFG_UNICODE_SOURCE_WINDOW); if (pos("Default Unicode", sUnicodeFont) > 0 && length(sCodeFont) > 5) _default_font(CFG_UNICODE_SOURCE_WINDOW,sCodeFont); if (machine()=='INTELSOLARIS' || machine()=='SPARCSOLARIS') { _default_font(CFG_MENU,'DejaVu Sans,10,0,0,'); _default_font(CFG_DIALOG,'DejaVu Sans,10,0,,'); _ConfigEnvVar('VSLICKDIALOGFONT','DejaVu Sans,10,0,,'); } /* Not so important. */ int fSearch = 0x400400; /* VSSEARCHFLAG_WRAP | VSSEARCHFLAG_PROMPT_WRAP */; _default_option('S', (_str)fSearch); #if __VERSION__ >= 17.0 /* * Language settings via API. */ int fNewAff = AFF_BEGIN_END_STYLE \ | AFF_INDENT_WITH_TABS \ | AFF_SYNTAX_INDENT \ /*| AFF_TABS*/ \ | AFF_NO_SPACE_BEFORE_PAREN \ | AFF_PAD_PARENS \ | AFF_INDENT_CASE \ | AFF_KEYWORD_CASING \ | AFF_TAG_CASING \ | AFF_ATTRIBUTE_CASING \ | AFF_VALUE_CASING \ /*| AFF_HEX_VALUE_CASING*/; def_adaptive_formatting_flags = ~fNewAff; replace_def_data("def-adaptive-formatting-flags", def_adaptive_formatting_flags); _str sLangId; foreach (sLangId in aMyLangIds) { LanguageSettings.setIndentCaseFromSwitch(sLangId, true); LanguageSettings.setBeginEndStyle(sLangId, BES_BEGIN_END_STYLE_2); LanguageSettings.setIndentWithTabs(sLangId, false); LanguageSettings.setUseAdaptiveFormatting(sLangId, true); LanguageSettings.setAdaptiveFormattingFlags(sLangId, ~fNewAff); LanguageSettings.setSaveStripTrailingSpaces(sLangId, STSO_STRIP_MODIFIED); LanguageSettings.setTabs(sLangId, "8+"); LanguageSettings.setSyntaxIndent(sLangId, 4); /* C/C++ setup, wrap at column 80 not 64. */ # if __VERSION__ >= 21.0 if (_LangGetPropertyInt32(sLangId, VSLANGPROPNAME_CW_FIXED_RIGHT_COLUMN) < 80) _LangSetPropertyInt32(sLangId, VSLANGPROPNAME_CW_FIXED_RIGHT_COLUMN, 80); # else sTmp = LanguageSettings.getCommentWrapOptions(sLangId); if (length(sTmp) > 10) { typeless ntBlockCommentWrap, ntDocCommentWrap, ntFixedWidth; parse sTmp with ntBlockCommentWrap ntDocCommentWrap nt3 nt4 nt5 ntFixedWidth sRest; if ((int)ntFixedWidth < 80) LanguageSettings.setCommentWrapOptions('c', ntBlockCommentWrap:+' ':+ntDocCommentWrap:+' ':+nt3:+' ':+nt4:+' ':+nt5:+' 80 ':+sRest); //replace_def_data("def-comment-wrap-c",'0 1 0 1 1 64 0 0 80 0 80 0 80 0 0 1 '); - default //replace_def_data("def-comment-wrap-c",'0 1 0 1 1 80 0 0 80 0 80 0 80 0 0 0 '); - disabled //replace_def_data("def-comment-wrap-c",'1 1 0 1 1 80 0 0 80 0 80 0 80 0 0 1 '); - enable block comment wrap. } # endif /* set the encoding to UTF-8 without any friggin useless signatures. */ idxExt = name_match('def-lang-for-ext-', 1, MISC_TYPE); while (idxExt > 0) { if (name_info(idxExt) == sLangId) { parse name_name(idxExt) with 'def-lang-for-ext-' auto sExt; sVarName = 'def-encoding-' :+ sExt; idxExtEncoding = find_index(sVarName, MISC_TYPE); if (idxExtEncoding != 0) delete_name(idxExtEncoding); } idxExt = name_match('def-lang-for-ext-', 0, MISC_TYPE); } //replace_def_data('def-encoding-' :+ sLangId, '+futf8 '); idxLangEncoding = find_index('def-encoding-' :+ sLangId, MISC_TYPE); if (idxLangEncoding != 0) delete_name(idxLangEncoding); } replace_def_data('def-encoding', '+futf8 '); LanguageSettings.setIndentWithTabs('mak', true); LanguageSettings.setLexerName('mak', 'kmk'); LanguageSettings.setSyntaxIndent('mak', 8); LanguageSettings.setBeautifierProfileName('c', "bird's Style"); LanguageSettings.setBeautifierProfileName('m', "bird's Objective-C Style"); /* Fix .asm and add .mac, .kmk, .cmd, and .pgsql. */ replace_def_data("def-lang-for-ext-asm", 'masm'); replace_def_data("def-lang-for-ext-mac", 'masm'); replace_def_data("def-lang-for-ext-kmk", 'mak'); replace_def_data("def-lang-for-ext-cmd", 'bat'); replace_def_data("def-lang-for-ext-pgsql", 'plsql'); /* * Change the codehelp default. */ # if __VERSION__ >= 22.0 VSCodeHelpFlags fOldCodeHelp, fNewCodeHelp; # else int fOldCodeHelp, fNewCodeHelp; # endif fOldCodeHelp = def_codehelp_flags; fNewCodeHelp = fOldCodeHelp \ | VSCODEHELPFLAG_AUTO_FUNCTION_HELP \ | VSCODEHELPFLAG_AUTO_LIST_MEMBERS \ | VSCODEHELPFLAG_SPACE_INSERTS_SPACE \ | VSCODEHELPFLAG_INSERT_OPEN_PAREN \ | VSCODEHELPFLAG_DISPLAY_MEMBER_COMMENTS \ | VSCODEHELPFLAG_DISPLAY_FUNCTION_COMMENTS \ | VSCODEHELPFLAG_REPLACE_IDENTIFIER \ | VSCODEHELPFLAG_PRESERVE_IDENTIFIER \ | VSCODEHELPFLAG_AUTO_PARAMETER_COMPLETION \ | VSCODEHELPFLAG_AUTO_LIST_PARAMS \ | VSCODEHELPFLAG_PARAMETER_TYPE_MATCHING \ | VSCODEHELPFLAG_NO_SPACE_AFTER_PAREN \ | VSCODEHELPFLAG_RESERVED_ON \ | VSCODEHELPFLAG_MOUSE_OVER_INFO \ | VSCODEHELPFLAG_AUTO_LIST_VALUES \ | VSCODEHELPFLAG_HIGHLIGHT_TAGS \ | VSCODEHELPFLAG_FIND_TAG_PREFERS_ALTERNATE \ ; fNewCodeHelp &= ~( VSCODEHELPFLAG_SPACE_COMPLETION \ | VSCODEHELPFLAG_AUTO_SYNTAX_HELP \ | VSCODEHELPFLAG_NO_SPACE_AFTER_COMMA \ | VSCODEHELPFLAG_STRICT_LIST_SELECT \ | VSCODEHELPFLAG_AUTO_LIST_VALUES \ | VSCODEHELPFLAG_FIND_TAG_PREFERS_DECLARATION \ | VSCODEHELPFLAG_FIND_TAG_PREFERS_DEFINITION \ | VSCODEHELPFLAG_FIND_TAG_HIDE_OPTIONS \ ); def_codehelp_flags = fNewCodeHelp; foreach (sLangId in aMyLangIds) { _str sVarName = 'def-codehelp-' :+ sLangId; int idxVar = find_index(sVarName, MISC_TYPE); if (idxVar != 0) replace_def_data(sVarName, fNewCodeHelp); } #endif # if __VERSION__ >= 21.0 /* Old style search dialog, not mini. */ def_gui_find_default = 1; # endif _fso_strip_spaces(STSO_STRIP_MODIFIED); /** @todo * - Auto restore clipboards * */ message("Please restart SlickEdit.") } static int kfile_to_array(_str sFile, _str (&asLines)[]) { asLines._makeempty(); int idTempView = 0; int idOrgView = 0; int rc = _open_temp_view(sFile, idTempView, idOrgView); if (!rc) { _GoToROffset(0); /* top of the file. */ int i = 0; do { _str sLine = ''; get_line(sLine); asLines[i] = sLine; i += 1; } while (down() == 0); _delete_temp_view(idTempView); activate_window(idOrgView); } return rc; } _command void kload_files(_str sFile = "file-not-specified.lst") { _str sFileDir = absolute(_strip_filename(sFile, 'NE')); _str aFiles[]; int rc = kfile_to_array(sFile, asFiles); if (rc == 0) { _str sFile; int i; for (i = 0; i < asFiles._length(); i++) { _str sFile = strip(asFiles[i]); if (length(sFile) > 0) { sAbsFile = absolute(sFile, sFileDir); message("Loading \"" :+ sAbsFile :+ "\"..."); //say("sAbsFile=" :+ sAbsFile); edit(sAbsFile); } } } else message("_GetFileContents failed: " :+ rc); } /** * Module initiation. */ definit() { /* do cleanup. */ for (i = 0; i < 999; i++) { index = name_match("def-koptions-", 1 /*find_first*/, MISC_TYPE); if (!index) break; delete_name(index); } /* do init */ k_styles_create(); #ifdef KDEV_WITH_MENU k_menu_create(); # if __VERSION__ < 18.0 /* Something with timers are busted, so excusing my code. */ iTimer = _set_timer(1000, k_menu_create, "timer"); # endif /* createMyColorSchemeAndUseIt();*/ #endif } kbuild-3149/Maintenance.kmk0000644000175000017500000001521613252530251015635 0ustar locutuslocutus# $Id: Maintenance.kmk 2413 2010-09-11 17:43:04Z bird $ ## @file # Maintenance Makefile for kBuild. # # # Copyright (c) 2008-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # DEPTH = . include $(PATH_KBUILD)/header.kmk RMTREE = $(ECHO) todo: $(RM) -Rf RMTREE = rm -Rf SVN = svn TAR = tar GZIP = gzip ifeq ($(strip $(KBUILD_SVN_INFO_KMK)),) $(error wtf? KBUILD_SVN_INFO_KMK is empty!) endif # # Creates the 'all' tarballs. # $(PATH_TARGET)/kBuild-$(KBUILD_VERSION)-all.tar.gz: | $$(dir $$@) $(RM) -f $(PATH_TARGET)/kBuild-$(KBUILD_VERSION)-all.tar $(PATH_TARGET)/kBuild-$(KBUILD_VERSION)-all.tar.gz $(RMTREE) $(PATH_TARGET)/all/ $(MKDIR) -p $(PATH_TARGET)/all/ $(SVN) export . $(PATH_TARGET)/all/kBuild-$(KBUILD_VERSION)/ $(INSTALL) $(KBUILD_SVN_INFO_KMK) \ $(PATH_TARGET)/all/kBuild-$(KBUILD_VERSION)/SvnInfo.kmk $(TAR) cvf $(PATH_TARGET)/kBuild-$(KBUILD_VERSION)-all.tar \ -C $(PATH_TARGET)/all/ kBuild-$(KBUILD_VERSION)/ $(GZIP) -9 $(PATH_TARGET)/kBuild-$(KBUILD_VERSION)-all.tar $(RMTREE) $(PATH_TARGET)/all/kBuild-$(KBUILD_VERSION)/ OTHER_CLEAN += \ $(PATH_TARGET)/kBuild-$(KBUILD_VERSION)-all.tar \ $(PATH_TARGET)/kBuild-$(KBUILD_VERSION)-all.tar.gz $(PATH_TARGET)/kBuild-$(KBUILD_SVN_REV)-all.tar.gz: | $$(dir $$@) $(RM) -f $(PATH_TARGET)/kBuild-$(KBUILD_SVN_REV)-all.tar $(PATH_TARGET)/kBuild-$(KBUILD_SVN_REV)-all.tar.gz $(RMTREE) $(PATH_TARGET)/night-all/ $(MKDIR) -p $(PATH_TARGET)/night-all/ $(SVN) export . $(PATH_TARGET)/night-all/kBuild-$(KBUILD_SVN_REV)/ $(INSTALL) $(KBUILD_SVN_INFO_KMK) \ $(PATH_TARGET)/night-all/kBuild-$(KBUILD_SVN_REV)/SvnInfo.kmk $(TAR) cvf $(PATH_TARGET)/kBuild-$(KBUILD_SVN_REV)-all.tar \ -C $(PATH_TARGET)/night-all/ kBuild-$(KBUILD_SVN_REV)/ $(GZIP) -9 $(PATH_TARGET)/kBuild-$(KBUILD_SVN_REV)-all.tar $(RMTREE) $(PATH_TARGET)/night-all/kBuild-$(KBUILD_SVN_REV)/ OTHER_CLEAN += \ $(PATH_TARGET)/kBuild-$(KBUILD_SVN_REV)-all.tar \ $(PATH_TARGET)/kBuild-$(KBUILD_SVN_REV)-all.tar.gz # # Creates the source tarballs. # $(PATH_TARGET)/kBuild-$(KBUILD_VERSION)-src.tar.gz: | $$(dir $$@) $(RM) -f $(PATH_TARGET)/kBuild-$(KBUILD_VERSION)-src.tar $(PATH_TARGET)/kBuild-$(KBUILD_VERSION)-src.tar.gz $(RMTREE) $(PATH_TARGET)/src/ $(MKDIR) -p $(PATH_TARGET)/src/ $(SVN) export . $(PATH_TARGET)/src/kBuild-$(KBUILD_VERSION)/ $(RMTREE) $(PATH_TARGET)/src/kBuild-$(KBUILD_VERSION)/kBuild/bin $(INSTALL) $(KBUILD_SVN_INFO_KMK) \ $(PATH_TARGET)/src/kBuild-$(KBUILD_VERSION)/SvnInfo.kmk $(TAR) cvf $(PATH_TARGET)/kBuild-$(KBUILD_VERSION)-src.tar \ -C $(PATH_TARGET)/src/ kBuild-$(KBUILD_VERSION)/ $(GZIP) -9 $(PATH_TARGET)/kBuild-$(KBUILD_VERSION)-src.tar $(RMTREE) $(PATH_TARGET)/src/kBuild-$(KBUILD_VERSION)/ OTHER_CLEAN += \ $(PATH_TARGET)/kBuild-$(KBUILD_VERSION)-src.tar \ $(PATH_TARGET)/kBuild-$(KBUILD_VERSION)-src.tar.gz $(PATH_TARGET)/kBuild-$(KBUILD_SVN_REV)-src.tar.gz: | $$(dir $$@) $(RM) -f $(PATH_TARGET)/kBuild-$(KBUILD_SVN_REV)-src.tar $(PATH_TARGET)/kBuild-$(KBUILD_SVN_REV)-src.tar.gz $(RMTREE) $(PATH_TARGET)/night-src/ $(MKDIR) -p $(PATH_TARGET)/night-src/ $(SVN) export . $(PATH_TARGET)/night-src/kBuild-$(KBUILD_SVN_REV)/ $(RMTREE) $(PATH_TARGET)/night-src/kBuild-$(KBUILD_SVN_REV)/kBuild/bin $(INSTALL) $(KBUILD_SVN_INFO_KMK) \ $(PATH_TARGET)/night-src/kBuild-$(KBUILD_SVN_REV)/SvnInfo.kmk $(TAR) cvf $(PATH_TARGET)/kBuild-$(KBUILD_SVN_REV)-src.tar \ -C $(PATH_TARGET)/night-src/ kBuild-$(KBUILD_SVN_REV)/ $(GZIP) -9 $(PATH_TARGET)/kBuild-$(KBUILD_SVN_REV)-src.tar $(RMTREE) $(PATH_TARGET)/night-src/kBuild-$(KBUILD_SVN_REV)/ OTHER_CLEAN += \ $(PATH_TARGET)/kBuild-$(KBUILD_SVN_REV)-src.tar \ $(PATH_TARGET)/kBuild-$(KBUILD_SVN_REV)-src.tar.gz # # Creates the binary tarballs. # $(PATH_TARGET)/kBuild-$(KBUILD_VERSION).tar.gz: | $$(dir $$@) $(RM) -f $(PATH_TARGET)/kBuild-$(KBUILD_VERSION).tar $(PATH_TARGET)/kBuild-$(KBUILD_VERSION).tar.gz $(RMTREE) $(PATH_TARGET)/bin/ $(MKDIR) -p $(PATH_TARGET)/bin/kBuild-$(KBUILD_VERSION)/ $(SVN) export kBuild/ $(PATH_TARGET)/bin/kBuild-$(KBUILD_VERSION)/kBuild/ $(TAR) cvf $(PATH_TARGET)/kBuild-$(KBUILD_VERSION).tar \ -C $(PATH_TARGET)/bin/ kBuild-$(KBUILD_VERSION)/ $(GZIP) -9 $(PATH_TARGET)/kBuild-$(KBUILD_VERSION).tar $(RMTREE) $(PATH_TARGET)/bin/kBuild-$(KBUILD_VERSION)/ OTHER_CLEAN += \ $(PATH_TARGET)/kBuild-$(KBUILD_VERSION).tar \ $(PATH_TARGET)/kBuild-$(KBUILD_VERSION).tar.gz $(PATH_TARGET)/kBuild-$(KBUILD_SVN_REV).tar.gz: | $$(dir $$@) $(RM) -f $(PATH_TARGET)/kBuild-$(KBUILD_SVN_REV).tar $(PATH_TARGET)/kBuild-$(KBUILD_SVN_REV).tar.gz $(RMTREE) $(PATH_TARGET)/night-bin/ $(MKDIR) -p $(PATH_TARGET)/night-bin/kBuild-$(KBUILD_SVN_REV)/ $(SVN) export kBuild/ $(PATH_TARGET)/night-bin/kBuild-$(KBUILD_SVN_REV)/kBuild/ $(TAR) cvf $(PATH_TARGET)/kBuild-$(KBUILD_SVN_REV).tar \ -C $(PATH_TARGET)/night-bin/ kBuild-$(KBUILD_SVN_REV)/ $(GZIP) -9 $(PATH_TARGET)/kBuild-$(KBUILD_SVN_REV).tar $(RMTREE) $(PATH_TARGET)/night-bin/kBuild-$(KBUILD_SVN_REV)/ OTHER_CLEAN += \ $(PATH_TARGET)/kBuild-$(KBUILD_SVN_REV).tar \ $(PATH_TARGET)/kBuild-$(KBUILD_SVN_REV).tar.gz # # Aliases # tarballs: \ $(PATH_TARGET)/kBuild-$(KBUILD_VERSION)-src.tar.gz \ $(PATH_TARGET)/kBuild-$(KBUILD_VERSION).tar.gz \ $(PATH_TARGET)/kBuild-$(KBUILD_SVN_REV).tar.gz \ $(PATH_TARGET)/kBuild-$(KBUILD_SVN_REV)-src.tar.gz release: \ $(PATH_TARGET)/kBuild-$(KBUILD_VERSION).tar.gz \ $(PATH_TARGET)/kBuild-$(KBUILD_VERSION)-src.tar.gz \ $(PATH_TARGET)/kBuild-$(KBUILD_VERSION)-all.tar.gz nightly: \ $(PATH_TARGET)/kBuild-$(KBUILD_SVN_REV).tar.gz \ $(PATH_TARGET)/kBuild-$(KBUILD_SVN_REV)-src.tar.gz \ $(PATH_TARGET)/kBuild-$(KBUILD_SVN_REV)-all.tar.gz .PHONY: tarballs release nightly include $(PATH_KBUILD)/footer.kmk kbuild-3149/src/0000755000175000017500000000000013252530215013471 5ustar locutuslocutuskbuild-3149/src/Makefile.kmk0000644000175000017500000000264213252530215015716 0ustar locutuslocutus# $Id: Makefile.kmk 3013 2016-11-07 11:54:02Z bird $ ## @file # Sub-makefile for the source directory. # # # Copyright (c) 2004-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # SUB_DEPTH = .. include $(KBUILD_PATH)/subheader.kmk include $(PATH_SUB_CURRENT)/lib/Makefile.kmk include $(PATH_SUB_CURRENT)/sed/Makefile.kmk include $(PATH_SUB_CURRENT)/kmk/Makefile.kmk include $(PATH_SUB_CURRENT)/kash/Makefile.kmk include $(PATH_SUB_CURRENT)/kDepPre/Makefile.kmk include $(PATH_SUB_CURRENT)/kObjCache/Makefile.kmk include $(PATH_SUB_CURRENT)/misc/Makefile.kmk ifeq ($(KBUILD_TARGET),win) include $(PATH_SUB_CURRENT)/kLibTweaker/Makefile.kmk include $(PATH_SUB_CURRENT)/kDeDup/Makefile.kmk include $(PATH_SUB_CURRENT)/kWorker/Makefile.kmk endif include $(FILE_KBUILD_SUB_FOOTER) kbuild-3149/src/kObjCache/0000755000175000017500000000000013252530204015300 5ustar locutuslocutuskbuild-3149/src/kObjCache/Makefile.kmk0000644000175000017500000000207313252530204017523 0ustar locutuslocutus# $Id: Makefile.kmk 2618 2012-08-02 03:34:40Z bird $ ## @file # Sub-makefile for kObjCache. # # # Copyright (c) 2007-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # SUB_DEPTH = ../.. include $(PATH_KBUILD)/subheader.kmk PROGRAMS += kObjCache kObjCache_TEMPLATE = BIN kObjCache_DEFS.release = NASSERT kObjCache_SOURCES = kObjCache.c kObjCache_LIBS = \ $(LIB_KDEP) \ $(LIB_KUTIL) include $(KBUILD_PATH)/subfooter.kmk kbuild-3149/src/kObjCache/kObjCache.c0000644000175000017500000047707113252530204017275 0ustar locutuslocutus/* $Id: kObjCache.c 3110 2017-10-20 19:14:56Z bird $ */ /** @file * kObjCache - Object Cache. */ /* * Copyright (c) 2007-2012 knut st. osmundsen * * This file is part of kBuild. * * kBuild 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. * * kBuild 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 kBuild. If not, see * */ /******************************************************************************* * Header Files * *******************************************************************************/ #if 0 # define ELECTRIC_HEAP # include "../kmk/electric.h" # include "../kmk/electric.c" #endif #include #include #include #include #include #include #include #include #include #include #ifndef PATH_MAX # ifdef _MAX_PATH # define PATH_MAX _MAX_PATH /* windows */ # else # define PATH_MAX 4096 /* gnu hurd */ # endif #endif #if defined(__OS2__) || defined(__WIN__) # include # include # ifdef __OS2__ # include # include # include # endif # if defined(_MSC_VER) # include typedef intptr_t pid_t; # endif # ifndef _P_WAIT # define _P_WAIT P_WAIT # endif # ifndef _P_NOWAIT # define _P_NOWAIT P_NOWAIT # endif #else # include # include # include # ifndef O_BINARY # define O_BINARY 0 # endif # ifndef __sun__ # include /* flock */ # endif #endif #if defined(__WIN__) # include # include "quoted_spawn.h" #endif #if defined(__HAIKU__) # include #endif #include "crc32.h" #include "md5.h" #include "kDep.h" /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** The max line length in a cache file. */ #define KOBJCACHE_MAX_LINE_LEN 16384 #if defined(__WIN__) # define PATH_SLASH '\\' #else # define PATH_SLASH '/' #endif #if defined(__OS2__) || defined(__WIN__) # define IS_SLASH(ch) ((ch) == '/' || (ch) == '\\') # define IS_SLASH_DRV(ch) ((ch) == '/' || (ch) == '\\' || (ch) == ':') #else # define IS_SLASH(ch) ((ch) == '/') # define IS_SLASH_DRV(ch) ((ch) == '/') #endif #ifndef STDIN_FILENO # define STDIN_FILENO 0 #endif #ifndef STDOUT_FILENO # define STDOUT_FILENO 1 #endif #ifndef STDERR_FILENO # define STDERR_FILENO 2 #endif #define MY_IS_BLANK(a_ch) ((a_ch) == ' ' || (a_ch) == '\t') #define KOC_BUF_MIN KOC_BUF_ALIGNMENT #define KOC_BUF_INCR KOC_BUF_ALIGNMENT #define KOC_BUF_ALIGNMENT (4U*1024U*1024U) /******************************************************************************* * Global Variables * *******************************************************************************/ /** Whether verbose output is enabled. */ static unsigned g_cVerbosityLevel = 0; /** What to prefix the errors with. */ static char g_szErrorPrefix[128]; /** Read buffer shared by the cache components. */ static char g_szLine[KOBJCACHE_MAX_LINE_LEN + 16]; /** How many times we've moved memory around. */ static size_t g_cMemMoves = 0; /** How much memory we've moved. */ static size_t g_cbMemMoved = 0; /******************************************************************************* * Internal Functions * *******************************************************************************/ static char *MakePathFromDirAndFile(const char *pszName, const char *pszDir); static char *CalcRelativeName(const char *pszPath, const char *pszDir); static FILE *FOpenFileInDir(const char *pszName, const char *pszDir, const char *pszMode); static int UnlinkFileInDir(const char *pszName, const char *pszDir); static int RenameFileInDir(const char *pszOldName, const char *pszNewName, const char *pszDir); static int DoesFileInDirExist(const char *pszName, const char *pszDir); static void *ReadFileInDir(const char *pszName, const char *pszDir, size_t *pcbFile); void FatalMsg(const char *pszFormat, ...) { va_list va; if (g_szErrorPrefix[0]) fprintf(stderr, "%s - fatal error: ", g_szErrorPrefix); else fprintf(stderr, "fatal error: "); va_start(va, pszFormat); vfprintf(stderr, pszFormat, va); va_end(va); } void FatalDie(const char *pszFormat, ...) { va_list va; if (g_szErrorPrefix[0]) fprintf(stderr, "%s - fatal error: ", g_szErrorPrefix); else fprintf(stderr, "fatal error: "); va_start(va, pszFormat); vfprintf(stderr, pszFormat, va); va_end(va); exit(1); } #if 0 /* unused */ static void ErrorMsg(const char *pszFormat, ...) { va_list va; if (g_szErrorPrefix[0]) fprintf(stderr, "%s - error: ", g_szErrorPrefix); else fprintf(stderr, "error: "); va_start(va, pszFormat); vfprintf(stderr, pszFormat, va); va_end(va); } #endif /* unused */ static void InfoMsg(unsigned uLevel, const char *pszFormat, ...) { if (uLevel <= g_cVerbosityLevel) { va_list va; if (g_szErrorPrefix[0]) fprintf(stderr, "%s - info: ", g_szErrorPrefix); else fprintf(stderr, "info: "); va_start(va, pszFormat); vfprintf(stderr, pszFormat, va); va_end(va); } } static void SetErrorPrefix(const char *pszPrefix, ...) { int cch; va_list va; va_start(va, pszPrefix); #if defined(_MSC_VER) || defined(__sun__) cch = vsprintf(g_szErrorPrefix, pszPrefix, va); if (cch >= sizeof(g_szErrorPrefix)) FatalDie("Buffer overflow setting error prefix!\n"); #else vsnprintf(g_szErrorPrefix, sizeof(g_szErrorPrefix), pszPrefix, va); #endif va_end(va); (void)cch; } #ifndef ELECTRIC_HEAP void *xmalloc(size_t cb) { void *pv = malloc(cb); if (!pv) FatalDie("out of memory (%d)\n", (int)cb); return pv; } void *xrealloc(void *pvOld, size_t cb) { void *pv = realloc(pvOld, cb); if (!pv) FatalDie("out of memory (%d)\n", (int)cb); return pv; } char *xstrdup(const char *pszIn) { char *psz; if (pszIn) { psz = strdup(pszIn); if (!psz) FatalDie("out of memory (%d)\n", (int)strlen(pszIn)); } else psz = NULL; return psz; } #endif void *xmallocz(size_t cb) { void *pv = xmalloc(cb); memset(pv, 0, cb); return pv; } /** * Returns a millisecond timestamp. * * @returns Millisecond timestamp. */ static uint32_t NowMs(void) { #if defined(__WIN__) return GetTickCount(); #else int iSavedErrno = errno; struct timeval tv = {0, 0}; gettimeofday(&tv, NULL); errno = iSavedErrno; return tv.tv_sec * 1000 + tv.tv_usec / 1000; #endif } /** * Gets the absolute path * * @returns A new heap buffer containing the absolute path. * @param pszPath The path to make absolute. (Readonly) */ static char *AbsPath(const char *pszPath) { /** @todo this isn't really working as it should... */ char szTmp[PATH_MAX]; #if defined(__OS2__) if ( _fullpath(szTmp, *pszPath ? pszPath : ".", sizeof(szTmp)) && !realpath(pszPath, szTmp)) return xstrdup(pszPath); #elif defined(__WIN__) if (!_fullpath(szTmp, *pszPath ? pszPath : ".", sizeof(szTmp))) return xstrdup(pszPath); #else if (!realpath(pszPath, szTmp)) return xstrdup(pszPath); #endif return xstrdup(szTmp); } /** * Utility function that finds the filename part in a path. * * @returns Pointer to the file name part (this may be ""). * @param pszPath The path to parse. */ static const char *FindFilenameInPath(const char *pszPath) { const char *pszFilename = strchr(pszPath, '\0') - 1; if (pszFilename < pszPath) return pszPath; while ( pszFilename > pszPath && !IS_SLASH_DRV(pszFilename[-1])) pszFilename--; return pszFilename; } /** * Utility function that combines a filename and a directory into a path. * * @returns malloced buffer containing the result. * @param pszName The file name. * @param pszDir The directory path. */ static char *MakePathFromDirAndFile(const char *pszName, const char *pszDir) { size_t cchName = strlen(pszName); size_t cchDir = strlen(pszDir); char *pszBuf = xmalloc(cchName + cchDir + 2); memcpy(pszBuf, pszDir, cchDir); if (cchDir > 0 && !IS_SLASH_DRV(pszDir[cchDir - 1])) pszBuf[cchDir++] = PATH_SLASH; memcpy(pszBuf + cchDir, pszName, cchName + 1); return pszBuf; } /** * Compares two path strings to see if they are identical. * * This doesn't do anything fancy, just the case ignoring and * slash unification. * * @returns 1 if equal, 0 otherwise. * @param pszPath1 The first path. * @param pszPath2 The second path. */ static int ArePathsIdentical(const char *pszPath1, const char *pszPath2) { #if defined(__OS2__) || defined(__WIN__) if (stricmp(pszPath1, pszPath2)) { /* Slashes may differ, compare char by char. */ const char *psz1 = pszPath1; const char *psz2 = pszPath2; for (;;) { if (*psz1 != *psz2) { if ( tolower(*psz1) != tolower(*psz2) && toupper(*psz1) != toupper(*psz2) && *psz1 != '/' && *psz1 != '\\' && *psz2 != '/' && *psz2 != '\\') return 0; } if (!*psz1) break; psz1++; psz2++; } } return 1; #else return !strcmp(pszPath1, pszPath2); #endif } /** * Compares two path strings to see if they are identical. * * This doesn't do anything fancy, just the case ignoring and * slash unification. * * @returns 1 if equal, 0 otherwise. * @param pszPath1 The first path. * @param pszPath2 The second path. * @param cch The number of characters to compare. */ static int ArePathsIdenticalN(const char *pszPath1, const char *pszPath2, size_t cch) { #if defined(__OS2__) || defined(__WIN__) if (strnicmp(pszPath1, pszPath2, cch)) { /* Slashes may differ, compare char by char. */ const char *psz1 = pszPath1; const char *psz2 = pszPath2; for ( ; cch; psz1++, psz2++, cch--) { if (*psz1 != *psz2) { if ( tolower(*psz1) != tolower(*psz2) && toupper(*psz1) != toupper(*psz2) && *psz1 != '/' && *psz1 != '\\' && *psz2 != '/' && *psz2 != '\\') return 0; } } } return 1; #else return !strncmp(pszPath1, pszPath2, cch); #endif } /** * Calculate how to get to pszPath from pszDir. * * @returns The relative path from pszDir to path pszPath. * @param pszPath The path to the object. * @param pszDir The directory it shall be relative to. */ static char *CalcRelativeName(const char *pszPath, const char *pszDir) { char *pszRet = NULL; char *pszAbsPath = NULL; size_t cchDir = strlen(pszDir); /* * This is indeed a bit tricky, so we'll try the easy way first... */ if (ArePathsIdenticalN(pszPath, pszDir, cchDir)) { if (pszPath[cchDir]) pszRet = (char *)pszPath + cchDir; else pszRet = "./"; } else { pszAbsPath = AbsPath(pszPath); if (ArePathsIdenticalN(pszAbsPath, pszDir, cchDir)) { if (pszPath[cchDir]) pszRet = pszAbsPath + cchDir; else pszRet = "./"; } } if (pszRet) { while (IS_SLASH_DRV(*pszRet)) pszRet++; pszRet = xstrdup(pszRet); free(pszAbsPath); return pszRet; } /* * Damn, it's gonna be complicated. Deal with that later. */ FatalDie("complicated relative path stuff isn't implemented yet. sorry.\n"); return NULL; } /** * Utility function that combines a filename and directory and passes it onto fopen. * * @returns fopen return value. * @param pszName The file name. * @param pszDir The directory path. * @param pszMode The fopen mode string. */ static FILE *FOpenFileInDir(const char *pszName, const char *pszDir, const char *pszMode) { char *pszPath = MakePathFromDirAndFile(pszName, pszDir); FILE *pFile = fopen(pszPath, pszMode); free(pszPath); return pFile; } /** * Utility function that combines a filename and directory and passes it onto open. * * @returns open return value. * @param pszName The file name. * @param pszDir The directory path. * @param fFlags The open flags. * @param fCreateMode The file creation mode. */ static int OpenFileInDir(const char *pszName, const char *pszDir, int fFlags, int fCreateMode) { char *pszPath = MakePathFromDirAndFile(pszName, pszDir); int fd = open(pszPath, fFlags, fCreateMode); free(pszPath); return fd; } /** * Deletes a file in a directory. * * @returns whatever unlink returns. * @param pszName The file name. * @param pszDir The directory path. */ static int UnlinkFileInDir(const char *pszName, const char *pszDir) { char *pszPath = MakePathFromDirAndFile(pszName, pszDir); int rc = unlink(pszPath); free(pszPath); return rc; } /** * Renames a file in a directory. * * @returns whatever rename returns. * @param pszOldName The new file name. * @param pszNewName The old file name. * @param pszDir The directory path. */ static int RenameFileInDir(const char *pszOldName, const char *pszNewName, const char *pszDir) { char *pszOldPath = MakePathFromDirAndFile(pszOldName, pszDir); char *pszNewPath = MakePathFromDirAndFile(pszNewName, pszDir); int rc = rename(pszOldPath, pszNewPath); free(pszOldPath); free(pszNewPath); return rc; } /** * Check if a (regular) file exists in a directory. * * @returns 1 if it exists and is a regular file, 0 if not. * @param pszName The file name. * @param pszDir The directory path. */ static int DoesFileInDirExist(const char *pszName, const char *pszDir) { char *pszPath = MakePathFromDirAndFile(pszName, pszDir); struct stat st; int rc = stat(pszPath, &st); free(pszPath); #ifdef S_ISREG return !rc && S_ISREG(st.st_mode); #elif defined(_MSC_VER) return !rc && (st.st_mode & _S_IFMT) == _S_IFREG; #else #error "Port me" #endif } /** * Reads into memory an entire file. * * @returns Pointer to the heap allocation containing the file. * On failure NULL and errno is returned. * @param pszName The file. * @param pszDir The directory the file resides in. * @param pcbFile Where to store the file size. */ static void *ReadFileInDir(const char *pszName, const char *pszDir, size_t *pcbFile) { int SavedErrno; char *pszPath = MakePathFromDirAndFile(pszName, pszDir); int fd = open(pszPath, O_RDONLY | O_BINARY); if (fd >= 0) { off_t cbFile = lseek(fd, 0, SEEK_END); if ( cbFile >= 0 && lseek(fd, 0, SEEK_SET) == 0) { char *pb = malloc(cbFile + 1); if (pb) { if (read(fd, pb, cbFile) == cbFile) { close(fd); pb[cbFile] = '\0'; *pcbFile = (size_t)cbFile; return pb; } SavedErrno = errno; free(pb); } else SavedErrno = ENOMEM; } else SavedErrno = errno; close(fd); } else SavedErrno = errno; free(pszPath); errno = SavedErrno; return NULL; } /** * Creates a directory including all necessary parent directories. * * @returns 0 on success, -1 + errno on failure. * @param pszDir The directory. */ static int MakePath(const char *pszPath) { int iErr = 0; char *pszAbsPath = AbsPath(pszPath); char *psz = pszAbsPath; /* Skip to the root slash (PC). */ while (!IS_SLASH(*psz) && *psz) psz++; /** @todo UNC */ for (;;) { char chSaved; /* skip slashes */ while (IS_SLASH(*psz)) psz++; if (!*psz) break; /* find the next slash or end and terminate the string. */ while (!IS_SLASH(*psz) && *psz) psz++; chSaved = *psz; *psz = '\0'; /* try create the directory, ignore failure because the directory already exists. */ errno = 0; #ifdef _MSC_VER if ( _mkdir(pszAbsPath) && errno != EEXIST) #else if ( mkdir(pszAbsPath, 0777) && errno != EEXIST && errno != ENOSYS /* Solaris nonsensical mkdir crap. */ && errno != EACCES /* Solaris nonsensical mkdir crap. */ ) #endif { iErr = errno; break; } /* restore the slash/terminator */ *psz = chSaved; } free(pszAbsPath); return iErr ? -1 : 0; } /** * Adds the arguments found in the pszCmdLine string to argument vector. * * The parsing of the pszCmdLine string isn't very sophisticated, no * escaping or quotes. * * @param pcArgs Pointer to the argument counter. * @param ppapszArgs Pointer to the argument vector pointer. * @param pszCmdLine The command line to parse and append. * @param pszWedgeArg Argument to put infront of anything found in pszCmdLine. */ static void AppendArgs(int *pcArgs, char ***ppapszArgs, const char *pszCmdLine, const char *pszWedgeArg) { int i; int cExtraArgs; const char *psz; char **papszArgs; /* * Count the new arguments. */ cExtraArgs = 0; psz = pszCmdLine; while (*psz) { while (isspace(*psz)) psz++; if (!psz) break; cExtraArgs++; while (!isspace(*psz) && *psz) psz++; } if (!cExtraArgs) return; /* * Allocate a new vector that can hold the arguments. * (Reallocating might not work since the argv might not be allocated * from the heap but off the stack or somewhere... ) */ i = *pcArgs; *pcArgs = i + cExtraArgs + !!pszWedgeArg; papszArgs = xmalloc((*pcArgs + 1) * sizeof(char *)); *ppapszArgs = memcpy(papszArgs, *ppapszArgs, i * sizeof(char *)); if (pszWedgeArg) papszArgs[i++] = xstrdup(pszWedgeArg); psz = pszCmdLine; while (*psz) { size_t cch; const char *pszEnd; while (isspace(*psz)) psz++; if (!psz) break; pszEnd = psz; while (!isspace(*pszEnd) && *pszEnd) pszEnd++; cch = pszEnd - psz; papszArgs[i] = xmalloc(cch + 1); memcpy(papszArgs[i], psz, cch); papszArgs[i][cch] = '\0'; i++; psz = pszEnd; } papszArgs[i] = NULL; } /** * Dependency collector state. */ typedef struct KOCDEP { /** The statemachine for processing the preprocessed code stream. */ enum KOCDEPSTATE { kOCDepState_Invalid = 0, kOCDepState_NeedNewLine, kOCDepState_NeedHash, kOCDepState_NeedLine_l, kOCDepState_NeedLine_l_HaveSpace, kOCDepState_NeedLine_i, kOCDepState_NeedLine_n, kOCDepState_NeedLine_e, kOCDepState_NeedSpaceBeforeDigit, kOCDepState_NeedFirstDigit, kOCDepState_NeedMoreDigits, kOCDepState_NeedQuote, kOCDepState_NeedEndQuote } enmState; /** Current offset into the filename buffer. */ uint32_t offFilename; /** The amount of space currently allocated for the filename buffer. */ uint32_t cbFilenameAlloced; /** Pointer to the filename buffer. */ char *pszFilename; /** The current dependency file. */ PDEP pCurDep; } KOCDEP; /** Pointer to a KOCDEP. */ typedef KOCDEP *PKOCDEP; /** * Initializes the dependency collector state. * * @param pDepState The dependency collector state. */ static void kOCDepInit(PKOCDEP pDepState) { pDepState->enmState = kOCDepState_NeedHash; pDepState->offFilename = 0; pDepState->cbFilenameAlloced = 0; pDepState->pszFilename = NULL; pDepState->pCurDep = NULL; } /** * Deletes the dependency collector state, releasing all resources. * * @param pDepState The dependency collector state. */ static void kOCDepDelete(PKOCDEP pDepState) { pDepState->enmState = kOCDepState_Invalid; free(pDepState->pszFilename); pDepState->pszFilename = NULL; depCleanup(); } /** * Unescapes a string in place. * * @returns The new string length. * @param psz The string to unescape (input and output). */ static size_t kOCDepUnescape(char *psz) { char *pszSrc = psz; char *pszDst = psz; char ch; while ((ch = *pszSrc++) != '\0') { if (ch == '\\') { char ch2 = *pszSrc; if (ch2) { pszSrc++; ch = ch2; } /* else: cannot happen / just ignore */ } *pszDst++ = ch; } *pszDst = '\0'; return pszDst - psz; } /** * Checks if the character at @a offChar is escaped or not. * * @returns 1 if escaped, 0 if not. * @param pach The string (not terminated). * @param offChar The offset of the character in question. */ static int kOCDepIsEscaped(char *pach, size_t offChar) { while (offChar > 0 && pach[offChar - 1] == '\\') { if ( offChar == 1 || pach[offChar - 2] != '\\') return 1; offChar -= 2; } return 0; } static void kOCDepEnter(PKOCDEP pDepState, const char *pszUnescFilename, size_t cchFilename) { if (cchFilename + 1 >= pDepState->cbFilenameAlloced) { pDepState->cbFilenameAlloced = (cchFilename + 1 + 15) & ~15; pDepState->pszFilename = (char *)xrealloc(pDepState->pszFilename, pDepState->cbFilenameAlloced); } memcpy(pDepState->pszFilename, pszUnescFilename, cchFilename); pDepState->pszFilename[cchFilename] = '\0'; cchFilename = kOCDepUnescape(pDepState->pszFilename); if ( !pDepState->pCurDep || cchFilename != pDepState->pCurDep->cchFilename || strcmp(pDepState->pszFilename, pDepState->pCurDep->szFilename)) pDepState->pCurDep = depAdd(pDepState->pszFilename, cchFilename); } /** * This consumes the preprocessor output and generate dependencies from it. * * The trick is to look at the line directives and which files get listed there. * * @returns The new state. This is a convenience for saving code space and it * isn't really meant to be of any use to the caller. * @param pDepState The dependency collector state. * @param pszInput The input. * @param cchInput The input length. */ static enum KOCDEPSTATE kOCDepConsumer(PKOCDEP pDepState, const char *pszInput, size_t cchInput) { enum KOCDEPSTATE enmState = pDepState->enmState; const char *psz; while (cchInput > 0) { switch (enmState) { case kOCDepState_NeedNewLine: psz = (const char *)memchr(pszInput, '\n', cchInput); if (!psz) return enmState; psz++; cchInput -= psz - pszInput; pszInput = psz; case kOCDepState_NeedHash: while (cchInput > 0 && MY_IS_BLANK(*pszInput)) cchInput--, pszInput++; if (!cchInput) return pDepState->enmState = kOCDepState_NeedHash; if (*pszInput != '#') break; pszInput++; cchInput--; enmState = kOCDepState_NeedLine_l; case kOCDepState_NeedLine_l: case kOCDepState_NeedLine_l_HaveSpace: while (cchInput > 0 && MY_IS_BLANK(*pszInput)) { enmState = kOCDepState_NeedLine_l_HaveSpace; cchInput--, pszInput++; } if (!cchInput) return pDepState->enmState = enmState; if (*pszInput != 'l') { /* # "" */ if (enmState != kOCDepState_NeedLine_l_HaveSpace || !isdigit(*pszInput)) break; pszInput++; cchInput--; enmState = kOCDepState_NeedMoreDigits; continue; } pszInput++; if (!--cchInput) return pDepState->enmState = kOCDepState_NeedLine_i; case kOCDepState_NeedLine_i: if (*pszInput != 'i') break; pszInput++; if (!--cchInput) return pDepState->enmState = kOCDepState_NeedLine_n; case kOCDepState_NeedLine_n: if (*pszInput != 'n') break; pszInput++; if (!--cchInput) return pDepState->enmState = kOCDepState_NeedLine_e; case kOCDepState_NeedLine_e: if (*pszInput != 'e') break; pszInput++; if (!--cchInput) return pDepState->enmState = kOCDepState_NeedSpaceBeforeDigit; case kOCDepState_NeedSpaceBeforeDigit: if (!MY_IS_BLANK(*pszInput)) break; pszInput++; cchInput--; case kOCDepState_NeedFirstDigit: while (cchInput > 0 && MY_IS_BLANK(*pszInput)) cchInput--, pszInput++; if (!cchInput) return pDepState->enmState = kOCDepState_NeedFirstDigit; if (!isdigit(*pszInput)) break; pszInput++; cchInput--; case kOCDepState_NeedMoreDigits: while (cchInput > 0 && isdigit(*pszInput)) cchInput--, pszInput++; if (!cchInput) return pDepState->enmState = kOCDepState_NeedMoreDigits; case kOCDepState_NeedQuote: while (cchInput > 0 && MY_IS_BLANK(*pszInput)) cchInput--, pszInput++; if (!cchInput) return pDepState->enmState = kOCDepState_NeedQuote; if (*pszInput != '"') break; pszInput++; cchInput--; case kOCDepState_NeedEndQuote: { uint32_t off = pDepState->offFilename; for (;;) { char ch; if (!cchInput) { pDepState->offFilename = off; return pDepState->enmState = kOCDepState_NeedEndQuote; } if (off + 1 >= pDepState->cbFilenameAlloced) { if (!pDepState->cbFilenameAlloced) pDepState->cbFilenameAlloced = 32; else pDepState->cbFilenameAlloced *= 2; pDepState->pszFilename = (char *)xrealloc(pDepState->pszFilename, pDepState->cbFilenameAlloced); } pDepState->pszFilename[off] = ch = *pszInput++; cchInput--; if ( ch == '"' && ( off == 0 || pDepState->pszFilename[off - 1] != '\\' || !kOCDepIsEscaped(pDepState->pszFilename, off))) { /* Done, unescape and add the file. */ size_t cchFilename; pDepState->pszFilename[off] = '\0'; cchFilename = kOCDepUnescape(pDepState->pszFilename); if ( !pDepState->pCurDep || cchFilename != pDepState->pCurDep->cchFilename || strcmp(pDepState->pszFilename, pDepState->pCurDep->szFilename)) pDepState->pCurDep = depAdd(pDepState->pszFilename, cchFilename); pDepState->offFilename = 0; break; } off++; } } case kOCDepState_Invalid: assert(0); break; } /* next newline */ enmState = kOCDepState_NeedNewLine; } return pDepState->enmState = enmState; } /** * Writes the dependencies to the specified file. * * @param pDepState The dependency collector state. * @param pszFilename The name of the dependency file. * @param pszObjFile The object file name, relative to @a pszObjDir. * @param pszObjDir The object file directory. * @param fFixCase Whether to fix the case of dependency files. * @param fQuiet Whether to be quiet about the dependencies. * @param fGenStubs Whether to generate stubs. */ static void kOCDepWriteToFile(PKOCDEP pDepState, const char *pszFilename, const char *pszObjFile, const char *pszObjDir, int fFixCase, int fQuiet, int fGenStubs) { char *pszObjFileAbs; char *psz; FILE *pFile = fopen(pszFilename, "w"); if (!pFile) FatalMsg("Failed to open dependency file '%s': %s\n", pszFilename, strerror(errno)); depOptimize(fFixCase, fQuiet, NULL /*pszIgnoredExt*/); /* Make object file name with unix slashes. */ pszObjFileAbs = MakePathFromDirAndFile(pszObjFile, pszObjDir); psz = pszObjFileAbs; while ((psz = strchr(psz, '\\')) != NULL) *psz++ = '/'; fprintf(pFile, "%s:", pszObjFileAbs); free(pszObjFileAbs); depPrint(pFile); if (fGenStubs) depPrintStubs(pFile); if (fclose(pFile) != 0) FatalMsg("Failed to write dependency file '%s': %s\n", pszFilename, strerror(errno)); } /** * Preprocessor output reader state. */ typedef struct KOCCPPRD { /** Pointer to the preprocessor output. */ char *pszBuf; /** Allocated buffer size. */ size_t cbBufAlloc; /** Amount preprocessor output that we've completed optimizations for. */ size_t cchDstOptimized; /** Offset to the start of the unoptimized source. */ size_t offSrcUnoptimized; /** The offset of the next bits to process. */ size_t offSrcCur; /** The offset where to put more raw preprocessor output. */ size_t offSrcRead; /** The line number corresponding to offOptimized. */ uint32_t uOptLineNo; /** The current line number. */ uint32_t uCurLineNo; /** Set if we're done, clear if we're expecting more preprocessor output. */ int fDone; /** The saved character at cchOptimized. */ char chSaved; /** Whether the optimizations are enabled. */ int fOptimize; /** Buffer holding the current file name (unescaped). */ char *pszFileNmBuf; /** The size of the file name buffer. */ size_t cbFileNmBuf; /** The length of the current file string. */ size_t cchCurFileNm; /** Line directive / new line sequence buffer. */ char *pszLineBuf; /** The size of the buffer pointed to by pszLineBuf. */ size_t cbLineBuf; /** Set if we should work the dependency generator as well. */ PKOCDEP pDepState; } KOCCPPRD; /** Pointer to a preprocessor reader state. */ typedef KOCCPPRD *PKOCCPPRD; /** * Allocate the initial C preprocessor output buffer. * * @param pCppRd The C preprocessor reader instance. * @param cbOldCpp The size of the output the last time. This is 0 if * there was not previous run. * @param fOptimize Whether optimizations are enabled. * @param pDepState Pointer to the dependency generator. Must only be set * if @a fOptimize is also set. */ static void kOCCppRdInit(PKOCCPPRD pCppRd, size_t cbOldCpp, int fOptimize, PKOCDEP pDepState) { assert(!pDepState || fOptimize); pCppRd->cbBufAlloc = cbOldCpp ? (cbOldCpp + KOC_BUF_INCR) & ~(KOC_BUF_ALIGNMENT - 1) : KOC_BUF_MIN; pCppRd->pszBuf = xmalloc(pCppRd->cbBufAlloc); pCppRd->cchCurFileNm = 0; pCppRd->cchDstOptimized = 0; pCppRd->offSrcUnoptimized = 0; pCppRd->offSrcCur = 0; pCppRd->offSrcRead = 0; pCppRd->uOptLineNo = 1; pCppRd->uCurLineNo = 1; pCppRd->fDone = 0; pCppRd->chSaved = 0; pCppRd->fOptimize = fOptimize; pCppRd->pszFileNmBuf = NULL; pCppRd->cbFileNmBuf = 0; pCppRd->cchCurFileNm = 0; pCppRd->pszLineBuf = NULL; pCppRd->cbLineBuf = 0; pCppRd->pDepState = pDepState; } static void kOCCppRdDelete(PKOCCPPRD pCppRd) { free(pCppRd->pszBuf); pCppRd->pszBuf = NULL; free(pCppRd->pszFileNmBuf); pCppRd->pszFileNmBuf = NULL; free(pCppRd->pszLineBuf); pCppRd->pszLineBuf = NULL; } /** * Allocate more buffer space for the C preprocessor output. * * @param pCppRd The C preprocessor reader instance. */ static size_t kOCCppRdGrowBuffer(PKOCCPPRD pCppRd) { pCppRd->cbBufAlloc += KOC_BUF_INCR; pCppRd->pszBuf = xrealloc(pCppRd->pszBuf, pCppRd->cbBufAlloc); return pCppRd->cbBufAlloc - pCppRd->offSrcRead; } static size_t kOCCppRdOptInsert(PKOCCPPRD pCppRd, size_t cchSrcReplaced, const char *pchInsert, size_t cchInsert) { size_t offDelta = 0; size_t cchAvail; pCppRd->offSrcUnoptimized += cchSrcReplaced; assert(pCppRd->offSrcUnoptimized <= pCppRd->offSrcCur); cchAvail = pCppRd->offSrcUnoptimized - pCppRd->cchDstOptimized; if (cchAvail < cchInsert) { size_t const cbToMove = pCppRd->offSrcRead - pCppRd->offSrcUnoptimized; assert(cbToMove <= pCppRd->offSrcRead); offDelta = cchInsert - cchAvail; while (pCppRd->offSrcRead + offDelta >= pCppRd->cbBufAlloc) kOCCppRdGrowBuffer(pCppRd); g_cMemMoves++; g_cbMemMoved += cbToMove + 1; memmove(pCppRd->pszBuf + pCppRd->offSrcUnoptimized + offDelta, pCppRd->pszBuf + pCppRd->offSrcUnoptimized, cbToMove + 1); pCppRd->offSrcRead += offDelta; pCppRd->offSrcUnoptimized += offDelta; pCppRd->offSrcCur += offDelta; assert(pCppRd->offSrcRead < 1 || pCppRd->pszBuf[pCppRd->offSrcRead - 1] != '\0'); } memcpy(pCppRd->pszBuf + pCppRd->cchDstOptimized, pchInsert, cchInsert); pCppRd->cchDstOptimized += cchInsert; return offDelta; } static void kOCCppRdOptCommit(PKOCCPPRD pCppRd) { size_t cchToCommit = pCppRd->offSrcCur - pCppRd->offSrcUnoptimized; assert(pCppRd->offSrcUnoptimized <= pCppRd->offSrcCur); if (cchToCommit) { memmove(pCppRd->pszBuf + pCppRd->cchDstOptimized, pCppRd->pszBuf + pCppRd->offSrcUnoptimized, cchToCommit); pCppRd->cchDstOptimized += cchToCommit; pCppRd->offSrcUnoptimized = pCppRd->offSrcCur; } pCppRd->uOptLineNo = pCppRd->uCurLineNo; } static char *kOCCppRdOptGetEol(PKOCCPPRD pCppRd, char *pszCur, size_t cbLeft) { char *pszEol = memchr(pszCur, '\n', cbLeft); if (pszEol) { if (pszCur != pszEol && pszEol[-1] == '\r') pszEol--; } else if (pCppRd->fDone && cbLeft) pszEol = pszCur + cbLeft; return pszEol; } static void kOCCppRdOptSetFile(PKOCCPPRD pCppRd, const char *pchFile, size_t cchFile) { if (cchFile >= pCppRd->cbFileNmBuf) { pCppRd->cbFileNmBuf = (cchFile + 15 + 1) & ~(size_t)15; pCppRd->pszFileNmBuf = xrealloc(pCppRd->pszFileNmBuf, pCppRd->cbFileNmBuf); } memcpy(pCppRd->pszFileNmBuf, pchFile, cchFile); pCppRd->pszFileNmBuf[cchFile] = '\0'; pCppRd->cchCurFileNm = cchFile; } static size_t kOCCppRdOptFmtLine(PKOCCPPRD pCppRd, uint32_t uLine, const char *pchFile, size_t cchFile) { size_t cchUsed; size_t cbNeeded; /* Make sure we've got enough buffer space. */ cbNeeded = sizeof("#line 4888222111 \"\"\n") + cchFile; if (cbNeeded > pCppRd->cbLineBuf) { pCppRd->cbLineBuf = (cbNeeded + 32 + 15) & ~(size_t)15; pCppRd->pszLineBuf = xrealloc(pCppRd->pszLineBuf, pCppRd->cbLineBuf); } /* Do the formatting. */ cchUsed = sprintf(pCppRd->pszLineBuf, "#line %lu", (unsigned long)uLine); if (cchFile) { pCppRd->pszLineBuf[cchUsed++] = ' '; pCppRd->pszLineBuf[cchUsed++] = '"'; memcpy(&pCppRd->pszLineBuf[cchUsed], pchFile, cchFile); cchUsed += cchFile; pCppRd->pszLineBuf[cchUsed++] = '"'; } pCppRd->pszLineBuf[cchUsed++] = '\n'; pCppRd->pszLineBuf[cchUsed] = '\0'; return cchUsed; } static size_t kOCCppRdOptFmtNewLines(PKOCCPPRD pCppRd, uint32_t cNewLines) { if (cNewLines + 1 > pCppRd->cbLineBuf) { pCppRd->cbLineBuf = (cNewLines + 1 + 32 + 15) & ~(size_t)15; pCppRd->pszLineBuf = xrealloc(pCppRd->pszLineBuf, pCppRd->cbLineBuf); } memset(pCppRd->pszLineBuf, '\n', cNewLines); pCppRd->pszLineBuf[cNewLines] = '\0'; return cNewLines; } static size_t kOCCppRdOptFlush(PKOCCPPRD pCppRd, size_t offSrcCur, int fLineDirNext) { size_t offDelta = 0; size_t const offSrcUnoptimized = pCppRd->offSrcUnoptimized; assert(offSrcUnoptimized <= offSrcCur); if (offSrcCur > offSrcUnoptimized) { /* * We've got unflushed whitelines. */ size_t const cchSrcInQuestion = offSrcCur - offSrcUnoptimized; uint32_t const cLinesInQuestion = pCppRd->uCurLineNo - pCppRd->uOptLineNo; size_t cchLineDir; if ( cLinesInQuestion <= 7 || (cchLineDir = kOCCppRdOptFmtLine(pCppRd, pCppRd->uCurLineNo, NULL, 0)) >= cLinesInQuestion) cchLineDir = kOCCppRdOptFmtNewLines(pCppRd, cLinesInQuestion); offDelta = kOCCppRdOptInsert(pCppRd, cchSrcInQuestion, pCppRd->pszLineBuf, cchLineDir); } (void)fLineDirNext; /* Use later if required. */ return offDelta; } static int kOCCppRdOptParseLine(PKOCCPPRD pCppRd, char *pszCur, char *pszEol, uint32_t *puNewLineNo, char **ppszNewFile, size_t *pcchNewFile) { char *psz = pszCur; uint32_t uNewLineNo; int fIsShort; /* * Check if it's a #line directive of some kind and parse it. */ if (*psz != '#') return 0; psz++; fIsShort = MY_IS_BLANK(*psz); while (MY_IS_BLANK(*psz)) psz++; if ( psz[0] == 'l' && psz[1] == 'i' && psz[2] == 'n' && psz[3] == 'e' && MY_IS_BLANK(psz[4]) ) { fIsShort = 0; psz += 5; while (MY_IS_BLANK(*psz)) psz++; } else if (fIsShort && isdigit(*psz)) fIsShort = 1; else return 0; /* Parse the line number. */ if (!isdigit(*psz)) return 0; uNewLineNo = *psz++ - '0'; while (isdigit(*psz)) { uNewLineNo *= 10; uNewLineNo += *psz++ - '0'; } if ( psz != pszEol && !MY_IS_BLANK(*psz)) return 0; /* * The file name part is optional. */ while (MY_IS_BLANK(*psz)) psz++; if ( psz != pszEol && *psz == '"') { *ppszNewFile = ++psz; while ( psz != pszEol && ( *psz != '"' || ( psz[-1] == '\\' && kOCDepIsEscaped(psz, psz - *ppszNewFile)) ) ) psz++; if (psz == pszEol) { /** @todo complain? */ return 0; } *pcchNewFile = psz - *ppszNewFile; do psz++; while (psz != pszEol && MY_IS_BLANK(*psz)); } else { /* No file given => Same as the current. */ *ppszNewFile = pCppRd->cchCurFileNm ? pCppRd->pszFileNmBuf : NULL; *pcchNewFile = pCppRd->cchCurFileNm; } if (psz != pszEol) { /** @todo complain? */ return 0; } *puNewLineNo = uNewLineNo; return 1; } static char *kOCCppRdOptHandleLine(PKOCCPPRD pCppRd, char *pszCur, size_t *pcbLeft, int *pfEmptyLine, char *pszEol) { size_t const offSrcLine = pCppRd->offSrcCur; size_t const cchSrcLine = pszEol - pCppRd->pszBuf - (pCppRd->fOptimize & 2 ? pCppRd->offSrcUnoptimized : pCppRd->offSrcCur); size_t const cbLeftAssert = *pcbLeft; char *pszNewFile; size_t cchNewFile; uint32_t uNewLineNo; assert(*pszEol == '\r' || *pszEol == '\n' || *pszEol == '\0'); /* Advance to the end of the line before we do anything. This can be a little confusing but it saves effort and avoid trouble in the end. */ pCppRd->offSrcCur = pszEol - pCppRd->pszBuf; *pcbLeft -= pszEol - pszCur; assert(*pcbLeft <= cbLeftAssert); (void)cbLeftAssert; /* * Try parse the directive a '#line' one.... */ if (!kOCCppRdOptParseLine(pCppRd, pszCur, pszEol, &uNewLineNo, &pszNewFile, &cchNewFile)) { /* * No line directive. Flush pending optimizations and indicate that * the line isn't empty and needs to be commited at EOL. */ kOCCppRdOptFlush(pCppRd, offSrcLine, 0); *pfEmptyLine = 0; } else { char *pszCurFile = pCppRd->cchCurFileNm ? pCppRd->pszFileNmBuf : NULL; if ( pszNewFile == pszCurFile || ( cchNewFile == pCppRd->cchCurFileNm && !memcmp(pszNewFile, pszCurFile, cchNewFile)) ) { /* * A #line directive specifying the same file. */ if (uNewLineNo >= pCppRd->uCurLineNo) *pfEmptyLine = 1; else { /* * It went backwards, so we need to flush the old section of * the file and emit another directive for starting the new one. */ size_t cchLineDir; if (!(pCppRd->fOptimize & 2)) kOCCppRdOptFlush(pCppRd, offSrcLine, 1); cchLineDir = kOCCppRdOptFmtLine(pCppRd, uNewLineNo, NULL, 0) - 1; /* sans \n */ kOCCppRdOptInsert(pCppRd, cchSrcLine, pCppRd->pszLineBuf, cchLineDir); *pfEmptyLine = 0; } } else { /* * The #line directive changed the file. */ size_t cchLineDir; kOCCppRdOptSetFile(pCppRd, pszNewFile, cchNewFile); /* save to do this early */ if (!(pCppRd->fOptimize & 2)) kOCCppRdOptFlush(pCppRd, offSrcLine, 1); cchLineDir = kOCCppRdOptFmtLine(pCppRd, uNewLineNo, pCppRd->pszFileNmBuf, cchNewFile) - 1; /* sans \n */ kOCCppRdOptInsert(pCppRd, cchSrcLine, pCppRd->pszLineBuf, cchLineDir); if (pCppRd->pDepState) kOCDepEnter(pCppRd->pDepState, pCppRd->pszFileNmBuf, cchNewFile); *pfEmptyLine = 0; } pCppRd->uCurLineNo = uNewLineNo - 1; } return pCppRd->pszBuf + pCppRd->offSrcCur; } static void kOCCppRdOpt(PKOCCPPRD pCppRd) { size_t cch; char *pszEol; char *pszCur = pCppRd->pszBuf + pCppRd->offSrcCur; size_t cbTodo = pCppRd->offSrcRead - pCppRd->offSrcCur; int fEmptyLine = 1; while (cbTodo > 0) { switch (*pszCur) { case ' ': case '\t': break; case '\n': pCppRd->offSrcCur = pszCur - pCppRd->pszBuf + 1; pCppRd->uCurLineNo++; if (!fEmptyLine) kOCCppRdOptCommit(pCppRd); fEmptyLine = 1; break; case '\r': /* "\r\n" -> "\n" */ if (cbTodo <= 1 && !pCppRd->fDone) return; if (pszCur[1] == '\n' && !fEmptyLine) { /* Commit the part up to the '\r' first, replace '\r\n' with '\n'. */ pCppRd->offSrcCur = pszCur - pCppRd->pszBuf; kOCCppRdOptCommit(pCppRd); pCppRd->offSrcCur += 2; kOCCppRdOptInsert(pCppRd, 2, "\n", 1); assert(cbTodo >= 2); cbTodo -= 2; pszCur += 2; fEmptyLine = 1; continue; } break; case '#': pszEol = kOCCppRdOptGetEol(pCppRd, pszCur + 1, cbTodo - 1); if (!pszEol) return; pszCur = kOCCppRdOptHandleLine(pCppRd, pszCur, &cbTodo, &fEmptyLine, pszEol); continue; default: /* * Some non-white stuff encountered, flush pending white * line optimizations and skip to the end of the line. */ fEmptyLine = 0; pszEol = kOCCppRdOptGetEol(pCppRd, pszCur + 1, cbTodo - 1); if (!pszEol) return; cch = pszEol - pszCur; pszCur += kOCCppRdOptFlush(pCppRd, pCppRd->offSrcCur, 0); assert(cch <= cbTodo); cbTodo -= cch; pszCur += cch; continue; } cbTodo--; pszCur++; } } static void kOCCppRdOptFinalize(PKOCCPPRD pCppRd) { pCppRd->fDone = 1; assert(pCppRd->offSrcRead < 1 || pCppRd->pszBuf[pCppRd->offSrcRead - 1] != '\0'); pCppRd->pszBuf[pCppRd->offSrcRead] = '\0'; kOCCppRdOpt(pCppRd); assert(pCppRd->offSrcCur == pCppRd->offSrcRead); kOCCppRdOptFlush(pCppRd, pCppRd->offSrcCur, 0); } /** * Read C preprocessor output from the given file descriptor, optionally * optimzing it. * * @returns Number of bytes read. 0 indicates end of file. * * @param pCppRd The C preprocessor reader instance. * @param fdIn The file descriptor to read the raw preprocessor output * from. * @param ppszRet Where to return the pointer to the output. * * @remarks Won't return on error, calls FatalDie on those occasions. */ static long kOCCppRdRead(PKOCCPPRD pCppRd, int fdIn, const char **ppszRet) { size_t cbLeft; long cbRead; if (pCppRd->fOptimize) { /* * Optimize the C preprocessor output on the way thru. */ size_t const cchOldOptimized = pCppRd->cchDstOptimized; if (pCppRd->chSaved) pCppRd->pszBuf[pCppRd->cchDstOptimized] = pCppRd->chSaved; do { /* Read more raw C preprocessor output. */ cbLeft = pCppRd->cbBufAlloc - pCppRd->offSrcRead; if (cbLeft <= 1) cbLeft = kOCCppRdGrowBuffer(pCppRd); do cbRead = read(fdIn, pCppRd->pszBuf + pCppRd->offSrcRead, (long)(cbLeft - 1)); while (cbRead < 0 && errno == EINTR); if (cbRead < 0) FatalDie("kOCCppRdRead - read(%d,,%ld) failed: %s\n", fdIn, (long)(cbLeft - 1), strerror(errno)); pCppRd->offSrcRead += cbRead; /* Optimize it. */ if (!cbRead) { kOCCppRdOptFinalize(pCppRd); break; } kOCCppRdOpt(pCppRd); } while (pCppRd->cchDstOptimized == cchOldOptimized); *ppszRet = &pCppRd->pszBuf[cchOldOptimized]; pCppRd->chSaved = pCppRd->pszBuf[pCppRd->cchDstOptimized]; pCppRd->pszBuf[pCppRd->cchDstOptimized] = '\0'; cbRead = (long)(pCppRd->cchDstOptimized - cchOldOptimized); } else { /* * Pass thru. */ char *pszBuf; cbLeft = pCppRd->cbBufAlloc - pCppRd->offSrcRead; if (cbLeft <= 1) cbLeft = kOCCppRdGrowBuffer(pCppRd); pszBuf = pCppRd->pszBuf + pCppRd->offSrcRead; do cbRead = read(fdIn, pszBuf, (long)(cbLeft - 1)); while (cbRead < 0 && errno == EINTR); if (cbRead < 0) FatalDie("kOCCppRdRead - read(%d,,%ld) failed: %s\n", fdIn, (long)(cbLeft - 1), strerror(errno)); *ppszRet = pszBuf; pCppRd->offSrcRead += cbRead; pszBuf[cbRead] = '\0'; } return cbRead; } /** * Grabs the output buffer from the C preprocessor reader. * * @param pCppRd The C preprocessor reader instance. * @param ppszRet Where to return the pointer to the output. * @param pcbRet Where to return the size of the output. */ static void kOCCppRdGrabOutput(PKOCCPPRD pCppRd, char **ppszRet, size_t *pcbRet) { assert(pCppRd->offSrcRead < 1 || pCppRd->pszBuf[pCppRd->offSrcRead - 1] != '\0'); *ppszRet = pCppRd->pszBuf; *pcbRet = pCppRd->fOptimize ? pCppRd->cchDstOptimized : pCppRd->offSrcRead; pCppRd->pszBuf = NULL; pCppRd->offSrcRead = 0; } /** A checksum list entry. * We keep a list checksums (of preprocessor output) that matches. * * The matching algorithm doesn't require the preprocessor output to be * indentical, only to produce the same object files. */ typedef struct KOCSUM { /** The next checksum. */ struct KOCSUM *pNext; /** The crc32 checksum. */ uint32_t crc32; /** The MD5 digest. */ unsigned char md5[16]; /** Valid or not. */ unsigned fUsed; } KOCSUM; /** Pointer to a KOCSUM. */ typedef KOCSUM *PKOCSUM; /** Pointer to a const KOCSUM. */ typedef const KOCSUM *PCKOCSUM; /** * Temporary context record used when calculating the checksum of some data. */ typedef struct KOCSUMCTX { /** The MD5 context. */ struct MD5Context MD5Ctx; } KOCSUMCTX; /** Pointer to a check context record. */ typedef KOCSUMCTX *PKOCSUMCTX; /** * Initializes a checksum object with an associated context. * * @param pSum The checksum object. * @param pCtx The checksum context. */ static void kOCSumInitWithCtx(PKOCSUM pSum, PKOCSUMCTX pCtx) { memset(pSum, 0, sizeof(*pSum)); MD5Init(&pCtx->MD5Ctx); } /** * Updates the checksum calculation. * * @param pSum The checksum. * @param pCtx The checksum calcuation context. * @param pvBuf The input data to checksum. * @param cbBuf The size of the input data. */ static void kOCSumUpdate(PKOCSUM pSum, PKOCSUMCTX pCtx, const void *pvBuf, size_t cbBuf) { /* * Take in relativly small chunks to try keep it in the cache. */ const unsigned char *pb = (const unsigned char *)pvBuf; while (cbBuf > 0) { size_t cb = cbBuf >= 128*1024 ? 128*1024 : cbBuf; pSum->crc32 = crc32(pSum->crc32, pb, cb); MD5Update(&pCtx->MD5Ctx, pb, (unsigned)cb); cbBuf -= cb; } } /** * Finalizes a checksum calculation. * * @param pSum The checksum. * @param pCtx The checksum calcuation context. */ static void kOCSumFinalize(PKOCSUM pSum, PKOCSUMCTX pCtx) { MD5Final(&pSum->md5[0], &pCtx->MD5Ctx); pSum->fUsed = 1; } /** * Init a check sum chain head. * * @param pSumHead The checksum head to init. */ static void kOCSumInit(PKOCSUM pSumHead) { memset(pSumHead, 0, sizeof(*pSumHead)); } /** * Parses the given string into a checksum head object. * * @returns 0 on success, -1 on format error. * @param pSumHead The checksum head to init. * @param pszVal The string to initialized it from. */ static int kOCSumInitFromString(PKOCSUM pSumHead, const char *pszVal) { unsigned i; char *pszNext; char *pszMD5; memset(pSumHead, 0, sizeof(*pSumHead)); pszMD5 = strchr(pszVal, ':'); if (pszMD5 == NULL) return -1; *pszMD5++ = '\0'; /* crc32 */ pSumHead->crc32 = (uint32_t)strtoul(pszVal, &pszNext, 16); if (pszNext && *pszNext) return -1; /* md5 */ for (i = 0; i < sizeof(pSumHead->md5) * 2; i++) { unsigned char ch = pszMD5[i]; int x; if ((unsigned char)(ch - '0') <= 9) x = ch - '0'; else if ((unsigned char)(ch - 'a') <= 5) x = ch - 'a' + 10; else if ((unsigned char)(ch - 'A') <= 5) x = ch - 'A' + 10; else return -1; if (!(i & 1)) pSumHead->md5[i >> 1] = x << 4; else pSumHead->md5[i >> 1] |= x; } pSumHead->fUsed = 1; return 0; } /** * Delete a check sum chain. * * @param pSumHead The head of the checksum chain. */ static void kOCSumDeleteChain(PKOCSUM pSumHead) { PKOCSUM pSum = pSumHead->pNext; while (pSum) { void *pvFree = pSum; pSum = pSum->pNext; free(pvFree); } memset(pSumHead, 0, sizeof(*pSumHead)); } /** * Insert a check sum into the chain. * * @param pSumHead The head of the checksum list. * @param pSumAdd The checksum to add (duplicate). */ static void kOCSumAdd(PKOCSUM pSumHead, PCKOCSUM pSumAdd) { if (pSumHead->fUsed) { PKOCSUM pNew = xmalloc(sizeof(*pNew)); *pNew = *pSumAdd; pNew->pNext = pSumHead->pNext; pNew->fUsed = 1; pSumHead->pNext = pNew; } else { *pSumHead = *pSumAdd; pSumHead->pNext = NULL; pSumHead->fUsed = 1; } } /** * Inserts an entrie chain into the given check sum chain. * * @param pSumHead The head of the checksum list. * @param pSumHeadAdd The head of the checksum list to be added. */ static void kOCSumAddChain(PKOCSUM pSumHead, PCKOCSUM pSumHeadAdd) { while (pSumHeadAdd) { kOCSumAdd(pSumHead, pSumHeadAdd); pSumHeadAdd = pSumHeadAdd->pNext; } } /** * Prints the checksum to the specified stream. * * @param pSum The checksum. * @param pFile The output file stream */ static void kOCSumFPrintf(PCKOCSUM pSum, FILE *pFile) { fprintf(pFile, "%#x:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", pSum->crc32, pSum->md5[0], pSum->md5[1], pSum->md5[2], pSum->md5[3], pSum->md5[4], pSum->md5[5], pSum->md5[6], pSum->md5[7], pSum->md5[8], pSum->md5[9], pSum->md5[10], pSum->md5[11], pSum->md5[12], pSum->md5[13], pSum->md5[14], pSum->md5[15]); } /** * Displays the checksum (not chain!) using the InfoMsg() method. * * @param pSum The checksum. * @param uLevel The info message level. * @param pszMsg Message to prefix the info message with. */ static void kOCSumInfo(PCKOCSUM pSum, unsigned uLevel, const char *pszMsg) { InfoMsg(uLevel, "%s: crc32=%#010x md5=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", pszMsg, pSum->crc32, pSum->md5[0], pSum->md5[1], pSum->md5[2], pSum->md5[3], pSum->md5[4], pSum->md5[5], pSum->md5[6], pSum->md5[7], pSum->md5[8], pSum->md5[9], pSum->md5[10], pSum->md5[11], pSum->md5[12], pSum->md5[13], pSum->md5[14], pSum->md5[15]); } /** * Compares two check sum entries. * * @returns 1 if equal, 0 if not equal. * * @param pSum1 The first checksum. * @param pSum2 The second checksum. */ static int kOCSumIsEqual(PCKOCSUM pSum1, PCKOCSUM pSum2) { if (pSum1 == pSum2) return 1; if (!pSum1 || !pSum2) return 0; if (pSum1->crc32 != pSum2->crc32) return 0; if (memcmp(&pSum1->md5[0], &pSum2->md5[0], sizeof(pSum1->md5))) return 0; return 1; } /** * Checks if the specified checksum equals one of the * checksums in the chain. * * @returns 1 if equals one of them, 0 if not. * * @param pSumHead The checksum chain too look in. * @param pSum The checksum to look for. * @todo ugly name. fix. */ static int kOCSumHasEqualInChain(PCKOCSUM pSumHead, PCKOCSUM pSum) { for (; pSumHead; pSumHead = pSumHead->pNext) { if (pSumHead == pSum) return 1; if (pSumHead->crc32 != pSum->crc32) continue; if (memcmp(&pSumHead->md5[0], &pSum->md5[0], sizeof(pSumHead->md5))) continue; return 1; } return 0; } /** * Checks if the checksum (chain) empty. * * @returns 1 if empty, 0 if it there is one or more checksums. * @param pSum The checksum to test. */ static int kOCSumIsEmpty(PCKOCSUM pSum) { return !pSum->fUsed; } /** * The representation of a cache entry. */ typedef struct KOCENTRY { /** The name of the cache entry. */ const char *pszName; /** The dir that all other names are relative to. */ char *pszDir; /** The absolute path. */ char *pszAbsPath; /** Set if the object needs to be (re)compiled. */ unsigned fNeedCompiling; /** Whether the preprocessor runs in piped mode. If clear it's file * mode (it could be redirected stdout, but that's essentially the * same from our point of view). */ unsigned fPipedPreComp; /** Whether the compiler runs in piped mode (preprocessor output on stdin). */ unsigned fPipedCompile; /** The name of the pipe that we're feeding the preprocessed output to the * compiler via. This is a Windows thing. */ char *pszNmPipeCompile; /** Name of the dependency file (generated from #line statements in the * preprocessor output). */ char *pszMakeDepFilename; /** Whether to fix the case of the make depedencies. */ int fMakeDepFixCase; /** Whether to do the make dependencies quietly. */ int fMakeDepQuiet; /** Whether to generate stubs for headers files. */ int fMakeDepGenStubs; /** The dependency collector state. */ KOCDEP DepState; /** Whether the optimizations are enabled. */ int fOptimizeCpp; /** Cache entry key that's used for some quick digest validation. */ uint32_t uKey; /** The file data. */ struct KOCENTRYDATA { /** The name of file containing the preprocessor output. */ char *pszCppName; /** Pointer to the preprocessor output. */ char *pszCppMapping; /** The size of the preprocessor output. 0 if not determined. */ size_t cbCpp; /** The preprocessor output checksums that will produce the cached object. */ KOCSUM SumHead; /** The number of milliseconds spent precompiling. */ uint32_t cMsCpp; /** The object filename (relative to the cache file). */ char *pszObjName; /** The compile argument vector used to build the object. */ char **papszArgvCompile; /** The size of the compile */ unsigned cArgvCompile; /** The checksum of the compiler argument vector. */ KOCSUM SumCompArgv; /** The number of milliseconds spent compiling. */ uint32_t cMsCompile; /** @todo need a list of additional output files for MSC. */ /** @todo need compiler output (warnings). */ /** The target os/arch identifier. */ char *pszTarget; } /** The old data.*/ Old, /** The new data. */ New; } KOCENTRY; /** Pointer to a KOCENTRY. */ typedef KOCENTRY *PKOCENTRY; /** Pointer to a const KOCENTRY. */ typedef const KOCENTRY *PCKOCENTRY; /** * Creates a cache entry for the given cache file name. * * @returns Pointer to a cache entry. * @param pszFilename The cache file name. */ static PKOCENTRY kOCEntryCreate(const char *pszFilename) { PKOCENTRY pEntry; size_t off; /* * Allocate an empty entry. */ pEntry = xmallocz(sizeof(*pEntry)); kOCDepInit(&pEntry->DepState); kOCSumInit(&pEntry->New.SumHead); kOCSumInit(&pEntry->Old.SumHead); kOCSumInit(&pEntry->New.SumCompArgv); kOCSumInit(&pEntry->Old.SumCompArgv); /* * Setup the directory and cache file name. */ pEntry->pszAbsPath = AbsPath(pszFilename); pEntry->pszName = FindFilenameInPath(pEntry->pszAbsPath); off = pEntry->pszName - pEntry->pszAbsPath; if (!off) FatalDie("Failed to find abs path for '%s'!\n", pszFilename); pEntry->pszDir = xmalloc(off); memcpy(pEntry->pszDir, pEntry->pszAbsPath, off - 1); pEntry->pszDir[off - 1] = '\0'; return pEntry; } /** * Destroys the cache entry freeing up all it's resources. * * @param pEntry The entry to free. */ static void kOCEntryDestroy(PKOCENTRY pEntry) { /** @todo free pEntry->pszName? */ free(pEntry->pszDir); free(pEntry->pszAbsPath); free(pEntry->pszNmPipeCompile); free(pEntry->pszMakeDepFilename); kOCDepDelete(&pEntry->DepState); kOCSumDeleteChain(&pEntry->New.SumHead); kOCSumDeleteChain(&pEntry->Old.SumHead); kOCSumDeleteChain(&pEntry->New.SumCompArgv); kOCSumDeleteChain(&pEntry->Old.SumCompArgv); free(pEntry->New.pszCppName); free(pEntry->Old.pszCppName); free(pEntry->New.pszCppMapping); free(pEntry->Old.pszCppMapping); free(pEntry->New.pszObjName); free(pEntry->Old.pszObjName); free(pEntry->New.pszTarget); free(pEntry->Old.pszTarget); while (pEntry->New.cArgvCompile > 0) free(pEntry->New.papszArgvCompile[--pEntry->New.cArgvCompile]); while (pEntry->Old.cArgvCompile > 0) free(pEntry->Old.papszArgvCompile[--pEntry->Old.cArgvCompile]); free(pEntry->New.papszArgvCompile); free(pEntry->Old.papszArgvCompile); free(pEntry); } /** * Calculates the checksum of an compiler argument vector. * * @param pEntry The cache entry. * @param papszArgv The argument vector. * @param cArgc The number of entries in the vector. * @param pszIgnorePath1 Path to ignore when encountered at the end of * arguments. (Not quite safe for simple file names, * but what the heck.) * @param pszIgnorePath2 Path to ignore when encountered at the end of * arguments. (Not quite safe for simple file names, * but what the heck.) * @param pSum Where to store the check sum. */ static void kOCEntryCalcArgvSum(PKOCENTRY pEntry, const char * const *papszArgv, unsigned cArgc, const char *pszIgnorePath1, const char *pszIgnorePath2, PKOCSUM pSum) { size_t cchIgnorePath1 = strlen(pszIgnorePath1); size_t cchIgnorePath2 = pszIgnorePath2 ? strlen(pszIgnorePath2) : ~(size_t)0; KOCSUMCTX Ctx; unsigned i; kOCSumInitWithCtx(pSum, &Ctx); for (i = 0; i < cArgc; i++) { size_t cch = strlen(papszArgv[i]); if ( ( cch < cchIgnorePath1 || !ArePathsIdenticalN(papszArgv[i] + cch - cchIgnorePath1, pszIgnorePath1, cch)) && ( cch < cchIgnorePath2 || !ArePathsIdenticalN(papszArgv[i] + cch - cchIgnorePath2, pszIgnorePath2, cch)) ) kOCSumUpdate(pSum, &Ctx, papszArgv[i], cch + 1); } kOCSumFinalize(pSum, &Ctx); (void)pEntry; } /** * Reads and parses the cache file. * * @param pEntry The entry to read it into. */ static void kOCEntryRead(PKOCENTRY pEntry) { FILE *pFile; pFile = FOpenFileInDir(pEntry->pszName, pEntry->pszDir, "rb"); if (pFile) { InfoMsg(4, "reading cache entry...\n"); /* * Check the magic. */ if ( !fgets(g_szLine, sizeof(g_szLine), pFile) || ( strcmp(g_szLine, "magic=kObjCacheEntry-v0.1.0\n") && strcmp(g_szLine, "magic=kObjCacheEntry-v0.1.1\n")) ) { InfoMsg(2, "bad cache file (magic)\n"); pEntry->fNeedCompiling = 1; } else { /* * Parse the rest of the file (relaxed order). */ unsigned i; int fBad = 0; int fBadBeforeMissing = 1; while (fgets(g_szLine, sizeof(g_szLine), pFile)) { char *pszNl; char *pszVal; /* Split the line and drop the trailing newline. */ pszVal = strchr(g_szLine, '='); if ((fBad = pszVal == NULL)) break; *pszVal++ = '\0'; pszNl = strchr(pszVal, '\n'); if (pszNl) *pszNl = '\0'; /* string case on variable name */ if (!strcmp(g_szLine, "obj")) { if ((fBad = pEntry->Old.pszObjName != NULL)) break; pEntry->Old.pszObjName = xstrdup(pszVal); } else if (!strcmp(g_szLine, "cpp")) { if ((fBad = pEntry->Old.pszCppName != NULL)) break; pEntry->Old.pszCppName = xstrdup(pszVal); } else if (!strcmp(g_szLine, "cpp-size")) { char *pszNext; if ((fBad = pEntry->Old.cbCpp != 0)) break; pEntry->Old.cbCpp = strtoul(pszVal, &pszNext, 0); if ((fBad = pszNext && *pszNext)) break; } else if (!strcmp(g_szLine, "cpp-sum")) { KOCSUM Sum; if ((fBad = kOCSumInitFromString(&Sum, pszVal))) break; kOCSumAdd(&pEntry->Old.SumHead, &Sum); } else if (!strcmp(g_szLine, "cpp-ms")) { char *pszNext; if ((fBad = pEntry->Old.cMsCpp != 0)) break; pEntry->Old.cMsCpp = strtoul(pszVal, &pszNext, 0); if ((fBad = pszNext && *pszNext)) break; } else if (!strcmp(g_szLine, "cc-argc")) { if ((fBad = pEntry->Old.papszArgvCompile != NULL)) break; pEntry->Old.cArgvCompile = atoi(pszVal); /* if wrong, we'll fail below. */ pEntry->Old.papszArgvCompile = xmallocz((pEntry->Old.cArgvCompile + 1) * sizeof(pEntry->Old.papszArgvCompile[0])); } else if (!strncmp(g_szLine, "cc-argv-#", sizeof("cc-argv-#") - 1)) { char *pszNext; unsigned iArg = strtoul(&g_szLine[sizeof("cc-argv-#") - 1], &pszNext, 0); if ((fBad = iArg >= pEntry->Old.cArgvCompile || pEntry->Old.papszArgvCompile[iArg] || (pszNext && *pszNext))) break; pEntry->Old.papszArgvCompile[iArg] = xstrdup(pszVal); } else if (!strcmp(g_szLine, "cc-argv-sum")) { if ((fBad = !kOCSumIsEmpty(&pEntry->Old.SumCompArgv))) break; if ((fBad = kOCSumInitFromString(&pEntry->Old.SumCompArgv, pszVal))) break; } else if (!strcmp(g_szLine, "cc-ms")) { char *pszNext; if ((fBad = pEntry->Old.cMsCompile != 0)) break; pEntry->Old.cMsCompile = strtoul(pszVal, &pszNext, 0); if ((fBad = pszNext && *pszNext)) break; } else if (!strcmp(g_szLine, "target")) { if ((fBad = pEntry->Old.pszTarget != NULL)) break; pEntry->Old.pszTarget = xstrdup(pszVal); } else if (!strcmp(g_szLine, "key")) { char *pszNext; if ((fBad = pEntry->uKey != 0)) break; pEntry->uKey = strtoul(pszVal, &pszNext, 0); if ((fBad = pszNext && *pszNext)) break; } else if (!strcmp(g_szLine, "the-end")) { fBadBeforeMissing = fBad = strcmp(pszVal, "fine"); break; } else { fBad = 1; break; } } /* parse loop */ /* * Did we find everything and does it add up correctly? */ if (!fBad && fBadBeforeMissing) { InfoMsg(2, "bad cache file (no end)\n"); fBad = 1; } else { fBadBeforeMissing = fBad; if ( !fBad && ( !pEntry->Old.papszArgvCompile || !pEntry->Old.pszObjName || !pEntry->Old.pszCppName || kOCSumIsEmpty(&pEntry->Old.SumHead))) fBad = 1; if (!fBad) for (i = 0; i < pEntry->Old.cArgvCompile; i++) if ((fBad = !pEntry->Old.papszArgvCompile[i])) break; if (!fBad) { KOCSUM Sum; kOCEntryCalcArgvSum(pEntry, (const char * const *)pEntry->Old.papszArgvCompile, pEntry->Old.cArgvCompile, pEntry->Old.pszObjName, pEntry->Old.pszCppName, &Sum); fBad = !kOCSumIsEqual(&pEntry->Old.SumCompArgv, &Sum); } if (fBad) InfoMsg(2, "bad cache file (%s)\n", fBadBeforeMissing ? g_szLine : "missing stuff"); else if (ferror(pFile)) { InfoMsg(2, "cache file read error\n"); fBad = 1; } /* * Verify the existance of the object file. */ if (!fBad) { struct stat st; char *pszPath = MakePathFromDirAndFile(pEntry->Old.pszObjName, pEntry->pszDir); if (stat(pszPath, &st) != 0) { InfoMsg(2, "failed to stat object file: %s\n", strerror(errno)); fBad = 1; } else { /** @todo verify size and the timestamp. */ } } } pEntry->fNeedCompiling = fBad; } fclose(pFile); } else { InfoMsg(2, "no cache file\n"); pEntry->fNeedCompiling = 1; } } /** * Writes the cache file. * * @param pEntry The entry to write. */ static void kOCEntryWrite(PKOCENTRY pEntry) { FILE *pFile; PCKOCSUM pSum; unsigned i; InfoMsg(4, "writing cache entry '%s'...\n", pEntry->pszName); pFile = FOpenFileInDir(pEntry->pszName, pEntry->pszDir, "wb"); if (!pFile) FatalDie("Failed to open '%s' in '%s': %s\n", pEntry->pszName, pEntry->pszDir, strerror(errno)); #define CHECK_LEN(expr) \ do { int cch = expr; if (cch >= KOBJCACHE_MAX_LINE_LEN) FatalDie("Line too long: %d (max %d)\nexpr: %s\n", cch, KOBJCACHE_MAX_LINE_LEN, #expr); } while (0) fprintf(pFile, "magic=kObjCacheEntry-v0.1.1\n"); CHECK_LEN(fprintf(pFile, "target=%s\n", pEntry->New.pszTarget ? pEntry->New.pszTarget : pEntry->Old.pszTarget)); CHECK_LEN(fprintf(pFile, "key=%lu\n", (unsigned long)pEntry->uKey)); CHECK_LEN(fprintf(pFile, "obj=%s\n", pEntry->New.pszObjName ? pEntry->New.pszObjName : pEntry->Old.pszObjName)); CHECK_LEN(fprintf(pFile, "cpp=%s\n", pEntry->New.pszCppName ? pEntry->New.pszCppName : pEntry->Old.pszCppName)); CHECK_LEN(fprintf(pFile, "cpp-size=%lu\n", (unsigned long)(pEntry->New.pszCppName ? pEntry->New.cbCpp : pEntry->Old.cbCpp))); CHECK_LEN(fprintf(pFile, "cpp-ms=%lu\n", (unsigned long)(pEntry->New.pszCppName ? pEntry->New.cMsCpp : pEntry->Old.cMsCpp))); CHECK_LEN(fprintf(pFile, "cc-ms=%lu\n", (unsigned long)(pEntry->New.pszCppName ? pEntry->New.cMsCompile : pEntry->Old.cMsCompile))); if (!kOCSumIsEmpty(&pEntry->New.SumCompArgv)) { CHECK_LEN(fprintf(pFile, "cc-argc=%u\n", pEntry->New.cArgvCompile)); for (i = 0; i < pEntry->New.cArgvCompile; i++) CHECK_LEN(fprintf(pFile, "cc-argv-#%u=%s\n", i, pEntry->New.papszArgvCompile[i])); fprintf(pFile, "cc-argv-sum="); kOCSumFPrintf(&pEntry->New.SumCompArgv, pFile); } else { CHECK_LEN(fprintf(pFile, "cc-argc=%u\n", pEntry->Old.cArgvCompile)); for (i = 0; i < pEntry->Old.cArgvCompile; i++) CHECK_LEN(fprintf(pFile, "cc-argv-#%u=%s\n", i, pEntry->Old.papszArgvCompile[i])); fprintf(pFile, "cc-argv-sum="); kOCSumFPrintf(&pEntry->Old.SumCompArgv, pFile); } for (pSum = !kOCSumIsEmpty(&pEntry->New.SumHead) ? &pEntry->New.SumHead : &pEntry->Old.SumHead; pSum; pSum = pSum->pNext) { fprintf(pFile, "cpp-sum="); kOCSumFPrintf(pSum, pFile); } fprintf(pFile, "the-end=fine\n"); #undef CHECK_LEN /* * Flush the file and check for errors. * On failure delete the file so we won't be seeing any invalid * files the next time or upset make with new timestamps. */ errno = 0; if ( fflush(pFile) < 0 || ferror(pFile)) { int iErr = errno; fclose(pFile); UnlinkFileInDir(pEntry->pszName, pEntry->pszDir); FatalDie("Stream error occured while writing '%s' in '%s': %s\n", pEntry->pszName, pEntry->pszDir, strerror(iErr)); } fclose(pFile); } /** * Checks that the read cache entry is valid. * It sets fNeedCompiling if it isn't. * * @returns 1 valid, 0 invalid. * @param pEntry The cache entry. */ static int kOCEntryCheck(PKOCENTRY pEntry) { return !pEntry->fNeedCompiling; } /** * Sets the object name and compares it with the old name if present. * * @param pEntry The cache entry. * @param pszObjName The new object name. */ static void kOCEntrySetCompileObjName(PKOCENTRY pEntry, const char *pszObjName) { assert(!pEntry->New.pszObjName); pEntry->New.pszObjName = CalcRelativeName(pszObjName, pEntry->pszDir); if ( !pEntry->fNeedCompiling && ( !pEntry->Old.pszObjName || strcmp(pEntry->New.pszObjName, pEntry->Old.pszObjName))) { InfoMsg(2, "object file name differs\n"); pEntry->fNeedCompiling = 1; } if ( !pEntry->fNeedCompiling && !DoesFileInDirExist(pEntry->New.pszObjName, pEntry->pszDir)) { InfoMsg(2, "object file doesn't exist\n"); pEntry->fNeedCompiling = 1; } } /** * Set the new compiler args, calc their checksum, and comparing them with any old ones. * * @param pEntry The cache entry. * @param papszArgvCompile The new argument vector for compilation. * @param cArgvCompile The number of arguments in the vector. * * @remark Must call kOCEntrySetCompileObjName before this function! */ static void kOCEntrySetCompileArgv(PKOCENTRY pEntry, const char * const *papszArgvCompile, unsigned cArgvCompile) { unsigned i; /* call me only once! */ assert(!pEntry->New.cArgvCompile); /* call kOCEntrySetCompilerObjName first! */ assert(pEntry->New.pszObjName); /* * Copy the argument vector and calculate the checksum. */ pEntry->New.cArgvCompile = cArgvCompile; pEntry->New.papszArgvCompile = xmalloc((cArgvCompile + 1) * sizeof(pEntry->New.papszArgvCompile[0])); for (i = 0; i < cArgvCompile; i++) pEntry->New.papszArgvCompile[i] = xstrdup(papszArgvCompile[i]); pEntry->New.papszArgvCompile[i] = NULL; /* for exev/spawnv */ kOCEntryCalcArgvSum(pEntry, papszArgvCompile, cArgvCompile, pEntry->New.pszObjName, pEntry->New.pszCppName, &pEntry->New.SumCompArgv); kOCSumInfo(&pEntry->New.SumCompArgv, 4, "comp-argv"); /* * Compare with the old argument vector. */ if ( !pEntry->fNeedCompiling && !kOCSumIsEqual(&pEntry->New.SumCompArgv, &pEntry->Old.SumCompArgv)) { InfoMsg(2, "compiler args differs\n"); pEntry->fNeedCompiling = 1; } } /** * Sets the arch/os target and compares it with the old name if present. * * @param pEntry The cache entry. * @param pszObjName The new object name. */ static void kOCEntrySetTarget(PKOCENTRY pEntry, const char *pszTarget) { assert(!pEntry->New.pszTarget); pEntry->New.pszTarget = xstrdup(pszTarget); if ( !pEntry->fNeedCompiling && ( !pEntry->Old.pszTarget || strcmp(pEntry->New.pszTarget, pEntry->Old.pszTarget))) { InfoMsg(2, "target differs\n"); pEntry->fNeedCompiling = 1; } } /** * Sets the preprocessor output filename. We don't generally care if this * matches the old name or not. * * @param pEntry The cache entry. * @param pszCppName The preprocessor output filename. */ static void kOCEntrySetCppName(PKOCENTRY pEntry, const char *pszCppName) { assert(!pEntry->New.pszCppName); pEntry->New.pszCppName = CalcRelativeName(pszCppName, pEntry->pszDir); } /** * Sets the piped mode of the preprocessor and compiler. * * @param pEntry The cache entry. * @param fRedirPreCompStdOut Whether the preprocessor is in piped mode. * @param fRedirCompileStdIn Whether the compiler is in piped mode. * @param pszNmPipeCompile The name of the named pipe to use to feed * the microsoft compiler. */ static void kOCEntrySetPipedMode(PKOCENTRY pEntry, int fRedirPreCompStdOut, int fRedirCompileStdIn, const char *pszNmPipeCompile) { pEntry->fPipedPreComp = fRedirPreCompStdOut; pEntry->fPipedCompile = fRedirCompileStdIn || pszNmPipeCompile; pEntry->pszNmPipeCompile = xstrdup(pszNmPipeCompile); } /** * Sets the dependency file. * * @param pEntry The cache entry. * @param pszMakeDepFilename The dependency filename. * @param fMakeDepFixCase Whether to fix the case of dependency files. * @param fMakeDepQuiet Whether to be quiet about the dependencies. * @param fMakeDepGenStubs Whether to generate stubs. */ static void kOCEntrySetDepFilename(PKOCENTRY pEntry, const char *pszMakeDepFilename, int fMakeDepFixCase, int fMakeDepQuiet, int fMakeDepGenStubs) { pEntry->pszMakeDepFilename = xstrdup(pszMakeDepFilename); pEntry->fMakeDepFixCase = fMakeDepFixCase; pEntry->fMakeDepQuiet = fMakeDepQuiet; pEntry->fMakeDepGenStubs = fMakeDepGenStubs; } /** * Configures the preprocessor output optimizations. * * @param pEntry The cache entry. * @param fOptimizeCpp The one and only flag, so far. */ static void kOCEntrySetOptimizations(PKOCENTRY pEntry, int fOptimizeCpp) { pEntry->fOptimizeCpp = fOptimizeCpp; } /** * Spawns a child in a synchronous fashion. * Terminating on failure. * * @param papszArgv Argument vector. The cArgv element is NULL. * @param pcMs The cache entry member use for time keeping. This * will be set to the current timestamp. * @param cArgv The number of arguments in the vector. * @param pszMsg Which operation this is, for use in messages. * @param pszStdOut Where to redirect standard out. */ static void kOCEntrySpawn(PCKOCENTRY pEntry, uint32_t *pcMs, const char * const *papszArgv, unsigned cArgv, const char *pszMsg, const char *pszStdOut) { #if defined(__OS2__) || defined(__WIN__) intptr_t rc; int fdStdOut = -1; if (pszStdOut) { int fdReDir; fdStdOut = dup(STDOUT_FILENO); close(STDOUT_FILENO); fdReDir = open(pszStdOut, O_CREAT | O_TRUNC | O_WRONLY, 0666); if (fdReDir < 0) FatalDie("%s - failed to create stdout redirection file '%s': %s\n", pszMsg, pszStdOut, strerror(errno)); if (fdReDir != STDOUT_FILENO) { if (dup2(fdReDir, STDOUT_FILENO) < 0) FatalDie("%s - dup2 failed: %s\n", pszMsg, strerror(errno)); close(fdReDir); } } *pcMs = NowMs(); errno = 0; # ifdef __WIN__ rc = quoted_spawnvp(_P_WAIT, papszArgv[0], papszArgv); # else rc = _spawnvp(_P_WAIT, papszArgv[0], papszArgv); # endif *pcMs = NowMs() - *pcMs; if (rc < 0) FatalDie("%s - _spawnvp failed (rc=0x%p): %s\n", pszMsg, rc, strerror(errno)); if (rc > 0) FatalDie("%s - failed rc=%d\n", pszMsg, (int)rc); if (fdStdOut != -1) { close(STDOUT_FILENO); fdStdOut = dup2(fdStdOut, STDOUT_FILENO); close(fdStdOut); } #else int iStatus; pid_t pidWait; pid_t pid; *pcMs = NowMs(); pid = fork(); if (!pid) { if (pszStdOut) { int fdReDir; close(STDOUT_FILENO); fdReDir = open(pszStdOut, O_CREAT | O_TRUNC | O_WRONLY, 0666); if (fdReDir < 0) FatalDie("%s - failed to create stdout redirection file '%s': %s\n", pszMsg, pszStdOut, strerror(errno)); if (fdReDir != STDOUT_FILENO) { if (dup2(fdReDir, STDOUT_FILENO) < 0) FatalDie("%s - dup2 failed: %s\n", pszMsg, strerror(errno)); close(fdReDir); } } execvp(papszArgv[0], (char **)papszArgv); FatalDie("%s - execvp failed: %s\n", pszMsg, strerror(errno)); } if (pid == -1) FatalDie("%s - fork() failed: %s\n", pszMsg, strerror(errno)); pidWait = waitpid(pid, &iStatus, 0); while (pidWait < 0 && errno == EINTR) pidWait = waitpid(pid, &iStatus, 0); *pcMs = NowMs() - *pcMs; if (pidWait != pid) FatalDie("%s - waitpid failed rc=%d: %s\n", pszMsg, pidWait, strerror(errno)); if (!WIFEXITED(iStatus)) FatalDie("%s - abended (iStatus=%#x)\n", pszMsg, iStatus); if (WEXITSTATUS(iStatus)) FatalDie("%s - failed with rc %d\n", pszMsg, WEXITSTATUS(iStatus)); #endif (void)pEntry; (void)cArgv; } /** * Spawns child with optional redirection of stdin and stdout. * * @param pEntry The cache entry. * @param pcMs The cache entry member use for time keeping. This * will be set to the current timestamp. * @param papszArgv Argument vector. The cArgv element is NULL. * @param cArgv The number of arguments in the vector. * @param fdStdIn Child stdin, -1 if it should inherit our stdin. Will be closed. * @param fdStdOut Child stdout, -1 if it should inherit our stdout. Will be closed. * @param pszMsg Message to start the info/error messages with. */ static pid_t kOCEntrySpawnChild(PCKOCENTRY pEntry, uint32_t *pcMs, const char * const *papszArgv, unsigned cArgv, int fdStdIn, int fdStdOut, const char *pszMsg) { pid_t pid; int fdSavedStdOut = -1; int fdSavedStdIn = -1; /* * Setup redirection. */ if (fdStdOut != -1 && fdStdOut != STDOUT_FILENO) { fdSavedStdOut = dup(STDOUT_FILENO); if (dup2(fdStdOut, STDOUT_FILENO) < 0) FatalDie("%s - dup2(,1) failed: %s\n", pszMsg, strerror(errno)); close(fdStdOut); #ifndef __WIN__ fcntl(fdSavedStdOut, F_SETFD, FD_CLOEXEC); #endif } if (fdStdIn != -1 && fdStdIn != STDIN_FILENO) { fdSavedStdIn = dup(STDIN_FILENO); if (dup2(fdStdIn, STDIN_FILENO) < 0) FatalDie("%s - dup2(,0) failed: %s\n", pszMsg, strerror(errno)); close(fdStdIn); #ifndef __WIN__ fcntl(fdSavedStdIn, F_SETFD, FD_CLOEXEC); #endif } /* * Create the child process. */ *pcMs = NowMs(); #if defined(__OS2__) || defined(__WIN__) errno = 0; # ifdef __WIN__ pid = quoted_spawnvp(_P_NOWAIT, papszArgv[0], papszArgv); # else pid = _spawnvp(_P_NOWAIT, papszArgv[0], papszArgv); # endif if (pid == -1) FatalDie("preprocess - _spawnvp failed: %s\n", strerror(errno)); #else pid = fork(); if (!pid) { execvp(papszArgv[0], (char **)papszArgv); FatalDie("preprocess - execvp failed: %s\n", strerror(errno)); } if (pid == -1) FatalDie("preprocess - fork() failed: %s\n", strerror(errno)); #endif /* * Restore stdout & stdin. */ if (fdSavedStdIn != -1) { close(STDIN_FILENO); dup2(fdStdOut, STDIN_FILENO); close(fdSavedStdIn); } if (fdSavedStdOut != -1) { close(STDOUT_FILENO); dup2(fdSavedStdOut, STDOUT_FILENO); close(fdSavedStdOut); } InfoMsg(3, "%s - spawned %ld\n", pszMsg, (long)pid); (void)cArgv; (void)pEntry; return pid; } /** * Waits for a child and exits fatally if the child failed in any way. * * @param pEntry The cache entry. * @param pcMs The millisecond timestamp that should be convert to * elapsed time. * @param pid The child to wait for. * @param pszMsg Message to start the info/error messages with. */ static void kOCEntryWaitChild(PCKOCENTRY pEntry, uint32_t *pcMs, pid_t pid, const char *pszMsg) { int iStatus = -1; pid_t pidWait; InfoMsg(3, "%s - wait-child %ld\n", pszMsg, (long)pid); #ifdef __WIN__ pidWait = _cwait(&iStatus, pid, _WAIT_CHILD); *pcMs = NowMs() - *pcMs; if (pidWait == -1) FatalDie("%s - waitpid failed: %s\n", pszMsg, strerror(errno)); if (iStatus) FatalDie("%s - failed with rc %d\n", pszMsg, iStatus); #else pidWait = waitpid(pid, &iStatus, 0); while (pidWait < 0 && errno == EINTR) pidWait = waitpid(pid, &iStatus, 0); *pcMs = NowMs() - *pcMs; if (pidWait != pid) FatalDie("%s - waitpid failed rc=%d: %s\n", pidWait, strerror(errno)); if (!WIFEXITED(iStatus)) FatalDie("%s - abended (iStatus=%#x)\n", pszMsg, iStatus); if (WEXITSTATUS(iStatus)) FatalDie("%s - failed with rc %d\n", pszMsg, WEXITSTATUS(iStatus)); #endif (void)pEntry; } /** * Creates a pipe for setting up redirected stdin/stdout. * * @param pEntry The cache entry. * @param paFDs Where to store the two file descriptors. * @param pszMsg The operation message for info/error messages. * @param pszPipeName The pipe name if it is supposed to be named. (Windows only.) * @param fText Whether to read text mode or binary mode. */ static void kOCEntryCreatePipe(PKOCENTRY pEntry, int *paFDs, const char *pszPipeName, const char *pszMsg, int fText) { paFDs[0] = paFDs[1] = -1; #if defined(__WIN__) if (pszPipeName) { HANDLE hPipe = CreateNamedPipeA(pszPipeName, /*PIPE_ACCESS_OUTBOUND*/ PIPE_ACCESS_DUPLEX, PIPE_READMODE_BYTE | PIPE_WAIT, 10 /* nMaxInstances */, 0x10000 /* nOutBuffer */, 0x10000 /* nInBuffer */, NMPWAIT_WAIT_FOREVER, NULL /* pSecurityAttributes */); if (hPipe == INVALID_HANDLE_VALUE) FatalDie("%s - CreateNamedPipe(%s) failed: %d\n", pszMsg, pszPipeName, GetLastError()); paFDs[1 /* write */] = _open_osfhandle((intptr_t)hPipe, _O_WRONLY | _O_TEXT | _O_NOINHERIT); if (paFDs[1 /* write */] == -1) FatalDie("%s - _open_osfhandle failed: %d\n", pszMsg, strerror(errno)); } else if ( _pipe(paFDs, 256*1024, _O_NOINHERIT | (fText ? _O_TEXT : _O_BINARY)) < 0 && _pipe(paFDs, 0, _O_NOINHERIT | (fText ? _O_TEXT : _O_BINARY)) < 0) #else if (pipe(paFDs) < 0) #endif FatalDie("%s - pipe failed: %s\n", pszMsg, strerror(errno)); #if !defined(__WIN__) fcntl(paFDs[0], F_SETFD, FD_CLOEXEC); fcntl(paFDs[1], F_SETFD, FD_CLOEXEC); #endif (void)pEntry; } /** * Spawns a child that produces output to stdout. * * @param papszArgv Argument vector. The cArgv element is NULL. * @param cArgv The number of arguments in the vector. * @param pszMsg The operation message for info/error messages. * @param pfnConsumer Pointer to a consumer callback function that is responsible * for servicing the child output and closing the pipe. */ static void kOCEntrySpawnProducer(PKOCENTRY pEntry, const char * const *papszArgv, unsigned cArgv, const char *pszMsg, void (*pfnConsumer)(PKOCENTRY, int)) { int fds[2]; pid_t pid; kOCEntryCreatePipe(pEntry, fds, NULL, pszMsg, pEntry->fOptimizeCpp); pid = kOCEntrySpawnChild(pEntry, &pEntry->New.cMsCpp, papszArgv, cArgv, -1, fds[1 /* write */], pszMsg); pfnConsumer(pEntry, fds[0 /* read */]); kOCEntryWaitChild(pEntry, &pEntry->New.cMsCpp, pid, pszMsg); } /** * Spawns a child that consumes input on stdin or via a named pipe. * * @param papszArgv Argument vector. The cArgv element is NULL. * @param cArgv The number of arguments in the vector. * @param pszMsg The operation message for info/error messages. * @param pfnProducer Pointer to a producer callback function that is responsible * for serving the child input and closing the pipe. */ static void kOCEntrySpawnConsumer(PKOCENTRY pEntry, const char * const *papszArgv, unsigned cArgv, const char *pszMsg, void (*pfnProducer)(PKOCENTRY, int)) { int fds[2]; pid_t pid; kOCEntryCreatePipe(pEntry, fds, pEntry->pszNmPipeCompile, pszMsg, 0 /*fText*/); pid = kOCEntrySpawnChild(pEntry, &pEntry->New.cMsCompile, papszArgv, cArgv, fds[0 /* read */], -1, pszMsg); #ifdef __WIN__ if (pEntry->pszNmPipeCompile && !ConnectNamedPipe((HANDLE)_get_osfhandle(fds[1 /* write */]), NULL)) FatalDie("compile - ConnectNamedPipe failed: %d\n", GetLastError()); #endif pfnProducer(pEntry, fds[1 /* write */]); kOCEntryWaitChild(pEntry, &pEntry->New.cMsCompile, pid, pszMsg); } /** * Spawns two child processes, one producing output and one consuming. * Terminating on failure. * * @param papszArgv Argument vector. The cArgv element is NULL. * @param cArgv The number of arguments in the vector. * @param pszMsg The operation message for info/error messages. * @param pfnConsumer Pointer to a consumer callback function that is responsible * for servicing the child output and closing the pipe. */ static void kOCEntrySpawnTee(PKOCENTRY pEntry, const char * const *papszProdArgv, unsigned cProdArgv, const char * const *papszConsArgv, unsigned cConsArgv, const char *pszMsg, void (*pfnTeeConsumer)(PKOCENTRY, int, int)) { int fds[2]; int fdIn, fdOut; pid_t pidProducer, pidConsumer; /* * The producer. */ kOCEntryCreatePipe(pEntry, fds, NULL, pszMsg, pEntry->fOptimizeCpp); pidConsumer = kOCEntrySpawnChild(pEntry, &pEntry->New.cMsCpp, papszProdArgv, cProdArgv, -1, fds[1 /* write */], pszMsg); fdIn = fds[0 /* read */]; /* * The consumer. */ kOCEntryCreatePipe(pEntry, fds, pEntry->pszNmPipeCompile, pszMsg, 0 /*fText*/); pidProducer = kOCEntrySpawnChild(pEntry, &pEntry->New.cMsCompile, papszConsArgv, cConsArgv, fds[0 /* read */], -1, pszMsg); fdOut = fds[1 /* write */]; /* * Hand it on to the tee consumer. */ pfnTeeConsumer(pEntry, fdIn, fdOut); /* * Reap the children. */ kOCEntryWaitChild(pEntry, &pEntry->New.cMsCpp, pidProducer, pszMsg); kOCEntryWaitChild(pEntry, &pEntry->New.cMsCompile, pidConsumer, pszMsg); } /** * Reads the output from the preprocessor. * * @param pEntry The cache entry. New.cbCpp and New.pszCppMapping will be updated. * @param pWhich Specifies what to read (old/new). * @param fNonFatal Whether failure is fatal or not. */ static int kOCEntryReadCppOutput(PKOCENTRY pEntry, struct KOCENTRYDATA *pWhich, int fNonFatal) { pWhich->pszCppMapping = ReadFileInDir(pWhich->pszCppName, pEntry->pszDir, &pWhich->cbCpp); if (!pWhich->pszCppMapping) { if (!fNonFatal) FatalDie("failed to open/read '%s' in '%s': %s\n", pWhich->pszCppName, pEntry->pszDir, strerror(errno)); InfoMsg(2, "failed to open/read '%s' in '%s': %s\n", pWhich->pszCppName, pEntry->pszDir, strerror(errno)); return -1; } InfoMsg(3, "preprocessed file is %lu bytes long\n", (unsigned long)pWhich->cbCpp); return 0; } /** * Worker for kOCEntryPreProcess and calculates the checksum of * the preprocessor output. * * @param pEntry The cache entry. NewSum will be updated. */ static void kOCEntryCalcChecksum(PKOCENTRY pEntry) { KOCSUMCTX Ctx; kOCSumInitWithCtx(&pEntry->New.SumHead, &Ctx); kOCSumUpdate(&pEntry->New.SumHead, &Ctx, pEntry->New.pszCppMapping, pEntry->New.cbCpp); kOCSumFinalize(&pEntry->New.SumHead, &Ctx); kOCSumInfo(&pEntry->New.SumHead, 4, "cpp (file)"); } /** * This consumes the preprocessor output and checksums it. * * @param pEntry The cache entry. * @param fdIn The preprocessor output pipe. * @param fdOut The compiler input pipe, -1 if no compiler. */ static void kOCEntryPreProcessConsumer(PKOCENTRY pEntry, int fdIn) { KOCSUMCTX Ctx; KOCCPPRD CppRd; kOCSumInitWithCtx(&pEntry->New.SumHead, &Ctx); kOCCppRdInit(&CppRd, pEntry->Old.cbCpp, pEntry->fOptimizeCpp, pEntry->pszMakeDepFilename ? &pEntry->DepState : NULL); for (;;) { /* * Read data from the pipe. */ const char *psz; long cbRead = kOCCppRdRead(&CppRd, fdIn, &psz); if (!cbRead) break; /* * Process the data. */ kOCSumUpdate(&pEntry->New.SumHead, &Ctx, psz, cbRead); if (pEntry->pszMakeDepFilename && !pEntry->fOptimizeCpp) kOCDepConsumer(&pEntry->DepState, psz, cbRead); } close(fdIn); kOCCppRdGrabOutput(&CppRd, &pEntry->New.pszCppMapping, &pEntry->New.cbCpp); kOCCppRdDelete(&CppRd); kOCSumFinalize(&pEntry->New.SumHead, &Ctx); kOCSumInfo(&pEntry->New.SumHead, 4, "cpp (pipe)"); } /** * Run the preprocessor and calculate the checksum of the output. * * @param pEntry The cache entry. * @param papszArgvPreComp The argument vector for executing preprocessor. * The cArgvPreComp'th argument must be NULL. * @param cArgvPreComp The number of arguments. */ static void kOCEntryPreProcess(PKOCENTRY pEntry, const char * const *papszArgvPreComp, unsigned cArgvPreComp) { /* * If we're executing the preprocessor in piped mode, it's relatively simple. */ if (pEntry->fPipedPreComp) kOCEntrySpawnProducer(pEntry, papszArgvPreComp, cArgvPreComp, "preprocess", kOCEntryPreProcessConsumer); else { /* * Rename the old preprocessed output to '-old' so the preprocessor won't * overwrite it when we execute it. */ if ( pEntry->Old.pszCppName && DoesFileInDirExist(pEntry->Old.pszCppName, pEntry->pszDir)) { size_t cch = strlen(pEntry->Old.pszCppName); char *psz = xmalloc(cch + sizeof("-old")); memcpy(psz, pEntry->Old.pszCppName, cch); memcpy(psz + cch, "-old", sizeof("-old")); InfoMsg(3, "renaming '%s' to '%s' in '%s'\n", pEntry->Old.pszCppName, psz, pEntry->pszDir); UnlinkFileInDir(psz, pEntry->pszDir); if (RenameFileInDir(pEntry->Old.pszCppName, psz, pEntry->pszDir)) FatalDie("failed to rename '%s' -> '%s' in '%s': %s\n", pEntry->Old.pszCppName, psz, pEntry->pszDir, strerror(errno)); free(pEntry->Old.pszCppName); pEntry->Old.pszCppName = psz; } /* * Preprocess it and calculate the checksum on the output. */ InfoMsg(3, "precompiling -> '%s'...\n", pEntry->New.pszCppName); kOCEntrySpawn(pEntry, &pEntry->New.cMsCpp, papszArgvPreComp, cArgvPreComp, "preprocess", NULL); kOCEntryReadCppOutput(pEntry, &pEntry->New, 0 /* fatal */); kOCEntryCalcChecksum(pEntry); if (pEntry->pszMakeDepFilename) kOCDepConsumer(&pEntry->DepState, pEntry->New.pszCppMapping, pEntry->New.cbCpp); } if (pEntry->pszMakeDepFilename) kOCDepWriteToFile(&pEntry->DepState, pEntry->pszMakeDepFilename, pEntry->New.pszObjName, pEntry->pszDir, pEntry->fMakeDepFixCase, pEntry->fMakeDepQuiet, pEntry->fMakeDepGenStubs); } /** * Worker function for kOCEntryTeeConsumer and kOCEntryCompileIt that * writes the preprocessor output to disk. * * @param pEntry The cache entry. * @param fFreeIt Whether we can free it after writing it or not. */ static void kOCEntryWriteCppOutput(PKOCENTRY pEntry, int fFreeIt) { /* * Remove old files. */ if (pEntry->Old.pszCppName) UnlinkFileInDir(pEntry->Old.pszCppName, pEntry->pszDir); if (pEntry->New.pszCppName) UnlinkFileInDir(pEntry->New.pszCppName, pEntry->pszDir); /* * Write it to disk if we've got a file name. */ if (pEntry->New.pszCppName) { long cbLeft; char *psz; int fd = OpenFileInDir(pEntry->New.pszCppName, pEntry->pszDir, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); if (fd == -1) FatalDie("Failed to create '%s' in '%s': %s\n", pEntry->New.pszCppName, pEntry->pszDir, strerror(errno)); psz = pEntry->New.pszCppMapping; cbLeft = (long)pEntry->New.cbCpp; while (cbLeft > 0) { long cbWritten = write(fd, psz, cbLeft); if (cbWritten < 0) { int iErr = errno; if (iErr == EINTR) continue; close(fd); UnlinkFileInDir(pEntry->New.pszCppName, pEntry->pszDir); FatalDie("error writing '%s' in '%s': %s\n", pEntry->New.pszCppName, pEntry->pszDir, strerror(iErr)); } psz += cbWritten; cbLeft -= cbWritten; } close(fd); } /* * Free it. */ if (fFreeIt) { free(pEntry->New.pszCppMapping); pEntry->New.pszCppMapping = NULL; } } /** * kOCEntrySpawnConsumer callback that passes the preprocessor output to the * compiler and writes it to the disk (latter only when necesary). * * @param pEntry The cache entry. * @param fdOut The pipe handle connected to the childs stdin. */ static void kOCEntryCompileProducer(PKOCENTRY pEntry, int fdOut) { const char *psz = pEntry->New.pszCppMapping; long cbLeft = (long)pEntry->New.cbCpp; while (cbLeft > 0) { long cbWritten = write(fdOut, psz, cbLeft); if (cbWritten < 0) { if (errno == EINTR) continue; #ifdef __WIN__ /* HACK */ if ( errno == EINVAL && pEntry->pszNmPipeCompile && DisconnectNamedPipe((HANDLE)_get_osfhandle(fdOut)) && ConnectNamedPipe((HANDLE)_get_osfhandle(fdOut), NULL)) { psz = pEntry->New.pszCppMapping; cbLeft = (long)pEntry->New.cbCpp; } FatalDie("compile - write(%d,,%ld) failed: %s - _doserrno=%d\n", fdOut, cbLeft, strerror(errno), _doserrno); #else FatalDie("compile - write(%d,,%ld) failed: %s\n", fdOut, cbLeft, strerror(errno)); #endif } psz += cbWritten; cbLeft -= cbWritten; } close(fdOut); if (pEntry->fPipedPreComp) kOCEntryWriteCppOutput(pEntry, 1 /* free it */); } /** * Does the actual compiling. * * @param pEntry The cache entry. */ static void kOCEntryCompileIt(PKOCENTRY pEntry) { /* * Delete the object files and free old cpp output that's no longer needed. */ if (pEntry->Old.pszObjName) UnlinkFileInDir(pEntry->Old.pszObjName, pEntry->pszDir); UnlinkFileInDir(pEntry->New.pszObjName, pEntry->pszDir); free(pEntry->Old.pszCppMapping); pEntry->Old.pszCppMapping = NULL; if (!pEntry->fPipedPreComp && !pEntry->fPipedCompile) { free(pEntry->New.pszCppMapping); pEntry->New.pszCppMapping = NULL; } /* * Do the (re-)compile job. */ if (pEntry->fPipedCompile) { if ( !pEntry->fPipedPreComp && !pEntry->New.pszCppMapping) kOCEntryReadCppOutput(pEntry, &pEntry->New, 0 /* fatal */); InfoMsg(3, "compiling -> '%s'...\n", pEntry->New.pszObjName); kOCEntrySpawnConsumer(pEntry, (const char * const *)pEntry->New.papszArgvCompile, pEntry->New.cArgvCompile, "compile", kOCEntryCompileProducer); } else { if (pEntry->fPipedPreComp) kOCEntryWriteCppOutput(pEntry, 1 /* free it */); InfoMsg(3, "compiling -> '%s'...\n", pEntry->New.pszObjName); kOCEntrySpawn(pEntry, &pEntry->New.cMsCompile, (const char * const *)pEntry->New.papszArgvCompile, pEntry->New.cArgvCompile, "compile", NULL); } } /** * kOCEntrySpawnTee callback that works sort of like 'tee'. * * It will calculate the preprocessed output checksum and * write it to disk while the compiler is busy compiling it. * * @param pEntry The cache entry. * @param fdIn The input handle (connected to the preprocessor). * @param fdOut The output handle (connected to the compiler). */ static void kOCEntryTeeConsumer(PKOCENTRY pEntry, int fdIn, int fdOut) { #ifdef __WIN__ unsigned fConnectedToCompiler = fdOut == -1 || pEntry->pszNmPipeCompile == NULL; #endif KOCSUMCTX Ctx; KOCCPPRD CppRd; kOCSumInitWithCtx(&pEntry->New.SumHead, &Ctx); kOCCppRdInit(&CppRd, pEntry->Old.cbCpp, pEntry->fOptimizeCpp, pEntry->pszMakeDepFilename ? &pEntry->DepState : NULL); InfoMsg(3, "preprocessor|compile - starting passhtru...\n"); for (;;) { /* * Read data from the pipe. */ const char *psz; long cbRead = kOCCppRdRead(&CppRd, fdIn, &psz); if (!cbRead) break; InfoMsg(3, "preprocessor|compile - read %d\n", cbRead); /* * Process the data. */ kOCSumUpdate(&pEntry->New.SumHead, &Ctx, psz, cbRead); if (pEntry->pszMakeDepFilename && !pEntry->fOptimizeCpp) kOCDepConsumer(&pEntry->DepState, psz, cbRead); #ifdef __WIN__ if ( !fConnectedToCompiler && !(fConnectedToCompiler = ConnectNamedPipe((HANDLE)_get_osfhandle(fdOut), NULL))) FatalDie("preprocess|compile - ConnectNamedPipe failed: %d\n", GetLastError()); #endif do { long cbWritten = write(fdOut, psz, cbRead); if (cbWritten < 0) { if (errno == EINTR) continue; FatalDie("preprocess|compile - write(%d,,%ld) failed: %s\n", fdOut, cbRead, strerror(errno)); } psz += cbWritten; cbRead -= cbWritten; } while (cbRead > 0); } InfoMsg(3, "preprocessor|compile - done passhtru\n"); close(fdIn); close(fdOut); kOCCppRdGrabOutput(&CppRd, &pEntry->New.pszCppMapping, &pEntry->New.cbCpp); kOCCppRdDelete(&CppRd); kOCSumFinalize(&pEntry->New.SumHead, &Ctx); kOCSumInfo(&pEntry->New.SumHead, 4, "cpp (tee)"); /* * Write the preprocessor output to disk and free the memory it * occupies while the compiler is busy compiling. */ kOCEntryWriteCppOutput(pEntry, 1 /* free it */); } /** * Performs pre-compile and compile in one go (typical clean build scenario). * * @param pEntry The cache entry. * @param papszArgvPreComp The argument vector for executing preprocessor. * The cArgvPreComp'th argument must be NULL. * @param cArgvPreComp The number of arguments. */ static void kOCEntryPreProcessAndCompile(PKOCENTRY pEntry, const char * const *papszArgvPreComp, unsigned cArgvPreComp) { if ( pEntry->fPipedCompile && pEntry->fPipedPreComp) { /* * Clean up old stuff first. */ if (pEntry->Old.pszObjName) UnlinkFileInDir(pEntry->Old.pszObjName, pEntry->pszDir); if (pEntry->New.pszObjName) UnlinkFileInDir(pEntry->New.pszObjName, pEntry->pszDir); if (pEntry->Old.pszCppName) UnlinkFileInDir(pEntry->Old.pszCppName, pEntry->pszDir); if (pEntry->New.pszCppName) UnlinkFileInDir(pEntry->New.pszCppName, pEntry->pszDir); /* * Do the actual compile and write the preprocessor output to disk. */ kOCEntrySpawnTee(pEntry, papszArgvPreComp, cArgvPreComp, (const char * const *)pEntry->New.papszArgvCompile, pEntry->New.cArgvCompile, "preprocess|compile", kOCEntryTeeConsumer); if (pEntry->pszMakeDepFilename) kOCDepWriteToFile(&pEntry->DepState, pEntry->pszMakeDepFilename, pEntry->New.pszObjName, pEntry->pszDir, pEntry->fMakeDepFixCase, pEntry->fMakeDepQuiet, pEntry->fMakeDepGenStubs); } else { kOCEntryPreProcess(pEntry, papszArgvPreComp, cArgvPreComp); kOCEntryCompileIt(pEntry); } } /** * Check whether the string is a '#line' statement. * * @returns 1 if it is, 0 if it isn't. * @param psz The line to examin. * @parma piLine Where to store the line number. * @parma ppszFile Where to store the start of the filename. */ static int kOCEntryIsLineStatement(const char *psz, unsigned *piLine, const char **ppszFile) { unsigned iLine; /* Expect a hash. */ if (*psz++ != '#') return 0; /* Skip blanks between '#' and the line / number */ while (*psz == ' ' || *psz == '\t') psz++; /* Skip the 'line' if present. */ if (!strncmp(psz, "line", sizeof("line") - 1)) psz += sizeof("line"); /* Expect a line number now. */ if ((unsigned char)(*psz - '0') > 9) return 0; iLine = 0; do { iLine *= 10; iLine += (*psz - '0'); psz++; } while ((unsigned char)(*psz - '0') <= 9); /* Expect one or more space now. */ if (*psz != ' ' && *psz != '\t') return 0; do psz++; while (*psz == ' ' || *psz == '\t'); /* that's good enough. */ *piLine = iLine; *ppszFile = psz; return 1; } /** * Scan backwards for the previous #line statement. * * @returns The filename in the previous statement. * @param pszStart Where to start. * @param pszStop Where to stop. Less than pszStart. * @param piLine The line number count to adjust. */ static const char *kOCEntryFindFileStatement(const char *pszStart, const char *pszStop, unsigned *piLine) { unsigned iLine = *piLine; assert(pszStart >= pszStop); while (pszStart >= pszStop) { if (*pszStart == '\n') iLine++; else if (*pszStart == '#') { unsigned iLineTmp; const char *pszFile; const char *psz = pszStart - 1; while (psz >= pszStop && (*psz == ' ' || *psz =='\t')) psz--; if ( (psz < pszStop || *psz == '\n') && kOCEntryIsLineStatement(pszStart, &iLineTmp, &pszFile)) { *piLine = iLine + iLineTmp - 1; return pszFile; } } pszStart--; } return NULL; } /** * Worker for kOCEntryCompareOldAndNewOutput() that compares the * preprocessed output using a fast but not very good method. * * @returns 1 if matching, 0 if not matching. * @param pEntry The entry containing the names of the files to compare. * The entry is not updated in any way. */ static int kOCEntryCompareFast(PCKOCENTRY pEntry) { const char * psz1 = pEntry->New.pszCppMapping; const char * const pszEnd1 = psz1 + pEntry->New.cbCpp; const char * psz2 = pEntry->Old.pszCppMapping; const char * const pszEnd2 = psz2 + pEntry->Old.cbCpp; assert(*pszEnd1 == '\0'); assert(*pszEnd2 == '\0'); /* * Iterate block by block and backtrack when we find a difference. */ for (;;) { size_t cch = pszEnd1 - psz1; if (cch > (size_t)(pszEnd2 - psz2)) cch = pszEnd2 - psz2; if (cch > 4096) cch = 4096; if ( cch && !memcmp(psz1, psz2, cch)) { /* no differences */ psz1 += cch; psz2 += cch; } else { /* * Pinpoint the difference exactly and the try find the start * of that line. Then skip forward until we find something to * work on that isn't spaces, #line statements or closing curly * braces. * * The closing curly braces are ignored because they are frequently * found at the end of header files (__END_DECLS) and the worst * thing that may happen if it isn't one of these braces we're * ignoring is that the final line in a function block is a little * bit off in the debug info. * * Since we might be skipping a few new empty headers, it is * possible that we will omit this header from the dependencies * when using VCC. This might not be a problem, since it seems * we'll have to use the preprocessor output to generate the deps * anyway. */ const char *psz; const char *pszMismatch1; const char *pszFile1 = NULL; unsigned iLine1 = 0; unsigned cCurlyBraces1 = 0; const char *pszMismatch2; const char *pszFile2 = NULL; unsigned iLine2 = 0; unsigned cCurlyBraces2 = 0; /* locate the difference. */ while (cch >= 512 && !memcmp(psz1, psz2, 512)) psz1 += 512, psz2 += 512, cch -= 512; while (cch >= 64 && !memcmp(psz1, psz2, 64)) psz1 += 64, psz2 += 64, cch -= 64; while (*psz1 == *psz2 && cch > 0) psz1++, psz2++, cch--; /* locate the start of that line. */ psz = psz1; while ( psz > pEntry->New.pszCppMapping && psz[-1] != '\n') psz--; psz2 -= (psz1 - psz); pszMismatch2 = psz2; pszMismatch1 = psz1 = psz; /* Parse the 1st file line by line. */ while (psz1 < pszEnd1) { if (*psz1 == '\n') { psz1++; iLine1++; } else { psz = psz1; while (isspace(*psz) && *psz != '\n') psz++; if (*psz == '\n') { psz1 = psz + 1; iLine1++; } else if (*psz == '#' && kOCEntryIsLineStatement(psz, &iLine1, &pszFile1)) { psz1 = memchr(psz, '\n', pszEnd1 - psz); if (!psz1++) psz1 = pszEnd1; } else if (*psz == '}') { do psz++; while (isspace(*psz) && *psz != '\n'); if (*psz == '\n') iLine1++; else if (psz != pszEnd1) break; cCurlyBraces1++; psz1 = psz; } else if (psz == pszEnd1) psz1 = psz; else /* found something that can be compared. */ break; } } /* Ditto for the 2nd file. */ while (psz2 < pszEnd2) { if (*psz2 == '\n') { psz2++; iLine2++; } else { psz = psz2; while (isspace(*psz) && *psz != '\n') psz++; if (*psz == '\n') { psz2 = psz + 1; iLine2++; } else if (*psz == '#' && kOCEntryIsLineStatement(psz, &iLine2, &pszFile2)) { psz2 = memchr(psz, '\n', pszEnd2 - psz); if (!psz2++) psz2 = pszEnd2; } else if (*psz == '}') { do psz++; while (isspace(*psz) && *psz != '\n'); if (*psz == '\n') iLine2++; else if (psz != pszEnd2) break; cCurlyBraces2++; psz2 = psz; } else if (psz == pszEnd2) psz2 = psz; else /* found something that can be compared. */ break; } } /* Match the number of ignored closing curly braces. */ if (cCurlyBraces1 != cCurlyBraces2) return 0; /* Reaching the end of any of them means the return statement can decide. */ if ( psz1 == pszEnd1 || psz2 == pszEnd2) break; /* Match the current line. */ psz = memchr(psz1, '\n', pszEnd1 - psz1); if (!psz++) psz = pszEnd1; cch = psz - psz1; if (psz2 + cch > pszEnd2) break; if (memcmp(psz1, psz2, cch)) break; /* Check that we're at the same location now. */ if (!pszFile1) pszFile1 = kOCEntryFindFileStatement(pszMismatch1, pEntry->New.pszCppMapping, &iLine1); if (!pszFile2) pszFile2 = kOCEntryFindFileStatement(pszMismatch2, pEntry->Old.pszCppMapping, &iLine2); if (pszFile1 && pszFile2) { if (iLine1 != iLine2) break; while (*pszFile1 == *pszFile2 && *pszFile1 != '\n' && *pszFile1) pszFile1++, pszFile2++; if (*pszFile1 != *pszFile2) break; } else if (pszFile1 || pszFile2) { assert(0); /* this shouldn't happen. */ break; } /* Advance. We might now have a misaligned buffer, but that's memcmps problem... */ psz1 += cch; psz2 += cch; } } return psz1 == pszEnd1 && psz2 == pszEnd2; } /** * Worker for kOCEntryCompileIfNeeded that compares the * preprocessed output. * * @returns 1 if matching, 0 if not matching. * @param pEntry The entry containing the names of the files to compare. * This will load the old cpp output (changing pszOldCppName and Old.cbCpp). */ static int kOCEntryCompareOldAndNewOutput(PKOCENTRY pEntry) { /* * I may implement a more sophisticated alternative method later... maybe. */ if (kOCEntryReadCppOutput(pEntry, &pEntry->Old, 1 /* nonfatal */) == -1) return 0; /*if () return kOCEntryCompareBest(pEntry);*/ return kOCEntryCompareFast(pEntry); } /** * Check if re-compilation is required. * This sets the fNeedCompile flag. * * @param pEntry The cache entry. */ static void kOCEntryCalcRecompile(PKOCENTRY pEntry) { if (pEntry->fNeedCompiling) return; /* * Check if the preprocessor output differ in any significant way? */ if (!kOCSumHasEqualInChain(&pEntry->Old.SumHead, &pEntry->New.SumHead)) { if (pEntry->fOptimizeCpp & 2) { InfoMsg(2, "no checksum match - no need to compare output, -O2.\n"); pEntry->fNeedCompiling = 1; } else { InfoMsg(2, "no checksum match - comparing output\n"); if (!kOCEntryCompareOldAndNewOutput(pEntry)) pEntry->fNeedCompiling = 1; else kOCSumAddChain(&pEntry->New.SumHead, &pEntry->Old.SumHead); } } } /** * Does this cache entry need compiling or what? * * @returns 1 if it does, 0 if it doesn't. * @param pEntry The cache entry in question. */ static int kOCEntryNeedsCompiling(PCKOCENTRY pEntry) { return pEntry->fNeedCompiling; } /** * Tries to hardlink a file. * * @returns 1 if it succeeded, 0 if it didn't. * @param pszLink The name of the hardlink. * @param pszLinkTo The file to hardlinkg @a pszDst to. */ static int kOCEntryTryHardlink(const char *pszLink, const char *pszLinkTo) { #ifdef __WIN__ typedef BOOL (WINAPI *PFNCREATEHARDLINKA)(LPCSTR, LPCSTR, LPSECURITY_ATTRIBUTES); static PFNCREATEHARDLINKA s_pfnCreateHardLinkA = NULL; static int s_fTried = FALSE; /* The API was introduced in Windows 2000, so resolve it dynamically. */ if (!s_pfnCreateHardLinkA) { if (!s_fTried) { HMODULE hmod = LoadLibrary("KERNEL32.DLL"); if (hmod) *(FARPROC *)&s_pfnCreateHardLinkA = GetProcAddress(hmod, "CreateHardLinkA"); s_fTried = TRUE; } if (!s_pfnCreateHardLinkA) return 0; } if (!s_pfnCreateHardLinkA(pszLink, pszLinkTo, NULL)) return 0; #else if (link(pszLinkTo, pszLink) != 0) return 0; #endif return 1; } /** * Worker function for kOCEntryCopy. * * @param pEntry The entry we're coping to, which pszTo is relative to. * @param pszTo The destination. * @param pszFrom The source. This path will be freed. */ static void kOCEntryCopyFile(PCKOCENTRY pEntry, const char *pszTo, char *pszSrc) { char *pszDst = MakePathFromDirAndFile(pszTo, pEntry->pszDir); unlink(pszDst); if (!kOCEntryTryHardlink(pszDst, pszSrc)) { char *pszBuf = xmalloc(256 * 1024); char *psz; int fdSrc; int fdDst; /* * Open the files. */ fdSrc = open(pszSrc, O_RDONLY | O_BINARY); if (fdSrc == -1) FatalDie("failed to open '%s': %s\n", pszSrc, strerror(errno)); fdDst = open(pszDst, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); if (fdDst == -1) FatalDie("failed to create '%s': %s\n", pszDst, strerror(errno)); /* * Copy them. */ for (;;) { /* read a chunk. */ long cbRead = read(fdSrc, pszBuf, 256*1024); if (cbRead < 0) { if (errno == EINTR) continue; FatalDie("read '%s' failed: %s\n", pszSrc, strerror(errno)); } if (!cbRead) break; /* eof */ /* write the chunk. */ psz = pszBuf; do { long cbWritten = write(fdDst, psz, cbRead); if (cbWritten < 0) { if (errno == EINTR) continue; FatalDie("write '%s' failed: %s\n", pszSrc, strerror(errno)); } psz += cbWritten; cbRead -= cbWritten; } while (cbRead > 0); } /* cleanup */ if (close(fdDst) != 0) FatalDie("closing '%s' failed: %s\n", pszDst, strerror(errno)); close(fdSrc); free(pszBuf); } free(pszDst); free(pszSrc); } /** * Copies the object (and whatever else) from one cache entry to another. * * This is called when a matching cache entry has been found and we don't * need to recompile anything. * * @param pEntry The entry to copy to. * @param pFrom The entry to copy from. */ static void kOCEntryCopy(PKOCENTRY pEntry, PCKOCENTRY pFrom) { kOCEntryCopyFile(pEntry, pEntry->New.pszObjName, MakePathFromDirAndFile(pFrom->New.pszObjName ? pFrom->New.pszObjName : pFrom->Old.pszObjName, pFrom->pszDir)); } /** * Gets the absolute path to the cache entry. * * @returns absolute path to the cache entry. * @param pEntry The cache entry in question. */ static const char *kOCEntryAbsPath(PCKOCENTRY pEntry) { return pEntry->pszAbsPath; } /** * Digest of one cache entry. * * This contains all the information required to find a matching * cache entry without having to open each of the files. */ typedef struct KOCDIGEST { /** The relative path to the entry. Optional if pszAbsPath is set. */ char *pszRelPath; /** The absolute path to the entry. Optional if pszRelPath is set. */ char *pszAbsPath; /** The target os/arch identifier. */ char *pszTarget; /** A unique number assigned to the entry when it's (re)-inserted * into the cache. This is used for simple consitency checking. */ uint32_t uKey; /** The checksum of the compile argument vector. */ KOCSUM SumCompArgv; /** The list of preprocessor output checksums that's . */ KOCSUM SumHead; } KOCDIGEST; /** Pointer to a file digest. */ typedef KOCDIGEST *PKOCDIGEST; /** Pointer to a const file digest. */ typedef KOCDIGEST *PCKOCDIGEST; /** * Initializes the specified digest. * * @param pDigest The digest. */ static void kOCDigestInit(PKOCDIGEST pDigest) { memset(pDigest, 0, sizeof(*pDigest)); kOCSumInit(&pDigest->SumHead); } /** * Initializes the digest for the specified entry. * * @param pDigest The (uninitialized) digest. * @param pEntry The entry. */ static void kOCDigestInitFromEntry(PKOCDIGEST pDigest, PCKOCENTRY pEntry) { kOCDigestInit(pDigest); pDigest->uKey = pEntry->uKey; pDigest->pszTarget = xstrdup(pEntry->New.pszTarget ? pEntry->New.pszTarget : pEntry->Old.pszTarget); kOCSumInit(&pDigest->SumCompArgv); if (!kOCSumIsEmpty(&pEntry->New.SumCompArgv)) kOCSumAdd(&pDigest->SumCompArgv, &pEntry->New.SumCompArgv); else kOCSumAdd(&pDigest->SumCompArgv, &pEntry->Old.SumCompArgv); kOCSumInit(&pDigest->SumHead); if (!kOCSumIsEmpty(&pEntry->New.SumHead)) kOCSumAddChain(&pDigest->SumHead, &pEntry->New.SumHead); else kOCSumAddChain(&pDigest->SumHead, &pEntry->Old.SumHead); /** @todo implement selective relative path support. */ pDigest->pszRelPath = NULL; pDigest->pszAbsPath = xstrdup(kOCEntryAbsPath(pEntry)); } /** * Purges a digest, freeing all resources and returning * it to the initial state. * * @param pDigest The digest. */ static void kOCDigestPurge(PKOCDIGEST pDigest) { free(pDigest->pszRelPath); free(pDigest->pszAbsPath); free(pDigest->pszTarget); pDigest->pszTarget = pDigest->pszAbsPath = pDigest->pszRelPath = NULL; pDigest->uKey = 0; kOCSumDeleteChain(&pDigest->SumCompArgv); kOCSumDeleteChain(&pDigest->SumHead); } /** * Returns the absolute path to the entry, calculating * the path if necessary. * * @returns absolute path. * @param pDigest The digest. * @param pszDir The cache directory that it might be relative to. */ static const char *kOCDigestAbsPath(PCKOCDIGEST pDigest, const char *pszDir) { if (!pDigest->pszAbsPath) { char *pszPath = MakePathFromDirAndFile(pDigest->pszRelPath, pszDir); ((PKOCDIGEST)pDigest)->pszAbsPath = AbsPath(pszPath); free(pszPath); } return pDigest->pszAbsPath; } /** * Checks that the digest matches the * * @returns 1 if valid, 0 if invalid in some way. * * @param pDigest The digest to validate. * @param pEntry What to validate it against. */ static int kOCDigestIsValid(PCKOCDIGEST pDigest, PCKOCENTRY pEntry) { PCKOCSUM pSum; PCKOCSUM pSumEntry; if (pDigest->uKey != pEntry->uKey) return 0; if (!kOCSumIsEqual(&pDigest->SumCompArgv, kOCSumIsEmpty(&pEntry->New.SumCompArgv) ? &pEntry->Old.SumCompArgv : &pEntry->New.SumCompArgv)) return 0; if (strcmp(pDigest->pszTarget, pEntry->New.pszTarget ? pEntry->New.pszTarget : pEntry->Old.pszTarget)) return 0; /* match the checksums */ pSumEntry = kOCSumIsEmpty(&pEntry->New.SumHead) ? &pEntry->Old.SumHead : &pEntry->New.SumHead; for (pSum = &pDigest->SumHead; pSum; pSum = pSum->pNext) if (!kOCSumHasEqualInChain(pSumEntry, pSum)) return 0; return 1; } /** * The structure for the central cache entry. */ typedef struct KOBJCACHE { /** The entry name. */ const char *pszName; /** The dir that relative names in the digest are relative to. */ char *pszDir; /** The absolute path. */ char *pszAbsPath; /** The cache file descriptor. */ int fd; /** The stream associated with fd. */ FILE *pFile; /** Whether it's currently locked or not. */ unsigned fLocked; /** Whether the cache file is dirty and needs writing back. */ unsigned fDirty; /** Whether this is a new cache or not. */ unsigned fNewCache; /** The cache file generation. */ uint32_t uGeneration; /** The next valid key. (Determin at load time.) */ uint32_t uNextKey; /** Number of digests in paDigests. */ unsigned cDigests; /** Array of digests for the KOCENTRY objects in the cache. */ PKOCDIGEST paDigests; } KOBJCACHE; /** Pointer to a cache. */ typedef KOBJCACHE *PKOBJCACHE; /** Pointer to a const cache. */ typedef KOBJCACHE const *PCKOBJCACHE; /** * Creates an empty cache. * * This doesn't touch the file system, it just create the data structure. * * @returns Pointer to a cache. * @param pszCacheFile The cache file. */ static PKOBJCACHE kObjCacheCreate(const char *pszCacheFile) { PKOBJCACHE pCache; size_t off; /* * Allocate an empty entry. */ pCache = xmallocz(sizeof(*pCache)); pCache->fd = -1; /* * Setup the directory and cache file name. */ pCache->pszAbsPath = AbsPath(pszCacheFile); pCache->pszName = FindFilenameInPath(pCache->pszAbsPath); off = pCache->pszName - pCache->pszAbsPath; if (!off) FatalDie("Failed to find abs path for '%s'!\n", pszCacheFile); pCache->pszDir = xmalloc(off); memcpy(pCache->pszDir, pCache->pszAbsPath, off - 1); pCache->pszDir[off - 1] = '\0'; return pCache; } /** * Destroys the cache - closing any open files, freeing up heap memory and such. * * @param pCache The cache. */ static void kObjCacheDestroy(PKOBJCACHE pCache) { if (pCache->pFile) { errno = 0; if (fclose(pCache->pFile) != 0) FatalMsg("fclose failed: %s\n", strerror(errno)); pCache->pFile = NULL; pCache->fd = -1; } free(pCache->paDigests); free(pCache->pszAbsPath); free(pCache->pszDir); free(pCache); } /** * Purges the data in the cache object. * * @param pCache The cache object. */ static void kObjCachePurge(PKOBJCACHE pCache) { while (pCache->cDigests > 0) kOCDigestPurge(&pCache->paDigests[--pCache->cDigests]); free(pCache->paDigests); pCache->paDigests = NULL; pCache->uGeneration = 0; pCache->uNextKey = 0; } /** * (Re-)reads the file. * * @param pCache The cache to (re)-read. */ static void kObjCacheRead(PKOBJCACHE pCache) { unsigned i; char szBuf[8192]; int fBad = 0; InfoMsg(4, "reading cache file...\n"); /* * Rewind the file & stream, and associate a temporary buffer * with the stream to speed up reading. */ if (lseek(pCache->fd, 0, SEEK_SET) == -1) FatalDie("lseek(cache-fd) failed: %s\n", strerror(errno)); rewind(pCache->pFile); if (setvbuf(pCache->pFile, szBuf, _IOFBF, sizeof(szBuf)) != 0) FatalDie("fdopen(cache-fd,rb) failed: %s\n", strerror(errno)); /* * Read magic and generation. */ if ( !fgets(g_szLine, sizeof(g_szLine), pCache->pFile) || strcmp(g_szLine, "magic=kObjCache-v0.1.0\n")) { InfoMsg(2, "bad cache file (magic)\n"); fBad = 1; } else if ( !fgets(g_szLine, sizeof(g_szLine), pCache->pFile) || strncmp(g_szLine, "generation=", sizeof("generation=") - 1)) { InfoMsg(2, "bad cache file (generation)\n"); fBad = 1; } else if ( pCache->uGeneration && (long)pCache->uGeneration == atol(&g_szLine[sizeof("generation=") - 1])) { InfoMsg(3, "drop re-read unmodified cache file\n"); fBad = 0; } else { int fBadBeforeMissing; /* * Read everything (anew). */ kObjCachePurge(pCache); do { PKOCDIGEST pDigest; char *pszNl; char *pszVal; char *psz; /* Split the line and drop the trailing newline. */ pszVal = strchr(g_szLine, '='); if ((fBad = pszVal == NULL)) break; *pszVal++ = '\0'; pszNl = strchr(pszVal, '\n'); if (pszNl) *pszNl = '\0'; /* digest '#'? */ psz = strchr(g_szLine, '#'); if (psz) { char *pszNext; i = strtoul(++psz, &pszNext, 0); if ((fBad = pszNext && *pszNext)) break; if ((fBad = i >= pCache->cDigests)) break; pDigest = &pCache->paDigests[i]; *psz = '\0'; } else pDigest = NULL; /* string case on value name. */ if (!strcmp(g_szLine, "sum-#")) { KOCSUM Sum; if ((fBad = kOCSumInitFromString(&Sum, pszVal) != 0)) break; kOCSumAdd(&pDigest->SumHead, &Sum); } else if (!strcmp(g_szLine, "digest-abs-#")) { if ((fBad = pDigest->pszAbsPath != NULL)) break; pDigest->pszAbsPath = xstrdup(pszVal); } else if (!strcmp(g_szLine, "digest-rel-#")) { if ((fBad = pDigest->pszRelPath != NULL)) break; pDigest->pszRelPath = xstrdup(pszVal); } else if (!strcmp(g_szLine, "key-#")) { if ((fBad = pDigest->uKey != 0)) break; pDigest->uKey = strtoul(pszVal, &psz, 0); if ((fBad = psz && *psz)) break; if (pDigest->uKey >= pCache->uNextKey) pCache->uNextKey = pDigest->uKey + 1; } else if (!strcmp(g_szLine, "comp-argv-sum-#")) { if ((fBad = !kOCSumIsEmpty(&pDigest->SumCompArgv))) break; if ((fBad = kOCSumInitFromString(&pDigest->SumCompArgv, pszVal) != 0)) break; } else if (!strcmp(g_szLine, "target-#")) { if ((fBad = pDigest->pszTarget != NULL)) break; pDigest->pszTarget = xstrdup(pszVal); } else if (!strcmp(g_szLine, "digests")) { if ((fBad = pCache->paDigests != NULL)) break; pCache->cDigests = strtoul(pszVal, &psz, 0); if ((fBad = psz && *psz)) break; i = (pCache->cDigests + 4) & ~3; pCache->paDigests = xmalloc(i * sizeof(pCache->paDigests[0])); for (i = 0; i < pCache->cDigests; i++) kOCDigestInit(&pCache->paDigests[i]); } else if (!strcmp(g_szLine, "generation")) { if ((fBad = pCache->uGeneration != 0)) break; pCache->uGeneration = strtoul(pszVal, &psz, 0); if ((fBad = psz && *psz)) break; } else if (!strcmp(g_szLine, "the-end")) { fBad = strcmp(pszVal, "fine"); break; } else { fBad = 1; break; } } while (fgets(g_szLine, sizeof(g_szLine), pCache->pFile)); /* * Did we find everything? */ fBadBeforeMissing = fBad; if ( !fBad && !pCache->uGeneration) fBad = 1; if (!fBad) for (i = 0; i < pCache->cDigests; i++) { if ((fBad = kOCSumIsEmpty(&pCache->paDigests[i].SumCompArgv))) break; if ((fBad = kOCSumIsEmpty(&pCache->paDigests[i].SumHead))) break; if ((fBad = pCache->paDigests[i].uKey == 0)) break; if ((fBad = pCache->paDigests[i].pszAbsPath == NULL && pCache->paDigests[i].pszRelPath == NULL)) break; if ((fBad = pCache->paDigests[i].pszTarget == NULL)) break; InfoMsg(4, "digest-%u: %s\n", i, pCache->paDigests[i].pszAbsPath ? pCache->paDigests[i].pszAbsPath : pCache->paDigests[i].pszRelPath); } if (fBad) InfoMsg(2, "bad cache file (%s)\n", fBadBeforeMissing ? g_szLine : "missing stuff"); else if (ferror(pCache->pFile)) { InfoMsg(2, "cache file read error\n"); fBad = 1; } } if (fBad) { kObjCachePurge(pCache); pCache->fNewCache = 1; } /* * Disassociate the buffer from the stream changing * it to non-buffered mode. */ if (setvbuf(pCache->pFile, NULL, _IONBF, 0) != 0) FatalDie("setvbuf(,0,,0) failed: %s\n", strerror(errno)); } /** * Re-writes the cache file. * * @param pCache The cache to commit and unlock. */ static void kObjCacheWrite(PKOBJCACHE pCache) { unsigned i; off_t cb; char szBuf[8192]; assert(pCache->fLocked); assert(pCache->fDirty); /* * Rewind the file & stream, and associate a temporary buffer * with the stream to speed up the writing. */ if (lseek(pCache->fd, 0, SEEK_SET) == -1) FatalDie("lseek(cache-fd) failed: %s\n", strerror(errno)); rewind(pCache->pFile); if (setvbuf(pCache->pFile, szBuf, _IOFBF, sizeof(szBuf)) != 0) FatalDie("setvbuf failed: %s\n", strerror(errno)); /* * Write the header. */ pCache->uGeneration++; fprintf(pCache->pFile, "magic=kObjCache-v0.1.0\n" "generation=%d\n" "digests=%d\n", pCache->uGeneration, pCache->cDigests); /* * Write the digests. */ for (i = 0; i < pCache->cDigests; i++) { PCKOCDIGEST pDigest = &pCache->paDigests[i]; PKOCSUM pSum; if (pDigest->pszAbsPath) fprintf(pCache->pFile, "digest-abs-#%u=%s\n", i, pDigest->pszAbsPath); if (pDigest->pszRelPath) fprintf(pCache->pFile, "digest-rel-#%u=%s\n", i, pDigest->pszRelPath); fprintf(pCache->pFile, "key-#%u=%u\n", i, pDigest->uKey); fprintf(pCache->pFile, "target-#%u=%s\n", i, pDigest->pszTarget); fprintf(pCache->pFile, "comp-argv-sum-#%u=", i); kOCSumFPrintf(&pDigest->SumCompArgv, pCache->pFile); for (pSum = &pDigest->SumHead; pSum; pSum = pSum->pNext) { fprintf(pCache->pFile, "sum-#%u=", i); kOCSumFPrintf(pSum, pCache->pFile); } } /* * Close the stream and unlock fhe file. * (Closing the stream shouldn't close the file handle IIRC...) */ fprintf(pCache->pFile, "the-end=fine\n"); errno = 0; if ( fflush(pCache->pFile) < 0 || ferror(pCache->pFile)) { int iErr = errno; fclose(pCache->pFile); UnlinkFileInDir(pCache->pszName, pCache->pszDir); FatalDie("Stream error occured while writing '%s' in '%s': %s\n", pCache->pszName, pCache->pszDir, strerror(iErr)); } if (setvbuf(pCache->pFile, NULL, _IONBF, 0) != 0) FatalDie("setvbuf(,0,,0) failed: %s\n", strerror(errno)); cb = lseek(pCache->fd, 0, SEEK_CUR); if (cb == -1) FatalDie("lseek(cache-file,0,CUR) failed: %s\n", strerror(errno)); #if defined(__WIN__) if (_chsize(pCache->fd, cb) == -1) #else if (ftruncate(pCache->fd, cb) == -1) #endif FatalDie("file truncation failed: %s\n", strerror(errno)); InfoMsg(4, "wrote '%s' in '%s', %d bytes\n", pCache->pszName, pCache->pszDir, cb); } /** * Cleans out all invalid digests.s * * This is done periodically from the unlock routine to make * sure we don't accidentally accumulate stale digests. * * @param pCache The cache to chek. */ static void kObjCacheClean(PKOBJCACHE pCache) { unsigned i = pCache->cDigests; while (i-- > 0) { /* * Try open it and purge it if it's bad. * (We don't kill the entry file because that's kmk clean's job.) */ PCKOCDIGEST pDigest = &pCache->paDigests[i]; PKOCENTRY pEntry = kOCEntryCreate(kOCDigestAbsPath(pDigest, pCache->pszDir)); kOCEntryRead(pEntry); if ( !kOCEntryCheck(pEntry) || !kOCDigestIsValid(pDigest, pEntry)) { unsigned cLeft; kOCDigestPurge(pDigest); pCache->cDigests--; cLeft = pCache->cDigests - i; if (cLeft) memmove(pDigest, pDigest + 1, cLeft * sizeof(*pDigest)); pCache->fDirty = 1; } kOCEntryDestroy(pEntry); } } /** * Locks the cache for exclusive access. * * This will open the file if necessary and lock the entire file * using the best suitable platform API (tricky). * * @param pCache The cache to lock. */ static void kObjCacheLock(PKOBJCACHE pCache) { struct stat st; #if defined(__WIN__) OVERLAPPED OverLapped; #endif assert(!pCache->fLocked); /* * Open it? */ if (pCache->fd < 0) { pCache->fd = OpenFileInDir(pCache->pszName, pCache->pszDir, O_CREAT | O_RDWR | O_BINARY, 0666); if (pCache->fd == -1) { MakePath(pCache->pszDir); pCache->fd = OpenFileInDir(pCache->pszName, pCache->pszDir, O_CREAT | O_RDWR | O_BINARY, 0666); if (pCache->fd == -1) FatalDie("Failed to create '%s' in '%s': %s\n", pCache->pszName, pCache->pszDir, strerror(errno)); } pCache->pFile = fdopen(pCache->fd, "r+b"); if (!pCache->pFile) FatalDie("fdopen failed: %s\n", strerror(errno)); if (setvbuf(pCache->pFile, NULL, _IONBF, 0) != 0) FatalDie("setvbuf(,0,,0) failed: %s\n", strerror(errno)); } /* * Lock it. */ #if defined(__WIN__) memset(&OverLapped, 0, sizeof(OverLapped)); if (!LockFileEx((HANDLE)_get_osfhandle(pCache->fd), LOCKFILE_EXCLUSIVE_LOCK, 0, ~0, 0, &OverLapped)) FatalDie("Failed to lock the cache file: Windows Error %d\n", GetLastError()); #elif defined(__sun__) { struct flock fl; fl.l_whence = 0; fl.l_start = 0; fl.l_len = 0; fl.l_type = F_WRLCK; if (fcntl(pCache->fd, F_SETLKW, &fl) != 0) FatalDie("Failed to lock the cache file: %s\n", strerror(errno)); } #else if (flock(pCache->fd, LOCK_EX) != 0) FatalDie("Failed to lock the cache file: %s\n", strerror(errno)); #endif pCache->fLocked = 1; /* * Check for new cache and read it it's an existing cache. * * There is no point in initializing a new cache until we've finished * compiling and has something to put into it, so we'll leave it as a * 0 byte file. */ if (fstat(pCache->fd, &st) == -1) FatalDie("fstat(cache-fd) failed: %s\n", strerror(errno)); if (st.st_size) kObjCacheRead(pCache); else { pCache->fNewCache = 1; InfoMsg(2, "the cache file is empty\n"); } } /** * Unlocks the cache (without writing anything back). * * @param pCache The cache to unlock. */ static void kObjCacheUnlock(PKOBJCACHE pCache) { #if defined(__WIN__) OVERLAPPED OverLapped; #endif assert(pCache->fLocked); /* * Write it back if it's dirty. */ if (pCache->fDirty) { if ( pCache->cDigests >= 16 && (pCache->uGeneration % 19) == 19) kObjCacheClean(pCache); kObjCacheWrite(pCache); pCache->fDirty = 0; } /* * Lock it. */ #if defined(__WIN__) memset(&OverLapped, 0, sizeof(OverLapped)); if (!UnlockFileEx((HANDLE)_get_osfhandle(pCache->fd), 0, ~0U, 0, &OverLapped)) FatalDie("Failed to unlock the cache file: Windows Error %d\n", GetLastError()); #elif defined(__sun__) { struct flock fl; fl.l_whence = 0; fl.l_start = 0; fl.l_len = 0; fl.l_type = F_UNLCK; if (fcntl(pCache->fd, F_SETLKW, &fl) != 0) FatalDie("Failed to lock the cache file: %s\n", strerror(errno)); } #else if (flock(pCache->fd, LOCK_UN) != 0) FatalDie("Failed to unlock the cache file: %s\n", strerror(errno)); #endif pCache->fLocked = 0; } /** * Removes the entry from the cache. * * The entry doesn't need to be in the cache. * The cache entry (file) itself is not touched. * * @param pCache The cache. * @param pEntry The entry. */ static void kObjCacheRemoveEntry(PKOBJCACHE pCache, PCKOCENTRY pEntry) { unsigned i = pCache->cDigests; while (i-- > 0) { PKOCDIGEST pDigest = &pCache->paDigests[i]; if (ArePathsIdentical(kOCDigestAbsPath(pDigest, pCache->pszDir), kOCEntryAbsPath(pEntry))) { unsigned cLeft; kOCDigestPurge(pDigest); pCache->cDigests--; cLeft = pCache->cDigests - i; if (cLeft) memmove(pDigest, pDigest + 1, cLeft * sizeof(*pDigest)); pCache->fDirty = 1; InfoMsg(3, "removing entry '%s'; %d left.\n", kOCEntryAbsPath(pEntry), pCache->cDigests); } } } /** * Inserts the entry into the cache. * * The cache entry (file) itself is not touched by this operation, * the pEntry object otoh is. * * @param pCache The cache. * @param pEntry The entry. */ static void kObjCacheInsertEntry(PKOBJCACHE pCache, PKOCENTRY pEntry) { unsigned i; /* * Find a new key. */ pEntry->uKey = pCache->uNextKey++; if (!pEntry->uKey) pEntry->uKey = pCache->uNextKey++; i = pCache->cDigests; while (i-- > 0) if (pCache->paDigests[i].uKey == pEntry->uKey) { pEntry->uKey = pCache->uNextKey++; if (!pEntry->uKey) pEntry->uKey = pCache->uNextKey++; i = pCache->cDigests; } /* * Reallocate the digest array? */ if ( !(pCache->cDigests & 3) && (pCache->cDigests || !pCache->paDigests)) pCache->paDigests = xrealloc(pCache->paDigests, sizeof(pCache->paDigests[0]) * (pCache->cDigests + 4)); /* * Create a new digest. */ kOCDigestInitFromEntry(&pCache->paDigests[pCache->cDigests], pEntry); pCache->cDigests++; InfoMsg(4, "Inserted digest #%u: %s\n", pCache->cDigests - 1, kOCEntryAbsPath(pEntry)); pCache->fDirty = 1; } /** * Find a matching cache entry. */ static PKOCENTRY kObjCacheFindMatchingEntry(PKOBJCACHE pCache, PCKOCENTRY pEntry) { unsigned i = pCache->cDigests; assert(pEntry->fNeedCompiling); assert(!kOCSumIsEmpty(&pEntry->New.SumCompArgv)); assert(!kOCSumIsEmpty(&pEntry->New.SumHead)); while (i-- > 0) { /* * Matching? */ PCKOCDIGEST pDigest = &pCache->paDigests[i]; if ( kOCSumIsEqual(&pDigest->SumCompArgv, &pEntry->New.SumCompArgv) && kOCSumHasEqualInChain(&pDigest->SumHead, &pEntry->New.SumHead)) { /* * Try open it. */ unsigned cLeft; PKOCENTRY pRetEntry = kOCEntryCreate(kOCDigestAbsPath(pDigest, pCache->pszDir)); kOCEntryRead(pRetEntry); if ( kOCEntryCheck(pRetEntry) && kOCDigestIsValid(pDigest, pRetEntry)) return pRetEntry; kOCEntryDestroy(pRetEntry); /* bad entry, purge it. */ InfoMsg(3, "removing bad digest '%s'\n", kOCDigestAbsPath(pDigest, pCache->pszDir)); kOCDigestPurge(pDigest); pCache->cDigests--; cLeft = pCache->cDigests - i; if (cLeft) memmove(pDigest, pDigest + 1, cLeft * sizeof(*pDigest)); pCache->fDirty = 1; } } return NULL; } /** * Is this a new cache? * * @returns 1 if new, 0 if not new. * @param pEntry The entry. */ static int kObjCacheIsNew(PKOBJCACHE pCache) { return pCache->fNewCache; } /** * Prints a syntax error and returns the appropriate exit code * * @returns approriate exit code. * @param pszFormat The syntax error message. * @param ... Message args. */ static int SyntaxError(const char *pszFormat, ...) { va_list va; fprintf(stderr, "kObjCache: syntax error: "); va_start(va, pszFormat); vfprintf(stderr, pszFormat, va); va_end(va); return 1; } /** * Prints the usage. * @returns 0. */ static int usage(FILE *pOut) { fprintf(pOut, "syntax: kObjCache [--kObjCache-options] [-v|--verbose]\n" " < [-c|--cache-file ]\n" " | [-n|--name ] [[-d|--cache-dir ]] >\n" " <-f|--file >\n" " <-t|--target >\n" " [-r|--redir-stdout] [-p|--passthru] [--named-pipe-compile ]\n" " --kObjCache-cpp \n" " --kObjCache-cc \n" " [--kObjCache-both [args]]\n" ); fprintf(pOut, " [--kObjCache-cpp|--kObjCache-cc [more args]]\n" " kObjCache <-V|--version>\n" " kObjCache [-?|/?|-h|/h|--help|/help]\n" "\n" "The env.var. KOBJCACHE_DIR sets the default cache diretory (-d).\n" "The env.var. KOBJCACHE_OPTS allow you to specifie additional options\n" "without having to mess with the makefiles. These are appended with " "a --kObjCache-options between them and the command args.\n" "\n"); return 0; } int main(int argc, char **argv) { PKOBJCACHE pCache; PKOCENTRY pEntry; const char *pszCacheDir = getenv("KOBJCACHE_DIR"); const char *pszCacheName = NULL; const char *pszCacheFile = NULL; const char *pszEntryFile = NULL; const char **papszArgvPreComp = NULL; unsigned cArgvPreComp = 0; const char *pszPreCompName = NULL; int fRedirPreCompStdOut = 0; const char **papszArgvCompile = NULL; unsigned cArgvCompile = 0; const char *pszObjName = NULL; int fRedirCompileStdIn = 0; const char *pszNmPipeCompile = NULL; const char *pszMakeDepFilename = NULL; int fMakeDepFixCase = 0; int fMakeDepGenStubs = 0; int fMakeDepQuiet = 0; int fOptimizePreprocessorOutput = 0; const char *pszTarget = NULL; enum { kOC_Options, kOC_CppArgv, kOC_CcArgv, kOC_BothArgv } enmMode = kOC_Options; size_t cch; char *psz; int i; SetErrorPrefix("kObjCache"); /* * Arguments passed in the environmnet? */ psz = getenv("KOBJCACHE_OPTS"); if (psz) AppendArgs(&argc, &argv, psz, "--kObjCache-options"); /* * Parse the arguments. */ if (argc <= 1) return usage(stderr); for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "--kObjCache-cpp")) { enmMode = kOC_CppArgv; if (!pszPreCompName) { if (++i >= argc) return SyntaxError("--kObjCache-cpp requires an object filename!\n"); pszPreCompName = argv[i]; } } else if (!strcmp(argv[i], "--kObjCache-cc")) { enmMode = kOC_CcArgv; if (!pszObjName) { if (++i >= argc) return SyntaxError("--kObjCache-cc requires an preprocessor output filename!\n"); pszObjName = argv[i]; } } else if (!strcmp(argv[i], "--kObjCache-both")) enmMode = kOC_BothArgv; else if (!strcmp(argv[i], "--kObjCache-options")) enmMode = kOC_Options; else if (!strcmp(argv[i], "--help")) return usage(stderr); else if (enmMode != kOC_Options) { if (enmMode == kOC_CppArgv || enmMode == kOC_BothArgv) { if (!(cArgvPreComp % 16)) papszArgvPreComp = xrealloc((void *)papszArgvPreComp, (cArgvPreComp + 17) * sizeof(papszArgvPreComp[0])); papszArgvPreComp[cArgvPreComp++] = argv[i]; papszArgvPreComp[cArgvPreComp] = NULL; } if (enmMode == kOC_CcArgv || enmMode == kOC_BothArgv) { if (!(cArgvCompile % 16)) papszArgvCompile = xrealloc((void *)papszArgvCompile, (cArgvCompile + 17) * sizeof(papszArgvCompile[0])); papszArgvCompile[cArgvCompile++] = argv[i]; papszArgvCompile[cArgvCompile] = NULL; } } else if (!strcmp(argv[i], "-f") || !strcmp(argv[i], "--entry-file")) { if (i + 1 >= argc) return SyntaxError("%s requires a cache entry filename!\n", argv[i]); pszEntryFile = argv[++i]; } else if (!strcmp(argv[i], "-c") || !strcmp(argv[i], "--cache-file")) { if (i + 1 >= argc) return SyntaxError("%s requires a cache filename!\n", argv[i]); pszCacheFile = argv[++i]; } else if (!strcmp(argv[i], "-n") || !strcmp(argv[i], "--name")) { if (i + 1 >= argc) return SyntaxError("%s requires a cache name!\n", argv[i]); pszCacheName = argv[++i]; } else if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--cache-dir")) { if (i + 1 >= argc) return SyntaxError("%s requires a cache directory!\n", argv[i]); pszCacheDir = argv[++i]; } else if (!strcmp(argv[i], "-t") || !strcmp(argv[i], "--target")) { if (i + 1 >= argc) return SyntaxError("%s requires a target platform/arch name!\n", argv[i]); pszTarget = argv[++i]; } else if (!strcmp(argv[i], "--named-pipe-compile")) { if (i + 1 >= argc) return SyntaxError("%s requires a pipe name!\n", argv[i]); pszNmPipeCompile = argv[++i]; fRedirCompileStdIn = 0; } else if (!strcmp(argv[i], "-m") || !strcmp(argv[i], "--make-dep-file")) { if (i + 1 >= argc) return SyntaxError("%s requires a filename!\n", argv[i]); pszMakeDepFilename = argv[++i]; } else if (!strcmp(argv[i], "--make-dep-fix-case")) fMakeDepFixCase = 1; else if (!strcmp(argv[i], "--make-dep-gen-stubs")) fMakeDepGenStubs = 1; else if (!strcmp(argv[i], "--make-dep-quiet")) fMakeDepQuiet = 1; else if (!strcmp(argv[i], "-O1") || !strcmp(argv[i], "--optimize-1")) fOptimizePreprocessorOutput = 1; else if (!strcmp(argv[i], "-O2") || !strcmp(argv[i], "--optimize-2")) fOptimizePreprocessorOutput = 1 | 2; else if (!strcmp(argv[i], "-p") || !strcmp(argv[i], "--passthru")) fRedirPreCompStdOut = fRedirCompileStdIn = 1; else if (!strcmp(argv[i], "-r") || !strcmp(argv[i], "--redir-stdout")) fRedirPreCompStdOut = 1; else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose")) g_cVerbosityLevel++; else if (!strcmp(argv[i], "-q") || !strcmp(argv[i], "--quiet")) g_cVerbosityLevel = 0; else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-?") || !strcmp(argv[i], "/h") || !strcmp(argv[i], "/?") || !strcmp(argv[i], "/help")) { usage(stdout); return 0; } else if (!strcmp(argv[i], "-V") || !strcmp(argv[i], "--version")) { printf("kObjCache - kBuild version %d.%d.%d ($Revision: 3110 $)\n" "Copyright (c) 2007-2012 knut st. osmundsen\n", KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH); return 0; } else return SyntaxError("Doesn't grok '%s'!\n", argv[i]); } if (!pszEntryFile) return SyntaxError("No cache entry filename (-f)!\n"); if (!pszTarget) return SyntaxError("No target name (-t)!\n"); if (!cArgvCompile) return SyntaxError("No compiler arguments (--kObjCache-cc)!\n"); if (!cArgvPreComp) return SyntaxError("No preprocessor arguments (--kObjCache-cc)!\n"); /* * Calc the cache file name. * It's a bit messy since the extension has to be replaced. */ if (!pszCacheFile) { if (!pszCacheDir) return SyntaxError("No cache dir (-d / KOBJCACHE_DIR) and no cache filename!\n"); if (!pszCacheName) { psz = (char *)FindFilenameInPath(pszEntryFile); if (!*psz) return SyntaxError("The cache file (-f) specifies a directory / nothing!\n"); cch = psz - pszEntryFile; pszCacheName = memcpy(xmalloc(cch + 5), psz, cch + 1); psz = strrchr(pszCacheName, '.'); if (!psz || psz <= pszCacheName) psz = (char *)pszCacheName + cch; memcpy(psz, ".koc", sizeof(".koc")); } pszCacheFile = MakePathFromDirAndFile(pszCacheName, pszCacheDir); } /* * Create and initialize the two objects we'll be working on. * * We're supposed to be the only ones actually writing to the local file, * so it's perfectly fine to read it here before we lock it. This simplifies * the detection of object name and compiler argument changes. */ SetErrorPrefix("kObjCache - %s", FindFilenameInPath(pszCacheFile)); pCache = kObjCacheCreate(pszCacheFile); pEntry = kOCEntryCreate(pszEntryFile); kOCEntryRead(pEntry); kOCEntrySetCppName(pEntry, pszPreCompName); kOCEntrySetCompileObjName(pEntry, pszObjName); kOCEntrySetCompileArgv(pEntry, papszArgvCompile, cArgvCompile); kOCEntrySetTarget(pEntry, pszTarget); kOCEntrySetPipedMode(pEntry, fRedirPreCompStdOut, fRedirCompileStdIn, pszNmPipeCompile); kOCEntrySetDepFilename(pEntry, pszMakeDepFilename, fMakeDepFixCase, fMakeDepQuiet, fMakeDepGenStubs); kOCEntrySetOptimizations(pEntry, fOptimizePreprocessorOutput); /* * Open (& lock) the two files and do validity checks and such. */ kObjCacheLock(pCache); if ( kObjCacheIsNew(pCache) && kOCEntryNeedsCompiling(pEntry)) { /* * Both files are missing/invalid. * Optimize this path as it is frequently used when making a clean build. */ kObjCacheUnlock(pCache); InfoMsg(1, "doing full compile\n"); kOCEntryPreProcessAndCompile(pEntry, papszArgvPreComp, cArgvPreComp); kObjCacheLock(pCache); } else { /* * Do the preprocess (don't need to lock the cache file for this). */ kObjCacheUnlock(pCache); kOCEntryPreProcess(pEntry, papszArgvPreComp, cArgvPreComp); /* * Check if we need to recompile. If we do, try see if the is a cache entry first. */ kOCEntryCalcRecompile(pEntry); if (kOCEntryNeedsCompiling(pEntry)) { PKOCENTRY pUseEntry; kObjCacheLock(pCache); kObjCacheRemoveEntry(pCache, pEntry); pUseEntry = kObjCacheFindMatchingEntry(pCache, pEntry); if (pUseEntry) { InfoMsg(1, "using cache entry '%s'\n", kOCEntryAbsPath(pUseEntry)); kOCEntryCopy(pEntry, pUseEntry); kOCEntryDestroy(pUseEntry); } else { kObjCacheUnlock(pCache); InfoMsg(1, "recompiling\n"); kOCEntryCompileIt(pEntry); kObjCacheLock(pCache); } } else { InfoMsg(1, "no need to recompile\n"); kObjCacheLock(pCache); } } /* * Update the cache files. */ kObjCacheRemoveEntry(pCache, pEntry); kObjCacheInsertEntry(pCache, pEntry); kOCEntryWrite(pEntry); kObjCacheUnlock(pCache); kObjCacheDestroy(pCache); if (fOptimizePreprocessorOutput) { InfoMsg(3, "g_cbMemMoved=%#x (%d)\n", g_cbMemMoved, g_cbMemMoved); InfoMsg(3, "g_cMemMoves=%#x (%d)\n", g_cMemMoves, g_cMemMoves); } return 0; } /** @page kObjCache Benchmarks. * * (2007-06-10) * * Mac OS X debug -j 3 cached clobber build (rm -Rf out ; sync ; svn diff ; sync ; sleep 1 ; time kmk -j 3 USE_KOBJCACHE=1): * real 11m28.811s * user 13m59.291s * sys 3m24.590s * * Mac OS X debug -j 3 cached depend build [cdefs.h] (touch include/iprt/cdefs.h ; sync ; svn diff ; sync ; sleep 1 ; time kmk -j 3 USE_KOBJCACHE=1): * real 1m26.895s * user 1m26.971s * sys 0m32.532s * * Mac OS X debug -j 3 cached depend build [err.h] (touch include/iprt/err.h ; sync ; svn diff ; sync ; sleep 1 ; time kmk -j 3 USE_KOBJCACHE=1): * real 1m18.049s * user 1m20.462s * sys 0m27.887s * * Mac OS X release -j 3 cached clobber build (rm -Rf out/darwin.x86/release ; sync ; svn diff ; sync ; sleep 1 ; time kmk -j 3 USE_KOBJCACHE=1 BUILD_TYPE=release): * real 13m27.751s * user 18m12.654s * sys 3m25.170s * * Mac OS X profile -j 3 cached clobber build (rm -Rf out/darwin.x86/profile ; sync ; svn diff ; sync ; sleep 1 ; time kmk -j 3 USE_KOBJCACHE=1 BUILD_TYPE=profile): * real 9m9.720s * user 8m53.005s * sys 2m13.110s * * Mac OS X debug -j 3 clobber build (rm -Rf out/darwin.x86/debug ; sync ; svn diff ; sync ; sleep 1 ; time kmk -j 3 BUILD_TYPE=debug): * real 10m18.129s * user 12m52.687s * sys 2m51.277s * * Mac OS X debug -j 3 debug build [cdefs.h] (touch include/iprt/cdefs.h ; sync ; svn diff ; sync ; sleep 1 ; time kmk -j 3 BUILD_TYPE=debug): * real 4m46.147s * user 5m27.087s * sys 1m11.775s * * Mac OS X debug -j 3 debug build [err.h] (touch include/iprt/cdefs.h ; sync ; svn diff ; sync ; sleep 1 ; time kmk -j 3 BUILD_TYPE=debug): * real 4m17.572s * user 5m7.450s * sys 1m3.450s * * Mac OS X release -j 3 clobber build (rm -Rf out/darwin.x86/release ; sync ; svn diff ; sync ; sleep 1 ; time kmk -j 3 BUILD_TYPE=release): * real 12m14.742s * user 17m11.794s * sys 2m51.454s * * Mac OS X profile -j 3 clobber build (rm -Rf out/darwin.x86/profile ; sync ; svn diff ; sync ; sleep 1 ; time kmk -j 3 BUILD_TYPE=profile): * real 12m33.821s * user 17m35.086s * sys 2m53.312s * * Note. The profile build can pick object files from the release build. * (all with KOBJCACHE_OPTS=-v; which means a bit more output and perhaps a second or two slower.) */ kbuild-3149/src/lib/0000755000175000017500000000000013252530252014240 5ustar locutuslocutuskbuild-3149/src/lib/nt_fullpath.h0000644000175000017500000000223713252530204016732 0ustar locutuslocutus/* $Id: nt_fullpath.h 2849 2016-08-30 14:28:46Z bird $ */ /** @file * fixcase - fixes the case of paths, windows specific. */ /* * Copyright (c) 2004-2016 knut st. osmundsen * * This file is part of kBuild. * * kBuild 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. * * kBuild 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 kBuild. If not, see * */ #ifndef ___lib_nt_fullpath_h___ #define ___lib_nt_fullpath_h___ #ifdef __cpluslus extern "C" #endif extern void nt_fullpath(const char *pszPath, char *pszFull, size_t cchFull); extern void nt_fullpath_cached(const char *pszPath, char *pszFull, size_t cchFull); #ifdef __cpluslus } #endif #endif kbuild-3149/src/lib/Makefile.kmk0000644000175000017500000000440613252530204016462 0ustar locutuslocutus# $Id: Makefile.kmk 3114 2017-10-29 18:02:04Z bird $ ## @file # Sub-makefile for various libraries and stuff. # # # Copyright (c) 2006-2016 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # SUB_DEPTH = ../.. include $(KBUILD_PATH)/subheader.kmk LIBRARIES += kDep kDep_TEMPLATE = LIB kDep_DEFS.win += NEED_ISBLANK=1 __WIN32__=1 kDep_SOURCES = kDep.c kDep_NOINST = 1 LIBRARIES += kUtil kUtil_TEMPLATE = LIB kUtil_DEFS.win = __WIN__ kUtil_SOURCES = \ crc32.c \ md5.c \ maybe_con_write.c \ maybe_con_fwrite.c \ dos2unix.c \ kbuild_version.c kUtil_SOURCES.win = \ msc_buffered_printf.c \ nt_fullpath.c \ nt_fullpath_cached.c \ quote_argv.c \ quoted_spawn.c \ nt/nthlpcore.c \ nt/nthlpfs.c \ nt/ntdir.c \ nt/ntstat.c \ nt/ntunlink.c \ nt/ntutimes.c \ nt/fts-nt.c \ nt/kFsCache.c \ kStuff/kHlp/CRT/kHlpCRTString.cpp \ kStuff/kHlp/CRT/kHlpCRTAlloc.cpp kUtil_SOURCES.solaris = \ restartable-syscall-wrappers.c #kUtil_SOURCES.linux = \ # restartable-syscall-wrappers.c kUtil_NOINST = 1 kbuild_version.c_DEFS = KBUILD_SVN_REV=$(KBUILD_SVN_REV) LIBRARIES.win += kWinStartup kWinStartup_TEMPLATE = LIB kWinStartup_SOURCES = startuphacks-win.c kWinStartup_NOINST = 1 PROGRAMS += wrapper wrapper_TEMPLATE = BIN wrapper_SOURCES = wrapper.c wrapper_NOINST = 1 PROGRAMS.win += tstNtStat tstNtStat_TEMPLATE = BIN tstNtStat_SOURCES = nt/tstNtStat.c tstNtStat_LIBS = $(LIB_KUTIL) tstNtStat_NOINST = 1 PROGRAMS.win += tstNtFts tstNtFts_TEMPLATE = BIN tstNtFts_SOURCES = nt/tstNtFts.c nt/fts-nt.c tstNtFts_LIBS = $(LIB_KUTIL) tstNtFts_NOINST = 1 include $(FILE_KBUILD_SUB_FOOTER) kbuild-3149/src/lib/md5.c0000644000175000017500000001752413252530204015077 0ustar locutuslocutus/* * This code implements the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was * written by Colin Plumb in 1993, no copyright is claimed. * This code is in the public domain; do with it what you wish. * * Equivalent code is available from RSA Data Security, Inc. * This code has been tested against that, and is equivalent, * except that you don't need to include two pages of legalese * with every copy. * * To compute the message digest of a chunk of bytes, declare an * MD5Context structure, pass it to MD5Init, call MD5Update as * needed on buffers full of bytes, and then call MD5Final, which * will fill a supplied 16-byte array with the digest. */ #include #include "md5.h" #define uint32 uint32_t #include "k/kDefs.h" #if K_ENDIAN == K_ENDIAN_LITTLE # define byteReverse(buf, len) do { /* Nothing */ } while (0) #else /* * Note: this code is harmless on little-endian machines. */ void byteReverse(unsigned char *buf, unsigned longs) { uint32 t; do { t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | ((unsigned) buf[1] << 8 | buf[0]); *(uint32 *) buf = t; buf += 4; } while (--longs); } #endif /* * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious * initialization constants. */ void MD5Init(struct MD5Context *ctx) { ctx->buf[0] = 0x67452301; ctx->buf[1] = 0xefcdab89; ctx->buf[2] = 0x98badcfe; ctx->buf[3] = 0x10325476; ctx->bits[0] = 0; ctx->bits[1] = 0; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ void MD5Update(struct MD5Context *ctx, const unsigned char *buf, unsigned len) { uint32 t; /* Update bitcount */ t = ctx->bits[0]; if ((ctx->bits[0] = t + ((uint32) len << 3)) < t) ctx->bits[1]++; /* Carry from low to high */ ctx->bits[1] += len >> 29; t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ /* Handle any leading odd-sized chunks */ if (t) { unsigned char *p = (unsigned char *) ctx->in + t; t = 64 - t; if (len < t) { memcpy(p, buf, len); return; } memcpy(p, buf, t); byteReverse(ctx->in, 16); MD5Transform(ctx->buf, (uint32 *) ctx->in); buf += t; len -= t; } /* Process data in 64-byte chunks */ while (len >= 64) { memcpy(ctx->in, buf, 64); byteReverse(ctx->in, 16); MD5Transform(ctx->buf, (uint32 *) ctx->in); buf += 64; len -= 64; } /* Handle any remaining bytes of data. */ memcpy(ctx->in, buf, len); } /* * Final wrapup - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ void MD5Final(unsigned char digest[16], struct MD5Context *ctx) { unsigned count; unsigned char *p; /* Compute number of bytes mod 64 */ count = (ctx->bits[0] >> 3) & 0x3F; /* Set the first char of padding to 0x80. This is safe since there is always at least one byte free */ p = ctx->in + count; *p++ = 0x80; /* Bytes of padding needed to make 64 bytes */ count = 64 - 1 - count; /* Pad out to 56 mod 64 */ if (count < 8) { /* Two lots of padding: Pad the first block to 64 bytes */ memset(p, 0, count); byteReverse(ctx->in, 16); MD5Transform(ctx->buf, (uint32 *) ctx->in); /* Now fill the next block with 56 bytes */ memset(ctx->in, 0, 56); } else { /* Pad block to 56 bytes */ memset(p, 0, count - 8); } byteReverse(ctx->in, 14); /* Append length in bits and transform */ ((uint32 *) ctx->in)[14] = ctx->bits[0]; ((uint32 *) ctx->in)[15] = ctx->bits[1]; MD5Transform(ctx->buf, (uint32 *) ctx->in); byteReverse((unsigned char *) ctx->buf, 4); memcpy(digest, ctx->buf, 16); memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ } /* The four core functions - F1 is optimized somewhat */ /* #define F1(x, y, z) (x & y | ~x & z) */ #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) F1(z, x, y) #define F3(x, y, z) (x ^ y ^ z) #define F4(x, y, z) (y ^ (x | ~z)) /* This is the central step in the MD5 algorithm. */ #define MD5STEP(f, w, x, y, z, data, s) \ ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data. MD5Update blocks * the data and converts bytes into longwords for this routine. */ void MD5Transform(uint32 buf[4], uint32 in[16]) { register uint32 a, b, c, d; a = buf[0]; b = buf[1]; c = buf[2]; d = buf[3]; MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); buf[0] += a; buf[1] += b; buf[2] += c; buf[3] += d; } kbuild-3149/src/lib/kbuild_version.c0000644000175000017500000000446713252530204017433 0ustar locutuslocutus/* $Id: kbuild_version.c 2851 2016-08-31 17:30:52Z bird $ */ /** @file * kbuild_version(), helper function. */ /* * Copyright (c) 2007-2013 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "kbuild_version.h" #include #include /** * Prints the kBuild version message and returns 0. * * @returns 0 * @param argv0 The argv0. */ int kbuild_version(const char *argv0) { const char *tmp; /* skip the path */ for (tmp = strpbrk(argv0, "\\/:"); tmp; tmp = strpbrk(argv0, "\\/:")) argv0 = tmp + 1; /* find the end, ignoring extenions */ tmp = strrchr(argv0, '.'); if (!tmp) tmp = strchr(argv0, '\0'); printf("%.*s - kBuild version %d.%d.%d (r%u)\n", (int)(tmp - argv0), argv0, KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH, KBUILD_SVN_REV); return 0; } kbuild-3149/src/lib/maybe_con_write.c0000644000175000017500000001031713252530204017551 0ustar locutuslocutus/* $Id: maybe_con_write.c 3065 2017-09-30 12:52:35Z bird $ */ /** @file * maybe_con_write - Optimized console output on windows. */ /* * Copyright (c) 2016 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ #ifdef KBUILD_OS_WINDOWS # include #endif #include #ifdef _MSC_VER # include # include typedef intptr_t ssize_t; typedef unsigned int to_write_t; #else # include typedef size_t to_write_t; #endif /** * Drop-in write replacement for optimizing console output on windows. * * @returns Number of bytes written, -1 + errno on failure. * @param fd The file descript to write to. * @param pvBuf What to write. * @param cbToWrite How much to write. */ ssize_t maybe_con_write(int fd, void *pvBuf, size_t cbToWrite) { ssize_t cbWritten; #ifdef KBUILD_OS_WINDOWS /* * If it's a TTY, do our own conversion to wide char and * call WriteConsoleW directly. */ if (cbToWrite > 0 && isatty(fd)) { HANDLE hCon = (HANDLE)_get_osfhandle(fd); if ( hCon != INVALID_HANDLE_VALUE && hCon != NULL) { size_t cwcTmp = cbToWrite * 2 + 16; wchar_t *pawcTmp = (wchar_t *)malloc(cwcTmp * sizeof(wchar_t)); if (pawcTmp) { int cwcToWrite; static UINT s_uConsoleCp = 0; if (s_uConsoleCp == 0) s_uConsoleCp = GetConsoleCP(); cwcToWrite = MultiByteToWideChar(s_uConsoleCp, 0 /*dwFlags*/, pvBuf, (int)cbToWrite, pawcTmp, (int)(cwcTmp - 1)); if (cwcToWrite > 0) { /* Let the CRT do the rest. At least the Visual C++ 2010 CRT sources indicates _cputws will do the right thing we want. */ pawcTmp[cwcToWrite] = '\0'; if (_cputws(pawcTmp) >= 0) return cbToWrite; return -1; } } } } #endif /* * Semi regular write handling. */ cbWritten = write(fd, pvBuf, (to_write_t)cbToWrite); if (cbWritten == (ssize_t)cbToWrite) { /* likely */ } else if (cbWritten >= 0 || errno == EINTR) { if (cbWritten < 0) cbWritten = 0; while (cbWritten < (ssize_t)cbToWrite) { ssize_t cbThis = write(fd, (char *)pvBuf + cbWritten, (to_write_t)(cbToWrite - cbWritten)); if (cbThis >= 0) cbWritten += cbThis; else if (errno != EINTR) return -1; } } return cbWritten; } kbuild-3149/src/lib/md5.h0000644000175000017500000000061513252530204015075 0ustar locutuslocutus#ifndef MD5_H #define MD5_H #include "mytypes.h" struct MD5Context { uint32_t buf[4]; uint32_t bits[2]; unsigned char in[64]; }; void MD5Init(struct MD5Context *); void MD5Update(struct MD5Context *, const unsigned char *, unsigned); void MD5Final(unsigned char digest[16], struct MD5Context *); void MD5Transform(uint32_t buf[4], uint32_t in[16]); #endif /* !MD5_H */ kbuild-3149/src/lib/testcase/0000755000175000017500000000000013252530204016050 5ustar locutuslocutuskbuild-3149/src/lib/testcase/mixed-text.txt0000644000175000017500000000261113252530204020701 0ustar locutuslocutusLorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing sem neque sed ipsum. Nam quam nunc, blandit vel, luctus pulvinar, hendrerit id, lorem. Maecenas nec odio et ante tincidunt tempus. Donec vitae sapien ut libero venenatis faucibus. Nullam quis ante. Etiam sit amet orci eget eros faucibus tincidunt. Duis leo. Sed fringilla mauris sit amet nibh. Donec sodales sagittis magna. Sed consequat, leo eget bibendum sodales, augue velit cursus nunc, kbuild-3149/src/lib/testcase/unix-text.txt0000644000175000017500000000255413252530204020564 0ustar locutuslocutusLorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing sem neque sed ipsum. Nam quam nunc, blandit vel, luctus pulvinar, hendrerit id, lorem. Maecenas nec odio et ante tincidunt tempus. Donec vitae sapien ut libero venenatis faucibus. Nullam quis ante. Etiam sit amet orci eget eros faucibus tincidunt. Duis leo. Sed fringilla mauris sit amet nibh. Donec sodales sagittis magna. Sed consequat, leo eget bibendum sodales, augue velit cursus nunc, kbuild-3149/src/lib/testcase/dos2unix-test.cmd0000644000175000017500000000241313252530204021265 0ustar locutuslocutus@setlocal @set INSPROG="E:\kBuild\svn\trunk\out\win.amd64\debug\stage\kBuild\bin\win.amd64\kmk_install.exe" @set TMPFILE="e:\tmp\tmp.txt" @set CMPPROG="E:\kBuild\svn\trunk\kBuild\bin\win.amd64\kmk_cmp.exe" @set RMPROG="E:\kBuild\svn\trunk\kBuild\bin\win.amd64\kmk_rm.exe" @%RMPROG% -f -- %TMPFILE% @echo ... dos2unix ... %INSPROG% --dos2unix dos-text.txt %TMPFILE% @if not errorlevel 0 goto end %CMPPROG% -- %TMPFILE% unix-text.txt @if not errorlevel 0 goto end %INSPROG% --dos2unix unix-text.txt %TMPFILE% @if not errorlevel 0 goto end %CMPPROG% -- %TMPFILE% unix-text.txt @if not errorlevel 0 goto end %INSPROG% --dos2unix mixed-text.txt %TMPFILE% @if not errorlevel 0 goto end %CMPPROG% -- %TMPFILE% unix-text.txt @if not errorlevel 0 goto end @echo ... unix2dos ... %INSPROG% --unix2dos unix-text.txt %TMPFILE% @if not errorlevel 0 goto end %CMPPROG% -- %TMPFILE% dos-text.txt @if not errorlevel 0 goto end %INSPROG% --unix2dos dos-text.txt %TMPFILE% @if not errorlevel 0 goto end %CMPPROG% -- %TMPFILE% dos-text.txt @if not errorlevel 0 goto end %INSPROG% --unix2dos mixed-text.txt %TMPFILE% @if not errorlevel 0 goto end %CMPPROG% -- %TMPFILE% dos-text.txt @if not errorlevel 0 goto end @%RMPROG% -f -- %TMPFILE% :end @endlocal kbuild-3149/src/lib/testcase/dos-text.txt0000644000175000017500000000261713252530204020366 0ustar locutuslocutusLorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing sem neque sed ipsum. Nam quam nunc, blandit vel, luctus pulvinar, hendrerit id, lorem. Maecenas nec odio et ante tincidunt tempus. Donec vitae sapien ut libero venenatis faucibus. Nullam quis ante. Etiam sit amet orci eget eros faucibus tincidunt. Duis leo. Sed fringilla mauris sit amet nibh. Donec sodales sagittis magna. Sed consequat, leo eget bibendum sodales, augue velit cursus nunc, kbuild-3149/src/lib/kDep.h0000644000175000017500000000431013252530204015267 0ustar locutuslocutus/* $Id: kDep.h 2955 2016-09-21 19:05:53Z bird $ */ /** @file * kDep - Common Dependency Managemnt Code. */ /* * Copyright (c) 2004-2013 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___kDep_h #define ___kDep_h /** A dependency. */ typedef struct DEP { /** Next dependency in the list. */ struct DEP *pNext; /** The filename hash. */ unsigned uHash; /** The length of the filename. */ size_t cchFilename; /** The filename. */ char szFilename[4]; } DEP, *PDEP; extern PDEP depAdd(const char *pszFilename, size_t cchFilename); extern void depOptimize(int fFixCase, int fQuiet, const char *pszIgnoredExt); extern void depPrint(FILE *pOutput); extern void depPrintStubs(FILE *pOutput); extern void depCleanup(void); extern void *depReadFileIntoMemory(FILE *pInput, size_t *pcbFile, void **ppvOpaque); extern void depFreeFileMemory(void *pvFile, void *pvOpaque); #ifdef ___k_kTypes_h___ extern void depHexDump(const KU8 *pb, size_t cb, size_t offBase); #endif #endif kbuild-3149/src/lib/crc32.c0000644000175000017500000001460713252530204015325 0ustar locutuslocutus/* $NetBSD: crc.c,v 1.18 2006/09/04 20:01:10 dsl Exp $ */ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * James W. Williams of NASA Goddard Space Flight Center. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /*#if HAVE_NBTOOL_CONFIG_H #include "nbtool_config.h" #endif*/ /*#include #if defined(__RCSID) && !defined(lint) #if 0 static char sccsid[] = "@(#)crc.c 8.1 (Berkeley) 6/17/93"; #else __RCSID("$NetBSD: crc.c,v 1.18 2006/09/04 20:01:10 dsl Exp $"); #endif #endif*/ /* not lint */ #include /*#include #include "extern.h"*/ #include "mytypes.h" #define u_int32_t uint32_t static const u_int32_t crctab[] = { 0x0, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 }; #if 0 /* * Compute a POSIX 1003.2 checksum. This routine has been broken out so that * other programs can use it. It takes a file descriptor to read from and * locations to store the crc and the number of bytes read. It returns 0 on * success and 1 on failure. Errno is set on failure. */ int crc(int fd, u_int32_t *cval, off_t *clen) { u_char *p; int nr; u_int32_t thecrc; off_t len; u_char buf[16 * 1024]; #endif #define COMPUTE(var, ch) (var) = (var) << 8 ^ crctab[(var) >> 24 ^ (ch)] #if 0 thecrc = 0; len = 0; while ((nr = read(fd, buf, sizeof(buf))) > 0) for (len += nr, p = buf; nr--; ++p) { COMPUTE(thecrc, *p); } if (nr < 0) return 1; *clen = len; /* Include the length of the file. */ for (; len != 0; len >>= 8) { COMPUTE(thecrc, len & 0xff); } *cval = ~thecrc; return 0; } #endif /* These two are rather more useful to the outside world */ uint32_t crc32(uint32_t thecrc, const void *buf, size_t len) { const uint8_t *p = buf; for (p = buf; len; p++, len--) COMPUTE(thecrc, *p); return thecrc; } #if 0 uint32_t crc_byte(uint32_t thecrc, unsigned int byte_val) { COMPUTE(thecrc, byte_val & 0xff); return thecrc; } #endif kbuild-3149/src/lib/restartable-syscall-wrappers.c0000644000175000017500000002073113252530204022225 0ustar locutuslocutus/* $Id: restartable-syscall-wrappers.c 2851 2016-08-31 17:30:52Z bird $ */ /** @file * restartable-syscall-wrappers.c - Workaround for annoying S11 "features". * * The symptoms are that open or mkdir occationally fails with EINTR when * receiving SIGCHLD at the wrong time. With a enough cores, this start * happening on a regular basis. * * The workaround here is to create our own wrappers for these syscalls which * will restart the syscall when appropriate. This depends on the libc * providing alternative names for the syscall entry points. */ /* * Copyright (c) 2011-2016 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #ifdef KBUILD_OS_SOLARIS # include /* Try drag in feature_tests.h. */ # include # undef _RESTRICT_KYWD # define _RESTRICT_KYWD # undef __PRAGMA_REDEFINE_EXTNAME #endif #include #include #include #include #include #include #include #include /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** Mangle a syscall name to it's weak alias. */ #ifdef KBUILD_OS_SOLARIS # define WRAP(a_name) _##a_name #elif defined(KBUILD_OS_LINUX) # define WRAP(a_name) __##a_name #else # error "Port Me" #endif /** Mangle a syscall name with optional '64' suffix. */ #if !defined(_LP64) && _FILE_OFFSET_BITS == 64 # define WRAP64(a_name) WRAP(a_name)##64 #else # define WRAP64(a_name) WRAP(a_name) #endif /** Check whether errno indicates restart. */ #ifdef ERESTART # define SHOULD_RESTART() (errno == EINTR || errno == ERESTART) #else # define SHOULD_RESTART() (errno == EINTR) #endif /** Used by XSTR. */ #define XSTR_INNER(x) #x /** Returns the expanded argument as a string. */ #define XSTR(x) XSTR_INNER(x) static int dlsym_libc(const char *pszSymbol, void **ppvSym) { static void *s_pvLibc = NULL; void *pvLibc; void *pvSym; /* * Use the RTLD_NEXT dl feature if present, it's designed for doing * exactly what we want here. */ #ifdef RTLD_NEXT pvSym = dlsym(RTLD_NEXT, pszSymbol); if (pvSym) { *ppvSym = pvSym; return 0; } #endif /* * Open libc. */ pvLibc = s_pvLibc; if (!pvLibc) { #ifdef RTLD_NOLOAD unsigned fFlags = RTLD_NOLOAD | RTLD_NOW; #else unsigned fFlags = RTLD_GLOBAL | RTLD_NOW; #endif #ifdef KBUILD_OS_LINUX pvLibc = dlopen("/lib/libc.so.6", fFlags); #else pvLibc = dlopen("/lib/libc.so", fFlags); #endif if (!pvLibc) { fprintf(stderr, "restartable-syscall-wrappers: failed to dlopen libc for resolving %s: %s\n", pszSymbol, dlerror()); errno = ENOSYS; return -1; } /** @todo check standard symbol? */ } /* * Resolve the symbol. */ pvSym = dlsym(pvLibc, pszSymbol); if (!pvSym) { fprintf(stderr, "restartable-syscall-wrappers: failed to resolve %s: %s\n", pszSymbol, dlerror()); errno = ENOSYS; return -1; } *ppvSym = pvSym; return 0; } #undef open int open(const char *pszPath, int fFlags, ...) { mode_t fMode; va_list va; int fd; static union { int (* pfnReal)(const char *, int, ...); void *pvSym; } s_u; if ( !s_u.pfnReal && dlsym_libc("open", &s_u.pvSym) != 0) return -1; va_start(va, fFlags); fMode = va_arg(va, mode_t); va_end(va); do fd = s_u.pfnReal(pszPath, fFlags, fMode); while (fd == -1 && SHOULD_RESTART()); return fd; } #undef open64 int open64(const char *pszPath, int fFlags, ...) { mode_t fMode; va_list va; int fd; static union { int (* pfnReal)(const char *, int, ...); void *pvSym; } s_u; if ( !s_u.pfnReal && dlsym_libc("open64", &s_u.pvSym) != 0) return -1; va_start(va, fFlags); fMode = va_arg(va, mode_t); va_end(va); do fd = s_u.pfnReal(pszPath, fFlags, fMode); while (fd == -1 && SHOULD_RESTART()); return fd; } #define WRAP_FN(a_Name, a_ParamsWithTypes, a_ParamsNoType, a_RetType, a_RetFailed) \ a_RetType a_Name a_ParamsWithTypes \ { \ static union \ { \ a_RetType (* pfnReal) a_ParamsWithTypes; \ void *pvSym; \ } s_u; \ a_RetType rc; \ \ if ( !s_u.pfnReal \ && dlsym_libc(#a_Name, &s_u.pvSym) != 0) \ return a_RetFailed; \ \ do \ rc = s_u.pfnReal a_ParamsNoType; \ while (rc == a_RetFailed && SHOULD_RESTART()); \ return rc; \ } typedef int ignore_semi_colon_##a_Name #undef mkdir WRAP_FN(mkdir, (const char *pszPath, mode_t fMode), (pszPath, fMode), int, -1); #undef rmdir WRAP_FN(rmdir, (const char *pszPath, mode_t fMode), (pszPath, fMode), int, -1); #undef unlink WRAP_FN(unlink, (const char *pszPath), (pszPath), int, -1); #undef remove WRAP_FN(remove, (const char *pszPath), (pszPath), int, -1); #undef symlink WRAP_FN(symlink, (const char *pszFrom, const char *pszTo), (pszFrom, pszTo), int, -1); #undef link WRAP_FN(link, (const char *pszFrom, const char *pszTo), (pszFrom, pszTo), int, -1); #undef stat WRAP_FN(stat, (const char *pszPath, struct stat *pStBuf), (pszPath, pStBuf), int, -1); #undef lstat WRAP_FN(lstat, (const char *pszPath, struct stat *pStBuf), (pszPath, pStBuf), int, -1); #undef stat64 WRAP_FN(stat64, (const char *pszPath, struct stat64 *pStBuf), (pszPath, pStBuf), int, -1); #undef lstat64 WRAP_FN(lstat64, (const char *pszPath, struct stat64 *pStBuf), (pszPath, pStBuf), int, -1); #undef read WRAP_FN(read, (int fd, void *pvBuf, size_t cbBuf), (fd, pvBuf, cbBuf), ssize_t, -1); #undef write WRAP_FN(write, (int fd, void *pvBuf, size_t cbBuf), (fd, pvBuf, cbBuf), ssize_t, -1); #undef fopen WRAP_FN(fopen, (const char *pszPath, const char *pszMode), (pszPath, pszMode), FILE *, NULL); #undef fopen64 WRAP_FN(fopen64, (const char *pszPath, const char *pszMode), (pszPath, pszMode), FILE *, NULL); #undef chmod WRAP_FN(chmod, (const char *pszPath, mode_t fMode), (pszPath, fMode), int, -1); #undef lchmod WRAP_FN(lchmod, (const char *pszPath, mode_t fMode), (pszPath, fMode), int, -1); #undef chown WRAP_FN(chown, (const char *pszPath, uid_t uid, gid_t gid), (pszPath, uid, gid), int, -1); #undef lchown WRAP_FN(lchown, (const char *pszPath, uid_t uid, gid_t gid), (pszPath, uid, gid), int, -1); #undef utime WRAP_FN(utime, (const char *pszPath, const struct utimbuf *pTimes), (pszPath, pTimes), int, -1); #undef utimes WRAP_FN(utimes, (const char *pszPath, const struct timeval *paTimes), (pszPath, paTimes), int, -1); #undef pathconf WRAP_FN(pathconf, (const char *pszPath, int iCfgNm), (pszPath, iCfgNm), long, -1); #undef readlink WRAP_FN(readlink, (const char *pszPath, char *pszBuf, size_t cbBuf), (pszPath, pszBuf, cbBuf), ssize_t, -1); kbuild-3149/src/lib/quote_argv.c0000644000175000017500000002056313252530204016563 0ustar locutuslocutus/* $Id: quote_argv.c 2912 2016-09-14 13:36:15Z bird $ */ /** @file * quote_argv - Correctly quote argv for spawn, windows specific. */ /* * Copyright (c) 2007-2016 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "quote_argv.h" #include #include #include #ifndef KBUILD_OS_WINDOWS # error "KBUILD_OS_WINDOWS not defined" #endif /** * Checks if this is an Watcom option where we must just pass thru the string * as-is. * * This is currnetly only used for -d (defining macros). * * @returns 1 if pass-thru, 0 if not. * @param pszArg The argument to consider. */ static int isWatcomPassThruOption(const char *pszArg) { char ch = *pszArg++; if (ch != '-' && ch != '/') return 0; ch = *pszArg++; switch (ch) { /* Example: -d+VAR="string-value" */ case 'd': if (ch == '+') ch = *pszArg++; if (!isalpha(ch) && ch != '_') return 0; return 1; default: return 0; } } /** * Replaces arguments in need of quoting. * * For details on how MSC parses the command line, see "Parsing C Command-Line * Arguments": http://msdn.microsoft.com/en-us/library/a1y7w461.aspx * * @returns 0 on success, -1 if out of memory. * @param argc The argument count. * @param argv The argument vector. * @param fWatcomBrainDamage Set if we're catering for wcc, wcc386 or similar * OpenWatcom tools. They seem to follow some * ancient or home made quoting convention. * @param fFreeOrLeak Whether to free replaced argv members * (non-zero), or just leak them (zero). This * depends on which argv you're working on. * Suggest doing the latter if it's main()'s argv. */ int quote_argv(int argc, char **argv, int fWatcomBrainDamage, int fFreeOrLeak) { int i; for (i = 0; i < argc; i++) { char *const pszOrgOrg = argv[i]; const char *pszOrg = pszOrgOrg; size_t cchOrg = strlen(pszOrg); const char *pszQuotes = (const char *)memchr(pszOrg, '"', cchOrg); const char *pszProblem = NULL; if ( pszQuotes || cchOrg == 0 || (pszProblem = (const char *)memchr(pszOrg, ' ', cchOrg)) != NULL || (pszProblem = (const char *)memchr(pszOrg, '\t', cchOrg)) != NULL || (pszProblem = (const char *)memchr(pszOrg, '\n', cchOrg)) != NULL || (pszProblem = (const char *)memchr(pszOrg, '\r', cchOrg)) != NULL || (pszProblem = (const char *)memchr(pszOrg, '&', cchOrg)) != NULL || (pszProblem = (const char *)memchr(pszOrg, '>', cchOrg)) != NULL || (pszProblem = (const char *)memchr(pszOrg, '<', cchOrg)) != NULL || (pszProblem = (const char *)memchr(pszOrg, '|', cchOrg)) != NULL || (pszProblem = (const char *)memchr(pszOrg, '%', cchOrg)) != NULL || (pszProblem = (const char *)memchr(pszOrg, '\'', cchOrg)) != NULL || ( !fWatcomBrainDamage && (pszProblem = (const char *)memchr(pszOrg, '=', cchOrg)) != NULL) || ( fWatcomBrainDamage && (pszProblem = (const char *)memchr(pszOrg, '\\', cchOrg)) != NULL) ) { char ch; int fComplicated = pszQuotes || (cchOrg > 0 && pszOrg[cchOrg - 1] == '\\'); size_t cchNew = fComplicated ? cchOrg * 2 + 2 : cchOrg + 2; char *pszNew = (char *)malloc(cchNew + 1 /*term*/ + 3 /*passthru hack*/); if (!pszNew) return -1; argv[i] = pszNew; /* Watcom does not grok stuff like "-i=c:\program files\watcom\h", it think it's a source specification. In that case the quote must follow the equal sign. */ if (fWatcomBrainDamage) { size_t cchUnquoted = 0; if (pszOrg[0] == '@') /* Response file quoting: @"file name.rsp" */ cchUnquoted = 1; else if (pszOrg[0] == '-' || pszOrg[0] == '/') /* Switch quoting. */ { if (isWatcomPassThruOption(pszOrg)) cchUnquoted = strlen(pszOrg) + 1; else { const char *pszNeedQuoting = (const char *)memchr(pszOrg, '=', cchOrg); /* For -i=dir and similar. */ if ( pszNeedQuoting == NULL || (uintptr_t)pszNeedQuoting > (uintptr_t)(pszProblem ? pszProblem : pszQuotes)) pszNeedQuoting = pszProblem ? pszProblem : pszQuotes; else pszNeedQuoting++; cchUnquoted = pszNeedQuoting - pszOrg; } } if (cchUnquoted) { memcpy(pszNew, pszOrg, cchUnquoted); pszNew += cchUnquoted; pszOrg += cchUnquoted; cchOrg -= cchUnquoted; } } *pszNew++ = '"'; if (fComplicated) { while ((ch = *pszOrg++) != '\0') { if (ch == '"') { *pszNew++ = '\\'; *pszNew++ = '"'; } else if (ch == '\\') { /* Backslashes are a bit complicated, they depends on whether a quotation mark follows them or not. They only require escaping if one does. */ unsigned cSlashes = 1; while ((ch = *pszOrg) == '\\') { pszOrg++; cSlashes++; } if (ch == '"' || ch == '\0') /* We put a " at the EOS. */ { while (cSlashes-- > 0) { *pszNew++ = '\\'; *pszNew++ = '\\'; } } else while (cSlashes-- > 0) *pszNew++ = '\\'; } else *pszNew++ = ch; } } else { memcpy(pszNew, pszOrg, cchOrg); pszNew += cchOrg; } *pszNew++ = '"'; *pszNew = '\0'; if (fFreeOrLeak) free(pszOrgOrg); } } /*for (i = 0; i < argc; i++) fprintf(stderr, "argv[%u]=%s;;\n", i, argv[i]);*/ return 0; } kbuild-3149/src/lib/nt_fullpath_cached.c0000644000175000017500000001226213252530204020213 0ustar locutuslocutus/* $Id: nt_fullpath_cached.c 2849 2016-08-30 14:28:46Z bird $ */ /** @file * fixcase - fixes the case of paths, windows specific. */ /* * Copyright (c) 2004-2010 knut st. osmundsen * * This file is part of kBuild. * * kBuild 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. * * kBuild 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 kBuild. If not, see * */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #include #include #include #include #include "nt_fullpath.h" /********************************************************************************************************************************* * Structures and Typedefs * *********************************************************************************************************************************/ typedef struct NTFULLPATHENTRY { /** Pointer to the next entry with the same hash table index. */ struct NTFULLPATHENTRY *pNext; /** The input hash. */ unsigned uHash; /** The input length. */ unsigned cchInput; /** Length of the result. */ unsigned cchResult; /** The result string (stored immediately after this structure). */ const char *pszResult; /** The input string (variable length). */ char szInput[1]; } NTFULLPATHENTRY; typedef NTFULLPATHENTRY *PNTFULLPATHENTRY; /********************************************************************************************************************************* * Global Variables * *********************************************************************************************************************************/ /** Number of result in the nt_fullpath cache. */ size_t g_cNtFullPathHashEntries = 0; /** Number of bytes used for nt_fullpath cache result entries. */ size_t g_cbNtFullPathHashEntries = 0; /** Number of hash table collsioins in the nt_fullpath cache. */ size_t g_cNtFullPathHashCollisions = 0; /** Hash table. */ PNTFULLPATHENTRY g_apNtFullPathHashTab[16381]; /** * A nt_fullpath frontend which caches the result of previous calls. */ void nt_fullpath_cached(const char *pszPath, char *pszFull, size_t cchFull) { PNTFULLPATHENTRY pEntry; unsigned cchInput; unsigned idx; unsigned cchResult; /* We use the sdbm hash algorithm here (see kDep.c for full details). */ unsigned const char *puch = (unsigned const char *)pszPath; unsigned uHash = 0; unsigned uChar; while ((uChar = *puch++) != 0) uHash = uChar + (uHash << 6) + (uHash << 16) - uHash; cchInput = (unsigned)((uintptr_t)&puch[-1] - (uintptr_t)pszPath); /* Do the cache lookup. */ idx = uHash % (sizeof(g_apNtFullPathHashTab) / sizeof(g_apNtFullPathHashTab[0])); for (pEntry = g_apNtFullPathHashTab[idx]; pEntry != NULL; pEntry = pEntry->pNext) if ( pEntry->uHash == uHash && pEntry->cchInput == cchInput && memcmp(pEntry->szInput, pszPath, cchInput) == 0) { if (cchFull > pEntry->cchResult) memcpy(pszFull, pEntry->pszResult, pEntry->cchResult + 1); else { assert(0); memcpy(pszFull, pEntry->pszResult, cchFull); pszFull[cchFull - 1] = '\0'; } return; } /* Make the call... */ nt_fullpath(pszPath, pszFull, cchFull); /* ... and cache the result. */ cchResult = (unsigned)strlen(pszFull); pEntry = malloc(sizeof(*pEntry) + cchInput + cchResult + 1); if (pEntry) { g_cbNtFullPathHashEntries += sizeof(*pEntry) + cchInput + cchResult + 1; pEntry->cchInput = cchInput; pEntry->cchResult = cchResult; pEntry->pszResult = &pEntry->szInput[cchInput + 1]; pEntry->uHash = uHash; memcpy(pEntry->szInput, pszPath, cchInput + 1); memcpy((char *)pEntry->pszResult, pszFull, cchResult + 1); pEntry->pNext = g_apNtFullPathHashTab[idx]; if (pEntry->pNext) g_cNtFullPathHashCollisions++; g_apNtFullPathHashTab[idx] = pEntry; g_cNtFullPathHashEntries++; } } kbuild-3149/src/lib/kbuild_version.h0000644000175000017500000000277313252530204017436 0ustar locutuslocutus/* $Id: kbuild_version.h 2851 2016-08-31 17:30:52Z bird $ */ /** @file * kbuild_version(), helper function. */ /* * Copyright (c) 2007-2013 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___lib_kbuild_version_h___ #define ___lib_kbuild_version_h___ int kbuild_version(const char *argv0); #endif kbuild-3149/src/lib/quoted_spawn.c0000644000175000017500000002075513252530204017123 0ustar locutuslocutus/* $Id: quoted_spawn.c 2851 2016-08-31 17:30:52Z bird $ */ /** @file * quote_spawn - Correctly Quote The _spawnvp arguments, windows specific. */ /* * Copyright (c) 2010-2016 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "quoted_spawn.h" #include #include #include #include #include #include /** * Tests if a strings needs quoting. * * @returns 1 if needs, 0 if it doesn't. * @param pszArg The string in question. */ static int quoted_spawn_need_quoting(const char *pszArg) { for (;;) switch (*pszArg++) { case 0: return 0; case ' ': case '"': case '&': case '>': case '<': case '|': case '%': /* Quote the control chars (tab is included). */ case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: return 1; } } /** * Frees any quoted arguments. * * @returns NULL. * @param papszArgsOrg The original argument vector. * @param papszArgsQuoted The quoted argument vector. * @param cArgs The number of arguments in the vector. */ static const char * const * quoted_spawn_free(const char * const *papszArgsOrg, const char * const *papszArgsQuoted, unsigned cArgs) { if ( papszArgsOrg != papszArgsQuoted && papszArgsQuoted != NULL) { int iSavedErrno = errno; /* A bit of paranoia. */ unsigned i = cArgs; while (i-- > 0) if (papszArgsQuoted[i] != papszArgsOrg[i]) free((char *)papszArgsQuoted[i]); free((void *)papszArgsQuoted); errno = iSavedErrno; } return NULL; } /** * Quote an argument string. * * @returns Quoted argument string (new). * @param pszArgOrg The original string. */ static const char *quoted_spawn_quote_arg(const char *pszArgOrg) { size_t cchArgOrg = strlen(pszArgOrg); size_t cchArgNew = 1 + cchArgOrg * 2 + 1 + 1; char *pszArgNew = malloc(cchArgNew); if (pszArgNew) { char ch; char *pszDst = pszArgNew; *pszDst++ = '"'; while ((ch = *pszArgOrg++)) { if (ch == '\\') { size_t cSlashes = 1; for (;;) { *pszDst++ = '\\'; ch = *pszArgOrg; if (ch != '\\') break; pszArgOrg++; cSlashes++; } if (ch == '"' || ch == '\0') { while (cSlashes-- > 0) *pszDst++ = '\\'; if (ch == '\0') break; *pszDst++ = '\\'; *pszDst++ = '"'; } } else if (ch == '"') { *pszDst++ = '\\'; *pszDst++ = '"'; } else *pszDst++ = ch; } *pszDst++ = '"'; *pszDst = '\0'; assert((size_t)(pszDst - pszArgNew) < cchArgNew - 1); } return pszArgNew; } /** * Quotes the arguments in an argument vector, producing a new vector. * * @returns The quoted argument vector. * @param papszArgsOrg The vector which arguments to quote. * @param iFirstArg The first argument that needs quoting. * @param pcArgs Where to return the argument count. */ static const char * const * quoted_spawn_quote_vector(const char * const *papszArgsOrg, unsigned iFirstArg, unsigned *pcArgs) { const char **papszArgsQuoted; unsigned cArgs; unsigned iArg; /* finish counting them and allocate the result array. */ cArgs = iFirstArg; while (papszArgsOrg[cArgs]) cArgs++; *pcArgs = cArgs; papszArgsQuoted = (const char **)calloc(sizeof(const char *), cArgs + 1); if (!papszArgsQuoted) return NULL; /* Process the arguments up to the first quoted one (no need to re-examine them). */ for (iArg = 0; iArg < iFirstArg; iArg++) papszArgsQuoted[iArg] = papszArgsOrg[iArg]; papszArgsQuoted[iArg] = quoted_spawn_quote_arg(papszArgsOrg[iArg]); if (!papszArgsQuoted[iArg]) return quoted_spawn_free(papszArgsOrg, papszArgsQuoted, cArgs); /* Process the remaining arguments. */ while (iArg < cArgs) { if (!quoted_spawn_need_quoting(papszArgsOrg[iArg])) papszArgsQuoted[iArg] = papszArgsOrg[iArg]; else { papszArgsQuoted[iArg] = quoted_spawn_quote_arg(papszArgsOrg[iArg]); if (!papszArgsQuoted[iArg]) return quoted_spawn_free(papszArgsOrg, papszArgsQuoted, cArgs); } iArg++; } return papszArgsQuoted; } /** * Checks if any of the arguments in the vector needs quoting and does the job. * * @returns If anything needs quoting a new vector is returned, otherwise the * original is returned. * @param papszArgsOrg The argument vector to check. * @param pcArgs Where to return the argument count. */ static const char * const * quoted_spawn_maybe_quote(const char * const *papszArgsOrg, unsigned *pcArgs) { unsigned iArg; for (iArg = 0; papszArgsOrg[iArg]; iArg++) if (quoted_spawn_need_quoting(papszArgsOrg[iArg])) return quoted_spawn_quote_vector(papszArgsOrg, iArg, pcArgs); *pcArgs = iArg; return papszArgsOrg; } /** * Wrapper for _spawnvp. * * @returns The process handle, see _spawnvp for details. * @param fMode The spawn mode, see _spawnvp for details. * @param pszExecPath The path to the executable, or just the name * if a PATH search is desired. * @param papszArgs The arguments to pass to the new process. */ intptr_t quoted_spawnvp(int fMode, const char *pszExecPath, const char * const *papszArgs) { intptr_t hProcess; unsigned cArgs; const char * const *papszArgsQuoted = quoted_spawn_maybe_quote(papszArgs, &cArgs); if (papszArgsQuoted) { //unsigned i; //fprintf(stderr, "debug: spawning '%s'\n", pszExecPath); //for (i = 0; i < cArgs; i++) // fprintf(stderr, "debug: #%02u: '%s'\n", i, papszArgsQuoted[i]); hProcess = _spawnvp(fMode, pszExecPath, papszArgsQuoted); quoted_spawn_free(papszArgs, papszArgsQuoted, cArgs); } else { errno = ENOMEM; hProcess = -1; } return hProcess; } kbuild-3149/src/lib/dos2unix.h0000644000175000017500000000413113252530204016160 0ustar locutuslocutus/* $Id: dos2unix.h 3114 2017-10-29 18:02:04Z bird $ */ /** @file * dos2unix - Line ending conversion routines. */ /* * Copyright (c) 2017 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___lib_dos2unix_h___ #define ___lib_dos2unix_h___ #include #define DOS2UNIX_STYLE_NONE 0x00 #define DOS2UNIX_STYLE_DOS 0x01 #define DOS2UNIX_STYLE_UNIX 0x02 #define DOS2UNIX_STYLE_MIXED 0x03 #define DOS2UNIX_STYLE_MASK 0x03 #define DOS2UNIX_F_BINARY 0x80 /**< Probably a binary file. */ int dos2unix_analyze_file(const char *pszFilename, KU32 *pfStyle, KSIZE *pcDosEols, KSIZE *pcUnixEols); int dos2unix_analyze_fd(int fd, KU32 *pfStyle, KSIZE *pcDosEols, KSIZE *pcUnixEols); KBOOL dos2unix_convert_to_unix(const char *pchSrc, KSIZE cchSrc, char *pchDst, KSIZE *pcchDst); KBOOL dos2unix_convert_to_dos(const char *pchSrc, KSIZE cchSrc, char *pchDst, KSIZE *pcchDst); #endif kbuild-3149/src/lib/mytypes.h0000644000175000017500000000333713252530204016126 0ustar locutuslocutus/* $Id: mytypes.h 2851 2016-08-31 17:30:52Z bird $ */ /** @file * mytypes - wrapper that ensures the necessary uintXY_t types are defined. */ /* * Copyright (c) 2007-2016 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___mytypes_h___ #define ___mytypes_h___ #include #include /* MSC: intptr_t */ #include #if defined(_MSC_VER) typedef unsigned int uint32_t; typedef signed int int32_t; typedef unsigned char uint8_t; typedef signed char int8_t; #else # include #endif #endif kbuild-3149/src/lib/nt/0000755000175000017500000000000013252530204014656 5ustar locutuslocutuskbuild-3149/src/lib/nt/tstNtStat.c0000644000175000017500000001205013252530204016770 0ustar locutuslocutus/* $Id: tstNtStat.c 3007 2016-11-06 16:46:43Z bird $ */ /** @file * Manual lstat/stat testcase. */ /* * Copyright (c) 2013 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include "ntstat.h" static int IsLeapYear(int iYear) { return iYear % 4 == 0 && ( iYear % 100 != 0 || iYear % 400 == 0); } static int DaysInMonth(int iYear, int iMonth) { switch (iMonth) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: return 31; case 4: case 6: case 9: case 11: return 30; case 2: return IsLeapYear(iYear) ? 29 : 28; default: *(void **)(size_t)iMonth = 0; /* crash! */ return 0; } } static char *FormatTimeSpec(char *pszBuf, BirdTimeSpec_T const *pTimeSpec) { if (pTimeSpec->tv_sec >= 0) { int iYear = 1970; int iMonth = 1; int iDay = 1; int iHour = 0; int iMin = 0; int iSec = 0; __int64 cSecs = pTimeSpec->tv_sec; /* lazy bird approach, find date, day by day */ while (cSecs >= 24*3600) { if ( iDay < 28 || iDay < DaysInMonth(iYear, iMonth)) iDay++; else { if (iMonth < 12) iMonth++; else { iYear++; iMonth = 1; } iDay = 1; } cSecs -= 24*3600; } iHour = (int)cSecs / 3600; cSecs %= 3600; iMin = (int)cSecs / 60; iSec = (int)cSecs % 60; sprintf(pszBuf, "%04d-%02d-%02dT%02u:%02u:%02u.%09u (%I64d.%09u)", iYear, iMonth, iDay, iHour, iMin, iSec, pTimeSpec->tv_nsec, pTimeSpec->tv_sec, pTimeSpec->tv_nsec); } else sprintf(pszBuf, "%I64d.%09u (before 1970-01-01)", pTimeSpec->tv_sec, pTimeSpec->tv_nsec); return pszBuf; } int main(int argc, char **argv) { int rc = 0; int i; for (i = 1; i < argc; i++) { struct stat st; if (lstat(argv[i], &st) == 0) { char szBuf[256]; printf("%s:\n", argv[i]); printf(" st_mode: %o\n", st.st_mode); printf(" st_isdirsymlink: %d\n", st.st_isdirsymlink); printf(" st_ismountpoint: %d\n", st.st_ismountpoint); printf(" st_size: %I64u (%#I64x)\n", st.st_size, st.st_size); printf(" st_atim: %s\n", FormatTimeSpec(szBuf, &st.st_atim)); printf(" st_mtim: %s\n", FormatTimeSpec(szBuf, &st.st_mtim)); printf(" st_ctim: %s\n", FormatTimeSpec(szBuf, &st.st_ctim)); printf(" st_birthtim: %s\n", FormatTimeSpec(szBuf, &st.st_birthtim)); printf(" st_ino: %#I64x\n", st.st_ino); printf(" st_dev: %#I64x\n", st.st_dev); printf(" st_nlink: %u\n", st.st_nlink); printf(" st_rdev: %#x\n", st.st_rdev); printf(" st_uid: %d\n", st.st_uid); printf(" st_gid: %d\n", st.st_gid); printf(" st_blksize: %d (%#x)\n", st.st_blksize, st.st_blksize); printf(" st_blocks: %I64u (%#I64x)\n", st.st_blocks, st.st_blocks); } else { fprintf(stderr, "stat failed on '%s': errno=%u\n", argv[i], errno); rc = 1; } } return rc; } kbuild-3149/src/lib/nt/ntstuff.h0000644000175000017500000005407513252530204016533 0ustar locutuslocutus/* $Id: ntstuff.h 3021 2017-01-07 16:52:16Z bird $ */ /** @file * Definitions, types, prototypes and globals for NT. */ /* * Copyright (c) 2005-2013 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___nt_ntstuff_h #define ___nt_ntstuff_h #define timeval timeval_Windows #define WIN32_NO_STATUS #include #include #undef WIN32_NO_STATUS #include #undef timeval #include /** @defgroup grp_nt_ntstuff NT Stuff * @{ */ typedef LONG MY_NTSTATUS; typedef ULONG MY_ACCESS_MASK; typedef struct MY_IO_STATUS_BLOCK { union { MY_NTSTATUS Status; PVOID Pointer; } u; ULONG_PTR Information; } MY_IO_STATUS_BLOCK; typedef VOID WINAPI MY_IO_APC_ROUTINE(PVOID, MY_IO_STATUS_BLOCK *, ULONG); typedef struct MY_UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } MY_UNICODE_STRING; typedef struct MY_STRING { USHORT Length; USHORT MaximumLength; PCHAR Buffer; } MY_STRING; typedef MY_STRING MY_ANSI_STRING; typedef struct MY_CURDIR { UNICODE_STRING DosPath; HANDLE Handle; } MY_CURDIR; typedef MY_CURDIR *PMY_CURDIR; typedef struct MY_RTL_DRIVE_LETTER_CURDIR { USHORT Flags; USHORT Length; ULONG TimeStamp; MY_ANSI_STRING DosPath; } MY_RTL_DRIVE_LETTER_CURDIR; typedef MY_RTL_DRIVE_LETTER_CURDIR *PRTL_DRIVE_LETTER_CURDIR; typedef struct MY_RTL_USER_PROCESS_PARAMETERS { ULONG MaximumLength; ULONG Length; ULONG Flags; ULONG DebugFlags; HANDLE ConsoleHandle; ULONG ConsoleFlags; HANDLE StandardInput; HANDLE StandardOutput; HANDLE StandardError; MY_CURDIR CurrentDirectory; MY_UNICODE_STRING DllPath; MY_UNICODE_STRING ImagePathName; MY_UNICODE_STRING CommandLine; PWSTR Environment; ULONG StartingX; ULONG StartingY; ULONG CountX; ULONG CountY; ULONG CountCharsX; ULONG CountCharsY; ULONG FillAttribute; ULONG WindowFlags; ULONG ShowWindowFlags; MY_UNICODE_STRING WindowTitle; MY_UNICODE_STRING DesktopInfo; MY_UNICODE_STRING ShellInfo; MY_UNICODE_STRING RuntimeInfo; MY_RTL_DRIVE_LETTER_CURDIR CurrentDirectories[0x20]; SIZE_T EnvironmentSize; /* >= Vista+ */ SIZE_T EnvironmentVersion; /* >= Windows 7. */ PVOID PackageDependencyData; /* >= Windows 8 or Windows 8.1. */ ULONG ProcessGroupId; /* >= Windows 8 or Windows 8.1. */ } MY_RTL_USER_PROCESS_PARAMETERS; typedef MY_RTL_USER_PROCESS_PARAMETERS *PMY_RTL_USER_PROCESS_PARAMETERS; typedef struct MY_OBJECT_ATTRIBUTES { ULONG Length; HANDLE RootDirectory; MY_UNICODE_STRING *ObjectName; ULONG Attributes; PVOID SecurityDescriptor; PVOID SecurityQualityOfService; } MY_OBJECT_ATTRIBUTES; #define MyInitializeObjectAttributes(a_pAttr, a_pName, a_fAttribs, a_hRoot, a_pSecDesc) \ do { \ (a_pAttr)->Length = sizeof(MY_OBJECT_ATTRIBUTES); \ (a_pAttr)->RootDirectory = (a_hRoot); \ (a_pAttr)->Attributes = (a_fAttribs); \ (a_pAttr)->ObjectName = (a_pName); \ (a_pAttr)->SecurityDescriptor = (a_pSecDesc); \ (a_pAttr)->SecurityQualityOfService = NULL; \ } while (0) typedef struct MY_FILE_BASIC_INFORMATION { LARGE_INTEGER CreationTime; LARGE_INTEGER LastAccessTime; LARGE_INTEGER LastWriteTime; LARGE_INTEGER ChangeTime; ULONG FileAttributes; } MY_FILE_BASIC_INFORMATION; typedef struct MY_FILE_STANDARD_INFORMATION { LARGE_INTEGER AllocationSize; LARGE_INTEGER EndOfFile; ULONG NumberOfLinks; BOOLEAN DeletePending; BOOLEAN Directory; } MY_FILE_STANDARD_INFORMATION; typedef struct MY_FILE_NETWORK_OPEN_INFORMATION { LARGE_INTEGER CreationTime; LARGE_INTEGER LastAccessTime; LARGE_INTEGER LastWriteTime; LARGE_INTEGER ChangeTime; LARGE_INTEGER AllocationSize; LARGE_INTEGER EndOfFile; ULONG FileAttributes; } MY_FILE_NETWORK_OPEN_INFORMATION; typedef struct MY_FILE_INTERNAL_INFORMATION { LARGE_INTEGER IndexNumber; } MY_FILE_INTERNAL_INFORMATION; typedef struct MY_FILE_EA_INFORMATION { ULONG EaSize; } MY_FILE_EA_INFORMATION; typedef struct MY_FILE_ACCESS_INFORMATION { ACCESS_MASK AccessFlags; } MY_FILE_ACCESS_INFORMATION; typedef struct MY_FILE_POSITION_INFORMATION { LARGE_INTEGER CurrentByteOffset; } MY_FILE_POSITION_INFORMATION; typedef struct MY_FILE_MODE_INFORMATION { ULONG Mode; } MY_FILE_MODE_INFORMATION; typedef struct MY_FILE_ALIGNMENT_INFORMATION { ULONG AlignmentRequirement; } MY_FILE_ALIGNMENT_INFORMATION; typedef struct MY_FILE_NAME_INFORMATION { ULONG FileNameLength; WCHAR FileName[1]; } MY_FILE_NAME_INFORMATION; typedef struct MY_FILE_ALL_INFORMATION { MY_FILE_BASIC_INFORMATION BasicInformation; MY_FILE_STANDARD_INFORMATION StandardInformation; MY_FILE_INTERNAL_INFORMATION InternalInformation; MY_FILE_EA_INFORMATION EaInformation; MY_FILE_ACCESS_INFORMATION AccessInformation; MY_FILE_POSITION_INFORMATION PositionInformation; MY_FILE_MODE_INFORMATION ModeInformation; MY_FILE_ALIGNMENT_INFORMATION AlignmentInformation; MY_FILE_NAME_INFORMATION NameInformation; } MY_FILE_ALL_INFORMATION; typedef struct MY_FILE_ATTRIBUTE_TAG_INFORMATION { ULONG FileAttributes; ULONG ReparseTag; } MY_FILE_ATTRIBUTE_TAG_INFORMATION; typedef struct MY_FILE_NAMES_INFORMATION { ULONG NextEntryOffset; ULONG FileIndex; ULONG FileNameLength; WCHAR FileName[1]; } MY_FILE_NAMES_INFORMATION; /** The sizeof(MY_FILE_NAMES_INFORMATION) without the FileName. */ #define MIN_SIZEOF_MY_FILE_NAMES_INFORMATION (4 + 4 + 4) typedef struct MY_FILE_ID_FULL_DIR_INFORMATION { ULONG NextEntryOffset; ULONG FileIndex; LARGE_INTEGER CreationTime; LARGE_INTEGER LastAccessTime; LARGE_INTEGER LastWriteTime; LARGE_INTEGER ChangeTime; LARGE_INTEGER EndOfFile; LARGE_INTEGER AllocationSize; ULONG FileAttributes; ULONG FileNameLength; ULONG EaSize; LARGE_INTEGER FileId; WCHAR FileName[1]; } MY_FILE_ID_FULL_DIR_INFORMATION; /** The sizeof(MY_FILE_NAMES_INFORMATION) without the FileName. */ #define MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION ( (size_t)&((MY_FILE_ID_FULL_DIR_INFORMATION *)0)->FileName ) typedef struct MY_FILE_BOTH_DIR_INFORMATION { ULONG NextEntryOffset; ULONG FileIndex; LARGE_INTEGER CreationTime; LARGE_INTEGER LastAccessTime; LARGE_INTEGER LastWriteTime; LARGE_INTEGER ChangeTime; LARGE_INTEGER EndOfFile; LARGE_INTEGER AllocationSize; ULONG FileAttributes; ULONG FileNameLength; ULONG EaSize; CCHAR ShortNameLength; WCHAR ShortName[12]; WCHAR FileName[1]; } MY_FILE_BOTH_DIR_INFORMATION; /** The sizeof(MY_FILE_BOTH_DIR_INFORMATION) without the FileName. */ #define MIN_SIZEOF_MY_FILE_BOTH_DIR_INFORMATION ( (size_t)&((MY_FILE_BOTH_DIR_INFORMATION *)0)->FileName ) typedef struct MY_FILE_ID_BOTH_DIR_INFORMATION { ULONG NextEntryOffset; ULONG FileIndex; LARGE_INTEGER CreationTime; LARGE_INTEGER LastAccessTime; LARGE_INTEGER LastWriteTime; LARGE_INTEGER ChangeTime; LARGE_INTEGER EndOfFile; LARGE_INTEGER AllocationSize; ULONG FileAttributes; ULONG FileNameLength; ULONG EaSize; CCHAR ShortNameLength; WCHAR ShortName[12]; LARGE_INTEGER FileId; WCHAR FileName[1]; } MY_FILE_ID_BOTH_DIR_INFORMATION; /** The sizeof(MY_FILE_NAMES_INFORMATION) without the FileName. */ #define MIN_SIZEOF_MY_FILE_ID_BOTH_DIR_INFORMATION ( (size_t)&((MY_FILE_ID_BOTH_DIR_INFORMATION *)0)->FileName ) typedef struct MY_FILE_DISPOSITION_INFORMATION { BOOLEAN DeleteFile; } MY_FILE_DISPOSITION_INFORMATION; typedef enum MY_FILE_INFORMATION_CLASS { MyFileDirectoryInformation = 1, MyFileFullDirectoryInformation, /* = 2 */ MyFileBothDirectoryInformation, /* = 3 */ MyFileBasicInformation, /* = 4 */ MyFileStandardInformation, /* = 5 */ MyFileInternalInformation, /* = 6 */ MyFileEaInformation, /* = 7 */ MyFileAccessInformation, /* = 8 */ MyFileNameInformation, /* = 9 */ MyFileRenameInformation, /* = 10 */ MyFileLinkInformation, /* = 11 */ MyFileNamesInformation, /* = 12 */ MyFileDispositionInformation, /* = 13 */ MyFilePositionInformation, /* = 14 */ MyFileFullEaInformation, /* = 15 */ MyFileModeInformation, /* = 16 */ MyFileAlignmentInformation, /* = 17 */ MyFileAllInformation, /* = 18 */ MyFileAllocationInformation, /* = 19 */ MyFileEndOfFileInformation, /* = 20 */ MyFileAlternateNameInformation, /* = 21 */ MyFileStreamInformation, /* = 22 */ MyFilePipeInformation, /* = 23 */ MyFilePipeLocalInformation, /* = 24 */ MyFilePipeRemoteInformation, /* = 25 */ MyFileMailslotQueryInformation, /* = 26 */ MyFileMailslotSetInformation, /* = 27 */ MyFileCompressionInformation, /* = 28 */ MyFileObjectIdInformation, /* = 29 */ MyFileCompletionInformation, /* = 30 */ MyFileMoveClusterInformation, /* = 31 */ MyFileQuotaInformation, /* = 32 */ MyFileReparsePointInformation, /* = 33 */ MyFileNetworkOpenInformation, /* = 34 */ MyFileAttributeTagInformation, /* = 35 */ MyFileTrackingInformation, /* = 36 */ MyFileIdBothDirectoryInformation, /* = 37 */ MyFileIdFullDirectoryInformation, /* = 38 */ MyFileValidDataLengthInformation, /* = 39 */ MyFileShortNameInformation, /* = 40 */ MyFileIoCompletionNotificationInformation, /* = 41 */ MyFileIoStatusBlockRangeInformation, /* = 42 */ MyFileIoPriorityHintInformation, /* = 43 */ MyFileSfioReserveInformation, /* = 44 */ MyFileSfioVolumeInformation, /* = 45 */ MyFileHardLinkInformation, /* = 46 */ MyFileProcessIdsUsingFileInformation, /* = 47 */ MyFileNormalizedNameInformation, /* = 48 */ MyFileNetworkPhysicalNameInformation, /* = 49 */ MyFileIdGlobalTxDirectoryInformation, /* = 50 */ MyFileIsRemoteDeviceInformation, /* = 51 */ MyFileAttributeCacheInformation, /* = 52 */ MyFileNumaNodeInformation, /* = 53 */ MyFileStandardLinkInformation, /* = 54 */ MyFileRemoteProtocolInformation, /* = 55 */ MyFileMaximumInformation } MY_FILE_INFORMATION_CLASS; typedef struct MY_FILE_FS_VOLUME_INFORMATION { LARGE_INTEGER VolumeCreationTime; ULONG VolumeSerialNumber; ULONG VolumeLabelLength; BOOLEAN SupportsObjects; WCHAR VolumeLabel[1]; } MY_FILE_FS_VOLUME_INFORMATION; typedef struct _MY_FILE_FS_ATTRIBUTE_INFORMATION { ULONG FileSystemAttributes; LONG MaximumComponentNameLength; ULONG FileSystemNameLength; WCHAR FileSystemName[1]; } MY_FILE_FS_ATTRIBUTE_INFORMATION; typedef enum MY_FSINFOCLASS { MyFileFsVolumeInformation = 1, MyFileFsLabelInformation, /* = 2 */ MyFileFsSizeInformation, /* = 3 */ MyFileFsDeviceInformation, /* = 4 */ MyFileFsAttributeInformation, /* = 5 */ MyFileFsControlInformation, /* = 6 */ MyFileFsFullSizeInformation, /* = 7 */ MyFileFsObjectIdInformation, /* = 8 */ MyFileFsDriverPathInformation, /* = 9 */ MyFileFsVolumeFlagsInformation, /* = 10 */ MyFileFsMaximumInformation } MY_FS_INFORMATION_CLASS; typedef struct MY_RTLP_CURDIR_REF { LONG RefCount; HANDLE Handle; } MY_RTLP_CURDIR_REF; typedef struct MY_RTL_RELATIVE_NAME_U { MY_UNICODE_STRING RelativeName; HANDLE ContainingDirectory; MY_RTLP_CURDIR_REF CurDirRef; } MY_RTL_RELATIVE_NAME_U; #ifndef OBJ_INHERIT # define OBJ_INHERIT 0x00000002U # define OBJ_PERMANENT 0x00000010U # define OBJ_EXCLUSIVE 0x00000020U # define OBJ_CASE_INSENSITIVE 0x00000040U # define OBJ_OPENIF 0x00000080U # define OBJ_OPENLINK 0x00000100U # define OBJ_KERNEL_HANDLE 0x00000200U # define OBJ_FORCE_ACCESS_CHECK 0x00000400U # define OBJ_VALID_ATTRIBUTES 0x000007f2U #endif #ifndef FILE_OPEN # define FILE_SUPERSEDE 0x00000000U # define FILE_OPEN 0x00000001U # define FILE_CREATE 0x00000002U # define FILE_OPEN_IF 0x00000003U # define FILE_OVERWRITE 0x00000004U # define FILE_OVERWRITE_IF 0x00000005U # define FILE_MAXIMUM_DISPOSITION 0x00000005U #endif #ifndef FILE_DIRECTORY_FILE # define FILE_DIRECTORY_FILE 0x00000001U # define FILE_WRITE_THROUGH 0x00000002U # define FILE_SEQUENTIAL_ONLY 0x00000004U # define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008U # define FILE_SYNCHRONOUS_IO_ALERT 0x00000010U # define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020U # define FILE_NON_DIRECTORY_FILE 0x00000040U # define FILE_CREATE_TREE_CONNECTION 0x00000080U # define FILE_COMPLETE_IF_OPLOCKED 0x00000100U # define FILE_NO_EA_KNOWLEDGE 0x00000200U # define FILE_OPEN_REMOTE_INSTANCE 0x00000400U # define FILE_RANDOM_ACCESS 0x00000800U # define FILE_DELETE_ON_CLOSE 0x00001000U # define FILE_OPEN_BY_FILE_ID 0x00002000U # define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000U # define FILE_NO_COMPRESSION 0x00008000U # define FILE_RESERVE_OPFILTER 0x00100000U # define FILE_OPEN_REPARSE_POINT 0x00200000U # define FILE_OPEN_NO_RECALL 0x00400000U # define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000U #endif #ifndef DUPLICATE_CLOSE_SOURCE /* For the misnomer NtDuplicateObject. */ # define DUPLICATE_CLOSE_SOURCE 0x00000001U # define DUPLICATE_SAME_ACCESS 0x00000002U #endif #ifndef DUPLICATE_SAME_ATTRIBUTES # define DUPLICATE_SAME_ATTRIBUTES 0x00000004U #endif /** @name NT status codes and associated macros. * @{ */ #define MY_NT_SUCCESS(a_ntRc) ((MY_NTSTATUS)(a_ntRc) >= 0) #define MY_NT_FAILURE(a_ntRc) ((MY_NTSTATUS)(a_ntRc) < 0) #define MY_STATUS_NO_MORE_FILES ((MY_NTSTATUS)0x80000006) #define MY_STATUS_OBJECT_NAME_INVALID ((MY_NTSTATUS)0xc0000033) #define MY_STATUS_OBJECT_NAME_NOT_FOUND ((MY_NTSTATUS)0xc0000034) #define MY_STATUS_OBJECT_PATH_INVALID ((MY_NTSTATUS)0xc0000039) #define MY_STATUS_OBJECT_PATH_NOT_FOUND ((MY_NTSTATUS)0xc000003a) #define MY_STATUS_OBJECT_PATH_SYNTAX_BAD ((MY_NTSTATUS)0xc000003b) /** @} */ /** The pseudohandle for the current process. */ #define MY_NT_CURRENT_PROCESS ((HANDLE)~(uintptr_t)0) /** The pseudohandle for the current thread. */ #define MY_NT_CURRENT_THREAD ((HANDLE)~(uintptr_t)1) typedef struct MY_CLIENT_ID { HANDLE UniqueProcess; HANDLE UniqueThread; } MY_CLIENT_ID; /** Partial TEB. */ typedef struct MY_PARTIAL_TEB { NT_TIB NtTib; PVOID EnvironmentPointer; MY_CLIENT_ID ClientId; PVOID ActiveRpcHandle; PVOID ThreadLocalStoragePointer; PPEB ProcessEnvironmentBlock; KU32 LastErrorValue; KU32 CountOfOwnedCriticalSections; PVOID CsrClientThread; PVOID Win32ThreadInfo; } MY_PARTIAL_TEB; /** Internal macro for reading uintptr_t sized TEB members. */ #if K_ARCH == K_ARCH_AMD64 # define MY_NT_READ_TEB_WORKER(a_offTebMember) ( __readgsqword(a_offTebMember) ) #elif K_ARCH == K_ARCH_X86_32 # define MY_NT_READ_TEB_WORKER(a_offTebMember) ( __readfsdword(a_offTebMember) ) #else # error "Port me!" #endif /** Get the PEB pointer. * @remark Needs stddef.h. */ #define MY_NT_CURRENT_PEB() ( (PPEB)MY_NT_READ_TEB_WORKER(offsetof(MY_PARTIAL_TEB, ProcessEnvironmentBlock)) ) /** Get the TEB pointer. * @remark Needs stddef.h. */ #define MY_NT_CURRENT_TEB() ( (PTEB)MY_NT_READ_TEB_WORKER(offsetof(NT_TIB, Self)) ) /******************************************************************************* * Global Variables * *******************************************************************************/ extern MY_NTSTATUS (WINAPI * g_pfnNtClose)(HANDLE); extern MY_NTSTATUS (WINAPI * g_pfnNtCreateFile)(PHANDLE, MY_ACCESS_MASK, MY_OBJECT_ATTRIBUTES *, MY_IO_STATUS_BLOCK *, PLARGE_INTEGER, ULONG, ULONG, ULONG, ULONG, PVOID, ULONG); extern MY_NTSTATUS (WINAPI * g_pfnNtDeleteFile)(MY_OBJECT_ATTRIBUTES *); extern MY_NTSTATUS (WINAPI * g_pfnNtDuplicateObject)(HANDLE hSrcProc, HANDLE hSrc, HANDLE hDstProc, HANDLE *phRet, MY_ACCESS_MASK fDesiredAccess, ULONG fAttribs, ULONG fOptions); extern MY_NTSTATUS (WINAPI * g_pfnNtReadFile)(HANDLE hFile, HANDLE hEvent, MY_IO_APC_ROUTINE *pfnApc, PVOID pvApcCtx, MY_IO_STATUS_BLOCK *, PVOID pvBuf, ULONG cbToRead, PLARGE_INTEGER poffFile, PULONG puKey); extern MY_NTSTATUS (WINAPI * g_pfnNtQueryInformationFile)(HANDLE, MY_IO_STATUS_BLOCK *, PVOID, LONG, MY_FILE_INFORMATION_CLASS); extern MY_NTSTATUS (WINAPI * g_pfnNtQueryVolumeInformationFile)(HANDLE, MY_IO_STATUS_BLOCK *, PVOID, LONG, MY_FS_INFORMATION_CLASS); extern MY_NTSTATUS (WINAPI * g_pfnNtQueryDirectoryFile)(HANDLE, HANDLE, MY_IO_APC_ROUTINE *, PVOID, MY_IO_STATUS_BLOCK *, PVOID, ULONG, MY_FILE_INFORMATION_CLASS, BOOLEAN, MY_UNICODE_STRING *, BOOLEAN); extern MY_NTSTATUS (WINAPI * g_pfnNtQueryAttributesFile)(MY_OBJECT_ATTRIBUTES *, MY_FILE_BASIC_INFORMATION *); extern MY_NTSTATUS (WINAPI * g_pfnNtQueryFullAttributesFile)(MY_OBJECT_ATTRIBUTES *, MY_FILE_NETWORK_OPEN_INFORMATION *); extern MY_NTSTATUS (WINAPI * g_pfnNtSetInformationFile)(HANDLE, MY_IO_STATUS_BLOCK *, PVOID, LONG, MY_FILE_INFORMATION_CLASS); extern BOOLEAN (WINAPI * g_pfnRtlDosPathNameToNtPathName_U)(PCWSTR, MY_UNICODE_STRING *, PCWSTR *, MY_RTL_RELATIVE_NAME_U *); extern MY_NTSTATUS (WINAPI * g_pfnRtlAnsiStringToUnicodeString)(MY_UNICODE_STRING *, MY_ANSI_STRING const *, BOOLEAN); extern MY_NTSTATUS (WINAPI * g_pfnRtlUnicodeStringToAnsiString)(MY_ANSI_STRING *, MY_UNICODE_STRING *, BOOLEAN); extern BOOLEAN (WINAPI * g_pfnRtlEqualUnicodeString)(MY_UNICODE_STRING const *pUniStr1, MY_UNICODE_STRING const *pUniStr2, BOOLEAN fCaseInsensitive); extern BOOLEAN (WINAPI * g_pfnRtlEqualString)(MY_ANSI_STRING const *pAnsiStr1, MY_ANSI_STRING const *pAnsiStr2, BOOLEAN fCaseInsensitive); extern UCHAR (WINAPI * g_pfnRtlUpperChar)(UCHAR uch); extern ULONG (WINAPI * g_pfnRtlNtStatusToDosError)(MY_NTSTATUS rcNt); extern VOID (WINAPI * g_pfnRtlAcquirePebLock)(VOID); extern VOID (WINAPI * g_pfnRtlReleasePebLock)(VOID); /** @} */ #endif kbuild-3149/src/lib/nt/nttypes.h0000644000175000017500000000360013252530204016534 0ustar locutuslocutus/* $Id: nttypes.h 3060 2017-09-21 15:11:07Z bird $ */ /** @file * MSC + NT basic & common types, various definitions. */ /* * Copyright (c) 2005-2017 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___nt_nttypes_h #define ___nt_nttypes_h #include typedef struct BirdTimeVal { __int64 tv_sec; __int32 tv_usec; __int32 tv_padding0; } BirdTimeVal_T; typedef struct BirdTimeSpec { __int64 tv_sec; __int32 tv_nsec; __int32 tv_padding0; } BirdTimeSpec_T; /** The distance between the NT and unix epochs given in NT time (units of 100 * ns). */ #define BIRD_NT_EPOCH_OFFSET_UNIX_100NS 116444736000000000LL #endif kbuild-3149/src/lib/nt/kFsCache.c0000644000175000017500000052112113252530204016473 0ustar locutuslocutus/* $Id: kFsCache.c 3082 2017-10-02 19:23:17Z bird $ */ /** @file * ntdircache.c - NT directory content cache. */ /* * Copyright (c) 2016 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ #include #include "nthlp.h" #include "ntstat.h" #include #include #include #ifdef _MSC_VER # include #endif //#include //#include //#include //#include #include "kFsCache.h" /********************************************************************************************************************************* * Defined Constants And Macros * *********************************************************************************************************************************/ /** @def KFSCACHE_LOG2 * More logging. */ #if 0 # define KFSCACHE_LOG2(a) KFSCACHE_LOG(a) #else # define KFSCACHE_LOG2(a) do { } while (0) #endif /********************************************************************************************************************************* * Structures and Typedefs * *********************************************************************************************************************************/ /** * Used by the code re-populating a directory. */ typedef struct KFSDIRREPOP { /** The old papChildren array. */ PKFSOBJ *papOldChildren; /** Number of children in the array. */ KU32 cOldChildren; /** The index into papOldChildren we expect to find the next entry. */ KU32 iNextOldChild; /** Add this to iNextOldChild . */ KI32 cNextOldChildInc; /** Pointer to the cache (name changes). */ PKFSCACHE pCache; } KFSDIRREPOP; /** Pointer to directory re-population data. */ typedef KFSDIRREPOP *PKFSDIRREPOP; /********************************************************************************************************************************* * Internal Functions * *********************************************************************************************************************************/ static KBOOL kFsCacheRefreshObj(PKFSCACHE pCache, PKFSOBJ pObj, KFSLOOKUPERROR *penmError); /** * Retains a reference to a cache object, internal version. * * @returns pObj * @param pObj The object. */ K_INLINE PKFSOBJ kFsCacheObjRetainInternal(PKFSOBJ pObj) { KU32 cRefs = ++pObj->cRefs; kHlpAssert(cRefs < 16384); K_NOREF(cRefs); return pObj; } #ifndef NDEBUG /** * Debug printing. * @param pszFormat Debug format string. * @param ... Format argument. */ void kFsCacheDbgPrintfV(const char *pszFormat, va_list va) { if (1) { DWORD const dwSavedErr = GetLastError(); fprintf(stderr, "debug: "); vfprintf(stderr, pszFormat, va); SetLastError(dwSavedErr); } } /** * Debug printing. * @param pszFormat Debug format string. * @param ... Format argument. */ void kFsCacheDbgPrintf(const char *pszFormat, ...) { if (1) { va_list va; va_start(va, pszFormat); kFsCacheDbgPrintfV(pszFormat, va); va_end(va); } } #endif /* !NDEBUG */ /** * Hashes a string. * * @returns 32-bit string hash. * @param pszString String to hash. */ static KU32 kFsCacheStrHash(const char *pszString) { /* This algorithm was created for sdbm (a public-domain reimplementation of ndbm) database library. it was found to do well in scrambling bits, causing better distribution of the keys and fewer splits. it also happens to be a good general hashing function with good distribution. the actual function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below is the faster version used in gawk. [there is even a faster, duff-device version] the magic constant 65599 was picked out of thin air while experimenting with different constants, and turns out to be a prime. this is one of the algorithms used in berkeley db (see sleepycat) and elsewhere. */ KU32 uHash = 0; KU32 uChar; while ((uChar = (unsigned char)*pszString++) != 0) uHash = uChar + (uHash << 6) + (uHash << 16) - uHash; return uHash; } /** * Hashes a string. * * @returns The string length. * @param pszString String to hash. * @param puHash Where to return the 32-bit string hash. */ static KSIZE kFsCacheStrHashEx(const char *pszString, KU32 *puHash) { const char * const pszStart = pszString; KU32 uHash = 0; KU32 uChar; while ((uChar = (unsigned char)*pszString) != 0) { uHash = uChar + (uHash << 6) + (uHash << 16) - uHash; pszString++; } *puHash = uHash; return pszString - pszStart; } /** * Hashes a substring. * * @returns 32-bit substring hash. * @param pchString Pointer to the substring (not terminated). * @param cchString The length of the substring. */ static KU32 kFsCacheStrHashN(const char *pchString, KSIZE cchString) { KU32 uHash = 0; while (cchString-- > 0) { KU32 uChar = (unsigned char)*pchString++; uHash = uChar + (uHash << 6) + (uHash << 16) - uHash; } return uHash; } /** * Hashes a UTF-16 string. * * @returns The string length in wchar_t units. * @param pwszString String to hash. * @param puHash Where to return the 32-bit string hash. */ static KSIZE kFsCacheUtf16HashEx(const wchar_t *pwszString, KU32 *puHash) { const wchar_t * const pwszStart = pwszString; KU32 uHash = 0; KU32 uChar; while ((uChar = *pwszString) != 0) { uHash = uChar + (uHash << 6) + (uHash << 16) - uHash; pwszString++; } *puHash = uHash; return pwszString - pwszStart; } /** * Hashes a UTF-16 substring. * * @returns 32-bit substring hash. * @param pwcString Pointer to the substring (not terminated). * @param cchString The length of the substring (in wchar_t's). */ static KU32 kFsCacheUtf16HashN(const wchar_t *pwcString, KSIZE cwcString) { KU32 uHash = 0; while (cwcString-- > 0) { KU32 uChar = *pwcString++; uHash = uChar + (uHash << 6) + (uHash << 16) - uHash; } return uHash; } /** * For use when kFsCacheIAreEqualW hit's something non-trivial. * * @returns K_TRUE if equal, K_FALSE if different. * @param pwcName1 The first string. * @param pwcName2 The second string. * @param cwcName The length of the two strings (in wchar_t's). */ KBOOL kFsCacheIAreEqualSlowW(const wchar_t *pwcName1, const wchar_t *pwcName2, KU16 cwcName) { MY_UNICODE_STRING UniStr1 = { cwcName * sizeof(wchar_t), cwcName * sizeof(wchar_t), (wchar_t *)pwcName1 }; MY_UNICODE_STRING UniStr2 = { cwcName * sizeof(wchar_t), cwcName * sizeof(wchar_t), (wchar_t *)pwcName2 }; return g_pfnRtlEqualUnicodeString(&UniStr1, &UniStr2, TRUE /*fCaseInsensitive*/); } /** * Compares two UTF-16 strings in a case-insensitive fashion. * * You would think we should be using _wscnicmp here instead, however it is * locale dependent and defaults to ASCII upper/lower handling setlocale hasn't * been called. * * @returns K_TRUE if equal, K_FALSE if different. * @param pwcName1 The first string. * @param pwcName2 The second string. * @param cwcName The length of the two strings (in wchar_t's). */ K_INLINE KBOOL kFsCacheIAreEqualW(const wchar_t *pwcName1, const wchar_t *pwcName2, KU32 cwcName) { while (cwcName > 0) { wchar_t wc1 = *pwcName1; wchar_t wc2 = *pwcName2; if (wc1 == wc2) { /* not unlikely */ } else if ( (KU16)wc1 < (KU16)0xc0 /* U+00C0 is the first upper/lower letter after 'z'. */ && (KU16)wc2 < (KU16)0xc0) { /* ASCII upper case. */ if ((KU16)wc1 - (KU16)0x61 < (KU16)26) wc1 &= ~(wchar_t)0x20; if ((KU16)wc2 - (KU16)0x61 < (KU16)26) wc2 &= ~(wchar_t)0x20; if (wc1 != wc2) return K_FALSE; } else return kFsCacheIAreEqualSlowW(pwcName1, pwcName2, (KU16)cwcName); pwcName2++; pwcName1++; cwcName--; } return K_TRUE; } /** * Looks for '..' in the path. * * @returns K_TRUE if '..' component found, K_FALSE if not. * @param pszPath The path. * @param cchPath The length of the path. */ static KBOOL kFsCacheHasDotDotA(const char *pszPath, KSIZE cchPath) { const char *pchDot = (const char *)kHlpMemChr(pszPath, '.', cchPath); while (pchDot) { if (pchDot[1] != '.') { pchDot++; pchDot = (const char *)kHlpMemChr(pchDot, '.', &pszPath[cchPath] - pchDot); } else { char ch; if ( (ch = pchDot[2]) != '\0' && IS_SLASH(ch)) { if (pchDot == pszPath) return K_TRUE; ch = pchDot[-1]; if ( IS_SLASH(ch) || ch == ':') return K_TRUE; } pchDot = (const char *)kHlpMemChr(pchDot + 2, '.', &pszPath[cchPath] - pchDot - 2); } } return K_FALSE; } /** * Looks for '..' in the path. * * @returns K_TRUE if '..' component found, K_FALSE if not. * @param pwszPath The path. * @param cwcPath The length of the path (in wchar_t's). */ static KBOOL kFsCacheHasDotDotW(const wchar_t *pwszPath, KSIZE cwcPath) { const wchar_t *pwcDot = wmemchr(pwszPath, '.', cwcPath); while (pwcDot) { if (pwcDot[1] != '.') { pwcDot++; pwcDot = wmemchr(pwcDot, '.', &pwszPath[cwcPath] - pwcDot); } else { wchar_t wch; if ( (wch = pwcDot[2]) != '\0' && IS_SLASH(wch)) { if (pwcDot == pwszPath) return K_TRUE; wch = pwcDot[-1]; if ( IS_SLASH(wch) || wch == ':') return K_TRUE; } pwcDot = wmemchr(pwcDot + 2, '.', &pwszPath[cwcPath] - pwcDot - 2); } } return K_FALSE; } /** * Creates an ANSI hash table entry for the given path. * * @returns The hash table entry or NULL if out of memory. * @param pCache The hash * @param pFsObj The resulting object. * @param pszPath The path. * @param cchPath The length of the path. * @param uHashPath The hash of the path. * @param fAbsolute Whether it can be refreshed using an absolute * lookup or requires the slow treatment. * @parma idxMissingGen The missing generation index. * @param idxHashTab The hash table index of the path. * @param enmError The lookup error. */ static PKFSHASHA kFsCacheCreatePathHashTabEntryA(PKFSCACHE pCache, PKFSOBJ pFsObj, const char *pszPath, KU32 cchPath, KU32 uHashPath, KU32 idxHashTab, BOOL fAbsolute, KU32 idxMissingGen, KFSLOOKUPERROR enmError) { PKFSHASHA pHashEntry = (PKFSHASHA)kHlpAlloc(sizeof(*pHashEntry) + cchPath + 1); if (pHashEntry) { pHashEntry->uHashPath = uHashPath; pHashEntry->cchPath = (KU16)cchPath; pHashEntry->fAbsolute = fAbsolute; pHashEntry->idxMissingGen = (KU8)idxMissingGen; pHashEntry->enmError = enmError; pHashEntry->pszPath = (const char *)kHlpMemCopy(pHashEntry + 1, pszPath, cchPath + 1); if (pFsObj) { pHashEntry->pFsObj = kFsCacheObjRetainInternal(pFsObj); pHashEntry->uCacheGen = pFsObj->bObjType != KFSOBJ_TYPE_MISSING ? pCache->auGenerations[ pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] : pCache->auGenerationsMissing[pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]; pFsObj->abUnused[0] += 1; // for debugging } else { pHashEntry->pFsObj = NULL; if (enmError != KFSLOOKUPERROR_UNSUPPORTED) pHashEntry->uCacheGen = pCache->auGenerationsMissing[idxMissingGen]; else pHashEntry->uCacheGen = KFSOBJ_CACHE_GEN_IGNORE; } pHashEntry->pNext = pCache->apAnsiPaths[idxHashTab]; pCache->apAnsiPaths[idxHashTab] = pHashEntry; pCache->cbAnsiPaths += sizeof(*pHashEntry) + cchPath + 1; pCache->cAnsiPaths++; if (pHashEntry->pNext) pCache->cAnsiPathCollisions++; } return pHashEntry; } /** * Creates an UTF-16 hash table entry for the given path. * * @returns The hash table entry or NULL if out of memory. * @param pCache The hash * @param pFsObj The resulting object. * @param pwszPath The path. * @param cwcPath The length of the path (in wchar_t's). * @param uHashPath The hash of the path. * @param fAbsolute Whether it can be refreshed using an absolute * lookup or requires the slow treatment. * @parma idxMissingGen The missing generation index. * @param idxHashTab The hash table index of the path. * @param enmError The lookup error. */ static PKFSHASHW kFsCacheCreatePathHashTabEntryW(PKFSCACHE pCache, PKFSOBJ pFsObj, const wchar_t *pwszPath, KU32 cwcPath, KU32 uHashPath, KU32 idxHashTab, BOOL fAbsolute, KU32 idxMissingGen, KFSLOOKUPERROR enmError) { PKFSHASHW pHashEntry = (PKFSHASHW)kHlpAlloc(sizeof(*pHashEntry) + (cwcPath + 1) * sizeof(wchar_t)); if (pHashEntry) { pHashEntry->uHashPath = uHashPath; pHashEntry->cwcPath = cwcPath; pHashEntry->fAbsolute = fAbsolute; pHashEntry->idxMissingGen = (KU8)idxMissingGen; pHashEntry->enmError = enmError; pHashEntry->pwszPath = (const wchar_t *)kHlpMemCopy(pHashEntry + 1, pwszPath, (cwcPath + 1) * sizeof(wchar_t)); if (pFsObj) { pHashEntry->pFsObj = kFsCacheObjRetainInternal(pFsObj); pHashEntry->uCacheGen = pFsObj->bObjType != KFSOBJ_TYPE_MISSING ? pCache->auGenerations[ pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] : pCache->auGenerationsMissing[pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]; pFsObj->abUnused[0] += 1; // for debugging } else { pHashEntry->pFsObj = NULL; if (enmError != KFSLOOKUPERROR_UNSUPPORTED) pHashEntry->uCacheGen = pCache->auGenerationsMissing[idxMissingGen]; else pHashEntry->uCacheGen = KFSOBJ_CACHE_GEN_IGNORE; } pHashEntry->pNext = pCache->apUtf16Paths[idxHashTab]; pCache->apUtf16Paths[idxHashTab] = pHashEntry; pCache->cbUtf16Paths += sizeof(*pHashEntry) + (cwcPath + 1) * sizeof(wchar_t); pCache->cUtf16Paths++; if (pHashEntry->pNext) pCache->cAnsiPathCollisions++; } return pHashEntry; } /** * Links the child in under the parent. * * @returns K_TRUE on success, K_FALSE if out of memory. * @param pParent The parent node. * @param pChild The child node. */ static KBOOL kFsCacheDirAddChild(PKFSCACHE pCache, PKFSDIR pParent, PKFSOBJ pChild, KFSLOOKUPERROR *penmError) { if (pParent->cChildren >= pParent->cChildrenAllocated) { void *pvNew = kHlpRealloc(pParent->papChildren, (pParent->cChildrenAllocated + 16) * sizeof(pParent->papChildren[0])); if (!pvNew) return K_FALSE; pParent->papChildren = (PKFSOBJ *)pvNew; pParent->cChildrenAllocated += 16; pCache->cbObjects += 16 * sizeof(pParent->papChildren[0]); } pParent->papChildren[pParent->cChildren++] = kFsCacheObjRetainInternal(pChild); return K_TRUE; } /** * Creates a new cache object. * * @returns Pointer (with 1 reference) to the new object. The object will not * be linked to the parent directory yet. * * NULL if we're out of memory. * * @param pCache The cache. * @param pParent The parent directory. * @param pszName The ANSI name. * @param cchName The length of the ANSI name. * @param pwszName The UTF-16 name. * @param cwcName The length of the UTF-16 name. * @param pszShortName The ANSI short name, NULL if none. * @param cchShortName The length of the ANSI short name, 0 if none. * @param pwszShortName The UTF-16 short name, NULL if none. * @param cwcShortName The length of the UTF-16 short name, 0 if none. * @param bObjType The objct type. * @param penmError Where to explain failures. */ PKFSOBJ kFsCacheCreateObject(PKFSCACHE pCache, PKFSDIR pParent, char const *pszName, KU16 cchName, wchar_t const *pwszName, KU16 cwcName, #ifdef KFSCACHE_CFG_SHORT_NAMES char const *pszShortName, KU16 cchShortName, wchar_t const *pwszShortName, KU16 cwcShortName, #endif KU8 bObjType, KFSLOOKUPERROR *penmError) { /* * Allocate the object. */ KBOOL const fDirish = bObjType != KFSOBJ_TYPE_FILE && bObjType != KFSOBJ_TYPE_OTHER; KSIZE const cbObj = fDirish ? sizeof(KFSDIR) : sizeof(KFSOBJ); KSIZE const cbNames = (cwcName + 1) * sizeof(wchar_t) + cchName + 1 #ifdef KFSCACHE_CFG_SHORT_NAMES + (cwcShortName > 0 ? (cwcShortName + 1) * sizeof(wchar_t) + cchShortName + 1 : 0) #endif ; PKFSOBJ pObj; kHlpAssert(pCache->u32Magic == KFSCACHE_MAGIC); pObj = (PKFSOBJ)kHlpAlloc(cbObj + cbNames); if (pObj) { KU8 *pbExtra = (KU8 *)pObj + cbObj; pCache->cbObjects += cbObj + cbNames; pCache->cObjects++; /* * Initialize the object. */ pObj->u32Magic = KFSOBJ_MAGIC; pObj->cRefs = 1; pObj->uCacheGen = bObjType != KFSOBJ_TYPE_MISSING ? pCache->auGenerations[pParent->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN] : pCache->auGenerationsMissing[pParent->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN]; pObj->bObjType = bObjType; pObj->fHaveStats = K_FALSE; pObj->abUnused[0] = K_FALSE; pObj->abUnused[1] = K_FALSE; pObj->fFlags = pParent->Obj.fFlags & KFSOBJ_F_INHERITED_MASK; pObj->pParent = pParent; pObj->uNameHash = 0; pObj->pNextNameHash = NULL; pObj->pNameAlloc = NULL; pObj->pUserDataHead = NULL; #ifdef KFSCACHE_CFG_UTF16 pObj->cwcParent = pParent->Obj.cwcParent + pParent->Obj.cwcName + !!pParent->Obj.cwcName; pObj->pwszName = (wchar_t *)kHlpMemCopy(pbExtra, pwszName, cwcName * sizeof(wchar_t)); pObj->cwcName = cwcName; pbExtra += cwcName * sizeof(wchar_t); *pbExtra++ = '\0'; *pbExtra++ = '\0'; # ifdef KFSCACHE_CFG_SHORT_NAMES pObj->cwcShortParent = pParent->Obj.cwcShortParent + pParent->Obj.cwcShortName + !!pParent->Obj.cwcShortName; if (cwcShortName) { pObj->pwszShortName = (wchar_t *)kHlpMemCopy(pbExtra, pwszShortName, cwcShortName * sizeof(wchar_t)); pObj->cwcShortName = cwcShortName; pbExtra += cwcShortName * sizeof(wchar_t); *pbExtra++ = '\0'; *pbExtra++ = '\0'; } else { pObj->pwszShortName = pObj->pwszName; pObj->cwcShortName = cwcName; } # endif #endif pObj->cchParent = pParent->Obj.cchParent + pParent->Obj.cchName + !!pParent->Obj.cchName; pObj->pszName = (char *)kHlpMemCopy(pbExtra, pszName, cchName); pObj->cchName = cchName; pbExtra += cchName; *pbExtra++ = '\0'; # ifdef KFSCACHE_CFG_SHORT_NAMES pObj->cchShortParent = pParent->Obj.cchShortParent + pParent->Obj.cchShortName + !!pParent->Obj.cchShortName; if (cchShortName) { pObj->pszShortName = (char *)kHlpMemCopy(pbExtra, pszShortName, cchShortName); pObj->cchShortName = cchShortName; pbExtra += cchShortName; *pbExtra++ = '\0'; } else { pObj->pszShortName = pObj->pszName; pObj->cchShortName = cchName; } #endif kHlpAssert(pbExtra - (KU8 *)pObj == cbObj); /* * Type specific initialization. */ if (fDirish) { PKFSDIR pDirObj = (PKFSDIR)pObj; pDirObj->cChildren = 0; pDirObj->cChildrenAllocated = 0; pDirObj->papChildren = NULL; pDirObj->fHashTabMask = 0; pDirObj->papHashTab = NULL; pDirObj->hDir = INVALID_HANDLE_VALUE; pDirObj->uDevNo = pParent->uDevNo; pDirObj->iLastWrite = 0; pDirObj->fPopulated = K_FALSE; } } else *penmError = KFSLOOKUPERROR_OUT_OF_MEMORY; return pObj; } /** * Creates a new object given wide char names. * * This function just converts the paths and calls kFsCacheCreateObject. * * * @returns Pointer (with 1 reference) to the new object. The object will not * be linked to the parent directory yet. * * NULL if we're out of memory. * * @param pCache The cache. * @param pParent The parent directory. * @param pszName The ANSI name. * @param cchName The length of the ANSI name. * @param pwszName The UTF-16 name. * @param cwcName The length of the UTF-16 name. * @param pwszShortName The UTF-16 short name, NULL if none. * @param cwcShortName The length of the UTF-16 short name, 0 if none. * @param bObjType The objct type. * @param penmError Where to explain failures. */ PKFSOBJ kFsCacheCreateObjectW(PKFSCACHE pCache, PKFSDIR pParent, wchar_t const *pwszName, KU32 cwcName, #ifdef KFSCACHE_CFG_SHORT_NAMES wchar_t const *pwszShortName, KU32 cwcShortName, #endif KU8 bObjType, KFSLOOKUPERROR *penmError) { /* Convert names to ANSI first so we know their lengths. */ char szName[KFSCACHE_CFG_MAX_ANSI_NAME]; int cchName = WideCharToMultiByte(CP_ACP, 0, pwszName, cwcName, szName, sizeof(szName) - 1, NULL, NULL); if (cchName >= 0) { #ifdef KFSCACHE_CFG_SHORT_NAMES char szShortName[12*3 + 1]; int cchShortName = 0; if ( cwcShortName == 0 || (cchShortName = WideCharToMultiByte(CP_ACP, 0, pwszShortName, cwcShortName, szShortName, sizeof(szShortName) - 1, NULL, NULL)) > 0) #endif { return kFsCacheCreateObject(pCache, pParent, szName, cchName, pwszName, cwcName, #ifdef KFSCACHE_CFG_SHORT_NAMES szShortName, cchShortName, pwszShortName, cwcShortName, #endif bObjType, penmError); } } *penmError = KFSLOOKUPERROR_ANSI_CONVERSION_ERROR; return NULL; } /** * Creates a missing object. * * This is used for caching negative results. * * @returns Pointer to the newly created object on success (already linked into * pParent). No reference. * * NULL on failure. * * @param pCache The cache. * @param pParent The parent directory. * @param pchName The name. * @param cchName The length of the name. * @param penmError Where to return failure explanations. */ static PKFSOBJ kFsCacheCreateMissingA(PKFSCACHE pCache, PKFSDIR pParent, const char *pchName, KU32 cchName, KFSLOOKUPERROR *penmError) { /* * Just convert the name to UTF-16 and call kFsCacheCreateObject to do the job. */ wchar_t wszName[KFSCACHE_CFG_MAX_PATH]; int cwcName = MultiByteToWideChar(CP_ACP, 0, pchName, cchName, wszName, KFSCACHE_CFG_MAX_UTF16_NAME - 1); if (cwcName > 0) { /** @todo check that it actually doesn't exists before we add it. We should not * trust the directory enumeration here, or maybe we should?? */ PKFSOBJ pMissing = kFsCacheCreateObject(pCache, pParent, pchName, cchName, wszName, cwcName, #ifdef KFSCACHE_CFG_SHORT_NAMES NULL, 0, NULL, 0, #endif KFSOBJ_TYPE_MISSING, penmError); if (pMissing) { KBOOL fRc = kFsCacheDirAddChild(pCache, pParent, pMissing, penmError); kFsCacheObjRelease(pCache, pMissing); return fRc ? pMissing : NULL; } return NULL; } *penmError = KFSLOOKUPERROR_UTF16_CONVERSION_ERROR; return NULL; } /** * Creates a missing object, UTF-16 version. * * This is used for caching negative results. * * @returns Pointer to the newly created object on success (already linked into * pParent). No reference. * * NULL on failure. * * @param pCache The cache. * @param pParent The parent directory. * @param pwcName The name. * @param cwcName The length of the name. * @param penmError Where to return failure explanations. */ static PKFSOBJ kFsCacheCreateMissingW(PKFSCACHE pCache, PKFSDIR pParent, const wchar_t *pwcName, KU32 cwcName, KFSLOOKUPERROR *penmError) { /** @todo check that it actually doesn't exists before we add it. We should not * trust the directory enumeration here, or maybe we should?? */ PKFSOBJ pMissing = kFsCacheCreateObjectW(pCache, pParent, pwcName, cwcName, #ifdef KFSCACHE_CFG_SHORT_NAMES NULL, 0, #endif KFSOBJ_TYPE_MISSING, penmError); if (pMissing) { KBOOL fRc = kFsCacheDirAddChild(pCache, pParent, pMissing, penmError); kFsCacheObjRelease(pCache, pMissing); return fRc ? pMissing : NULL; } return NULL; } /** * Does the growing of names. * * @returns pCur * @param pCache The cache. * @param pCur The object. * @param pchName The name (not necessarily terminated). * @param cchName Name length. * @param pwcName The UTF-16 name (not necessarily terminated). * @param cwcName The length of the UTF-16 name in wchar_t's. * @param pchShortName The short name. * @param cchShortName The length of the short name. This is 0 if no short * name. * @param pwcShortName The short UTF-16 name. * @param cwcShortName The length of the short UTF-16 name. This is 0 if * no short name. */ static PKFSOBJ kFsCacheRefreshGrowNames(PKFSCACHE pCache, PKFSOBJ pCur, const char *pchName, KU32 cchName, wchar_t const *pwcName, KU32 cwcName #ifdef KFSCACHE_CFG_SHORT_NAMES , const char *pchShortName, KU32 cchShortName, wchar_t const *pwcShortName, KU32 cwcShortName #endif ) { PKFSOBJNAMEALLOC pNameAlloc; char *pch; KU32 cbNeeded; pCache->cNameGrowths++; /* * Figure out our requirements. */ cbNeeded = sizeof(KU32) + cchName + 1; #ifdef KFSCACHE_CFG_UTF16 cbNeeded += (cwcName + 1) * sizeof(wchar_t); #endif #ifdef KFSCACHE_CFG_SHORT_NAMES cbNeeded += cchShortName + !!cchShortName; # ifdef KFSCACHE_CFG_UTF16 cbNeeded += (cwcShortName + !!cwcShortName) * sizeof(wchar_t); # endif #endif cbNeeded = K_ALIGN_Z(cbNeeded, 8); /* Memory will likely be 8 or 16 byte aligned, so we might just claim it. */ /* * Allocate memory. */ pNameAlloc = pCur->pNameAlloc; if (!pNameAlloc) { pNameAlloc = (PKFSOBJNAMEALLOC)kHlpAlloc(cbNeeded); if (!pNameAlloc) return pCur; pCache->cbObjects += cbNeeded; pCur->pNameAlloc = pNameAlloc; pNameAlloc->cb = cbNeeded; } else if (pNameAlloc->cb < cbNeeded) { pNameAlloc = (PKFSOBJNAMEALLOC)kHlpRealloc(pNameAlloc, cbNeeded); if (!pNameAlloc) return pCur; pCache->cbObjects += cbNeeded - pNameAlloc->cb; pCur->pNameAlloc = pNameAlloc; pNameAlloc->cb = cbNeeded; } /* * Copy out the new names, starting with the wide char ones to avoid misaligning them. */ pch = &pNameAlloc->abSpace[0]; #ifdef KFSCACHE_CFG_UTF16 pCur->pwszName = (wchar_t *)pch; pCur->cwcName = cwcName; pch = kHlpMemPCopy(pch, pwcName, cwcName * sizeof(wchar_t)); *pch++ = '\0'; *pch++ = '\0'; # ifdef KFSCACHE_CFG_SHORT_NAMES if (cwcShortName == 0) { pCur->pwszShortName = pCur->pwszName; pCur->cwcShortName = pCur->cwcName; } else { pCur->pwszShortName = (wchar_t *)pch; pCur->cwcShortName = cwcShortName; pch = kHlpMemPCopy(pch, pwcShortName, cwcShortName * sizeof(wchar_t)); *pch++ = '\0'; *pch++ = '\0'; } # endif #endif pCur->pszName = pch; pCur->cchName = cchName; pch = kHlpMemPCopy(pch, pchName, cchShortName); *pch++ = '\0'; #ifdef KFSCACHE_CFG_SHORT_NAMES if (cchShortName == 0) { pCur->pszShortName = pCur->pszName; pCur->cchShortName = pCur->cchName; } else { pCur->pszShortName = pch; pCur->cchShortName = cchShortName; pch = kHlpMemPCopy(pch, pchShortName, cchShortName); *pch++ = '\0'; } #endif return pCur; } /** * Worker for kFsCacheDirFindOldChild that refreshes the file ID value on an * object found by name. * * @returns pCur. * @param pDirRePop Repopulation data. * @param pCur The object to check the names of. * @param idFile The file ID. */ static PKFSOBJ kFsCacheDirRefreshOldChildFileId(PKFSDIRREPOP pDirRePop, PKFSOBJ pCur, KI64 idFile) { KFSCACHE_LOG(("Refreshing %s/%s/ - %s changed file ID from %#llx -> %#llx...\n", pCur->pParent->Obj.pParent->Obj.pszName, pCur->pParent->Obj.pszName, pCur->pszName, pCur->Stats.st_ino, idFile)); pCur->Stats.st_ino = idFile; /** @todo inform user data items... */ return pCur; } /** * Worker for kFsCacheDirFindOldChild that checks the names after an old object * has been found the file ID. * * @returns pCur. * @param pDirRePop Repopulation data. * @param pCur The object to check the names of. * @param pwcName The file name. * @param cwcName The length of the filename (in wchar_t's). * @param pwcShortName The short name, if present. * @param cwcShortName The length of the short name (in wchar_t's). */ static PKFSOBJ kFsCacheDirRefreshOldChildName(PKFSDIRREPOP pDirRePop, PKFSOBJ pCur, wchar_t const *pwcName, KU32 cwcName #ifdef KFSCACHE_CFG_SHORT_NAMES , wchar_t const *pwcShortName, KU32 cwcShortName #endif ) { char szName[KFSCACHE_CFG_MAX_ANSI_NAME]; int cchName; pDirRePop->pCache->cNameChanges++; /* * Convert the names to ANSI first, that way we know all the lengths. */ cchName = WideCharToMultiByte(CP_ACP, 0, pwcName, cwcName, szName, sizeof(szName) - 1, NULL, NULL); if (cchName >= 0) { #ifdef KFSCACHE_CFG_SHORT_NAMES char szShortName[12*3 + 1]; int cchShortName = 0; if ( cwcShortName == 0 || (cchShortName = WideCharToMultiByte(CP_ACP, 0, pwcShortName, cwcShortName, szShortName, sizeof(szShortName) - 1, NULL, NULL)) > 0) #endif { /* * Shortening is easy for non-directory objects, for * directory object we're only good when the length doesn't change * on any of the components (cchParent et al). * * This deals with your typical xxxx.ext.tmp -> xxxx.ext renames. */ if ( cchName <= pCur->cchName #ifdef KFSCACHE_CFG_UTF16 && cwcName <= pCur->cwcName #endif #ifdef KFSCACHE_CFG_SHORT_NAMES && ( cchShortName == 0 || ( cchShortName <= pCur->cchShortName && pCur->pszShortName != pCur->pszName # ifdef KFSCACHE_CFG_UTF16 && cwcShortName <= pCur->cwcShortName && pCur->pwszShortName != pCur->pwszName # endif ) ) #endif ) { if ( pCur->bObjType != KFSOBJ_TYPE_DIR || ( cchName == pCur->cchName #ifdef KFSCACHE_CFG_UTF16 && cwcName == pCur->cwcName #endif #ifdef KFSCACHE_CFG_SHORT_NAMES && ( cchShortName == 0 || ( cchShortName == pCur->cchShortName # ifdef KFSCACHE_CFG_UTF16 && cwcShortName == pCur->cwcShortName ) # endif ) #endif ) ) { KFSCACHE_LOG(("Refreshing %ls - name changed to '%*.*ls'\n", pCur->pwszName, cwcName, cwcName, pwcName)); *(char *)kHlpMemPCopy((void *)pCur->pszName, szName, cchName) = '\0'; pCur->cchName = cchName; #ifdef KFSCACHE_CFG_UTF16 *(wchar_t *)kHlpMemPCopy((void *)pCur->pwszName, pwcName, cwcName * sizeof(wchar_t)) = '\0'; pCur->cwcName = cwcName; #endif #ifdef KFSCACHE_CFG_SHORT_NAMES *(char *)kHlpMemPCopy((void *)pCur->pszShortName, szShortName, cchShortName) = '\0'; pCur->cchShortName = cchShortName; # ifdef KFSCACHE_CFG_UTF16 *(wchar_t *)kHlpMemPCopy((void *)pCur->pwszShortName, pwcShortName, cwcShortName * sizeof(wchar_t)) = '\0'; pCur->cwcShortName = cwcShortName; # endif #endif return pCur; } } return kFsCacheRefreshGrowNames(pDirRePop->pCache, pCur, szName, cchName, pwcName, cwcName, #ifdef KFSCACHE_CFG_SHORT_NAMES szShortName, cchShortName, pwcShortName, cwcShortName #endif ); } } fprintf(stderr, "kFsCacheDirRefreshOldChildName: WideCharToMultiByte error\n"); return pCur; } /** * Worker for kFsCacheDirFindOldChild that checks the names after an old object * has been found by the file ID. * * @returns pCur. * @param pDirRePop Repopulation data. * @param pCur The object to check the names of. * @param pwcName The file name. * @param cwcName The length of the filename (in wchar_t's). * @param pwcShortName The short name, if present. * @param cwcShortName The length of the short name (in wchar_t's). */ K_INLINE PKFSOBJ kFsCacheDirCheckOldChildName(PKFSDIRREPOP pDirRePop, PKFSOBJ pCur, wchar_t const *pwcName, KU32 cwcName #ifdef KFSCACHE_CFG_SHORT_NAMES , wchar_t const *pwcShortName, KU32 cwcShortName #endif ) { if ( pCur->cwcName == cwcName && kHlpMemComp(pCur->pwszName, pwcName, cwcName * sizeof(wchar_t)) == 0) { #ifdef KFSCACHE_CFG_SHORT_NAMES if (cwcShortName == 0 ? pCur->pwszShortName == pCur->pwszName || ( pCur->cwcShortName == cwcName && kHlpMemComp(pCur->pwszShortName, pCur->pwszName, cwcName * sizeof(wchar_t)) == 0) : pCur->cwcShortName == cwcShortName && kHlpMemComp(pCur->pwszShortName, pwcShortName, cwcShortName * sizeof(wchar_t)) == 0 ) #endif { return pCur; } } #ifdef KFSCACHE_CFG_SHORT_NAMES return kFsCacheDirRefreshOldChildName(pDirRePop, pCur, pwcName, cwcName, pwcShortName, cwcShortName); #else return kFsCacheDirRefreshOldChildName(pDirRePop, pCur, pwcName, cwcName); #endif } /** * Worker for kFsCachePopuplateOrRefreshDir that locates an old child object * while re-populating a directory. * * @returns Pointer to the existing object if found, NULL if not. * @param pDirRePop Repopulation data. * @param idFile The file ID, 0 if none. * @param pwcName The file name. * @param cwcName The length of the filename (in wchar_t's). * @param pwcShortName The short name, if present. * @param cwcShortName The length of the short name (in wchar_t's). */ static PKFSOBJ kFsCacheDirFindOldChildSlow(PKFSDIRREPOP pDirRePop, KI64 idFile, wchar_t const *pwcName, KU32 cwcName #ifdef KFSCACHE_CFG_SHORT_NAMES , wchar_t const *pwcShortName, KU32 cwcShortName #endif ) { KU32 cOldChildren = pDirRePop->cOldChildren; KU32 const iNextOldChild = K_MIN(pDirRePop->iNextOldChild, cOldChildren - 1); KU32 iCur; KI32 cInc; KI32 cDirLefts; kHlpAssertReturn(cOldChildren > 0, NULL); /* * Search by file ID first, if we've got one. * ASSUMES that KU32 wraps around when -1 is added to 0. */ if ( idFile != 0 && idFile != KI64_MAX && idFile != KI64_MIN) { cInc = pDirRePop->cNextOldChildInc; kHlpAssert(cInc == -1 || cInc == 1); for (cDirLefts = 2; cDirLefts > 0; cDirLefts--) { for (iCur = iNextOldChild; iCur < cOldChildren; iCur += cInc) { PKFSOBJ pCur = pDirRePop->papOldChildren[iCur]; if (pCur->Stats.st_ino == idFile) { /* Remove it and check the name. */ pDirRePop->cOldChildren = --cOldChildren; if (iCur < cOldChildren) pDirRePop->papOldChildren[iCur] = pDirRePop->papOldChildren[cOldChildren]; else cInc = -1; pDirRePop->cNextOldChildInc = cInc; pDirRePop->iNextOldChild = iCur + cInc; #ifdef KFSCACHE_CFG_SHORT_NAMES return kFsCacheDirCheckOldChildName(pDirRePop, pCur, pwcName, cwcName, pwcShortName, cwcShortName); #else return kFsCacheDirCheckOldChildName(pDirRePop, pCur, pwcName, cwcName, pwcShortName, cwcShortName); #endif } } cInc = -cInc; } } /* * Search by name. * ASSUMES that KU32 wraps around when -1 is added to 0. */ cInc = pDirRePop->cNextOldChildInc; kHlpAssert(cInc == -1 || cInc == 1); for (cDirLefts = 2; cDirLefts > 0; cDirLefts--) { for (iCur = iNextOldChild; iCur < cOldChildren; iCur += cInc) { PKFSOBJ pCur = pDirRePop->papOldChildren[iCur]; if ( ( pCur->cwcName == cwcName && kFsCacheIAreEqualW(pCur->pwszName, pwcName, cwcName)) #ifdef KFSCACHE_CFG_SHORT_NAMES || ( pCur->cwcShortName == cwcName && pCur->pwszShortName != pCur->pwszName && kFsCacheIAreEqualW(pCur->pwszShortName, pwcName, cwcName)) #endif ) { /* Do this first so the compiler can share the rest with the above file ID return. */ if (pCur->Stats.st_ino == idFile) { /* likely */ } else pCur = kFsCacheDirRefreshOldChildFileId(pDirRePop, pCur, idFile); /* Remove it and check the name. */ pDirRePop->cOldChildren = --cOldChildren; if (iCur < cOldChildren) pDirRePop->papOldChildren[iCur] = pDirRePop->papOldChildren[cOldChildren]; else cInc = -1; pDirRePop->cNextOldChildInc = cInc; pDirRePop->iNextOldChild = iCur + cInc; #ifdef KFSCACHE_CFG_SHORT_NAMES return kFsCacheDirCheckOldChildName(pDirRePop, pCur, pwcName, cwcName, pwcShortName, cwcShortName); #else return kFsCacheDirCheckOldChildName(pDirRePop, pCur, pwcName, cwcName, pwcShortName, cwcShortName); #endif } } cInc = -cInc; } return NULL; } /** * Worker for kFsCachePopuplateOrRefreshDir that locates an old child object * while re-populating a directory. * * @returns Pointer to the existing object if found, NULL if not. * @param pDirRePop Repopulation data. * @param idFile The file ID, 0 if none. * @param pwcName The file name. * @param cwcName The length of the filename (in wchar_t's). * @param pwcShortName The short name, if present. * @param cwcShortName The length of the short name (in wchar_t's). */ K_INLINE PKFSOBJ kFsCacheDirFindOldChild(PKFSDIRREPOP pDirRePop, KI64 idFile, wchar_t const *pwcName, KU32 cwcName #ifdef KFSCACHE_CFG_SHORT_NAMES , wchar_t const *pwcShortName, KU32 cwcShortName #endif ) { /* * We only check the iNextOldChild element here, hoping that the compiler * will actually inline this code, letting the slow version of the function * do the rest. */ KU32 cOldChildren = pDirRePop->cOldChildren; if (cOldChildren > 0) { KU32 const iNextOldChild = K_MIN(pDirRePop->iNextOldChild, cOldChildren - 1); PKFSOBJ pCur = pDirRePop->papOldChildren[iNextOldChild]; if ( pCur->Stats.st_ino == idFile && idFile != 0 && idFile != KI64_MAX && idFile != KI64_MIN) pCur = kFsCacheDirCheckOldChildName(pDirRePop, pCur, pwcName, cwcName, pwcShortName, cwcShortName); else if ( pCur->cwcName == cwcName && kHlpMemComp(pCur->pwszName, pwcName, cwcName * sizeof(wchar_t)) == 0) { if (pCur->Stats.st_ino == idFile) { /* likely */ } else pCur = kFsCacheDirRefreshOldChildFileId(pDirRePop, pCur, idFile); #ifdef KFSCACHE_CFG_SHORT_NAMES if (cwcShortName == 0 ? pCur->pwszShortName == pCur->pwszName || ( pCur->cwcShortName == cwcName && kHlpMemComp(pCur->pwszShortName, pCur->pwszName, cwcName * sizeof(wchar_t)) == 0) : pCur->cwcShortName == cwcShortName && kHlpMemComp(pCur->pwszShortName, pwcShortName, cwcShortName * sizeof(wchar_t)) == 0 ) { /* likely */ } else pCur = kFsCacheDirRefreshOldChildName(pDirRePop, pCur, pwcName, cwcName, pwcShortName, cwcShortName); #endif } else pCur = NULL; if (pCur) { /* * Got a match. Remove the child from the array, replacing it with * the last element. (This means we're reversing the second half of * the elements, which is why we need cNextOldChildInc.) */ pDirRePop->cOldChildren = --cOldChildren; if (iNextOldChild < cOldChildren) pDirRePop->papOldChildren[iNextOldChild] = pDirRePop->papOldChildren[cOldChildren]; pDirRePop->iNextOldChild = iNextOldChild + pDirRePop->cNextOldChildInc; return pCur; } #ifdef KFSCACHE_CFG_SHORT_NAMES return kFsCacheDirFindOldChildSlow(pDirRePop, idFile, pwcName, cwcName, pwcShortName, cwcShortName); #else return kFsCacheDirFindOldChildSlow(pDirRePop, idFile, pwcName, cwcName); #endif } return NULL; } /** * Does the initial directory populating or refreshes it if it has been * invalidated. * * This assumes the parent directory is opened. * * @returns K_TRUE on success, K_FALSE on error. * @param pCache The cache. * @param pDir The directory. * @param penmError Where to store K_FALSE explanation. */ static KBOOL kFsCachePopuplateOrRefreshDir(PKFSCACHE pCache, PKFSDIR pDir, KFSLOOKUPERROR *penmError) { KBOOL fRefreshing = K_FALSE; KFSDIRREPOP DirRePop = { NULL, 0, 0, 0, NULL }; MY_UNICODE_STRING UniStrStar = { 1 * sizeof(wchar_t), 2 * sizeof(wchar_t), L"*" }; /** @todo May have to make this more flexible wrt information classes since * older windows versions (XP, w2K) might not correctly support the * ones with file ID on all file systems. */ #ifdef KFSCACHE_CFG_SHORT_NAMES MY_FILE_INFORMATION_CLASS const enmInfoClassWithId = MyFileIdBothDirectoryInformation; MY_FILE_INFORMATION_CLASS enmInfoClass = MyFileIdBothDirectoryInformation; #else MY_FILE_INFORMATION_CLASS const enmInfoClassWithId = MyFileIdFullDirectoryInformation; MY_FILE_INFORMATION_CLASS enmInfoClass = MyFileIdFullDirectoryInformation; #endif MY_NTSTATUS rcNt; MY_IO_STATUS_BLOCK Ios; union { /* Include the structures for better alignment. */ MY_FILE_ID_BOTH_DIR_INFORMATION WithId; MY_FILE_ID_FULL_DIR_INFORMATION NoId; /** Buffer padding. We're using a 56KB buffer here to avoid size troubles * with CIFS and such that starts at 64KB. */ KU8 abBuf[56*1024]; } uBuf; /* * Open the directory. */ if (pDir->hDir == INVALID_HANDLE_VALUE) { MY_OBJECT_ATTRIBUTES ObjAttr; MY_UNICODE_STRING UniStr; kHlpAssert(!pDir->fPopulated); Ios.Information = -1; Ios.u.Status = -1; UniStr.Buffer = (wchar_t *)pDir->Obj.pwszName; UniStr.Length = (USHORT)(pDir->Obj.cwcName * sizeof(wchar_t)); UniStr.MaximumLength = UniStr.Length + sizeof(wchar_t); kHlpAssertStmtReturn(pDir->Obj.pParent, *penmError = KFSLOOKUPERROR_INTERNAL_ERROR, K_FALSE); kHlpAssertStmtReturn(pDir->Obj.pParent->hDir != INVALID_HANDLE_VALUE, *penmError = KFSLOOKUPERROR_INTERNAL_ERROR, K_FALSE); MyInitializeObjectAttributes(&ObjAttr, &UniStr, OBJ_CASE_INSENSITIVE, pDir->Obj.pParent->hDir, NULL /*pSecAttr*/); /** @todo FILE_OPEN_REPARSE_POINT? */ rcNt = g_pfnNtCreateFile(&pDir->hDir, FILE_READ_DATA | FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | SYNCHRONIZE, &ObjAttr, &Ios, NULL, /*cbFileInitialAlloc */ FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, NULL, /*pEaBuffer*/ 0); /*cbEaBuffer*/ if (MY_NT_SUCCESS(rcNt)) { /* likely */ } else { pDir->hDir = INVALID_HANDLE_VALUE; *penmError = KFSLOOKUPERROR_DIR_OPEN_ERROR; return K_FALSE; } } /* * When re-populating, we replace papChildren in the directory and pick * from the old one as we go along. */ else if (pDir->fPopulated) { KU32 cAllocated; void *pvNew; /* Make sure we really need to do this first. */ if (!pDir->fNeedRePopulating) { if ( pDir->Obj.uCacheGen == KFSOBJ_CACHE_GEN_IGNORE || pDir->Obj.uCacheGen == pCache->auGenerations[pDir->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN]) return K_TRUE; if ( kFsCacheRefreshObj(pCache, &pDir->Obj, penmError) && !pDir->fNeedRePopulating) return K_TRUE; } /* Yes we do need to. */ cAllocated = K_ALIGN_Z(pDir->cChildren, 16); pvNew = kHlpAlloc(sizeof(pDir->papChildren[0]) * cAllocated); if (pvNew) { DirRePop.papOldChildren = pDir->papChildren; DirRePop.cOldChildren = pDir->cChildren; DirRePop.iNextOldChild = 0; DirRePop.cNextOldChildInc = 1; DirRePop.pCache = pCache; pDir->cChildren = 0; pDir->cChildrenAllocated = cAllocated; pDir->papChildren = (PKFSOBJ *)pvNew; } else { *penmError = KFSLOOKUPERROR_OUT_OF_MEMORY; return K_FALSE; } fRefreshing = K_TRUE; } if (!fRefreshing) KFSCACHE_LOG(("Populating %s...\n", pDir->Obj.pszName)); else KFSCACHE_LOG(("Refreshing %s...\n", pDir->Obj.pszName)); /* * Enumerate the directory content. * * Note! The "*" filter is necessary because kFsCacheRefreshObj may have * previously quried a single file name and just passing NULL would * restart that single file name query. */ Ios.Information = -1; Ios.u.Status = -1; rcNt = g_pfnNtQueryDirectoryFile(pDir->hDir, NULL, /* hEvent */ NULL, /* pfnApcComplete */ NULL, /* pvApcCompleteCtx */ &Ios, &uBuf, sizeof(uBuf), enmInfoClass, FALSE, /* fReturnSingleEntry */ &UniStrStar, /* Filter / restart pos. */ TRUE); /* fRestartScan */ while (MY_NT_SUCCESS(rcNt)) { /* * Process the entries in the buffer. */ KSIZE offBuf = 0; for (;;) { union { KU8 *pb; #ifdef KFSCACHE_CFG_SHORT_NAMES MY_FILE_ID_BOTH_DIR_INFORMATION *pWithId; MY_FILE_BOTH_DIR_INFORMATION *pNoId; #else MY_FILE_ID_FULL_DIR_INFORMATION *pWithId; MY_FILE_FULL_DIR_INFORMATION *pNoId; #endif } uPtr; PKFSOBJ pCur; KU32 offNext; KU32 cbMinCur; wchar_t *pwchFilename; /* ASSUME only the FileName member differs between the two structures. */ uPtr.pb = &uBuf.abBuf[offBuf]; if (enmInfoClass == enmInfoClassWithId) { pwchFilename = &uPtr.pWithId->FileName[0]; cbMinCur = (KU32)((uintptr_t)&uPtr.pWithId->FileName[0] - (uintptr_t)uPtr.pWithId); cbMinCur += uPtr.pNoId->FileNameLength; } else { pwchFilename = &uPtr.pNoId->FileName[0]; cbMinCur = (KU32)((uintptr_t)&uPtr.pNoId->FileName[0] - (uintptr_t)uPtr.pNoId); cbMinCur += uPtr.pNoId->FileNameLength; } /* We need to skip the '.' and '..' entries. */ if ( *pwchFilename != '.' || uPtr.pNoId->FileNameLength > 4 || !( uPtr.pNoId->FileNameLength == 2 || ( uPtr.pNoId->FileNameLength == 4 && pwchFilename[1] == '.') ) ) { KBOOL fRc; KU8 const bObjType = uPtr.pNoId->FileAttributes & FILE_ATTRIBUTE_DIRECTORY ? KFSOBJ_TYPE_DIR : uPtr.pNoId->FileAttributes & (FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_REPARSE_POINT) ? KFSOBJ_TYPE_OTHER : KFSOBJ_TYPE_FILE; /* * If refreshing, we must first see if this directory entry already * exists. */ if (!fRefreshing) pCur = NULL; else { pCur = kFsCacheDirFindOldChild(&DirRePop, enmInfoClass == enmInfoClassWithId ? uPtr.pWithId->FileId.QuadPart : 0, pwchFilename, uPtr.pWithId->FileNameLength / sizeof(wchar_t) #ifdef KFSCACHE_CFG_SHORT_NAMES , uPtr.pWithId->ShortName, uPtr.pWithId->ShortNameLength / sizeof(wchar_t) #endif ); if (pCur) { if (pCur->bObjType == bObjType) { if (pCur->bObjType == KFSOBJ_TYPE_DIR) { PKFSDIR pCurDir = (PKFSDIR)pCur; if ( !pCurDir->fPopulated || ( pCurDir->iLastWrite == uPtr.pWithId->LastWriteTime.QuadPart && (pCur->fFlags & KFSOBJ_F_WORKING_DIR_MTIME) ) ) { /* kind of likely */ } else { KFSCACHE_LOG(("Refreshing %s/%s/ - %s/ needs re-populating...\n", pDir->Obj.pParent->Obj.pszName, pDir->Obj.pszName, pCur->pszName)); pCurDir->fNeedRePopulating = K_TRUE; } } } else if (pCur->bObjType == KFSOBJ_TYPE_MISSING) { KFSCACHE_LOG(("Refreshing %s/%s/ - %s appeared as %u, was missing.\n", pDir->Obj.pParent->Obj.pszName, pDir->Obj.pszName, pCur->pszName, bObjType)); pCur->bObjType = bObjType; } else { KFSCACHE_LOG(("Refreshing %s/%s/ - %s changed type from %u to %u! Dropping old object.\n", pDir->Obj.pParent->Obj.pszName, pDir->Obj.pszName, pCur->pszName, pCur->bObjType, bObjType)); kFsCacheObjRelease(pCache, pCur); pCur = NULL; } } else KFSCACHE_LOG(("Refreshing %s/%s/ - %*.*ls added.\n", pDir->Obj.pParent->Obj.pszName, pDir->Obj.pszName, uPtr.pNoId->FileNameLength / sizeof(wchar_t), uPtr.pNoId->FileNameLength / sizeof(wchar_t), pwchFilename)); } if (!pCur) { /* * Create the entry (not linked yet). */ pCur = kFsCacheCreateObjectW(pCache, pDir, pwchFilename, uPtr.pNoId->FileNameLength / sizeof(wchar_t), #ifdef KFSCACHE_CFG_SHORT_NAMES uPtr.pNoId->ShortName, uPtr.pNoId->ShortNameLength / sizeof(wchar_t), #endif bObjType, penmError); if (!pCur) return K_FALSE; kHlpAssert(pCur->cRefs == 1); } #ifdef KFSCACHE_CFG_SHORT_NAMES if (enmInfoClass == enmInfoClassWithId) birdStatFillFromFileIdBothDirInfo(&pCur->Stats, uPtr.pWithId); else birdStatFillFromFileBothDirInfo(&pCur->Stats, uPtr.pNoId); #else if (enmInfoClass == enmInfoClassWithId) birdStatFillFromFileIdFullDirInfo(&pCur->Stats, uPtr.pWithId); else birdStatFillFromFileFullDirInfo(&pCur->Stats, uPtr.pNoId); #endif pCur->Stats.st_dev = pDir->uDevNo; pCur->fHaveStats = K_TRUE; /* * Add the entry to the directory. */ fRc = kFsCacheDirAddChild(pCache, pDir, pCur, penmError); kFsCacheObjRelease(pCache, pCur); if (fRc) { /* likely */ } else { rcNt = STATUS_NO_MEMORY; break; } } /* * When seeing '.' we update the directory info. */ else if (uPtr.pNoId->FileNameLength == 2) { pDir->iLastWrite = uPtr.pNoId->LastWriteTime.QuadPart; #ifdef KFSCACHE_CFG_SHORT_NAMES if (enmInfoClass == enmInfoClassWithId) birdStatFillFromFileIdBothDirInfo(&pDir->Obj.Stats, uPtr.pWithId); else birdStatFillFromFileBothDirInfo(&pDir->Obj.Stats, uPtr.pNoId); #else if (enmInfoClass == enmInfoClassWithId) birdStatFillFromFileIdFullDirInfo(&pDir->Obj.Stats, uPtr.pWithId); else birdStatFillFromFileFullDirInfo(&pDir->Obj.Stats, uPtr.pNoId); #endif } /* * Advance. */ offNext = uPtr.pNoId->NextEntryOffset; if ( offNext >= cbMinCur && offNext < sizeof(uBuf)) offBuf += offNext; else break; } /* * Read the next chunk. */ rcNt = g_pfnNtQueryDirectoryFile(pDir->hDir, NULL, /* hEvent */ NULL, /* pfnApcComplete */ NULL, /* pvApcCompleteCtx */ &Ios, &uBuf, sizeof(uBuf), enmInfoClass, FALSE, /* fReturnSingleEntry */ &UniStrStar, /* Filter / restart pos. */ FALSE); /* fRestartScan */ } if (rcNt == MY_STATUS_NO_MORE_FILES) { /* * If refreshing, add missing children objects and ditch the rest. * We ignore errors while adding missing children (lazy bird). */ if (!fRefreshing) { /* more likely */ } else { while (DirRePop.cOldChildren > 0) { KFSLOOKUPERROR enmErrorIgn; PKFSOBJ pOldChild = DirRePop.papOldChildren[--DirRePop.cOldChildren]; if (pOldChild->bObjType == KFSOBJ_TYPE_MISSING) kFsCacheDirAddChild(pCache, pDir, pOldChild, &enmErrorIgn); else { KFSCACHE_LOG(("Refreshing %s/%s/ - %s was removed.\n", pDir->Obj.pParent->Obj.pszName, pDir->Obj.pszName, pOldChild->pszName)); kHlpAssert(pOldChild->bObjType != KFSOBJ_TYPE_DIR); /* Remove from hash table. */ if (pOldChild->uNameHash != 0) { KU32 idx = pOldChild->uNameHash & pDir->fHashTabMask; PKFSOBJ pPrev = pDir->papHashTab[idx]; if (pPrev == pOldChild) pDir->papHashTab[idx] = pOldChild->pNextNameHash; else { while (pPrev && pPrev->pNextNameHash != pOldChild) pPrev = pPrev->pNextNameHash; kHlpAssert(pPrev); if (pPrev) pPrev->pNextNameHash = pOldChild->pNextNameHash; } pOldChild->uNameHash = 0; } } kFsCacheObjRelease(pCache, pOldChild); } kHlpFree(DirRePop.papOldChildren); } /* * Mark the directory as fully populated and up to date. */ pDir->fPopulated = K_TRUE; pDir->fNeedRePopulating = K_FALSE; if (pDir->Obj.uCacheGen != KFSOBJ_CACHE_GEN_IGNORE) pDir->Obj.uCacheGen = pCache->auGenerations[pDir->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN]; return K_TRUE; } /* * If we failed during refresh, add back remaining old children. */ if (!fRefreshing) { while (DirRePop.cOldChildren > 0) { KFSLOOKUPERROR enmErrorIgn; PKFSOBJ pOldChild = DirRePop.papOldChildren[--DirRePop.cOldChildren]; kFsCacheDirAddChild(pCache, pDir, pOldChild, &enmErrorIgn); kFsCacheObjRelease(pCache, pOldChild); } kHlpFree(DirRePop.papOldChildren); } kHlpAssertMsgFailed(("%#x\n", rcNt)); *penmError = KFSLOOKUPERROR_DIR_READ_ERROR; return K_TRUE; } /** * Does the initial directory populating or refreshes it if it has been * invalidated. * * This assumes the parent directory is opened. * * @returns K_TRUE on success, K_FALSE on error. * @param pCache The cache. * @param pDir The directory. * @param penmError Where to store K_FALSE explanation. Optional. */ KBOOL kFsCacheDirEnsurePopuplated(PKFSCACHE pCache, PKFSDIR pDir, KFSLOOKUPERROR *penmError) { KFSLOOKUPERROR enmIgnored; if ( pDir->fPopulated && !pDir->fNeedRePopulating && ( pDir->Obj.uCacheGen == KFSOBJ_CACHE_GEN_IGNORE || pDir->Obj.uCacheGen == pCache->auGenerations[pDir->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN]) ) return K_TRUE; return kFsCachePopuplateOrRefreshDir(pCache, pDir, penmError ? penmError : &enmIgnored); } /** * Checks whether the modified timestamp differs on this directory. * * @returns K_TRUE if possibly modified, K_FALSE if definitely not modified. * @param pDir The directory.. */ static KBOOL kFsCacheDirIsModified(PKFSDIR pDir) { if ( pDir->hDir != INVALID_HANDLE_VALUE && (pDir->Obj.fFlags & KFSOBJ_F_WORKING_DIR_MTIME) ) { if (!pDir->fNeedRePopulating) { MY_IO_STATUS_BLOCK Ios; MY_FILE_BASIC_INFORMATION BasicInfo; MY_NTSTATUS rcNt; Ios.Information = -1; Ios.u.Status = -1; rcNt = g_pfnNtQueryInformationFile(pDir->hDir, &Ios, &BasicInfo, sizeof(BasicInfo), MyFileBasicInformation); if (MY_NT_SUCCESS(rcNt)) { if (BasicInfo.LastWriteTime.QuadPart != pDir->iLastWrite) { pDir->fNeedRePopulating = K_TRUE; return K_TRUE; } return K_FALSE; } } } /* The cache root never changes. */ else if (!pDir->Obj.pParent) return K_FALSE; return K_TRUE; } static KBOOL kFsCacheRefreshMissing(PKFSCACHE pCache, PKFSOBJ pMissing, KFSLOOKUPERROR *penmError) { /* * If we can, we start by checking whether the parent directory * has been modified. If it has, we need to check if this entry * was added or not, most likely it wasn't added. */ if (!kFsCacheDirIsModified(pMissing->pParent)) { KFSCACHE_LOG(("Parent of missing not written to %s/%s\n", pMissing->pParent->Obj.pszName, pMissing->pszName)); pMissing->uCacheGen = pCache->auGenerationsMissing[pMissing->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]; } else { MY_UNICODE_STRING UniStr; MY_OBJECT_ATTRIBUTES ObjAttr; MY_FILE_BASIC_INFORMATION BasicInfo; MY_NTSTATUS rcNt; UniStr.Buffer = (wchar_t *)pMissing->pwszName; UniStr.Length = (USHORT)(pMissing->cwcName * sizeof(wchar_t)); UniStr.MaximumLength = UniStr.Length + sizeof(wchar_t); kHlpAssert(pMissing->pParent->hDir != INVALID_HANDLE_VALUE); MyInitializeObjectAttributes(&ObjAttr, &UniStr, OBJ_CASE_INSENSITIVE, pMissing->pParent->hDir, NULL /*pSecAttr*/); rcNt = g_pfnNtQueryAttributesFile(&ObjAttr, &BasicInfo); if (!MY_NT_SUCCESS(rcNt)) { /* * Probably more likely that a missing node stays missing. */ pMissing->uCacheGen = pCache->auGenerationsMissing[pMissing->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]; KFSCACHE_LOG(("Still missing %s/%s\n", pMissing->pParent->Obj.pszName, pMissing->pszName)); } else { /* * We must metamorphose this node. This is tedious business * because we need to check the file name casing. We might * just as well update the parent directory... */ KU8 const bObjType = BasicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY ? KFSOBJ_TYPE_DIR : BasicInfo.FileAttributes & (FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_REPARSE_POINT) ? KFSOBJ_TYPE_OTHER : KFSOBJ_TYPE_FILE; KFSCACHE_LOG(("Birth of %s/%s as %d with attribs %#x...\n", pMissing->pParent->Obj.pszName, pMissing->pszName, bObjType, BasicInfo.FileAttributes)); pMissing->bObjType = bObjType; pMissing->uCacheGen = pCache->auGenerations[pMissing->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]; /** * @todo refresh missing object names when it appears. */ } } return K_TRUE; } static KBOOL kFsCacheRefreshMissingIntermediateDir(PKFSCACHE pCache, PKFSOBJ pMissing, KFSLOOKUPERROR *penmError) { if (kFsCacheRefreshMissing(pCache, pMissing, penmError)) { if ( pMissing->bObjType == KFSOBJ_TYPE_DIR || pMissing->bObjType == KFSOBJ_TYPE_MISSING) return K_TRUE; *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_DIR; } return K_FALSE; } /** * Generic object refresh. * * This does not refresh the content of directories. * * @returns K_TRUE on success. K_FALSE and *penmError on failure. * @param pCache The cache. * @param pObj The object. * @param penmError Where to return error info. */ static KBOOL kFsCacheRefreshObj(PKFSCACHE pCache, PKFSOBJ pObj, KFSLOOKUPERROR *penmError) { KBOOL fRc; /* * Since we generally assume nothing goes away in this cache, we only really * have a hard time with negative entries. So, missing stuff goes to * complicated land. */ if (pObj->bObjType == KFSOBJ_TYPE_MISSING) fRc = kFsCacheRefreshMissing(pCache, pObj, penmError); else { /* * This object is supposed to exist, so all we need to do is query essential * stats again. Since we've already got handles on directories, there are * two ways to go about this. */ union { MY_FILE_NETWORK_OPEN_INFORMATION FullInfo; MY_FILE_STANDARD_INFORMATION StdInfo; #ifdef KFSCACHE_CFG_SHORT_NAMES MY_FILE_ID_BOTH_DIR_INFORMATION WithId; //MY_FILE_BOTH_DIR_INFORMATION NoId; #else MY_FILE_ID_FULL_DIR_INFORMATION WithId; //MY_FILE_FULL_DIR_INFORMATION NoId; #endif KU8 abPadding[ sizeof(wchar_t) * KFSCACHE_CFG_MAX_UTF16_NAME + sizeof(MY_FILE_ID_BOTH_DIR_INFORMATION)]; } uBuf; MY_IO_STATUS_BLOCK Ios; MY_NTSTATUS rcNt; if ( pObj->bObjType != KFSOBJ_TYPE_DIR || ((PKFSDIR)pObj)->hDir == INVALID_HANDLE_VALUE) { #if 1 /* This always works and doesn't mess up NtQueryDirectoryFile. */ MY_UNICODE_STRING UniStr; MY_OBJECT_ATTRIBUTES ObjAttr; UniStr.Buffer = (wchar_t *)pObj->pwszName; UniStr.Length = (USHORT)(pObj->cwcName * sizeof(wchar_t)); UniStr.MaximumLength = UniStr.Length + sizeof(wchar_t); kHlpAssert(pObj->pParent->hDir != INVALID_HANDLE_VALUE); MyInitializeObjectAttributes(&ObjAttr, &UniStr, OBJ_CASE_INSENSITIVE, pObj->pParent->hDir, NULL /*pSecAttr*/); rcNt = g_pfnNtQueryFullAttributesFile(&ObjAttr, &uBuf.FullInfo); if (MY_NT_SUCCESS(rcNt)) { pObj->Stats.st_size = uBuf.FullInfo.EndOfFile.QuadPart; birdNtTimeToTimeSpec(uBuf.FullInfo.CreationTime.QuadPart, &pObj->Stats.st_birthtim); birdNtTimeToTimeSpec(uBuf.FullInfo.ChangeTime.QuadPart, &pObj->Stats.st_ctim); birdNtTimeToTimeSpec(uBuf.FullInfo.LastWriteTime.QuadPart, &pObj->Stats.st_mtim); birdNtTimeToTimeSpec(uBuf.FullInfo.LastAccessTime.QuadPart, &pObj->Stats.st_atim); pObj->Stats.st_attribs = uBuf.FullInfo.FileAttributes; pObj->Stats.st_blksize = 65536; pObj->Stats.st_blocks = (uBuf.FullInfo.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1) / BIRD_STAT_BLOCK_SIZE; } #else /* This alternative lets us keep the inode number up to date and detect name case changes. Update: This doesn't work on windows 7, it ignores the UniStr and continue with the "*" search. So, we're using the above query instead for the time being. */ MY_UNICODE_STRING UniStr; # ifdef KFSCACHE_CFG_SHORT_NAMES MY_FILE_INFORMATION_CLASS enmInfoClass = MyFileIdBothDirectoryInformation; # else MY_FILE_INFORMATION_CLASS enmInfoClass = MyFileIdFullDirectoryInformation; # endif UniStr.Buffer = (wchar_t *)pObj->pwszName; UniStr.Length = (USHORT)(pObj->cwcName * sizeof(wchar_t)); UniStr.MaximumLength = UniStr.Length + sizeof(wchar_t); kHlpAssert(pObj->pParent->hDir != INVALID_HANDLE_VALUE); Ios.Information = -1; Ios.u.Status = -1; rcNt = g_pfnNtQueryDirectoryFile(pObj->pParent->hDir, NULL, /* hEvent */ NULL, /* pfnApcComplete */ NULL, /* pvApcCompleteCtx */ &Ios, &uBuf, sizeof(uBuf), enmInfoClass, TRUE, /* fReturnSingleEntry */ &UniStr, /* Filter / restart pos. */ TRUE); /* fRestartScan */ if (MY_NT_SUCCESS(rcNt)) { if (pObj->Stats.st_ino == uBuf.WithId.FileId.QuadPart) KFSCACHE_LOG(("Refreshing %s/%s, no ID change...\n", pObj->pParent->Obj.pszName, pObj->pszName)); else if ( pObj->cwcName == uBuf.WithId.FileNameLength / sizeof(wchar_t) # ifdef KFSCACHE_CFG_SHORT_NAMES && ( uBuf.WithId.ShortNameLength == 0 ? pObj->pwszName == pObj->pwszShortName || ( pObj->cwcName == pObj->cwcShortName && memcmp(pObj->pwszName, pObj->pwszShortName, pObj->cwcName * sizeof(wchar_t)) == 0) : pObj->cwcShortName == uBuf.WithId.ShortNameLength / sizeof(wchar_t) && memcmp(pObj->pwszShortName, uBuf.WithId.ShortName, uBuf.WithId.ShortNameLength) == 0 ) # endif && memcmp(pObj->pwszName, uBuf.WithId.FileName, uBuf.WithId.FileNameLength) == 0 ) { KFSCACHE_LOG(("Refreshing %s/%s, ID changed %#llx -> %#llx...\n", pObj->pParent->Obj.pszName, pObj->pszName, pObj->Stats.st_ino, uBuf.WithId.FileId.QuadPart)); pObj->Stats.st_ino = uBuf.WithId.FileId.QuadPart; } else { KFSCACHE_LOG(("Refreshing %s/%s, ID changed %#llx -> %#llx and names too...\n", pObj->pParent->Obj.pszName, pObj->pszName, pObj->Stats.st_ino, uBuf.WithId.FileId.QuadPart)); fprintf(stderr, "kFsCacheRefreshObj - ID + name change not implemented!!\n"); fflush(stderr); __debugbreak(); pObj->Stats.st_ino = uBuf.WithId.FileId.QuadPart; /** @todo implement as needed. */ } pObj->Stats.st_size = uBuf.WithId.EndOfFile.QuadPart; birdNtTimeToTimeSpec(uBuf.WithId.CreationTime.QuadPart, &pObj->Stats.st_birthtim); birdNtTimeToTimeSpec(uBuf.WithId.ChangeTime.QuadPart, &pObj->Stats.st_ctim); birdNtTimeToTimeSpec(uBuf.WithId.LastWriteTime.QuadPart, &pObj->Stats.st_mtim); birdNtTimeToTimeSpec(uBuf.WithId.LastAccessTime.QuadPart, &pObj->Stats.st_atim); pObj->Stats.st_attribs = uBuf.WithId.FileAttributes; pObj->Stats.st_blksize = 65536; pObj->Stats.st_blocks = (uBuf.WithId.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1) / BIRD_STAT_BLOCK_SIZE; } #endif if (MY_NT_SUCCESS(rcNt)) { pObj->uCacheGen = pCache->auGenerations[pObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]; fRc = K_TRUE; } else { /* ouch! */ kHlpAssertMsgFailed(("%#x\n", rcNt)); fprintf(stderr, "kFsCacheRefreshObj - rcNt=%#x on non-dir - not implemented!\n", rcNt); __debugbreak(); fRc = K_FALSE; } } else { /* * An open directory. Query information via the handle, the * file ID shouldn't have been able to change, so we can use * NtQueryInformationFile. Right... */ PKFSDIR pDir = (PKFSDIR)pObj; Ios.Information = -1; Ios.u.Status = -1; rcNt = g_pfnNtQueryInformationFile(pDir->hDir, &Ios, &uBuf.FullInfo, sizeof(uBuf.FullInfo), MyFileNetworkOpenInformation); if (MY_NT_SUCCESS(rcNt)) rcNt = Ios.u.Status; if (MY_NT_SUCCESS(rcNt)) { pObj->Stats.st_size = uBuf.FullInfo.EndOfFile.QuadPart; birdNtTimeToTimeSpec(uBuf.FullInfo.CreationTime.QuadPart, &pObj->Stats.st_birthtim); birdNtTimeToTimeSpec(uBuf.FullInfo.ChangeTime.QuadPart, &pObj->Stats.st_ctim); birdNtTimeToTimeSpec(uBuf.FullInfo.LastWriteTime.QuadPart, &pObj->Stats.st_mtim); birdNtTimeToTimeSpec(uBuf.FullInfo.LastAccessTime.QuadPart, &pObj->Stats.st_atim); pObj->Stats.st_attribs = uBuf.FullInfo.FileAttributes; pObj->Stats.st_blksize = 65536; pObj->Stats.st_blocks = (uBuf.FullInfo.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1) / BIRD_STAT_BLOCK_SIZE; if ( pDir->iLastWrite == uBuf.FullInfo.LastWriteTime.QuadPart && (pObj->fFlags & KFSOBJ_F_WORKING_DIR_MTIME) ) KFSCACHE_LOG(("Refreshing %s/%s/ - no re-populating necessary.\n", pObj->pParent->Obj.pszName, pObj->pszName)); else { KFSCACHE_LOG(("Refreshing %s/%s/ - needs re-populating...\n", pObj->pParent->Obj.pszName, pObj->pszName)); pDir->fNeedRePopulating = K_TRUE; #if 0 /* Refresh the link count. */ rcNt = g_pfnNtQueryInformationFile(pDir->hDir, &Ios, &StdInfo, sizeof(StdInfo), FileStandardInformation); if (MY_NT_SUCCESS(rcNt)) rcNt = Ios.s.Status; if (MY_NT_SUCCESS(rcNt)) pObj->Stats.st_nlink = StdInfo.NumberOfLinks; #endif } } if (MY_NT_SUCCESS(rcNt)) { pObj->uCacheGen = pCache->auGenerations[pObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]; fRc = K_TRUE; } else { /* ouch! */ kHlpAssertMsgFailed(("%#x\n", rcNt)); fprintf(stderr, "kFsCacheRefreshObj - rcNt=%#x on dir - not implemented!\n", rcNt); fflush(stderr); __debugbreak(); fRc = K_FALSE; } } } return fRc; } /** * Looks up a drive letter. * * Will enter the drive if necessary. * * @returns Pointer to the root directory of the drive or an update-to-date * missing node. * @param pCache The cache. * @param chLetter The uppercased drive letter. * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX. * @param penmError Where to return details as to why the lookup * failed. */ static PKFSOBJ kFsCacheLookupDrive(PKFSCACHE pCache, char chLetter, KU32 fFlags, KFSLOOKUPERROR *penmError) { KU32 const uNameHash = chLetter - 'A'; PKFSOBJ pCur = pCache->RootDir.papHashTab[uNameHash]; KU32 cLeft; PKFSOBJ *ppCur; MY_UNICODE_STRING NtPath; wchar_t wszTmp[8]; char szTmp[4]; /* * Custom drive letter hashing. */ kHlpAssert((uNameHash & pCache->RootDir.fHashTabMask) == uNameHash); while (pCur) { if ( pCur->uNameHash == uNameHash && pCur->cchName == 2 && pCur->pszName[0] == chLetter && pCur->pszName[1] == ':') { if (pCur->bObjType == KFSOBJ_TYPE_DIR) return pCur; if ( (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH) || kFsCacheRefreshMissingIntermediateDir(pCache, pCur, penmError)) return pCur; return NULL; } pCur = pCur->pNextNameHash; } /* * Make 100% sure it's not there. */ cLeft = pCache->RootDir.cChildren; ppCur = pCache->RootDir.papChildren; while (cLeft-- > 0) { pCur = *ppCur++; if ( pCur->cchName == 2 && pCur->pszName[0] == chLetter && pCur->pszName[1] == ':') { if (pCur->bObjType == KFSOBJ_TYPE_DIR) return pCur; kHlpAssert(pCur->bObjType == KFSOBJ_TYPE_MISSING); if ( (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH) || kFsCacheRefreshMissingIntermediateDir(pCache, pCur, penmError)) return pCur; return NULL; } } if (fFlags & KFSCACHE_LOOKUP_F_NO_INSERT) { *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND; /* close enough */ return NULL; } /* * Need to add it. We always keep the drive letters open for the benefit * of kFsCachePopuplateOrRefreshDir and others. */ wszTmp[0] = szTmp[0] = chLetter; wszTmp[1] = szTmp[1] = ':'; wszTmp[2] = szTmp[2] = '\\'; wszTmp[3] = '.'; wszTmp[4] = '\0'; szTmp[2] = '\0'; NtPath.Buffer = NULL; NtPath.Length = 0; NtPath.MaximumLength = 0; if (g_pfnRtlDosPathNameToNtPathName_U(wszTmp, &NtPath, NULL, NULL)) { HANDLE hDir; MY_NTSTATUS rcNt; rcNt = birdOpenFileUniStr(NULL /*hRoot*/, &NtPath, FILE_READ_DATA | FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | SYNCHRONIZE, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, OBJ_CASE_INSENSITIVE, &hDir); birdFreeNtPath(&NtPath); if (MY_NT_SUCCESS(rcNt)) { PKFSDIR pDir = (PKFSDIR)kFsCacheCreateObject(pCache, &pCache->RootDir, szTmp, 2, wszTmp, 2, #ifdef KFSCACHE_CFG_SHORT_NAMES NULL, 0, NULL, 0, #endif KFSOBJ_TYPE_DIR, penmError); if (pDir) { /* * We need a little bit of extra info for a drive root. These things are typically * inherited by subdirectories down the tree, so, we do it all here for till that changes. */ union { MY_FILE_FS_VOLUME_INFORMATION VolInfo; MY_FILE_FS_ATTRIBUTE_INFORMATION FsAttrInfo; char abPadding[sizeof(MY_FILE_FS_VOLUME_INFORMATION) + 512]; } uBuf; MY_IO_STATUS_BLOCK Ios; KBOOL fRc; kHlpAssert(pDir->hDir == INVALID_HANDLE_VALUE); pDir->hDir = hDir; if (birdStatHandle(hDir, &pDir->Obj.Stats, pDir->Obj.pszName) == 0) { pDir->Obj.fHaveStats = K_TRUE; pDir->uDevNo = pDir->Obj.Stats.st_dev; } else { /* Just in case. */ pDir->Obj.fHaveStats = K_FALSE; rcNt = birdQueryVolumeDeviceNumber(hDir, &uBuf.VolInfo, sizeof(uBuf), &pDir->uDevNo); kHlpAssertMsg(MY_NT_SUCCESS(rcNt), ("%#x\n", rcNt)); } /* Get the file system. */ pDir->Obj.fFlags &= ~(KFSOBJ_F_NTFS | KFSOBJ_F_WORKING_DIR_MTIME); Ios.Information = -1; Ios.u.Status = -1; rcNt = g_pfnNtQueryVolumeInformationFile(hDir, &Ios, &uBuf.FsAttrInfo, sizeof(uBuf), MyFileFsAttributeInformation); if (MY_NT_SUCCESS(rcNt)) rcNt = Ios.u.Status; if (MY_NT_SUCCESS(rcNt)) { if ( uBuf.FsAttrInfo.FileSystemName[0] == 'N' && uBuf.FsAttrInfo.FileSystemName[1] == 'T' && uBuf.FsAttrInfo.FileSystemName[2] == 'F' && uBuf.FsAttrInfo.FileSystemName[3] == 'S' && uBuf.FsAttrInfo.FileSystemName[4] == '\0') { DWORD dwDriveType = GetDriveTypeW(wszTmp); if ( dwDriveType == DRIVE_FIXED || dwDriveType == DRIVE_RAMDISK) pDir->Obj.fFlags |= KFSOBJ_F_NTFS | KFSOBJ_F_WORKING_DIR_MTIME; } } /* * Link the new drive letter into the root dir. */ fRc = kFsCacheDirAddChild(pCache, &pCache->RootDir, &pDir->Obj, penmError); kFsCacheObjRelease(pCache, &pDir->Obj); if (fRc) { pDir->Obj.pNextNameHash = pCache->RootDir.papHashTab[uNameHash]; pCache->RootDir.papHashTab[uNameHash] = &pDir->Obj; return &pDir->Obj; } return NULL; } g_pfnNtClose(hDir); return NULL; } /* Assume it doesn't exist if this happens... This may be a little to restrictive wrt status code checks. */ kHlpAssertMsgStmtReturn( rcNt == MY_STATUS_OBJECT_NAME_NOT_FOUND || rcNt == MY_STATUS_OBJECT_PATH_NOT_FOUND || rcNt == MY_STATUS_OBJECT_PATH_INVALID || rcNt == MY_STATUS_OBJECT_PATH_SYNTAX_BAD, ("%#x\n", rcNt), *penmError = KFSLOOKUPERROR_DIR_OPEN_ERROR, NULL); } else { kHlpAssertFailed(); *penmError = KFSLOOKUPERROR_OUT_OF_MEMORY; return NULL; } /* * Maybe create a missing entry. */ if (pCache->fFlags & KFSCACHE_F_MISSING_OBJECTS) { PKFSOBJ pMissing = kFsCacheCreateObject(pCache, &pCache->RootDir, szTmp, 2, wszTmp, 2, #ifdef KFSCACHE_CFG_SHORT_NAMES NULL, 0, NULL, 0, #endif KFSOBJ_TYPE_MISSING, penmError); if (pMissing) { KBOOL fRc = kFsCacheDirAddChild(pCache, &pCache->RootDir, pMissing, penmError); kFsCacheObjRelease(pCache, pMissing); return fRc ? pMissing : NULL; } } else { /** @todo this isn't necessary correct for a root spec. */ *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND; } return NULL; } /** * Slow path that allocates the child hash table and enters the given one. * * Allocation fialures are ignored. * * @param pCache The cache (for stats). * @param pDir The directory. * @param uNameHash The name hash to enter @a pChild under. * @param pChild The child to enter into the hash table. */ static void kFsCacheDirAllocHashTabAndEnterChild(PKFSCACHE pCache, PKFSDIR pDir, KU32 uNameHash, PKFSOBJ pChild) { if (uNameHash != 0) /* paranoia ^ 4! */ { /* * Double the current number of children and round up to a multiple of * two so we can avoid division. */ KU32 cbHashTab; KU32 cEntries; kHlpAssert(pDir->cChildren > 0); if (pDir->cChildren <= KU32_MAX / 4) { #if defined(_MSC_VER) && 1 KU32 cEntriesRaw = pDir->cChildren * 2; KU32 cEntriesShift; kHlpAssert(sizeof(cEntries) == (unsigned long)); if (_BitScanReverse(&cEntriesShift, cEntriesRaw)) { if ( K_BIT32(cEntriesShift) < cEntriesRaw && cEntriesShift < 31U) cEntriesShift++; cEntries = K_BIT32(cEntriesShift); } else { kHlpAssertFailed(); cEntries = KU32_MAX / 2 + 1; } #else cEntries = pDir->cChildren * 2 - 1; cEntries |= cEntries >> 1; cEntries |= cEntries >> 2; cEntries |= cEntries >> 4; cEntries |= cEntries >> 8; cEntries |= cEntries >> 16; cEntries++; #endif } else cEntries = KU32_MAX / 2 + 1; kHlpAssert((cEntries & (cEntries - 1)) == 0); cbHashTab = cEntries * sizeof(pDir->papHashTab[0]); pDir->papHashTab = (PKFSOBJ *)kHlpAllocZ(cbHashTab); if (pDir->papHashTab) { KU32 idx; pDir->fHashTabMask = cEntries - 1; pCache->cbObjects += cbHashTab; pCache->cChildHashTabs++; pCache->cChildHashEntriesTotal += cEntries; /* * Insert it. */ pChild->uNameHash = uNameHash; idx = uNameHash & (pDir->fHashTabMask); pChild->pNextNameHash = pDir->papHashTab[idx]; pDir->papHashTab[idx] = pChild; pCache->cChildHashed++; } } } /** * Look up a child node, ANSI version. * * @returns Pointer to the child if found, NULL if not. * @param pCache The cache. * @param pParent The parent directory to search. * @param pchName The child name to search for (not terminated). * @param cchName The length of the child name. */ static PKFSOBJ kFsCacheFindChildA(PKFSCACHE pCache, PKFSDIR pParent, const char *pchName, KU32 cchName) { /* * Check for '.' first ('..' won't appear). */ if (cchName != 1 || *pchName != '.') { PKFSOBJ *ppCur; KU32 cLeft; KU32 uNameHash; /* * Do hash table lookup. * * This caches previous lookups, which should be useful when looking up * intermediate directories at least. */ if (pParent->papHashTab != NULL) { PKFSOBJ pCur; uNameHash = kFsCacheStrHashN(pchName, cchName); pCur = pParent->papHashTab[uNameHash & pParent->fHashTabMask]; while (pCur) { if ( pCur->uNameHash == uNameHash && ( ( pCur->cchName == cchName && _mbsnicmp(pCur->pszName, pchName, cchName) == 0) #ifdef KFSCACHE_CFG_SHORT_NAMES || ( pCur->cchShortName == cchName && pCur->pszShortName != pCur->pszName && _mbsnicmp(pCur->pszShortName, pchName, cchName) == 0) #endif ) ) { pCache->cChildHashHits++; pCache->cChildSearches++; return pCur; } pCur = pCur->pNextNameHash; } } else uNameHash = 0; /* * Do linear search. */ cLeft = pParent->cChildren; ppCur = pParent->papChildren; while (cLeft-- > 0) { PKFSOBJ pCur = *ppCur++; if ( ( pCur->cchName == cchName && _mbsnicmp(pCur->pszName, pchName, cchName) == 0) #ifdef KFSCACHE_CFG_SHORT_NAMES || ( pCur->cchShortName == cchName && pCur->pszShortName != pCur->pszName && _mbsnicmp(pCur->pszShortName, pchName, cchName) == 0) #endif ) { /* * Consider entering it into the parent hash table. * Note! We hash the input, not the name we found. */ if ( pCur->uNameHash == 0 && pParent->cChildren >= 2) { if (pParent->papHashTab) { if (uNameHash != 0) { KU32 idxNameHash = uNameHash & pParent->fHashTabMask; pCur->uNameHash = uNameHash; pCur->pNextNameHash = pParent->papHashTab[idxNameHash]; pParent->papHashTab[idxNameHash] = pCur; if (pCur->pNextNameHash) pCache->cChildHashCollisions++; pCache->cChildHashed++; } } else kFsCacheDirAllocHashTabAndEnterChild(pCache, pParent, kFsCacheStrHashN(pchName, cchName), pCur); } pCache->cChildSearches++; return pCur; } } pCache->cChildSearches++; return NULL; } return &pParent->Obj; } /** * Look up a child node, UTF-16 version. * * @returns Pointer to the child if found, NULL if not. * @param pCache The cache. * @param pParent The parent directory to search. * @param pwcName The child name to search for (not terminated). * @param cwcName The length of the child name (in wchar_t's). */ static PKFSOBJ kFsCacheFindChildW(PKFSCACHE pCache, PKFSDIR pParent, const wchar_t *pwcName, KU32 cwcName) { /* * Check for '.' first ('..' won't appear). */ if (cwcName != 1 || *pwcName != '.') { PKFSOBJ *ppCur; KU32 cLeft; KU32 uNameHash; /* * Do hash table lookup. * * This caches previous lookups, which should be useful when looking up * intermediate directories at least. */ if (pParent->papHashTab != NULL) { PKFSOBJ pCur; uNameHash = kFsCacheUtf16HashN(pwcName, cwcName); pCur = pParent->papHashTab[uNameHash & pParent->fHashTabMask]; while (pCur) { if ( pCur->uNameHash == uNameHash && ( ( pCur->cwcName == cwcName && kFsCacheIAreEqualW(pCur->pwszName, pwcName, cwcName)) #ifdef KFSCACHE_CFG_SHORT_NAMES || ( pCur->cwcShortName == cwcName && pCur->pwszShortName != pCur->pwszName && kFsCacheIAreEqualW(pCur->pwszShortName, pwcName, cwcName)) #endif ) ) { pCache->cChildHashHits++; pCache->cChildSearches++; return pCur; } pCur = pCur->pNextNameHash; } } else uNameHash = 0; /* * Do linear search. */ cLeft = pParent->cChildren; ppCur = pParent->papChildren; while (cLeft-- > 0) { PKFSOBJ pCur = *ppCur++; if ( ( pCur->cwcName == cwcName && kFsCacheIAreEqualW(pCur->pwszName, pwcName, cwcName)) #ifdef KFSCACHE_CFG_SHORT_NAMES || ( pCur->cwcShortName == cwcName && pCur->pwszShortName != pCur->pwszName && kFsCacheIAreEqualW(pCur->pwszShortName, pwcName, cwcName)) #endif ) { /* * Consider entering it into the parent hash table. * Note! We hash the input, not the name we found. */ if ( pCur->uNameHash == 0 && pParent->cChildren >= 4) { if (pParent->papHashTab) { if (uNameHash != 0) { KU32 idxNameHash = uNameHash & pParent->fHashTabMask; pCur->uNameHash = uNameHash; pCur->pNextNameHash = pParent->papHashTab[idxNameHash]; pParent->papHashTab[idxNameHash] = pCur; if (pCur->pNextNameHash) pCache->cChildHashCollisions++; pCache->cChildHashed++; } } else kFsCacheDirAllocHashTabAndEnterChild(pCache, pParent, kFsCacheUtf16HashN(pwcName, cwcName), pCur); } pCache->cChildSearches++; return pCur; } } pCache->cChildSearches++; return NULL; } return &pParent->Obj; } /** * Looks up a UNC share, ANSI version. * * We keep both the server and share in the root directory entry. This means we * have to clean up the entry name before we can insert it. * * @returns Pointer to the share root directory or an update-to-date missing * node. * @param pCache The cache. * @param pszPath The path. * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX. * @param poff Where to return the root dire. * @param penmError Where to return details as to why the lookup * failed. */ static PKFSOBJ kFsCacheLookupUncShareA(PKFSCACHE pCache, const char *pszPath, KU32 fFlags, KU32 *poff, KFSLOOKUPERROR *penmError) { /* * Special case: Long path prefix w/ drive letter following it. * Note! Must've been converted from wide char to ANSI. */ if ( IS_SLASH(pszPath[0]) && IS_SLASH(pszPath[1]) && pszPath[2] == '?' && IS_SLASH(pszPath[3]) && IS_ALPHA(pszPath[4]) && pszPath[5] == ':' && IS_SLASH(pszPath[6]) ) { *poff = 4 + 2; return kFsCacheLookupDrive(pCache, pszPath[4], fFlags, penmError); } #if 0 /* later */ KU32 offStartServer; KU32 offEndServer; KU32 offStartShare; KU32 offEnd = 2; while (IS_SLASH(pszPath[offEnd])) offEnd++; offStartServer = offEnd; while ( (ch = pszPath[offEnd]) != '\0' && !IS_SLASH(ch)) offEnd++; offEndServer = offEnd; if (ch != '\0') { /* likely */ } else { *penmError = KFSLOOKUPERROR_NOT_FOUND; return NULL; } while (IS_SLASH(pszPath[offEnd])) offEnd++; offStartServer = offEnd; while ( (ch = pszPath[offEnd]) != '\0' && !IS_SLASH(ch)) offEnd++; #endif *penmError = KFSLOOKUPERROR_UNSUPPORTED; return NULL; } /** * Looks up a UNC share, UTF-16 version. * * We keep both the server and share in the root directory entry. This means we * have to clean up the entry name before we can insert it. * * @returns Pointer to the share root directory or an update-to-date missing * node. * @param pCache The cache. * @param pwszPath The path. * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX. * @param poff Where to return the root dir. * @param penmError Where to return details as to why the lookup * failed. */ static PKFSOBJ kFsCacheLookupUncShareW(PKFSCACHE pCache, const wchar_t *pwszPath, KU32 fFlags, KU32 *poff, KFSLOOKUPERROR *penmError) { /* * Special case: Long path prefix w/ drive letter following it. */ if ( IS_SLASH(pwszPath[0]) && IS_SLASH(pwszPath[1]) && pwszPath[2] == '?' && IS_SLASH(pwszPath[3]) && IS_ALPHA(pwszPath[4]) && pwszPath[5] == ':' && IS_SLASH(pwszPath[6]) ) { *poff = 4 + 2; return kFsCacheLookupDrive(pCache, (char)pwszPath[4], fFlags, penmError); } #if 0 /* later */ KU32 offStartServer; KU32 offEndServer; KU32 offStartShare; KU32 offEnd = 2; while (IS_SLASH(pwszPath[offEnd])) offEnd++; offStartServer = offEnd; while ( (ch = pwszPath[offEnd]) != '\0' && !IS_SLASH(ch)) offEnd++; offEndServer = offEnd; if (ch != '\0') { /* likely */ } else { *penmError = KFSLOOKUPERROR_NOT_FOUND; return NULL; } while (IS_SLASH(pwszPath[offEnd])) offEnd++; offStartServer = offEnd; while ( (ch = pwszPath[offEnd]) != '\0' && !IS_SLASH(ch)) offEnd++; #endif *penmError = KFSLOOKUPERROR_UNSUPPORTED; return NULL; } /** * Walks an full path relative to the given directory, ANSI version. * * This will create any missing nodes while walking. * * The caller will have to do the path hash table insertion of the result. * * @returns Pointer to the tree node corresponding to @a pszPath. * NULL on lookup failure, see @a penmError for details. * @param pCache The cache. * @param pParent The directory to start the lookup in. * @param pszPath The path to walk. * @param cchPath The length of the path. * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX. * @param penmError Where to return details as to why the lookup * failed. * @param ppLastAncestor Where to return the last parent element found * (referenced) in case of error like an path/file * not found problem. Optional. */ PKFSOBJ kFsCacheLookupRelativeToDirA(PKFSCACHE pCache, PKFSDIR pParent, const char *pszPath, KU32 cchPath, KU32 fFlags, KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor) { /* * Walk loop. */ KU32 off = 0; if (ppLastAncestor) *ppLastAncestor = NULL; for (;;) { PKFSOBJ pChild; /* * Find the end of the component, counting trailing slashes. */ char ch; KU32 cchSlashes = 0; KU32 offEnd = off + 1; while ((ch = pszPath[offEnd]) != '\0') { if (!IS_SLASH(ch)) offEnd++; else { do cchSlashes++; while (IS_SLASH(pszPath[offEnd + cchSlashes])); break; } } /* * Do we need to populate or refresh this directory first? */ if ( !pParent->fNeedRePopulating && pParent->fPopulated && ( pParent->Obj.uCacheGen == KFSOBJ_CACHE_GEN_IGNORE || pParent->Obj.uCacheGen == pCache->auGenerations[pParent->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN]) ) { /* likely */ } else if ( (fFlags & (KFSCACHE_LOOKUP_F_NO_INSERT | fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH)) || kFsCachePopuplateOrRefreshDir(pCache, pParent, penmError)) { /* likely */ } else { if (ppLastAncestor) *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj); return NULL; } /* * Search the current node for the name. * * If we don't find it, we may insert a missing node depending on * the cache configuration. */ pChild = kFsCacheFindChildA(pCache, pParent, &pszPath[off], offEnd - off); if (pChild != NULL) { /* probably likely */ } else { if ( (pCache->fFlags & KFSCACHE_F_MISSING_OBJECTS) && !(fFlags & KFSCACHE_LOOKUP_F_NO_INSERT)) pChild = kFsCacheCreateMissingA(pCache, pParent, &pszPath[off], offEnd - off, penmError); if (cchSlashes == 0 || offEnd + cchSlashes >= cchPath) { if (pChild) return kFsCacheObjRetainInternal(pChild); *penmError = KFSLOOKUPERROR_NOT_FOUND; } else *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND; if (ppLastAncestor) *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj); return NULL; } /* Advance off and check if we're done already. */ off = offEnd + cchSlashes; if ( cchSlashes == 0 || off >= cchPath) { if ( pChild->bObjType != KFSOBJ_TYPE_MISSING || pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE || pChild->uCacheGen == pCache->auGenerationsMissing[pChild->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH) || kFsCacheRefreshMissing(pCache, pChild, penmError) ) { /* likely */ } else { if (ppLastAncestor) *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj); return NULL; } return kFsCacheObjRetainInternal(pChild); } /* * Check that it's a directory. If a missing entry, we may have to * refresh it and re-examin it. */ if (pChild->bObjType == KFSOBJ_TYPE_DIR) pParent = (PKFSDIR)pChild; else if (pChild->bObjType != KFSOBJ_TYPE_MISSING) { *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_DIR; if (ppLastAncestor) *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj); return NULL; } else if ( pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE || pChild->uCacheGen == pCache->auGenerationsMissing[pChild->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH)) { *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND; if (ppLastAncestor) *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj); return NULL; } else if (kFsCacheRefreshMissingIntermediateDir(pCache, pChild, penmError)) pParent = (PKFSDIR)pChild; else { if (ppLastAncestor) *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj); return NULL; } } /* not reached */ return NULL; } /** * Walks an full path relative to the given directory, UTF-16 version. * * This will create any missing nodes while walking. * * The caller will have to do the path hash table insertion of the result. * * @returns Pointer to the tree node corresponding to @a pszPath. * NULL on lookup failure, see @a penmError for details. * @param pCache The cache. * @param pParent The directory to start the lookup in. * @param pszPath The path to walk. No dot-dot bits allowed! * @param cchPath The length of the path. * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX. * @param penmError Where to return details as to why the lookup * failed. * @param ppLastAncestor Where to return the last parent element found * (referenced) in case of error like an path/file * not found problem. Optional. */ PKFSOBJ kFsCacheLookupRelativeToDirW(PKFSCACHE pCache, PKFSDIR pParent, const wchar_t *pwszPath, KU32 cwcPath, KU32 fFlags, KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor) { /* * Walk loop. */ KU32 off = 0; if (ppLastAncestor) *ppLastAncestor = NULL; for (;;) { PKFSOBJ pChild; /* * Find the end of the component, counting trailing slashes. */ wchar_t wc; KU32 cwcSlashes = 0; KU32 offEnd = off + 1; while ((wc = pwszPath[offEnd]) != '\0') { if (!IS_SLASH(wc)) offEnd++; else { do cwcSlashes++; while (IS_SLASH(pwszPath[offEnd + cwcSlashes])); break; } } /* * Do we need to populate or refresh this directory first? */ if ( !pParent->fNeedRePopulating && pParent->fPopulated && ( pParent->Obj.uCacheGen == KFSOBJ_CACHE_GEN_IGNORE || pParent->Obj.uCacheGen == pCache->auGenerations[pParent->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN]) ) { /* likely */ } else if ( (fFlags & (KFSCACHE_LOOKUP_F_NO_INSERT | fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH)) || kFsCachePopuplateOrRefreshDir(pCache, pParent, penmError)) { /* likely */ } else { if (ppLastAncestor) *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj); return NULL; } /* * Search the current node for the name. * * If we don't find it, we may insert a missing node depending on * the cache configuration. */ pChild = kFsCacheFindChildW(pCache, pParent, &pwszPath[off], offEnd - off); if (pChild != NULL) { /* probably likely */ } else { if ( (pCache->fFlags & KFSCACHE_F_MISSING_OBJECTS) && !(fFlags & KFSCACHE_LOOKUP_F_NO_INSERT)) pChild = kFsCacheCreateMissingW(pCache, pParent, &pwszPath[off], offEnd - off, penmError); if (cwcSlashes == 0 || offEnd + cwcSlashes >= cwcPath) { if (pChild) return kFsCacheObjRetainInternal(pChild); *penmError = KFSLOOKUPERROR_NOT_FOUND; } else *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND; if (ppLastAncestor) *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj); return NULL; } /* Advance off and check if we're done already. */ off = offEnd + cwcSlashes; if ( cwcSlashes == 0 || off >= cwcPath) { if ( pChild->bObjType != KFSOBJ_TYPE_MISSING || pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE || pChild->uCacheGen == pCache->auGenerationsMissing[pChild->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH) || kFsCacheRefreshMissing(pCache, pChild, penmError) ) { /* likely */ } else { if (ppLastAncestor) *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj); return NULL; } return kFsCacheObjRetainInternal(pChild); } /* * Check that it's a directory. If a missing entry, we may have to * refresh it and re-examin it. */ if (pChild->bObjType == KFSOBJ_TYPE_DIR) pParent = (PKFSDIR)pChild; else if (pChild->bObjType != KFSOBJ_TYPE_MISSING) { *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_DIR; if (ppLastAncestor) *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj); return NULL; } else if ( pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE || pChild->uCacheGen == pCache->auGenerationsMissing[pChild->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH) ) { *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND; if (ppLastAncestor) *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj); return NULL; } else if (kFsCacheRefreshMissingIntermediateDir(pCache, pChild, penmError)) pParent = (PKFSDIR)pChild; else { if (ppLastAncestor) *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj); return NULL; } } return NULL; } /** * Walk the file system tree for the given absolute path, entering it into the * hash table. * * This will create any missing nodes while walking. * * The caller will have to do the path hash table insertion of the result. * * @returns Pointer to the tree node corresponding to @a pszPath. * NULL on lookup failure, see @a penmError for details. * @param pCache The cache. * @param pszPath The path to walk. No dot-dot bits allowed! * @param cchPath The length of the path. * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX. * @param penmError Where to return details as to why the lookup * failed. * @param ppLastAncestor Where to return the last parent element found * (referenced) in case of error an path/file not * found problem. Optional. */ static PKFSOBJ kFsCacheLookupAbsoluteA(PKFSCACHE pCache, const char *pszPath, KU32 cchPath, KU32 fFlags, KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor) { PKFSOBJ pRoot; KU32 cchSlashes; KU32 offEnd; KFSCACHE_LOG2(("kFsCacheLookupAbsoluteA(%s)\n", pszPath)); /* * The root "directory" needs special handling, so we keep it outside the * main search loop. (Special: Cannot enumerate it, UNCs, ++.) */ cchSlashes = 0; if ( pszPath[1] == ':' && IS_ALPHA(pszPath[0])) { /* Drive letter. */ offEnd = 2; kHlpAssert(IS_SLASH(pszPath[2])); pRoot = kFsCacheLookupDrive(pCache, toupper(pszPath[0]), fFlags, penmError); } else if ( IS_SLASH(pszPath[0]) && IS_SLASH(pszPath[1]) ) pRoot = kFsCacheLookupUncShareA(pCache, pszPath, fFlags, &offEnd, penmError); else { *penmError = KFSLOOKUPERROR_UNSUPPORTED; return NULL; } if (pRoot) { /* likely */ } else return NULL; /* Count slashes trailing the root spec. */ if (offEnd < cchPath) { kHlpAssert(IS_SLASH(pszPath[offEnd])); do cchSlashes++; while (IS_SLASH(pszPath[offEnd + cchSlashes])); } /* Done already? */ if (offEnd >= cchPath) { if ( pRoot->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE || pRoot->uCacheGen == ( pRoot->bObjType != KFSOBJ_TYPE_MISSING ? pCache->auGenerations[ pRoot->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] : pCache->auGenerationsMissing[pRoot->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]) || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH) || kFsCacheRefreshObj(pCache, pRoot, penmError)) return kFsCacheObjRetainInternal(pRoot); if (ppLastAncestor) *ppLastAncestor = kFsCacheObjRetainInternal(pRoot); return NULL; } /* Check that we've got a valid result and not a cached negative one. */ if (pRoot->bObjType == KFSOBJ_TYPE_DIR) { /* likely */ } else { kHlpAssert(pRoot->bObjType == KFSOBJ_TYPE_MISSING); kHlpAssert( pRoot->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE || pRoot->uCacheGen == pCache->auGenerationsMissing[pRoot->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]); return pRoot; } /* * Now that we've found a valid root directory, lookup the * remainder of the path starting with it. */ return kFsCacheLookupRelativeToDirA(pCache, (PKFSDIR)pRoot, &pszPath[offEnd + cchSlashes], cchPath - offEnd - cchSlashes, fFlags, penmError, ppLastAncestor); } /** * Walk the file system tree for the given absolute path, UTF-16 version. * * This will create any missing nodes while walking. * * The caller will have to do the path hash table insertion of the result. * * @returns Pointer to the tree node corresponding to @a pszPath. * NULL on lookup failure, see @a penmError for details. * @param pCache The cache. * @param pwszPath The path to walk. * @param cwcPath The length of the path (in wchar_t's). * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX. * @param penmError Where to return details as to why the lookup * failed. * @param ppLastAncestor Where to return the last parent element found * (referenced) in case of error an path/file not * found problem. Optional. */ static PKFSOBJ kFsCacheLookupAbsoluteW(PKFSCACHE pCache, const wchar_t *pwszPath, KU32 cwcPath, KU32 fFlags, KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor) { PKFSDIR pParent = &pCache->RootDir; PKFSOBJ pRoot; KU32 off; KU32 cwcSlashes; KU32 offEnd; KFSCACHE_LOG2(("kFsCacheLookupAbsoluteW(%ls)\n", pwszPath)); /* * The root "directory" needs special handling, so we keep it outside the * main search loop. (Special: Cannot enumerate it, UNCs, ++.) */ cwcSlashes = 0; off = 0; if ( pwszPath[1] == ':' && IS_ALPHA(pwszPath[0])) { /* Drive letter. */ offEnd = 2; kHlpAssert(IS_SLASH(pwszPath[2])); pRoot = kFsCacheLookupDrive(pCache, toupper(pwszPath[0]), fFlags, penmError); } else if ( IS_SLASH(pwszPath[0]) && IS_SLASH(pwszPath[1]) ) pRoot = kFsCacheLookupUncShareW(pCache, pwszPath, fFlags, &offEnd, penmError); else { *penmError = KFSLOOKUPERROR_UNSUPPORTED; return NULL; } if (pRoot) { /* likely */ } else return NULL; /* Count slashes trailing the root spec. */ if (offEnd < cwcPath) { kHlpAssert(IS_SLASH(pwszPath[offEnd])); do cwcSlashes++; while (IS_SLASH(pwszPath[offEnd + cwcSlashes])); } /* Done already? */ if (offEnd >= cwcPath) { if ( pRoot->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE || pRoot->uCacheGen == (pRoot->bObjType != KFSOBJ_TYPE_MISSING ? pCache->auGenerations[ pRoot->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] : pCache->auGenerationsMissing[pRoot->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]) || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH) || kFsCacheRefreshObj(pCache, pRoot, penmError)) return kFsCacheObjRetainInternal(pRoot); if (ppLastAncestor) *ppLastAncestor = kFsCacheObjRetainInternal(pRoot); return NULL; } /* Check that we've got a valid result and not a cached negative one. */ if (pRoot->bObjType == KFSOBJ_TYPE_DIR) { /* likely */ } else { kHlpAssert(pRoot->bObjType == KFSOBJ_TYPE_MISSING); kHlpAssert( pRoot->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE || pRoot->uCacheGen == pCache->auGenerationsMissing[pRoot->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]); return pRoot; } /* * Now that we've found a valid root directory, lookup the * remainder of the path starting with it. */ return kFsCacheLookupRelativeToDirW(pCache, (PKFSDIR)pRoot, &pwszPath[offEnd + cwcSlashes], cwcPath - offEnd - cwcSlashes, fFlags, penmError, ppLastAncestor); } /** * This deals with paths that are relative and paths that contains '..' * elements, ANSI version. * * @returns Pointer to object corresponding to @a pszPath on success. * NULL if this isn't a path we care to cache. * * @param pCache The cache. * @param pszPath The path. * @param cchPath The length of the path. * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX. * @param penmError Where to return details as to why the lookup * failed. * @param ppLastAncestor Where to return the last parent element found * (referenced) in case of error an path/file not * found problem. Optional. */ static PKFSOBJ kFsCacheLookupSlowA(PKFSCACHE pCache, const char *pszPath, KU32 cchPath, KU32 fFlags, KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor) { /* * We just call GetFullPathNameA here to do the job as getcwd and _getdcwd * ends up calling it anyway. */ char szFull[KFSCACHE_CFG_MAX_PATH]; UINT cchFull = GetFullPathNameA(pszPath, sizeof(szFull), szFull, NULL); if ( cchFull >= 3 && cchFull < sizeof(szFull)) { KFSCACHE_LOG2(("kFsCacheLookupSlowA(%s)\n", pszPath)); return kFsCacheLookupAbsoluteA(pCache, szFull, cchFull, fFlags, penmError, ppLastAncestor); } /* The path is too long! */ kHlpAssertMsgFailed(("'%s' -> cchFull=%u\n", pszPath, cchFull)); *penmError = KFSLOOKUPERROR_PATH_TOO_LONG; return NULL; } /** * This deals with paths that are relative and paths that contains '..' * elements, UTF-16 version. * * @returns Pointer to object corresponding to @a pszPath on success. * NULL if this isn't a path we care to cache. * * @param pCache The cache. * @param pwszPath The path. * @param cwcPath The length of the path (in wchar_t's). * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX. * @param penmError Where to return details as to why the lookup * failed. * @param ppLastAncestor Where to return the last parent element found * (referenced) in case of error an path/file not * found problem. Optional. */ static PKFSOBJ kFsCacheLookupSlowW(PKFSCACHE pCache, const wchar_t *pwszPath, KU32 wcwPath, KU32 fFlags, KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor) { /* * We just call GetFullPathNameA here to do the job as getcwd and _getdcwd * ends up calling it anyway. */ wchar_t wszFull[KFSCACHE_CFG_MAX_PATH]; UINT cwcFull = GetFullPathNameW(pwszPath, KFSCACHE_CFG_MAX_PATH, wszFull, NULL); if ( cwcFull >= 3 && cwcFull < KFSCACHE_CFG_MAX_PATH) { KFSCACHE_LOG2(("kFsCacheLookupSlowA(%ls)\n", pwszPath)); return kFsCacheLookupAbsoluteW(pCache, wszFull, cwcFull, fFlags, penmError, ppLastAncestor); } /* The path is too long! */ kHlpAssertMsgFailed(("'%ls' -> cwcFull=%u\n", pwszPath, cwcFull)); *penmError = KFSLOOKUPERROR_PATH_TOO_LONG; return NULL; } /** * Refreshes a path hash that has expired, ANSI version. * * @returns pHash on success, NULL if removed. * @param pCache The cache. * @param pHashEntry The path hash. * @param idxHashTab The hash table entry. */ static PKFSHASHA kFsCacheRefreshPathA(PKFSCACHE pCache, PKFSHASHA pHashEntry, KU32 idxHashTab) { PKFSOBJ pLastAncestor = NULL; if (!pHashEntry->pFsObj) { if (pHashEntry->fAbsolute) pHashEntry->pFsObj = kFsCacheLookupAbsoluteA(pCache, pHashEntry->pszPath, pHashEntry->cchPath, 0 /*fFlags*/, &pHashEntry->enmError, &pLastAncestor); else pHashEntry->pFsObj = kFsCacheLookupSlowA(pCache, pHashEntry->pszPath, pHashEntry->cchPath, 0 /*fFlags*/, &pHashEntry->enmError, &pLastAncestor); } else { KU8 bOldType = pHashEntry->pFsObj->bObjType; KFSLOOKUPERROR enmError; if (kFsCacheRefreshObj(pCache, pHashEntry->pFsObj, &enmError)) { if (pHashEntry->pFsObj->bObjType == bOldType) { } else { kFsCacheObjRelease(pCache, pHashEntry->pFsObj); if (pHashEntry->fAbsolute) pHashEntry->pFsObj = kFsCacheLookupAbsoluteA(pCache, pHashEntry->pszPath, pHashEntry->cchPath, 0 /*fFlags*/, &pHashEntry->enmError, &pLastAncestor); else pHashEntry->pFsObj = kFsCacheLookupSlowA(pCache, pHashEntry->pszPath, pHashEntry->cchPath, 0 /*fFlags*/, &pHashEntry->enmError, &pLastAncestor); } } else { fprintf(stderr, "kFsCacheRefreshPathA - refresh failure handling not implemented!\n"); __debugbreak(); /** @todo just remove this entry. */ return NULL; } } if (pLastAncestor && !pHashEntry->pFsObj) pHashEntry->idxMissingGen = pLastAncestor->fFlags & KFSOBJ_F_USE_CUSTOM_GEN; pHashEntry->uCacheGen = !pHashEntry->pFsObj ? pCache->auGenerationsMissing[pHashEntry->idxMissingGen] : pHashEntry->pFsObj->bObjType == KFSOBJ_TYPE_MISSING ? pCache->auGenerationsMissing[pHashEntry->pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] : pCache->auGenerations[ pHashEntry->pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]; if (pLastAncestor) kFsCacheObjRelease(pCache, pLastAncestor); return pHashEntry; } /** * Refreshes a path hash that has expired, UTF-16 version. * * @returns pHash on success, NULL if removed. * @param pCache The cache. * @param pHashEntry The path hash. * @param idxHashTab The hash table entry. */ static PKFSHASHW kFsCacheRefreshPathW(PKFSCACHE pCache, PKFSHASHW pHashEntry, KU32 idxHashTab) { PKFSOBJ pLastAncestor = NULL; if (!pHashEntry->pFsObj) { if (pHashEntry->fAbsolute) pHashEntry->pFsObj = kFsCacheLookupAbsoluteW(pCache, pHashEntry->pwszPath, pHashEntry->cwcPath, 0 /*fFlags*/, &pHashEntry->enmError, &pLastAncestor); else pHashEntry->pFsObj = kFsCacheLookupSlowW(pCache, pHashEntry->pwszPath, pHashEntry->cwcPath, 0 /*fFlags*/, &pHashEntry->enmError, &pLastAncestor); } else { KU8 bOldType = pHashEntry->pFsObj->bObjType; KFSLOOKUPERROR enmError; if (kFsCacheRefreshObj(pCache, pHashEntry->pFsObj, &enmError)) { if (pHashEntry->pFsObj->bObjType == bOldType) { } else { kFsCacheObjRelease(pCache, pHashEntry->pFsObj); if (pHashEntry->fAbsolute) pHashEntry->pFsObj = kFsCacheLookupAbsoluteW(pCache, pHashEntry->pwszPath, pHashEntry->cwcPath, 0 /*fFlags*/, &pHashEntry->enmError, &pLastAncestor); else pHashEntry->pFsObj = kFsCacheLookupSlowW(pCache, pHashEntry->pwszPath, pHashEntry->cwcPath, 0 /*fFlags*/, &pHashEntry->enmError, &pLastAncestor); } } else { fprintf(stderr, "kFsCacheRefreshPathW - refresh failure handling not implemented!\n"); fflush(stderr); __debugbreak(); /** @todo just remove this entry. */ return NULL; } } if (pLastAncestor && !pHashEntry->pFsObj) pHashEntry->idxMissingGen = pLastAncestor->fFlags & KFSOBJ_F_USE_CUSTOM_GEN; pHashEntry->uCacheGen = !pHashEntry->pFsObj ? pCache->auGenerationsMissing[pHashEntry->idxMissingGen] : pHashEntry->pFsObj->bObjType == KFSOBJ_TYPE_MISSING ? pCache->auGenerationsMissing[pHashEntry->pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] : pCache->auGenerations[ pHashEntry->pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]; if (pLastAncestor) kFsCacheObjRelease(pCache, pLastAncestor); return pHashEntry; } /** * Internal lookup worker that looks up a KFSOBJ for the given ANSI path with * length and hash. * * This will first try the hash table. If not in the hash table, the file * system cache tree is walked, missing bits filled in and finally a hash table * entry is created. * * Only drive letter paths are cachable. We don't do any UNC paths at this * point. * * @returns Reference to object corresponding to @a pszPath on success, this * must be released by kFsCacheObjRelease. * NULL if not a path we care to cache. * @param pCache The cache. * @param pchPath The path to lookup. * @param cchPath The path length. * @param uHashPath The hash of the path. * @param penmError Where to return details as to why the lookup * failed. */ static PKFSOBJ kFsCacheLookupHashedA(PKFSCACHE pCache, const char *pchPath, KU32 cchPath, KU32 uHashPath, KFSLOOKUPERROR *penmError) { /* * Do hash table lookup of the path. */ KU32 idxHashTab = uHashPath % K_ELEMENTS(pCache->apAnsiPaths); PKFSHASHA pHashEntry = pCache->apAnsiPaths[idxHashTab]; kHlpAssert(pCache->u32Magic == KFSCACHE_MAGIC); if (pHashEntry) { do { if ( pHashEntry->uHashPath == uHashPath && pHashEntry->cchPath == cchPath && kHlpMemComp(pHashEntry->pszPath, pchPath, cchPath) == 0) { PKFSOBJ pFsObj; if ( pHashEntry->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE || pHashEntry->uCacheGen == ( (pFsObj = pHashEntry->pFsObj) != NULL ? pFsObj->bObjType != KFSOBJ_TYPE_MISSING ? pCache->auGenerations[ pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] : pCache->auGenerationsMissing[pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] : pCache->auGenerationsMissing[pHashEntry->idxMissingGen]) || (pHashEntry = kFsCacheRefreshPathA(pCache, pHashEntry, idxHashTab)) ) { pCache->cLookups++; pCache->cPathHashHits++; KFSCACHE_LOG2(("kFsCacheLookupA(%*.*s) - hit %p\n", cchPath, cchPath, pchPath, pHashEntry->pFsObj)); *penmError = pHashEntry->enmError; if (pHashEntry->pFsObj) return kFsCacheObjRetainInternal(pHashEntry->pFsObj); return NULL; } break; } pHashEntry = pHashEntry->pNext; } while (pHashEntry); } /* * Create an entry for it by walking the file system cache and filling in the blanks. */ if ( cchPath > 0 && cchPath < KFSCACHE_CFG_MAX_PATH) { PKFSOBJ pFsObj; KBOOL fAbsolute; PKFSOBJ pLastAncestor = NULL; /* Is absolute without any '..' bits? */ if ( cchPath >= 3 && ( ( pchPath[1] == ':' /* Drive letter */ && IS_SLASH(pchPath[2]) && IS_ALPHA(pchPath[0]) ) || ( IS_SLASH(pchPath[0]) /* UNC */ && IS_SLASH(pchPath[1]) ) ) && !kFsCacheHasDotDotA(pchPath, cchPath) ) { pFsObj = kFsCacheLookupAbsoluteA(pCache, pchPath, cchPath, 0 /*fFlags*/, penmError, &pLastAncestor); fAbsolute = K_TRUE; } else { pFsObj = kFsCacheLookupSlowA(pCache, pchPath, cchPath, 0 /*fFlags*/, penmError, &pLastAncestor); fAbsolute = K_FALSE; } if ( pFsObj || ( (pCache->fFlags & KFSCACHE_F_MISSING_PATHS) && *penmError != KFSLOOKUPERROR_PATH_TOO_LONG) || *penmError == KFSLOOKUPERROR_UNSUPPORTED ) kFsCacheCreatePathHashTabEntryA(pCache, pFsObj, pchPath, cchPath, uHashPath, idxHashTab, fAbsolute, pLastAncestor ? pLastAncestor->fFlags & KFSOBJ_F_USE_CUSTOM_GEN : 0, *penmError); if (pLastAncestor) kFsCacheObjRelease(pCache, pLastAncestor); pCache->cLookups++; if (pFsObj) pCache->cWalkHits++; return pFsObj; } *penmError = KFSLOOKUPERROR_PATH_TOO_LONG; return NULL; } /** * Internal lookup worker that looks up a KFSOBJ for the given UTF-16 path with * length and hash. * * This will first try the hash table. If not in the hash table, the file * system cache tree is walked, missing bits filled in and finally a hash table * entry is created. * * Only drive letter paths are cachable. We don't do any UNC paths at this * point. * * @returns Reference to object corresponding to @a pwcPath on success, this * must be released by kFsCacheObjRelease. * NULL if not a path we care to cache. * @param pCache The cache. * @param pwcPath The path to lookup. * @param cwcPath The length of the path (in wchar_t's). * @param uHashPath The hash of the path. * @param penmError Where to return details as to why the lookup * failed. */ static PKFSOBJ kFsCacheLookupHashedW(PKFSCACHE pCache, const wchar_t *pwcPath, KU32 cwcPath, KU32 uHashPath, KFSLOOKUPERROR *penmError) { /* * Do hash table lookup of the path. */ KU32 idxHashTab = uHashPath % K_ELEMENTS(pCache->apAnsiPaths); PKFSHASHW pHashEntry = pCache->apUtf16Paths[idxHashTab]; kHlpAssert(pCache->u32Magic == KFSCACHE_MAGIC); if (pHashEntry) { do { if ( pHashEntry->uHashPath == uHashPath && pHashEntry->cwcPath == cwcPath && kHlpMemComp(pHashEntry->pwszPath, pwcPath, cwcPath) == 0) { PKFSOBJ pFsObj; if ( pHashEntry->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE || pHashEntry->uCacheGen == ((pFsObj = pHashEntry->pFsObj) != NULL ? pFsObj->bObjType != KFSOBJ_TYPE_MISSING ? pCache->auGenerations[ pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] : pCache->auGenerationsMissing[pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] : pCache->auGenerationsMissing[pHashEntry->idxMissingGen]) || (pHashEntry = kFsCacheRefreshPathW(pCache, pHashEntry, idxHashTab)) ) { pCache->cLookups++; pCache->cPathHashHits++; KFSCACHE_LOG2(("kFsCacheLookupW(%*.*ls) - hit %p\n", cwcPath, cwcPath, pwcPath, pHashEntry->pFsObj)); *penmError = pHashEntry->enmError; if (pHashEntry->pFsObj) return kFsCacheObjRetainInternal(pHashEntry->pFsObj); return NULL; } break; } pHashEntry = pHashEntry->pNext; } while (pHashEntry); } /* * Create an entry for it by walking the file system cache and filling in the blanks. */ if ( cwcPath > 0 && cwcPath < KFSCACHE_CFG_MAX_PATH) { PKFSOBJ pFsObj; KBOOL fAbsolute; PKFSOBJ pLastAncestor = NULL; /* Is absolute without any '..' bits? */ if ( cwcPath >= 3 && ( ( pwcPath[1] == ':' /* Drive letter */ && IS_SLASH(pwcPath[2]) && IS_ALPHA(pwcPath[0]) ) || ( IS_SLASH(pwcPath[0]) /* UNC */ && IS_SLASH(pwcPath[1]) ) ) && !kFsCacheHasDotDotW(pwcPath, cwcPath) ) { pFsObj = kFsCacheLookupAbsoluteW(pCache, pwcPath, cwcPath, 0 /*fFlags*/, penmError, &pLastAncestor); fAbsolute = K_TRUE; } else { pFsObj = kFsCacheLookupSlowW(pCache, pwcPath, cwcPath, 0 /*fFlags*/, penmError, &pLastAncestor); fAbsolute = K_FALSE; } if ( pFsObj || ( (pCache->fFlags & KFSCACHE_F_MISSING_PATHS) && *penmError != KFSLOOKUPERROR_PATH_TOO_LONG) || *penmError == KFSLOOKUPERROR_UNSUPPORTED ) kFsCacheCreatePathHashTabEntryW(pCache, pFsObj, pwcPath, cwcPath, uHashPath, idxHashTab, fAbsolute, pLastAncestor ? pLastAncestor->fFlags & KFSOBJ_F_USE_CUSTOM_GEN : 0, *penmError); if (pLastAncestor) kFsCacheObjRelease(pCache, pLastAncestor); pCache->cLookups++; if (pFsObj) pCache->cWalkHits++; return pFsObj; } *penmError = KFSLOOKUPERROR_PATH_TOO_LONG; return NULL; } /** * Looks up a KFSOBJ for the given ANSI path. * * This will first try the hash table. If not in the hash table, the file * system cache tree is walked, missing bits filled in and finally a hash table * entry is created. * * Only drive letter paths are cachable. We don't do any UNC paths at this * point. * * @returns Reference to object corresponding to @a pszPath on success, this * must be released by kFsCacheObjRelease. * NULL if not a path we care to cache. * @param pCache The cache. * @param pszPath The path to lookup. * @param penmError Where to return details as to why the lookup * failed. */ PKFSOBJ kFsCacheLookupA(PKFSCACHE pCache, const char *pszPath, KFSLOOKUPERROR *penmError) { KU32 uHashPath; KU32 cchPath = (KU32)kFsCacheStrHashEx(pszPath, &uHashPath); return kFsCacheLookupHashedA(pCache, pszPath, cchPath, uHashPath, penmError); } /** * Looks up a KFSOBJ for the given UTF-16 path. * * This will first try the hash table. If not in the hash table, the file * system cache tree is walked, missing bits filled in and finally a hash table * entry is created. * * Only drive letter paths are cachable. We don't do any UNC paths at this * point. * * @returns Reference to object corresponding to @a pwszPath on success, this * must be released by kFsCacheObjRelease. * NULL if not a path we care to cache. * @param pCache The cache. * @param pwszPath The path to lookup. * @param penmError Where to return details as to why the lookup * failed. */ PKFSOBJ kFsCacheLookupW(PKFSCACHE pCache, const wchar_t *pwszPath, KFSLOOKUPERROR *penmError) { KU32 uHashPath; KU32 cwcPath = (KU32)kFsCacheUtf16HashEx(pwszPath, &uHashPath); return kFsCacheLookupHashedW(pCache, pwszPath, cwcPath, uHashPath, penmError); } /** * Looks up a KFSOBJ for the given ANSI path. * * This will first try the hash table. If not in the hash table, the file * system cache tree is walked, missing bits filled in and finally a hash table * entry is created. * * Only drive letter paths are cachable. We don't do any UNC paths at this * point. * * @returns Reference to object corresponding to @a pchPath on success, this * must be released by kFsCacheObjRelease. * NULL if not a path we care to cache. * @param pCache The cache. * @param pchPath The path to lookup (does not need to be nul * terminated). * @param cchPath The path length. * @param penmError Where to return details as to why the lookup * failed. */ PKFSOBJ kFsCacheLookupWithLengthA(PKFSCACHE pCache, const char *pchPath, KSIZE cchPath, KFSLOOKUPERROR *penmError) { return kFsCacheLookupHashedA(pCache, pchPath, (KU32)cchPath, kFsCacheStrHashN(pchPath, cchPath), penmError); } /** * Looks up a KFSOBJ for the given UTF-16 path. * * This will first try the hash table. If not in the hash table, the file * system cache tree is walked, missing bits filled in and finally a hash table * entry is created. * * Only drive letter paths are cachable. We don't do any UNC paths at this * point. * * @returns Reference to object corresponding to @a pwchPath on success, this * must be released by kFsCacheObjRelease. * NULL if not a path we care to cache. * @param pCache The cache. * @param pwcPath The path to lookup (does not need to be nul * terminated). * @param cwcPath The path length (in wchar_t's). * @param penmError Where to return details as to why the lookup * failed. */ PKFSOBJ kFsCacheLookupWithLengthW(PKFSCACHE pCache, const wchar_t *pwcPath, KSIZE cwcPath, KFSLOOKUPERROR *penmError) { return kFsCacheLookupHashedW(pCache, pwcPath, (KU32)cwcPath, kFsCacheUtf16HashN(pwcPath, cwcPath), penmError); } /** * Wrapper around kFsCacheLookupA that drops KFSOBJ_TYPE_MISSING and returns * KFSLOOKUPERROR_NOT_FOUND instead. * * @returns Reference to object corresponding to @a pszPath on success, this * must be released by kFsCacheObjRelease. * NULL if not a path we care to cache. * @param pCache The cache. * @param pszPath The path to lookup. * @param penmError Where to return details as to why the lookup * failed. */ PKFSOBJ kFsCacheLookupNoMissingA(PKFSCACHE pCache, const char *pszPath, KFSLOOKUPERROR *penmError) { PKFSOBJ pObj = kFsCacheLookupA(pCache, pszPath, penmError); if (pObj) { if (pObj->bObjType != KFSOBJ_TYPE_MISSING) return pObj; kFsCacheObjRelease(pCache, pObj); *penmError = KFSLOOKUPERROR_NOT_FOUND; } return NULL; } /** * Wrapper around kFsCacheLookupW that drops KFSOBJ_TYPE_MISSING and returns * KFSLOOKUPERROR_NOT_FOUND instead. * * @returns Reference to object corresponding to @a pszPath on success, this * must be released by kFsCacheObjRelease. * NULL if not a path we care to cache. * @param pCache The cache. * @param pwszPath The path to lookup. * @param penmError Where to return details as to why the lookup * failed. */ PKFSOBJ kFsCacheLookupNoMissingW(PKFSCACHE pCache, const wchar_t *pwszPath, KFSLOOKUPERROR *penmError) { PKFSOBJ pObj = kFsCacheLookupW(pCache, pwszPath, penmError); if (pObj) { if (pObj->bObjType != KFSOBJ_TYPE_MISSING) return pObj; kFsCacheObjRelease(pCache, pObj); *penmError = KFSLOOKUPERROR_NOT_FOUND; } return NULL; } /** * Destroys a cache object which has a zero reference count. * * @returns 0 * @param pCache The cache. * @param pObj The object. * @param pszWhere Where it was released from. */ KU32 kFsCacheObjDestroy(PKFSCACHE pCache, PKFSOBJ pObj, const char *pszWhere) { kHlpAssert(pObj->cRefs == 0); kHlpAssert(pObj->pParent == NULL); kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC); KFSCACHE_LOG(("Destroying %s/%s, type=%d, pObj=%p, pszWhere=%s\n", pObj->pParent ? pObj->pParent->Obj.pszName : "", pObj->pszName, pObj->bObjType, pObj, pszWhere)); if (pObj->abUnused[1] != 0) { fprintf(stderr, "Destroying %s/%s, type=%d, path hash entries: %d!\n", pObj->pParent ? pObj->pParent->Obj.pszName : "", pObj->pszName, pObj->bObjType, pObj->abUnused[0]); fflush(stderr); __debugbreak(); } /* * Invalidate the structure. */ pObj->u32Magic = ~KFSOBJ_MAGIC; /* * Destroy any user data first. */ while (pObj->pUserDataHead != NULL) { PKFSUSERDATA pUserData = pObj->pUserDataHead; pObj->pUserDataHead = pUserData->pNext; if (pUserData->pfnDestructor) pUserData->pfnDestructor(pCache, pObj, pUserData); kHlpFree(pUserData); } /* * Do type specific destruction */ switch (pObj->bObjType) { case KFSOBJ_TYPE_MISSING: /* nothing else to do here */ pCache->cbObjects -= sizeof(KFSDIR); break; case KFSOBJ_TYPE_DIR: { PKFSDIR pDir = (PKFSDIR)pObj; KU32 cChildren = pDir->cChildren; pCache->cbObjects -= sizeof(*pDir) + K_ALIGN_Z(cChildren, 16) * sizeof(pDir->papChildren) + (pDir->fHashTabMask + !!pDir->fHashTabMask) * sizeof(pDir->papHashTab[0]); pDir->cChildren = 0; while (cChildren-- > 0) kFsCacheObjRelease(pCache, pDir->papChildren[cChildren]); kHlpFree(pDir->papChildren); pDir->papChildren = NULL; kHlpFree(pDir->papHashTab); pDir->papHashTab = NULL; break; } case KFSOBJ_TYPE_FILE: case KFSOBJ_TYPE_OTHER: pCache->cbObjects -= sizeof(*pObj); break; default: return 0; } /* * Common bits. */ pCache->cbObjects -= pObj->cchName + 1; #ifdef KFSCACHE_CFG_UTF16 pCache->cbObjects -= (pObj->cwcName + 1) * sizeof(wchar_t); #endif #ifdef KFSCACHE_CFG_SHORT_NAMES if (pObj->pszName != pObj->pszShortName) { pCache->cbObjects -= pObj->cchShortName + 1; # ifdef KFSCACHE_CFG_UTF16 pCache->cbObjects -= (pObj->cwcShortName + 1) * sizeof(wchar_t); # endif } #endif pCache->cObjects--; if (pObj->pNameAlloc) { pCache->cbObjects -= pObj->pNameAlloc->cb; kHlpFree(pObj->pNameAlloc); } kHlpFree(pObj); return 0; } /** * Releases a reference to a cache object. * * @returns New reference count. * @param pCache The cache. * @param pObj The object. */ #undef kFsCacheObjRelease KU32 kFsCacheObjRelease(PKFSCACHE pCache, PKFSOBJ pObj) { if (pObj) { KU32 cRefs; kHlpAssert(pCache->u32Magic == KFSCACHE_MAGIC); kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC); cRefs = --pObj->cRefs; if (cRefs) return cRefs; return kFsCacheObjDestroy(pCache, pObj, "kFsCacheObjRelease"); } return 0; } /** * Debug version of kFsCacheObjRelease * * @returns New reference count. * @param pCache The cache. * @param pObj The object. * @param pszWhere Where it's invoked from. */ KU32 kFsCacheObjReleaseTagged(PKFSCACHE pCache, PKFSOBJ pObj, const char *pszWhere) { if (pObj) { KU32 cRefs; kHlpAssert(pCache->u32Magic == KFSCACHE_MAGIC); kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC); cRefs = --pObj->cRefs; if (cRefs) return cRefs; return kFsCacheObjDestroy(pCache, pObj, pszWhere); } return 0; } /** * Retains a reference to a cahce object. * * @returns New reference count. * @param pObj The object. */ KU32 kFsCacheObjRetain(PKFSOBJ pObj) { KU32 cRefs; kHlpAssert(pCache->u32Magic == KFSCACHE_MAGIC); kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC); cRefs = ++pObj->cRefs; kHlpAssert(cRefs < 16384); return cRefs; } /** * Associates an item of user data with the given object. * * If the data needs cleaning up before being free, set the * PKFSUSERDATA::pfnDestructor member of the returned structure. * * @returns Pointer to the user data on success. * NULL if out of memory or key already in use. * * @param pCache The cache. * @param pObj The object. * @param uKey The user data key. * @param cbUserData The size of the user data. */ PKFSUSERDATA kFsCacheObjAddUserData(PKFSCACHE pCache, PKFSOBJ pObj, KUPTR uKey, KSIZE cbUserData) { kHlpAssert(cbUserData >= sizeof(*pNew)); if (kFsCacheObjGetUserData(pCache, pObj, uKey) == NULL) { PKFSUSERDATA pNew = (PKFSUSERDATA)kHlpAllocZ(cbUserData); if (pNew) { pNew->uKey = uKey; pNew->pfnDestructor = NULL; pNew->pNext = pObj->pUserDataHead; pObj->pUserDataHead = pNew; return pNew; } } return NULL; } /** * Retrieves an item of user data associated with the given object. * * @returns Pointer to the associated user data if found, otherwise NULL. * @param pCache The cache. * @param pObj The object. * @param uKey The user data key. */ PKFSUSERDATA kFsCacheObjGetUserData(PKFSCACHE pCache, PKFSOBJ pObj, KUPTR uKey) { PKFSUSERDATA pCur; kHlpAssert(pCache->u32Magic == KFSCACHE_MAGIC); kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC); for (pCur = pObj->pUserDataHead; pCur; pCur = pCur->pNext) if (pCur->uKey == uKey) return pCur; return NULL; } /** * Gets the full path to @a pObj, ANSI version. * * @returns K_TRUE on success, K_FALSE on buffer overflow (nothing stored). * @param pObj The object to get the full path to. * @param pszPath Where to return the path * @param cbPath The size of the output buffer. * @param chSlash The slash to use. */ KBOOL kFsCacheObjGetFullPathA(PKFSOBJ pObj, char *pszPath, KSIZE cbPath, char chSlash) { KSIZE off = pObj->cchParent; kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC); if (off > 0) { KSIZE offEnd = off + pObj->cchName; if (offEnd < cbPath) { PKFSDIR pAncestor; pszPath[off + pObj->cchName] = '\0'; memcpy(&pszPath[off], pObj->pszName, pObj->cchName); for (pAncestor = pObj->pParent; off > 0; pAncestor = pAncestor->Obj.pParent) { kHlpAssert(off > 1); kHlpAssert(pAncestor != NULL); kHlpAssert(pAncestor->Obj.cchName > 0); pszPath[--off] = chSlash; off -= pAncestor->Obj.cchName; kHlpAssert(pAncestor->Obj.cchParent == off); memcpy(&pszPath[off], pAncestor->Obj.pszName, pAncestor->Obj.cchName); } return K_TRUE; } } else { KBOOL const fDriveLetter = pObj->cchName == 2 && pObj->pszName[2] == ':'; off = pObj->cchName; if (off + fDriveLetter < cbPath) { memcpy(pszPath, pObj->pszName, off); if (fDriveLetter) pszPath[off++] = chSlash; pszPath[off] = '\0'; return K_TRUE; } } return K_FALSE; } /** * Gets the full path to @a pObj, UTF-16 version. * * @returns K_TRUE on success, K_FALSE on buffer overflow (nothing stored). * @param pObj The object to get the full path to. * @param pszPath Where to return the path * @param cbPath The size of the output buffer. * @param wcSlash The slash to use. */ KBOOL kFsCacheObjGetFullPathW(PKFSOBJ pObj, wchar_t *pwszPath, KSIZE cwcPath, wchar_t wcSlash) { KSIZE off = pObj->cwcParent; kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC); if (off > 0) { KSIZE offEnd = off + pObj->cwcName; if (offEnd < cwcPath) { PKFSDIR pAncestor; pwszPath[off + pObj->cwcName] = '\0'; memcpy(&pwszPath[off], pObj->pwszName, pObj->cwcName * sizeof(wchar_t)); for (pAncestor = pObj->pParent; off > 0; pAncestor = pAncestor->Obj.pParent) { kHlpAssert(off > 1); kHlpAssert(pAncestor != NULL); kHlpAssert(pAncestor->Obj.cwcName > 0); pwszPath[--off] = wcSlash; off -= pAncestor->Obj.cwcName; kHlpAssert(pAncestor->Obj.cwcParent == off); memcpy(&pwszPath[off], pAncestor->Obj.pwszName, pAncestor->Obj.cwcName * sizeof(wchar_t)); } return K_TRUE; } } else { KBOOL const fDriveLetter = pObj->cchName == 2 && pObj->pszName[2] == ':'; off = pObj->cwcName; if (off + fDriveLetter < cwcPath) { memcpy(pwszPath, pObj->pwszName, off * sizeof(wchar_t)); if (fDriveLetter) pwszPath[off++] = wcSlash; pwszPath[off] = '\0'; return K_TRUE; } } return K_FALSE; } #ifdef KFSCACHE_CFG_SHORT_NAMES /** * Gets the full short path to @a pObj, ANSI version. * * @returns K_TRUE on success, K_FALSE on buffer overflow (nothing stored). * @param pObj The object to get the full path to. * @param pszPath Where to return the path * @param cbPath The size of the output buffer. * @param chSlash The slash to use. */ KBOOL kFsCacheObjGetFullShortPathA(PKFSOBJ pObj, char *pszPath, KSIZE cbPath, char chSlash) { KSIZE off = pObj->cchShortParent; kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC); if (off > 0) { KSIZE offEnd = off + pObj->cchShortName; if (offEnd < cbPath) { PKFSDIR pAncestor; pszPath[off + pObj->cchShortName] = '\0'; memcpy(&pszPath[off], pObj->pszShortName, pObj->cchShortName); for (pAncestor = pObj->pParent; off > 0; pAncestor = pAncestor->Obj.pParent) { kHlpAssert(off > 1); kHlpAssert(pAncestor != NULL); kHlpAssert(pAncestor->Obj.cchShortName > 0); pszPath[--off] = chSlash; off -= pAncestor->Obj.cchShortName; kHlpAssert(pAncestor->Obj.cchShortParent == off); memcpy(&pszPath[off], pAncestor->Obj.pszShortName, pAncestor->Obj.cchShortName); } return K_TRUE; } } else { KBOOL const fDriveLetter = pObj->cchShortName == 2 && pObj->pszShortName[2] == ':'; off = pObj->cchShortName; if (off + fDriveLetter < cbPath) { memcpy(pszPath, pObj->pszShortName, off); if (fDriveLetter) pszPath[off++] = chSlash; pszPath[off] = '\0'; return K_TRUE; } } return K_FALSE; } /** * Gets the full short path to @a pObj, UTF-16 version. * * @returns K_TRUE on success, K_FALSE on buffer overflow (nothing stored). * @param pObj The object to get the full path to. * @param pszPath Where to return the path * @param cbPath The size of the output buffer. * @param wcSlash The slash to use. */ KBOOL kFsCacheObjGetFullShortPathW(PKFSOBJ pObj, wchar_t *pwszPath, KSIZE cwcPath, wchar_t wcSlash) { KSIZE off = pObj->cwcShortParent; kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC); if (off > 0) { KSIZE offEnd = off + pObj->cwcShortName; if (offEnd < cwcPath) { PKFSDIR pAncestor; pwszPath[off + pObj->cwcShortName] = '\0'; memcpy(&pwszPath[off], pObj->pwszShortName, pObj->cwcShortName * sizeof(wchar_t)); for (pAncestor = pObj->pParent; off > 0; pAncestor = pAncestor->Obj.pParent) { kHlpAssert(off > 1); kHlpAssert(pAncestor != NULL); kHlpAssert(pAncestor->Obj.cwcShortName > 0); pwszPath[--off] = wcSlash; off -= pAncestor->Obj.cwcShortName; kHlpAssert(pAncestor->Obj.cwcShortParent == off); memcpy(&pwszPath[off], pAncestor->Obj.pwszShortName, pAncestor->Obj.cwcShortName * sizeof(wchar_t)); } return K_TRUE; } } else { KBOOL const fDriveLetter = pObj->cchShortName == 2 && pObj->pszShortName[2] == ':'; off = pObj->cwcShortName; if (off + fDriveLetter < cwcPath) { memcpy(pwszPath, pObj->pwszShortName, off * sizeof(wchar_t)); if (fDriveLetter) pwszPath[off++] = wcSlash; pwszPath[off] = '\0'; return K_TRUE; } } return K_FALSE; } #endif /* KFSCACHE_CFG_SHORT_NAMES */ /** * Read the specified bits from the files into the given buffer, simple version. * * @returns K_TRUE on success (all requested bytes read), * K_FALSE on any kind of failure. * * @param pCache The cache. * @param pFileObj The file object. * @param offStart Where to start reading. * @param pvBuf Where to store what we read. * @param cbToRead How much to read (exact). */ KBOOL kFsCacheFileSimpleOpenReadClose(PKFSCACHE pCache, PKFSOBJ pFileObj, KU64 offStart, void *pvBuf, KSIZE cbToRead) { /* * Open the file relative to the parent directory. */ MY_NTSTATUS rcNt; HANDLE hFile; MY_IO_STATUS_BLOCK Ios; MY_OBJECT_ATTRIBUTES ObjAttr; MY_UNICODE_STRING UniStr; kHlpAssertReturn(pFileObj->bObjType == KFSOBJ_TYPE_FILE, K_FALSE); kHlpAssert(pFileObj->pParent); kHlpAssertReturn(pFileObj->pParent->hDir != INVALID_HANDLE_VALUE, K_FALSE); kHlpAssertReturn(offStart == 0, K_FALSE); /** @todo when needed */ Ios.Information = -1; Ios.u.Status = -1; UniStr.Buffer = (wchar_t *)pFileObj->pwszName; UniStr.Length = (USHORT)(pFileObj->cwcName * sizeof(wchar_t)); UniStr.MaximumLength = UniStr.Length + sizeof(wchar_t); MyInitializeObjectAttributes(&ObjAttr, &UniStr, OBJ_CASE_INSENSITIVE, pFileObj->pParent->hDir, NULL /*pSecAttr*/); rcNt = g_pfnNtCreateFile(&hFile, GENERIC_READ | SYNCHRONIZE, &ObjAttr, &Ios, NULL, /*cbFileInitialAlloc */ FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, /*pEaBuffer*/ 0); /*cbEaBuffer*/ if (MY_NT_SUCCESS(rcNt)) { LARGE_INTEGER offFile; offFile.QuadPart = offStart; Ios.Information = -1; Ios.u.Status = -1; rcNt = g_pfnNtReadFile(hFile, NULL /*hEvent*/, NULL /*pfnApcComplete*/, NULL /*pvApcCtx*/, &Ios, pvBuf, (KU32)cbToRead, !offStart ? &offFile : NULL, NULL /*puKey*/); if (MY_NT_SUCCESS(rcNt)) rcNt = Ios.u.Status; if (MY_NT_SUCCESS(rcNt)) { if (Ios.Information == cbToRead) { g_pfnNtClose(hFile); return K_TRUE; } KFSCACHE_LOG(("Error reading %#x bytes from '%ls': Information=%p\n", pFileObj->pwszName, Ios.Information)); } else KFSCACHE_LOG(("Error reading %#x bytes from '%ls': %#x\n", pFileObj->pwszName, rcNt)); g_pfnNtClose(hFile); } else KFSCACHE_LOG(("Error opening '%ls' for caching: %#x\n", pFileObj->pwszName, rcNt)); return K_FALSE; } /** * Invalidate all cache entries of missing files. * * @param pCache The cache. */ void kFsCacheInvalidateMissing(PKFSCACHE pCache) { kHlpAssert(pCache->u32Magic == KFSOBJ_MAGIC); pCache->auGenerationsMissing[0]++; kHlpAssert(pCache->uGenerationMissing < KU32_MAX); KFSCACHE_LOG(("Invalidate missing %#x\n", pCache->auGenerationsMissing[0])); } /** * Invalidate all cache entries (regular, custom & missing). * * @param pCache The cache. */ void kFsCacheInvalidateAll(PKFSCACHE pCache) { kHlpAssert(pCache->u32Magic == KFSOBJ_MAGIC); pCache->auGenerationsMissing[0]++; kHlpAssert(pCache->auGenerationsMissing[0] < KU32_MAX); pCache->auGenerationsMissing[1]++; kHlpAssert(pCache->auGenerationsMissing[1] < KU32_MAX); pCache->auGenerations[0]++; kHlpAssert(pCache->auGenerations[0] < KU32_MAX); pCache->auGenerations[1]++; kHlpAssert(pCache->auGenerations[1] < KU32_MAX); KFSCACHE_LOG(("Invalidate all - default: %#x/%#x, custom: %#x/%#x\n", pCache->auGenerationsMissing[0], pCache->auGenerations[0], pCache->auGenerationsMissing[1], pCache->auGenerations[1])); } /** * Invalidate all cache entries with custom generation handling set. * * @see kFsCacheSetupCustomRevisionForTree, KFSOBJ_F_USE_CUSTOM_GEN * @param pCache The cache. */ void kFsCacheInvalidateCustomMissing(PKFSCACHE pCache) { kHlpAssert(pCache->u32Magic == KFSOBJ_MAGIC); pCache->auGenerationsMissing[1]++; kHlpAssert(pCache->auGenerationsMissing[1] < KU32_MAX); KFSCACHE_LOG(("Invalidate missing custom %#x\n", pCache->auGenerationsMissing[1])); } /** * Invalidate all cache entries with custom generation handling set, both * missing and regular present entries. * * @see kFsCacheSetupCustomRevisionForTree, KFSOBJ_F_USE_CUSTOM_GEN * @param pCache The cache. */ void kFsCacheInvalidateCustomBoth(PKFSCACHE pCache) { kHlpAssert(pCache->u32Magic == KFSOBJ_MAGIC); pCache->auGenerations[1]++; kHlpAssert(pCache->auGenerations[1] < KU32_MAX); pCache->auGenerationsMissing[1]++; kHlpAssert(pCache->auGenerationsMissing[1] < KU32_MAX); KFSCACHE_LOG(("Invalidate both custom %#x/%#x\n", pCache->auGenerationsMissing[1], pCache->auGenerations[1])); } /** * Applies the given flags to all the objects in a tree. * * @param pRoot Where to start applying the flag changes. * @param fAndMask The AND mask. * @param fOrMask The OR mask. */ static void kFsCacheApplyFlagsToTree(PKFSDIR pRoot, KU32 fAndMask, KU32 fOrMask) { PKFSOBJ *ppCur = ((PKFSDIR)pRoot)->papChildren; KU32 cLeft = ((PKFSDIR)pRoot)->cChildren; while (cLeft-- > 0) { PKFSOBJ pCur = *ppCur++; if (pCur->bObjType != KFSOBJ_TYPE_DIR) pCur->fFlags = (fAndMask & pCur->fFlags) | fOrMask; else kFsCacheApplyFlagsToTree((PKFSDIR)pCur, fAndMask, fOrMask); } pRoot->Obj.fFlags = (fAndMask & pRoot->Obj.fFlags) | fOrMask; } /** * Sets up using custom revisioning for the specified directory tree or file. * * There are some restrictions of the current implementation: * - If the root of the sub-tree is ever deleted from the cache (i.e. * deleted in real life and reflected in the cache), the setting is lost. * - It is not automatically applied to the lookup paths caches. * * @returns K_TRUE on success, K_FALSE on failure. * @param pCache The cache. * @param pRoot The root of the subtree. A non-directory is * fine, like a missing node. */ KBOOL kFsCacheSetupCustomRevisionForTree(PKFSCACHE pCache, PKFSOBJ pRoot) { if (pRoot) { if (pRoot->bObjType == KFSOBJ_TYPE_DIR) kFsCacheApplyFlagsToTree((PKFSDIR)pRoot, KU32_MAX, KFSOBJ_F_USE_CUSTOM_GEN); else pRoot->fFlags |= KFSOBJ_F_USE_CUSTOM_GEN; return K_TRUE; } return K_FALSE; } /** * Invalidates a deleted directory, ANSI version. * * @returns K_TRUE if found and is a non-root directory. Otherwise K_FALSE. * @param pCache The cache. * @param pszDir The directory. */ KBOOL kFsCacheInvalidateDeletedDirectoryA(PKFSCACHE pCache, const char *pszDir) { KU32 cchDir = (KU32)kHlpStrLen(pszDir); KFSLOOKUPERROR enmError; PKFSOBJ pFsObj; /* Is absolute without any '..' bits? */ if ( cchDir >= 3 && ( ( pszDir[1] == ':' /* Drive letter */ && IS_SLASH(pszDir[2]) && IS_ALPHA(pszDir[0]) ) || ( IS_SLASH(pszDir[0]) /* UNC */ && IS_SLASH(pszDir[1]) ) ) && !kFsCacheHasDotDotA(pszDir, cchDir) ) pFsObj = kFsCacheLookupAbsoluteA(pCache, pszDir, cchDir, KFSCACHE_LOOKUP_F_NO_INSERT | KFSCACHE_LOOKUP_F_NO_REFRESH, &enmError, NULL); else pFsObj = kFsCacheLookupSlowA(pCache, pszDir, cchDir, KFSCACHE_LOOKUP_F_NO_INSERT | KFSCACHE_LOOKUP_F_NO_REFRESH, &enmError, NULL); if (pFsObj) { /* Is directory? */ if (pFsObj->bObjType == KFSOBJ_TYPE_DIR) { if (pFsObj->pParent != &pCache->RootDir) { PKFSDIR pDir = (PKFSDIR)pFsObj; KFSCACHE_LOG(("kFsCacheInvalidateDeletedDirectoryA: %s hDir=%p\n", pszDir, pDir->hDir)); if (pDir->hDir != INVALID_HANDLE_VALUE) { g_pfnNtClose(pDir->hDir); pDir->hDir = INVALID_HANDLE_VALUE; } pDir->fNeedRePopulating = K_TRUE; pDir->Obj.uCacheGen = pCache->auGenerations[pDir->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN] - 1; kFsCacheObjRetainInternal(&pDir->Obj); return K_TRUE; } KFSCACHE_LOG(("kFsCacheInvalidateDeletedDirectoryA: Trying to invalidate a root directory was deleted! %s\n", pszDir)); } else KFSCACHE_LOG(("kFsCacheInvalidateDeletedDirectoryA: Trying to invalidate a non-directory: bObjType=%d %s\n", pFsObj->bObjType, pszDir)); kFsCacheObjRetainInternal(pFsObj); } else KFSCACHE_LOG(("kFsCacheInvalidateDeletedDirectoryA: '%s' was not found\n", pszDir)); return K_FALSE; } PKFSCACHE kFsCacheCreate(KU32 fFlags) { PKFSCACHE pCache; birdResolveImports(); pCache = (PKFSCACHE)kHlpAllocZ(sizeof(*pCache)); if (pCache) { /* Dummy root dir entry. */ pCache->RootDir.Obj.u32Magic = KFSOBJ_MAGIC; pCache->RootDir.Obj.cRefs = 1; pCache->RootDir.Obj.uCacheGen = KFSOBJ_CACHE_GEN_IGNORE; pCache->RootDir.Obj.bObjType = KFSOBJ_TYPE_DIR; pCache->RootDir.Obj.fHaveStats = K_FALSE; pCache->RootDir.Obj.pParent = NULL; pCache->RootDir.Obj.pszName = ""; pCache->RootDir.Obj.cchName = 0; pCache->RootDir.Obj.cchParent = 0; #ifdef KFSCACHE_CFG_UTF16 pCache->RootDir.Obj.cwcName = 0; pCache->RootDir.Obj.cwcParent = 0; pCache->RootDir.Obj.pwszName = L""; #endif #ifdef KFSCACHE_CFG_SHORT_NAMES pCache->RootDir.Obj.pszShortName = NULL; pCache->RootDir.Obj.cchShortName = 0; pCache->RootDir.Obj.cchShortParent = 0; # ifdef KFSCACHE_CFG_UTF16 pCache->RootDir.Obj.cwcShortName; pCache->RootDir.Obj.cwcShortParent; pCache->RootDir.Obj.pwszShortName; # endif #endif pCache->RootDir.cChildren = 0; pCache->RootDir.cChildrenAllocated = 0; pCache->RootDir.papChildren = NULL; pCache->RootDir.hDir = INVALID_HANDLE_VALUE; pCache->RootDir.fHashTabMask = 255; /* 256: 26 drive letters and 102 UNCs before we're half ways. */ pCache->RootDir.papHashTab = (PKFSOBJ *)kHlpAllocZ(256 * sizeof(pCache->RootDir.papHashTab[0])); if (pCache->RootDir.papHashTab) { /* The cache itself. */ pCache->u32Magic = KFSCACHE_MAGIC; pCache->fFlags = fFlags; pCache->auGenerations[0] = KU32_MAX / 4; pCache->auGenerations[1] = KU32_MAX / 32; pCache->auGenerationsMissing[0] = KU32_MAX / 256; pCache->auGenerationsMissing[1] = 1; pCache->cObjects = 1; pCache->cbObjects = sizeof(pCache->RootDir) + (pCache->RootDir.fHashTabMask + 1) * sizeof(pCache->RootDir.papHashTab[0]); pCache->cPathHashHits = 0; pCache->cWalkHits = 0; pCache->cChildSearches = 0; pCache->cChildHashHits = 0; pCache->cChildHashed = 0; pCache->cChildHashTabs = 1; pCache->cChildHashEntriesTotal = pCache->RootDir.fHashTabMask + 1; pCache->cChildHashCollisions = 0; pCache->cNameChanges = 0; pCache->cNameGrowths = 0; pCache->cAnsiPaths = 0; pCache->cAnsiPathCollisions = 0; pCache->cbAnsiPaths = 0; #ifdef KFSCACHE_CFG_UTF16 pCache->cUtf16Paths = 0; pCache->cUtf16PathCollisions = 0; pCache->cbUtf16Paths = 0; #endif return pCache; } kHlpFree(pCache); } return NULL; } kbuild-3149/src/lib/nt/ntstat.h0000644000175000017500000001227113252530204016347 0ustar locutuslocutus/* $Id: ntstat.h 3007 2016-11-06 16:46:43Z bird $ */ /** @file * MSC + NT stat, lstat and fstat implementation and wrappers. */ /* * Copyright (c) 2005-2013 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___nt_ntstat_h #define ___nt_ntstat_h #include "nttypes.h" #include #include #include #undef stat #undef lstat #undef fstat /** The distance between the NT and unix epochs given in NT time (units of 100 * ns). */ #define BIRD_NT_EPOCH_OFFSET_UNIX_100NS 116444736000000000LL typedef struct BirdStat { unsigned __int16 st_mode; unsigned __int8 st_isdirsymlink; /**< Set if directory symlink. */ unsigned __int8 st_ismountpoint; /**< Set if mount point; 1 if not followed, 2 if followed (lstat & readdir only). */ unsigned __int16 st_padding0[2]; __int64 st_size; BirdTimeSpec_T st_atim; BirdTimeSpec_T st_mtim; BirdTimeSpec_T st_ctim; BirdTimeSpec_T st_birthtim; unsigned __int64 st_ino; unsigned __int64 st_dev; unsigned __int32 st_nlink; unsigned __int16 st_rdev; __int16 st_uid; __int16 st_gid; unsigned __int16 st_padding1; unsigned __int32 st_attribs; unsigned __int32 st_blksize; __int64 st_blocks; } BirdStat_T; #define BIRD_STAT_BLOCK_SIZE 512 #define st_atime st_atim.tv_sec #define st_ctime st_ctim.tv_sec #define st_mtime st_mtim.tv_sec #define st_birthtime st_birthtim.tv_sec int birdStatFollowLink(const char *pszPath, BirdStat_T *pStat); int birdStatFollowLinkW(const wchar_t *pwszPath, BirdStat_T *pStat); int birdStatOnLink(const char *pszPath, BirdStat_T *pStat); int birdStatOnLinkW(const wchar_t *pwszPath, BirdStat_T *pStat); int birdStatAt(void *hRoot, const char *pszPath, BirdStat_T *pStat, int fFollowLink); int birdStatAtW(void *hRoot, const wchar_t *pwszPath, BirdStat_T *pStat, int fFollowLink); int birdStatOnFd(int fd, BirdStat_T *pStat); int birdStatOnFdJustSize(int fd, __int64 *pcbFile); int birdStatModTimeOnly(const char *pszPath, BirdTimeSpec_T *pTimeSpec, int fFollowLink); #ifdef ___nt_ntstuff_h int birdStatHandle(HANDLE hFile, BirdStat_T *pStat, const char *pszPath); void birdStatFillFromFileIdFullDirInfo(BirdStat_T *pStat, MY_FILE_ID_FULL_DIR_INFORMATION const *pBuf); void birdStatFillFromFileIdBothDirInfo(BirdStat_T *pStat, MY_FILE_ID_BOTH_DIR_INFORMATION const *pBuf); void birdStatFillFromFileBothDirInfo(BirdStat_T *pStat, MY_FILE_BOTH_DIR_INFORMATION const *pBuf); MY_NTSTATUS birdQueryVolumeDeviceNumber(HANDLE hFile, MY_FILE_FS_VOLUME_INFORMATION *pVolInfo, size_t cbVolInfo, unsigned __int64 *puDevNo); unsigned __int64 birdVolumeInfoToDeviceNumber(MY_FILE_FS_VOLUME_INFORMATION const *pVolInfo); #endif #define STAT_REDEFINED_ALREADY #define stat BirdStat #define BirdStat(a_pszPath, a_pStat) birdStatFollowLink(a_pszPath, a_pStat) #define lstat(a_pszPath, a_pStat) birdStatOnLink(a_pszPath, a_pStat) #define fstat(a_fd, a_pStat) birdStatOnFd(a_fd, a_pStat) #ifndef _S_IFLNK # define _S_IFLNK 0xa000 #endif #ifndef S_IFLNK # define S_IFLNK _S_IFLNK #endif #ifndef S_IFIFO # define S_IFIFO _S_IFIFO #endif #ifndef S_ISLNK # define S_ISLNK(m) (((m) & _S_IFMT) == _S_IFLNK) #endif #ifndef S_ISDIR # define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR) #endif #ifndef S_ISREG # define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG) #endif #define S_IRWXU (_S_IREAD | _S_IWRITE | _S_IEXEC) #define S_IXUSR _S_IEXEC #define S_IWUSR _S_IWRITE #define S_IRUSR _S_IREAD #define S_IRWXG 0000070 #define S_IRGRP 0000040 #define S_IWGRP 0000020 #define S_IXGRP 0000010 #define S_IRWXO 0000007 #define S_IROTH 0000004 #define S_IWOTH 0000002 #define S_IXOTH 0000001 #define S_ISUID 0004000 #define S_ISGID 0002000 #define ALLPERMS 0000777 #endif kbuild-3149/src/lib/nt/ntunlink.h0000644000175000017500000000423513252530204016675 0ustar locutuslocutus/* $Id: ntunlink.h 3060 2017-09-21 15:11:07Z bird $ */ /** @file * MSC + NT unlink and variations. */ /* * Copyright (c) 2005-2013 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___nt_ntunlink_h #define ___nt_ntunlink_h #include "nttypes.h" #include int birdUnlink(const char *pszFile); int birdUnlinkW(const wchar_t *pwszFile); int birdUnlinkEx(void *hRoot, const char *pszFile); int birdUnlinkExW(void *hRoot, const wchar_t *pwszFile); int birdUnlinkForced(const char *pszFile); int birdUnlinkForcedW(const wchar_t *pwszFile); int birdUnlinkForcedEx(void *hRoot, const char *pszFile); int birdUnlinkForcedExW(void *hRoot, const wchar_t *pszFile); int birdUnlinkForcedFast(const char *pszFile); int birdUnlinkForcedFastW(const wchar_t *pwszFile); int birdUnlinkForcedFastEx(void *hRoot, const char *pszFile); int birdUnlinkForcedFastExW(void *hRoot, const wchar_t *pwszFile); #undef unlink #define unlink(a_pszPath) birdUnlinkForced(a_pszPath) #endif kbuild-3149/src/lib/nt/ntstat.c0000644000175000017500000010463713252530204016352 0ustar locutuslocutus/* $Id: ntstat.c 3019 2017-01-07 00:07:08Z bird $ */ /** @file * MSC + NT stat, lstat and fstat. */ /* * Copyright (c) 2005-2013 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #include "ntstuff.h" #include "nthlp.h" #include "ntstat.h" #undef stat static int birdIsExecutableExtension(const char *pszExt) { switch (pszExt[0]) { default: return 0; case 'e': /* exe */ return pszExt[1] == 'x' && pszExt[2] == 'e' && pszExt[3] == '\0'; case 'b': /* bat */ return pszExt[1] == 'a' && pszExt[2] == 't' && pszExt[3] == '\0'; case 'v': /* vbs */ return pszExt[1] == 'b' && pszExt[2] == 's' && pszExt[3] == '\0'; case 'c': /* com and cmd */ return (pszExt[1] == 'o' && pszExt[2] == 'm' && pszExt[3] == '\0') || (pszExt[1] == 'm' && pszExt[2] == 'd' && pszExt[3] == '\0'); } } static int birdIsFileExecutable(const char *pszName) { if (pszName) { const char *pszExt = NULL; char szExt[8]; size_t cchExt; unsigned i; char ch; /* Look for a 3 char extension. */ ch = *pszName++; if (!ch) return 0; while ((ch = *pszName++) != '\0') if (ch == '.') pszExt = pszName; if (!pszExt) return 0; pszExt++; cchExt = pszName - pszExt; if (cchExt != 3) return 0; /* Copy the extension out and lower case it. Fail immediately on non-alpha chars. */ for (i = 0; i < cchExt; i++, pszExt++) { ch = *pszExt; if (ch >= 'a' && ch <= 'z') { /* likely */ } else if (ch >= 'A' && ch <= 'Z') ch += 'a' - 'A'; else return 0; szExt[i] = ch; } szExt[i] = '\0'; return birdIsExecutableExtension(szExt); } return 0; } /** * @a pwcName could be the full path. */ static int birdIsFileExecutableW(WCHAR const *pwcName, size_t cwcName) { char szExt[8]; unsigned cchExt; unsigned i; WCHAR const *pwc; /* Look for a 3 char extension. */ if (cwcName > 2 && pwcName[cwcName - 2] == '.') return 0; else if (cwcName > 3 && pwcName[cwcName - 3] == '.') return 0; else if (cwcName > 4 && pwcName[cwcName - 4] == '.') cchExt = 3; else return 0; /* Copy the extension out and lower case it. Fail immediately on non-alpha chars. */ pwc = &pwcName[cwcName - cchExt]; for (i = 0; i < cchExt; i++, pwc++) { WCHAR wc = *pwc; if (wc >= 'a' && wc <= 'z') { /* likely */ } else if (wc >= 'A' && wc <= 'Z') wc += 'a' - 'A'; else return 0; szExt[i] = (char)wc; } szExt[i] = '\0'; return birdIsExecutableExtension(szExt); } static unsigned short birdFileInfoToMode(ULONG fAttribs, ULONG uReparseTag, const char *pszName, const wchar_t *pwszName, size_t cbNameW, unsigned __int8 *pfIsDirSymlink, unsigned __int8 *pfIsMountPoint) { unsigned short fMode; /* File type. */ *pfIsDirSymlink = 0; *pfIsMountPoint = 0; if (!(fAttribs & FILE_ATTRIBUTE_REPARSE_POINT)) { if (fAttribs & FILE_ATTRIBUTE_DIRECTORY) fMode = S_IFDIR; else fMode = S_IFREG; } else { switch (uReparseTag) { case IO_REPARSE_TAG_SYMLINK: *pfIsDirSymlink = !!(fAttribs & FILE_ATTRIBUTE_DIRECTORY); fMode = S_IFLNK; break; case IO_REPARSE_TAG_MOUNT_POINT: *pfIsMountPoint = 1; default: if (fAttribs & FILE_ATTRIBUTE_DIRECTORY) fMode = S_IFDIR; else fMode = S_IFREG; break; } } /* Access mask. */ fMode |= S_IROTH | S_IRGRP | S_IRUSR; if (!(fAttribs & FILE_ATTRIBUTE_READONLY)) fMode |= S_IWOTH | S_IWGRP | S_IWUSR; if ( (fAttribs & FILE_ATTRIBUTE_DIRECTORY) || (pwszName ? birdIsFileExecutableW(pwszName, cbNameW / sizeof(wchar_t)) : birdIsFileExecutable(pszName)) ) fMode |= S_IXOTH | S_IXGRP | S_IXUSR; return fMode; } /** * Fills in a stat structure from an MY_FILE_ID_FULL_DIR_INFORMATION entry. * * @param pStat The stat structure. * @param pBuf The MY_FILE_ID_FULL_DIR_INFORMATION entry. * @remarks Caller sets st_dev. */ void birdStatFillFromFileIdFullDirInfo(BirdStat_T *pStat, MY_FILE_ID_FULL_DIR_INFORMATION const *pBuf) { pStat->st_mode = birdFileInfoToMode(pBuf->FileAttributes, pBuf->EaSize, NULL /*pszPath*/, pBuf->FileName, pBuf->FileNameLength, &pStat->st_isdirsymlink, &pStat->st_ismountpoint); pStat->st_padding0[0] = 0; pStat->st_padding0[1] = 0; pStat->st_size = pBuf->EndOfFile.QuadPart; birdNtTimeToTimeSpec(pBuf->CreationTime.QuadPart, &pStat->st_birthtim); birdNtTimeToTimeSpec(pBuf->ChangeTime.QuadPart, &pStat->st_ctim); birdNtTimeToTimeSpec(pBuf->LastWriteTime.QuadPart, &pStat->st_mtim); birdNtTimeToTimeSpec(pBuf->LastAccessTime.QuadPart, &pStat->st_atim); pStat->st_ino = pBuf->FileId.QuadPart; pStat->st_nlink = 1; pStat->st_rdev = 0; pStat->st_uid = 0; pStat->st_gid = 0; pStat->st_padding1 = 0; pStat->st_attribs = pBuf->FileAttributes; pStat->st_blksize = 65536; pStat->st_blocks = (pBuf->AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1) / BIRD_STAT_BLOCK_SIZE; } /** * Fills in a stat structure from an MY_FILE_ID_BOTH_DIR_INFORMATION entry. * * @param pStat The stat structure. * @param pBuf The MY_FILE_ID_BOTH_DIR_INFORMATION entry. * @remarks Caller sets st_dev. */ void birdStatFillFromFileIdBothDirInfo(BirdStat_T *pStat, MY_FILE_ID_BOTH_DIR_INFORMATION const *pBuf) { pStat->st_mode = birdFileInfoToMode(pBuf->FileAttributes, pBuf->EaSize, NULL /*pszPath*/, pBuf->FileName, pBuf->FileNameLength, &pStat->st_isdirsymlink, &pStat->st_ismountpoint); pStat->st_padding0[0] = 0; pStat->st_padding0[1] = 0; pStat->st_size = pBuf->EndOfFile.QuadPart; birdNtTimeToTimeSpec(pBuf->CreationTime.QuadPart, &pStat->st_birthtim); birdNtTimeToTimeSpec(pBuf->ChangeTime.QuadPart, &pStat->st_ctim); birdNtTimeToTimeSpec(pBuf->LastWriteTime.QuadPart, &pStat->st_mtim); birdNtTimeToTimeSpec(pBuf->LastAccessTime.QuadPart, &pStat->st_atim); pStat->st_ino = pBuf->FileId.QuadPart; pStat->st_nlink = 1; pStat->st_rdev = 0; pStat->st_uid = 0; pStat->st_gid = 0; pStat->st_padding1 = 0; pStat->st_attribs = pBuf->FileAttributes; pStat->st_blksize = 65536; pStat->st_blocks = (pBuf->AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1) / BIRD_STAT_BLOCK_SIZE; } /** * Fills in a stat structure from an MY_FILE_BOTH_DIR_INFORMATION entry. * * @param pStat The stat structure. * @param pBuf The MY_FILE_BOTH_DIR_INFORMATION entry. * @remarks Caller sets st_dev. */ void birdStatFillFromFileBothDirInfo(BirdStat_T *pStat, MY_FILE_BOTH_DIR_INFORMATION const *pBuf) { pStat->st_mode = birdFileInfoToMode(pBuf->FileAttributes, pBuf->EaSize, NULL /*pszPath*/, pBuf->FileName, pBuf->FileNameLength, &pStat->st_isdirsymlink, &pStat->st_ismountpoint); pStat->st_padding0[0] = 0; pStat->st_padding0[1] = 0; pStat->st_size = pBuf->EndOfFile.QuadPart; birdNtTimeToTimeSpec(pBuf->CreationTime.QuadPart, &pStat->st_birthtim); birdNtTimeToTimeSpec(pBuf->ChangeTime.QuadPart, &pStat->st_ctim); birdNtTimeToTimeSpec(pBuf->LastWriteTime.QuadPart, &pStat->st_mtim); birdNtTimeToTimeSpec(pBuf->LastAccessTime.QuadPart, &pStat->st_atim); pStat->st_ino = 0; pStat->st_nlink = 1; pStat->st_rdev = 0; pStat->st_uid = 0; pStat->st_gid = 0; pStat->st_padding1 = 0; pStat->st_attribs = pBuf->FileAttributes; pStat->st_blksize = 65536; pStat->st_blocks = (pBuf->AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1) / BIRD_STAT_BLOCK_SIZE; } int birdStatHandle2(HANDLE hFile, BirdStat_T *pStat, const char *pszPath, const wchar_t *pwszPath) { int rc; MY_NTSTATUS rcNt; #if 0 ULONG cbAll = sizeof(MY_FILE_ALL_INFORMATION) + 0x10000; MY_FILE_ALL_INFORMATION *pAll = (MY_FILE_ALL_INFORMATION *)birdTmpAlloc(cbAll); if (pAll) { MY_IO_STATUS_BLOCK Ios; Ios.Information = 0; Ios.u.Status = -1; rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pAll, cbAll, MyFileAllInformation); if (MY_NT_SUCCESS(rcNt)) rcNt = Ios.u.Status; if (MY_NT_SUCCESS(rcNt)) { pStat->st_mode = birdFileInfoToMode(pAll->BasicInformation.FileAttributes, pszPath, pAll->NameInformation.FileNamepAll->NameInformation.FileNameLength, hFile, &pStat->st_isdirsymlink, &pStat->st_ismountpoint); pStat->st_padding0[0] = 0; pStat->st_padding0[1] = 0; pStat->st_size = pAll->StandardInformation.EndOfFile.QuadPart; birdNtTimeToTimeSpec(pAll->BasicInformation.CreationTime.QuadPart, &pStat->st_birthtim); birdNtTimeToTimeSpec(pAll->BasicInformation.ChangeTime.QuadPart, &pStat->st_ctim); birdNtTimeToTimeSpec(pAll->BasicInformation.LastWriteTime.QuadPart, &pStat->st_mtim); birdNtTimeToTimeSpec(pAll->BasicInformation.LastAccessTime.QuadPart, &pStat->st_atim); pStat->st_ino = pAll->InternalInformation.IndexNumber.QuadPart; pStat->st_nlink = pAll->StandardInformation.NumberOfLinks; pStat->st_rdev = 0; pStat->st_uid = 0; pStat->st_gid = 0; pStat->st_padding1 = 0; pStat->st_attribs = pAll->StandardInformation.FileAttributes; pStat->st_blksize = 65536; pStat->st_blocks = (pAll->StandardInformation.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1) / BIRD_STAT_BLOCK_SIZE; /* Get the serial number, reusing the buffer from above. */ rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pAll, cbAll, MyFileFsVolumeInformation); if (MY_NT_SUCCESS(rcNt)) rcNt = Ios.u.Status; if (MY_NT_SUCCESS(rcNt)) { MY_FILE_FS_VOLUME_INFORMATION const *pVolInfo = (MY_FILE_FS_VOLUME_INFORMATION const *)pAll; pStat->st_dev = pVolInfo->VolumeSerialNumber | (pVolInfo->VolumeCreationTime.QuadPart << 32); rc = 0; } else { pStat->st_dev = 0; rc = birdSetErrnoFromNt(rcNt); } } else rc = birdSetErrnoFromNt(rcNt); } else rc = birdSetErrnoToNoMem(); #else ULONG cbNameInfo = 0; MY_FILE_NAME_INFORMATION *pNameInfo = NULL; MY_FILE_STANDARD_INFORMATION StdInfo; MY_FILE_BASIC_INFORMATION BasicInfo; MY_FILE_INTERNAL_INFORMATION InternalInfo; MY_FILE_ATTRIBUTE_TAG_INFORMATION TagInfo; MY_IO_STATUS_BLOCK Ios; Ios.Information = 0; Ios.u.Status = -1; rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &StdInfo, sizeof(StdInfo), MyFileStandardInformation); if (MY_NT_SUCCESS(rcNt)) rcNt = Ios.u.Status; if (MY_NT_SUCCESS(rcNt)) rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &BasicInfo, sizeof(BasicInfo), MyFileBasicInformation); if (MY_NT_SUCCESS(rcNt)) rcNt = Ios.u.Status; if (MY_NT_SUCCESS(rcNt)) rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &InternalInfo, sizeof(InternalInfo), MyFileInternalInformation); if (MY_NT_SUCCESS(rcNt)) rcNt = Ios.u.Status; if (MY_NT_SUCCESS(rcNt)) { if (!(BasicInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) TagInfo.ReparseTag = 0; else { MY_NTSTATUS rcNt2 = g_pfnNtQueryInformationFile(hFile, &Ios, &TagInfo, sizeof(TagInfo), MyFileAttributeTagInformation); if ( !MY_NT_SUCCESS(rcNt2) || !MY_NT_SUCCESS(Ios.u.Status)) TagInfo.ReparseTag = 0; } } if ( MY_NT_SUCCESS(rcNt) && !pszPath && !pwszPath && !(BasicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { cbNameInfo = 0x10020; pNameInfo = (MY_FILE_NAME_INFORMATION *)alloca(cbNameInfo); rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pNameInfo, cbNameInfo, MyFileNameInformation); if (MY_NT_SUCCESS(rcNt)) rcNt = Ios.u.Status; } if (MY_NT_SUCCESS(rcNt)) { pStat->st_mode = birdFileInfoToMode(BasicInfo.FileAttributes, TagInfo.ReparseTag, pszPath, pNameInfo ? pNameInfo->FileName : pwszPath, pNameInfo ? pNameInfo->FileNameLength : pwszPath ? wcslen(pwszPath) * sizeof(wchar_t) : 0, &pStat->st_isdirsymlink, &pStat->st_ismountpoint); pStat->st_padding0[0] = 0; pStat->st_padding0[1] = 0; pStat->st_size = StdInfo.EndOfFile.QuadPart; birdNtTimeToTimeSpec(BasicInfo.CreationTime.QuadPart, &pStat->st_birthtim); birdNtTimeToTimeSpec(BasicInfo.ChangeTime.QuadPart, &pStat->st_ctim); birdNtTimeToTimeSpec(BasicInfo.LastWriteTime.QuadPart, &pStat->st_mtim); birdNtTimeToTimeSpec(BasicInfo.LastAccessTime.QuadPart, &pStat->st_atim); pStat->st_ino = InternalInfo.IndexNumber.QuadPart; pStat->st_nlink = StdInfo.NumberOfLinks; pStat->st_rdev = 0; pStat->st_uid = 0; pStat->st_gid = 0; pStat->st_padding1 = 0; pStat->st_attribs = BasicInfo.FileAttributes; pStat->st_blksize = 65536; pStat->st_blocks = (StdInfo.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1) / BIRD_STAT_BLOCK_SIZE; /* Get the serial number, reusing the buffer from above. */ if (!cbNameInfo) { cbNameInfo = sizeof(MY_FILE_FS_VOLUME_INFORMATION) + 1024; pNameInfo = (MY_FILE_NAME_INFORMATION *)alloca(cbNameInfo); } rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pNameInfo, cbNameInfo, MyFileFsVolumeInformation); if (MY_NT_SUCCESS(rcNt)) rcNt = Ios.u.Status; if (MY_NT_SUCCESS(rcNt)) { MY_FILE_FS_VOLUME_INFORMATION const *pVolInfo = (MY_FILE_FS_VOLUME_INFORMATION const *)pNameInfo; pStat->st_dev = pVolInfo->VolumeSerialNumber | (pVolInfo->VolumeCreationTime.QuadPart << 32); rc = 0; } else { pStat->st_dev = 0; rc = birdSetErrnoFromNt(rcNt); } } else rc = birdSetErrnoFromNt(rcNt); #endif return rc; } int birdStatHandle(HANDLE hFile, BirdStat_T *pStat, const char *pszPath) { return birdStatHandle2(hFile, pStat, pszPath, NULL); } /** * Generates a device number from the volume information. * * @returns Device number. * @param pVolInfo Volume information. */ unsigned __int64 birdVolumeInfoToDeviceNumber(const MY_FILE_FS_VOLUME_INFORMATION *pVolInfo) { return pVolInfo->VolumeSerialNumber | (pVolInfo->VolumeCreationTime.QuadPart << 32); } /** * Quries the volume information and generates a device number from it. * * @returns NT status code. * @param hFile The file/dir/whatever to query the volume info * and device number for. * @param pVolInfo User provided buffer for volume information. * @param cbVolInfo The size of the buffer. * @param puDevNo Where to return the device number. This is set * to zero on failure. */ MY_NTSTATUS birdQueryVolumeDeviceNumber(HANDLE hFile, MY_FILE_FS_VOLUME_INFORMATION *pVolInfo, size_t cbVolInfo, unsigned __int64 *puDevNo) { MY_IO_STATUS_BLOCK Ios; MY_NTSTATUS rcNt; Ios.u.Status = -1; Ios.Information = -1; pVolInfo->VolumeSerialNumber = 0; pVolInfo->VolumeCreationTime.QuadPart = 0; rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pVolInfo, (LONG)cbVolInfo, MyFileFsVolumeInformation); if (MY_NT_SUCCESS(rcNt)) { *puDevNo = birdVolumeInfoToDeviceNumber(pVolInfo); return Ios.u.Status; } *puDevNo = 0; return rcNt; } static int birdStatInternal(HANDLE hRoot, const char *pszPath, BirdStat_T *pStat, int fFollow) { int rc; HANDLE hFile = birdOpenFileEx(hRoot, pszPath, FILE_READ_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_OPEN_FOR_BACKUP_INTENT | (fFollow ? 0 : FILE_OPEN_REPARSE_POINT), OBJ_CASE_INSENSITIVE); if (hFile != INVALID_HANDLE_VALUE) { rc = birdStatHandle2(hFile, pStat, pszPath, NULL); birdCloseFile(hFile); if (rc || !pStat->st_ismountpoint) { /* very likely */ } else { /* * If we hit a mount point (NTFS volume mounted under an empty NTFS directory), * we should return information about what's mounted there rather than the * directory it is mounted at as this is what UNIX does. */ hFile = birdOpenFileEx(hRoot, pszPath, FILE_READ_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_OPEN_FOR_BACKUP_INTENT, OBJ_CASE_INSENSITIVE); if (hFile != INVALID_HANDLE_VALUE) { rc = birdStatHandle2(hFile, pStat, pszPath, NULL); pStat->st_ismountpoint = 2; birdCloseFile(hFile); } } #if 0 { static char s_szPrev[256]; size_t cchPath = strlen(pszPath); if (memcmp(s_szPrev, pszPath, cchPath >= 255 ? 255 : cchPath + 1) == 0) fprintf(stderr, "stat: %s -> rc/errno=%d/%u\n", pszPath, rc, errno); else memcpy(s_szPrev, pszPath, cchPath + 1); } #endif //fprintf(stderr, "stat: %s -> rc/errno=%d/%u\n", pszPath, rc, errno); } else { //fprintf(stderr, "stat: %s -> %u\n", pszPath, GetLastError()); /* * On things like pagefile.sys we may get sharing violation. We fall * back on directory enumeration for dealing with that. */ if ( errno == ETXTBSY && strchr(pszPath, '*') == NULL /* Serious paranoia... */ && strchr(pszPath, '?') == NULL) { MY_UNICODE_STRING NameUniStr; hFile = birdOpenParentDir(hRoot, pszPath, FILE_READ_DATA | SYNCHRONIZE, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, OBJ_CASE_INSENSITIVE, &NameUniStr); if (hFile != INVALID_HANDLE_VALUE) { MY_FILE_ID_FULL_DIR_INFORMATION *pBuf; ULONG cbBuf = sizeof(*pBuf) + NameUniStr.MaximumLength + 1024; MY_IO_STATUS_BLOCK Ios; MY_NTSTATUS rcNt; pBuf = (MY_FILE_ID_FULL_DIR_INFORMATION *)alloca(cbBuf); Ios.u.Status = -1; Ios.Information = -1; rcNt = g_pfnNtQueryDirectoryFile(hFile, NULL, NULL, NULL, &Ios, pBuf, cbBuf, MyFileIdFullDirectoryInformation, FALSE, &NameUniStr, TRUE); if (MY_NT_SUCCESS(rcNt)) rcNt = Ios.u.Status; if (MY_NT_SUCCESS(rcNt)) { /* * Convert the data. */ birdStatFillFromFileIdFullDirInfo(pStat, pBuf); /* Get the serial number, reusing the buffer from above. */ rcNt = birdQueryVolumeDeviceNumber(hFile, (MY_FILE_FS_VOLUME_INFORMATION *)pBuf, cbBuf, &pStat->st_dev); if (MY_NT_SUCCESS(rcNt)) rc = 0; else rc = birdSetErrnoFromNt(rcNt); } birdFreeNtPath(&NameUniStr); birdCloseFile(hFile); if (MY_NT_SUCCESS(rcNt)) return 0; birdSetErrnoFromNt(rcNt); } } rc = -1; } return rc; } static int birdStatInternalW(HANDLE hRoot, const wchar_t *pwszPath, BirdStat_T *pStat, int fFollow) { int rc; HANDLE hFile = birdOpenFileExW(hRoot, pwszPath, FILE_READ_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_OPEN_FOR_BACKUP_INTENT | (fFollow ? 0 : FILE_OPEN_REPARSE_POINT), OBJ_CASE_INSENSITIVE); if (hFile != INVALID_HANDLE_VALUE) { rc = birdStatHandle2(hFile, pStat, NULL, pwszPath); birdCloseFile(hFile); if (rc || !pStat->st_ismountpoint) { /* very likely */ } else { /* * If we hit a mount point (NTFS volume mounted under an empty NTFS directory), * we should return information about what's mounted there rather than the * directory it is mounted at as this is what UNIX does. */ hFile = birdOpenFileExW(hRoot, pwszPath, FILE_READ_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_OPEN_FOR_BACKUP_INTENT, OBJ_CASE_INSENSITIVE); if (hFile != INVALID_HANDLE_VALUE) { rc = birdStatHandle2(hFile, pStat, NULL, pwszPath); pStat->st_ismountpoint = 2; birdCloseFile(hFile); } } } else { /* * On things like pagefile.sys we may get sharing violation. We fall * back on directory enumeration for dealing with that. */ if ( errno == ETXTBSY && wcschr(pwszPath, '*') == NULL /* Serious paranoia... */ && wcschr(pwszPath, '?') == NULL) { MY_UNICODE_STRING NameUniStr; hFile = birdOpenParentDirW(hRoot, pwszPath, FILE_READ_DATA | SYNCHRONIZE, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, OBJ_CASE_INSENSITIVE, &NameUniStr); if (hFile != INVALID_HANDLE_VALUE) { MY_FILE_ID_FULL_DIR_INFORMATION *pBuf; ULONG cbBuf = sizeof(*pBuf) + NameUniStr.MaximumLength + 1024; MY_IO_STATUS_BLOCK Ios; MY_NTSTATUS rcNt; pBuf = (MY_FILE_ID_FULL_DIR_INFORMATION *)alloca(cbBuf); Ios.u.Status = -1; Ios.Information = -1; rcNt = g_pfnNtQueryDirectoryFile(hFile, NULL, NULL, NULL, &Ios, pBuf, cbBuf, MyFileIdFullDirectoryInformation, FALSE, &NameUniStr, TRUE); if (MY_NT_SUCCESS(rcNt)) rcNt = Ios.u.Status; if (MY_NT_SUCCESS(rcNt)) { /* * Convert the data. */ birdStatFillFromFileIdFullDirInfo(pStat, pBuf); /* Get the serial number, reusing the buffer from above. */ rcNt = birdQueryVolumeDeviceNumber(hFile, (MY_FILE_FS_VOLUME_INFORMATION *)pBuf, cbBuf, &pStat->st_dev); if (MY_NT_SUCCESS(rcNt)) rc = 0; else rc = birdSetErrnoFromNt(rcNt); } birdFreeNtPath(&NameUniStr); birdCloseFile(hFile); if (MY_NT_SUCCESS(rcNt)) return 0; birdSetErrnoFromNt(rcNt); } } rc = -1; } return rc; } /** * Implements UNIX fstat(). */ int birdStatOnFd(int fd, BirdStat_T *pStat) { int rc; HANDLE hFile = (HANDLE)_get_osfhandle(fd); if (hFile != INVALID_HANDLE_VALUE) { DWORD fFileType; birdResolveImports(); SetLastError(NO_ERROR); fFileType = GetFileType(hFile) & ~FILE_TYPE_REMOTE; switch (fFileType) { case FILE_TYPE_DISK: rc = birdStatHandle2(hFile, pStat, NULL, NULL); break; case FILE_TYPE_CHAR: case FILE_TYPE_PIPE: if (fFileType == FILE_TYPE_PIPE) pStat->st_mode = S_IFIFO | 0666; else pStat->st_mode = S_IFCHR | 0666; pStat->st_padding0[0] = 0; pStat->st_padding0[1] = 0; pStat->st_size = 0; pStat->st_atim.tv_sec = 0; pStat->st_atim.tv_nsec = 0; pStat->st_mtim.tv_sec = 0; pStat->st_mtim.tv_nsec = 0; pStat->st_ctim.tv_sec = 0; pStat->st_ctim.tv_nsec = 0; pStat->st_birthtim.tv_sec = 0; pStat->st_birthtim.tv_nsec = 0; pStat->st_ino = 0; pStat->st_dev = 0; pStat->st_rdev = 0; pStat->st_uid = 0; pStat->st_gid = 0; pStat->st_padding1 = 0; pStat->st_attribs = fFileType == FILE_TYPE_PIPE ? FILE_ATTRIBUTE_NORMAL : FILE_ATTRIBUTE_DEVICE; pStat->st_blksize = 512; pStat->st_blocks = 0; if (fFileType == FILE_TYPE_PIPE) { DWORD cbAvail; if (PeekNamedPipe(hFile, NULL, 0, NULL, &cbAvail, NULL)) pStat->st_size = cbAvail; } rc = 0; break; case FILE_TYPE_UNKNOWN: default: if (GetLastError() == NO_ERROR) rc = birdSetErrnoToBadFileNo(); else rc = birdSetErrnoFromWin32(GetLastError()); break; } } else rc = -1; return rc; } /** * Special case that only gets the file size and nothing else. */ int birdStatOnFdJustSize(int fd, __int64 *pcbFile) { int rc; HANDLE hFile = (HANDLE)_get_osfhandle(fd); if (hFile != INVALID_HANDLE_VALUE) { LARGE_INTEGER cbLocal; if (GetFileSizeEx(hFile, &cbLocal)) { *pcbFile = cbLocal.QuadPart; rc = 0; } else { BirdStat_T Stat; rc = birdStatOnFd(fd, &Stat); if (rc == 0) *pcbFile = Stat.st_size; } } else rc = -1; return rc; } /** * Implements UNIX stat(). */ int birdStatFollowLink(const char *pszPath, BirdStat_T *pStat) { return birdStatInternal(NULL, pszPath, pStat, 1 /*fFollow*/); } /** * Implements UNIX stat(). */ int birdStatFollowLinkW(const wchar_t *pwszPath, BirdStat_T *pStat) { return birdStatInternalW(NULL, pwszPath, pStat, 1 /*fFollow*/); } /** * Implements UNIX lstat(). */ int birdStatOnLink(const char *pszPath, BirdStat_T *pStat) { return birdStatInternal(NULL, pszPath, pStat, 0 /*fFollow*/); } /** * Implements UNIX lstat(). */ int birdStatOnLinkW(const wchar_t *pwszPath, BirdStat_T *pStat) { return birdStatInternalW(NULL, pwszPath, pStat, 0 /*fFollow*/); } /** * Implements an API like UNIX fstatat(). * * @returns 0 on success, -1 and errno on failure. * @param hRoot NT handle pwszPath is relative to. * @param pszPath The path. * @param pStat Where to return stats. * @param fFollowLink Whether to follow links. */ int birdStatAt(HANDLE hRoot, const char *pszPath, BirdStat_T *pStat, int fFollowLink) { return birdStatInternal(hRoot, pszPath, pStat, fFollowLink != 0); } /** * Implements an API like UNIX fstatat(). * * @returns 0 on success, -1 and errno on failure. * @param hRoot NT handle pwszPath is relative to. * @param pwszPath The path. * @param pStat Where to return stats. * @param fFollowLink Whether to follow links. */ int birdStatAtW(HANDLE hRoot, const wchar_t *pwszPath, BirdStat_T *pStat, int fFollowLink) { return birdStatInternalW(hRoot, pwszPath, pStat, fFollowLink != 0); } /** * Internal worker for birdStatModTimeOnly. */ static int birdStatOnlyInternal(const char *pszPath, int fFollowLink, MY_FILE_BASIC_INFORMATION *pBasicInfo) { int rc; HANDLE hFile = birdOpenFile(pszPath, FILE_READ_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_OPEN_FOR_BACKUP_INTENT | (fFollowLink ? 0 : FILE_OPEN_REPARSE_POINT), OBJ_CASE_INSENSITIVE); if (hFile != INVALID_HANDLE_VALUE) { MY_NTSTATUS rcNt = 0; MY_IO_STATUS_BLOCK Ios; Ios.Information = 0; Ios.u.Status = -1; if (pBasicInfo) { rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pBasicInfo, sizeof(*pBasicInfo), MyFileBasicInformation); if (MY_NT_SUCCESS(rcNt)) rcNt = Ios.u.Status; } birdCloseFile(hFile); if (MY_NT_SUCCESS(rcNt)) rc = 0; else { birdSetErrnoFromNt(rcNt); rc = -1; } } else { //fprintf(stderr, "stat: %s -> %u\n", pszPath, GetLastError()); /* On things like pagefile.sys we may get sharing violation. */ if (GetLastError() == ERROR_SHARING_VIOLATION) { /** @todo Fall back on the parent directory enum if we run into a sharing * violation. */ } rc = -1; } return rc; } /** * Special function for getting the modification time. */ int birdStatModTimeOnly(const char *pszPath, BirdTimeSpec_T *pTimeSpec, int fFollowLink) { MY_FILE_BASIC_INFORMATION BasicInfo; int rc = birdStatOnlyInternal(pszPath, fFollowLink, &BasicInfo); if (!rc) birdNtTimeToTimeSpec(BasicInfo.LastWriteTime.QuadPart, pTimeSpec); return rc; } kbuild-3149/src/lib/nt/kFsCache.h0000644000175000017500000005061113252530204016501 0ustar locutuslocutus/* $Id: kFsCache.h 2967 2016-09-26 18:14:13Z bird $ */ /** @file * kFsCache.c - NT directory content cache. */ /* * Copyright (c) 2016 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___lib_nt_kFsCache_h___ #define ___lib_nt_kFsCache_h___ #include #include "ntstat.h" #ifndef NDEBUG # include #endif /** @def KFSCACHE_CFG_UTF16 * Whether to compile in the UTF-16 names support. */ #define KFSCACHE_CFG_UTF16 1 /** @def KFSCACHE_CFG_SHORT_NAMES * Whether to compile in the short name support. */ #define KFSCACHE_CFG_SHORT_NAMES 1 /** @def KFSCACHE_CFG_PATH_HASH_TAB_SIZE * Size of the path hash table. */ #define KFSCACHE_CFG_PATH_HASH_TAB_SIZE 99991 /** The max length paths we consider. */ #define KFSCACHE_CFG_MAX_PATH 1024 /** The max ANSI name length. */ #define KFSCACHE_CFG_MAX_ANSI_NAME (256*3 + 16) /** The max UTF-16 name length. */ #define KFSCACHE_CFG_MAX_UTF16_NAME (256*2 + 16) /** Special KFSOBJ::uCacheGen number indicating that it does not apply. */ #define KFSOBJ_CACHE_GEN_IGNORE KU32_MAX /** @name KFSOBJ_TYPE_XXX - KFSOBJ::bObjType * @{ */ /** Directory, type KFSDIR. */ #define KFSOBJ_TYPE_DIR KU8_C(0x01) /** Regular file - type KFSOBJ. */ #define KFSOBJ_TYPE_FILE KU8_C(0x02) /** Other file - type KFSOBJ. */ #define KFSOBJ_TYPE_OTHER KU8_C(0x03) /** Caching of a negative result - type KFSOBJ. * @remarks We will allocate enough space for the largest cache node, so this * can metamorph into any other object should it actually turn up. */ #define KFSOBJ_TYPE_MISSING KU8_C(0x04) ///** Invalidated entry flag. */ //#define KFSOBJ_TYPE_F_INVALID KU8_C(0x20) /** @} */ /** @name KFSOBJ_F_XXX - KFSOBJ::fFlags * @{ */ /** Use custom generation. * @remarks This is given the value 1, as we use it as an index into * KFSCACHE::auGenerations, 0 being the default. */ #define KFSOBJ_F_USE_CUSTOM_GEN KU32_C(0x00000001) /** Whether the file system update the modified timestamp of directories * when something is removed from it or added to it. * @remarks They say NTFS is the only windows filesystem doing this. */ #define KFSOBJ_F_WORKING_DIR_MTIME KU32_C(0x00000002) /** NTFS file system volume. */ #define KFSOBJ_F_NTFS KU32_C(0x80000000) /** Flags that are automatically inherited. */ #define KFSOBJ_F_INHERITED_MASK KU32_C(0xffffffff) /** @} */ #define IS_ALPHA(ch) ( ((ch) >= 'A' && (ch) <= 'Z') || ((ch) >= 'a' && (ch) <= 'z') ) #define IS_SLASH(ch) ((ch) == '\\' || (ch) == '/') /** Pointer to a cache. */ typedef struct KFSCACHE *PKFSCACHE; /** Pointer to a core object. */ typedef struct KFSOBJ *PKFSOBJ; /** Pointer to a directory object. */ typedef struct KFSDIR *PKFSDIR; /** Pointer to a directory hash table entry. */ typedef struct KFSOBJHASH *PKFSOBJHASH; /** Pointer to a user data item. */ typedef struct KFSUSERDATA *PKFSUSERDATA; /** * User data item associated with a cache node. */ typedef struct KFSUSERDATA { /** Pointer to the next piece of user data. */ PKFSUSERDATA pNext; /** The key identifying this user. */ KUPTR uKey; /** The destructor. */ void (*pfnDestructor)(PKFSCACHE pCache, PKFSOBJ pObj, PKFSUSERDATA pData); } KFSUSERDATA; /** * Storage for name strings for the unlikely event that they should grow in * length after the KFSOBJ was created. */ typedef struct KFSOBJNAMEALLOC { /** Size of the allocation. */ KU32 cb; /** The space for names. */ char abSpace[1]; } KFSOBJNAMEALLOC; /** Name growth allocation. */ typedef KFSOBJNAMEALLOC *PKFSOBJNAMEALLOC; /** * Base cache node. */ typedef struct KFSOBJ { /** Magic value (KFSOBJ_MAGIC). */ KU32 u32Magic; /** Number of references. */ KU32 volatile cRefs; /** The cache generation, see KFSOBJ_CACHE_GEN_IGNORE. */ KU32 uCacheGen; /** The object type, KFSOBJ_TYPE_XXX. */ KU8 bObjType; /** Set if the Stats member is valid, clear if not. */ KBOOL fHaveStats; /** Unused flags. */ KBOOL abUnused[2]; /** Flags, KFSOBJ_F_XXX. */ KU32 fFlags; /** Hash value of the name inserted into the parent hash table. * This is 0 if not inserted. Names are only hashed and inserted as they are * first found thru linear searching of its siblings, and which name it is * dependens on the lookup function (W or A) and whether the normal name or * short name seems to have matched. * * @note It was ruled out as too much work to hash and track all four names, * so instead this minimalist approach was choosen in stead. */ KU32 uNameHash; /** Pointer to the next child with the same name hash value. */ PKFSOBJ pNextNameHash; /** Pointer to the parent (directory). * This is only NULL for a root. */ PKFSDIR pParent; /** The directory name. (Allocated after the structure.) */ const char *pszName; /** The length of pszName. */ KU16 cchName; /** The length of the parent path (up to where pszName starts). * @note This is valuable when constructing an absolute path to this node by * means of the parent pointer (no need for recursion). */ KU16 cchParent; #ifdef KFSCACHE_CFG_UTF16 /** The length of pwszName (in wchar_t's). */ KU16 cwcName; /** The length of the parent UTF-16 path (in wchar_t's). * @note This is valuable when constructing an absolute path to this node by * means of the parent pointer (no need for recursion). */ KU16 cwcParent; /** The UTF-16 object name. (Allocated after the structure.) */ const wchar_t *pwszName; #endif #ifdef KFSCACHE_CFG_SHORT_NAMES /** The short object name. (Allocated after the structure, could be same * as pszName.) */ const char *pszShortName; /** The length of pszShortName. */ KU16 cchShortName; /** The length of the short parent path (up to where pszShortName starts). */ KU16 cchShortParent; # ifdef KFSCACHE_CFG_UTF16 /** The length of pwszShortName (in wchar_t's). */ KU16 cwcShortName; /** The length of the short parent UTF-16 path (in wchar_t's). */ KU16 cwcShortParent; /** The UTF-16 short object name. (Allocated after the structure, possibly * same as pwszName.) */ const wchar_t *pwszShortName; # endif #endif /** Allocation for handling name length increases. */ PKFSOBJNAMEALLOC pNameAlloc; /** Pointer to the first user data item */ PKFSUSERDATA pUserDataHead; /** Stats - only valid when fHaveStats is set. */ BirdStat_T Stats; } KFSOBJ; /** The magic for a KFSOBJ structure (Thelonious Sphere Monk). */ #define KFSOBJ_MAGIC KU32_C(0x19171010) /** * Directory node in the cache. */ typedef struct KFSDIR { /** The core object information. */ KFSOBJ Obj; /** Child objects. */ PKFSOBJ *papChildren; /** The number of child objects. */ KU32 cChildren; /** The allocated size of papChildren. */ KU32 cChildrenAllocated; /** Pointer to the child hash table. */ PKFSOBJ *papHashTab; /** The mask shift of the hash table. * Hash table size is a power of two, this is the size minus one. * * @remarks The hash table is optional and populated by lookup hits. The * assumption being that a lookup is repeated and will choose a good * name to hash on. We've got up to 4 different hashes, so this * was the easy way out. */ KU32 fHashTabMask; /** Handle to the directory (we generally keep it open). */ #ifndef DECLARE_HANDLE KUPTR hDir; #else HANDLE hDir; #endif /** The device number we queried/inherited when opening it. */ KU64 uDevNo; /** The last write time sampled the last time the directory was refreshed. * @remarks May differ from st_mtim because it will be updated when the * parent directory is refreshed. */ KI64 iLastWrite; /** Set if populated. */ KBOOL fPopulated; /** Set if it needs re-populated. */ KBOOL fNeedRePopulating; } KFSDIR; /** * Lookup errors. */ typedef enum KFSLOOKUPERROR { /** Lookup was a success. */ KFSLOOKUPERROR_SUCCESS = 0, /** A path component was not found. */ KFSLOOKUPERROR_PATH_COMP_NOT_FOUND, /** A path component is not a directory. */ KFSLOOKUPERROR_PATH_COMP_NOT_DIR, /** The final path entry is not a directory (trailing slash). */ KFSLOOKUPERROR_NOT_DIR, /** Not found. */ KFSLOOKUPERROR_NOT_FOUND, /** The path is too long. */ KFSLOOKUPERROR_PATH_TOO_LONG, /** Unsupported path type. */ KFSLOOKUPERROR_UNSUPPORTED, /** We're out of memory. */ KFSLOOKUPERROR_OUT_OF_MEMORY, /** Error opening directory. */ KFSLOOKUPERROR_DIR_OPEN_ERROR, /** Error reading directory. */ KFSLOOKUPERROR_DIR_READ_ERROR, /** UTF-16 to ANSI conversion error. */ KFSLOOKUPERROR_ANSI_CONVERSION_ERROR, /** ANSI to UTF-16 conversion error. */ KFSLOOKUPERROR_UTF16_CONVERSION_ERROR, /** Internal error. */ KFSLOOKUPERROR_INTERNAL_ERROR } KFSLOOKUPERROR; /** Pointer to an ANSI path hash table entry. */ typedef struct KFSHASHA *PKFSHASHA; /** * ANSI file system path hash table entry. * The path hash table allows us to skip parsing and walking a path. */ typedef struct KFSHASHA { /** Next entry with the same hash table slot. */ PKFSHASHA pNext; /** Path hash value. */ KU32 uHashPath; /** The path length. */ KU16 cchPath; /** Set if aboslute path. */ KBOOL fAbsolute; /** Index into KFSCACHE:auGenerationsMissing when pFsObj is NULL. */ KU8 idxMissingGen; /** The cache generation ID. */ KU32 uCacheGen; /** The lookup error (when pFsObj is NULL). */ KFSLOOKUPERROR enmError; /** The path. (Allocated after the structure.) */ const char *pszPath; /** Pointer to the matching FS object. * This is NULL for negative path entries? */ PKFSOBJ pFsObj; } KFSHASHA; #ifdef KFSCACHE_CFG_UTF16 /** Pointer to an UTF-16 path hash table entry. */ typedef struct KFSHASHW *PKFSHASHW; /** * UTF-16 file system path hash table entry. The path hash table allows us * to skip parsing and walking a path. */ typedef struct KFSHASHW { /** Next entry with the same hash table slot. */ PKFSHASHW pNext; /** Path hash value. */ KU32 uHashPath; /** The path length (in wchar_t units). */ KU16 cwcPath; /** Set if aboslute path. */ KBOOL fAbsolute; /** Index into KFSCACHE:auGenerationsMissing when pFsObj is NULL. */ KU8 idxMissingGen; /** The cache generation ID. */ KU32 uCacheGen; /** The lookup error (when pFsObj is NULL). */ KFSLOOKUPERROR enmError; /** The path. (Allocated after the structure.) */ const wchar_t *pwszPath; /** Pointer to the matching FS object. * This is NULL for negative path entries? */ PKFSOBJ pFsObj; } KFSHASHW; #endif /** @name KFSCACHE_F_XXX * @{ */ /** Whether to cache missing directory entries (KFSOBJ_TYPE_MISSING). */ #define KFSCACHE_F_MISSING_OBJECTS KU32_C(0x00000001) /** Whether to cache missing paths. */ #define KFSCACHE_F_MISSING_PATHS KU32_C(0x00000002) /** @} */ /** * Directory cache instance. */ typedef struct KFSCACHE { /** Magic value (KFSCACHE_MAGIC). */ KU32 u32Magic; /** Cache flags. */ KU32 fFlags; /** The default and custom cache generations for stuff that exists, indexed by * KFSOBJ_F_USE_CUSTOM_GEN. * * The custom generation can be used to invalidate parts of the file system that * are known to be volatile without triggering refreshing of the more static * parts. Like the 'out' directory in a kBuild setup or a 'TEMP' directory are * expected to change and you need to invalidate the caching of these frequently * to stay on top of things. Whereas the sources, headers, compilers, sdk, * ddks, windows directory and such generally doesn't change all that often. */ KU32 auGenerations[2]; /** The current cache generation for missing objects, negative results, ++. * This comes with a custom variant too. Indexed by KFSOBJ_F_USE_CUSTOM_GEN. */ KU32 auGenerationsMissing[2]; /** Number of cache objects. */ KSIZE cObjects; /** Memory occupied by the cache object structures. */ KSIZE cbObjects; /** Number of lookups. */ KSIZE cLookups; /** Number of hits in the path hash tables. */ KSIZE cPathHashHits; /** Number of hits walking the file system hierarchy. */ KSIZE cWalkHits; /** Number of child searches. */ KSIZE cChildSearches; /** Number of cChildLookups resolved thru hash table hits. */ KSIZE cChildHashHits; /** The number of child hash tables. */ KSIZE cChildHashTabs; /** The sum of all child hash table sizes. */ KSIZE cChildHashEntriesTotal; /** Number of children inserted into the hash tables. */ KSIZE cChildHashed; /** Number of collisions in the child hash tables. */ KSIZE cChildHashCollisions; /** Number times a object name changed. */ KSIZE cNameChanges; /** Number times a object name grew and needed KFSOBJNAMEALLOC. * (Subset of cNameChanges) */ KSIZE cNameGrowths; /** The root directory. */ KFSDIR RootDir; /** File system hash table for ANSI filename strings. */ PKFSHASHA apAnsiPaths[KFSCACHE_CFG_PATH_HASH_TAB_SIZE]; /** Number of paths in the apAnsiPaths hash table. */ KSIZE cAnsiPaths; /** Number of collisions in the apAnsiPaths hash table. */ KSIZE cAnsiPathCollisions; /** Amount of memory used by the path entries. */ KSIZE cbAnsiPaths; #ifdef KFSCACHE_CFG_UTF16 /** Number of paths in the apUtf16Paths hash table. */ KSIZE cUtf16Paths; /** Number of collisions in the apUtf16Paths hash table. */ KSIZE cUtf16PathCollisions; /** Amount of memory used by the UTF-16 path entries. */ KSIZE cbUtf16Paths; /** File system hash table for UTF-16 filename strings. */ PKFSHASHW apUtf16Paths[KFSCACHE_CFG_PATH_HASH_TAB_SIZE]; #endif } KFSCACHE; /** Magic value for KFSCACHE::u32Magic (Jon Batiste). */ #define KFSCACHE_MAGIC KU32_C(0x19861111) /** @def KW_LOG * Generic logging. * @param a Argument list for kFsCacheDbgPrintf */ #ifdef NDEBUG # define KFSCACHE_LOG(a) do { } while (0) #else # define KFSCACHE_LOG(a) kFsCacheDbgPrintf a void kFsCacheDbgPrintfV(const char *pszFormat, va_list va); void kFsCacheDbgPrintf(const char *pszFormat, ...); #endif KBOOL kFsCacheDirEnsurePopuplated(PKFSCACHE pCache, PKFSDIR pDir, KFSLOOKUPERROR *penmError); KBOOL kFsCacheDirAddChild(PKFSCACHE pCache, PKFSDIR pParent, PKFSOBJ pChild, KFSLOOKUPERROR *penmError); PKFSOBJ kFsCacheCreateObject(PKFSCACHE pCache, PKFSDIR pParent, char const *pszName, KU16 cchName, wchar_t const *pwszName, KU16 cwcName, #ifdef KFSCACHE_CFG_SHORT_NAMES char const *pszShortName, KU16 cchShortName, wchar_t const *pwszShortName, KU16 cwcShortName, #endif KU8 bObjType, KFSLOOKUPERROR *penmError); PKFSOBJ kFsCacheCreateObjectW(PKFSCACHE pCache, PKFSDIR pParent, wchar_t const *pwszName, KU32 cwcName, #ifdef KFSCACHE_CFG_SHORT_NAMES wchar_t const *pwszShortName, KU32 cwcShortName, #endif KU8 bObjType, KFSLOOKUPERROR *penmError); PKFSOBJ kFsCacheLookupA(PKFSCACHE pCache, const char *pszPath, KFSLOOKUPERROR *penmError); PKFSOBJ kFsCacheLookupW(PKFSCACHE pCache, const wchar_t *pwszPath, KFSLOOKUPERROR *penmError); PKFSOBJ kFsCacheLookupRelativeToDirA(PKFSCACHE pCache, PKFSDIR pParent, const char *pszPath, KU32 cchPath, KU32 fFlags, KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor); PKFSOBJ kFsCacheLookupRelativeToDirW(PKFSCACHE pCache, PKFSDIR pParent, const wchar_t *pwszPath, KU32 cwcPath, KU32 fFlags, KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor); PKFSOBJ kFsCacheLookupWithLengthA(PKFSCACHE pCache, const char *pchPath, KSIZE cchPath, KFSLOOKUPERROR *penmError); PKFSOBJ kFsCacheLookupWithLengthW(PKFSCACHE pCache, const wchar_t *pwcPath, KSIZE cwcPath, KFSLOOKUPERROR *penmError); PKFSOBJ kFsCacheLookupNoMissingA(PKFSCACHE pCache, const char *pszPath, KFSLOOKUPERROR *penmError); PKFSOBJ kFsCacheLookupNoMissingW(PKFSCACHE pCache, const wchar_t *pwszPath, KFSLOOKUPERROR *penmError); /** @name KFSCACHE_LOOKUP_F_XXX - lookup flags * @{ */ /** No inserting new cache entries. * This effectively prevent directories from being repopulated too. */ #define KFSCACHE_LOOKUP_F_NO_INSERT KU32_C(1) /** No refreshing cache entries. */ #define KFSCACHE_LOOKUP_F_NO_REFRESH KU32_C(2) /** @} */ KU32 kFsCacheObjRelease(PKFSCACHE pCache, PKFSOBJ pObj); KU32 kFsCacheObjReleaseTagged(PKFSCACHE pCache, PKFSOBJ pObj, const char *pszWhere); #ifndef NDEBUG /* enable to debug object release. */ # define kFsCacheObjRelease(a_pCache, a_pObj) kFsCacheObjReleaseTagged(a_pCache, a_pObj, __FUNCTION__) #endif KU32 kFsCacheObjRetain(PKFSOBJ pObj); PKFSUSERDATA kFsCacheObjAddUserData(PKFSCACHE pCache, PKFSOBJ pObj, KUPTR uKey, KSIZE cbUserData); PKFSUSERDATA kFsCacheObjGetUserData(PKFSCACHE pCache, PKFSOBJ pObj, KUPTR uKey); KBOOL kFsCacheObjGetFullPathA(PKFSOBJ pObj, char *pszPath, KSIZE cbPath, char chSlash); KBOOL kFsCacheObjGetFullPathW(PKFSOBJ pObj, wchar_t *pwszPath, KSIZE cwcPath, wchar_t wcSlash); KBOOL kFsCacheObjGetFullShortPathA(PKFSOBJ pObj, char *pszPath, KSIZE cbPath, char chSlash); KBOOL kFsCacheObjGetFullShortPathW(PKFSOBJ pObj, wchar_t *pwszPath, KSIZE cwcPath, wchar_t wcSlash); KBOOL kFsCacheFileSimpleOpenReadClose(PKFSCACHE pCache, PKFSOBJ pFileObj, KU64 offStart, void *pvBuf, KSIZE cbToRead); PKFSCACHE kFsCacheCreate(KU32 fFlags); void kFsCacheDestroy(PKFSCACHE); void kFsCacheInvalidateMissing(PKFSCACHE pCache); void kFsCacheInvalidateAll(PKFSCACHE pCache); void kFsCacheInvalidateCustomMissing(PKFSCACHE pCache); void kFsCacheInvalidateCustomBoth(PKFSCACHE pCache); KBOOL kFsCacheSetupCustomRevisionForTree(PKFSCACHE pCache, PKFSOBJ pRoot); KBOOL kFsCacheInvalidateDeletedDirectoryA(PKFSCACHE pCache, const char *pszDir); #endif kbuild-3149/src/lib/nt/ntdir.c0000644000175000017500000005330013252530204016143 0ustar locutuslocutus/* $Id: ntdir.c 3007 2016-11-06 16:46:43Z bird $ */ /** @file * MSC + NT opendir, readdir, telldir, seekdir, and closedir. */ /* * Copyright (c) 2005-2016 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #include #include "ntstuff.h" #include "nthlp.h" #include "ntdir.h" /** * Implements opendir. */ BirdDir_T *birdDirOpen(const char *pszPath) { HANDLE hDir = birdOpenFile(pszPath, FILE_READ_DATA | SYNCHRONIZE, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, OBJ_CASE_INSENSITIVE); if (hDir != INVALID_HANDLE_VALUE) { BirdDir_T *pDir = birdDirOpenFromHandle((void *)hDir, NULL, BIRDDIR_F_CLOSE_HANDLE); if (pDir) return pDir; birdCloseFile(hDir); } return NULL; } /** * Alternative opendir, with extra stat() info returned by readdir(). */ BirdDir_T *birdDirOpenExtraInfo(const char *pszPath) { HANDLE hDir = birdOpenFile(pszPath, FILE_READ_DATA | SYNCHRONIZE, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, OBJ_CASE_INSENSITIVE); if (hDir != INVALID_HANDLE_VALUE) { BirdDir_T *pDir = birdDirOpenFromHandle((void *)hDir, NULL, BIRDDIR_F_CLOSE_HANDLE | BIRDDIR_F_EXTRA_INFO); if (pDir) return pDir; birdCloseFile(hDir); } return NULL; } BirdDir_T *birdDirOpenExW(void *hRoot, const wchar_t *pwszPath, const wchar_t *pwszFilter, unsigned fFlags) { HANDLE hDir = birdOpenFileExW((HANDLE)hRoot, pwszPath, FILE_READ_DATA | SYNCHRONIZE, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, OBJ_CASE_INSENSITIVE); if (hDir != INVALID_HANDLE_VALUE) { BirdDir_T *pDir = birdDirOpenFromHandle((void *)hDir, pwszFilter, fFlags | BIRDDIR_F_CLOSE_HANDLE); if (pDir) return pDir; birdCloseFile(hDir); } return NULL; } /** * Internal worker for birdStatModTimeOnly. */ BirdDir_T *birdDirOpenFromHandle(void *pvHandle, const void *pvReserved, unsigned fFlags) { if (!pvReserved && !(fFlags & BIRDDIR_F_STATIC_ALLOC)) { /* * Allocate and initialize the directory enum handle. */ BirdDir_T *pDir = (BirdDir_T *)birdMemAlloc(sizeof(*pDir)); if (pDir) { pDir->uMagic = BIRD_DIR_MAGIC; pDir->fFlags = fFlags; pDir->pvHandle = pvHandle; pDir->uDev = 0; pDir->offPos = 0; pDir->fHaveData = 0; pDir->fFirst = 1; pDir->iInfoClass = fFlags & BIRDDIR_F_EXTRA_INFO ? MyFileIdFullDirectoryInformation : MyFileNamesInformation; pDir->offBuf = 0; pDir->cbBuf = 0; pDir->pabBuf = NULL; return pDir; } } else { assert(!(fFlags & BIRDDIR_F_STATIC_ALLOC)); assert(pvReserved == NULL); } birdSetErrnoToInvalidArg(); return NULL; } /** * Special API that takes a preallocated BirdDir_T and can be called again * without involving birdDirClose. * * */ BirdDir_T *birdDirOpenFromHandleWithReuse(BirdDir_T *pDir, void *pvHandle, const void *pvReserved, unsigned fFlags) { if (!pvReserved) { /* * Allocate and initialize the directory enum handle. */ if (pDir) { if (pDir->uMagic == BIRD_DIR_MAGIC) { if ( (pDir->fFlags & BIRDDIR_F_CLOSE_HANDLE) && pDir->pvHandle != INVALID_HANDLE_VALUE) birdCloseFile((HANDLE)pDir->pvHandle); } else { pDir->cbBuf = 0; pDir->pabBuf = NULL; pDir->uMagic = BIRD_DIR_MAGIC; } pDir->pvHandle = pvHandle; pDir->fFlags = fFlags; pDir->uDev = 0; pDir->offPos = 0; pDir->fHaveData = 0; pDir->fFirst = 1; pDir->iInfoClass = fFlags & BIRDDIR_F_EXTRA_INFO ? MyFileIdFullDirectoryInformation : MyFileNamesInformation; pDir->offBuf = 0; return pDir; } } else assert(pvReserved == NULL); birdSetErrnoToInvalidArg(); return NULL; } static int birdDirReadMore(BirdDir_T *pDir) { MY_NTSTATUS rcNt; MY_IO_STATUS_BLOCK Ios; int fFirst; /* * Retrieve the volume serial number + creation time and create the * device number the first time around. Also allocate a buffer. */ fFirst = pDir->fFirst; if (fFirst) { union { MY_FILE_FS_VOLUME_INFORMATION VolInfo; unsigned char abBuf[1024]; } uBuf; Ios.Information = 0; Ios.u.Status = -1; rcNt = g_pfnNtQueryVolumeInformationFile((HANDLE)pDir->pvHandle, &Ios, &uBuf, sizeof(uBuf), MyFileFsVolumeInformation); if (MY_NT_SUCCESS(rcNt)) rcNt = Ios.u.Status; if (MY_NT_SUCCESS(rcNt)) pDir->uDev = uBuf.VolInfo.VolumeSerialNumber | (uBuf.VolInfo.VolumeCreationTime.QuadPart << 32); else pDir->uDev = 0; if (!pDir->pabBuf) { /* * Allocate a buffer. * * Better not exceed 64KB or CIFS may throw a fit. Also, on win10/64 * here there is a noticable speedup when going one byte below 64KB. */ pDir->cbBuf = 0xffe0; pDir->pabBuf = birdMemAlloc(pDir->cbBuf); if (!pDir->pabBuf) return birdSetErrnoToNoMem(); } pDir->fFirst = 0; } /* * Read another buffer full. */ Ios.Information = 0; Ios.u.Status = -1; rcNt = g_pfnNtQueryDirectoryFile((HANDLE)pDir->pvHandle, NULL, /* hEvent */ NULL, /* pfnApcComplete */ NULL, /* pvApcCompleteCtx */ &Ios, pDir->pabBuf, pDir->cbBuf, (MY_FILE_INFORMATION_CLASS)pDir->iInfoClass, FALSE, /* fReturnSingleEntry */ NULL, /* Filter / restart pos. */ pDir->fFlags & BIRDDIR_F_RESTART_SCAN ? TRUE : FALSE); /* fRestartScan */ if (!MY_NT_SUCCESS(rcNt)) { int rc; if (rcNt == MY_STATUS_NO_MORE_FILES) rc = 0; else rc = birdSetErrnoFromNt(rcNt); pDir->fHaveData = 0; pDir->offBuf = pDir->cbBuf; return rc; } pDir->offBuf = 0; pDir->fHaveData = 1; pDir->fFlags &= ~BIRDDIR_F_RESTART_SCAN; return 0; } static int birdDirCopyNameToEntry(WCHAR const *pwcName, ULONG cbName, BirdDirEntry_T *pEntry) { int cchOut = WideCharToMultiByte(CP_ACP, 0, pwcName, cbName / sizeof(WCHAR), pEntry->d_name, sizeof(pEntry->d_name) - 1, NULL, NULL); if (cchOut > 0) { pEntry->d_name[cchOut] = '\0'; pEntry->d_namlen = (unsigned __int16)cchOut; pEntry->d_reclen = (unsigned __int16)((size_t)&pEntry->d_name[cchOut + 1] - (size_t)pEntry); return 0; } return -1; } /** * Deals with mount points. * * @param pDir The directory handle. * @param pInfo The NT entry information. * @param pEntryStat The stats for the mount point directory that needs * updating (a d_stat member). */ static void birdDirUpdateMountPointInfo(BirdDir_T *pDir, MY_FILE_ID_FULL_DIR_INFORMATION *pInfo, BirdStat_T *pEntryStat) { /* * Try open the root directory of the mount. * (Can't use birdStatAtW here because the name isn't terminated.) */ HANDLE hRoot = INVALID_HANDLE_VALUE; MY_NTSTATUS rcNt; MY_UNICODE_STRING Name; Name.Buffer = pInfo->FileName; Name.Length = Name.MaximumLength = (USHORT)pInfo->FileNameLength; rcNt = birdOpenFileUniStr((HANDLE)pDir->pvHandle, &Name, FILE_READ_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_OPEN_FOR_BACKUP_INTENT, OBJ_CASE_INSENSITIVE, &hRoot); if (MY_NT_SUCCESS(rcNt)) { int iSavedErrno = errno; BirdStat_T RootStat; if (birdStatHandle(hRoot, &RootStat, NULL) == 0) { RootStat.st_ismountpoint = 2; *pEntryStat = RootStat; } birdCloseFile(hRoot); errno = iSavedErrno; } /* else: don't mind failures, we've got some info. */ } /** * Implements readdir_r(). * * @remarks birdDirReadReentrantW is a copy of this. Keep them in sync! */ int birdDirReadReentrant(BirdDir_T *pDir, BirdDirEntry_T *pEntry, BirdDirEntry_T **ppResult) { int fSkipEntry; *ppResult = NULL; if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC) return birdSetErrnoToBadFileNo(); do { ULONG offNext; ULONG cbMinCur; /* * Read more? */ if (!pDir->fHaveData) { if (birdDirReadMore(pDir) != 0) return -1; if (!pDir->fHaveData) return 0; } /* * Convert the NT data to the unixy output structure. */ fSkipEntry = 0; switch (pDir->iInfoClass) { case MyFileNamesInformation: { MY_FILE_NAMES_INFORMATION *pInfo = (MY_FILE_NAMES_INFORMATION *)&pDir->pabBuf[pDir->offBuf]; if ( pDir->offBuf >= pDir->cbBuf - MIN_SIZEOF_MY_FILE_NAMES_INFORMATION || pInfo->FileNameLength >= pDir->cbBuf || pDir->offBuf + pInfo->FileNameLength + MIN_SIZEOF_MY_FILE_NAMES_INFORMATION > pDir->cbBuf) { fSkipEntry = 1; pDir->fHaveData = 0; continue; } memset(&pEntry->d_stat, 0, sizeof(pEntry->d_stat)); pEntry->d_stat.st_mode = S_IFMT; pEntry->d_type = DT_UNKNOWN; pEntry->d_reclen = 0; pEntry->d_namlen = 0; if (birdDirCopyNameToEntry(pInfo->FileName, pInfo->FileNameLength, pEntry) != 0) fSkipEntry = 1; cbMinCur = MIN_SIZEOF_MY_FILE_NAMES_INFORMATION + pInfo->FileNameLength; offNext = pInfo->NextEntryOffset; break; } case MyFileIdFullDirectoryInformation: { MY_FILE_ID_FULL_DIR_INFORMATION *pInfo = (MY_FILE_ID_FULL_DIR_INFORMATION *)&pDir->pabBuf[pDir->offBuf]; if ( pDir->offBuf >= pDir->cbBuf - MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION || pInfo->FileNameLength >= pDir->cbBuf || pDir->offBuf + pInfo->FileNameLength + MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION > pDir->cbBuf) { fSkipEntry = 1; pDir->fHaveData = 0; continue; } pEntry->d_type = DT_UNKNOWN; pEntry->d_reclen = 0; pEntry->d_namlen = 0; if (birdDirCopyNameToEntry(pInfo->FileName, pInfo->FileNameLength, pEntry) != 0) fSkipEntry = 1; birdStatFillFromFileIdFullDirInfo(&pEntry->d_stat, pInfo); pEntry->d_stat.st_dev = pDir->uDev; switch (pEntry->d_stat.st_mode & S_IFMT) { case S_IFREG: pEntry->d_type = DT_REG; break; case S_IFDIR: pEntry->d_type = DT_DIR; break; case S_IFLNK: pEntry->d_type = DT_LNK; break; case S_IFIFO: pEntry->d_type = DT_FIFO; break; case S_IFCHR: pEntry->d_type = DT_CHR; break; default: #ifndef NDEBUG __debugbreak(); #endif pEntry->d_type = DT_UNKNOWN; break; } if (pEntry->d_stat.st_ismountpoint != 1) { /* likely. */ } else birdDirUpdateMountPointInfo(pDir, pInfo, &pEntry->d_stat); cbMinCur = MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION + pInfo->FileNameLength; offNext = pInfo->NextEntryOffset; break; } default: return birdSetErrnoToBadFileNo(); } /* * Advance. */ if ( offNext >= cbMinCur && offNext < pDir->cbBuf) pDir->offBuf += offNext; else { pDir->fHaveData = 0; pDir->offBuf = pDir->cbBuf; } pDir->offPos++; } while (fSkipEntry); /* * Successful return. */ *ppResult = pEntry; return 0; } /** * Implements readdir(). */ BirdDirEntry_T *birdDirRead(BirdDir_T *pDir) { BirdDirEntry_T *pRet = NULL; birdDirReadReentrant(pDir, &pDir->u.DirEntry, &pRet); return pRet; } static int birdDirCopyNameToEntryW(WCHAR const *pwcName, ULONG cbName, BirdDirEntryW_T *pEntry) { ULONG cwcName = cbName / sizeof(wchar_t); if (cwcName < sizeof(pEntry->d_name)) { memcpy(pEntry->d_name, pwcName, cbName); pEntry->d_name[cwcName] = '\0'; pEntry->d_namlen = (unsigned __int16)cwcName; pEntry->d_reclen = (unsigned __int16)((size_t)&pEntry->d_name[cwcName + 1] - (size_t)pEntry); return 0; } return -1; } /** * Implements readdir_r(), UTF-16 version. * * @remarks This is a copy of birdDirReadReentrant where only the name handling * and entry type differs. Remember to keep them in sync! */ int birdDirReadReentrantW(BirdDir_T *pDir, BirdDirEntryW_T *pEntry, BirdDirEntryW_T **ppResult) { int fSkipEntry; *ppResult = NULL; if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC) return birdSetErrnoToBadFileNo(); do { ULONG offNext; ULONG cbMinCur; /* * Read more? */ if (!pDir->fHaveData) { if (birdDirReadMore(pDir) != 0) return -1; if (!pDir->fHaveData) return 0; } /* * Convert the NT data to the unixy output structure. */ fSkipEntry = 0; switch (pDir->iInfoClass) { case MyFileNamesInformation: { MY_FILE_NAMES_INFORMATION *pInfo = (MY_FILE_NAMES_INFORMATION *)&pDir->pabBuf[pDir->offBuf]; if ( pDir->offBuf >= pDir->cbBuf - MIN_SIZEOF_MY_FILE_NAMES_INFORMATION || pInfo->FileNameLength >= pDir->cbBuf || pDir->offBuf + pInfo->FileNameLength + MIN_SIZEOF_MY_FILE_NAMES_INFORMATION > pDir->cbBuf) { fSkipEntry = 1; pDir->fHaveData = 0; continue; } memset(&pEntry->d_stat, 0, sizeof(pEntry->d_stat)); pEntry->d_stat.st_mode = S_IFMT; pEntry->d_type = DT_UNKNOWN; pEntry->d_reclen = 0; pEntry->d_namlen = 0; if (birdDirCopyNameToEntryW(pInfo->FileName, pInfo->FileNameLength, pEntry) != 0) fSkipEntry = 1; cbMinCur = MIN_SIZEOF_MY_FILE_NAMES_INFORMATION + pInfo->FileNameLength; offNext = pInfo->NextEntryOffset; break; } case MyFileIdFullDirectoryInformation: { MY_FILE_ID_FULL_DIR_INFORMATION *pInfo = (MY_FILE_ID_FULL_DIR_INFORMATION *)&pDir->pabBuf[pDir->offBuf]; if ( pDir->offBuf >= pDir->cbBuf - MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION || pInfo->FileNameLength >= pDir->cbBuf || pDir->offBuf + pInfo->FileNameLength + MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION > pDir->cbBuf) { fSkipEntry = 1; pDir->fHaveData = 0; continue; } pEntry->d_type = DT_UNKNOWN; pEntry->d_reclen = 0; pEntry->d_namlen = 0; if (birdDirCopyNameToEntryW(pInfo->FileName, pInfo->FileNameLength, pEntry) != 0) fSkipEntry = 1; birdStatFillFromFileIdFullDirInfo(&pEntry->d_stat, pInfo); pEntry->d_stat.st_dev = pDir->uDev; switch (pEntry->d_stat.st_mode & S_IFMT) { case S_IFREG: pEntry->d_type = DT_REG; break; case S_IFDIR: pEntry->d_type = DT_DIR; break; case S_IFLNK: pEntry->d_type = DT_LNK; break; case S_IFIFO: pEntry->d_type = DT_FIFO; break; case S_IFCHR: pEntry->d_type = DT_CHR; break; default: #ifndef NDEBUG __debugbreak(); #endif pEntry->d_type = DT_UNKNOWN; break; } if (pEntry->d_stat.st_ismountpoint != 1) { /* likely. */ } else birdDirUpdateMountPointInfo(pDir, pInfo, &pEntry->d_stat); cbMinCur = MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION + pInfo->FileNameLength; offNext = pInfo->NextEntryOffset; break; } default: return birdSetErrnoToBadFileNo(); } /* * Advance. */ if ( offNext >= cbMinCur && offNext < pDir->cbBuf) pDir->offBuf += offNext; else { pDir->fHaveData = 0; pDir->offBuf = pDir->cbBuf; } pDir->offPos++; } while (fSkipEntry); /* * Successful return. */ *ppResult = pEntry; return 0; } /** * Implements readdir(). */ BirdDirEntryW_T *birdDirReadW(BirdDir_T *pDir) { BirdDirEntryW_T *pRet = NULL; birdDirReadReentrantW(pDir, &pDir->u.DirEntryW, &pRet); return pRet; } /** * Implements telldir(). */ long birdDirTell(BirdDir_T *pDir) { if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC) return birdSetErrnoToBadFileNo(); return pDir->offPos; } void birdDirSeek(BirdDir_T *pDir, long offDir); /** * Implements closedir(). */ int birdDirClose(BirdDir_T *pDir) { if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC) return birdSetErrnoToBadFileNo(); pDir->uMagic++; if (pDir->fFlags & BIRDDIR_F_CLOSE_HANDLE) birdCloseFile((HANDLE)pDir->pvHandle); pDir->pvHandle = (void *)INVALID_HANDLE_VALUE; birdMemFree(pDir->pabBuf); pDir->pabBuf = NULL; if (!(pDir->fFlags & BIRDDIR_F_STATIC_ALLOC)) birdMemFree(pDir); return 0; } kbuild-3149/src/lib/nt/nthlpcore.c0000644000175000017500000004552113252530204017027 0ustar locutuslocutus/* $Id: nthlpcore.c 2998 2016-11-05 19:37:35Z bird $ */ /** @file * MSC + NT core helpers functions and globals. */ /* * Copyright (c) 2005-2013 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include "nthlp.h" #ifndef NDEBUG # include #endif /******************************************************************************* * Global Variables * *******************************************************************************/ MY_NTSTATUS (WINAPI *g_pfnNtClose)(HANDLE); MY_NTSTATUS (WINAPI *g_pfnNtCreateFile)(PHANDLE, MY_ACCESS_MASK, MY_OBJECT_ATTRIBUTES *, MY_IO_STATUS_BLOCK *, PLARGE_INTEGER, ULONG, ULONG, ULONG, ULONG, PVOID, ULONG); MY_NTSTATUS (WINAPI *g_pfnNtDeleteFile)(MY_OBJECT_ATTRIBUTES *); MY_NTSTATUS (WINAPI *g_pfnNtDuplicateObject)(HANDLE hSrcProc, HANDLE hSrc, HANDLE hDstProc, HANDLE *phRet, MY_ACCESS_MASK fDesiredAccess, ULONG fAttribs, ULONG fOptions); MY_NTSTATUS (WINAPI *g_pfnNtReadFile)(HANDLE hFile, HANDLE hEvent, MY_IO_APC_ROUTINE *pfnApc, PVOID pvApcCtx, MY_IO_STATUS_BLOCK *, PVOID pvBuf, ULONG cbToRead, PLARGE_INTEGER poffFile, PULONG puKey); MY_NTSTATUS (WINAPI *g_pfnNtQueryInformationFile)(HANDLE, MY_IO_STATUS_BLOCK *, PVOID, LONG, MY_FILE_INFORMATION_CLASS); MY_NTSTATUS (WINAPI *g_pfnNtQueryVolumeInformationFile)(HANDLE, MY_IO_STATUS_BLOCK *, PVOID, LONG, MY_FS_INFORMATION_CLASS); MY_NTSTATUS (WINAPI *g_pfnNtQueryDirectoryFile)(HANDLE, HANDLE, MY_IO_APC_ROUTINE *, PVOID, MY_IO_STATUS_BLOCK *, PVOID, ULONG, MY_FILE_INFORMATION_CLASS, BOOLEAN, MY_UNICODE_STRING *, BOOLEAN); MY_NTSTATUS (WINAPI *g_pfnNtQueryAttributesFile)(MY_OBJECT_ATTRIBUTES *, MY_FILE_BASIC_INFORMATION *); MY_NTSTATUS (WINAPI *g_pfnNtQueryFullAttributesFile)(MY_OBJECT_ATTRIBUTES *, MY_FILE_NETWORK_OPEN_INFORMATION *); MY_NTSTATUS (WINAPI *g_pfnNtSetInformationFile)(HANDLE, MY_IO_STATUS_BLOCK *, PVOID, LONG, MY_FILE_INFORMATION_CLASS); BOOLEAN (WINAPI *g_pfnRtlDosPathNameToNtPathName_U)(PCWSTR, MY_UNICODE_STRING *, PCWSTR *, MY_RTL_RELATIVE_NAME_U *); MY_NTSTATUS (WINAPI *g_pfnRtlAnsiStringToUnicodeString)(MY_UNICODE_STRING *, MY_ANSI_STRING const *, BOOLEAN); MY_NTSTATUS (WINAPI *g_pfnRtlUnicodeStringToAnsiString)(MY_ANSI_STRING *, MY_UNICODE_STRING *, BOOLEAN); BOOLEAN (WINAPI *g_pfnRtlEqualUnicodeString)(MY_UNICODE_STRING const *, MY_UNICODE_STRING const *, BOOLEAN); BOOLEAN (WINAPI *g_pfnRtlEqualString)(MY_ANSI_STRING const *, MY_ANSI_STRING const *, BOOLEAN); UCHAR (WINAPI *g_pfnRtlUpperChar)(UCHAR uch); ULONG (WINAPI *g_pfnRtlNtStatusToDosError)(MY_NTSTATUS rcNt); VOID (WINAPI *g_pfnRtlAcquirePebLock)(VOID); VOID (WINAPI *g_pfnRtlReleasePebLock)(VOID); static struct { FARPROC *ppfn; const char *pszName; } const g_apfnDynamicNtdll[] = { { (FARPROC *)&g_pfnNtClose, "NtClose" }, { (FARPROC *)&g_pfnNtCreateFile, "NtCreateFile" }, { (FARPROC *)&g_pfnNtDeleteFile, "NtDeleteFile" }, { (FARPROC *)&g_pfnNtDuplicateObject, "NtDuplicateObject" }, { (FARPROC *)&g_pfnNtReadFile, "NtReadFile" }, { (FARPROC *)&g_pfnNtQueryInformationFile, "NtQueryInformationFile" }, { (FARPROC *)&g_pfnNtQueryVolumeInformationFile, "NtQueryVolumeInformationFile" }, { (FARPROC *)&g_pfnNtQueryDirectoryFile, "NtQueryDirectoryFile" }, { (FARPROC *)&g_pfnNtQueryAttributesFile, "NtQueryAttributesFile" }, { (FARPROC *)&g_pfnNtQueryFullAttributesFile, "NtQueryFullAttributesFile" }, { (FARPROC *)&g_pfnNtSetInformationFile, "NtSetInformationFile" }, { (FARPROC *)&g_pfnRtlDosPathNameToNtPathName_U, "RtlDosPathNameToNtPathName_U" }, { (FARPROC *)&g_pfnRtlAnsiStringToUnicodeString, "RtlAnsiStringToUnicodeString" }, { (FARPROC *)&g_pfnRtlUnicodeStringToAnsiString, "RtlUnicodeStringToAnsiString" }, { (FARPROC *)&g_pfnRtlEqualUnicodeString, "RtlEqualUnicodeString" }, { (FARPROC *)&g_pfnRtlEqualString, "RtlEqualString" }, { (FARPROC *)&g_pfnRtlUpperChar, "RtlUpperChar" }, { (FARPROC *)&g_pfnRtlNtStatusToDosError, "RtlNtStatusToDosError" }, { (FARPROC *)&g_pfnRtlAcquirePebLock, "RtlAcquirePebLock" }, { (FARPROC *)&g_pfnRtlReleasePebLock, "RtlReleasePebLock" }, }; /** Set to 1 if we've successfully resolved the imports, otherwise 0. */ int g_fResolvedNtImports = 0; void birdResolveImportsWorker(void) { HMODULE hMod = LoadLibraryW(L"ntdll.dll"); int i = sizeof(g_apfnDynamicNtdll) / sizeof(g_apfnDynamicNtdll[0]); while (i-- > 0) { const char *pszSym = g_apfnDynamicNtdll[i].pszName; FARPROC pfn; *g_apfnDynamicNtdll[i].ppfn = pfn = GetProcAddress(hMod, pszSym); if (!pfn) { /* Write short message and die. */ static const char s_szMsg[] = "\r\nFatal error resolving NTDLL.DLL symbols!\r\nSymbol: "; DWORD cbWritten; if ( !WriteFile(GetStdHandle(STD_ERROR_HANDLE), s_szMsg, sizeof(s_szMsg) - 1, &cbWritten, NULL) || !WriteFile(GetStdHandle(STD_ERROR_HANDLE), pszSym, (DWORD)strlen(pszSym), &cbWritten, NULL) || !WriteFile(GetStdHandle(STD_ERROR_HANDLE), "\r\n", sizeof("\r\n") - 1, &cbWritten, NULL) ) *(void **)i = NULL; ExitProcess(127); } } g_fResolvedNtImports = 1; } void *birdTmpAlloc(size_t cb) { return malloc(cb); } void birdTmpFree(void *pv) { if (pv) free(pv); } void *birdMemAlloc(size_t cb) { return malloc(cb); } void *birdMemAllocZ(size_t cb) { return calloc(cb, 1); } void birdMemFree(void *pv) { if (pv) free(pv); } int birdErrnoFromNtStatus(MY_NTSTATUS rcNt) { switch (rcNt) { /* EPERM = 1 */ case STATUS_CANNOT_DELETE: return EPERM; /* ENOENT = 2 */ case STATUS_NOT_FOUND: case STATUS_OBJECT_NAME_NOT_FOUND: case STATUS_OBJECT_PATH_NOT_FOUND: case STATUS_OBJECT_NAME_INVALID: case STATUS_INVALID_COMPUTER_NAME: case STATUS_VARIABLE_NOT_FOUND: case STATUS_MESSAGE_NOT_FOUND: case STATUS_DLL_NOT_FOUND: case STATUS_ORDINAL_NOT_FOUND: case STATUS_ENTRYPOINT_NOT_FOUND: case STATUS_PATH_NOT_COVERED: case STATUS_BAD_NETWORK_PATH: case STATUS_DFS_EXIT_PATH_FOUND: case RPC_NT_OBJECT_NOT_FOUND: case STATUS_DELETE_PENDING: return ENOENT; /* ESRCH = 3 */ case STATUS_PROCESS_NOT_IN_JOB: return ESRCH; /* EINTR = 4 */ case STATUS_ALERTED: case STATUS_USER_APC: return EINTR; /* EIO = 5 */ /* ENXIO = 6 */ /* E2BIG = 7 */ /* ENOEXEC = 8 */ case STATUS_INVALID_IMAGE_FORMAT: case STATUS_INVALID_IMAGE_NE_FORMAT: case STATUS_INVALID_IMAGE_LE_FORMAT: case STATUS_INVALID_IMAGE_NOT_MZ: case STATUS_INVALID_IMAGE_PROTECT: case STATUS_INVALID_IMAGE_WIN_16: case STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT: case STATUS_IMAGE_CHECKSUM_MISMATCH: case STATUS_IMAGE_MP_UP_MISMATCH: case STATUS_IMAGE_MACHINE_TYPE_MISMATCH: case STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE: case STATUS_SYSTEM_IMAGE_BAD_SIGNATURE: case STATUS_SECTION_NOT_IMAGE: case STATUS_INVALID_IMAGE_WIN_32: case STATUS_INVALID_IMAGE_WIN_64: case STATUS_INVALID_IMAGE_HASH: case STATUS_IMAGE_CERT_REVOKED: return ENOEXEC; /* EBADF = 9 */ case STATUS_INVALID_HANDLE: case STATUS_PORT_CLOSED: case STATUS_OPLOCK_HANDLE_CLOSED: case STATUS_HANDLES_CLOSED: case STATUS_FILE_FORCED_CLOSED: return EBADF; /* ECHILD = 10 */ /* EAGAIN = 11 */ case STATUS_WMI_TRY_AGAIN: case STATUS_GRAPHICS_TRY_AGAIN_LATER: case STATUS_GRAPHICS_TRY_AGAIN_NOW: return EAGAIN; /* ENOMEM = 12 */ case STATUS_NO_MEMORY: case STATUS_HV_INSUFFICIENT_MEMORY: case STATUS_INSUFFICIENT_RESOURCES: case STATUS_REMOTE_RESOURCES: case STATUS_INSUFF_SERVER_RESOURCES: return ENOMEM; /* EACCES = 13 */ case STATUS_ACCESS_DENIED: case STATUS_NETWORK_ACCESS_DENIED: case RPC_NT_PROXY_ACCESS_DENIED: case STATUS_CTX_SHADOW_DENIED: case STATUS_CTX_WINSTATION_ACCESS_DENIED: return EACCES; /* EFAULT = 14 */ case STATUS_ACCESS_VIOLATION: case STATUS_HARDWARE_MEMORY_ERROR: return EFAULT; /* EBUSY = 16 */ case STATUS_PIPE_BUSY: case STATUS_RESOURCE_IN_USE: return EBUSY; /* EEXIST = 17 */ case STATUS_OBJECT_NAME_EXISTS: case STATUS_OBJECT_NAME_COLLISION: case STATUS_DUPLICATE_NAME: return EEXIST; /* EXDEV = 18 */ case STATUS_NOT_SAME_DEVICE: return EXDEV; /* ENODEV = 19 */ /* ENOTDIR = 20 */ case STATUS_NOT_A_DIRECTORY: case STATUS_DIRECTORY_IS_A_REPARSE_POINT: case STATUS_OBJECT_PATH_SYNTAX_BAD: case STATUS_OBJECT_PATH_INVALID: case STATUS_OBJECT_TYPE_MISMATCH: return ENOTDIR; /* EISDIR = 21 */ case STATUS_FILE_IS_A_DIRECTORY: return EISDIR; /* EINVAL = 22 */ case STATUS_INVALID_PARAMETER: case STATUS_INVALID_PARAMETER_1: case STATUS_INVALID_PARAMETER_2: case STATUS_INVALID_PARAMETER_3: case STATUS_INVALID_PARAMETER_4: case STATUS_INVALID_PARAMETER_5: case STATUS_INVALID_PARAMETER_6: case STATUS_INVALID_PARAMETER_7: case STATUS_INVALID_PARAMETER_8: case STATUS_INVALID_PARAMETER_9: case STATUS_INVALID_PARAMETER_10: case STATUS_INVALID_PARAMETER_11: case STATUS_INVALID_PARAMETER_12: case STATUS_INVALID_PARAMETER_MIX: return EINVAL; /* ENFILE = 23 */ /* EMFILE = 24 */ case STATUS_TOO_MANY_OPENED_FILES: return EMFILE; /* ENOTTY = 25 */ /* EFBIG = 27 */ /* ENOSPC = 28 */ case STATUS_DISK_FULL: return ENOSPC; /* ESPIPE = 29 */ /* EROFS = 30 */ /* EMLINK = 31 */ /* EPIPE = 32 */ case STATUS_PIPE_BROKEN: case RPC_NT_PIPE_CLOSED: return EPIPE; /* EDOM = 33 */ /* ERANGE = 34 */ /* EDEADLK = 36 */ case STATUS_POSSIBLE_DEADLOCK: return EDEADLK; /* ENAMETOOLONG = 38 */ case STATUS_NAME_TOO_LONG: return ENAMETOOLONG; /* ENOLCK = 39 */ /* ENOSYS = 40 */ case STATUS_NOT_SUPPORTED: return ENOSYS; /* ENOTEMPTY = 41 */ case STATUS_DIRECTORY_NOT_EMPTY: return ENOTEMPTY; /* EILSEQ = 42 */ /* EADDRINUSE = 100 */ /* EADDRNOTAVAIL = 101 */ /* EAFNOSUPPORT = 102 */ /* EALREADY = 103 */ case STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED: case STATUS_DEVICE_ALREADY_ATTACHED: case STATUS_PORT_ALREADY_SET: case STATUS_IMAGE_ALREADY_LOADED: case STATUS_TOKEN_ALREADY_IN_USE: case STATUS_IMAGE_ALREADY_LOADED_AS_DLL: case STATUS_ADDRESS_ALREADY_EXISTS: case STATUS_ADDRESS_ALREADY_ASSOCIATED: return EALREADY; /* EBADMSG = 104 */ /* ECANCELED = 105 */ /* ECONNABORTED = 106 */ /* ECONNREFUSED = 107 */ /* ECONNRESET = 108 */ /* EDESTADDRREQ = 109 */ /* EHOSTUNREACH = 110 */ case STATUS_HOST_UNREACHABLE: return EHOSTUNREACH; /* EIDRM = 111 */ /* EINPROGRESS = 112 */ /* EISCONN = 113 */ /* ELOOP = 114 */ /* EMSGSIZE = 115 */ /* ENETDOWN = 116 */ /* ENETRESET = 117 */ /* ENETUNREACH = 118 */ case STATUS_NETWORK_UNREACHABLE: return ENETUNREACH; /* ENOBUFS = 119 */ /* ENODATA = 120 */ /* ENOLINK = 121 */ /* ENOMSG = 122 */ /* ENOPROTOOPT = 123 */ /* ENOSR = 124 */ /* ENOSTR = 125 */ /* ENOTCONN = 126 */ /* ENOTRECOVERABLE = 127 */ /* ENOTSOCK = 128 */ /* ENOTSUP = 129 */ /* EOPNOTSUPP = 130 */ /* EOTHER = 131 */ /* EOVERFLOW = 132 */ /* EOWNERDEAD = 133 */ /* EPROTO = 134 */ /* EPROTONOSUPPORT = 135 */ /* EPROTOTYPE = 136 */ /* ETIME = 137 */ /* ETIMEDOUT = 138 */ case STATUS_VIRTUAL_CIRCUIT_CLOSED: case STATUS_TIMEOUT: return ETIMEDOUT; /* ETXTBSY = 139 */ case STATUS_SHARING_VIOLATION: return ETXTBSY; /* EWOULDBLOCK = 140 */ } #ifndef NDEBUG __debugbreak(); fprintf(stderr, "rcNt=%#x (%d)\n", rcNt, rcNt); #endif return EINVAL; } int birdSetErrnoFromNt(MY_NTSTATUS rcNt) { errno = birdErrnoFromNtStatus(rcNt); #if 0 { ULONG rcWin32; _doserrno = rcWin32 = g_pfnRtlNtStatusToDosError(rcNt); SetLastError(rcWin32); } #endif return -1; } int birdSetErrnoFromWin32(DWORD dwErr) { switch (dwErr) { default: case ERROR_INVALID_FUNCTION: errno = EINVAL; break; case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; case ERROR_TOO_MANY_OPEN_FILES: errno = EMFILE; break; case ERROR_ACCESS_DENIED: errno = EACCES; break; case ERROR_INVALID_HANDLE: errno = EBADF; break; case ERROR_ARENA_TRASHED: errno = ENOMEM; break; case ERROR_NOT_ENOUGH_MEMORY: errno = ENOMEM; break; case ERROR_INVALID_BLOCK: errno = ENOMEM; break; case ERROR_BAD_ENVIRONMENT: errno = E2BIG; break; case ERROR_BAD_FORMAT: errno = ENOEXEC; break; case ERROR_INVALID_ACCESS: errno = EINVAL; break; case ERROR_INVALID_DATA: errno = EINVAL; break; case ERROR_INVALID_DRIVE: errno = ENOENT; break; case ERROR_CURRENT_DIRECTORY: errno = EACCES; break; case ERROR_NOT_SAME_DEVICE: errno = EXDEV; break; case ERROR_NO_MORE_FILES: errno = ENOENT; break; case ERROR_LOCK_VIOLATION: errno = EACCES; break; case ERROR_BAD_NETPATH: errno = ENOENT; break; case ERROR_NETWORK_ACCESS_DENIED: errno = EACCES; break; case ERROR_BAD_NET_NAME: errno = ENOENT; break; case ERROR_FILE_EXISTS: errno = EEXIST; break; case ERROR_CANNOT_MAKE: errno = EACCES; break; case ERROR_FAIL_I24: errno = EACCES; break; case ERROR_INVALID_PARAMETER: errno = EINVAL; break; case ERROR_NO_PROC_SLOTS: errno = EAGAIN; break; case ERROR_DRIVE_LOCKED: errno = EACCES; break; case ERROR_BROKEN_PIPE: errno = EPIPE; break; case ERROR_DISK_FULL: errno = ENOSPC; break; case ERROR_INVALID_TARGET_HANDLE: errno = EBADF; break; case ERROR_WAIT_NO_CHILDREN: errno = ECHILD; break; case ERROR_CHILD_NOT_COMPLETE: errno = ECHILD; break; case ERROR_DIRECT_ACCESS_HANDLE: errno = EBADF; break; case ERROR_NEGATIVE_SEEK: errno = EINVAL; break; case ERROR_SEEK_ON_DEVICE: errno = EACCES; break; case ERROR_DIR_NOT_EMPTY: errno = ENOTEMPTY; break; case ERROR_NOT_LOCKED: errno = EACCES; break; case ERROR_BAD_PATHNAME: errno = ENOENT; break; case ERROR_MAX_THRDS_REACHED: errno = EAGAIN; break; case ERROR_LOCK_FAILED: errno = EACCES; break; case ERROR_ALREADY_EXISTS: errno = EEXIST; break; case ERROR_FILENAME_EXCED_RANGE: errno = ENOENT; break; case ERROR_NESTING_NOT_ALLOWED: errno = EAGAIN; break; #ifdef EMLINK case ERROR_TOO_MANY_LINKS: errno = EMLINK; break; #endif case ERROR_SHARING_VIOLATION: errno = ETXTBSY; break; } return -1; } int birdSetErrnoToNoMem(void) { errno = ENOMEM; return -1; } int birdSetErrnoToInvalidArg(void) { errno = EINVAL; return -1; } int birdSetErrnoToBadFileNo(void) { errno = EBADF; return -1; } kbuild-3149/src/lib/nt/nthlp.h0000644000175000017500000001173013252530204016156 0ustar locutuslocutus/* $Id: nthlp.h 3060 2017-09-21 15:11:07Z bird $ */ /** @file * MSC + NT helper functions. */ /* * Copyright (c) 2005-2013 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___nt_nthlp_h #define ___nt_nthlp_h #include "ntstuff.h" #include "nttypes.h" /** Lazy resolving of the NTDLL imports. */ #define birdResolveImports() do { if (g_fResolvedNtImports) {} else birdResolveImportsWorker(); } while (0) void birdResolveImportsWorker(void); extern int g_fResolvedNtImports; void *birdTmpAlloc(size_t cb); void birdTmpFree(void *pv); void *birdMemAlloc(size_t cb); void *birdMemAllocZ(size_t cb); void birdMemFree(void *pv); int birdSetErrnoFromNt(MY_NTSTATUS rcNt); int birdSetErrnoFromWin32(DWORD dwErr); int birdSetErrnoToNoMem(void); int birdSetErrnoToInvalidArg(void); int birdSetErrnoToBadFileNo(void); HANDLE birdOpenFile(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs); HANDLE birdOpenFileW(const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs); HANDLE birdOpenFileEx(HANDLE hRoot, const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs); HANDLE birdOpenFileExW(HANDLE hRoot, const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs); HANDLE birdOpenParentDir(HANDLE hRoot, const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, MY_UNICODE_STRING *pNameUniStr); HANDLE birdOpenParentDirW(HANDLE hRoot, const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, MY_UNICODE_STRING *pNameUniStr); MY_NTSTATUS birdOpenFileUniStr(HANDLE hRoot, MY_UNICODE_STRING *pNtPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, HANDLE *phFile); HANDLE birdOpenCurrentDirectory(void); void birdCloseFile(HANDLE hFile); int birdDosToNtPath(const char *pszPath, MY_UNICODE_STRING *pNtPath); int birdDosToNtPathW(const wchar_t *pwszPath, MY_UNICODE_STRING *pNtPath); int birdDosToRelativeNtPath(const char *pszPath, MY_UNICODE_STRING *pNtPath); int birdDosToRelativeNtPathW(const wchar_t *pszPath, MY_UNICODE_STRING *pNtPath); void birdFreeNtPath(MY_UNICODE_STRING *pNtPath); static __inline void birdNtTimeToTimeSpec(__int64 iNtTime, BirdTimeSpec_T *pTimeSpec) { iNtTime -= BIRD_NT_EPOCH_OFFSET_UNIX_100NS; pTimeSpec->tv_sec = iNtTime / 10000000; pTimeSpec->tv_nsec = (iNtTime % 10000000) * 100; } static __inline void birdNtTimeToTimeVal(__int64 iNtTime, BirdTimeVal_T *pTimeVal) { iNtTime -= BIRD_NT_EPOCH_OFFSET_UNIX_100NS; pTimeVal->tv_sec = iNtTime / 10000000; pTimeVal->tv_usec = (iNtTime % 10000000) / 10; } static __inline __int64 birdNtTimeFromTimeVal(BirdTimeVal_T const *pTimeVal) { __int64 iNtTime = pTimeVal->tv_sec * 10000000; iNtTime += pTimeVal->tv_usec * 10; iNtTime += BIRD_NT_EPOCH_OFFSET_UNIX_100NS; return iNtTime; } #endif kbuild-3149/src/lib/nt/ntutimes.c0000644000175000017500000000721713252530204016701 0ustar locutuslocutus/* $Id: ntutimes.c 3097 2017-10-14 03:52:44Z bird $ */ /** @file * MSC + NT utimes and lutimes */ /* * Copyright (c) 2005-2017 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "ntutimes.h" #include "ntstuff.h" #include "nthlp.h" static int birdUtimesInternal(const char *pszPath, BirdTimeVal_T paTimes[2], int fFollowLink) { HANDLE hFile = birdOpenFileEx(NULL, pszPath, FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_OPEN_FOR_BACKUP_INTENT | (fFollowLink ? 0 : FILE_OPEN_REPARSE_POINT), OBJ_CASE_INSENSITIVE); if (hFile != INVALID_HANDLE_VALUE) { MY_FILE_BASIC_INFORMATION Info; MY_IO_STATUS_BLOCK Ios; MY_NTSTATUS rcNt; memset(&Info, 0, sizeof(Info)); if (paTimes) { Info.LastAccessTime.QuadPart = birdNtTimeFromTimeVal(&paTimes[0]); Info.LastWriteTime.QuadPart = birdNtTimeFromTimeVal(&paTimes[1]); } else { /** @todo replace this with something from ntdll */ FILETIME Now; GetSystemTimeAsFileTime(&Now); Info.LastAccessTime.HighPart = Now.dwHighDateTime; Info.LastAccessTime.LowPart = Now.dwLowDateTime; Info.LastWriteTime.HighPart = Now.dwHighDateTime; Info.LastWriteTime.LowPart = Now.dwLowDateTime; } Ios.Information = -1; Ios.u.Status = -1; rcNt = g_pfnNtSetInformationFile(hFile, &Ios, &Info, sizeof(Info), MyFileBasicInformation); birdCloseFile(hFile); if (MY_NT_SUCCESS(rcNt)) return 0; birdSetErrnoFromNt(rcNt); } return -1; } int birdUtimes(const char *pszFile, BirdTimeVal_T paTimes[2]) { return birdUtimesInternal(pszFile, paTimes, 1 /*fFollowLink*/); } int birdLUtimes(const char *pszFile, BirdTimeVal_T paTimes[2]) { return birdUtimesInternal(pszFile, paTimes, 0 /*fFollowLink*/); } kbuild-3149/src/lib/nt/ntdir.h0000644000175000017500000001234013252530204016147 0ustar locutuslocutus/* $Id: ntdir.h 3005 2016-11-06 00:07:37Z bird $ */ /** @file * MSC + NT opendir, readdir, closedir and friends. */ /* * Copyright (c) 2005-2013 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___nt_ntdir_h #define ___nt_ntdir_h #include "nttypes.h" #include "ntstat.h" typedef struct dirent { /** Optional stat information. * Only provided if using birdDirOpenExtraInfo(). */ BirdStat_T d_stat; /** The record length. */ unsigned __int16 d_reclen; /** The name length. */ unsigned __int16 d_namlen; /** The name type. */ unsigned char d_type; /** The name. */ char d_name[512 - sizeof(BirdStat_T) - 2 - 2 - 1]; } BirdDirEntry_T; typedef struct direntw { /** Optional stat information. * Only provided if using birdDirOpenExtraInfo(). */ BirdStat_T d_stat; /** The record length. */ unsigned __int16 d_reclen; /** The name length (in wchar_t). */ unsigned __int16 d_namlen; /** The name type. */ unsigned char d_type; /** The name. */ wchar_t d_name[512 - sizeof(BirdStat_T) - 2 - 2 - 1]; } BirdDirEntryW_T; #define d_ino d_stat.st_ino; /** @name d_type values. * @{ */ #define DT_UNKNOWN 0 #define DT_FIFO 1 #define DT_CHR 2 #define DT_DIR 4 #define DT_BLK 6 #define DT_REG 8 #define DT_LNK 10 #define DT_SOCK 12 #define DT_WHT 14 /** @} */ /** @name BIRDDIR_F_XXX - birdDirOpenFromHandle & BirdDir_T::fFlags * @{ */ /** birdDirClose should also close pvHandle. */ #define BIRDDIR_F_CLOSE_HANDLE 1U /** birdDirClose should not close the handle. */ #define BIRDDIR_F_KEEP_HANDLE 0U /** Provide extra info (stat). */ #define BIRDDIR_F_EXTRA_INFO 2U /** Whether to restart the scan. */ #define BIRDDIR_F_RESTART_SCAN 4U /** Set if the BirdDir_T structure is statically allocated. */ #define BIRDDIR_F_STATIC_ALLOC 8U /** @} */ typedef struct BirdDir { /** Magic value. */ unsigned uMagic; /** Flags. */ unsigned fFlags; /** The directory handle. */ void *pvHandle; /** The device number (st_dev). */ unsigned __int64 uDev; /** The current position. */ long offPos; /** Set if we haven't yet read anything. */ int fFirst; /** Set if we have data in the buffer. */ int fHaveData; /** The info type we're querying. */ int iInfoClass; /** The current buffer position. */ unsigned offBuf; /** The number of bytes allocated for pabBuf. */ unsigned cbBuf; /** Buffer of size cbBuf. */ unsigned char *pabBuf; /** Static directory entry. */ union { BirdDirEntry_T DirEntry; BirdDirEntryW_T DirEntryW; } u; } BirdDir_T; /** Magic value for BirdDir. */ #define BIRD_DIR_MAGIC 0x19731120 BirdDir_T *birdDirOpen(const char *pszPath); BirdDir_T *birdDirOpenExtraInfo(const char *pszPath); BirdDir_T *birdDirOpenExW(void *hRoot, const wchar_t *pwszPath, const wchar_t *pwszFilter, unsigned fFlags); BirdDir_T *birdDirOpenFromHandle(void *hDir, const void *pvReserved, unsigned fFlags); BirdDir_T *birdDirOpenFromHandleWithReuse(BirdDir_T *pDir, void *pvHandle, const void *pvReserved, unsigned fFlags); BirdDirEntry_T *birdDirRead(BirdDir_T *pDir); BirdDirEntryW_T *birdDirReadW(BirdDir_T *pDir); long birdDirTell(BirdDir_T *pDir); void birdDirSeek(BirdDir_T *pDir, long offDir); int birdDirClose(BirdDir_T *pDir); #define opendir birdDirOpen #define readdir birdDirRead #define telldir birdDirTell #define seekdir birdDirSeek #define rewinddir(a_pDir, a_offDir) birdDirSeek(a_pDir, 0) #define closedir birdDirClose #define _D_NAMLEN(a_pEnt) ((a_pEnt)->d_namlen) typedef BirdDir_T DIR; #endif kbuild-3149/src/lib/nt/nthlpfs.c0000644000175000017500000004774513252530204016521 0ustar locutuslocutus/* $Id: nthlpfs.c 2997 2016-11-01 23:28:02Z bird $ */ /** @file * MSC + NT helpers for file system related functions. */ /* * Copyright (c) 2005-2013 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "nthlp.h" #include #include #include #include /******************************************************************************* * Global Variables * *******************************************************************************/ static int g_fHaveOpenReparsePoint = -1; static int birdHasTrailingSlash(const char *pszPath) { char ch, ch2; /* Skip leading slashes. */ while ((ch = *pszPath) == '/' || ch == '\\') pszPath++; if (ch == '\0') return 0; /* Find the last char. */ while ((ch2 = *++pszPath) != '\0') ch = ch2; return ch == '/' || ch == '\\' || ch == ':'; } static int birdHasTrailingSlashW(const wchar_t *pwszPath) { wchar_t wc, wc2; /* Skip leading slashes. */ while ((wc = *pwszPath) == '/' || wc == '\\') pwszPath++; if (wc == '\0') return 0; /* Find the last char. */ while ((wc2 = *++pwszPath) != '\0') wc = wc2; return wc == '/' || wc == '\\' || wc == ':'; } static int birdIsPathDirSpec(const char *pszPath) { char ch, ch2; /* Check for empty string. */ ch = *pszPath; if (ch == '\0') return 0; /* Find the last char. */ while ((ch2 = *++pszPath) != '\0') ch = ch2; return ch == '/' || ch == '\\' || ch == ':'; } static int birdIsPathDirSpecW(const wchar_t *pwszPath) { wchar_t wc, wc2; /* Check for empty string. */ wc = *pwszPath; if (wc == '\0') return 0; /* Find the last char. */ while ((wc2 = *++pwszPath) != '\0') wc = wc2; return wc == '/' || wc == '\\' || wc == ':'; } int birdDosToNtPath(const char *pszPath, MY_UNICODE_STRING *pNtPath) { MY_NTSTATUS rcNt; WCHAR wszTmp[4096]; MY_UNICODE_STRING TmpUniStr; MY_ANSI_STRING Src; birdResolveImports(); pNtPath->Length = pNtPath->MaximumLength = 0; pNtPath->Buffer = NULL; /* * Convert the input to wide char. */ Src.Buffer = (PCHAR)pszPath; Src.MaximumLength = Src.Length = (USHORT)strlen(pszPath); TmpUniStr.Length = 0; TmpUniStr.MaximumLength = sizeof(wszTmp) - sizeof(WCHAR); TmpUniStr.Buffer = wszTmp; rcNt = g_pfnRtlAnsiStringToUnicodeString(&TmpUniStr, &Src, FALSE); if (MY_NT_SUCCESS(rcNt)) { if (TmpUniStr.Length > 0 && !(TmpUniStr.Length & 1)) { wszTmp[TmpUniStr.Length / sizeof(WCHAR)] = '\0'; /* * Convert the wide DOS path to an NT path. */ if (g_pfnRtlDosPathNameToNtPathName_U(wszTmp, pNtPath, NULL, FALSE)) return 0; } rcNt = -1; } return birdSetErrnoFromNt(rcNt); } int birdDosToNtPathW(const wchar_t *pwszPath, MY_UNICODE_STRING *pNtPath) { birdResolveImports(); pNtPath->Length = pNtPath->MaximumLength = 0; pNtPath->Buffer = NULL; /* * Convert the wide DOS path to an NT path. */ if (g_pfnRtlDosPathNameToNtPathName_U(pwszPath, pNtPath, NULL, FALSE)) return 0; return birdSetErrnoFromNt(STATUS_NO_MEMORY); } /** * Converts UNIX slashes to DOS ones. * * @returns 0 * @param pNtPath The relative NT path to fix up. */ static int birdFixRelativeNtPathSlashesAndReturn0(MY_UNICODE_STRING *pNtPath) { size_t cwcLeft = pNtPath->Length / sizeof(wchar_t); wchar_t *pwcStart = pNtPath->Buffer; wchar_t *pwcHit; /* Convert slashes. */ while ((pwcHit = wmemchr(pwcStart, '/', cwcLeft)) != NULL) { *pwcHit = '\\'; cwcLeft -= pwcHit - pwcStart; pwcHit = pwcStart; } #if 0 /* Strip trailing slashes (NT doesn't like them). */ while ( pNtPath->Length >= sizeof(wchar_t) && pNtPath->Buffer[(pNtPath->Length - sizeof(wchar_t)) / sizeof(wchar_t)] == '\\') { pNtPath->Length -= sizeof(wchar_t); pNtPath->Buffer[pNtPath->Length / sizeof(wchar_t)] = '\0'; } /* If it was all trailing slashes we convert it to a dot path. */ if ( pNtPath->Length == 0 && pNtPath->MaximumLength >= sizeof(wchar_t) * 2) { pNtPath->Length = sizeof(wchar_t); pNtPath->Buffer[0] = '.'; pNtPath->Buffer[1] = '\0'; } #endif return 0; } /** * Similar to birdDosToNtPath, but it does call RtlDosPathNameToNtPathName_U. * * @returns 0 on success, -1 + errno on failure. * @param pszPath The relative path. * @param pNtPath Where to return the NT path. Call birdFreeNtPath when done. */ int birdDosToRelativeNtPath(const char *pszPath, MY_UNICODE_STRING *pNtPath) { MY_NTSTATUS rcNt; MY_ANSI_STRING Src; birdResolveImports(); /* * Just convert to wide char. */ pNtPath->Length = pNtPath->MaximumLength = 0; pNtPath->Buffer = NULL; Src.Buffer = (PCHAR)pszPath; Src.MaximumLength = Src.Length = (USHORT)strlen(pszPath); rcNt = g_pfnRtlAnsiStringToUnicodeString(pNtPath, &Src, TRUE /* Allocate */); if (MY_NT_SUCCESS(rcNt)) return birdFixRelativeNtPathSlashesAndReturn0(pNtPath); return birdSetErrnoFromNt(rcNt); } /** * Similar to birdDosToNtPathW, but it does call RtlDosPathNameToNtPathName_U. * * @returns 0 on success, -1 + errno on failure. * @param pwszPath The relative path. * @param pNtPath Where to return the NT path. Call birdFreeNtPath when done. */ int birdDosToRelativeNtPathW(const wchar_t *pwszPath, MY_UNICODE_STRING *pNtPath) { size_t cwcPath = wcslen(pwszPath); if (cwcPath < 0xfffe) { pNtPath->Length = (USHORT)(cwcPath * sizeof(wchar_t)); pNtPath->MaximumLength = pNtPath->Length + sizeof(wchar_t); pNtPath->Buffer = HeapAlloc(GetProcessHeap(), 0, pNtPath->MaximumLength); if (pNtPath->Buffer) { memcpy(pNtPath->Buffer, pwszPath, pNtPath->MaximumLength); return birdFixRelativeNtPathSlashesAndReturn0(pNtPath); } errno = ENOMEM; } else errno = ENAMETOOLONG; return -1; } /** * Frees a string returned by birdDosToNtPath, birdDosToNtPathW or * birdDosToRelativeNtPath. * * @param pNtPath The the NT path to free. */ void birdFreeNtPath(MY_UNICODE_STRING *pNtPath) { HeapFree(GetProcessHeap(), 0, pNtPath->Buffer); pNtPath->Buffer = NULL; pNtPath->Length = 0; pNtPath->MaximumLength = 0; } MY_NTSTATUS birdOpenFileUniStr(HANDLE hRoot, MY_UNICODE_STRING *pNtPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, HANDLE *phFile) { MY_IO_STATUS_BLOCK Ios; MY_OBJECT_ATTRIBUTES ObjAttr; MY_NTSTATUS rcNt; birdResolveImports(); if ( (fCreateOptions & FILE_OPEN_REPARSE_POINT) && g_fHaveOpenReparsePoint == 0) fCreateOptions &= ~FILE_OPEN_REPARSE_POINT; Ios.Information = -1; Ios.u.Status = 0; MyInitializeObjectAttributes(&ObjAttr, pNtPath, fObjAttribs, hRoot, NULL /*pSecAttr*/); rcNt = g_pfnNtCreateFile(phFile, fDesiredAccess, &ObjAttr, &Ios, NULL, /* cbFileInitialAlloc */ fFileAttribs, fShareAccess, fCreateDisposition, fCreateOptions, NULL, /* pEaBuffer */ 0); /* cbEaBuffer*/ if ( rcNt == STATUS_INVALID_PARAMETER && g_fHaveOpenReparsePoint < 0 && (fCreateOptions & FILE_OPEN_REPARSE_POINT)) { fCreateOptions &= ~FILE_OPEN_REPARSE_POINT; Ios.Information = -1; Ios.u.Status = 0; MyInitializeObjectAttributes(&ObjAttr, pNtPath, fObjAttribs, NULL /*hRoot*/, NULL /*pSecAttr*/); rcNt = g_pfnNtCreateFile(phFile, fDesiredAccess, &ObjAttr, &Ios, NULL, /* cbFileInitialAlloc */ fFileAttribs, fShareAccess, fCreateDisposition, fCreateOptions, NULL, /* pEaBuffer */ 0); /* cbEaBuffer*/ if (rcNt != STATUS_INVALID_PARAMETER) g_fHaveOpenReparsePoint = 0; } return rcNt; } HANDLE birdOpenFile(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs) { MY_UNICODE_STRING NtPath; MY_NTSTATUS rcNt; /* * Adjust inputs. */ if (birdIsPathDirSpec(pszPath)) fCreateOptions |= FILE_DIRECTORY_FILE; /* * Convert the path and call birdOpenFileUniStr to do the real work. */ if (birdDosToNtPath(pszPath, &NtPath) == 0) { HANDLE hFile; rcNt = birdOpenFileUniStr(NULL /*hRoot*/, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess, fCreateDisposition, fCreateOptions, fObjAttribs, &hFile); birdFreeNtPath(&NtPath); if (MY_NT_SUCCESS(rcNt)) return hFile; birdSetErrnoFromNt(rcNt); } return INVALID_HANDLE_VALUE; } HANDLE birdOpenFileW(const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs) { MY_UNICODE_STRING NtPath; MY_NTSTATUS rcNt; /* * Adjust inputs. */ if (birdIsPathDirSpecW(pwszPath)) fCreateOptions |= FILE_DIRECTORY_FILE; /* * Convert the path and call birdOpenFileUniStr to do the real work. */ if (birdDosToNtPathW(pwszPath, &NtPath) == 0) { HANDLE hFile; rcNt = birdOpenFileUniStr(NULL /*hRoot*/, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess, fCreateDisposition, fCreateOptions, fObjAttribs, &hFile); birdFreeNtPath(&NtPath); if (MY_NT_SUCCESS(rcNt)) return hFile; birdSetErrnoFromNt(rcNt); } return INVALID_HANDLE_VALUE; } HANDLE birdOpenFileEx(HANDLE hRoot, const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs) { MY_UNICODE_STRING NtPath; MY_NTSTATUS rcNt; /* * Adjust inputs. */ if (birdIsPathDirSpec(pszPath)) fCreateOptions |= FILE_DIRECTORY_FILE; /* * Convert the path and call birdOpenFileUniStr to do the real work. */ if (hRoot == INVALID_HANDLE_VALUE) hRoot = NULL; if ((hRoot != NULL ? birdDosToRelativeNtPath(pszPath, &NtPath) : birdDosToNtPath(pszPath, &NtPath)) == 0) { HANDLE hFile; rcNt = birdOpenFileUniStr(hRoot, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess, fCreateDisposition, fCreateOptions, fObjAttribs, &hFile); birdFreeNtPath(&NtPath); if (MY_NT_SUCCESS(rcNt)) return hFile; birdSetErrnoFromNt(rcNt); } return INVALID_HANDLE_VALUE; } HANDLE birdOpenFileExW(HANDLE hRoot, const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs) { MY_UNICODE_STRING NtPath; MY_NTSTATUS rcNt; /* * Adjust inputs. */ if (birdIsPathDirSpecW(pwszPath)) fCreateOptions |= FILE_DIRECTORY_FILE; /* * Convert the path (could save ourselves this if pwszPath is perfect) and * call birdOpenFileUniStr to do the real work. */ if (hRoot == INVALID_HANDLE_VALUE) hRoot = NULL; if ((hRoot != NULL ? birdDosToRelativeNtPathW(pwszPath, &NtPath) : birdDosToNtPathW(pwszPath, &NtPath)) == 0) { HANDLE hFile; rcNt = birdOpenFileUniStr(hRoot, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess, fCreateDisposition, fCreateOptions, fObjAttribs, &hFile); birdFreeNtPath(&NtPath); if (MY_NT_SUCCESS(rcNt)) return hFile; birdSetErrnoFromNt(rcNt); } return INVALID_HANDLE_VALUE; } static HANDLE birdOpenParentDirCommon(HANDLE hRoot, MY_UNICODE_STRING *pNtPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, MY_UNICODE_STRING *pNameUniStr) { MY_NTSTATUS rcNt; /* * Strip the path down to the directory. */ USHORT offName = pNtPath->Length / sizeof(WCHAR); USHORT cwcName = offName; WCHAR wc = 0; while ( offName > 0 && (wc = pNtPath->Buffer[offName - 1]) != '\\' && wc != '/' && wc != ':') offName--; if ( offName > 0 || (hRoot != NULL && cwcName > 0)) { cwcName -= offName; /* Make a copy of the file name, if requested. */ rcNt = STATUS_SUCCESS; if (pNameUniStr) { pNameUniStr->Length = cwcName * sizeof(WCHAR); pNameUniStr->MaximumLength = pNameUniStr->Length + sizeof(WCHAR); pNameUniStr->Buffer = (WCHAR *)HeapAlloc(GetProcessHeap(), 0, pNameUniStr->MaximumLength); if (pNameUniStr->Buffer) { memcpy(pNameUniStr->Buffer, &pNtPath->Buffer[offName], pNameUniStr->Length); pNameUniStr->Buffer[cwcName] = '\0'; } else rcNt = STATUS_NO_MEMORY; } /* Chop, chop. */ // Bad idea, breaks \\?\c:\pagefile.sys. //while ( offName > 0 // Bad idea, breaks \\?\c:\pagefile.sys. // && ( (wc = pNtPath->Buffer[offName - 1]) == '\\' // Bad idea, breaks \\?\c:\pagefile.sys. // || wc == '/')) // Bad idea, breaks \\?\c:\pagefile.sys. // offName--; if (offName == 0) pNtPath->Buffer[offName++] = '.'; /* Hack for dir handle + dir entry name. */ pNtPath->Length = offName * sizeof(WCHAR); pNtPath->Buffer[offName] = '\0'; if (MY_NT_SUCCESS(rcNt)) { /* * Finally, try open the directory. */ HANDLE hFile; fCreateOptions |= FILE_DIRECTORY_FILE; rcNt = birdOpenFileUniStr(hRoot, pNtPath, fDesiredAccess, fFileAttribs, fShareAccess, fCreateDisposition, fCreateOptions, fObjAttribs, &hFile); if (MY_NT_SUCCESS(rcNt)) { birdFreeNtPath(pNtPath); return hFile; } } if (pNameUniStr) birdFreeNtPath(pNameUniStr); } else rcNt = STATUS_INVALID_PARAMETER; birdFreeNtPath(pNtPath); birdSetErrnoFromNt(rcNt); return INVALID_HANDLE_VALUE; } HANDLE birdOpenParentDir(HANDLE hRoot, const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, MY_UNICODE_STRING *pNameUniStr) { /* * Convert the path and join up with the UTF-16 version (it'll free NtPath). */ MY_UNICODE_STRING NtPath; if (hRoot == INVALID_HANDLE_VALUE) hRoot = NULL; if ( hRoot == NULL ? birdDosToNtPath(pszPath, &NtPath) == 0 : birdDosToRelativeNtPath(pszPath, &NtPath) == 0) return birdOpenParentDirCommon(hRoot, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess, fCreateDisposition, fCreateOptions, fObjAttribs, pNameUniStr); return INVALID_HANDLE_VALUE; } HANDLE birdOpenParentDirW(HANDLE hRoot, const wchar_t *pwszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess, ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs, MY_UNICODE_STRING *pNameUniStr) { /* * Convert the path and join up with the ansi version (it'll free NtPath). */ MY_UNICODE_STRING NtPath; if (hRoot == INVALID_HANDLE_VALUE) hRoot = NULL; if ( hRoot == NULL ? birdDosToNtPathW(pwszPath, &NtPath) == 0 : birdDosToRelativeNtPathW(pwszPath, &NtPath) == 0) return birdOpenParentDirCommon(hRoot, &NtPath, fDesiredAccess, fFileAttribs, fShareAccess, fCreateDisposition, fCreateOptions, fObjAttribs, pNameUniStr); return INVALID_HANDLE_VALUE; } /** * Returns a handle to the current working directory of the process. * * @returns CWD handle with FILE_TRAVERSE and SYNCHRONIZE access. May return * INVALID_HANDLE_VALUE w/ errno for invalid CWD. */ HANDLE birdOpenCurrentDirectory(void) { PMY_RTL_USER_PROCESS_PARAMETERS pProcParams; MY_NTSTATUS rcNt; HANDLE hRet = INVALID_HANDLE_VALUE; birdResolveImports(); /* * We'll try get this from the PEB. */ g_pfnRtlAcquirePebLock(); pProcParams = (PMY_RTL_USER_PROCESS_PARAMETERS)MY_NT_CURRENT_PEB()->ProcessParameters; if (pProcParams != NULL) rcNt = g_pfnNtDuplicateObject(MY_NT_CURRENT_PROCESS, pProcParams->CurrentDirectory.Handle, MY_NT_CURRENT_PROCESS, &hRet, FILE_TRAVERSE | SYNCHRONIZE, 0 /*fAttribs*/, 0 /*fOptions*/); else rcNt = STATUS_INVALID_PARAMETER; g_pfnRtlReleasePebLock(); if (MY_NT_SUCCESS(rcNt)) return hRet; /* * Fallback goes thru birdOpenFileW. */ return birdOpenFileW(L".", FILE_TRAVERSE | SYNCHRONIZE, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, OBJ_CASE_INSENSITIVE); } void birdCloseFile(HANDLE hFile) { birdResolveImports(); g_pfnNtClose(hFile); } kbuild-3149/src/lib/nt/Makefile.kup0000644000175000017500000000000013252530204017102 0ustar locutuslocutuskbuild-3149/src/lib/nt/ntutimes.h0000644000175000017500000000337413252530204016706 0ustar locutuslocutus/* $Id: ntutimes.h 3060 2017-09-21 15:11:07Z bird $ */ /** @file * MSC + NT utimes and lutimes. */ /* * Copyright (c) 2005-2017 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___nt_ntutimes_h #define ___nt_ntutimes_h #include "nttypes.h" int birdUtimes(const char *pszFile, BirdTimeVal_T paTimes[2]); int birdLUtimes(const char *pszFile, BirdTimeVal_T paTimes[2]); #undef utimes #define utimes(a_pszPath, a_paTimes) birdUtimes(a_pszPath, a_paTimes) #undef lutimes #define lutimes(a_pszPath, a_paTimes) birdLUtimes(a_pszPath, a_paTimes) #endif kbuild-3149/src/lib/nt/fts-nt.h0000644000175000017500000001715613252530204016254 0ustar locutuslocutus/* $Id: fts-nt.h 3004 2016-11-05 23:18:51Z bird $ */ /** @file * Header for the NT port of BSD fts.h. * * @copyright Copyright (c) 1989, 1993 The Regents of the University of California. All rights reserved. * @copyright NT modifications Copyright (C) 2016 knut st. osmundsen * @licenses BSD3 */ /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)fts.h 8.3 (Berkeley) 8/14/94 * $FreeBSD$ * */ #ifndef INCLUDED_FTS_NT_H #define INCLUDED_FTS_NT_H #include #include #include "ntstat.h" /* ensure correct stat structure */ typedef uint64_t fts_dev_t; typedef uint64_t fts_ino_t; typedef uint32_t fts_nlink_t; #ifdef _WINNT_ typedef HANDLE fts_fd_t; # define NT_FTS_INVALID_HANDLE_VALUE INVALID_HANDLE_VALUE #else typedef void * fts_fd_t; # define NT_FTS_INVALID_HANDLE_VALUE ((void *)~(uintptr_t)0) #endif #define FTSCALL __cdecl typedef struct { struct _ftsent *fts_cur; /* current node */ struct _ftsent *fts_child; /* linked list of children */ struct _ftsent **fts_array; /* sort array */ fts_dev_t fts_dev; /* starting device # */ char *fts_path; /* path for this descent */ size_t fts_pathlen; /* sizeof(path) */ wchar_t *fts_wcspath; /* NT: UTF-16 path for this descent. */ size_t fts_cwcpath; /* NT: size of fts_wcspath buffer */ size_t fts_nitems; /* elements in the sort array */ int (FTSCALL *fts_compar) /* compare function */ (const struct _ftsent * const *, const struct _ftsent * const *); #define FTS_COMFOLLOW 0x001 /* follow command line symlinks */ #define FTS_LOGICAL 0x002 /* logical walk */ #define FTS_NOCHDIR 0x004 /* don't change directories */ #define FTS_NOSTAT 0x008 /* don't get stat info */ #define FTS_PHYSICAL 0x010 /* physical walk */ #define FTS_SEEDOT 0x020 /* return dot and dot-dot */ #define FTS_XDEV 0x040 /* don't cross devices */ #if 0 /* No whiteout on NT. */ #define FTS_WHITEOUT 0x080 /* return whiteout information */ #endif #define FTS_NO_ANSI 0x40000000 /* NT: No ansi name or access path. */ #define FTS_OPTIONMASK 0x400000ff /* valid user option mask */ #define FTS_NAMEONLY 0x100 /* (private) child names only */ #define FTS_STOP 0x200 /* (private) unrecoverable error */ int fts_options; /* fts_open options, global flags */ void *fts_clientptr; /* thunk for sort function */ } FTS; typedef struct _ftsent { struct _ftsent *fts_cycle; /* cycle node */ struct _ftsent *fts_parent; /* parent directory */ struct _ftsent *fts_link; /* next file in directory */ int64_t fts_number; /* local numeric value */ #define fts_bignum fts_number /* XXX non-std, should go away */ void *fts_pointer; /* local address value */ char *fts_accpath; /* access path */ wchar_t *fts_wcsaccpath; /* NT: UTF-16 access path */ char *fts_path; /* root path */ wchar_t *fts_wcspath; /* NT: UTF-16 root path */ int fts_errno; /* errno for this node */ size_t fts_alloc_size; /* internal - size of the allocation for this entry. */ fts_fd_t fts_dirfd; /* NT: Handle to the directory (NT_FTS_)INVALID_HANDLE_VALUE if not valid */ size_t fts_pathlen; /* strlen(fts_path) */ size_t fts_cwcpath; /* NT: length of fts_wcspath. */ size_t fts_namelen; /* strlen(fts_name) */ size_t fts_cwcname; /* NT: length of fts_wcsname. */ fts_ino_t fts_ino; /* inode */ fts_dev_t fts_dev; /* device */ fts_nlink_t fts_nlink; /* link count */ #define FTS_ROOTPARENTLEVEL -1 #define FTS_ROOTLEVEL 0 long fts_level; /* depth (-1 to N) */ #define FTS_D 1 /* preorder directory */ #define FTS_DC 2 /* directory that causes cycles */ #define FTS_DEFAULT 3 /* none of the above */ #define FTS_DNR 4 /* unreadable directory */ #define FTS_DOT 5 /* dot or dot-dot */ #define FTS_DP 6 /* postorder directory */ #define FTS_ERR 7 /* error; errno is set */ #define FTS_F 8 /* regular file */ #define FTS_INIT 9 /* initialized only */ #define FTS_NS 10 /* stat(2) failed */ #define FTS_NSOK 11 /* no stat(2) requested */ #define FTS_SL 12 /* symbolic link */ #define FTS_SLNONE 13 /* symbolic link without target */ //#define FTS_W 14 /* whiteout object */ int fts_info; /* user status for FTSENT structure */ #define FTS_DONTCHDIR 0x01 /* don't chdir .. to the parent */ #define FTS_SYMFOLLOW 0x02 /* followed a symlink to get here */ #define FTS_ISW 0x04 /* this is a whiteout object */ unsigned fts_flags; /* private flags for FTSENT structure */ #define FTS_AGAIN 1 /* read node again */ #define FTS_FOLLOW 2 /* follow symbolic link */ #define FTS_NOINSTR 3 /* no instructions */ #define FTS_SKIP 4 /* discard node */ int fts_instr; /* fts_set() instructions */ struct stat *fts_statp; /* stat(2) information */ char *fts_name; /* file name */ wchar_t *fts_wcsname; /* NT: UTF-16 file name. */ FTS *fts_fts; /* back pointer to main FTS */ BirdStat_T fts_stat; /* NT: We always got stat info. */ } FTSENT; #ifdef __cplusplus extern "C" { #endif FTSENT *FTSCALL nt_fts_children(FTS *, int); int FTSCALL nt_fts_close(FTS *); void *FTSCALL nt_fts_get_clientptr(FTS *); #define fts_get_clientptr(fts) ((fts)->fts_clientptr) FTS *FTSCALL nt_fts_get_stream(FTSENT *); #define fts_get_stream(ftsent) ((ftsent)->fts_fts) FTS *FTSCALL nt_fts_open(char * const *, int, int (FTSCALL*)(const FTSENT * const *, const FTSENT * const *)); FTS *FTSCALL nt_fts_openw(wchar_t * const *, int, int (FTSCALL*)(const FTSENT * const *, const FTSENT * const *)); FTSENT *FTSCALL nt_fts_read(FTS *); int FTSCALL nt_fts_set(FTS *, FTSENT *, int); void FTSCALL nt_fts_set_clientptr(FTS *, void *); /* API mappings. */ #define fts_children(a_pFts, a_iInstr) nt_fts_children(a_pFts, a_iInstr) #define fts_close(a_pFts) nt_fts_close(a_pFts) #define fts_open(a_papszArgs, a_fOptions, a_pfnCompare) nt_fts_open(a_papszArgs, a_fOptions, a_pfnCompare) #define fts_read(a_pFts) nt_fts_read(a_pFts) #define fts_set(a_pFts, a_pFtsEntry, a_iInstr) nt_fts_set(a_pFts, a_pFtsEntry, a_iInstr) #define fts_set_clientptr(a_pFts, a_pvUser) nt_fts_set_clientptr(a_pFts, a_pvUser) #ifdef __cplusplus } #endif #endif /* !INCLUDED_FTS_NT_H */ kbuild-3149/src/lib/nt/tstNtFts.c0000644000175000017500000002035413252530204016617 0ustar locutuslocutus /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ #ifndef USE_OLD_FTS # include "fts-nt.h" #else # include "kmkbuiltin/ftsfake.h" #endif #include #include #include #include static int usage(const char *argv0) { printf("usage: %s [options] \n", argv0); printf("\n" "options:\n" " -d, --see-dot\n" " FTS_SEEDOT\n" " -p, --physical\n" " FTS_PHYSICAL\n" " -l, --logical\n" " FTS_LOGICAL\n" " -H, --dereference-command-line\n" " FTS_COMFOLLOW\n" " -L, --dereference\n" " Follow symbolic links while scanning directories.\n" " -P, --no-dereference\n" " Do not follow symbolic links while scanning directories.\n" " -c, --no-chdir\n" " FTS_NOCHDIR\n" " -s, --no-stat\n" " FTS_NOSTAT\n" " -x, --one-file-system\n" " FTS_XDEV\n" " -q, --quiet\n" " Quiet operation, no output.\n" " -v, --verbose\n" " Verbose operation (default).\n" ); return 0; } int main(int argc, char **argv) { FTS *pFts; int i; int rcExit = 0; int cVerbosity = 1; int fFollowLinks = 0; int fFtsFlags = 0; unsigned fDoneOptions = 0; unsigned cFtsArgs = 0; char const **papszFtsArgs = calloc(argc + 1, sizeof(char *)); /* * Parse options and heap up non-options. */ for (i = 1; i < argc; i++) { const char *pszArg = argv[i]; if (*pszArg == '-' && !fDoneOptions) { char chOpt = *++pszArg; pszArg++; if (chOpt == '-') { if (!chOpt) { fDoneOptions = 1; continue; } if (strcmp(pszArg, "help") == 0) chOpt = 'h'; else if (strcmp(pszArg, "version") == 0) chOpt = 'V'; else if (strcmp(pszArg, "see-dot") == 0) chOpt = 'd'; else if (strcmp(pszArg, "physical") == 0) chOpt = 'p'; else if (strcmp(pszArg, "logical") == 0) chOpt = 'l'; else if (strcmp(pszArg, "dereference-command-line") == 0) chOpt = 'H'; else if (strcmp(pszArg, "no-chdir") == 0) chOpt = 'c'; else if (strcmp(pszArg, "no-stat") == 0) chOpt = 's'; else if (strcmp(pszArg, "one-file-system") == 0) chOpt = 'x'; else if (strcmp(pszArg, "quiet") == 0) chOpt = 'q'; else if (strcmp(pszArg, "verbose") == 0) chOpt = 'v'; else if (strcmp(pszArg, "no-ansi") == 0) chOpt = 'w'; else { fprintf(stderr, "syntax error: Unknown option: %s (%s)\n", argv[i], pszArg); return 2; } pszArg = ""; } do { switch (chOpt) { case '?': case 'h': return usage(argv[0]); case 'V': printf("v0.0.0\n"); return 0; case 'd': fFtsFlags |= FTS_SEEDOT; break; case 'l': fFtsFlags |= FTS_LOGICAL; break; case 'p': fFtsFlags |= FTS_PHYSICAL; break; case 'H': fFtsFlags |= FTS_COMFOLLOW; break; case 'c': fFtsFlags |= FTS_NOCHDIR; break; case 's': fFtsFlags |= FTS_NOSTAT; break; case 'x': fFtsFlags |= FTS_XDEV; break; #ifdef FTS_NO_ANSI case 'w': fFtsFlags |= FTS_NO_ANSI; break; #endif case 'L': fFollowLinks = 1; break; case 'P': fFollowLinks = 0; break; case 'q': cVerbosity = 0; break; case 'v': cVerbosity++; break; default: fprintf(stderr, "syntax error: Unknown option: -%c (%s)\n", chOpt, argv[i]); return 2; } chOpt = *pszArg++; } while (chOpt != '\0'); } else papszFtsArgs[cFtsArgs++] = pszArg; } #ifdef USE_OLD_FTS if (papszFtsArgs[0] == NULL) { fprintf(stderr, "Nothing to do\n"); return 1; } #endif /* * Do the traversal. */ errno = 0; pFts = fts_open((char **)papszFtsArgs, fFtsFlags, NULL /*pfnCompare*/); if (pFts) { for (;;) { FTSENT *pFtsEnt = fts_read(pFts); if (pFtsEnt) { const char *pszState; switch (pFtsEnt->fts_info) { case FTS_D: pszState = "D"; break; case FTS_DC: pszState = "DC"; break; case FTS_DEFAULT: pszState = "DEFAULT"; break; case FTS_DNR: pszState = "DNR"; break; case FTS_DOT: pszState = "DOT"; break; case FTS_DP: pszState = "DP"; break; case FTS_ERR: pszState = "ERR"; break; case FTS_F: pszState = "F"; break; case FTS_INIT: pszState = "INIT"; break; case FTS_NS: pszState = "NS"; break; case FTS_NSOK: pszState = "NSOK"; break; case FTS_SL: pszState = "SL"; break; case FTS_SLNONE: pszState = "SLNONE"; break; default: pszState = "Invalid"; rcExit = 1; break; } if (cVerbosity > 0) { #ifdef FTS_NO_ANSI if (fFtsFlags & FTS_NO_ANSI) printf("%8s %ls\n", pszState, pFtsEnt->fts_wcsaccpath); else #endif printf("%8s %s\n", pszState, pFtsEnt->fts_accpath); } if ( pFtsEnt->fts_info == FTS_SL && pFtsEnt->fts_number == 0 && fFollowLinks && ( (fFtsFlags & FTS_COMFOLLOW) || pFtsEnt->fts_level > FTS_ROOTLEVEL) ) { pFtsEnt->fts_number++; fts_set(pFts, pFtsEnt, FTS_FOLLOW); } } else { if (errno != 0) { fprintf(stderr, "fts_read failed: errno=%d\n", errno); rcExit = 1; } break; } } /* enum loop */ errno = 0; i = fts_close(pFts); if (i != 0) { fprintf(stderr, "fts_close failed: errno=%d\n", errno); rcExit = 1; } } else { fprintf(stderr, "fts_open failed: errno=%d (cFtsArgs=%u)\n", errno, cFtsArgs); rcExit = 1; } return rcExit; } kbuild-3149/src/lib/nt/ntunlink.c0000644000175000017500000001761013252530204016671 0ustar locutuslocutus/* $Id: ntunlink.c 3126 2017-11-16 16:05:25Z bird $ */ /** @file * MSC + NT unlink and variations. */ /* * Copyright (c) 2005-2017 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "ntunlink.h" #include "ntstuff.h" #include "nthlp.h" static MY_NTSTATUS birdMakeWritable(MY_UNICODE_STRING *pNtPath) { MY_NTSTATUS rcNt; HANDLE hFile; rcNt = birdOpenFileUniStr(NULL /*hRoot*/, pNtPath, FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | SYNCHRONIZE, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, OBJ_CASE_INSENSITIVE, &hFile); if (MY_NT_SUCCESS(rcNt)) { MY_FILE_BASIC_INFORMATION BasicInfo; MY_IO_STATUS_BLOCK Ios; DWORD dwAttr; Ios.Information = -1; Ios.u.Status = -1; rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &BasicInfo, sizeof(BasicInfo), MyFileBasicInformation); if (MY_NT_SUCCESS(rcNt) && MY_NT_SUCCESS(Ios.u.Status)) dwAttr = BasicInfo.FileAttributes & ~FILE_ATTRIBUTE_READONLY; else dwAttr = FILE_ATTRIBUTE_NORMAL; memset(&BasicInfo, 0, sizeof(BasicInfo)); BasicInfo.FileAttributes = dwAttr; Ios.Information = -1; Ios.u.Status = -1; rcNt = g_pfnNtSetInformationFile(hFile, &Ios, &BasicInfo, sizeof(BasicInfo), MyFileBasicInformation); birdCloseFile(hFile); } return rcNt; } static int birdUnlinkInternal(HANDLE hRoot, const char *pszFile, const wchar_t *pwszFile, int fReadOnlyToo, int fFast) { MY_UNICODE_STRING NtPath; int rc; if (hRoot == INVALID_HANDLE_VALUE) hRoot = NULL; if (hRoot == NULL) { if (pwszFile) rc = birdDosToNtPathW(pwszFile, &NtPath); else rc = birdDosToNtPath(pszFile, &NtPath); } else { if (pwszFile) rc = birdDosToRelativeNtPathW(pwszFile, &NtPath); else rc = birdDosToRelativeNtPath(pszFile, &NtPath); } if (rc == 0) { MY_NTSTATUS rcNt; if (fFast) { /* This uses FILE_DELETE_ON_CLOSE. Probably only suitable when in a hurry... */ MY_OBJECT_ATTRIBUTES ObjAttr; MyInitializeObjectAttributes(&ObjAttr, &NtPath, OBJ_CASE_INSENSITIVE, hRoot, NULL /*pSecAttr*/); rcNt = g_pfnNtDeleteFile(&ObjAttr); /* In case some file system does things differently than NTFS. */ if (rcNt == STATUS_CANNOT_DELETE) { birdMakeWritable(&NtPath); rcNt = g_pfnNtDeleteFile(&ObjAttr); } } else { /* Use the set information stuff. Probably more reliable. */ HANDLE hFile; int fMayTryAgain = 1; for (;;) { rcNt = birdOpenFileUniStr(hRoot, &NtPath, DELETE | SYNCHRONIZE, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT, OBJ_CASE_INSENSITIVE, &hFile); if (MY_NT_SUCCESS(rcNt)) { MY_FILE_DISPOSITION_INFORMATION DispInfo; MY_IO_STATUS_BLOCK Ios; DispInfo.DeleteFile = TRUE; Ios.Information = -1; Ios.u.Status = -1; rcNt = g_pfnNtSetInformationFile(hFile, &Ios, &DispInfo, sizeof(DispInfo), MyFileDispositionInformation); birdCloseFile(hFile); } if (rcNt != STATUS_CANNOT_DELETE || !fMayTryAgain) break; fMayTryAgain = 0; birdMakeWritable(&NtPath); } } birdFreeNtPath(&NtPath); if (MY_NT_SUCCESS(rcNt)) rc = 0; else rc = birdSetErrnoFromNt(rcNt); } return rc; } int birdUnlink(const char *pszFile) { return birdUnlinkInternal(NULL /*hRoot*/, pszFile, NULL /*pwszFile*/, 0 /*fReadOnlyToo*/, 0 /*fFast*/); } int birdUnlinkW(const wchar_t *pwszFile) { return birdUnlinkInternal(NULL /*hRoot*/, NULL /*pwszFile*/, pwszFile, 0 /*fReadOnlyToo*/, 0 /*fFast*/); } int birdUnlinkEx(void *hRoot, const char *pszFile) { return birdUnlinkInternal((HANDLE)hRoot, pszFile, NULL /*pwszFile*/, 0 /*fReadOnlyToo*/, 0 /*fFast*/); } int birdUnlinkExW(void *hRoot, const wchar_t *pwszFile) { return birdUnlinkInternal((HANDLE)hRoot, NULL /*pszFile*/, pwszFile, 0 /*fReadOnlyToo*/, 0 /*fFast*/); } int birdUnlinkForced(const char *pszFile) { return birdUnlinkInternal(NULL /*hRoot*/, pszFile, NULL /*pwszFile*/, 1 /*fReadOnlyToo*/, 0 /*fFast*/); } int birdUnlinkForcedW(const wchar_t *pwszFile) { return birdUnlinkInternal(NULL /*hRoot*/, NULL /*pszFile*/, pwszFile, 1 /*fReadOnlyToo*/, 0 /*fFast*/); } int birdUnlinkForcedEx(void *hRoot, const char *pszFile) { return birdUnlinkInternal((HANDLE)hRoot, pszFile, NULL /*pwszFile*/, 1 /*fReadOnlyToo*/, 0 /*fFast*/); } int birdUnlinkForcedExW(void *hRoot, const wchar_t *pwszFile) { return birdUnlinkInternal((HANDLE)hRoot, NULL /*pszFile*/, pwszFile, 1 /*fReadOnlyToo*/, 0 /*fFast*/); } int birdUnlinkForcedFast(const char *pszFile) { return birdUnlinkInternal(NULL /*hRoot*/, pszFile, NULL /*pwszFile*/, 1 /*fReadOnlyToo*/, 1 /*fFast*/); } int birdUnlinkForcedFastW(const wchar_t *pwszFile) { return birdUnlinkInternal(NULL /*hRoot*/, NULL /*pszFile*/, pwszFile, 1 /*fReadOnlyToo*/, 1 /*fFast*/); } int birdUnlinkForcedFastEx(void *hRoot, const char *pszFile) { return birdUnlinkInternal((HANDLE)hRoot, pszFile, NULL /*pwszFile*/, 1 /*fReadOnlyToo*/, 1 /*fFast*/); } int birdUnlinkForcedFastExW(void *hRoot, const wchar_t *pwszFile) { return birdUnlinkInternal((HANDLE)hRoot, NULL /*pszFile*/, pwszFile, 1 /*fReadOnlyToo*/, 1 /*fFast*/); } kbuild-3149/src/lib/nt/fts-nt.c0000644000175000017500000011565413252530204016251 0ustar locutuslocutus/* $Id: fts-nt.c 3009 2016-11-07 02:21:59Z bird $ */ /** @file * Source for the NT port of BSD fts.c. * * @copyright 1990, 1993, 1994 The Regents of the University of California. All rights reserved. * @copyright NT modifications Copyright (C) 2016 knut st. osmundsen * @licenses BSD3 * * * Some hints about how the code works. * * The input directories & files are entered into a pseudo root directory and * processed one after another, depth first. * * Directories are completely read into memory first and arranged as linked * list anchored on FTS::fts_cur. fts_read does a pop-like operation on that * list, freeing the nodes after they've been completely processed. * Subdirectories are returned twice by fts_read, the first time when it * decends into it (FTS_D), and the second time as it ascends from it (FTS_DP). * * In parallel to fts_read, there's the fts_children API that fetches the * directory content in a similar manner, but for the consumption of the API * caller rather than FTS itself. The result hangs on FTS::fts_child so it can * be freed when the directory changes or used by fts_read when it is called * upon to enumerate the directory. * * * The NT port of the code does away with the directory changing in favor of * using directory relative opens (present in NT since for ever, just not * exposed thru Win32). A new FTSENT member fts_dirfd has been added to make * this possible for API users too. * * Note! When using Win32 APIs with path input relative to the current * directory, the internal DOS <-> NT path converter will expand it to a * full path and subject it to the 260 char limit. * * The richer NT directory enumeration API allows us to do away with all the * stat() calls, and not have to do link counting and other interesting things * to try speed things up. (You typical stat() implementation on windows is * actually a directory enum call with the name of the file as filter.) */ /*- * Copyright (c) 1990, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $OpenBSD: fts.c,v 1.22 1999/10/03 19:22:22 millert Exp $ */ #if 0 #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94"; #endif /* LIBC_SCCS and not lint */ #endif #include #include "fts-nt.h" #include #include #include #include "nthlp.h" #include "ntdir.h" #include //debug static FTSENT *fts_alloc(FTS *sp, char const *name, size_t namelen, wchar_t const *wcsname, size_t cwcname); static FTSENT *fts_alloc_ansi(FTS *sp, char const *name, size_t namelen); static FTSENT *fts_alloc_utf16(FTS *sp, wchar_t const *wcsname, size_t cwcname); static void nt_fts_free_alloc_cache(FTS *sp); static FTSENT *fts_build(FTS *, int); static void fts_lfree(FTSENT *); static void fts_load(FTS *, FTSENT *); static size_t fts_maxarglen(char * const *); static size_t fts_maxarglenw(wchar_t * const *); static void fts_padjust(FTS *, FTSENT *); static void fts_padjustw(FTS *, FTSENT *); static int fts_palloc(FTS *, size_t, size_t); static FTSENT *fts_sort(FTS *, FTSENT *, size_t); static int fts_stat(FTS *, FTSENT *, int, HANDLE); static int fts_process_stats(FTSENT *, BirdStat_T const *); #define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2]))) #define CLR(opt) (sp->fts_options &= ~(opt)) #define ISSET(opt) (sp->fts_options & (opt)) #define SET(opt) (sp->fts_options |= (opt)) /* fts_build flags */ #define BCHILD 1 /* fts_children */ #define BNAMES 2 /* fts_children, names only */ #define BREAD 3 /* fts_read */ /* NT needs these: */ #define MAXPATHLEN 260 #define MAX(a, b) ( (a) >= (b) ? (a) : (b) ) /** Enables BirdDir_T reuse. (Saves malloc and free calls.) */ #define FTS_WITH_DIRHANDLE_REUSE /** Enables allocation statistics. */ //#define FTS_WITH_STATISTICS /** Enables FTSENT allocation cache. */ #define FTS_WITH_ALLOC_CACHE /** Number of size buckets for the FTSENT allocation cache. */ #define FTS_NUM_FREE_BUCKETS 64 /** Shift for converting size to free bucket index. */ #define FTS_FREE_BUCKET_SHIFT 4 /** The FTSENT allocation alignment. */ #define FTS_ALIGN_FTSENT (1U << FTS_FREE_BUCKET_SHIFT) /* * Internal representation of an FTS, including extra implementation * details. The FTS returned from fts_open points to this structure's * ftsp_fts member (and can be cast to an _fts_private as required) */ struct _fts_private { FTS ftsp_fts; #ifdef FTS_WITH_DIRHANDLE_REUSE /** Statically allocate directory handle. */ BirdDir_T dirhandle; #endif #ifdef FTS_WITH_ALLOC_CACHE /** Number of free entries in the above buckets. */ size_t numfree; # ifdef FTS_WITH_STATISTICS size_t allocs; size_t hits; size_t misses; # endif /** Free FTSENT buckets (by size). * This is to avoid hitting the heap, which is a little sluggish on windows. */ struct { FTSENT *head; } freebuckets[FTS_NUM_FREE_BUCKETS]; #endif }; static FTS * FTSCALL nt_fts_open_common(char * const *argv, wchar_t * const *wcsargv, int options, int (*compar)(const FTSENT * const *, const FTSENT * const *)) { struct _fts_private *priv; FTS *sp; FTSENT *p, *root; FTSENT *parent, *tmp; size_t len, nitems; birdResolveImports(); /* Options check. */ if (options & ~FTS_OPTIONMASK) { errno = EINVAL; return (NULL); } /* fts_open() requires at least one path */ if (wcsargv ? *wcsargv == NULL : *argv == NULL) { errno = EINVAL; return (NULL); } /* Allocate/initialize the stream. */ if ((priv = calloc(1, sizeof(*priv))) == NULL) return (NULL); sp = &priv->ftsp_fts; sp->fts_compar = compar; sp->fts_options = options; SET(FTS_NOCHDIR); /* NT: FTS_NOCHDIR is always on (for external consumes) */ /* Shush, GCC. */ tmp = NULL; /* * Start out with 1K of path space, and enough, in any case, * to hold the user's paths. */ if (fts_palloc(sp, MAX(argv ? fts_maxarglen(argv) : 1, MAXPATHLEN), MAX(wcsargv ? fts_maxarglenw(wcsargv) : 1, MAXPATHLEN)) ) goto mem1; /* Allocate/initialize root's parent. */ if ((parent = fts_alloc(sp, NULL, 0, NULL, 0)) == NULL) goto mem2; parent->fts_level = FTS_ROOTPARENTLEVEL; /* Allocate/initialize root(s). */ for (root = NULL, nitems = 0; wcsargv ? *wcsargv != NULL : *argv != NULL; ++nitems) { /* NT: We need to do some small input transformations to make this and the API user code happy. 1. Lone drive letters get a dot appended so it won't matter if a slash is appended afterwards. 2. DOS slashes are converted to UNIX ones. */ wchar_t *wcslash; if (wcsargv) { len = wcslen(*wcsargv); if (len == 2 && wcsargv[0][1] == ':') { wchar_t wcsdrive[4]; wcsdrive[0] = wcsargv[0][0]; wcsdrive[1] = ':'; wcsdrive[2] = '.'; wcsdrive[3] = '\0'; p = fts_alloc_utf16(sp, wcsdrive, 3); } else { p = fts_alloc_utf16(sp, *wcsargv, len); } wcsargv++; } else { len = strlen(*argv); if (len == 2 && argv[0][1] == ':') { char szdrive[4]; szdrive[0] = argv[0][0]; szdrive[1] = ':'; szdrive[2] = '.'; szdrive[3] = '\0'; p = fts_alloc_ansi(sp, szdrive, 3); } else { p = fts_alloc_ansi(sp, *argv, len); } argv++; } if (p != NULL) { /* likely */ } else { goto mem3; } wcslash = wcschr(p->fts_wcsname, '\\'); while (wcslash != NULL) { *wcslash++ = '/'; wcslash = wcschr(p->fts_wcsname, '\\'); } if (p->fts_name) { char *slash = strchr(p->fts_name, '\\'); while (slash != NULL) { *slash++ = '/'; slash = strchr(p->fts_name, '\\'); } } p->fts_level = FTS_ROOTLEVEL; p->fts_parent = parent; p->fts_accpath = p->fts_name; p->fts_wcsaccpath = p->fts_wcsname; p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW), INVALID_HANDLE_VALUE); /* Command-line "." and ".." are real directories. */ if (p->fts_info == FTS_DOT) p->fts_info = FTS_D; /* * If comparison routine supplied, traverse in sorted * order; otherwise traverse in the order specified. */ if (compar) { p->fts_link = root; root = p; } else { p->fts_link = NULL; if (root == NULL) tmp = root = p; else { tmp->fts_link = p; tmp = p; } } } if (compar && nitems > 1) root = fts_sort(sp, root, nitems); /* * Allocate a dummy pointer and make fts_read think that we've just * finished the node before the root(s); set p->fts_info to FTS_INIT * so that everything about the "current" node is ignored. */ if ((sp->fts_cur = fts_alloc(sp, NULL, 0, NULL, 0)) == NULL) goto mem3; sp->fts_cur->fts_link = root; sp->fts_cur->fts_info = FTS_INIT; return (sp); mem3: fts_lfree(root); free(parent); mem2: free(sp->fts_path); free(sp->fts_wcspath); mem1: free(sp); return (NULL); } FTS * FTSCALL nt_fts_open(char * const *argv, int options, int (*compar)(const FTSENT * const *, const FTSENT * const *)) { return nt_fts_open_common(argv, NULL, options, compar); } FTS * FTSCALL nt_fts_openw(wchar_t * const *argv, int options, int (*compar)(const FTSENT * const *, const FTSENT * const *)) { return nt_fts_open_common(NULL, argv, options, compar); } /** * Called by fts_read for FTS_ROOTLEVEL entries only. */ static void fts_load(FTS *sp, FTSENT *p) { size_t len; wchar_t *pwc; /* * Load the stream structure for the next traversal. Since we don't * actually enter the directory until after the preorder visit, set * the fts_accpath field specially so the chdir gets done to the right * place and the user can access the first node. From fts_open it's * known that the path will fit. */ if (!(sp->fts_options & FTS_NO_ANSI)) { char *cp; len = p->fts_pathlen = p->fts_namelen; memmove(sp->fts_path, p->fts_name, len + 1); cp = strrchr(p->fts_name, '/'); if (cp != NULL && (cp != p->fts_name || cp[1])) { len = strlen(++cp); memmove(p->fts_name, cp, len + 1); p->fts_namelen = len; } p->fts_accpath = p->fts_path = sp->fts_path; } len = p->fts_cwcpath = p->fts_cwcname; memmove(sp->fts_wcspath, p->fts_wcsname, (len + 1) * sizeof(wchar_t)); pwc = wcsrchr(p->fts_wcsname, '/'); if (pwc != NULL && (pwc != p->fts_wcsname || pwc[1])) { len = wcslen(++pwc); memmove(p->fts_wcsname, pwc, (len + 1) * sizeof(wchar_t)); p->fts_cwcname = len; } p->fts_wcsaccpath = p->fts_wcspath = sp->fts_wcspath; sp->fts_dev = p->fts_dev; } int FTSCALL nt_fts_close(FTS *sp) { FTSENT *freep, *p; /*int saved_errno;*/ /* * This still works if we haven't read anything -- the dummy structure * points to the root list, so we step through to the end of the root * list which has a valid parent pointer. */ if (sp->fts_cur) { for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) { freep = p; p = p->fts_link != NULL ? p->fts_link : p->fts_parent; free(freep); } free(p); } /* Free up child linked list, sort array, path buffer. */ if (sp->fts_child) fts_lfree(sp->fts_child); if (sp->fts_array) free(sp->fts_array); free(sp->fts_path); free(sp->fts_wcspath); #ifdef FTS_WITH_ALLOC_CACHE # ifdef FTS_WITH_STATISTICS { struct _fts_private *priv = (struct _fts_private *)sp; fprintf(stderr, "numfree=%u allocs=%u hits=%u (%uppt) misses=%u (%uppt) other=%u\n", priv->numfree, priv->allocs, priv->hits, (unsigned)((double)priv->hits * 1000.0 / priv->allocs), priv->misses, (unsigned)((double)priv->misses * 1000.0 / priv->allocs), priv->allocs - priv->misses - priv->hits); } # endif #endif nt_fts_free_alloc_cache(sp); #ifdef FTS_WITH_DIRHANDLE_REUSE birdDirClose(&((struct _fts_private *)sp)->dirhandle); #endif /* Free up the stream pointer. */ free(sp); return (0); } /** * Frees a FTSENT structure by way of the allocation cache. */ static void fts_free_entry(FTS *sp, FTSENT *tmp) { if (tmp != NULL) { struct _fts_private *priv = (struct _fts_private *)sp; #ifdef FTS_WITH_ALLOC_CACHE size_t idx; #endif if (tmp->fts_dirfd == INVALID_HANDLE_VALUE) { /* There are probably more files than directories out there. */ } else { birdCloseFile(tmp->fts_dirfd); tmp->fts_dirfd = INVALID_HANDLE_VALUE; } #ifdef FTS_WITH_ALLOC_CACHE idx = (tmp->fts_alloc_size - sizeof(FTSENT)) >> FTS_FREE_BUCKET_SHIFT; if (idx < FTS_NUM_FREE_BUCKETS) { tmp->fts_link = priv->freebuckets[idx].head; priv->freebuckets[idx].head = tmp; } else { tmp->fts_link = priv->freebuckets[FTS_NUM_FREE_BUCKETS - 1].head; priv->freebuckets[FTS_NUM_FREE_BUCKETS - 1].head = tmp; } priv->numfree++; #else free(tmp); #endif } } /* * Special case of "/" at the end of the path so that slashes aren't * appended which would cause paths to be written as "....//foo". */ #define NAPPEND(p) ( p->fts_pathlen - (p->fts_path[p->fts_pathlen - 1] == '/') ) #define NAPPENDW(p) ( p->fts_cwcpath - (p->fts_wcspath[p->fts_cwcpath - 1] == L'/') ) FTSENT * FTSCALL nt_fts_read(FTS *sp) { FTSENT *p, *tmp; int instr; wchar_t *pwc; /* Set current node pointer. */ p = sp->fts_cur; /* If finished or unrecoverable error, return NULL. */ if (p != NULL && !ISSET(FTS_STOP)) { /* likely */ } else { return (NULL); } /* Save and zero out user instructions. */ instr = p->fts_instr; p->fts_instr = FTS_NOINSTR; /* Any type of file may be re-visited; re-stat and re-turn. */ if (instr != FTS_AGAIN) { /* likely */ } else { p->fts_info = fts_stat(sp, p, 0, INVALID_HANDLE_VALUE); return (p); } /* * Following a symlink -- SLNONE test allows application to see * SLNONE and recover. If indirecting through a symlink, have * keep a pointer to current location. If unable to get that * pointer, follow fails. * * NT: Since we don't change directory, we just set FTS_SYMFOLLOW * here in case a API client checks it. */ if ( instr != FTS_FOLLOW || (p->fts_info != FTS_SL && p->fts_info != FTS_SLNONE)) { /* likely */ } else { p->fts_info = fts_stat(sp, p, 1, INVALID_HANDLE_VALUE); if (p->fts_info == FTS_D /*&& !ISSET(FTS_NOCHDIR)*/) { p->fts_flags |= FTS_SYMFOLLOW; } return (p); } /* Directory in pre-order. */ if (p->fts_info == FTS_D) { /* If skipped or crossed mount point, do post-order visit. */ if ( instr == FTS_SKIP || (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) { if (sp->fts_child) { fts_lfree(sp->fts_child); sp->fts_child = NULL; } p->fts_info = FTS_DP; return (p); } /* Rebuild if only read the names and now traversing. */ if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) { CLR(FTS_NAMEONLY); fts_lfree(sp->fts_child); sp->fts_child = NULL; } /* * Cd to the subdirectory. * * If have already read and now fail to chdir, whack the list * to make the names come out right, and set the parent errno * so the application will eventually get an error condition. * Set the FTS_DONTCHDIR flag so that when we logically change * directories back to the parent we don't do a chdir. * * If haven't read do so. If the read fails, fts_build sets * FTS_STOP or the fts_info field of the node. */ if (sp->fts_child == NULL) { p = fts_build(sp, BREAD); if (p != NULL) { /* likely */ } else { if (ISSET(FTS_STOP)) return (NULL); return sp->fts_cur; } } else { p = sp->fts_child; sp->fts_child = NULL; } goto name; } /* Move to the next node on this level. */ next: tmp = p; if ((p = p->fts_link) != NULL) { /* * If reached the top, return to the original directory (or * the root of the tree), and load the paths for the next root. */ if (p->fts_level != FTS_ROOTLEVEL) { /* likely */ } else { fts_free_entry(sp, tmp); fts_load(sp, p); return (sp->fts_cur = p); } /* * User may have called fts_set on the node. If skipped, * ignore. If followed, get a file descriptor so we can * get back if necessary. */ if (p->fts_instr != FTS_SKIP) { /* likely */ } else { fts_free_entry(sp, tmp); goto next; } if (p->fts_instr != FTS_FOLLOW) { /* likely */ } else { p->fts_info = fts_stat(sp, p, 1, INVALID_HANDLE_VALUE); /* NT: See above regarding fts_flags. */ if (p->fts_info == FTS_D) { p->fts_flags |= FTS_SYMFOLLOW; } p->fts_instr = FTS_NOINSTR; } fts_free_entry(sp, tmp); name: if (!(sp->fts_options & FTS_NO_ANSI)) { char *t = sp->fts_path + NAPPEND(p->fts_parent); *t++ = '/'; memmove(t, p->fts_name, p->fts_namelen + 1); } pwc = sp->fts_wcspath + NAPPENDW(p->fts_parent); *pwc++ = '/'; memmove(pwc, p->fts_wcsname, (p->fts_cwcname + 1) * sizeof(wchar_t)); return (sp->fts_cur = p); } /* Move up to the parent node. */ p = tmp->fts_parent; if (p->fts_level != FTS_ROOTPARENTLEVEL) { /* likely */ } else { /* * Done; free everything up and set errno to 0 so the user * can distinguish between error and EOF. */ fts_free_entry(sp, tmp); fts_free_entry(sp, p); errno = 0; return (sp->fts_cur = NULL); } /* NUL terminate the pathname. */ if (!(sp->fts_options & FTS_NO_ANSI)) sp->fts_path[p->fts_pathlen] = '\0'; sp->fts_wcspath[ p->fts_cwcpath] = '\0'; /* * Return to the parent directory. If at a root node or came through * a symlink, go back through the file descriptor. Otherwise, cd up * one directory. * * NT: We're doing no fchdir, but we need to close the directory handle. */ if (p->fts_dirfd != INVALID_HANDLE_VALUE) { birdCloseFile(p->fts_dirfd); p->fts_dirfd = INVALID_HANDLE_VALUE; } fts_free_entry(sp, tmp); p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP; return (sp->fts_cur = p); } /* * Fts_set takes the stream as an argument although it's not used in this * implementation; it would be necessary if anyone wanted to add global * semantics to fts using fts_set. An error return is allowed for similar * reasons. */ /* ARGSUSED */ int FTSCALL nt_fts_set(FTS *sp, FTSENT *p, int instr) { if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW && instr != FTS_NOINSTR && instr != FTS_SKIP) { errno = EINVAL; return (1); } p->fts_instr = instr; return (0); } FTSENT * FTSCALL nt_fts_children(FTS *sp, int instr) { FTSENT *p; if (instr != 0 && instr != FTS_NAMEONLY) { errno = EINVAL; return (NULL); } /* Set current node pointer. */ p = sp->fts_cur; /* * Errno set to 0 so user can distinguish empty directory from * an error. */ errno = 0; /* Fatal errors stop here. */ if (ISSET(FTS_STOP)) return (NULL); /* Return logical hierarchy of user's arguments. */ if (p->fts_info == FTS_INIT) return (p->fts_link); /* * If not a directory being visited in pre-order, stop here. Could * allow FTS_DNR, assuming the user has fixed the problem, but the * same effect is available with FTS_AGAIN. */ if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */) return (NULL); /* Free up any previous child list. */ if (sp->fts_child != NULL) { fts_lfree(sp->fts_child); sp->fts_child = NULL; /* (bird - double free for _open(".") failure in original) */ } /* NT: Some BSD utility sets FTS_NAMEONLY? We don't really need this optimization, but since it only hurts that utility, it can stay. */ if (instr == FTS_NAMEONLY) { assert(0); /* don't specify FTS_NAMEONLY on NT. */ SET(FTS_NAMEONLY); instr = BNAMES; } else instr = BCHILD; return (sp->fts_child = fts_build(sp, instr)); } #ifndef fts_get_clientptr #error "fts_get_clientptr not defined" #endif void * (FTSCALL fts_get_clientptr)(FTS *sp) { return (fts_get_clientptr(sp)); } #ifndef fts_get_stream #error "fts_get_stream not defined" #endif FTS * (FTSCALL fts_get_stream)(FTSENT *p) { return (fts_get_stream(p)); } void FTSCALL nt_fts_set_clientptr(FTS *sp, void *clientptr) { sp->fts_clientptr = clientptr; } /* * This is the tricky part -- do not casually change *anything* in here. The * idea is to build the linked list of entries that are used by fts_children * and fts_read. There are lots of special cases. * * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is * set and it's a physical walk (so that symbolic links can't be directories), * we can do things quickly. First, if it's a 4.4BSD file system, the type * of the file is in the directory entry. Otherwise, we assume that the number * of subdirectories in a node is equal to the number of links to the parent. * The former skips all stat calls. The latter skips stat calls in any leaf * directories and for any files after the subdirectories in the directory have * been found, cutting the stat calls by about 2/3. * * NT: We do not do any link counting or stat avoiding, which invalidates the * above warnings. This function is very simple for us. */ static FTSENT * fts_build(FTS *sp, int type) { BirdDirEntryW_T *dp; FTSENT *p, *cur; FTSENT * volatile head,* volatile *tailp; /* volatile is to prevent aliasing trouble */ DIR *dirp; int saved_errno, doadjust, doadjust_utf16; long level; size_t len, cwcdir, maxlen, cwcmax, nitems; unsigned fDirOpenFlags; /* Set current node pointer. */ cur = sp->fts_cur; /* * Open the directory for reading. If this fails, we're done. * If being called from fts_read, set the fts_info field. * * NT: We do a two stage open so we can keep the directory handle around * after we've enumerated the directory. The dir handle is used by * us here and by the API users to more efficiently and safely open * members of the directory. */ fDirOpenFlags = BIRDDIR_F_EXTRA_INFO | BIRDDIR_F_KEEP_HANDLE; if (cur->fts_dirfd == INVALID_HANDLE_VALUE) { if (cur->fts_parent->fts_dirfd != INVALID_HANDLE_VALUE) { /* (This works fine for symlinks too, since we follow them.) */ cur->fts_dirfd = birdOpenFileExW(cur->fts_parent->fts_dirfd, cur->fts_wcsname, FILE_READ_DATA | SYNCHRONIZE, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, OBJ_CASE_INSENSITIVE); } else { cur->fts_dirfd = birdOpenFileW(cur->fts_wcsaccpath, FILE_READ_DATA | SYNCHRONIZE, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, OBJ_CASE_INSENSITIVE); } if (cur->fts_dirfd != INVALID_HANDLE_VALUE) { /* likely */ } else goto l_open_err; } else { fDirOpenFlags |= BIRDDIR_F_RESTART_SCAN; } #ifdef FTS_WITH_DIRHANDLE_REUSE dirp = birdDirOpenFromHandleWithReuse(&((struct _fts_private *)sp)->dirhandle, cur->fts_dirfd, NULL, fDirOpenFlags | BIRDDIR_F_STATIC_ALLOC); #else dirp = birdDirOpenFromHandle(cur->fts_dirfd, NULL, fDirOpenFlags); #endif if (dirp == NULL) { l_open_err: if (type == BREAD) { cur->fts_info = FTS_DNR; cur->fts_errno = errno; } return (NULL); } /* * Figure out the max file name length that can be stored in the * current path -- the inner loop allocates more path as necessary. * We really wouldn't have to do the maxlen calculations here, we * could do them in fts_read before returning the path, but it's a * lot easier here since the length is part of the dirent structure. */ if (sp->fts_options & FTS_NO_ANSI) { len = 0; maxlen = 0x10000; } else { len = NAPPEND(cur); len++; maxlen = sp->fts_pathlen - len; } cwcdir = NAPPENDW(cur); cwcdir++; cwcmax = sp->fts_cwcpath - len; level = cur->fts_level + 1; /* Read the directory, attaching each entry to the `link' pointer. */ doadjust = doadjust_utf16 = 0; nitems = 0; head = NULL; tailp = &head; while ((dp = birdDirReadW(dirp)) != NULL) { if (ISSET(FTS_SEEDOT) || !ISDOT(dp->d_name)) { /* assume dirs have two or more entries */ } else { continue; } if ((p = fts_alloc_utf16(sp, dp->d_name, dp->d_namlen)) != NULL) { /* likely */ } else { goto mem1; } /* include space for NUL */ if (p->fts_namelen < maxlen && p->fts_cwcname < cwcmax) { /* likely */ } else { void *oldaddr = sp->fts_path; wchar_t *oldwcspath = sp->fts_wcspath; if (fts_palloc(sp, p->fts_namelen >= maxlen ? len + p->fts_namelen + 1 : 0, p->fts_cwcname >= cwcmax ? cwcdir + p->fts_cwcname + 1 : 0)) { mem1: /* * No more memory for path or structures. Save * errno, free up the current structure and the * structures already allocated. */ saved_errno = errno; if (p) free(p); fts_lfree(head); #ifndef FTS_WITH_DIRHANDLE_REUSE birdDirClose(dirp); #endif birdCloseFile(cur->fts_dirfd); cur->fts_dirfd = INVALID_HANDLE_VALUE; cur->fts_info = FTS_ERR; SET(FTS_STOP); errno = saved_errno; return (NULL); } /* Did realloc() change the pointer? */ doadjust |= oldaddr != sp->fts_path; doadjust_utf16 |= oldwcspath != sp->fts_wcspath; maxlen = sp->fts_pathlen - len; cwcmax = sp->fts_cwcpath - cwcdir; } p->fts_level = level; p->fts_parent = sp->fts_cur; p->fts_pathlen = len + p->fts_namelen; p->fts_cwcpath = cwcdir + p->fts_cwcname; p->fts_accpath = p->fts_path; p->fts_wcsaccpath = p->fts_wcspath; p->fts_stat = dp->d_stat; p->fts_info = fts_process_stats(p, &dp->d_stat); /* We walk in directory order so "ls -f" doesn't get upset. */ p->fts_link = NULL; *tailp = p; tailp = &p->fts_link; ++nitems; } #ifndef FTS_WITH_DIRHANDLE_REUSE birdDirClose(dirp); #endif /* * If realloc() changed the address of the path, adjust the * addresses for the rest of the tree and the dir list. */ if (doadjust) fts_padjust(sp, head); if (doadjust_utf16) fts_padjustw(sp, head); /* If didn't find anything, return NULL. */ if (!nitems) { if (type == BREAD) cur->fts_info = FTS_DP; return (NULL); } /* Sort the entries. */ if (sp->fts_compar && nitems > 1) head = fts_sort(sp, head, nitems); return (head); } /** * @note Only used on NT with input arguments, FTS_AGAIN, and links that needs * following. On link information is generally retrieved during directory * enumeration on NT, in line with it's DOS/OS2/FAT API heritage. */ static int fts_stat(FTS *sp, FTSENT *p, int follow, HANDLE dfd) { int saved_errno; const wchar_t *wcspath; if (dfd == INVALID_HANDLE_VALUE) { wcspath = p->fts_wcsaccpath; } else { wcspath = p->fts_wcsname; } /* * If doing a logical walk, or application requested FTS_FOLLOW, do * a stat(2). If that fails, check for a non-existent symlink. If * fail, set the errno from the stat call. */ if (ISSET(FTS_LOGICAL) || follow) { if (birdStatAtW(dfd, wcspath, &p->fts_stat, 1 /*fFollowLink*/)) { saved_errno = errno; if (birdStatAtW(dfd, wcspath, &p->fts_stat, 0 /*fFollowLink*/)) { p->fts_errno = saved_errno; goto err; } errno = 0; if (S_ISLNK(p->fts_stat.st_mode)) return (FTS_SLNONE); } } else if (birdStatAtW(dfd, wcspath, &p->fts_stat, 0 /*fFollowLink*/)) { p->fts_errno = errno; err: memset(&p->fts_stat, 0, sizeof(struct stat)); return (FTS_NS); } return fts_process_stats(p, &p->fts_stat); } /* Shared between fts_stat and fts_build. */ static int fts_process_stats(FTSENT *p, BirdStat_T const *sbp) { if (S_ISDIR(sbp->st_mode)) { FTSENT *t; fts_dev_t dev; fts_ino_t ino; /* * Set the device/inode. Used to find cycles and check for * crossing mount points. Also remember the link count, used * in fts_build to limit the number of stat calls. It is * understood that these fields are only referenced if fts_info * is set to FTS_D. */ dev = p->fts_dev = sbp->st_dev; ino = p->fts_ino = sbp->st_ino; p->fts_nlink = sbp->st_nlink; if (ISDOT(p->fts_wcsname)) return (FTS_DOT); /* * Cycle detection is done by brute force when the directory * is first encountered. If the tree gets deep enough or the * number of symbolic links to directories is high enough, * something faster might be worthwhile. */ for (t = p->fts_parent; t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent) if (ino == t->fts_ino && dev == t->fts_dev) { p->fts_cycle = t; return (FTS_DC); } return (FTS_D); } if (S_ISLNK(sbp->st_mode)) return (FTS_SL); if (S_ISREG(sbp->st_mode)) return (FTS_F); return (FTS_DEFAULT); } /* * The comparison function takes pointers to pointers to FTSENT structures. * Qsort wants a comparison function that takes pointers to void. * (Both with appropriate levels of const-poisoning, of course!) * Use a trampoline function to deal with the difference. */ static int fts_compar(const void *a, const void *b) { FTS *parent; parent = (*(const FTSENT * const *)a)->fts_fts; return (*parent->fts_compar)(a, b); } static FTSENT * fts_sort(FTS *sp, FTSENT *head, size_t nitems) { FTSENT **ap, *p; /* * Construct an array of pointers to the structures and call qsort(3). * Reassemble the array in the order returned by qsort. If unable to * sort for memory reasons, return the directory entries in their * current order. Allocate enough space for the current needs plus * 40 so don't realloc one entry at a time. */ if (nitems > sp->fts_nitems) { void *ptr; sp->fts_nitems = nitems + 40; ptr = realloc(sp->fts_array, sp->fts_nitems * sizeof(FTSENT *)); if (ptr != NULL) { sp->fts_array = ptr; } else { free(sp->fts_array); sp->fts_array = NULL; sp->fts_nitems = 0; return (head); } } for (ap = sp->fts_array, p = head; p; p = p->fts_link) *ap++ = p; qsort(sp->fts_array, nitems, sizeof(FTSENT *), fts_compar); for (head = *(ap = sp->fts_array); --nitems; ++ap) ap[0]->fts_link = ap[1]; ap[0]->fts_link = NULL; return (head); } static FTSENT * fts_alloc(FTS *sp, char const *name, size_t namelen, wchar_t const *wcsname, size_t cwcname) { struct _fts_private *priv = (struct _fts_private *)sp; FTSENT *p; size_t len; #ifdef FTS_WITH_ALLOC_CACHE size_t aligned; size_t idx; #endif #if defined(FTS_WITH_STATISTICS) && defined(FTS_WITH_ALLOC_CACHE) priv->allocs++; #endif /* * The file name is a variable length array. Allocate the FTSENT * structure and the file name. */ len = sizeof(FTSENT) + (cwcname + 1) * sizeof(wchar_t); if (!(sp->fts_options & FTS_NO_ANSI)) len += namelen + 1; /* * To speed things up we cache entries. This code is a little insane, * but that's preferable to slow code. */ #ifdef FTS_WITH_ALLOC_CACHE aligned = (len + FTS_ALIGN_FTSENT + 1) & ~(size_t)(FTS_ALIGN_FTSENT - 1); idx = ((aligned - sizeof(FTSENT)) >> FTS_FREE_BUCKET_SHIFT); if ( idx < FTS_NUM_FREE_BUCKETS && (p = priv->freebuckets[idx].head) && p->fts_alloc_size >= len) { priv->freebuckets[idx].head = p->fts_link; priv->numfree--; # ifdef FTS_WITH_STATISTICS priv->hits++; # endif } else { # ifdef FTS_WITH_STATISTICS priv->misses++; # endif p = malloc(aligned); if (p) { p->fts_alloc_size = (unsigned)aligned; } else { nt_fts_free_alloc_cache(sp); p = malloc(len); if (!p) return NULL; p->fts_alloc_size = (unsigned)len; } } #else /* !FTS_WITH_ALLOC_CACHE */ p = malloc(len); if (p) { p->fts_alloc_size = (unsigned)len; } else { return NULL; } #endif /* !FTS_WITH_ALLOC_CACHE */ /* Copy the names and guarantee NUL termination. */ p->fts_wcsname = (wchar_t *)(p + 1); memcpy(p->fts_wcsname, wcsname, cwcname * sizeof(wchar_t)); p->fts_wcsname[cwcname] = '\0'; p->fts_cwcname = cwcname; if (!(sp->fts_options & FTS_NO_ANSI)) { p->fts_name = (char *)(p->fts_wcsname + cwcname + 1); memcpy(p->fts_name, name, namelen); p->fts_name[namelen] = '\0'; p->fts_namelen = namelen; } else { p->fts_name = NULL; p->fts_namelen = 0; } p->fts_path = sp->fts_path; p->fts_wcspath = sp->fts_wcspath; p->fts_statp = &p->fts_stat; p->fts_errno = 0; p->fts_flags = 0; p->fts_instr = FTS_NOINSTR; p->fts_number = 0; p->fts_pointer = NULL; p->fts_fts = sp; p->fts_dirfd = INVALID_HANDLE_VALUE; return (p); } /** * Converts the ANSI name to UTF-16 and calls fts_alloc. * * @returns Pointer to allocated and mostly initialized FTSENT structure on * success. NULL on failure, caller needs to record it. * @param sp Pointer to FTS instance. * @param name The ANSI name. * @param namelen The ANSI name length. */ static FTSENT * fts_alloc_ansi(FTS *sp, char const *name, size_t namelen) { MY_UNICODE_STRING UniStr; MY_ANSI_STRING AnsiStr; MY_NTSTATUS rcNt; FTSENT *pRet; UniStr.Buffer = NULL; UniStr.MaximumLength = UniStr.Length = 0; AnsiStr.Buffer = (char *)name; AnsiStr.Length = AnsiStr.MaximumLength = (USHORT)namelen; rcNt = g_pfnRtlAnsiStringToUnicodeString(&UniStr, &AnsiStr, TRUE /*fAllocate*/); if (NT_SUCCESS(rcNt)) { pRet = fts_alloc(sp, name, namelen, UniStr.Buffer, UniStr.Length / sizeof(wchar_t)); HeapFree(GetProcessHeap(), 0, UniStr.Buffer); } else { pRet = NULL; } return pRet; } /** * Converts the UTF-16 name to ANSI (if necessary) and calls fts_alloc. * * @returns Pointer to allocated and mostly initialized FTSENT structure on * success. NULL on failure, caller needs to record it. * @param sp Pointer to the FTS instance. * @param wcsname The UTF-16 name. * @param cwcname The UTF-16 name length. */ static FTSENT * fts_alloc_utf16(FTS *sp, wchar_t const *wcsname, size_t cwcname) { FTSENT *pRet; if (sp->fts_options & FTS_NO_ANSI) { pRet = fts_alloc(sp, NULL, 0, wcsname, cwcname); } else { MY_UNICODE_STRING UniStr; MY_ANSI_STRING AnsiStr; MY_NTSTATUS rcNt; UniStr.Buffer = (wchar_t *)wcsname; UniStr.MaximumLength = UniStr.Length = (USHORT)(cwcname * sizeof(wchar_t)); AnsiStr.Buffer = NULL; AnsiStr.Length = AnsiStr.MaximumLength = 0; rcNt = g_pfnRtlUnicodeStringToAnsiString(&AnsiStr, &UniStr, TRUE /*fAllocate*/); if (NT_SUCCESS(rcNt)) { pRet = fts_alloc(sp, AnsiStr.Buffer, AnsiStr.Length, wcsname, cwcname); HeapFree(GetProcessHeap(), 0, AnsiStr.Buffer); } else { pRet = NULL; } } return pRet; } /** * Frees up the FTSENT allocation cache. * * Used by nt_fts_close, but also called by fts_alloc on alloc failure. * * @param sp Pointer to the FTS instance. */ static void nt_fts_free_alloc_cache(FTS *sp) { #ifdef FTS_WITH_ALLOC_CACHE struct _fts_private *priv = (struct _fts_private *)sp; unsigned i = K_ELEMENTS(priv->freebuckets); while (i-- > 0) { FTSENT *cur = priv->freebuckets[i].head; priv->freebuckets[i].head = NULL; while (cur) { FTSENT *freeit = cur; cur = cur->fts_link; free(freeit); } } priv->numfree = 0; #else (void)sp; #endif } static void fts_lfree(FTSENT *head) { FTSENT *p; /* Free a linked list of structures. */ while ((p = head)) { head = head->fts_link; assert(p->fts_dirfd == INVALID_HANDLE_VALUE); free(p); } } /* * Allow essentially unlimited paths; find, rm, ls should all work on any tree. * Most systems will allow creation of paths much longer than MAXPATHLEN, even * though the kernel won't resolve them. Add the size (not just what's needed) * plus 256 bytes so don't realloc the path 2 bytes at a time. */ static int fts_palloc(FTS *sp, size_t more, size_t cwcmore) { void *ptr; /** @todo Isn't more and cwcmore minimum buffer sizes rather than what needs * to be added to the buffer?? This code makes no sense when looking at * the way the caller checks things out! */ if (more) { sp->fts_pathlen += more + 256; ptr = realloc(sp->fts_path, sp->fts_pathlen); if (ptr) { sp->fts_path = ptr; } else { free(sp->fts_path); sp->fts_path = NULL; free(sp->fts_wcspath); sp->fts_wcspath = NULL; return 1; } } if (cwcmore) { sp->fts_cwcpath += cwcmore + 256; ptr = realloc(sp->fts_wcspath, sp->fts_cwcpath); if (ptr) { sp->fts_wcspath = ptr; } else { free(sp->fts_path); sp->fts_path = NULL; free(sp->fts_wcspath); sp->fts_wcspath = NULL; return 1; } } return 0; } /* * When the path is realloc'd, have to fix all of the pointers in structures * already returned. */ static void fts_padjust(FTS *sp, FTSENT *head) { FTSENT *p; char *addr = sp->fts_path; #define ADJUST(p) do { \ if ((p)->fts_accpath != (p)->fts_name) { \ (p)->fts_accpath = \ (char *)addr + ((p)->fts_accpath - (p)->fts_path); \ } \ (p)->fts_path = addr; \ } while (0) /* Adjust the current set of children. */ for (p = sp->fts_child; p; p = p->fts_link) ADJUST(p); /* Adjust the rest of the tree, including the current level. */ for (p = head; p->fts_level >= FTS_ROOTLEVEL;) { ADJUST(p); p = p->fts_link ? p->fts_link : p->fts_parent; } } /* * When the UTF-16 path is realloc'd, have to fix all of the pointers in * structures already returned. */ static void fts_padjustw(FTS *sp, FTSENT *head) { FTSENT *p; wchar_t *addr = sp->fts_wcspath; #define ADJUSTW(p) \ do { \ if ((p)->fts_wcsaccpath != (p)->fts_wcsname) \ (p)->fts_wcsaccpath = addr + ((p)->fts_wcsaccpath - (p)->fts_wcspath); \ (p)->fts_wcspath = addr; \ } while (0) /* Adjust the current set of children. */ for (p = sp->fts_child; p; p = p->fts_link) ADJUSTW(p); /* Adjust the rest of the tree, including the current level. */ for (p = head; p->fts_level >= FTS_ROOTLEVEL;) { ADJUSTW(p); p = p->fts_link ? p->fts_link : p->fts_parent; } } static size_t fts_maxarglen(char * const *argv) { size_t len, max; for (max = 0; *argv; ++argv) if ((len = strlen(*argv)) > max) max = len; return (max + 1); } /** Returns the max string size (including term). */ static size_t fts_maxarglenw(wchar_t * const *argv) { size_t max = 0; for (; *argv; ++argv) { size_t len = wcslen(*argv); if (len > max) max = len; } return max + 1; } kbuild-3149/src/lib/kStuff/0000755000175000017500000000000013252530254015504 5ustar locutuslocutuskbuild-3149/src/lib/kStuff/Makefile.kmk0000644000175000017500000000355413252530254017734 0ustar locutuslocutus# $Id: Makefile.kmk 29 2009-07-01 20:30:29Z bird $ ## @file # kStuff - Top-level makefile. # # # Copyright (c) 2006-2007 Knut St. Osmundsen # # 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. # DEPTH = . include $(PATH_KBUILD)/subheader.kmk include $(PATH_SUB_CURRENT)/kCpu/Makefile.kmk include $(PATH_SUB_CURRENT)/kDbg/Makefile.kmk include $(PATH_SUB_CURRENT)/kErr/Makefile.kmk include $(PATH_SUB_CURRENT)/kLdr/Makefile.kmk include $(PATH_SUB_CURRENT)/kRdr/Makefile.kmk include $(PATH_SUB_CURRENT)/kHlp/Makefile.kmk ifn1of ($(KBUILD_TARGET), darwin) include $(PATH_SUB_CURRENT)/kProfiler2/Makefile.kmk endif LIBRARIES += kStuffStatic kStuffStatic_TEMPLATE = kStuffLIB kStuffStatic_SOURCES = \ $(TARGET_kCpuStatic) \ $(TARGET_kDbgStatic) \ $(TARGET_kErrStatic) \ $(TARGET_kLdrStatic) \ $(TARGET_kRdrStatic) include $(PATH_KBUILD)/subfooter.kmk kbuild-3149/src/lib/kStuff/kProfiler2/0000755000175000017500000000000013252530254017523 5ustar locutuslocutuskbuild-3149/src/lib/kStuff/kProfiler2/kPrf2WinApi-dumpbin.sed0000644000175000017500000000435413252530254023756 0ustar locutuslocutus# $Id: kPrf2WinApi-dumpbin.sed 29 2009-07-01 20:30:29Z bird $ ## @file # Strip down dumpbin /export output. # # # Copyright (c) 2008 Knut St. Osmundsen # # 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. # # # State switch # x /^exports$/b exports /^summary$/b summary b header # # Header # :header x /^[[:space:]][[:space:]]*ordinal[[:space:]]*name[[:space:]]*$/b switch_to_exports b drop_line # # Exports # :switch_to_exports s/^.*$/exports/ h b drop_line :exports x /^[[:space:]][[:space:]]*Summary[[:space:]]*$/b switch_to_summary s/^[[:space:]]*// s/[[:space:]]*$// s/[[:space:]][[:space:]]*/ /g /^$/b drop_line # Filter out APIs that hasn't been implemented. /AddLocalAlternateComputerNameA/b drop_line /AddLocalAlternateComputerNameW/b drop_line /EnumerateLocalComputerNamesA/b drop_line /EnumerateLocalComputerNamesW/b drop_line /RemoveLocalAlternateComputerNameA/b drop_line /RemoveLocalAlternateComputerNameW/b drop_line /SetLocalPrimaryComputerNameA/b drop_line /SetLocalPrimaryComputerNameW/b drop_line /__C_specific_handler/b drop_line /__misaligned_access/b drop_line /_local_unwind/b drop_line b end # # Summary # :switch_to_summary s/^.*$/summary/ h b drop_line :summary x b drop_line # # Tail # :drop_line d :end kbuild-3149/src/lib/kStuff/kProfiler2/tstlongjmp.c0000644000175000017500000000172713252530254022077 0ustar locutuslocutus #include #include /* just try trick the compiler into not optimizing stuff by making it "uncertain" which path to take. */ int always_true(void) { time_t t = time(NULL); if (t == time(NULL)) return 1; if (t != time(NULL)) return 1; if (t == time(NULL)) return 1; if (t != time(NULL)) return 1; return 0; } jmp_buf g_JmpBuf; int onelevel(void) { if (always_true()) longjmp(g_JmpBuf, 1); return 0; } int twolevels_inner(void) { if (always_true()) longjmp(g_JmpBuf, 1); return 0; } int twolevels_outer(void) { int rc; always_true(); rc = twolevels_inner(); always_true(); return rc; } int main() { int rc = 1; /* first */ if (!setjmp(g_JmpBuf)) rc = onelevel(); /* second */ if (!setjmp(g_JmpBuf)) rc = twolevels_outer(); return rc != 1; } kbuild-3149/src/lib/kStuff/kProfiler2/Makefile.kmk0000644000175000017500000002134113252530254021745 0ustar locutuslocutus# $Id: Makefile.kmk 29 2009-07-01 20:30:29Z bird $ ## @file # kProfiler Mark 2, sub-makefile. # # # Copyright (c) 2006-2007 Knut St. Osmundsen # # 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. # DEPTH ?= .. SUB_DEPTH = .. include $(PATH_KBUILD)/subheader.kmk #LIBRARIES += kPrf2GC kPrf2R0 DLLS += kPrf2 PROGRAMS += kPrf2Read # # Our template. # TEMPLATE_kPrf2 = kProfiler Template if1of ($(BUILD_TARGET), win) TEMPLATE_kPrf2_EXTENDS = kStuff else # Eliminate these TEMPLATE_kPrf2_TOOL = GCC3 TEMPLATE_kPrf2_TOOL.os2 = GCC3OMF TEMPLATE_kPrf2_TOOL.win.x86 = VCC70 TEMPLATE_kPrf2_TOOL.win.amd64 = VCC80AMD64 TEMPLATE_kPrf2_ASTOOL = YASM TEMPLATE_kPrf2_ASTOOL.os2 = NASM TEMPLATE_kPrf2_SDKS.win = WINPSDK TEMPLATE_kPrf2_CXXFLAGS.freebsd = -g TEMPLATE_kPrf2_CXXFLAGS.linux = -g TEMPLATE_kPrf2_CXXFLAGS.os2 = -g TEMPLATE_kPrf2_CXXFLAGS.win = -Zi -Zl -W3 -GF -GR- TEMPLATE_kPrf2_CXXFLAGS.win.amd64 = -GS- #-FAcs ifneq ($(BUILD_TYPE),debug) TEMPLATE_kPrf2_CXXFLAGS.freebsd+= -O3 TEMPLATE_kPrf2_CXXFLAGS.linux += -O3 TEMPLATE_kPrf2_CXXFLAGS.os2 += -O3 TEMPLATE_kPrf2_CXXFLAGS.win += -O2b2 endif TEMPLATE_kPrf2_ASFLAGS.freebsd = -f elf TEMPLATE_kPrf2_ASFLAGS.linux = -f elf TEMPLATE_kPrf2_ASFLAGS.os2 = -f omf TEMPLATE_kPrf2_ASFLAGS.win.x86 = -f win32 -g cv8 TEMPLATE_kPrf2_ASFLAGS.win.amd64 = -f win64 -g cv8 TEMPLATE_kPrf2_INCS = \ ../include TEMPLATE_kPrf2_LDFLAGS.freebsd = -g TEMPLATE_kPrf2_LDFLAGS.linux = -g TEMPLATE_kPrf2_LDFLAGS.os2 = -g TEMPLATE_kPrf2_LDFLAGS.win = /DEBUG TEMPLATE_kPrf2_LIBS.freebsd = TEMPLATE_kPrf2_LIBS.linux = TEMPLATE_kPrf2_LIBS.os2 = TEMPLATE_kPrf2_LIBS.win = \ $(PATH_SDK_WINPSDK_LIB)/psapi.Lib TEMPLATE_kPrf2_LIBS.win.x86 = \ $(PATH_TOOL_VCC70_LIB)/libcmt.lib \ $(PATH_TOOL_VCC70_LIB)/oldnames.lib TEMPLATE_kPrf2_LIBS.win.amd64 = \ $(PATH_TOOL_VCC80AMD64_LIB)/oldnames.lib \ $(PATH_TOOL_VCC80AMD64_LIB)/libcmt.lib endif # # kPrf2 - The profiler module. # kPrf2_TEMPLATE = kPrf2 kPrf2_DEFS.x86 = KPRF_BITS=32 kPrf2_DEFS.amd64 = KPRF_BITS=64 kPrf2_LDFLAGS.win.amd64 = -Entry:DllMain kPrf2_SOURCES = \ kProfileR3.cpp # kProfileGC.cpp # kProfileR0.cpp kPrf2_SOURCES.win = \ dllmain-win.cpp \ kPrf2WinApiWrapperHlp.c \ prf$(BUILD_TARGET_ARCH)msc.asm \ kPrf2-win-$(BUILD_TARGET_ARCH).def prfx86msc.asm_DEFS.win.x86 = \ KPRF_ENTER=_KPrfEnter \ KPRF_LEAVE=_KPrfLeave prfamd64msc.asm_DEFS.win.amd64 = \ KPRF_ENTER=KPrfEnter \ KPRF_LEAVE=KPrfLeave # # kPrf2Read - The read & producer of statistics. # kPrf2Read_TEMPLATE = kStuffEXE kPrf2Read_SOURCES = \ kPrf2Read.cpp kPrf2Read_LIBS = \ $(PATH_LIB)/kDbgStatic$(SUFF_LIB) \ $(PATH_LIB)/kRdrStatic$(SUFF_LIB) \ $(PATH_LIB)/kHlpCRTStatic$(SUFF_LIB) # # kPrf2WinApiWrappers # IMPORT_LIBS.win += kPrf2WinApiWrappersImp kPrf2WinApiWrappersImp_TEMPLATE = kStuffEXE kPrf2WinApiWrappersImp_SOURCES.x86 = kPrf2WinApiWrappersImp-x86.def kPrf2WinApiWrappersImp_SOURCES.amd64 = kPrf2WinApiWrappersImp-amd64.def DLLS.win += kPrf2WinApiWrappers kPrf2WinApiWrappers_TEMPLATE = kPrf2 kPrf2WinApiWrappers_CFLAGS = -GH -Gh kPrf2WinApiWrappers_LDFLAGS.win.x86 = -Entry:DllMain@12 kPrf2WinApiWrappers_LDFLAGS.win.amd64 = -Entry:DllMain kPrf2WinApiWrappers_SOURCES = \ kPrf2WinApiWrappers.c \ kPrf2WinApiWrappersImp-$(BUILD_TARGET_ARCH).def kPrf2WinApiWrappers_LIBS = \ $(PATH_kPrf2)/kPrf2.lib ifeq (0,1) kPrf2WinApiWrappers-kernel32.h: $(SED) -f kPrf2WinApi-pre.sed --output $@.tmp \ $(PATH_SDK_WINPSDK_INC)/WinBase.h \ $(PATH_SDK_WINPSDK_INC)/WinCon.h \ $(PATH_SDK_WINPSDK_INC)/WinNLS.h \ $(PATH_SDK_WINPSDK_INC)/WinVer.h \ $(PATH_SDK_WINPSDK_INC)/WinNT.h \ $(PATH_SDK_WINPSDK_INC)/TlHelp32.h $(APPEND) $@.tmp 'BOOL WINAPI ReplaceFile( LPCSTR lpReplacedFileName, LPCSTR lpReplacementFileName, LPCSTR lpBackupFileName, DWORD dwReplaceFlags, LPVOID lpExclude, LPVOID lpReserved );' $(APPEND) $@.tmp 'BOOL WINAPI SetConsoleCursor( PVOID pvUnknown1, PVOID pvUnknown2 );' $(APPEND) $@.tmp 'LPCH WINAPI GetEnvironmentStringsA( VOID );' $(APPEND) $@.tmp 'BOOL WINAPI GetBinaryType( LPCSTR lpApplicationName, LPDWORD lpBinaryType );' $(APPEND) $@.tmp 'WORD NTAPI RtlCaptureStackBackTrace( DWORD FramesToSkip, DWORD FramesToCapture, PVOID * BackTrace, PDWORD BackTraceHash );' $(APPEND) $@.tmp 'PVOID RtlFillMemory( PVOID pv, int ch, SIZE_T cb );' $(APPEND) $@.tmp 'PVOID RtlZeroMemory( PVOID pv, SIZE_T cb );' $(APPEND) $@.tmp 'PVOID RtlMoveMemory( PVOID pvDst, PVOID pvSrc, SIZE_T cb );' $(APPEND) $@.tmp 'VOID NTAPI RtlUnwind( PVOID TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue );' $(APPEND) $@.tmp 'VOID NTAPI RtlUnwindEx( FRAME_POINTERS TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue, PCONTEXT ContextRecord, PUNWIND_HISTORY_TABLE HistoryTable );' $(APPEND) $@.tmp 'ULONGLONG WINAPI RtlVirtualUnwind( ULONG HandlerType, ULONGLONG ImageBase, ULONGLONG ControlPC, PRUNTIME_FUNCTION FunctionEntry, PCONTEXT ContextRecord, PBOOLEAN InFunction, PFRAME_POINTERS EstablisherFrame, PKNONVOLATILE_CONTEXT_POINTERS ContextPointers );' $(APPEND) $@.tmp 'PVOID WINAPI RtlPcToFileHeader( PVOID PcValue, PVOID * BaseOfImage );' $(APPEND) $@.tmp 'PVOID WINAPI RtlLookupFunctionEntry( ULONGLONG ControlPC, PULONGLONG ImageBase, PULONGLONG TargetGp );' $(APPEND) $@.tmp 'void WINAPI RtlRaiseException(PEXCEPTION_RECORD pXcpRec);' $(APPEND) $@.tmp 'int WINAPI uaw_lstrcmpW( LPCUWSTR lpString1, LPCUWSTR lpString2 );' $(APPEND) $@.tmp 'int WINAPI uaw_lstrcmpiW( LPCUWSTR lpString1, LPCUWSTR lpString2 );' $(APPEND) $@.tmp 'int WINAPI uaw_lstrlenW( LPCUWSTR lpString );' $(APPEND) $@.tmp 'LPUWSTR WINAPI uaw_wcschr( LPCUWSTR lpString, WCHAR wc );' $(APPEND) $@.tmp 'LPUWSTR WINAPI uaw_wcscpy( LPUWSTR lpDst, LPCUWSTR lpSrc );' $(APPEND) $@.tmp 'int WINAPI uaw_wcsicmp( LPCUWSTR lp1, LPCUWSTR lp2 );' $(APPEND) $@.tmp 'SIZE_T WINAPI uaw_wcslen( LPCUWSTR lp1 );' $(APPEND) $@.tmp 'LPUWSTR WINAPI uaw_wcsrchr( LPCUWSTR lpString, WCHAR wc );' $(APPEND) $@.tmp 'LPSTR WINAPI lstrcat( LPSTR lpString1, LPCSTR lpString2 );' $(APPEND) $@.tmp 'int WINAPI lstrcmp( LPCSTR lpString1, LPCSTR lpString2 );' $(APPEND) $@.tmp 'int WINAPI lstrcmpi( LPCSTR lpString1, LPCSTR lpString2 );' $(APPEND) $@.tmp 'LPSTR WINAPI lstrcpy( LPSTR lpString1, LPCSTR lpString2 );' $(APPEND) $@.tmp 'LPSTR WINAPI lstrcpyn( LPSTR lpString1, LPCSTR lpString2, int iMaxLength );' $(APPEND) $@.tmp 'int WINAPI lstrlen( LPCSTR lpString );' $(SED) -f kPrf2WinApi-gencode.sed --output $@ $@.tmp $(RM) -f $@.tmp kPrf2WinApiWrappersImp-$(KBUILD_TARGET_ARCH).def: $(RM) -f $@ $(PATH_TOOL_$(TEMPLATE_kStuff_TOOL.win.$(BUILD_TARGET_ARCH))_BIN)/dumpbin.exe /EXPORTS /OUT:$@.tmp $(PATH_SDK_WINPSDK_LIB)/Kernel32.lib $(SED) -f kPrf2WinApi-dumpbin.sed --output $@.tmp2 $@.tmp $(APPEND) $@ 'LIBRARY kPrf2WinApiWrappers' $(APPEND) $@ 'EXPORTS' $(SED) -f kPrf2WinApi-genimp.sed --append $@ $@.tmp2 $(RM) -f $@.tmp $@.tmp2 endif # # A simple testcase. # PROGRAMS.win.x86 += tst tst_TOOL = VCC70 tst_SDKS = WINPSDK tst_CFLAGS = -GH -Gh -Zi -Zl -GR- -GX- -GF- -W3 -wd4244 tst_SOURCES = tst.c tst.c_CFLAGS = -Od tst_LDFLAGS = /DEBUG tst_LIBS = \ $(PATH_TOOL_VCC70_LIB)/msvcrt.lib \ $(PATH_TOOL_VCC70_LIB)/msvcprt.lib \ $(PATH_TOOL_VCC70_LIB)/oldnames.lib \ $(PATH_kPrf2)/kPrf2.lib PROGRAMS += tstlongjmp tstlongjmp_TEMPLATE = kStuffEXE tstlongjmp_CFLAGS.win = -GH -Gh -Zi tstlongjmp_SOURCES = tstlongjmp.c tstlongjmp_LIBS = \ $(PATH_kPrf2)/kPrf2.lib # Generate the rules include $(PATH_KBUILD)/subfooter.kmk # # Aliases for .cpp.h files so we can more easily do syntax checking from the editor. # CORE := $(wildcard *core*.cpp.h *core*.h.h) $(CORE:.h=.o) $(CORE:.h=.obj) : kProfileR3.o READ := $(wildcard *read*.cpp.h *read*.h.h) $(READ:.h=.o) $(READ:.h=.obj) : kPrf2Read.o kbuild-3149/src/lib/kStuff/kProfiler2/kPrf2Read.cpp0000644000175000017500000003475513252530254022025 0ustar locutuslocutus/* $Id: kPrf2Read.cpp 77 2016-06-22 17:03:55Z bird $ */ /** @file * kProfiler Mark 2 - The reader and producer of statistics. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #include #include /** @def KPRF_OFF2PTR * Internal helper for converting a offset to a pointer. * @internal */ #define KPRF_OFF2PTR(TypePrefix, TypeName, off, pHdr) \ ( (KPRF_TYPE(TypePrefix, TypeName)) ((off) + (KUPTR)pHdr) ) /** @def KPRF_ALIGN * The usual align macro. * @internal */ #define KPRF_ALIGN(n, align) ( ((n) + ( (align) - 1)) & ~((align) - 1) ) /** @def KPRF_OFFSETOF * My usual extended offsetof macro, except this returns KU32 and mangles the type name. * @internal */ #define KPRF_OFFSETOF(kPrfType, Member) ( (KU32)(KUPTR)&((KPRF_TYPE(P,kPrfType))0)->Member ) /** @def PRF_SIZEOF * Size of a kPrf type. * @internal */ #define KPRF_SIZEOF(kPrfType) sizeof(KPRF_TYPE(,kPrfType)) #ifdef _MSC_VER # define KPRF_FMT_U64 "I64u" # define KPRF_FMT_X64 "I64x" # define KPRF_FMT_I64 "I64d" #else # define KPRF_FMT_X64 "llx" # define KPRF_FMT_U64 "llu" # define KPRF_FMT_I64 "lld" #endif /* * Instantiate the readers. */ /* 32-bit */ #define KPRF_NAME(Suffix) KPrf32##Suffix #define KPRF_TYPE(Prefix,Suffix) Prefix##KPRF32##Suffix #define KPRF_BITS 32 #define KPRF_FMT_UPTR "#010x" #include "prfcore.h.h" #include "prfreader.cpp.h" #undef KPRF_FMT_UPTR #undef KPRF_NAME #undef KPRF_TYPE #undef KPRF_BITS /* 64-bit */ #define KPRF_NAME(Suffix) KPrf64##Suffix #define KPRF_TYPE(Prefix,Suffix) Prefix##KPRF64##Suffix #define KPRF_BITS 64 #ifdef _MSC_VER # define KPRF_FMT_UPTR "#018I64x" #else # define KPRF_FMT_UPTR "#018llx" #endif #include "prfcore.h.h" #include "prfreader.cpp.h" #undef KPRF_FMT_UPTR #undef KPRF_NAME #undef KPRF_TYPE #undef KPRF_BITS /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * Header union type. */ typedef union KPRFHDR { KPRF32HDR Hdr32; KPRF64HDR Hdr64; } KPRFHDR; typedef KPRFHDR *PKPRFHDR; typedef const KPRFHDR *PCKPRFHDR; /** * Read the data set into memory. * * @returns Pointer to the loaded data set. (release using free()). * * @param pszFilename The path to the profiler data set. * @param pcb Where to store the size of the data set. * @param pOut Where to write errors. */ PKPRFHDR kPrfLoad(const char *pszFilename, KU32 *pcb, FILE *pOut) { FILE *pFile = fopen(pszFilename, "rb"); if (!pFile) { fprintf(pOut, "Cannot open '%s' for reading!\n", pszFilename); return NULL; } /* * Read the file into memory. */ long cbFile; if ( !fseek(pFile, 0, SEEK_END) && (cbFile = ftell(pFile)) >= 0 && !fseek(pFile, 0, SEEK_SET) ) { if (pcb) *pcb = cbFile; void *pvData = malloc(cbFile); if (pvData) { if (fread(pvData, cbFile, 1, pFile)) { fclose(pFile); return (PKPRFHDR)pvData; } fprintf(pOut, "Failed reading '%s' into memory!\n", pszFilename); free(pvData); } else fprintf(pOut, "Failed to allocate %ld bytes of memory for reading the file '%s' into!\n", cbFile, pszFilename); } else fprintf(pOut, "Failed to determin the size of '%s'!\n", pszFilename); fclose(pFile); return NULL; } /** * Validates the data set * * @returns true if valid. * @returns false if invalid. * * @param pHdr Pointer to the data set. * @param cb The size of the data set. * @param pOut Where to write error messages. */ static bool kPrfIsValidate(PCKPRFHDR pHdr, KU32 cb, FILE *pOut) { /* * We ASSUMES that the header is identicial with the exception * of the uBasePtr size. (this is padded out and the upper bits are all zero) */ if ( pHdr->Hdr32.u32Magic != KPRF32HDR_MAGIC && pHdr->Hdr32.u32Magic != KPRF64HDR_MAGIC) { fprintf(pOut, "Invalid magic %#x\n", pHdr->Hdr32.u32Magic); return false; } if ( pHdr->Hdr32.cFormatBits != 32 && pHdr->Hdr32.cFormatBits != 64) { fprintf(pOut, "Invalid/Unsupported bit count %u\n", pHdr->Hdr32.cFormatBits); return false; } if (pHdr->Hdr32.cb > cb) { fprintf(pOut, "Data set size mismatch. Header say %#x, input is %#x\n", pHdr->Hdr32.cb, cb); return false; } #define KPRF_VALIDATE_SIZE(MemBaseName, cb32, cb64) do {\ if (pHdr->Hdr32.cb##MemBaseName > (pHdr->Hdr32.cFormatBits == 32 ? cb32 : cb64)) \ { \ fprintf(pOut, "cb" #MemBaseName " was expected to be %#x but is %#x. Probably a format change, rebuild.\n", \ (unsigned)(pHdr->Hdr32.cFormatBits == 32 ? cb32 : cb64), pHdr->Hdr32.cb##MemBaseName); \ return false; \ }\ } while (0) KPRF_VALIDATE_SIZE(Function, sizeof(KPRF32FUNC), sizeof(KPRF64FUNC)); KPRF_VALIDATE_SIZE(Thread, sizeof(KPRF32THREAD), sizeof(KPRF64THREAD)); KPRF_VALIDATE_SIZE(Stack, (KU32)&((PKPRF32STACK)0)->aFrames[pHdr->Hdr32.cMaxStackFrames], (KU32)&((PKPRF64STACK)0)->aFrames[pHdr->Hdr32.cMaxStackFrames]); KUPTR cbHeader = (KUPTR)&pHdr->Hdr32.aiFunctions[pHdr->Hdr32.cFunctions] - (KUPTR)pHdr; if ( cbHeader != (KU32)cbHeader || cbHeader >= cb) { fprintf(pOut, "cFunctions (%#x) is too large to fit the lookup table inside the data set.\n", pHdr->Hdr32.cFunctions); return false; } /* The space assignment is hereby required to be equal to the member order in the header. */ KU32 offMin = cbHeader; #define KPRF_VALIDATE_OFF(off, name) do {\ if ( off > 0 \ && off < offMin) \ { \ fprintf(pOut, #name " (%#x) is overlapping with other element or invalid space assignment order.\n", off); \ return false; \ }\ if (off >= cb) \ { \ fprintf(pOut, #name " (%#x) is outside the data set (%#x)\n", off, cb); \ return false; \ }\ } while (0) #define KPRF_VALIDATE_MEM(MemBaseName) do {\ KPRF_VALIDATE_OFF(pHdr->Hdr32.off##MemBaseName##s, off##MemBaseName##s); \ if ( pHdr->Hdr32.off##MemBaseName##s \ && ( pHdr->Hdr32.off##MemBaseName##s + pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s > cb \ || pHdr->Hdr32.off##MemBaseName##s + pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s < pHdr->Hdr32.off##MemBaseName##s)\ ) \ { \ fprintf(pOut, #MemBaseName " (%#x) is outside the data set (%#x)\n", \ pHdr->Hdr32.off##MemBaseName##s + pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s, cb); \ return false; \ }\ if (pHdr->Hdr32.c##MemBaseName##s > pHdr->Hdr32.cMax##MemBaseName##s) \ { \ fprintf(pOut, "c" #MemBaseName " (%#x) higher than the max (%#x)\n", \ pHdr->Hdr32.c##MemBaseName##s, pHdr->Hdr32.cMax##MemBaseName##s); \ return false; \ } \ if (pHdr->Hdr32.off##MemBaseName##s) \ offMin += pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s; \ } while (0) KPRF_VALIDATE_MEM(Function); KPRF_VALIDATE_OFF(pHdr->Hdr32.offModSegs, offModSegs); if (pHdr->Hdr32.offModSegs) KPRF_VALIDATE_OFF(pHdr->Hdr32.offModSegs + pHdr->Hdr32.cbMaxModSegs, cbMaxModSegs); if (pHdr->Hdr32.cbModSegs > pHdr->Hdr32.cbMaxModSegs) { fprintf(pOut, "ccbModSegs (%#x) higher than the max (%#x)\n", pHdr->Hdr32.cbModSegs, pHdr->Hdr32.cbMaxModSegs); return false; } if (pHdr->Hdr32.offModSegs) \ offMin += pHdr->Hdr32.cbMaxModSegs; \ KPRF_VALIDATE_MEM(Thread); KPRF_VALIDATE_MEM(Stack); KPRF_VALIDATE_OFF(pHdr->Hdr32.offCommandLine, offCommandLine); KPRF_VALIDATE_OFF(pHdr->Hdr32.offCommandLine + pHdr->Hdr32.cchCommandLine, cchCommandLine); /* * Validate the function lookup table */ for (KU32 i = 0; i < pHdr->Hdr32.cFunctions; i++) if (pHdr->Hdr32.aiFunctions[i] >= pHdr->Hdr32.cFunctions) { fprintf(pOut, "Function lookup entry %#x is invalid: index %#x, max is %#x\n", i, pHdr->Hdr32.aiFunctions[i], pHdr->Hdr32.cFunctions); return false; } /* * Validate the functions. */ switch (pHdr->Hdr32.cFormatBits) { case 32: return KPrf32IsValid(&pHdr->Hdr32, cb, pOut); case 64: return KPrf64IsValid(&pHdr->Hdr64, cb, pOut); } return false; #undef KPRF_VALIDATE_SIZE #undef KPRF_VALIDATE_MEM #undef KPRF_VALIDATE_OFF } /** * Dumps a kProfiler 2 format file. * * @returns 0 on success. * @returns -1 on failure. * * @param pszFilename The path to the profiler data set. * @param pOut Where to write the output. */ int KPrfDumpFile(const char *pszFilename, FILE *pOut) { /* * Load and validate the data set. */ KU32 cb; PKPRFHDR pHdr = kPrfLoad(pszFilename, &cb, pOut); if (!pHdr) return -1; if (!kPrfIsValidate(pHdr, cb, pOut)) return -1; /* * Switch to the appropirate dumper routine. */ int rc; switch (pHdr->Hdr32.cFormatBits) { case 32: rc = KPrf32Dump(&pHdr->Hdr32, pOut); break; case 64: rc = KPrf64Dump(&pHdr->Hdr64, pOut); break; default: fprintf(stderr, "Unsupported bit count %d\n", pHdr->Hdr32.cFormatBits); rc = -1; break; } return rc; } /** * Creates a HTML report from a kProfiler 2 format file. * * @returns 0 on success. * @returns -1 on failure. * * @param pszFilename The path to the profiler data set. * @param pOut Where to write the output. */ int KPrfHtmlReport(const char *pszFilename, FILE *pOut) { /* * Load and validate the data set. */ KU32 cb; PKPRFHDR pHdr = kPrfLoad(pszFilename, &cb, pOut); if (!pHdr) return -1; if (!kPrfIsValidate(pHdr, cb, pOut)) return -1; /* * Switch to the appropirate dumper routine. */ int rc; switch (pHdr->Hdr32.cFormatBits) { case 32: { PKPRF32REPORT pReport; rc = KPrf32Analyse(&pHdr->Hdr32, &pReport); if (!rc) { rc = KPrf32WriteHtmlReport(pReport, pOut); if (rc) fprintf(stderr, "Error while writing HTML report for '%s'\n", pszFilename); KPrf32DeleteReport(pReport); } else fprintf(stderr, "Analysis of '%s' failed!\n", pszFilename); break; } case 64: { PKPRF64REPORT pReport; rc = KPrf64Analyse(&pHdr->Hdr64, &pReport); if (!rc) { rc = KPrf64WriteHtmlReport(pReport, pOut); if (rc) fprintf(stderr, "Error while writing HTML report for '%s'\n", pszFilename); KPrf64DeleteReport(pReport); } else fprintf(stderr, "Analysis of '%s' failed!\n", pszFilename); break; } default: fprintf(stderr, "Unsupported bit count %d\n", pHdr->Hdr32.cFormatBits); rc = -1; break; } return rc; } /** * Prints the usage. */ static int Usage(void) { printf("kProfiler MK2 - Reader & Producer of Statistics\n" "usage: kPrf2Read [-r|-d] [[-r|-d] file2 []]\n" ); return 1; } int main(int argc, char **argv) { /* * Parse arguments. */ if (argc <= 1) return Usage(); enum { OP_DUMP, OP_HTML } enmOp = OP_DUMP; for (int i = 1; i < argc; i++) { if (argv[i][0] == '-') { switch (argv[i][1]) { case 'h': case 'H': case '?': case '-': return Usage(); case 'd': enmOp = OP_DUMP; break; case 'r': enmOp = OP_HTML; break; default: printf("Syntax error: Unknown argument '%s'\n", argv[i]); return 1; } } else { int rc; switch (enmOp) { case OP_DUMP: rc = KPrfDumpFile(argv[i], stdout); break; case OP_HTML: rc = KPrfHtmlReport(argv[i], stdout); break; } if (rc) return rc; } } return 0; } kbuild-3149/src/lib/kStuff/kProfiler2/kPrf2-win-amd64.def0000644000175000017500000000253013252530254022673 0ustar locutuslocutus; $Id: kPrf2-win-amd64.def 29 2009-07-01 20:30:29Z bird $LIBRARY kPrf2 ;; @file ; kProfiler Mark 2 - Windows Linker Definition File, AMD64. ; ; ; Copyright (c) 2006-2007 Knut St. Osmundsen ; ; 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. ; LIBRARY kPrf2 EXPORTS _penter _pexit KPrfInit kPrf2WrapResolve kbuild-3149/src/lib/kStuff/kProfiler2/kPrf2WinApi-pre.sed0000644000175000017500000000615713252530254023111 0ustar locutuslocutus# $Id: kPrf2WinApi-pre.sed 29 2009-07-01 20:30:29Z bird $ ## @file # This SED script will try normalize a windows header # in order to make it easy to pick out function prototypes. # # # Copyright (c) 2008 Knut St. Osmundsen # # 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. # # Drop all preprocessor lines (#if/#else/#endif/#define/#undef/#pragma/comments) # (we don't bother with multi line comments ATM.) /^[[:space:]]*#/b drop_line /^[[:space:]]*\/\//b drop_line # Drop empty lines. /^[[:space:]]*$/b drop_line # Drop trailing comments and trailing whitespace s/[[:space:]][[:space:]]*\/\.*$//g s,[[:space:]][[:space:]]*/\*[^*/]*\*/[[:space:]]*$,,g s/[[:space:]][[:space:]]*$//g # Pick out the WINBASEAPI stuff (WinBase.h) /^WINBASEAPI/b winapi /^NTSYSAPI/b winapi /^WINAPI$/b winapi_perhaps /^APIENTRY$/b winapi_perhaps h d b end # No WINBASEAPI, so we'll have to carefully check the hold buffer. :winapi_perhaps x /^[A-Z][A-Z0-9_][A-Z0-9_]*[A-Z0-9]$/!b drop_line G s/\r/ /g s/\n/ /g b winapi # Make it one line and a bit standardized :winapi /;/b winapi_got_it N b winapi :winapi_got_it s/\n/ /g s/[[:space:]][[:space:]]*\/\*[^*/]*\*\/[[:space:]]*//g s/[[:space:]][[:space:]]*(/(/g s/)[[:space:]][[:space:]]*/)/g s/(\([^[:space:]]\)/( \1/g s/\([^[:space:]]\))/\1 )/g s/[*]\([^[:space:]]\)/* \1/g s/\([^[:space:]]\)[*]/\1 */g s/[[:space:]][[:space:]]*/ /g s/[[:space:]][[:space:]]*,/,/g s/,/, /g s/,[[:space:]][[:space:]]*/, /g # Drop the nasty bit of the sal.h / SpecString.h stuff. s/[[:space:]]__[a-z][a-z_]*([^()]*)[[:space:]]*/ /g s/[[:space:]]__out[a-z_]*[[:space:]]*/ /g s/[[:space:]]__in[a-z_]*[[:space:]]*/ /g s/[[:space:]]__deref[a-z_]*[[:space:]]*/ /g s/[[:space:]]__reserved[[:space:]]*/ /g s/[[:space:]]__nullnullterminated[[:space:]]*/ /g s/[[:space:]]__checkReturn[[:space:]]*/ /g # Drop some similar stuff. s/[[:space:]]OPTIONAL[[:space:]]/ /g s/[[:space:]]OPTIONAL,/ ,/g # The __declspec() bit isn't necessary s/WINBASEAPI *// s/NTSYSAPI *// s/DECLSPEC_NORETURN *// s/__declspec([^()]*) *// # Normalize spaces. s/[[:space:]]/ /g # Clear the hold space x s/^.*$// x b end :drop_line s/^.*$// h d :end kbuild-3149/src/lib/kStuff/kProfiler2/kPrf2-win-x86.def0000644000175000017500000000250613252530254022410 0ustar locutuslocutus; $Id: kPrf2-win-x86.def 29 2009-07-01 20:30:29Z bird $ ;; @file ; kProfiler Mark 2 - Windows Linker Definition File, x86. ; ; ; Copyright (c) 2006-2007 Knut St. Osmundsen ; ; 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. ; LIBRARY kPrf2 EXPORTS _penter _pexit KPrfInit kPrf2WrapResolve kbuild-3149/src/lib/kStuff/kProfiler2/kPrf2WinApiWrappers.c0000644000175000017500000000714213252530254023513 0ustar locutuslocutus/* $Id: kPrf2WinApiWrappers.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * Wrappers for a number of common Windows APIs. */ /* * Copyright (c) 2008 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #define _ADVAPI32_ #define _KERNEL32_ #define _WIN32_WINNT 0x0600 #define UNICODE #include #include #include #include "kPrf2WinApiWrapperHlp.h" #if K_ARCH == K_ARCH_X86_32 typedef PVOID PRUNTIME_FUNCTION; typedef FARPROC PGET_RUNTIME_FUNCTION_CALLBACK; #endif /* RtlUnwindEx is used by msvcrt on amd64, but winnt.h only defines it for IA64... */ typedef struct _FRAME_POINTERS { ULONGLONG MemoryStackFp; ULONGLONG BackingStoreFp; } FRAME_POINTERS, *PFRAME_POINTERS; typedef PVOID PUNWIND_HISTORY_TABLE; typedef PVOID PKNONVOLATILE_CONTEXT_POINTERS; /******************************************************************************* * Global Variables * *******************************************************************************/ KPRF2WRAPDLL g_Kernel32 = { INVALID_HANDLE_VALUE, "KERNEL32" }; /* * Include the generated code. */ #include "kPrf2WinApiWrappers-kernel32.h" /* TODO (amd64): AddLocalAlternateComputerNameA AddLocalAlternateComputerNameW EnumerateLocalComputerNamesA EnumerateLocalComputerNamesW RemoveLocalAlternateComputerNameA RemoveLocalAlternateComputerNameW RtlLookupFunctionEntry RtlPcToFileHeader RtlRaiseException RtlVirtualUnwind SetConsoleCursor SetLocalPrimaryComputerNameA SetLocalPrimaryComputerNameW __C_specific_handler __misaligned_access _local_unwind */ /** * The DLL Main for the Windows API wrapper DLL. * * @returns Success indicator. * @param hInstDll The instance handle of the DLL. (i.e. the module handle) * @param fdwReason The reason why we're here. This is a 'flag' for reasons of * tradition, it's really a kind of enum. * @param pReserved Reserved / undocumented something. */ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, PVOID pReserved) { switch (fdwReason) { case DLL_PROCESS_ATTACH: break; case DLL_PROCESS_DETACH: break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; } return TRUE; } kbuild-3149/src/lib/kStuff/kProfiler2/prfcorereloc.cpp.h0000644000175000017500000000347013252530254023146 0ustar locutuslocutus/* $Id: prfcorereloc.cpp.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kProfiler Mark 2 - Core SetBasePtr Code Template. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /** * Set (or modify) the base pointer for the profiler. * * The purpose of the base pointer is to allow profiling of relocatable code. Set the * base pointer right after initializing the data set, and update it when relocating * the code (both by calling this function), and Bob's your uncle! :-) * * @param pHdr The header returned from the initializer. * @param uBasePtr The new base pointer value. */ KPRF_DECL_FUNC(void, SetBasePtr)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(,UPTR) uBasePtr) { pHdr->uBasePtr = uBasePtr; } kbuild-3149/src/lib/kStuff/kProfiler2/prfamd64msc.asm0000644000175000017500000003253513252530254022363 0ustar locutuslocutus; $Id: prfamd64msc.asm 29 2009-07-01 20:30:29Z bird $; ;; @file ; kProfiler Mark 2 - Microsoft C/C++ Compiler Interaction, AMD64. ; ; ; Copyright (c) 2006-2007 Knut St. Osmundsen ; ; 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. ; [section .data] ; g_fCalibrated: dd 0 g_OverheadAdj: dd 0 [section .text] extern KPRF_ENTER extern KPRF_LEAVE global _penter global _pexit ;ifdef UNDEFINED global common_return_path global common_overhead global common_no_overhead global calibrate global calib_inner_update_minimum global calib_inner_next global calib_outer_dec global calib_outer_inc global calib_done global calib_nullproc ;endif ;; ; On x86 the call to this function has been observed to be put before ; creating the stack frame, as the very first instruction in the function. ; ; Thus the stack layout is as follows: ; 24 return address of the calling function. ; 20 our return address - the address of the calling function + 5. ; 1c eax ; 18 edx ; 14 eflags ; 10 ecx ; c tsc high - param 3 ; 8 tsc low ; 4 frame pointer - param 2 ; 0 function ptr - param 1 ; ; align 16 _penter: ; save volatile register and get the time stamp. push rax push rdx rdtsc pushfq push rcx push r8 push r9 push r10 push r11 sub rsp, 28h ; rsp is unaligned at this point (8 pushes). ; reserve 20h for spill, and 8 bytes for ts. ; setting up the enter call frame mov r8d, edx shl r8, 32 or r8, rax ; param 3 - the timestamp mov [rsp + 20h], r8 ; save the tsc for later use. lea rdx, [rsp + 8*8 + 28h] ; Param 2 - default frame pointer mov rcx, [rdx] ; Param 1 - The function address ; MSC seems to put the _penter both before and after the typical sub rsp, xxh ; statement as if it cannot quite make up its mind. We'll try adjust for this ; to make the unwinding a bit more accurate wrt to longjmp/throw. But since ; there are also an uneven amount of push/pop around the _penter/_pexit we ; can never really make a perfect job of it. sigh. cmp word [rcx - 5 - 4], 08348h ; sub rsp, imm8 jne .not_byte_sub cmp byte [rcx - 5 - 2], 0ech jne .not_byte_sub movzx eax, byte [rcx - 5 - 1] ; imm8 add rdx, rax jmp .call_prf_enter .not_byte_sub: cmp word [rcx - 5 - 7], 08148h ; sub rsp, imm32 jne .not_dword_sub cmp byte [rcx - 5 - 5], 0ech jne .not_dword_sub mov eax, [rcx - 5 - 4] ; imm32 add rdx, rax ; jmp .call_prf_enter .not_dword_sub: .call_prf_enter: call KPRF_ENTER jmp common_return_path ;; ; On x86 the call to this function has been observed to be put right before ; return instruction. This fact matters since since we have to calc the same ; stack address as in _penter. ; ; Thus the stack layout is as follows: ; 24 return address of the calling function. ; 20 our return address - the address of the calling function + 5. ; 1c eax ; 18 edx ; 14 eflags ; 10 ecx ; c tsc high - param 3 ; 8 tsc low ; 4 frame pointer - param 2 ; 0 function ptr - param 1 ; ; align 16 _pexit: ; save volatile register and get the time stamp. push rax push rdx rdtsc pushfq push rcx push r8 push r9 push r10 push r11 sub rsp, 28h ; rsp is unaligned at this point (8 pushes). ; reserve 20h for spill, and 8 bytes for ts. ; setting up the enter call frame mov r8d, edx shl r8, 32 or r8, rax ; param 3 - the timestamp mov [rsp + 20h], r8 ; save the tsc for later use. lea rdx, [rsp + 8*8 + 28h] ; Param 2 - frame pointer. mov rcx, [rdx] ; Param 1 - The function address ; MSC some times put the _pexit before the add rsp, xxh. To try match up with ; any adjustments made in _penter, we'll try detect this. cmp word [rcx], 08348h ; add rsp, imm8 jne .not_byte_sub cmp byte [rcx + 2], 0c4h jne .not_byte_sub movzx eax, byte [rcx + 3] ; imm8 add rdx, rax jmp .call_prf_leave .not_byte_sub: cmp word [rcx], 08148h ; add rsp, imm32 jne .not_dword_sub cmp byte [rcx + 2], 0c4h jne .not_dword_sub mov eax, [rcx + 3] ; imm32 add rdx, rax ; jmp .call_prf_leave .not_dword_sub: .call_prf_leave: call KPRF_LEAVE jmp common_return_path ;; ; This is the common return path for both the enter and exit hooks. ; It's kept common because we can then use the same overhead adjustment ; and save some calibration efforts. It also saves space :-) align 16 common_return_path: ; Update overhead test rax, rax jz common_no_overhead cmp byte [g_fCalibrated wrt rip], 0 jnz common_overhead call calibrate common_overhead: mov rcx, rax ; rcx <- pointer to overhead counter. mov eax, [g_OverheadAdj wrt rip]; apply the adjustment before reading tsc sub [rsp + 20h], rax rdtsc shl rdx, 32 or rdx, rax ; rdx = 64-bit timestamp sub rdx, [rsp + 20h] ; rdx = elapsed lock add [rcx], rdx ; update counter. common_no_overhead: ; restore volatile registers. add rsp, 28h pop r11 pop r10 pop r9 pop r8 pop rcx popfq pop rdx pop rax ret ;; ; Data rsi points to while we're calibrating. struc CALIBDATA .Overhead resq 1 .Profiled resq 1 .EnterTS resq 1 .Min resq 1 endstruc align 16 ;; ; Do necessary calibrations. ; calibrate: ; prolog - save everything push rbp pushfq push rax ; pushaq push rbx push rcx push rdx push rdi push rsi push r8 push r9 push r10 push r11 push r12 push r13 push r14 push r15 mov rbp, rsp sub rsp, CALIBDATA_size mov rsi, rsp ; rsi points to the CALIBDATA and rsp, -16 ; ; Indicate that we have finished calibrating. ; mov eax, 1 xchg dword [g_fCalibrated wrt rip], eax ; ; The outer loop - find the right adjustment. ; mov ebx, 200h ; loop counter. calib_outer_loop: ; ; The inner loop - calls the function number of times to establish a ; good minimum value ; mov ecx, 200h mov dword [rsi + CALIBDATA.Min], 0ffffffffh mov dword [rsi + CALIBDATA.Min + 4], 07fffffffh calib_inner_loop: ; zero the overhead and profiled times. xor eax, eax mov [rsi + CALIBDATA.Overhead], rax mov [rsi + CALIBDATA.Profiled], rax call calib_nullproc ; subtract the overhead mov rax, [rsi + CALIBDATA.Profiled] sub rax, [rsi + CALIBDATA.Overhead] ; update the minimum value. bt rax, 63 jc near calib_outer_dec ; if negative, just simplify and shortcut cmp rax, [rsi + CALIBDATA.Min] jge calib_inner_next calib_inner_update_minimum: mov [rsi + CALIBDATA.Min], rax calib_inner_next: loop calib_inner_loop ; Is the minimum value acceptable? test dword [rsi + CALIBDATA.Min + 4], 80000000h jnz calib_outer_dec ; simplify if negative. cmp dword [rsi + CALIBDATA.Min + 4], 0 jnz calib_outer_inc ; this shouldn't be possible cmp dword [rsi + CALIBDATA.Min], 1fh jbe calib_outer_dec ; too low - 2 ticks per pair is the minimum! ;cmp dword [rsi + CALIBDATA.Min], 30h ;jbe calib_done ; this is fine! cmp dword [rsi + CALIBDATA.Min], 70h ; - a bit weird... jbe calib_outer_next ; do the full 200h*200h iteration calib_outer_inc: inc dword [g_OverheadAdj wrt rip] jmp calib_outer_next calib_outer_dec: cmp dword [g_OverheadAdj wrt rip], 1 je calib_done dec dword [g_OverheadAdj wrt rip] calib_outer_next: dec ebx jnz calib_outer_loop calib_done: ; epilog - restore it all. mov rsp, rbp pop r15 pop r14 pop r13 pop r12 pop r11 pop r10 pop r9 pop r8 pop rsi pop rdi pop rdx pop rcx pop rbx pop rax popfq pop rbp ret ;; ; The calibration _penter - this must be identical to the real thing except for the KPRF call. align 16 calib_penter: ; This part must be identical past the rdtsc. push rax push rdx rdtsc pushfq push rcx push r8 push r9 push r10 push r11 sub rsp, 28h ; rsp is unaligned at this point (8 pushes). ; reserve 20h for spill, and 8 bytes for ts. ; store the entry / stack frame. mov r8d, edx shl r8, 32 or r8, rax mov [rsp + 20h], r8 mov [rsi + CALIBDATA.EnterTS], r8 lea rax, [rsi + CALIBDATA.Overhead] jmp common_overhead ;; ; The calibration _pexit - this must be identical to the real thing except for the KPRF call. align 16 calib_pexit: ; This part must be identical past the rdtsc. push rax push rdx rdtsc pushfq push rcx push r8 push r9 push r10 push r11 sub rsp, 28h ; rsp is unaligned at this point (8 pushes). ; reserve 20h for spill, and 8 bytes for ts. ; store the entry / stack frame. mov r8d, edx shl r8, 32 or r8, rax mov [rsp + 20h], r8 sub r8, [rsi + CALIBDATA.EnterTS] add [rsi + CALIBDATA.Profiled], r8 lea rax, [rsi + CALIBDATA.EnterTS] jmp common_overhead ;; ; The 'function' we're profiling. ; The general idea is that each pair should take something like 2-10 ticks. ; ; (Btw. If we don't use multiple pairs here, we end up with the wrong result.) align 16 calib_nullproc: call calib_penter ;0 call calib_pexit call calib_penter ;1 call calib_pexit call calib_penter ;2 call calib_pexit call calib_penter ;3 call calib_pexit call calib_penter ;4 call calib_pexit call calib_penter ;5 call calib_pexit call calib_penter ;6 call calib_pexit call calib_penter ;7 call calib_pexit call calib_penter ;8 call calib_pexit call calib_penter ;9 call calib_pexit call calib_penter ;a call calib_pexit call calib_penter ;b call calib_pexit call calib_penter ;c call calib_pexit call calib_penter ;d call calib_pexit call calib_penter ;e call calib_pexit call calib_penter ;f call calib_pexit ret ; ; Dummy stack check function. ; global __chkstk __chkstk: ret kbuild-3149/src/lib/kStuff/kProfiler2/prfcorefunction.cpp.h0000644000175000017500000000753413252530254023674 0ustar locutuslocutus/* $Id: prfcorefunction.cpp.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kProfiler Mark 2 - Core NewFunction Code Template. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /** * Creates a new function. * * @returns Pointer to the new function. * @returns NULL if we're out of space. */ static KPRF_TYPE(P,FUNC) KPRF_NAME(NewFunction)(KPRF_TYPE(P,HDR) pHdr,KPRF_TYPE(,UPTR) uPC) { /* * First find the position of the function (it might actually have been inserted by someone else by now too). */ KPRF_FUNCS_WRITE_LOCK(); KPRF_TYPE(P,FUNC) paFunctions = KPRF_OFF2PTR(P,FUNC, pHdr->offFunctions, pHdr); KI32 iStart = 0; KI32 iLast = pHdr->cFunctions - 1; KI32 i = iLast / 2; for (;;) { KU32 iFunction = pHdr->aiFunctions[i]; KPRF_TYPE(,IPTR) iDiff = uPC - paFunctions[iFunction].uEntryPtr; if (!iDiff) { KPRF_FUNCS_WRITE_UNLOCK(); return &paFunctions[iFunction]; } if (iLast == iStart) break; if (iDiff < 0) iLast = i - 1; else iStart = i + 1; if (iLast < iStart) break; i = iStart + (iLast - iStart) / 2; } /* * Adjust the index so we're exactly in the right spot. * (I've too much of a headache to figure out if the above loop leaves us where we should be.) */ const KI32 iNew = pHdr->cFunctions; if (paFunctions[pHdr->aiFunctions[i]].uEntryPtr > uPC) { while ( i > 0 && paFunctions[pHdr->aiFunctions[i - 1]].uEntryPtr > uPC) i--; } else { while ( i < iNew && paFunctions[pHdr->aiFunctions[i]].uEntryPtr < uPC) i++; } /* * Ensure that there still is space for the function. */ if (iNew >= (KI32)pHdr->cMaxFunctions) { KPRF_FUNCS_WRITE_UNLOCK(); return NULL; } pHdr->cFunctions++; KPRF_TYPE(P,FUNC) pNew = &paFunctions[iNew]; /* init the new function entry */ pNew->uEntryPtr = uPC; pNew->offModSeg = 0; pNew->cOnStack = 0; pNew->cCalls = 0; pNew->OnStack.MinTicks = ~(KU64)0; pNew->OnStack.MaxTicks = 0; pNew->OnStack.SumTicks = 0; pNew->OnTopOfStack.MinTicks = ~(KU64)0; pNew->OnTopOfStack.MaxTicks = 0; pNew->OnTopOfStack.SumTicks = 0; /* shift the function index array and insert the new one. */ KI32 j = iNew; while (j > i) { pHdr->aiFunctions[j] = pHdr->aiFunctions[j - 1]; j--; } pHdr->aiFunctions[i] = iNew; KPRF_FUNCS_WRITE_UNLOCK(); /* * Record the module segment (i.e. add it if it's new). */ pNew->offModSeg = KPRF_NAME(RecordModSeg)(pHdr, uPC); return pNew; } kbuild-3149/src/lib/kStuff/kProfiler2/kProfileR3.cpp0000644000175000017500000013014013252530254022206 0ustar locutuslocutus/* $Id: kProfileR3.cpp 29 2009-07-01 20:30:29Z bird $ */ /** @file * kProfiler Mark 2 - The Ring-3 Implementation. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #if K_OS == K_OS_WINDOWS # include # include # include # if _MSC_VER >= 1400 # include # define HAVE_INTRIN # endif #elif K_OS == K_OS_LINUX || K_OS == K_OS_FREEBSD # define KPRF_USE_PTHREAD # include # include # define KPRF_USE_MMAN # include # include # include # include # ifndef O_BINARY # define O_BINARY 0 # endif #elif K_OS == K_OS_OS2 # define INCL_BASE # include # include # include #else # error "not ported to this OS..." #endif #include #include /* * Instantiate the header. */ #define KPRF_NAME(Suffix) KPrf##Suffix #define KPRF_TYPE(Prefix,Suffix) Prefix##KPRF##Suffix #if K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 # define KPRF_DECL_FUNC(type, name) extern "C" __declspec(dllexport) type __cdecl KPRF_NAME(name) #else # define KPRF_DECL_FUNC(type, name) extern "C" type KPRF_NAME(name) #endif #if 1 # ifdef __GNUC__ # define KPRF_ASSERT(expr) do { if (!(expr)) { __asm__ __volatile__("int3\n\tnop\n\t");} } while (0) # else # define KPRF_ASSERT(expr) do { if (!(expr)) { __debugbreak(); } } while (0) # endif #else # define KPRF_ASSERT(expr) do { } while (0) #endif #include "prfcore.h.h" /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** Mutex lock type. */ #if defined(KPRF_USE_PTHREAD) typedef pthread_mutex_t KPRF_TYPE(,MUTEX); #elif K_OS == K_OS_WINDOWS typedef CRITICAL_SECTION KPRF_TYPE(,MUTEX); #elif K_OS == K_OS_OS2 typedef struct _fmutex KPRF_TYPE(,MUTEX); #endif /** Pointer to a mutex lock. */ typedef KPRF_TYPE(,MUTEX) *KPRF_TYPE(P,MUTEX); #if defined(KPRF_USE_PTHREAD) /** Read/Write lock type. */ typedef pthread_rwlock_t KPRF_TYPE(,RWLOCK); #elif K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 /** Read/Write lock state. */ typedef enum KPRF_TYPE(,RWLOCKSTATE) { RWLOCK_STATE_UNINITIALIZED = 0, RWLOCK_STATE_SHARED, RWLOCK_STATE_LOCKING, RWLOCK_STATE_EXCLUSIVE, RWLOCK_STATE_32BIT_HACK = 0x7fffffff } KPRF_TYPE(,RWLOCKSTATE); /** Update the state. */ #define KPRF_RWLOCK_SETSTATE(pRWLock, enmNewState) \ kPrfAtomicSet32((volatile KU32 *)&(pRWLock)->enmState, (KU32)(enmNewState)) /** Read/Write lock type. */ typedef struct KPRF_TYPE(,RWLOCK) { /** This mutex serialize the access and updating of the members * of this structure. */ KPRF_TYPE(,MUTEX) Mutex; /** The current number of readers. */ KU32 cReaders; /** The number of readers waiting. */ KU32 cReadersWaiting; /** The current number of waiting writers. */ KU32 cWritersWaiting; # if K_OS == K_OS_WINDOWS /** The handle of the event object on which the waiting readers block. (manual reset). */ HANDLE hevReaders; /** The handle of the event object on which the waiting writers block. (manual reset). */ HANDLE hevWriters; # elif K_OS == K_OS_OS2 /** The handle of the event semaphore on which the waiting readers block. */ HEV hevReaders; /** The handle of the event semaphore on which the waiting writers block. */ HEV hevWriters; # endif /** The current state of the read-write lock. */ KPRF_TYPE(,RWLOCKSTATE) enmState; } KPRF_TYPE(,RWLOCK); #endif /** Pointer to a Read/Write lock. */ typedef KPRF_TYPE(,RWLOCK) *KPRF_TYPE(P,RWLOCK); /******************************************************************************* * Global Variables * *******************************************************************************/ /** The TLS index / key. */ #if K_OS == K_OS_WINDOWS static DWORD g_dwThreadTLS = TLS_OUT_OF_INDEXES; #elif defined(KPRF_USE_PTHREAD) static pthread_key_t g_ThreadKey = (pthread_key_t)-1; #elif K_OS == K_OS_OS2 static KPRF_TYPE(P,THREAD) *g_ppThread = NULL; #else # error "Not ported to your OS - or you're missing the OS define(s)." #endif /** Pointer to the profiler header. */ static KPRF_TYPE(P,HDR) g_pHdr = NULL; #define KPRF_GET_HDR() g_pHdr /** Whether the profiler is enabled or not. */ static bool g_fEnabled = false; #define KPRF_IS_ACTIVE() g_fEnabled /** The mutex protecting the threads in g_pHdr. */ static KPRF_TYPE(,MUTEX) g_ThreadsMutex; /** The mutex protecting the module segments in g_pHdr. */ static KPRF_TYPE(,MUTEX) g_ModSegsMutex; /** The read-write lock protecting the functions in g_pHdr. */ static KPRF_TYPE(,RWLOCK) g_FunctionsRWLock; /******************************************************************************* * Internal Functions * *******************************************************************************/ static KPRF_TYPE(P,THREAD) kPrfGetThreadAutoReg(void); #ifdef KPRF_USE_PTHREAD static void kPrfPThreadKeyDtor(void *pvThread); #endif /** * Gets the pointer to the profiler data for the current thread. * * This implementation automatically adds unknown threads. * * @returns Pointer to the profiler thread data. * @returns NULL if we're out of thread space. */ static inline KPRF_TYPE(P,THREAD) kPrfGetThread(void) { KPRF_TYPE(P,THREAD) pThread; /* Win32/64 */ #if K_OS == K_OS_WINDOWS pThread = (KPRF_TYPE(P,THREAD))TlsGetValue(g_dwThreadTLS); /* Posix Threads */ #elif defined(KPRF_USE_PTHREAD) pThread = (KPRF_TYPE(P,THREAD))pthread_getspecific(g_ThreadKey); #elif K_OS == K_OS_OS2 pThread = *g_ppThread; #else # error not implemented #endif if (!pThread) pThread = kPrfGetThreadAutoReg(); return pThread; } #define KPRF_GET_THREAD() kPrfGetThread() /** * The the ID of the current thread. * * @returns The thread id. */ static inline KUPTR kPrfGetThreadId(void) { /* Win32/64 */ #if K_OS == K_OS_WINDOWS KUPTR ThreadId = (KUPTR)GetCurrentThreadId(); /* Posix Threads */ #elif defined(KPRF_USE_PTHREAD) KUPTR ThreadId = (KUPTR)pthread_self(); #elif K_OS == K_OS_OS2 PTIB pTib; PPIB pPib; DosGetInfoBlocks(&pTib, &pPib); ThreadId = pTib->tib_ptib2->tib2_ultid; #else # error not implemented #endif return ThreadId; } #define KPRF_GET_THREADID() kPrfGetThreadId() /** * The the ID of the current process. * * @returns The process id. */ static inline KUPTR kPrfGetProcessId(void) { /* Win32/64 */ #if K_OS == K_OS_WINDOWS KUPTR ThreadId = (KUPTR)GetProcessId(GetCurrentProcess()); #elif K_OS == K_OS_OS2 PTIB pTib; PPIB pPib; DosGetInfoBlocks(&pTib, &pPib); ThreadId = pPib->pib_pid; #else KUPTR ThreadId = (KUPTR)getpid(); #endif return ThreadId; } #define KPRF_GET_PROCESSID() kPrfGetProcessId() /** * Sets the pointer to the profiler data for the current thread. * * We require fast access to the profiler thread data, so we store * it in a TLS (thread local storage) item/key where the implementation * allows that. * * @param pThread The pointer to the profiler thread data for the current thread. */ static inline void kPrfSetThread(KPRF_TYPE(P,THREAD) pThread) { /* Win32/64 */ #if K_OS == K_OS_WINDOWS BOOL fRc = TlsSetValue(g_dwThreadTLS, pThread); /* Posix Threads */ #elif defined(KPRF_USE_PTHREAD) int rc = pthread_setspecific(g_ThreadKey, pThread); #elif K_OS == K_OS_OS2 *g_ppThread = pThread; #else # error not implemented #endif } #define KPRF_SET_THREAD(pThread) kPrfSetThread(pThread) /** * Get the now timestamp. * This must correspond to what the assembly code are doing. */ static inline KU64 kPrfNow(void) { #if defined(HAVE_INTRIN) return __rdtsc(); # else union { KU64 u64; struct { KU32 u32Lo; KU32 u32Hi; } s; } u; # if defined(__GNUC__) __asm__ __volatile__ ("rdtsc\n\t" : "=a" (u.s.u32Lo), "=d" (u.s.u32Hi)); # else __asm { rdtsc mov [u.s.u32Lo], eax mov [u.s.u32Hi], edx } # endif return u.u64; #endif } #define KPRF_NOW() kPrfNow() /** * Atomically set a 32-bit value. */ static inline void kPrfAtomicSet32(volatile KU32 *pu32, const KU32 u32) { #if defined(HAVE_INTRIN) _InterlockedExchange((long volatile *)pu32, (const long)u32); #elif defined(__GNUC__) __asm__ __volatile__("xchgl %0, %1\n\t" : "=m" (*pu32) : "r" (u32)); #elif _MSC_VER __asm { mov edx, [pu32] mov eax, [u32] xchg [edx], eax } #else *pu32 = u32; #endif } #define KPRF_ATOMIC_SET32(a,b) kPrfAtomicSet32(a, b) /** * Atomically set a 64-bit value. */ static inline void kPrfAtomicSet64(volatile KU64 *pu64, KU64 u64) { #if defined(HAVE_INTRIN) && KPRF_BITS == 64 _InterlockedExchange64((KI64 *)pu64, (const KI64)u64); #elif defined(__GNUC__) && KPRF_BITS == 64 __asm__ __volatile__("xchgq %0, %1\n\t" : "=m" (*pu64) : "r" (u64)); #elif defined(__GNUC__) && KPRF_BITS == 32 __asm__ __volatile__("1:\n\t" "lock; cmpxchg8b %1\n\t" "jnz 1b\n\t" : "=A" (u64), "=m" (*pu64) : "0" (*pu64), "b" ( (KU32)u64 ), "c" ( (KU32)(u64 >> 32) )); #elif _MSC_VER __asm { mov ebx, dword ptr [u64] mov ecx, dword ptr [u64 + 4] mov esi, pu64 mov eax, dword ptr [esi] mov edx, dword ptr [esi + 4] retry: lock cmpxchg8b [esi] jnz retry } #else *pu64 = u64; #endif } #define KPRF_ATOMIC_SET64(a,b) kPrfAtomicSet64(a, b) /** * Atomically add a 32-bit integer to another. */ static inline void kPrfAtomicAdd32(volatile KU32 *pu32, const KU32 u32) { #if defined(HAVE_INTRIN) _InterlockedExchangeAdd((volatile long *)pu32, (const long)u32); #elif defined(__GNUC__) __asm__ __volatile__("lock; addl %0, %1\n\t" : "=m" (*pu32) : "r" (u32)); #elif _MSC_VER __asm { mov edx, [pu32] mov eax, dword ptr [u32] lock add [edx], eax } #else *pu32 += u32; #endif } #define KPRF_ATOMIC_ADD32(a,b) kPrfAtomicAdd32(a, b) #define KPRF_ATOMIC_INC32(a) kPrfAtomicAdd32(a, 1); #define KPRF_ATOMIC_DEC32(a) kPrfAtomicAdd32(a, (KU32)-1); /** * Atomically add a 64-bit integer to another. * Atomically isn't quite required, just a non-corruptive manner, assuming all updates are adds. */ static inline void kPrfAtomicAdd64(volatile KU64 *pu64, const KU64 u64) { #if defined(HAVE_INTRIN) && KPRF_BITS == 64 _InterlockedExchangeAdd64((volatile KI64 *)pu64, (const KI64)u64); #elif defined(__GNUC__) && KPRF_BITS == 64 __asm__ __volatile__("lock; addq %0, %1\n\t" : "=m" (*pu64) : "r" (u64)); #elif defined(__GNUC__) && KPRF_BITS == 32 __asm__ __volatile__("lock; addl %0, %2\n\t" "lock; adcl %1, %3\n\t" : "=m" (*(volatile KU32 *)pu64), "=m" (*((volatile KU32 *)pu64 + 1)) : "r" ((KU32)u64), "r" ((KU32)(u64 >> 32))); #elif _MSC_VER __asm { mov edx, [pu64] mov eax, dword ptr [u64] mov ecx, dword ptr [u64 + 4] lock add [edx], eax lock adc [edx + 4], ecx } #else *pu64 += u64; #endif } #define KPRF_ATOMIC_ADD64(a,b) kPrfAtomicAdd64(a, b) #define KPRF_ATOMIC_INC64(a) kPrfAtomicAdd64(a, 1); /** * Initializes a mutex. * * @returns 0 on success. * @returns -1 on failure. * @param pMutex The mutex to init. */ static int kPrfMutexInit(KPRF_TYPE(P,MUTEX) pMutex) { #if defined(KPRF_USE_PTHREAD) if (!pthread_mutex_init(pMutex, NULL)); return 0; return -1; #elif K_OS == K_OS_WINDOWS InitializeCriticalSection(pMutex); return 0; #elif K_OS == K_OS_OS2 if (!_fmutex_create(pMutex, 0)) return 0; return -1; #endif } /** * Deletes a mutex. * * @param pMutex The mutex to delete. */ static void kPrfMutexDelete(KPRF_TYPE(P,MUTEX) pMutex) { #if defined(KPRF_USE_PTHREAD) pthread_mutex_destroy(pMutex); #elif K_OS == K_OS_WINDOWS DeleteCriticalSection(pMutex); #elif K_OS == K_OS_OS2 _fmutex_close(pMutex); #endif } /** * Locks a mutex. * @param pMutex The mutex lock. */ static inline void kPrfMutexAcquire(KPRF_TYPE(P,MUTEX) pMutex) { #if K_OS == K_OS_WINDOWS EnterCriticalSection(pMutex); #elif defined(KPRF_USE_PTHREAD) pthread_mutex_lock(pMutex); #elif K_OS == K_OS_OS2 fmutex_request(pMutex); #endif } /** * Unlocks a mutex. * @param pMutex The mutex lock. */ static inline void kPrfMutexRelease(KPRF_TYPE(P,MUTEX) pMutex) { #if K_OS == K_OS_WINDOWS LeaveCriticalSection(pMutex); #elif defined(KPRF_USE_PTHREAD) pthread_mutex_lock(pMutex); #elif K_OS == K_OS_OS2 fmutex_request(pMutex); #endif } #define KPRF_THREADS_LOCK() kPrfMutexAcquire(&g_ThreadsMutex) #define KPRF_THREADS_UNLOCK() kPrfMutexRelease(&g_ThreadsMutex) #define KPRF_MODSEGS_LOCK() kPrfMutexAcquire(&g_ModSegsMutex) #define KPRF_MODSEGS_UNLOCK() kPrfMutexRelease(&g_ModSegsMutex) /** * Initializes a read-write lock. * * @returns 0 on success. * @returns -1 on failure. * @param pRWLock The read-write lock to initialize. */ static inline int kPrfRWLockInit(KPRF_TYPE(P,RWLOCK) pRWLock) { #if defined(KPRF_USE_PTHREAD) if (!pthread_rwlock_init(pRWLock, NULL)) return 0; return -1; #elif K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 if (kPrfMutexInit(&pRWLock->Mutex)) return -1; pRWLock->cReaders = 0; pRWLock->cReadersWaiting = 0; pRWLock->cWritersWaiting = 0; pRWLock->enmState = RWLOCK_STATE_SHARED; # if K_OS == K_OS_WINDOWS pRWLock->hevReaders = CreateEvent(NULL, TRUE, TRUE, NULL); pRWLock->hevWriters = CreateEvent(NULL, FALSE, FALSE, NULL); if ( pRWLock->hevReaders != INVALID_HANDLE_VALUE && pRWLock->hevWriters != INVALID_HANDLE_VALUE) return 0; CloseHandle(pRWLock->hevReaders); CloseHandle(pRWLock->hevWriters); # elif K_OS == K_OS_OS2 APIRET rc = DosCreateEventSem(NULL, &pRWLock->hevReaders, 0, TRUE); if (!rc) { rc = DosCreateEventSem(NULL, &pRWLock->hevWriters, 0, TRUE); if (!rc) return 0; pRWLock->hevWriters = NULLHANDLE; DosCloseEventSem(pRWLock->hevReaders); } pRWLock->hevReaders = NULLHANDLE; # endif pRWLock->enmState = RWLOCK_STATE_UNINITIALIZED; kPrfMutexDelete(&pRWLock->Mutex); return -1; #endif } /** * Deleters a read-write lock. * * @param pRWLock The read-write lock to delete. */ static inline void kPrfRWLockDelete(KPRF_TYPE(P,RWLOCK) pRWLock) { #if defined(KPRF_USE_PTHREAD) pthread_rwlock_destroy(pRWLock); #elif K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED) return; pRWLock->enmState = RWLOCK_STATE_UNINITIALIZED; kPrfMutexDelete(&pRWLock->Mutex); pRWLock->cReaders = 0; pRWLock->cReadersWaiting = 0; pRWLock->cWritersWaiting = 0; # if K_OS == K_OS_WINDOWS CloseHandle(pRWLock->hevReaders); pRWLock->hevReaders = INVALID_HANDLE_VALUE; CloseHandle(pRWLock->hevWriters); pRWLock->hevWriters = INVALID_HANDLE_VALUE; # elif K_OS == K_OS_OS2 DosCloseEventSem(pRWLock->hevReaders); pRWLock->hevReaders = NULLHANDLE; DosCloseEventSem(pRWLock->hevWriters); pRWLock->hevWriters = NULLHANDLE; # endif #endif } /** * Acquires read access to the read-write lock. * @param pRWLock The read-write lock. */ static inline void kPrfRWLockAcquireRead(KPRF_TYPE(P,RWLOCK) pRWLock) { #if defined(KPRF_USE_PTHREAD) pthread_rwlock_rdlock(pRWLock); #elif K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED) return; kPrfMutexAcquire(&pRWLock->Mutex); if (pRWLock->enmState == RWLOCK_STATE_SHARED) { KPRF_ATOMIC_INC32(&pRWLock->cReaders); kPrfMutexRelease(&pRWLock->Mutex); return; } for (;;) { /* have to wait */ KPRF_ATOMIC_INC32(&pRWLock->cReadersWaiting); # if K_OS == K_OS_WINDOWS HANDLE hev = pRWLock->hevReaders; ResetEvent(hev); # elif K_OS == K_OS_OS2 HEV hev = pRWLock->hevReaders; ULONG cIgnored; DosResetEventSem(hev, &cIgnored); # endif kPrfMutexRelease(&pRWLock->Mutex); # if K_OS == K_OS_WINDOWS switch (WaitForSingleObject(hev, INFINITE)) { case WAIT_IO_COMPLETION: case WAIT_TIMEOUT: case WAIT_OBJECT_0: break; case WAIT_ABANDONED: default: return; } # elif K_OS == K_OS_OS2 switch (DosWaitEventSem(hev, SEM_INDEFINITE_WAIT)) { case NO_ERROR: case ERROR_SEM_TIMEOUT: case ERROR_TIMEOUT: case ERROR_INTERRUPT: break; default: return; } # endif kPrfMutexAcquire(&pRWLock->Mutex); if (pRWLock->enmState == RWLOCK_STATE_SHARED) { KPRF_ATOMIC_INC32(&pRWLock->cReaders); KPRF_ATOMIC_DEC32(&pRWLock->cReadersWaiting); kPrfMutexRelease(&pRWLock->Mutex); return; } } #endif } /** * Releases read access to the read-write lock. * @param pRWLock The read-write lock. */ static inline void kPrfRWLockReleaseRead(KPRF_TYPE(P,RWLOCK) pRWLock) { #if defined(KPRF_USE_PTHREAD) pthread_rwlock_unlock(pRWLock); #elif K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED) return; /* * If we're still in the shared state, or if there * are more readers out there, or if there are no * waiting writers, all we have to do is decrement an leave. * * That's the most frequent, thing and should be fast. */ kPrfMutexAcquire(&pRWLock->Mutex); KPRF_ATOMIC_DEC32(&pRWLock->cReaders); if ( pRWLock->enmState == RWLOCK_STATE_SHARED || pRWLock->cReaders || !pRWLock->cWritersWaiting) { kPrfMutexRelease(&pRWLock->Mutex); return; } /* * Wake up one (or more on OS/2) waiting writers. */ # if K_OS == K_OS_WINDOWS SetEvent(pRWLock->hevWriters); # elif K_OS == K_OS_OS2 DosPostEvent(pRWLock->hevwriters); # endif kPrfMutexRelease(&pRWLock->Mutex); #endif } /** * Acquires write access to the read-write lock. * @param pRWLock The read-write lock. */ static inline void kPrfRWLockAcquireWrite(KPRF_TYPE(P,RWLOCK) pRWLock) { #if defined(KPRF_USE_PTHREAD) pthread_rwlock_wrlock(pRWLock); #elif K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED) return; kPrfMutexAcquire(&pRWLock->Mutex); if ( !pRWLock->cReaders && ( pRWLock->enmState == RWLOCK_STATE_SHARED || pRWLock->enmState == RWLOCK_STATE_LOCKING) ) { KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_EXCLUSIVE); kPrfMutexRelease(&pRWLock->Mutex); return; } /* * We'll have to wait. */ if (pRWLock->enmState == RWLOCK_STATE_SHARED) KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_LOCKING); KPRF_ATOMIC_INC32(&pRWLock->cWritersWaiting); for (;;) { # if K_OS == K_OS_WINDOWS HANDLE hev = pRWLock->hevWriters; # elif K_OS == K_OS_OS2 HEV hev = pRWLock->hevWriters; # endif kPrfMutexRelease(&pRWLock->Mutex); # if K_OS == K_OS_WINDOWS switch (WaitForSingleObject(hev, INFINITE)) { case WAIT_IO_COMPLETION: case WAIT_TIMEOUT: case WAIT_OBJECT_0: break; case WAIT_ABANDONED: default: KPRF_ATOMIC_DEC32(&pRWLock->cWritersWaiting); return; } # elif K_OS == K_OS_OS2 switch (DosWaitEventSem(hev, SEM_INDEFINITE_WAIT)) { case NO_ERROR: case ERROR_SEM_TIMEOUT: case ERROR_TIMEOUT: case ERROR_INTERRUPT: break; default: KPRF_ATOMIC_DEC32(&pRWLock->cWritersWaiting); return; } ULONG cIgnored; DosResetEventSem(hev, &cIgnored); # endif /* * Try acquire the lock. */ kPrfMutexAcquire(&pRWLock->Mutex); if ( !pRWLock->cReaders && ( pRWLock->enmState == RWLOCK_STATE_SHARED || pRWLock->enmState == RWLOCK_STATE_LOCKING) ) { KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_EXCLUSIVE); KPRF_ATOMIC_DEC32(&pRWLock->cWritersWaiting); kPrfMutexRelease(&pRWLock->Mutex); return; } } #endif } /** * Releases write access to the read-write lock. * @param pRWLock The read-write lock. */ static inline void kPrfRWLockReleaseWrite(KPRF_TYPE(P,RWLOCK) pRWLock) { #if defined(KPRF_USE_PTHREAD) pthread_rwlock_unlock(pRWLock); #elif K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2 if (pRWLock->enmState == RWLOCK_STATE_UNINITIALIZED) return; /* * The common thing is that there are noone waiting. * But, before that usual paranoia. */ kPrfMutexAcquire(&pRWLock->Mutex); if (pRWLock->enmState != RWLOCK_STATE_EXCLUSIVE) { kPrfMutexRelease(&pRWLock->Mutex); return; } if ( !pRWLock->cReadersWaiting && !pRWLock->cWritersWaiting) { KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_SHARED); kPrfMutexRelease(&pRWLock->Mutex); return; } /* * Someone is waiting, wake them up as we change the state. */ # if K_OS == K_OS_WINDOWS HANDLE hev = INVALID_HANDLE_VALUE; # elif K_OS == K_OS_OS2 HEV hev = NULLHANDLE; # endif if (pRWLock->cWritersWaiting) { KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_LOCKING); hev = pRWLock->hevWriters; } else { KPRF_RWLOCK_SETSTATE(pRWLock, RWLOCK_STATE_SHARED); hev = pRWLock->hevReaders; } # if K_OS == K_OS_WINDOWS SetEvent(hev); # elif K_OS == K_OS_OS2 DosPostEvent(pRWLock->hevwriters); # endif kPrfMutexRelease(&pRWLock->Mutex); #endif } #define KPRF_FUNCS_WRITE_LOCK() kPrfRWLockAcquireWrite(&g_FunctionsRWLock) #define KPRF_FUNCS_WRITE_UNLOCK() kPrfRWLockReleaseWrite(&g_FunctionsRWLock) #define KPRF_FUNCS_READ_LOCK() kPrfRWLockAcquireRead(&g_FunctionsRWLock) #define KPRF_FUNCS_READ_UNLOCK() kPrfRWLockReleaseRead(&g_FunctionsRWLock) /** * Finds the module segment which the address belongs to. * */ static int kPrfGetModSeg(KPRF_TYPE(,UPTR) uAddress, char *pszPath, KU32 cchPath, KU32 *piSegment, KPRF_TYPE(P,UPTR) puBasePtr, KPRF_TYPE(P,UPTR) pcbSegmentMinusOne) { #if K_OS == K_OS_WINDOWS /* * Enumerate the module handles. */ HANDLE hProcess = GetCurrentProcess(); DWORD cbNeeded = 0; HMODULE hModIgnored; if ( !EnumProcessModules(hProcess, &hModIgnored, sizeof(hModIgnored), &cbNeeded) && GetLastError() != ERROR_BUFFER_OVERFLOW) /** figure out what this actually returns */ cbNeeded = 256 * sizeof(HMODULE); cbNeeded += sizeof(HMODULE) * 32; HMODULE *pahModules = (HMODULE *)alloca(cbNeeded); if (EnumProcessModules(hProcess, pahModules, cbNeeded, &cbNeeded)) { const unsigned cModules = cbNeeded / sizeof(HMODULE); for (unsigned i = 0; i < cModules; i++) { __try { const KUPTR uImageBase = (KUPTR)pahModules[i]; union { KU8 *pu8; PIMAGE_DOS_HEADER pDos; PIMAGE_NT_HEADERS pNt; PIMAGE_NT_HEADERS32 pNt32; PIMAGE_NT_HEADERS64 pNt64; KUPTR u; } u; u.u = uImageBase; /* reject modules higher than the address. */ if (uAddress < u.u) continue; /* Skip past the MZ header */ if (u.pDos->e_magic == IMAGE_DOS_SIGNATURE) u.pu8 += u.pDos->e_lfanew; /* Ignore anything which isn't an NT header. */ if (u.pNt->Signature != IMAGE_NT_SIGNATURE) continue; /* Extract necessary info from the optional header (comes in 32-bit and 64-bit variations, we simplify a bit). */ KU32 cbImage; PIMAGE_SECTION_HEADER paSHs; if (u.pNt->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)) { paSHs = (PIMAGE_SECTION_HEADER)(u.pNt32 + 1); cbImage = u.pNt32->OptionalHeader.SizeOfImage; } else if (u.pNt->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64)) { paSHs = (PIMAGE_SECTION_HEADER)(u.pNt64 + 1); cbImage = u.pNt64->OptionalHeader.SizeOfImage; } else continue; /* Is our address within the image size */ KUPTR uRVA = uAddress - (KUPTR)pahModules[i]; if (uRVA >= cbImage) continue; /* * Iterate the section headers and figure which section we're in. * (segment == section + 1) */ const KU32 cSHs = u.pNt->FileHeader.NumberOfSections; if (uRVA < paSHs[0].VirtualAddress) { /* the implicit header section */ *puBasePtr = uImageBase; *pcbSegmentMinusOne = paSHs[0].VirtualAddress - 1; *piSegment = 0; } else { KU32 iSH = 0; for (;;) { if (iSH >= cSHs) { /* this shouldn't happen, but in case it does simply deal with it. */ *puBasePtr = paSHs[iSH - 1].VirtualAddress + paSHs[iSH - 1].Misc.VirtualSize + uImageBase; *pcbSegmentMinusOne = cbImage - *puBasePtr; *piSegment = iSH + 1; break; } if (uRVA - paSHs[iSH].VirtualAddress < paSHs[iSH].Misc.VirtualSize) { *puBasePtr = paSHs[iSH].VirtualAddress + uImageBase; *pcbSegmentMinusOne = paSHs[iSH].Misc.VirtualSize; *piSegment = iSH + 1; break; } iSH++; } } /* * Finally, get the module name. * There are multiple ways, try them all before giving up. */ if ( !GetModuleFileNameEx(hProcess, pahModules[i], pszPath, cchPath) && !GetModuleFileName(pahModules[i], pszPath, cchPath) && !GetMappedFileName(hProcess, (PVOID)uAddress, pszPath, cchPath) && !GetModuleBaseName(hProcess, pahModules[i], pszPath, cchPath)) *pszPath = '\0'; return 0; } __except (EXCEPTION_EXECUTE_HANDLER) { } } } #elif K_OS == K_OS_OS2 /* * Just ask the loader. */ ULONG offObj = 0; ULONG iObj = 0; HMODULE hmod = NULLHANDLE; APIRET rc = DosQueryModFromEIP(&hmod, &iObj, cchPath, pszPath, &offObj, uAddress); if (!rc) { *piSegment = iObj; *puBasePtr = uAddress - offObj; *pcbSegmentMinusOne = KPRF_ALIGN(offObj, 0x1000) - 1; /* minimum size */ /* * Query the page attributes starting at the current page. The query will not enter * into the next object since PAG_BASE is requested. */ ULONG cb = ~0UL; ULONG fFlags = ~0UL; uAddress &= ~(KUPTR)0xfff; rc = DosQueryMem((PVOID)(uAddress, &cb, &fFlags); if (!rc) { *pcbSegmentMinusOne = (offObj & ~(KUPTR)0xfff) + KPRF_ALIGN(cb, 0x1000) - 1; if ((fFlags & PAG_BASE) && cb <= 0x1000) /* don't quite remember if PAG_BASE returns one page or not */ { cb = ~0UL; fFlags = ~0UL; rc = DosQueryMem((PVOID)(uAddress + 0x1000), &cb, &fFlags); if (!rc & !(fFlags & (PAG_BASE | PAG_FREE))) *pcbSegmentMinusOne += KPRF_ALIGN(cb, 0x1000); } } return 0; } #endif /* The common fallback */ *pszPath = '\0'; *piSegment = 0; *puBasePtr = 0; *pcbSegmentMinusOne = ~(KPRF_TYPE(,UPTR))0; return -1; } #define KPRF_GET_MODSEG(uAddress, pszPath, cchPath, piSegment, puBasePtr, pcbSegmentMinusOne) \ kPrfGetModSeg(uAddress, pszPath, cchPath, piSegment, puBasePtr, pcbSegmentMinusOne) /* * Instantiate the implementation */ #include "prfcorepre.cpp.h" #include "prfcoremodseg.cpp.h" #include "prfcorefunction.cpp.h" #include "prfcore.cpp.h" #include "prfcoreinit.cpp.h" #include "prfcoreterm.cpp.h" #include "prfcorepost.cpp.h" /** * Registers an unknown thread. * * @returns Pointer to the registered thread. */ static KPRF_TYPE(P,THREAD) kPrfGetThreadAutoReg(void) { KUPTR uStackBasePtr; #if 0 /** @todo I'm sure Win32 has a way of obtaining the top and bottom of the stack, OS/2 did... * Some limit stuff in posix / ansi also comes to mind... */ #elif K_OS == K_OS_OS2 PTIB pTib; PPIB pPib; DosGetInfoBlocks(&pTib, &pPib); /* never fails except if you give it bad input, thus 'Get' not 'Query'. */ /* I never recall which of these is the right one... */ uStackBasePtr = (KUPTR)pTib->tib_pstack < (KUPTR)pTib->tib_pstack_limit ? (KUPTR)pTib->tib_pstack : (KUPTR)pTib->tib_pstack_limit; #else /* the default is top of the current stack page (assuming a page to be 4KB) */ uStackBasePtr = (KUPTR)&uStackBasePtr; uStackBasePtr = (uStackBasePtr + 0xfff) & ~(KUPTR)0xfff; #endif return KPRF_NAME(RegisterThread)(uStackBasePtr, ""); } /** * Get a env.var. variable. * * @returns pszValue. * @param pszVar The variable name. * @param pszValue Where to store the value. * @param cchValue The size of the value buffer. * @param pszDefault The default value. */ static char *kPrfGetEnvString(const char *pszVar, char *pszValue, KU32 cchValue, const char *pszDefault) { #if K_OS == K_OS_WINDOWS if (GetEnvironmentVariable(pszVar, pszValue, cchValue)) return pszValue; #elif K_OS == K_OS_OS2 PSZ pszValue; if ( !DosScanEnv((PCSZ)pszVar, &pszValue) && !*pszValue) pszDefault = pszValue; #else const char *pszTmp = getenv(pszVar); if (pszTmp) pszDefault = pszTmp; #endif /* * Copy the result into the buffer. */ char *psz = pszValue; while (*pszDefault && cchValue-- > 1) *psz++ = *pszDefault++; *psz = '\0'; return pszValue; } /** * The the value of an env.var. * * @returns The value of the env.var. * @returns The default if the value was not found. * @param pszVar The variable name. * @param uDefault The default value. */ static KU32 kPrfGetEnvValue(const char *pszVar, KU32 uDefault) { #if K_OS == K_OS_WINDOWS char szBuf[128]; const char *pszValue = szBuf; if (!GetEnvironmentVariable(pszVar, szBuf, sizeof(szBuf))) pszValue = NULL; #elif K_OS == K_OS_OS2 PSZ pszValue; if (DosScanEnv((PCSZ)pszVar, &pszValue)) pszValue = NULL; #else const char *pszValue = getenv(pszVar); #endif /* * Discard the obvious stuff. */ if (!pszValue) return uDefault; while (*pszValue == ' ' || *pszValue == '\t') pszValue++; if (!*pszValue) return uDefault; /* * Interpret the value. */ unsigned uBase = 10; KU32 uValue = 0; const char *psz = pszValue; /* prefix - only hex */ if (*psz == '0' && (psz[1] == 'x' || psz[1] == 'X')) { uBase = 16; psz += 2; } /* read the value */ while (*psz) { unsigned char ch = (unsigned char)*psz; if (ch >= '0' && ch <= '9') ch -= '0'; else if ( uBase > 10 && ch >= 'a' && ch <= 'f') ch -= 'a' + 10; else if ( uBase > 10 && ch >= 'a' && ch <= 'F') ch -= 'a' + 10; else break; uValue *= uBase; uValue += ch; psz++; } /* postfixes */ switch (*psz) { case 'm': case 'M': uValue *= 1024*1024; break; case 'k': case 'K': uValue *= 1024; break; } /* * If the value is still 0, we return the default. */ return uValue ? uValue : uDefault; } /** * Allocates memory. * * @returns Pointer to the allocated memory. * @returns NULL on failure. * @param cb The amount of memory (in bytes) to allocate. */ static void *kPrfAllocMem(KU32 cb) { #if K_OS == K_OS_WINDOWS void *pv = VirtualAlloc(NULL, cb, MEM_COMMIT, PAGE_EXECUTE_READWRITE); #elif defined(KPRF_USE_MMAN) void *pv = mmap(NULL, cb, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); #elif K_OS == K_OS_OS2 void *pv; # ifdef INCL_DOSEXAPIS if (DosAllocMemEx(&pv, cb, PAG_READ | PAG_WRITE | PAG_EXECUTE | PAG_COMMIT | OBJ_FORK))s # else if (DosAllocMem(&pv, cb, PAG_READ | PAG_WRITE | PAG_EXECUTE | PAG_COMMIT)) # endif pvBuf = NULL; #else # error not implemented #endif return pv; } /** * Frees memory. * * @param pv The memory to free. */ static void kPrfFreeMem(void *pv) { #if K_OS == K_OS_WINDOWS VirtualFree(pv, 0, MEM_RELEASE); #elif defined(KPRF_USE_MMAN) munmap(pv, 0); /** @todo check if 0 is allowed here.. */ #elif K_OS == K_OS_OS2 # ifdef INCL_DOSEXAPIS DosFreeMemEx(&pv); # else DosFreeMem(&pv); # endif #else # error not implemented #endif } /** * Writes a data buffer to a new file. * * Any existing file will be overwritten. * * * @returns 0 on success. * @returns -1 on failure. * * @param pszName The name of the file. * @param pvData The data to write. * @param cbData The amount of data to write. */ static int kPrfWriteFile(const char *pszName, const void *pvData, KU32 cbData) { #if K_OS == K_OS_WINDOWS int rc = -1; HANDLE hFile = CreateFile(pszName,GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE); if (hFile != INVALID_HANDLE_VALUE) { DWORD dwWritten; if ( WriteFile(hFile, pvData, cbData, &dwWritten, NULL) && dwWritten == cbData) rc = 0; CloseHandle(hFile); } return rc; #elif K_OS == K_OS_OS2 HFILE hFile; ULONG ulAction = 0; APIRET rc = DosOpen(pszName, &hFile, &ulAction, cbData, FILE_NORMAL, OPEN_ACTION_REPLACE_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW, OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYWRITE | OPEN_FLAGS_NOINHERIT | OPEN_FLAGS_SEQUENTIAL, NULL); if (!rc) { ULONG cbWritten; rc = DosWrite(hFile, pvData, cbData, &cbWritten); if (!rc && cbWritten != cbData) rc = -1; DosClose(hFile); } return rc ? -1 : 0; #else int rc = -1; int fd = open(pszName, O_WRONLY | O_CREAT | O_BINARY | O_TRUNC, 0666); if (fd >= 0) { if (write(fd, pvData, cbData) == cbData) rc = 0; close(fd); } return rc; #endif } /** * Initializes and start the profiling. * * This should typically be called from some kind of module init * function, so we can start profiling upon/before entering main(). * * @returns 0 on success * @returns -1 on failure. * */ int kPrfInitialize(void) { /* * Only initialize once. */ if (KPRF_GET_HDR()) return 0; /* * Initial suggestions. */ KU32 cbModSegs = kPrfGetEnvValue("KPRF2_CBMODSEGS", 128*1024); KU32 cFunctions = kPrfGetEnvValue("KPRF2_CFUNCTIONS", 8192); KU32 cThreads = kPrfGetEnvValue("KPRF2_CTHREADS", 256); KU32 cStacks = kPrfGetEnvValue("KPRF2_CSTACKS", 48); KU32 cFrames = kPrfGetEnvValue("KPRF2_CFRAMES", 448); KU32 fAffinity = kPrfGetEnvValue("KPRF2_AFFINITY", 0); KU32 cb = KPRF_NAME(CalcSize)(cFunctions, cbModSegs, cThreads, cStacks, cFrames); /* * Allocate and initialize the data set. */ void *pvBuf = kPrfAllocMem(cb); if (!pvBuf) return -1; KPRF_TYPE(P,HDR) pHdr = KPRF_NAME(Init)(pvBuf, cb, cFunctions, cbModSegs, cThreads, cStacks, cFrames); if (pHdr) { /* * Initialize semaphores. */ if (!kPrfMutexInit(&g_ThreadsMutex)) { if (!kPrfMutexInit(&g_ModSegsMutex)) { if (!kPrfRWLockInit(&g_FunctionsRWLock)) { /* * Allocate the TLS entry. */ #if K_OS == K_OS_WINDOWS g_dwThreadTLS = TlsAlloc(); if (g_dwThreadTLS != TLS_OUT_OF_INDEXES) #elif defined(KPRF_USE_PTHREAD) int rc = pthread_key_create(&g_ThreadKey, kPrfPThreadKeyDtor); if (!rc) #elif K_OS == K_OS_OS2 int rc = DosAllocThreadLocalMemory(sizeof(void *), (PULONG*)&g_ppThread); /** @todo check if this is a count or a size. */ if (!rc) #endif { /* * Apply the affinity mask, if specified. */ if (fAffinity) { #if K_OS == K_OS_WINDOWS SetProcessAffinityMask(GetCurrentProcess(), fAffinity); #endif } g_pHdr = pHdr; g_fEnabled = true; return 0; } kPrfRWLockDelete(&g_FunctionsRWLock); } kPrfMutexDelete(&g_ModSegsMutex); } kPrfMutexDelete(&g_ThreadsMutex); } } kPrfFreeMem(pvBuf); return -1; } /** * Stops, dumps, and terminates the profiling. * * This should typically be called from some kind of module destruction * function, so we can profile parts of the termination sequence too. * * @returns 0 on success * @returns -1 on failure. * */ int kPrfTerminate(void) { /* * Stop the profiling. * As a safety precaution, sleep a little bit to allow threads * still at large inside profiler code some time to get out. */ g_fEnabled = false; KPRF_TYPE(P,HDR) pHdr = g_pHdr; g_pHdr = NULL; if (!pHdr) return -1; #if K_OS == K_OS_WINDOWS Sleep(10); #elif K_OS == K_OS_OS2 DosSleep(10); #else usleep(10000); #endif /* * Unwind all active threads and so forth. */ KPRF_NAME(TerminateAll)(pHdr); /* * Use the stack space to fill in process details. */ #if K_OS == K_OS_WINDOWS /* all is one single string */ const char *pszCommandLine = GetCommandLine(); if (pszCommandLine) KPRF_NAME(SetCommandLine)(pHdr, 1, &pszCommandLine); #elif K_OS == K_OS_OS2 || K_OS == K_OS_OS2 PTIB pTib; PPIB pPib; DosGetInfoBlocks(&pTib, &pPib); if (pPib->pib_pchcmd) { /* Tradition say that the commandline is made up of two zero terminate strings * - first the executable name, then the arguments. Similar to what unix does, * only completely mocked up because of the CMD.EXE tradition. */ const char *apszArgs[2]; apszArgs[0] = pPib->pib_pchcmd; apszArgs[1] = pPib->pib_pchcmd; while (apszArgs[1][0]) apszArgs[1]++; apszArgs[1]++; KPRF_NAME(SetCommandLine)(pHdr, 2, apszArgs); } #else /* linux can read /proc/self/something I guess. Don't know about the rest... */ #endif /* * Write the file to disk. */ char szName[260 + 16]; kPrfGetEnvString("KPRF2_FILE", szName, sizeof(szName) - 16, "kPrf2-"); /* append the process id */ KUPTR pid = kPrfGetProcessId(); char *psz = szName; while (*psz) psz++; static char s_szDigits[0x11] = "0123456789abcdef"; KU32 uShift = KPRF_BITS - 4; while ( uShift > 0 && !(pid & (0xf << uShift))) uShift -= 4; *psz++ = s_szDigits[(pid >> uShift) & 0xf]; while (uShift > 0) { uShift -= 4; *psz++ = s_szDigits[(pid >> uShift) & 0xf]; } /* .kPrf2 */ *psz++ = '.'; *psz++ = 'k'; *psz++ = 'P'; *psz++ = 'r'; *psz++ = 'f'; *psz++ = '2'; *psz++ = '\0'; /* write the file. */ int rc = kPrfWriteFile(szName, pHdr, pHdr->cb); /* * Free resources. */ kPrfFreeMem(pHdr); #if K_OS == K_OS_WINDOWS TlsFree(g_dwThreadTLS); g_dwThreadTLS = TLS_OUT_OF_INDEXES; #elif defined(KPRF_USE_PTHREAD) pthread_key_delete(g_ThreadKey); g_ThreadKey = (pthread_key_t)-1; #elif K_OS == K_OS_OS2 DosFreeThreadLocalMemory((PULONG)g_ppThread); g_ppThread = NULL; #else # error "port me!" #endif kPrfMutexDelete(&g_ThreadsMutex); kPrfMutexDelete(&g_ModSegsMutex); kPrfRWLockDelete(&g_FunctionsRWLock); return rc; } /** * Terminate the current thread. */ void kPrfTerminateThread(void) { KPRF_NAME(DeregisterThread)(); } #ifdef KPRF_USE_PTHREAD /** * TLS destructor. */ static void kPrfPThreadKeyDtor(void *pvThread) { KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR(); if (pHdr) { KPRF_TYPE(P,THREAD) pThread = (KPRF_TYPE(P,THREAD))pvThread; pthread_setspecific(g_ThreadKey, pvThread); KPRF_NAME(TerminateThread)(pHdr, pThread, KPRF_NOW()); pthread_setspecific(g_ThreadKey, NULL); } } #endif kbuild-3149/src/lib/kStuff/kProfiler2/prfcore.cpp.h0000644000175000017500000005026113252530254022121 0ustar locutuslocutus/* $Id: prfcore.cpp.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kProfiler Mark 2 - Core Code Template. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /** * Gets a function, create a new one if necessary. */ static KPRF_TYPE(P,FUNC) KPRF_NAME(GetFunction)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(,UPTR) uPC) { /* * Perform a binary search of the function lookup table. */ KPRF_TYPE(P,FUNC) paFunctions = KPRF_OFF2PTR(P,FUNC, pHdr->offFunctions, pHdr); KPRF_FUNCS_READ_LOCK(); KI32 iStart = 0; KI32 iLast = pHdr->cFunctions - 1; KI32 i = iLast / 2; for (;;) { KU32 iFunction = pHdr->aiFunctions[i]; KPRF_TYPE(,IPTR) iDiff = uPC - paFunctions[iFunction].uEntryPtr; if (!iDiff) { KPRF_FUNCS_READ_UNLOCK(); return &paFunctions[iFunction]; } if (iLast == iStart) break; if (iDiff < 0) iLast = i - 1; else iStart = i + 1; if (iLast < iStart) break; i = iStart + (iLast - iStart) / 2; } KPRF_FUNCS_READ_UNLOCK(); /* * It wasn't found, try add it. */ if (pHdr->cFunctions < pHdr->cMaxFunctions) return KPRF_NAME(NewFunction)(pHdr, uPC); return NULL; } /** * Unwind one frame. */ static KU64* KPRF_NAME(UnwindOne)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(P,STACK) pStack, KPRF_TYPE(,UPTR) uPC, KU64 TS) { /* * Pop off the frame and update the frame below / thread. */ KPRF_TYPE(P,FRAME) pFrame = &pStack->aFrames[--pStack->cFrames]; KU64 *pCurOverheadTicks; if (pStack->cFrames) { KPRF_TYPE(P,FRAME) pTopFrame = pFrame - 1; pTopFrame->OverheadTicks += pFrame->OverheadTicks + pFrame->CurOverheadTicks; pTopFrame->SleepTicks += pFrame->SleepTicks; pTopFrame->OnTopOfStackStart = TS; pTopFrame->CurOverheadTicks = 0; pCurOverheadTicks = &pTopFrame->CurOverheadTicks; } else { KPRF_TYPE(P,THREAD) pThread = KPRF_OFF2PTR(P,THREAD, pStack->offThread, pHdr); pThread->ProfiledTicks += TS - pFrame->OnStackStart - pFrame->CurOverheadTicks - pFrame->OverheadTicks - pFrame->SleepTicks; pThread->OverheadTicks += pFrame->OverheadTicks + pFrame->CurOverheadTicks; pThread->SleepTicks += pFrame->SleepTicks; pCurOverheadTicks = &pThread->OverheadTicks; } /* * Update the function (if any). */ if (pFrame->offFunction) { KPRF_TYPE(P,FUNC) pFunc = KPRF_OFF2PTR(P,FUNC, pFrame->offFunction, pHdr); /* Time on stack */ KU64 Ticks = TS - pFrame->OnStackStart; Ticks -= pFrame->OverheadTicks + pFrame->CurOverheadTicks + pFrame->SleepTicks; /** @todo adjust overhead */ KPRF_ASSERT(!(Ticks >> 63)); if (pFunc->OnStack.MinTicks > Ticks) KPRF_ATOMIC_SET64(&pFunc->OnStack.MinTicks, Ticks); if (pFunc->OnStack.MaxTicks < Ticks) KPRF_ATOMIC_SET64(&pFunc->OnStack.MaxTicks, Ticks); KPRF_ATOMIC_ADD64(&pFunc->OnStack.SumTicks, Ticks); /* Time on top of stack */ Ticks = TS - pFrame->OnTopOfStackStart; Ticks -= pFrame->CurOverheadTicks; Ticks += pFrame->OnTopOfStackTicks; /** @todo adjust overhead */ KPRF_ASSERT(!(Ticks >> 63)); if (pFunc->OnTopOfStack.MinTicks > Ticks) KPRF_ATOMIC_SET64(&pFunc->OnTopOfStack.MinTicks, Ticks); if (pFunc->OnTopOfStack.MaxTicks < Ticks) KPRF_ATOMIC_SET64(&pFunc->OnTopOfStack.MaxTicks, Ticks); KPRF_ATOMIC_ADD64(&pFunc->OnTopOfStack.SumTicks, Ticks); /* calls */ if (pFrame->cCalls) KPRF_ATOMIC_ADD64(&pFunc->cCalls, pFrame->cCalls); } return pCurOverheadTicks; } /** * Unwinds the stack. * * On MSC+AMD64 we have to be very very careful here, because the uFramePtr cannot be trusted. */ static KU64* KPRF_NAME(UnwindInt)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(P,STACK) pStack, KPRF_TYPE(,UPTR) uPC, KPRF_TYPE(,UPTR) uFramePtr, KU64 TS) { /** @todo need to deal with alternative stacks! */ /* * Pop the stack until we're down below the current frame (uFramePtr). */ KI32 iFrame = pStack->cFrames - 1; KPRF_TYPE(P,FRAME) pFrame = &pStack->aFrames[iFrame]; /* the most frequent case first. */ #if K_OS == K_OS_WINDOWS && K_ARCH == K_ARCH_AMD64 if ( uFramePtr == pFrame->uFramePtr || ( pFrame->uFramePtr < uFramePtr && iFrame > 0 && pFrame[-1].uFramePtr > uFramePtr)) return KPRF_NAME(UnwindOne)(pHdr, pStack, uPC, TS); #else if (uFramePtr == pFrame->uFramePtr) return KPRF_NAME(UnwindOne)(pHdr, pStack, uPC, TS); #endif /* none? */ if (pFrame->uFramePtr > uFramePtr) return &pFrame->CurOverheadTicks; /* one or more, possibly all */ KU64 *pCurOverheadTicks = KPRF_NAME(UnwindOne)(pHdr, pStack, uPC, TS); pFrame--; if ( iFrame > 0 #if K_OS == K_OS_WINDOWS && K_ARCH == K_ARCH_AMD64 && pFrame->uFramePtr <= uFramePtr && pFrame[-1].uFramePtr > uFramePtr) #else && pFrame->uFramePtr <= uFramePtr) #endif { KPRF_TYPE(P,THREAD) pThread = KPRF_OFF2PTR(P,THREAD, pStack->offThread, pHdr); pThread->cUnwinds++; /* (This is the reason for what looks like a bad loop unrolling.) */ pCurOverheadTicks = KPRF_NAME(UnwindOne)(pHdr, pStack, uPC, TS); iFrame -= 2; pFrame--; #if K_OS == K_OS_WINDOWS && K_ARCH == K_ARCH_AMD64 while ( iFrame > 0 && pFrame->uFramePtr <= uFramePtr && pFrame[-1].uFramePtr > uFramePtr) #else while ( iFrame >= 0 && pFrame->uFramePtr <= uFramePtr) #endif { pCurOverheadTicks = KPRF_NAME(UnwindOne)(pHdr, pStack, uPC, TS); iFrame--; pFrame--; } } return pCurOverheadTicks; } /** * Enter function. * * @returns Where to account overhead. * @returns NULL if profiling is inactive. * * @param uPC The program counter register. (not relative) * @param uFramePtr The stack frame address. This must match the one passed to kPrfLeave. (not relative) * @param TS The timestamp when we entered into the profiler. * This must not be modified touched! * * @internal ? */ KPRF_DECL_FUNC(KU64 *, Enter)(KPRF_TYPE(,UPTR) uPC, KPRF_TYPE(,UPTR) uFramePtr, const KU64 TS) { /* * Is profiling active ? */ if (!KPRF_IS_ACTIVE()) return NULL; /* * Get the header and adjust input addresses. */ KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR(); if (!pHdr) return NULL; const KPRF_TYPE(,UPTR) uBasePtr = pHdr->uBasePtr; if (uBasePtr) { uFramePtr -= uBasePtr; uPC -= uBasePtr; } /* * Get the current thread. Reject unknown, inactive (in whatever way), * and thread which has performed a stack switch. */ KPRF_TYPE(P,THREAD) pThread = KPRF_GET_THREAD(); if (!pThread) return NULL; KPRF_TYPE(,THREADSTATE) enmThreadState = pThread->enmState; if ( enmThreadState != KPRF_TYPE(,THREADSTATE_ACTIVE) && enmThreadState != KPRF_TYPE(,THREADSTATE_OVERFLOWED) ) return NULL; if (pThread->uStackBasePtr < uFramePtr) /* ASSUMES stack direction */ { pThread->cStackSwitchRejects++; return NULL; } pThread->enmState = KPRF_TYPE(,THREADSTATE_SUSPENDED); /* * Update the thread statistics. */ pThread->cCalls++; KPRF_TYPE(,UPTR) cbStack = pThread->uStackBasePtr - uFramePtr; /* ASSUMES stack direction */ if (pThread->cbMaxStack < cbStack) pThread->cbMaxStack = cbStack; /* * Check if an longjmp or throw has taken place. * This check will not work if a stack switch has taken place (can fix that later). */ KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pThread->offStack, pHdr); KU32 iFrame = pStack->cFrames; KPRF_TYPE(P,FRAME) pFrame = &pStack->aFrames[iFrame]; if ( iFrame #if K_OS == K_OS_WINDOWS && K_ARCH == K_ARCH_AMD64 && 0) /* don't bother her yet because of _penter/_pexit frame problems. */ #else && pThread->uStackBasePtr >= uFramePtr /* ASSUMES stack direction */ && pFrame[-1].uFramePtr + (KPRF_BITS - 8) / 8 < uFramePtr) /* ASSUMES stack direction */ #endif { KPRF_NAME(UnwindInt)(pHdr, pStack, uPC, uFramePtr, TS); iFrame = pStack->cFrames; } /* * Allocate a new stack frame. */ if (iFrame >= pHdr->cMaxStackFrames) { /* overflow */ pThread->enmState = KPRF_TYPE(,THREADSTATE_OVERFLOWED); pThread->cOverflows += enmThreadState != KPRF_TYPE(,THREADSTATE_OVERFLOWED); return &pStack->aFrames[iFrame - 1].CurOverheadTicks; } pStack->cFrames++; /* * Update the old top frame if any. */ if (iFrame) { KPRF_TYPE(P,FRAME) pOldFrame = pFrame - 1; pOldFrame->OnTopOfStackTicks += TS - pOldFrame->OnTopOfStackStart; pOldFrame->cCalls++; } /* * Fill in the new frame. */ pFrame->CurOverheadTicks = 0; pFrame->OverheadTicks = 0; pFrame->SleepTicks = 0; pFrame->OnStackStart = TS; pFrame->OnTopOfStackStart = TS; pFrame->OnTopOfStackTicks = 0; pFrame->cCalls = 0; pFrame->uFramePtr = uFramePtr; /* * Find the relevant function. */ KPRF_TYPE(P,FUNC) pFunc = KPRF_NAME(GetFunction)(pHdr, uPC); if (pFunc) { pFrame->offFunction = KPRF_PTR2OFF(pFunc, pHdr); pFunc->cOnStack++; } else pFrame->offFunction = 0; /* * Nearly done, We only have to reactivate the thread and account overhead. * The latter is delegated to the caller. */ pThread->enmState = KPRF_TYPE(,THREADSTATE_ACTIVE); return &pFrame->CurOverheadTicks; } /** * Leave function. * * @returns Where to account overhead. * @returns NULL if profiling is inactive. * * @param uPC The program counter register. * @param uFramePtr The stack frame address. This must match the one passed to kPrfEnter. * @param TS The timestamp when we entered into the profiler. * This must not be modified because the caller could be using it! * @internal */ KPRF_DECL_FUNC(KU64 *, Leave)(KPRF_TYPE(,UPTR) uPC, KPRF_TYPE(,UPTR) uFramePtr, const KU64 TS) { /* * Is profiling active ? */ if (!KPRF_IS_ACTIVE()) return NULL; /* * Get the header and adjust input addresses. */ KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR(); if (!pHdr) return NULL; const KPRF_TYPE(,UPTR) uBasePtr = pHdr->uBasePtr; if (uBasePtr) { uFramePtr -= uBasePtr; uPC -= uBasePtr; } /* * Get the current thread and suspend profiling of the thread until we leave this function. * Also reject threads which aren't active in some way. */ KPRF_TYPE(P,THREAD) pThread = KPRF_GET_THREAD(); if (!pThread) return NULL; KPRF_TYPE(,THREADSTATE) enmThreadState = pThread->enmState; if ( enmThreadState != KPRF_TYPE(,THREADSTATE_ACTIVE) && enmThreadState != KPRF_TYPE(,THREADSTATE_OVERFLOWED) ) return NULL; KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pThread->offStack, pHdr); if (!pStack->cFrames) return NULL; pThread->enmState = KPRF_TYPE(,THREADSTATE_SUSPENDED); /* * Unwind the stack down to and including the entry indicated by uFramePtr. * Leave it to the caller to update the overhead. */ KU64 *pCurOverheadTicks = KPRF_NAME(UnwindInt)(pHdr, pStack, uPC, uFramePtr, TS); pThread->enmState = enmThreadState; return pCurOverheadTicks; } /** * Register the current thread. * * A thread can only be profiled if it has been registered by a call to this function. * * @param uPC The program counter register. * @param uStackBasePtr The base of the stack. */ KPRF_DECL_FUNC(KPRF_TYPE(P,THREAD), RegisterThread)(KPRF_TYPE(,UPTR) uStackBasePtr, const char *pszName) { /* * Get the header and adjust input address. * (It doesn't matter whether we're active or not.) */ KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR(); if (!pHdr) return NULL; const KPRF_TYPE(,UPTR) uBasePtr = pHdr->uBasePtr; if (uBasePtr) uStackBasePtr -= uBasePtr; /* * Allocate a thread and a stack. */ KPRF_THREADS_LOCK(); if (pHdr->cThreads < pHdr->cMaxThreads) { KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pHdr->offStacks, pHdr); KU32 cLeft = pHdr->cMaxStacks; do { if (!pStack->offThread) { /* init the stack. */ pStack->cFrames = 0; pStack->offThread = pHdr->offThreads + pHdr->cbThread * pHdr->cThreads++; pHdr->cStacks++; /* init the thread */ KPRF_TYPE(P,THREAD) pThread = KPRF_OFF2PTR(P,THREAD, pStack->offThread, pHdr); pThread->ThreadId = KPRF_GET_THREADID(); unsigned i = 0; if (pszName) while (i < sizeof(pThread->szName) - 1 && *pszName) pThread->szName[i++] = *pszName++; while (i < sizeof(pThread->szName)) pThread->szName[i++] = '\0'; pThread->enmState = KPRF_TYPE(,THREADSTATE_SUSPENDED); pThread->Reserved0 = KPRF_TYPE(,THREADSTATE_TERMINATED); pThread->uStackBasePtr = uStackBasePtr; pThread->cbMaxStack = 0; pThread->cCalls = 0; pThread->cOverflows = 0; pThread->cStackSwitchRejects = 0; pThread->cUnwinds = 0; pThread->ProfiledTicks = 0; pThread->OverheadTicks = 0; pThread->SleepTicks = 0; pThread->offStack = KPRF_PTR2OFF(pStack, pHdr); /* set the thread and make it active. */ KPRF_THREADS_UNLOCK(); KPRF_SET_THREAD(pThread); pThread->enmState = KPRF_TYPE(,THREADSTATE_ACTIVE); return pThread; } /* next */ pStack = KPRF_TYPE(P,STACK)(((KPRF_TYPE(,UPTR))pStack + pHdr->cbStack)); } while (--cLeft > 0); } KPRF_THREADS_UNLOCK(); return NULL; } /** * Terminates a thread. * * To terminate the current thread use DeregisterThread(), because that * cleans up the TLS entry too. * * @param pHdr The profiler data set header. * @param pThread The thread to terminate. * @param TS The timestamp to use when terminating the thread. */ KPRF_DECL_FUNC(void, TerminateThread)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(P,THREAD) pThread, KU64 TS) { if (pThread->enmState == KPRF_TYPE(,THREADSTATE_TERMINATED)) return; pThread->enmState = KPRF_TYPE(,THREADSTATE_TERMINATED); /* * Unwind the entire stack. */ if (pThread->offStack) { KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pThread->offStack, pHdr); for (KU32 cFrames = pStack->cFrames; cFrames > 0; cFrames--) KPRF_NAME(UnwindOne)(pHdr, pStack, 0, TS); /* * Free the stack. */ pThread->offStack = 0; KPRF_THREADS_LOCK(); pStack->offThread = 0; pHdr->cStacks--; KPRF_THREADS_UNLOCK(); } } /** * Deregister (terminate) the current thread. */ KPRF_DECL_FUNC(void, DeregisterThread)(void) { KU64 TS = KPRF_NOW(); /* * Get the header, then get the thread and mark it terminated. * (It doesn't matter whether we're active or not.) */ KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR(); if (!pHdr) return; KPRF_TYPE(P,THREAD) pThread = KPRF_GET_THREAD(); KPRF_SET_THREAD(NULL); if (!pThread) return; KPRF_NAME(TerminateThread)(pHdr, pThread, TS); } /** * Resumes / restarts a thread. * * @param fReset If set the stack is reset. */ KPRF_DECL_FUNC(void, ResumeThread)(int fReset) { KU64 TS = KPRF_NOW(); /* * Get the header, then get the thread and mark it terminated. * (It doesn't matter whether we're active or not.) */ KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR(); if (!pHdr) return; KPRF_TYPE(P,THREAD) pThread = KPRF_GET_THREAD(); if (!pThread) return; if (pThread->enmState != KPRF_TYPE(,THREADSTATE_SUSPENDED)) return; /* * Reset (unwind) the stack? */ KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pThread->offStack, pHdr); if (fReset) { KU32 cFrames = pStack->cFrames; while (cFrames-- > 0) KPRF_NAME(UnwindOne)(pHdr, pStack, 0, TS); } /* * If we've got any thing on the stack, we'll have to stop the sleeping period. */ else if (pStack->cFrames > 0) { KPRF_TYPE(P,FRAME) pFrame = &pStack->aFrames[pStack->cFrames - 1]; /* update the sleeping time and set the start of the new top-of-stack period. */ pFrame->SleepTicks += TS - pFrame->OnTopOfStackStart; pFrame->OnTopOfStackStart = TS; } /** @todo we're not accounting overhead here! */ /* * We're done, switch the thread to active state. */ pThread->enmState = KPRF_TYPE(,THREADSTATE_ACTIVE); } /** * Suspend / completes a thread. * * The thread will be in a suspend state where the time will be accounted for as sleeping. * * @param fUnwind If set the stack is unwound and the thread statistics updated. */ KPRF_DECL_FUNC(void, SuspendThread)(int fUnwind) { KU64 TS = KPRF_NOW(); /* * Get the header, then get the thread and mark it terminated. * (It doesn't matter whether we're active or not.) */ KPRF_TYPE(P,HDR) pHdr = KPRF_GET_HDR(); if (!pHdr) return; KPRF_TYPE(P,THREAD) pThread = KPRF_GET_THREAD(); if (!pThread) return; if ( pThread->enmState != KPRF_TYPE(,THREADSTATE_ACTIVE) && pThread->enmState != KPRF_TYPE(,THREADSTATE_OVERFLOWED) && (pThread->enmState != KPRF_TYPE(,THREADSTATE_SUSPENDED) || fUnwind)) return; pThread->enmState = KPRF_TYPE(,THREADSTATE_SUSPENDED); /* * Unwind the stack? */ KPRF_TYPE(P,STACK) pStack = KPRF_OFF2PTR(P,STACK, pThread->offStack, pHdr); if (fUnwind) { KU32 cFrames = pStack->cFrames; while (cFrames-- > 0) KPRF_NAME(UnwindOne)(pHdr, pStack, 0, TS); } /* * If we've got any thing on the stack, we'll have to record the sleeping period * of the thread. If not we'll ignore it (for now at least). */ else if (pStack->cFrames > 0) { KPRF_TYPE(P,FRAME) pFrame = &pStack->aFrames[pStack->cFrames - 1]; /* update the top of stack time and set the start of the sleep period. */ pFrame->OnTopOfStackTicks += TS - pFrame->OnTopOfStackStart; pFrame->OnTopOfStackStart = TS; } /** @todo we're not accounting overhead here! */ } kbuild-3149/src/lib/kStuff/kProfiler2/prfcoreinit.cpp.h0000644000175000017500000001447413252530254023013 0ustar locutuslocutus/* $Id: prfcoreinit.cpp.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kProfiler Mark 2 - Core Initialization Code Template. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /** * Calculates the size of the profiler data set. * * @returns The size of the data set in bytes. * * @param cMaxFunctions The max number of functions. * @param cbMaxModSeg The max bytes for module segments. * @param cMaxThreads The max number of threads. * @param cMaxStacks The max number of stacks. (should be less or equal to the max number of threads) * @param cMaxStackFrames The max number of frames on each of the stacks. * * @remark This function does not input checks, it only aligns it. The caller is * responsible for the input to make some sense. */ KPRF_DECL_FUNC(KU32, CalcSize)(KU32 cMaxFunctions, KU32 cbMaxModSegs, KU32 cMaxThreads, KU32 cMaxStacks, KU32 cMaxStackFrames) { /* * Normalize input. */ KPRF_SETMIN_ALIGN(cMaxFunctions, 16, 16); KPRF_SETMIN_ALIGN(cbMaxModSegs, KPRF_SIZEOF(MODSEG), 32); KPRF_SETMIN_ALIGN(cMaxThreads, 1, 1); KPRF_SETMIN_ALIGN(cMaxStacks, 1, 1); KPRF_SETMIN_ALIGN(cMaxStackFrames, 32, 32); /* * Calc the size from the input. * We do not take overflows into account, stupid user means stupid result. */ KU32 cb = KPRF_OFFSETOF(HDR, aiFunctions[cMaxFunctions]); KU32 cbTotal = KPRF_ALIGN(cb, 32); cb = cMaxFunctions * KPRF_SIZEOF(FUNC); cbTotal += KPRF_ALIGN(cb, 32); cbTotal += cbMaxModSegs; cb = cMaxThreads * KPRF_SIZEOF(THREAD); cbTotal += KPRF_ALIGN(cb, 32); cb = cMaxStacks * KPRF_SIZEOF(STACK); cbTotal += KPRF_ALIGN(cb, 32); cb = cMaxStackFrames * cMaxStacks * KPRF_SIZEOF(FRAME); cbTotal += KPRF_ALIGN(cb, 32); return cbTotal; } /** * Initializes the profiler data set. * * @returns Pointer to the initialized profiler header on success. * @returns NULL if the input doesn't add up. * * @param pvData Where to initialize the profiler data set. * @param cbData The size of the available data. * @param cMaxFunctions The max number of functions. * @param cbMaxModSeg The max bytes for module segments. * @param cMaxThreads The max number of threads. * @param cMaxStacks The max number of stacks. (should be less or equal to the max number of threads) * @param cMaxStackFrames The max number of frames on each of the stacks. * */ KPRF_DECL_FUNC(KPRF_TYPE(P,HDR), Init)(void *pvData, KU32 cbData, KU32 cMaxFunctions, KU32 cbMaxModSegs, KU32 cMaxThreads, KU32 cMaxStacks, KU32 cMaxStackFrames) { /* * Normalize the input. */ if (!pvData) return NULL; KPRF_SETMIN_ALIGN(cMaxFunctions, 16, 16); KPRF_SETMIN_ALIGN(cbMaxModSegs, KPRF_SIZEOF(MODSEG), 32); KPRF_SETMIN_ALIGN(cMaxThreads, 1, 1); KPRF_SETMIN_ALIGN(cMaxStacks, 1, 1); KPRF_SETMIN_ALIGN(cMaxStackFrames, 32, 32); /* * The header. */ KU32 off = 0; KU32 cb = KPRF_OFFSETOF(HDR, aiFunctions[cMaxFunctions]); cb = KPRF_ALIGN(cb, 32); if (cbData < off + cb || off > off + cb) return NULL; KPRF_TYPE(P,HDR) pHdr = (KPRF_TYPE(P,HDR))pvData; /* the core header */ pHdr->u32Magic = 0; /* Set at the very end */ pHdr->cFormatBits = KPRF_BITS; pHdr->uBasePtr = 0; /* Can be set afterwards using SetBasePtr. */ #if KPRF_BITS <= 16 pHdr->u16Reserved = 0; #endif #if KPRF_BITS <= 32 pHdr->u32Reserved = 0; #endif pHdr->cb = cbData; pHdr->cbAllocated = cbData; /* functions */ off += cb; cb = cMaxFunctions * KPRF_SIZEOF(FUNC); cb = KPRF_ALIGN(cb, 32); if (cbData < off + cb || off > off + cb) return NULL; pHdr->cMaxFunctions = cMaxFunctions; pHdr->cFunctions = 0; pHdr->offFunctions = off; pHdr->cbFunction = KPRF_SIZEOF(FUNC); /* modsegs */ off += cb; cb = KPRF_ALIGN(cbMaxModSegs, 32); if (cbData < off + cb || off > off + cb) return NULL; pHdr->cbMaxModSegs = cbMaxModSegs; pHdr->cbModSegs = 0; pHdr->offModSegs = off; /* threads */ off += cb; cb = cMaxThreads * KPRF_SIZEOF(THREAD); cb = KPRF_ALIGN(cb, 32); if (cbData < off + cb || off > off + cb) return NULL; pHdr->cMaxThreads = cMaxThreads; pHdr->cThreads = 0; pHdr->offThreads = off; pHdr->cbThread = KPRF_SIZEOF(THREAD); /* stacks */ off += cb; cb = cMaxStacks * KPRF_OFFSETOF(STACK, aFrames[cMaxStackFrames]); cb = KPRF_ALIGN(cb, 32); if (cbData < off + cb || off > off + cb) return NULL; pHdr->cMaxStacks = cMaxStacks; pHdr->cStacks = 0; pHdr->offStacks = off; pHdr->cbStack = KPRF_OFFSETOF(STACK, aFrames[cMaxStackFrames]); pHdr->cMaxStackFrames = cMaxStackFrames; /* commandline */ pHdr->offCommandLine = 0; pHdr->cchCommandLine = 0; /* the final size */ pHdr->cb = off + cb; /* * Done. */ pHdr->u32Magic = KPRF_TYPE(,HDR_MAGIC); return pHdr; } kbuild-3149/src/lib/kStuff/kProfiler2/prfreader.cpp.h0000644000175000017500000016213113252530254022433 0ustar locutuslocutus/* $Id: prfreader.cpp.h 77 2016-06-22 17:03:55Z bird $ */ /** @file * kProfiler Mark 2 - Reader Code Template. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /** * Validates the non-header parts of a data-set. * * @returns true if valid. * @returns false if invalid. (written description to pOut) * * @param pHdr Pointer to the data set. * @param cb The size of the data set. * @param pOut Where to write error messages. */ static bool KPRF_NAME(IsValid)(KPRF_TYPE(PC,HDR) pHdr, KU32 cb, FILE *pOut) { KPRF_TYPE(,UPTR) uMaxPtr = ~(KPRF_TYPE(,UPTR))0 - pHdr->uBasePtr; /* * Iterate the module segments. */ KU32 off = pHdr->offModSegs; while (off < pHdr->offModSegs + pHdr->cbModSegs) { KPRF_TYPE(PC,MODSEG) pCur = KPRF_OFF2PTR(PC,MODSEG, off, pHdr); KU32 cbCur = KPRF_OFFSETOF(MODSEG, szPath[pCur->cchPath + 1]); cbCur = KPRF_ALIGN(cbCur, KPRF_SIZEOF(UPTR)); if (cbCur + off > pHdr->offModSegs + pHdr->cbModSegs) { fprintf(pOut, "The module segment record at 0x%x is too long!\n", off); return false; } if (pCur->uBasePtr > uMaxPtr) fprintf(pOut, "warning: The module segment record at 0x%x has a too high base address.\n", off); if (strlen(pCur->szPath) != pCur->cchPath) { fprintf(pOut, "The module segment record at 0x%x has an invalid path length 0x%x it the actual length is 0x%x\n", off, pCur->cchPath, strlen(pCur->szPath)); return false; } /* next */ off += cbCur; } /* * Iterate the functions. */ KPRF_TYPE(PC,FUNC) paFuncs = KPRF_OFF2PTR(PC,FUNC, pHdr->offFunctions, pHdr); for (KU32 i = 0; i < pHdr->cFunctions; i++) { KPRF_TYPE(PC,FUNC) pCur = &paFuncs[i]; if (pCur->uEntryPtr > uMaxPtr) fprintf(pOut, "warning: Function 0x%x has a too high base address.\n", i); if (pCur->offModSeg) { if ( pCur->offModSeg < pHdr->offModSegs || pCur->offModSeg >= pHdr->offModSegs + pHdr->cbModSegs || pCur->offModSeg != KPRF_ALIGN(pCur->offModSeg, sizeof(pCur->uEntryPtr)) ) { fprintf(pOut, "Function 0x%x has an invalid offModSeg value (0x%x).\n", i, pCur->offModSeg); return false; } /** @todo more validation here.. */ } } /* * Validate the threads. */ KPRF_TYPE(PC,THREAD) paThreads = KPRF_OFF2PTR(PC,THREAD, pHdr->offThreads, pHdr); for (KU32 i = 0; i < pHdr->cThreads; i++) { KPRF_TYPE(PC,THREAD) pCur = &paThreads[i]; if (pCur->uStackBasePtr > uMaxPtr) fprintf(pOut, "warning: Thread 0x%x has a too high base address.\n", i); switch (pCur->enmState) { case KPRF_TYPE(,THREADSTATE_ACTIVE): case KPRF_TYPE(,THREADSTATE_SUSPENDED): case KPRF_TYPE(,THREADSTATE_OVERFLOWED): case KPRF_TYPE(,THREADSTATE_TERMINATED): break; default: fprintf(pOut, "Thread 0x%x has an invalid state value (0x%x).\n", i, pCur->enmState); return false; } } return true; } /** * Dumps a file of a particular format. * * @returns 0 on success. (you might want to check the pOut state) * @returns -1 on failure. * * @param pHdr Pointer to the data set. * @param pOut The output file. This is opened for text writing. * @param pReader The reader object. */ static int KPRF_NAME(Dump)(KPRF_TYPE(PC,HDR) pHdr, FILE *pOut) { /* * Any commandline? */ if (pHdr->offCommandLine) fprintf(pOut, "Commandline: %s (%d bytes)\n", (char *)KPRF_OFF2PTR(PC,MODSEG, pHdr->offCommandLine, pHdr), /* stupid, stupid, type hacking. */ pHdr->cchCommandLine); /* * Dump the module segments. */ fprintf(pOut, "Module Segments: off=0x%x 0x%x/0x%x (bytes)\n" "----------------\n", pHdr->offModSegs, pHdr->cbModSegs, pHdr->cbMaxModSegs); KU32 off = pHdr->offModSegs; while (off < pHdr->offModSegs + pHdr->cbModSegs) { KPRF_TYPE(PC,MODSEG) pCur = KPRF_OFF2PTR(PC,MODSEG, off, pHdr); KU32 cbCur = KPRF_OFFSETOF(MODSEG, szPath[pCur->cchPath + 1]); cbCur = KPRF_ALIGN(cbCur, KPRF_SIZEOF(UPTR)); fprintf(pOut, "0x%04x: iSegment=0x%08x uBasePtr=%" KPRF_FMT_UPTR " szPath='%s' (%d bytes)\n", off, pCur->iSegment, pCur->uBasePtr, pCur->szPath, pCur->cchPath); /* next */ off += cbCur; } fprintf(pOut, "\n"); /* * Dump the functions. */ fprintf(pOut, "Functions: off=0x%x 0x%x/0x%x\n" "----------\n", pHdr->offFunctions, pHdr->cFunctions, pHdr->cMaxFunctions); KPRF_TYPE(PC,FUNC) paFuncs = KPRF_OFF2PTR(PC,FUNC, pHdr->offFunctions, pHdr); for (KU32 i = 0; i < pHdr->cFunctions; i++) { KPRF_TYPE(PC,FUNC) pCur = &paFuncs[i]; fprintf(pOut, "0x%04x: uEntryPtr=%" KPRF_FMT_UPTR " cOnStack=0x%" KPRF_FMT_X64 " cCalls=0x%" KPRF_FMT_X64 "\n" " OnStack={0x%" KPRF_FMT_X64 ", 0x%" KPRF_FMT_X64 ", 0x%" KPRF_FMT_X64 "}\n" " OnTopOfStack={0x%" KPRF_FMT_X64 ", 0x%" KPRF_FMT_X64 ", 0x%" KPRF_FMT_X64 "}\n", i, pCur->uEntryPtr, pCur->cOnStack, pCur->cCalls, pCur->OnStack.MinTicks, pCur->OnStack.MaxTicks, pCur->OnStack.SumTicks, pCur->OnTopOfStack.MinTicks, pCur->OnTopOfStack.MaxTicks, pCur->OnTopOfStack.SumTicks); if (pCur->offModSeg) { KPRF_TYPE(PC,MODSEG) pModSeg = KPRF_OFF2PTR(PC,MODSEG, pCur->offModSeg, pHdr); fprintf(pOut, " offModSeg=0x%08x iSegment=0x%02x uBasePtr=%" KPRF_FMT_UPTR " szPath='%s' (%d bytes)\n", pCur->offModSeg, pModSeg->iSegment, pModSeg->uBasePtr, pModSeg->szPath, pModSeg->cchPath); #if 1 PKDBGMOD pMod; int rc = kDbgModuleOpen(&pMod, pModSeg->szPath, NULL /* pLdrMod */); if (!rc) { KDBGSYMBOL Sym; rc = kDbgModuleQuerySymbol(pMod, pModSeg->iSegment, pCur->uEntryPtr - pModSeg->uBasePtr, &Sym); if (!rc) { fprintf(pOut, " %s\n", Sym.szName); } kDbgModuleClose(pMod); } #endif } } fprintf(pOut, "\n"); /* * Dump the threads. */ fprintf(pOut, "Threads: off=0x%x 0x%x/0x%x (Stacks=0x%x/0x%x cMaxStackFrames=0x%x)\n" "--------\n", pHdr->offThreads, pHdr->cThreads, pHdr->cMaxThreads, pHdr->cStacks, pHdr->cMaxStacks, pHdr->cMaxStackFrames); KPRF_TYPE(PC,THREAD) paThreads = KPRF_OFF2PTR(PC,THREAD, pHdr->offThreads, pHdr); for (KU32 i = 0; i < pHdr->cThreads; i++) { KPRF_TYPE(PC,THREAD) pCur = &paThreads[i]; fprintf(pOut, "0x%02x: ThreadId=0x%08" KPRF_FMT_X64 " enmState=%d szName='%s'\n" " uStackBasePtr=%" KPRF_FMT_UPTR " cbMaxStack=%" KPRF_FMT_UPTR "\n" " cCalls=0x%" KPRF_FMT_X64 " cOverflows=0x%" KPRF_FMT_X64 " cStackSwitchRejects=0x%" KPRF_FMT_X64 "\n" " cUnwinds=0x%" KPRF_FMT_X64 " ProfiledTicks=0x%" KPRF_FMT_X64 " OverheadTicks=0x%" KPRF_FMT_X64 "\n", i, pCur->ThreadId, pCur->enmState, pCur->szName, pCur->uStackBasePtr, pCur->cbMaxStack, pCur->cCalls, pCur->cOverflows, pCur->cStackSwitchRejects, pCur->cUnwinds, pCur->ProfiledTicks, pCur->OverheadTicks); } return 0; } /** Pointer to a report module. * @internal */ typedef struct KPRF_TYPE(,REPORTMOD) *KPRF_TYPE(P,REPORTMOD); /** Pointer to a report module segment. * @internal */ typedef struct KPRF_TYPE(,REPORTMODSEG) *KPRF_TYPE(P,REPORTMODSEG); /** * A report module segment. * * @internal */ typedef struct KPRF_TYPE(,REPORTMODSEG) { /** AVL node core. The key is the data set offset of the module segment record. */ KDBGADDR offSegment; struct KPRF_TYPE(,REPORTMODSEG) *mpLeft; /**< AVL left branch. */ struct KPRF_TYPE(,REPORTMODSEG) *mpRight; /**< AVL rigth branch. */ /** Pointer to the next segment for the module. */ KPRF_TYPE(P,REPORTMODSEG) pNext; /** Pointer to the module segment data in the data set. */ KPRF_TYPE(PC,MODSEG) pModSeg; /** Pointer to the module this segment belongs to. */ KPRF_TYPE(P,REPORTMOD) pMod; /** The time this segment has spent on the stack.. */ KU64 OnStackTicks; /** The time this segment has spent on the top of the stack.. */ KU64 OnTopOfStackTicks; /** The number of profiled functions from this segment. */ KU32 cFunctions; KU8 mHeight; /**< AVL Subtree height. */ } KPRF_TYPE(,REPORTMODSEG), *KPRF_TYPE(P,REPORTMODSEG); /** * A report module segment. * * @internal */ typedef struct KPRF_TYPE(,REPORTMOD) { /** The module number. */ KU32 iMod; /** Pointer to the next module in the list. */ KPRF_TYPE(P,REPORTMOD) pNext; /** Pointer to the list of segments belonging to this module. */ KPRF_TYPE(P,REPORTMODSEG) pFirstSeg; /** The debug module handle. */ PKDBGMOD pDbgMod; /** The time this segment has spent on the stack.. */ KU64 OnStackTicks; /** The time this segment has spent on the top of the stack.. */ KU64 OnTopOfStackTicks; /** The number of profiled functions from this segment. */ KU32 cFunctions; } KPRF_TYPE(,REPORTMOD), *KPRF_TYPE(P,REPORTMOD); /** * A report function. * * @internal */ typedef struct KPRF_TYPE(,REPORTFUNC) { /** Pointer to the function data in the data set. */ KPRF_TYPE(PC,FUNC) pFunc; /** Pointer to the module segment this function belongs to. (can be NULL) */ KPRF_TYPE(P,REPORTMODSEG) pModSeg; /** Pointer to the function symbol. */ PKDBGSYMBOL pSym; /** Pointer to the function line number. */ PKDBGLINE pLine; } KPRF_TYPE(,REPORTFUNC), *KPRF_TYPE(P,REPORTFUNC); /** * Compares two REPROTFUNC records to determin which has the higher on-stack time. */ static int KPRF_NAME(FuncCompareOnStack)(const void *pv1, const void *pv2) { KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; if (p1->OnStack.SumTicks > p2->OnStack.SumTicks) return -1; if (p1->OnStack.SumTicks < p2->OnStack.SumTicks) return 1; if (p1->OnStack.MaxTicks > p2->OnStack.MaxTicks) return -1; if (p1->OnStack.MaxTicks < p2->OnStack.MaxTicks) return 1; if (p1->OnStack.MinTicks > p2->OnStack.MinTicks) return -1; if (p1->OnStack.MinTicks < p2->OnStack.MinTicks) return 1; if (p1 < p2) return -1; return 1; } /** * Compares two REPROTFUNC records to determin which has the higher on-stack average time. */ static int KPRF_NAME(FuncCompareOnStackAvg)(const void *pv1, const void *pv2) { KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; if (p1->OnStack.SumTicks / p1->cOnStack > p2->OnStack.SumTicks / p2->cOnStack) return -1; if (p1->OnStack.SumTicks / p1->cOnStack < p2->OnStack.SumTicks / p2->cOnStack) return 1; return KPRF_NAME(FuncCompareOnStack)(pv1, pv2); } /** * Compares two REPROTFUNC records to determin which has the higher on-stack min time. */ static int KPRF_NAME(FuncCompareOnStackMin)(const void *pv1, const void *pv2) { KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; if (p1->OnStack.MinTicks > p2->OnStack.MinTicks) return -1; if (p1->OnStack.MinTicks < p2->OnStack.MinTicks) return 1; return KPRF_NAME(FuncCompareOnStack)(pv1, pv2); } /** * Compares two REPROTFUNC records to determin which has the higher on-stack max time. */ static int KPRF_NAME(FuncCompareOnStackMax)(const void *pv1, const void *pv2) { KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; if (p1->OnStack.MaxTicks > p2->OnStack.MaxTicks) return -1; if (p1->OnStack.MaxTicks < p2->OnStack.MaxTicks) return 1; return KPRF_NAME(FuncCompareOnStack)(pv1, pv2); } /** * Compares two REPROTFUNC records to determin which has the higher on-stack time. */ static int KPRF_NAME(FuncCompareOnTopOfStack)(const void *pv1, const void *pv2) { KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; if (p1->OnTopOfStack.SumTicks > p2->OnTopOfStack.SumTicks) return -1; if (p1->OnTopOfStack.SumTicks < p2->OnTopOfStack.SumTicks) return 1; if (p1->OnTopOfStack.MaxTicks > p2->OnTopOfStack.MaxTicks) return -1; if (p1->OnTopOfStack.MaxTicks < p2->OnTopOfStack.MaxTicks) return 1; if (p1->OnTopOfStack.MinTicks > p2->OnTopOfStack.MinTicks) return -1; if (p1->OnTopOfStack.MinTicks < p2->OnTopOfStack.MinTicks) return 1; if (p1 < p2) return -1; return 1; } /** * Compares two REPROTFUNC records to determin which has the higher on-stack average time. */ static int KPRF_NAME(FuncCompareOnTopOfStackAvg)(const void *pv1, const void *pv2) { KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; if (p1->OnTopOfStack.SumTicks / p1->cOnStack > p2->OnTopOfStack.SumTicks / p2->cOnStack) return -1; if (p1->OnTopOfStack.SumTicks / p1->cOnStack < p2->OnTopOfStack.SumTicks / p2->cOnStack) return 1; return KPRF_NAME(FuncCompareOnTopOfStack)(pv1, pv2); } /** * Compares two REPROTFUNC records to determin which has the higher on-stack min time. */ static int KPRF_NAME(FuncCompareOnTopOfStackMin)(const void *pv1, const void *pv2) { KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; if (p1->OnTopOfStack.MinTicks > p2->OnTopOfStack.MinTicks) return -1; if (p1->OnTopOfStack.MinTicks < p2->OnTopOfStack.MinTicks) return 1; return KPRF_NAME(FuncCompareOnTopOfStack)(pv1, pv2); } /** * Compares two REPROTFUNC records to determin which has the higher on-stack min time. */ static int KPRF_NAME(FuncCompareOnTopOfStackMax)(const void *pv1, const void *pv2) { KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; if (p1->OnTopOfStack.MaxTicks > p2->OnTopOfStack.MaxTicks) return -1; if (p1->OnTopOfStack.MaxTicks < p2->OnTopOfStack.MaxTicks) return 1; return KPRF_NAME(FuncCompareOnTopOfStack)(pv1, pv2); } /** * Compares two REPROTFUNC records to determin which has the higher call to count. */ static int KPRF_NAME(FuncCompareCallsTo)(const void *pv1, const void *pv2) { KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; if (p1->cOnStack > p2->cOnStack) return -1; if (p1->cOnStack < p2->cOnStack) return 1; return KPRF_NAME(FuncCompareOnStack)(pv1, pv2); } /** * Compares two REPROTFUNC records to determin which has the higher call from count. */ static int KPRF_NAME(FuncCompareCallsFrom)(const void *pv1, const void *pv2) { KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc; KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc; if (p1->cCalls > p2->cCalls) return -1; if (p1->cCalls < p2->cCalls) return 1; return KPRF_NAME(FuncCompareOnTopOfStack)(pv1, pv2); } /** * A report thread. * * @internal */ typedef struct KPRF_TYPE(,REPORTTHREAD) { /** Pointer to the thread data in the data set. */ KPRF_TYPE(PC,THREAD) pThread; } KPRF_TYPE(,REPORTTHREAD), *KPRF_TYPE(P,REPORTTHREAD); /** * Data-set analysis report. * * This is an internal structure to store temporary data between the * analysis stage and the priting state. * * @internal */ typedef struct KPRF_TYPE(,REPORT) { /** Pointer to the data set. */ KPRF_TYPE(PC,HDR) pHdr; /** @name Data-set item wrappers. * @{ */ /** Pointer to the array of threads. */ KPRF_TYPE(P,REPORTTHREAD) paThreads; /** Pointer to the array of functions. */ KPRF_TYPE(P,REPORTFUNC) paFunctions; /** Pointer to the head of the module list. */ KPRF_TYPE(P,REPORTMOD) pFirstMod; /** The number of modules in the list. */ KU32 cMods; /** The module segment tree. (Only kAvl cares about this.) */ KPRF_TYPE(P,REPORTMODSEG) pModSegTree; /** The number of module segments in the tree. */ KU32 cModSegs; /** @} */ /** @name Sorting. * @{ */ /** Pointer to the array of threads. */ KPRF_TYPE(P,REPORTTHREAD) *papSortedThreads; /** Pointer to the array of functions. */ KPRF_TYPE(P,REPORTFUNC) *papSortedFunctions; /** @} */ /** @name Accumulated Thread Data. * @{ */ /** Sum of the profiled ticks. */ KU64 ProfiledTicks; /** Sum of the overhead ticks. */ KU64 OverheadTicks; /** Sum of the sleep ticks. */ KU64 SleepTicks; /** Sum of calls performed. */ KU64 cCalls; /** @} */ } KPRF_TYPE(,REPORT), *KPRF_TYPE(P,REPORT), **KPRF_TYPE(PP,REPORT); /* Instantiate the AVL tree code. */ #define KAVL_CHECK_FOR_EQUAL_INSERT #define KAVL_MAX_STACK 32 #define KAVL_STD_KEY_COMP #define mKey offSegment #define KAVLKEY KDBGADDR #define KAVLNODE KPRF_TYPE(,REPORTMODSEG) #define mpRoot pModSegTree #define KAVLROOT KPRF_TYPE(,REPORT) #define KAVL_FN(name) KPRF_NAME(ReportTree ## name) #define KAVL_TYPE(prefix,name) KPRF_TYPE(prefix, REPORTMODESEG ## name) #define KAVL_INT(name) KPRF_NAME(REPORTMODESEGINT ## name) #define KAVL_DECL(type) K_DECL_INLINE(type) #include #include #include #include /** * Allocates and initializes a report. * * @returns Pointer to the report on success. * @returns NULL on failure. */ static KPRF_TYPE(P,REPORT) KPRF_NAME(NewReport)(KPRF_TYPE(PC,HDR) pHdr) { /* * Allocate memory for the report. * Everything but the mods and modsegs is allocated in the same block as the report. */ KSIZE cb = KPRF_ALIGN(KPRF_SIZEOF(REPORT), 32); KUPTR offThreads = cb; cb += KPRF_ALIGN(KPRF_SIZEOF(REPORTTHREAD) * pHdr->cThreads, 32); KUPTR offFunctions = cb; cb += KPRF_ALIGN(KPRF_SIZEOF(REPORTFUNC) * pHdr->cFunctions, 32); KUPTR offSortedThreads = cb; cb += KPRF_ALIGN(sizeof(KPRF_TYPE(P,REPORTTHREAD)) * pHdr->cThreads, 32); KUPTR offSortedFunctions = cb; cb += KPRF_ALIGN(sizeof(KPRF_TYPE(P,REPORTFUNC)) * pHdr->cFunctions, 32); KPRF_TYPE(P,REPORT) pReport = (KPRF_TYPE(P,REPORT))malloc(cb); if (!pReport) return NULL; /* * Initialize it. */ pReport->pHdr = pHdr; pReport->paThreads = (KPRF_TYPE(P,REPORTTHREAD))((KU8 *)pReport + offThreads); pReport->paFunctions = (KPRF_TYPE(P,REPORTFUNC))((KU8 *)pReport + offFunctions); pReport->pFirstMod = NULL; pReport->cMods = 0; KPRF_NAME(ReportTreeInit)(pReport); pReport->cModSegs = 0; pReport->papSortedThreads = (KPRF_TYPE(P,REPORTTHREAD) *)((KU8 *)pReport + offSortedThreads); pReport->papSortedFunctions = (KPRF_TYPE(P,REPORTFUNC) *)((KU8 *)pReport + offSortedFunctions); pReport->ProfiledTicks = 0; pReport->OverheadTicks = 0; pReport->SleepTicks = 0; pReport->cCalls = 0; return pReport; } /** * AVL callback for deleting a module segment node. * * @returns 0 * @param pCore The tree node to delete. * @param pvParam User parameter, ignored. */ static int KPRF_NAME(DeleteModSeg)(KPRF_TYPE(P,REPORTMODSEG) pCore, void *pvParam) { free(pCore); return 0; } /** * Releases all the resources held be a report. * * @param pReport The report to delete. */ static void KPRF_NAME(DeleteReport)(KPRF_TYPE(P,REPORT) pReport) { /* * The list and AVL. */ while (pReport->pFirstMod) { KPRF_TYPE(P,REPORTMOD) pFree = pReport->pFirstMod; pReport->pFirstMod = pFree->pNext; kDbgModuleClose(pFree->pDbgMod); free(pFree); } KPRF_NAME(ReportTreeDestroy)(pReport, KPRF_NAME(DeleteModSeg), NULL); /* * The function debug info. */ KU32 i = pReport->pHdr->cFunctions; while (i-- > 0) { kDbgSymbolFree(pReport->paFunctions[i].pSym); kDbgLineFree(pReport->paFunctions[i].pLine); } /* * The report it self. */ pReport->pHdr = NULL; free(pReport); } /** * Builds the module segment tree and the list of modules. * * @returns 0 on success. * @returns -1 on failure. * @param pReport The report to work on. */ static int KPRF_NAME(AnalyzeModSegs)(KPRF_TYPE(P,REPORT) pReport) { const KU32 offEnd = pReport->pHdr->offModSegs + pReport->pHdr->cbModSegs; KU32 off = pReport->pHdr->offModSegs; while (off < offEnd) { KPRF_TYPE(PC,MODSEG) pCur = KPRF_OFF2PTR(PC,MODSEG, off, pReport->pHdr); KU32 cbCur = KPRF_OFFSETOF(MODSEG, szPath[pCur->cchPath + 1]); cbCur = KPRF_ALIGN(cbCur, KPRF_SIZEOF(UPTR)); /* * Create a new modseg record. */ KPRF_TYPE(P,REPORTMODSEG) pSeg = (KPRF_TYPE(P,REPORTMODSEG))malloc(sizeof(*pSeg)); if (!pSeg) return -1; pSeg->offSegment = off; pSeg->pModSeg = pCur; pSeg->pMod = NULL; /* below */ pSeg->OnStackTicks = 0; pSeg->OnTopOfStackTicks = 0; pSeg->cFunctions = 0; if (!KPRF_NAME(ReportTreeInsert)(pReport, pSeg)) { free(pSeg); return -1; } pReport->cModSegs++; /* * Search for the module record. */ KPRF_TYPE(P,REPORTMOD) pMod = pReport->pFirstMod; while ( pMod && ( pMod->pFirstSeg->pModSeg->cchPath != pCur->cchPath || memcmp(pMod->pFirstSeg->pModSeg->szPath, pCur->szPath, pCur->cchPath))) pMod = pMod->pNext; if (pMod) { /** @todo sort segments */ pSeg->pMod = pMod; pSeg->pNext = pMod->pFirstSeg; pMod->pFirstSeg = pSeg; } else { KPRF_TYPE(P,REPORTMOD) pMod = (KPRF_TYPE(P,REPORTMOD))malloc(sizeof(*pMod) + pCur->cchPath); if (!pMod) return -1; pSeg->pMod = pMod; pSeg->pNext = NULL; pMod->iMod = pReport->cMods++; pMod->pNext = pReport->pFirstMod; pReport->pFirstMod = pMod; pMod->pFirstSeg = pSeg; pMod->pDbgMod = NULL; pMod->OnStackTicks = 0; pMod->OnTopOfStackTicks = 0; pMod->cFunctions = 0; int rc = kDbgModuleOpen(&pMod->pDbgMod, pSeg->pModSeg->szPath, NULL /* kLdrMod */); if (rc) pMod->pDbgMod = NULL; } /* next */ off += cbCur; } return 0; } /** * Initializes the function arrays. * * @returns 0 on success. * @returns -1 on failure. * @param pReport The report to work on. */ static int KPRF_NAME(AnalyseFunctions)(KPRF_TYPE(P,REPORT) pReport) { KU32 iFunc = pReport->pHdr->cFunctions; KPRF_TYPE(PC,FUNC) pFunc = KPRF_OFF2PTR(PC,FUNC, pReport->pHdr->offFunctions + iFunc * sizeof(*pFunc), pReport->pHdr); KPRF_TYPE(P,REPORTFUNC) pReportFunc = &pReport->paFunctions[iFunc]; while (iFunc-- > 0) { pFunc--; pReportFunc--; pReport->papSortedFunctions[iFunc] = pReportFunc; pReportFunc->pFunc = pFunc; pReportFunc->pModSeg = KPRF_NAME(ReportTreeGet)(pReport, pFunc->offModSeg); pReportFunc->pSym = NULL; pReportFunc->pLine = NULL; if (pReportFunc->pModSeg) { /* Collect module segment and module statistics. */ KPRF_TYPE(P,REPORTMODSEG) pModSeg = pReportFunc->pModSeg; pModSeg->cFunctions++; pModSeg->OnStackTicks += pFunc->OnStack.SumTicks; pModSeg->OnTopOfStackTicks += pFunc->OnTopOfStack.SumTicks; KPRF_TYPE(P,REPORTMOD) pMod = pModSeg->pMod; pMod->cFunctions++; pMod->OnStackTicks += pFunc->OnStack.SumTicks; pMod->OnTopOfStackTicks += pFunc->OnTopOfStack.SumTicks; /* Get debug info. */ KDBGADDR offSegment = pFunc->uEntryPtr - pModSeg->pModSeg->uBasePtr; int rc = kDbgModuleQuerySymbolA(pMod->pDbgMod, pModSeg->pModSeg->iSegment, offSegment, &pReportFunc->pSym); /** @todo check displacement! */ if (rc) pReportFunc->pSym = NULL; rc = kDbgModuleQueryLineA(pMod->pDbgMod, pModSeg->pModSeg->iSegment, offSegment, &pReportFunc->pLine); if (rc) pReportFunc->pLine = NULL; } } return 0; } /** * Initializes the thread arrays. * * @returns 0 on success. * @returns -1 on failure. * @param pReport The report to work on. */ static int KPRF_NAME(AnalyseThreads)(KPRF_TYPE(P,REPORT) pReport) { KU32 iThread = pReport->pHdr->cThreads; KPRF_TYPE(PC,THREAD) pThread = KPRF_OFF2PTR(PC,THREAD, pReport->pHdr->offThreads + iThread * sizeof(*pThread), pReport->pHdr); KPRF_TYPE(P,REPORTTHREAD) pReportThread = &pReport->paThreads[iThread]; while (iThread-- > 0) { pThread--; pReportThread--; pReport->papSortedThreads[iThread] = pReportThread; pReportThread->pThread = pThread; /* collect statistics */ pReport->ProfiledTicks += pThread->ProfiledTicks; pReport->OverheadTicks += pThread->OverheadTicks; pReport->SleepTicks += pThread->SleepTicks; pReport->cCalls += pThread->cCalls; } return 0; } /** * Analyses the data set, producing a report. * * @returns 0 on success. * @returns -1 on failure. * * @param pHdr The data set. * @param ppReport Where to store the report. */ static int KPRF_NAME(Analyse)(KPRF_TYPE(PC,HDR) pHdr, KPRF_TYPE(PP,REPORT) ppReport) { *ppReport = NULL; /* allocate it */ KPRF_TYPE(P,REPORT) pReport = KPRF_NAME(NewReport)(pHdr); if (!pReport) return -1; /* read module segments */ int rc = KPRF_NAME(AnalyzeModSegs)(pReport); if (!rc) { /* read functions. */ rc = KPRF_NAME(AnalyseFunctions)(pReport); if (!rc) { /* read threads */ rc = KPRF_NAME(AnalyseThreads)(pReport); if (!rc) { *ppReport = pReport; return 0; } } } KPRF_NAME(DeleteReport)(pReport); return rc; } /** * Writes row with 32-bit value. * @internal */ static void KPRF_NAME(HtmlWriteRowU32X32)(FILE *pOut, const char *pszName, KU32 u32, const char *pszUnit) { fprintf(pOut, " \n" " %s\n" " %u (0x%x)%s%s\n" " \n", pszName, u32, u32, pszUnit ? " " : "", pszUnit ? pszUnit : ""); } /** * Writes row with 32-bit value. * @internal */ static void KPRF_NAME(HtmlWriteRowU32)(FILE *pOut, const char *pszName, KU32 u32, const char *pszUnit) { fprintf(pOut, " \n" " %s\n" " %u%s%s\n" " \n", pszName, u32, pszUnit ? " " : "", pszUnit ? pszUnit : ""); } /** * Writes row with 64-bit value. * @internal */ static void KPRF_NAME(HtmlWriteRowU64)(FILE *pOut, const char *pszName, KU64 u64, const char *pszUnit) { fprintf(pOut, " \n" " %s\n" " % " KPRF_FMT_U64 " (0x%" KPRF_FMT_X64 ")%s%s\n" " \n", pszName, u64, u64, pszUnit ? " " : "", pszUnit ? pszUnit : ""); } /** * Writes row with 64-bit hex value. * @internal */ static void KPRF_NAME(HtmlWriteRowX64)(FILE *pOut, const char *pszName, KU64 u64, const char *pszUnit) { fprintf(pOut, " \n" " %s\n" " 0x%" KPRF_FMT_X64 "%s%s\n" " \n", pszName, u64, pszUnit ? " " : "", pszUnit ? pszUnit : ""); } /** * Writes a ticks. */ static void KPRF_NAME(HtmlWriteParts)(FILE *pOut, KU64 cTicks, KU64 cTotalTicks) { /** U+2030 PER MILLE SIGN */ static const KU8 s_szPerMilleSignUtf8[4] = { 0xe2, 0x80, 0xb0, 0}; if (cTicks * 100 / cTotalTicks) { KU32 u = (KU32)((cTicks * 1000) / cTotalTicks); fprintf(pOut, "%u.%01u%%", u / 10, u %10); } else //if (cTicks * 100000 / cTotalTicks) { KU32 u = (KU32)((cTicks * 100000) / cTotalTicks); fprintf(pOut, "%u.%02u%s", u / 100, u % 100, s_szPerMilleSignUtf8); } /* else if (cTicks * 1000000 / cTotalTicks) fprintf(pOut, "%u ppm", (unsigned)((cTicks * 1000000) / cTotalTicks)); else fprintf(pOut, "%u ppb", (unsigned)((cTicks * 1000000000) / cTotalTicks)); */ } /** * Writes a ticks. */ static void KPRF_NAME(HtmlWriteTicks)(FILE *pOut, KU64 cTicks, KU64 cTotalTicks) { fprintf(pOut, "%" KPRF_FMT_U64 "", cTicks); if (cTotalTicks) { fprintf(pOut, ""); KPRF_NAME(HtmlWriteParts)(pOut, cTicks, cTotalTicks); } } /** * Writes row with ticks value. * * @param pOut Where to write. * @aaran pszName The row name. * @param cTicks The tick count. * @param cTotalTicks If non-zero, this is used for cTicks / cTotalTicks. * @internal */ static void KPRF_NAME(HtmlWriteRowTicks)(FILE *pOut, const char *pszName, KU64 cTicks, KU64 cTotalTicks) { fprintf(pOut, " \n" " %s\n" " ", pszName); KPRF_NAME(HtmlWriteTicks)(pOut, cTicks, cTotalTicks); fprintf(pOut, "\n" " \n", cTotalTicks ? 4 : 5); } /** * Writes row with a time stat value. * * @param pOut Where to write. * @aaran pszName The row name. * @param cTicks The tick count. * @param cTotalTicks If non-zero, this is used for cTicks / cTotalTicks. * @internal */ static void KPRF_NAME(HtmlWriteRowTimeStat)(FILE *pOut, const char *pszName, KPRF_TYPE(PC,TIMESTAT) pTimeStat, KU64 cTotalTicks) { fprintf(pOut, " \n" " %s\n" " ", pszName); KPRF_NAME(HtmlWriteTicks)(pOut, pTimeStat->SumTicks, cTotalTicks); fprintf(pOut, "\n" " "); KPRF_NAME(HtmlWriteTicks)(pOut, pTimeStat->MinTicks, cTotalTicks); fprintf(pOut, "\n" " "); KPRF_NAME(HtmlWriteTicks)(pOut, pTimeStat->MaxTicks, cTotalTicks); fprintf(pOut, "\n" " \n"); } /** * Writes row with calls value. * * @param pOut Where to write. * @aaran pszName The row name. * @param cCalls The call count. * @param cTotalCalls This is used for cCalls / cTotalCalls. * @internal */ static void KPRF_NAME(HtmlWriteRowCalls)(FILE *pOut, const char *pszName, KU64 cCalls, KU64 cTotalCalls) { fprintf(pOut, " \n" " %s\n" " %" KPRF_FMT_U64"", pszName, cCalls); KPRF_NAME(HtmlWriteParts)(pOut, cCalls, cTotalCalls); fprintf(pOut, "" " \n"); } /** * Writes row with pointer value. * @internal */ static void KPRF_NAME(HtmlWriteRowUPTR)(FILE *pOut, const char *pszName, KPRF_TYPE(,UPTR) uPtr, const char *pszUnit) { fprintf(pOut, " \n" " %s\n" " %" KPRF_FMT_UPTR "%s%s\n" " \n", pszName, uPtr, pszUnit ? " " : "", pszUnit ? pszUnit : ""); } /** * Writes row with string value. * @internal */ static void KPRF_NAME(HtmlWriteRowString)(FILE *pOut, const char *pszName, const char *pszClass, const char *pszFormat, ...) { fprintf(pOut, " \n" " %s\n" " ", pszName, pszClass ? " class=\"" : "", pszClass ? pszClass : "", pszClass ? "\"" : ""); va_list va; va_start(va, pszFormat); vfprintf(pOut, pszFormat, va); va_end(va); fprintf(pOut, "\n" " \n"); } /** * The first column */ typedef enum KPRF_TYPE(,FIRSTCOLUMN) { KPRF_TYPE(,FIRSTCOLUMN_ON_STACK) = 0, KPRF_TYPE(,FIRSTCOLUMN_ON_TOP_OF_STACK), KPRF_TYPE(,FIRSTCOLUMN_CALLS_TO), KPRF_TYPE(,FIRSTCOLUMN_CALLS_FROM), KPRF_TYPE(,FIRSTCOLUMN_MAX) } KPRF_TYPE(,FIRSTCOLUMN); /** * Prints the table with the sorted functions. * The tricky bit is that the sorted column should be to the left of the function name. */ static void KPRF_NAME(HtmlWriteSortedFunctions)(KPRF_TYPE(P,REPORT) pReport, FILE *pOut, const char *pszName, const char *pszTitle, KPRF_TYPE(,FIRSTCOLUMN) enmFirst) { fprintf(pOut, "

%s

\n" "\n", pszName, pszTitle); fprintf(pOut, "\n" " \n" " \n", " \n" " \n" " \n" " \n", " \n", " \n" " \n" " \n" " \n", " \n", " \n", " \n"); for (unsigned i = (enmFirst + 1) % KPRF_TYPE(,FIRSTCOLUMN_MAX); i != enmFirst; i = (i + 1) % KPRF_TYPE(,FIRSTCOLUMN_MAX)) fprintf(pOut, "%s", s_pszHeaders[i * 2]); fprintf(pOut, " \n" " \n" " \n"); for (KU32 iFunc = 0; iFunc < pReport->pHdr->cFunctions; iFunc++) { KPRF_TYPE(P,REPORTFUNC) pReportFunc = pReport->papSortedFunctions[iFunc]; KPRF_TYPE(PC,FUNC) pFunc = pReportFunc->pFunc; fprintf(pOut, " \n" " \n", iFunc); unsigned i = enmFirst; do { switch (i) { case KPRF_TYPE(,FIRSTCOLUMN_ON_STACK): fprintf(pOut, " \n" " \n" " \n" " \n"); break; case KPRF_TYPE(,FIRSTCOLUMN_ON_TOP_OF_STACK): fprintf(pOut, " \n" " \n" " \n" " \n"); break; case KPRF_TYPE(,FIRSTCOLUMN_CALLS_TO): fprintf(pOut, " \n"); break; case KPRF_TYPE(,FIRSTCOLUMN_CALLS_FROM): fprintf(pOut, " \n"); break; default: break; } /* inject the function column */ if (i == enmFirst) { fprintf(pOut, " \n", pReportFunc->pSym->szName); else fprintf(pOut, "%" KPRF_FMT_UPTR "\n", pFunc->uEntryPtr); } /* next */ i = (i + 1) % KPRF_TYPE(,FIRSTCOLUMN_MAX); } while (i != enmFirst); fprintf(pOut, " \n"); } fprintf(pOut, "
\n"); static const char *s_pszHeaders[KPRF_TYPE(,FIRSTCOLUMN_MAX) * 2] = { " Time On Stack (ticks)SumMinAverageMaxTime On To Top (ticks)SumMinAverageMaxCalls To\n", " Calls From\n", }; fprintf(pOut, "%s", s_pszHeaders[enmFirst * 2]); fprintf(pOut, " Function
\n"); fprintf(pOut, "%s", s_pszHeaders[enmFirst * 2 + 1]); fprintf(pOut, " \n"); for (unsigned i = (enmFirst + 1) % KPRF_TYPE(,FIRSTCOLUMN_MAX); i != enmFirst; i = (i + 1) % KPRF_TYPE(,FIRSTCOLUMN_MAX)) fprintf(pOut, "%s", s_pszHeaders[i * 2 + 1]); fprintf(pOut, "
%u%" KPRF_FMT_U64 "", pFunc->OnStack.SumTicks); KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnStack.SumTicks, pReport->ProfiledTicks); fprintf(pOut, "%" KPRF_FMT_U64 "", pFunc->OnStack.MinTicks); KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnStack.MinTicks, pReport->ProfiledTicks); fprintf(pOut, "%" KPRF_FMT_U64 "", pFunc->OnStack.SumTicks / pFunc->cOnStack); KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnStack.MinTicks, pReport->ProfiledTicks); fprintf(pOut, "%" KPRF_FMT_U64 "", pFunc->OnStack.MaxTicks); KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnStack.MaxTicks, pReport->ProfiledTicks); fprintf(pOut, "%" KPRF_FMT_U64 "", pFunc->OnTopOfStack.SumTicks); KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnTopOfStack.SumTicks, pReport->ProfiledTicks); fprintf(pOut, "%" KPRF_FMT_U64 "", pFunc->OnTopOfStack.MinTicks); KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnTopOfStack.MinTicks, pReport->ProfiledTicks); fprintf(pOut, "%" KPRF_FMT_U64 "", pFunc->OnTopOfStack.SumTicks / pFunc->cOnStack); KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnTopOfStack.MinTicks, pReport->ProfiledTicks); fprintf(pOut, "%" KPRF_FMT_U64 "", pFunc->OnTopOfStack.MaxTicks); KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnTopOfStack.MaxTicks, pReport->ProfiledTicks); fprintf(pOut, "%" KPRF_FMT_U64 "", pFunc->cOnStack); KPRF_NAME(HtmlWriteParts)(pOut, pFunc->cOnStack, pReport->cCalls); fprintf(pOut, "%" KPRF_FMT_U64 "", pFunc->cCalls); KPRF_NAME(HtmlWriteParts)(pOut, pFunc->cCalls, pReport->cCalls); fprintf(pOut, "", (unsigned)(uintptr_t)(pReportFunc - pReport->paFunctions)); if (pReportFunc->pSym) fprintf(pOut, "%s
\n" "\n"); } /** * Writes an HTML report. * * @returns 0 on success. * @returns -1 on failure. * @param pReport The report to put into HTML. * @param pOut The file stream to write the HTML to. */ static int KPRF_NAME(WriteHtmlReport)(KPRF_TYPE(P,REPORT) pReport, FILE *pOut) { KPRF_TYPE(PC,HDR) pHdr = pReport->pHdr; /* * Write the standard html. */ fprintf(pOut, "\n" "\n" "\n" " \n" " kProfiler 2 - %s\n" "\n" "\n" "\n" , pHdr->offCommandLine ? (const char *)KPRF_OFF2PTR(P,FUNC, pHdr->offCommandLine, pHdr) : "" ); /* * Table of contents. */ fprintf(pOut, "

Table of Contents

\n" "\n" "\n" "\n" "\n"); /* * Summary. */ fprintf(pOut, "

1.0 Summary

\n" "\n" "

\n" "\n"); if (pHdr->offCommandLine) KPRF_NAME(HtmlWriteRowString)(pOut, "Command Line", NULL, "%s", (const char *)KPRF_OFF2PTR(P,FUNC, pHdr->offCommandLine, pHdr)); KPRF_NAME(HtmlWriteRowU32X32)(pOut, "Threads", pHdr->cThreads, NULL); KPRF_NAME(HtmlWriteRowU32X32)(pOut, "Modules", pReport->cMods, NULL); KPRF_NAME(HtmlWriteRowU32X32)(pOut, "Functions", pHdr->cFunctions, NULL); KPRF_NAME(HtmlWriteRowTicks)(pOut, "Profiled", pReport->ProfiledTicks, pReport->ProfiledTicks); KPRF_NAME(HtmlWriteRowTicks)(pOut, "Sleep", pReport->SleepTicks, pReport->ProfiledTicks); KPRF_NAME(HtmlWriteRowTicks)(pOut, "Overhead", pReport->OverheadTicks, pReport->ProfiledTicks + pReport->OverheadTicks); KPRF_NAME(HtmlWriteRowCalls)(pOut, "Recorded Calls", pReport->cCalls, pReport->cCalls); fprintf(pOut, "\n"); KPRF_NAME(HtmlWriteRowString)(pOut, "kProfiler Version ", NULL, "Mark 2 Alpha 1"); KPRF_NAME(HtmlWriteRowString)(pOut, "kProfiler Build Time ", NULL, __DATE__ " " __TIME__); fprintf(pOut, "
 
\n" "

\n" "\n" "\n"); /* * Functions. */ fprintf(pOut, "

2.0 Functions

\n" "\n"); qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnStack)); KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnStack", "2.1 Time On Stack", KPRF_TYPE(,FIRSTCOLUMN_ON_STACK)); qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnStackAvg)); KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnStack-Avg", "2.2.1 Time On Stack - Average", KPRF_TYPE(,FIRSTCOLUMN_ON_STACK)); qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnStackMin)); KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnStack-Min", "2.2.2 Time On Stack - Min", KPRF_TYPE(,FIRSTCOLUMN_ON_STACK)); qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnStackMax)); KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnStack-Max", "2.2.3 Time On Stack - Max", KPRF_TYPE(,FIRSTCOLUMN_ON_STACK)); qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnTopOfStack)); KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnTopOfStack", "2.2 Time On Top Of Stack", KPRF_TYPE(,FIRSTCOLUMN_ON_TOP_OF_STACK)); qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnTopOfStackAvg)); KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnTopOfStack-Avg","2.2.1 Time On Top Of Stack - Average", KPRF_TYPE(,FIRSTCOLUMN_ON_TOP_OF_STACK)); qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnTopOfStackMin)); KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnTopOfStack-Min","2.2.2 Time On Top Of Stack - Min", KPRF_TYPE(,FIRSTCOLUMN_ON_TOP_OF_STACK)); qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnTopOfStackMax)); KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnTopOfStack-Max","2.2.3 Time On Top Of Stack - Max", KPRF_TYPE(,FIRSTCOLUMN_ON_TOP_OF_STACK)); qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareCallsTo)); KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-CallsTo", "2.4 Calls To", KPRF_TYPE(,FIRSTCOLUMN_CALLS_TO)); qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareCallsFrom)); KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-CallsFrom", "2.5 Calls From", KPRF_TYPE(,FIRSTCOLUMN_CALLS_FROM)); fprintf(pOut, "

2.5 Function Details

\n" "\n" "

\n" "\n"); for (KU32 iFunc = 0; iFunc < pHdr->cFunctions; iFunc++) { KPRF_TYPE(P,REPORTFUNC) pReportFunc = &pReport->paFunctions[iFunc]; KPRF_TYPE(PC,FUNC) pFunc = pReportFunc->pFunc; fprintf(pOut, "\n", iFunc); KPRF_NAME(HtmlWriteRowU32)(pOut, "Function No.", iFunc, NULL); if (pReportFunc->pSym) KPRF_NAME(HtmlWriteRowString)(pOut, "Name", "Name", "%s", pReportFunc->pSym->szName); if (pReportFunc->pLine) KPRF_NAME(HtmlWriteRowString)(pOut, "Location", NULL, "%s Line #%d", pReportFunc->pLine->szFile, pReportFunc->pLine->szFile, pReportFunc->pLine->iLine); if (pReportFunc->pModSeg) { KPRF_NAME(HtmlWriteRowString)(pOut, "Module", NULL, "%s", pReportFunc->pModSeg->pMod->iMod, pReportFunc->pModSeg->pModSeg->szPath); KPRF_NAME(HtmlWriteRowString)(pOut, "Segment:Offset", NULL, "%x:%" KPRF_FMT_UPTR, pReportFunc->pModSeg->pModSeg->iSegment, pFunc->uEntryPtr - pReportFunc->pModSeg->pModSeg->uBasePtr); } KPRF_NAME(HtmlWriteRowUPTR)(pOut, "Address", pFunc->uEntryPtr, NULL); KPRF_NAME(HtmlWriteRowTimeStat)(pOut, "On Stack", &pFunc->OnStack, pReport->ProfiledTicks); KPRF_NAME(HtmlWriteRowTimeStat)(pOut, "On Top Of Stack", &pFunc->OnTopOfStack, pReport->ProfiledTicks); KPRF_NAME(HtmlWriteRowCalls)(pOut, "Calls To", pFunc->cOnStack, pReport->cCalls); KPRF_NAME(HtmlWriteRowCalls)(pOut, "Calls From", pFunc->cCalls, pReport->cCalls); fprintf(pOut, "\n"); } fprintf(pOut, "
 
\n" "

\n" "\n"); /* * Threads. */ fprintf(pOut, "

3.0 Threads

\n" "\n" "

\n" "\n"); for (KU32 iThread = 0; iThread < pHdr->cThreads; iThread++) { KPRF_TYPE(PC,THREAD) pThread = pReport->paThreads[iThread].pThread; fprintf(pOut, "\n", iThread); KPRF_NAME(HtmlWriteRowU32)(pOut, "Thread No.", iThread, NULL); KPRF_NAME(HtmlWriteRowX64)(pOut, "Thread Id", pThread->ThreadId, NULL); if (pThread->szName[0]) KPRF_NAME(HtmlWriteRowString)(pOut, "Name", "Name", "%s", pThread->szName); KPRF_NAME(HtmlWriteRowUPTR)(pOut, "Stack Base Address", pThread->uStackBasePtr, NULL); KPRF_NAME(HtmlWriteRowUPTR)(pOut, "Max Stack Depth", pThread->cbMaxStack, "bytes"); //KPRF_NAME(HtmlWriteRowUPTR)(pOut, "Max Stack Depth", pThread->cMaxFrames, "frames"); /** @todo max stack frames! */ KPRF_NAME(HtmlWriteRowTicks)(pOut, "Profiled", pThread->ProfiledTicks, pReport->ProfiledTicks); KPRF_NAME(HtmlWriteRowTicks)(pOut, "Sleep", pThread->SleepTicks, pReport->ProfiledTicks); KPRF_NAME(HtmlWriteRowTicks)(pOut, "Overhead", pThread->OverheadTicks, pReport->ProfiledTicks + pReport->OverheadTicks); KPRF_NAME(HtmlWriteRowCalls)(pOut, "Recorded Calls", pThread->cCalls, pReport->cCalls); KPRF_NAME(HtmlWriteRowU64)(pOut, "Unwinds", pThread->cUnwinds, NULL); KPRF_NAME(HtmlWriteRowU64)(pOut, "Profiler Stack Overflows", pThread->cOverflows, NULL); KPRF_NAME(HtmlWriteRowU64)(pOut, "Profiler Stack Switch Rejects", pThread->cStackSwitchRejects, NULL); fprintf(pOut, "\n"); } fprintf(pOut, "
 
\n" "

\n" "\n"); /* * Modules. */ fprintf(pOut, "

4.0 Modules

\n" "\n" "

\n" "\n"); KPRF_TYPE(P,REPORTMOD) pMod = pReport->pFirstMod; KU32 iMod = 0; while (pMod) { fprintf(pOut, "\n" "\n", iMod, iMod); KPRF_NAME(HtmlWriteRowU32)(pOut, "Module No.", iMod, NULL); KPRF_NAME(HtmlWriteRowString)(pOut, "Name", "Name", "%s", pMod->pFirstSeg->pModSeg->szPath); for (KPRF_TYPE(P,REPORTMODSEG) pSeg = pMod->pFirstSeg; pSeg; pSeg = pSeg->pNext) { char szName[64]; sprintf(szName, "Segment No.%u - Base", pSeg->pModSeg->iSegment); KPRF_NAME(HtmlWriteRowUPTR)(pOut, szName, pSeg->pModSeg->uBasePtr, NULL); sprintf(szName, "Segment No.%u - Size", pSeg->pModSeg->iSegment); KPRF_NAME(HtmlWriteRowUPTR)(pOut, szName, pSeg->pModSeg->cbSegmentMinusOne + 1 > pSeg->pModSeg->cbSegmentMinusOne ? pSeg->pModSeg->cbSegmentMinusOne + 1 : pSeg->pModSeg->cbSegmentMinusOne, NULL); } KPRF_NAME(HtmlWriteRowTicks)(pOut, "On Stack", pMod->OnStackTicks, pReport->ProfiledTicks); KPRF_NAME(HtmlWriteRowTicks)(pOut, "On Top Of Stack", pMod->OnTopOfStackTicks, pReport->ProfiledTicks); KPRF_NAME(HtmlWriteRowU32)(pOut, "Functions", pMod->cFunctions, NULL); fprintf(pOut, "\n"); /* next */ iMod++; pMod = pMod->pNext; } fprintf(pOut, "
 
\n" "

\n" "\n"); /* * The End. */ fprintf(pOut, "\n" "\n"); return 0; } kbuild-3149/src/lib/kStuff/kProfiler2/kPrf2WinApi-genimp.sed0000644000175000017500000000307613252530254023577 0ustar locutuslocutus# $Id: kPrf2WinApi-genimp.sed 29 2009-07-01 20:30:29Z bird $ ## # Generate imports from normalized dumpbin output. # # # Copyright (c) 2008 Knut St. Osmundsen # # 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. # # Normalize the input a bit. s/[[:space:]][[:space:]]*/ /g s/^[[:space:]]// s/[[:space:]]$// /^$/b drop_line # Expects a single name - no ordinals yet. /\@/b have_at s/^\(.*\)$/ \1=kPrf2Wrap_\1/ b end :have_at h s/^\([^ ]\)\(@[0-9]*\)$/ \1\2=kPrf2Wrap_\1/ p g s/^\([^ ]\)\(@[0-9]*\)$/ \1=kPrf2Wrap_\1/ b end :drop_line d b end :end kbuild-3149/src/lib/kStuff/kProfiler2/dllmain-win.cpp0000644000175000017500000000520113252530254022440 0ustar locutuslocutus/* $Id: dllmain-win.cpp 29 2009-07-01 20:30:29Z bird $ */ /** @file * kProfiler Mark 2 - The Windows DllMain for the profiler DLL. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include "kProfileR3.h" /** * The DLL Main for the kPrf DLL. * * This is required because we need to initialize the profiler at some point * and because we need to know when threads terminate. (We don't care about * when threads get created, we simply pick them up when we see them the * first time.) * * @returns Success indicator. * @param hInstDll The instance handle of the DLL. (i.e. the module handle) * @param fdwReason The reason why we're here. This is a 'flag' for reasons of * tradition, it's really a kind of enum. * @param pReserved Reserved / undocumented something. */ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, PVOID pReserved) { switch (fdwReason) { case DLL_PROCESS_ATTACH: if (kPrfInitialize()) return FALSE; break; case DLL_PROCESS_DETACH: kPrfTerminate(); break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: kPrfTerminateThread(); break; } return TRUE; } kbuild-3149/src/lib/kStuff/kProfiler2/prfcorepre.cpp.h0000644000175000017500000001256713252530254022637 0ustar locutuslocutus/* $Id: prfcorepre.cpp.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kProfiler Mark 2 - Core Pre-Code Template. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /** @def KPRF_OFF2PTR * Internal helper for converting a offset to a pointer. * @internal */ #define KPRF_OFF2PTR(TypePrefix, TypeName, off, pHdr) \ ( (KPRF_TYPE(TypePrefix, TypeName)) ((off) + (KPRF_TYPE(,UPTR))pHdr) ) /** @def KPRF_PTR2OFF * Internal helper for converting a pointer to a offset. * @internal */ #define KPRF_PTR2OFF(ptr, pHdr) \ ( (KPRF_TYPE(,UPTR))(ptr) - (KPRF_TYPE(,UPTR))(pHdr) ) /** @def KPRF_ALIGN * The usual align macro. * @internal */ #define KPRF_ALIGN(n, align) ( ((n) + ( (align) - 1)) & ~((align) - 1) ) /** @def KPRF_SETMIN_ALIGN * Ensures a minimum and aligned value. * @internal */ #define KPRF_SETMIN_ALIGN(n, min, align) \ do { \ if ((n) < (min)) \ (n) = (min); \ else { \ const KU32 u32 = ((n) + ( (align) - 1)) & ~((align) - 1); \ if (u32 >= (n)) \ (n) = u32; \ } \ } while (0) /** @def KPRF_OFFSETOF * My usual extended OFFSETOF macro, except this returns KU32 and mangles the type name. * @internal */ #define KPRF_OFFSETOF(kPrfType, Member) ( (KU32)(KUPTR)&((KPRF_TYPE(P,kPrfType))0)->Member ) /** @def PRF_SIZEOF * Size of a kPrf type. * @internal */ #define KPRF_SIZEOF(kPrfType) sizeof(KPRF_TYPE(,kPrfType)) /** @def KPRF_NOW * Gets the current timestamp. */ #ifndef KPRF_NOW # error "KPRF_NOW isn't defined!" #endif /** @def KRPF_IS_ACTIVE * Checks if profiling is activated or not. * The idea is to use some global variable for disabling and enabling * profiling in order to deal with init/term issues. */ #ifndef KPRF_IS_ACTIVE # define KPRF_IS_ACTIVE() 1 #endif /** @def KPRF_GET_HDR * Gets the pointer to the profiler data header. */ #ifndef KPRF_GET_HDR # error "KPRF_GET_HDR isn't defined!" #endif /** @def KPRF_GET_THREADID * Gets native thread id. This must be unique. */ #ifndef KPRF_GET_THREADID # error "KPRF_GET_THREADID isn't defined!" #endif /** @def KPRF_SET_THREAD * Sets the pointer to the current thread so we can get to it * without doing a linear search by thread id. */ #ifndef KPRF_SET_THREAD # error "KPRF_SET_THREAD isn't defined!" #endif /** @def KPRF_GET_THREAD * Gets the pointer to the current thread as set by KPRF_SET_THREAD. */ #ifndef KPRF_GET_THREAD # error "KPRF_GET_THREAD isn't defined!" #endif /** @def KPRF_MODSEGS_LOCK * Lock the module segment for updating. */ #ifndef KPRF_MODSEGS_LOCK # define KPRF_MODSEGS_LOCK() do { } while (0) #endif /** @def KPRF_MODSEGS_UNLOCK * Unlock the module segments. */ #ifndef KPRF_MODSEGS_UNLOCK # define KPRF_MODSEGS_UNLOCK() do { } while (0) #endif /** @def KPRF_THREADS_LOCK * Lock the threads for updating. */ #ifndef KPRF_THREADS_LOCK # define KPRF_THREADS_LOCK() do { } while (0) #endif /** @def KPRF_THREADS_UNLOCK * Unlock the threads. */ #ifndef KPRF_THREADS_UNLOCK # define KPRF_THREADS_UNLOCK() do { } while (0) #endif /** @def KPRF_FUNCS_READ_LOCK * Lock the functions for reading. */ #ifndef KPRF_FUNCS_READ_LOCK # define KPRF_FUNCS_READ_LOCK() do { } while (0) #endif /** @def KPRF_FUNCS_READ_UNLOCK * Releases a read lock on the functions. */ #ifndef KPRF_FUNCS_READ_UNLOCK # define KPRF_FUNCS_READ_UNLOCK() do { } while (0) #endif /** @def KPRF_FUNCS_WRITE_LOCK * Lock the functions for updating. */ #ifndef KPRF_FUNCS_WRITE_LOCK # define KPRF_FUNCS_WRITE_LOCK() do { } while (0) #endif /** @def KPRF_FUNCS_WRITE_UNLOCK * Releases a write lock on the functions. */ #ifndef KPRF_FUNCS_WRITE_UNLOCK # define KPRF_FUNCS_WRITE_UNLOCK() do { } while (0) #endif /** @def KPRF_ATOMIC_SET32 * Atomically set a 32-bit value. */ #ifndef KPRF_ATOMIC_SET32 # define KPRF_ATOMIC_SET32(pu32, u32) do { *(pu32) = (u32); } while (0) #endif /** @def KPRF_ATOMIC_SET64 * Atomically (well, in a safe way) adds to a 64-bit value. */ #ifndef KPRF_ATOMIC_ADD64 # define KPRF_ATOMIC_ADD64(pu64, u64) do { *(pu64) += (u64); } while (0) #endif /** @def KPRF_ATOMIC_SET64 * Atomically (well, in a safe way) increments a 64-bit value. */ #ifndef KPRF_ATOMIC_INC64 # define KPRF_ATOMIC_INC64(pu64) KPRF_ATOMIC_ADD64(pu64, 1) #endif kbuild-3149/src/lib/kStuff/kProfiler2/kPrfReader.h0000644000175000017500000000167513252530254021732 0ustar locutuslocutus #include typedef /** * Debug info cache. * * An objects of this class acts a frontend to the low-level * debug info readers. */ class kPrfDebugInfoCache { public: kPrfDebugInfoCache(unsigned cMaxModules = ~0U); ~kPrfDebugInfoCache(); /** Resolves a symbol in a specific module. */ int findSymbol(); int findLine(); }; /** * Internal class which does the reader job behind the API / commandline tool. */ class kPrfReader { public: kPrfReader(const char *pszDataSetPath); ~kPrfReader(); /** Analyses the data set. */ int analyse(int fSomeOptionsIHaventFiguredOutYet); /** Writes the analysis report as HTML. */ int reportAsHtml(FILE *pOut); /** Dumps the data set in a raw fashion to the specified file stream. */ int dump(FILE *pOut); protected: /** Pointer to the debug info cache object. */ kPrfDebugInfoCache *pDbgCache; }; kbuild-3149/src/lib/kStuff/kProfiler2/prfcoremodseg.cpp.h0000644000175000017500000001610613252530254023320 0ustar locutuslocutus/* $Id: prfcoremodseg.cpp.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kProfiler Mark 2 - Core Module Segment Code Template. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /** * Adds a module segment. * * @returns Offset to the module if existing or successfully added * @returns 0 if not found. * * @param pHdr The profiler header. * @param pModSeg Pointer to the module segment to insert (it's copied of course). * @param off The offset into the modseg area which has been searched. * (This is relative to the first moddule segment record (at pHdr->offModSegs).) */ static KU32 KPRF_NAME(InsertModSeg)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(PC,MODSEG) pModSeg, KU32 off) { /* * Lookup the module segment, inserting it if not found (and there is room). */ for (;;) { if (off >= pHdr->cbModSegs) { /* * It was the end, let's try insert it. * * This is where we lock the modseg stuff. The deal is that we * serialize the actual inserting without blocking lookups. This * means that we may end up with potential racing inserts, but * unless there is a large amount of modules being profiled that's * probably not going to be much of a problem. Anyway if we race, * we'll simply have to search the new additions before we add our * own stuff. */ KPRF_MODSEGS_LOCK(); if (off >= pHdr->cbModSegs) { KU32 cbModSeg = KPRF_OFFSETOF(MODSEG, szPath[pModSeg->cchPath + 1]); cbModSeg = KPRF_ALIGN(cbModSeg, KPRF_SIZEOF(UPTR)); if (off + cbModSeg <= pHdr->cbMaxModSegs) { KPRF_TYPE(P,MODSEG) pNew = KPRF_OFF2PTR(P,MODSEG, off + pHdr->offModSegs, pHdr); pNew->uBasePtr = pModSeg->uBasePtr; pNew->cbSegmentMinusOne = pModSeg->cbSegmentMinusOne; pNew->iSegment = pModSeg->iSegment; pNew->fLoaded = pModSeg->fLoaded; pNew->cchPath = pModSeg->cchPath; KI32 iPath = pModSeg->cchPath; do pNew->szPath[iPath] = pModSeg->szPath[iPath]; while (--iPath >= 0); /* commit it */ KPRF_ATOMIC_SET32(&pHdr->cbModSegs, off + cbModSeg); off += pHdr->offModSegs; } else off = 0; KPRF_MODSEGS_UNLOCK(); return off; } KPRF_MODSEGS_UNLOCK(); /* someone raced us, check the new entries. */ } /* * Match? */ KPRF_TYPE(PC,MODSEG) pCur = KPRF_OFF2PTR(P,MODSEG, off + pHdr->offModSegs, pHdr); if ( pCur->uBasePtr == pModSeg->uBasePtr && pCur->fLoaded == pModSeg->fLoaded && pCur->cchPath == pModSeg->cchPath && pCur->iSegment == pModSeg->iSegment && pCur->cbSegmentMinusOne == pModSeg->cbSegmentMinusOne ) { KI32 iPath = pModSeg->cchPath; for (;;) { if (!iPath--) return off + pHdr->offModSegs; if (pModSeg->szPath[iPath] != pCur->szPath[iPath]) break; } /* didn't match, continue searching */ } KU32 cbCur = KPRF_OFFSETOF(MODSEG, szPath[pCur->cchPath + 1]); off += KPRF_ALIGN(cbCur, KPRF_SIZEOF(UPTR)); } } /** * Queries data for and inserts a new module segment. * * * @returns Offset to the module if existing or successfully added * @returns 0 if not found. * * @param pHdr The profiler header. * @param uPC Address within the module. * @param off The offset into the modseg area which has been searched. * (This is relative to the first moddule segment record (at pHdr->offModSegs).) */ static KU32 KPRF_NAME(NewModSeg)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(,UPTR) uPC, KU32 off) { /* * Query the module name and object of the function. */ #pragma pack(1) struct { KPRF_TYPE(,MODSEG) ModSeg; char szMorePath[260]; } s; #pragma pack() if (KPRF_GET_MODSEG(uPC + pHdr->uBasePtr, s.ModSeg.szPath, sizeof(s.ModSeg.szPath) + sizeof(s.szMorePath), &s.ModSeg.iSegment, &s.ModSeg.uBasePtr, &s.ModSeg.cbSegmentMinusOne)) return 0; s.ModSeg.uBasePtr -= pHdr->uBasePtr; s.ModSeg.fLoaded = 1; s.ModSeg.cchPath = 0; while (s.ModSeg.szPath[s.ModSeg.cchPath]) s.ModSeg.cchPath++; return KPRF_NAME(InsertModSeg)(pHdr, &s.ModSeg, off); } /** * Record a module segment. * * This is an internal worker for recording a module segment when adding * a new function. * * @returns Offset to the module if existing or successfully added * @returns 0 if not found. * * @param pHdr The profiler header. * @param uPC Address within the module. */ static KU32 KPRF_NAME(RecordModSeg)(KPRF_TYPE(P,HDR) pHdr, KPRF_TYPE(,UPTR) uPC) { /* * Lookup the module segment, inserting it if not found (and there is room). */ KU32 off = 0; KPRF_TYPE(PC,MODSEG) pCur = KPRF_OFF2PTR(P,MODSEG, pHdr->offModSegs, pHdr); const KU32 cbModSegs = pHdr->cbModSegs; for (;;) { /* done and not found? */ if (off >= cbModSegs) return KPRF_NAME(NewModSeg)(pHdr, uPC, off); /* * Match? */ if ( pCur->fLoaded && uPC - pCur->uBasePtr <= pCur->cbSegmentMinusOne) return off + pHdr->offModSegs; KU32 cbCur = KPRF_OFFSETOF(MODSEG, szPath[pCur->cchPath + 1]); cbCur = KPRF_ALIGN(cbCur, KPRF_SIZEOF(UPTR)); off += cbCur; pCur = (KPRF_TYPE(PC,MODSEG))((KU8 *)pCur + cbCur); } } kbuild-3149/src/lib/kStuff/kProfiler2/kProfileR3.h0000644000175000017500000000263213252530254021657 0ustar locutuslocutus/* $Id: kProfileR3.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kProfiler Mark 2 - Internal header, Ring-3. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___kProfileR3_h___ #define ___kProfileR3_h___ int kPrfInitialize(void); int kPrfTerminate(void); void kPrfTerminateThread(void); #endif kbuild-3149/src/lib/kStuff/kProfiler2/prfx86msc.asm0000644000175000017500000002523413252530254022073 0ustar locutuslocutus; $Id: prfx86msc.asm 29 2009-07-01 20:30:29Z bird $ ;; @file ; kProfiler Mark 2 - Microsoft C/C++ Compiler Interaction, x86. ; ; ; Copyright (c) 2006-2007 Knut St. Osmundsen ; ; 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. ; [section .data] ; g_fCalibrated: dd 0 g_OverheadAdj: dd 0 [section .text] extern KPRF_ENTER extern KPRF_LEAVE global __penter global __pexit ;ifdef UNDEFINED global common_return_path global common_overhead global common_no_overhead global calibrate global calib_inner_update_minimum global calib_inner_next global calib_outer_dec global calib_outer_inc global calib_done global calib_nullproc ;endif ;; ; On x86 the call to this function has been observed to be put before ; creating the stack frame, as the very first instruction in the function. ; ; Thus the stack layout is as follows: ; 24 return address of the calling function. ; 20 our return address - the address of the calling function + 5. ; 1c eax ; 18 edx ; 14 eflags ; 10 ecx ; c tsc high - param 3 ; 8 tsc low ; 4 frame pointer - param 2 ; 0 function ptr - param 1 ; ; align 16 __penter: ; save volatile register and get the time stamp. push eax push edx rdtsc pushfd push ecx ; setting up the enter call frame (cdecl). sub esp, 4 + 4 + 8 mov [esp + 0ch], edx ; Param 3 - the timestamp mov [esp + 08h], eax lea edx, [esp + 24h] ; Param 2 - frame pointer (pointer to the return address of the function calling us) mov [esp + 04h], edx mov eax, [esp + 20h] ; Param 1 - The function address sub eax, 5 ; call instruction mov [esp], eax call KPRF_ENTER jmp common_return_path ;; ; On x86 the call to this function has been observed to be put right before ; return instruction. This fact matters since since we have to calc the same ; stack address as in _penter. ; ; Thus the stack layout is as follows: ; 24 return address of the calling function. ; 20 our return address - the address of the calling function + 5. ; 1c eax ; 18 edx ; 14 eflags ; 10 ecx ; c tsc high - param 3 ; 8 tsc low ; 4 frame pointer - param 2 ; 0 function ptr - param 1 ; ; align 16 __pexit: ; save volatile register and get the time stamp. push eax push edx rdtsc pushfd push ecx ; setting up the leave call frame (cdecl). sub esp, 4 + 4 + 8 mov [esp + 0ch], edx ; Param 3 - the timestamp mov [esp + 08h], eax lea edx, [esp + 24h] ; Param 2 - frame pointer (pointer to the return address of the function calling us) mov [esp + 04h], edx mov eax, [esp + 20h] ; Param 1 - Some address in the function. sub eax, 5 ; call instruction mov [esp], eax call KPRF_LEAVE jmp common_return_path ;; ; This is the common return path for both the enter and exit hooks. ; It's kept common because we can then use the same overhead adjustment ; and save some calibration efforts. It also saves space :-) align 16 common_return_path: ; Update overhead test eax, eax jz common_no_overhead cmp byte [g_fCalibrated], 0 jnz common_overhead call calibrate common_overhead: mov ecx, eax ; ecx <- pointer to overhead counter. mov eax, [g_OverheadAdj] ; apply the adjustment before reading tsc sub [esp + 08h], eax sbb dword [esp + 0ch], 0 rdtsc sub eax, [esp + 08h] sbb edx, [esp + 0ch] add [ecx], eax adc [ecx + 4], edx common_no_overhead: add esp, 4 + 4 + 8 ; restore volatile registers. pop ecx popfd pop edx pop eax ret ;; ; Data esi points to while we're calibrating. struc CALIBDATA .OverheadLo resd 1 .OverheadHi resd 1 .ProfiledLo resd 1 .ProfiledHi resd 1 .EnterTSLo resd 1 .EnterTSHi resd 1 .MinLo resd 1 .MinHi resd 1 endstruc align 16 ;; ; Do necessary calibrations. ; calibrate: ; prolog push ebp mov ebp, esp pushfd pushad sub esp, CALIBDATA_size mov esi, esp ; esi points to the CALIBDATA ; ; Indicate that we have finished calibrating. ; mov eax, 1 xchg dword [g_fCalibrated], eax ; ; The outer loop - find the right adjustment. ; mov ebx, 200h ; loop counter. calib_outer_loop: ; ; The inner loop - calls the function number of times to establish a ; good minimum value ; mov ecx, 200h mov dword [esi + CALIBDATA.MinLo], 0ffffffffh mov dword [esi + CALIBDATA.MinHi], 07fffffffh calib_inner_loop: ; zero the overhead and profiled times. xor eax, eax mov [esi + CALIBDATA.OverheadLo], eax mov [esi + CALIBDATA.OverheadHi], eax mov [esi + CALIBDATA.ProfiledLo], eax mov [esi + CALIBDATA.ProfiledHi], eax call calib_nullproc ; subtract the overhead mov eax, [esi + CALIBDATA.ProfiledLo] mov edx, [esi + CALIBDATA.ProfiledHi] sub eax, [esi + CALIBDATA.OverheadLo] sbb edx, [esi + CALIBDATA.OverheadHi] ; update the minimum value. test edx, 080000000h jnz near calib_outer_dec ; if negative, just simplify and shortcut cmp edx, [esi + CALIBDATA.MinHi] jg calib_inner_next jl calib_inner_update_minimum cmp eax, [esi + CALIBDATA.MinLo] jge calib_inner_next calib_inner_update_minimum: mov [esi + CALIBDATA.MinLo], eax mov [esi + CALIBDATA.MinHi], edx calib_inner_next: loop calib_inner_loop ; Is the minimum value acceptable? test dword [esi + CALIBDATA.MinHi], 80000000h jnz calib_outer_dec ; simplify if negative. cmp dword [esi + CALIBDATA.MinHi], 0 jnz calib_outer_inc ; this shouldn't be possible cmp dword [esi + CALIBDATA.MinLo], 1fh jbe calib_outer_dec ; too low - 2 ticks per pair is the minimum! cmp dword [esi + CALIBDATA.MinLo], 30h jbe calib_done ; this is fine! calib_outer_inc: inc dword [g_OverheadAdj] jmp calib_outer_next calib_outer_dec: cmp dword [g_OverheadAdj], 1 je calib_done dec dword [g_OverheadAdj] calib_outer_next: dec ebx jnz calib_outer_loop calib_done: ; epilog add esp, CALIBDATA_size popad popfd leave ret ;; ; The calibration __penter - this must be identical to the real thing except for the KPRF call. align 16 calib_penter: ; This part must be identical push eax push edx rdtsc pushfd push ecx ; store the entry mov [esi + CALIBDATA.EnterTSLo], eax mov [esi + CALIBDATA.EnterTSHi], edx ; create the call frame push edx push eax push 0 push 0 lea eax, [esi + CALIBDATA.OverheadLo] jmp common_overhead ;; ; The calibration __pexit - this must be identical to the real thing except for the KPRF call. align 16 calib_pexit: ; This part must be identical push eax push edx rdtsc pushfd push ecx ; update the time push eax push edx sub eax, [esi + CALIBDATA.EnterTSLo] sbb edx, [esi + CALIBDATA.EnterTSHi] add [esi + CALIBDATA.ProfiledLo], eax adc [esi + CALIBDATA.ProfiledHi], edx pop edx pop eax ; create the call frame push edx push eax push 0 push 0 lea eax, [esi + CALIBDATA.EnterTSLo] jmp common_overhead ;; ; The 'function' we're profiling. ; The general idea is that each pair should take something like 2-10 ticks. ; ; (Btw. If we don't use multiple pairs here, we end up with the wrong result.) align 16 calib_nullproc: call calib_penter ;0 call calib_pexit call calib_penter ;1 call calib_pexit call calib_penter ;2 call calib_pexit call calib_penter ;3 call calib_pexit call calib_penter ;4 call calib_pexit call calib_penter ;5 call calib_pexit call calib_penter ;6 call calib_pexit call calib_penter ;7 call calib_pexit call calib_penter ;8 call calib_pexit call calib_penter ;9 call calib_pexit call calib_penter ;a call calib_pexit call calib_penter ;b call calib_pexit call calib_penter ;c call calib_pexit call calib_penter ;d call calib_pexit call calib_penter ;e call calib_pexit call calib_penter ;f call calib_pexit ret kbuild-3149/src/lib/kStuff/kProfiler2/kPrf2WinApi-gencode.sed0000644000175000017500000000715613252530254023727 0ustar locutuslocutus# $Id: kPrf2WinApi-gencode.sed 29 2009-07-01 20:30:29Z bird $ ## @file # Generate code (for kernel32). # # # Copyright (c) 2008 Knut St. Osmundsen # # 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. # # Example: # BOOL WINAPI FindActCtxSectionGuid( DWORD dwFlags, const GUID * lpExtensionGuid, ULONG ulSectionId, const GUID * lpGuidToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData ); # # Should be turned into: # typedef BOOL WINAPI FN_FindActCtxSectionGuid( DWORD dwFlags, const GUID * lpExtensionGuid, ULONG ulSectionId, const GUID * lpGuidToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData ); # __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindActCtxSectionGuid( DWORD dwFlags, const GUID * lpExtensionGuid, ULONG ulSectionId, const GUID * lpGuidToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData ) # { # static FN_FindActCtxSectionGuid *pfn = 0; # if (!pfn) # kPrfWrapResolve((void **)&pfn, "FindActCtxSectionGuid", &g_Kernel32); # return pfn( dwFlags, lpExtensionGuid, ulSectionId, lpGuidToFind, ReturnedData ); # } # # Ignore empty lines. /^[[:space:]]*$/b delete # Some hacks. /([[:space:]]*VOID[[:space:]]*)/b no_hacking_void s/([[:space:]]*\([A-Z][A-Z0-9_]*\)[[:space:]]*)/( \1 a)/ :no_hacking_void # Save the pattern space. h # Make the typedef. s/[[:space:]]\([A-Za-z_][A-Za-z0-9_]*\)(/ FN_\1(/ s/^/typedef / p # Function definition g s/\n//g s/\r//g s/[[:space:]]\([A-Za-z_][A-Za-z0-9_]*\)(/ kPrf2Wrap_\1(/ s/^/__declspec(dllexport) / s/;// p i\ { # static FN_FindActCtxSectionGuid *pfn = 0; # if (!pfn) g s/^.*[[:space:]]\([A-Za-z_][A-Za-z0-9_]*\)(.*$/ static FN_\1 *pfn = 0;/ p i\ if (!pfn) # kPrfWrapResolve((void **)&pfn, "FindActCtxSectionGuid", &g_Kernel32); g s/^.*[[:space:]]\([A-Za-z_][A-Za-z0-9_]*\)(.*$/ kPrf2WrapResolve((void **)\&pfn, "\1\", \&g_Kernel32);/ p # The invocation and return statement. # Some trouble here.... g /^VOID WINAPI/b void_return /^void WINAPI/b void_return /^VOID __cdecl/b void_return /^void __cdecl/b void_return /^VOID NTAPI/b void_return /^void NTAPI/b void_return s/^.*(/ return pfn(/ b morph_params :void_return s/^.*(/ pfn(/ :morph_params s/ *\[\] *// s/ \*/ /g s/, *[a-zA-Z_][^,)]* \([a-zA-Z_][a-zA-Z_0-9]* *)\)/, \1/g s/( *[a-zA-Z_][^,)]* \([a-zA-Z_][a-zA-Z_0-9]* *[,)]\)/( \1/g s/, *[a-zA-Z_][^,)]* \([a-zA-Z_][a-zA-Z_0-9]* *,\)/, \1/g s/, *[a-zA-Z_][^,)]* \([a-zA-Z_][a-zA-Z_0-9]* *,\)/, \1/g s/, *[a-zA-Z_][^,)]* \([a-zA-Z_][a-zA-Z_0-9]* *,\)/, \1/g s/, *[a-zA-Z_][^,)]* \([a-zA-Z_][a-zA-Z_0-9]* *,\)/, \1/g s/( VOID )/ ()/ s/( void )/ ()/ p i\ } i\ # Done :delete d kbuild-3149/src/lib/kStuff/kProfiler2/kPrf2WinApiWrapperHlp.h0000644000175000017500000000300313252530254023771 0ustar locutuslocutus/* $Id: kPrf2WinApiWrapperHlp.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * Helpers for the Windows API wrapper DLL. */ /* * Copyright (c) 2008 Knut St. Osmundsen * * 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. */ typedef struct KPRF2WRAPDLL { HMODULE hmod; char szName[32]; } KPRF2WRAPDLL; typedef KPRF2WRAPDLL *PKPRF2WRAPDLL; typedef KPRF2WRAPDLL const *PCKPRF2WRAPDLL; FARPROC kPrf2WrapResolve(void **ppfn, const char *pszName, PKPRF2WRAPDLL pDll); kbuild-3149/src/lib/kStuff/kProfiler2/prfcorepost.cpp.h0000644000175000017500000000266013252530254023027 0ustar locutuslocutus/* $Id: prfcorepost.cpp.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kProfiler Mark 2 - Core Post-Code Template. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /* * Clean up all our defines. */ #undef KPRF_OFFSETOF #undef KPRF_ALIGN #undef KPRF_SETMIN_ALIGN #undef KPRF_PTR2OFF #undef KPRF_OFF2PTREx #undef KPRF_OFF2PTR kbuild-3149/src/lib/kStuff/kProfiler2/prfcoreterm.cpp.h0000644000175000017500000001031513252530254023005 0ustar locutuslocutus/* $Id: prfcoreterm.cpp.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kProfiler Mark 2 - Core Termination Code Template. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /** * Unwinds and terminates all the threads, and frees the stack space. * * @returns The new data set size. (pHdr->cb) * @param pHdr The profiler data set header. */ KPRF_DECL_FUNC(KU32, TerminateAll)(KPRF_TYPE(P,HDR) pHdr) { KU64 TS = KPRF_NOW(); if (!pHdr) return 0; /* * Iterate the threads and terminate all which are non-terminated. */ KPRF_TYPE(P,THREAD) paThread = KPRF_OFF2PTR(P,THREAD, pHdr->offThreads, pHdr); for (KU32 i = 0; i < pHdr->cThreads; i++) { KPRF_TYPE(P,THREAD) pCur = &paThread[i]; switch (pCur->enmState) { /* these states needs no work. */ case KPRF_TYPE(,THREADSTATE_TERMINATED): case KPRF_TYPE(,THREADSTATE_UNUSED): default: break; /* these are active and requires unwinding.*/ case KPRF_TYPE(,THREADSTATE_ACTIVE): case KPRF_TYPE(,THREADSTATE_SUSPENDED): case KPRF_TYPE(,THREADSTATE_OVERFLOWED): KPRF_NAME(TerminateThread)(pHdr, pCur, TS); break; } } /* * Free the stacks. */ if (pHdr->offStacks) { /* only if the stack is at the end of the data set. */ const KU32 cbStacks = KPRF_ALIGN(pHdr->cMaxStacks * pHdr->cbStack, 32); if (pHdr->offStacks + cbStacks == pHdr->cb) pHdr->cb -= cbStacks; pHdr->offStacks = 0; } return pHdr->cb; } /** * Sets the commandline. * * This is typically done after TerminateAll, when the stacks has * been freed up and there is plenty free space. * * @returns The new data set size. (pHdr->cb) * @param pHdr The profiler data set header. * @param cArgs The number of arguments in the array. * @param papszArgs Pointer to an array of arguments. */ KPRF_DECL_FUNC(KU32, SetCommandLine)(KPRF_TYPE(P,HDR) pHdr, unsigned cArgs, const char * const *papszArgs) { if (!pHdr) return 0; /* * Any space at all? */ if (pHdr->cb + 16 > pHdr->cbAllocated) /* 16 bytes min */ return pHdr->cb; /* * Encode untill we run out of space. */ pHdr->offCommandLine = pHdr->cb; char *psz = (char *)pHdr + pHdr->cb; char *pszMax = (char *)pHdr + pHdr->cbAllocated - 1; for (unsigned i = 0; i < cArgs && psz + 7 < pszMax; i++) { if (i > 0) *psz++ = ' '; *psz++ = '\''; const char *pszArg = papszArgs[i]; while (psz < pszMax) { char ch = *pszArg++; if (!ch) break; if (ch == '\'') { if (psz + 1 >= pszMax) break; *psz++ = '\\'; } *psz++ = ch; } if (psz < pszMax) *psz++ = '\''; } *psz++ = '\0'; pHdr->cb = psz - (char *)pHdr; pHdr->cchCommandLine = pHdr->cb - pHdr->offCommandLine - 1; return pHdr->cb; } kbuild-3149/src/lib/kStuff/kProfiler2/kPrf2WinApiWrappersImp-x86.def0000644000175000017500000010636213252530254025124 0ustar locutuslocutusLIBRARY kPrf2WinApiWrappers EXPORTS _ActivateActCtx@8 _ActivateActCtx@8 _AddAtomA@4 _AddAtomA@4 _AddAtomW@4 _AddAtomW@4 _AddConsoleAliasA@12 _AddConsoleAliasA@12 _AddConsoleAliasW@12 _AddConsoleAliasW@12 _AddRefActCtx@4 _AddRefActCtx@4 _AddVectoredContinueHandler@8 _AddVectoredContinueHandler@8 _AddVectoredExceptionHandler@8 _AddVectoredExceptionHandler@8 _AllocConsole@0 _AllocConsole@0 _AllocateUserPhysicalPages@12 _AllocateUserPhysicalPages@12 _AreFileApisANSI@0 _AreFileApisANSI@0 _AssignProcessToJobObject@8 _AssignProcessToJobObject@8 _AttachConsole@4 _AttachConsole@4 _BackupRead@28 _BackupRead@28 _BackupSeek@24 _BackupSeek@24 _BackupWrite@28 _BackupWrite@28 _Beep@8 _Beep@8 _BeginUpdateResourceA@8 _BeginUpdateResourceA@8 _BeginUpdateResourceW@8 _BeginUpdateResourceW@8 _BindIoCompletionCallback@12 _BindIoCompletionCallback@12 _BuildCommDCBA@8 _BuildCommDCBA@8 _BuildCommDCBAndTimeoutsA@12 _BuildCommDCBAndTimeoutsA@12 _BuildCommDCBAndTimeoutsW@12 _BuildCommDCBAndTimeoutsW@12 _BuildCommDCBW@8 _BuildCommDCBW@8 _CallNamedPipeA@28 _CallNamedPipeA@28 _CallNamedPipeW@28 _CallNamedPipeW@28 _CancelDeviceWakeupRequest@4 _CancelDeviceWakeupRequest@4 _CancelIo@4 _CancelIo@4 _CancelTimerQueueTimer@8 _CancelTimerQueueTimer@8 _CancelWaitableTimer@4 _CancelWaitableTimer@4 _ChangeTimerQueueTimer@16 _ChangeTimerQueueTimer@16 _CheckNameLegalDOS8Dot3A@20 _CheckNameLegalDOS8Dot3A@20 _CheckNameLegalDOS8Dot3W@20 _CheckNameLegalDOS8Dot3W@20 _CheckRemoteDebuggerPresent@8 _CheckRemoteDebuggerPresent@8 _ClearCommBreak@4 _ClearCommBreak@4 _ClearCommError@12 _ClearCommError@12 _CloseHandle@4 _CloseHandle@4 _CommConfigDialogA@12 _CommConfigDialogA@12 _CommConfigDialogW@12 _CommConfigDialogW@12 _CompareFileTime@8 _CompareFileTime@8 _CompareStringA@24 _CompareStringA@24 _CompareStringW@24 _CompareStringW@24 _ConnectNamedPipe@8 _ConnectNamedPipe@8 _ContinueDebugEvent@12 _ContinueDebugEvent@12 _ConvertDefaultLocale@4 _ConvertDefaultLocale@4 _ConvertFiberToThread@0 _ConvertFiberToThread@0 _ConvertThreadToFiber@4 _ConvertThreadToFiber@4 _ConvertThreadToFiberEx@8 _ConvertThreadToFiberEx@8 _CopyFileA@12 _CopyFileA@12 _CopyFileExA@24 _CopyFileExA@24 _CopyFileExW@24 _CopyFileExW@24 _CopyFileW@12 _CopyFileW@12 _CreateActCtxA@4 _CreateActCtxA@4 _CreateActCtxW@4 _CreateActCtxW@4 _CreateConsoleScreenBuffer@20 _CreateConsoleScreenBuffer@20 _CreateDirectoryA@8 _CreateDirectoryA@8 _CreateDirectoryExA@12 _CreateDirectoryExA@12 _CreateDirectoryExW@12 _CreateDirectoryExW@12 _CreateDirectoryW@8 _CreateDirectoryW@8 _CreateEventA@16 _CreateEventA@16 _CreateEventW@16 _CreateEventW@16 _CreateFiber@12 _CreateFiber@12 _CreateFiberEx@20 _CreateFiberEx@20 _CreateFileA@28 _CreateFileA@28 _CreateFileMappingA@24 _CreateFileMappingA@24 _CreateFileMappingW@24 _CreateFileMappingW@24 _CreateFileW@28 _CreateFileW@28 _CreateHardLinkA@12 _CreateHardLinkA@12 _CreateHardLinkW@12 _CreateHardLinkW@12 _CreateIoCompletionPort@16 _CreateIoCompletionPort@16 _CreateJobObjectA@8 _CreateJobObjectA@8 _CreateJobObjectW@8 _CreateJobObjectW@8 _CreateJobSet@12 _CreateJobSet@12 _CreateMailslotA@16 _CreateMailslotA@16 _CreateMailslotW@16 _CreateMailslotW@16 _CreateMemoryResourceNotification@4 _CreateMemoryResourceNotification@4 _CreateMutexA@12 _CreateMutexA@12 _CreateMutexW@12 _CreateMutexW@12 _CreateNamedPipeA@32 _CreateNamedPipeA@32 _CreateNamedPipeW@32 _CreateNamedPipeW@32 _CreatePipe@16 _CreatePipe@16 _CreateProcessA@40 _CreateProcessA@40 _CreateProcessW@40 _CreateProcessW@40 _CreateRemoteThread@28 _CreateRemoteThread@28 _CreateSemaphoreA@16 _CreateSemaphoreA@16 _CreateSemaphoreW@16 _CreateSemaphoreW@16 _CreateTapePartition@16 _CreateTapePartition@16 _CreateThread@24 _CreateThread@24 _CreateTimerQueue@0 _CreateTimerQueue@0 _CreateTimerQueueTimer@28 _CreateTimerQueueTimer@28 _CreateToolhelp32Snapshot@8 _CreateToolhelp32Snapshot@8 _CreateWaitableTimerA@12 _CreateWaitableTimerA@12 _CreateWaitableTimerW@12 _CreateWaitableTimerW@12 _DeactivateActCtx@8 _DeactivateActCtx@8 _DebugActiveProcess@4 _DebugActiveProcess@4 _DebugActiveProcessStop@4 _DebugActiveProcessStop@4 _DebugBreak@0 _DebugBreak@0 _DebugBreakProcess@4 _DebugBreakProcess@4 _DebugSetProcessKillOnExit@4 _DebugSetProcessKillOnExit@4 _DecodePointer@4 _DecodePointer@4 _DecodeSystemPointer@4 _DecodeSystemPointer@4 _DefineDosDeviceA@12 _DefineDosDeviceA@12 _DefineDosDeviceW@12 _DefineDosDeviceW@12 _DeleteAtom@4 _DeleteAtom@4 _DeleteCriticalSection@4 _DeleteCriticalSection@4 _DeleteFiber@4 _DeleteFiber@4 _DeleteFileA@4 _DeleteFileA@4 _DeleteFileW@4 _DeleteFileW@4 _DeleteTimerQueue@4 _DeleteTimerQueue@4 _DeleteTimerQueueEx@8 _DeleteTimerQueueEx@8 _DeleteTimerQueueTimer@12 _DeleteTimerQueueTimer@12 _DeleteVolumeMountPointA@4 _DeleteVolumeMountPointA@4 _DeleteVolumeMountPointW@4 _DeleteVolumeMountPointW@4 _DeviceIoControl@32 _DeviceIoControl@32 _DisableThreadLibraryCalls@4 _DisableThreadLibraryCalls@4 _DisconnectNamedPipe@4 _DisconnectNamedPipe@4 _DnsHostnameToComputerNameA@12 _DnsHostnameToComputerNameA@12 _DnsHostnameToComputerNameW@12 _DnsHostnameToComputerNameW@12 _DosDateTimeToFileTime@12 _DosDateTimeToFileTime@12 _DuplicateHandle@28 _DuplicateHandle@28 _EncodePointer@4 _EncodePointer@4 _EncodeSystemPointer@4 _EncodeSystemPointer@4 _EndUpdateResourceA@8 _EndUpdateResourceA@8 _EndUpdateResourceW@8 _EndUpdateResourceW@8 _EnterCriticalSection@4 _EnterCriticalSection@4 _EnumCalendarInfoA@16 _EnumCalendarInfoA@16 _EnumCalendarInfoExA@16 _EnumCalendarInfoExA@16 _EnumCalendarInfoExW@16 _EnumCalendarInfoExW@16 _EnumCalendarInfoW@16 _EnumCalendarInfoW@16 _EnumDateFormatsA@12 _EnumDateFormatsA@12 _EnumDateFormatsExA@12 _EnumDateFormatsExA@12 _EnumDateFormatsExW@12 _EnumDateFormatsExW@12 _EnumDateFormatsW@12 _EnumDateFormatsW@12 _EnumLanguageGroupLocalesA@16 _EnumLanguageGroupLocalesA@16 _EnumLanguageGroupLocalesW@16 _EnumLanguageGroupLocalesW@16 _EnumResourceLanguagesA@20 _EnumResourceLanguagesA@20 _EnumResourceLanguagesW@20 _EnumResourceLanguagesW@20 _EnumResourceNamesA@16 _EnumResourceNamesA@16 _EnumResourceNamesW@16 _EnumResourceNamesW@16 _EnumResourceTypesA@12 _EnumResourceTypesA@12 _EnumResourceTypesW@12 _EnumResourceTypesW@12 _EnumSystemCodePagesA@8 _EnumSystemCodePagesA@8 _EnumSystemCodePagesW@8 _EnumSystemCodePagesW@8 _EnumSystemFirmwareTables@12 _EnumSystemFirmwareTables@12 _EnumSystemGeoID@12 _EnumSystemGeoID@12 _EnumSystemLanguageGroupsA@12 _EnumSystemLanguageGroupsA@12 _EnumSystemLanguageGroupsW@12 _EnumSystemLanguageGroupsW@12 _EnumSystemLocalesA@8 _EnumSystemLocalesA@8 _EnumSystemLocalesW@8 _EnumSystemLocalesW@8 _EnumTimeFormatsA@12 _EnumTimeFormatsA@12 _EnumTimeFormatsW@12 _EnumTimeFormatsW@12 _EnumUILanguagesA@12 _EnumUILanguagesA@12 _EnumUILanguagesW@12 _EnumUILanguagesW@12 _EraseTape@12 _EraseTape@12 _EscapeCommFunction@8 _EscapeCommFunction@8 _ExitProcess@4 _ExitProcess@4 _ExitThread@4 _ExitThread@4 _ExpandEnvironmentStringsA@12 _ExpandEnvironmentStringsA@12 _ExpandEnvironmentStringsW@12 _ExpandEnvironmentStringsW@12 _FatalAppExitA@8 _FatalAppExitA@8 _FatalAppExitW@8 _FatalAppExitW@8 _FatalExit@4 _FatalExit@4 _FileTimeToDosDateTime@12 _FileTimeToDosDateTime@12 _FileTimeToLocalFileTime@8 _FileTimeToLocalFileTime@8 _FileTimeToSystemTime@8 _FileTimeToSystemTime@8 _FillConsoleOutputAttribute@20 _FillConsoleOutputAttribute@20 _FillConsoleOutputCharacterA@20 _FillConsoleOutputCharacterA@20 _FillConsoleOutputCharacterW@20 _FillConsoleOutputCharacterW@20 _FindActCtxSectionGuid@20 _FindActCtxSectionGuid@20 _FindActCtxSectionStringA@20 _FindActCtxSectionStringA@20 _FindActCtxSectionStringW@20 _FindActCtxSectionStringW@20 _FindAtomA@4 _FindAtomA@4 _FindAtomW@4 _FindAtomW@4 _FindClose@4 _FindClose@4 _FindCloseChangeNotification@4 _FindCloseChangeNotification@4 _FindFirstChangeNotificationA@12 _FindFirstChangeNotificationA@12 _FindFirstChangeNotificationW@12 _FindFirstChangeNotificationW@12 _FindFirstFileA@8 _FindFirstFileA@8 _FindFirstFileExA@24 _FindFirstFileExA@24 _FindFirstFileExW@24 _FindFirstFileExW@24 _FindFirstFileW@8 _FindFirstFileW@8 _FindFirstStreamW@16 _FindFirstStreamW@16 _FindFirstVolumeA@8 _FindFirstVolumeA@8 _FindFirstVolumeMountPointA@12 _FindFirstVolumeMountPointA@12 _FindFirstVolumeMountPointW@12 _FindFirstVolumeMountPointW@12 _FindFirstVolumeW@8 _FindFirstVolumeW@8 _FindNextChangeNotification@4 _FindNextChangeNotification@4 _FindNextFileA@8 _FindNextFileA@8 _FindNextFileW@8 _FindNextFileW@8 _FindNextStreamW@8 _FindNextStreamW@8 _FindNextVolumeA@12 _FindNextVolumeA@12 _FindNextVolumeMountPointA@12 _FindNextVolumeMountPointA@12 _FindNextVolumeMountPointW@12 _FindNextVolumeMountPointW@12 _FindNextVolumeW@12 _FindNextVolumeW@12 _FindResourceA@12 _FindResourceA@12 _FindResourceExA@16 _FindResourceExA@16 _FindResourceExW@16 _FindResourceExW@16 _FindResourceW@12 _FindResourceW@12 _FindVolumeClose@4 _FindVolumeClose@4 _FindVolumeMountPointClose@4 _FindVolumeMountPointClose@4 _FlsAlloc@4 _FlsAlloc@4 _FlsFree@4 _FlsFree@4 _FlsGetValue@4 _FlsGetValue@4 _FlsSetValue@8 _FlsSetValue@8 _FlushConsoleInputBuffer@4 _FlushConsoleInputBuffer@4 _FlushFileBuffers@4 _FlushFileBuffers@4 _FlushInstructionCache@12 _FlushInstructionCache@12 _FlushViewOfFile@8 _FlushViewOfFile@8 _FoldStringA@20 _FoldStringA@20 _FoldStringW@20 _FoldStringW@20 _FormatMessageA@28 _FormatMessageA@28 _FormatMessageW@28 _FormatMessageW@28 _FreeConsole@0 _FreeConsole@0 _FreeEnvironmentStringsA@4 _FreeEnvironmentStringsA@4 _FreeEnvironmentStringsW@4 _FreeEnvironmentStringsW@4 _FreeLibrary@4 _FreeLibrary@4 _FreeLibraryAndExitThread@8 _FreeLibraryAndExitThread@8 _FreeResource@4 _FreeResource@4 _FreeUserPhysicalPages@12 _FreeUserPhysicalPages@12 _GenerateConsoleCtrlEvent@8 _GenerateConsoleCtrlEvent@8 _GetACP@0 _GetACP@0 _GetAtomNameA@12 _GetAtomNameA@12 _GetAtomNameW@12 _GetAtomNameW@12 _GetBinaryType@8 _GetBinaryType@8 _GetBinaryTypeA@8 _GetBinaryTypeA@8 _GetBinaryTypeW@8 _GetBinaryTypeW@8 _GetCPInfo@8 _GetCPInfo@8 _GetCPInfoExA@12 _GetCPInfoExA@12 _GetCPInfoExW@12 _GetCPInfoExW@12 _GetCalendarInfoA@24 _GetCalendarInfoA@24 _GetCalendarInfoW@24 _GetCalendarInfoW@24 _GetCommConfig@12 _GetCommConfig@12 _GetCommMask@8 _GetCommMask@8 _GetCommModemStatus@8 _GetCommModemStatus@8 _GetCommProperties@8 _GetCommProperties@8 _GetCommState@8 _GetCommState@8 _GetCommTimeouts@8 _GetCommTimeouts@8 _GetCommandLineA@0 _GetCommandLineA@0 _GetCommandLineW@0 _GetCommandLineW@0 _GetCompressedFileSizeA@8 _GetCompressedFileSizeA@8 _GetCompressedFileSizeW@8 _GetCompressedFileSizeW@8 _GetComputerNameA@8 _GetComputerNameA@8 _GetComputerNameExA@12 _GetComputerNameExA@12 _GetComputerNameExW@12 _GetComputerNameExW@12 _GetComputerNameW@8 _GetComputerNameW@8 _GetConsoleAliasA@16 _GetConsoleAliasA@16 _GetConsoleAliasExesA@8 _GetConsoleAliasExesA@8 _GetConsoleAliasExesLengthA@0 _GetConsoleAliasExesLengthA@0 _GetConsoleAliasExesLengthW@0 _GetConsoleAliasExesLengthW@0 _GetConsoleAliasExesW@8 _GetConsoleAliasExesW@8 _GetConsoleAliasW@16 _GetConsoleAliasW@16 _GetConsoleAliasesA@12 _GetConsoleAliasesA@12 _GetConsoleAliasesLengthA@4 _GetConsoleAliasesLengthA@4 _GetConsoleAliasesLengthW@4 _GetConsoleAliasesLengthW@4 _GetConsoleAliasesW@12 _GetConsoleAliasesW@12 _GetConsoleCP@0 _GetConsoleCP@0 _GetConsoleCursorInfo@8 _GetConsoleCursorInfo@8 _GetConsoleDisplayMode@4 _GetConsoleDisplayMode@4 _GetConsoleFontSize@8 _GetConsoleFontSize@8 _GetConsoleMode@8 _GetConsoleMode@8 _GetConsoleOutputCP@0 _GetConsoleOutputCP@0 _GetConsoleProcessList@8 _GetConsoleProcessList@8 _GetConsoleScreenBufferInfo@8 _GetConsoleScreenBufferInfo@8 _GetConsoleSelectionInfo@4 _GetConsoleSelectionInfo@4 _GetConsoleTitleA@8 _GetConsoleTitleA@8 _GetConsoleTitleW@8 _GetConsoleTitleW@8 _GetConsoleWindow@0 _GetConsoleWindow@0 _GetCurrencyFormatA@24 _GetCurrencyFormatA@24 _GetCurrencyFormatW@24 _GetCurrencyFormatW@24 _GetCurrentActCtx@4 _GetCurrentActCtx@4 _GetCurrentConsoleFont@12 _GetCurrentConsoleFont@12 _GetCurrentDirectoryA@8 _GetCurrentDirectoryA@8 _GetCurrentDirectoryW@8 _GetCurrentDirectoryW@8 _GetCurrentProcess@0 _GetCurrentProcess@0 _GetCurrentProcessId@0 _GetCurrentProcessId@0 _GetCurrentProcessorNumber@0 _GetCurrentProcessorNumber@0 _GetCurrentThread@0 _GetCurrentThread@0 _GetCurrentThreadId@0 _GetCurrentThreadId@0 _GetDateFormatA@24 _GetDateFormatA@24 _GetDateFormatW@24 _GetDateFormatW@24 _GetDefaultCommConfigA@12 _GetDefaultCommConfigA@12 _GetDefaultCommConfigW@12 _GetDefaultCommConfigW@12 _GetDevicePowerState@8 _GetDevicePowerState@8 _GetDiskFreeSpaceA@20 _GetDiskFreeSpaceA@20 _GetDiskFreeSpaceExA@16 _GetDiskFreeSpaceExA@16 _GetDiskFreeSpaceExW@16 _GetDiskFreeSpaceExW@16 _GetDiskFreeSpaceW@20 _GetDiskFreeSpaceW@20 _GetDllDirectoryA@8 _GetDllDirectoryA@8 _GetDllDirectoryW@8 _GetDllDirectoryW@8 _GetDriveTypeA@4 _GetDriveTypeA@4 _GetDriveTypeW@4 _GetDriveTypeW@4 _GetEnvironmentStrings@0 _GetEnvironmentStrings@0 _GetEnvironmentStringsA@0 _GetEnvironmentStringsA@0 _GetEnvironmentStringsW@0 _GetEnvironmentStringsW@0 _GetEnvironmentVariableA@12 _GetEnvironmentVariableA@12 _GetEnvironmentVariableW@12 _GetEnvironmentVariableW@12 _GetExitCodeProcess@8 _GetExitCodeProcess@8 _GetExitCodeThread@8 _GetExitCodeThread@8 _GetFileAttributesA@4 _GetFileAttributesA@4 _GetFileAttributesExA@12 _GetFileAttributesExA@12 _GetFileAttributesExW@12 _GetFileAttributesExW@12 _GetFileAttributesW@4 _GetFileAttributesW@4 _GetFileInformationByHandle@8 _GetFileInformationByHandle@8 _GetFileSize@8 _GetFileSize@8 _GetFileSizeEx@8 _GetFileSizeEx@8 _GetFileTime@16 _GetFileTime@16 _GetFileType@4 _GetFileType@4 _GetFirmwareEnvironmentVariableA@16 _GetFirmwareEnvironmentVariableA@16 _GetFirmwareEnvironmentVariableW@16 _GetFirmwareEnvironmentVariableW@16 _GetFullPathNameA@16 _GetFullPathNameA@16 _GetFullPathNameW@16 _GetFullPathNameW@16 _GetGeoInfoA@20 _GetGeoInfoA@20 _GetGeoInfoW@20 _GetGeoInfoW@20 _GetHandleInformation@8 _GetHandleInformation@8 _GetLargePageMinimum@0 _GetLargePageMinimum@0 _GetLargestConsoleWindowSize@4 _GetLargestConsoleWindowSize@4 _GetLastError@0 _GetLastError@0 _GetLocalTime@4 _GetLocalTime@4 _GetLocaleInfoA@16 _GetLocaleInfoA@16 _GetLocaleInfoW@16 _GetLocaleInfoW@16 _GetLogicalDriveStringsA@8 _GetLogicalDriveStringsA@8 _GetLogicalDriveStringsW@8 _GetLogicalDriveStringsW@8 _GetLogicalDrives@0 _GetLogicalDrives@0 _GetLogicalProcessorInformation@8 _GetLogicalProcessorInformation@8 _GetLongPathNameA@12 _GetLongPathNameA@12 _GetLongPathNameW@12 _GetLongPathNameW@12 _GetMailslotInfo@20 _GetMailslotInfo@20 _GetModuleFileNameA@12 _GetModuleFileNameA@12 _GetModuleFileNameW@12 _GetModuleFileNameW@12 _GetModuleHandleA@4 _GetModuleHandleA@4 _GetModuleHandleExA@12 _GetModuleHandleExA@12 _GetModuleHandleExW@12 _GetModuleHandleExW@12 _GetModuleHandleW@4 _GetModuleHandleW@4 _GetNLSVersion@12 _GetNLSVersion@12 _GetNamedPipeHandleStateA@28 _GetNamedPipeHandleStateA@28 _GetNamedPipeHandleStateW@28 _GetNamedPipeHandleStateW@28 _GetNamedPipeInfo@20 _GetNamedPipeInfo@20 _GetNativeSystemInfo@4 _GetNativeSystemInfo@4 _GetNumaAvailableMemoryNode@8 _GetNumaAvailableMemoryNode@8 _GetNumaHighestNodeNumber@4 _GetNumaHighestNodeNumber@4 _GetNumaNodeProcessorMask@8 _GetNumaNodeProcessorMask@8 _GetNumaProcessorNode@8 _GetNumaProcessorNode@8 _GetNumberFormatA@24 _GetNumberFormatA@24 _GetNumberFormatW@24 _GetNumberFormatW@24 _GetNumberOfConsoleInputEvents@8 _GetNumberOfConsoleInputEvents@8 _GetNumberOfConsoleMouseButtons@4 _GetNumberOfConsoleMouseButtons@4 _GetOEMCP@0 _GetOEMCP@0 _GetOverlappedResult@16 _GetOverlappedResult@16 _GetPriorityClass@4 _GetPriorityClass@4 _GetPrivateProfileIntA@16 _GetPrivateProfileIntA@16 _GetPrivateProfileIntW@16 _GetPrivateProfileIntW@16 _GetPrivateProfileSectionA@16 _GetPrivateProfileSectionA@16 _GetPrivateProfileSectionNamesA@12 _GetPrivateProfileSectionNamesA@12 _GetPrivateProfileSectionNamesW@12 _GetPrivateProfileSectionNamesW@12 _GetPrivateProfileSectionW@16 _GetPrivateProfileSectionW@16 _GetPrivateProfileStringA@24 _GetPrivateProfileStringA@24 _GetPrivateProfileStringW@24 _GetPrivateProfileStringW@24 _GetPrivateProfileStructA@20 _GetPrivateProfileStructA@20 _GetPrivateProfileStructW@20 _GetPrivateProfileStructW@20 _GetProcAddress@8 _GetProcAddress@8 _GetProcessAffinityMask@12 _GetProcessAffinityMask@12 _GetProcessHandleCount@8 _GetProcessHandleCount@8 _GetProcessHeap@0 _GetProcessHeap@0 _GetProcessHeaps@8 _GetProcessHeaps@8 _GetProcessId@4 _GetProcessId@4 _GetProcessIdOfThread@4 _GetProcessIdOfThread@4 _GetProcessIoCounters@8 _GetProcessIoCounters@8 _GetProcessPriorityBoost@8 _GetProcessPriorityBoost@8 _GetProcessShutdownParameters@8 _GetProcessShutdownParameters@8 _GetProcessTimes@20 _GetProcessTimes@20 _GetProcessVersion@4 _GetProcessVersion@4 _GetProcessWorkingSetSize@12 _GetProcessWorkingSetSize@12 _GetProcessWorkingSetSizeEx@16 _GetProcessWorkingSetSizeEx@16 _GetProfileIntA@12 _GetProfileIntA@12 _GetProfileIntW@12 _GetProfileIntW@12 _GetProfileSectionA@12 _GetProfileSectionA@12 _GetProfileSectionW@12 _GetProfileSectionW@12 _GetProfileStringA@20 _GetProfileStringA@20 _GetProfileStringW@20 _GetProfileStringW@20 _GetQueuedCompletionStatus@20 _GetQueuedCompletionStatus@20 _GetShortPathNameA@12 _GetShortPathNameA@12 _GetShortPathNameW@12 _GetShortPathNameW@12 _GetStartupInfoA@4 _GetStartupInfoA@4 _GetStartupInfoW@4 _GetStartupInfoW@4 _GetStdHandle@4 _GetStdHandle@4 _GetStringTypeA@20 _GetStringTypeA@20 _GetStringTypeExA@20 _GetStringTypeExA@20 _GetStringTypeExW@20 _GetStringTypeExW@20 _GetStringTypeW@16 _GetStringTypeW@16 _GetSystemDefaultLCID@0 _GetSystemDefaultLCID@0 _GetSystemDefaultLangID@0 _GetSystemDefaultLangID@0 _GetSystemDefaultUILanguage@0 _GetSystemDefaultUILanguage@0 _GetSystemDirectoryA@8 _GetSystemDirectoryA@8 _GetSystemDirectoryW@8 _GetSystemDirectoryW@8 _GetSystemFileCacheSize@12 _GetSystemFileCacheSize@12 _GetSystemFirmwareTable@16 _GetSystemFirmwareTable@16 _GetSystemInfo@4 _GetSystemInfo@4 _GetSystemPowerStatus@4 _GetSystemPowerStatus@4 _GetSystemRegistryQuota@8 _GetSystemRegistryQuota@8 _GetSystemTime@4 _GetSystemTime@4 _GetSystemTimeAdjustment@12 _GetSystemTimeAdjustment@12 _GetSystemTimeAsFileTime@4 _GetSystemTimeAsFileTime@4 _GetSystemTimes@12 _GetSystemTimes@12 _GetSystemWindowsDirectoryA@8 _GetSystemWindowsDirectoryA@8 _GetSystemWindowsDirectoryW@8 _GetSystemWindowsDirectoryW@8 _GetSystemWow64DirectoryA@8 _GetSystemWow64DirectoryA@8 _GetSystemWow64DirectoryW@8 _GetSystemWow64DirectoryW@8 _GetTapeParameters@16 _GetTapeParameters@16 _GetTapePosition@20 _GetTapePosition@20 _GetTapeStatus@4 _GetTapeStatus@4 _GetTempFileNameA@16 _GetTempFileNameA@16 _GetTempFileNameW@16 _GetTempFileNameW@16 _GetTempPathA@8 _GetTempPathA@8 _GetTempPathW@8 _GetTempPathW@8 _GetThreadContext@8 _GetThreadContext@8 _GetThreadIOPendingFlag@8 _GetThreadIOPendingFlag@8 _GetThreadId@4 _GetThreadId@4 _GetThreadLocale@0 _GetThreadLocale@0 _GetThreadPriority@4 _GetThreadPriority@4 _GetThreadPriorityBoost@8 _GetThreadPriorityBoost@8 _GetThreadSelectorEntry@12 _GetThreadSelectorEntry@12 _GetThreadTimes@20 _GetThreadTimes@20 _GetTickCount@0 _GetTickCount@0 _GetTimeFormatA@24 _GetTimeFormatA@24 _GetTimeFormatW@24 _GetTimeFormatW@24 _GetTimeZoneInformation@4 _GetTimeZoneInformation@4 _GetUserDefaultLCID@0 _GetUserDefaultLCID@0 _GetUserDefaultLangID@0 _GetUserDefaultLangID@0 _GetUserDefaultUILanguage@0 _GetUserDefaultUILanguage@0 _GetUserGeoID@4 _GetUserGeoID@4 _GetVersion@0 _GetVersion@0 _GetVersionExA@4 _GetVersionExA@4 _GetVersionExW@4 _GetVersionExW@4 _GetVolumeInformationA@32 _GetVolumeInformationA@32 _GetVolumeInformationW@32 _GetVolumeInformationW@32 _GetVolumeNameForVolumeMountPointA@12 _GetVolumeNameForVolumeMountPointA@12 _GetVolumeNameForVolumeMountPointW@12 _GetVolumeNameForVolumeMountPointW@12 _GetVolumePathNameA@12 _GetVolumePathNameA@12 _GetVolumePathNameW@12 _GetVolumePathNameW@12 _GetVolumePathNamesForVolumeNameA@16 _GetVolumePathNamesForVolumeNameA@16 _GetVolumePathNamesForVolumeNameW@16 _GetVolumePathNamesForVolumeNameW@16 _GetWindowsDirectoryA@8 _GetWindowsDirectoryA@8 _GetWindowsDirectoryW@8 _GetWindowsDirectoryW@8 _GetWriteWatch@24 _GetWriteWatch@24 _GlobalAddAtomA@4 _GlobalAddAtomA@4 _GlobalAddAtomW@4 _GlobalAddAtomW@4 _GlobalAlloc@8 _GlobalAlloc@8 _GlobalCompact@4 _GlobalCompact@4 _GlobalDeleteAtom@4 _GlobalDeleteAtom@4 _GlobalFindAtomA@4 _GlobalFindAtomA@4 _GlobalFindAtomW@4 _GlobalFindAtomW@4 _GlobalFix@4 _GlobalFix@4 _GlobalFlags@4 _GlobalFlags@4 _GlobalFree@4 _GlobalFree@4 _GlobalGetAtomNameA@12 _GlobalGetAtomNameA@12 _GlobalGetAtomNameW@12 _GlobalGetAtomNameW@12 _GlobalHandle@4 _GlobalHandle@4 _GlobalLock@4 _GlobalLock@4 _GlobalMemoryStatus@4 _GlobalMemoryStatus@4 _GlobalMemoryStatusEx@4 _GlobalMemoryStatusEx@4 _GlobalReAlloc@12 _GlobalReAlloc@12 _GlobalSize@4 _GlobalSize@4 _GlobalUnWire@4 _GlobalUnWire@4 _GlobalUnfix@4 _GlobalUnfix@4 _GlobalUnlock@4 _GlobalUnlock@4 _GlobalWire@4 _GlobalWire@4 _Heap32First@12 _Heap32First@12 _Heap32ListFirst@8 _Heap32ListFirst@8 _Heap32ListNext@8 _Heap32ListNext@8 _Heap32Next@4 _Heap32Next@4 _HeapAlloc@12 _HeapAlloc@12 _HeapCompact@8 _HeapCompact@8 _HeapCreate@12 _HeapCreate@12 _HeapDestroy@4 _HeapDestroy@4 _HeapFree@12 _HeapFree@12 _HeapLock@4 _HeapLock@4 _HeapQueryInformation@20 _HeapQueryInformation@20 _HeapReAlloc@16 _HeapReAlloc@16 _HeapSetInformation@16 _HeapSetInformation@16 _HeapSize@12 _HeapSize@12 _HeapUnlock@4 _HeapUnlock@4 _HeapValidate@12 _HeapValidate@12 _HeapWalk@8 _HeapWalk@8 _InitAtomTable@4 _InitAtomTable@4 _InitializeCriticalSection@4 _InitializeCriticalSection@4 _InitializeCriticalSectionAndSpinCount@8 _InitializeCriticalSectionAndSpinCount@8 _InitializeSListHead@4 _InitializeSListHead@4 _InterlockedCompareExchange64@20 _InterlockedCompareExchange64@20 _InterlockedCompareExchange@12 _InterlockedCompareExchange@12 _InterlockedDecrement@4 _InterlockedDecrement@4 _InterlockedExchange@8 _InterlockedExchange@8 _InterlockedExchangeAdd@8 _InterlockedExchangeAdd@8 _InterlockedFlushSList@4 _InterlockedFlushSList@4 _InterlockedIncrement@4 _InterlockedIncrement@4 _InterlockedPopEntrySList@4 _InterlockedPopEntrySList@4 _InterlockedPushEntrySList@8 _InterlockedPushEntrySList@8 _IsBadCodePtr@4 _IsBadCodePtr@4 _IsBadHugeReadPtr@8 _IsBadHugeReadPtr@8 _IsBadHugeWritePtr@8 _IsBadHugeWritePtr@8 _IsBadReadPtr@8 _IsBadReadPtr@8 _IsBadStringPtrA@8 _IsBadStringPtrA@8 _IsBadStringPtrW@8 _IsBadStringPtrW@8 _IsBadWritePtr@8 _IsBadWritePtr@8 _IsDBCSLeadByte@4 _IsDBCSLeadByte@4 _IsDBCSLeadByteEx@8 _IsDBCSLeadByteEx@8 _IsDebuggerPresent@0 _IsDebuggerPresent@0 _IsNLSDefinedString@20 _IsNLSDefinedString@20 _IsProcessInJob@12 _IsProcessInJob@12 _IsProcessorFeaturePresent@4 _IsProcessorFeaturePresent@4 _IsSystemResumeAutomatic@0 _IsSystemResumeAutomatic@0 _IsValidCodePage@4 _IsValidCodePage@4 _IsValidLanguageGroup@8 _IsValidLanguageGroup@8 _IsValidLocale@8 _IsValidLocale@8 _IsWow64Process@8 _IsWow64Process@8 _LCMapStringA@24 _LCMapStringA@24 _LCMapStringW@24 _LCMapStringW@24 _LeaveCriticalSection@4 _LeaveCriticalSection@4 _LoadLibraryA@4 _LoadLibraryA@4 _LoadLibraryExA@12 _LoadLibraryExA@12 _LoadLibraryExW@12 _LoadLibraryExW@12 _LoadLibraryW@4 _LoadLibraryW@4 _LoadModule@8 _LoadModule@8 _LoadResource@8 _LoadResource@8 _LocalAlloc@8 _LocalAlloc@8 _LocalCompact@4 _LocalCompact@4 _LocalFileTimeToFileTime@8 _LocalFileTimeToFileTime@8 _LocalFlags@4 _LocalFlags@4 _LocalFree@4 _LocalFree@4 _LocalHandle@4 _LocalHandle@4 _LocalLock@4 _LocalLock@4 _LocalReAlloc@12 _LocalReAlloc@12 _LocalShrink@8 _LocalShrink@8 _LocalSize@4 _LocalSize@4 _LocalUnlock@4 _LocalUnlock@4 _LockFile@20 _LockFile@20 _LockFileEx@24 _LockFileEx@24 _LockResource@4 _LockResource@4 _MapUserPhysicalPages@12 _MapUserPhysicalPages@12 _MapUserPhysicalPagesScatter@12 _MapUserPhysicalPagesScatter@12 _MapViewOfFile@20 _MapViewOfFile@20 _MapViewOfFileEx@24 _MapViewOfFileEx@24 _Module32First@8 _Module32First@8 _Module32FirstW@8 _Module32FirstW@8 _Module32Next@8 _Module32Next@8 _Module32NextW@8 _Module32NextW@8 _MoveFileA@8 _MoveFileA@8 _MoveFileExA@12 _MoveFileExA@12 _MoveFileExW@12 _MoveFileExW@12 _MoveFileW@8 _MoveFileW@8 _MoveFileWithProgressA@20 _MoveFileWithProgressA@20 _MoveFileWithProgressW@20 _MoveFileWithProgressW@20 _MulDiv@12 _MulDiv@12 _MultiByteToWideChar@24 _MultiByteToWideChar@24 _NeedCurrentDirectoryForExePathA@4 _NeedCurrentDirectoryForExePathA@4 _NeedCurrentDirectoryForExePathW@4 _NeedCurrentDirectoryForExePathW@4 _OpenEventA@12 _OpenEventA@12 _OpenEventW@12 _OpenEventW@12 _OpenFile@12 _OpenFile@12 _OpenFileMappingA@12 _OpenFileMappingA@12 _OpenFileMappingW@12 _OpenFileMappingW@12 _OpenJobObjectA@12 _OpenJobObjectA@12 _OpenJobObjectW@12 _OpenJobObjectW@12 _OpenMutexA@12 _OpenMutexA@12 _OpenMutexW@12 _OpenMutexW@12 _OpenProcess@12 _OpenProcess@12 _OpenSemaphoreA@12 _OpenSemaphoreA@12 _OpenSemaphoreW@12 _OpenSemaphoreW@12 _OpenThread@12 _OpenThread@12 _OpenWaitableTimerA@12 _OpenWaitableTimerA@12 _OpenWaitableTimerW@12 _OpenWaitableTimerW@12 _OutputDebugStringA@4 _OutputDebugStringA@4 _OutputDebugStringW@4 _OutputDebugStringW@4 _PeekConsoleInputA@16 _PeekConsoleInputA@16 _PeekConsoleInputW@16 _PeekConsoleInputW@16 _PeekNamedPipe@24 _PeekNamedPipe@24 _PostQueuedCompletionStatus@16 _PostQueuedCompletionStatus@16 _PrepareTape@12 _PrepareTape@12 _Process32First@8 _Process32First@8 _Process32FirstW@8 _Process32FirstW@8 _Process32Next@8 _Process32Next@8 _Process32NextW@8 _Process32NextW@8 _ProcessIdToSessionId@8 _ProcessIdToSessionId@8 _PulseEvent@4 _PulseEvent@4 _PurgeComm@8 _PurgeComm@8 _QueryActCtxW@28 _QueryActCtxW@28 _QueryDepthSList@4 _QueryDepthSList@4 _QueryDosDeviceA@12 _QueryDosDeviceA@12 _QueryDosDeviceW@12 _QueryDosDeviceW@12 _QueryInformationJobObject@20 _QueryInformationJobObject@20 _QueryMemoryResourceNotification@8 _QueryMemoryResourceNotification@8 _QueryPerformanceCounter@4 _QueryPerformanceCounter@4 _QueryPerformanceFrequency@4 _QueryPerformanceFrequency@4 _QueueUserAPC@12 _QueueUserAPC@12 _QueueUserWorkItem@12 _QueueUserWorkItem@12 _RaiseException@16 _RaiseException@16 _ReOpenFile@16 _ReOpenFile@16 _ReadConsoleA@20 _ReadConsoleA@20 _ReadConsoleInputA@16 _ReadConsoleInputA@16 _ReadConsoleInputW@16 _ReadConsoleInputW@16 _ReadConsoleOutputA@20 _ReadConsoleOutputA@20 _ReadConsoleOutputAttribute@20 _ReadConsoleOutputAttribute@20 _ReadConsoleOutputCharacterA@20 _ReadConsoleOutputCharacterA@20 _ReadConsoleOutputCharacterW@20 _ReadConsoleOutputCharacterW@20 _ReadConsoleOutputW@20 _ReadConsoleOutputW@20 _ReadConsoleW@20 _ReadConsoleW@20 _ReadDirectoryChangesW@32 _ReadDirectoryChangesW@32 _ReadFile@20 _ReadFile@20 _ReadFileEx@20 _ReadFileEx@20 _ReadFileScatter@20 _ReadFileScatter@20 _ReadProcessMemory@20 _ReadProcessMemory@20 _RegisterWaitForSingleObject@24 _RegisterWaitForSingleObject@24 _RegisterWaitForSingleObjectEx@20 _RegisterWaitForSingleObjectEx@20 _ReleaseActCtx@4 _ReleaseActCtx@4 _ReleaseMutex@4 _ReleaseMutex@4 _ReleaseSemaphore@12 _ReleaseSemaphore@12 _RemoveDirectoryA@4 _RemoveDirectoryA@4 _RemoveDirectoryW@4 _RemoveDirectoryW@4 _RemoveVectoredContinueHandler@4 _RemoveVectoredContinueHandler@4 _RemoveVectoredExceptionHandler@4 _RemoveVectoredExceptionHandler@4 _ReplaceFile@24 _ReplaceFile@24 _ReplaceFileA@24 _ReplaceFileA@24 _ReplaceFileW@24 _ReplaceFileW@24 _RequestDeviceWakeup@4 _RequestDeviceWakeup@4 _RequestWakeupLatency@4 _RequestWakeupLatency@4 _ResetEvent@4 _ResetEvent@4 _ResetWriteWatch@8 _ResetWriteWatch@8 _RestoreLastError@4 _RestoreLastError@4 _ResumeThread@4 _ResumeThread@4 _RtlCaptureContext@4 _RtlCaptureContext@4 _RtlCaptureStackBackTrace@16 _RtlCaptureStackBackTrace@16 _RtlFillMemory@12 _RtlFillMemory@12 _RtlMoveMemory@12 _RtlMoveMemory@12 _RtlUnwind@16 _RtlUnwind@16 _RtlZeroMemory@8 _RtlZeroMemory@8 _ScrollConsoleScreenBufferA@20 _ScrollConsoleScreenBufferA@20 _ScrollConsoleScreenBufferW@20 _ScrollConsoleScreenBufferW@20 _SearchPathA@24 _SearchPathA@24 _SearchPathW@24 _SearchPathW@24 _SetCalendarInfoA@16 _SetCalendarInfoA@16 _SetCalendarInfoW@16 _SetCalendarInfoW@16 _SetCommBreak@4 _SetCommBreak@4 _SetCommConfig@12 _SetCommConfig@12 _SetCommMask@8 _SetCommMask@8 _SetCommState@8 _SetCommState@8 _SetCommTimeouts@8 _SetCommTimeouts@8 _SetComputerNameA@4 _SetComputerNameA@4 _SetComputerNameExA@8 _SetComputerNameExA@8 _SetComputerNameExW@8 _SetComputerNameExW@8 _SetComputerNameW@4 _SetComputerNameW@4 _SetConsoleActiveScreenBuffer@4 _SetConsoleActiveScreenBuffer@4 _SetConsoleCP@4 _SetConsoleCP@4 _SetConsoleCtrlHandler@8 _SetConsoleCtrlHandler@8 _SetConsoleCursor@8 _SetConsoleCursor@8 _SetConsoleCursorInfo@8 _SetConsoleCursorInfo@8 _SetConsoleCursorPosition@8 _SetConsoleCursorPosition@8 _SetConsoleMode@8 _SetConsoleMode@8 _SetConsoleOutputCP@4 _SetConsoleOutputCP@4 _SetConsoleScreenBufferSize@8 _SetConsoleScreenBufferSize@8 _SetConsoleTextAttribute@8 _SetConsoleTextAttribute@8 _SetConsoleTitleA@4 _SetConsoleTitleA@4 _SetConsoleTitleW@4 _SetConsoleTitleW@4 _SetConsoleWindowInfo@12 _SetConsoleWindowInfo@12 _SetCriticalSectionSpinCount@8 _SetCriticalSectionSpinCount@8 _SetCurrentDirectoryA@4 _SetCurrentDirectoryA@4 _SetCurrentDirectoryW@4 _SetCurrentDirectoryW@4 _SetDefaultCommConfigA@12 _SetDefaultCommConfigA@12 _SetDefaultCommConfigW@12 _SetDefaultCommConfigW@12 _SetDllDirectoryA@4 _SetDllDirectoryA@4 _SetDllDirectoryW@4 _SetDllDirectoryW@4 _SetEndOfFile@4 _SetEndOfFile@4 _SetEnvironmentStringsA@4 _SetEnvironmentStringsA@4 _SetEnvironmentStringsW@4 _SetEnvironmentStringsW@4 _SetEnvironmentVariableA@8 _SetEnvironmentVariableA@8 _SetEnvironmentVariableW@8 _SetEnvironmentVariableW@8 _SetErrorMode@4 _SetErrorMode@4 _SetEvent@4 _SetEvent@4 _SetFileApisToANSI@0 _SetFileApisToANSI@0 _SetFileApisToOEM@0 _SetFileApisToOEM@0 _SetFileAttributesA@8 _SetFileAttributesA@8 _SetFileAttributesW@8 _SetFileAttributesW@8 _SetFilePointer@16 _SetFilePointer@16 _SetFilePointerEx@20 _SetFilePointerEx@20 _SetFileShortNameA@8 _SetFileShortNameA@8 _SetFileShortNameW@8 _SetFileShortNameW@8 _SetFileTime@16 _SetFileTime@16 _SetFileValidData@12 _SetFileValidData@12 _SetFirmwareEnvironmentVariableA@16 _SetFirmwareEnvironmentVariableA@16 _SetFirmwareEnvironmentVariableW@16 _SetFirmwareEnvironmentVariableW@16 _SetHandleCount@4 _SetHandleCount@4 _SetHandleInformation@12 _SetHandleInformation@12 _SetInformationJobObject@16 _SetInformationJobObject@16 _SetLastError@4 _SetLastError@4 _SetLocalTime@4 _SetLocalTime@4 _SetLocaleInfoA@12 _SetLocaleInfoA@12 _SetLocaleInfoW@12 _SetLocaleInfoW@12 _SetMailslotInfo@8 _SetMailslotInfo@8 _SetMessageWaitingIndicator@8 _SetMessageWaitingIndicator@8 _SetNamedPipeHandleState@16 _SetNamedPipeHandleState@16 _SetPriorityClass@8 _SetPriorityClass@8 _SetProcessAffinityMask@8 _SetProcessAffinityMask@8 _SetProcessPriorityBoost@8 _SetProcessPriorityBoost@8 _SetProcessShutdownParameters@8 _SetProcessShutdownParameters@8 _SetProcessWorkingSetSize@12 _SetProcessWorkingSetSize@12 _SetProcessWorkingSetSizeEx@16 _SetProcessWorkingSetSizeEx@16 _SetStdHandle@8 _SetStdHandle@8 _SetSystemFileCacheSize@12 _SetSystemFileCacheSize@12 _SetSystemPowerState@8 _SetSystemPowerState@8 _SetSystemTime@4 _SetSystemTime@4 _SetSystemTimeAdjustment@8 _SetSystemTimeAdjustment@8 _SetTapeParameters@12 _SetTapeParameters@12 _SetTapePosition@24 _SetTapePosition@24 _SetThreadAffinityMask@8 _SetThreadAffinityMask@8 _SetThreadContext@8 _SetThreadContext@8 _SetThreadExecutionState@4 _SetThreadExecutionState@4 _SetThreadIdealProcessor@8 _SetThreadIdealProcessor@8 _SetThreadLocale@4 _SetThreadLocale@4 _SetThreadPriority@8 _SetThreadPriority@8 _SetThreadPriorityBoost@8 _SetThreadPriorityBoost@8 _SetThreadStackGuarantee@4 _SetThreadStackGuarantee@4 _SetTimeZoneInformation@4 _SetTimeZoneInformation@4 _SetTimerQueueTimer@24 _SetTimerQueueTimer@24 _SetUnhandledExceptionFilter@4 _SetUnhandledExceptionFilter@4 _SetUserGeoID@4 _SetUserGeoID@4 _SetVolumeLabelA@8 _SetVolumeLabelA@8 _SetVolumeLabelW@8 _SetVolumeLabelW@8 _SetVolumeMountPointA@8 _SetVolumeMountPointA@8 _SetVolumeMountPointW@8 _SetVolumeMountPointW@8 _SetWaitableTimer@24 _SetWaitableTimer@24 _SetupComm@12 _SetupComm@12 _SignalObjectAndWait@16 _SignalObjectAndWait@16 _SizeofResource@8 _SizeofResource@8 _Sleep@4 _Sleep@4 _SleepEx@8 _SleepEx@8 _SuspendThread@4 _SuspendThread@4 _SwitchToFiber@4 _SwitchToFiber@4 _SwitchToThread@0 _SwitchToThread@0 _SystemTimeToFileTime@8 _SystemTimeToFileTime@8 _SystemTimeToTzSpecificLocalTime@12 _SystemTimeToTzSpecificLocalTime@12 _TerminateJobObject@8 _TerminateJobObject@8 _TerminateProcess@8 _TerminateProcess@8 _TerminateThread@8 _TerminateThread@8 _Thread32First@8 _Thread32First@8 _Thread32Next@8 _Thread32Next@8 _TlsAlloc@0 _TlsAlloc@0 _TlsFree@4 _TlsFree@4 _TlsGetValue@4 _TlsGetValue@4 _TlsSetValue@8 _TlsSetValue@8 _Toolhelp32ReadProcessMemory@20 _Toolhelp32ReadProcessMemory@20 _TransactNamedPipe@28 _TransactNamedPipe@28 _TransmitCommChar@8 _TransmitCommChar@8 _TryEnterCriticalSection@4 _TryEnterCriticalSection@4 _TzSpecificLocalTimeToSystemTime@12 _TzSpecificLocalTimeToSystemTime@12 _UnhandledExceptionFilter@4 _UnhandledExceptionFilter@4 _UnlockFile@20 _UnlockFile@20 _UnlockFileEx@20 _UnlockFileEx@20 _UnmapViewOfFile@4 _UnmapViewOfFile@4 _UnregisterWait@4 _UnregisterWait@4 _UnregisterWaitEx@8 _UnregisterWaitEx@8 _UpdateResourceA@24 _UpdateResourceA@24 _UpdateResourceW@24 _UpdateResourceW@24 _VerLanguageNameA@12 _VerLanguageNameA@12 _VerLanguageNameW@12 _VerLanguageNameW@12 _VerSetConditionMask@16 _VerSetConditionMask@16 _VerifyVersionInfoA@16 _VerifyVersionInfoA@16 _VerifyVersionInfoW@16 _VerifyVersionInfoW@16 _VirtualAlloc@16 _VirtualAlloc@16 _VirtualAllocEx@20 _VirtualAllocEx@20 _VirtualFree@12 _VirtualFree@12 _VirtualFreeEx@16 _VirtualFreeEx@16 _VirtualLock@8 _VirtualLock@8 _VirtualProtect@16 _VirtualProtect@16 _VirtualProtectEx@20 _VirtualProtectEx@20 _VirtualQuery@12 _VirtualQuery@12 _VirtualQueryEx@16 _VirtualQueryEx@16 _VirtualUnlock@8 _VirtualUnlock@8 _WTSGetActiveConsoleSessionId@0 _WTSGetActiveConsoleSessionId@0 _WaitCommEvent@12 _WaitCommEvent@12 _WaitForDebugEvent@8 _WaitForDebugEvent@8 _WaitForMultipleObjects@16 _WaitForMultipleObjects@16 _WaitForMultipleObjectsEx@20 _WaitForMultipleObjectsEx@20 _WaitForSingleObject@8 _WaitForSingleObject@8 _WaitForSingleObjectEx@12 _WaitForSingleObjectEx@12 _WaitNamedPipeA@8 _WaitNamedPipeA@8 _WaitNamedPipeW@8 _WaitNamedPipeW@8 _WideCharToMultiByte@32 _WideCharToMultiByte@32 _WinExec@8 _WinExec@8 _Wow64DisableWow64FsRedirection@4 _Wow64DisableWow64FsRedirection@4 _Wow64EnableWow64FsRedirection@4 _Wow64EnableWow64FsRedirection@4 _Wow64RevertWow64FsRedirection@4 _Wow64RevertWow64FsRedirection@4 _WriteConsoleA@20 _WriteConsoleA@20 _WriteConsoleInputA@16 _WriteConsoleInputA@16 _WriteConsoleInputW@16 _WriteConsoleInputW@16 _WriteConsoleOutputA@20 _WriteConsoleOutputA@20 _WriteConsoleOutputAttribute@20 _WriteConsoleOutputAttribute@20 _WriteConsoleOutputCharacterA@20 _WriteConsoleOutputCharacterA@20 _WriteConsoleOutputCharacterW@20 _WriteConsoleOutputCharacterW@20 _WriteConsoleOutputW@20 _WriteConsoleOutputW@20 _WriteConsoleW@20 _WriteConsoleW@20 _WriteFile@20 _WriteFile@20 _WriteFileEx@20 _WriteFileEx@20 _WriteFileGather@20 _WriteFileGather@20 _WritePrivateProfileSectionA@12 _WritePrivateProfileSectionA@12 _WritePrivateProfileSectionW@12 _WritePrivateProfileSectionW@12 _WritePrivateProfileStringA@16 _WritePrivateProfileStringA@16 _WritePrivateProfileStringW@16 _WritePrivateProfileStringW@16 _WritePrivateProfileStructA@20 _WritePrivateProfileStructA@20 _WritePrivateProfileStructW@20 _WritePrivateProfileStructW@20 _WriteProcessMemory@20 _WriteProcessMemory@20 _WriteProfileSectionA@8 _WriteProfileSectionA@8 _WriteProfileSectionW@8 _WriteProfileSectionW@8 _WriteProfileStringA@12 _WriteProfileStringA@12 _WriteProfileStringW@12 _WriteProfileStringW@12 _WriteTapemark@16 _WriteTapemark@16 _ZombifyActCtx@4 _ZombifyActCtx@4 __hread@12 __hread@12 __hwrite@12 __hwrite@12 __lclose@4 __lclose@4 __lcreat@8 __lcreat@8 __llseek@12 __llseek@12 __lopen@8 __lopen@8 __lread@12 __lread@12 __lwrite@12 __lwrite@12 _lstrcat@8 _lstrcat@8 _lstrcatA@8 _lstrcatA@8 _lstrcatW@8 _lstrcatW@8 _lstrcmp@8 _lstrcmp@8 _lstrcmpA@8 _lstrcmpA@8 _lstrcmpW@8 _lstrcmpW@8 _lstrcmpi@8 _lstrcmpi@8 _lstrcmpiA@8 _lstrcmpiA@8 _lstrcmpiW@8 _lstrcmpiW@8 _lstrcpy@8 _lstrcpy@8 _lstrcpyA@8 _lstrcpyA@8 _lstrcpyW@8 _lstrcpyW@8 _lstrcpyn@12 _lstrcpyn@12 _lstrcpynA@12 _lstrcpynA@12 _lstrcpynW@12 _lstrcpynW@12 _lstrlen@4 _lstrlen@4 _lstrlenA@4 _lstrlenA@4 _lstrlenW@4 _lstrlenW@4 kbuild-3149/src/lib/kStuff/kProfiler2/prfcore.h.h0000644000175000017500000003303413252530254021565 0ustar locutuslocutus/* $Id: prfcore.h.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kProfiler Mark 2 - Core Header Template. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /** @def KPRF_NAME * Mixed case name macro. */ #ifndef KPRF_NAME # define KPRF_NAME(Name) Name #endif /** @def KPRF_TYPE * Upper case type name macro. */ #ifndef KPRF_TYPE # define KPRF_TYPE(Prefix,Name) Prefix##Name #endif /** @type KPRF_DECL_FUNC * The calling convention used. */ #ifndef KPRF_DECL_FUNC # define KPRF_DECL_FUNC(type, name) type name #endif /** @def KPRF_BITS * The bitsize of the format. */ #ifndef KPRF_BITS # define KPRF_BITS 32 #endif /** @type UPTR * The basic unsigned interger pointer type. */ /** @type IPTR * The basic signed interger pointer type. */ #if KPRF_BITS == 16 typedef KU16 KPRF_TYPE(,UPTR); typedef KI16 KPRF_TYPE(,IPTR); #elif KPRF_BITS == 32 typedef KU32 KPRF_TYPE(,UPTR); typedef KI32 KPRF_TYPE(,IPTR); #elif KPRF_BITS == 64 typedef KU64 KPRF_TYPE(,UPTR); typedef KI64 KPRF_TYPE(,IPTR); #else # error "KPRF_BITS has an invalid value. Supported values are 16, 32 and 64." #endif /** @type KPRF_TYPE(P,UPTR) * Pointer to the basic pointer type. */ typedef KPRF_TYPE(,UPTR) *KPRF_TYPE(P,UPTR); /** * Various constants. */ enum KPRF_TYPE(,CONSTANTS) { /** Magic for the profiler header. (Unix Epoc) */ KPRF_TYPE(,HDR_MAGIC) = 0x19700101 }; /** * The profile data header. */ typedef struct KPRF_TYPE(,HDR) { /** [0] The magic number for file data. (KPRF_TYPE(,HDR_MAGIC)) */ KU32 u32Magic; /** [4] KPRF_BITS. */ KU32 cFormatBits; /** [8] The base address which all pointers should be relative to. */ KPRF_TYPE(,UPTR) uBasePtr; #if KPRF_BITS <= 16 /** [a] Reserved. */ KU16 u16Reserved; #endif #if KPRF_BITS <= 32 /** [c] Reserved. */ KU32 u32Reserved; #endif /** [10] The size of this data set. */ KU32 cb; /** [10] The allocated data set size. */ KU32 cbAllocated; /** [18] The max number of functions the function table can hold. */ KU32 cMaxFunctions; /** [1c] The current number of functions in the function table. */ KU32 cFunctions; /** [20] The offset of the function table (relative to this header). */ KU32 offFunctions; /** [24] The size of a function entry. */ KU32 cbFunction; /** [28] The max number of bytes the module segments can occupy. */ KU32 cbMaxModSegs; /** [2c] The current size of the module segment records. */ KU32 cbModSegs; /** [30] The offset of the module segment records (relative to this header). */ KU32 offModSegs; /** [34] The max number of threads the thread table can contain. */ KU32 cMaxThreads; /** [38] The current number of threads in the thread table. */ KU32 cThreads; /** [3c] The offset of the thread table (relative to this header). */ KU32 offThreads; /** [40] The size of a thread entry. */ KU32 cbThread; /** [44] The max number of stacks the stack table can contain. */ KU32 cMaxStacks; /** [48] The max number of stacks. * Unlike the other members, the stacks can be reused. It follows that * this count doesn't specify the number of used slots from the start. */ KU32 cStacks; /** [4c] The offset of the thread table (relative to this header). * This is usually 0 in a stored data set. */ KU32 offStacks; /** [50] The size of a stack. */ KU32 cbStack; /** [54] The maxium stack depth. */ KU32 cMaxStackFrames; /** [58] The process commandline. * Might not always apply is will be 0 in those cases. This is normally written * where the stacks used to be. */ KU32 offCommandLine; /** [5c] The length of the command line. (excludes the terminator). */ KU32 cchCommandLine; /** [60] The function lookup table (it contains indexes). * This is sorted by address so that a binary search can be performed. * Access to this table is managed externally, but generally a read/write lock is employed. */ KU32 aiFunctions[1]; } KPRF_TYPE(,HDR); /** Pointer to a profiler data header. */ typedef KPRF_TYPE(,HDR) *KPRF_TYPE(P,HDR); /** Pointer to a const profiler data header. */ typedef const KPRF_TYPE(,HDR) *KPRF_TYPE(PC,HDR); /** * Time statistics. */ typedef struct KPRF_TYPE(,TIMESTAT) /** @todo bad names and descriptions! */ { /** The minimum period */ KU64 volatile MinTicks; /** The maximum period */ KU64 volatile MaxTicks; /** The sum of all periods. */ KU64 volatile SumTicks; } KPRF_TYPE(,TIMESTAT); /** Pointer to time statistics. */ typedef KPRF_TYPE(,TIMESTAT) *KPRF_TYPE(P,TIMESTAT); /** Pointer to const time statistics. */ typedef const KPRF_TYPE(,TIMESTAT) *KPRF_TYPE(PC,TIMESTAT); /** * A Module Segment. */ typedef struct KPRF_TYPE(,MODSEG) { /** The address of the segment. (relative address) */ KPRF_TYPE(,UPTR) uBasePtr; /** The size of the segment minus one (so the entire address space can be covered). */ KPRF_TYPE(,UPTR) cbSegmentMinusOne; /** The segment number. (0 based) */ KU32 iSegment; /** Flag indicating whether this segment is loaded or not. * (A 16-bit value was choosen out of convenience, all that's stored is 0 or 1 anyway.) */ KU16 fLoaded; /** The length of the path. * This is used to calculate the length of the record: offsetof(MODSEG, szPath) + cchPath + 1 */ KU16 cchPath; /** The module name. */ char szPath[1]; } KPRF_TYPE(,MODSEG); /** Pointer to a module segment. */ typedef KPRF_TYPE(,MODSEG) *KPRF_TYPE(P,MODSEG); /** Pointer to a const module segment. */ typedef const KPRF_TYPE(,MODSEG) *KPRF_TYPE(PC,MODSEG); /** * The profiler data for a function. */ typedef struct KPRF_TYPE(,FUNC) { /** The entry address of the function. (relative address) * This is the return address of the entry hook (_mcount, _penter, _ProfileHook32, ...). */ KPRF_TYPE(,UPTR) uEntryPtr; /** Offset (relative to the profiler header) of the module segment to which this function belongs. */ KU32 offModSeg; /** The number times on the stack. */ KU64 volatile cOnStack; /** The number of calls made from this function. */ KU64 volatile cCalls; /** Time on stack. */ KPRF_TYPE(,TIMESTAT) OnStack; /** Time on top of the stack, i.e. executing. */ KPRF_TYPE(,TIMESTAT) OnTopOfStack; /** @todo recursion */ } KPRF_TYPE(,FUNC); /** Pointer to the profiler data for a function. */ typedef KPRF_TYPE(,FUNC) *KPRF_TYPE(P,FUNC); /** Pointer to the const profiler data for a function. */ typedef const KPRF_TYPE(,FUNC) *KPRF_TYPE(PC,FUNC); /** * Stack frame. */ typedef struct KPRF_TYPE(,FRAME) { /** The accumulated overhead. * Over head is accumulated by the parent frame when a child is poped off the stack. */ KU64 OverheadTicks; /** The current (top of stack) overhead. */ KU64 CurOverheadTicks; /** The accumulated sleep ticks. * It's possible to notify the profiler that the thread is being put into a wait/sleep/yield * state. The time spent sleeping is transfered to the parent frame when poping of a child one. */ KU64 SleepTicks; /** The start of the on-stack period. */ KU64 OnStackStart; /** The accumulated time on top (excludes overhead (sleep doesn't apply here obviously)). */ KU64 OnTopOfStackTicks; /** The start of the current on-top-of-stack period. * This is also to mark the start of a sleeping period, the ResumeThread function will always * treat it as the start of the suspend period. */ KU64 OnTopOfStackStart; /** The number of calls made from this stack frame. */ KU64 cCalls; /** Stack address of this frame. * This is used to detect throw and longjmp, and is also used to deal with overflow. (relative address) */ KPRF_TYPE(,UPTR) uFramePtr; /** Offset (relative to the profiler header) to the function record. * This is 0 if we're out of function space. */ KU32 offFunction; } KPRF_TYPE(,FRAME); /** Pointer to a stack frame. */ typedef KPRF_TYPE(,FRAME) *KPRF_TYPE(P,FRAME); /** Pointer to a const stack frame. */ typedef const KPRF_TYPE(,FRAME) *KPRF_TYPE(PC,FRAME); /** * Stack. */ typedef struct KPRF_TYPE(,STACK) { /** The offset (relative to the profiler header) of the thread owning the stack. * This is zero if not in use, and non-zero if in use. */ KU32 offThread; /** The number of active stack frames. */ KU32 cFrames; /** The stack frames. * The actual size of this array is specified in the header. */ KPRF_TYPE(,FRAME) aFrames[1]; } KPRF_TYPE(,STACK); /** Pointer to a stack. */ typedef KPRF_TYPE(,STACK) *KPRF_TYPE(P,STACK); /** Pointer to a const stack. */ typedef const KPRF_TYPE(,STACK) *KPRF_TYPE(PC,STACK); /** * The thread state. */ typedef enum KPRF_TYPE(,THREADSTATE) { /** The thread hasn't been used yet. */ KPRF_TYPE(,THREADSTATE_UNUSED) = 0, /** The thread is activly being profiled. * A thread is added in the suspended state and then activated when * starting to execute the first function. */ KPRF_TYPE(,THREADSTATE_ACTIVE), /** The thread is currently suspended from profiling. * Upon entering profiler code the thread is suspended, it's reactivated * upon normal return. */ KPRF_TYPE(,THREADSTATE_SUSPENDED), /** The thread is currently suspended due of stack overflow. * When we overflow the stack frame array, the thread enter the overflow state. In this * state nothing is profiled but we keep looking for the exit of the top frame. */ KPRF_TYPE(,THREADSTATE_OVERFLOWED), /** The thread is terminated. * When we received a thread termination notification the thread is unwinded, statistics * updated and the state changed to terminated. A terminated thread cannot be revivied. */ KPRF_TYPE(,THREADSTATE_TERMINATED), /** Ensure 32-bit size. */ KPRF_TYPE(,THREADSTATE_32BIT_HACK) = 0x7fffffff } KPRF_TYPE(,THREADSTATE); /** * Thread statistics and stack. */ typedef struct KPRF_TYPE(,THREAD) { /** The native thread id. */ KU64 ThreadId; /** The thread name. (optional) */ char szName[32]; /** The thread current thread state. */ KPRF_TYPE(,THREADSTATE) enmState; /** Alignment. */ KPRF_TYPE(,THREADSTATE) Reserved0; /** The base pointer of the thread stack. (relative address) */ KPRF_TYPE(,UPTR) uStackBasePtr; /** The maximum depth of the thread stack (bytes). */ KPRF_TYPE(,UPTR) cbMaxStack; /** The number of calls done by this thread. */ KU64 cCalls; /** The number of times the stack overflowed. */ KU64 cOverflows; /** The number of times stack entries has been rejected because of a stack switch. */ KU64 cStackSwitchRejects; /** The number of times the stack has been unwinded more than one frame. */ KU64 cUnwinds; /** The profiled ticks. (This does not include sleep or overhead ticks.) * This is the accumulated on-stack values for the final stack frames. */ KU64 ProfiledTicks; /** The accumulated overhead of this thread. */ KU64 OverheadTicks; /** The accumulated sleep ticks for this thread. * See KPRF_TYPE(,FRAME)::SleepTicks for details. */ KU64 SleepTicks; /** The offset of the stack. */ KU32 offStack; } KPRF_TYPE(,THREAD); /** Pointer to a thread. */ typedef KPRF_TYPE(,THREAD) *KPRF_TYPE(P,THREAD); /** Pointer to a const thread. */ typedef const KPRF_TYPE(,THREAD) *KPRF_TYPE(PC,THREAD); kbuild-3149/src/lib/kStuff/kProfiler2/tst.c0000644000175000017500000000127413252530254020505 0ustar locutuslocutus#include #ifdef _MSC_VER void __cdecl _penter(void); void __cdecl _pexit(void); __declspec(naked) int naked(void) { __asm { call _penter call _pexit xor eax, eax ret } } #endif int bar(void) { unsigned i; for (i = 0; i < 1000; i += 7) i += i & 1; return i; } int foo(void) { unsigned i, rc = 0; for (i = 0; i < 1000; i++) rc += bar(); #ifdef _MSC_VER for (; i < 2000; i++) rc += naked(); #endif return i; } int main() { int rc; printf("hello"); fflush(stdout); rc = foo(); printf("world\n"); return rc; } kbuild-3149/src/lib/kStuff/kProfiler2/kPrf2WinApiWrappersImp-amd64.def0000644000175000017500000011753413252530254025415 0ustar locutuslocutusLIBRARY kPrf2WinApiWrappers EXPORTS ActivateActCtx=kPrf2Wrap_ActivateActCtx AddAtomA=kPrf2Wrap_AddAtomA AddAtomW=kPrf2Wrap_AddAtomW AddConsoleAliasA=kPrf2Wrap_AddConsoleAliasA AddConsoleAliasW=kPrf2Wrap_AddConsoleAliasW AddRefActCtx=kPrf2Wrap_AddRefActCtx AddVectoredContinueHandler=kPrf2Wrap_AddVectoredContinueHandler AddVectoredExceptionHandler=kPrf2Wrap_AddVectoredExceptionHandler AllocConsole=kPrf2Wrap_AllocConsole AllocateUserPhysicalPages=kPrf2Wrap_AllocateUserPhysicalPages AreFileApisANSI=kPrf2Wrap_AreFileApisANSI AssignProcessToJobObject=kPrf2Wrap_AssignProcessToJobObject AttachConsole=kPrf2Wrap_AttachConsole BackupRead=kPrf2Wrap_BackupRead BackupSeek=kPrf2Wrap_BackupSeek BackupWrite=kPrf2Wrap_BackupWrite Beep=kPrf2Wrap_Beep BeginUpdateResourceA=kPrf2Wrap_BeginUpdateResourceA BeginUpdateResourceW=kPrf2Wrap_BeginUpdateResourceW BindIoCompletionCallback=kPrf2Wrap_BindIoCompletionCallback BuildCommDCBA=kPrf2Wrap_BuildCommDCBA BuildCommDCBAndTimeoutsA=kPrf2Wrap_BuildCommDCBAndTimeoutsA BuildCommDCBAndTimeoutsW=kPrf2Wrap_BuildCommDCBAndTimeoutsW BuildCommDCBW=kPrf2Wrap_BuildCommDCBW CallNamedPipeA=kPrf2Wrap_CallNamedPipeA CallNamedPipeW=kPrf2Wrap_CallNamedPipeW CancelDeviceWakeupRequest=kPrf2Wrap_CancelDeviceWakeupRequest CancelIo=kPrf2Wrap_CancelIo CancelTimerQueueTimer=kPrf2Wrap_CancelTimerQueueTimer CancelWaitableTimer=kPrf2Wrap_CancelWaitableTimer ChangeTimerQueueTimer=kPrf2Wrap_ChangeTimerQueueTimer CheckNameLegalDOS8Dot3A=kPrf2Wrap_CheckNameLegalDOS8Dot3A CheckNameLegalDOS8Dot3W=kPrf2Wrap_CheckNameLegalDOS8Dot3W CheckRemoteDebuggerPresent=kPrf2Wrap_CheckRemoteDebuggerPresent ClearCommBreak=kPrf2Wrap_ClearCommBreak ClearCommError=kPrf2Wrap_ClearCommError CloseHandle=kPrf2Wrap_CloseHandle CommConfigDialogA=kPrf2Wrap_CommConfigDialogA CommConfigDialogW=kPrf2Wrap_CommConfigDialogW CompareFileTime=kPrf2Wrap_CompareFileTime CompareStringA=kPrf2Wrap_CompareStringA CompareStringW=kPrf2Wrap_CompareStringW ConnectNamedPipe=kPrf2Wrap_ConnectNamedPipe ContinueDebugEvent=kPrf2Wrap_ContinueDebugEvent ConvertDefaultLocale=kPrf2Wrap_ConvertDefaultLocale ConvertFiberToThread=kPrf2Wrap_ConvertFiberToThread ConvertThreadToFiber=kPrf2Wrap_ConvertThreadToFiber ConvertThreadToFiberEx=kPrf2Wrap_ConvertThreadToFiberEx CopyFileA=kPrf2Wrap_CopyFileA CopyFileExA=kPrf2Wrap_CopyFileExA CopyFileExW=kPrf2Wrap_CopyFileExW CopyFileW=kPrf2Wrap_CopyFileW CreateActCtxA=kPrf2Wrap_CreateActCtxA CreateActCtxW=kPrf2Wrap_CreateActCtxW CreateConsoleScreenBuffer=kPrf2Wrap_CreateConsoleScreenBuffer CreateDirectoryA=kPrf2Wrap_CreateDirectoryA CreateDirectoryExA=kPrf2Wrap_CreateDirectoryExA CreateDirectoryExW=kPrf2Wrap_CreateDirectoryExW CreateDirectoryW=kPrf2Wrap_CreateDirectoryW CreateEventA=kPrf2Wrap_CreateEventA CreateEventW=kPrf2Wrap_CreateEventW CreateFiber=kPrf2Wrap_CreateFiber CreateFiberEx=kPrf2Wrap_CreateFiberEx CreateFileA=kPrf2Wrap_CreateFileA CreateFileMappingA=kPrf2Wrap_CreateFileMappingA CreateFileMappingW=kPrf2Wrap_CreateFileMappingW CreateFileW=kPrf2Wrap_CreateFileW CreateHardLinkA=kPrf2Wrap_CreateHardLinkA CreateHardLinkW=kPrf2Wrap_CreateHardLinkW CreateIoCompletionPort=kPrf2Wrap_CreateIoCompletionPort CreateJobObjectA=kPrf2Wrap_CreateJobObjectA CreateJobObjectW=kPrf2Wrap_CreateJobObjectW CreateJobSet=kPrf2Wrap_CreateJobSet CreateMailslotA=kPrf2Wrap_CreateMailslotA CreateMailslotW=kPrf2Wrap_CreateMailslotW CreateMemoryResourceNotification=kPrf2Wrap_CreateMemoryResourceNotification CreateMutexA=kPrf2Wrap_CreateMutexA CreateMutexW=kPrf2Wrap_CreateMutexW CreateNamedPipeA=kPrf2Wrap_CreateNamedPipeA CreateNamedPipeW=kPrf2Wrap_CreateNamedPipeW CreatePipe=kPrf2Wrap_CreatePipe CreateProcessA=kPrf2Wrap_CreateProcessA CreateProcessW=kPrf2Wrap_CreateProcessW CreateRemoteThread=kPrf2Wrap_CreateRemoteThread CreateSemaphoreA=kPrf2Wrap_CreateSemaphoreA CreateSemaphoreW=kPrf2Wrap_CreateSemaphoreW CreateTapePartition=kPrf2Wrap_CreateTapePartition CreateThread=kPrf2Wrap_CreateThread CreateTimerQueue=kPrf2Wrap_CreateTimerQueue CreateTimerQueueTimer=kPrf2Wrap_CreateTimerQueueTimer CreateToolhelp32Snapshot=kPrf2Wrap_CreateToolhelp32Snapshot CreateWaitableTimerA=kPrf2Wrap_CreateWaitableTimerA CreateWaitableTimerW=kPrf2Wrap_CreateWaitableTimerW DeactivateActCtx=kPrf2Wrap_DeactivateActCtx DebugActiveProcess=kPrf2Wrap_DebugActiveProcess DebugActiveProcessStop=kPrf2Wrap_DebugActiveProcessStop DebugBreak=kPrf2Wrap_DebugBreak DebugBreakProcess=kPrf2Wrap_DebugBreakProcess DebugSetProcessKillOnExit=kPrf2Wrap_DebugSetProcessKillOnExit DecodePointer=kPrf2Wrap_DecodePointer DecodeSystemPointer=kPrf2Wrap_DecodeSystemPointer DefineDosDeviceA=kPrf2Wrap_DefineDosDeviceA DefineDosDeviceW=kPrf2Wrap_DefineDosDeviceW DeleteAtom=kPrf2Wrap_DeleteAtom DeleteCriticalSection=kPrf2Wrap_DeleteCriticalSection DeleteFiber=kPrf2Wrap_DeleteFiber DeleteFileA=kPrf2Wrap_DeleteFileA DeleteFileW=kPrf2Wrap_DeleteFileW DeleteTimerQueue=kPrf2Wrap_DeleteTimerQueue DeleteTimerQueueEx=kPrf2Wrap_DeleteTimerQueueEx DeleteTimerQueueTimer=kPrf2Wrap_DeleteTimerQueueTimer DeleteVolumeMountPointA=kPrf2Wrap_DeleteVolumeMountPointA DeleteVolumeMountPointW=kPrf2Wrap_DeleteVolumeMountPointW DeviceIoControl=kPrf2Wrap_DeviceIoControl DisableThreadLibraryCalls=kPrf2Wrap_DisableThreadLibraryCalls DisconnectNamedPipe=kPrf2Wrap_DisconnectNamedPipe DnsHostnameToComputerNameA=kPrf2Wrap_DnsHostnameToComputerNameA DnsHostnameToComputerNameW=kPrf2Wrap_DnsHostnameToComputerNameW DosDateTimeToFileTime=kPrf2Wrap_DosDateTimeToFileTime DuplicateHandle=kPrf2Wrap_DuplicateHandle EncodePointer=kPrf2Wrap_EncodePointer EncodeSystemPointer=kPrf2Wrap_EncodeSystemPointer EndUpdateResourceA=kPrf2Wrap_EndUpdateResourceA EndUpdateResourceW=kPrf2Wrap_EndUpdateResourceW EnterCriticalSection=kPrf2Wrap_EnterCriticalSection EnumCalendarInfoA=kPrf2Wrap_EnumCalendarInfoA EnumCalendarInfoExA=kPrf2Wrap_EnumCalendarInfoExA EnumCalendarInfoExW=kPrf2Wrap_EnumCalendarInfoExW EnumCalendarInfoW=kPrf2Wrap_EnumCalendarInfoW EnumDateFormatsA=kPrf2Wrap_EnumDateFormatsA EnumDateFormatsExA=kPrf2Wrap_EnumDateFormatsExA EnumDateFormatsExW=kPrf2Wrap_EnumDateFormatsExW EnumDateFormatsW=kPrf2Wrap_EnumDateFormatsW EnumLanguageGroupLocalesA=kPrf2Wrap_EnumLanguageGroupLocalesA EnumLanguageGroupLocalesW=kPrf2Wrap_EnumLanguageGroupLocalesW EnumResourceLanguagesA=kPrf2Wrap_EnumResourceLanguagesA EnumResourceLanguagesW=kPrf2Wrap_EnumResourceLanguagesW EnumResourceNamesA=kPrf2Wrap_EnumResourceNamesA EnumResourceNamesW=kPrf2Wrap_EnumResourceNamesW EnumResourceTypesA=kPrf2Wrap_EnumResourceTypesA EnumResourceTypesW=kPrf2Wrap_EnumResourceTypesW EnumSystemCodePagesA=kPrf2Wrap_EnumSystemCodePagesA EnumSystemCodePagesW=kPrf2Wrap_EnumSystemCodePagesW EnumSystemFirmwareTables=kPrf2Wrap_EnumSystemFirmwareTables EnumSystemGeoID=kPrf2Wrap_EnumSystemGeoID EnumSystemLanguageGroupsA=kPrf2Wrap_EnumSystemLanguageGroupsA EnumSystemLanguageGroupsW=kPrf2Wrap_EnumSystemLanguageGroupsW EnumSystemLocalesA=kPrf2Wrap_EnumSystemLocalesA EnumSystemLocalesW=kPrf2Wrap_EnumSystemLocalesW EnumTimeFormatsA=kPrf2Wrap_EnumTimeFormatsA EnumTimeFormatsW=kPrf2Wrap_EnumTimeFormatsW EnumUILanguagesA=kPrf2Wrap_EnumUILanguagesA EnumUILanguagesW=kPrf2Wrap_EnumUILanguagesW EraseTape=kPrf2Wrap_EraseTape EscapeCommFunction=kPrf2Wrap_EscapeCommFunction ExitProcess=kPrf2Wrap_ExitProcess ExitThread=kPrf2Wrap_ExitThread ExpandEnvironmentStringsA=kPrf2Wrap_ExpandEnvironmentStringsA ExpandEnvironmentStringsW=kPrf2Wrap_ExpandEnvironmentStringsW FatalAppExitA=kPrf2Wrap_FatalAppExitA FatalAppExitW=kPrf2Wrap_FatalAppExitW FatalExit=kPrf2Wrap_FatalExit FileTimeToDosDateTime=kPrf2Wrap_FileTimeToDosDateTime FileTimeToLocalFileTime=kPrf2Wrap_FileTimeToLocalFileTime FileTimeToSystemTime=kPrf2Wrap_FileTimeToSystemTime FillConsoleOutputAttribute=kPrf2Wrap_FillConsoleOutputAttribute FillConsoleOutputCharacterA=kPrf2Wrap_FillConsoleOutputCharacterA FillConsoleOutputCharacterW=kPrf2Wrap_FillConsoleOutputCharacterW FindActCtxSectionGuid=kPrf2Wrap_FindActCtxSectionGuid FindActCtxSectionStringA=kPrf2Wrap_FindActCtxSectionStringA FindActCtxSectionStringW=kPrf2Wrap_FindActCtxSectionStringW FindAtomA=kPrf2Wrap_FindAtomA FindAtomW=kPrf2Wrap_FindAtomW FindClose=kPrf2Wrap_FindClose FindCloseChangeNotification=kPrf2Wrap_FindCloseChangeNotification FindFirstChangeNotificationA=kPrf2Wrap_FindFirstChangeNotificationA FindFirstChangeNotificationW=kPrf2Wrap_FindFirstChangeNotificationW FindFirstFileA=kPrf2Wrap_FindFirstFileA FindFirstFileExA=kPrf2Wrap_FindFirstFileExA FindFirstFileExW=kPrf2Wrap_FindFirstFileExW FindFirstFileW=kPrf2Wrap_FindFirstFileW FindFirstStreamW=kPrf2Wrap_FindFirstStreamW FindFirstVolumeA=kPrf2Wrap_FindFirstVolumeA FindFirstVolumeMountPointA=kPrf2Wrap_FindFirstVolumeMountPointA FindFirstVolumeMountPointW=kPrf2Wrap_FindFirstVolumeMountPointW FindFirstVolumeW=kPrf2Wrap_FindFirstVolumeW FindNextChangeNotification=kPrf2Wrap_FindNextChangeNotification FindNextFileA=kPrf2Wrap_FindNextFileA FindNextFileW=kPrf2Wrap_FindNextFileW FindNextStreamW=kPrf2Wrap_FindNextStreamW FindNextVolumeA=kPrf2Wrap_FindNextVolumeA FindNextVolumeMountPointA=kPrf2Wrap_FindNextVolumeMountPointA FindNextVolumeMountPointW=kPrf2Wrap_FindNextVolumeMountPointW FindNextVolumeW=kPrf2Wrap_FindNextVolumeW FindResourceA=kPrf2Wrap_FindResourceA FindResourceExA=kPrf2Wrap_FindResourceExA FindResourceExW=kPrf2Wrap_FindResourceExW FindResourceW=kPrf2Wrap_FindResourceW FindVolumeClose=kPrf2Wrap_FindVolumeClose FindVolumeMountPointClose=kPrf2Wrap_FindVolumeMountPointClose FlsAlloc=kPrf2Wrap_FlsAlloc FlsFree=kPrf2Wrap_FlsFree FlsGetValue=kPrf2Wrap_FlsGetValue FlsSetValue=kPrf2Wrap_FlsSetValue FlushConsoleInputBuffer=kPrf2Wrap_FlushConsoleInputBuffer FlushFileBuffers=kPrf2Wrap_FlushFileBuffers FlushInstructionCache=kPrf2Wrap_FlushInstructionCache FlushViewOfFile=kPrf2Wrap_FlushViewOfFile FoldStringA=kPrf2Wrap_FoldStringA FoldStringW=kPrf2Wrap_FoldStringW FormatMessageA=kPrf2Wrap_FormatMessageA FormatMessageW=kPrf2Wrap_FormatMessageW FreeConsole=kPrf2Wrap_FreeConsole FreeEnvironmentStringsA=kPrf2Wrap_FreeEnvironmentStringsA FreeEnvironmentStringsW=kPrf2Wrap_FreeEnvironmentStringsW FreeLibrary=kPrf2Wrap_FreeLibrary FreeLibraryAndExitThread=kPrf2Wrap_FreeLibraryAndExitThread FreeResource=kPrf2Wrap_FreeResource FreeUserPhysicalPages=kPrf2Wrap_FreeUserPhysicalPages GenerateConsoleCtrlEvent=kPrf2Wrap_GenerateConsoleCtrlEvent GetACP=kPrf2Wrap_GetACP GetAtomNameA=kPrf2Wrap_GetAtomNameA GetAtomNameW=kPrf2Wrap_GetAtomNameW GetBinaryType=kPrf2Wrap_GetBinaryType GetBinaryTypeA=kPrf2Wrap_GetBinaryTypeA GetBinaryTypeW=kPrf2Wrap_GetBinaryTypeW GetCPInfo=kPrf2Wrap_GetCPInfo GetCPInfoExA=kPrf2Wrap_GetCPInfoExA GetCPInfoExW=kPrf2Wrap_GetCPInfoExW GetCalendarInfoA=kPrf2Wrap_GetCalendarInfoA GetCalendarInfoW=kPrf2Wrap_GetCalendarInfoW GetCommConfig=kPrf2Wrap_GetCommConfig GetCommMask=kPrf2Wrap_GetCommMask GetCommModemStatus=kPrf2Wrap_GetCommModemStatus GetCommProperties=kPrf2Wrap_GetCommProperties GetCommState=kPrf2Wrap_GetCommState GetCommTimeouts=kPrf2Wrap_GetCommTimeouts GetCommandLineA=kPrf2Wrap_GetCommandLineA GetCommandLineW=kPrf2Wrap_GetCommandLineW GetCompressedFileSizeA=kPrf2Wrap_GetCompressedFileSizeA GetCompressedFileSizeW=kPrf2Wrap_GetCompressedFileSizeW GetComputerNameA=kPrf2Wrap_GetComputerNameA GetComputerNameExA=kPrf2Wrap_GetComputerNameExA GetComputerNameExW=kPrf2Wrap_GetComputerNameExW GetComputerNameW=kPrf2Wrap_GetComputerNameW GetConsoleAliasA=kPrf2Wrap_GetConsoleAliasA GetConsoleAliasExesA=kPrf2Wrap_GetConsoleAliasExesA GetConsoleAliasExesLengthA=kPrf2Wrap_GetConsoleAliasExesLengthA GetConsoleAliasExesLengthW=kPrf2Wrap_GetConsoleAliasExesLengthW GetConsoleAliasExesW=kPrf2Wrap_GetConsoleAliasExesW GetConsoleAliasW=kPrf2Wrap_GetConsoleAliasW GetConsoleAliasesA=kPrf2Wrap_GetConsoleAliasesA GetConsoleAliasesLengthA=kPrf2Wrap_GetConsoleAliasesLengthA GetConsoleAliasesLengthW=kPrf2Wrap_GetConsoleAliasesLengthW GetConsoleAliasesW=kPrf2Wrap_GetConsoleAliasesW GetConsoleCP=kPrf2Wrap_GetConsoleCP GetConsoleCursorInfo=kPrf2Wrap_GetConsoleCursorInfo GetConsoleDisplayMode=kPrf2Wrap_GetConsoleDisplayMode GetConsoleFontSize=kPrf2Wrap_GetConsoleFontSize GetConsoleMode=kPrf2Wrap_GetConsoleMode GetConsoleOutputCP=kPrf2Wrap_GetConsoleOutputCP GetConsoleProcessList=kPrf2Wrap_GetConsoleProcessList GetConsoleScreenBufferInfo=kPrf2Wrap_GetConsoleScreenBufferInfo GetConsoleSelectionInfo=kPrf2Wrap_GetConsoleSelectionInfo GetConsoleTitleA=kPrf2Wrap_GetConsoleTitleA GetConsoleTitleW=kPrf2Wrap_GetConsoleTitleW GetConsoleWindow=kPrf2Wrap_GetConsoleWindow GetCurrencyFormatA=kPrf2Wrap_GetCurrencyFormatA GetCurrencyFormatW=kPrf2Wrap_GetCurrencyFormatW GetCurrentActCtx=kPrf2Wrap_GetCurrentActCtx GetCurrentConsoleFont=kPrf2Wrap_GetCurrentConsoleFont GetCurrentDirectoryA=kPrf2Wrap_GetCurrentDirectoryA GetCurrentDirectoryW=kPrf2Wrap_GetCurrentDirectoryW GetCurrentProcess=kPrf2Wrap_GetCurrentProcess GetCurrentProcessId=kPrf2Wrap_GetCurrentProcessId GetCurrentProcessorNumber=kPrf2Wrap_GetCurrentProcessorNumber GetCurrentThread=kPrf2Wrap_GetCurrentThread GetCurrentThreadId=kPrf2Wrap_GetCurrentThreadId GetDateFormatA=kPrf2Wrap_GetDateFormatA GetDateFormatW=kPrf2Wrap_GetDateFormatW GetDefaultCommConfigA=kPrf2Wrap_GetDefaultCommConfigA GetDefaultCommConfigW=kPrf2Wrap_GetDefaultCommConfigW GetDevicePowerState=kPrf2Wrap_GetDevicePowerState GetDiskFreeSpaceA=kPrf2Wrap_GetDiskFreeSpaceA GetDiskFreeSpaceExA=kPrf2Wrap_GetDiskFreeSpaceExA GetDiskFreeSpaceExW=kPrf2Wrap_GetDiskFreeSpaceExW GetDiskFreeSpaceW=kPrf2Wrap_GetDiskFreeSpaceW GetDllDirectoryA=kPrf2Wrap_GetDllDirectoryA GetDllDirectoryW=kPrf2Wrap_GetDllDirectoryW GetDriveTypeA=kPrf2Wrap_GetDriveTypeA GetDriveTypeW=kPrf2Wrap_GetDriveTypeW GetEnvironmentStrings=kPrf2Wrap_GetEnvironmentStrings GetEnvironmentStringsA=kPrf2Wrap_GetEnvironmentStringsA GetEnvironmentStringsW=kPrf2Wrap_GetEnvironmentStringsW GetEnvironmentVariableA=kPrf2Wrap_GetEnvironmentVariableA GetEnvironmentVariableW=kPrf2Wrap_GetEnvironmentVariableW GetExitCodeProcess=kPrf2Wrap_GetExitCodeProcess GetExitCodeThread=kPrf2Wrap_GetExitCodeThread GetFileAttributesA=kPrf2Wrap_GetFileAttributesA GetFileAttributesExA=kPrf2Wrap_GetFileAttributesExA GetFileAttributesExW=kPrf2Wrap_GetFileAttributesExW GetFileAttributesW=kPrf2Wrap_GetFileAttributesW GetFileInformationByHandle=kPrf2Wrap_GetFileInformationByHandle GetFileSize=kPrf2Wrap_GetFileSize GetFileSizeEx=kPrf2Wrap_GetFileSizeEx GetFileTime=kPrf2Wrap_GetFileTime GetFileType=kPrf2Wrap_GetFileType GetFirmwareEnvironmentVariableA=kPrf2Wrap_GetFirmwareEnvironmentVariableA GetFirmwareEnvironmentVariableW=kPrf2Wrap_GetFirmwareEnvironmentVariableW GetFullPathNameA=kPrf2Wrap_GetFullPathNameA GetFullPathNameW=kPrf2Wrap_GetFullPathNameW GetGeoInfoA=kPrf2Wrap_GetGeoInfoA GetGeoInfoW=kPrf2Wrap_GetGeoInfoW GetHandleInformation=kPrf2Wrap_GetHandleInformation GetLargePageMinimum=kPrf2Wrap_GetLargePageMinimum GetLargestConsoleWindowSize=kPrf2Wrap_GetLargestConsoleWindowSize GetLastError=kPrf2Wrap_GetLastError GetLocalTime=kPrf2Wrap_GetLocalTime GetLocaleInfoA=kPrf2Wrap_GetLocaleInfoA GetLocaleInfoW=kPrf2Wrap_GetLocaleInfoW GetLogicalDriveStringsA=kPrf2Wrap_GetLogicalDriveStringsA GetLogicalDriveStringsW=kPrf2Wrap_GetLogicalDriveStringsW GetLogicalDrives=kPrf2Wrap_GetLogicalDrives GetLogicalProcessorInformation=kPrf2Wrap_GetLogicalProcessorInformation GetLongPathNameA=kPrf2Wrap_GetLongPathNameA GetLongPathNameW=kPrf2Wrap_GetLongPathNameW GetMailslotInfo=kPrf2Wrap_GetMailslotInfo GetModuleFileNameA=kPrf2Wrap_GetModuleFileNameA GetModuleFileNameW=kPrf2Wrap_GetModuleFileNameW GetModuleHandleA=kPrf2Wrap_GetModuleHandleA GetModuleHandleExA=kPrf2Wrap_GetModuleHandleExA GetModuleHandleExW=kPrf2Wrap_GetModuleHandleExW GetModuleHandleW=kPrf2Wrap_GetModuleHandleW GetNLSVersion=kPrf2Wrap_GetNLSVersion GetNamedPipeHandleStateA=kPrf2Wrap_GetNamedPipeHandleStateA GetNamedPipeHandleStateW=kPrf2Wrap_GetNamedPipeHandleStateW GetNamedPipeInfo=kPrf2Wrap_GetNamedPipeInfo GetNativeSystemInfo=kPrf2Wrap_GetNativeSystemInfo GetNumaAvailableMemoryNode=kPrf2Wrap_GetNumaAvailableMemoryNode GetNumaHighestNodeNumber=kPrf2Wrap_GetNumaHighestNodeNumber GetNumaNodeProcessorMask=kPrf2Wrap_GetNumaNodeProcessorMask GetNumaProcessorNode=kPrf2Wrap_GetNumaProcessorNode GetNumberFormatA=kPrf2Wrap_GetNumberFormatA GetNumberFormatW=kPrf2Wrap_GetNumberFormatW GetNumberOfConsoleInputEvents=kPrf2Wrap_GetNumberOfConsoleInputEvents GetNumberOfConsoleMouseButtons=kPrf2Wrap_GetNumberOfConsoleMouseButtons GetOEMCP=kPrf2Wrap_GetOEMCP GetOverlappedResult=kPrf2Wrap_GetOverlappedResult GetPriorityClass=kPrf2Wrap_GetPriorityClass GetPrivateProfileIntA=kPrf2Wrap_GetPrivateProfileIntA GetPrivateProfileIntW=kPrf2Wrap_GetPrivateProfileIntW GetPrivateProfileSectionA=kPrf2Wrap_GetPrivateProfileSectionA GetPrivateProfileSectionNamesA=kPrf2Wrap_GetPrivateProfileSectionNamesA GetPrivateProfileSectionNamesW=kPrf2Wrap_GetPrivateProfileSectionNamesW GetPrivateProfileSectionW=kPrf2Wrap_GetPrivateProfileSectionW GetPrivateProfileStringA=kPrf2Wrap_GetPrivateProfileStringA GetPrivateProfileStringW=kPrf2Wrap_GetPrivateProfileStringW GetPrivateProfileStructA=kPrf2Wrap_GetPrivateProfileStructA GetPrivateProfileStructW=kPrf2Wrap_GetPrivateProfileStructW GetProcAddress=kPrf2Wrap_GetProcAddress GetProcessAffinityMask=kPrf2Wrap_GetProcessAffinityMask GetProcessHandleCount=kPrf2Wrap_GetProcessHandleCount GetProcessHeap=kPrf2Wrap_GetProcessHeap GetProcessHeaps=kPrf2Wrap_GetProcessHeaps GetProcessId=kPrf2Wrap_GetProcessId GetProcessIdOfThread=kPrf2Wrap_GetProcessIdOfThread GetProcessIoCounters=kPrf2Wrap_GetProcessIoCounters GetProcessPriorityBoost=kPrf2Wrap_GetProcessPriorityBoost GetProcessShutdownParameters=kPrf2Wrap_GetProcessShutdownParameters GetProcessTimes=kPrf2Wrap_GetProcessTimes GetProcessVersion=kPrf2Wrap_GetProcessVersion GetProcessWorkingSetSize=kPrf2Wrap_GetProcessWorkingSetSize GetProcessWorkingSetSizeEx=kPrf2Wrap_GetProcessWorkingSetSizeEx GetProfileIntA=kPrf2Wrap_GetProfileIntA GetProfileIntW=kPrf2Wrap_GetProfileIntW GetProfileSectionA=kPrf2Wrap_GetProfileSectionA GetProfileSectionW=kPrf2Wrap_GetProfileSectionW GetProfileStringA=kPrf2Wrap_GetProfileStringA GetProfileStringW=kPrf2Wrap_GetProfileStringW GetQueuedCompletionStatus=kPrf2Wrap_GetQueuedCompletionStatus GetShortPathNameA=kPrf2Wrap_GetShortPathNameA GetShortPathNameW=kPrf2Wrap_GetShortPathNameW GetStartupInfoA=kPrf2Wrap_GetStartupInfoA GetStartupInfoW=kPrf2Wrap_GetStartupInfoW GetStdHandle=kPrf2Wrap_GetStdHandle GetStringTypeA=kPrf2Wrap_GetStringTypeA GetStringTypeExA=kPrf2Wrap_GetStringTypeExA GetStringTypeExW=kPrf2Wrap_GetStringTypeExW GetStringTypeW=kPrf2Wrap_GetStringTypeW GetSystemDefaultLCID=kPrf2Wrap_GetSystemDefaultLCID GetSystemDefaultLangID=kPrf2Wrap_GetSystemDefaultLangID GetSystemDefaultUILanguage=kPrf2Wrap_GetSystemDefaultUILanguage GetSystemDirectoryA=kPrf2Wrap_GetSystemDirectoryA GetSystemDirectoryW=kPrf2Wrap_GetSystemDirectoryW GetSystemFileCacheSize=kPrf2Wrap_GetSystemFileCacheSize GetSystemFirmwareTable=kPrf2Wrap_GetSystemFirmwareTable GetSystemInfo=kPrf2Wrap_GetSystemInfo GetSystemPowerStatus=kPrf2Wrap_GetSystemPowerStatus GetSystemRegistryQuota=kPrf2Wrap_GetSystemRegistryQuota GetSystemTime=kPrf2Wrap_GetSystemTime GetSystemTimeAdjustment=kPrf2Wrap_GetSystemTimeAdjustment GetSystemTimeAsFileTime=kPrf2Wrap_GetSystemTimeAsFileTime GetSystemTimes=kPrf2Wrap_GetSystemTimes GetSystemWindowsDirectoryA=kPrf2Wrap_GetSystemWindowsDirectoryA GetSystemWindowsDirectoryW=kPrf2Wrap_GetSystemWindowsDirectoryW GetSystemWow64DirectoryA=kPrf2Wrap_GetSystemWow64DirectoryA GetSystemWow64DirectoryW=kPrf2Wrap_GetSystemWow64DirectoryW GetTapeParameters=kPrf2Wrap_GetTapeParameters GetTapePosition=kPrf2Wrap_GetTapePosition GetTapeStatus=kPrf2Wrap_GetTapeStatus GetTempFileNameA=kPrf2Wrap_GetTempFileNameA GetTempFileNameW=kPrf2Wrap_GetTempFileNameW GetTempPathA=kPrf2Wrap_GetTempPathA GetTempPathW=kPrf2Wrap_GetTempPathW GetThreadContext=kPrf2Wrap_GetThreadContext GetThreadIOPendingFlag=kPrf2Wrap_GetThreadIOPendingFlag GetThreadId=kPrf2Wrap_GetThreadId GetThreadLocale=kPrf2Wrap_GetThreadLocale GetThreadPriority=kPrf2Wrap_GetThreadPriority GetThreadPriorityBoost=kPrf2Wrap_GetThreadPriorityBoost GetThreadSelectorEntry=kPrf2Wrap_GetThreadSelectorEntry GetThreadTimes=kPrf2Wrap_GetThreadTimes GetTickCount=kPrf2Wrap_GetTickCount GetTimeFormatA=kPrf2Wrap_GetTimeFormatA GetTimeFormatW=kPrf2Wrap_GetTimeFormatW GetTimeZoneInformation=kPrf2Wrap_GetTimeZoneInformation GetUserDefaultLCID=kPrf2Wrap_GetUserDefaultLCID GetUserDefaultLangID=kPrf2Wrap_GetUserDefaultLangID GetUserDefaultUILanguage=kPrf2Wrap_GetUserDefaultUILanguage GetUserGeoID=kPrf2Wrap_GetUserGeoID GetVersion=kPrf2Wrap_GetVersion GetVersionExA=kPrf2Wrap_GetVersionExA GetVersionExW=kPrf2Wrap_GetVersionExW GetVolumeInformationA=kPrf2Wrap_GetVolumeInformationA GetVolumeInformationW=kPrf2Wrap_GetVolumeInformationW GetVolumeNameForVolumeMountPointA=kPrf2Wrap_GetVolumeNameForVolumeMountPointA GetVolumeNameForVolumeMountPointW=kPrf2Wrap_GetVolumeNameForVolumeMountPointW GetVolumePathNameA=kPrf2Wrap_GetVolumePathNameA GetVolumePathNameW=kPrf2Wrap_GetVolumePathNameW GetVolumePathNamesForVolumeNameA=kPrf2Wrap_GetVolumePathNamesForVolumeNameA GetVolumePathNamesForVolumeNameW=kPrf2Wrap_GetVolumePathNamesForVolumeNameW GetWindowsDirectoryA=kPrf2Wrap_GetWindowsDirectoryA GetWindowsDirectoryW=kPrf2Wrap_GetWindowsDirectoryW GetWriteWatch=kPrf2Wrap_GetWriteWatch GlobalAddAtomA=kPrf2Wrap_GlobalAddAtomA GlobalAddAtomW=kPrf2Wrap_GlobalAddAtomW GlobalAlloc=kPrf2Wrap_GlobalAlloc GlobalCompact=kPrf2Wrap_GlobalCompact GlobalDeleteAtom=kPrf2Wrap_GlobalDeleteAtom GlobalFindAtomA=kPrf2Wrap_GlobalFindAtomA GlobalFindAtomW=kPrf2Wrap_GlobalFindAtomW GlobalFix=kPrf2Wrap_GlobalFix GlobalFlags=kPrf2Wrap_GlobalFlags GlobalFree=kPrf2Wrap_GlobalFree GlobalGetAtomNameA=kPrf2Wrap_GlobalGetAtomNameA GlobalGetAtomNameW=kPrf2Wrap_GlobalGetAtomNameW GlobalHandle=kPrf2Wrap_GlobalHandle GlobalLock=kPrf2Wrap_GlobalLock GlobalMemoryStatus=kPrf2Wrap_GlobalMemoryStatus GlobalMemoryStatusEx=kPrf2Wrap_GlobalMemoryStatusEx GlobalReAlloc=kPrf2Wrap_GlobalReAlloc GlobalSize=kPrf2Wrap_GlobalSize GlobalUnWire=kPrf2Wrap_GlobalUnWire GlobalUnfix=kPrf2Wrap_GlobalUnfix GlobalUnlock=kPrf2Wrap_GlobalUnlock GlobalWire=kPrf2Wrap_GlobalWire Heap32First=kPrf2Wrap_Heap32First Heap32ListFirst=kPrf2Wrap_Heap32ListFirst Heap32ListNext=kPrf2Wrap_Heap32ListNext Heap32Next=kPrf2Wrap_Heap32Next HeapAlloc=kPrf2Wrap_HeapAlloc HeapCompact=kPrf2Wrap_HeapCompact HeapCreate=kPrf2Wrap_HeapCreate HeapDestroy=kPrf2Wrap_HeapDestroy HeapFree=kPrf2Wrap_HeapFree HeapLock=kPrf2Wrap_HeapLock HeapQueryInformation=kPrf2Wrap_HeapQueryInformation HeapReAlloc=kPrf2Wrap_HeapReAlloc HeapSetInformation=kPrf2Wrap_HeapSetInformation HeapSize=kPrf2Wrap_HeapSize HeapUnlock=kPrf2Wrap_HeapUnlock HeapValidate=kPrf2Wrap_HeapValidate HeapWalk=kPrf2Wrap_HeapWalk InitAtomTable=kPrf2Wrap_InitAtomTable InitializeCriticalSection=kPrf2Wrap_InitializeCriticalSection InitializeCriticalSectionAndSpinCount=kPrf2Wrap_InitializeCriticalSectionAndSpinCount InitializeSListHead=kPrf2Wrap_InitializeSListHead InterlockedFlushSList=kPrf2Wrap_InterlockedFlushSList InterlockedPopEntrySList=kPrf2Wrap_InterlockedPopEntrySList InterlockedPushEntrySList=kPrf2Wrap_InterlockedPushEntrySList IsBadCodePtr=kPrf2Wrap_IsBadCodePtr IsBadHugeReadPtr=kPrf2Wrap_IsBadHugeReadPtr IsBadHugeWritePtr=kPrf2Wrap_IsBadHugeWritePtr IsBadReadPtr=kPrf2Wrap_IsBadReadPtr IsBadStringPtrA=kPrf2Wrap_IsBadStringPtrA IsBadStringPtrW=kPrf2Wrap_IsBadStringPtrW IsBadWritePtr=kPrf2Wrap_IsBadWritePtr IsDBCSLeadByte=kPrf2Wrap_IsDBCSLeadByte IsDBCSLeadByteEx=kPrf2Wrap_IsDBCSLeadByteEx IsDebuggerPresent=kPrf2Wrap_IsDebuggerPresent IsNLSDefinedString=kPrf2Wrap_IsNLSDefinedString IsProcessInJob=kPrf2Wrap_IsProcessInJob IsProcessorFeaturePresent=kPrf2Wrap_IsProcessorFeaturePresent IsSystemResumeAutomatic=kPrf2Wrap_IsSystemResumeAutomatic IsValidCodePage=kPrf2Wrap_IsValidCodePage IsValidLanguageGroup=kPrf2Wrap_IsValidLanguageGroup IsValidLocale=kPrf2Wrap_IsValidLocale IsWow64Process=kPrf2Wrap_IsWow64Process LCMapStringA=kPrf2Wrap_LCMapStringA LCMapStringW=kPrf2Wrap_LCMapStringW LeaveCriticalSection=kPrf2Wrap_LeaveCriticalSection LoadLibraryA=kPrf2Wrap_LoadLibraryA LoadLibraryExA=kPrf2Wrap_LoadLibraryExA LoadLibraryExW=kPrf2Wrap_LoadLibraryExW LoadLibraryW=kPrf2Wrap_LoadLibraryW LoadModule=kPrf2Wrap_LoadModule LoadResource=kPrf2Wrap_LoadResource LocalAlloc=kPrf2Wrap_LocalAlloc LocalCompact=kPrf2Wrap_LocalCompact LocalFileTimeToFileTime=kPrf2Wrap_LocalFileTimeToFileTime LocalFlags=kPrf2Wrap_LocalFlags LocalFree=kPrf2Wrap_LocalFree LocalHandle=kPrf2Wrap_LocalHandle LocalLock=kPrf2Wrap_LocalLock LocalReAlloc=kPrf2Wrap_LocalReAlloc LocalShrink=kPrf2Wrap_LocalShrink LocalSize=kPrf2Wrap_LocalSize LocalUnlock=kPrf2Wrap_LocalUnlock LockFile=kPrf2Wrap_LockFile LockFileEx=kPrf2Wrap_LockFileEx LockResource=kPrf2Wrap_LockResource MapUserPhysicalPages=kPrf2Wrap_MapUserPhysicalPages MapUserPhysicalPagesScatter=kPrf2Wrap_MapUserPhysicalPagesScatter MapViewOfFile=kPrf2Wrap_MapViewOfFile MapViewOfFileEx=kPrf2Wrap_MapViewOfFileEx Module32First=kPrf2Wrap_Module32First Module32FirstW=kPrf2Wrap_Module32FirstW Module32Next=kPrf2Wrap_Module32Next Module32NextW=kPrf2Wrap_Module32NextW MoveFileA=kPrf2Wrap_MoveFileA MoveFileExA=kPrf2Wrap_MoveFileExA MoveFileExW=kPrf2Wrap_MoveFileExW MoveFileW=kPrf2Wrap_MoveFileW MoveFileWithProgressA=kPrf2Wrap_MoveFileWithProgressA MoveFileWithProgressW=kPrf2Wrap_MoveFileWithProgressW MulDiv=kPrf2Wrap_MulDiv MultiByteToWideChar=kPrf2Wrap_MultiByteToWideChar NeedCurrentDirectoryForExePathA=kPrf2Wrap_NeedCurrentDirectoryForExePathA NeedCurrentDirectoryForExePathW=kPrf2Wrap_NeedCurrentDirectoryForExePathW OpenEventA=kPrf2Wrap_OpenEventA OpenEventW=kPrf2Wrap_OpenEventW OpenFile=kPrf2Wrap_OpenFile OpenFileMappingA=kPrf2Wrap_OpenFileMappingA OpenFileMappingW=kPrf2Wrap_OpenFileMappingW OpenJobObjectA=kPrf2Wrap_OpenJobObjectA OpenJobObjectW=kPrf2Wrap_OpenJobObjectW OpenMutexA=kPrf2Wrap_OpenMutexA OpenMutexW=kPrf2Wrap_OpenMutexW OpenProcess=kPrf2Wrap_OpenProcess OpenSemaphoreA=kPrf2Wrap_OpenSemaphoreA OpenSemaphoreW=kPrf2Wrap_OpenSemaphoreW OpenThread=kPrf2Wrap_OpenThread OpenWaitableTimerA=kPrf2Wrap_OpenWaitableTimerA OpenWaitableTimerW=kPrf2Wrap_OpenWaitableTimerW OutputDebugStringA=kPrf2Wrap_OutputDebugStringA OutputDebugStringW=kPrf2Wrap_OutputDebugStringW PeekConsoleInputA=kPrf2Wrap_PeekConsoleInputA PeekConsoleInputW=kPrf2Wrap_PeekConsoleInputW PeekNamedPipe=kPrf2Wrap_PeekNamedPipe PostQueuedCompletionStatus=kPrf2Wrap_PostQueuedCompletionStatus PrepareTape=kPrf2Wrap_PrepareTape Process32First=kPrf2Wrap_Process32First Process32FirstW=kPrf2Wrap_Process32FirstW Process32Next=kPrf2Wrap_Process32Next Process32NextW=kPrf2Wrap_Process32NextW ProcessIdToSessionId=kPrf2Wrap_ProcessIdToSessionId PulseEvent=kPrf2Wrap_PulseEvent PurgeComm=kPrf2Wrap_PurgeComm QueryActCtxW=kPrf2Wrap_QueryActCtxW QueryDepthSList=kPrf2Wrap_QueryDepthSList QueryDosDeviceA=kPrf2Wrap_QueryDosDeviceA QueryDosDeviceW=kPrf2Wrap_QueryDosDeviceW QueryInformationJobObject=kPrf2Wrap_QueryInformationJobObject QueryMemoryResourceNotification=kPrf2Wrap_QueryMemoryResourceNotification QueryPerformanceCounter=kPrf2Wrap_QueryPerformanceCounter QueryPerformanceFrequency=kPrf2Wrap_QueryPerformanceFrequency QueueUserAPC=kPrf2Wrap_QueueUserAPC QueueUserWorkItem=kPrf2Wrap_QueueUserWorkItem RaiseException=kPrf2Wrap_RaiseException ReOpenFile=kPrf2Wrap_ReOpenFile ReadConsoleA=kPrf2Wrap_ReadConsoleA ReadConsoleInputA=kPrf2Wrap_ReadConsoleInputA ReadConsoleInputW=kPrf2Wrap_ReadConsoleInputW ReadConsoleOutputA=kPrf2Wrap_ReadConsoleOutputA ReadConsoleOutputAttribute=kPrf2Wrap_ReadConsoleOutputAttribute ReadConsoleOutputCharacterA=kPrf2Wrap_ReadConsoleOutputCharacterA ReadConsoleOutputCharacterW=kPrf2Wrap_ReadConsoleOutputCharacterW ReadConsoleOutputW=kPrf2Wrap_ReadConsoleOutputW ReadConsoleW=kPrf2Wrap_ReadConsoleW ReadDirectoryChangesW=kPrf2Wrap_ReadDirectoryChangesW ReadFile=kPrf2Wrap_ReadFile ReadFileEx=kPrf2Wrap_ReadFileEx ReadFileScatter=kPrf2Wrap_ReadFileScatter ReadProcessMemory=kPrf2Wrap_ReadProcessMemory RegisterWaitForSingleObject=kPrf2Wrap_RegisterWaitForSingleObject RegisterWaitForSingleObjectEx=kPrf2Wrap_RegisterWaitForSingleObjectEx ReleaseActCtx=kPrf2Wrap_ReleaseActCtx ReleaseMutex=kPrf2Wrap_ReleaseMutex ReleaseSemaphore=kPrf2Wrap_ReleaseSemaphore RemoveDirectoryA=kPrf2Wrap_RemoveDirectoryA RemoveDirectoryW=kPrf2Wrap_RemoveDirectoryW RemoveVectoredContinueHandler=kPrf2Wrap_RemoveVectoredContinueHandler RemoveVectoredExceptionHandler=kPrf2Wrap_RemoveVectoredExceptionHandler ReplaceFile=kPrf2Wrap_ReplaceFile ReplaceFileA=kPrf2Wrap_ReplaceFileA ReplaceFileW=kPrf2Wrap_ReplaceFileW RequestDeviceWakeup=kPrf2Wrap_RequestDeviceWakeup RequestWakeupLatency=kPrf2Wrap_RequestWakeupLatency ResetEvent=kPrf2Wrap_ResetEvent ResetWriteWatch=kPrf2Wrap_ResetWriteWatch RestoreLastError=kPrf2Wrap_RestoreLastError ResumeThread=kPrf2Wrap_ResumeThread RtlAddFunctionTable=kPrf2Wrap_RtlAddFunctionTable RtlCaptureContext=kPrf2Wrap_RtlCaptureContext RtlCaptureStackBackTrace=kPrf2Wrap_RtlCaptureStackBackTrace RtlCompareMemory=kPrf2Wrap_RtlCompareMemory RtlDeleteFunctionTable=kPrf2Wrap_RtlDeleteFunctionTable RtlFillMemory=kPrf2Wrap_RtlFillMemory RtlInstallFunctionTableCallback=kPrf2Wrap_RtlInstallFunctionTableCallback RtlLookupFunctionEntry=kPrf2Wrap_RtlLookupFunctionEntry RtlMoveMemory=kPrf2Wrap_RtlMoveMemory RtlPcToFileHeader=kPrf2Wrap_RtlPcToFileHeader RtlRaiseException=kPrf2Wrap_RtlRaiseException RtlRestoreContext=kPrf2Wrap_RtlRestoreContext RtlUnwind=kPrf2Wrap_RtlUnwind RtlUnwindEx=kPrf2Wrap_RtlUnwindEx RtlVirtualUnwind=kPrf2Wrap_RtlVirtualUnwind RtlZeroMemory=kPrf2Wrap_RtlZeroMemory ScrollConsoleScreenBufferA=kPrf2Wrap_ScrollConsoleScreenBufferA ScrollConsoleScreenBufferW=kPrf2Wrap_ScrollConsoleScreenBufferW SearchPathA=kPrf2Wrap_SearchPathA SearchPathW=kPrf2Wrap_SearchPathW SetCalendarInfoA=kPrf2Wrap_SetCalendarInfoA SetCalendarInfoW=kPrf2Wrap_SetCalendarInfoW SetCommBreak=kPrf2Wrap_SetCommBreak SetCommConfig=kPrf2Wrap_SetCommConfig SetCommMask=kPrf2Wrap_SetCommMask SetCommState=kPrf2Wrap_SetCommState SetCommTimeouts=kPrf2Wrap_SetCommTimeouts SetComputerNameA=kPrf2Wrap_SetComputerNameA SetComputerNameExA=kPrf2Wrap_SetComputerNameExA SetComputerNameExW=kPrf2Wrap_SetComputerNameExW SetComputerNameW=kPrf2Wrap_SetComputerNameW SetConsoleActiveScreenBuffer=kPrf2Wrap_SetConsoleActiveScreenBuffer SetConsoleCP=kPrf2Wrap_SetConsoleCP SetConsoleCtrlHandler=kPrf2Wrap_SetConsoleCtrlHandler SetConsoleCursor=kPrf2Wrap_SetConsoleCursor SetConsoleCursorInfo=kPrf2Wrap_SetConsoleCursorInfo SetConsoleCursorPosition=kPrf2Wrap_SetConsoleCursorPosition SetConsoleMode=kPrf2Wrap_SetConsoleMode SetConsoleOutputCP=kPrf2Wrap_SetConsoleOutputCP SetConsoleScreenBufferSize=kPrf2Wrap_SetConsoleScreenBufferSize SetConsoleTextAttribute=kPrf2Wrap_SetConsoleTextAttribute SetConsoleTitleA=kPrf2Wrap_SetConsoleTitleA SetConsoleTitleW=kPrf2Wrap_SetConsoleTitleW SetConsoleWindowInfo=kPrf2Wrap_SetConsoleWindowInfo SetCriticalSectionSpinCount=kPrf2Wrap_SetCriticalSectionSpinCount SetCurrentDirectoryA=kPrf2Wrap_SetCurrentDirectoryA SetCurrentDirectoryW=kPrf2Wrap_SetCurrentDirectoryW SetDefaultCommConfigA=kPrf2Wrap_SetDefaultCommConfigA SetDefaultCommConfigW=kPrf2Wrap_SetDefaultCommConfigW SetDllDirectoryA=kPrf2Wrap_SetDllDirectoryA SetDllDirectoryW=kPrf2Wrap_SetDllDirectoryW SetEndOfFile=kPrf2Wrap_SetEndOfFile SetEnvironmentStringsA=kPrf2Wrap_SetEnvironmentStringsA SetEnvironmentStringsW=kPrf2Wrap_SetEnvironmentStringsW SetEnvironmentVariableA=kPrf2Wrap_SetEnvironmentVariableA SetEnvironmentVariableW=kPrf2Wrap_SetEnvironmentVariableW SetErrorMode=kPrf2Wrap_SetErrorMode SetEvent=kPrf2Wrap_SetEvent SetFileApisToANSI=kPrf2Wrap_SetFileApisToANSI SetFileApisToOEM=kPrf2Wrap_SetFileApisToOEM SetFileAttributesA=kPrf2Wrap_SetFileAttributesA SetFileAttributesW=kPrf2Wrap_SetFileAttributesW SetFilePointer=kPrf2Wrap_SetFilePointer SetFilePointerEx=kPrf2Wrap_SetFilePointerEx SetFileShortNameA=kPrf2Wrap_SetFileShortNameA SetFileShortNameW=kPrf2Wrap_SetFileShortNameW SetFileTime=kPrf2Wrap_SetFileTime SetFileValidData=kPrf2Wrap_SetFileValidData SetFirmwareEnvironmentVariableA=kPrf2Wrap_SetFirmwareEnvironmentVariableA SetFirmwareEnvironmentVariableW=kPrf2Wrap_SetFirmwareEnvironmentVariableW SetHandleCount=kPrf2Wrap_SetHandleCount SetHandleInformation=kPrf2Wrap_SetHandleInformation SetInformationJobObject=kPrf2Wrap_SetInformationJobObject SetLastError=kPrf2Wrap_SetLastError SetLocalTime=kPrf2Wrap_SetLocalTime SetLocaleInfoA=kPrf2Wrap_SetLocaleInfoA SetLocaleInfoW=kPrf2Wrap_SetLocaleInfoW SetMailslotInfo=kPrf2Wrap_SetMailslotInfo SetMessageWaitingIndicator=kPrf2Wrap_SetMessageWaitingIndicator SetNamedPipeHandleState=kPrf2Wrap_SetNamedPipeHandleState SetPriorityClass=kPrf2Wrap_SetPriorityClass SetProcessAffinityMask=kPrf2Wrap_SetProcessAffinityMask SetProcessPriorityBoost=kPrf2Wrap_SetProcessPriorityBoost SetProcessShutdownParameters=kPrf2Wrap_SetProcessShutdownParameters SetProcessWorkingSetSize=kPrf2Wrap_SetProcessWorkingSetSize SetProcessWorkingSetSizeEx=kPrf2Wrap_SetProcessWorkingSetSizeEx SetStdHandle=kPrf2Wrap_SetStdHandle SetSystemFileCacheSize=kPrf2Wrap_SetSystemFileCacheSize SetSystemPowerState=kPrf2Wrap_SetSystemPowerState SetSystemTime=kPrf2Wrap_SetSystemTime SetSystemTimeAdjustment=kPrf2Wrap_SetSystemTimeAdjustment SetTapeParameters=kPrf2Wrap_SetTapeParameters SetTapePosition=kPrf2Wrap_SetTapePosition SetThreadAffinityMask=kPrf2Wrap_SetThreadAffinityMask SetThreadContext=kPrf2Wrap_SetThreadContext SetThreadExecutionState=kPrf2Wrap_SetThreadExecutionState SetThreadIdealProcessor=kPrf2Wrap_SetThreadIdealProcessor SetThreadLocale=kPrf2Wrap_SetThreadLocale SetThreadPriority=kPrf2Wrap_SetThreadPriority SetThreadPriorityBoost=kPrf2Wrap_SetThreadPriorityBoost SetThreadStackGuarantee=kPrf2Wrap_SetThreadStackGuarantee SetTimeZoneInformation=kPrf2Wrap_SetTimeZoneInformation SetTimerQueueTimer=kPrf2Wrap_SetTimerQueueTimer SetUnhandledExceptionFilter=kPrf2Wrap_SetUnhandledExceptionFilter SetUserGeoID=kPrf2Wrap_SetUserGeoID SetVolumeLabelA=kPrf2Wrap_SetVolumeLabelA SetVolumeLabelW=kPrf2Wrap_SetVolumeLabelW SetVolumeMountPointA=kPrf2Wrap_SetVolumeMountPointA SetVolumeMountPointW=kPrf2Wrap_SetVolumeMountPointW SetWaitableTimer=kPrf2Wrap_SetWaitableTimer SetupComm=kPrf2Wrap_SetupComm SignalObjectAndWait=kPrf2Wrap_SignalObjectAndWait SizeofResource=kPrf2Wrap_SizeofResource Sleep=kPrf2Wrap_Sleep SleepEx=kPrf2Wrap_SleepEx SuspendThread=kPrf2Wrap_SuspendThread SwitchToFiber=kPrf2Wrap_SwitchToFiber SwitchToThread=kPrf2Wrap_SwitchToThread SystemTimeToFileTime=kPrf2Wrap_SystemTimeToFileTime SystemTimeToTzSpecificLocalTime=kPrf2Wrap_SystemTimeToTzSpecificLocalTime TerminateJobObject=kPrf2Wrap_TerminateJobObject TerminateProcess=kPrf2Wrap_TerminateProcess TerminateThread=kPrf2Wrap_TerminateThread Thread32First=kPrf2Wrap_Thread32First Thread32Next=kPrf2Wrap_Thread32Next TlsAlloc=kPrf2Wrap_TlsAlloc TlsFree=kPrf2Wrap_TlsFree TlsGetValue=kPrf2Wrap_TlsGetValue TlsSetValue=kPrf2Wrap_TlsSetValue Toolhelp32ReadProcessMemory=kPrf2Wrap_Toolhelp32ReadProcessMemory TransactNamedPipe=kPrf2Wrap_TransactNamedPipe TransmitCommChar=kPrf2Wrap_TransmitCommChar TryEnterCriticalSection=kPrf2Wrap_TryEnterCriticalSection TzSpecificLocalTimeToSystemTime=kPrf2Wrap_TzSpecificLocalTimeToSystemTime UnhandledExceptionFilter=kPrf2Wrap_UnhandledExceptionFilter UnlockFile=kPrf2Wrap_UnlockFile UnlockFileEx=kPrf2Wrap_UnlockFileEx UnmapViewOfFile=kPrf2Wrap_UnmapViewOfFile UnregisterWait=kPrf2Wrap_UnregisterWait UnregisterWaitEx=kPrf2Wrap_UnregisterWaitEx UpdateResourceA=kPrf2Wrap_UpdateResourceA UpdateResourceW=kPrf2Wrap_UpdateResourceW VerLanguageNameA=kPrf2Wrap_VerLanguageNameA VerLanguageNameW=kPrf2Wrap_VerLanguageNameW VerSetConditionMask=kPrf2Wrap_VerSetConditionMask VerifyVersionInfoA=kPrf2Wrap_VerifyVersionInfoA VerifyVersionInfoW=kPrf2Wrap_VerifyVersionInfoW VirtualAlloc=kPrf2Wrap_VirtualAlloc VirtualAllocEx=kPrf2Wrap_VirtualAllocEx VirtualFree=kPrf2Wrap_VirtualFree VirtualFreeEx=kPrf2Wrap_VirtualFreeEx VirtualLock=kPrf2Wrap_VirtualLock VirtualProtect=kPrf2Wrap_VirtualProtect VirtualProtectEx=kPrf2Wrap_VirtualProtectEx VirtualQuery=kPrf2Wrap_VirtualQuery VirtualQueryEx=kPrf2Wrap_VirtualQueryEx VirtualUnlock=kPrf2Wrap_VirtualUnlock WTSGetActiveConsoleSessionId=kPrf2Wrap_WTSGetActiveConsoleSessionId WaitCommEvent=kPrf2Wrap_WaitCommEvent WaitForDebugEvent=kPrf2Wrap_WaitForDebugEvent WaitForMultipleObjects=kPrf2Wrap_WaitForMultipleObjects WaitForMultipleObjectsEx=kPrf2Wrap_WaitForMultipleObjectsEx WaitForSingleObject=kPrf2Wrap_WaitForSingleObject WaitForSingleObjectEx=kPrf2Wrap_WaitForSingleObjectEx WaitNamedPipeA=kPrf2Wrap_WaitNamedPipeA WaitNamedPipeW=kPrf2Wrap_WaitNamedPipeW WideCharToMultiByte=kPrf2Wrap_WideCharToMultiByte WinExec=kPrf2Wrap_WinExec Wow64DisableWow64FsRedirection=kPrf2Wrap_Wow64DisableWow64FsRedirection Wow64EnableWow64FsRedirection=kPrf2Wrap_Wow64EnableWow64FsRedirection Wow64RevertWow64FsRedirection=kPrf2Wrap_Wow64RevertWow64FsRedirection WriteConsoleA=kPrf2Wrap_WriteConsoleA WriteConsoleInputA=kPrf2Wrap_WriteConsoleInputA WriteConsoleInputW=kPrf2Wrap_WriteConsoleInputW WriteConsoleOutputA=kPrf2Wrap_WriteConsoleOutputA WriteConsoleOutputAttribute=kPrf2Wrap_WriteConsoleOutputAttribute WriteConsoleOutputCharacterA=kPrf2Wrap_WriteConsoleOutputCharacterA WriteConsoleOutputCharacterW=kPrf2Wrap_WriteConsoleOutputCharacterW WriteConsoleOutputW=kPrf2Wrap_WriteConsoleOutputW WriteConsoleW=kPrf2Wrap_WriteConsoleW WriteFile=kPrf2Wrap_WriteFile WriteFileEx=kPrf2Wrap_WriteFileEx WriteFileGather=kPrf2Wrap_WriteFileGather WritePrivateProfileSectionA=kPrf2Wrap_WritePrivateProfileSectionA WritePrivateProfileSectionW=kPrf2Wrap_WritePrivateProfileSectionW WritePrivateProfileStringA=kPrf2Wrap_WritePrivateProfileStringA WritePrivateProfileStringW=kPrf2Wrap_WritePrivateProfileStringW WritePrivateProfileStructA=kPrf2Wrap_WritePrivateProfileStructA WritePrivateProfileStructW=kPrf2Wrap_WritePrivateProfileStructW WriteProcessMemory=kPrf2Wrap_WriteProcessMemory WriteProfileSectionA=kPrf2Wrap_WriteProfileSectionA WriteProfileSectionW=kPrf2Wrap_WriteProfileSectionW WriteProfileStringA=kPrf2Wrap_WriteProfileStringA WriteProfileStringW=kPrf2Wrap_WriteProfileStringW WriteTapemark=kPrf2Wrap_WriteTapemark ZombifyActCtx=kPrf2Wrap_ZombifyActCtx _hread=kPrf2Wrap__hread _hwrite=kPrf2Wrap__hwrite _lclose=kPrf2Wrap__lclose _lcreat=kPrf2Wrap__lcreat _llseek=kPrf2Wrap__llseek _lopen=kPrf2Wrap__lopen _lread=kPrf2Wrap__lread _lwrite=kPrf2Wrap__lwrite lstrcat=kPrf2Wrap_lstrcat lstrcatA=kPrf2Wrap_lstrcatA lstrcatW=kPrf2Wrap_lstrcatW lstrcmp=kPrf2Wrap_lstrcmp lstrcmpA=kPrf2Wrap_lstrcmpA lstrcmpW=kPrf2Wrap_lstrcmpW lstrcmpi=kPrf2Wrap_lstrcmpi lstrcmpiA=kPrf2Wrap_lstrcmpiA lstrcmpiW=kPrf2Wrap_lstrcmpiW lstrcpy=kPrf2Wrap_lstrcpy lstrcpyA=kPrf2Wrap_lstrcpyA lstrcpyW=kPrf2Wrap_lstrcpyW lstrcpyn=kPrf2Wrap_lstrcpyn lstrcpynA=kPrf2Wrap_lstrcpynA lstrcpynW=kPrf2Wrap_lstrcpynW lstrlen=kPrf2Wrap_lstrlen lstrlenA=kPrf2Wrap_lstrlenA lstrlenW=kPrf2Wrap_lstrlenW uaw_lstrcmpW=kPrf2Wrap_uaw_lstrcmpW uaw_lstrcmpiW=kPrf2Wrap_uaw_lstrcmpiW uaw_lstrlenW=kPrf2Wrap_uaw_lstrlenW uaw_wcschr=kPrf2Wrap_uaw_wcschr uaw_wcscpy=kPrf2Wrap_uaw_wcscpy uaw_wcsicmp=kPrf2Wrap_uaw_wcsicmp uaw_wcslen=kPrf2Wrap_uaw_wcslen uaw_wcsrchr=kPrf2Wrap_uaw_wcsrchr kbuild-3149/src/lib/kStuff/kProfiler2/kPrf2WinApiWrappers-kernel32.h0000644000175000017500000156362013252530254025154 0ustar locutuslocutustypedef PVOID WINAPI FN_EncodePointer( PVOID Ptr ); __declspec(dllexport) PVOID WINAPI kPrf2Wrap_EncodePointer( PVOID Ptr ) { static FN_EncodePointer *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EncodePointer", &g_Kernel32); return pfn( Ptr ); } typedef PVOID WINAPI FN_DecodePointer( PVOID Ptr ); __declspec(dllexport) PVOID WINAPI kPrf2Wrap_DecodePointer( PVOID Ptr ) { static FN_DecodePointer *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DecodePointer", &g_Kernel32); return pfn( Ptr ); } typedef PVOID WINAPI FN_EncodeSystemPointer( PVOID Ptr ); __declspec(dllexport) PVOID WINAPI kPrf2Wrap_EncodeSystemPointer( PVOID Ptr ) { static FN_EncodeSystemPointer *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EncodeSystemPointer", &g_Kernel32); return pfn( Ptr ); } typedef PVOID WINAPI FN_DecodeSystemPointer( PVOID Ptr ); __declspec(dllexport) PVOID WINAPI kPrf2Wrap_DecodeSystemPointer( PVOID Ptr ) { static FN_DecodeSystemPointer *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DecodeSystemPointer", &g_Kernel32); return pfn( Ptr ); } typedef DWORD WINAPI FN_GetFreeSpace( UINT a); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetFreeSpace( UINT a) { static FN_GetFreeSpace *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetFreeSpace", &g_Kernel32); return pfn( a); } typedef LONG WINAPI FN_InterlockedIncrement( LONG volatile * lpAddend ); __declspec(dllexport) LONG WINAPI kPrf2Wrap_InterlockedIncrement( LONG volatile * lpAddend ) { static FN_InterlockedIncrement *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "InterlockedIncrement", &g_Kernel32); return pfn( lpAddend ); } typedef LONG WINAPI FN_InterlockedDecrement( LONG volatile * lpAddend ); __declspec(dllexport) LONG WINAPI kPrf2Wrap_InterlockedDecrement( LONG volatile * lpAddend ) { static FN_InterlockedDecrement *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "InterlockedDecrement", &g_Kernel32); return pfn( lpAddend ); } typedef LONG WINAPI FN_InterlockedExchange( LONG volatile * Target, LONG Value ); __declspec(dllexport) LONG WINAPI kPrf2Wrap_InterlockedExchange( LONG volatile * Target, LONG Value ) { static FN_InterlockedExchange *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "InterlockedExchange", &g_Kernel32); return pfn( Target, Value ); } typedef LONG WINAPI FN_InterlockedExchangeAdd( LONG volatile * Addend, LONG Value ); __declspec(dllexport) LONG WINAPI kPrf2Wrap_InterlockedExchangeAdd( LONG volatile * Addend, LONG Value ) { static FN_InterlockedExchangeAdd *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "InterlockedExchangeAdd", &g_Kernel32); return pfn( Addend, Value ); } typedef LONG WINAPI FN_InterlockedCompareExchange( LONG volatile * Destination, LONG Exchange, LONG Comperand ); __declspec(dllexport) LONG WINAPI kPrf2Wrap_InterlockedCompareExchange( LONG volatile * Destination, LONG Exchange, LONG Comperand ) { static FN_InterlockedCompareExchange *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "InterlockedCompareExchange", &g_Kernel32); return pfn( Destination, Exchange, Comperand ); } typedef LONGLONG WINAPI FN_InterlockedCompareExchange64( LONGLONG volatile * Destination, LONGLONG Exchange, LONGLONG Comperand ); __declspec(dllexport) LONGLONG WINAPI kPrf2Wrap_InterlockedCompareExchange64( LONGLONG volatile * Destination, LONGLONG Exchange, LONGLONG Comperand ) { static FN_InterlockedCompareExchange64 *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "InterlockedCompareExchange64", &g_Kernel32); return pfn( Destination, Exchange, Comperand ); } typedef VOID WINAPI FN_InitializeSListHead( PSLIST_HEADER ListHead ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_InitializeSListHead( PSLIST_HEADER ListHead ) { static FN_InitializeSListHead *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "InitializeSListHead", &g_Kernel32); pfn( ListHead ); } typedef PSLIST_ENTRY WINAPI FN_InterlockedPopEntrySList( PSLIST_HEADER ListHead ); __declspec(dllexport) PSLIST_ENTRY WINAPI kPrf2Wrap_InterlockedPopEntrySList( PSLIST_HEADER ListHead ) { static FN_InterlockedPopEntrySList *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "InterlockedPopEntrySList", &g_Kernel32); return pfn( ListHead ); } typedef PSLIST_ENTRY WINAPI FN_InterlockedPushEntrySList( PSLIST_HEADER ListHead, PSLIST_ENTRY ListEntry ); __declspec(dllexport) PSLIST_ENTRY WINAPI kPrf2Wrap_InterlockedPushEntrySList( PSLIST_HEADER ListHead, PSLIST_ENTRY ListEntry ) { static FN_InterlockedPushEntrySList *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "InterlockedPushEntrySList", &g_Kernel32); return pfn( ListHead, ListEntry ); } typedef PSLIST_ENTRY WINAPI FN_InterlockedFlushSList( PSLIST_HEADER ListHead ); __declspec(dllexport) PSLIST_ENTRY WINAPI kPrf2Wrap_InterlockedFlushSList( PSLIST_HEADER ListHead ) { static FN_InterlockedFlushSList *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "InterlockedFlushSList", &g_Kernel32); return pfn( ListHead ); } typedef USHORT WINAPI FN_QueryDepthSList( PSLIST_HEADER ListHead ); __declspec(dllexport) USHORT WINAPI kPrf2Wrap_QueryDepthSList( PSLIST_HEADER ListHead ) { static FN_QueryDepthSList *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "QueryDepthSList", &g_Kernel32); return pfn( ListHead ); } typedef BOOL WINAPI FN_FreeResource( HGLOBAL hResData ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FreeResource( HGLOBAL hResData ) { static FN_FreeResource *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FreeResource", &g_Kernel32); return pfn( hResData ); } typedef LPVOID WINAPI FN_LockResource( HGLOBAL hResData ); __declspec(dllexport) LPVOID WINAPI kPrf2Wrap_LockResource( HGLOBAL hResData ) { static FN_LockResource *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LockResource", &g_Kernel32); return pfn( hResData ); } typedef BOOL WINAPI FN_FreeLibrary( HMODULE hLibModule ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FreeLibrary( HMODULE hLibModule ) { static FN_FreeLibrary *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FreeLibrary", &g_Kernel32); return pfn( hLibModule ); } typedef VOID WINAPI FN_FreeLibraryAndExitThread( HMODULE hLibModule, DWORD dwExitCode ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_FreeLibraryAndExitThread( HMODULE hLibModule, DWORD dwExitCode ) { static FN_FreeLibraryAndExitThread *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FreeLibraryAndExitThread", &g_Kernel32); pfn( hLibModule, dwExitCode ); } typedef BOOL WINAPI FN_DisableThreadLibraryCalls( HMODULE hLibModule ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_DisableThreadLibraryCalls( HMODULE hLibModule ) { static FN_DisableThreadLibraryCalls *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DisableThreadLibraryCalls", &g_Kernel32); return pfn( hLibModule ); } typedef FARPROC WINAPI FN_GetProcAddress( HMODULE hModule, LPCSTR lpProcName ); __declspec(dllexport) FARPROC WINAPI kPrf2Wrap_GetProcAddress( HMODULE hModule, LPCSTR lpProcName ) { static FN_GetProcAddress *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetProcAddress", &g_Kernel32); return pfn( hModule, lpProcName ); } typedef DWORD WINAPI FN_GetVersion( VOID ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetVersion( VOID ) { static FN_GetVersion *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetVersion", &g_Kernel32); return pfn (); } typedef HGLOBAL WINAPI FN_GlobalAlloc( UINT uFlags, SIZE_T dwBytes ); __declspec(dllexport) HGLOBAL WINAPI kPrf2Wrap_GlobalAlloc( UINT uFlags, SIZE_T dwBytes ) { static FN_GlobalAlloc *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GlobalAlloc", &g_Kernel32); return pfn( uFlags, dwBytes ); } typedef HGLOBAL WINAPI FN_GlobalReAlloc( HGLOBAL hMem, SIZE_T dwBytes, UINT uFlags ); __declspec(dllexport) HGLOBAL WINAPI kPrf2Wrap_GlobalReAlloc( HGLOBAL hMem, SIZE_T dwBytes, UINT uFlags ) { static FN_GlobalReAlloc *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GlobalReAlloc", &g_Kernel32); return pfn( hMem, dwBytes, uFlags ); } typedef SIZE_T WINAPI FN_GlobalSize( HGLOBAL hMem ); __declspec(dllexport) SIZE_T WINAPI kPrf2Wrap_GlobalSize( HGLOBAL hMem ) { static FN_GlobalSize *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GlobalSize", &g_Kernel32); return pfn( hMem ); } typedef UINT WINAPI FN_GlobalFlags( HGLOBAL hMem ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_GlobalFlags( HGLOBAL hMem ) { static FN_GlobalFlags *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GlobalFlags", &g_Kernel32); return pfn( hMem ); } typedef LPVOID WINAPI FN_GlobalLock( HGLOBAL hMem ); __declspec(dllexport) LPVOID WINAPI kPrf2Wrap_GlobalLock( HGLOBAL hMem ) { static FN_GlobalLock *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GlobalLock", &g_Kernel32); return pfn( hMem ); } typedef HGLOBAL WINAPI FN_GlobalHandle( LPCVOID pMem ); __declspec(dllexport) HGLOBAL WINAPI kPrf2Wrap_GlobalHandle( LPCVOID pMem ) { static FN_GlobalHandle *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GlobalHandle", &g_Kernel32); return pfn( pMem ); } typedef BOOL WINAPI FN_GlobalUnlock( HGLOBAL hMem ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GlobalUnlock( HGLOBAL hMem ) { static FN_GlobalUnlock *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GlobalUnlock", &g_Kernel32); return pfn( hMem ); } typedef HGLOBAL WINAPI FN_GlobalFree( HGLOBAL hMem ); __declspec(dllexport) HGLOBAL WINAPI kPrf2Wrap_GlobalFree( HGLOBAL hMem ) { static FN_GlobalFree *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GlobalFree", &g_Kernel32); return pfn( hMem ); } typedef SIZE_T WINAPI FN_GlobalCompact( DWORD dwMinFree ); __declspec(dllexport) SIZE_T WINAPI kPrf2Wrap_GlobalCompact( DWORD dwMinFree ) { static FN_GlobalCompact *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GlobalCompact", &g_Kernel32); return pfn( dwMinFree ); } typedef VOID WINAPI FN_GlobalFix( HGLOBAL hMem ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_GlobalFix( HGLOBAL hMem ) { static FN_GlobalFix *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GlobalFix", &g_Kernel32); pfn( hMem ); } typedef VOID WINAPI FN_GlobalUnfix( HGLOBAL hMem ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_GlobalUnfix( HGLOBAL hMem ) { static FN_GlobalUnfix *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GlobalUnfix", &g_Kernel32); pfn( hMem ); } typedef LPVOID WINAPI FN_GlobalWire( HGLOBAL hMem ); __declspec(dllexport) LPVOID WINAPI kPrf2Wrap_GlobalWire( HGLOBAL hMem ) { static FN_GlobalWire *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GlobalWire", &g_Kernel32); return pfn( hMem ); } typedef BOOL WINAPI FN_GlobalUnWire( HGLOBAL hMem ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GlobalUnWire( HGLOBAL hMem ) { static FN_GlobalUnWire *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GlobalUnWire", &g_Kernel32); return pfn( hMem ); } typedef VOID WINAPI FN_GlobalMemoryStatus( LPMEMORYSTATUS lpBuffer ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_GlobalMemoryStatus( LPMEMORYSTATUS lpBuffer ) { static FN_GlobalMemoryStatus *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GlobalMemoryStatus", &g_Kernel32); pfn( lpBuffer ); } typedef BOOL WINAPI FN_GlobalMemoryStatusEx( LPMEMORYSTATUSEX lpBuffer ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GlobalMemoryStatusEx( LPMEMORYSTATUSEX lpBuffer ) { static FN_GlobalMemoryStatusEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GlobalMemoryStatusEx", &g_Kernel32); return pfn( lpBuffer ); } typedef HLOCAL WINAPI FN_LocalAlloc( UINT uFlags, SIZE_T uBytes ); __declspec(dllexport) HLOCAL WINAPI kPrf2Wrap_LocalAlloc( UINT uFlags, SIZE_T uBytes ) { static FN_LocalAlloc *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LocalAlloc", &g_Kernel32); return pfn( uFlags, uBytes ); } typedef HLOCAL WINAPI FN_LocalReAlloc( HLOCAL hMem, SIZE_T uBytes, UINT uFlags ); __declspec(dllexport) HLOCAL WINAPI kPrf2Wrap_LocalReAlloc( HLOCAL hMem, SIZE_T uBytes, UINT uFlags ) { static FN_LocalReAlloc *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LocalReAlloc", &g_Kernel32); return pfn( hMem, uBytes, uFlags ); } typedef LPVOID WINAPI FN_LocalLock( HLOCAL hMem ); __declspec(dllexport) LPVOID WINAPI kPrf2Wrap_LocalLock( HLOCAL hMem ) { static FN_LocalLock *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LocalLock", &g_Kernel32); return pfn( hMem ); } typedef HLOCAL WINAPI FN_LocalHandle( LPCVOID pMem ); __declspec(dllexport) HLOCAL WINAPI kPrf2Wrap_LocalHandle( LPCVOID pMem ) { static FN_LocalHandle *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LocalHandle", &g_Kernel32); return pfn( pMem ); } typedef BOOL WINAPI FN_LocalUnlock( HLOCAL hMem ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_LocalUnlock( HLOCAL hMem ) { static FN_LocalUnlock *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LocalUnlock", &g_Kernel32); return pfn( hMem ); } typedef SIZE_T WINAPI FN_LocalSize( HLOCAL hMem ); __declspec(dllexport) SIZE_T WINAPI kPrf2Wrap_LocalSize( HLOCAL hMem ) { static FN_LocalSize *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LocalSize", &g_Kernel32); return pfn( hMem ); } typedef UINT WINAPI FN_LocalFlags( HLOCAL hMem ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_LocalFlags( HLOCAL hMem ) { static FN_LocalFlags *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LocalFlags", &g_Kernel32); return pfn( hMem ); } typedef HLOCAL WINAPI FN_LocalFree( HLOCAL hMem ); __declspec(dllexport) HLOCAL WINAPI kPrf2Wrap_LocalFree( HLOCAL hMem ) { static FN_LocalFree *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LocalFree", &g_Kernel32); return pfn( hMem ); } typedef SIZE_T WINAPI FN_LocalShrink( HLOCAL hMem, UINT cbNewSize ); __declspec(dllexport) SIZE_T WINAPI kPrf2Wrap_LocalShrink( HLOCAL hMem, UINT cbNewSize ) { static FN_LocalShrink *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LocalShrink", &g_Kernel32); return pfn( hMem, cbNewSize ); } typedef SIZE_T WINAPI FN_LocalCompact( UINT uMinFree ); __declspec(dllexport) SIZE_T WINAPI kPrf2Wrap_LocalCompact( UINT uMinFree ) { static FN_LocalCompact *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LocalCompact", &g_Kernel32); return pfn( uMinFree ); } typedef BOOL WINAPI FN_FlushInstructionCache( HANDLE hProcess, LPCVOID lpBaseAddress, SIZE_T dwSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FlushInstructionCache( HANDLE hProcess, LPCVOID lpBaseAddress, SIZE_T dwSize ) { static FN_FlushInstructionCache *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FlushInstructionCache", &g_Kernel32); return pfn( hProcess, lpBaseAddress, dwSize ); } typedef LPVOID WINAPI FN_VirtualAlloc( LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect ); __declspec(dllexport) LPVOID WINAPI kPrf2Wrap_VirtualAlloc( LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect ) { static FN_VirtualAlloc *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "VirtualAlloc", &g_Kernel32); return pfn( lpAddress, dwSize, flAllocationType, flProtect ); } typedef BOOL WINAPI FN_VirtualFree( LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_VirtualFree( LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType ) { static FN_VirtualFree *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "VirtualFree", &g_Kernel32); return pfn( lpAddress, dwSize, dwFreeType ); } typedef BOOL WINAPI FN_VirtualProtect( LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_VirtualProtect( LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect ) { static FN_VirtualProtect *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "VirtualProtect", &g_Kernel32); return pfn( lpAddress, dwSize, flNewProtect, lpflOldProtect ); } typedef SIZE_T WINAPI FN_VirtualQuery( LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength ); __declspec(dllexport) SIZE_T WINAPI kPrf2Wrap_VirtualQuery( LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength ) { static FN_VirtualQuery *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "VirtualQuery", &g_Kernel32); return pfn( lpAddress, lpBuffer, dwLength ); } typedef LPVOID WINAPI FN_VirtualAllocEx( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect ); __declspec(dllexport) LPVOID WINAPI kPrf2Wrap_VirtualAllocEx( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect ) { static FN_VirtualAllocEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "VirtualAllocEx", &g_Kernel32); return pfn( hProcess, lpAddress, dwSize, flAllocationType, flProtect ); } typedef UINT WINAPI FN_GetWriteWatch( DWORD dwFlags, PVOID lpBaseAddress, SIZE_T dwRegionSize, PVOID * lpAddresses, ULONG_PTR * lpdwCount, PULONG lpdwGranularity ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_GetWriteWatch( DWORD dwFlags, PVOID lpBaseAddress, SIZE_T dwRegionSize, PVOID * lpAddresses, ULONG_PTR * lpdwCount, PULONG lpdwGranularity ) { static FN_GetWriteWatch *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetWriteWatch", &g_Kernel32); return pfn( dwFlags, lpBaseAddress, dwRegionSize, lpAddresses, lpdwCount, lpdwGranularity ); } typedef UINT WINAPI FN_ResetWriteWatch( LPVOID lpBaseAddress, SIZE_T dwRegionSize ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_ResetWriteWatch( LPVOID lpBaseAddress, SIZE_T dwRegionSize ) { static FN_ResetWriteWatch *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ResetWriteWatch", &g_Kernel32); return pfn( lpBaseAddress, dwRegionSize ); } typedef SIZE_T WINAPI FN_GetLargePageMinimum( VOID ); __declspec(dllexport) SIZE_T WINAPI kPrf2Wrap_GetLargePageMinimum( VOID ) { static FN_GetLargePageMinimum *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetLargePageMinimum", &g_Kernel32); return pfn (); } typedef UINT WINAPI FN_EnumSystemFirmwareTables( DWORD FirmwareTableProviderSignature, PVOID pFirmwareTableEnumBuffer, DWORD BufferSize ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_EnumSystemFirmwareTables( DWORD FirmwareTableProviderSignature, PVOID pFirmwareTableEnumBuffer, DWORD BufferSize ) { static FN_EnumSystemFirmwareTables *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnumSystemFirmwareTables", &g_Kernel32); return pfn( FirmwareTableProviderSignature, pFirmwareTableEnumBuffer, BufferSize ); } typedef UINT WINAPI FN_GetSystemFirmwareTable( DWORD FirmwareTableProviderSignature, DWORD FirmwareTableID, PVOID pFirmwareTableBuffer, DWORD BufferSize ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_GetSystemFirmwareTable( DWORD FirmwareTableProviderSignature, DWORD FirmwareTableID, PVOID pFirmwareTableBuffer, DWORD BufferSize ) { static FN_GetSystemFirmwareTable *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSystemFirmwareTable", &g_Kernel32); return pfn( FirmwareTableProviderSignature, FirmwareTableID, pFirmwareTableBuffer, BufferSize ); } typedef BOOL WINAPI FN_VirtualFreeEx( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_VirtualFreeEx( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType ) { static FN_VirtualFreeEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "VirtualFreeEx", &g_Kernel32); return pfn( hProcess, lpAddress, dwSize, dwFreeType ); } typedef BOOL WINAPI FN_VirtualProtectEx( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_VirtualProtectEx( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect ) { static FN_VirtualProtectEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "VirtualProtectEx", &g_Kernel32); return pfn( hProcess, lpAddress, dwSize, flNewProtect, lpflOldProtect ); } typedef SIZE_T WINAPI FN_VirtualQueryEx( HANDLE hProcess, LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength ); __declspec(dllexport) SIZE_T WINAPI kPrf2Wrap_VirtualQueryEx( HANDLE hProcess, LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength ) { static FN_VirtualQueryEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "VirtualQueryEx", &g_Kernel32); return pfn( hProcess, lpAddress, lpBuffer, dwLength ); } typedef HANDLE WINAPI FN_HeapCreate( DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_HeapCreate( DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize ) { static FN_HeapCreate *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "HeapCreate", &g_Kernel32); return pfn( flOptions, dwInitialSize, dwMaximumSize ); } typedef BOOL WINAPI FN_HeapDestroy( HANDLE hHeap ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_HeapDestroy( HANDLE hHeap ) { static FN_HeapDestroy *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "HeapDestroy", &g_Kernel32); return pfn( hHeap ); } typedef LPVOID WINAPI FN_HeapAlloc( HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes ); __declspec(dllexport) LPVOID WINAPI kPrf2Wrap_HeapAlloc( HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes ) { static FN_HeapAlloc *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "HeapAlloc", &g_Kernel32); return pfn( hHeap, dwFlags, dwBytes ); } typedef LPVOID WINAPI FN_HeapReAlloc( HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dwBytes ); __declspec(dllexport) LPVOID WINAPI kPrf2Wrap_HeapReAlloc( HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dwBytes ) { static FN_HeapReAlloc *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "HeapReAlloc", &g_Kernel32); return pfn( hHeap, dwFlags, lpMem, dwBytes ); } typedef BOOL WINAPI FN_HeapFree( HANDLE hHeap, DWORD dwFlags, LPVOID lpMem ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_HeapFree( HANDLE hHeap, DWORD dwFlags, LPVOID lpMem ) { static FN_HeapFree *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "HeapFree", &g_Kernel32); return pfn( hHeap, dwFlags, lpMem ); } typedef SIZE_T WINAPI FN_HeapSize( HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem ); __declspec(dllexport) SIZE_T WINAPI kPrf2Wrap_HeapSize( HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem ) { static FN_HeapSize *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "HeapSize", &g_Kernel32); return pfn( hHeap, dwFlags, lpMem ); } typedef BOOL WINAPI FN_HeapValidate( HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_HeapValidate( HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem ) { static FN_HeapValidate *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "HeapValidate", &g_Kernel32); return pfn( hHeap, dwFlags, lpMem ); } typedef SIZE_T WINAPI FN_HeapCompact( HANDLE hHeap, DWORD dwFlags ); __declspec(dllexport) SIZE_T WINAPI kPrf2Wrap_HeapCompact( HANDLE hHeap, DWORD dwFlags ) { static FN_HeapCompact *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "HeapCompact", &g_Kernel32); return pfn( hHeap, dwFlags ); } typedef HANDLE WINAPI FN_GetProcessHeap( VOID ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_GetProcessHeap( VOID ) { static FN_GetProcessHeap *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetProcessHeap", &g_Kernel32); return pfn (); } typedef DWORD WINAPI FN_GetProcessHeaps( DWORD NumberOfHeaps, PHANDLE ProcessHeaps ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetProcessHeaps( DWORD NumberOfHeaps, PHANDLE ProcessHeaps ) { static FN_GetProcessHeaps *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetProcessHeaps", &g_Kernel32); return pfn( NumberOfHeaps, ProcessHeaps ); } typedef BOOL WINAPI FN_HeapLock( HANDLE hHeap ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_HeapLock( HANDLE hHeap ) { static FN_HeapLock *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "HeapLock", &g_Kernel32); return pfn( hHeap ); } typedef BOOL WINAPI FN_HeapUnlock( HANDLE hHeap ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_HeapUnlock( HANDLE hHeap ) { static FN_HeapUnlock *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "HeapUnlock", &g_Kernel32); return pfn( hHeap ); } typedef BOOL WINAPI FN_HeapWalk( HANDLE hHeap, LPPROCESS_HEAP_ENTRY lpEntry ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_HeapWalk( HANDLE hHeap, LPPROCESS_HEAP_ENTRY lpEntry ) { static FN_HeapWalk *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "HeapWalk", &g_Kernel32); return pfn( hHeap, lpEntry ); } typedef BOOL WINAPI FN_HeapSetInformation( HANDLE HeapHandle, HEAP_INFORMATION_CLASS HeapInformationClass, PVOID HeapInformation, SIZE_T HeapInformationLength ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_HeapSetInformation( HANDLE HeapHandle, HEAP_INFORMATION_CLASS HeapInformationClass, PVOID HeapInformation, SIZE_T HeapInformationLength ) { static FN_HeapSetInformation *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "HeapSetInformation", &g_Kernel32); return pfn( HeapHandle, HeapInformationClass, HeapInformation, HeapInformationLength ); } typedef BOOL WINAPI FN_HeapQueryInformation( HANDLE HeapHandle, HEAP_INFORMATION_CLASS HeapInformationClass, PVOID HeapInformation, SIZE_T HeapInformationLength, PSIZE_T ReturnLength ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_HeapQueryInformation( HANDLE HeapHandle, HEAP_INFORMATION_CLASS HeapInformationClass, PVOID HeapInformation, SIZE_T HeapInformationLength, PSIZE_T ReturnLength ) { static FN_HeapQueryInformation *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "HeapQueryInformation", &g_Kernel32); return pfn( HeapHandle, HeapInformationClass, HeapInformation, HeapInformationLength, ReturnLength ); } typedef BOOL WINAPI FN_GetBinaryTypeA( LPCSTR lpApplicationName, LPDWORD lpBinaryType ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetBinaryTypeA( LPCSTR lpApplicationName, LPDWORD lpBinaryType ) { static FN_GetBinaryTypeA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetBinaryTypeA", &g_Kernel32); return pfn( lpApplicationName, lpBinaryType ); } typedef BOOL WINAPI FN_GetBinaryTypeW( LPCWSTR lpApplicationName, LPDWORD lpBinaryType ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetBinaryTypeW( LPCWSTR lpApplicationName, LPDWORD lpBinaryType ) { static FN_GetBinaryTypeW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetBinaryTypeW", &g_Kernel32); return pfn( lpApplicationName, lpBinaryType ); } typedef DWORD WINAPI FN_GetShortPathNameA( LPCSTR lpszLongPath, LPSTR lpszShortPath, DWORD cchBuffer ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetShortPathNameA( LPCSTR lpszLongPath, LPSTR lpszShortPath, DWORD cchBuffer ) { static FN_GetShortPathNameA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetShortPathNameA", &g_Kernel32); return pfn( lpszLongPath, lpszShortPath, cchBuffer ); } typedef DWORD WINAPI FN_GetShortPathNameW( LPCWSTR lpszLongPath, LPWSTR lpszShortPath, DWORD cchBuffer ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetShortPathNameW( LPCWSTR lpszLongPath, LPWSTR lpszShortPath, DWORD cchBuffer ) { static FN_GetShortPathNameW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetShortPathNameW", &g_Kernel32); return pfn( lpszLongPath, lpszShortPath, cchBuffer ); } typedef DWORD WINAPI FN_GetLongPathNameA( LPCSTR lpszShortPath, LPSTR lpszLongPath, DWORD cchBuffer ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetLongPathNameA( LPCSTR lpszShortPath, LPSTR lpszLongPath, DWORD cchBuffer ) { static FN_GetLongPathNameA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetLongPathNameA", &g_Kernel32); return pfn( lpszShortPath, lpszLongPath, cchBuffer ); } typedef DWORD WINAPI FN_GetLongPathNameW( LPCWSTR lpszShortPath, LPWSTR lpszLongPath, DWORD cchBuffer ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetLongPathNameW( LPCWSTR lpszShortPath, LPWSTR lpszLongPath, DWORD cchBuffer ) { static FN_GetLongPathNameW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetLongPathNameW", &g_Kernel32); return pfn( lpszShortPath, lpszLongPath, cchBuffer ); } typedef BOOL WINAPI FN_GetProcessAffinityMask( HANDLE hProcess, PDWORD_PTR lpProcessAffinityMask, PDWORD_PTR lpSystemAffinityMask ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetProcessAffinityMask( HANDLE hProcess, PDWORD_PTR lpProcessAffinityMask, PDWORD_PTR lpSystemAffinityMask ) { static FN_GetProcessAffinityMask *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetProcessAffinityMask", &g_Kernel32); return pfn( hProcess, lpProcessAffinityMask, lpSystemAffinityMask ); } typedef BOOL WINAPI FN_SetProcessAffinityMask( HANDLE hProcess, DWORD_PTR dwProcessAffinityMask ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetProcessAffinityMask( HANDLE hProcess, DWORD_PTR dwProcessAffinityMask ) { static FN_SetProcessAffinityMask *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetProcessAffinityMask", &g_Kernel32); return pfn( hProcess, dwProcessAffinityMask ); } typedef BOOL WINAPI FN_GetProcessHandleCount( HANDLE hProcess, PDWORD pdwHandleCount ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetProcessHandleCount( HANDLE hProcess, PDWORD pdwHandleCount ) { static FN_GetProcessHandleCount *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetProcessHandleCount", &g_Kernel32); return pfn( hProcess, pdwHandleCount ); } typedef BOOL WINAPI FN_GetProcessTimes( HANDLE hProcess, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetProcessTimes( HANDLE hProcess, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime ) { static FN_GetProcessTimes *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetProcessTimes", &g_Kernel32); return pfn( hProcess, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime ); } typedef BOOL WINAPI FN_GetProcessIoCounters( HANDLE hProcess, PIO_COUNTERS lpIoCounters ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetProcessIoCounters( HANDLE hProcess, PIO_COUNTERS lpIoCounters ) { static FN_GetProcessIoCounters *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetProcessIoCounters", &g_Kernel32); return pfn( hProcess, lpIoCounters ); } typedef BOOL WINAPI FN_GetProcessWorkingSetSize( HANDLE hProcess, PSIZE_T lpMinimumWorkingSetSize, PSIZE_T lpMaximumWorkingSetSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetProcessWorkingSetSize( HANDLE hProcess, PSIZE_T lpMinimumWorkingSetSize, PSIZE_T lpMaximumWorkingSetSize ) { static FN_GetProcessWorkingSetSize *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetProcessWorkingSetSize", &g_Kernel32); return pfn( hProcess, lpMinimumWorkingSetSize, lpMaximumWorkingSetSize ); } typedef BOOL WINAPI FN_GetProcessWorkingSetSizeEx( HANDLE hProcess, PSIZE_T lpMinimumWorkingSetSize, PSIZE_T lpMaximumWorkingSetSize, PDWORD Flags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetProcessWorkingSetSizeEx( HANDLE hProcess, PSIZE_T lpMinimumWorkingSetSize, PSIZE_T lpMaximumWorkingSetSize, PDWORD Flags ) { static FN_GetProcessWorkingSetSizeEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetProcessWorkingSetSizeEx", &g_Kernel32); return pfn( hProcess, lpMinimumWorkingSetSize, lpMaximumWorkingSetSize, Flags ); } typedef BOOL WINAPI FN_SetProcessWorkingSetSize( HANDLE hProcess, SIZE_T dwMinimumWorkingSetSize, SIZE_T dwMaximumWorkingSetSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetProcessWorkingSetSize( HANDLE hProcess, SIZE_T dwMinimumWorkingSetSize, SIZE_T dwMaximumWorkingSetSize ) { static FN_SetProcessWorkingSetSize *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetProcessWorkingSetSize", &g_Kernel32); return pfn( hProcess, dwMinimumWorkingSetSize, dwMaximumWorkingSetSize ); } typedef BOOL WINAPI FN_SetProcessWorkingSetSizeEx( HANDLE hProcess, SIZE_T dwMinimumWorkingSetSize, SIZE_T dwMaximumWorkingSetSize, DWORD Flags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetProcessWorkingSetSizeEx( HANDLE hProcess, SIZE_T dwMinimumWorkingSetSize, SIZE_T dwMaximumWorkingSetSize, DWORD Flags ) { static FN_SetProcessWorkingSetSizeEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetProcessWorkingSetSizeEx", &g_Kernel32); return pfn( hProcess, dwMinimumWorkingSetSize, dwMaximumWorkingSetSize, Flags ); } typedef HANDLE WINAPI FN_OpenProcess( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenProcess( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId ) { static FN_OpenProcess *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "OpenProcess", &g_Kernel32); return pfn( dwDesiredAccess, bInheritHandle, dwProcessId ); } typedef HANDLE WINAPI FN_GetCurrentProcess( VOID ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_GetCurrentProcess( VOID ) { static FN_GetCurrentProcess *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetCurrentProcess", &g_Kernel32); return pfn (); } typedef DWORD WINAPI FN_GetCurrentProcessId( VOID ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetCurrentProcessId( VOID ) { static FN_GetCurrentProcessId *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetCurrentProcessId", &g_Kernel32); return pfn (); } typedef VOID WINAPI FN_ExitProcess( UINT uExitCode ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_ExitProcess( UINT uExitCode ) { static FN_ExitProcess *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ExitProcess", &g_Kernel32); pfn( uExitCode ); } typedef BOOL WINAPI FN_TerminateProcess( HANDLE hProcess, UINT uExitCode ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_TerminateProcess( HANDLE hProcess, UINT uExitCode ) { static FN_TerminateProcess *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "TerminateProcess", &g_Kernel32); return pfn( hProcess, uExitCode ); } typedef BOOL WINAPI FN_GetExitCodeProcess( HANDLE hProcess, LPDWORD lpExitCode ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetExitCodeProcess( HANDLE hProcess, LPDWORD lpExitCode ) { static FN_GetExitCodeProcess *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetExitCodeProcess", &g_Kernel32); return pfn( hProcess, lpExitCode ); } typedef VOID WINAPI FN_FatalExit( int ExitCode ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_FatalExit( int ExitCode ) { static FN_FatalExit *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FatalExit", &g_Kernel32); pfn( ExitCode ); } typedef LPCH WINAPI FN_GetEnvironmentStrings( VOID ); __declspec(dllexport) LPCH WINAPI kPrf2Wrap_GetEnvironmentStrings( VOID ) { static FN_GetEnvironmentStrings *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetEnvironmentStrings", &g_Kernel32); return pfn (); } typedef LPWCH WINAPI FN_GetEnvironmentStringsW( VOID ); __declspec(dllexport) LPWCH WINAPI kPrf2Wrap_GetEnvironmentStringsW( VOID ) { static FN_GetEnvironmentStringsW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetEnvironmentStringsW", &g_Kernel32); return pfn (); } typedef BOOL WINAPI FN_SetEnvironmentStringsA( LPCH NewEnvironment ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetEnvironmentStringsA( LPCH NewEnvironment ) { static FN_SetEnvironmentStringsA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetEnvironmentStringsA", &g_Kernel32); return pfn( NewEnvironment ); } typedef BOOL WINAPI FN_SetEnvironmentStringsW( LPWCH NewEnvironment ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetEnvironmentStringsW( LPWCH NewEnvironment ) { static FN_SetEnvironmentStringsW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetEnvironmentStringsW", &g_Kernel32); return pfn( NewEnvironment ); } typedef BOOL WINAPI FN_FreeEnvironmentStringsA( LPCH a); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FreeEnvironmentStringsA( LPCH a) { static FN_FreeEnvironmentStringsA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FreeEnvironmentStringsA", &g_Kernel32); return pfn( a); } typedef BOOL WINAPI FN_FreeEnvironmentStringsW( LPWCH a); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FreeEnvironmentStringsW( LPWCH a) { static FN_FreeEnvironmentStringsW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FreeEnvironmentStringsW", &g_Kernel32); return pfn( a); } typedef VOID WINAPI FN_RaiseException( DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments, CONST ULONG_PTR * lpArguments ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_RaiseException( DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments, CONST ULONG_PTR * lpArguments ) { static FN_RaiseException *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RaiseException", &g_Kernel32); pfn( dwExceptionCode, dwExceptionFlags, nNumberOfArguments, lpArguments ); } typedef LONG WINAPI FN_UnhandledExceptionFilter( struct _EXCEPTION_POINTERS * ExceptionInfo ); __declspec(dllexport) LONG WINAPI kPrf2Wrap_UnhandledExceptionFilter( struct _EXCEPTION_POINTERS * ExceptionInfo ) { static FN_UnhandledExceptionFilter *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "UnhandledExceptionFilter", &g_Kernel32); return pfn( ExceptionInfo ); } typedef LPTOP_LEVEL_EXCEPTION_FILTER WINAPI FN_SetUnhandledExceptionFilter( LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter ); __declspec(dllexport) LPTOP_LEVEL_EXCEPTION_FILTER WINAPI kPrf2Wrap_SetUnhandledExceptionFilter( LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter ) { static FN_SetUnhandledExceptionFilter *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetUnhandledExceptionFilter", &g_Kernel32); return pfn( lpTopLevelExceptionFilter ); } typedef LPVOID WINAPI FN_CreateFiber( SIZE_T dwStackSize, LPFIBER_START_ROUTINE lpStartAddress, LPVOID lpParameter ); __declspec(dllexport) LPVOID WINAPI kPrf2Wrap_CreateFiber( SIZE_T dwStackSize, LPFIBER_START_ROUTINE lpStartAddress, LPVOID lpParameter ) { static FN_CreateFiber *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateFiber", &g_Kernel32); return pfn( dwStackSize, lpStartAddress, lpParameter ); } typedef LPVOID WINAPI FN_CreateFiberEx( SIZE_T dwStackCommitSize, SIZE_T dwStackReserveSize, DWORD dwFlags, LPFIBER_START_ROUTINE lpStartAddress, LPVOID lpParameter ); __declspec(dllexport) LPVOID WINAPI kPrf2Wrap_CreateFiberEx( SIZE_T dwStackCommitSize, SIZE_T dwStackReserveSize, DWORD dwFlags, LPFIBER_START_ROUTINE lpStartAddress, LPVOID lpParameter ) { static FN_CreateFiberEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateFiberEx", &g_Kernel32); return pfn( dwStackCommitSize, dwStackReserveSize, dwFlags, lpStartAddress, lpParameter ); } typedef VOID WINAPI FN_DeleteFiber( LPVOID lpFiber ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_DeleteFiber( LPVOID lpFiber ) { static FN_DeleteFiber *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DeleteFiber", &g_Kernel32); pfn( lpFiber ); } typedef LPVOID WINAPI FN_ConvertThreadToFiber( LPVOID lpParameter ); __declspec(dllexport) LPVOID WINAPI kPrf2Wrap_ConvertThreadToFiber( LPVOID lpParameter ) { static FN_ConvertThreadToFiber *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ConvertThreadToFiber", &g_Kernel32); return pfn( lpParameter ); } typedef LPVOID WINAPI FN_ConvertThreadToFiberEx( LPVOID lpParameter, DWORD dwFlags ); __declspec(dllexport) LPVOID WINAPI kPrf2Wrap_ConvertThreadToFiberEx( LPVOID lpParameter, DWORD dwFlags ) { static FN_ConvertThreadToFiberEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ConvertThreadToFiberEx", &g_Kernel32); return pfn( lpParameter, dwFlags ); } typedef BOOL WINAPI FN_ConvertFiberToThread( VOID ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ConvertFiberToThread( VOID ) { static FN_ConvertFiberToThread *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ConvertFiberToThread", &g_Kernel32); return pfn (); } typedef VOID WINAPI FN_SwitchToFiber( LPVOID lpFiber ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_SwitchToFiber( LPVOID lpFiber ) { static FN_SwitchToFiber *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SwitchToFiber", &g_Kernel32); pfn( lpFiber ); } typedef BOOL WINAPI FN_SwitchToThread( VOID ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SwitchToThread( VOID ) { static FN_SwitchToThread *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SwitchToThread", &g_Kernel32); return pfn (); } typedef HANDLE WINAPI FN_CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ) { static FN_CreateThread *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateThread", &g_Kernel32); return pfn( lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId ); } typedef HANDLE WINAPI FN_CreateRemoteThread( HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateRemoteThread( HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ) { static FN_CreateRemoteThread *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateRemoteThread", &g_Kernel32); return pfn( hProcess, lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId ); } typedef HANDLE WINAPI FN_GetCurrentThread( VOID ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_GetCurrentThread( VOID ) { static FN_GetCurrentThread *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetCurrentThread", &g_Kernel32); return pfn (); } typedef DWORD WINAPI FN_GetCurrentThreadId( VOID ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetCurrentThreadId( VOID ) { static FN_GetCurrentThreadId *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetCurrentThreadId", &g_Kernel32); return pfn (); } typedef BOOL WINAPI FN_SetThreadStackGuarantee( PULONG StackSizeInBytes ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetThreadStackGuarantee( PULONG StackSizeInBytes ) { static FN_SetThreadStackGuarantee *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetThreadStackGuarantee", &g_Kernel32); return pfn( StackSizeInBytes ); } typedef DWORD WINAPI FN_GetProcessIdOfThread( HANDLE Thread ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetProcessIdOfThread( HANDLE Thread ) { static FN_GetProcessIdOfThread *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetProcessIdOfThread", &g_Kernel32); return pfn( Thread ); } typedef DWORD WINAPI FN_GetThreadId( HANDLE Thread ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetThreadId( HANDLE Thread ) { static FN_GetThreadId *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetThreadId", &g_Kernel32); return pfn( Thread ); } typedef DWORD WINAPI FN_GetProcessId( HANDLE Process ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetProcessId( HANDLE Process ) { static FN_GetProcessId *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetProcessId", &g_Kernel32); return pfn( Process ); } typedef DWORD WINAPI FN_GetCurrentProcessorNumber( VOID ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetCurrentProcessorNumber( VOID ) { static FN_GetCurrentProcessorNumber *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetCurrentProcessorNumber", &g_Kernel32); return pfn (); } typedef DWORD_PTR WINAPI FN_SetThreadAffinityMask( HANDLE hThread, DWORD_PTR dwThreadAffinityMask ); __declspec(dllexport) DWORD_PTR WINAPI kPrf2Wrap_SetThreadAffinityMask( HANDLE hThread, DWORD_PTR dwThreadAffinityMask ) { static FN_SetThreadAffinityMask *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetThreadAffinityMask", &g_Kernel32); return pfn( hThread, dwThreadAffinityMask ); } typedef DWORD WINAPI FN_SetThreadIdealProcessor( HANDLE hThread, DWORD dwIdealProcessor ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_SetThreadIdealProcessor( HANDLE hThread, DWORD dwIdealProcessor ) { static FN_SetThreadIdealProcessor *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetThreadIdealProcessor", &g_Kernel32); return pfn( hThread, dwIdealProcessor ); } typedef BOOL WINAPI FN_SetProcessPriorityBoost( HANDLE hProcess, BOOL bDisablePriorityBoost ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetProcessPriorityBoost( HANDLE hProcess, BOOL bDisablePriorityBoost ) { static FN_SetProcessPriorityBoost *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetProcessPriorityBoost", &g_Kernel32); return pfn( hProcess, bDisablePriorityBoost ); } typedef BOOL WINAPI FN_GetProcessPriorityBoost( HANDLE hProcess, PBOOL pDisablePriorityBoost ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetProcessPriorityBoost( HANDLE hProcess, PBOOL pDisablePriorityBoost ) { static FN_GetProcessPriorityBoost *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetProcessPriorityBoost", &g_Kernel32); return pfn( hProcess, pDisablePriorityBoost ); } typedef BOOL WINAPI FN_RequestWakeupLatency( LATENCY_TIME latency ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_RequestWakeupLatency( LATENCY_TIME latency ) { static FN_RequestWakeupLatency *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RequestWakeupLatency", &g_Kernel32); return pfn( latency ); } typedef BOOL WINAPI FN_IsSystemResumeAutomatic( VOID ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsSystemResumeAutomatic( VOID ) { static FN_IsSystemResumeAutomatic *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "IsSystemResumeAutomatic", &g_Kernel32); return pfn (); } typedef HANDLE WINAPI FN_OpenThread( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenThread( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId ) { static FN_OpenThread *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "OpenThread", &g_Kernel32); return pfn( dwDesiredAccess, bInheritHandle, dwThreadId ); } typedef BOOL WINAPI FN_SetThreadPriority( HANDLE hThread, int nPriority ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetThreadPriority( HANDLE hThread, int nPriority ) { static FN_SetThreadPriority *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetThreadPriority", &g_Kernel32); return pfn( hThread, nPriority ); } typedef BOOL WINAPI FN_SetThreadPriorityBoost( HANDLE hThread, BOOL bDisablePriorityBoost ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetThreadPriorityBoost( HANDLE hThread, BOOL bDisablePriorityBoost ) { static FN_SetThreadPriorityBoost *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetThreadPriorityBoost", &g_Kernel32); return pfn( hThread, bDisablePriorityBoost ); } typedef BOOL WINAPI FN_GetThreadPriorityBoost( HANDLE hThread, PBOOL pDisablePriorityBoost ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetThreadPriorityBoost( HANDLE hThread, PBOOL pDisablePriorityBoost ) { static FN_GetThreadPriorityBoost *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetThreadPriorityBoost", &g_Kernel32); return pfn( hThread, pDisablePriorityBoost ); } typedef int WINAPI FN_GetThreadPriority( HANDLE hThread ); __declspec(dllexport) int WINAPI kPrf2Wrap_GetThreadPriority( HANDLE hThread ) { static FN_GetThreadPriority *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetThreadPriority", &g_Kernel32); return pfn( hThread ); } typedef BOOL WINAPI FN_GetThreadTimes( HANDLE hThread, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetThreadTimes( HANDLE hThread, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime ) { static FN_GetThreadTimes *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetThreadTimes", &g_Kernel32); return pfn( hThread, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime ); } typedef BOOL WINAPI FN_GetThreadIOPendingFlag( HANDLE hThread, PBOOL lpIOIsPending ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetThreadIOPendingFlag( HANDLE hThread, PBOOL lpIOIsPending ) { static FN_GetThreadIOPendingFlag *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetThreadIOPendingFlag", &g_Kernel32); return pfn( hThread, lpIOIsPending ); } typedef VOID WINAPI FN_ExitThread( DWORD dwExitCode ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_ExitThread( DWORD dwExitCode ) { static FN_ExitThread *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ExitThread", &g_Kernel32); pfn( dwExitCode ); } typedef BOOL WINAPI FN_TerminateThread( HANDLE hThread, DWORD dwExitCode ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_TerminateThread( HANDLE hThread, DWORD dwExitCode ) { static FN_TerminateThread *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "TerminateThread", &g_Kernel32); return pfn( hThread, dwExitCode ); } typedef BOOL WINAPI FN_GetExitCodeThread( HANDLE hThread, LPDWORD lpExitCode ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetExitCodeThread( HANDLE hThread, LPDWORD lpExitCode ) { static FN_GetExitCodeThread *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetExitCodeThread", &g_Kernel32); return pfn( hThread, lpExitCode ); } typedef BOOL WINAPI FN_GetThreadSelectorEntry( HANDLE hThread, DWORD dwSelector, LPLDT_ENTRY lpSelectorEntry ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetThreadSelectorEntry( HANDLE hThread, DWORD dwSelector, LPLDT_ENTRY lpSelectorEntry ) { static FN_GetThreadSelectorEntry *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetThreadSelectorEntry", &g_Kernel32); return pfn( hThread, dwSelector, lpSelectorEntry ); } typedef EXECUTION_STATE WINAPI FN_SetThreadExecutionState( EXECUTION_STATE esFlags ); __declspec(dllexport) EXECUTION_STATE WINAPI kPrf2Wrap_SetThreadExecutionState( EXECUTION_STATE esFlags ) { static FN_SetThreadExecutionState *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetThreadExecutionState", &g_Kernel32); return pfn( esFlags ); } typedef DWORD WINAPI FN_GetLastError( VOID ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetLastError( VOID ) { static FN_GetLastError *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetLastError", &g_Kernel32); return pfn (); } typedef VOID WINAPI FN_SetLastError( DWORD dwErrCode ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_SetLastError( DWORD dwErrCode ) { static FN_SetLastError *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetLastError", &g_Kernel32); pfn( dwErrCode ); } typedef VOID WINAPI FN_RestoreLastError( DWORD dwErrCode ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_RestoreLastError( DWORD dwErrCode ) { static FN_RestoreLastError *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RestoreLastError", &g_Kernel32); pfn( dwErrCode ); } typedef BOOL WINAPI FN_GetOverlappedResult( HANDLE hFile, LPOVERLAPPED lpOverlapped, LPDWORD lpNumberOfBytesTransferred, BOOL bWait ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetOverlappedResult( HANDLE hFile, LPOVERLAPPED lpOverlapped, LPDWORD lpNumberOfBytesTransferred, BOOL bWait ) { static FN_GetOverlappedResult *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetOverlappedResult", &g_Kernel32); return pfn( hFile, lpOverlapped, lpNumberOfBytesTransferred, bWait ); } typedef HANDLE WINAPI FN_CreateIoCompletionPort( HANDLE FileHandle, HANDLE ExistingCompletionPort, ULONG_PTR CompletionKey, DWORD NumberOfConcurrentThreads ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateIoCompletionPort( HANDLE FileHandle, HANDLE ExistingCompletionPort, ULONG_PTR CompletionKey, DWORD NumberOfConcurrentThreads ) { static FN_CreateIoCompletionPort *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateIoCompletionPort", &g_Kernel32); return pfn( FileHandle, ExistingCompletionPort, CompletionKey, NumberOfConcurrentThreads ); } typedef BOOL WINAPI FN_GetQueuedCompletionStatus( HANDLE CompletionPort, LPDWORD lpNumberOfBytesTransferred, PULONG_PTR lpCompletionKey, LPOVERLAPPED * lpOverlapped, DWORD dwMilliseconds ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetQueuedCompletionStatus( HANDLE CompletionPort, LPDWORD lpNumberOfBytesTransferred, PULONG_PTR lpCompletionKey, LPOVERLAPPED * lpOverlapped, DWORD dwMilliseconds ) { static FN_GetQueuedCompletionStatus *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetQueuedCompletionStatus", &g_Kernel32); return pfn( CompletionPort, lpNumberOfBytesTransferred, lpCompletionKey, lpOverlapped, dwMilliseconds ); } typedef BOOL WINAPI FN_PostQueuedCompletionStatus( HANDLE CompletionPort, DWORD dwNumberOfBytesTransferred, ULONG_PTR dwCompletionKey, LPOVERLAPPED lpOverlapped ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_PostQueuedCompletionStatus( HANDLE CompletionPort, DWORD dwNumberOfBytesTransferred, ULONG_PTR dwCompletionKey, LPOVERLAPPED lpOverlapped ) { static FN_PostQueuedCompletionStatus *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "PostQueuedCompletionStatus", &g_Kernel32); return pfn( CompletionPort, dwNumberOfBytesTransferred, dwCompletionKey, lpOverlapped ); } typedef UINT WINAPI FN_SetErrorMode( UINT uMode ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_SetErrorMode( UINT uMode ) { static FN_SetErrorMode *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetErrorMode", &g_Kernel32); return pfn( uMode ); } typedef BOOL WINAPI FN_ReadProcessMemory( HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesRead ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadProcessMemory( HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesRead ) { static FN_ReadProcessMemory *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ReadProcessMemory", &g_Kernel32); return pfn( hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead ); } typedef BOOL WINAPI FN_WriteProcessMemory( HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesWritten ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteProcessMemory( HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesWritten ) { static FN_WriteProcessMemory *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WriteProcessMemory", &g_Kernel32); return pfn( hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesWritten ); } typedef BOOL WINAPI FN_GetThreadContext( HANDLE hThread, LPCONTEXT lpContext ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetThreadContext( HANDLE hThread, LPCONTEXT lpContext ) { static FN_GetThreadContext *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetThreadContext", &g_Kernel32); return pfn( hThread, lpContext ); } typedef BOOL WINAPI FN_SetThreadContext( HANDLE hThread, CONST CONTEXT * lpContext ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetThreadContext( HANDLE hThread, CONST CONTEXT * lpContext ) { static FN_SetThreadContext *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetThreadContext", &g_Kernel32); return pfn( hThread, lpContext ); } typedef DWORD WINAPI FN_SuspendThread( HANDLE hThread ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_SuspendThread( HANDLE hThread ) { static FN_SuspendThread *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SuspendThread", &g_Kernel32); return pfn( hThread ); } typedef DWORD WINAPI FN_ResumeThread( HANDLE hThread ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_ResumeThread( HANDLE hThread ) { static FN_ResumeThread *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ResumeThread", &g_Kernel32); return pfn( hThread ); } typedef DWORD WINAPI FN_QueueUserAPC( PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_QueueUserAPC( PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData ) { static FN_QueueUserAPC *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "QueueUserAPC", &g_Kernel32); return pfn( pfnAPC, hThread, dwData ); } typedef BOOL WINAPI FN_IsDebuggerPresent( VOID ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsDebuggerPresent( VOID ) { static FN_IsDebuggerPresent *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "IsDebuggerPresent", &g_Kernel32); return pfn (); } typedef BOOL WINAPI FN_CheckRemoteDebuggerPresent( HANDLE hProcess, PBOOL pbDebuggerPresent ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CheckRemoteDebuggerPresent( HANDLE hProcess, PBOOL pbDebuggerPresent ) { static FN_CheckRemoteDebuggerPresent *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CheckRemoteDebuggerPresent", &g_Kernel32); return pfn( hProcess, pbDebuggerPresent ); } typedef VOID WINAPI FN_DebugBreak( VOID ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_DebugBreak( VOID ) { static FN_DebugBreak *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DebugBreak", &g_Kernel32); pfn (); } typedef BOOL WINAPI FN_WaitForDebugEvent( LPDEBUG_EVENT lpDebugEvent, DWORD dwMilliseconds ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_WaitForDebugEvent( LPDEBUG_EVENT lpDebugEvent, DWORD dwMilliseconds ) { static FN_WaitForDebugEvent *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WaitForDebugEvent", &g_Kernel32); return pfn( lpDebugEvent, dwMilliseconds ); } typedef BOOL WINAPI FN_ContinueDebugEvent( DWORD dwProcessId, DWORD dwThreadId, DWORD dwContinueStatus ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ContinueDebugEvent( DWORD dwProcessId, DWORD dwThreadId, DWORD dwContinueStatus ) { static FN_ContinueDebugEvent *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ContinueDebugEvent", &g_Kernel32); return pfn( dwProcessId, dwThreadId, dwContinueStatus ); } typedef BOOL WINAPI FN_DebugActiveProcess( DWORD dwProcessId ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_DebugActiveProcess( DWORD dwProcessId ) { static FN_DebugActiveProcess *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DebugActiveProcess", &g_Kernel32); return pfn( dwProcessId ); } typedef BOOL WINAPI FN_DebugActiveProcessStop( DWORD dwProcessId ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_DebugActiveProcessStop( DWORD dwProcessId ) { static FN_DebugActiveProcessStop *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DebugActiveProcessStop", &g_Kernel32); return pfn( dwProcessId ); } typedef BOOL WINAPI FN_DebugSetProcessKillOnExit( BOOL KillOnExit ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_DebugSetProcessKillOnExit( BOOL KillOnExit ) { static FN_DebugSetProcessKillOnExit *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DebugSetProcessKillOnExit", &g_Kernel32); return pfn( KillOnExit ); } typedef BOOL WINAPI FN_DebugBreakProcess( HANDLE Process ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_DebugBreakProcess( HANDLE Process ) { static FN_DebugBreakProcess *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DebugBreakProcess", &g_Kernel32); return pfn( Process ); } typedef VOID WINAPI FN_InitializeCriticalSection( LPCRITICAL_SECTION lpCriticalSection ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_InitializeCriticalSection( LPCRITICAL_SECTION lpCriticalSection ) { static FN_InitializeCriticalSection *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "InitializeCriticalSection", &g_Kernel32); pfn( lpCriticalSection ); } typedef VOID WINAPI FN_EnterCriticalSection( LPCRITICAL_SECTION lpCriticalSection ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_EnterCriticalSection( LPCRITICAL_SECTION lpCriticalSection ) { static FN_EnterCriticalSection *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnterCriticalSection", &g_Kernel32); pfn( lpCriticalSection ); } typedef VOID WINAPI FN_LeaveCriticalSection( LPCRITICAL_SECTION lpCriticalSection ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_LeaveCriticalSection( LPCRITICAL_SECTION lpCriticalSection ) { static FN_LeaveCriticalSection *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LeaveCriticalSection", &g_Kernel32); pfn( lpCriticalSection ); } typedef BOOL WINAPI FN_InitializeCriticalSectionAndSpinCount( LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_InitializeCriticalSectionAndSpinCount( LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount ) { static FN_InitializeCriticalSectionAndSpinCount *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "InitializeCriticalSectionAndSpinCount", &g_Kernel32); return pfn( lpCriticalSection, dwSpinCount ); } typedef DWORD WINAPI FN_SetCriticalSectionSpinCount( LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_SetCriticalSectionSpinCount( LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount ) { static FN_SetCriticalSectionSpinCount *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetCriticalSectionSpinCount", &g_Kernel32); return pfn( lpCriticalSection, dwSpinCount ); } typedef BOOL WINAPI FN_TryEnterCriticalSection( LPCRITICAL_SECTION lpCriticalSection ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_TryEnterCriticalSection( LPCRITICAL_SECTION lpCriticalSection ) { static FN_TryEnterCriticalSection *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "TryEnterCriticalSection", &g_Kernel32); return pfn( lpCriticalSection ); } typedef VOID WINAPI FN_DeleteCriticalSection( LPCRITICAL_SECTION lpCriticalSection ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_DeleteCriticalSection( LPCRITICAL_SECTION lpCriticalSection ) { static FN_DeleteCriticalSection *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DeleteCriticalSection", &g_Kernel32); pfn( lpCriticalSection ); } typedef BOOL WINAPI FN_SetEvent( HANDLE hEvent ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetEvent( HANDLE hEvent ) { static FN_SetEvent *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetEvent", &g_Kernel32); return pfn( hEvent ); } typedef BOOL WINAPI FN_ResetEvent( HANDLE hEvent ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ResetEvent( HANDLE hEvent ) { static FN_ResetEvent *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ResetEvent", &g_Kernel32); return pfn( hEvent ); } typedef BOOL WINAPI FN_PulseEvent( HANDLE hEvent ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_PulseEvent( HANDLE hEvent ) { static FN_PulseEvent *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "PulseEvent", &g_Kernel32); return pfn( hEvent ); } typedef BOOL WINAPI FN_ReleaseSemaphore( HANDLE hSemaphore, LONG lReleaseCount, LPLONG lpPreviousCount ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReleaseSemaphore( HANDLE hSemaphore, LONG lReleaseCount, LPLONG lpPreviousCount ) { static FN_ReleaseSemaphore *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ReleaseSemaphore", &g_Kernel32); return pfn( hSemaphore, lReleaseCount, lpPreviousCount ); } typedef BOOL WINAPI FN_ReleaseMutex( HANDLE hMutex ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReleaseMutex( HANDLE hMutex ) { static FN_ReleaseMutex *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ReleaseMutex", &g_Kernel32); return pfn( hMutex ); } typedef DWORD WINAPI FN_WaitForSingleObject( HANDLE hHandle, DWORD dwMilliseconds ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_WaitForSingleObject( HANDLE hHandle, DWORD dwMilliseconds ) { static FN_WaitForSingleObject *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WaitForSingleObject", &g_Kernel32); return pfn( hHandle, dwMilliseconds ); } typedef DWORD WINAPI FN_WaitForMultipleObjects( DWORD nCount, CONST HANDLE * lpHandles, BOOL bWaitAll, DWORD dwMilliseconds ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_WaitForMultipleObjects( DWORD nCount, CONST HANDLE * lpHandles, BOOL bWaitAll, DWORD dwMilliseconds ) { static FN_WaitForMultipleObjects *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WaitForMultipleObjects", &g_Kernel32); return pfn( nCount, lpHandles, bWaitAll, dwMilliseconds ); } typedef VOID WINAPI FN_Sleep( DWORD dwMilliseconds ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_Sleep( DWORD dwMilliseconds ) { static FN_Sleep *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "Sleep", &g_Kernel32); pfn( dwMilliseconds ); } typedef HGLOBAL WINAPI FN_LoadResource( HMODULE hModule, HRSRC hResInfo ); __declspec(dllexport) HGLOBAL WINAPI kPrf2Wrap_LoadResource( HMODULE hModule, HRSRC hResInfo ) { static FN_LoadResource *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LoadResource", &g_Kernel32); return pfn( hModule, hResInfo ); } typedef DWORD WINAPI FN_SizeofResource( HMODULE hModule, HRSRC hResInfo ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_SizeofResource( HMODULE hModule, HRSRC hResInfo ) { static FN_SizeofResource *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SizeofResource", &g_Kernel32); return pfn( hModule, hResInfo ); } typedef ATOM WINAPI FN_GlobalDeleteAtom( ATOM nAtom ); __declspec(dllexport) ATOM WINAPI kPrf2Wrap_GlobalDeleteAtom( ATOM nAtom ) { static FN_GlobalDeleteAtom *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GlobalDeleteAtom", &g_Kernel32); return pfn( nAtom ); } typedef BOOL WINAPI FN_InitAtomTable( DWORD nSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_InitAtomTable( DWORD nSize ) { static FN_InitAtomTable *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "InitAtomTable", &g_Kernel32); return pfn( nSize ); } typedef ATOM WINAPI FN_DeleteAtom( ATOM nAtom ); __declspec(dllexport) ATOM WINAPI kPrf2Wrap_DeleteAtom( ATOM nAtom ) { static FN_DeleteAtom *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DeleteAtom", &g_Kernel32); return pfn( nAtom ); } typedef UINT WINAPI FN_SetHandleCount( UINT uNumber ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_SetHandleCount( UINT uNumber ) { static FN_SetHandleCount *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetHandleCount", &g_Kernel32); return pfn( uNumber ); } typedef DWORD WINAPI FN_GetLogicalDrives( VOID ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetLogicalDrives( VOID ) { static FN_GetLogicalDrives *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetLogicalDrives", &g_Kernel32); return pfn (); } typedef BOOL WINAPI FN_LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh ) { static FN_LockFile *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LockFile", &g_Kernel32); return pfn( hFile, dwFileOffsetLow, dwFileOffsetHigh, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh ); } typedef BOOL WINAPI FN_UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh ) { static FN_UnlockFile *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "UnlockFile", &g_Kernel32); return pfn( hFile, dwFileOffsetLow, dwFileOffsetHigh, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh ); } typedef BOOL WINAPI FN_LockFileEx( HANDLE hFile, DWORD dwFlags, DWORD dwReserved, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh, LPOVERLAPPED lpOverlapped ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_LockFileEx( HANDLE hFile, DWORD dwFlags, DWORD dwReserved, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh, LPOVERLAPPED lpOverlapped ) { static FN_LockFileEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LockFileEx", &g_Kernel32); return pfn( hFile, dwFlags, dwReserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh, lpOverlapped ); } typedef BOOL WINAPI FN_UnlockFileEx( HANDLE hFile, DWORD dwReserved, DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh, LPOVERLAPPED lpOverlapped ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_UnlockFileEx( HANDLE hFile, DWORD dwReserved, DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh, LPOVERLAPPED lpOverlapped ) { static FN_UnlockFileEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "UnlockFileEx", &g_Kernel32); return pfn( hFile, dwReserved, nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh, lpOverlapped ); } typedef BOOL WINAPI FN_GetFileInformationByHandle( HANDLE hFile, LPBY_HANDLE_FILE_INFORMATION lpFileInformation ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetFileInformationByHandle( HANDLE hFile, LPBY_HANDLE_FILE_INFORMATION lpFileInformation ) { static FN_GetFileInformationByHandle *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetFileInformationByHandle", &g_Kernel32); return pfn( hFile, lpFileInformation ); } typedef DWORD WINAPI FN_GetFileType( HANDLE hFile ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetFileType( HANDLE hFile ) { static FN_GetFileType *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetFileType", &g_Kernel32); return pfn( hFile ); } typedef DWORD WINAPI FN_GetFileSize( HANDLE hFile, LPDWORD lpFileSizeHigh ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetFileSize( HANDLE hFile, LPDWORD lpFileSizeHigh ) { static FN_GetFileSize *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetFileSize", &g_Kernel32); return pfn( hFile, lpFileSizeHigh ); } typedef BOOL WINAPI FN_GetFileSizeEx( HANDLE hFile, PLARGE_INTEGER lpFileSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetFileSizeEx( HANDLE hFile, PLARGE_INTEGER lpFileSize ) { static FN_GetFileSizeEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetFileSizeEx", &g_Kernel32); return pfn( hFile, lpFileSize ); } typedef HANDLE WINAPI FN_GetStdHandle( DWORD nStdHandle ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_GetStdHandle( DWORD nStdHandle ) { static FN_GetStdHandle *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetStdHandle", &g_Kernel32); return pfn( nStdHandle ); } typedef BOOL WINAPI FN_SetStdHandle( DWORD nStdHandle, HANDLE hHandle ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetStdHandle( DWORD nStdHandle, HANDLE hHandle ) { static FN_SetStdHandle *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetStdHandle", &g_Kernel32); return pfn( nStdHandle, hHandle ); } typedef BOOL WINAPI FN_WriteFile( HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteFile( HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped ) { static FN_WriteFile *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WriteFile", &g_Kernel32); return pfn( hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped ); } typedef BOOL WINAPI FN_ReadFile( HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadFile( HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped ) { static FN_ReadFile *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ReadFile", &g_Kernel32); return pfn( hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped ); } typedef BOOL WINAPI FN_FlushFileBuffers( HANDLE hFile ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FlushFileBuffers( HANDLE hFile ) { static FN_FlushFileBuffers *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FlushFileBuffers", &g_Kernel32); return pfn( hFile ); } typedef BOOL WINAPI FN_DeviceIoControl( HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_DeviceIoControl( HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped ) { static FN_DeviceIoControl *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DeviceIoControl", &g_Kernel32); return pfn( hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped ); } typedef BOOL WINAPI FN_RequestDeviceWakeup( HANDLE hDevice ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_RequestDeviceWakeup( HANDLE hDevice ) { static FN_RequestDeviceWakeup *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RequestDeviceWakeup", &g_Kernel32); return pfn( hDevice ); } typedef BOOL WINAPI FN_CancelDeviceWakeupRequest( HANDLE hDevice ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CancelDeviceWakeupRequest( HANDLE hDevice ) { static FN_CancelDeviceWakeupRequest *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CancelDeviceWakeupRequest", &g_Kernel32); return pfn( hDevice ); } typedef BOOL WINAPI FN_GetDevicePowerState( HANDLE hDevice, BOOL * pfOn ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetDevicePowerState( HANDLE hDevice, BOOL * pfOn ) { static FN_GetDevicePowerState *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetDevicePowerState", &g_Kernel32); return pfn( hDevice, pfOn ); } typedef BOOL WINAPI FN_SetMessageWaitingIndicator( HANDLE hMsgIndicator, ULONG ulMsgCount ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetMessageWaitingIndicator( HANDLE hMsgIndicator, ULONG ulMsgCount ) { static FN_SetMessageWaitingIndicator *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetMessageWaitingIndicator", &g_Kernel32); return pfn( hMsgIndicator, ulMsgCount ); } typedef BOOL WINAPI FN_SetEndOfFile( HANDLE hFile ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetEndOfFile( HANDLE hFile ) { static FN_SetEndOfFile *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetEndOfFile", &g_Kernel32); return pfn( hFile ); } typedef DWORD WINAPI FN_SetFilePointer( HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_SetFilePointer( HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod ) { static FN_SetFilePointer *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetFilePointer", &g_Kernel32); return pfn( hFile, lDistanceToMove, lpDistanceToMoveHigh, dwMoveMethod ); } typedef BOOL WINAPI FN_SetFilePointerEx( HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetFilePointerEx( HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod ) { static FN_SetFilePointerEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetFilePointerEx", &g_Kernel32); return pfn( hFile, liDistanceToMove, lpNewFilePointer, dwMoveMethod ); } typedef BOOL WINAPI FN_FindClose( HANDLE hFindFile ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindClose( HANDLE hFindFile ) { static FN_FindClose *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindClose", &g_Kernel32); return pfn( hFindFile ); } typedef BOOL WINAPI FN_GetFileTime( HANDLE hFile, LPFILETIME lpCreationTime, LPFILETIME lpLastAccessTime, LPFILETIME lpLastWriteTime ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetFileTime( HANDLE hFile, LPFILETIME lpCreationTime, LPFILETIME lpLastAccessTime, LPFILETIME lpLastWriteTime ) { static FN_GetFileTime *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetFileTime", &g_Kernel32); return pfn( hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime ); } typedef BOOL WINAPI FN_SetFileTime( HANDLE hFile, CONST FILETIME * lpCreationTime, CONST FILETIME * lpLastAccessTime, CONST FILETIME * lpLastWriteTime ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetFileTime( HANDLE hFile, CONST FILETIME * lpCreationTime, CONST FILETIME * lpLastAccessTime, CONST FILETIME * lpLastWriteTime ) { static FN_SetFileTime *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetFileTime", &g_Kernel32); return pfn( hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime ); } typedef BOOL WINAPI FN_SetFileValidData( HANDLE hFile, LONGLONG ValidDataLength ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetFileValidData( HANDLE hFile, LONGLONG ValidDataLength ) { static FN_SetFileValidData *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetFileValidData", &g_Kernel32); return pfn( hFile, ValidDataLength ); } typedef BOOL WINAPI FN_SetFileShortNameA( HANDLE hFile, LPCSTR lpShortName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetFileShortNameA( HANDLE hFile, LPCSTR lpShortName ) { static FN_SetFileShortNameA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetFileShortNameA", &g_Kernel32); return pfn( hFile, lpShortName ); } typedef BOOL WINAPI FN_SetFileShortNameW( HANDLE hFile, LPCWSTR lpShortName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetFileShortNameW( HANDLE hFile, LPCWSTR lpShortName ) { static FN_SetFileShortNameW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetFileShortNameW", &g_Kernel32); return pfn( hFile, lpShortName ); } typedef BOOL WINAPI FN_CloseHandle( HANDLE hObject ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CloseHandle( HANDLE hObject ) { static FN_CloseHandle *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CloseHandle", &g_Kernel32); return pfn( hObject ); } typedef BOOL WINAPI FN_DuplicateHandle( HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_DuplicateHandle( HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions ) { static FN_DuplicateHandle *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DuplicateHandle", &g_Kernel32); return pfn( hSourceProcessHandle, hSourceHandle, hTargetProcessHandle, lpTargetHandle, dwDesiredAccess, bInheritHandle, dwOptions ); } typedef BOOL WINAPI FN_GetHandleInformation( HANDLE hObject, LPDWORD lpdwFlags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetHandleInformation( HANDLE hObject, LPDWORD lpdwFlags ) { static FN_GetHandleInformation *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetHandleInformation", &g_Kernel32); return pfn( hObject, lpdwFlags ); } typedef BOOL WINAPI FN_SetHandleInformation( HANDLE hObject, DWORD dwMask, DWORD dwFlags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetHandleInformation( HANDLE hObject, DWORD dwMask, DWORD dwFlags ) { static FN_SetHandleInformation *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetHandleInformation", &g_Kernel32); return pfn( hObject, dwMask, dwFlags ); } typedef DWORD WINAPI FN_LoadModule( LPCSTR lpModuleName, LPVOID lpParameterBlock ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_LoadModule( LPCSTR lpModuleName, LPVOID lpParameterBlock ) { static FN_LoadModule *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LoadModule", &g_Kernel32); return pfn( lpModuleName, lpParameterBlock ); } typedef UINT WINAPI FN_WinExec( LPCSTR lpCmdLine, UINT uCmdShow ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_WinExec( LPCSTR lpCmdLine, UINT uCmdShow ) { static FN_WinExec *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WinExec", &g_Kernel32); return pfn( lpCmdLine, uCmdShow ); } typedef BOOL WINAPI FN_ClearCommBreak( HANDLE hFile ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ClearCommBreak( HANDLE hFile ) { static FN_ClearCommBreak *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ClearCommBreak", &g_Kernel32); return pfn( hFile ); } typedef BOOL WINAPI FN_ClearCommError( HANDLE hFile, LPDWORD lpErrors, LPCOMSTAT lpStat ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ClearCommError( HANDLE hFile, LPDWORD lpErrors, LPCOMSTAT lpStat ) { static FN_ClearCommError *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ClearCommError", &g_Kernel32); return pfn( hFile, lpErrors, lpStat ); } typedef BOOL WINAPI FN_SetupComm( HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetupComm( HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue ) { static FN_SetupComm *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetupComm", &g_Kernel32); return pfn( hFile, dwInQueue, dwOutQueue ); } typedef BOOL WINAPI FN_EscapeCommFunction( HANDLE hFile, DWORD dwFunc ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EscapeCommFunction( HANDLE hFile, DWORD dwFunc ) { static FN_EscapeCommFunction *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EscapeCommFunction", &g_Kernel32); return pfn( hFile, dwFunc ); } typedef BOOL WINAPI FN_GetCommConfig( HANDLE hCommDev, LPCOMMCONFIG lpCC, LPDWORD lpdwSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetCommConfig( HANDLE hCommDev, LPCOMMCONFIG lpCC, LPDWORD lpdwSize ) { static FN_GetCommConfig *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetCommConfig", &g_Kernel32); return pfn( hCommDev, lpCC, lpdwSize ); } typedef BOOL WINAPI FN_GetCommMask( HANDLE hFile, LPDWORD lpEvtMask ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetCommMask( HANDLE hFile, LPDWORD lpEvtMask ) { static FN_GetCommMask *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetCommMask", &g_Kernel32); return pfn( hFile, lpEvtMask ); } typedef BOOL WINAPI FN_GetCommProperties( HANDLE hFile, LPCOMMPROP lpCommProp ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetCommProperties( HANDLE hFile, LPCOMMPROP lpCommProp ) { static FN_GetCommProperties *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetCommProperties", &g_Kernel32); return pfn( hFile, lpCommProp ); } typedef BOOL WINAPI FN_GetCommModemStatus( HANDLE hFile, LPDWORD lpModemStat ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetCommModemStatus( HANDLE hFile, LPDWORD lpModemStat ) { static FN_GetCommModemStatus *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetCommModemStatus", &g_Kernel32); return pfn( hFile, lpModemStat ); } typedef BOOL WINAPI FN_GetCommState( HANDLE hFile, LPDCB lpDCB ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetCommState( HANDLE hFile, LPDCB lpDCB ) { static FN_GetCommState *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetCommState", &g_Kernel32); return pfn( hFile, lpDCB ); } typedef BOOL WINAPI FN_GetCommTimeouts( HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetCommTimeouts( HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts ) { static FN_GetCommTimeouts *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetCommTimeouts", &g_Kernel32); return pfn( hFile, lpCommTimeouts ); } typedef BOOL WINAPI FN_PurgeComm( HANDLE hFile, DWORD dwFlags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_PurgeComm( HANDLE hFile, DWORD dwFlags ) { static FN_PurgeComm *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "PurgeComm", &g_Kernel32); return pfn( hFile, dwFlags ); } typedef BOOL WINAPI FN_SetCommBreak( HANDLE hFile ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetCommBreak( HANDLE hFile ) { static FN_SetCommBreak *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetCommBreak", &g_Kernel32); return pfn( hFile ); } typedef BOOL WINAPI FN_SetCommConfig( HANDLE hCommDev, LPCOMMCONFIG lpCC, DWORD dwSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetCommConfig( HANDLE hCommDev, LPCOMMCONFIG lpCC, DWORD dwSize ) { static FN_SetCommConfig *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetCommConfig", &g_Kernel32); return pfn( hCommDev, lpCC, dwSize ); } typedef BOOL WINAPI FN_SetCommMask( HANDLE hFile, DWORD dwEvtMask ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetCommMask( HANDLE hFile, DWORD dwEvtMask ) { static FN_SetCommMask *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetCommMask", &g_Kernel32); return pfn( hFile, dwEvtMask ); } typedef BOOL WINAPI FN_SetCommState( HANDLE hFile, LPDCB lpDCB ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetCommState( HANDLE hFile, LPDCB lpDCB ) { static FN_SetCommState *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetCommState", &g_Kernel32); return pfn( hFile, lpDCB ); } typedef BOOL WINAPI FN_SetCommTimeouts( HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetCommTimeouts( HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts ) { static FN_SetCommTimeouts *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetCommTimeouts", &g_Kernel32); return pfn( hFile, lpCommTimeouts ); } typedef BOOL WINAPI FN_TransmitCommChar( HANDLE hFile, char cChar ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_TransmitCommChar( HANDLE hFile, char cChar ) { static FN_TransmitCommChar *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "TransmitCommChar", &g_Kernel32); return pfn( hFile, cChar ); } typedef BOOL WINAPI FN_WaitCommEvent( HANDLE hFile, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_WaitCommEvent( HANDLE hFile, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped ) { static FN_WaitCommEvent *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WaitCommEvent", &g_Kernel32); return pfn( hFile, lpEvtMask, lpOverlapped ); } typedef DWORD WINAPI FN_SetTapePosition( HANDLE hDevice, DWORD dwPositionMethod, DWORD dwPartition, DWORD dwOffsetLow, DWORD dwOffsetHigh, BOOL bImmediate ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_SetTapePosition( HANDLE hDevice, DWORD dwPositionMethod, DWORD dwPartition, DWORD dwOffsetLow, DWORD dwOffsetHigh, BOOL bImmediate ) { static FN_SetTapePosition *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetTapePosition", &g_Kernel32); return pfn( hDevice, dwPositionMethod, dwPartition, dwOffsetLow, dwOffsetHigh, bImmediate ); } typedef DWORD WINAPI FN_GetTapePosition( HANDLE hDevice, DWORD dwPositionType, LPDWORD lpdwPartition, LPDWORD lpdwOffsetLow, LPDWORD lpdwOffsetHigh ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetTapePosition( HANDLE hDevice, DWORD dwPositionType, LPDWORD lpdwPartition, LPDWORD lpdwOffsetLow, LPDWORD lpdwOffsetHigh ) { static FN_GetTapePosition *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetTapePosition", &g_Kernel32); return pfn( hDevice, dwPositionType, lpdwPartition, lpdwOffsetLow, lpdwOffsetHigh ); } typedef DWORD WINAPI FN_PrepareTape( HANDLE hDevice, DWORD dwOperation, BOOL bImmediate ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_PrepareTape( HANDLE hDevice, DWORD dwOperation, BOOL bImmediate ) { static FN_PrepareTape *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "PrepareTape", &g_Kernel32); return pfn( hDevice, dwOperation, bImmediate ); } typedef DWORD WINAPI FN_EraseTape( HANDLE hDevice, DWORD dwEraseType, BOOL bImmediate ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_EraseTape( HANDLE hDevice, DWORD dwEraseType, BOOL bImmediate ) { static FN_EraseTape *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EraseTape", &g_Kernel32); return pfn( hDevice, dwEraseType, bImmediate ); } typedef DWORD WINAPI FN_CreateTapePartition( HANDLE hDevice, DWORD dwPartitionMethod, DWORD dwCount, DWORD dwSize ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_CreateTapePartition( HANDLE hDevice, DWORD dwPartitionMethod, DWORD dwCount, DWORD dwSize ) { static FN_CreateTapePartition *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateTapePartition", &g_Kernel32); return pfn( hDevice, dwPartitionMethod, dwCount, dwSize ); } typedef DWORD WINAPI FN_WriteTapemark( HANDLE hDevice, DWORD dwTapemarkType, DWORD dwTapemarkCount, BOOL bImmediate ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_WriteTapemark( HANDLE hDevice, DWORD dwTapemarkType, DWORD dwTapemarkCount, BOOL bImmediate ) { static FN_WriteTapemark *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WriteTapemark", &g_Kernel32); return pfn( hDevice, dwTapemarkType, dwTapemarkCount, bImmediate ); } typedef DWORD WINAPI FN_GetTapeStatus( HANDLE hDevice ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetTapeStatus( HANDLE hDevice ) { static FN_GetTapeStatus *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetTapeStatus", &g_Kernel32); return pfn( hDevice ); } typedef DWORD WINAPI FN_GetTapeParameters( HANDLE hDevice, DWORD dwOperation, LPDWORD lpdwSize, LPVOID lpTapeInformation ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetTapeParameters( HANDLE hDevice, DWORD dwOperation, LPDWORD lpdwSize, LPVOID lpTapeInformation ) { static FN_GetTapeParameters *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetTapeParameters", &g_Kernel32); return pfn( hDevice, dwOperation, lpdwSize, lpTapeInformation ); } typedef DWORD WINAPI FN_SetTapeParameters( HANDLE hDevice, DWORD dwOperation, LPVOID lpTapeInformation ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_SetTapeParameters( HANDLE hDevice, DWORD dwOperation, LPVOID lpTapeInformation ) { static FN_SetTapeParameters *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetTapeParameters", &g_Kernel32); return pfn( hDevice, dwOperation, lpTapeInformation ); } typedef BOOL WINAPI FN_Beep( DWORD dwFreq, DWORD dwDuration ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_Beep( DWORD dwFreq, DWORD dwDuration ) { static FN_Beep *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "Beep", &g_Kernel32); return pfn( dwFreq, dwDuration ); } typedef int WINAPI FN_MulDiv( int nNumber, int nNumerator, int nDenominator ); __declspec(dllexport) int WINAPI kPrf2Wrap_MulDiv( int nNumber, int nNumerator, int nDenominator ) { static FN_MulDiv *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "MulDiv", &g_Kernel32); return pfn( nNumber, nNumerator, nDenominator ); } typedef VOID WINAPI FN_GetSystemTime( LPSYSTEMTIME lpSystemTime ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_GetSystemTime( LPSYSTEMTIME lpSystemTime ) { static FN_GetSystemTime *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSystemTime", &g_Kernel32); pfn( lpSystemTime ); } typedef VOID WINAPI FN_GetSystemTimeAsFileTime( LPFILETIME lpSystemTimeAsFileTime ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_GetSystemTimeAsFileTime( LPFILETIME lpSystemTimeAsFileTime ) { static FN_GetSystemTimeAsFileTime *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSystemTimeAsFileTime", &g_Kernel32); pfn( lpSystemTimeAsFileTime ); } typedef BOOL WINAPI FN_SetSystemTime( CONST SYSTEMTIME * lpSystemTime ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetSystemTime( CONST SYSTEMTIME * lpSystemTime ) { static FN_SetSystemTime *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetSystemTime", &g_Kernel32); return pfn( lpSystemTime ); } typedef VOID WINAPI FN_GetLocalTime( LPSYSTEMTIME lpSystemTime ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_GetLocalTime( LPSYSTEMTIME lpSystemTime ) { static FN_GetLocalTime *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetLocalTime", &g_Kernel32); pfn( lpSystemTime ); } typedef BOOL WINAPI FN_SetLocalTime( CONST SYSTEMTIME * lpSystemTime ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetLocalTime( CONST SYSTEMTIME * lpSystemTime ) { static FN_SetLocalTime *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetLocalTime", &g_Kernel32); return pfn( lpSystemTime ); } typedef VOID WINAPI FN_GetSystemInfo( LPSYSTEM_INFO lpSystemInfo ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_GetSystemInfo( LPSYSTEM_INFO lpSystemInfo ) { static FN_GetSystemInfo *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSystemInfo", &g_Kernel32); pfn( lpSystemInfo ); } typedef BOOL WINAPI FN_SetSystemFileCacheSize( SIZE_T MinimumFileCacheSize, SIZE_T MaximumFileCacheSize, DWORD Flags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetSystemFileCacheSize( SIZE_T MinimumFileCacheSize, SIZE_T MaximumFileCacheSize, DWORD Flags ) { static FN_SetSystemFileCacheSize *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetSystemFileCacheSize", &g_Kernel32); return pfn( MinimumFileCacheSize, MaximumFileCacheSize, Flags ); } typedef BOOL WINAPI FN_GetSystemFileCacheSize( PSIZE_T lpMinimumFileCacheSize, PSIZE_T lpMaximumFileCacheSize, PDWORD lpFlags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetSystemFileCacheSize( PSIZE_T lpMinimumFileCacheSize, PSIZE_T lpMaximumFileCacheSize, PDWORD lpFlags ) { static FN_GetSystemFileCacheSize *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSystemFileCacheSize", &g_Kernel32); return pfn( lpMinimumFileCacheSize, lpMaximumFileCacheSize, lpFlags ); } typedef BOOL WINAPI FN_GetSystemRegistryQuota( PDWORD pdwQuotaAllowed, PDWORD pdwQuotaUsed ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetSystemRegistryQuota( PDWORD pdwQuotaAllowed, PDWORD pdwQuotaUsed ) { static FN_GetSystemRegistryQuota *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSystemRegistryQuota", &g_Kernel32); return pfn( pdwQuotaAllowed, pdwQuotaUsed ); } typedef BOOL WINAPI FN_GetSystemTimes( LPFILETIME lpIdleTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetSystemTimes( LPFILETIME lpIdleTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime ) { static FN_GetSystemTimes *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSystemTimes", &g_Kernel32); return pfn( lpIdleTime, lpKernelTime, lpUserTime ); } typedef VOID WINAPI FN_GetNativeSystemInfo( LPSYSTEM_INFO lpSystemInfo ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_GetNativeSystemInfo( LPSYSTEM_INFO lpSystemInfo ) { static FN_GetNativeSystemInfo *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetNativeSystemInfo", &g_Kernel32); pfn( lpSystemInfo ); } typedef BOOL WINAPI FN_IsProcessorFeaturePresent( DWORD ProcessorFeature ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsProcessorFeaturePresent( DWORD ProcessorFeature ) { static FN_IsProcessorFeaturePresent *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "IsProcessorFeaturePresent", &g_Kernel32); return pfn( ProcessorFeature ); } typedef BOOL WINAPI FN_SystemTimeToTzSpecificLocalTime( LPTIME_ZONE_INFORMATION lpTimeZoneInformation, LPSYSTEMTIME lpUniversalTime, LPSYSTEMTIME lpLocalTime ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SystemTimeToTzSpecificLocalTime( LPTIME_ZONE_INFORMATION lpTimeZoneInformation, LPSYSTEMTIME lpUniversalTime, LPSYSTEMTIME lpLocalTime ) { static FN_SystemTimeToTzSpecificLocalTime *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SystemTimeToTzSpecificLocalTime", &g_Kernel32); return pfn( lpTimeZoneInformation, lpUniversalTime, lpLocalTime ); } typedef BOOL WINAPI FN_TzSpecificLocalTimeToSystemTime( LPTIME_ZONE_INFORMATION lpTimeZoneInformation, LPSYSTEMTIME lpLocalTime, LPSYSTEMTIME lpUniversalTime ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_TzSpecificLocalTimeToSystemTime( LPTIME_ZONE_INFORMATION lpTimeZoneInformation, LPSYSTEMTIME lpLocalTime, LPSYSTEMTIME lpUniversalTime ) { static FN_TzSpecificLocalTimeToSystemTime *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "TzSpecificLocalTimeToSystemTime", &g_Kernel32); return pfn( lpTimeZoneInformation, lpLocalTime, lpUniversalTime ); } typedef DWORD WINAPI FN_GetTimeZoneInformation( LPTIME_ZONE_INFORMATION lpTimeZoneInformation ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetTimeZoneInformation( LPTIME_ZONE_INFORMATION lpTimeZoneInformation ) { static FN_GetTimeZoneInformation *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetTimeZoneInformation", &g_Kernel32); return pfn( lpTimeZoneInformation ); } typedef BOOL WINAPI FN_SetTimeZoneInformation( CONST TIME_ZONE_INFORMATION * lpTimeZoneInformation ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetTimeZoneInformation( CONST TIME_ZONE_INFORMATION * lpTimeZoneInformation ) { static FN_SetTimeZoneInformation *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetTimeZoneInformation", &g_Kernel32); return pfn( lpTimeZoneInformation ); } typedef BOOL WINAPI FN_SystemTimeToFileTime( CONST SYSTEMTIME * lpSystemTime, LPFILETIME lpFileTime ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SystemTimeToFileTime( CONST SYSTEMTIME * lpSystemTime, LPFILETIME lpFileTime ) { static FN_SystemTimeToFileTime *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SystemTimeToFileTime", &g_Kernel32); return pfn( lpSystemTime, lpFileTime ); } typedef BOOL WINAPI FN_FileTimeToLocalFileTime( CONST FILETIME * lpFileTime, LPFILETIME lpLocalFileTime ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FileTimeToLocalFileTime( CONST FILETIME * lpFileTime, LPFILETIME lpLocalFileTime ) { static FN_FileTimeToLocalFileTime *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FileTimeToLocalFileTime", &g_Kernel32); return pfn( lpFileTime, lpLocalFileTime ); } typedef BOOL WINAPI FN_LocalFileTimeToFileTime( CONST FILETIME * lpLocalFileTime, LPFILETIME lpFileTime ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_LocalFileTimeToFileTime( CONST FILETIME * lpLocalFileTime, LPFILETIME lpFileTime ) { static FN_LocalFileTimeToFileTime *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LocalFileTimeToFileTime", &g_Kernel32); return pfn( lpLocalFileTime, lpFileTime ); } typedef BOOL WINAPI FN_FileTimeToSystemTime( CONST FILETIME * lpFileTime, LPSYSTEMTIME lpSystemTime ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FileTimeToSystemTime( CONST FILETIME * lpFileTime, LPSYSTEMTIME lpSystemTime ) { static FN_FileTimeToSystemTime *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FileTimeToSystemTime", &g_Kernel32); return pfn( lpFileTime, lpSystemTime ); } typedef LONG WINAPI FN_CompareFileTime( CONST FILETIME * lpFileTime1, CONST FILETIME * lpFileTime2 ); __declspec(dllexport) LONG WINAPI kPrf2Wrap_CompareFileTime( CONST FILETIME * lpFileTime1, CONST FILETIME * lpFileTime2 ) { static FN_CompareFileTime *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CompareFileTime", &g_Kernel32); return pfn( lpFileTime1, lpFileTime2 ); } typedef BOOL WINAPI FN_FileTimeToDosDateTime( CONST FILETIME * lpFileTime, LPWORD lpFatDate, LPWORD lpFatTime ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FileTimeToDosDateTime( CONST FILETIME * lpFileTime, LPWORD lpFatDate, LPWORD lpFatTime ) { static FN_FileTimeToDosDateTime *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FileTimeToDosDateTime", &g_Kernel32); return pfn( lpFileTime, lpFatDate, lpFatTime ); } typedef BOOL WINAPI FN_DosDateTimeToFileTime( WORD wFatDate, WORD wFatTime, LPFILETIME lpFileTime ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_DosDateTimeToFileTime( WORD wFatDate, WORD wFatTime, LPFILETIME lpFileTime ) { static FN_DosDateTimeToFileTime *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DosDateTimeToFileTime", &g_Kernel32); return pfn( wFatDate, wFatTime, lpFileTime ); } typedef DWORD WINAPI FN_GetTickCount( VOID ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetTickCount( VOID ) { static FN_GetTickCount *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetTickCount", &g_Kernel32); return pfn (); } typedef BOOL WINAPI FN_SetSystemTimeAdjustment( DWORD dwTimeAdjustment, BOOL bTimeAdjustmentDisabled ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetSystemTimeAdjustment( DWORD dwTimeAdjustment, BOOL bTimeAdjustmentDisabled ) { static FN_SetSystemTimeAdjustment *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetSystemTimeAdjustment", &g_Kernel32); return pfn( dwTimeAdjustment, bTimeAdjustmentDisabled ); } typedef BOOL WINAPI FN_GetSystemTimeAdjustment( PDWORD lpTimeAdjustment, PDWORD lpTimeIncrement, PBOOL lpTimeAdjustmentDisabled ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetSystemTimeAdjustment( PDWORD lpTimeAdjustment, PDWORD lpTimeIncrement, PBOOL lpTimeAdjustmentDisabled ) { static FN_GetSystemTimeAdjustment *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSystemTimeAdjustment", &g_Kernel32); return pfn( lpTimeAdjustment, lpTimeIncrement, lpTimeAdjustmentDisabled ); } typedef DWORD WINAPI FN_FormatMessageA( DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPSTR lpBuffer, DWORD nSize, va_list * Arguments ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_FormatMessageA( DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPSTR lpBuffer, DWORD nSize, va_list * Arguments ) { static FN_FormatMessageA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FormatMessageA", &g_Kernel32); return pfn( dwFlags, lpSource, dwMessageId, dwLanguageId, lpBuffer, nSize, Arguments ); } typedef DWORD WINAPI FN_FormatMessageW( DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, va_list * Arguments ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_FormatMessageW( DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, va_list * Arguments ) { static FN_FormatMessageW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FormatMessageW", &g_Kernel32); return pfn( dwFlags, lpSource, dwMessageId, dwLanguageId, lpBuffer, nSize, Arguments ); } typedef BOOL WINAPI FN_CreatePipe( PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreatePipe( PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize ) { static FN_CreatePipe *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreatePipe", &g_Kernel32); return pfn( hReadPipe, hWritePipe, lpPipeAttributes, nSize ); } typedef BOOL WINAPI FN_ConnectNamedPipe( HANDLE hNamedPipe, LPOVERLAPPED lpOverlapped ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ConnectNamedPipe( HANDLE hNamedPipe, LPOVERLAPPED lpOverlapped ) { static FN_ConnectNamedPipe *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ConnectNamedPipe", &g_Kernel32); return pfn( hNamedPipe, lpOverlapped ); } typedef BOOL WINAPI FN_DisconnectNamedPipe( HANDLE hNamedPipe ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_DisconnectNamedPipe( HANDLE hNamedPipe ) { static FN_DisconnectNamedPipe *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DisconnectNamedPipe", &g_Kernel32); return pfn( hNamedPipe ); } typedef BOOL WINAPI FN_SetNamedPipeHandleState( HANDLE hNamedPipe, LPDWORD lpMode, LPDWORD lpMaxCollectionCount, LPDWORD lpCollectDataTimeout ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetNamedPipeHandleState( HANDLE hNamedPipe, LPDWORD lpMode, LPDWORD lpMaxCollectionCount, LPDWORD lpCollectDataTimeout ) { static FN_SetNamedPipeHandleState *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetNamedPipeHandleState", &g_Kernel32); return pfn( hNamedPipe, lpMode, lpMaxCollectionCount, lpCollectDataTimeout ); } typedef BOOL WINAPI FN_GetNamedPipeInfo( HANDLE hNamedPipe, LPDWORD lpFlags, LPDWORD lpOutBufferSize, LPDWORD lpInBufferSize, LPDWORD lpMaxInstances ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetNamedPipeInfo( HANDLE hNamedPipe, LPDWORD lpFlags, LPDWORD lpOutBufferSize, LPDWORD lpInBufferSize, LPDWORD lpMaxInstances ) { static FN_GetNamedPipeInfo *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetNamedPipeInfo", &g_Kernel32); return pfn( hNamedPipe, lpFlags, lpOutBufferSize, lpInBufferSize, lpMaxInstances ); } typedef BOOL WINAPI FN_PeekNamedPipe( HANDLE hNamedPipe, LPVOID lpBuffer, DWORD nBufferSize, LPDWORD lpBytesRead, LPDWORD lpTotalBytesAvail, LPDWORD lpBytesLeftThisMessage ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_PeekNamedPipe( HANDLE hNamedPipe, LPVOID lpBuffer, DWORD nBufferSize, LPDWORD lpBytesRead, LPDWORD lpTotalBytesAvail, LPDWORD lpBytesLeftThisMessage ) { static FN_PeekNamedPipe *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "PeekNamedPipe", &g_Kernel32); return pfn( hNamedPipe, lpBuffer, nBufferSize, lpBytesRead, lpTotalBytesAvail, lpBytesLeftThisMessage ); } typedef BOOL WINAPI FN_TransactNamedPipe( HANDLE hNamedPipe, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesRead, LPOVERLAPPED lpOverlapped ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_TransactNamedPipe( HANDLE hNamedPipe, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesRead, LPOVERLAPPED lpOverlapped ) { static FN_TransactNamedPipe *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "TransactNamedPipe", &g_Kernel32); return pfn( hNamedPipe, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesRead, lpOverlapped ); } typedef HANDLE WINAPI FN_CreateMailslotA( LPCSTR lpName, DWORD nMaxMessageSize, DWORD lReadTimeout, LPSECURITY_ATTRIBUTES lpSecurityAttributes ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateMailslotA( LPCSTR lpName, DWORD nMaxMessageSize, DWORD lReadTimeout, LPSECURITY_ATTRIBUTES lpSecurityAttributes ) { static FN_CreateMailslotA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateMailslotA", &g_Kernel32); return pfn( lpName, nMaxMessageSize, lReadTimeout, lpSecurityAttributes ); } typedef HANDLE WINAPI FN_CreateMailslotW( LPCWSTR lpName, DWORD nMaxMessageSize, DWORD lReadTimeout, LPSECURITY_ATTRIBUTES lpSecurityAttributes ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateMailslotW( LPCWSTR lpName, DWORD nMaxMessageSize, DWORD lReadTimeout, LPSECURITY_ATTRIBUTES lpSecurityAttributes ) { static FN_CreateMailslotW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateMailslotW", &g_Kernel32); return pfn( lpName, nMaxMessageSize, lReadTimeout, lpSecurityAttributes ); } typedef BOOL WINAPI FN_GetMailslotInfo( HANDLE hMailslot, LPDWORD lpMaxMessageSize, LPDWORD lpNextSize, LPDWORD lpMessageCount, LPDWORD lpReadTimeout ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetMailslotInfo( HANDLE hMailslot, LPDWORD lpMaxMessageSize, LPDWORD lpNextSize, LPDWORD lpMessageCount, LPDWORD lpReadTimeout ) { static FN_GetMailslotInfo *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetMailslotInfo", &g_Kernel32); return pfn( hMailslot, lpMaxMessageSize, lpNextSize, lpMessageCount, lpReadTimeout ); } typedef BOOL WINAPI FN_SetMailslotInfo( HANDLE hMailslot, DWORD lReadTimeout ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetMailslotInfo( HANDLE hMailslot, DWORD lReadTimeout ) { static FN_SetMailslotInfo *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetMailslotInfo", &g_Kernel32); return pfn( hMailslot, lReadTimeout ); } typedef LPVOID WINAPI FN_MapViewOfFile( HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap ); __declspec(dllexport) LPVOID WINAPI kPrf2Wrap_MapViewOfFile( HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap ) { static FN_MapViewOfFile *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "MapViewOfFile", &g_Kernel32); return pfn( hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow, dwNumberOfBytesToMap ); } typedef BOOL WINAPI FN_FlushViewOfFile( LPCVOID lpBaseAddress, SIZE_T dwNumberOfBytesToFlush ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FlushViewOfFile( LPCVOID lpBaseAddress, SIZE_T dwNumberOfBytesToFlush ) { static FN_FlushViewOfFile *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FlushViewOfFile", &g_Kernel32); return pfn( lpBaseAddress, dwNumberOfBytesToFlush ); } typedef BOOL WINAPI FN_UnmapViewOfFile( LPCVOID lpBaseAddress ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_UnmapViewOfFile( LPCVOID lpBaseAddress ) { static FN_UnmapViewOfFile *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "UnmapViewOfFile", &g_Kernel32); return pfn( lpBaseAddress ); } typedef BOOL WINAPI FN_EncryptFileA( LPCSTR lpFileName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EncryptFileA( LPCSTR lpFileName ) { static FN_EncryptFileA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EncryptFileA", &g_Kernel32); return pfn( lpFileName ); } typedef BOOL WINAPI FN_EncryptFileW( LPCWSTR lpFileName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EncryptFileW( LPCWSTR lpFileName ) { static FN_EncryptFileW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EncryptFileW", &g_Kernel32); return pfn( lpFileName ); } typedef BOOL WINAPI FN_DecryptFileA( LPCSTR lpFileName, DWORD dwReserved ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_DecryptFileA( LPCSTR lpFileName, DWORD dwReserved ) { static FN_DecryptFileA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DecryptFileA", &g_Kernel32); return pfn( lpFileName, dwReserved ); } typedef BOOL WINAPI FN_DecryptFileW( LPCWSTR lpFileName, DWORD dwReserved ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_DecryptFileW( LPCWSTR lpFileName, DWORD dwReserved ) { static FN_DecryptFileW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DecryptFileW", &g_Kernel32); return pfn( lpFileName, dwReserved ); } typedef BOOL WINAPI FN_FileEncryptionStatusA( LPCSTR lpFileName, LPDWORD lpStatus ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FileEncryptionStatusA( LPCSTR lpFileName, LPDWORD lpStatus ) { static FN_FileEncryptionStatusA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FileEncryptionStatusA", &g_Kernel32); return pfn( lpFileName, lpStatus ); } typedef BOOL WINAPI FN_FileEncryptionStatusW( LPCWSTR lpFileName, LPDWORD lpStatus ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FileEncryptionStatusW( LPCWSTR lpFileName, LPDWORD lpStatus ) { static FN_FileEncryptionStatusW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FileEncryptionStatusW", &g_Kernel32); return pfn( lpFileName, lpStatus ); } typedef DWORD WINAPI FN_OpenEncryptedFileRawA( LPCSTR lpFileName, ULONG ulFlags, PVOID * pvContext ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_OpenEncryptedFileRawA( LPCSTR lpFileName, ULONG ulFlags, PVOID * pvContext ) { static FN_OpenEncryptedFileRawA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "OpenEncryptedFileRawA", &g_Kernel32); return pfn( lpFileName, ulFlags, pvContext ); } typedef DWORD WINAPI FN_OpenEncryptedFileRawW( LPCWSTR lpFileName, ULONG ulFlags, PVOID * pvContext ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_OpenEncryptedFileRawW( LPCWSTR lpFileName, ULONG ulFlags, PVOID * pvContext ) { static FN_OpenEncryptedFileRawW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "OpenEncryptedFileRawW", &g_Kernel32); return pfn( lpFileName, ulFlags, pvContext ); } typedef DWORD WINAPI FN_ReadEncryptedFileRaw( PFE_EXPORT_FUNC pfExportCallback, PVOID pvCallbackContext, PVOID pvContext ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_ReadEncryptedFileRaw( PFE_EXPORT_FUNC pfExportCallback, PVOID pvCallbackContext, PVOID pvContext ) { static FN_ReadEncryptedFileRaw *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ReadEncryptedFileRaw", &g_Kernel32); return pfn( pfExportCallback, pvCallbackContext, pvContext ); } typedef DWORD WINAPI FN_WriteEncryptedFileRaw( PFE_IMPORT_FUNC pfImportCallback, PVOID pvCallbackContext, PVOID pvContext ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_WriteEncryptedFileRaw( PFE_IMPORT_FUNC pfImportCallback, PVOID pvCallbackContext, PVOID pvContext ) { static FN_WriteEncryptedFileRaw *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WriteEncryptedFileRaw", &g_Kernel32); return pfn( pfImportCallback, pvCallbackContext, pvContext ); } typedef VOID WINAPI FN_CloseEncryptedFileRaw( PVOID pvContext ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_CloseEncryptedFileRaw( PVOID pvContext ) { static FN_CloseEncryptedFileRaw *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CloseEncryptedFileRaw", &g_Kernel32); pfn( pvContext ); } typedef int WINAPI FN_lstrcmpA( LPCSTR lpString1, LPCSTR lpString2 ); __declspec(dllexport) int WINAPI kPrf2Wrap_lstrcmpA( LPCSTR lpString1, LPCSTR lpString2 ) { static FN_lstrcmpA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "lstrcmpA", &g_Kernel32); return pfn( lpString1, lpString2 ); } typedef int WINAPI FN_lstrcmpW( LPCWSTR lpString1, LPCWSTR lpString2 ); __declspec(dllexport) int WINAPI kPrf2Wrap_lstrcmpW( LPCWSTR lpString1, LPCWSTR lpString2 ) { static FN_lstrcmpW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "lstrcmpW", &g_Kernel32); return pfn( lpString1, lpString2 ); } typedef int WINAPI FN_lstrcmpiA( LPCSTR lpString1, LPCSTR lpString2 ); __declspec(dllexport) int WINAPI kPrf2Wrap_lstrcmpiA( LPCSTR lpString1, LPCSTR lpString2 ) { static FN_lstrcmpiA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "lstrcmpiA", &g_Kernel32); return pfn( lpString1, lpString2 ); } typedef int WINAPI FN_lstrcmpiW( LPCWSTR lpString1, LPCWSTR lpString2 ); __declspec(dllexport) int WINAPI kPrf2Wrap_lstrcmpiW( LPCWSTR lpString1, LPCWSTR lpString2 ) { static FN_lstrcmpiW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "lstrcmpiW", &g_Kernel32); return pfn( lpString1, lpString2 ); } typedef LPSTR WINAPI FN_lstrcpynA( LPSTR lpString1, LPCSTR lpString2, int iMaxLength ); __declspec(dllexport) LPSTR WINAPI kPrf2Wrap_lstrcpynA( LPSTR lpString1, LPCSTR lpString2, int iMaxLength ) { static FN_lstrcpynA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "lstrcpynA", &g_Kernel32); return pfn( lpString1, lpString2, iMaxLength ); } typedef LPWSTR WINAPI FN_lstrcpynW( LPWSTR lpString1, LPCWSTR lpString2, int iMaxLength ); __declspec(dllexport) LPWSTR WINAPI kPrf2Wrap_lstrcpynW( LPWSTR lpString1, LPCWSTR lpString2, int iMaxLength ) { static FN_lstrcpynW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "lstrcpynW", &g_Kernel32); return pfn( lpString1, lpString2, iMaxLength ); } typedef LPSTR WINAPI FN_lstrcpyA( LPSTR lpString1, LPCSTR lpString2 ); __declspec(dllexport) LPSTR WINAPI kPrf2Wrap_lstrcpyA( LPSTR lpString1, LPCSTR lpString2 ) { static FN_lstrcpyA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "lstrcpyA", &g_Kernel32); return pfn( lpString1, lpString2 ); } typedef LPWSTR WINAPI FN_lstrcpyW( LPWSTR lpString1, LPCWSTR lpString2 ); __declspec(dllexport) LPWSTR WINAPI kPrf2Wrap_lstrcpyW( LPWSTR lpString1, LPCWSTR lpString2 ) { static FN_lstrcpyW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "lstrcpyW", &g_Kernel32); return pfn( lpString1, lpString2 ); } typedef LPSTR WINAPI FN_lstrcatA( LPSTR lpString1, LPCSTR lpString2 ); __declspec(dllexport) LPSTR WINAPI kPrf2Wrap_lstrcatA( LPSTR lpString1, LPCSTR lpString2 ) { static FN_lstrcatA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "lstrcatA", &g_Kernel32); return pfn( lpString1, lpString2 ); } typedef LPWSTR WINAPI FN_lstrcatW( LPWSTR lpString1, LPCWSTR lpString2 ); __declspec(dllexport) LPWSTR WINAPI kPrf2Wrap_lstrcatW( LPWSTR lpString1, LPCWSTR lpString2 ) { static FN_lstrcatW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "lstrcatW", &g_Kernel32); return pfn( lpString1, lpString2 ); } typedef int WINAPI FN_lstrlenA( LPCSTR lpString ); __declspec(dllexport) int WINAPI kPrf2Wrap_lstrlenA( LPCSTR lpString ) { static FN_lstrlenA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "lstrlenA", &g_Kernel32); return pfn( lpString ); } typedef int WINAPI FN_lstrlenW( LPCWSTR lpString ); __declspec(dllexport) int WINAPI kPrf2Wrap_lstrlenW( LPCWSTR lpString ) { static FN_lstrlenW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "lstrlenW", &g_Kernel32); return pfn( lpString ); } typedef HFILE WINAPI FN_OpenFile( LPCSTR lpFileName, LPOFSTRUCT lpReOpenBuff, UINT uStyle ); __declspec(dllexport) HFILE WINAPI kPrf2Wrap_OpenFile( LPCSTR lpFileName, LPOFSTRUCT lpReOpenBuff, UINT uStyle ) { static FN_OpenFile *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "OpenFile", &g_Kernel32); return pfn( lpFileName, lpReOpenBuff, uStyle ); } typedef HFILE WINAPI FN__lopen( LPCSTR lpPathName, int iReadWrite ); __declspec(dllexport) HFILE WINAPI kPrf2Wrap__lopen( LPCSTR lpPathName, int iReadWrite ) { static FN__lopen *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "_lopen", &g_Kernel32); return pfn( lpPathName, iReadWrite ); } typedef HFILE WINAPI FN__lcreat( LPCSTR lpPathName, int iAttribute ); __declspec(dllexport) HFILE WINAPI kPrf2Wrap__lcreat( LPCSTR lpPathName, int iAttribute ) { static FN__lcreat *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "_lcreat", &g_Kernel32); return pfn( lpPathName, iAttribute ); } typedef UINT WINAPI FN__lread( HFILE hFile, LPVOID lpBuffer, UINT uBytes ); __declspec(dllexport) UINT WINAPI kPrf2Wrap__lread( HFILE hFile, LPVOID lpBuffer, UINT uBytes ) { static FN__lread *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "_lread", &g_Kernel32); return pfn( hFile, lpBuffer, uBytes ); } typedef UINT WINAPI FN__lwrite( HFILE hFile, LPCCH lpBuffer, UINT uBytes ); __declspec(dllexport) UINT WINAPI kPrf2Wrap__lwrite( HFILE hFile, LPCCH lpBuffer, UINT uBytes ) { static FN__lwrite *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "_lwrite", &g_Kernel32); return pfn( hFile, lpBuffer, uBytes ); } typedef long WINAPI FN__hread( HFILE hFile, LPVOID lpBuffer, long lBytes ); __declspec(dllexport) long WINAPI kPrf2Wrap__hread( HFILE hFile, LPVOID lpBuffer, long lBytes ) { static FN__hread *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "_hread", &g_Kernel32); return pfn( hFile, lpBuffer, lBytes ); } typedef long WINAPI FN__hwrite( HFILE hFile, LPCCH lpBuffer, long lBytes ); __declspec(dllexport) long WINAPI kPrf2Wrap__hwrite( HFILE hFile, LPCCH lpBuffer, long lBytes ) { static FN__hwrite *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "_hwrite", &g_Kernel32); return pfn( hFile, lpBuffer, lBytes ); } typedef HFILE WINAPI FN__lclose( HFILE hFile ); __declspec(dllexport) HFILE WINAPI kPrf2Wrap__lclose( HFILE hFile ) { static FN__lclose *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "_lclose", &g_Kernel32); return pfn( hFile ); } typedef LONG WINAPI FN__llseek( HFILE hFile, LONG lOffset, int iOrigin ); __declspec(dllexport) LONG WINAPI kPrf2Wrap__llseek( HFILE hFile, LONG lOffset, int iOrigin ) { static FN__llseek *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "_llseek", &g_Kernel32); return pfn( hFile, lOffset, iOrigin ); } typedef BOOL WINAPI FN_IsTextUnicode( CONST VOID * lpv, int iSize, LPINT lpiResult ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsTextUnicode( CONST VOID * lpv, int iSize, LPINT lpiResult ) { static FN_IsTextUnicode *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "IsTextUnicode", &g_Kernel32); return pfn( lpv, iSize, lpiResult ); } typedef DWORD WINAPI FN_FlsAlloc( PFLS_CALLBACK_FUNCTION lpCallback ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_FlsAlloc( PFLS_CALLBACK_FUNCTION lpCallback ) { static FN_FlsAlloc *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FlsAlloc", &g_Kernel32); return pfn( lpCallback ); } typedef PVOID WINAPI FN_FlsGetValue( DWORD dwFlsIndex ); __declspec(dllexport) PVOID WINAPI kPrf2Wrap_FlsGetValue( DWORD dwFlsIndex ) { static FN_FlsGetValue *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FlsGetValue", &g_Kernel32); return pfn( dwFlsIndex ); } typedef BOOL WINAPI FN_FlsSetValue( DWORD dwFlsIndex, PVOID lpFlsData ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FlsSetValue( DWORD dwFlsIndex, PVOID lpFlsData ) { static FN_FlsSetValue *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FlsSetValue", &g_Kernel32); return pfn( dwFlsIndex, lpFlsData ); } typedef BOOL WINAPI FN_FlsFree( DWORD dwFlsIndex ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FlsFree( DWORD dwFlsIndex ) { static FN_FlsFree *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FlsFree", &g_Kernel32); return pfn( dwFlsIndex ); } typedef DWORD WINAPI FN_TlsAlloc( VOID ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_TlsAlloc( VOID ) { static FN_TlsAlloc *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "TlsAlloc", &g_Kernel32); return pfn (); } typedef LPVOID WINAPI FN_TlsGetValue( DWORD dwTlsIndex ); __declspec(dllexport) LPVOID WINAPI kPrf2Wrap_TlsGetValue( DWORD dwTlsIndex ) { static FN_TlsGetValue *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "TlsGetValue", &g_Kernel32); return pfn( dwTlsIndex ); } typedef BOOL WINAPI FN_TlsSetValue( DWORD dwTlsIndex, LPVOID lpTlsValue ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_TlsSetValue( DWORD dwTlsIndex, LPVOID lpTlsValue ) { static FN_TlsSetValue *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "TlsSetValue", &g_Kernel32); return pfn( dwTlsIndex, lpTlsValue ); } typedef BOOL WINAPI FN_TlsFree( DWORD dwTlsIndex ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_TlsFree( DWORD dwTlsIndex ) { static FN_TlsFree *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "TlsFree", &g_Kernel32); return pfn( dwTlsIndex ); } typedef DWORD WINAPI FN_SleepEx( DWORD dwMilliseconds, BOOL bAlertable ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_SleepEx( DWORD dwMilliseconds, BOOL bAlertable ) { static FN_SleepEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SleepEx", &g_Kernel32); return pfn( dwMilliseconds, bAlertable ); } typedef DWORD WINAPI FN_WaitForSingleObjectEx( HANDLE hHandle, DWORD dwMilliseconds, BOOL bAlertable ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_WaitForSingleObjectEx( HANDLE hHandle, DWORD dwMilliseconds, BOOL bAlertable ) { static FN_WaitForSingleObjectEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WaitForSingleObjectEx", &g_Kernel32); return pfn( hHandle, dwMilliseconds, bAlertable ); } typedef DWORD WINAPI FN_WaitForMultipleObjectsEx( DWORD nCount, CONST HANDLE * lpHandles, BOOL bWaitAll, DWORD dwMilliseconds, BOOL bAlertable ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_WaitForMultipleObjectsEx( DWORD nCount, CONST HANDLE * lpHandles, BOOL bWaitAll, DWORD dwMilliseconds, BOOL bAlertable ) { static FN_WaitForMultipleObjectsEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WaitForMultipleObjectsEx", &g_Kernel32); return pfn( nCount, lpHandles, bWaitAll, dwMilliseconds, bAlertable ); } typedef DWORD WINAPI FN_SignalObjectAndWait( HANDLE hObjectToSignal, HANDLE hObjectToWaitOn, DWORD dwMilliseconds, BOOL bAlertable ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_SignalObjectAndWait( HANDLE hObjectToSignal, HANDLE hObjectToWaitOn, DWORD dwMilliseconds, BOOL bAlertable ) { static FN_SignalObjectAndWait *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SignalObjectAndWait", &g_Kernel32); return pfn( hObjectToSignal, hObjectToWaitOn, dwMilliseconds, bAlertable ); } typedef BOOL WINAPI FN_ReadFileEx( HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadFileEx( HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine ) { static FN_ReadFileEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ReadFileEx", &g_Kernel32); return pfn( hFile, lpBuffer, nNumberOfBytesToRead, lpOverlapped, lpCompletionRoutine ); } typedef BOOL WINAPI FN_WriteFileEx( HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteFileEx( HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine ) { static FN_WriteFileEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WriteFileEx", &g_Kernel32); return pfn( hFile, lpBuffer, nNumberOfBytesToWrite, lpOverlapped, lpCompletionRoutine ); } typedef BOOL WINAPI FN_BackupRead( HANDLE hFile, LPBYTE lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, BOOL bAbort, BOOL bProcessSecurity, LPVOID * lpContext ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_BackupRead( HANDLE hFile, LPBYTE lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, BOOL bAbort, BOOL bProcessSecurity, LPVOID * lpContext ) { static FN_BackupRead *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "BackupRead", &g_Kernel32); return pfn( hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, bAbort, bProcessSecurity, lpContext ); } typedef BOOL WINAPI FN_BackupSeek( HANDLE hFile, DWORD dwLowBytesToSeek, DWORD dwHighBytesToSeek, LPDWORD lpdwLowByteSeeked, LPDWORD lpdwHighByteSeeked, LPVOID * lpContext ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_BackupSeek( HANDLE hFile, DWORD dwLowBytesToSeek, DWORD dwHighBytesToSeek, LPDWORD lpdwLowByteSeeked, LPDWORD lpdwHighByteSeeked, LPVOID * lpContext ) { static FN_BackupSeek *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "BackupSeek", &g_Kernel32); return pfn( hFile, dwLowBytesToSeek, dwHighBytesToSeek, lpdwLowByteSeeked, lpdwHighByteSeeked, lpContext ); } typedef BOOL WINAPI FN_BackupWrite( HANDLE hFile, LPBYTE lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, BOOL bAbort, BOOL bProcessSecurity, LPVOID * lpContext ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_BackupWrite( HANDLE hFile, LPBYTE lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, BOOL bAbort, BOOL bProcessSecurity, LPVOID * lpContext ) { static FN_BackupWrite *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "BackupWrite", &g_Kernel32); return pfn( hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, bAbort, bProcessSecurity, lpContext ); } typedef BOOL WINAPI FN_ReadFileScatter( HANDLE hFile, FILE_SEGMENT_ELEMENT aSegmentArray[], DWORD nNumberOfBytesToRead, LPDWORD lpReserved, LPOVERLAPPED lpOverlapped ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadFileScatter( HANDLE hFile, FILE_SEGMENT_ELEMENT aSegmentArray[], DWORD nNumberOfBytesToRead, LPDWORD lpReserved, LPOVERLAPPED lpOverlapped ) { static FN_ReadFileScatter *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ReadFileScatter", &g_Kernel32); return pfn( hFile, aSegmentArray, nNumberOfBytesToRead, lpReserved, lpOverlapped ); } typedef BOOL WINAPI FN_WriteFileGather( HANDLE hFile, FILE_SEGMENT_ELEMENT aSegmentArray[], DWORD nNumberOfBytesToWrite, LPDWORD lpReserved, LPOVERLAPPED lpOverlapped ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteFileGather( HANDLE hFile, FILE_SEGMENT_ELEMENT aSegmentArray[], DWORD nNumberOfBytesToWrite, LPDWORD lpReserved, LPOVERLAPPED lpOverlapped ) { static FN_WriteFileGather *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WriteFileGather", &g_Kernel32); return pfn( hFile, aSegmentArray, nNumberOfBytesToWrite, lpReserved, lpOverlapped ); } typedef HANDLE WINAPI FN_CreateMutexA( LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCSTR lpName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateMutexA( LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCSTR lpName ) { static FN_CreateMutexA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateMutexA", &g_Kernel32); return pfn( lpMutexAttributes, bInitialOwner, lpName ); } typedef HANDLE WINAPI FN_CreateMutexW( LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCWSTR lpName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateMutexW( LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCWSTR lpName ) { static FN_CreateMutexW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateMutexW", &g_Kernel32); return pfn( lpMutexAttributes, bInitialOwner, lpName ); } typedef HANDLE WINAPI FN_OpenMutexA( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenMutexA( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName ) { static FN_OpenMutexA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "OpenMutexA", &g_Kernel32); return pfn( dwDesiredAccess, bInheritHandle, lpName ); } typedef HANDLE WINAPI FN_OpenMutexW( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenMutexW( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName ) { static FN_OpenMutexW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "OpenMutexW", &g_Kernel32); return pfn( dwDesiredAccess, bInheritHandle, lpName ); } typedef HANDLE WINAPI FN_CreateEventA( LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCSTR lpName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateEventA( LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCSTR lpName ) { static FN_CreateEventA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateEventA", &g_Kernel32); return pfn( lpEventAttributes, bManualReset, bInitialState, lpName ); } typedef HANDLE WINAPI FN_CreateEventW( LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCWSTR lpName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateEventW( LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCWSTR lpName ) { static FN_CreateEventW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateEventW", &g_Kernel32); return pfn( lpEventAttributes, bManualReset, bInitialState, lpName ); } typedef HANDLE WINAPI FN_OpenEventA( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenEventA( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName ) { static FN_OpenEventA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "OpenEventA", &g_Kernel32); return pfn( dwDesiredAccess, bInheritHandle, lpName ); } typedef HANDLE WINAPI FN_OpenEventW( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenEventW( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName ) { static FN_OpenEventW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "OpenEventW", &g_Kernel32); return pfn( dwDesiredAccess, bInheritHandle, lpName ); } typedef HANDLE WINAPI FN_CreateSemaphoreA( LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCSTR lpName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateSemaphoreA( LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCSTR lpName ) { static FN_CreateSemaphoreA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateSemaphoreA", &g_Kernel32); return pfn( lpSemaphoreAttributes, lInitialCount, lMaximumCount, lpName ); } typedef HANDLE WINAPI FN_CreateSemaphoreW( LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCWSTR lpName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateSemaphoreW( LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCWSTR lpName ) { static FN_CreateSemaphoreW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateSemaphoreW", &g_Kernel32); return pfn( lpSemaphoreAttributes, lInitialCount, lMaximumCount, lpName ); } typedef HANDLE WINAPI FN_OpenSemaphoreA( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenSemaphoreA( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName ) { static FN_OpenSemaphoreA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "OpenSemaphoreA", &g_Kernel32); return pfn( dwDesiredAccess, bInheritHandle, lpName ); } typedef HANDLE WINAPI FN_OpenSemaphoreW( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenSemaphoreW( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName ) { static FN_OpenSemaphoreW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "OpenSemaphoreW", &g_Kernel32); return pfn( dwDesiredAccess, bInheritHandle, lpName ); } typedef HANDLE WINAPI FN_CreateWaitableTimerA( LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset, LPCSTR lpTimerName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateWaitableTimerA( LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset, LPCSTR lpTimerName ) { static FN_CreateWaitableTimerA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateWaitableTimerA", &g_Kernel32); return pfn( lpTimerAttributes, bManualReset, lpTimerName ); } typedef HANDLE WINAPI FN_CreateWaitableTimerW( LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset, LPCWSTR lpTimerName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateWaitableTimerW( LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset, LPCWSTR lpTimerName ) { static FN_CreateWaitableTimerW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateWaitableTimerW", &g_Kernel32); return pfn( lpTimerAttributes, bManualReset, lpTimerName ); } typedef HANDLE WINAPI FN_OpenWaitableTimerA( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpTimerName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenWaitableTimerA( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpTimerName ) { static FN_OpenWaitableTimerA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "OpenWaitableTimerA", &g_Kernel32); return pfn( dwDesiredAccess, bInheritHandle, lpTimerName ); } typedef HANDLE WINAPI FN_OpenWaitableTimerW( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpTimerName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenWaitableTimerW( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpTimerName ) { static FN_OpenWaitableTimerW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "OpenWaitableTimerW", &g_Kernel32); return pfn( dwDesiredAccess, bInheritHandle, lpTimerName ); } typedef BOOL WINAPI FN_SetWaitableTimer( HANDLE hTimer, const LARGE_INTEGER * lpDueTime, LONG lPeriod, PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine, BOOL fResume ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetWaitableTimer( HANDLE hTimer, const LARGE_INTEGER * lpDueTime, LONG lPeriod, PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine, BOOL fResume ) { static FN_SetWaitableTimer *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetWaitableTimer", &g_Kernel32); return pfn( hTimer, lpDueTime, lPeriod, pfnCompletionRoutine, lpArgToCompletionRoutine, fResume ); } typedef BOOL WINAPI FN_CancelWaitableTimer( HANDLE hTimer ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CancelWaitableTimer( HANDLE hTimer ) { static FN_CancelWaitableTimer *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CancelWaitableTimer", &g_Kernel32); return pfn( hTimer ); } typedef HANDLE WINAPI FN_CreateFileMappingA( HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateFileMappingA( HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName ) { static FN_CreateFileMappingA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateFileMappingA", &g_Kernel32); return pfn( hFile, lpFileMappingAttributes, flProtect, dwMaximumSizeHigh, dwMaximumSizeLow, lpName ); } typedef HANDLE WINAPI FN_CreateFileMappingW( HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCWSTR lpName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateFileMappingW( HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCWSTR lpName ) { static FN_CreateFileMappingW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateFileMappingW", &g_Kernel32); return pfn( hFile, lpFileMappingAttributes, flProtect, dwMaximumSizeHigh, dwMaximumSizeLow, lpName ); } typedef HANDLE WINAPI FN_OpenFileMappingA( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenFileMappingA( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName ) { static FN_OpenFileMappingA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "OpenFileMappingA", &g_Kernel32); return pfn( dwDesiredAccess, bInheritHandle, lpName ); } typedef HANDLE WINAPI FN_OpenFileMappingW( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenFileMappingW( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName ) { static FN_OpenFileMappingW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "OpenFileMappingW", &g_Kernel32); return pfn( dwDesiredAccess, bInheritHandle, lpName ); } typedef DWORD WINAPI FN_GetLogicalDriveStringsA( DWORD nBufferLength, LPSTR lpBuffer ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetLogicalDriveStringsA( DWORD nBufferLength, LPSTR lpBuffer ) { static FN_GetLogicalDriveStringsA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetLogicalDriveStringsA", &g_Kernel32); return pfn( nBufferLength, lpBuffer ); } typedef DWORD WINAPI FN_GetLogicalDriveStringsW( DWORD nBufferLength, LPWSTR lpBuffer ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetLogicalDriveStringsW( DWORD nBufferLength, LPWSTR lpBuffer ) { static FN_GetLogicalDriveStringsW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetLogicalDriveStringsW", &g_Kernel32); return pfn( nBufferLength, lpBuffer ); } typedef HANDLE WINAPI FN_CreateMemoryResourceNotification( MEMORY_RESOURCE_NOTIFICATION_TYPE NotificationType ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateMemoryResourceNotification( MEMORY_RESOURCE_NOTIFICATION_TYPE NotificationType ) { static FN_CreateMemoryResourceNotification *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateMemoryResourceNotification", &g_Kernel32); return pfn( NotificationType ); } typedef BOOL WINAPI FN_QueryMemoryResourceNotification( HANDLE ResourceNotificationHandle, PBOOL ResourceState ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_QueryMemoryResourceNotification( HANDLE ResourceNotificationHandle, PBOOL ResourceState ) { static FN_QueryMemoryResourceNotification *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "QueryMemoryResourceNotification", &g_Kernel32); return pfn( ResourceNotificationHandle, ResourceState ); } typedef HMODULE WINAPI FN_LoadLibraryA( LPCSTR lpLibFileName ); __declspec(dllexport) HMODULE WINAPI kPrf2Wrap_LoadLibraryA( LPCSTR lpLibFileName ) { static FN_LoadLibraryA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LoadLibraryA", &g_Kernel32); return pfn( lpLibFileName ); } typedef HMODULE WINAPI FN_LoadLibraryW( LPCWSTR lpLibFileName ); __declspec(dllexport) HMODULE WINAPI kPrf2Wrap_LoadLibraryW( LPCWSTR lpLibFileName ) { static FN_LoadLibraryW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LoadLibraryW", &g_Kernel32); return pfn( lpLibFileName ); } typedef HMODULE WINAPI FN_LoadLibraryExA( LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags ); __declspec(dllexport) HMODULE WINAPI kPrf2Wrap_LoadLibraryExA( LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags ) { static FN_LoadLibraryExA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LoadLibraryExA", &g_Kernel32); return pfn( lpLibFileName, hFile, dwFlags ); } typedef HMODULE WINAPI FN_LoadLibraryExW( LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags ); __declspec(dllexport) HMODULE WINAPI kPrf2Wrap_LoadLibraryExW( LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags ) { static FN_LoadLibraryExW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LoadLibraryExW", &g_Kernel32); return pfn( lpLibFileName, hFile, dwFlags ); } typedef DWORD WINAPI FN_GetModuleFileNameA( HMODULE hModule, LPCH lpFilename, DWORD nSize ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetModuleFileNameA( HMODULE hModule, LPCH lpFilename, DWORD nSize ) { static FN_GetModuleFileNameA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetModuleFileNameA", &g_Kernel32); return pfn( hModule, lpFilename, nSize ); } typedef DWORD WINAPI FN_GetModuleFileNameW( HMODULE hModule, LPWCH lpFilename, DWORD nSize ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetModuleFileNameW( HMODULE hModule, LPWCH lpFilename, DWORD nSize ) { static FN_GetModuleFileNameW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetModuleFileNameW", &g_Kernel32); return pfn( hModule, lpFilename, nSize ); } typedef HMODULE WINAPI FN_GetModuleHandleA( LPCSTR lpModuleName ); __declspec(dllexport) HMODULE WINAPI kPrf2Wrap_GetModuleHandleA( LPCSTR lpModuleName ) { static FN_GetModuleHandleA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetModuleHandleA", &g_Kernel32); return pfn( lpModuleName ); } typedef HMODULE WINAPI FN_GetModuleHandleW( LPCWSTR lpModuleName ); __declspec(dllexport) HMODULE WINAPI kPrf2Wrap_GetModuleHandleW( LPCWSTR lpModuleName ) { static FN_GetModuleHandleW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetModuleHandleW", &g_Kernel32); return pfn( lpModuleName ); } typedef BOOL WINAPI FN_GetModuleHandleExA( DWORD dwFlags, LPCSTR lpModuleName, HMODULE * phModule ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetModuleHandleExA( DWORD dwFlags, LPCSTR lpModuleName, HMODULE * phModule ) { static FN_GetModuleHandleExA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetModuleHandleExA", &g_Kernel32); return pfn( dwFlags, lpModuleName, phModule ); } typedef BOOL WINAPI FN_GetModuleHandleExW( DWORD dwFlags, LPCWSTR lpModuleName, HMODULE * phModule ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetModuleHandleExW( DWORD dwFlags, LPCWSTR lpModuleName, HMODULE * phModule ) { static FN_GetModuleHandleExW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetModuleHandleExW", &g_Kernel32); return pfn( dwFlags, lpModuleName, phModule ); } typedef BOOL WINAPI FN_NeedCurrentDirectoryForExePathA( LPCSTR ExeName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_NeedCurrentDirectoryForExePathA( LPCSTR ExeName ) { static FN_NeedCurrentDirectoryForExePathA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "NeedCurrentDirectoryForExePathA", &g_Kernel32); return pfn( ExeName ); } typedef BOOL WINAPI FN_NeedCurrentDirectoryForExePathW( LPCWSTR ExeName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_NeedCurrentDirectoryForExePathW( LPCWSTR ExeName ) { static FN_NeedCurrentDirectoryForExePathW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "NeedCurrentDirectoryForExePathW", &g_Kernel32); return pfn( ExeName ); } typedef BOOL WINAPI FN_CreateProcessA( LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateProcessA( LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ) { static FN_CreateProcessA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateProcessA", &g_Kernel32); return pfn( lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation ); } typedef BOOL WINAPI FN_CreateProcessW( LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateProcessW( LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ) { static FN_CreateProcessW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateProcessW", &g_Kernel32); return pfn( lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation ); } typedef BOOL WINAPI FN_SetProcessShutdownParameters( DWORD dwLevel, DWORD dwFlags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetProcessShutdownParameters( DWORD dwLevel, DWORD dwFlags ) { static FN_SetProcessShutdownParameters *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetProcessShutdownParameters", &g_Kernel32); return pfn( dwLevel, dwFlags ); } typedef BOOL WINAPI FN_GetProcessShutdownParameters( LPDWORD lpdwLevel, LPDWORD lpdwFlags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetProcessShutdownParameters( LPDWORD lpdwLevel, LPDWORD lpdwFlags ) { static FN_GetProcessShutdownParameters *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetProcessShutdownParameters", &g_Kernel32); return pfn( lpdwLevel, lpdwFlags ); } typedef DWORD WINAPI FN_GetProcessVersion( DWORD ProcessId ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetProcessVersion( DWORD ProcessId ) { static FN_GetProcessVersion *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetProcessVersion", &g_Kernel32); return pfn( ProcessId ); } typedef VOID WINAPI FN_FatalAppExitA( UINT uAction, LPCSTR lpMessageText ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_FatalAppExitA( UINT uAction, LPCSTR lpMessageText ) { static FN_FatalAppExitA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FatalAppExitA", &g_Kernel32); pfn( uAction, lpMessageText ); } typedef VOID WINAPI FN_FatalAppExitW( UINT uAction, LPCWSTR lpMessageText ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_FatalAppExitW( UINT uAction, LPCWSTR lpMessageText ) { static FN_FatalAppExitW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FatalAppExitW", &g_Kernel32); pfn( uAction, lpMessageText ); } typedef VOID WINAPI FN_GetStartupInfoA( LPSTARTUPINFOA lpStartupInfo ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_GetStartupInfoA( LPSTARTUPINFOA lpStartupInfo ) { static FN_GetStartupInfoA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetStartupInfoA", &g_Kernel32); pfn( lpStartupInfo ); } typedef VOID WINAPI FN_GetStartupInfoW( LPSTARTUPINFOW lpStartupInfo ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_GetStartupInfoW( LPSTARTUPINFOW lpStartupInfo ) { static FN_GetStartupInfoW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetStartupInfoW", &g_Kernel32); pfn( lpStartupInfo ); } typedef LPSTR WINAPI FN_GetCommandLineA( VOID ); __declspec(dllexport) LPSTR WINAPI kPrf2Wrap_GetCommandLineA( VOID ) { static FN_GetCommandLineA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetCommandLineA", &g_Kernel32); return pfn (); } typedef LPWSTR WINAPI FN_GetCommandLineW( VOID ); __declspec(dllexport) LPWSTR WINAPI kPrf2Wrap_GetCommandLineW( VOID ) { static FN_GetCommandLineW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetCommandLineW", &g_Kernel32); return pfn (); } typedef DWORD WINAPI FN_GetEnvironmentVariableA( LPCSTR lpName, LPSTR lpBuffer, DWORD nSize ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetEnvironmentVariableA( LPCSTR lpName, LPSTR lpBuffer, DWORD nSize ) { static FN_GetEnvironmentVariableA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetEnvironmentVariableA", &g_Kernel32); return pfn( lpName, lpBuffer, nSize ); } typedef DWORD WINAPI FN_GetEnvironmentVariableW( LPCWSTR lpName, LPWSTR lpBuffer, DWORD nSize ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetEnvironmentVariableW( LPCWSTR lpName, LPWSTR lpBuffer, DWORD nSize ) { static FN_GetEnvironmentVariableW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetEnvironmentVariableW", &g_Kernel32); return pfn( lpName, lpBuffer, nSize ); } typedef BOOL WINAPI FN_SetEnvironmentVariableA( LPCSTR lpName, LPCSTR lpValue ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetEnvironmentVariableA( LPCSTR lpName, LPCSTR lpValue ) { static FN_SetEnvironmentVariableA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetEnvironmentVariableA", &g_Kernel32); return pfn( lpName, lpValue ); } typedef BOOL WINAPI FN_SetEnvironmentVariableW( LPCWSTR lpName, LPCWSTR lpValue ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetEnvironmentVariableW( LPCWSTR lpName, LPCWSTR lpValue ) { static FN_SetEnvironmentVariableW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetEnvironmentVariableW", &g_Kernel32); return pfn( lpName, lpValue ); } typedef DWORD WINAPI FN_ExpandEnvironmentStringsA( LPCSTR lpSrc, LPSTR lpDst, DWORD nSize ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_ExpandEnvironmentStringsA( LPCSTR lpSrc, LPSTR lpDst, DWORD nSize ) { static FN_ExpandEnvironmentStringsA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ExpandEnvironmentStringsA", &g_Kernel32); return pfn( lpSrc, lpDst, nSize ); } typedef DWORD WINAPI FN_ExpandEnvironmentStringsW( LPCWSTR lpSrc, LPWSTR lpDst, DWORD nSize ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_ExpandEnvironmentStringsW( LPCWSTR lpSrc, LPWSTR lpDst, DWORD nSize ) { static FN_ExpandEnvironmentStringsW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ExpandEnvironmentStringsW", &g_Kernel32); return pfn( lpSrc, lpDst, nSize ); } typedef DWORD WINAPI FN_GetFirmwareEnvironmentVariableA( LPCSTR lpName, LPCSTR lpGuid, PVOID pBuffer, DWORD nSize ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetFirmwareEnvironmentVariableA( LPCSTR lpName, LPCSTR lpGuid, PVOID pBuffer, DWORD nSize ) { static FN_GetFirmwareEnvironmentVariableA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetFirmwareEnvironmentVariableA", &g_Kernel32); return pfn( lpName, lpGuid, pBuffer, nSize ); } typedef DWORD WINAPI FN_GetFirmwareEnvironmentVariableW( LPCWSTR lpName, LPCWSTR lpGuid, PVOID pBuffer, DWORD nSize ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetFirmwareEnvironmentVariableW( LPCWSTR lpName, LPCWSTR lpGuid, PVOID pBuffer, DWORD nSize ) { static FN_GetFirmwareEnvironmentVariableW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetFirmwareEnvironmentVariableW", &g_Kernel32); return pfn( lpName, lpGuid, pBuffer, nSize ); } typedef BOOL WINAPI FN_SetFirmwareEnvironmentVariableA( LPCSTR lpName, LPCSTR lpGuid, PVOID pValue, DWORD nSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetFirmwareEnvironmentVariableA( LPCSTR lpName, LPCSTR lpGuid, PVOID pValue, DWORD nSize ) { static FN_SetFirmwareEnvironmentVariableA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetFirmwareEnvironmentVariableA", &g_Kernel32); return pfn( lpName, lpGuid, pValue, nSize ); } typedef BOOL WINAPI FN_SetFirmwareEnvironmentVariableW( LPCWSTR lpName, LPCWSTR lpGuid, PVOID pValue, DWORD nSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetFirmwareEnvironmentVariableW( LPCWSTR lpName, LPCWSTR lpGuid, PVOID pValue, DWORD nSize ) { static FN_SetFirmwareEnvironmentVariableW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetFirmwareEnvironmentVariableW", &g_Kernel32); return pfn( lpName, lpGuid, pValue, nSize ); } typedef VOID WINAPI FN_OutputDebugStringA( LPCSTR lpOutputString ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_OutputDebugStringA( LPCSTR lpOutputString ) { static FN_OutputDebugStringA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "OutputDebugStringA", &g_Kernel32); pfn( lpOutputString ); } typedef VOID WINAPI FN_OutputDebugStringW( LPCWSTR lpOutputString ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_OutputDebugStringW( LPCWSTR lpOutputString ) { static FN_OutputDebugStringW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "OutputDebugStringW", &g_Kernel32); pfn( lpOutputString ); } typedef HRSRC WINAPI FN_FindResourceA( HMODULE hModule, LPCSTR lpName, LPCSTR lpType ); __declspec(dllexport) HRSRC WINAPI kPrf2Wrap_FindResourceA( HMODULE hModule, LPCSTR lpName, LPCSTR lpType ) { static FN_FindResourceA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindResourceA", &g_Kernel32); return pfn( hModule, lpName, lpType ); } typedef HRSRC WINAPI FN_FindResourceW( HMODULE hModule, LPCWSTR lpName, LPCWSTR lpType ); __declspec(dllexport) HRSRC WINAPI kPrf2Wrap_FindResourceW( HMODULE hModule, LPCWSTR lpName, LPCWSTR lpType ) { static FN_FindResourceW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindResourceW", &g_Kernel32); return pfn( hModule, lpName, lpType ); } typedef HRSRC WINAPI FN_FindResourceExA( HMODULE hModule, LPCSTR lpType, LPCSTR lpName, WORD wLanguage ); __declspec(dllexport) HRSRC WINAPI kPrf2Wrap_FindResourceExA( HMODULE hModule, LPCSTR lpType, LPCSTR lpName, WORD wLanguage ) { static FN_FindResourceExA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindResourceExA", &g_Kernel32); return pfn( hModule, lpType, lpName, wLanguage ); } typedef HRSRC WINAPI FN_FindResourceExW( HMODULE hModule, LPCWSTR lpType, LPCWSTR lpName, WORD wLanguage ); __declspec(dllexport) HRSRC WINAPI kPrf2Wrap_FindResourceExW( HMODULE hModule, LPCWSTR lpType, LPCWSTR lpName, WORD wLanguage ) { static FN_FindResourceExW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindResourceExW", &g_Kernel32); return pfn( hModule, lpType, lpName, wLanguage ); } typedef BOOL WINAPI FN_EnumResourceTypesA( HMODULE hModule, ENUMRESTYPEPROCA lpEnumFunc, LONG_PTR lParam ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumResourceTypesA( HMODULE hModule, ENUMRESTYPEPROCA lpEnumFunc, LONG_PTR lParam ) { static FN_EnumResourceTypesA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnumResourceTypesA", &g_Kernel32); return pfn( hModule, lpEnumFunc, lParam ); } typedef BOOL WINAPI FN_EnumResourceTypesW( HMODULE hModule, ENUMRESTYPEPROCW lpEnumFunc, LONG_PTR lParam ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumResourceTypesW( HMODULE hModule, ENUMRESTYPEPROCW lpEnumFunc, LONG_PTR lParam ) { static FN_EnumResourceTypesW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnumResourceTypesW", &g_Kernel32); return pfn( hModule, lpEnumFunc, lParam ); } typedef BOOL WINAPI FN_EnumResourceNamesA( HMODULE hModule, LPCSTR lpType, ENUMRESNAMEPROCA lpEnumFunc, LONG_PTR lParam ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumResourceNamesA( HMODULE hModule, LPCSTR lpType, ENUMRESNAMEPROCA lpEnumFunc, LONG_PTR lParam ) { static FN_EnumResourceNamesA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnumResourceNamesA", &g_Kernel32); return pfn( hModule, lpType, lpEnumFunc, lParam ); } typedef BOOL WINAPI FN_EnumResourceNamesW( HMODULE hModule, LPCWSTR lpType, ENUMRESNAMEPROCW lpEnumFunc, LONG_PTR lParam ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumResourceNamesW( HMODULE hModule, LPCWSTR lpType, ENUMRESNAMEPROCW lpEnumFunc, LONG_PTR lParam ) { static FN_EnumResourceNamesW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnumResourceNamesW", &g_Kernel32); return pfn( hModule, lpType, lpEnumFunc, lParam ); } typedef BOOL WINAPI FN_EnumResourceLanguagesA( HMODULE hModule, LPCSTR lpType, LPCSTR lpName, ENUMRESLANGPROCA lpEnumFunc, LONG_PTR lParam ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumResourceLanguagesA( HMODULE hModule, LPCSTR lpType, LPCSTR lpName, ENUMRESLANGPROCA lpEnumFunc, LONG_PTR lParam ) { static FN_EnumResourceLanguagesA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnumResourceLanguagesA", &g_Kernel32); return pfn( hModule, lpType, lpName, lpEnumFunc, lParam ); } typedef BOOL WINAPI FN_EnumResourceLanguagesW( HMODULE hModule, LPCWSTR lpType, LPCWSTR lpName, ENUMRESLANGPROCW lpEnumFunc, LONG_PTR lParam ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumResourceLanguagesW( HMODULE hModule, LPCWSTR lpType, LPCWSTR lpName, ENUMRESLANGPROCW lpEnumFunc, LONG_PTR lParam ) { static FN_EnumResourceLanguagesW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnumResourceLanguagesW", &g_Kernel32); return pfn( hModule, lpType, lpName, lpEnumFunc, lParam ); } typedef HANDLE WINAPI FN_BeginUpdateResourceA( LPCSTR pFileName, BOOL bDeleteExistingResources ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_BeginUpdateResourceA( LPCSTR pFileName, BOOL bDeleteExistingResources ) { static FN_BeginUpdateResourceA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "BeginUpdateResourceA", &g_Kernel32); return pfn( pFileName, bDeleteExistingResources ); } typedef HANDLE WINAPI FN_BeginUpdateResourceW( LPCWSTR pFileName, BOOL bDeleteExistingResources ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_BeginUpdateResourceW( LPCWSTR pFileName, BOOL bDeleteExistingResources ) { static FN_BeginUpdateResourceW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "BeginUpdateResourceW", &g_Kernel32); return pfn( pFileName, bDeleteExistingResources ); } typedef BOOL WINAPI FN_UpdateResourceA( HANDLE hUpdate, LPCSTR lpType, LPCSTR lpName, WORD wLanguage, LPVOID lpData, DWORD cb ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_UpdateResourceA( HANDLE hUpdate, LPCSTR lpType, LPCSTR lpName, WORD wLanguage, LPVOID lpData, DWORD cb ) { static FN_UpdateResourceA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "UpdateResourceA", &g_Kernel32); return pfn( hUpdate, lpType, lpName, wLanguage, lpData, cb ); } typedef BOOL WINAPI FN_UpdateResourceW( HANDLE hUpdate, LPCWSTR lpType, LPCWSTR lpName, WORD wLanguage, LPVOID lpData, DWORD cb ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_UpdateResourceW( HANDLE hUpdate, LPCWSTR lpType, LPCWSTR lpName, WORD wLanguage, LPVOID lpData, DWORD cb ) { static FN_UpdateResourceW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "UpdateResourceW", &g_Kernel32); return pfn( hUpdate, lpType, lpName, wLanguage, lpData, cb ); } typedef BOOL WINAPI FN_EndUpdateResourceA( HANDLE hUpdate, BOOL fDiscard ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EndUpdateResourceA( HANDLE hUpdate, BOOL fDiscard ) { static FN_EndUpdateResourceA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EndUpdateResourceA", &g_Kernel32); return pfn( hUpdate, fDiscard ); } typedef BOOL WINAPI FN_EndUpdateResourceW( HANDLE hUpdate, BOOL fDiscard ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EndUpdateResourceW( HANDLE hUpdate, BOOL fDiscard ) { static FN_EndUpdateResourceW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EndUpdateResourceW", &g_Kernel32); return pfn( hUpdate, fDiscard ); } typedef ATOM WINAPI FN_GlobalAddAtomA( LPCSTR lpString ); __declspec(dllexport) ATOM WINAPI kPrf2Wrap_GlobalAddAtomA( LPCSTR lpString ) { static FN_GlobalAddAtomA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GlobalAddAtomA", &g_Kernel32); return pfn( lpString ); } typedef ATOM WINAPI FN_GlobalAddAtomW( LPCWSTR lpString ); __declspec(dllexport) ATOM WINAPI kPrf2Wrap_GlobalAddAtomW( LPCWSTR lpString ) { static FN_GlobalAddAtomW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GlobalAddAtomW", &g_Kernel32); return pfn( lpString ); } typedef ATOM WINAPI FN_GlobalFindAtomA( LPCSTR lpString ); __declspec(dllexport) ATOM WINAPI kPrf2Wrap_GlobalFindAtomA( LPCSTR lpString ) { static FN_GlobalFindAtomA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GlobalFindAtomA", &g_Kernel32); return pfn( lpString ); } typedef ATOM WINAPI FN_GlobalFindAtomW( LPCWSTR lpString ); __declspec(dllexport) ATOM WINAPI kPrf2Wrap_GlobalFindAtomW( LPCWSTR lpString ) { static FN_GlobalFindAtomW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GlobalFindAtomW", &g_Kernel32); return pfn( lpString ); } typedef UINT WINAPI FN_GlobalGetAtomNameA( ATOM nAtom, LPSTR lpBuffer, int nSize ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_GlobalGetAtomNameA( ATOM nAtom, LPSTR lpBuffer, int nSize ) { static FN_GlobalGetAtomNameA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GlobalGetAtomNameA", &g_Kernel32); return pfn( nAtom, lpBuffer, nSize ); } typedef UINT WINAPI FN_GlobalGetAtomNameW( ATOM nAtom, LPWSTR lpBuffer, int nSize ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_GlobalGetAtomNameW( ATOM nAtom, LPWSTR lpBuffer, int nSize ) { static FN_GlobalGetAtomNameW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GlobalGetAtomNameW", &g_Kernel32); return pfn( nAtom, lpBuffer, nSize ); } typedef ATOM WINAPI FN_AddAtomA( LPCSTR lpString ); __declspec(dllexport) ATOM WINAPI kPrf2Wrap_AddAtomA( LPCSTR lpString ) { static FN_AddAtomA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AddAtomA", &g_Kernel32); return pfn( lpString ); } typedef ATOM WINAPI FN_AddAtomW( LPCWSTR lpString ); __declspec(dllexport) ATOM WINAPI kPrf2Wrap_AddAtomW( LPCWSTR lpString ) { static FN_AddAtomW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AddAtomW", &g_Kernel32); return pfn( lpString ); } typedef ATOM WINAPI FN_FindAtomA( LPCSTR lpString ); __declspec(dllexport) ATOM WINAPI kPrf2Wrap_FindAtomA( LPCSTR lpString ) { static FN_FindAtomA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindAtomA", &g_Kernel32); return pfn( lpString ); } typedef ATOM WINAPI FN_FindAtomW( LPCWSTR lpString ); __declspec(dllexport) ATOM WINAPI kPrf2Wrap_FindAtomW( LPCWSTR lpString ) { static FN_FindAtomW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindAtomW", &g_Kernel32); return pfn( lpString ); } typedef UINT WINAPI FN_GetAtomNameA( ATOM nAtom, LPSTR lpBuffer, int nSize ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_GetAtomNameA( ATOM nAtom, LPSTR lpBuffer, int nSize ) { static FN_GetAtomNameA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetAtomNameA", &g_Kernel32); return pfn( nAtom, lpBuffer, nSize ); } typedef UINT WINAPI FN_GetAtomNameW( ATOM nAtom, LPWSTR lpBuffer, int nSize ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_GetAtomNameW( ATOM nAtom, LPWSTR lpBuffer, int nSize ) { static FN_GetAtomNameW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetAtomNameW", &g_Kernel32); return pfn( nAtom, lpBuffer, nSize ); } typedef UINT WINAPI FN_GetProfileIntA( LPCSTR lpAppName, LPCSTR lpKeyName, INT nDefault ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_GetProfileIntA( LPCSTR lpAppName, LPCSTR lpKeyName, INT nDefault ) { static FN_GetProfileIntA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetProfileIntA", &g_Kernel32); return pfn( lpAppName, lpKeyName, nDefault ); } typedef UINT WINAPI FN_GetProfileIntW( LPCWSTR lpAppName, LPCWSTR lpKeyName, INT nDefault ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_GetProfileIntW( LPCWSTR lpAppName, LPCWSTR lpKeyName, INT nDefault ) { static FN_GetProfileIntW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetProfileIntW", &g_Kernel32); return pfn( lpAppName, lpKeyName, nDefault ); } typedef DWORD WINAPI FN_GetProfileStringA( LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpDefault, LPSTR lpReturnedString, DWORD nSize ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetProfileStringA( LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpDefault, LPSTR lpReturnedString, DWORD nSize ) { static FN_GetProfileStringA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetProfileStringA", &g_Kernel32); return pfn( lpAppName, lpKeyName, lpDefault, lpReturnedString, nSize ); } typedef DWORD WINAPI FN_GetProfileStringW( LPCWSTR lpAppName, LPCWSTR lpKeyName, LPCWSTR lpDefault, LPWSTR lpReturnedString, DWORD nSize ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetProfileStringW( LPCWSTR lpAppName, LPCWSTR lpKeyName, LPCWSTR lpDefault, LPWSTR lpReturnedString, DWORD nSize ) { static FN_GetProfileStringW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetProfileStringW", &g_Kernel32); return pfn( lpAppName, lpKeyName, lpDefault, lpReturnedString, nSize ); } typedef BOOL WINAPI FN_WriteProfileStringA( LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpString ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteProfileStringA( LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpString ) { static FN_WriteProfileStringA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WriteProfileStringA", &g_Kernel32); return pfn( lpAppName, lpKeyName, lpString ); } typedef BOOL WINAPI FN_WriteProfileStringW( LPCWSTR lpAppName, LPCWSTR lpKeyName, LPCWSTR lpString ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteProfileStringW( LPCWSTR lpAppName, LPCWSTR lpKeyName, LPCWSTR lpString ) { static FN_WriteProfileStringW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WriteProfileStringW", &g_Kernel32); return pfn( lpAppName, lpKeyName, lpString ); } typedef DWORD WINAPI FN_GetProfileSectionA( LPCSTR lpAppName, LPSTR lpReturnedString, DWORD nSize ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetProfileSectionA( LPCSTR lpAppName, LPSTR lpReturnedString, DWORD nSize ) { static FN_GetProfileSectionA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetProfileSectionA", &g_Kernel32); return pfn( lpAppName, lpReturnedString, nSize ); } typedef DWORD WINAPI FN_GetProfileSectionW( LPCWSTR lpAppName, LPWSTR lpReturnedString, DWORD nSize ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetProfileSectionW( LPCWSTR lpAppName, LPWSTR lpReturnedString, DWORD nSize ) { static FN_GetProfileSectionW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetProfileSectionW", &g_Kernel32); return pfn( lpAppName, lpReturnedString, nSize ); } typedef BOOL WINAPI FN_WriteProfileSectionA( LPCSTR lpAppName, LPCSTR lpString ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteProfileSectionA( LPCSTR lpAppName, LPCSTR lpString ) { static FN_WriteProfileSectionA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WriteProfileSectionA", &g_Kernel32); return pfn( lpAppName, lpString ); } typedef BOOL WINAPI FN_WriteProfileSectionW( LPCWSTR lpAppName, LPCWSTR lpString ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteProfileSectionW( LPCWSTR lpAppName, LPCWSTR lpString ) { static FN_WriteProfileSectionW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WriteProfileSectionW", &g_Kernel32); return pfn( lpAppName, lpString ); } typedef UINT WINAPI FN_GetPrivateProfileIntA( LPCSTR lpAppName, LPCSTR lpKeyName, INT nDefault, LPCSTR lpFileName ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_GetPrivateProfileIntA( LPCSTR lpAppName, LPCSTR lpKeyName, INT nDefault, LPCSTR lpFileName ) { static FN_GetPrivateProfileIntA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetPrivateProfileIntA", &g_Kernel32); return pfn( lpAppName, lpKeyName, nDefault, lpFileName ); } typedef UINT WINAPI FN_GetPrivateProfileIntW( LPCWSTR lpAppName, LPCWSTR lpKeyName, INT nDefault, LPCWSTR lpFileName ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_GetPrivateProfileIntW( LPCWSTR lpAppName, LPCWSTR lpKeyName, INT nDefault, LPCWSTR lpFileName ) { static FN_GetPrivateProfileIntW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetPrivateProfileIntW", &g_Kernel32); return pfn( lpAppName, lpKeyName, nDefault, lpFileName ); } typedef DWORD WINAPI FN_GetPrivateProfileStringA( LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpDefault, LPSTR lpReturnedString, DWORD nSize, LPCSTR lpFileName ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetPrivateProfileStringA( LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpDefault, LPSTR lpReturnedString, DWORD nSize, LPCSTR lpFileName ) { static FN_GetPrivateProfileStringA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetPrivateProfileStringA", &g_Kernel32); return pfn( lpAppName, lpKeyName, lpDefault, lpReturnedString, nSize, lpFileName ); } typedef DWORD WINAPI FN_GetPrivateProfileStringW( LPCWSTR lpAppName, LPCWSTR lpKeyName, LPCWSTR lpDefault, LPWSTR lpReturnedString, DWORD nSize, LPCWSTR lpFileName ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetPrivateProfileStringW( LPCWSTR lpAppName, LPCWSTR lpKeyName, LPCWSTR lpDefault, LPWSTR lpReturnedString, DWORD nSize, LPCWSTR lpFileName ) { static FN_GetPrivateProfileStringW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetPrivateProfileStringW", &g_Kernel32); return pfn( lpAppName, lpKeyName, lpDefault, lpReturnedString, nSize, lpFileName ); } typedef BOOL WINAPI FN_WritePrivateProfileStringA( LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpString, LPCSTR lpFileName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_WritePrivateProfileStringA( LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpString, LPCSTR lpFileName ) { static FN_WritePrivateProfileStringA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WritePrivateProfileStringA", &g_Kernel32); return pfn( lpAppName, lpKeyName, lpString, lpFileName ); } typedef BOOL WINAPI FN_WritePrivateProfileStringW( LPCWSTR lpAppName, LPCWSTR lpKeyName, LPCWSTR lpString, LPCWSTR lpFileName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_WritePrivateProfileStringW( LPCWSTR lpAppName, LPCWSTR lpKeyName, LPCWSTR lpString, LPCWSTR lpFileName ) { static FN_WritePrivateProfileStringW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WritePrivateProfileStringW", &g_Kernel32); return pfn( lpAppName, lpKeyName, lpString, lpFileName ); } typedef DWORD WINAPI FN_GetPrivateProfileSectionA( LPCSTR lpAppName, LPSTR lpReturnedString, DWORD nSize, LPCSTR lpFileName ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetPrivateProfileSectionA( LPCSTR lpAppName, LPSTR lpReturnedString, DWORD nSize, LPCSTR lpFileName ) { static FN_GetPrivateProfileSectionA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetPrivateProfileSectionA", &g_Kernel32); return pfn( lpAppName, lpReturnedString, nSize, lpFileName ); } typedef DWORD WINAPI FN_GetPrivateProfileSectionW( LPCWSTR lpAppName, LPWSTR lpReturnedString, DWORD nSize, LPCWSTR lpFileName ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetPrivateProfileSectionW( LPCWSTR lpAppName, LPWSTR lpReturnedString, DWORD nSize, LPCWSTR lpFileName ) { static FN_GetPrivateProfileSectionW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetPrivateProfileSectionW", &g_Kernel32); return pfn( lpAppName, lpReturnedString, nSize, lpFileName ); } typedef BOOL WINAPI FN_WritePrivateProfileSectionA( LPCSTR lpAppName, LPCSTR lpString, LPCSTR lpFileName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_WritePrivateProfileSectionA( LPCSTR lpAppName, LPCSTR lpString, LPCSTR lpFileName ) { static FN_WritePrivateProfileSectionA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WritePrivateProfileSectionA", &g_Kernel32); return pfn( lpAppName, lpString, lpFileName ); } typedef BOOL WINAPI FN_WritePrivateProfileSectionW( LPCWSTR lpAppName, LPCWSTR lpString, LPCWSTR lpFileName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_WritePrivateProfileSectionW( LPCWSTR lpAppName, LPCWSTR lpString, LPCWSTR lpFileName ) { static FN_WritePrivateProfileSectionW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WritePrivateProfileSectionW", &g_Kernel32); return pfn( lpAppName, lpString, lpFileName ); } typedef DWORD WINAPI FN_GetPrivateProfileSectionNamesA( LPSTR lpszReturnBuffer, DWORD nSize, LPCSTR lpFileName ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetPrivateProfileSectionNamesA( LPSTR lpszReturnBuffer, DWORD nSize, LPCSTR lpFileName ) { static FN_GetPrivateProfileSectionNamesA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetPrivateProfileSectionNamesA", &g_Kernel32); return pfn( lpszReturnBuffer, nSize, lpFileName ); } typedef DWORD WINAPI FN_GetPrivateProfileSectionNamesW( LPWSTR lpszReturnBuffer, DWORD nSize, LPCWSTR lpFileName ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetPrivateProfileSectionNamesW( LPWSTR lpszReturnBuffer, DWORD nSize, LPCWSTR lpFileName ) { static FN_GetPrivateProfileSectionNamesW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetPrivateProfileSectionNamesW", &g_Kernel32); return pfn( lpszReturnBuffer, nSize, lpFileName ); } typedef BOOL WINAPI FN_GetPrivateProfileStructA( LPCSTR lpszSection, LPCSTR lpszKey, LPVOID lpStruct, UINT uSizeStruct, LPCSTR szFile ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetPrivateProfileStructA( LPCSTR lpszSection, LPCSTR lpszKey, LPVOID lpStruct, UINT uSizeStruct, LPCSTR szFile ) { static FN_GetPrivateProfileStructA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetPrivateProfileStructA", &g_Kernel32); return pfn( lpszSection, lpszKey, lpStruct, uSizeStruct, szFile ); } typedef BOOL WINAPI FN_GetPrivateProfileStructW( LPCWSTR lpszSection, LPCWSTR lpszKey, LPVOID lpStruct, UINT uSizeStruct, LPCWSTR szFile ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetPrivateProfileStructW( LPCWSTR lpszSection, LPCWSTR lpszKey, LPVOID lpStruct, UINT uSizeStruct, LPCWSTR szFile ) { static FN_GetPrivateProfileStructW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetPrivateProfileStructW", &g_Kernel32); return pfn( lpszSection, lpszKey, lpStruct, uSizeStruct, szFile ); } typedef BOOL WINAPI FN_WritePrivateProfileStructA( LPCSTR lpszSection, LPCSTR lpszKey, LPVOID lpStruct, UINT uSizeStruct, LPCSTR szFile ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_WritePrivateProfileStructA( LPCSTR lpszSection, LPCSTR lpszKey, LPVOID lpStruct, UINT uSizeStruct, LPCSTR szFile ) { static FN_WritePrivateProfileStructA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WritePrivateProfileStructA", &g_Kernel32); return pfn( lpszSection, lpszKey, lpStruct, uSizeStruct, szFile ); } typedef BOOL WINAPI FN_WritePrivateProfileStructW( LPCWSTR lpszSection, LPCWSTR lpszKey, LPVOID lpStruct, UINT uSizeStruct, LPCWSTR szFile ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_WritePrivateProfileStructW( LPCWSTR lpszSection, LPCWSTR lpszKey, LPVOID lpStruct, UINT uSizeStruct, LPCWSTR szFile ) { static FN_WritePrivateProfileStructW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WritePrivateProfileStructW", &g_Kernel32); return pfn( lpszSection, lpszKey, lpStruct, uSizeStruct, szFile ); } typedef UINT WINAPI FN_GetDriveTypeA( LPCSTR lpRootPathName ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_GetDriveTypeA( LPCSTR lpRootPathName ) { static FN_GetDriveTypeA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetDriveTypeA", &g_Kernel32); return pfn( lpRootPathName ); } typedef UINT WINAPI FN_GetDriveTypeW( LPCWSTR lpRootPathName ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_GetDriveTypeW( LPCWSTR lpRootPathName ) { static FN_GetDriveTypeW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetDriveTypeW", &g_Kernel32); return pfn( lpRootPathName ); } typedef UINT WINAPI FN_GetSystemDirectoryA( LPSTR lpBuffer, UINT uSize ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_GetSystemDirectoryA( LPSTR lpBuffer, UINT uSize ) { static FN_GetSystemDirectoryA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSystemDirectoryA", &g_Kernel32); return pfn( lpBuffer, uSize ); } typedef UINT WINAPI FN_GetSystemDirectoryW( LPWSTR lpBuffer, UINT uSize ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_GetSystemDirectoryW( LPWSTR lpBuffer, UINT uSize ) { static FN_GetSystemDirectoryW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSystemDirectoryW", &g_Kernel32); return pfn( lpBuffer, uSize ); } typedef DWORD WINAPI FN_GetTempPathA( DWORD nBufferLength, LPSTR lpBuffer ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetTempPathA( DWORD nBufferLength, LPSTR lpBuffer ) { static FN_GetTempPathA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetTempPathA", &g_Kernel32); return pfn( nBufferLength, lpBuffer ); } typedef DWORD WINAPI FN_GetTempPathW( DWORD nBufferLength, LPWSTR lpBuffer ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetTempPathW( DWORD nBufferLength, LPWSTR lpBuffer ) { static FN_GetTempPathW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetTempPathW", &g_Kernel32); return pfn( nBufferLength, lpBuffer ); } typedef UINT WINAPI FN_GetTempFileNameA( LPCSTR lpPathName, LPCSTR lpPrefixString, UINT uUnique, LPSTR lpTempFileName ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_GetTempFileNameA( LPCSTR lpPathName, LPCSTR lpPrefixString, UINT uUnique, LPSTR lpTempFileName ) { static FN_GetTempFileNameA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetTempFileNameA", &g_Kernel32); return pfn( lpPathName, lpPrefixString, uUnique, lpTempFileName ); } typedef UINT WINAPI FN_GetTempFileNameW( LPCWSTR lpPathName, LPCWSTR lpPrefixString, UINT uUnique, LPWSTR lpTempFileName ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_GetTempFileNameW( LPCWSTR lpPathName, LPCWSTR lpPrefixString, UINT uUnique, LPWSTR lpTempFileName ) { static FN_GetTempFileNameW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetTempFileNameW", &g_Kernel32); return pfn( lpPathName, lpPrefixString, uUnique, lpTempFileName ); } typedef UINT WINAPI FN_GetWindowsDirectoryA( LPSTR lpBuffer, UINT uSize ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_GetWindowsDirectoryA( LPSTR lpBuffer, UINT uSize ) { static FN_GetWindowsDirectoryA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetWindowsDirectoryA", &g_Kernel32); return pfn( lpBuffer, uSize ); } typedef UINT WINAPI FN_GetWindowsDirectoryW( LPWSTR lpBuffer, UINT uSize ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_GetWindowsDirectoryW( LPWSTR lpBuffer, UINT uSize ) { static FN_GetWindowsDirectoryW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetWindowsDirectoryW", &g_Kernel32); return pfn( lpBuffer, uSize ); } typedef UINT WINAPI FN_GetSystemWindowsDirectoryA( LPSTR lpBuffer, UINT uSize ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_GetSystemWindowsDirectoryA( LPSTR lpBuffer, UINT uSize ) { static FN_GetSystemWindowsDirectoryA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSystemWindowsDirectoryA", &g_Kernel32); return pfn( lpBuffer, uSize ); } typedef UINT WINAPI FN_GetSystemWindowsDirectoryW( LPWSTR lpBuffer, UINT uSize ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_GetSystemWindowsDirectoryW( LPWSTR lpBuffer, UINT uSize ) { static FN_GetSystemWindowsDirectoryW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSystemWindowsDirectoryW", &g_Kernel32); return pfn( lpBuffer, uSize ); } typedef UINT WINAPI FN_GetSystemWow64DirectoryA( LPSTR lpBuffer, UINT uSize ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_GetSystemWow64DirectoryA( LPSTR lpBuffer, UINT uSize ) { static FN_GetSystemWow64DirectoryA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSystemWow64DirectoryA", &g_Kernel32); return pfn( lpBuffer, uSize ); } typedef UINT WINAPI FN_GetSystemWow64DirectoryW( LPWSTR lpBuffer, UINT uSize ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_GetSystemWow64DirectoryW( LPWSTR lpBuffer, UINT uSize ) { static FN_GetSystemWow64DirectoryW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSystemWow64DirectoryW", &g_Kernel32); return pfn( lpBuffer, uSize ); } typedef BOOLEAN WINAPI FN_Wow64EnableWow64FsRedirection( BOOLEAN Wow64FsEnableRedirection ); __declspec(dllexport) BOOLEAN WINAPI kPrf2Wrap_Wow64EnableWow64FsRedirection( BOOLEAN Wow64FsEnableRedirection ) { static FN_Wow64EnableWow64FsRedirection *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "Wow64EnableWow64FsRedirection", &g_Kernel32); return pfn( Wow64FsEnableRedirection ); } typedef BOOL WINAPI FN_Wow64DisableWow64FsRedirection( PVOID * OldValue ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_Wow64DisableWow64FsRedirection( PVOID * OldValue ) { static FN_Wow64DisableWow64FsRedirection *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "Wow64DisableWow64FsRedirection", &g_Kernel32); return pfn( OldValue ); } typedef BOOL WINAPI FN_Wow64RevertWow64FsRedirection( PVOID OlValue ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_Wow64RevertWow64FsRedirection( PVOID OlValue ) { static FN_Wow64RevertWow64FsRedirection *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "Wow64RevertWow64FsRedirection", &g_Kernel32); return pfn( OlValue ); } typedef BOOL WINAPI FN_SetCurrentDirectoryA( LPCSTR lpPathName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetCurrentDirectoryA( LPCSTR lpPathName ) { static FN_SetCurrentDirectoryA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetCurrentDirectoryA", &g_Kernel32); return pfn( lpPathName ); } typedef BOOL WINAPI FN_SetCurrentDirectoryW( LPCWSTR lpPathName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetCurrentDirectoryW( LPCWSTR lpPathName ) { static FN_SetCurrentDirectoryW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetCurrentDirectoryW", &g_Kernel32); return pfn( lpPathName ); } typedef DWORD WINAPI FN_GetCurrentDirectoryA( DWORD nBufferLength, LPSTR lpBuffer ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetCurrentDirectoryA( DWORD nBufferLength, LPSTR lpBuffer ) { static FN_GetCurrentDirectoryA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetCurrentDirectoryA", &g_Kernel32); return pfn( nBufferLength, lpBuffer ); } typedef DWORD WINAPI FN_GetCurrentDirectoryW( DWORD nBufferLength, LPWSTR lpBuffer ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetCurrentDirectoryW( DWORD nBufferLength, LPWSTR lpBuffer ) { static FN_GetCurrentDirectoryW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetCurrentDirectoryW", &g_Kernel32); return pfn( nBufferLength, lpBuffer ); } typedef BOOL WINAPI FN_SetDllDirectoryA( LPCSTR lpPathName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetDllDirectoryA( LPCSTR lpPathName ) { static FN_SetDllDirectoryA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetDllDirectoryA", &g_Kernel32); return pfn( lpPathName ); } typedef BOOL WINAPI FN_SetDllDirectoryW( LPCWSTR lpPathName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetDllDirectoryW( LPCWSTR lpPathName ) { static FN_SetDllDirectoryW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetDllDirectoryW", &g_Kernel32); return pfn( lpPathName ); } typedef DWORD WINAPI FN_GetDllDirectoryA( DWORD nBufferLength, LPSTR lpBuffer ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetDllDirectoryA( DWORD nBufferLength, LPSTR lpBuffer ) { static FN_GetDllDirectoryA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetDllDirectoryA", &g_Kernel32); return pfn( nBufferLength, lpBuffer ); } typedef DWORD WINAPI FN_GetDllDirectoryW( DWORD nBufferLength, LPWSTR lpBuffer ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetDllDirectoryW( DWORD nBufferLength, LPWSTR lpBuffer ) { static FN_GetDllDirectoryW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetDllDirectoryW", &g_Kernel32); return pfn( nBufferLength, lpBuffer ); } typedef BOOL WINAPI FN_GetDiskFreeSpaceA( LPCSTR lpRootPathName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetDiskFreeSpaceA( LPCSTR lpRootPathName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters ) { static FN_GetDiskFreeSpaceA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetDiskFreeSpaceA", &g_Kernel32); return pfn( lpRootPathName, lpSectorsPerCluster, lpBytesPerSector, lpNumberOfFreeClusters, lpTotalNumberOfClusters ); } typedef BOOL WINAPI FN_GetDiskFreeSpaceW( LPCWSTR lpRootPathName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetDiskFreeSpaceW( LPCWSTR lpRootPathName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters ) { static FN_GetDiskFreeSpaceW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetDiskFreeSpaceW", &g_Kernel32); return pfn( lpRootPathName, lpSectorsPerCluster, lpBytesPerSector, lpNumberOfFreeClusters, lpTotalNumberOfClusters ); } typedef BOOL WINAPI FN_GetDiskFreeSpaceExA( LPCSTR lpDirectoryName, PULARGE_INTEGER lpFreeBytesAvailableToCaller, PULARGE_INTEGER lpTotalNumberOfBytes, PULARGE_INTEGER lpTotalNumberOfFreeBytes ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetDiskFreeSpaceExA( LPCSTR lpDirectoryName, PULARGE_INTEGER lpFreeBytesAvailableToCaller, PULARGE_INTEGER lpTotalNumberOfBytes, PULARGE_INTEGER lpTotalNumberOfFreeBytes ) { static FN_GetDiskFreeSpaceExA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetDiskFreeSpaceExA", &g_Kernel32); return pfn( lpDirectoryName, lpFreeBytesAvailableToCaller, lpTotalNumberOfBytes, lpTotalNumberOfFreeBytes ); } typedef BOOL WINAPI FN_GetDiskFreeSpaceExW( LPCWSTR lpDirectoryName, PULARGE_INTEGER lpFreeBytesAvailableToCaller, PULARGE_INTEGER lpTotalNumberOfBytes, PULARGE_INTEGER lpTotalNumberOfFreeBytes ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetDiskFreeSpaceExW( LPCWSTR lpDirectoryName, PULARGE_INTEGER lpFreeBytesAvailableToCaller, PULARGE_INTEGER lpTotalNumberOfBytes, PULARGE_INTEGER lpTotalNumberOfFreeBytes ) { static FN_GetDiskFreeSpaceExW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetDiskFreeSpaceExW", &g_Kernel32); return pfn( lpDirectoryName, lpFreeBytesAvailableToCaller, lpTotalNumberOfBytes, lpTotalNumberOfFreeBytes ); } typedef BOOL WINAPI FN_CreateDirectoryA( LPCSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateDirectoryA( LPCSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes ) { static FN_CreateDirectoryA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateDirectoryA", &g_Kernel32); return pfn( lpPathName, lpSecurityAttributes ); } typedef BOOL WINAPI FN_CreateDirectoryW( LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateDirectoryW( LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes ) { static FN_CreateDirectoryW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateDirectoryW", &g_Kernel32); return pfn( lpPathName, lpSecurityAttributes ); } typedef BOOL WINAPI FN_CreateDirectoryExA( LPCSTR lpTemplateDirectory, LPCSTR lpNewDirectory, LPSECURITY_ATTRIBUTES lpSecurityAttributes ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateDirectoryExA( LPCSTR lpTemplateDirectory, LPCSTR lpNewDirectory, LPSECURITY_ATTRIBUTES lpSecurityAttributes ) { static FN_CreateDirectoryExA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateDirectoryExA", &g_Kernel32); return pfn( lpTemplateDirectory, lpNewDirectory, lpSecurityAttributes ); } typedef BOOL WINAPI FN_CreateDirectoryExW( LPCWSTR lpTemplateDirectory, LPCWSTR lpNewDirectory, LPSECURITY_ATTRIBUTES lpSecurityAttributes ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateDirectoryExW( LPCWSTR lpTemplateDirectory, LPCWSTR lpNewDirectory, LPSECURITY_ATTRIBUTES lpSecurityAttributes ) { static FN_CreateDirectoryExW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateDirectoryExW", &g_Kernel32); return pfn( lpTemplateDirectory, lpNewDirectory, lpSecurityAttributes ); } typedef BOOL WINAPI FN_RemoveDirectoryA( LPCSTR lpPathName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_RemoveDirectoryA( LPCSTR lpPathName ) { static FN_RemoveDirectoryA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RemoveDirectoryA", &g_Kernel32); return pfn( lpPathName ); } typedef BOOL WINAPI FN_RemoveDirectoryW( LPCWSTR lpPathName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_RemoveDirectoryW( LPCWSTR lpPathName ) { static FN_RemoveDirectoryW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RemoveDirectoryW", &g_Kernel32); return pfn( lpPathName ); } typedef DWORD WINAPI FN_GetFullPathNameA( LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer, LPSTR * lpFilePart ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetFullPathNameA( LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer, LPSTR * lpFilePart ) { static FN_GetFullPathNameA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetFullPathNameA", &g_Kernel32); return pfn( lpFileName, nBufferLength, lpBuffer, lpFilePart ); } typedef DWORD WINAPI FN_GetFullPathNameW( LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lpBuffer, LPWSTR * lpFilePart ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetFullPathNameW( LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lpBuffer, LPWSTR * lpFilePart ) { static FN_GetFullPathNameW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetFullPathNameW", &g_Kernel32); return pfn( lpFileName, nBufferLength, lpBuffer, lpFilePart ); } typedef BOOL WINAPI FN_DefineDosDeviceA( DWORD dwFlags, LPCSTR lpDeviceName, LPCSTR lpTargetPath ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_DefineDosDeviceA( DWORD dwFlags, LPCSTR lpDeviceName, LPCSTR lpTargetPath ) { static FN_DefineDosDeviceA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DefineDosDeviceA", &g_Kernel32); return pfn( dwFlags, lpDeviceName, lpTargetPath ); } typedef BOOL WINAPI FN_DefineDosDeviceW( DWORD dwFlags, LPCWSTR lpDeviceName, LPCWSTR lpTargetPath ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_DefineDosDeviceW( DWORD dwFlags, LPCWSTR lpDeviceName, LPCWSTR lpTargetPath ) { static FN_DefineDosDeviceW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DefineDosDeviceW", &g_Kernel32); return pfn( dwFlags, lpDeviceName, lpTargetPath ); } typedef DWORD WINAPI FN_QueryDosDeviceA( LPCSTR lpDeviceName, LPSTR lpTargetPath, DWORD ucchMax ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_QueryDosDeviceA( LPCSTR lpDeviceName, LPSTR lpTargetPath, DWORD ucchMax ) { static FN_QueryDosDeviceA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "QueryDosDeviceA", &g_Kernel32); return pfn( lpDeviceName, lpTargetPath, ucchMax ); } typedef DWORD WINAPI FN_QueryDosDeviceW( LPCWSTR lpDeviceName, LPWSTR lpTargetPath, DWORD ucchMax ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_QueryDosDeviceW( LPCWSTR lpDeviceName, LPWSTR lpTargetPath, DWORD ucchMax ) { static FN_QueryDosDeviceW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "QueryDosDeviceW", &g_Kernel32); return pfn( lpDeviceName, lpTargetPath, ucchMax ); } typedef HANDLE WINAPI FN_CreateFileA( LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateFileA( LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile ) { static FN_CreateFileA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateFileA", &g_Kernel32); return pfn( lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile ); } typedef HANDLE WINAPI FN_CreateFileW( LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateFileW( LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile ) { static FN_CreateFileW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateFileW", &g_Kernel32); return pfn( lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile ); } typedef HANDLE WINAPI FN_ReOpenFile( HANDLE hOriginalFile, DWORD dwDesiredAccess, DWORD dwShareMode, DWORD dwFlagsAndAttributes ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_ReOpenFile( HANDLE hOriginalFile, DWORD dwDesiredAccess, DWORD dwShareMode, DWORD dwFlagsAndAttributes ) { static FN_ReOpenFile *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ReOpenFile", &g_Kernel32); return pfn( hOriginalFile, dwDesiredAccess, dwShareMode, dwFlagsAndAttributes ); } typedef BOOL WINAPI FN_SetFileAttributesA( LPCSTR lpFileName, DWORD dwFileAttributes ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetFileAttributesA( LPCSTR lpFileName, DWORD dwFileAttributes ) { static FN_SetFileAttributesA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetFileAttributesA", &g_Kernel32); return pfn( lpFileName, dwFileAttributes ); } typedef BOOL WINAPI FN_SetFileAttributesW( LPCWSTR lpFileName, DWORD dwFileAttributes ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetFileAttributesW( LPCWSTR lpFileName, DWORD dwFileAttributes ) { static FN_SetFileAttributesW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetFileAttributesW", &g_Kernel32); return pfn( lpFileName, dwFileAttributes ); } typedef DWORD WINAPI FN_GetFileAttributesA( LPCSTR lpFileName ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetFileAttributesA( LPCSTR lpFileName ) { static FN_GetFileAttributesA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetFileAttributesA", &g_Kernel32); return pfn( lpFileName ); } typedef DWORD WINAPI FN_GetFileAttributesW( LPCWSTR lpFileName ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetFileAttributesW( LPCWSTR lpFileName ) { static FN_GetFileAttributesW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetFileAttributesW", &g_Kernel32); return pfn( lpFileName ); } typedef BOOL WINAPI FN_GetFileAttributesExA( LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, LPVOID lpFileInformation ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetFileAttributesExA( LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, LPVOID lpFileInformation ) { static FN_GetFileAttributesExA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetFileAttributesExA", &g_Kernel32); return pfn( lpFileName, fInfoLevelId, lpFileInformation ); } typedef BOOL WINAPI FN_GetFileAttributesExW( LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, LPVOID lpFileInformation ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetFileAttributesExW( LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, LPVOID lpFileInformation ) { static FN_GetFileAttributesExW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetFileAttributesExW", &g_Kernel32); return pfn( lpFileName, fInfoLevelId, lpFileInformation ); } typedef DWORD WINAPI FN_GetCompressedFileSizeA( LPCSTR lpFileName, LPDWORD lpFileSizeHigh ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetCompressedFileSizeA( LPCSTR lpFileName, LPDWORD lpFileSizeHigh ) { static FN_GetCompressedFileSizeA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetCompressedFileSizeA", &g_Kernel32); return pfn( lpFileName, lpFileSizeHigh ); } typedef DWORD WINAPI FN_GetCompressedFileSizeW( LPCWSTR lpFileName, LPDWORD lpFileSizeHigh ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetCompressedFileSizeW( LPCWSTR lpFileName, LPDWORD lpFileSizeHigh ) { static FN_GetCompressedFileSizeW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetCompressedFileSizeW", &g_Kernel32); return pfn( lpFileName, lpFileSizeHigh ); } typedef BOOL WINAPI FN_DeleteFileA( LPCSTR lpFileName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_DeleteFileA( LPCSTR lpFileName ) { static FN_DeleteFileA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DeleteFileA", &g_Kernel32); return pfn( lpFileName ); } typedef BOOL WINAPI FN_DeleteFileW( LPCWSTR lpFileName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_DeleteFileW( LPCWSTR lpFileName ) { static FN_DeleteFileW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DeleteFileW", &g_Kernel32); return pfn( lpFileName ); } typedef BOOL WINAPI FN_CheckNameLegalDOS8Dot3A( LPCSTR lpName, LPSTR lpOemName, DWORD OemNameSize, PBOOL pbNameContainsSpaces , PBOOL pbNameLegal ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CheckNameLegalDOS8Dot3A( LPCSTR lpName, LPSTR lpOemName, DWORD OemNameSize, PBOOL pbNameContainsSpaces , PBOOL pbNameLegal ) { static FN_CheckNameLegalDOS8Dot3A *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CheckNameLegalDOS8Dot3A", &g_Kernel32); return pfn( lpName, lpOemName, OemNameSize, pbNameContainsSpaces , pbNameLegal ); } typedef BOOL WINAPI FN_CheckNameLegalDOS8Dot3W( LPCWSTR lpName, LPSTR lpOemName, DWORD OemNameSize, PBOOL pbNameContainsSpaces , PBOOL pbNameLegal ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CheckNameLegalDOS8Dot3W( LPCWSTR lpName, LPSTR lpOemName, DWORD OemNameSize, PBOOL pbNameContainsSpaces , PBOOL pbNameLegal ) { static FN_CheckNameLegalDOS8Dot3W *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CheckNameLegalDOS8Dot3W", &g_Kernel32); return pfn( lpName, lpOemName, OemNameSize, pbNameContainsSpaces , pbNameLegal ); } typedef HANDLE WINAPI FN_FindFirstFileExA( LPCSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, LPVOID lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, LPVOID lpSearchFilter, DWORD dwAdditionalFlags ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_FindFirstFileExA( LPCSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, LPVOID lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, LPVOID lpSearchFilter, DWORD dwAdditionalFlags ) { static FN_FindFirstFileExA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindFirstFileExA", &g_Kernel32); return pfn( lpFileName, fInfoLevelId, lpFindFileData, fSearchOp, lpSearchFilter, dwAdditionalFlags ); } typedef HANDLE WINAPI FN_FindFirstFileExW( LPCWSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, LPVOID lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, LPVOID lpSearchFilter, DWORD dwAdditionalFlags ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_FindFirstFileExW( LPCWSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, LPVOID lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, LPVOID lpSearchFilter, DWORD dwAdditionalFlags ) { static FN_FindFirstFileExW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindFirstFileExW", &g_Kernel32); return pfn( lpFileName, fInfoLevelId, lpFindFileData, fSearchOp, lpSearchFilter, dwAdditionalFlags ); } typedef HANDLE WINAPI FN_FindFirstFileA( LPCSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_FindFirstFileA( LPCSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData ) { static FN_FindFirstFileA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindFirstFileA", &g_Kernel32); return pfn( lpFileName, lpFindFileData ); } typedef HANDLE WINAPI FN_FindFirstFileW( LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFindFileData ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_FindFirstFileW( LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFindFileData ) { static FN_FindFirstFileW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindFirstFileW", &g_Kernel32); return pfn( lpFileName, lpFindFileData ); } typedef BOOL WINAPI FN_FindNextFileA( HANDLE hFindFile, LPWIN32_FIND_DATAA lpFindFileData ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindNextFileA( HANDLE hFindFile, LPWIN32_FIND_DATAA lpFindFileData ) { static FN_FindNextFileA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindNextFileA", &g_Kernel32); return pfn( hFindFile, lpFindFileData ); } typedef BOOL WINAPI FN_FindNextFileW( HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindNextFileW( HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData ) { static FN_FindNextFileW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindNextFileW", &g_Kernel32); return pfn( hFindFile, lpFindFileData ); } typedef DWORD WINAPI FN_SearchPathA( LPCSTR lpPath, LPCSTR lpFileName, LPCSTR lpExtension, DWORD nBufferLength, LPSTR lpBuffer, LPSTR * lpFilePart ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_SearchPathA( LPCSTR lpPath, LPCSTR lpFileName, LPCSTR lpExtension, DWORD nBufferLength, LPSTR lpBuffer, LPSTR * lpFilePart ) { static FN_SearchPathA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SearchPathA", &g_Kernel32); return pfn( lpPath, lpFileName, lpExtension, nBufferLength, lpBuffer, lpFilePart ); } typedef DWORD WINAPI FN_SearchPathW( LPCWSTR lpPath, LPCWSTR lpFileName, LPCWSTR lpExtension, DWORD nBufferLength, LPWSTR lpBuffer, LPWSTR * lpFilePart ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_SearchPathW( LPCWSTR lpPath, LPCWSTR lpFileName, LPCWSTR lpExtension, DWORD nBufferLength, LPWSTR lpBuffer, LPWSTR * lpFilePart ) { static FN_SearchPathW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SearchPathW", &g_Kernel32); return pfn( lpPath, lpFileName, lpExtension, nBufferLength, lpBuffer, lpFilePart ); } typedef BOOL WINAPI FN_CopyFileA( LPCSTR lpExistingFileName, LPCSTR lpNewFileName, BOOL bFailIfExists ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CopyFileA( LPCSTR lpExistingFileName, LPCSTR lpNewFileName, BOOL bFailIfExists ) { static FN_CopyFileA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CopyFileA", &g_Kernel32); return pfn( lpExistingFileName, lpNewFileName, bFailIfExists ); } typedef BOOL WINAPI FN_CopyFileW( LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, BOOL bFailIfExists ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CopyFileW( LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, BOOL bFailIfExists ) { static FN_CopyFileW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CopyFileW", &g_Kernel32); return pfn( lpExistingFileName, lpNewFileName, bFailIfExists ); } typedef BOOL WINAPI FN_CopyFileExA( LPCSTR lpExistingFileName, LPCSTR lpNewFileName, LPPROGRESS_ROUTINE lpProgressRoutine, LPVOID lpData, LPBOOL pbCancel, DWORD dwCopyFlags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CopyFileExA( LPCSTR lpExistingFileName, LPCSTR lpNewFileName, LPPROGRESS_ROUTINE lpProgressRoutine, LPVOID lpData, LPBOOL pbCancel, DWORD dwCopyFlags ) { static FN_CopyFileExA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CopyFileExA", &g_Kernel32); return pfn( lpExistingFileName, lpNewFileName, lpProgressRoutine, lpData, pbCancel, dwCopyFlags ); } typedef BOOL WINAPI FN_CopyFileExW( LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, LPPROGRESS_ROUTINE lpProgressRoutine, LPVOID lpData, LPBOOL pbCancel, DWORD dwCopyFlags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CopyFileExW( LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, LPPROGRESS_ROUTINE lpProgressRoutine, LPVOID lpData, LPBOOL pbCancel, DWORD dwCopyFlags ) { static FN_CopyFileExW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CopyFileExW", &g_Kernel32); return pfn( lpExistingFileName, lpNewFileName, lpProgressRoutine, lpData, pbCancel, dwCopyFlags ); } typedef BOOL WINAPI FN_MoveFileA( LPCSTR lpExistingFileName, LPCSTR lpNewFileName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_MoveFileA( LPCSTR lpExistingFileName, LPCSTR lpNewFileName ) { static FN_MoveFileA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "MoveFileA", &g_Kernel32); return pfn( lpExistingFileName, lpNewFileName ); } typedef BOOL WINAPI FN_MoveFileW( LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_MoveFileW( LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName ) { static FN_MoveFileW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "MoveFileW", &g_Kernel32); return pfn( lpExistingFileName, lpNewFileName ); } typedef BOOL WINAPI FN_MoveFileExA( LPCSTR lpExistingFileName, LPCSTR lpNewFileName, DWORD dwFlags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_MoveFileExA( LPCSTR lpExistingFileName, LPCSTR lpNewFileName, DWORD dwFlags ) { static FN_MoveFileExA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "MoveFileExA", &g_Kernel32); return pfn( lpExistingFileName, lpNewFileName, dwFlags ); } typedef BOOL WINAPI FN_MoveFileExW( LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, DWORD dwFlags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_MoveFileExW( LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, DWORD dwFlags ) { static FN_MoveFileExW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "MoveFileExW", &g_Kernel32); return pfn( lpExistingFileName, lpNewFileName, dwFlags ); } typedef BOOL WINAPI FN_MoveFileWithProgressA( LPCSTR lpExistingFileName, LPCSTR lpNewFileName, LPPROGRESS_ROUTINE lpProgressRoutine, LPVOID lpData, DWORD dwFlags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_MoveFileWithProgressA( LPCSTR lpExistingFileName, LPCSTR lpNewFileName, LPPROGRESS_ROUTINE lpProgressRoutine, LPVOID lpData, DWORD dwFlags ) { static FN_MoveFileWithProgressA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "MoveFileWithProgressA", &g_Kernel32); return pfn( lpExistingFileName, lpNewFileName, lpProgressRoutine, lpData, dwFlags ); } typedef BOOL WINAPI FN_MoveFileWithProgressW( LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, LPPROGRESS_ROUTINE lpProgressRoutine, LPVOID lpData, DWORD dwFlags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_MoveFileWithProgressW( LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, LPPROGRESS_ROUTINE lpProgressRoutine, LPVOID lpData, DWORD dwFlags ) { static FN_MoveFileWithProgressW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "MoveFileWithProgressW", &g_Kernel32); return pfn( lpExistingFileName, lpNewFileName, lpProgressRoutine, lpData, dwFlags ); } typedef BOOL WINAPI FN_ReplaceFileA( LPCSTR lpReplacedFileName, LPCSTR lpReplacementFileName, LPCSTR lpBackupFileName, DWORD dwReplaceFlags, LPVOID lpExclude, LPVOID lpReserved ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReplaceFileA( LPCSTR lpReplacedFileName, LPCSTR lpReplacementFileName, LPCSTR lpBackupFileName, DWORD dwReplaceFlags, LPVOID lpExclude, LPVOID lpReserved ) { static FN_ReplaceFileA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ReplaceFileA", &g_Kernel32); return pfn( lpReplacedFileName, lpReplacementFileName, lpBackupFileName, dwReplaceFlags, lpExclude, lpReserved ); } typedef BOOL WINAPI FN_ReplaceFileW( LPCWSTR lpReplacedFileName, LPCWSTR lpReplacementFileName, LPCWSTR lpBackupFileName, DWORD dwReplaceFlags, LPVOID lpExclude, LPVOID lpReserved ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReplaceFileW( LPCWSTR lpReplacedFileName, LPCWSTR lpReplacementFileName, LPCWSTR lpBackupFileName, DWORD dwReplaceFlags, LPVOID lpExclude, LPVOID lpReserved ) { static FN_ReplaceFileW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ReplaceFileW", &g_Kernel32); return pfn( lpReplacedFileName, lpReplacementFileName, lpBackupFileName, dwReplaceFlags, lpExclude, lpReserved ); } typedef BOOL WINAPI FN_CreateHardLinkA( LPCSTR lpFileName, LPCSTR lpExistingFileName, LPSECURITY_ATTRIBUTES lpSecurityAttributes ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateHardLinkA( LPCSTR lpFileName, LPCSTR lpExistingFileName, LPSECURITY_ATTRIBUTES lpSecurityAttributes ) { static FN_CreateHardLinkA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateHardLinkA", &g_Kernel32); return pfn( lpFileName, lpExistingFileName, lpSecurityAttributes ); } typedef BOOL WINAPI FN_CreateHardLinkW( LPCWSTR lpFileName, LPCWSTR lpExistingFileName, LPSECURITY_ATTRIBUTES lpSecurityAttributes ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateHardLinkW( LPCWSTR lpFileName, LPCWSTR lpExistingFileName, LPSECURITY_ATTRIBUTES lpSecurityAttributes ) { static FN_CreateHardLinkW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateHardLinkW", &g_Kernel32); return pfn( lpFileName, lpExistingFileName, lpSecurityAttributes ); } typedef HANDLE WINAPI FN_FindFirstStreamW( LPCWSTR lpFileName, STREAM_INFO_LEVELS InfoLevel, LPVOID lpFindStreamData, DWORD dwFlags ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_FindFirstStreamW( LPCWSTR lpFileName, STREAM_INFO_LEVELS InfoLevel, LPVOID lpFindStreamData, DWORD dwFlags ) { static FN_FindFirstStreamW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindFirstStreamW", &g_Kernel32); return pfn( lpFileName, InfoLevel, lpFindStreamData, dwFlags ); } typedef BOOL APIENTRY FN_FindNextStreamW( HANDLE hFindStream, LPVOID lpFindStreamData ); __declspec(dllexport) BOOL APIENTRY kPrf2Wrap_FindNextStreamW( HANDLE hFindStream, LPVOID lpFindStreamData ) { static FN_FindNextStreamW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindNextStreamW", &g_Kernel32); return pfn( hFindStream, lpFindStreamData ); } typedef HANDLE WINAPI FN_CreateNamedPipeA( LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances, DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateNamedPipeA( LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances, DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes ) { static FN_CreateNamedPipeA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateNamedPipeA", &g_Kernel32); return pfn( lpName, dwOpenMode, dwPipeMode, nMaxInstances, nOutBufferSize, nInBufferSize, nDefaultTimeOut, lpSecurityAttributes ); } typedef HANDLE WINAPI FN_CreateNamedPipeW( LPCWSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances, DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateNamedPipeW( LPCWSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances, DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes ) { static FN_CreateNamedPipeW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateNamedPipeW", &g_Kernel32); return pfn( lpName, dwOpenMode, dwPipeMode, nMaxInstances, nOutBufferSize, nInBufferSize, nDefaultTimeOut, lpSecurityAttributes ); } typedef BOOL WINAPI FN_GetNamedPipeHandleStateA( HANDLE hNamedPipe, LPDWORD lpState, LPDWORD lpCurInstances, LPDWORD lpMaxCollectionCount, LPDWORD lpCollectDataTimeout, LPSTR lpUserName, DWORD nMaxUserNameSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetNamedPipeHandleStateA( HANDLE hNamedPipe, LPDWORD lpState, LPDWORD lpCurInstances, LPDWORD lpMaxCollectionCount, LPDWORD lpCollectDataTimeout, LPSTR lpUserName, DWORD nMaxUserNameSize ) { static FN_GetNamedPipeHandleStateA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetNamedPipeHandleStateA", &g_Kernel32); return pfn( hNamedPipe, lpState, lpCurInstances, lpMaxCollectionCount, lpCollectDataTimeout, lpUserName, nMaxUserNameSize ); } typedef BOOL WINAPI FN_GetNamedPipeHandleStateW( HANDLE hNamedPipe, LPDWORD lpState, LPDWORD lpCurInstances, LPDWORD lpMaxCollectionCount, LPDWORD lpCollectDataTimeout, LPWSTR lpUserName, DWORD nMaxUserNameSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetNamedPipeHandleStateW( HANDLE hNamedPipe, LPDWORD lpState, LPDWORD lpCurInstances, LPDWORD lpMaxCollectionCount, LPDWORD lpCollectDataTimeout, LPWSTR lpUserName, DWORD nMaxUserNameSize ) { static FN_GetNamedPipeHandleStateW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetNamedPipeHandleStateW", &g_Kernel32); return pfn( hNamedPipe, lpState, lpCurInstances, lpMaxCollectionCount, lpCollectDataTimeout, lpUserName, nMaxUserNameSize ); } typedef BOOL WINAPI FN_CallNamedPipeA( LPCSTR lpNamedPipeName, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesRead, DWORD nTimeOut ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CallNamedPipeA( LPCSTR lpNamedPipeName, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesRead, DWORD nTimeOut ) { static FN_CallNamedPipeA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CallNamedPipeA", &g_Kernel32); return pfn( lpNamedPipeName, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesRead, nTimeOut ); } typedef BOOL WINAPI FN_CallNamedPipeW( LPCWSTR lpNamedPipeName, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesRead, DWORD nTimeOut ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CallNamedPipeW( LPCWSTR lpNamedPipeName, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesRead, DWORD nTimeOut ) { static FN_CallNamedPipeW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CallNamedPipeW", &g_Kernel32); return pfn( lpNamedPipeName, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesRead, nTimeOut ); } typedef BOOL WINAPI FN_WaitNamedPipeA( LPCSTR lpNamedPipeName, DWORD nTimeOut ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_WaitNamedPipeA( LPCSTR lpNamedPipeName, DWORD nTimeOut ) { static FN_WaitNamedPipeA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WaitNamedPipeA", &g_Kernel32); return pfn( lpNamedPipeName, nTimeOut ); } typedef BOOL WINAPI FN_WaitNamedPipeW( LPCWSTR lpNamedPipeName, DWORD nTimeOut ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_WaitNamedPipeW( LPCWSTR lpNamedPipeName, DWORD nTimeOut ) { static FN_WaitNamedPipeW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WaitNamedPipeW", &g_Kernel32); return pfn( lpNamedPipeName, nTimeOut ); } typedef BOOL WINAPI FN_SetVolumeLabelA( LPCSTR lpRootPathName, LPCSTR lpVolumeName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetVolumeLabelA( LPCSTR lpRootPathName, LPCSTR lpVolumeName ) { static FN_SetVolumeLabelA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetVolumeLabelA", &g_Kernel32); return pfn( lpRootPathName, lpVolumeName ); } typedef BOOL WINAPI FN_SetVolumeLabelW( LPCWSTR lpRootPathName, LPCWSTR lpVolumeName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetVolumeLabelW( LPCWSTR lpRootPathName, LPCWSTR lpVolumeName ) { static FN_SetVolumeLabelW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetVolumeLabelW", &g_Kernel32); return pfn( lpRootPathName, lpVolumeName ); } typedef VOID WINAPI FN_SetFileApisToOEM( VOID ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_SetFileApisToOEM( VOID ) { static FN_SetFileApisToOEM *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetFileApisToOEM", &g_Kernel32); pfn (); } typedef VOID WINAPI FN_SetFileApisToANSI( VOID ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_SetFileApisToANSI( VOID ) { static FN_SetFileApisToANSI *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetFileApisToANSI", &g_Kernel32); pfn (); } typedef BOOL WINAPI FN_AreFileApisANSI( VOID ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AreFileApisANSI( VOID ) { static FN_AreFileApisANSI *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AreFileApisANSI", &g_Kernel32); return pfn (); } typedef BOOL WINAPI FN_GetVolumeInformationA( LPCSTR lpRootPathName, LPSTR lpVolumeNameBuffer, DWORD nVolumeNameSize, LPDWORD lpVolumeSerialNumber, LPDWORD lpMaximumComponentLength, LPDWORD lpFileSystemFlags, LPSTR lpFileSystemNameBuffer, DWORD nFileSystemNameSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetVolumeInformationA( LPCSTR lpRootPathName, LPSTR lpVolumeNameBuffer, DWORD nVolumeNameSize, LPDWORD lpVolumeSerialNumber, LPDWORD lpMaximumComponentLength, LPDWORD lpFileSystemFlags, LPSTR lpFileSystemNameBuffer, DWORD nFileSystemNameSize ) { static FN_GetVolumeInformationA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetVolumeInformationA", &g_Kernel32); return pfn( lpRootPathName, lpVolumeNameBuffer, nVolumeNameSize, lpVolumeSerialNumber, lpMaximumComponentLength, lpFileSystemFlags, lpFileSystemNameBuffer, nFileSystemNameSize ); } typedef BOOL WINAPI FN_GetVolumeInformationW( LPCWSTR lpRootPathName, LPWSTR lpVolumeNameBuffer, DWORD nVolumeNameSize, LPDWORD lpVolumeSerialNumber, LPDWORD lpMaximumComponentLength, LPDWORD lpFileSystemFlags, LPWSTR lpFileSystemNameBuffer, DWORD nFileSystemNameSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetVolumeInformationW( LPCWSTR lpRootPathName, LPWSTR lpVolumeNameBuffer, DWORD nVolumeNameSize, LPDWORD lpVolumeSerialNumber, LPDWORD lpMaximumComponentLength, LPDWORD lpFileSystemFlags, LPWSTR lpFileSystemNameBuffer, DWORD nFileSystemNameSize ) { static FN_GetVolumeInformationW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetVolumeInformationW", &g_Kernel32); return pfn( lpRootPathName, lpVolumeNameBuffer, nVolumeNameSize, lpVolumeSerialNumber, lpMaximumComponentLength, lpFileSystemFlags, lpFileSystemNameBuffer, nFileSystemNameSize ); } typedef BOOL WINAPI FN_CancelIo( HANDLE hFile ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CancelIo( HANDLE hFile ) { static FN_CancelIo *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CancelIo", &g_Kernel32); return pfn( hFile ); } typedef BOOL WINAPI FN_ClearEventLogA( HANDLE hEventLog, LPCSTR lpBackupFileName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ClearEventLogA( HANDLE hEventLog, LPCSTR lpBackupFileName ) { static FN_ClearEventLogA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ClearEventLogA", &g_Kernel32); return pfn( hEventLog, lpBackupFileName ); } typedef BOOL WINAPI FN_ClearEventLogW( HANDLE hEventLog, LPCWSTR lpBackupFileName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ClearEventLogW( HANDLE hEventLog, LPCWSTR lpBackupFileName ) { static FN_ClearEventLogW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ClearEventLogW", &g_Kernel32); return pfn( hEventLog, lpBackupFileName ); } typedef BOOL WINAPI FN_BackupEventLogA( HANDLE hEventLog, LPCSTR lpBackupFileName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_BackupEventLogA( HANDLE hEventLog, LPCSTR lpBackupFileName ) { static FN_BackupEventLogA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "BackupEventLogA", &g_Kernel32); return pfn( hEventLog, lpBackupFileName ); } typedef BOOL WINAPI FN_BackupEventLogW( HANDLE hEventLog, LPCWSTR lpBackupFileName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_BackupEventLogW( HANDLE hEventLog, LPCWSTR lpBackupFileName ) { static FN_BackupEventLogW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "BackupEventLogW", &g_Kernel32); return pfn( hEventLog, lpBackupFileName ); } typedef BOOL WINAPI FN_CloseEventLog( HANDLE hEventLog ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CloseEventLog( HANDLE hEventLog ) { static FN_CloseEventLog *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CloseEventLog", &g_Kernel32); return pfn( hEventLog ); } typedef BOOL WINAPI FN_DeregisterEventSource( HANDLE hEventLog ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_DeregisterEventSource( HANDLE hEventLog ) { static FN_DeregisterEventSource *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DeregisterEventSource", &g_Kernel32); return pfn( hEventLog ); } typedef BOOL WINAPI FN_NotifyChangeEventLog( HANDLE hEventLog, HANDLE hEvent ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_NotifyChangeEventLog( HANDLE hEventLog, HANDLE hEvent ) { static FN_NotifyChangeEventLog *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "NotifyChangeEventLog", &g_Kernel32); return pfn( hEventLog, hEvent ); } typedef BOOL WINAPI FN_GetNumberOfEventLogRecords( HANDLE hEventLog, PDWORD NumberOfRecords ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetNumberOfEventLogRecords( HANDLE hEventLog, PDWORD NumberOfRecords ) { static FN_GetNumberOfEventLogRecords *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetNumberOfEventLogRecords", &g_Kernel32); return pfn( hEventLog, NumberOfRecords ); } typedef BOOL WINAPI FN_GetOldestEventLogRecord( HANDLE hEventLog, PDWORD OldestRecord ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetOldestEventLogRecord( HANDLE hEventLog, PDWORD OldestRecord ) { static FN_GetOldestEventLogRecord *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetOldestEventLogRecord", &g_Kernel32); return pfn( hEventLog, OldestRecord ); } typedef HANDLE WINAPI FN_OpenEventLogA( LPCSTR lpUNCServerName, LPCSTR lpSourceName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenEventLogA( LPCSTR lpUNCServerName, LPCSTR lpSourceName ) { static FN_OpenEventLogA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "OpenEventLogA", &g_Kernel32); return pfn( lpUNCServerName, lpSourceName ); } typedef HANDLE WINAPI FN_OpenEventLogW( LPCWSTR lpUNCServerName, LPCWSTR lpSourceName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenEventLogW( LPCWSTR lpUNCServerName, LPCWSTR lpSourceName ) { static FN_OpenEventLogW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "OpenEventLogW", &g_Kernel32); return pfn( lpUNCServerName, lpSourceName ); } typedef HANDLE WINAPI FN_RegisterEventSourceA( LPCSTR lpUNCServerName, LPCSTR lpSourceName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_RegisterEventSourceA( LPCSTR lpUNCServerName, LPCSTR lpSourceName ) { static FN_RegisterEventSourceA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RegisterEventSourceA", &g_Kernel32); return pfn( lpUNCServerName, lpSourceName ); } typedef HANDLE WINAPI FN_RegisterEventSourceW( LPCWSTR lpUNCServerName, LPCWSTR lpSourceName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_RegisterEventSourceW( LPCWSTR lpUNCServerName, LPCWSTR lpSourceName ) { static FN_RegisterEventSourceW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RegisterEventSourceW", &g_Kernel32); return pfn( lpUNCServerName, lpSourceName ); } typedef HANDLE WINAPI FN_OpenBackupEventLogA( LPCSTR lpUNCServerName, LPCSTR lpFileName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenBackupEventLogA( LPCSTR lpUNCServerName, LPCSTR lpFileName ) { static FN_OpenBackupEventLogA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "OpenBackupEventLogA", &g_Kernel32); return pfn( lpUNCServerName, lpFileName ); } typedef HANDLE WINAPI FN_OpenBackupEventLogW( LPCWSTR lpUNCServerName, LPCWSTR lpFileName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenBackupEventLogW( LPCWSTR lpUNCServerName, LPCWSTR lpFileName ) { static FN_OpenBackupEventLogW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "OpenBackupEventLogW", &g_Kernel32); return pfn( lpUNCServerName, lpFileName ); } typedef BOOL WINAPI FN_ReadEventLogA( HANDLE hEventLog, DWORD dwReadFlags, DWORD dwRecordOffset, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, DWORD * pnBytesRead, DWORD * pnMinNumberOfBytesNeeded ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadEventLogA( HANDLE hEventLog, DWORD dwReadFlags, DWORD dwRecordOffset, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, DWORD * pnBytesRead, DWORD * pnMinNumberOfBytesNeeded ) { static FN_ReadEventLogA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ReadEventLogA", &g_Kernel32); return pfn( hEventLog, dwReadFlags, dwRecordOffset, lpBuffer, nNumberOfBytesToRead, pnBytesRead, pnMinNumberOfBytesNeeded ); } typedef BOOL WINAPI FN_ReadEventLogW( HANDLE hEventLog, DWORD dwReadFlags, DWORD dwRecordOffset, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, DWORD * pnBytesRead, DWORD * pnMinNumberOfBytesNeeded ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadEventLogW( HANDLE hEventLog, DWORD dwReadFlags, DWORD dwRecordOffset, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, DWORD * pnBytesRead, DWORD * pnMinNumberOfBytesNeeded ) { static FN_ReadEventLogW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ReadEventLogW", &g_Kernel32); return pfn( hEventLog, dwReadFlags, dwRecordOffset, lpBuffer, nNumberOfBytesToRead, pnBytesRead, pnMinNumberOfBytesNeeded ); } typedef BOOL WINAPI FN_ReportEventA( HANDLE hEventLog, WORD wType, WORD wCategory, DWORD dwEventID, PSID lpUserSid, WORD wNumStrings, DWORD dwDataSize, LPCSTR * lpStrings, LPVOID lpRawData ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReportEventA( HANDLE hEventLog, WORD wType, WORD wCategory, DWORD dwEventID, PSID lpUserSid, WORD wNumStrings, DWORD dwDataSize, LPCSTR * lpStrings, LPVOID lpRawData ) { static FN_ReportEventA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ReportEventA", &g_Kernel32); return pfn( hEventLog, wType, wCategory, dwEventID, lpUserSid, wNumStrings, dwDataSize, lpStrings, lpRawData ); } typedef BOOL WINAPI FN_ReportEventW( HANDLE hEventLog, WORD wType, WORD wCategory, DWORD dwEventID, PSID lpUserSid, WORD wNumStrings, DWORD dwDataSize, LPCWSTR * lpStrings, LPVOID lpRawData ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReportEventW( HANDLE hEventLog, WORD wType, WORD wCategory, DWORD dwEventID, PSID lpUserSid, WORD wNumStrings, DWORD dwDataSize, LPCWSTR * lpStrings, LPVOID lpRawData ) { static FN_ReportEventW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ReportEventW", &g_Kernel32); return pfn( hEventLog, wType, wCategory, dwEventID, lpUserSid, wNumStrings, dwDataSize, lpStrings, lpRawData ); } typedef BOOL WINAPI FN_GetEventLogInformation( HANDLE hEventLog, DWORD dwInfoLevel, LPVOID lpBuffer, DWORD cbBufSize, LPDWORD pcbBytesNeeded ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetEventLogInformation( HANDLE hEventLog, DWORD dwInfoLevel, LPVOID lpBuffer, DWORD cbBufSize, LPDWORD pcbBytesNeeded ) { static FN_GetEventLogInformation *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetEventLogInformation", &g_Kernel32); return pfn( hEventLog, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded ); } typedef BOOL WINAPI FN_DuplicateToken( HANDLE ExistingTokenHandle, SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, PHANDLE DuplicateTokenHandle ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_DuplicateToken( HANDLE ExistingTokenHandle, SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, PHANDLE DuplicateTokenHandle ) { static FN_DuplicateToken *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DuplicateToken", &g_Kernel32); return pfn( ExistingTokenHandle, ImpersonationLevel, DuplicateTokenHandle ); } typedef BOOL WINAPI FN_GetKernelObjectSecurity( HANDLE Handle, SECURITY_INFORMATION RequestedInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetKernelObjectSecurity( HANDLE Handle, SECURITY_INFORMATION RequestedInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded ) { static FN_GetKernelObjectSecurity *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetKernelObjectSecurity", &g_Kernel32); return pfn( Handle, RequestedInformation, pSecurityDescriptor, nLength, lpnLengthNeeded ); } typedef BOOL WINAPI FN_ImpersonateNamedPipeClient( HANDLE hNamedPipe ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ImpersonateNamedPipeClient( HANDLE hNamedPipe ) { static FN_ImpersonateNamedPipeClient *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ImpersonateNamedPipeClient", &g_Kernel32); return pfn( hNamedPipe ); } typedef BOOL WINAPI FN_ImpersonateSelf( SECURITY_IMPERSONATION_LEVEL ImpersonationLevel ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ImpersonateSelf( SECURITY_IMPERSONATION_LEVEL ImpersonationLevel ) { static FN_ImpersonateSelf *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ImpersonateSelf", &g_Kernel32); return pfn( ImpersonationLevel ); } typedef BOOL WINAPI FN_RevertToSelf( VOID ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_RevertToSelf( VOID ) { static FN_RevertToSelf *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RevertToSelf", &g_Kernel32); return pfn (); } typedef BOOL APIENTRY FN_SetThreadToken( PHANDLE Thread, HANDLE Token ); __declspec(dllexport) BOOL APIENTRY kPrf2Wrap_SetThreadToken( PHANDLE Thread, HANDLE Token ) { static FN_SetThreadToken *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetThreadToken", &g_Kernel32); return pfn( Thread, Token ); } typedef BOOL WINAPI FN_AccessCheck( PSECURITY_DESCRIPTOR pSecurityDescriptor, HANDLE ClientToken, DWORD DesiredAccess, PGENERIC_MAPPING GenericMapping, PPRIVILEGE_SET PrivilegeSet, LPDWORD PrivilegeSetLength, LPDWORD GrantedAccess, LPBOOL AccessStatus ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AccessCheck( PSECURITY_DESCRIPTOR pSecurityDescriptor, HANDLE ClientToken, DWORD DesiredAccess, PGENERIC_MAPPING GenericMapping, PPRIVILEGE_SET PrivilegeSet, LPDWORD PrivilegeSetLength, LPDWORD GrantedAccess, LPBOOL AccessStatus ) { static FN_AccessCheck *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AccessCheck", &g_Kernel32); return pfn( pSecurityDescriptor, ClientToken, DesiredAccess, GenericMapping, PrivilegeSet, PrivilegeSetLength, GrantedAccess, AccessStatus ); } typedef BOOL WINAPI FN_AccessCheckByType( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID PrincipalSelfSid, HANDLE ClientToken, DWORD DesiredAccess, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, PPRIVILEGE_SET PrivilegeSet, LPDWORD PrivilegeSetLength, LPDWORD GrantedAccess, LPBOOL AccessStatus ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AccessCheckByType( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID PrincipalSelfSid, HANDLE ClientToken, DWORD DesiredAccess, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, PPRIVILEGE_SET PrivilegeSet, LPDWORD PrivilegeSetLength, LPDWORD GrantedAccess, LPBOOL AccessStatus ) { static FN_AccessCheckByType *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AccessCheckByType", &g_Kernel32); return pfn( pSecurityDescriptor, PrincipalSelfSid, ClientToken, DesiredAccess, ObjectTypeList, ObjectTypeListLength, GenericMapping, PrivilegeSet, PrivilegeSetLength, GrantedAccess, AccessStatus ); } typedef BOOL WINAPI FN_AccessCheckByTypeResultList( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID PrincipalSelfSid, HANDLE ClientToken, DWORD DesiredAccess, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, PPRIVILEGE_SET PrivilegeSet, LPDWORD PrivilegeSetLength, LPDWORD GrantedAccessList, LPDWORD AccessStatusList ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AccessCheckByTypeResultList( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID PrincipalSelfSid, HANDLE ClientToken, DWORD DesiredAccess, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, PPRIVILEGE_SET PrivilegeSet, LPDWORD PrivilegeSetLength, LPDWORD GrantedAccessList, LPDWORD AccessStatusList ) { static FN_AccessCheckByTypeResultList *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AccessCheckByTypeResultList", &g_Kernel32); return pfn( pSecurityDescriptor, PrincipalSelfSid, ClientToken, DesiredAccess, ObjectTypeList, ObjectTypeListLength, GenericMapping, PrivilegeSet, PrivilegeSetLength, GrantedAccessList, AccessStatusList ); } typedef BOOL WINAPI FN_OpenProcessToken( HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_OpenProcessToken( HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle ) { static FN_OpenProcessToken *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "OpenProcessToken", &g_Kernel32); return pfn( ProcessHandle, DesiredAccess, TokenHandle ); } typedef BOOL WINAPI FN_OpenThreadToken( HANDLE ThreadHandle, DWORD DesiredAccess, BOOL OpenAsSelf, PHANDLE TokenHandle ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_OpenThreadToken( HANDLE ThreadHandle, DWORD DesiredAccess, BOOL OpenAsSelf, PHANDLE TokenHandle ) { static FN_OpenThreadToken *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "OpenThreadToken", &g_Kernel32); return pfn( ThreadHandle, DesiredAccess, OpenAsSelf, TokenHandle ); } typedef BOOL WINAPI FN_GetTokenInformation( HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, LPVOID TokenInformation, DWORD TokenInformationLength, PDWORD ReturnLength ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetTokenInformation( HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, LPVOID TokenInformation, DWORD TokenInformationLength, PDWORD ReturnLength ) { static FN_GetTokenInformation *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetTokenInformation", &g_Kernel32); return pfn( TokenHandle, TokenInformationClass, TokenInformation, TokenInformationLength, ReturnLength ); } typedef BOOL WINAPI FN_SetTokenInformation( HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, LPVOID TokenInformation, DWORD TokenInformationLength ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetTokenInformation( HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, LPVOID TokenInformation, DWORD TokenInformationLength ) { static FN_SetTokenInformation *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetTokenInformation", &g_Kernel32); return pfn( TokenHandle, TokenInformationClass, TokenInformation, TokenInformationLength ); } typedef BOOL WINAPI FN_AdjustTokenPrivileges( HANDLE TokenHandle, BOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState, DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, PDWORD ReturnLength ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AdjustTokenPrivileges( HANDLE TokenHandle, BOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState, DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, PDWORD ReturnLength ) { static FN_AdjustTokenPrivileges *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AdjustTokenPrivileges", &g_Kernel32); return pfn( TokenHandle, DisableAllPrivileges, NewState, BufferLength, PreviousState, ReturnLength ); } typedef BOOL WINAPI FN_AdjustTokenGroups( HANDLE TokenHandle, BOOL ResetToDefault, PTOKEN_GROUPS NewState, DWORD BufferLength, PTOKEN_GROUPS PreviousState, PDWORD ReturnLength ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AdjustTokenGroups( HANDLE TokenHandle, BOOL ResetToDefault, PTOKEN_GROUPS NewState, DWORD BufferLength, PTOKEN_GROUPS PreviousState, PDWORD ReturnLength ) { static FN_AdjustTokenGroups *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AdjustTokenGroups", &g_Kernel32); return pfn( TokenHandle, ResetToDefault, NewState, BufferLength, PreviousState, ReturnLength ); } typedef BOOL WINAPI FN_PrivilegeCheck( HANDLE ClientToken, PPRIVILEGE_SET RequiredPrivileges, LPBOOL pfResult ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_PrivilegeCheck( HANDLE ClientToken, PPRIVILEGE_SET RequiredPrivileges, LPBOOL pfResult ) { static FN_PrivilegeCheck *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "PrivilegeCheck", &g_Kernel32); return pfn( ClientToken, RequiredPrivileges, pfResult ); } typedef BOOL WINAPI FN_AccessCheckAndAuditAlarmA( LPCSTR SubsystemName, LPVOID HandleId, LPSTR ObjectTypeName, LPSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, DWORD DesiredAccess, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPBOOL AccessStatus, LPBOOL pfGenerateOnClose ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AccessCheckAndAuditAlarmA( LPCSTR SubsystemName, LPVOID HandleId, LPSTR ObjectTypeName, LPSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, DWORD DesiredAccess, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPBOOL AccessStatus, LPBOOL pfGenerateOnClose ) { static FN_AccessCheckAndAuditAlarmA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AccessCheckAndAuditAlarmA", &g_Kernel32); return pfn( SubsystemName, HandleId, ObjectTypeName, ObjectName, SecurityDescriptor, DesiredAccess, GenericMapping, ObjectCreation, GrantedAccess, AccessStatus, pfGenerateOnClose ); } typedef BOOL WINAPI FN_AccessCheckAndAuditAlarmW( LPCWSTR SubsystemName, LPVOID HandleId, LPWSTR ObjectTypeName, LPWSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, DWORD DesiredAccess, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPBOOL AccessStatus, LPBOOL pfGenerateOnClose ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AccessCheckAndAuditAlarmW( LPCWSTR SubsystemName, LPVOID HandleId, LPWSTR ObjectTypeName, LPWSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, DWORD DesiredAccess, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPBOOL AccessStatus, LPBOOL pfGenerateOnClose ) { static FN_AccessCheckAndAuditAlarmW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AccessCheckAndAuditAlarmW", &g_Kernel32); return pfn( SubsystemName, HandleId, ObjectTypeName, ObjectName, SecurityDescriptor, DesiredAccess, GenericMapping, ObjectCreation, GrantedAccess, AccessStatus, pfGenerateOnClose ); } typedef BOOL WINAPI FN_AccessCheckByTypeAndAuditAlarmA( LPCSTR SubsystemName, LPVOID HandleId, LPCSTR ObjectTypeName, LPCSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, PSID PrincipalSelfSid, DWORD DesiredAccess, AUDIT_EVENT_TYPE AuditType, DWORD Flags, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPBOOL AccessStatus, LPBOOL pfGenerateOnClose ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AccessCheckByTypeAndAuditAlarmA( LPCSTR SubsystemName, LPVOID HandleId, LPCSTR ObjectTypeName, LPCSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, PSID PrincipalSelfSid, DWORD DesiredAccess, AUDIT_EVENT_TYPE AuditType, DWORD Flags, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPBOOL AccessStatus, LPBOOL pfGenerateOnClose ) { static FN_AccessCheckByTypeAndAuditAlarmA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AccessCheckByTypeAndAuditAlarmA", &g_Kernel32); return pfn( SubsystemName, HandleId, ObjectTypeName, ObjectName, SecurityDescriptor, PrincipalSelfSid, DesiredAccess, AuditType, Flags, ObjectTypeList, ObjectTypeListLength, GenericMapping, ObjectCreation, GrantedAccess, AccessStatus, pfGenerateOnClose ); } typedef BOOL WINAPI FN_AccessCheckByTypeAndAuditAlarmW( LPCWSTR SubsystemName, LPVOID HandleId, LPCWSTR ObjectTypeName, LPCWSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, PSID PrincipalSelfSid, DWORD DesiredAccess, AUDIT_EVENT_TYPE AuditType, DWORD Flags, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPBOOL AccessStatus, LPBOOL pfGenerateOnClose ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AccessCheckByTypeAndAuditAlarmW( LPCWSTR SubsystemName, LPVOID HandleId, LPCWSTR ObjectTypeName, LPCWSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, PSID PrincipalSelfSid, DWORD DesiredAccess, AUDIT_EVENT_TYPE AuditType, DWORD Flags, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPBOOL AccessStatus, LPBOOL pfGenerateOnClose ) { static FN_AccessCheckByTypeAndAuditAlarmW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AccessCheckByTypeAndAuditAlarmW", &g_Kernel32); return pfn( SubsystemName, HandleId, ObjectTypeName, ObjectName, SecurityDescriptor, PrincipalSelfSid, DesiredAccess, AuditType, Flags, ObjectTypeList, ObjectTypeListLength, GenericMapping, ObjectCreation, GrantedAccess, AccessStatus, pfGenerateOnClose ); } typedef BOOL WINAPI FN_AccessCheckByTypeResultListAndAuditAlarmA( LPCSTR SubsystemName, LPVOID HandleId, LPCSTR ObjectTypeName, LPCSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, PSID PrincipalSelfSid, DWORD DesiredAccess, AUDIT_EVENT_TYPE AuditType, DWORD Flags, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPDWORD AccessStatusList, LPBOOL pfGenerateOnClose ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AccessCheckByTypeResultListAndAuditAlarmA( LPCSTR SubsystemName, LPVOID HandleId, LPCSTR ObjectTypeName, LPCSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, PSID PrincipalSelfSid, DWORD DesiredAccess, AUDIT_EVENT_TYPE AuditType, DWORD Flags, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPDWORD AccessStatusList, LPBOOL pfGenerateOnClose ) { static FN_AccessCheckByTypeResultListAndAuditAlarmA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AccessCheckByTypeResultListAndAuditAlarmA", &g_Kernel32); return pfn( SubsystemName, HandleId, ObjectTypeName, ObjectName, SecurityDescriptor, PrincipalSelfSid, DesiredAccess, AuditType, Flags, ObjectTypeList, ObjectTypeListLength, GenericMapping, ObjectCreation, GrantedAccess, AccessStatusList, pfGenerateOnClose ); } typedef BOOL WINAPI FN_AccessCheckByTypeResultListAndAuditAlarmW( LPCWSTR SubsystemName, LPVOID HandleId, LPCWSTR ObjectTypeName, LPCWSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, PSID PrincipalSelfSid, DWORD DesiredAccess, AUDIT_EVENT_TYPE AuditType, DWORD Flags, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPDWORD AccessStatusList, LPBOOL pfGenerateOnClose ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AccessCheckByTypeResultListAndAuditAlarmW( LPCWSTR SubsystemName, LPVOID HandleId, LPCWSTR ObjectTypeName, LPCWSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, PSID PrincipalSelfSid, DWORD DesiredAccess, AUDIT_EVENT_TYPE AuditType, DWORD Flags, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPDWORD AccessStatusList, LPBOOL pfGenerateOnClose ) { static FN_AccessCheckByTypeResultListAndAuditAlarmW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AccessCheckByTypeResultListAndAuditAlarmW", &g_Kernel32); return pfn( SubsystemName, HandleId, ObjectTypeName, ObjectName, SecurityDescriptor, PrincipalSelfSid, DesiredAccess, AuditType, Flags, ObjectTypeList, ObjectTypeListLength, GenericMapping, ObjectCreation, GrantedAccess, AccessStatusList, pfGenerateOnClose ); } typedef BOOL WINAPI FN_AccessCheckByTypeResultListAndAuditAlarmByHandleA( LPCSTR SubsystemName, LPVOID HandleId, HANDLE ClientToken, LPCSTR ObjectTypeName, LPCSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, PSID PrincipalSelfSid, DWORD DesiredAccess, AUDIT_EVENT_TYPE AuditType, DWORD Flags, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPDWORD AccessStatusList, LPBOOL pfGenerateOnClose ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AccessCheckByTypeResultListAndAuditAlarmByHandleA( LPCSTR SubsystemName, LPVOID HandleId, HANDLE ClientToken, LPCSTR ObjectTypeName, LPCSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, PSID PrincipalSelfSid, DWORD DesiredAccess, AUDIT_EVENT_TYPE AuditType, DWORD Flags, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPDWORD AccessStatusList, LPBOOL pfGenerateOnClose ) { static FN_AccessCheckByTypeResultListAndAuditAlarmByHandleA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AccessCheckByTypeResultListAndAuditAlarmByHandleA", &g_Kernel32); return pfn( SubsystemName, HandleId, ClientToken, ObjectTypeName, ObjectName, SecurityDescriptor, PrincipalSelfSid, DesiredAccess, AuditType, Flags, ObjectTypeList, ObjectTypeListLength, GenericMapping, ObjectCreation, GrantedAccess, AccessStatusList, pfGenerateOnClose ); } typedef BOOL WINAPI FN_AccessCheckByTypeResultListAndAuditAlarmByHandleW( LPCWSTR SubsystemName, LPVOID HandleId, HANDLE ClientToken, LPCWSTR ObjectTypeName, LPCWSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, PSID PrincipalSelfSid, DWORD DesiredAccess, AUDIT_EVENT_TYPE AuditType, DWORD Flags, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPDWORD AccessStatusList, LPBOOL pfGenerateOnClose ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AccessCheckByTypeResultListAndAuditAlarmByHandleW( LPCWSTR SubsystemName, LPVOID HandleId, HANDLE ClientToken, LPCWSTR ObjectTypeName, LPCWSTR ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, PSID PrincipalSelfSid, DWORD DesiredAccess, AUDIT_EVENT_TYPE AuditType, DWORD Flags, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPDWORD AccessStatusList, LPBOOL pfGenerateOnClose ) { static FN_AccessCheckByTypeResultListAndAuditAlarmByHandleW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AccessCheckByTypeResultListAndAuditAlarmByHandleW", &g_Kernel32); return pfn( SubsystemName, HandleId, ClientToken, ObjectTypeName, ObjectName, SecurityDescriptor, PrincipalSelfSid, DesiredAccess, AuditType, Flags, ObjectTypeList, ObjectTypeListLength, GenericMapping, ObjectCreation, GrantedAccess, AccessStatusList, pfGenerateOnClose ); } typedef BOOL WINAPI FN_ObjectOpenAuditAlarmA( LPCSTR SubsystemName, LPVOID HandleId, LPSTR ObjectTypeName, LPSTR ObjectName, PSECURITY_DESCRIPTOR pSecurityDescriptor, HANDLE ClientToken, DWORD DesiredAccess, DWORD GrantedAccess, PPRIVILEGE_SET Privileges, BOOL ObjectCreation, BOOL AccessGranted, LPBOOL GenerateOnClose ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ObjectOpenAuditAlarmA( LPCSTR SubsystemName, LPVOID HandleId, LPSTR ObjectTypeName, LPSTR ObjectName, PSECURITY_DESCRIPTOR pSecurityDescriptor, HANDLE ClientToken, DWORD DesiredAccess, DWORD GrantedAccess, PPRIVILEGE_SET Privileges, BOOL ObjectCreation, BOOL AccessGranted, LPBOOL GenerateOnClose ) { static FN_ObjectOpenAuditAlarmA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ObjectOpenAuditAlarmA", &g_Kernel32); return pfn( SubsystemName, HandleId, ObjectTypeName, ObjectName, pSecurityDescriptor, ClientToken, DesiredAccess, GrantedAccess, Privileges, ObjectCreation, AccessGranted, GenerateOnClose ); } typedef BOOL WINAPI FN_ObjectOpenAuditAlarmW( LPCWSTR SubsystemName, LPVOID HandleId, LPWSTR ObjectTypeName, LPWSTR ObjectName, PSECURITY_DESCRIPTOR pSecurityDescriptor, HANDLE ClientToken, DWORD DesiredAccess, DWORD GrantedAccess, PPRIVILEGE_SET Privileges, BOOL ObjectCreation, BOOL AccessGranted, LPBOOL GenerateOnClose ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ObjectOpenAuditAlarmW( LPCWSTR SubsystemName, LPVOID HandleId, LPWSTR ObjectTypeName, LPWSTR ObjectName, PSECURITY_DESCRIPTOR pSecurityDescriptor, HANDLE ClientToken, DWORD DesiredAccess, DWORD GrantedAccess, PPRIVILEGE_SET Privileges, BOOL ObjectCreation, BOOL AccessGranted, LPBOOL GenerateOnClose ) { static FN_ObjectOpenAuditAlarmW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ObjectOpenAuditAlarmW", &g_Kernel32); return pfn( SubsystemName, HandleId, ObjectTypeName, ObjectName, pSecurityDescriptor, ClientToken, DesiredAccess, GrantedAccess, Privileges, ObjectCreation, AccessGranted, GenerateOnClose ); } typedef BOOL WINAPI FN_ObjectPrivilegeAuditAlarmA( LPCSTR SubsystemName, LPVOID HandleId, HANDLE ClientToken, DWORD DesiredAccess, PPRIVILEGE_SET Privileges, BOOL AccessGranted ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ObjectPrivilegeAuditAlarmA( LPCSTR SubsystemName, LPVOID HandleId, HANDLE ClientToken, DWORD DesiredAccess, PPRIVILEGE_SET Privileges, BOOL AccessGranted ) { static FN_ObjectPrivilegeAuditAlarmA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ObjectPrivilegeAuditAlarmA", &g_Kernel32); return pfn( SubsystemName, HandleId, ClientToken, DesiredAccess, Privileges, AccessGranted ); } typedef BOOL WINAPI FN_ObjectPrivilegeAuditAlarmW( LPCWSTR SubsystemName, LPVOID HandleId, HANDLE ClientToken, DWORD DesiredAccess, PPRIVILEGE_SET Privileges, BOOL AccessGranted ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ObjectPrivilegeAuditAlarmW( LPCWSTR SubsystemName, LPVOID HandleId, HANDLE ClientToken, DWORD DesiredAccess, PPRIVILEGE_SET Privileges, BOOL AccessGranted ) { static FN_ObjectPrivilegeAuditAlarmW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ObjectPrivilegeAuditAlarmW", &g_Kernel32); return pfn( SubsystemName, HandleId, ClientToken, DesiredAccess, Privileges, AccessGranted ); } typedef BOOL WINAPI FN_ObjectCloseAuditAlarmA( LPCSTR SubsystemName, LPVOID HandleId, BOOL GenerateOnClose ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ObjectCloseAuditAlarmA( LPCSTR SubsystemName, LPVOID HandleId, BOOL GenerateOnClose ) { static FN_ObjectCloseAuditAlarmA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ObjectCloseAuditAlarmA", &g_Kernel32); return pfn( SubsystemName, HandleId, GenerateOnClose ); } typedef BOOL WINAPI FN_ObjectCloseAuditAlarmW( LPCWSTR SubsystemName, LPVOID HandleId, BOOL GenerateOnClose ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ObjectCloseAuditAlarmW( LPCWSTR SubsystemName, LPVOID HandleId, BOOL GenerateOnClose ) { static FN_ObjectCloseAuditAlarmW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ObjectCloseAuditAlarmW", &g_Kernel32); return pfn( SubsystemName, HandleId, GenerateOnClose ); } typedef BOOL WINAPI FN_ObjectDeleteAuditAlarmA( LPCSTR SubsystemName, LPVOID HandleId, BOOL GenerateOnClose ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ObjectDeleteAuditAlarmA( LPCSTR SubsystemName, LPVOID HandleId, BOOL GenerateOnClose ) { static FN_ObjectDeleteAuditAlarmA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ObjectDeleteAuditAlarmA", &g_Kernel32); return pfn( SubsystemName, HandleId, GenerateOnClose ); } typedef BOOL WINAPI FN_ObjectDeleteAuditAlarmW( LPCWSTR SubsystemName, LPVOID HandleId, BOOL GenerateOnClose ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ObjectDeleteAuditAlarmW( LPCWSTR SubsystemName, LPVOID HandleId, BOOL GenerateOnClose ) { static FN_ObjectDeleteAuditAlarmW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ObjectDeleteAuditAlarmW", &g_Kernel32); return pfn( SubsystemName, HandleId, GenerateOnClose ); } typedef BOOL WINAPI FN_PrivilegedServiceAuditAlarmA( LPCSTR SubsystemName, LPCSTR ServiceName, HANDLE ClientToken, PPRIVILEGE_SET Privileges, BOOL AccessGranted ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_PrivilegedServiceAuditAlarmA( LPCSTR SubsystemName, LPCSTR ServiceName, HANDLE ClientToken, PPRIVILEGE_SET Privileges, BOOL AccessGranted ) { static FN_PrivilegedServiceAuditAlarmA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "PrivilegedServiceAuditAlarmA", &g_Kernel32); return pfn( SubsystemName, ServiceName, ClientToken, Privileges, AccessGranted ); } typedef BOOL WINAPI FN_PrivilegedServiceAuditAlarmW( LPCWSTR SubsystemName, LPCWSTR ServiceName, HANDLE ClientToken, PPRIVILEGE_SET Privileges, BOOL AccessGranted ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_PrivilegedServiceAuditAlarmW( LPCWSTR SubsystemName, LPCWSTR ServiceName, HANDLE ClientToken, PPRIVILEGE_SET Privileges, BOOL AccessGranted ) { static FN_PrivilegedServiceAuditAlarmW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "PrivilegedServiceAuditAlarmW", &g_Kernel32); return pfn( SubsystemName, ServiceName, ClientToken, Privileges, AccessGranted ); } typedef BOOL WINAPI FN_IsWellKnownSid( PSID pSid, WELL_KNOWN_SID_TYPE WellKnownSidType ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsWellKnownSid( PSID pSid, WELL_KNOWN_SID_TYPE WellKnownSidType ) { static FN_IsWellKnownSid *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "IsWellKnownSid", &g_Kernel32); return pfn( pSid, WellKnownSidType ); } typedef BOOL WINAPI FN_CreateWellKnownSid( WELL_KNOWN_SID_TYPE WellKnownSidType, PSID DomainSid, PSID pSid, DWORD * cbSid ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateWellKnownSid( WELL_KNOWN_SID_TYPE WellKnownSidType, PSID DomainSid, PSID pSid, DWORD * cbSid ) { static FN_CreateWellKnownSid *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateWellKnownSid", &g_Kernel32); return pfn( WellKnownSidType, DomainSid, pSid, cbSid ); } typedef BOOL WINAPI FN_EqualDomainSid( PSID pSid1, PSID pSid2, BOOL * pfEqual ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EqualDomainSid( PSID pSid1, PSID pSid2, BOOL * pfEqual ) { static FN_EqualDomainSid *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EqualDomainSid", &g_Kernel32); return pfn( pSid1, pSid2, pfEqual ); } typedef BOOL WINAPI FN_GetWindowsAccountDomainSid( PSID pSid, PSID pDomainSid, DWORD * cbDomainSid ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetWindowsAccountDomainSid( PSID pSid, PSID pDomainSid, DWORD * cbDomainSid ) { static FN_GetWindowsAccountDomainSid *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetWindowsAccountDomainSid", &g_Kernel32); return pfn( pSid, pDomainSid, cbDomainSid ); } typedef BOOL WINAPI FN_IsValidSid( PSID pSid ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsValidSid( PSID pSid ) { static FN_IsValidSid *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "IsValidSid", &g_Kernel32); return pfn( pSid ); } typedef BOOL WINAPI FN_EqualSid( PSID pSid1, PSID pSid2 ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EqualSid( PSID pSid1, PSID pSid2 ) { static FN_EqualSid *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EqualSid", &g_Kernel32); return pfn( pSid1, pSid2 ); } typedef BOOL WINAPI FN_EqualPrefixSid( PSID pSid1, PSID pSid2 ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EqualPrefixSid( PSID pSid1, PSID pSid2 ) { static FN_EqualPrefixSid *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EqualPrefixSid", &g_Kernel32); return pfn( pSid1, pSid2 ); } typedef DWORD WINAPI FN_GetSidLengthRequired( UCHAR nSubAuthorityCount ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetSidLengthRequired( UCHAR nSubAuthorityCount ) { static FN_GetSidLengthRequired *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSidLengthRequired", &g_Kernel32); return pfn( nSubAuthorityCount ); } typedef BOOL WINAPI FN_AllocateAndInitializeSid( PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority, BYTE nSubAuthorityCount, DWORD nSubAuthority0, DWORD nSubAuthority1, DWORD nSubAuthority2, DWORD nSubAuthority3, DWORD nSubAuthority4, DWORD nSubAuthority5, DWORD nSubAuthority6, DWORD nSubAuthority7, PSID * pSid ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AllocateAndInitializeSid( PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority, BYTE nSubAuthorityCount, DWORD nSubAuthority0, DWORD nSubAuthority1, DWORD nSubAuthority2, DWORD nSubAuthority3, DWORD nSubAuthority4, DWORD nSubAuthority5, DWORD nSubAuthority6, DWORD nSubAuthority7, PSID * pSid ) { static FN_AllocateAndInitializeSid *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AllocateAndInitializeSid", &g_Kernel32); return pfn( pIdentifierAuthority, nSubAuthorityCount, nSubAuthority0, nSubAuthority1, nSubAuthority2, nSubAuthority3, nSubAuthority4, nSubAuthority5, nSubAuthority6, nSubAuthority7, pSid ); } typedef PVOID WINAPI FN_FreeSid( PSID pSid ); __declspec(dllexport) PVOID WINAPI kPrf2Wrap_FreeSid( PSID pSid ) { static FN_FreeSid *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FreeSid", &g_Kernel32); return pfn( pSid ); } typedef BOOL WINAPI FN_InitializeSid( PSID Sid, PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority, BYTE nSubAuthorityCount ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_InitializeSid( PSID Sid, PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority, BYTE nSubAuthorityCount ) { static FN_InitializeSid *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "InitializeSid", &g_Kernel32); return pfn( Sid, pIdentifierAuthority, nSubAuthorityCount ); } typedef PSID_IDENTIFIER_AUTHORITY WINAPI FN_GetSidIdentifierAuthority( PSID pSid ); __declspec(dllexport) PSID_IDENTIFIER_AUTHORITY WINAPI kPrf2Wrap_GetSidIdentifierAuthority( PSID pSid ) { static FN_GetSidIdentifierAuthority *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSidIdentifierAuthority", &g_Kernel32); return pfn( pSid ); } typedef PDWORD WINAPI FN_GetSidSubAuthority( PSID pSid, DWORD nSubAuthority ); __declspec(dllexport) PDWORD WINAPI kPrf2Wrap_GetSidSubAuthority( PSID pSid, DWORD nSubAuthority ) { static FN_GetSidSubAuthority *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSidSubAuthority", &g_Kernel32); return pfn( pSid, nSubAuthority ); } typedef PUCHAR WINAPI FN_GetSidSubAuthorityCount( PSID pSid ); __declspec(dllexport) PUCHAR WINAPI kPrf2Wrap_GetSidSubAuthorityCount( PSID pSid ) { static FN_GetSidSubAuthorityCount *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSidSubAuthorityCount", &g_Kernel32); return pfn( pSid ); } typedef DWORD WINAPI FN_GetLengthSid( PSID pSid ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetLengthSid( PSID pSid ) { static FN_GetLengthSid *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetLengthSid", &g_Kernel32); return pfn( pSid ); } typedef BOOL WINAPI FN_CopySid( DWORD nDestinationSidLength, PSID pDestinationSid, PSID pSourceSid ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CopySid( DWORD nDestinationSidLength, PSID pDestinationSid, PSID pSourceSid ) { static FN_CopySid *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CopySid", &g_Kernel32); return pfn( nDestinationSidLength, pDestinationSid, pSourceSid ); } typedef BOOL WINAPI FN_AreAllAccessesGranted( DWORD GrantedAccess, DWORD DesiredAccess ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AreAllAccessesGranted( DWORD GrantedAccess, DWORD DesiredAccess ) { static FN_AreAllAccessesGranted *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AreAllAccessesGranted", &g_Kernel32); return pfn( GrantedAccess, DesiredAccess ); } typedef BOOL WINAPI FN_AreAnyAccessesGranted( DWORD GrantedAccess, DWORD DesiredAccess ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AreAnyAccessesGranted( DWORD GrantedAccess, DWORD DesiredAccess ) { static FN_AreAnyAccessesGranted *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AreAnyAccessesGranted", &g_Kernel32); return pfn( GrantedAccess, DesiredAccess ); } typedef VOID WINAPI FN_MapGenericMask( PDWORD AccessMask, PGENERIC_MAPPING GenericMapping ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_MapGenericMask( PDWORD AccessMask, PGENERIC_MAPPING GenericMapping ) { static FN_MapGenericMask *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "MapGenericMask", &g_Kernel32); pfn( AccessMask, GenericMapping ); } typedef BOOL WINAPI FN_IsValidAcl( PACL pAcl ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsValidAcl( PACL pAcl ) { static FN_IsValidAcl *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "IsValidAcl", &g_Kernel32); return pfn( pAcl ); } typedef BOOL WINAPI FN_InitializeAcl( PACL pAcl, DWORD nAclLength, DWORD dwAclRevision ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_InitializeAcl( PACL pAcl, DWORD nAclLength, DWORD dwAclRevision ) { static FN_InitializeAcl *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "InitializeAcl", &g_Kernel32); return pfn( pAcl, nAclLength, dwAclRevision ); } typedef BOOL WINAPI FN_GetAclInformation( PACL pAcl, LPVOID pAclInformation, DWORD nAclInformationLength, ACL_INFORMATION_CLASS dwAclInformationClass ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetAclInformation( PACL pAcl, LPVOID pAclInformation, DWORD nAclInformationLength, ACL_INFORMATION_CLASS dwAclInformationClass ) { static FN_GetAclInformation *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetAclInformation", &g_Kernel32); return pfn( pAcl, pAclInformation, nAclInformationLength, dwAclInformationClass ); } typedef BOOL WINAPI FN_SetAclInformation( PACL pAcl, LPVOID pAclInformation, DWORD nAclInformationLength, ACL_INFORMATION_CLASS dwAclInformationClass ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetAclInformation( PACL pAcl, LPVOID pAclInformation, DWORD nAclInformationLength, ACL_INFORMATION_CLASS dwAclInformationClass ) { static FN_SetAclInformation *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetAclInformation", &g_Kernel32); return pfn( pAcl, pAclInformation, nAclInformationLength, dwAclInformationClass ); } typedef BOOL WINAPI FN_AddAce( PACL pAcl, DWORD dwAceRevision, DWORD dwStartingAceIndex, LPVOID pAceList, DWORD nAceListLength ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AddAce( PACL pAcl, DWORD dwAceRevision, DWORD dwStartingAceIndex, LPVOID pAceList, DWORD nAceListLength ) { static FN_AddAce *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AddAce", &g_Kernel32); return pfn( pAcl, dwAceRevision, dwStartingAceIndex, pAceList, nAceListLength ); } typedef BOOL WINAPI FN_DeleteAce( PACL pAcl, DWORD dwAceIndex ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_DeleteAce( PACL pAcl, DWORD dwAceIndex ) { static FN_DeleteAce *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DeleteAce", &g_Kernel32); return pfn( pAcl, dwAceIndex ); } typedef BOOL WINAPI FN_GetAce( PACL pAcl, DWORD dwAceIndex, LPVOID * pAce ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetAce( PACL pAcl, DWORD dwAceIndex, LPVOID * pAce ) { static FN_GetAce *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetAce", &g_Kernel32); return pfn( pAcl, dwAceIndex, pAce ); } typedef BOOL WINAPI FN_AddAccessAllowedAce( PACL pAcl, DWORD dwAceRevision, DWORD AccessMask, PSID pSid ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AddAccessAllowedAce( PACL pAcl, DWORD dwAceRevision, DWORD AccessMask, PSID pSid ) { static FN_AddAccessAllowedAce *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AddAccessAllowedAce", &g_Kernel32); return pfn( pAcl, dwAceRevision, AccessMask, pSid ); } typedef BOOL WINAPI FN_AddAccessAllowedAceEx( PACL pAcl, DWORD dwAceRevision, DWORD AceFlags, DWORD AccessMask, PSID pSid ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AddAccessAllowedAceEx( PACL pAcl, DWORD dwAceRevision, DWORD AceFlags, DWORD AccessMask, PSID pSid ) { static FN_AddAccessAllowedAceEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AddAccessAllowedAceEx", &g_Kernel32); return pfn( pAcl, dwAceRevision, AceFlags, AccessMask, pSid ); } typedef BOOL WINAPI FN_AddAccessDeniedAce( PACL pAcl, DWORD dwAceRevision, DWORD AccessMask, PSID pSid ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AddAccessDeniedAce( PACL pAcl, DWORD dwAceRevision, DWORD AccessMask, PSID pSid ) { static FN_AddAccessDeniedAce *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AddAccessDeniedAce", &g_Kernel32); return pfn( pAcl, dwAceRevision, AccessMask, pSid ); } typedef BOOL WINAPI FN_AddAccessDeniedAceEx( PACL pAcl, DWORD dwAceRevision, DWORD AceFlags, DWORD AccessMask, PSID pSid ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AddAccessDeniedAceEx( PACL pAcl, DWORD dwAceRevision, DWORD AceFlags, DWORD AccessMask, PSID pSid ) { static FN_AddAccessDeniedAceEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AddAccessDeniedAceEx", &g_Kernel32); return pfn( pAcl, dwAceRevision, AceFlags, AccessMask, pSid ); } typedef BOOL WINAPI FN_AddAuditAccessAce( PACL pAcl, DWORD dwAceRevision, DWORD dwAccessMask, PSID pSid, BOOL bAuditSuccess, BOOL bAuditFailure ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AddAuditAccessAce( PACL pAcl, DWORD dwAceRevision, DWORD dwAccessMask, PSID pSid, BOOL bAuditSuccess, BOOL bAuditFailure ) { static FN_AddAuditAccessAce *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AddAuditAccessAce", &g_Kernel32); return pfn( pAcl, dwAceRevision, dwAccessMask, pSid, bAuditSuccess, bAuditFailure ); } typedef BOOL WINAPI FN_AddAuditAccessAceEx( PACL pAcl, DWORD dwAceRevision, DWORD AceFlags, DWORD dwAccessMask, PSID pSid, BOOL bAuditSuccess, BOOL bAuditFailure ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AddAuditAccessAceEx( PACL pAcl, DWORD dwAceRevision, DWORD AceFlags, DWORD dwAccessMask, PSID pSid, BOOL bAuditSuccess, BOOL bAuditFailure ) { static FN_AddAuditAccessAceEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AddAuditAccessAceEx", &g_Kernel32); return pfn( pAcl, dwAceRevision, AceFlags, dwAccessMask, pSid, bAuditSuccess, bAuditFailure ); } typedef BOOL WINAPI FN_AddAccessAllowedObjectAce( PACL pAcl, DWORD dwAceRevision, DWORD AceFlags, DWORD AccessMask, GUID * ObjectTypeGuid, GUID * InheritedObjectTypeGuid, PSID pSid ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AddAccessAllowedObjectAce( PACL pAcl, DWORD dwAceRevision, DWORD AceFlags, DWORD AccessMask, GUID * ObjectTypeGuid, GUID * InheritedObjectTypeGuid, PSID pSid ) { static FN_AddAccessAllowedObjectAce *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AddAccessAllowedObjectAce", &g_Kernel32); return pfn( pAcl, dwAceRevision, AceFlags, AccessMask, ObjectTypeGuid, InheritedObjectTypeGuid, pSid ); } typedef BOOL WINAPI FN_AddAccessDeniedObjectAce( PACL pAcl, DWORD dwAceRevision, DWORD AceFlags, DWORD AccessMask, GUID * ObjectTypeGuid, GUID * InheritedObjectTypeGuid, PSID pSid ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AddAccessDeniedObjectAce( PACL pAcl, DWORD dwAceRevision, DWORD AceFlags, DWORD AccessMask, GUID * ObjectTypeGuid, GUID * InheritedObjectTypeGuid, PSID pSid ) { static FN_AddAccessDeniedObjectAce *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AddAccessDeniedObjectAce", &g_Kernel32); return pfn( pAcl, dwAceRevision, AceFlags, AccessMask, ObjectTypeGuid, InheritedObjectTypeGuid, pSid ); } typedef BOOL WINAPI FN_AddAuditAccessObjectAce( PACL pAcl, DWORD dwAceRevision, DWORD AceFlags, DWORD AccessMask, GUID * ObjectTypeGuid, GUID * InheritedObjectTypeGuid, PSID pSid, BOOL bAuditSuccess, BOOL bAuditFailure ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AddAuditAccessObjectAce( PACL pAcl, DWORD dwAceRevision, DWORD AceFlags, DWORD AccessMask, GUID * ObjectTypeGuid, GUID * InheritedObjectTypeGuid, PSID pSid, BOOL bAuditSuccess, BOOL bAuditFailure ) { static FN_AddAuditAccessObjectAce *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AddAuditAccessObjectAce", &g_Kernel32); return pfn( pAcl, dwAceRevision, AceFlags, AccessMask, ObjectTypeGuid, InheritedObjectTypeGuid, pSid, bAuditSuccess, bAuditFailure ); } typedef BOOL WINAPI FN_FindFirstFreeAce( PACL pAcl, LPVOID * pAce ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindFirstFreeAce( PACL pAcl, LPVOID * pAce ) { static FN_FindFirstFreeAce *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindFirstFreeAce", &g_Kernel32); return pfn( pAcl, pAce ); } typedef BOOL WINAPI FN_InitializeSecurityDescriptor( PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD dwRevision ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_InitializeSecurityDescriptor( PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD dwRevision ) { static FN_InitializeSecurityDescriptor *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "InitializeSecurityDescriptor", &g_Kernel32); return pfn( pSecurityDescriptor, dwRevision ); } typedef BOOL WINAPI FN_IsValidSecurityDescriptor( PSECURITY_DESCRIPTOR pSecurityDescriptor ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsValidSecurityDescriptor( PSECURITY_DESCRIPTOR pSecurityDescriptor ) { static FN_IsValidSecurityDescriptor *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "IsValidSecurityDescriptor", &g_Kernel32); return pfn( pSecurityDescriptor ); } typedef DWORD WINAPI FN_GetSecurityDescriptorLength( PSECURITY_DESCRIPTOR pSecurityDescriptor ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetSecurityDescriptorLength( PSECURITY_DESCRIPTOR pSecurityDescriptor ) { static FN_GetSecurityDescriptorLength *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSecurityDescriptorLength", &g_Kernel32); return pfn( pSecurityDescriptor ); } typedef BOOL WINAPI FN_GetSecurityDescriptorControl( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSECURITY_DESCRIPTOR_CONTROL pControl, LPDWORD lpdwRevision ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetSecurityDescriptorControl( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSECURITY_DESCRIPTOR_CONTROL pControl, LPDWORD lpdwRevision ) { static FN_GetSecurityDescriptorControl *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSecurityDescriptorControl", &g_Kernel32); return pfn( pSecurityDescriptor, pControl, lpdwRevision ); } typedef BOOL WINAPI FN_SetSecurityDescriptorControl( PSECURITY_DESCRIPTOR pSecurityDescriptor, SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest, SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetSecurityDescriptorControl( PSECURITY_DESCRIPTOR pSecurityDescriptor, SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest, SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet ) { static FN_SetSecurityDescriptorControl *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetSecurityDescriptorControl", &g_Kernel32); return pfn( pSecurityDescriptor, ControlBitsOfInterest, ControlBitsToSet ); } typedef BOOL WINAPI FN_SetSecurityDescriptorDacl( PSECURITY_DESCRIPTOR pSecurityDescriptor, BOOL bDaclPresent, PACL pDacl, BOOL bDaclDefaulted ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetSecurityDescriptorDacl( PSECURITY_DESCRIPTOR pSecurityDescriptor, BOOL bDaclPresent, PACL pDacl, BOOL bDaclDefaulted ) { static FN_SetSecurityDescriptorDacl *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetSecurityDescriptorDacl", &g_Kernel32); return pfn( pSecurityDescriptor, bDaclPresent, pDacl, bDaclDefaulted ); } typedef BOOL WINAPI FN_GetSecurityDescriptorDacl( PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, PACL * pDacl, LPBOOL lpbDaclDefaulted ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetSecurityDescriptorDacl( PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, PACL * pDacl, LPBOOL lpbDaclDefaulted ) { static FN_GetSecurityDescriptorDacl *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSecurityDescriptorDacl", &g_Kernel32); return pfn( pSecurityDescriptor, lpbDaclPresent, pDacl, lpbDaclDefaulted ); } typedef BOOL WINAPI FN_SetSecurityDescriptorSacl( PSECURITY_DESCRIPTOR pSecurityDescriptor, BOOL bSaclPresent, PACL pSacl, BOOL bSaclDefaulted ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetSecurityDescriptorSacl( PSECURITY_DESCRIPTOR pSecurityDescriptor, BOOL bSaclPresent, PACL pSacl, BOOL bSaclDefaulted ) { static FN_SetSecurityDescriptorSacl *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetSecurityDescriptorSacl", &g_Kernel32); return pfn( pSecurityDescriptor, bSaclPresent, pSacl, bSaclDefaulted ); } typedef BOOL WINAPI FN_GetSecurityDescriptorSacl( PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbSaclPresent, PACL * pSacl, LPBOOL lpbSaclDefaulted ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetSecurityDescriptorSacl( PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbSaclPresent, PACL * pSacl, LPBOOL lpbSaclDefaulted ) { static FN_GetSecurityDescriptorSacl *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSecurityDescriptorSacl", &g_Kernel32); return pfn( pSecurityDescriptor, lpbSaclPresent, pSacl, lpbSaclDefaulted ); } typedef BOOL WINAPI FN_SetSecurityDescriptorOwner( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID pOwner, BOOL bOwnerDefaulted ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetSecurityDescriptorOwner( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID pOwner, BOOL bOwnerDefaulted ) { static FN_SetSecurityDescriptorOwner *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetSecurityDescriptorOwner", &g_Kernel32); return pfn( pSecurityDescriptor, pOwner, bOwnerDefaulted ); } typedef BOOL WINAPI FN_GetSecurityDescriptorOwner( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID * pOwner, LPBOOL lpbOwnerDefaulted ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetSecurityDescriptorOwner( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID * pOwner, LPBOOL lpbOwnerDefaulted ) { static FN_GetSecurityDescriptorOwner *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSecurityDescriptorOwner", &g_Kernel32); return pfn( pSecurityDescriptor, pOwner, lpbOwnerDefaulted ); } typedef BOOL WINAPI FN_SetSecurityDescriptorGroup( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID pGroup, BOOL bGroupDefaulted ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetSecurityDescriptorGroup( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID pGroup, BOOL bGroupDefaulted ) { static FN_SetSecurityDescriptorGroup *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetSecurityDescriptorGroup", &g_Kernel32); return pfn( pSecurityDescriptor, pGroup, bGroupDefaulted ); } typedef BOOL WINAPI FN_GetSecurityDescriptorGroup( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID * pGroup, LPBOOL lpbGroupDefaulted ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetSecurityDescriptorGroup( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID * pGroup, LPBOOL lpbGroupDefaulted ) { static FN_GetSecurityDescriptorGroup *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSecurityDescriptorGroup", &g_Kernel32); return pfn( pSecurityDescriptor, pGroup, lpbGroupDefaulted ); } typedef DWORD WINAPI FN_SetSecurityDescriptorRMControl( PSECURITY_DESCRIPTOR SecurityDescriptor, PUCHAR RMControl ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_SetSecurityDescriptorRMControl( PSECURITY_DESCRIPTOR SecurityDescriptor, PUCHAR RMControl ) { static FN_SetSecurityDescriptorRMControl *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetSecurityDescriptorRMControl", &g_Kernel32); return pfn( SecurityDescriptor, RMControl ); } typedef DWORD WINAPI FN_GetSecurityDescriptorRMControl( PSECURITY_DESCRIPTOR SecurityDescriptor, PUCHAR RMControl ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetSecurityDescriptorRMControl( PSECURITY_DESCRIPTOR SecurityDescriptor, PUCHAR RMControl ) { static FN_GetSecurityDescriptorRMControl *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSecurityDescriptorRMControl", &g_Kernel32); return pfn( SecurityDescriptor, RMControl ); } typedef BOOL WINAPI FN_CreatePrivateObjectSecurity( PSECURITY_DESCRIPTOR ParentDescriptor, PSECURITY_DESCRIPTOR CreatorDescriptor, PSECURITY_DESCRIPTOR * NewDescriptor, BOOL IsDirectoryObject, HANDLE Token, PGENERIC_MAPPING GenericMapping ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreatePrivateObjectSecurity( PSECURITY_DESCRIPTOR ParentDescriptor, PSECURITY_DESCRIPTOR CreatorDescriptor, PSECURITY_DESCRIPTOR * NewDescriptor, BOOL IsDirectoryObject, HANDLE Token, PGENERIC_MAPPING GenericMapping ) { static FN_CreatePrivateObjectSecurity *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreatePrivateObjectSecurity", &g_Kernel32); return pfn( ParentDescriptor, CreatorDescriptor, NewDescriptor, IsDirectoryObject, Token, GenericMapping ); } typedef BOOL WINAPI FN_ConvertToAutoInheritPrivateObjectSecurity( PSECURITY_DESCRIPTOR ParentDescriptor, PSECURITY_DESCRIPTOR CurrentSecurityDescriptor, PSECURITY_DESCRIPTOR * NewSecurityDescriptor, GUID * ObjectType, BOOLEAN IsDirectoryObject, PGENERIC_MAPPING GenericMapping ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ConvertToAutoInheritPrivateObjectSecurity( PSECURITY_DESCRIPTOR ParentDescriptor, PSECURITY_DESCRIPTOR CurrentSecurityDescriptor, PSECURITY_DESCRIPTOR * NewSecurityDescriptor, GUID * ObjectType, BOOLEAN IsDirectoryObject, PGENERIC_MAPPING GenericMapping ) { static FN_ConvertToAutoInheritPrivateObjectSecurity *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ConvertToAutoInheritPrivateObjectSecurity", &g_Kernel32); return pfn( ParentDescriptor, CurrentSecurityDescriptor, NewSecurityDescriptor, ObjectType, IsDirectoryObject, GenericMapping ); } typedef BOOL WINAPI FN_CreatePrivateObjectSecurityEx( PSECURITY_DESCRIPTOR ParentDescriptor, PSECURITY_DESCRIPTOR CreatorDescriptor, PSECURITY_DESCRIPTOR * NewDescriptor, GUID * ObjectType, BOOL IsContainerObject, ULONG AutoInheritFlags, HANDLE Token, PGENERIC_MAPPING GenericMapping ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreatePrivateObjectSecurityEx( PSECURITY_DESCRIPTOR ParentDescriptor, PSECURITY_DESCRIPTOR CreatorDescriptor, PSECURITY_DESCRIPTOR * NewDescriptor, GUID * ObjectType, BOOL IsContainerObject, ULONG AutoInheritFlags, HANDLE Token, PGENERIC_MAPPING GenericMapping ) { static FN_CreatePrivateObjectSecurityEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreatePrivateObjectSecurityEx", &g_Kernel32); return pfn( ParentDescriptor, CreatorDescriptor, NewDescriptor, ObjectType, IsContainerObject, AutoInheritFlags, Token, GenericMapping ); } typedef BOOL WINAPI FN_CreatePrivateObjectSecurityWithMultipleInheritance( PSECURITY_DESCRIPTOR ParentDescriptor, PSECURITY_DESCRIPTOR CreatorDescriptor, PSECURITY_DESCRIPTOR * NewDescriptor, GUID * *ObjectTypes, ULONG GuidCount, BOOL IsContainerObject, ULONG AutoInheritFlags, HANDLE Token, PGENERIC_MAPPING GenericMapping ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreatePrivateObjectSecurityWithMultipleInheritance( PSECURITY_DESCRIPTOR ParentDescriptor, PSECURITY_DESCRIPTOR CreatorDescriptor, PSECURITY_DESCRIPTOR * NewDescriptor, GUID * *ObjectTypes, ULONG GuidCount, BOOL IsContainerObject, ULONG AutoInheritFlags, HANDLE Token, PGENERIC_MAPPING GenericMapping ) { static FN_CreatePrivateObjectSecurityWithMultipleInheritance *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreatePrivateObjectSecurityWithMultipleInheritance", &g_Kernel32); return pfn( ParentDescriptor, CreatorDescriptor, NewDescriptor, ObjectTypes, GuidCount, IsContainerObject, AutoInheritFlags, Token, GenericMapping ); } typedef BOOL WINAPI FN_SetPrivateObjectSecurity( SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR ModificationDescriptor, PSECURITY_DESCRIPTOR * ObjectsSecurityDescriptor, PGENERIC_MAPPING GenericMapping, HANDLE Token ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetPrivateObjectSecurity( SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR ModificationDescriptor, PSECURITY_DESCRIPTOR * ObjectsSecurityDescriptor, PGENERIC_MAPPING GenericMapping, HANDLE Token ) { static FN_SetPrivateObjectSecurity *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetPrivateObjectSecurity", &g_Kernel32); return pfn( SecurityInformation, ModificationDescriptor, ObjectsSecurityDescriptor, GenericMapping, Token ); } typedef BOOL WINAPI FN_SetPrivateObjectSecurityEx( SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR ModificationDescriptor, PSECURITY_DESCRIPTOR * ObjectsSecurityDescriptor, ULONG AutoInheritFlags, PGENERIC_MAPPING GenericMapping, HANDLE Token ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetPrivateObjectSecurityEx( SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR ModificationDescriptor, PSECURITY_DESCRIPTOR * ObjectsSecurityDescriptor, ULONG AutoInheritFlags, PGENERIC_MAPPING GenericMapping, HANDLE Token ) { static FN_SetPrivateObjectSecurityEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetPrivateObjectSecurityEx", &g_Kernel32); return pfn( SecurityInformation, ModificationDescriptor, ObjectsSecurityDescriptor, AutoInheritFlags, GenericMapping, Token ); } typedef BOOL WINAPI FN_GetPrivateObjectSecurity( PSECURITY_DESCRIPTOR ObjectDescriptor, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR ResultantDescriptor, DWORD DescriptorLength, PDWORD ReturnLength ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetPrivateObjectSecurity( PSECURITY_DESCRIPTOR ObjectDescriptor, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR ResultantDescriptor, DWORD DescriptorLength, PDWORD ReturnLength ) { static FN_GetPrivateObjectSecurity *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetPrivateObjectSecurity", &g_Kernel32); return pfn( ObjectDescriptor, SecurityInformation, ResultantDescriptor, DescriptorLength, ReturnLength ); } typedef BOOL WINAPI FN_DestroyPrivateObjectSecurity( PSECURITY_DESCRIPTOR * ObjectDescriptor ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_DestroyPrivateObjectSecurity( PSECURITY_DESCRIPTOR * ObjectDescriptor ) { static FN_DestroyPrivateObjectSecurity *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DestroyPrivateObjectSecurity", &g_Kernel32); return pfn( ObjectDescriptor ); } typedef BOOL WINAPI FN_MakeSelfRelativeSD( PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor, PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor, LPDWORD lpdwBufferLength ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_MakeSelfRelativeSD( PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor, PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor, LPDWORD lpdwBufferLength ) { static FN_MakeSelfRelativeSD *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "MakeSelfRelativeSD", &g_Kernel32); return pfn( pAbsoluteSecurityDescriptor, pSelfRelativeSecurityDescriptor, lpdwBufferLength ); } typedef BOOL WINAPI FN_MakeAbsoluteSD( PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor, PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor, LPDWORD lpdwAbsoluteSecurityDescriptorSize, PACL pDacl, LPDWORD lpdwDaclSize, PACL pSacl, LPDWORD lpdwSaclSize, PSID pOwner, LPDWORD lpdwOwnerSize, PSID pPrimaryGroup, LPDWORD lpdwPrimaryGroupSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_MakeAbsoluteSD( PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor, PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor, LPDWORD lpdwAbsoluteSecurityDescriptorSize, PACL pDacl, LPDWORD lpdwDaclSize, PACL pSacl, LPDWORD lpdwSaclSize, PSID pOwner, LPDWORD lpdwOwnerSize, PSID pPrimaryGroup, LPDWORD lpdwPrimaryGroupSize ) { static FN_MakeAbsoluteSD *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "MakeAbsoluteSD", &g_Kernel32); return pfn( pSelfRelativeSecurityDescriptor, pAbsoluteSecurityDescriptor, lpdwAbsoluteSecurityDescriptorSize, pDacl, lpdwDaclSize, pSacl, lpdwSaclSize, pOwner, lpdwOwnerSize, pPrimaryGroup, lpdwPrimaryGroupSize ); } typedef BOOL WINAPI FN_MakeAbsoluteSD2( PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor, LPDWORD lpdwBufferSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_MakeAbsoluteSD2( PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor, LPDWORD lpdwBufferSize ) { static FN_MakeAbsoluteSD2 *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "MakeAbsoluteSD2", &g_Kernel32); return pfn( pSelfRelativeSecurityDescriptor, lpdwBufferSize ); } typedef BOOL WINAPI FN_SetFileSecurityA( LPCSTR lpFileName, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetFileSecurityA( LPCSTR lpFileName, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor ) { static FN_SetFileSecurityA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetFileSecurityA", &g_Kernel32); return pfn( lpFileName, SecurityInformation, pSecurityDescriptor ); } typedef BOOL WINAPI FN_SetFileSecurityW( LPCWSTR lpFileName, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetFileSecurityW( LPCWSTR lpFileName, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor ) { static FN_SetFileSecurityW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetFileSecurityW", &g_Kernel32); return pfn( lpFileName, SecurityInformation, pSecurityDescriptor ); } typedef BOOL WINAPI FN_GetFileSecurityA( LPCSTR lpFileName, SECURITY_INFORMATION RequestedInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetFileSecurityA( LPCSTR lpFileName, SECURITY_INFORMATION RequestedInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded ) { static FN_GetFileSecurityA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetFileSecurityA", &g_Kernel32); return pfn( lpFileName, RequestedInformation, pSecurityDescriptor, nLength, lpnLengthNeeded ); } typedef BOOL WINAPI FN_GetFileSecurityW( LPCWSTR lpFileName, SECURITY_INFORMATION RequestedInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetFileSecurityW( LPCWSTR lpFileName, SECURITY_INFORMATION RequestedInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded ) { static FN_GetFileSecurityW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetFileSecurityW", &g_Kernel32); return pfn( lpFileName, RequestedInformation, pSecurityDescriptor, nLength, lpnLengthNeeded ); } typedef BOOL WINAPI FN_SetKernelObjectSecurity( HANDLE Handle, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR SecurityDescriptor ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetKernelObjectSecurity( HANDLE Handle, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR SecurityDescriptor ) { static FN_SetKernelObjectSecurity *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetKernelObjectSecurity", &g_Kernel32); return pfn( Handle, SecurityInformation, SecurityDescriptor ); } typedef HANDLE WINAPI FN_FindFirstChangeNotificationA( LPCSTR lpPathName, BOOL bWatchSubtree, DWORD dwNotifyFilter ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_FindFirstChangeNotificationA( LPCSTR lpPathName, BOOL bWatchSubtree, DWORD dwNotifyFilter ) { static FN_FindFirstChangeNotificationA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindFirstChangeNotificationA", &g_Kernel32); return pfn( lpPathName, bWatchSubtree, dwNotifyFilter ); } typedef HANDLE WINAPI FN_FindFirstChangeNotificationW( LPCWSTR lpPathName, BOOL bWatchSubtree, DWORD dwNotifyFilter ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_FindFirstChangeNotificationW( LPCWSTR lpPathName, BOOL bWatchSubtree, DWORD dwNotifyFilter ) { static FN_FindFirstChangeNotificationW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindFirstChangeNotificationW", &g_Kernel32); return pfn( lpPathName, bWatchSubtree, dwNotifyFilter ); } typedef BOOL WINAPI FN_FindNextChangeNotification( HANDLE hChangeHandle ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindNextChangeNotification( HANDLE hChangeHandle ) { static FN_FindNextChangeNotification *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindNextChangeNotification", &g_Kernel32); return pfn( hChangeHandle ); } typedef BOOL WINAPI FN_FindCloseChangeNotification( HANDLE hChangeHandle ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindCloseChangeNotification( HANDLE hChangeHandle ) { static FN_FindCloseChangeNotification *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindCloseChangeNotification", &g_Kernel32); return pfn( hChangeHandle ); } typedef BOOL WINAPI FN_ReadDirectoryChangesW( HANDLE hDirectory, LPVOID lpBuffer, DWORD nBufferLength, BOOL bWatchSubtree, DWORD dwNotifyFilter, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadDirectoryChangesW( HANDLE hDirectory, LPVOID lpBuffer, DWORD nBufferLength, BOOL bWatchSubtree, DWORD dwNotifyFilter, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine ) { static FN_ReadDirectoryChangesW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ReadDirectoryChangesW", &g_Kernel32); return pfn( hDirectory, lpBuffer, nBufferLength, bWatchSubtree, dwNotifyFilter, lpBytesReturned, lpOverlapped, lpCompletionRoutine ); } typedef BOOL WINAPI FN_VirtualLock( LPVOID lpAddress, SIZE_T dwSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_VirtualLock( LPVOID lpAddress, SIZE_T dwSize ) { static FN_VirtualLock *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "VirtualLock", &g_Kernel32); return pfn( lpAddress, dwSize ); } typedef BOOL WINAPI FN_VirtualUnlock( LPVOID lpAddress, SIZE_T dwSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_VirtualUnlock( LPVOID lpAddress, SIZE_T dwSize ) { static FN_VirtualUnlock *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "VirtualUnlock", &g_Kernel32); return pfn( lpAddress, dwSize ); } typedef LPVOID WINAPI FN_MapViewOfFileEx( HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap, LPVOID lpBaseAddress ); __declspec(dllexport) LPVOID WINAPI kPrf2Wrap_MapViewOfFileEx( HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap, LPVOID lpBaseAddress ) { static FN_MapViewOfFileEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "MapViewOfFileEx", &g_Kernel32); return pfn( hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow, dwNumberOfBytesToMap, lpBaseAddress ); } typedef BOOL WINAPI FN_SetPriorityClass( HANDLE hProcess, DWORD dwPriorityClass ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetPriorityClass( HANDLE hProcess, DWORD dwPriorityClass ) { static FN_SetPriorityClass *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetPriorityClass", &g_Kernel32); return pfn( hProcess, dwPriorityClass ); } typedef DWORD WINAPI FN_GetPriorityClass( HANDLE hProcess ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetPriorityClass( HANDLE hProcess ) { static FN_GetPriorityClass *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetPriorityClass", &g_Kernel32); return pfn( hProcess ); } typedef BOOL WINAPI FN_IsBadReadPtr( CONST VOID * lp, UINT_PTR ucb ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsBadReadPtr( CONST VOID * lp, UINT_PTR ucb ) { static FN_IsBadReadPtr *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "IsBadReadPtr", &g_Kernel32); return pfn( lp, ucb ); } typedef BOOL WINAPI FN_IsBadWritePtr( LPVOID lp, UINT_PTR ucb ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsBadWritePtr( LPVOID lp, UINT_PTR ucb ) { static FN_IsBadWritePtr *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "IsBadWritePtr", &g_Kernel32); return pfn( lp, ucb ); } typedef BOOL WINAPI FN_IsBadHugeReadPtr( CONST VOID * lp, UINT_PTR ucb ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsBadHugeReadPtr( CONST VOID * lp, UINT_PTR ucb ) { static FN_IsBadHugeReadPtr *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "IsBadHugeReadPtr", &g_Kernel32); return pfn( lp, ucb ); } typedef BOOL WINAPI FN_IsBadHugeWritePtr( LPVOID lp, UINT_PTR ucb ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsBadHugeWritePtr( LPVOID lp, UINT_PTR ucb ) { static FN_IsBadHugeWritePtr *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "IsBadHugeWritePtr", &g_Kernel32); return pfn( lp, ucb ); } typedef BOOL WINAPI FN_IsBadCodePtr( FARPROC lpfn ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsBadCodePtr( FARPROC lpfn ) { static FN_IsBadCodePtr *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "IsBadCodePtr", &g_Kernel32); return pfn( lpfn ); } typedef BOOL WINAPI FN_IsBadStringPtrA( LPCSTR lpsz, UINT_PTR ucchMax ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsBadStringPtrA( LPCSTR lpsz, UINT_PTR ucchMax ) { static FN_IsBadStringPtrA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "IsBadStringPtrA", &g_Kernel32); return pfn( lpsz, ucchMax ); } typedef BOOL WINAPI FN_IsBadStringPtrW( LPCWSTR lpsz, UINT_PTR ucchMax ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsBadStringPtrW( LPCWSTR lpsz, UINT_PTR ucchMax ) { static FN_IsBadStringPtrW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "IsBadStringPtrW", &g_Kernel32); return pfn( lpsz, ucchMax ); } typedef BOOL WINAPI FN_LookupAccountSidA( LPCSTR lpSystemName, PSID Sid, LPSTR Name, LPDWORD cchName, LPSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, PSID_NAME_USE peUse ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_LookupAccountSidA( LPCSTR lpSystemName, PSID Sid, LPSTR Name, LPDWORD cchName, LPSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, PSID_NAME_USE peUse ) { static FN_LookupAccountSidA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LookupAccountSidA", &g_Kernel32); return pfn( lpSystemName, Sid, Name, cchName, ReferencedDomainName, cchReferencedDomainName, peUse ); } typedef BOOL WINAPI FN_LookupAccountSidW( LPCWSTR lpSystemName, PSID Sid, LPWSTR Name, LPDWORD cchName, LPWSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, PSID_NAME_USE peUse ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_LookupAccountSidW( LPCWSTR lpSystemName, PSID Sid, LPWSTR Name, LPDWORD cchName, LPWSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, PSID_NAME_USE peUse ) { static FN_LookupAccountSidW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LookupAccountSidW", &g_Kernel32); return pfn( lpSystemName, Sid, Name, cchName, ReferencedDomainName, cchReferencedDomainName, peUse ); } typedef BOOL WINAPI FN_LookupAccountNameA( LPCSTR lpSystemName, LPCSTR lpAccountName, PSID Sid, LPDWORD cbSid, LPSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, PSID_NAME_USE peUse ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_LookupAccountNameA( LPCSTR lpSystemName, LPCSTR lpAccountName, PSID Sid, LPDWORD cbSid, LPSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, PSID_NAME_USE peUse ) { static FN_LookupAccountNameA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LookupAccountNameA", &g_Kernel32); return pfn( lpSystemName, lpAccountName, Sid, cbSid, ReferencedDomainName, cchReferencedDomainName, peUse ); } typedef BOOL WINAPI FN_LookupAccountNameW( LPCWSTR lpSystemName, LPCWSTR lpAccountName, PSID Sid, LPDWORD cbSid, LPWSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, PSID_NAME_USE peUse ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_LookupAccountNameW( LPCWSTR lpSystemName, LPCWSTR lpAccountName, PSID Sid, LPDWORD cbSid, LPWSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, PSID_NAME_USE peUse ) { static FN_LookupAccountNameW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LookupAccountNameW", &g_Kernel32); return pfn( lpSystemName, lpAccountName, Sid, cbSid, ReferencedDomainName, cchReferencedDomainName, peUse ); } typedef BOOL WINAPI FN_LookupPrivilegeValueA( LPCSTR lpSystemName, LPCSTR lpName, PLUID lpLuid ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_LookupPrivilegeValueA( LPCSTR lpSystemName, LPCSTR lpName, PLUID lpLuid ) { static FN_LookupPrivilegeValueA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LookupPrivilegeValueA", &g_Kernel32); return pfn( lpSystemName, lpName, lpLuid ); } typedef BOOL WINAPI FN_LookupPrivilegeValueW( LPCWSTR lpSystemName, LPCWSTR lpName, PLUID lpLuid ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_LookupPrivilegeValueW( LPCWSTR lpSystemName, LPCWSTR lpName, PLUID lpLuid ) { static FN_LookupPrivilegeValueW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LookupPrivilegeValueW", &g_Kernel32); return pfn( lpSystemName, lpName, lpLuid ); } typedef BOOL WINAPI FN_LookupPrivilegeNameA( LPCSTR lpSystemName, PLUID lpLuid, LPSTR lpName, LPDWORD cchName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_LookupPrivilegeNameA( LPCSTR lpSystemName, PLUID lpLuid, LPSTR lpName, LPDWORD cchName ) { static FN_LookupPrivilegeNameA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LookupPrivilegeNameA", &g_Kernel32); return pfn( lpSystemName, lpLuid, lpName, cchName ); } typedef BOOL WINAPI FN_LookupPrivilegeNameW( LPCWSTR lpSystemName, PLUID lpLuid, LPWSTR lpName, LPDWORD cchName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_LookupPrivilegeNameW( LPCWSTR lpSystemName, PLUID lpLuid, LPWSTR lpName, LPDWORD cchName ) { static FN_LookupPrivilegeNameW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LookupPrivilegeNameW", &g_Kernel32); return pfn( lpSystemName, lpLuid, lpName, cchName ); } typedef BOOL WINAPI FN_LookupPrivilegeDisplayNameA( LPCSTR lpSystemName, LPCSTR lpName, LPSTR lpDisplayName, LPDWORD cchDisplayName, LPDWORD lpLanguageId ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_LookupPrivilegeDisplayNameA( LPCSTR lpSystemName, LPCSTR lpName, LPSTR lpDisplayName, LPDWORD cchDisplayName, LPDWORD lpLanguageId ) { static FN_LookupPrivilegeDisplayNameA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LookupPrivilegeDisplayNameA", &g_Kernel32); return pfn( lpSystemName, lpName, lpDisplayName, cchDisplayName, lpLanguageId ); } typedef BOOL WINAPI FN_LookupPrivilegeDisplayNameW( LPCWSTR lpSystemName, LPCWSTR lpName, LPWSTR lpDisplayName, LPDWORD cchDisplayName, LPDWORD lpLanguageId ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_LookupPrivilegeDisplayNameW( LPCWSTR lpSystemName, LPCWSTR lpName, LPWSTR lpDisplayName, LPDWORD cchDisplayName, LPDWORD lpLanguageId ) { static FN_LookupPrivilegeDisplayNameW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LookupPrivilegeDisplayNameW", &g_Kernel32); return pfn( lpSystemName, lpName, lpDisplayName, cchDisplayName, lpLanguageId ); } typedef BOOL WINAPI FN_AllocateLocallyUniqueId( PLUID Luid ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AllocateLocallyUniqueId( PLUID Luid ) { static FN_AllocateLocallyUniqueId *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AllocateLocallyUniqueId", &g_Kernel32); return pfn( Luid ); } typedef BOOL WINAPI FN_BuildCommDCBA( LPCSTR lpDef, LPDCB lpDCB ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_BuildCommDCBA( LPCSTR lpDef, LPDCB lpDCB ) { static FN_BuildCommDCBA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "BuildCommDCBA", &g_Kernel32); return pfn( lpDef, lpDCB ); } typedef BOOL WINAPI FN_BuildCommDCBW( LPCWSTR lpDef, LPDCB lpDCB ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_BuildCommDCBW( LPCWSTR lpDef, LPDCB lpDCB ) { static FN_BuildCommDCBW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "BuildCommDCBW", &g_Kernel32); return pfn( lpDef, lpDCB ); } typedef BOOL WINAPI FN_BuildCommDCBAndTimeoutsA( LPCSTR lpDef, LPDCB lpDCB, LPCOMMTIMEOUTS lpCommTimeouts ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_BuildCommDCBAndTimeoutsA( LPCSTR lpDef, LPDCB lpDCB, LPCOMMTIMEOUTS lpCommTimeouts ) { static FN_BuildCommDCBAndTimeoutsA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "BuildCommDCBAndTimeoutsA", &g_Kernel32); return pfn( lpDef, lpDCB, lpCommTimeouts ); } typedef BOOL WINAPI FN_BuildCommDCBAndTimeoutsW( LPCWSTR lpDef, LPDCB lpDCB, LPCOMMTIMEOUTS lpCommTimeouts ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_BuildCommDCBAndTimeoutsW( LPCWSTR lpDef, LPDCB lpDCB, LPCOMMTIMEOUTS lpCommTimeouts ) { static FN_BuildCommDCBAndTimeoutsW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "BuildCommDCBAndTimeoutsW", &g_Kernel32); return pfn( lpDef, lpDCB, lpCommTimeouts ); } typedef BOOL WINAPI FN_CommConfigDialogA( LPCSTR lpszName, HWND hWnd, LPCOMMCONFIG lpCC ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CommConfigDialogA( LPCSTR lpszName, HWND hWnd, LPCOMMCONFIG lpCC ) { static FN_CommConfigDialogA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CommConfigDialogA", &g_Kernel32); return pfn( lpszName, hWnd, lpCC ); } typedef BOOL WINAPI FN_CommConfigDialogW( LPCWSTR lpszName, HWND hWnd, LPCOMMCONFIG lpCC ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CommConfigDialogW( LPCWSTR lpszName, HWND hWnd, LPCOMMCONFIG lpCC ) { static FN_CommConfigDialogW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CommConfigDialogW", &g_Kernel32); return pfn( lpszName, hWnd, lpCC ); } typedef BOOL WINAPI FN_GetDefaultCommConfigA( LPCSTR lpszName, LPCOMMCONFIG lpCC, LPDWORD lpdwSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetDefaultCommConfigA( LPCSTR lpszName, LPCOMMCONFIG lpCC, LPDWORD lpdwSize ) { static FN_GetDefaultCommConfigA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetDefaultCommConfigA", &g_Kernel32); return pfn( lpszName, lpCC, lpdwSize ); } typedef BOOL WINAPI FN_GetDefaultCommConfigW( LPCWSTR lpszName, LPCOMMCONFIG lpCC, LPDWORD lpdwSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetDefaultCommConfigW( LPCWSTR lpszName, LPCOMMCONFIG lpCC, LPDWORD lpdwSize ) { static FN_GetDefaultCommConfigW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetDefaultCommConfigW", &g_Kernel32); return pfn( lpszName, lpCC, lpdwSize ); } typedef BOOL WINAPI FN_SetDefaultCommConfigA( LPCSTR lpszName, LPCOMMCONFIG lpCC, DWORD dwSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetDefaultCommConfigA( LPCSTR lpszName, LPCOMMCONFIG lpCC, DWORD dwSize ) { static FN_SetDefaultCommConfigA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetDefaultCommConfigA", &g_Kernel32); return pfn( lpszName, lpCC, dwSize ); } typedef BOOL WINAPI FN_SetDefaultCommConfigW( LPCWSTR lpszName, LPCOMMCONFIG lpCC, DWORD dwSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetDefaultCommConfigW( LPCWSTR lpszName, LPCOMMCONFIG lpCC, DWORD dwSize ) { static FN_SetDefaultCommConfigW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetDefaultCommConfigW", &g_Kernel32); return pfn( lpszName, lpCC, dwSize ); } typedef BOOL WINAPI FN_GetComputerNameA( LPSTR lpBuffer, LPDWORD nSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetComputerNameA( LPSTR lpBuffer, LPDWORD nSize ) { static FN_GetComputerNameA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetComputerNameA", &g_Kernel32); return pfn( lpBuffer, nSize ); } typedef BOOL WINAPI FN_GetComputerNameW( LPWSTR lpBuffer, LPDWORD nSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetComputerNameW( LPWSTR lpBuffer, LPDWORD nSize ) { static FN_GetComputerNameW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetComputerNameW", &g_Kernel32); return pfn( lpBuffer, nSize ); } typedef BOOL WINAPI FN_SetComputerNameA( LPCSTR lpComputerName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetComputerNameA( LPCSTR lpComputerName ) { static FN_SetComputerNameA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetComputerNameA", &g_Kernel32); return pfn( lpComputerName ); } typedef BOOL WINAPI FN_SetComputerNameW( LPCWSTR lpComputerName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetComputerNameW( LPCWSTR lpComputerName ) { static FN_SetComputerNameW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetComputerNameW", &g_Kernel32); return pfn( lpComputerName ); } typedef BOOL WINAPI FN_GetComputerNameExA( COMPUTER_NAME_FORMAT NameType, LPSTR lpBuffer, LPDWORD nSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetComputerNameExA( COMPUTER_NAME_FORMAT NameType, LPSTR lpBuffer, LPDWORD nSize ) { static FN_GetComputerNameExA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetComputerNameExA", &g_Kernel32); return pfn( NameType, lpBuffer, nSize ); } typedef BOOL WINAPI FN_GetComputerNameExW( COMPUTER_NAME_FORMAT NameType, LPWSTR lpBuffer, LPDWORD nSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetComputerNameExW( COMPUTER_NAME_FORMAT NameType, LPWSTR lpBuffer, LPDWORD nSize ) { static FN_GetComputerNameExW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetComputerNameExW", &g_Kernel32); return pfn( NameType, lpBuffer, nSize ); } typedef BOOL WINAPI FN_SetComputerNameExA( COMPUTER_NAME_FORMAT NameType, LPCSTR lpBuffer ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetComputerNameExA( COMPUTER_NAME_FORMAT NameType, LPCSTR lpBuffer ) { static FN_SetComputerNameExA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetComputerNameExA", &g_Kernel32); return pfn( NameType, lpBuffer ); } typedef BOOL WINAPI FN_SetComputerNameExW( COMPUTER_NAME_FORMAT NameType, LPCWSTR lpBuffer ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetComputerNameExW( COMPUTER_NAME_FORMAT NameType, LPCWSTR lpBuffer ) { static FN_SetComputerNameExW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetComputerNameExW", &g_Kernel32); return pfn( NameType, lpBuffer ); } typedef BOOL WINAPI FN_DnsHostnameToComputerNameA( LPCSTR Hostname, LPSTR ComputerName, LPDWORD nSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_DnsHostnameToComputerNameA( LPCSTR Hostname, LPSTR ComputerName, LPDWORD nSize ) { static FN_DnsHostnameToComputerNameA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DnsHostnameToComputerNameA", &g_Kernel32); return pfn( Hostname, ComputerName, nSize ); } typedef BOOL WINAPI FN_DnsHostnameToComputerNameW( LPCWSTR Hostname, LPWSTR ComputerName, LPDWORD nSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_DnsHostnameToComputerNameW( LPCWSTR Hostname, LPWSTR ComputerName, LPDWORD nSize ) { static FN_DnsHostnameToComputerNameW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DnsHostnameToComputerNameW", &g_Kernel32); return pfn( Hostname, ComputerName, nSize ); } typedef BOOL WINAPI FN_GetUserNameA( LPSTR lpBuffer, LPDWORD pcbBuffer ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetUserNameA( LPSTR lpBuffer, LPDWORD pcbBuffer ) { static FN_GetUserNameA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetUserNameA", &g_Kernel32); return pfn( lpBuffer, pcbBuffer ); } typedef BOOL WINAPI FN_GetUserNameW( LPWSTR lpBuffer, LPDWORD pcbBuffer ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetUserNameW( LPWSTR lpBuffer, LPDWORD pcbBuffer ) { static FN_GetUserNameW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetUserNameW", &g_Kernel32); return pfn( lpBuffer, pcbBuffer ); } typedef BOOL WINAPI FN_LogonUserA( LPCSTR lpszUsername, LPCSTR lpszDomain, LPCSTR lpszPassword, DWORD dwLogonType, DWORD dwLogonProvider, PHANDLE phToken ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_LogonUserA( LPCSTR lpszUsername, LPCSTR lpszDomain, LPCSTR lpszPassword, DWORD dwLogonType, DWORD dwLogonProvider, PHANDLE phToken ) { static FN_LogonUserA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LogonUserA", &g_Kernel32); return pfn( lpszUsername, lpszDomain, lpszPassword, dwLogonType, dwLogonProvider, phToken ); } typedef BOOL WINAPI FN_LogonUserW( LPCWSTR lpszUsername, LPCWSTR lpszDomain, LPCWSTR lpszPassword, DWORD dwLogonType, DWORD dwLogonProvider, PHANDLE phToken ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_LogonUserW( LPCWSTR lpszUsername, LPCWSTR lpszDomain, LPCWSTR lpszPassword, DWORD dwLogonType, DWORD dwLogonProvider, PHANDLE phToken ) { static FN_LogonUserW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LogonUserW", &g_Kernel32); return pfn( lpszUsername, lpszDomain, lpszPassword, dwLogonType, dwLogonProvider, phToken ); } typedef BOOL WINAPI FN_LogonUserExA( LPCSTR lpszUsername, LPCSTR lpszDomain, LPCSTR lpszPassword, DWORD dwLogonType, DWORD dwLogonProvider, PHANDLE phToken, PSID * ppLogonSid, PVOID * ppProfileBuffer, LPDWORD pdwProfileLength, PQUOTA_LIMITS pQuotaLimits ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_LogonUserExA( LPCSTR lpszUsername, LPCSTR lpszDomain, LPCSTR lpszPassword, DWORD dwLogonType, DWORD dwLogonProvider, PHANDLE phToken, PSID * ppLogonSid, PVOID * ppProfileBuffer, LPDWORD pdwProfileLength, PQUOTA_LIMITS pQuotaLimits ) { static FN_LogonUserExA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LogonUserExA", &g_Kernel32); return pfn( lpszUsername, lpszDomain, lpszPassword, dwLogonType, dwLogonProvider, phToken, ppLogonSid, ppProfileBuffer, pdwProfileLength, pQuotaLimits ); } typedef BOOL WINAPI FN_LogonUserExW( LPCWSTR lpszUsername, LPCWSTR lpszDomain, LPCWSTR lpszPassword, DWORD dwLogonType, DWORD dwLogonProvider, PHANDLE phToken, PSID * ppLogonSid, PVOID * ppProfileBuffer, LPDWORD pdwProfileLength, PQUOTA_LIMITS pQuotaLimits ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_LogonUserExW( LPCWSTR lpszUsername, LPCWSTR lpszDomain, LPCWSTR lpszPassword, DWORD dwLogonType, DWORD dwLogonProvider, PHANDLE phToken, PSID * ppLogonSid, PVOID * ppProfileBuffer, LPDWORD pdwProfileLength, PQUOTA_LIMITS pQuotaLimits ) { static FN_LogonUserExW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LogonUserExW", &g_Kernel32); return pfn( lpszUsername, lpszDomain, lpszPassword, dwLogonType, dwLogonProvider, phToken, ppLogonSid, ppProfileBuffer, pdwProfileLength, pQuotaLimits ); } typedef BOOL WINAPI FN_ImpersonateLoggedOnUser( HANDLE hToken ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ImpersonateLoggedOnUser( HANDLE hToken ) { static FN_ImpersonateLoggedOnUser *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ImpersonateLoggedOnUser", &g_Kernel32); return pfn( hToken ); } typedef BOOL WINAPI FN_CreateProcessAsUserA( HANDLE hToken, LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateProcessAsUserA( HANDLE hToken, LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ) { static FN_CreateProcessAsUserA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateProcessAsUserA", &g_Kernel32); return pfn( hToken, lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation ); } typedef BOOL WINAPI FN_CreateProcessAsUserW( HANDLE hToken, LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateProcessAsUserW( HANDLE hToken, LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ) { static FN_CreateProcessAsUserW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateProcessAsUserW", &g_Kernel32); return pfn( hToken, lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation ); } typedef BOOL WINAPI FN_CreateProcessWithLogonW( LPCWSTR lpUsername, LPCWSTR lpDomain, LPCWSTR lpPassword, DWORD dwLogonFlags, LPCWSTR lpApplicationName, LPWSTR lpCommandLine, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateProcessWithLogonW( LPCWSTR lpUsername, LPCWSTR lpDomain, LPCWSTR lpPassword, DWORD dwLogonFlags, LPCWSTR lpApplicationName, LPWSTR lpCommandLine, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ) { static FN_CreateProcessWithLogonW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateProcessWithLogonW", &g_Kernel32); return pfn( lpUsername, lpDomain, lpPassword, dwLogonFlags, lpApplicationName, lpCommandLine, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation ); } typedef BOOL WINAPI FN_CreateProcessWithTokenW( HANDLE hToken, DWORD dwLogonFlags, LPCWSTR lpApplicationName, LPWSTR lpCommandLine, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateProcessWithTokenW( HANDLE hToken, DWORD dwLogonFlags, LPCWSTR lpApplicationName, LPWSTR lpCommandLine, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ) { static FN_CreateProcessWithTokenW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateProcessWithTokenW", &g_Kernel32); return pfn( hToken, dwLogonFlags, lpApplicationName, lpCommandLine, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation ); } typedef BOOL APIENTRY FN_ImpersonateAnonymousToken( HANDLE ThreadHandle ); __declspec(dllexport) BOOL APIENTRY kPrf2Wrap_ImpersonateAnonymousToken( HANDLE ThreadHandle ) { static FN_ImpersonateAnonymousToken *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ImpersonateAnonymousToken", &g_Kernel32); return pfn( ThreadHandle ); } typedef BOOL WINAPI FN_DuplicateTokenEx( HANDLE hExistingToken, DWORD dwDesiredAccess, LPSECURITY_ATTRIBUTES lpTokenAttributes, SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, TOKEN_TYPE TokenType, PHANDLE phNewToken ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_DuplicateTokenEx( HANDLE hExistingToken, DWORD dwDesiredAccess, LPSECURITY_ATTRIBUTES lpTokenAttributes, SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, TOKEN_TYPE TokenType, PHANDLE phNewToken ) { static FN_DuplicateTokenEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DuplicateTokenEx", &g_Kernel32); return pfn( hExistingToken, dwDesiredAccess, lpTokenAttributes, ImpersonationLevel, TokenType, phNewToken ); } typedef BOOL APIENTRY FN_CreateRestrictedToken( HANDLE ExistingTokenHandle, DWORD Flags, DWORD DisableSidCount, PSID_AND_ATTRIBUTES SidsToDisable, DWORD DeletePrivilegeCount, PLUID_AND_ATTRIBUTES PrivilegesToDelete, DWORD RestrictedSidCount, PSID_AND_ATTRIBUTES SidsToRestrict, PHANDLE NewTokenHandle ); __declspec(dllexport) BOOL APIENTRY kPrf2Wrap_CreateRestrictedToken( HANDLE ExistingTokenHandle, DWORD Flags, DWORD DisableSidCount, PSID_AND_ATTRIBUTES SidsToDisable, DWORD DeletePrivilegeCount, PLUID_AND_ATTRIBUTES PrivilegesToDelete, DWORD RestrictedSidCount, PSID_AND_ATTRIBUTES SidsToRestrict, PHANDLE NewTokenHandle ) { static FN_CreateRestrictedToken *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateRestrictedToken", &g_Kernel32); return pfn( ExistingTokenHandle, Flags, DisableSidCount, SidsToDisable, DeletePrivilegeCount, PrivilegesToDelete, RestrictedSidCount, SidsToRestrict, NewTokenHandle ); } typedef BOOL WINAPI FN_IsTokenRestricted( HANDLE TokenHandle ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsTokenRestricted( HANDLE TokenHandle ) { static FN_IsTokenRestricted *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "IsTokenRestricted", &g_Kernel32); return pfn( TokenHandle ); } typedef BOOL WINAPI FN_IsTokenUntrusted( HANDLE TokenHandle ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsTokenUntrusted( HANDLE TokenHandle ) { static FN_IsTokenUntrusted *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "IsTokenUntrusted", &g_Kernel32); return pfn( TokenHandle ); } typedef BOOL APIENTRY FN_CheckTokenMembership( HANDLE TokenHandle, PSID SidToCheck, PBOOL IsMember ); __declspec(dllexport) BOOL APIENTRY kPrf2Wrap_CheckTokenMembership( HANDLE TokenHandle, PSID SidToCheck, PBOOL IsMember ) { static FN_CheckTokenMembership *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CheckTokenMembership", &g_Kernel32); return pfn( TokenHandle, SidToCheck, IsMember ); } typedef BOOL WINAPI FN_RegisterWaitForSingleObject( PHANDLE phNewWaitObject, HANDLE hObject, WAITORTIMERCALLBACK Callback, PVOID Context, ULONG dwMilliseconds, ULONG dwFlags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_RegisterWaitForSingleObject( PHANDLE phNewWaitObject, HANDLE hObject, WAITORTIMERCALLBACK Callback, PVOID Context, ULONG dwMilliseconds, ULONG dwFlags ) { static FN_RegisterWaitForSingleObject *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RegisterWaitForSingleObject", &g_Kernel32); return pfn( phNewWaitObject, hObject, Callback, Context, dwMilliseconds, dwFlags ); } typedef HANDLE WINAPI FN_RegisterWaitForSingleObjectEx( HANDLE hObject, WAITORTIMERCALLBACK Callback, PVOID Context, ULONG dwMilliseconds, ULONG dwFlags ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_RegisterWaitForSingleObjectEx( HANDLE hObject, WAITORTIMERCALLBACK Callback, PVOID Context, ULONG dwMilliseconds, ULONG dwFlags ) { static FN_RegisterWaitForSingleObjectEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RegisterWaitForSingleObjectEx", &g_Kernel32); return pfn( hObject, Callback, Context, dwMilliseconds, dwFlags ); } typedef BOOL WINAPI FN_UnregisterWait( HANDLE WaitHandle ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_UnregisterWait( HANDLE WaitHandle ) { static FN_UnregisterWait *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "UnregisterWait", &g_Kernel32); return pfn( WaitHandle ); } typedef BOOL WINAPI FN_UnregisterWaitEx( HANDLE WaitHandle, HANDLE CompletionEvent ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_UnregisterWaitEx( HANDLE WaitHandle, HANDLE CompletionEvent ) { static FN_UnregisterWaitEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "UnregisterWaitEx", &g_Kernel32); return pfn( WaitHandle, CompletionEvent ); } typedef BOOL WINAPI FN_QueueUserWorkItem( LPTHREAD_START_ROUTINE Function, PVOID Context, ULONG Flags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_QueueUserWorkItem( LPTHREAD_START_ROUTINE Function, PVOID Context, ULONG Flags ) { static FN_QueueUserWorkItem *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "QueueUserWorkItem", &g_Kernel32); return pfn( Function, Context, Flags ); } typedef BOOL WINAPI FN_BindIoCompletionCallback( HANDLE FileHandle, LPOVERLAPPED_COMPLETION_ROUTINE Function, ULONG Flags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_BindIoCompletionCallback( HANDLE FileHandle, LPOVERLAPPED_COMPLETION_ROUTINE Function, ULONG Flags ) { static FN_BindIoCompletionCallback *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "BindIoCompletionCallback", &g_Kernel32); return pfn( FileHandle, Function, Flags ); } typedef HANDLE WINAPI FN_CreateTimerQueue( VOID ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateTimerQueue( VOID ) { static FN_CreateTimerQueue *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateTimerQueue", &g_Kernel32); return pfn (); } typedef BOOL WINAPI FN_CreateTimerQueueTimer( PHANDLE phNewTimer, HANDLE TimerQueue, WAITORTIMERCALLBACK Callback, PVOID Parameter, DWORD DueTime, DWORD Period, ULONG Flags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateTimerQueueTimer( PHANDLE phNewTimer, HANDLE TimerQueue, WAITORTIMERCALLBACK Callback, PVOID Parameter, DWORD DueTime, DWORD Period, ULONG Flags ) { static FN_CreateTimerQueueTimer *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateTimerQueueTimer", &g_Kernel32); return pfn( phNewTimer, TimerQueue, Callback, Parameter, DueTime, Period, Flags ); } typedef BOOL WINAPI FN_ChangeTimerQueueTimer( HANDLE TimerQueue, HANDLE Timer, ULONG DueTime, ULONG Period ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ChangeTimerQueueTimer( HANDLE TimerQueue, HANDLE Timer, ULONG DueTime, ULONG Period ) { static FN_ChangeTimerQueueTimer *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ChangeTimerQueueTimer", &g_Kernel32); return pfn( TimerQueue, Timer, DueTime, Period ); } typedef BOOL WINAPI FN_DeleteTimerQueueTimer( HANDLE TimerQueue, HANDLE Timer, HANDLE CompletionEvent ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_DeleteTimerQueueTimer( HANDLE TimerQueue, HANDLE Timer, HANDLE CompletionEvent ) { static FN_DeleteTimerQueueTimer *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DeleteTimerQueueTimer", &g_Kernel32); return pfn( TimerQueue, Timer, CompletionEvent ); } typedef BOOL WINAPI FN_DeleteTimerQueueEx( HANDLE TimerQueue, HANDLE CompletionEvent ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_DeleteTimerQueueEx( HANDLE TimerQueue, HANDLE CompletionEvent ) { static FN_DeleteTimerQueueEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DeleteTimerQueueEx", &g_Kernel32); return pfn( TimerQueue, CompletionEvent ); } typedef HANDLE WINAPI FN_SetTimerQueueTimer( HANDLE TimerQueue, WAITORTIMERCALLBACK Callback, PVOID Parameter, DWORD DueTime, DWORD Period, BOOL PreferIo ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_SetTimerQueueTimer( HANDLE TimerQueue, WAITORTIMERCALLBACK Callback, PVOID Parameter, DWORD DueTime, DWORD Period, BOOL PreferIo ) { static FN_SetTimerQueueTimer *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetTimerQueueTimer", &g_Kernel32); return pfn( TimerQueue, Callback, Parameter, DueTime, Period, PreferIo ); } typedef BOOL WINAPI FN_CancelTimerQueueTimer( HANDLE TimerQueue, HANDLE Timer ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CancelTimerQueueTimer( HANDLE TimerQueue, HANDLE Timer ) { static FN_CancelTimerQueueTimer *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CancelTimerQueueTimer", &g_Kernel32); return pfn( TimerQueue, Timer ); } typedef BOOL WINAPI FN_DeleteTimerQueue( HANDLE TimerQueue ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_DeleteTimerQueue( HANDLE TimerQueue ) { static FN_DeleteTimerQueue *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DeleteTimerQueue", &g_Kernel32); return pfn( TimerQueue ); } typedef BOOL WINAPI FN_GetCurrentHwProfileA( LPHW_PROFILE_INFOA lpHwProfileInfo ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetCurrentHwProfileA( LPHW_PROFILE_INFOA lpHwProfileInfo ) { static FN_GetCurrentHwProfileA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetCurrentHwProfileA", &g_Kernel32); return pfn( lpHwProfileInfo ); } typedef BOOL WINAPI FN_GetCurrentHwProfileW( LPHW_PROFILE_INFOW lpHwProfileInfo ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetCurrentHwProfileW( LPHW_PROFILE_INFOW lpHwProfileInfo ) { static FN_GetCurrentHwProfileW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetCurrentHwProfileW", &g_Kernel32); return pfn( lpHwProfileInfo ); } typedef BOOL WINAPI FN_QueryPerformanceCounter( LARGE_INTEGER * lpPerformanceCount ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_QueryPerformanceCounter( LARGE_INTEGER * lpPerformanceCount ) { static FN_QueryPerformanceCounter *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "QueryPerformanceCounter", &g_Kernel32); return pfn( lpPerformanceCount ); } typedef BOOL WINAPI FN_QueryPerformanceFrequency( LARGE_INTEGER * lpFrequency ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_QueryPerformanceFrequency( LARGE_INTEGER * lpFrequency ) { static FN_QueryPerformanceFrequency *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "QueryPerformanceFrequency", &g_Kernel32); return pfn( lpFrequency ); } typedef BOOL WINAPI FN_GetVersionExA( LPOSVERSIONINFOA lpVersionInformation ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetVersionExA( LPOSVERSIONINFOA lpVersionInformation ) { static FN_GetVersionExA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetVersionExA", &g_Kernel32); return pfn( lpVersionInformation ); } typedef BOOL WINAPI FN_GetVersionExW( LPOSVERSIONINFOW lpVersionInformation ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetVersionExW( LPOSVERSIONINFOW lpVersionInformation ) { static FN_GetVersionExW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetVersionExW", &g_Kernel32); return pfn( lpVersionInformation ); } typedef BOOL WINAPI FN_VerifyVersionInfoA( LPOSVERSIONINFOEXA lpVersionInformation, DWORD dwTypeMask, DWORDLONG dwlConditionMask ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_VerifyVersionInfoA( LPOSVERSIONINFOEXA lpVersionInformation, DWORD dwTypeMask, DWORDLONG dwlConditionMask ) { static FN_VerifyVersionInfoA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "VerifyVersionInfoA", &g_Kernel32); return pfn( lpVersionInformation, dwTypeMask, dwlConditionMask ); } typedef BOOL WINAPI FN_VerifyVersionInfoW( LPOSVERSIONINFOEXW lpVersionInformation, DWORD dwTypeMask, DWORDLONG dwlConditionMask ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_VerifyVersionInfoW( LPOSVERSIONINFOEXW lpVersionInformation, DWORD dwTypeMask, DWORDLONG dwlConditionMask ) { static FN_VerifyVersionInfoW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "VerifyVersionInfoW", &g_Kernel32); return pfn( lpVersionInformation, dwTypeMask, dwlConditionMask ); } typedef BOOL WINAPI FN_GetSystemPowerStatus( LPSYSTEM_POWER_STATUS lpSystemPowerStatus ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetSystemPowerStatus( LPSYSTEM_POWER_STATUS lpSystemPowerStatus ) { static FN_GetSystemPowerStatus *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSystemPowerStatus", &g_Kernel32); return pfn( lpSystemPowerStatus ); } typedef BOOL WINAPI FN_SetSystemPowerState( BOOL fSuspend, BOOL fForce ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetSystemPowerState( BOOL fSuspend, BOOL fForce ) { static FN_SetSystemPowerState *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetSystemPowerState", &g_Kernel32); return pfn( fSuspend, fForce ); } typedef BOOL WINAPI FN_AllocateUserPhysicalPages( HANDLE hProcess, PULONG_PTR NumberOfPages, PULONG_PTR PageArray ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AllocateUserPhysicalPages( HANDLE hProcess, PULONG_PTR NumberOfPages, PULONG_PTR PageArray ) { static FN_AllocateUserPhysicalPages *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AllocateUserPhysicalPages", &g_Kernel32); return pfn( hProcess, NumberOfPages, PageArray ); } typedef BOOL WINAPI FN_FreeUserPhysicalPages( HANDLE hProcess, PULONG_PTR NumberOfPages, PULONG_PTR PageArray ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FreeUserPhysicalPages( HANDLE hProcess, PULONG_PTR NumberOfPages, PULONG_PTR PageArray ) { static FN_FreeUserPhysicalPages *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FreeUserPhysicalPages", &g_Kernel32); return pfn( hProcess, NumberOfPages, PageArray ); } typedef BOOL WINAPI FN_MapUserPhysicalPages( PVOID VirtualAddress, ULONG_PTR NumberOfPages, PULONG_PTR PageArray ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_MapUserPhysicalPages( PVOID VirtualAddress, ULONG_PTR NumberOfPages, PULONG_PTR PageArray ) { static FN_MapUserPhysicalPages *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "MapUserPhysicalPages", &g_Kernel32); return pfn( VirtualAddress, NumberOfPages, PageArray ); } typedef BOOL WINAPI FN_MapUserPhysicalPagesScatter( PVOID * VirtualAddresses, ULONG_PTR NumberOfPages, PULONG_PTR PageArray ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_MapUserPhysicalPagesScatter( PVOID * VirtualAddresses, ULONG_PTR NumberOfPages, PULONG_PTR PageArray ) { static FN_MapUserPhysicalPagesScatter *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "MapUserPhysicalPagesScatter", &g_Kernel32); return pfn( VirtualAddresses, NumberOfPages, PageArray ); } typedef HANDLE WINAPI FN_CreateJobObjectA( LPSECURITY_ATTRIBUTES lpJobAttributes, LPCSTR lpName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateJobObjectA( LPSECURITY_ATTRIBUTES lpJobAttributes, LPCSTR lpName ) { static FN_CreateJobObjectA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateJobObjectA", &g_Kernel32); return pfn( lpJobAttributes, lpName ); } typedef HANDLE WINAPI FN_CreateJobObjectW( LPSECURITY_ATTRIBUTES lpJobAttributes, LPCWSTR lpName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateJobObjectW( LPSECURITY_ATTRIBUTES lpJobAttributes, LPCWSTR lpName ) { static FN_CreateJobObjectW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateJobObjectW", &g_Kernel32); return pfn( lpJobAttributes, lpName ); } typedef HANDLE WINAPI FN_OpenJobObjectA( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenJobObjectA( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName ) { static FN_OpenJobObjectA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "OpenJobObjectA", &g_Kernel32); return pfn( dwDesiredAccess, bInheritHandle, lpName ); } typedef HANDLE WINAPI FN_OpenJobObjectW( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_OpenJobObjectW( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName ) { static FN_OpenJobObjectW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "OpenJobObjectW", &g_Kernel32); return pfn( dwDesiredAccess, bInheritHandle, lpName ); } typedef BOOL WINAPI FN_AssignProcessToJobObject( HANDLE hJob, HANDLE hProcess ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AssignProcessToJobObject( HANDLE hJob, HANDLE hProcess ) { static FN_AssignProcessToJobObject *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AssignProcessToJobObject", &g_Kernel32); return pfn( hJob, hProcess ); } typedef BOOL WINAPI FN_TerminateJobObject( HANDLE hJob, UINT uExitCode ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_TerminateJobObject( HANDLE hJob, UINT uExitCode ) { static FN_TerminateJobObject *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "TerminateJobObject", &g_Kernel32); return pfn( hJob, uExitCode ); } typedef BOOL WINAPI FN_QueryInformationJobObject( HANDLE hJob, JOBOBJECTINFOCLASS JobObjectInformationClass, LPVOID lpJobObjectInformation, DWORD cbJobObjectInformationLength, LPDWORD lpReturnLength ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_QueryInformationJobObject( HANDLE hJob, JOBOBJECTINFOCLASS JobObjectInformationClass, LPVOID lpJobObjectInformation, DWORD cbJobObjectInformationLength, LPDWORD lpReturnLength ) { static FN_QueryInformationJobObject *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "QueryInformationJobObject", &g_Kernel32); return pfn( hJob, JobObjectInformationClass, lpJobObjectInformation, cbJobObjectInformationLength, lpReturnLength ); } typedef BOOL WINAPI FN_SetInformationJobObject( HANDLE hJob, JOBOBJECTINFOCLASS JobObjectInformationClass, LPVOID lpJobObjectInformation, DWORD cbJobObjectInformationLength ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetInformationJobObject( HANDLE hJob, JOBOBJECTINFOCLASS JobObjectInformationClass, LPVOID lpJobObjectInformation, DWORD cbJobObjectInformationLength ) { static FN_SetInformationJobObject *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetInformationJobObject", &g_Kernel32); return pfn( hJob, JobObjectInformationClass, lpJobObjectInformation, cbJobObjectInformationLength ); } typedef BOOL WINAPI FN_IsProcessInJob( HANDLE ProcessHandle, HANDLE JobHandle, PBOOL Result ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsProcessInJob( HANDLE ProcessHandle, HANDLE JobHandle, PBOOL Result ) { static FN_IsProcessInJob *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "IsProcessInJob", &g_Kernel32); return pfn( ProcessHandle, JobHandle, Result ); } typedef BOOL WINAPI FN_CreateJobSet( ULONG NumJob, PJOB_SET_ARRAY UserJobSet, ULONG Flags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_CreateJobSet( ULONG NumJob, PJOB_SET_ARRAY UserJobSet, ULONG Flags ) { static FN_CreateJobSet *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateJobSet", &g_Kernel32); return pfn( NumJob, UserJobSet, Flags ); } typedef PVOID WINAPI FN_AddVectoredExceptionHandler( ULONG First, PVECTORED_EXCEPTION_HANDLER Handler ); __declspec(dllexport) PVOID WINAPI kPrf2Wrap_AddVectoredExceptionHandler( ULONG First, PVECTORED_EXCEPTION_HANDLER Handler ) { static FN_AddVectoredExceptionHandler *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AddVectoredExceptionHandler", &g_Kernel32); return pfn( First, Handler ); } typedef ULONG WINAPI FN_RemoveVectoredExceptionHandler( PVOID Handle ); __declspec(dllexport) ULONG WINAPI kPrf2Wrap_RemoveVectoredExceptionHandler( PVOID Handle ) { static FN_RemoveVectoredExceptionHandler *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RemoveVectoredExceptionHandler", &g_Kernel32); return pfn( Handle ); } typedef PVOID WINAPI FN_AddVectoredContinueHandler( ULONG First, PVECTORED_EXCEPTION_HANDLER Handler ); __declspec(dllexport) PVOID WINAPI kPrf2Wrap_AddVectoredContinueHandler( ULONG First, PVECTORED_EXCEPTION_HANDLER Handler ) { static FN_AddVectoredContinueHandler *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AddVectoredContinueHandler", &g_Kernel32); return pfn( First, Handler ); } typedef ULONG WINAPI FN_RemoveVectoredContinueHandler( PVOID Handle ); __declspec(dllexport) ULONG WINAPI kPrf2Wrap_RemoveVectoredContinueHandler( PVOID Handle ) { static FN_RemoveVectoredContinueHandler *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RemoveVectoredContinueHandler", &g_Kernel32); return pfn( Handle ); } typedef HANDLE WINAPI FN_FindFirstVolumeA( LPSTR lpszVolumeName, DWORD cchBufferLength ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_FindFirstVolumeA( LPSTR lpszVolumeName, DWORD cchBufferLength ) { static FN_FindFirstVolumeA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindFirstVolumeA", &g_Kernel32); return pfn( lpszVolumeName, cchBufferLength ); } typedef HANDLE WINAPI FN_FindFirstVolumeW( LPWSTR lpszVolumeName, DWORD cchBufferLength ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_FindFirstVolumeW( LPWSTR lpszVolumeName, DWORD cchBufferLength ) { static FN_FindFirstVolumeW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindFirstVolumeW", &g_Kernel32); return pfn( lpszVolumeName, cchBufferLength ); } typedef BOOL WINAPI FN_FindNextVolumeA( HANDLE hFindVolume, LPSTR lpszVolumeName, DWORD cchBufferLength ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindNextVolumeA( HANDLE hFindVolume, LPSTR lpszVolumeName, DWORD cchBufferLength ) { static FN_FindNextVolumeA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindNextVolumeA", &g_Kernel32); return pfn( hFindVolume, lpszVolumeName, cchBufferLength ); } typedef BOOL WINAPI FN_FindNextVolumeW( HANDLE hFindVolume, LPWSTR lpszVolumeName, DWORD cchBufferLength ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindNextVolumeW( HANDLE hFindVolume, LPWSTR lpszVolumeName, DWORD cchBufferLength ) { static FN_FindNextVolumeW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindNextVolumeW", &g_Kernel32); return pfn( hFindVolume, lpszVolumeName, cchBufferLength ); } typedef BOOL WINAPI FN_FindVolumeClose( HANDLE hFindVolume ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindVolumeClose( HANDLE hFindVolume ) { static FN_FindVolumeClose *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindVolumeClose", &g_Kernel32); return pfn( hFindVolume ); } typedef HANDLE WINAPI FN_FindFirstVolumeMountPointA( LPCSTR lpszRootPathName, LPSTR lpszVolumeMountPoint, DWORD cchBufferLength ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_FindFirstVolumeMountPointA( LPCSTR lpszRootPathName, LPSTR lpszVolumeMountPoint, DWORD cchBufferLength ) { static FN_FindFirstVolumeMountPointA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindFirstVolumeMountPointA", &g_Kernel32); return pfn( lpszRootPathName, lpszVolumeMountPoint, cchBufferLength ); } typedef HANDLE WINAPI FN_FindFirstVolumeMountPointW( LPCWSTR lpszRootPathName, LPWSTR lpszVolumeMountPoint, DWORD cchBufferLength ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_FindFirstVolumeMountPointW( LPCWSTR lpszRootPathName, LPWSTR lpszVolumeMountPoint, DWORD cchBufferLength ) { static FN_FindFirstVolumeMountPointW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindFirstVolumeMountPointW", &g_Kernel32); return pfn( lpszRootPathName, lpszVolumeMountPoint, cchBufferLength ); } typedef BOOL WINAPI FN_FindNextVolumeMountPointA( HANDLE hFindVolumeMountPoint, LPSTR lpszVolumeMountPoint, DWORD cchBufferLength ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindNextVolumeMountPointA( HANDLE hFindVolumeMountPoint, LPSTR lpszVolumeMountPoint, DWORD cchBufferLength ) { static FN_FindNextVolumeMountPointA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindNextVolumeMountPointA", &g_Kernel32); return pfn( hFindVolumeMountPoint, lpszVolumeMountPoint, cchBufferLength ); } typedef BOOL WINAPI FN_FindNextVolumeMountPointW( HANDLE hFindVolumeMountPoint, LPWSTR lpszVolumeMountPoint, DWORD cchBufferLength ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindNextVolumeMountPointW( HANDLE hFindVolumeMountPoint, LPWSTR lpszVolumeMountPoint, DWORD cchBufferLength ) { static FN_FindNextVolumeMountPointW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindNextVolumeMountPointW", &g_Kernel32); return pfn( hFindVolumeMountPoint, lpszVolumeMountPoint, cchBufferLength ); } typedef BOOL WINAPI FN_FindVolumeMountPointClose( HANDLE hFindVolumeMountPoint ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindVolumeMountPointClose( HANDLE hFindVolumeMountPoint ) { static FN_FindVolumeMountPointClose *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindVolumeMountPointClose", &g_Kernel32); return pfn( hFindVolumeMountPoint ); } typedef BOOL WINAPI FN_SetVolumeMountPointA( LPCSTR lpszVolumeMountPoint, LPCSTR lpszVolumeName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetVolumeMountPointA( LPCSTR lpszVolumeMountPoint, LPCSTR lpszVolumeName ) { static FN_SetVolumeMountPointA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetVolumeMountPointA", &g_Kernel32); return pfn( lpszVolumeMountPoint, lpszVolumeName ); } typedef BOOL WINAPI FN_SetVolumeMountPointW( LPCWSTR lpszVolumeMountPoint, LPCWSTR lpszVolumeName ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetVolumeMountPointW( LPCWSTR lpszVolumeMountPoint, LPCWSTR lpszVolumeName ) { static FN_SetVolumeMountPointW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetVolumeMountPointW", &g_Kernel32); return pfn( lpszVolumeMountPoint, lpszVolumeName ); } typedef BOOL WINAPI FN_DeleteVolumeMountPointA( LPCSTR lpszVolumeMountPoint ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_DeleteVolumeMountPointA( LPCSTR lpszVolumeMountPoint ) { static FN_DeleteVolumeMountPointA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DeleteVolumeMountPointA", &g_Kernel32); return pfn( lpszVolumeMountPoint ); } typedef BOOL WINAPI FN_DeleteVolumeMountPointW( LPCWSTR lpszVolumeMountPoint ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_DeleteVolumeMountPointW( LPCWSTR lpszVolumeMountPoint ) { static FN_DeleteVolumeMountPointW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DeleteVolumeMountPointW", &g_Kernel32); return pfn( lpszVolumeMountPoint ); } typedef BOOL WINAPI FN_GetVolumeNameForVolumeMountPointA( LPCSTR lpszVolumeMountPoint, LPSTR lpszVolumeName, DWORD cchBufferLength ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetVolumeNameForVolumeMountPointA( LPCSTR lpszVolumeMountPoint, LPSTR lpszVolumeName, DWORD cchBufferLength ) { static FN_GetVolumeNameForVolumeMountPointA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetVolumeNameForVolumeMountPointA", &g_Kernel32); return pfn( lpszVolumeMountPoint, lpszVolumeName, cchBufferLength ); } typedef BOOL WINAPI FN_GetVolumeNameForVolumeMountPointW( LPCWSTR lpszVolumeMountPoint, LPWSTR lpszVolumeName, DWORD cchBufferLength ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetVolumeNameForVolumeMountPointW( LPCWSTR lpszVolumeMountPoint, LPWSTR lpszVolumeName, DWORD cchBufferLength ) { static FN_GetVolumeNameForVolumeMountPointW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetVolumeNameForVolumeMountPointW", &g_Kernel32); return pfn( lpszVolumeMountPoint, lpszVolumeName, cchBufferLength ); } typedef BOOL WINAPI FN_GetVolumePathNameA( LPCSTR lpszFileName, LPSTR lpszVolumePathName, DWORD cchBufferLength ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetVolumePathNameA( LPCSTR lpszFileName, LPSTR lpszVolumePathName, DWORD cchBufferLength ) { static FN_GetVolumePathNameA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetVolumePathNameA", &g_Kernel32); return pfn( lpszFileName, lpszVolumePathName, cchBufferLength ); } typedef BOOL WINAPI FN_GetVolumePathNameW( LPCWSTR lpszFileName, LPWSTR lpszVolumePathName, DWORD cchBufferLength ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetVolumePathNameW( LPCWSTR lpszFileName, LPWSTR lpszVolumePathName, DWORD cchBufferLength ) { static FN_GetVolumePathNameW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetVolumePathNameW", &g_Kernel32); return pfn( lpszFileName, lpszVolumePathName, cchBufferLength ); } typedef BOOL WINAPI FN_GetVolumePathNamesForVolumeNameA( LPCSTR lpszVolumeName, LPCH lpszVolumePathNames, DWORD cchBufferLength, PDWORD lpcchReturnLength ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetVolumePathNamesForVolumeNameA( LPCSTR lpszVolumeName, LPCH lpszVolumePathNames, DWORD cchBufferLength, PDWORD lpcchReturnLength ) { static FN_GetVolumePathNamesForVolumeNameA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetVolumePathNamesForVolumeNameA", &g_Kernel32); return pfn( lpszVolumeName, lpszVolumePathNames, cchBufferLength, lpcchReturnLength ); } typedef BOOL WINAPI FN_GetVolumePathNamesForVolumeNameW( LPCWSTR lpszVolumeName, LPWCH lpszVolumePathNames, DWORD cchBufferLength, PDWORD lpcchReturnLength ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetVolumePathNamesForVolumeNameW( LPCWSTR lpszVolumeName, LPWCH lpszVolumePathNames, DWORD cchBufferLength, PDWORD lpcchReturnLength ) { static FN_GetVolumePathNamesForVolumeNameW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetVolumePathNamesForVolumeNameW", &g_Kernel32); return pfn( lpszVolumeName, lpszVolumePathNames, cchBufferLength, lpcchReturnLength ); } typedef HANDLE WINAPI FN_CreateActCtxA( PCACTCTXA pActCtx ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateActCtxA( PCACTCTXA pActCtx ) { static FN_CreateActCtxA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateActCtxA", &g_Kernel32); return pfn( pActCtx ); } typedef HANDLE WINAPI FN_CreateActCtxW( PCACTCTXW pActCtx ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateActCtxW( PCACTCTXW pActCtx ) { static FN_CreateActCtxW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateActCtxW", &g_Kernel32); return pfn( pActCtx ); } typedef VOID WINAPI FN_AddRefActCtx( HANDLE hActCtx ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_AddRefActCtx( HANDLE hActCtx ) { static FN_AddRefActCtx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AddRefActCtx", &g_Kernel32); pfn( hActCtx ); } typedef VOID WINAPI FN_ReleaseActCtx( HANDLE hActCtx ); __declspec(dllexport) VOID WINAPI kPrf2Wrap_ReleaseActCtx( HANDLE hActCtx ) { static FN_ReleaseActCtx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ReleaseActCtx", &g_Kernel32); pfn( hActCtx ); } typedef BOOL WINAPI FN_ZombifyActCtx( HANDLE hActCtx ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ZombifyActCtx( HANDLE hActCtx ) { static FN_ZombifyActCtx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ZombifyActCtx", &g_Kernel32); return pfn( hActCtx ); } typedef BOOL WINAPI FN_ActivateActCtx( HANDLE hActCtx, ULONG_PTR * lpCookie ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ActivateActCtx( HANDLE hActCtx, ULONG_PTR * lpCookie ) { static FN_ActivateActCtx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ActivateActCtx", &g_Kernel32); return pfn( hActCtx, lpCookie ); } typedef BOOL WINAPI FN_DeactivateActCtx( DWORD dwFlags, ULONG_PTR ulCookie ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_DeactivateActCtx( DWORD dwFlags, ULONG_PTR ulCookie ) { static FN_DeactivateActCtx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "DeactivateActCtx", &g_Kernel32); return pfn( dwFlags, ulCookie ); } typedef BOOL WINAPI FN_GetCurrentActCtx( HANDLE * lphActCtx ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetCurrentActCtx( HANDLE * lphActCtx ) { static FN_GetCurrentActCtx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetCurrentActCtx", &g_Kernel32); return pfn( lphActCtx ); } typedef BOOL WINAPI FN_FindActCtxSectionStringA( DWORD dwFlags, const GUID * lpExtensionGuid, ULONG ulSectionId, LPCSTR lpStringToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindActCtxSectionStringA( DWORD dwFlags, const GUID * lpExtensionGuid, ULONG ulSectionId, LPCSTR lpStringToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData ) { static FN_FindActCtxSectionStringA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindActCtxSectionStringA", &g_Kernel32); return pfn( dwFlags, lpExtensionGuid, ulSectionId, lpStringToFind, ReturnedData ); } typedef BOOL WINAPI FN_FindActCtxSectionStringW( DWORD dwFlags, const GUID * lpExtensionGuid, ULONG ulSectionId, LPCWSTR lpStringToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindActCtxSectionStringW( DWORD dwFlags, const GUID * lpExtensionGuid, ULONG ulSectionId, LPCWSTR lpStringToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData ) { static FN_FindActCtxSectionStringW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindActCtxSectionStringW", &g_Kernel32); return pfn( dwFlags, lpExtensionGuid, ulSectionId, lpStringToFind, ReturnedData ); } typedef BOOL WINAPI FN_FindActCtxSectionGuid( DWORD dwFlags, const GUID * lpExtensionGuid, ULONG ulSectionId, const GUID * lpGuidToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FindActCtxSectionGuid( DWORD dwFlags, const GUID * lpExtensionGuid, ULONG ulSectionId, const GUID * lpGuidToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData ) { static FN_FindActCtxSectionGuid *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FindActCtxSectionGuid", &g_Kernel32); return pfn( dwFlags, lpExtensionGuid, ulSectionId, lpGuidToFind, ReturnedData ); } typedef BOOL WINAPI FN_QueryActCtxW( DWORD dwFlags, HANDLE hActCtx, PVOID pvSubInstance, ULONG ulInfoClass, PVOID pvBuffer, SIZE_T cbBuffer, SIZE_T * pcbWrittenOrRequired ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_QueryActCtxW( DWORD dwFlags, HANDLE hActCtx, PVOID pvSubInstance, ULONG ulInfoClass, PVOID pvBuffer, SIZE_T cbBuffer, SIZE_T * pcbWrittenOrRequired ) { static FN_QueryActCtxW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "QueryActCtxW", &g_Kernel32); return pfn( dwFlags, hActCtx, pvSubInstance, ulInfoClass, pvBuffer, cbBuffer, pcbWrittenOrRequired ); } typedef BOOL WINAPI FN_ProcessIdToSessionId( DWORD dwProcessId, DWORD * pSessionId ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ProcessIdToSessionId( DWORD dwProcessId, DWORD * pSessionId ) { static FN_ProcessIdToSessionId *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ProcessIdToSessionId", &g_Kernel32); return pfn( dwProcessId, pSessionId ); } typedef DWORD WINAPI FN_WTSGetActiveConsoleSessionId( ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_WTSGetActiveConsoleSessionId( ) { static FN_WTSGetActiveConsoleSessionId *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WTSGetActiveConsoleSessionId", &g_Kernel32); return pfn( ); } typedef BOOL WINAPI FN_IsWow64Process( HANDLE hProcess, PBOOL Wow64Process ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsWow64Process( HANDLE hProcess, PBOOL Wow64Process ) { static FN_IsWow64Process *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "IsWow64Process", &g_Kernel32); return pfn( hProcess, Wow64Process ); } typedef BOOL WINAPI FN_GetLogicalProcessorInformation( PSYSTEM_LOGICAL_PROCESSOR_INFORMATION Buffer, PDWORD ReturnedLength ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetLogicalProcessorInformation( PSYSTEM_LOGICAL_PROCESSOR_INFORMATION Buffer, PDWORD ReturnedLength ) { static FN_GetLogicalProcessorInformation *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetLogicalProcessorInformation", &g_Kernel32); return pfn( Buffer, ReturnedLength ); } typedef BOOL WINAPI FN_GetNumaHighestNodeNumber( PULONG HighestNodeNumber ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetNumaHighestNodeNumber( PULONG HighestNodeNumber ) { static FN_GetNumaHighestNodeNumber *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetNumaHighestNodeNumber", &g_Kernel32); return pfn( HighestNodeNumber ); } typedef BOOL WINAPI FN_GetNumaProcessorNode( UCHAR Processor, PUCHAR NodeNumber ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetNumaProcessorNode( UCHAR Processor, PUCHAR NodeNumber ) { static FN_GetNumaProcessorNode *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetNumaProcessorNode", &g_Kernel32); return pfn( Processor, NodeNumber ); } typedef BOOL WINAPI FN_GetNumaNodeProcessorMask( UCHAR Node, PULONGLONG ProcessorMask ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetNumaNodeProcessorMask( UCHAR Node, PULONGLONG ProcessorMask ) { static FN_GetNumaNodeProcessorMask *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetNumaNodeProcessorMask", &g_Kernel32); return pfn( Node, ProcessorMask ); } typedef BOOL WINAPI FN_GetNumaAvailableMemoryNode( UCHAR Node, PULONGLONG AvailableBytes ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetNumaAvailableMemoryNode( UCHAR Node, PULONGLONG AvailableBytes ) { static FN_GetNumaAvailableMemoryNode *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetNumaAvailableMemoryNode", &g_Kernel32); return pfn( Node, AvailableBytes ); } typedef BOOL WINAPI FN_PeekConsoleInputA( IN HANDLE hConsoleInput, OUT PINPUT_RECORD lpBuffer, IN DWORD nLength, OUT LPDWORD lpNumberOfEventsRead ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_PeekConsoleInputA( IN HANDLE hConsoleInput, OUT PINPUT_RECORD lpBuffer, IN DWORD nLength, OUT LPDWORD lpNumberOfEventsRead ) { static FN_PeekConsoleInputA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "PeekConsoleInputA", &g_Kernel32); return pfn( hConsoleInput, lpBuffer, nLength, lpNumberOfEventsRead ); } typedef BOOL WINAPI FN_PeekConsoleInputW( IN HANDLE hConsoleInput, OUT PINPUT_RECORD lpBuffer, IN DWORD nLength, OUT LPDWORD lpNumberOfEventsRead ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_PeekConsoleInputW( IN HANDLE hConsoleInput, OUT PINPUT_RECORD lpBuffer, IN DWORD nLength, OUT LPDWORD lpNumberOfEventsRead ) { static FN_PeekConsoleInputW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "PeekConsoleInputW", &g_Kernel32); return pfn( hConsoleInput, lpBuffer, nLength, lpNumberOfEventsRead ); } typedef BOOL WINAPI FN_ReadConsoleInputA( IN HANDLE hConsoleInput, OUT PINPUT_RECORD lpBuffer, IN DWORD nLength, OUT LPDWORD lpNumberOfEventsRead ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadConsoleInputA( IN HANDLE hConsoleInput, OUT PINPUT_RECORD lpBuffer, IN DWORD nLength, OUT LPDWORD lpNumberOfEventsRead ) { static FN_ReadConsoleInputA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ReadConsoleInputA", &g_Kernel32); return pfn( hConsoleInput, lpBuffer, nLength, lpNumberOfEventsRead ); } typedef BOOL WINAPI FN_ReadConsoleInputW( IN HANDLE hConsoleInput, OUT PINPUT_RECORD lpBuffer, IN DWORD nLength, OUT LPDWORD lpNumberOfEventsRead ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadConsoleInputW( IN HANDLE hConsoleInput, OUT PINPUT_RECORD lpBuffer, IN DWORD nLength, OUT LPDWORD lpNumberOfEventsRead ) { static FN_ReadConsoleInputW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ReadConsoleInputW", &g_Kernel32); return pfn( hConsoleInput, lpBuffer, nLength, lpNumberOfEventsRead ); } typedef BOOL WINAPI FN_WriteConsoleInputA( IN HANDLE hConsoleInput, IN CONST INPUT_RECORD * lpBuffer, IN DWORD nLength, OUT LPDWORD lpNumberOfEventsWritten ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteConsoleInputA( IN HANDLE hConsoleInput, IN CONST INPUT_RECORD * lpBuffer, IN DWORD nLength, OUT LPDWORD lpNumberOfEventsWritten ) { static FN_WriteConsoleInputA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WriteConsoleInputA", &g_Kernel32); return pfn( hConsoleInput, lpBuffer, nLength, lpNumberOfEventsWritten ); } typedef BOOL WINAPI FN_WriteConsoleInputW( IN HANDLE hConsoleInput, IN CONST INPUT_RECORD * lpBuffer, IN DWORD nLength, OUT LPDWORD lpNumberOfEventsWritten ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteConsoleInputW( IN HANDLE hConsoleInput, IN CONST INPUT_RECORD * lpBuffer, IN DWORD nLength, OUT LPDWORD lpNumberOfEventsWritten ) { static FN_WriteConsoleInputW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WriteConsoleInputW", &g_Kernel32); return pfn( hConsoleInput, lpBuffer, nLength, lpNumberOfEventsWritten ); } typedef BOOL WINAPI FN_ReadConsoleOutputA( IN HANDLE hConsoleOutput, OUT PCHAR_INFO lpBuffer, IN COORD dwBufferSize, IN COORD dwBufferCoord, IN OUT PSMALL_RECT lpReadRegion ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadConsoleOutputA( IN HANDLE hConsoleOutput, OUT PCHAR_INFO lpBuffer, IN COORD dwBufferSize, IN COORD dwBufferCoord, IN OUT PSMALL_RECT lpReadRegion ) { static FN_ReadConsoleOutputA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ReadConsoleOutputA", &g_Kernel32); return pfn( hConsoleOutput, lpBuffer, dwBufferSize, dwBufferCoord, lpReadRegion ); } typedef BOOL WINAPI FN_ReadConsoleOutputW( IN HANDLE hConsoleOutput, OUT PCHAR_INFO lpBuffer, IN COORD dwBufferSize, IN COORD dwBufferCoord, IN OUT PSMALL_RECT lpReadRegion ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadConsoleOutputW( IN HANDLE hConsoleOutput, OUT PCHAR_INFO lpBuffer, IN COORD dwBufferSize, IN COORD dwBufferCoord, IN OUT PSMALL_RECT lpReadRegion ) { static FN_ReadConsoleOutputW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ReadConsoleOutputW", &g_Kernel32); return pfn( hConsoleOutput, lpBuffer, dwBufferSize, dwBufferCoord, lpReadRegion ); } typedef BOOL WINAPI FN_WriteConsoleOutputA( IN HANDLE hConsoleOutput, IN CONST CHAR_INFO * lpBuffer, IN COORD dwBufferSize, IN COORD dwBufferCoord, IN OUT PSMALL_RECT lpWriteRegion ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteConsoleOutputA( IN HANDLE hConsoleOutput, IN CONST CHAR_INFO * lpBuffer, IN COORD dwBufferSize, IN COORD dwBufferCoord, IN OUT PSMALL_RECT lpWriteRegion ) { static FN_WriteConsoleOutputA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WriteConsoleOutputA", &g_Kernel32); return pfn( hConsoleOutput, lpBuffer, dwBufferSize, dwBufferCoord, lpWriteRegion ); } typedef BOOL WINAPI FN_WriteConsoleOutputW( IN HANDLE hConsoleOutput, IN CONST CHAR_INFO * lpBuffer, IN COORD dwBufferSize, IN COORD dwBufferCoord, IN OUT PSMALL_RECT lpWriteRegion ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteConsoleOutputW( IN HANDLE hConsoleOutput, IN CONST CHAR_INFO * lpBuffer, IN COORD dwBufferSize, IN COORD dwBufferCoord, IN OUT PSMALL_RECT lpWriteRegion ) { static FN_WriteConsoleOutputW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WriteConsoleOutputW", &g_Kernel32); return pfn( hConsoleOutput, lpBuffer, dwBufferSize, dwBufferCoord, lpWriteRegion ); } typedef BOOL WINAPI FN_ReadConsoleOutputCharacterA( IN HANDLE hConsoleOutput, OUT LPSTR lpCharacter, IN DWORD nLength, IN COORD dwReadCoord, OUT LPDWORD lpNumberOfCharsRead ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadConsoleOutputCharacterA( IN HANDLE hConsoleOutput, OUT LPSTR lpCharacter, IN DWORD nLength, IN COORD dwReadCoord, OUT LPDWORD lpNumberOfCharsRead ) { static FN_ReadConsoleOutputCharacterA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ReadConsoleOutputCharacterA", &g_Kernel32); return pfn( hConsoleOutput, lpCharacter, nLength, dwReadCoord, lpNumberOfCharsRead ); } typedef BOOL WINAPI FN_ReadConsoleOutputCharacterW( IN HANDLE hConsoleOutput, OUT LPWSTR lpCharacter, IN DWORD nLength, IN COORD dwReadCoord, OUT LPDWORD lpNumberOfCharsRead ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadConsoleOutputCharacterW( IN HANDLE hConsoleOutput, OUT LPWSTR lpCharacter, IN DWORD nLength, IN COORD dwReadCoord, OUT LPDWORD lpNumberOfCharsRead ) { static FN_ReadConsoleOutputCharacterW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ReadConsoleOutputCharacterW", &g_Kernel32); return pfn( hConsoleOutput, lpCharacter, nLength, dwReadCoord, lpNumberOfCharsRead ); } typedef BOOL WINAPI FN_ReadConsoleOutputAttribute( IN HANDLE hConsoleOutput, OUT LPWORD lpAttribute, IN DWORD nLength, IN COORD dwReadCoord, OUT LPDWORD lpNumberOfAttrsRead ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadConsoleOutputAttribute( IN HANDLE hConsoleOutput, OUT LPWORD lpAttribute, IN DWORD nLength, IN COORD dwReadCoord, OUT LPDWORD lpNumberOfAttrsRead ) { static FN_ReadConsoleOutputAttribute *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ReadConsoleOutputAttribute", &g_Kernel32); return pfn( hConsoleOutput, lpAttribute, nLength, dwReadCoord, lpNumberOfAttrsRead ); } typedef BOOL WINAPI FN_WriteConsoleOutputCharacterA( IN HANDLE hConsoleOutput, IN LPCSTR lpCharacter, IN DWORD nLength, IN COORD dwWriteCoord, OUT LPDWORD lpNumberOfCharsWritten ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteConsoleOutputCharacterA( IN HANDLE hConsoleOutput, IN LPCSTR lpCharacter, IN DWORD nLength, IN COORD dwWriteCoord, OUT LPDWORD lpNumberOfCharsWritten ) { static FN_WriteConsoleOutputCharacterA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WriteConsoleOutputCharacterA", &g_Kernel32); return pfn( hConsoleOutput, lpCharacter, nLength, dwWriteCoord, lpNumberOfCharsWritten ); } typedef BOOL WINAPI FN_WriteConsoleOutputCharacterW( IN HANDLE hConsoleOutput, IN LPCWSTR lpCharacter, IN DWORD nLength, IN COORD dwWriteCoord, OUT LPDWORD lpNumberOfCharsWritten ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteConsoleOutputCharacterW( IN HANDLE hConsoleOutput, IN LPCWSTR lpCharacter, IN DWORD nLength, IN COORD dwWriteCoord, OUT LPDWORD lpNumberOfCharsWritten ) { static FN_WriteConsoleOutputCharacterW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WriteConsoleOutputCharacterW", &g_Kernel32); return pfn( hConsoleOutput, lpCharacter, nLength, dwWriteCoord, lpNumberOfCharsWritten ); } typedef BOOL WINAPI FN_WriteConsoleOutputAttribute( IN HANDLE hConsoleOutput, IN CONST WORD * lpAttribute, IN DWORD nLength, IN COORD dwWriteCoord, OUT LPDWORD lpNumberOfAttrsWritten ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteConsoleOutputAttribute( IN HANDLE hConsoleOutput, IN CONST WORD * lpAttribute, IN DWORD nLength, IN COORD dwWriteCoord, OUT LPDWORD lpNumberOfAttrsWritten ) { static FN_WriteConsoleOutputAttribute *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WriteConsoleOutputAttribute", &g_Kernel32); return pfn( hConsoleOutput, lpAttribute, nLength, dwWriteCoord, lpNumberOfAttrsWritten ); } typedef BOOL WINAPI FN_FillConsoleOutputCharacterA( IN HANDLE hConsoleOutput, IN CHAR cCharacter, IN DWORD nLength, IN COORD dwWriteCoord, OUT LPDWORD lpNumberOfCharsWritten ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FillConsoleOutputCharacterA( IN HANDLE hConsoleOutput, IN CHAR cCharacter, IN DWORD nLength, IN COORD dwWriteCoord, OUT LPDWORD lpNumberOfCharsWritten ) { static FN_FillConsoleOutputCharacterA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FillConsoleOutputCharacterA", &g_Kernel32); return pfn( hConsoleOutput, cCharacter, nLength, dwWriteCoord, lpNumberOfCharsWritten ); } typedef BOOL WINAPI FN_FillConsoleOutputCharacterW( IN HANDLE hConsoleOutput, IN WCHAR cCharacter, IN DWORD nLength, IN COORD dwWriteCoord, OUT LPDWORD lpNumberOfCharsWritten ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FillConsoleOutputCharacterW( IN HANDLE hConsoleOutput, IN WCHAR cCharacter, IN DWORD nLength, IN COORD dwWriteCoord, OUT LPDWORD lpNumberOfCharsWritten ) { static FN_FillConsoleOutputCharacterW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FillConsoleOutputCharacterW", &g_Kernel32); return pfn( hConsoleOutput, cCharacter, nLength, dwWriteCoord, lpNumberOfCharsWritten ); } typedef BOOL WINAPI FN_FillConsoleOutputAttribute( IN HANDLE hConsoleOutput, IN WORD wAttribute, IN DWORD nLength, IN COORD dwWriteCoord, OUT LPDWORD lpNumberOfAttrsWritten ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FillConsoleOutputAttribute( IN HANDLE hConsoleOutput, IN WORD wAttribute, IN DWORD nLength, IN COORD dwWriteCoord, OUT LPDWORD lpNumberOfAttrsWritten ) { static FN_FillConsoleOutputAttribute *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FillConsoleOutputAttribute", &g_Kernel32); return pfn( hConsoleOutput, wAttribute, nLength, dwWriteCoord, lpNumberOfAttrsWritten ); } typedef BOOL WINAPI FN_GetConsoleMode( IN HANDLE hConsoleHandle, OUT LPDWORD lpMode ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetConsoleMode( IN HANDLE hConsoleHandle, OUT LPDWORD lpMode ) { static FN_GetConsoleMode *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetConsoleMode", &g_Kernel32); return pfn( hConsoleHandle, lpMode ); } typedef BOOL WINAPI FN_GetNumberOfConsoleInputEvents( IN HANDLE hConsoleInput, OUT LPDWORD lpNumberOfEvents ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetNumberOfConsoleInputEvents( IN HANDLE hConsoleInput, OUT LPDWORD lpNumberOfEvents ) { static FN_GetNumberOfConsoleInputEvents *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetNumberOfConsoleInputEvents", &g_Kernel32); return pfn( hConsoleInput, lpNumberOfEvents ); } typedef BOOL WINAPI FN_GetConsoleScreenBufferInfo( IN HANDLE hConsoleOutput, OUT PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetConsoleScreenBufferInfo( IN HANDLE hConsoleOutput, OUT PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo ) { static FN_GetConsoleScreenBufferInfo *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetConsoleScreenBufferInfo", &g_Kernel32); return pfn( hConsoleOutput, lpConsoleScreenBufferInfo ); } typedef COORD WINAPI FN_GetLargestConsoleWindowSize( IN HANDLE hConsoleOutput ); __declspec(dllexport) COORD WINAPI kPrf2Wrap_GetLargestConsoleWindowSize( IN HANDLE hConsoleOutput ) { static FN_GetLargestConsoleWindowSize *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetLargestConsoleWindowSize", &g_Kernel32); return pfn( hConsoleOutput ); } typedef BOOL WINAPI FN_GetConsoleCursorInfo( IN HANDLE hConsoleOutput, OUT PCONSOLE_CURSOR_INFO lpConsoleCursorInfo ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetConsoleCursorInfo( IN HANDLE hConsoleOutput, OUT PCONSOLE_CURSOR_INFO lpConsoleCursorInfo ) { static FN_GetConsoleCursorInfo *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetConsoleCursorInfo", &g_Kernel32); return pfn( hConsoleOutput, lpConsoleCursorInfo ); } typedef BOOL WINAPI FN_GetCurrentConsoleFont( IN HANDLE hConsoleOutput, IN BOOL bMaximumWindow, OUT PCONSOLE_FONT_INFO lpConsoleCurrentFont ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetCurrentConsoleFont( IN HANDLE hConsoleOutput, IN BOOL bMaximumWindow, OUT PCONSOLE_FONT_INFO lpConsoleCurrentFont ) { static FN_GetCurrentConsoleFont *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetCurrentConsoleFont", &g_Kernel32); return pfn( hConsoleOutput, bMaximumWindow, lpConsoleCurrentFont ); } typedef COORD WINAPI FN_GetConsoleFontSize( IN HANDLE hConsoleOutput, IN DWORD nFont ); __declspec(dllexport) COORD WINAPI kPrf2Wrap_GetConsoleFontSize( IN HANDLE hConsoleOutput, IN DWORD nFont ) { static FN_GetConsoleFontSize *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetConsoleFontSize", &g_Kernel32); return pfn( hConsoleOutput, nFont ); } typedef BOOL WINAPI FN_GetConsoleSelectionInfo( OUT PCONSOLE_SELECTION_INFO lpConsoleSelectionInfo ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetConsoleSelectionInfo( OUT PCONSOLE_SELECTION_INFO lpConsoleSelectionInfo ) { static FN_GetConsoleSelectionInfo *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetConsoleSelectionInfo", &g_Kernel32); return pfn( lpConsoleSelectionInfo ); } typedef BOOL WINAPI FN_GetNumberOfConsoleMouseButtons( OUT LPDWORD lpNumberOfMouseButtons ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetNumberOfConsoleMouseButtons( OUT LPDWORD lpNumberOfMouseButtons ) { static FN_GetNumberOfConsoleMouseButtons *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetNumberOfConsoleMouseButtons", &g_Kernel32); return pfn( lpNumberOfMouseButtons ); } typedef BOOL WINAPI FN_SetConsoleMode( IN HANDLE hConsoleHandle, IN DWORD dwMode ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetConsoleMode( IN HANDLE hConsoleHandle, IN DWORD dwMode ) { static FN_SetConsoleMode *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetConsoleMode", &g_Kernel32); return pfn( hConsoleHandle, dwMode ); } typedef BOOL WINAPI FN_SetConsoleActiveScreenBuffer( IN HANDLE hConsoleOutput ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetConsoleActiveScreenBuffer( IN HANDLE hConsoleOutput ) { static FN_SetConsoleActiveScreenBuffer *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetConsoleActiveScreenBuffer", &g_Kernel32); return pfn( hConsoleOutput ); } typedef BOOL WINAPI FN_FlushConsoleInputBuffer( IN HANDLE hConsoleInput ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FlushConsoleInputBuffer( IN HANDLE hConsoleInput ) { static FN_FlushConsoleInputBuffer *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FlushConsoleInputBuffer", &g_Kernel32); return pfn( hConsoleInput ); } typedef BOOL WINAPI FN_SetConsoleScreenBufferSize( IN HANDLE hConsoleOutput, IN COORD dwSize ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetConsoleScreenBufferSize( IN HANDLE hConsoleOutput, IN COORD dwSize ) { static FN_SetConsoleScreenBufferSize *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetConsoleScreenBufferSize", &g_Kernel32); return pfn( hConsoleOutput, dwSize ); } typedef BOOL WINAPI FN_SetConsoleCursorPosition( IN HANDLE hConsoleOutput, IN COORD dwCursorPosition ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetConsoleCursorPosition( IN HANDLE hConsoleOutput, IN COORD dwCursorPosition ) { static FN_SetConsoleCursorPosition *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetConsoleCursorPosition", &g_Kernel32); return pfn( hConsoleOutput, dwCursorPosition ); } typedef BOOL WINAPI FN_SetConsoleCursorInfo( IN HANDLE hConsoleOutput, IN CONST CONSOLE_CURSOR_INFO * lpConsoleCursorInfo ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetConsoleCursorInfo( IN HANDLE hConsoleOutput, IN CONST CONSOLE_CURSOR_INFO * lpConsoleCursorInfo ) { static FN_SetConsoleCursorInfo *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetConsoleCursorInfo", &g_Kernel32); return pfn( hConsoleOutput, lpConsoleCursorInfo ); } typedef BOOL WINAPI FN_ScrollConsoleScreenBufferA( IN HANDLE hConsoleOutput, IN CONST SMALL_RECT * lpScrollRectangle, IN CONST SMALL_RECT * lpClipRectangle, IN COORD dwDestinationOrigin, IN CONST CHAR_INFO * lpFill ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ScrollConsoleScreenBufferA( IN HANDLE hConsoleOutput, IN CONST SMALL_RECT * lpScrollRectangle, IN CONST SMALL_RECT * lpClipRectangle, IN COORD dwDestinationOrigin, IN CONST CHAR_INFO * lpFill ) { static FN_ScrollConsoleScreenBufferA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ScrollConsoleScreenBufferA", &g_Kernel32); return pfn( hConsoleOutput, lpScrollRectangle, lpClipRectangle, dwDestinationOrigin, lpFill ); } typedef BOOL WINAPI FN_ScrollConsoleScreenBufferW( IN HANDLE hConsoleOutput, IN CONST SMALL_RECT * lpScrollRectangle, IN CONST SMALL_RECT * lpClipRectangle, IN COORD dwDestinationOrigin, IN CONST CHAR_INFO * lpFill ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ScrollConsoleScreenBufferW( IN HANDLE hConsoleOutput, IN CONST SMALL_RECT * lpScrollRectangle, IN CONST SMALL_RECT * lpClipRectangle, IN COORD dwDestinationOrigin, IN CONST CHAR_INFO * lpFill ) { static FN_ScrollConsoleScreenBufferW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ScrollConsoleScreenBufferW", &g_Kernel32); return pfn( hConsoleOutput, lpScrollRectangle, lpClipRectangle, dwDestinationOrigin, lpFill ); } typedef BOOL WINAPI FN_SetConsoleWindowInfo( IN HANDLE hConsoleOutput, IN BOOL bAbsolute, IN CONST SMALL_RECT * lpConsoleWindow ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetConsoleWindowInfo( IN HANDLE hConsoleOutput, IN BOOL bAbsolute, IN CONST SMALL_RECT * lpConsoleWindow ) { static FN_SetConsoleWindowInfo *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetConsoleWindowInfo", &g_Kernel32); return pfn( hConsoleOutput, bAbsolute, lpConsoleWindow ); } typedef BOOL WINAPI FN_SetConsoleTextAttribute( IN HANDLE hConsoleOutput, IN WORD wAttributes ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetConsoleTextAttribute( IN HANDLE hConsoleOutput, IN WORD wAttributes ) { static FN_SetConsoleTextAttribute *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetConsoleTextAttribute", &g_Kernel32); return pfn( hConsoleOutput, wAttributes ); } typedef BOOL WINAPI FN_SetConsoleCtrlHandler( IN PHANDLER_ROUTINE HandlerRoutine, IN BOOL Add ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetConsoleCtrlHandler( IN PHANDLER_ROUTINE HandlerRoutine, IN BOOL Add ) { static FN_SetConsoleCtrlHandler *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetConsoleCtrlHandler", &g_Kernel32); return pfn( HandlerRoutine, Add ); } typedef BOOL WINAPI FN_GenerateConsoleCtrlEvent( IN DWORD dwCtrlEvent, IN DWORD dwProcessGroupId ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GenerateConsoleCtrlEvent( IN DWORD dwCtrlEvent, IN DWORD dwProcessGroupId ) { static FN_GenerateConsoleCtrlEvent *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GenerateConsoleCtrlEvent", &g_Kernel32); return pfn( dwCtrlEvent, dwProcessGroupId ); } typedef BOOL WINAPI FN_AllocConsole( VOID ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AllocConsole( VOID ) { static FN_AllocConsole *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AllocConsole", &g_Kernel32); return pfn (); } typedef BOOL WINAPI FN_FreeConsole( VOID ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_FreeConsole( VOID ) { static FN_FreeConsole *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FreeConsole", &g_Kernel32); return pfn (); } typedef BOOL WINAPI FN_AttachConsole( IN DWORD dwProcessId ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_AttachConsole( IN DWORD dwProcessId ) { static FN_AttachConsole *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AttachConsole", &g_Kernel32); return pfn( dwProcessId ); } typedef DWORD WINAPI FN_GetConsoleTitleA( OUT LPSTR lpConsoleTitle, IN DWORD nSize ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetConsoleTitleA( OUT LPSTR lpConsoleTitle, IN DWORD nSize ) { static FN_GetConsoleTitleA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetConsoleTitleA", &g_Kernel32); return pfn( lpConsoleTitle, nSize ); } typedef DWORD WINAPI FN_GetConsoleTitleW( OUT LPWSTR lpConsoleTitle, IN DWORD nSize ); __declspec(dllexport) DWORD WINAPI kPrf2Wrap_GetConsoleTitleW( OUT LPWSTR lpConsoleTitle, IN DWORD nSize ) { static FN_GetConsoleTitleW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetConsoleTitleW", &g_Kernel32); return pfn( lpConsoleTitle, nSize ); } typedef BOOL WINAPI FN_SetConsoleTitleA( IN LPCSTR lpConsoleTitle ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetConsoleTitleA( IN LPCSTR lpConsoleTitle ) { static FN_SetConsoleTitleA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetConsoleTitleA", &g_Kernel32); return pfn( lpConsoleTitle ); } typedef BOOL WINAPI FN_SetConsoleTitleW( IN LPCWSTR lpConsoleTitle ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetConsoleTitleW( IN LPCWSTR lpConsoleTitle ) { static FN_SetConsoleTitleW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetConsoleTitleW", &g_Kernel32); return pfn( lpConsoleTitle ); } typedef BOOL WINAPI FN_ReadConsoleA( IN HANDLE hConsoleInput, OUT LPVOID lpBuffer, IN DWORD nNumberOfCharsToRead, OUT LPDWORD lpNumberOfCharsRead, IN LPVOID lpReserved ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadConsoleA( IN HANDLE hConsoleInput, OUT LPVOID lpBuffer, IN DWORD nNumberOfCharsToRead, OUT LPDWORD lpNumberOfCharsRead, IN LPVOID lpReserved ) { static FN_ReadConsoleA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ReadConsoleA", &g_Kernel32); return pfn( hConsoleInput, lpBuffer, nNumberOfCharsToRead, lpNumberOfCharsRead, lpReserved ); } typedef BOOL WINAPI FN_ReadConsoleW( IN HANDLE hConsoleInput, OUT LPVOID lpBuffer, IN DWORD nNumberOfCharsToRead, OUT LPDWORD lpNumberOfCharsRead, IN LPVOID lpReserved ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReadConsoleW( IN HANDLE hConsoleInput, OUT LPVOID lpBuffer, IN DWORD nNumberOfCharsToRead, OUT LPDWORD lpNumberOfCharsRead, IN LPVOID lpReserved ) { static FN_ReadConsoleW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ReadConsoleW", &g_Kernel32); return pfn( hConsoleInput, lpBuffer, nNumberOfCharsToRead, lpNumberOfCharsRead, lpReserved ); } typedef BOOL WINAPI FN_WriteConsoleA( IN HANDLE hConsoleOutput, IN CONST VOID * lpBuffer, IN DWORD nNumberOfCharsToWrite, OUT LPDWORD lpNumberOfCharsWritten, IN LPVOID lpReserved ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteConsoleA( IN HANDLE hConsoleOutput, IN CONST VOID * lpBuffer, IN DWORD nNumberOfCharsToWrite, OUT LPDWORD lpNumberOfCharsWritten, IN LPVOID lpReserved ) { static FN_WriteConsoleA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WriteConsoleA", &g_Kernel32); return pfn( hConsoleOutput, lpBuffer, nNumberOfCharsToWrite, lpNumberOfCharsWritten, lpReserved ); } typedef BOOL WINAPI FN_WriteConsoleW( IN HANDLE hConsoleOutput, IN CONST VOID * lpBuffer, IN DWORD nNumberOfCharsToWrite, OUT LPDWORD lpNumberOfCharsWritten, IN LPVOID lpReserved ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_WriteConsoleW( IN HANDLE hConsoleOutput, IN CONST VOID * lpBuffer, IN DWORD nNumberOfCharsToWrite, OUT LPDWORD lpNumberOfCharsWritten, IN LPVOID lpReserved ) { static FN_WriteConsoleW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WriteConsoleW", &g_Kernel32); return pfn( hConsoleOutput, lpBuffer, nNumberOfCharsToWrite, lpNumberOfCharsWritten, lpReserved ); } typedef HANDLE WINAPI FN_CreateConsoleScreenBuffer( IN DWORD dwDesiredAccess, IN DWORD dwShareMode, IN CONST SECURITY_ATTRIBUTES * lpSecurityAttributes, IN DWORD dwFlags, IN LPVOID lpScreenBufferData ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateConsoleScreenBuffer( IN DWORD dwDesiredAccess, IN DWORD dwShareMode, IN CONST SECURITY_ATTRIBUTES * lpSecurityAttributes, IN DWORD dwFlags, IN LPVOID lpScreenBufferData ) { static FN_CreateConsoleScreenBuffer *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateConsoleScreenBuffer", &g_Kernel32); return pfn( dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwFlags, lpScreenBufferData ); } typedef UINT WINAPI FN_GetConsoleCP( VOID ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_GetConsoleCP( VOID ) { static FN_GetConsoleCP *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetConsoleCP", &g_Kernel32); return pfn (); } typedef BOOL WINAPI FN_SetConsoleCP( IN UINT wCodePageID ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetConsoleCP( IN UINT wCodePageID ) { static FN_SetConsoleCP *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetConsoleCP", &g_Kernel32); return pfn( wCodePageID ); } typedef UINT WINAPI FN_GetConsoleOutputCP( VOID ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_GetConsoleOutputCP( VOID ) { static FN_GetConsoleOutputCP *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetConsoleOutputCP", &g_Kernel32); return pfn (); } typedef BOOL WINAPI FN_SetConsoleOutputCP( IN UINT wCodePageID ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetConsoleOutputCP( IN UINT wCodePageID ) { static FN_SetConsoleOutputCP *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetConsoleOutputCP", &g_Kernel32); return pfn( wCodePageID ); } typedef BOOL APIENTRY FN_GetConsoleDisplayMode( OUT LPDWORD lpModeFlags ); __declspec(dllexport) BOOL APIENTRY kPrf2Wrap_GetConsoleDisplayMode( OUT LPDWORD lpModeFlags ) { static FN_GetConsoleDisplayMode *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetConsoleDisplayMode", &g_Kernel32); return pfn( lpModeFlags ); } typedef HWND APIENTRY FN_GetConsoleWindow( VOID ); __declspec(dllexport) HWND APIENTRY kPrf2Wrap_GetConsoleWindow( VOID ) { static FN_GetConsoleWindow *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetConsoleWindow", &g_Kernel32); return pfn (); } typedef DWORD APIENTRY FN_GetConsoleProcessList( OUT LPDWORD lpdwProcessList, IN DWORD dwProcessCount ); __declspec(dllexport) DWORD APIENTRY kPrf2Wrap_GetConsoleProcessList( OUT LPDWORD lpdwProcessList, IN DWORD dwProcessCount ) { static FN_GetConsoleProcessList *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetConsoleProcessList", &g_Kernel32); return pfn( lpdwProcessList, dwProcessCount ); } typedef BOOL APIENTRY FN_AddConsoleAliasA( IN LPSTR Source, IN LPSTR Target, IN LPSTR ExeName ); __declspec(dllexport) BOOL APIENTRY kPrf2Wrap_AddConsoleAliasA( IN LPSTR Source, IN LPSTR Target, IN LPSTR ExeName ) { static FN_AddConsoleAliasA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AddConsoleAliasA", &g_Kernel32); return pfn( Source, Target, ExeName ); } typedef BOOL APIENTRY FN_AddConsoleAliasW( IN LPWSTR Source, IN LPWSTR Target, IN LPWSTR ExeName ); __declspec(dllexport) BOOL APIENTRY kPrf2Wrap_AddConsoleAliasW( IN LPWSTR Source, IN LPWSTR Target, IN LPWSTR ExeName ) { static FN_AddConsoleAliasW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "AddConsoleAliasW", &g_Kernel32); return pfn( Source, Target, ExeName ); } typedef DWORD APIENTRY FN_GetConsoleAliasA( IN LPSTR Source, OUT LPSTR TargetBuffer, IN DWORD TargetBufferLength, IN LPSTR ExeName ); __declspec(dllexport) DWORD APIENTRY kPrf2Wrap_GetConsoleAliasA( IN LPSTR Source, OUT LPSTR TargetBuffer, IN DWORD TargetBufferLength, IN LPSTR ExeName ) { static FN_GetConsoleAliasA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetConsoleAliasA", &g_Kernel32); return pfn( Source, TargetBuffer, TargetBufferLength, ExeName ); } typedef DWORD APIENTRY FN_GetConsoleAliasW( IN LPWSTR Source, OUT LPWSTR TargetBuffer, IN DWORD TargetBufferLength, IN LPWSTR ExeName ); __declspec(dllexport) DWORD APIENTRY kPrf2Wrap_GetConsoleAliasW( IN LPWSTR Source, OUT LPWSTR TargetBuffer, IN DWORD TargetBufferLength, IN LPWSTR ExeName ) { static FN_GetConsoleAliasW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetConsoleAliasW", &g_Kernel32); return pfn( Source, TargetBuffer, TargetBufferLength, ExeName ); } typedef DWORD APIENTRY FN_GetConsoleAliasesLengthA( IN LPSTR ExeName ); __declspec(dllexport) DWORD APIENTRY kPrf2Wrap_GetConsoleAliasesLengthA( IN LPSTR ExeName ) { static FN_GetConsoleAliasesLengthA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetConsoleAliasesLengthA", &g_Kernel32); return pfn( ExeName ); } typedef DWORD APIENTRY FN_GetConsoleAliasesLengthW( IN LPWSTR ExeName ); __declspec(dllexport) DWORD APIENTRY kPrf2Wrap_GetConsoleAliasesLengthW( IN LPWSTR ExeName ) { static FN_GetConsoleAliasesLengthW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetConsoleAliasesLengthW", &g_Kernel32); return pfn( ExeName ); } typedef DWORD APIENTRY FN_GetConsoleAliasExesLengthA( VOID ); __declspec(dllexport) DWORD APIENTRY kPrf2Wrap_GetConsoleAliasExesLengthA( VOID ) { static FN_GetConsoleAliasExesLengthA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetConsoleAliasExesLengthA", &g_Kernel32); return pfn (); } typedef DWORD APIENTRY FN_GetConsoleAliasExesLengthW( VOID ); __declspec(dllexport) DWORD APIENTRY kPrf2Wrap_GetConsoleAliasExesLengthW( VOID ) { static FN_GetConsoleAliasExesLengthW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetConsoleAliasExesLengthW", &g_Kernel32); return pfn (); } typedef DWORD APIENTRY FN_GetConsoleAliasesA( OUT LPSTR AliasBuffer, IN DWORD AliasBufferLength, IN LPSTR ExeName ); __declspec(dllexport) DWORD APIENTRY kPrf2Wrap_GetConsoleAliasesA( OUT LPSTR AliasBuffer, IN DWORD AliasBufferLength, IN LPSTR ExeName ) { static FN_GetConsoleAliasesA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetConsoleAliasesA", &g_Kernel32); return pfn( AliasBuffer, AliasBufferLength, ExeName ); } typedef DWORD APIENTRY FN_GetConsoleAliasesW( OUT LPWSTR AliasBuffer, IN DWORD AliasBufferLength, IN LPWSTR ExeName ); __declspec(dllexport) DWORD APIENTRY kPrf2Wrap_GetConsoleAliasesW( OUT LPWSTR AliasBuffer, IN DWORD AliasBufferLength, IN LPWSTR ExeName ) { static FN_GetConsoleAliasesW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetConsoleAliasesW", &g_Kernel32); return pfn( AliasBuffer, AliasBufferLength, ExeName ); } typedef DWORD APIENTRY FN_GetConsoleAliasExesA( OUT LPSTR ExeNameBuffer, IN DWORD ExeNameBufferLength ); __declspec(dllexport) DWORD APIENTRY kPrf2Wrap_GetConsoleAliasExesA( OUT LPSTR ExeNameBuffer, IN DWORD ExeNameBufferLength ) { static FN_GetConsoleAliasExesA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetConsoleAliasExesA", &g_Kernel32); return pfn( ExeNameBuffer, ExeNameBufferLength ); } typedef DWORD APIENTRY FN_GetConsoleAliasExesW( OUT LPWSTR ExeNameBuffer, IN DWORD ExeNameBufferLength ); __declspec(dllexport) DWORD APIENTRY kPrf2Wrap_GetConsoleAliasExesW( OUT LPWSTR ExeNameBuffer, IN DWORD ExeNameBufferLength ) { static FN_GetConsoleAliasExesW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetConsoleAliasExesW", &g_Kernel32); return pfn( ExeNameBuffer, ExeNameBufferLength ); } typedef BOOL WINAPI FN_IsValidCodePage( UINT CodePage ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsValidCodePage( UINT CodePage ) { static FN_IsValidCodePage *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "IsValidCodePage", &g_Kernel32); return pfn( CodePage ); } typedef UINT WINAPI FN_GetACP( void ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_GetACP( void ) { static FN_GetACP *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetACP", &g_Kernel32); return pfn (); } typedef UINT WINAPI FN_GetOEMCP( void ); __declspec(dllexport) UINT WINAPI kPrf2Wrap_GetOEMCP( void ) { static FN_GetOEMCP *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetOEMCP", &g_Kernel32); return pfn (); } typedef BOOL WINAPI FN_GetCPInfo( UINT CodePage, LPCPINFO lpCPInfo ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetCPInfo( UINT CodePage, LPCPINFO lpCPInfo ) { static FN_GetCPInfo *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetCPInfo", &g_Kernel32); return pfn( CodePage, lpCPInfo ); } typedef BOOL WINAPI FN_GetCPInfoExA( UINT CodePage, DWORD dwFlags, LPCPINFOEXA lpCPInfoEx ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetCPInfoExA( UINT CodePage, DWORD dwFlags, LPCPINFOEXA lpCPInfoEx ) { static FN_GetCPInfoExA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetCPInfoExA", &g_Kernel32); return pfn( CodePage, dwFlags, lpCPInfoEx ); } typedef BOOL WINAPI FN_GetCPInfoExW( UINT CodePage, DWORD dwFlags, LPCPINFOEXW lpCPInfoEx ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetCPInfoExW( UINT CodePage, DWORD dwFlags, LPCPINFOEXW lpCPInfoEx ) { static FN_GetCPInfoExW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetCPInfoExW", &g_Kernel32); return pfn( CodePage, dwFlags, lpCPInfoEx ); } typedef BOOL WINAPI FN_IsDBCSLeadByte( BYTE TestChar ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsDBCSLeadByte( BYTE TestChar ) { static FN_IsDBCSLeadByte *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "IsDBCSLeadByte", &g_Kernel32); return pfn( TestChar ); } typedef BOOL WINAPI FN_IsDBCSLeadByteEx( UINT CodePage, BYTE TestChar ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsDBCSLeadByteEx( UINT CodePage, BYTE TestChar ) { static FN_IsDBCSLeadByteEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "IsDBCSLeadByteEx", &g_Kernel32); return pfn( CodePage, TestChar ); } typedef int WINAPI FN_MultiByteToWideChar( UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar ); __declspec(dllexport) int WINAPI kPrf2Wrap_MultiByteToWideChar( UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar ) { static FN_MultiByteToWideChar *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "MultiByteToWideChar", &g_Kernel32); return pfn( CodePage, dwFlags, lpMultiByteStr, cbMultiByte, lpWideCharStr, cchWideChar ); } typedef int WINAPI FN_WideCharToMultiByte( UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar ); __declspec(dllexport) int WINAPI kPrf2Wrap_WideCharToMultiByte( UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar ) { static FN_WideCharToMultiByte *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "WideCharToMultiByte", &g_Kernel32); return pfn( CodePage, dwFlags, lpWideCharStr, cchWideChar, lpMultiByteStr, cbMultiByte, lpDefaultChar, lpUsedDefaultChar ); } typedef int WINAPI FN_CompareStringA( LCID Locale, DWORD dwCmpFlags, LPCSTR lpString1, int cchCount1, LPCSTR lpString2, int cchCount2 ); __declspec(dllexport) int WINAPI kPrf2Wrap_CompareStringA( LCID Locale, DWORD dwCmpFlags, LPCSTR lpString1, int cchCount1, LPCSTR lpString2, int cchCount2 ) { static FN_CompareStringA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CompareStringA", &g_Kernel32); return pfn( Locale, dwCmpFlags, lpString1, cchCount1, lpString2, cchCount2 ); } typedef int WINAPI FN_CompareStringW( LCID Locale, DWORD dwCmpFlags, LPCWSTR lpString1, int cchCount1, LPCWSTR lpString2, int cchCount2 ); __declspec(dllexport) int WINAPI kPrf2Wrap_CompareStringW( LCID Locale, DWORD dwCmpFlags, LPCWSTR lpString1, int cchCount1, LPCWSTR lpString2, int cchCount2 ) { static FN_CompareStringW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CompareStringW", &g_Kernel32); return pfn( Locale, dwCmpFlags, lpString1, cchCount1, lpString2, cchCount2 ); } typedef int WINAPI FN_LCMapStringA( LCID Locale, DWORD dwMapFlags, LPCSTR lpSrcStr, int cchSrc, LPSTR lpDestStr, int cchDest ); __declspec(dllexport) int WINAPI kPrf2Wrap_LCMapStringA( LCID Locale, DWORD dwMapFlags, LPCSTR lpSrcStr, int cchSrc, LPSTR lpDestStr, int cchDest ) { static FN_LCMapStringA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LCMapStringA", &g_Kernel32); return pfn( Locale, dwMapFlags, lpSrcStr, cchSrc, lpDestStr, cchDest ); } typedef int WINAPI FN_LCMapStringW( LCID Locale, DWORD dwMapFlags, LPCWSTR lpSrcStr, int cchSrc, LPWSTR lpDestStr, int cchDest ); __declspec(dllexport) int WINAPI kPrf2Wrap_LCMapStringW( LCID Locale, DWORD dwMapFlags, LPCWSTR lpSrcStr, int cchSrc, LPWSTR lpDestStr, int cchDest ) { static FN_LCMapStringW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "LCMapStringW", &g_Kernel32); return pfn( Locale, dwMapFlags, lpSrcStr, cchSrc, lpDestStr, cchDest ); } typedef int WINAPI FN_GetLocaleInfoA( LCID Locale, LCTYPE LCType, LPSTR lpLCData, int cchData ); __declspec(dllexport) int WINAPI kPrf2Wrap_GetLocaleInfoA( LCID Locale, LCTYPE LCType, LPSTR lpLCData, int cchData ) { static FN_GetLocaleInfoA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetLocaleInfoA", &g_Kernel32); return pfn( Locale, LCType, lpLCData, cchData ); } typedef int WINAPI FN_GetLocaleInfoW( LCID Locale, LCTYPE LCType, LPWSTR lpLCData, int cchData ); __declspec(dllexport) int WINAPI kPrf2Wrap_GetLocaleInfoW( LCID Locale, LCTYPE LCType, LPWSTR lpLCData, int cchData ) { static FN_GetLocaleInfoW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetLocaleInfoW", &g_Kernel32); return pfn( Locale, LCType, lpLCData, cchData ); } typedef BOOL WINAPI FN_SetLocaleInfoA( LCID Locale, LCTYPE LCType, LPCSTR lpLCData ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetLocaleInfoA( LCID Locale, LCTYPE LCType, LPCSTR lpLCData ) { static FN_SetLocaleInfoA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetLocaleInfoA", &g_Kernel32); return pfn( Locale, LCType, lpLCData ); } typedef BOOL WINAPI FN_SetLocaleInfoW( LCID Locale, LCTYPE LCType, LPCWSTR lpLCData ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetLocaleInfoW( LCID Locale, LCTYPE LCType, LPCWSTR lpLCData ) { static FN_SetLocaleInfoW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetLocaleInfoW", &g_Kernel32); return pfn( Locale, LCType, lpLCData ); } typedef int WINAPI FN_GetCalendarInfoA( LCID Locale, CALID Calendar, CALTYPE CalType, LPSTR lpCalData, int cchData, LPDWORD lpValue ); __declspec(dllexport) int WINAPI kPrf2Wrap_GetCalendarInfoA( LCID Locale, CALID Calendar, CALTYPE CalType, LPSTR lpCalData, int cchData, LPDWORD lpValue ) { static FN_GetCalendarInfoA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetCalendarInfoA", &g_Kernel32); return pfn( Locale, Calendar, CalType, lpCalData, cchData, lpValue ); } typedef int WINAPI FN_GetCalendarInfoW( LCID Locale, CALID Calendar, CALTYPE CalType, LPWSTR lpCalData, int cchData, LPDWORD lpValue ); __declspec(dllexport) int WINAPI kPrf2Wrap_GetCalendarInfoW( LCID Locale, CALID Calendar, CALTYPE CalType, LPWSTR lpCalData, int cchData, LPDWORD lpValue ) { static FN_GetCalendarInfoW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetCalendarInfoW", &g_Kernel32); return pfn( Locale, Calendar, CalType, lpCalData, cchData, lpValue ); } typedef BOOL WINAPI FN_SetCalendarInfoA( LCID Locale, CALID Calendar, CALTYPE CalType, LPCSTR lpCalData ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetCalendarInfoA( LCID Locale, CALID Calendar, CALTYPE CalType, LPCSTR lpCalData ) { static FN_SetCalendarInfoA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetCalendarInfoA", &g_Kernel32); return pfn( Locale, Calendar, CalType, lpCalData ); } typedef BOOL WINAPI FN_SetCalendarInfoW( LCID Locale, CALID Calendar, CALTYPE CalType, LPCWSTR lpCalData ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetCalendarInfoW( LCID Locale, CALID Calendar, CALTYPE CalType, LPCWSTR lpCalData ) { static FN_SetCalendarInfoW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetCalendarInfoW", &g_Kernel32); return pfn( Locale, Calendar, CalType, lpCalData ); } typedef int WINAPI FN_GetTimeFormatA( LCID Locale, DWORD dwFlags, CONST SYSTEMTIME * lpTime, LPCSTR lpFormat, LPSTR lpTimeStr, int cchTime ); __declspec(dllexport) int WINAPI kPrf2Wrap_GetTimeFormatA( LCID Locale, DWORD dwFlags, CONST SYSTEMTIME * lpTime, LPCSTR lpFormat, LPSTR lpTimeStr, int cchTime ) { static FN_GetTimeFormatA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetTimeFormatA", &g_Kernel32); return pfn( Locale, dwFlags, lpTime, lpFormat, lpTimeStr, cchTime ); } typedef int WINAPI FN_GetTimeFormatW( LCID Locale, DWORD dwFlags, CONST SYSTEMTIME * lpTime, LPCWSTR lpFormat, LPWSTR lpTimeStr, int cchTime ); __declspec(dllexport) int WINAPI kPrf2Wrap_GetTimeFormatW( LCID Locale, DWORD dwFlags, CONST SYSTEMTIME * lpTime, LPCWSTR lpFormat, LPWSTR lpTimeStr, int cchTime ) { static FN_GetTimeFormatW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetTimeFormatW", &g_Kernel32); return pfn( Locale, dwFlags, lpTime, lpFormat, lpTimeStr, cchTime ); } typedef int WINAPI FN_GetDateFormatA( LCID Locale, DWORD dwFlags, CONST SYSTEMTIME * lpDate, LPCSTR lpFormat, LPSTR lpDateStr, int cchDate ); __declspec(dllexport) int WINAPI kPrf2Wrap_GetDateFormatA( LCID Locale, DWORD dwFlags, CONST SYSTEMTIME * lpDate, LPCSTR lpFormat, LPSTR lpDateStr, int cchDate ) { static FN_GetDateFormatA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetDateFormatA", &g_Kernel32); return pfn( Locale, dwFlags, lpDate, lpFormat, lpDateStr, cchDate ); } typedef int WINAPI FN_GetDateFormatW( LCID Locale, DWORD dwFlags, CONST SYSTEMTIME * lpDate, LPCWSTR lpFormat, LPWSTR lpDateStr, int cchDate ); __declspec(dllexport) int WINAPI kPrf2Wrap_GetDateFormatW( LCID Locale, DWORD dwFlags, CONST SYSTEMTIME * lpDate, LPCWSTR lpFormat, LPWSTR lpDateStr, int cchDate ) { static FN_GetDateFormatW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetDateFormatW", &g_Kernel32); return pfn( Locale, dwFlags, lpDate, lpFormat, lpDateStr, cchDate ); } typedef int WINAPI FN_GetNumberFormatA( LCID Locale, DWORD dwFlags, LPCSTR lpValue, CONST NUMBERFMTA * lpFormat, LPSTR lpNumberStr, int cchNumber ); __declspec(dllexport) int WINAPI kPrf2Wrap_GetNumberFormatA( LCID Locale, DWORD dwFlags, LPCSTR lpValue, CONST NUMBERFMTA * lpFormat, LPSTR lpNumberStr, int cchNumber ) { static FN_GetNumberFormatA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetNumberFormatA", &g_Kernel32); return pfn( Locale, dwFlags, lpValue, lpFormat, lpNumberStr, cchNumber ); } typedef int WINAPI FN_GetNumberFormatW( LCID Locale, DWORD dwFlags, LPCWSTR lpValue, CONST NUMBERFMTW * lpFormat, LPWSTR lpNumberStr, int cchNumber ); __declspec(dllexport) int WINAPI kPrf2Wrap_GetNumberFormatW( LCID Locale, DWORD dwFlags, LPCWSTR lpValue, CONST NUMBERFMTW * lpFormat, LPWSTR lpNumberStr, int cchNumber ) { static FN_GetNumberFormatW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetNumberFormatW", &g_Kernel32); return pfn( Locale, dwFlags, lpValue, lpFormat, lpNumberStr, cchNumber ); } typedef int WINAPI FN_GetCurrencyFormatA( LCID Locale, DWORD dwFlags, LPCSTR lpValue, CONST CURRENCYFMTA * lpFormat, LPSTR lpCurrencyStr, int cchCurrency ); __declspec(dllexport) int WINAPI kPrf2Wrap_GetCurrencyFormatA( LCID Locale, DWORD dwFlags, LPCSTR lpValue, CONST CURRENCYFMTA * lpFormat, LPSTR lpCurrencyStr, int cchCurrency ) { static FN_GetCurrencyFormatA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetCurrencyFormatA", &g_Kernel32); return pfn( Locale, dwFlags, lpValue, lpFormat, lpCurrencyStr, cchCurrency ); } typedef int WINAPI FN_GetCurrencyFormatW( LCID Locale, DWORD dwFlags, LPCWSTR lpValue, CONST CURRENCYFMTW * lpFormat, LPWSTR lpCurrencyStr, int cchCurrency ); __declspec(dllexport) int WINAPI kPrf2Wrap_GetCurrencyFormatW( LCID Locale, DWORD dwFlags, LPCWSTR lpValue, CONST CURRENCYFMTW * lpFormat, LPWSTR lpCurrencyStr, int cchCurrency ) { static FN_GetCurrencyFormatW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetCurrencyFormatW", &g_Kernel32); return pfn( Locale, dwFlags, lpValue, lpFormat, lpCurrencyStr, cchCurrency ); } typedef BOOL WINAPI FN_EnumCalendarInfoA( CALINFO_ENUMPROCA lpCalInfoEnumProc, LCID Locale, CALID Calendar, CALTYPE CalType ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumCalendarInfoA( CALINFO_ENUMPROCA lpCalInfoEnumProc, LCID Locale, CALID Calendar, CALTYPE CalType ) { static FN_EnumCalendarInfoA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnumCalendarInfoA", &g_Kernel32); return pfn( lpCalInfoEnumProc, Locale, Calendar, CalType ); } typedef BOOL WINAPI FN_EnumCalendarInfoW( CALINFO_ENUMPROCW lpCalInfoEnumProc, LCID Locale, CALID Calendar, CALTYPE CalType ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumCalendarInfoW( CALINFO_ENUMPROCW lpCalInfoEnumProc, LCID Locale, CALID Calendar, CALTYPE CalType ) { static FN_EnumCalendarInfoW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnumCalendarInfoW", &g_Kernel32); return pfn( lpCalInfoEnumProc, Locale, Calendar, CalType ); } typedef BOOL WINAPI FN_EnumCalendarInfoExA( CALINFO_ENUMPROCEXA lpCalInfoEnumProcEx, LCID Locale, CALID Calendar, CALTYPE CalType ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumCalendarInfoExA( CALINFO_ENUMPROCEXA lpCalInfoEnumProcEx, LCID Locale, CALID Calendar, CALTYPE CalType ) { static FN_EnumCalendarInfoExA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnumCalendarInfoExA", &g_Kernel32); return pfn( lpCalInfoEnumProcEx, Locale, Calendar, CalType ); } typedef BOOL WINAPI FN_EnumCalendarInfoExW( CALINFO_ENUMPROCEXW lpCalInfoEnumProcEx, LCID Locale, CALID Calendar, CALTYPE CalType ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumCalendarInfoExW( CALINFO_ENUMPROCEXW lpCalInfoEnumProcEx, LCID Locale, CALID Calendar, CALTYPE CalType ) { static FN_EnumCalendarInfoExW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnumCalendarInfoExW", &g_Kernel32); return pfn( lpCalInfoEnumProcEx, Locale, Calendar, CalType ); } typedef BOOL WINAPI FN_EnumTimeFormatsA( TIMEFMT_ENUMPROCA lpTimeFmtEnumProc, LCID Locale, DWORD dwFlags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumTimeFormatsA( TIMEFMT_ENUMPROCA lpTimeFmtEnumProc, LCID Locale, DWORD dwFlags ) { static FN_EnumTimeFormatsA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnumTimeFormatsA", &g_Kernel32); return pfn( lpTimeFmtEnumProc, Locale, dwFlags ); } typedef BOOL WINAPI FN_EnumTimeFormatsW( TIMEFMT_ENUMPROCW lpTimeFmtEnumProc, LCID Locale, DWORD dwFlags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumTimeFormatsW( TIMEFMT_ENUMPROCW lpTimeFmtEnumProc, LCID Locale, DWORD dwFlags ) { static FN_EnumTimeFormatsW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnumTimeFormatsW", &g_Kernel32); return pfn( lpTimeFmtEnumProc, Locale, dwFlags ); } typedef BOOL WINAPI FN_EnumDateFormatsA( DATEFMT_ENUMPROCA lpDateFmtEnumProc, LCID Locale, DWORD dwFlags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumDateFormatsA( DATEFMT_ENUMPROCA lpDateFmtEnumProc, LCID Locale, DWORD dwFlags ) { static FN_EnumDateFormatsA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnumDateFormatsA", &g_Kernel32); return pfn( lpDateFmtEnumProc, Locale, dwFlags ); } typedef BOOL WINAPI FN_EnumDateFormatsW( DATEFMT_ENUMPROCW lpDateFmtEnumProc, LCID Locale, DWORD dwFlags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumDateFormatsW( DATEFMT_ENUMPROCW lpDateFmtEnumProc, LCID Locale, DWORD dwFlags ) { static FN_EnumDateFormatsW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnumDateFormatsW", &g_Kernel32); return pfn( lpDateFmtEnumProc, Locale, dwFlags ); } typedef BOOL WINAPI FN_EnumDateFormatsExA( DATEFMT_ENUMPROCEXA lpDateFmtEnumProcEx, LCID Locale, DWORD dwFlags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumDateFormatsExA( DATEFMT_ENUMPROCEXA lpDateFmtEnumProcEx, LCID Locale, DWORD dwFlags ) { static FN_EnumDateFormatsExA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnumDateFormatsExA", &g_Kernel32); return pfn( lpDateFmtEnumProcEx, Locale, dwFlags ); } typedef BOOL WINAPI FN_EnumDateFormatsExW( DATEFMT_ENUMPROCEXW lpDateFmtEnumProcEx, LCID Locale, DWORD dwFlags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumDateFormatsExW( DATEFMT_ENUMPROCEXW lpDateFmtEnumProcEx, LCID Locale, DWORD dwFlags ) { static FN_EnumDateFormatsExW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnumDateFormatsExW", &g_Kernel32); return pfn( lpDateFmtEnumProcEx, Locale, dwFlags ); } typedef BOOL WINAPI FN_IsValidLanguageGroup( LGRPID LanguageGroup, DWORD dwFlags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsValidLanguageGroup( LGRPID LanguageGroup, DWORD dwFlags ) { static FN_IsValidLanguageGroup *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "IsValidLanguageGroup", &g_Kernel32); return pfn( LanguageGroup, dwFlags ); } typedef BOOL WINAPI FN_GetNLSVersion( NLS_FUNCTION Function, LCID Locale, LPNLSVERSIONINFO lpVersionInformation ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetNLSVersion( NLS_FUNCTION Function, LCID Locale, LPNLSVERSIONINFO lpVersionInformation ) { static FN_GetNLSVersion *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetNLSVersion", &g_Kernel32); return pfn( Function, Locale, lpVersionInformation ); } typedef BOOL WINAPI FN_IsNLSDefinedString( NLS_FUNCTION Function, DWORD dwFlags, LPNLSVERSIONINFO lpVersionInformation, LPCWSTR lpString, INT cchStr ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsNLSDefinedString( NLS_FUNCTION Function, DWORD dwFlags, LPNLSVERSIONINFO lpVersionInformation, LPCWSTR lpString, INT cchStr ) { static FN_IsNLSDefinedString *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "IsNLSDefinedString", &g_Kernel32); return pfn( Function, dwFlags, lpVersionInformation, lpString, cchStr ); } typedef BOOL WINAPI FN_IsValidLocale( LCID Locale, DWORD dwFlags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_IsValidLocale( LCID Locale, DWORD dwFlags ) { static FN_IsValidLocale *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "IsValidLocale", &g_Kernel32); return pfn( Locale, dwFlags ); } typedef int WINAPI FN_GetGeoInfoA( GEOID Location, GEOTYPE GeoType, LPSTR lpGeoData, int cchData, LANGID LangId ); __declspec(dllexport) int WINAPI kPrf2Wrap_GetGeoInfoA( GEOID Location, GEOTYPE GeoType, LPSTR lpGeoData, int cchData, LANGID LangId ) { static FN_GetGeoInfoA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetGeoInfoA", &g_Kernel32); return pfn( Location, GeoType, lpGeoData, cchData, LangId ); } typedef int WINAPI FN_GetGeoInfoW( GEOID Location, GEOTYPE GeoType, LPWSTR lpGeoData, int cchData, LANGID LangId ); __declspec(dllexport) int WINAPI kPrf2Wrap_GetGeoInfoW( GEOID Location, GEOTYPE GeoType, LPWSTR lpGeoData, int cchData, LANGID LangId ) { static FN_GetGeoInfoW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetGeoInfoW", &g_Kernel32); return pfn( Location, GeoType, lpGeoData, cchData, LangId ); } typedef BOOL WINAPI FN_EnumSystemGeoID( GEOCLASS GeoClass, GEOID ParentGeoId, GEO_ENUMPROC lpGeoEnumProc ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumSystemGeoID( GEOCLASS GeoClass, GEOID ParentGeoId, GEO_ENUMPROC lpGeoEnumProc ) { static FN_EnumSystemGeoID *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnumSystemGeoID", &g_Kernel32); return pfn( GeoClass, ParentGeoId, lpGeoEnumProc ); } typedef GEOID WINAPI FN_GetUserGeoID( GEOCLASS GeoClass ); __declspec(dllexport) GEOID WINAPI kPrf2Wrap_GetUserGeoID( GEOCLASS GeoClass ) { static FN_GetUserGeoID *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetUserGeoID", &g_Kernel32); return pfn( GeoClass ); } typedef BOOL WINAPI FN_SetUserGeoID( GEOID GeoId ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetUserGeoID( GEOID GeoId ) { static FN_SetUserGeoID *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetUserGeoID", &g_Kernel32); return pfn( GeoId ); } typedef LCID WINAPI FN_ConvertDefaultLocale( LCID Locale ); __declspec(dllexport) LCID WINAPI kPrf2Wrap_ConvertDefaultLocale( LCID Locale ) { static FN_ConvertDefaultLocale *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ConvertDefaultLocale", &g_Kernel32); return pfn( Locale ); } typedef LCID WINAPI FN_GetThreadLocale( void ); __declspec(dllexport) LCID WINAPI kPrf2Wrap_GetThreadLocale( void ) { static FN_GetThreadLocale *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetThreadLocale", &g_Kernel32); return pfn (); } typedef BOOL WINAPI FN_SetThreadLocale( LCID Locale ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetThreadLocale( LCID Locale ) { static FN_SetThreadLocale *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetThreadLocale", &g_Kernel32); return pfn( Locale ); } typedef LANGID WINAPI FN_GetSystemDefaultUILanguage( void ); __declspec(dllexport) LANGID WINAPI kPrf2Wrap_GetSystemDefaultUILanguage( void ) { static FN_GetSystemDefaultUILanguage *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSystemDefaultUILanguage", &g_Kernel32); return pfn (); } typedef LANGID WINAPI FN_GetUserDefaultUILanguage( void ); __declspec(dllexport) LANGID WINAPI kPrf2Wrap_GetUserDefaultUILanguage( void ) { static FN_GetUserDefaultUILanguage *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetUserDefaultUILanguage", &g_Kernel32); return pfn (); } typedef LANGID WINAPI FN_GetSystemDefaultLangID( void ); __declspec(dllexport) LANGID WINAPI kPrf2Wrap_GetSystemDefaultLangID( void ) { static FN_GetSystemDefaultLangID *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSystemDefaultLangID", &g_Kernel32); return pfn (); } typedef LANGID WINAPI FN_GetUserDefaultLangID( void ); __declspec(dllexport) LANGID WINAPI kPrf2Wrap_GetUserDefaultLangID( void ) { static FN_GetUserDefaultLangID *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetUserDefaultLangID", &g_Kernel32); return pfn (); } typedef LCID WINAPI FN_GetSystemDefaultLCID( void ); __declspec(dllexport) LCID WINAPI kPrf2Wrap_GetSystemDefaultLCID( void ) { static FN_GetSystemDefaultLCID *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetSystemDefaultLCID", &g_Kernel32); return pfn (); } typedef LCID WINAPI FN_GetUserDefaultLCID( void ); __declspec(dllexport) LCID WINAPI kPrf2Wrap_GetUserDefaultLCID( void ) { static FN_GetUserDefaultLCID *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetUserDefaultLCID", &g_Kernel32); return pfn (); } typedef BOOL WINAPI FN_GetStringTypeExA( LCID Locale, DWORD dwInfoType, LPCSTR lpSrcStr, int cchSrc, LPWORD lpCharType ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetStringTypeExA( LCID Locale, DWORD dwInfoType, LPCSTR lpSrcStr, int cchSrc, LPWORD lpCharType ) { static FN_GetStringTypeExA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetStringTypeExA", &g_Kernel32); return pfn( Locale, dwInfoType, lpSrcStr, cchSrc, lpCharType ); } typedef BOOL WINAPI FN_GetStringTypeExW( LCID Locale, DWORD dwInfoType, LPCWSTR lpSrcStr, int cchSrc, LPWORD lpCharType ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetStringTypeExW( LCID Locale, DWORD dwInfoType, LPCWSTR lpSrcStr, int cchSrc, LPWORD lpCharType ) { static FN_GetStringTypeExW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetStringTypeExW", &g_Kernel32); return pfn( Locale, dwInfoType, lpSrcStr, cchSrc, lpCharType ); } typedef BOOL WINAPI FN_GetStringTypeA( LCID Locale, DWORD dwInfoType, LPCSTR lpSrcStr, int cchSrc, LPWORD lpCharType ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetStringTypeA( LCID Locale, DWORD dwInfoType, LPCSTR lpSrcStr, int cchSrc, LPWORD lpCharType ) { static FN_GetStringTypeA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetStringTypeA", &g_Kernel32); return pfn( Locale, dwInfoType, lpSrcStr, cchSrc, lpCharType ); } typedef BOOL WINAPI FN_GetStringTypeW( DWORD dwInfoType, LPCWSTR lpSrcStr, int cchSrc, LPWORD lpCharType ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetStringTypeW( DWORD dwInfoType, LPCWSTR lpSrcStr, int cchSrc, LPWORD lpCharType ) { static FN_GetStringTypeW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetStringTypeW", &g_Kernel32); return pfn( dwInfoType, lpSrcStr, cchSrc, lpCharType ); } typedef int WINAPI FN_FoldStringA( DWORD dwMapFlags, LPCSTR lpSrcStr, int cchSrc, LPSTR lpDestStr, int cchDest ); __declspec(dllexport) int WINAPI kPrf2Wrap_FoldStringA( DWORD dwMapFlags, LPCSTR lpSrcStr, int cchSrc, LPSTR lpDestStr, int cchDest ) { static FN_FoldStringA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FoldStringA", &g_Kernel32); return pfn( dwMapFlags, lpSrcStr, cchSrc, lpDestStr, cchDest ); } typedef int WINAPI FN_FoldStringW( DWORD dwMapFlags, LPCWSTR lpSrcStr, int cchSrc, LPWSTR lpDestStr, int cchDest ); __declspec(dllexport) int WINAPI kPrf2Wrap_FoldStringW( DWORD dwMapFlags, LPCWSTR lpSrcStr, int cchSrc, LPWSTR lpDestStr, int cchDest ) { static FN_FoldStringW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "FoldStringW", &g_Kernel32); return pfn( dwMapFlags, lpSrcStr, cchSrc, lpDestStr, cchDest ); } typedef BOOL WINAPI FN_EnumSystemLanguageGroupsA( LANGUAGEGROUP_ENUMPROCA lpLanguageGroupEnumProc, DWORD dwFlags, LONG_PTR lParam ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumSystemLanguageGroupsA( LANGUAGEGROUP_ENUMPROCA lpLanguageGroupEnumProc, DWORD dwFlags, LONG_PTR lParam ) { static FN_EnumSystemLanguageGroupsA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnumSystemLanguageGroupsA", &g_Kernel32); return pfn( lpLanguageGroupEnumProc, dwFlags, lParam ); } typedef BOOL WINAPI FN_EnumSystemLanguageGroupsW( LANGUAGEGROUP_ENUMPROCW lpLanguageGroupEnumProc, DWORD dwFlags, LONG_PTR lParam ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumSystemLanguageGroupsW( LANGUAGEGROUP_ENUMPROCW lpLanguageGroupEnumProc, DWORD dwFlags, LONG_PTR lParam ) { static FN_EnumSystemLanguageGroupsW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnumSystemLanguageGroupsW", &g_Kernel32); return pfn( lpLanguageGroupEnumProc, dwFlags, lParam ); } typedef BOOL WINAPI FN_EnumLanguageGroupLocalesA( LANGGROUPLOCALE_ENUMPROCA lpLangGroupLocaleEnumProc, LGRPID LanguageGroup, DWORD dwFlags, LONG_PTR lParam ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumLanguageGroupLocalesA( LANGGROUPLOCALE_ENUMPROCA lpLangGroupLocaleEnumProc, LGRPID LanguageGroup, DWORD dwFlags, LONG_PTR lParam ) { static FN_EnumLanguageGroupLocalesA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnumLanguageGroupLocalesA", &g_Kernel32); return pfn( lpLangGroupLocaleEnumProc, LanguageGroup, dwFlags, lParam ); } typedef BOOL WINAPI FN_EnumLanguageGroupLocalesW( LANGGROUPLOCALE_ENUMPROCW lpLangGroupLocaleEnumProc, LGRPID LanguageGroup, DWORD dwFlags, LONG_PTR lParam ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumLanguageGroupLocalesW( LANGGROUPLOCALE_ENUMPROCW lpLangGroupLocaleEnumProc, LGRPID LanguageGroup, DWORD dwFlags, LONG_PTR lParam ) { static FN_EnumLanguageGroupLocalesW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnumLanguageGroupLocalesW", &g_Kernel32); return pfn( lpLangGroupLocaleEnumProc, LanguageGroup, dwFlags, lParam ); } typedef BOOL WINAPI FN_EnumUILanguagesA( UILANGUAGE_ENUMPROCA lpUILanguageEnumProc, DWORD dwFlags, LONG_PTR lParam ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumUILanguagesA( UILANGUAGE_ENUMPROCA lpUILanguageEnumProc, DWORD dwFlags, LONG_PTR lParam ) { static FN_EnumUILanguagesA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnumUILanguagesA", &g_Kernel32); return pfn( lpUILanguageEnumProc, dwFlags, lParam ); } typedef BOOL WINAPI FN_EnumUILanguagesW( UILANGUAGE_ENUMPROCW lpUILanguageEnumProc, DWORD dwFlags, LONG_PTR lParam ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumUILanguagesW( UILANGUAGE_ENUMPROCW lpUILanguageEnumProc, DWORD dwFlags, LONG_PTR lParam ) { static FN_EnumUILanguagesW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnumUILanguagesW", &g_Kernel32); return pfn( lpUILanguageEnumProc, dwFlags, lParam ); } typedef BOOL WINAPI FN_EnumSystemLocalesA( LOCALE_ENUMPROCA lpLocaleEnumProc, DWORD dwFlags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumSystemLocalesA( LOCALE_ENUMPROCA lpLocaleEnumProc, DWORD dwFlags ) { static FN_EnumSystemLocalesA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnumSystemLocalesA", &g_Kernel32); return pfn( lpLocaleEnumProc, dwFlags ); } typedef BOOL WINAPI FN_EnumSystemLocalesW( LOCALE_ENUMPROCW lpLocaleEnumProc, DWORD dwFlags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumSystemLocalesW( LOCALE_ENUMPROCW lpLocaleEnumProc, DWORD dwFlags ) { static FN_EnumSystemLocalesW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnumSystemLocalesW", &g_Kernel32); return pfn( lpLocaleEnumProc, dwFlags ); } typedef BOOL WINAPI FN_EnumSystemCodePagesA( CODEPAGE_ENUMPROCA lpCodePageEnumProc, DWORD dwFlags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumSystemCodePagesA( CODEPAGE_ENUMPROCA lpCodePageEnumProc, DWORD dwFlags ) { static FN_EnumSystemCodePagesA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnumSystemCodePagesA", &g_Kernel32); return pfn( lpCodePageEnumProc, dwFlags ); } typedef BOOL WINAPI FN_EnumSystemCodePagesW( CODEPAGE_ENUMPROCW lpCodePageEnumProc, DWORD dwFlags ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_EnumSystemCodePagesW( CODEPAGE_ENUMPROCW lpCodePageEnumProc, DWORD dwFlags ) { static FN_EnumSystemCodePagesW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "EnumSystemCodePagesW", &g_Kernel32); return pfn( lpCodePageEnumProc, dwFlags ); } typedef DWORD APIENTRY FN_VerFindFileA( DWORD uFlags, LPSTR szFileName, LPSTR szWinDir, LPSTR szAppDir, LPSTR szCurDir, PUINT lpuCurDirLen, LPSTR szDestDir, PUINT lpuDestDirLen ); __declspec(dllexport) DWORD APIENTRY kPrf2Wrap_VerFindFileA( DWORD uFlags, LPSTR szFileName, LPSTR szWinDir, LPSTR szAppDir, LPSTR szCurDir, PUINT lpuCurDirLen, LPSTR szDestDir, PUINT lpuDestDirLen ) { static FN_VerFindFileA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "VerFindFileA", &g_Kernel32); return pfn( uFlags, szFileName, szWinDir, szAppDir, szCurDir, lpuCurDirLen, szDestDir, lpuDestDirLen ); } typedef DWORD APIENTRY FN_VerFindFileW( DWORD uFlags, LPWSTR szFileName, LPWSTR szWinDir, LPWSTR szAppDir, LPWSTR szCurDir, PUINT lpuCurDirLen, LPWSTR szDestDir, PUINT lpuDestDirLen ); __declspec(dllexport) DWORD APIENTRY kPrf2Wrap_VerFindFileW( DWORD uFlags, LPWSTR szFileName, LPWSTR szWinDir, LPWSTR szAppDir, LPWSTR szCurDir, PUINT lpuCurDirLen, LPWSTR szDestDir, PUINT lpuDestDirLen ) { static FN_VerFindFileW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "VerFindFileW", &g_Kernel32); return pfn( uFlags, szFileName, szWinDir, szAppDir, szCurDir, lpuCurDirLen, szDestDir, lpuDestDirLen ); } typedef DWORD APIENTRY FN_VerInstallFileA( DWORD uFlags, LPSTR szSrcFileName, LPSTR szDestFileName, LPSTR szSrcDir, LPSTR szDestDir, LPSTR szCurDir, LPSTR szTmpFile, PUINT lpuTmpFileLen ); __declspec(dllexport) DWORD APIENTRY kPrf2Wrap_VerInstallFileA( DWORD uFlags, LPSTR szSrcFileName, LPSTR szDestFileName, LPSTR szSrcDir, LPSTR szDestDir, LPSTR szCurDir, LPSTR szTmpFile, PUINT lpuTmpFileLen ) { static FN_VerInstallFileA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "VerInstallFileA", &g_Kernel32); return pfn( uFlags, szSrcFileName, szDestFileName, szSrcDir, szDestDir, szCurDir, szTmpFile, lpuTmpFileLen ); } typedef DWORD APIENTRY FN_VerInstallFileW( DWORD uFlags, LPWSTR szSrcFileName, LPWSTR szDestFileName, LPWSTR szSrcDir, LPWSTR szDestDir, LPWSTR szCurDir, LPWSTR szTmpFile, PUINT lpuTmpFileLen ); __declspec(dllexport) DWORD APIENTRY kPrf2Wrap_VerInstallFileW( DWORD uFlags, LPWSTR szSrcFileName, LPWSTR szDestFileName, LPWSTR szSrcDir, LPWSTR szDestDir, LPWSTR szCurDir, LPWSTR szTmpFile, PUINT lpuTmpFileLen ) { static FN_VerInstallFileW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "VerInstallFileW", &g_Kernel32); return pfn( uFlags, szSrcFileName, szDestFileName, szSrcDir, szDestDir, szCurDir, szTmpFile, lpuTmpFileLen ); } typedef DWORD APIENTRY FN_GetFileVersionInfoSizeA( LPCSTR lptstrFilename, LPDWORD lpdwHandle ); __declspec(dllexport) DWORD APIENTRY kPrf2Wrap_GetFileVersionInfoSizeA( LPCSTR lptstrFilename, LPDWORD lpdwHandle ) { static FN_GetFileVersionInfoSizeA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetFileVersionInfoSizeA", &g_Kernel32); return pfn( lptstrFilename, lpdwHandle ); } typedef DWORD APIENTRY FN_GetFileVersionInfoSizeW( LPCWSTR lptstrFilename, LPDWORD lpdwHandle ); __declspec(dllexport) DWORD APIENTRY kPrf2Wrap_GetFileVersionInfoSizeW( LPCWSTR lptstrFilename, LPDWORD lpdwHandle ) { static FN_GetFileVersionInfoSizeW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetFileVersionInfoSizeW", &g_Kernel32); return pfn( lptstrFilename, lpdwHandle ); } typedef BOOL APIENTRY FN_GetFileVersionInfoA( LPCSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData ); __declspec(dllexport) BOOL APIENTRY kPrf2Wrap_GetFileVersionInfoA( LPCSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData ) { static FN_GetFileVersionInfoA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetFileVersionInfoA", &g_Kernel32); return pfn( lptstrFilename, dwHandle, dwLen, lpData ); } typedef BOOL APIENTRY FN_GetFileVersionInfoW( LPCWSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData ); __declspec(dllexport) BOOL APIENTRY kPrf2Wrap_GetFileVersionInfoW( LPCWSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData ) { static FN_GetFileVersionInfoW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetFileVersionInfoW", &g_Kernel32); return pfn( lptstrFilename, dwHandle, dwLen, lpData ); } typedef DWORD APIENTRY FN_VerLanguageNameA( DWORD wLang, LPSTR szLang, DWORD nSize ); __declspec(dllexport) DWORD APIENTRY kPrf2Wrap_VerLanguageNameA( DWORD wLang, LPSTR szLang, DWORD nSize ) { static FN_VerLanguageNameA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "VerLanguageNameA", &g_Kernel32); return pfn( wLang, szLang, nSize ); } typedef DWORD APIENTRY FN_VerLanguageNameW( DWORD wLang, LPWSTR szLang, DWORD nSize ); __declspec(dllexport) DWORD APIENTRY kPrf2Wrap_VerLanguageNameW( DWORD wLang, LPWSTR szLang, DWORD nSize ) { static FN_VerLanguageNameW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "VerLanguageNameW", &g_Kernel32); return pfn( wLang, szLang, nSize ); } typedef BOOL APIENTRY FN_VerQueryValueA( const LPVOID pBlock, LPSTR lpSubBlock, LPVOID * lplpBuffer, PUINT puLen ); __declspec(dllexport) BOOL APIENTRY kPrf2Wrap_VerQueryValueA( const LPVOID pBlock, LPSTR lpSubBlock, LPVOID * lplpBuffer, PUINT puLen ) { static FN_VerQueryValueA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "VerQueryValueA", &g_Kernel32); return pfn( pBlock, lpSubBlock, lplpBuffer, puLen ); } typedef BOOL APIENTRY FN_VerQueryValueW( const LPVOID pBlock, LPWSTR lpSubBlock, LPVOID * lplpBuffer, PUINT puLen ); __declspec(dllexport) BOOL APIENTRY kPrf2Wrap_VerQueryValueW( const LPVOID pBlock, LPWSTR lpSubBlock, LPVOID * lplpBuffer, PUINT puLen ) { static FN_VerQueryValueW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "VerQueryValueW", &g_Kernel32); return pfn( pBlock, lpSubBlock, lplpBuffer, puLen ); } typedef VOID __cdecl FN_RtlRestoreContext( IN PCONTEXT ContextRecord, IN struct _EXCEPTION_RECORD * ExceptionRecord ); __declspec(dllexport) VOID __cdecl kPrf2Wrap_RtlRestoreContext( IN PCONTEXT ContextRecord, IN struct _EXCEPTION_RECORD * ExceptionRecord ) { static FN_RtlRestoreContext *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RtlRestoreContext", &g_Kernel32); pfn( ContextRecord, ExceptionRecord ); } typedef BOOLEAN __cdecl FN_RtlAddFunctionTable( IN PRUNTIME_FUNCTION FunctionTable, IN DWORD EntryCount, IN DWORD64 BaseAddress ); __declspec(dllexport) BOOLEAN __cdecl kPrf2Wrap_RtlAddFunctionTable( IN PRUNTIME_FUNCTION FunctionTable, IN DWORD EntryCount, IN DWORD64 BaseAddress ) { static FN_RtlAddFunctionTable *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RtlAddFunctionTable", &g_Kernel32); return pfn( FunctionTable, EntryCount, BaseAddress ); } typedef BOOLEAN __cdecl FN_RtlInstallFunctionTableCallback( IN DWORD64 TableIdentifier, IN DWORD64 BaseAddress, IN DWORD Length, IN PGET_RUNTIME_FUNCTION_CALLBACK Callback, IN PVOID Context, IN PCWSTR OutOfProcessCallbackDll ); __declspec(dllexport) BOOLEAN __cdecl kPrf2Wrap_RtlInstallFunctionTableCallback( IN DWORD64 TableIdentifier, IN DWORD64 BaseAddress, IN DWORD Length, IN PGET_RUNTIME_FUNCTION_CALLBACK Callback, IN PVOID Context, IN PCWSTR OutOfProcessCallbackDll ) { static FN_RtlInstallFunctionTableCallback *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RtlInstallFunctionTableCallback", &g_Kernel32); return pfn( TableIdentifier, BaseAddress, Length, Callback, Context, OutOfProcessCallbackDll ); } typedef BOOLEAN __cdecl FN_RtlDeleteFunctionTable( IN PRUNTIME_FUNCTION FunctionTable ); __declspec(dllexport) BOOLEAN __cdecl kPrf2Wrap_RtlDeleteFunctionTable( IN PRUNTIME_FUNCTION FunctionTable ) { static FN_RtlDeleteFunctionTable *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RtlDeleteFunctionTable", &g_Kernel32); return pfn( FunctionTable ); } typedef VOID NTAPI FN_RtlInitializeSListHead( IN PSLIST_HEADER ListHead ); __declspec(dllexport) VOID NTAPI kPrf2Wrap_RtlInitializeSListHead( IN PSLIST_HEADER ListHead ) { static FN_RtlInitializeSListHead *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RtlInitializeSListHead", &g_Kernel32); pfn( ListHead ); } typedef PSLIST_ENTRY NTAPI FN_RtlFirstEntrySList( IN const SLIST_HEADER * ListHead ); __declspec(dllexport) PSLIST_ENTRY NTAPI kPrf2Wrap_RtlFirstEntrySList( IN const SLIST_HEADER * ListHead ) { static FN_RtlFirstEntrySList *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RtlFirstEntrySList", &g_Kernel32); return pfn( ListHead ); } typedef PSLIST_ENTRY NTAPI FN_RtlInterlockedPopEntrySList( IN PSLIST_HEADER ListHead ); __declspec(dllexport) PSLIST_ENTRY NTAPI kPrf2Wrap_RtlInterlockedPopEntrySList( IN PSLIST_HEADER ListHead ) { static FN_RtlInterlockedPopEntrySList *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RtlInterlockedPopEntrySList", &g_Kernel32); return pfn( ListHead ); } typedef PSLIST_ENTRY NTAPI FN_RtlInterlockedPushEntrySList( IN PSLIST_HEADER ListHead, IN PSLIST_ENTRY ListEntry ); __declspec(dllexport) PSLIST_ENTRY NTAPI kPrf2Wrap_RtlInterlockedPushEntrySList( IN PSLIST_HEADER ListHead, IN PSLIST_ENTRY ListEntry ) { static FN_RtlInterlockedPushEntrySList *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RtlInterlockedPushEntrySList", &g_Kernel32); return pfn( ListHead, ListEntry ); } typedef PSLIST_ENTRY NTAPI FN_RtlInterlockedFlushSList( IN PSLIST_HEADER ListHead ); __declspec(dllexport) PSLIST_ENTRY NTAPI kPrf2Wrap_RtlInterlockedFlushSList( IN PSLIST_HEADER ListHead ) { static FN_RtlInterlockedFlushSList *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RtlInterlockedFlushSList", &g_Kernel32); return pfn( ListHead ); } typedef WORD NTAPI FN_RtlQueryDepthSList( IN PSLIST_HEADER ListHead ); __declspec(dllexport) WORD NTAPI kPrf2Wrap_RtlQueryDepthSList( IN PSLIST_HEADER ListHead ) { static FN_RtlQueryDepthSList *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RtlQueryDepthSList", &g_Kernel32); return pfn( ListHead ); } typedef VOID NTAPI FN_RtlCaptureContext( OUT PCONTEXT ContextRecord ); __declspec(dllexport) VOID NTAPI kPrf2Wrap_RtlCaptureContext( OUT PCONTEXT ContextRecord ) { static FN_RtlCaptureContext *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RtlCaptureContext", &g_Kernel32); pfn( ContextRecord ); } typedef SIZE_T NTAPI FN_RtlCompareMemory( const VOID * Source1, const VOID * Source2, SIZE_T Length ); __declspec(dllexport) SIZE_T NTAPI kPrf2Wrap_RtlCompareMemory( const VOID * Source1, const VOID * Source2, SIZE_T Length ) { static FN_RtlCompareMemory *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RtlCompareMemory", &g_Kernel32); return pfn( Source1, Source2, Length ); } typedef ULONGLONG NTAPI FN_VerSetConditionMask( IN ULONGLONG ConditionMask, IN DWORD TypeMask, IN BYTE Condition ); __declspec(dllexport) ULONGLONG NTAPI kPrf2Wrap_VerSetConditionMask( IN ULONGLONG ConditionMask, IN DWORD TypeMask, IN BYTE Condition ) { static FN_VerSetConditionMask *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "VerSetConditionMask", &g_Kernel32); return pfn( ConditionMask, TypeMask, Condition ); } typedef DWORD NTAPI FN_RtlSetHeapInformation( IN PVOID HeapHandle, IN HEAP_INFORMATION_CLASS HeapInformationClass, IN PVOID HeapInformation , IN SIZE_T HeapInformationLength ); __declspec(dllexport) DWORD NTAPI kPrf2Wrap_RtlSetHeapInformation( IN PVOID HeapHandle, IN HEAP_INFORMATION_CLASS HeapInformationClass, IN PVOID HeapInformation , IN SIZE_T HeapInformationLength ) { static FN_RtlSetHeapInformation *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RtlSetHeapInformation", &g_Kernel32); return pfn( HeapHandle, HeapInformationClass, HeapInformation , HeapInformationLength ); } typedef DWORD NTAPI FN_RtlQueryHeapInformation( IN PVOID HeapHandle, IN HEAP_INFORMATION_CLASS HeapInformationClass, OUT PVOID HeapInformation , IN SIZE_T HeapInformationLength , OUT PSIZE_T ReturnLength ); __declspec(dllexport) DWORD NTAPI kPrf2Wrap_RtlQueryHeapInformation( IN PVOID HeapHandle, IN HEAP_INFORMATION_CLASS HeapInformationClass, OUT PVOID HeapInformation , IN SIZE_T HeapInformationLength , OUT PSIZE_T ReturnLength ) { static FN_RtlQueryHeapInformation *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RtlQueryHeapInformation", &g_Kernel32); return pfn( HeapHandle, HeapInformationClass, HeapInformation , HeapInformationLength , ReturnLength ); } typedef HANDLE WINAPI FN_CreateToolhelp32Snapshot( DWORD dwFlags, DWORD th32ProcessID ); __declspec(dllexport) HANDLE WINAPI kPrf2Wrap_CreateToolhelp32Snapshot( DWORD dwFlags, DWORD th32ProcessID ) { static FN_CreateToolhelp32Snapshot *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "CreateToolhelp32Snapshot", &g_Kernel32); return pfn( dwFlags, th32ProcessID ); } typedef BOOL WINAPI FN_Heap32ListFirst( HANDLE hSnapshot, LPHEAPLIST32 lphl ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_Heap32ListFirst( HANDLE hSnapshot, LPHEAPLIST32 lphl ) { static FN_Heap32ListFirst *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "Heap32ListFirst", &g_Kernel32); return pfn( hSnapshot, lphl ); } typedef BOOL WINAPI FN_Heap32ListNext( HANDLE hSnapshot, LPHEAPLIST32 lphl ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_Heap32ListNext( HANDLE hSnapshot, LPHEAPLIST32 lphl ) { static FN_Heap32ListNext *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "Heap32ListNext", &g_Kernel32); return pfn( hSnapshot, lphl ); } typedef BOOL WINAPI FN_Heap32First( LPHEAPENTRY32 lphe, DWORD th32ProcessID, ULONG_PTR th32HeapID ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_Heap32First( LPHEAPENTRY32 lphe, DWORD th32ProcessID, ULONG_PTR th32HeapID ) { static FN_Heap32First *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "Heap32First", &g_Kernel32); return pfn( lphe, th32ProcessID, th32HeapID ); } typedef BOOL WINAPI FN_Heap32Next( LPHEAPENTRY32 lphe ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_Heap32Next( LPHEAPENTRY32 lphe ) { static FN_Heap32Next *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "Heap32Next", &g_Kernel32); return pfn( lphe ); } typedef BOOL WINAPI FN_Toolhelp32ReadProcessMemory( DWORD th32ProcessID, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T cbRead, SIZE_T * lpNumberOfBytesRead ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_Toolhelp32ReadProcessMemory( DWORD th32ProcessID, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T cbRead, SIZE_T * lpNumberOfBytesRead ) { static FN_Toolhelp32ReadProcessMemory *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "Toolhelp32ReadProcessMemory", &g_Kernel32); return pfn( th32ProcessID, lpBaseAddress, lpBuffer, cbRead, lpNumberOfBytesRead ); } typedef BOOL WINAPI FN_Process32FirstW( HANDLE hSnapshot, LPPROCESSENTRY32W lppe ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_Process32FirstW( HANDLE hSnapshot, LPPROCESSENTRY32W lppe ) { static FN_Process32FirstW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "Process32FirstW", &g_Kernel32); return pfn( hSnapshot, lppe ); } typedef BOOL WINAPI FN_Process32NextW( HANDLE hSnapshot, LPPROCESSENTRY32W lppe ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_Process32NextW( HANDLE hSnapshot, LPPROCESSENTRY32W lppe ) { static FN_Process32NextW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "Process32NextW", &g_Kernel32); return pfn( hSnapshot, lppe ); } typedef BOOL WINAPI FN_Process32First( HANDLE hSnapshot, LPPROCESSENTRY32 lppe ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_Process32First( HANDLE hSnapshot, LPPROCESSENTRY32 lppe ) { static FN_Process32First *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "Process32First", &g_Kernel32); return pfn( hSnapshot, lppe ); } typedef BOOL WINAPI FN_Process32Next( HANDLE hSnapshot, LPPROCESSENTRY32 lppe ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_Process32Next( HANDLE hSnapshot, LPPROCESSENTRY32 lppe ) { static FN_Process32Next *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "Process32Next", &g_Kernel32); return pfn( hSnapshot, lppe ); } typedef BOOL WINAPI FN_Thread32First( HANDLE hSnapshot, LPTHREADENTRY32 lpte ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_Thread32First( HANDLE hSnapshot, LPTHREADENTRY32 lpte ) { static FN_Thread32First *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "Thread32First", &g_Kernel32); return pfn( hSnapshot, lpte ); } typedef BOOL WINAPI FN_Thread32Next( HANDLE hSnapshot, LPTHREADENTRY32 lpte ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_Thread32Next( HANDLE hSnapshot, LPTHREADENTRY32 lpte ) { static FN_Thread32Next *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "Thread32Next", &g_Kernel32); return pfn( hSnapshot, lpte ); } typedef BOOL WINAPI FN_Module32FirstW( HANDLE hSnapshot, LPMODULEENTRY32W lpme ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_Module32FirstW( HANDLE hSnapshot, LPMODULEENTRY32W lpme ) { static FN_Module32FirstW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "Module32FirstW", &g_Kernel32); return pfn( hSnapshot, lpme ); } typedef BOOL WINAPI FN_Module32NextW( HANDLE hSnapshot, LPMODULEENTRY32W lpme ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_Module32NextW( HANDLE hSnapshot, LPMODULEENTRY32W lpme ) { static FN_Module32NextW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "Module32NextW", &g_Kernel32); return pfn( hSnapshot, lpme ); } typedef BOOL WINAPI FN_Module32First( HANDLE hSnapshot, LPMODULEENTRY32 lpme ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_Module32First( HANDLE hSnapshot, LPMODULEENTRY32 lpme ) { static FN_Module32First *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "Module32First", &g_Kernel32); return pfn( hSnapshot, lpme ); } typedef BOOL WINAPI FN_Module32Next( HANDLE hSnapshot, LPMODULEENTRY32 lpme ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_Module32Next( HANDLE hSnapshot, LPMODULEENTRY32 lpme ) { static FN_Module32Next *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "Module32Next", &g_Kernel32); return pfn( hSnapshot, lpme ); } typedef BOOL WINAPI FN_ReplaceFile( LPCSTR lpReplacedFileName, LPCSTR lpReplacementFileName, LPCSTR lpBackupFileName, DWORD dwReplaceFlags, LPVOID lpExclude, LPVOID lpReserved ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_ReplaceFile( LPCSTR lpReplacedFileName, LPCSTR lpReplacementFileName, LPCSTR lpBackupFileName, DWORD dwReplaceFlags, LPVOID lpExclude, LPVOID lpReserved ) { static FN_ReplaceFile *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "ReplaceFile", &g_Kernel32); return pfn( lpReplacedFileName, lpReplacementFileName, lpBackupFileName, dwReplaceFlags, lpExclude, lpReserved ); } typedef BOOL WINAPI FN_SetConsoleCursor( PVOID pvUnknown1, PVOID pvUnknown2 ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_SetConsoleCursor( PVOID pvUnknown1, PVOID pvUnknown2 ) { static FN_SetConsoleCursor *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "SetConsoleCursor", &g_Kernel32); return pfn( pvUnknown1, pvUnknown2 ); } typedef LPCH WINAPI FN_GetEnvironmentStringsA( VOID ); __declspec(dllexport) LPCH WINAPI kPrf2Wrap_GetEnvironmentStringsA( VOID ) { static FN_GetEnvironmentStringsA *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetEnvironmentStringsA", &g_Kernel32); return pfn (); } typedef BOOL WINAPI FN_GetBinaryType( LPCSTR lpApplicationName, LPDWORD lpBinaryType ); __declspec(dllexport) BOOL WINAPI kPrf2Wrap_GetBinaryType( LPCSTR lpApplicationName, LPDWORD lpBinaryType ) { static FN_GetBinaryType *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "GetBinaryType", &g_Kernel32); return pfn( lpApplicationName, lpBinaryType ); } typedef WORD NTAPI FN_RtlCaptureStackBackTrace( DWORD FramesToSkip, DWORD FramesToCapture, PVOID * BackTrace, PDWORD BackTraceHash ); __declspec(dllexport) WORD NTAPI kPrf2Wrap_RtlCaptureStackBackTrace( DWORD FramesToSkip, DWORD FramesToCapture, PVOID * BackTrace, PDWORD BackTraceHash ) { static FN_RtlCaptureStackBackTrace *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RtlCaptureStackBackTrace", &g_Kernel32); return pfn( FramesToSkip, FramesToCapture, BackTrace, BackTraceHash ); } typedef PVOID FN_RtlFillMemory( PVOID pv, int ch, SIZE_T cb ); __declspec(dllexport) PVOID kPrf2Wrap_RtlFillMemory( PVOID pv, int ch, SIZE_T cb ) { static FN_RtlFillMemory *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RtlFillMemory", &g_Kernel32); return pfn( pv, ch, cb ); } typedef PVOID FN_RtlZeroMemory( PVOID pv, SIZE_T cb ); __declspec(dllexport) PVOID kPrf2Wrap_RtlZeroMemory( PVOID pv, SIZE_T cb ) { static FN_RtlZeroMemory *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RtlZeroMemory", &g_Kernel32); return pfn( pv, cb ); } typedef PVOID FN_RtlMoveMemory( PVOID pvDst, PVOID pvSrc, SIZE_T cb ); __declspec(dllexport) PVOID kPrf2Wrap_RtlMoveMemory( PVOID pvDst, PVOID pvSrc, SIZE_T cb ) { static FN_RtlMoveMemory *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RtlMoveMemory", &g_Kernel32); return pfn( pvDst, pvSrc, cb ); } typedef VOID NTAPI FN_RtlUnwind( PVOID TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue ); __declspec(dllexport) VOID NTAPI kPrf2Wrap_RtlUnwind( PVOID TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue ) { static FN_RtlUnwind *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RtlUnwind", &g_Kernel32); pfn( TargetFrame, TargetIp, ExceptionRecord, ReturnValue ); } typedef VOID NTAPI FN_RtlUnwindEx( FRAME_POINTERS TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue, PCONTEXT ContextRecord, PUNWIND_HISTORY_TABLE HistoryTable ); __declspec(dllexport) VOID NTAPI kPrf2Wrap_RtlUnwindEx( FRAME_POINTERS TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue, PCONTEXT ContextRecord, PUNWIND_HISTORY_TABLE HistoryTable ) { static FN_RtlUnwindEx *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RtlUnwindEx", &g_Kernel32); pfn( TargetFrame, TargetIp, ExceptionRecord, ReturnValue, ContextRecord, HistoryTable ); } typedef ULONGLONG WINAPI FN_RtlVirtualUnwind( ULONG HandlerType, ULONGLONG ImageBase, ULONGLONG ControlPC, PRUNTIME_FUNCTION FunctionEntry, PCONTEXT ContextRecord, PBOOLEAN InFunction, PFRAME_POINTERS EstablisherFrame, PKNONVOLATILE_CONTEXT_POINTERS ContextPointers ); __declspec(dllexport) ULONGLONG WINAPI kPrf2Wrap_RtlVirtualUnwind( ULONG HandlerType, ULONGLONG ImageBase, ULONGLONG ControlPC, PRUNTIME_FUNCTION FunctionEntry, PCONTEXT ContextRecord, PBOOLEAN InFunction, PFRAME_POINTERS EstablisherFrame, PKNONVOLATILE_CONTEXT_POINTERS ContextPointers ) { static FN_RtlVirtualUnwind *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RtlVirtualUnwind", &g_Kernel32); return pfn( HandlerType, ImageBase, ControlPC, FunctionEntry, ContextRecord, InFunction, EstablisherFrame, ContextPointers ); } typedef PVOID WINAPI FN_RtlPcToFileHeader( PVOID PcValue, PVOID * BaseOfImage ); __declspec(dllexport) PVOID WINAPI kPrf2Wrap_RtlPcToFileHeader( PVOID PcValue, PVOID * BaseOfImage ) { static FN_RtlPcToFileHeader *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RtlPcToFileHeader", &g_Kernel32); return pfn( PcValue, BaseOfImage ); } typedef PVOID WINAPI FN_RtlLookupFunctionEntry( ULONGLONG ControlPC, PULONGLONG ImageBase, PULONGLONG TargetGp ); __declspec(dllexport) PVOID WINAPI kPrf2Wrap_RtlLookupFunctionEntry( ULONGLONG ControlPC, PULONGLONG ImageBase, PULONGLONG TargetGp ) { static FN_RtlLookupFunctionEntry *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RtlLookupFunctionEntry", &g_Kernel32); return pfn( ControlPC, ImageBase, TargetGp ); } typedef void WINAPI FN_RtlRaiseException(PEXCEPTION_RECORD pXcpRec); __declspec(dllexport) void WINAPI kPrf2Wrap_RtlRaiseException(PEXCEPTION_RECORD pXcpRec) { static FN_RtlRaiseException *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "RtlRaiseException", &g_Kernel32); pfn( pXcpRec); } typedef int WINAPI FN_uaw_lstrcmpW( LPCUWSTR lpString1, LPCUWSTR lpString2 ); __declspec(dllexport) int WINAPI kPrf2Wrap_uaw_lstrcmpW( LPCUWSTR lpString1, LPCUWSTR lpString2 ) { static FN_uaw_lstrcmpW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "uaw_lstrcmpW", &g_Kernel32); return pfn( lpString1, lpString2 ); } typedef int WINAPI FN_uaw_lstrcmpiW( LPCUWSTR lpString1, LPCUWSTR lpString2 ); __declspec(dllexport) int WINAPI kPrf2Wrap_uaw_lstrcmpiW( LPCUWSTR lpString1, LPCUWSTR lpString2 ) { static FN_uaw_lstrcmpiW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "uaw_lstrcmpiW", &g_Kernel32); return pfn( lpString1, lpString2 ); } typedef int WINAPI FN_uaw_lstrlenW( LPCUWSTR lpString ); __declspec(dllexport) int WINAPI kPrf2Wrap_uaw_lstrlenW( LPCUWSTR lpString ) { static FN_uaw_lstrlenW *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "uaw_lstrlenW", &g_Kernel32); return pfn( lpString ); } typedef LPUWSTR WINAPI FN_uaw_wcschr( LPCUWSTR lpString, WCHAR wc ); __declspec(dllexport) LPUWSTR WINAPI kPrf2Wrap_uaw_wcschr( LPCUWSTR lpString, WCHAR wc ) { static FN_uaw_wcschr *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "uaw_wcschr", &g_Kernel32); return pfn( lpString, wc ); } typedef LPUWSTR WINAPI FN_uaw_wcscpy( LPUWSTR lpDst, LPCUWSTR lpSrc ); __declspec(dllexport) LPUWSTR WINAPI kPrf2Wrap_uaw_wcscpy( LPUWSTR lpDst, LPCUWSTR lpSrc ) { static FN_uaw_wcscpy *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "uaw_wcscpy", &g_Kernel32); return pfn( lpDst, lpSrc ); } typedef int WINAPI FN_uaw_wcsicmp( LPCUWSTR lp1, LPCUWSTR lp2 ); __declspec(dllexport) int WINAPI kPrf2Wrap_uaw_wcsicmp( LPCUWSTR lp1, LPCUWSTR lp2 ) { static FN_uaw_wcsicmp *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "uaw_wcsicmp", &g_Kernel32); return pfn( lp1, lp2 ); } typedef SIZE_T WINAPI FN_uaw_wcslen( LPCUWSTR lp1 ); __declspec(dllexport) SIZE_T WINAPI kPrf2Wrap_uaw_wcslen( LPCUWSTR lp1 ) { static FN_uaw_wcslen *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "uaw_wcslen", &g_Kernel32); return pfn( lp1 ); } typedef LPUWSTR WINAPI FN_uaw_wcsrchr( LPCUWSTR lpString, WCHAR wc ); __declspec(dllexport) LPUWSTR WINAPI kPrf2Wrap_uaw_wcsrchr( LPCUWSTR lpString, WCHAR wc ) { static FN_uaw_wcsrchr *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "uaw_wcsrchr", &g_Kernel32); return pfn( lpString, wc ); } typedef LPSTR WINAPI FN_lstrcat( LPSTR lpString1, LPCSTR lpString2 ); __declspec(dllexport) LPSTR WINAPI kPrf2Wrap_lstrcat( LPSTR lpString1, LPCSTR lpString2 ) { static FN_lstrcat *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "lstrcat", &g_Kernel32); return pfn( lpString1, lpString2 ); } typedef int WINAPI FN_lstrcmp( LPCSTR lpString1, LPCSTR lpString2 ); __declspec(dllexport) int WINAPI kPrf2Wrap_lstrcmp( LPCSTR lpString1, LPCSTR lpString2 ) { static FN_lstrcmp *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "lstrcmp", &g_Kernel32); return pfn( lpString1, lpString2 ); } typedef int WINAPI FN_lstrcmpi( LPCSTR lpString1, LPCSTR lpString2 ); __declspec(dllexport) int WINAPI kPrf2Wrap_lstrcmpi( LPCSTR lpString1, LPCSTR lpString2 ) { static FN_lstrcmpi *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "lstrcmpi", &g_Kernel32); return pfn( lpString1, lpString2 ); } typedef LPSTR WINAPI FN_lstrcpy( LPSTR lpString1, LPCSTR lpString2 ); __declspec(dllexport) LPSTR WINAPI kPrf2Wrap_lstrcpy( LPSTR lpString1, LPCSTR lpString2 ) { static FN_lstrcpy *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "lstrcpy", &g_Kernel32); return pfn( lpString1, lpString2 ); } typedef LPSTR WINAPI FN_lstrcpyn( LPSTR lpString1, LPCSTR lpString2, int iMaxLength ); __declspec(dllexport) LPSTR WINAPI kPrf2Wrap_lstrcpyn( LPSTR lpString1, LPCSTR lpString2, int iMaxLength ) { static FN_lstrcpyn *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "lstrcpyn", &g_Kernel32); return pfn( lpString1, lpString2, iMaxLength ); } typedef int WINAPI FN_lstrlen( LPCSTR lpString ); __declspec(dllexport) int WINAPI kPrf2Wrap_lstrlen( LPCSTR lpString ) { static FN_lstrlen *pfn = 0; if (!pfn) kPrf2WrapResolve((void **)&pfn, "lstrlen", &g_Kernel32); return pfn( lpString ); } kbuild-3149/src/lib/kStuff/kProfiler2/kPrf2WinApiWrapperHlp.c0000644000175000017500000000360713252530254023776 0ustar locutuslocutus/* $Id: kPrf2WinApiWrapperHlp.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * Helpers for the Windows API wrapper DLL. */ /* * Copyright (c) 2008 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include "kPRf2WinApiWRapperHlp.h" FARPROC kPrf2WrapResolve(void **ppfn, const char *pszName, PKPRF2WRAPDLL pDll) { FARPROC pfn; HMODULE hmod = pDll->hmod; if (hmod == INVALID_HANDLE_VALUE) { hmod = LoadLibraryA(pDll->szName); pDll->hmod = hmod; } pfn = GetProcAddress(hmod, pszName); *ppfn = (void *)pfn; return pfn; } kbuild-3149/src/lib/kStuff/kCpu/0000755000175000017500000000000013252530254016406 5ustar locutuslocutuskbuild-3149/src/lib/kStuff/kCpu/kCpuGetArchAndCpu.c0000644000175000017500000000403413252530254022006 0ustar locutuslocutus/* $Id: kCpuGetArchAndCpu.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kCpu - kCpuGetArchAndCpu. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include /** * Gets the arch+cpu of the calling cpu. * * @param penmArch Where to store the cpu architecture. * @param penmCpu Where to store the cpu brand/model. */ KCPU_DECL(void) kCpuGetArchAndCpu(PKCPUARCH penmArch, PKCPU penmCpu) { #if K_ARCH == K_ARCH_AMD64 *penmArch = KCPUARCH_AMD64; *penmCpu = KCPU_AMD64_BLEND; /** @todo check it using cpu. */ #elif K_ARCH == K_ARCH_X86_32 *penmArch = KCPUARCH_X86_32; *penmCpu = KCPU_X86_32_BLEND; /** @todo check it using cpu. */ #else # error "Port me" #endif } kbuild-3149/src/lib/kStuff/kCpu/Makefile.kmk0000644000175000017500000000271213252530254020631 0ustar locutuslocutus# $Id: Makefile.kmk 29 2009-07-01 20:30:29Z bird $ ## @file # kCpu - The CPU and Architecture API, sub-makefile. # # # Copyright (c) 2006-2007 Knut St. Osmundsen # # 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. # DEPTH ?= .. SUB_DEPTH = .. include $(PATH_KBUILD)/subheader.kmk LIBRARIES += kCpuStatic kCpuStatic_TEMPLATE = kStuffLIB kCpuStatic_SOURCES = \ kCpuCompare.c \ kCpuGetArchAndCpu.c include $(PATH_KBUILD)/subfooter.kmk kbuild-3149/src/lib/kStuff/kCpu/kCpuCompare.c0000644000175000017500000001134713252530254020771 0ustar locutuslocutus/* $Id: kCpuCompare.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kCpu - kCpuCompare. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include /** * Compares arch+cpu some code was generated for with a arch+cpu for executing it * to see if it'll work out fine or not. * * @returns 0 if the code is compatible with the cpu. * @returns KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE if the arch+cpu isn't compatible with the code. * * @param enmCodeArch The architecture the code was generated for. * @param enmCodeCpu The cpu the code was generated for. * @param enmArch The architecture to run it on. * @param enmCpu The cpu to run it on. */ KCPU_DECL(int) kCpuCompare(KCPUARCH enmCodeArch, KCPU enmCodeCpu, KCPUARCH enmArch, KCPU enmCpu) { /* * Compare arch and cpu. */ if (enmCodeArch != enmArch) return KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; /* exact match is nice. */ if (enmCodeCpu == enmCpu) return 0; switch (enmArch) { case K_ARCH_X86_16: if (enmCpu < KCPU_FIRST_X86_16 || enmCpu > KCPU_LAST_X86_16) return KERR_INVALID_PARAMETER; /* intel? */ if (enmCodeCpu <= KCPU_CORE2_16) { /* also intel? */ if (enmCpu <= KCPU_CORE2_16) return enmCodeCpu <= enmCpu ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; switch (enmCpu) { case KCPU_K6_16: return enmCodeCpu <= KCPU_I586 ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; case KCPU_K7_16: case KCPU_K8_16: default: return enmCodeCpu <= KCPU_I686 ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; } } /* amd */ return enmCpu >= KCPU_K6_16 && enmCpu <= KCPU_K8_16 ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; case K_ARCH_X86_32: if (enmCpu < KCPU_FIRST_X86_32 || enmCpu > KCPU_LAST_X86_32) return KERR_INVALID_PARAMETER; /* blend? */ if (enmCodeCpu == KCPU_X86_32_BLEND) return 0; /* intel? */ if (enmCodeCpu <= KCPU_CORE2_32) { /* also intel? */ if (enmCpu <= KCPU_CORE2_32) return enmCodeCpu <= enmCpu ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; switch (enmCpu) { case KCPU_K6: return enmCodeCpu <= KCPU_I586 ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; case KCPU_K7: case KCPU_K8_32: default: return enmCodeCpu <= KCPU_I686 ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; } } /* amd */ return enmCpu >= KCPU_K6 && enmCpu <= KCPU_K8_32 ? 0 : KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; case K_ARCH_AMD64: if (enmCpu < KCPU_FIRST_AMD64 || enmCpu > KCPU_LAST_AMD64) return KERR_INVALID_PARAMETER; /* blend? */ if (enmCodeCpu == KCPU_AMD64_BLEND) return 0; /* this is simple for now. */ return KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; default: break; } return KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; } kbuild-3149/src/lib/kStuff/kRdr/0000755000175000017500000000000013252530254016406 5ustar locutuslocutuskbuild-3149/src/lib/kStuff/kRdr/Makefile.kmk0000644000175000017500000000305113252530254020626 0ustar locutuslocutus# $Id: Makefile.kmk 29 2009-07-01 20:30:29Z bird $ ## @file # kRdr - The File Provider, sub-makefile. # # # Copyright (c) 2006-2007 Knut St. Osmundsen # # 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. # DEPTH ?= .. SUB_DEPTH = .. include $(PATH_KBUILD)/subheader.kmk # # kRdrStatic - The file provider module. # LIBRARIES += kRdrStatic kRdrStatic_TEMPLATE = kStuffLIB kRdrStatic_DEFS = KDBG_BUILDING kRdrStatic_SOURCES = \ kRdr.cpp \ kRdrFile.cpp \ kRdrBuffered.cpp # Generate the rules include $(PATH_KBUILD)/subfooter.kmk kbuild-3149/src/lib/kStuff/kRdr/kRdrBuffered.cpp0000644000175000017500000005546513252530254021476 0ustar locutuslocutus/* $Id: kRdrBuffered.cpp 79 2016-07-27 14:25:09Z bird $ */ /** @file * kRdrBuffered - Buffered File Provider. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "kRdrInternal.h" #include #include /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * The buffered file provier instance. * This is just a wrapper around another file provider. */ typedef struct KRDRBUF { /** The file reader vtable. */ KRDR Core; /** The actual file provider that we're wrapping. */ PKRDR pRdr; /** The current file offset. */ KFOFF offFile; /** The file size. */ KFOFF cbFile; /** The offset of the buffer. */ KFOFF offBuf; /** The offset of the end of the buffer. */ KFOFF offBufEnd; /** The number of valid buffer bytes. */ KSIZE cbBufValid; /** The size of the buffer. */ KSIZE cbBuf; /** The buffer. */ KU8 *pbBuf; /** Whether the pRdr instance should be closed together with us or not. */ KBOOL fCloseIt; /** Set if the buffer has been messed up by kRdrBufLineQ. */ KBOOL fTainedByLineQ; } KRDRBUF, *PKRDRBUF; /******************************************************************************* * Internal Functions * *******************************************************************************/ static void krdrBufDone(PKRDR pRdr); static int krdrBufUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments); static int krdrBufProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect); static int krdrBufRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments); static int krdrBufMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed); static KSIZE krdrBufPageSize(PKRDR pRdr); static const char *krdrBufName(PKRDR pRdr); static KIPTR krdrBufNativeFH(PKRDR pRdr); static KFOFF krdrBufTell(PKRDR pRdr); static KFOFF krdrBufSize(PKRDR pRdr); static int krdrBufAllUnmap(PKRDR pRdr, const void *pvBits); static int krdrBufAllMap(PKRDR pRdr, const void **ppvBits); static int krdrBufRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off); static int krdrBufDestroy(PKRDR pRdr); static int krdrBufCreate(PPKRDR ppRdr, const char *pszFilename); /******************************************************************************* * Global Variables * *******************************************************************************/ /** Native file provider operations. * * @remark This is not in the file provider list as its intended for wrapping * other kRdr instances. */ static const KRDROPS g_krdrBufOps = { "Buffered kRdr", NULL, krdrBufCreate, krdrBufDestroy, krdrBufRead, krdrBufAllMap, krdrBufAllUnmap, krdrBufSize, krdrBufTell, krdrBufName, krdrBufNativeFH, krdrBufPageSize, krdrBufMap, krdrBufRefresh, krdrBufProtect, krdrBufUnmap, krdrBufDone, 42 }; /** @copydoc KRDROPS::pfnDone */ static void krdrBufDone(PKRDR pRdr) { PKRDRBUF pThis = (PKRDRBUF)pRdr; return pThis->pRdr->pOps->pfnDone(pThis->pRdr); } /** @copydoc KRDROPS::pfnUnmap */ static int krdrBufUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments) { PKRDRBUF pThis = (PKRDRBUF)pRdr; return pThis->pRdr->pOps->pfnUnmap(pThis->pRdr, pvBase, cSegments, paSegments); } /** @copydoc KRDROPS::pfnProtect */ static int krdrBufProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect) { PKRDRBUF pThis = (PKRDRBUF)pRdr; return pThis->pRdr->pOps->pfnProtect(pThis->pRdr, pvBase, cSegments, paSegments, fUnprotectOrProtect); } /** @copydoc KRDROPS::pfnRefresh */ static int krdrBufRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments) { PKRDRBUF pThis = (PKRDRBUF)pRdr; return pThis->pRdr->pOps->pfnRefresh(pThis->pRdr, pvBase, cSegments, paSegments); } /** @copydoc KRDROPS::pfnMap */ static int krdrBufMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed) { PKRDRBUF pThis = (PKRDRBUF)pRdr; return pThis->pRdr->pOps->pfnMap(pThis->pRdr, ppvBase, cSegments, paSegments, fFixed); } /** @copydoc KRDROPS::pfnPageSize */ static KSIZE krdrBufPageSize(PKRDR pRdr) { PKRDRBUF pThis = (PKRDRBUF)pRdr; return pThis->pRdr->pOps->pfnPageSize(pThis->pRdr); } /** @copydoc KRDROPS::pfnName */ static const char *krdrBufName(PKRDR pRdr) { PKRDRBUF pThis = (PKRDRBUF)pRdr; return pThis->pRdr->pOps->pfnName(pThis->pRdr); } /** @copydoc KRDROPS::pfnNativeFH */ static KIPTR krdrBufNativeFH(PKRDR pRdr) { PKRDRBUF pThis = (PKRDRBUF)pRdr; return pThis->pRdr->pOps->pfnNativeFH(pThis->pRdr); } /** @copydoc KRDROPS::pfnTell */ static KFOFF krdrBufTell(PKRDR pRdr) { PKRDRBUF pThis = (PKRDRBUF)pRdr; return pThis->offFile; } /** @copydoc KRDROPS::pfnSize */ static KFOFF krdrBufSize(PKRDR pRdr) { PKRDRBUF pThis = (PKRDRBUF)pRdr; return pThis->cbFile; } /** @copydoc KRDROPS::pfnAllUnmap */ static int krdrBufAllUnmap(PKRDR pRdr, const void *pvBits) { PKRDRBUF pThis = (PKRDRBUF)pRdr; return pThis->pRdr->pOps->pfnAllUnmap(pThis->pRdr, pvBits); } /** @copydoc KRDROPS::pfnAllMap */ static int krdrBufAllMap(PKRDR pRdr, const void **ppvBits) { PKRDRBUF pThis = (PKRDRBUF)pRdr; return pThis->pRdr->pOps->pfnAllMap(pThis->pRdr, ppvBits); } /** * Fills the buffer with file bits starting at the specified offset. * * @returns 0 on success, pfnRead error code on failure. * @param pThis The instance. * @param off Where to start reading. */ static int krdrBufFillBuffer(PKRDRBUF pThis, KFOFF off) { kRdrAssert(off < pThis->cbFile); /* Reposition the buffer if it's past the end of the file so that we maximize its usability. We leave one unused byte at the end of the buffer so kRdrBufLineQ can terminate its string properly. Of course, this might end up re-reading a lot of stuff for no future gain, but whatever... */ kRdrAssert(pThis->cbBuf <= pThis->cbFile + 1); KFOFF cbLeft = pThis->cbFile - off; KSIZE cbRead = pThis->cbBuf; if ((KSSIZE)cbRead - 1 >= cbLeft) { cbRead--; off = pThis->cbFile - cbRead; } int rc = pThis->pRdr->pOps->pfnRead(pThis->pRdr, pThis->pbBuf, cbRead, off); if (!rc) { pThis->offBuf = off; pThis->offBufEnd = off + cbRead; pThis->cbBufValid = cbRead; } else { pThis->offBuf = pThis->offBufEnd = 0; pThis->cbBufValid = 0; } pThis->fTainedByLineQ = K_FALSE; return rc; } /** @copydoc KRDROPS::pfnRead */ static int krdrBufRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off) { PKRDRBUF pThis = (PKRDRBUF)pRdr; /* * We need to validate and update the file offset before * we start making partial reads from the buffer and stuff. */ KFOFF offEnd = off + cb; if ( off >= pThis->cbFile || offEnd > pThis->cbFile || offEnd < off) return KERR_OUT_OF_RANGE; /* includes EOF. */ pThis->offFile = offEnd; if (!cb) return 0; /* * Scratch the buffer if kRdrBufLineQ has tained it. */ if (pThis->fTainedByLineQ) { pThis->offBuf = pThis->offBufEnd = 0; pThis->cbBufValid = 0; } /* * Is any part of the request in the buffer? * * We will currently ignore buffer hits in the middle of the * request because it's annoying to implement and it's * questionable whether it'll benefit much performance wise. */ if (pThis->cbBufValid > 0) { if (off >= pThis->offBuf) { if (off < pThis->offBufEnd) { /* head (or all) of the request is in the buffer. */ KSIZE cbMaxChunk = (KSIZE)(pThis->offBufEnd - off); KSIZE cbChunk = K_MIN(cb, cbMaxChunk); kHlpMemCopy(pvBuf, &pThis->pbBuf[off - pThis->offBuf], cbChunk); if (cbChunk == cb) return 0; cb -= cbChunk; pvBuf = (KU8 *)pvBuf + cbChunk; off += cbChunk; } } else if ( offEnd > pThis->offBuf && offEnd <= pThis->offBufEnd) { /* the end of the request is in the buffer. */ KSIZE cbChunk = (KSIZE)(pThis->offBufEnd - (offEnd)); kHlpMemCopy((KU8 *)pvBuf + (pThis->offBuf - off), pThis->pbBuf, cbChunk); kRdrAssert(cbChunk < cb); cb -= cbChunk; offEnd -= cbChunk; } } /* * If the buffer is larger than the read request, read a full buffer * starting at the requested offset. Otherwise perform an unbuffered * read. */ if (pThis->cbBuf > cb) { int rc = krdrBufFillBuffer(pThis, off); if (rc) return rc; if (pThis->offBuf == off) kHlpMemCopy(pvBuf, pThis->pbBuf, cb); else { kRdrAssert(off > pThis->offBuf); kRdrAssert(off + cb <= pThis->offBufEnd); kHlpMemCopy(pvBuf, pThis->pbBuf + (off - pThis->offBuf), cb); } } else { int rc = pThis->pRdr->pOps->pfnRead(pThis->pRdr, pvBuf, cb, off); if (rc) return rc; } return 0; } /** @copydoc KRDROPS::pfnDestroy */ static int krdrBufDestroy(PKRDR pRdr) { PKRDRBUF pThis = (PKRDRBUF)pRdr; /* Close the kRdr instance that we're wrapping. */ if (pThis->fCloseIt) { int rc = pThis->pRdr->pOps->pfnDestroy(pThis->pRdr); if (rc) return rc; pThis->fCloseIt = K_FALSE; pThis->pRdr = NULL; } kHlpFree(pThis->pbBuf); pThis->pbBuf = NULL; kHlpFree(pRdr); return 0; } /** @copydoc KRDROPS::pfnCreate */ static int krdrBufCreate(PPKRDR ppRdr, const char *pszFilename) { K_NOREF(ppRdr); K_NOREF(pszFilename); return KERR_NOT_IMPLEMENTED; } /** * Worker for kRdrBufOpen and kRdrBufWrap. * * It's essentially kRdrBufWrap without error checking. * * @returns 0 on success, one of the kErrors status code on failure. * @param ppRdr Where to store the new file provider instance. * @param pRdrWrapped The file provider instance to buffer. * @param fCloseIt Whether it the pRdrWrapped instance should be closed * when the new instance is closed. */ static int krdrBufWrapIt(PPKRDR ppRdr, PKRDR pRdrWrapped, KBOOL fCloseIt) { PKRDRBUF pThis = (PKRDRBUF)kHlpAlloc(sizeof(*pThis)); if (pThis) { pThis->Core.u32Magic = KRDR_MAGIC; pThis->Core.pOps = &g_krdrBufOps; pThis->pRdr = pRdrWrapped; pThis->offFile = pRdrWrapped->pOps->pfnTell(pRdrWrapped); pThis->cbFile = pRdrWrapped->pOps->pfnSize(pRdrWrapped); pThis->offBuf = pThis->offBufEnd = 0; pThis->cbBufValid = 0; pThis->fCloseIt = fCloseIt; pThis->fTainedByLineQ = K_FALSE; if (pThis->cbFile < 128*1024) pThis->cbBuf = (KSIZE)pThis->cbFile + 1; /* need space for the kRdrBufLineQ terminator. */ else pThis->cbBuf = 64*1024; pThis->pbBuf = (KU8 *)kHlpAlloc(pThis->cbBuf); if (pThis->pbBuf) { *ppRdr = &pThis->Core; return 0; } pThis->Core.u32Magic = 0; kHlpFree(pThis); } return KERR_NO_MEMORY; } /** * Opens a file provider with a buffered wrapper. * * @returns 0 on success, KERR_* on failure. * @param ppRdr Where to store the buffered file reader instance on success. * @param pszFilename The name of the file that should be opened. */ KRDR_DECL(int) kRdrBufOpen(PPKRDR ppRdr, const char *pszFilename) { kRdrAssertPtrReturn(ppRdr, KERR_INVALID_POINTER); *ppRdr = NULL; PKRDR pRdrWrapped; int rc = kRdrOpen(&pRdrWrapped, pszFilename); if (!rc) { rc = krdrBufWrapIt(ppRdr, pRdrWrapped, K_TRUE); if (rc) kRdrClose(pRdrWrapped); } return rc; } /** * Creates a buffered file provider instance for an existing one. * * @returns 0 on success, KERR_* on failure. * @param ppRdr Where to store the new file provider pointer. * @param pRdr The file provider instance to wrap. * @param fCLoseIt Whether it the wrapped reader should be automatically * closed when the wrapper closes. */ KRDR_DECL(int) kRdrBufWrap(PPKRDR ppRdr, PKRDR pRdr, KBOOL fCloseIt) { KRDR_VALIDATE(pRdr); return krdrBufWrapIt(ppRdr, pRdr, fCloseIt); } /** * Checks whether the file provider instance is of the buffered type or not. * * @returns K_TRUE if it is, otherwise K_FALSE. * @param pRdr The file provider instance to check. */ KRDR_DECL(KBOOL) kRdrBufIsBuffered(PKRDR pRdr) { KRDR_VALIDATE_EX(pRdr, K_FALSE); return pRdr->pOps == &g_krdrBufOps; } /** * Reads a line from a buffered file provider. * * The trailing '\n' or '\r\n' is stripped. * * @returns 0 on success. KERR_* on failure. * @retval KRDR_ERR_LINE_TOO_LONG if the line is too long to fit in the passed in buffer. * @retval KRDR_ERR_NOT_BUFFERED_RDR if pRdr isn't a buffered reader. * @param pRdr The buffered file reader. * @param pszLine Where to store the line. * @param cbLine The size of the the line buffer. */ KRDR_DECL(int) kRdrBufLine(PKRDR pRdr, char *pszLine, KSIZE cbLine) { return kRdrBufLineEx(pRdr, pszLine, &cbLine); } /** * Reads a line from a buffered file provider. * * The trailing '\n' or '\r\n' is stripped. * * @returns 0 on success. KERR_* on failure. * @retval KRDR_ERR_LINE_TOO_LONG if the line is too long to fit in the passed in buffer. * @retval KRDR_ERR_NOT_BUFFERED_RDR if pRdr isn't a buffered reader. * @param pRdr The buffered file reader. * @param pszLine Where to store the line. * @param pcbLine The size of the the line buffer on input, the length of the * returned line on output. */ KRDR_DECL(int) kRdrBufLineEx(PKRDR pRdr, char *pszLine, KSIZE *pcbLine) { /* * Validate input. */ kRdrAssertPtrReturn(pcbLine, KERR_INVALID_POINTER); KSIZE cbLeft = *pcbLine; *pcbLine = 0; kRdrAssertReturn(cbLeft > 0, KERR_INVALID_PARAMETER); KRDR_VALIDATE(pRdr); kRdrAssertReturn(pRdr->pOps != &g_krdrBufOps, KRDR_ERR_NOT_BUFFERED_RDR); kRdrAssertPtrReturn(pszLine, KERR_INVALID_POINTER); /* check for EOF */ PKRDRBUF pThis = (PKRDRBUF)pRdr; if (pThis->offFile >= pThis->cbFile) { kRdrAssert(pThis->offFile == pThis->cbFile); *pszLine = '\0'; *pcbLine = 0; return KERR_EOF; } /* * Scratch the buffer if kRdrBufLineQ has tained it. */ if (pThis->fTainedByLineQ) { pThis->offBuf = pThis->offBufEnd = 0; pThis->cbBufValid = 0; } /* * Buffered read loop. * * The overflow logic is a bit fishy wrt to overflowing at an "\r\n" * that arrives at a buffer boundrary. The current policy is to try * our best to not to fail with overflow in the EOL sequence or EOF. * If it's the end of the buffer, it will not be refilled just to * check for this because that's too much work. */ cbLeft--; /* reserve space for the terminator. */ char *pszOut = pszLine; for (;;) { /* * Do we need to (re-)fill the buffer or does it contain something * that we can work on already? */ if ( !pThis->cbBufValid || pThis->offFile >= pThis->offBufEnd || pThis->offFile < pThis->offBuf) { int rc = krdrBufFillBuffer(pThis, pThis->offFile); if (rc) { *pszOut = '\0'; return rc; } } /* * Parse the buffer looking for the EOL indicator. */ kRdrAssert(pThis->offFile >= pThis->offBuf && pThis->offFile < pThis->offBufEnd); kRdrAssert(sizeof(char) == sizeof(*pThis->pbBuf)); const char * const pszStart = (const char *)&pThis->pbBuf[pThis->offFile - pThis->offBuf]; const char * const pszEnd = (const char *)&pThis->pbBuf[pThis->cbBufValid]; const char *psz = pszStart; while (psz < pszEnd) { const char ch = *psz; if (ch == '\n') { /* found the EOL, update file position and line length. */ pThis->offFile += psz - pszStart + 1; *pcbLine += psz - pszStart; /* terminate the string, checking for "\r\n" first. */ if ( *pcbLine && pszOut[-1] == '\r') { *pcbLine -= 1; pszOut--; } *pszOut = '\0'; return 0; } if (!cbLeft) { /* the line is *probably* too long. */ pThis->offFile += psz - pszStart; *pcbLine += psz - pszStart; *pszOut = '\0'; /* The only possible case where the line actually isn't too long is if we're at a "\r\n" sequence. We will re-fill the buffer if necessary to check for the '\n' as it's not that much work. */ if ( ch == '\r' && pThis->offFile + 2 <= pThis->cbFile) { if (psz + 1 >= pszEnd) { int rc = krdrBufFillBuffer(pThis, pThis->offFile); if (rc) { *pszOut = '\0'; return rc; } } psz = (const char *)&pThis->pbBuf[pThis->offFile - pThis->offBuf]; kRdrAssert(*psz == '\r'); if (psz[1] == '\n') { *pcbLine -= 1; pszOut[-1] = '\0'; pThis->offFile += 2; return 0; } } return KRDR_ERR_LINE_TOO_LONG; } /* copy and advance */ *pszOut++ = ch; cbLeft--; psz++; } /* advance past the buffer and check for EOF. */ *pcbLine += pszEnd - pszStart; pThis->offFile = pThis->offBufEnd; if (pThis->offFile >= pThis->cbFile) { kRdrAssert(pThis->offFile == pThis->cbFile); *pszOut = '\0'; return 0; } } } /** * Worker for kRdrBufLineQ that searches the current buffer for EOL or EOF. * * When a EOF marker is found * * * @returns NULL if EOL/EOF isn't found the buffer. * @param pThis The buffered reader instance. */ static const char * krdrBufLineQWorker(PKRDRBUF pThis) { kRdrAssert(pThis->offFile >= pThis->offBuf && pThis->offFile < pThis->offBufEnd); /* * Search the buffer. */ kRdrAssert(sizeof(char) == sizeof(*pThis->pbBuf)); const char * const pszStart = (const char *)&pThis->pbBuf[pThis->offFile - pThis->offBuf]; const char * const pszEnd = (const char *)&pThis->pbBuf[pThis->cbBufValid]; char *psz = (char *)pszStart; while (psz < pszEnd) { char ch = *psz; if (ch == '\n') { pThis->offFile += psz - pszStart; pThis->fTainedByLineQ = K_TRUE; *psz = '\0'; if ( psz > pszStart && psz[-1] == '\r') *--psz = '\0'; return pszStart; } psz++; } /* * Check for EOF. There must be room for a terminator char here. */ if ( pThis->offBufEnd >= pThis->cbFile && (pThis->offBufEnd - pThis->offBuf) < (KSSIZE)pThis->cbBuf) { pThis->offFile = pThis->cbFile; pThis->pbBuf[pThis->cbBufValid] = '\0'; return pszStart; } return NULL; } /** * Get the pointer to the next next line in the buffer. * The returned line is zero terminated. * * @returns A pointer to the line on success. This becomes invalid * upon the next call to this kRdr instance. * @returns NULL on EOF, read error of if the line was too long. * @param pRdr The buffered file reader. */ KRDR_DECL(const char *) kRdrBufLineQ(PKRDR pRdr) { /* * Validate input. */ KRDR_VALIDATE_EX(pRdr, NULL); kRdrAssertReturn(pRdr->pOps != &g_krdrBufOps, NULL); /* check for EOF */ PKRDRBUF pThis = (PKRDRBUF)pRdr; if (pThis->offFile >= pThis->cbFile) { kRdrAssert(pThis->offFile == pThis->cbFile); return NULL; } /* * Search the current buffer if possible */ if ( pThis->cbBufValid && pThis->offFile >= pThis->offBuf && pThis->offFile < pThis->offBufEnd) { const char *psz = krdrBufLineQWorker(pThis); if (psz) return psz; } /* * Fill the buffer in an optimal way and look for the EOL/EOF (again). */ int rc = krdrBufFillBuffer(pThis, pThis->offFile); if (rc) return NULL; return krdrBufLineQWorker(pThis); } kbuild-3149/src/lib/kStuff/kRdr/kRdr.cpp0000644000175000017500000002157113252530254020022 0ustar locutuslocutus/* $Id: kRdr.cpp 29 2009-07-01 20:30:29Z bird $ */ /** @file * kRdr - The File Provider. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "kRdrInternal.h" /******************************************************************************* * Global Variables * *******************************************************************************/ /** The list of file providers. */ static PCKRDROPS g_pRdrHead = &g_kRdrFileOps; /** * Adds a new file provider. * * @param pAdd The new file provider. */ KRDR_DECL(void) kRdrAddProvider(PKRDROPS pAdd) { pAdd->pNext = g_pRdrHead; g_pRdrHead = pAdd; } /** * Tries to opens a file. * * @returns 0 on success, OS status code on failure. * @param ppRdr Where to store the file provider instance. * @param pszFilename The filename. */ KRDR_DECL(int) kRdrOpen(PPKRDR ppRdr, const char *pszFilename) { int rc = -1; PCKRDROPS pCur; for (pCur = g_pRdrHead; pCur; pCur = pCur->pNext) { rc = pCur->pfnCreate(ppRdr, pszFilename); if (!rc) return 0; } return rc; } /** * Closes the file. * * @returns 0 on success, OS specific error code on failure. * On failure, the file provider instance will be in an indeterminate state - don't touch it! * @param pRdr The file provider instance. */ KRDR_DECL(int) kRdrClose(PKRDR pRdr) { KRDR_VALIDATE(pRdr); return pRdr->pOps->pfnDestroy(pRdr); } /** Read bits from the file. * * @returns 0 on success, OS specific error code on failure. * @param pRdr The file provider instance. * @param pvBuf Where to put the bits. * @param cb The number of bytes to read. * @param off Where to start reading. */ KRDR_DECL(int) kRdrRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off) { KRDR_VALIDATE(pRdr); return pRdr->pOps->pfnRead(pRdr, pvBuf, cb, off); } /** Map all the file bits into memory (read only). * * @returns 0 on success, OS specific error code on failure. * @param pRdr The file provider instance. * @param ppvBits Where to store the address of the mapping. * The size can be obtained using pfnSize. */ KRDR_DECL(int) kRdrAllMap(PKRDR pRdr, const void **ppvBits) { KRDR_VALIDATE(pRdr); return pRdr->pOps->pfnAllMap(pRdr, ppvBits); } /** Unmap a file bits mapping obtained by KRDROPS::pfnAllMap. * * @returns 0 on success, OS specific error code on failure. * @param pRdr The file provider instance. * @param pvBits The mapping address. */ KRDR_DECL(int) kRdrAllUnmap(PKRDR pRdr, const void *pvBits) { KRDR_VALIDATE(pRdr); return pRdr->pOps->pfnAllUnmap(pRdr, pvBits); } /** Get the file size. * * @returns The file size. Returns -1 on failure. * @param pRdr The file provider instance. */ KRDR_DECL(KFOFF) kRdrSize(PKRDR pRdr) { KRDR_VALIDATE(pRdr); return pRdr->pOps->pfnSize(pRdr); } /** Get the file pointer offset. * * @returns The file pointer offset. Returns -1 on failure. * @param pRdr The file provider instance. */ KRDR_DECL(KFOFF) kRdrTell(PKRDR pRdr) { KRDR_VALIDATE(pRdr); return pRdr->pOps->pfnTell(pRdr); } /** Get the file name. * * @returns The file name. Returns NULL on failure. * @param pRdr The file provider instance. */ KRDR_DECL(const char *) kRdrName(PKRDR pRdr) { KRDR_VALIDATE_EX(pRdr, NULL); return pRdr->pOps->pfnName(pRdr); } /** Get the native file handle if possible. * * @returns The native file handle. Returns -1 if not available. * @param pRdr The file provider instance. */ KRDR_DECL(KIPTR) kRdrNativeFH(PKRDR pRdr) { KRDR_VALIDATE_EX(pRdr, -1); return pRdr->pOps->pfnNativeFH(pRdr); } /** * Gets the page size used when mapping sections of the file. * * @returns The page size. * @param pRdr The file provider instance. */ KRDR_DECL(KSIZE) kRdrPageSize(PKRDR pRdr) { KRDR_VALIDATE_EX(pRdr, 0x10000); return pRdr->pOps->pfnPageSize(pRdr); } /** * Maps the segments of a image into memory. * * The file reader will be using the RVA member of each segment to figure out where * it goes relative to the image base address. * * @returns 0 on success, OS specific error code on failure. * @param pRdr The file provider instance. * @param ppvBase On input when fFixed is set, this contains the base address of the mapping. * On output this contains the base of the image mapping. * @param cSegments The number of segments in the array pointed to by paSegments. * @param paSegments The segments thats going to be mapped. * @param fFixed If set, the address at *ppvBase should be the base address of the mapping. */ KRDR_DECL(int) kRdrMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed) { KRDR_VALIDATE(pRdr); return pRdr->pOps->pfnMap(pRdr, ppvBase, cSegments, paSegments, fFixed); } /** * Reloads dirty pages in mapped image. * * @returns 0 on success, OS specific error code on failure. * @param pRdr The file provider instance. * @param pvBase The base address of the image mapping. * @param cSegments The number of segments in the array pointed to by paSegments. * @param paSegments The segments thats going to be mapped. */ KRDR_DECL(int) kRdrRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments) { KRDR_VALIDATE(pRdr); return pRdr->pOps->pfnRefresh(pRdr, pvBase, cSegments, paSegments); } /** * Protects or unprotects an image mapping. * * This is typically used for getting write access to read or execute only * pages while applying fixups. * * @returns 0 on success, OS specific error code on failure. * @param pRdr The file provider instance. * @param pvBase The base address of the image mapping. * @param cSegments The number of segments in the array pointed to by paSegments. * @param paSegments The segments thats going to be mapped. * @param fUnprotectOrProtect When set the all mapped segments are made writable. * When clean the segment protection is restored. */ KRDR_DECL(int) kRdrProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect) { KRDR_VALIDATE(pRdr); return pRdr->pOps->pfnProtect(pRdr, pvBase, cSegments, paSegments, fUnprotectOrProtect); } /** * Unmaps a image mapping. * * @returns 0 on success, OS specific error code on failure. * @param pRdr The file provider instance. * @param pvBase The base address of the image mapping. * @param cSegments The number of segments in the array pointed to by paSegments. * @param paSegments The segments thats going to be mapped. */ KRDR_DECL(int) kRdrUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments) { KRDR_VALIDATE(pRdr); return pRdr->pOps->pfnUnmap(pRdr, pvBase, cSegments, paSegments); } /** * We're done reading from the file but would like to keep file mappings. * * If the OS support closing the file handle while the file is mapped, * the reader should do so. * * @param pRdr The file provider instance. */ KRDR_DECL(void) kRdrDone(PKRDR pRdr) { KRDR_VALIDATE_VOID(pRdr); pRdr->pOps->pfnDone(pRdr); } kbuild-3149/src/lib/kStuff/kRdr/kRdrInternal.h0000644000175000017500000001037513252530254021164 0ustar locutuslocutus/* $Id: kRdrInternal.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kRdr - Internal Header. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___kRdrInternal_h___ #define ___kRdrInternal_h___ #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** @defgroup grp_kRdrInternal - Internals * @internal * @addtogroup grp_kRdr * @{ */ /** @def KRDR_STRICT * If defined the kRdr assertions and other runtime checks will be enabled. */ #ifdef K_ALL_STRICT # undef KRDR_STRICT # define KRDR_STRICT #endif /** @name Our Assert macros * @{ */ #ifdef KRDR_STRICT # define kRdrAssert(expr) kHlpAssert(expr) # define kRdrAssertReturn(expr, rcRet) kHlpAssertReturn(expr, rcRet) # define kRdrAssertMsg(expr, msg) kHlpAssertMsg(expr, msg) # define kRdrAssertMsgReturn(expr, msg, rcRet) kHlpAssertMsgReturn(expr, msg, rcRet) #else /* !KRDR_STRICT */ # define kRdrAssert(expr) do { } while (0) # define kRdrAssertReturn(expr, rcRet) do { if (!(expr)) return (rcRet); } while (0) # define kRdrAssertMsg(expr, msg) do { } while (0) # define kRdrAssertMsgReturn(expr, msg, rcRet) do { if (!(expr)) return (rcRet); } while (0) #endif /* !KRDR_STRICT */ #define kRdrAssertPtr(ptr) kRdrAssertMsg(K_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr))) #define kRdrAssertPtrReturn(ptr, rcRet) kRdrAssertMsgReturn(K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet)) #define kRdrAssertPtrNull(ptr) kRdrAssertMsg(!(ptr) || K_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr))) #define kRdrAssertPtrNullReturn(ptr, rcRet) kRdrAssertMsgReturn(!(ptr) || K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet)) #define kRdrAssertRC(rc) kRdrAssertMsg((rc) == 0, ("%s = %d\n", #rc, (rc))) #define kRdrAssertRCReturn(rc, rcRet) kRdrAssertMsgReturn((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet)), (rcRet)) #define kRdrAssertFailed() kRdrAssert(0) #define kRdrAssertFailedReturn(rcRet) kRdrAssertReturn(0, (rcRet)) #define kRdrAssertMsgFailed(msg) kRdrAssertMsg(0, msg) #define kRdrAssertMsgFailedReturn(msg, rcRet) kRdrAssertMsgReturn(0, msg, (rcRet)) /** @} */ /** Return / crash validation of a reader argument. */ #define KRDR_VALIDATE_EX(pRdr, rc) \ do { \ if ( (pRdr)->u32Magic != KRDR_MAGIC \ || (pRdr)->pOps == NULL \ )\ { \ return (rc); \ } \ } while (0) /** Return / crash validation of a reader argument. */ #define KRDR_VALIDATE(pRdr) \ KRDR_VALIDATE_EX(pRdr, KERR_INVALID_PARAMETER) /** Return / crash validation of a reader argument. */ #define KRDR_VALIDATE_VOID(pRdr) \ do { \ if ( !K_VALID_PTR(pRdr) \ || (pRdr)->u32Magic != KRDR_MAGIC \ || (pRdr)->pOps == NULL \ )\ { \ return; \ } \ } while (0) /** @name Built-in Providers * @{ */ extern const KRDROPS g_kRdrFileOps; /** @} */ /** @} */ #ifdef __cplusplus } #endif #endif kbuild-3149/src/lib/kStuff/kRdr/kRdrFile.cpp0000644000175000017500000011174613252530254020626 0ustar locutuslocutus/* $Id: kRdrFile.cpp 81 2016-08-18 22:10:38Z bird $ */ /** @file * kRdrFile - The Native File Provider */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "kRdrInternal.h" #include #include #include #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS # include # include # include # include #elif K_OS == K_OS_OS2 # define INCL_ERRORS # define INCL_BASE # include #elif K_OS == K_OS_WINDOWS # define WIN32_NO_STATUS # include # include # include # ifdef __cplusplus extern "C" { # endif /** @todo find a non-conflicting header with NTSTATUS, NTAPI, ++ */ typedef LONG NTSTATUS; #define NT_SUCCESS(x) ((x)>=0) typedef struct _OBJECT_ATTRIBUTES { ULONG Length; HANDLE RootDirectory; PUNICODE_STRING ObjectName; ULONG Attributes; PVOID SecurityDescriptor; PVOID SecurityQualityOfService; } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; typedef enum _SECTION_INHERIT { ViewShare = 1, ViewUnmap = 2 } SECTION_INHERIT; # define NTOSAPI __declspec(dllimport) # define NtCurrentProcess() GetCurrentProcess() # ifndef MEM_DOS_LIM # define MEM_DOS_LIM 0x40000000UL # endif NTOSAPI NTSTATUS NTAPI NtCreateSection( OUT PHANDLE SectionHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN PLARGE_INTEGER SectionSize OPTIONAL, IN ULONG Protect, IN ULONG Attributes, IN HANDLE FileHandle OPTIONAL ); NTOSAPI NTSTATUS NTAPI NtMapViewOfSection( IN HANDLE SectionHandle, IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN ULONG ZeroBits, IN ULONG CommitSize, IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, IN OUT PSIZE_T ViewSize, IN SECTION_INHERIT InheritDisposition, IN ULONG AllocationType, IN ULONG Protect ); NTOSAPI NTSTATUS NTAPI NtUnmapViewOfSection( IN HANDLE ProcessHandle, IN PVOID BaseAddress ); NTOSAPI NTSTATUS NTAPI NtClose( IN HANDLE Handle ); NTOSAPI NTSTATUS NTAPI ZwProtectVirtualMemory( IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T ProtectSize, IN ULONG NewProtect, OUT PULONG OldProtect ); # define NtProtectVirtualMemory ZwProtectVirtualMemory NTOSAPI NTSTATUS NTAPI NtAllocateVirtualMemory( IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN ULONG ZeroBits, IN OUT PSIZE_T AllocationSize, IN ULONG AllocationType, IN ULONG Protect ); NTOSAPI NTSTATUS NTAPI NtFreeVirtualMemory( IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T FreeSize, IN ULONG FreeType ); # ifdef __cplusplus } # endif #else # error "port me" #endif /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * Prepared stuff. */ typedef struct KRDRFILEPREP { /** The address of the prepared region. */ void *pv; /** The size of the prepared region. */ KSIZE cb; #if K_OS == K_OS_WINDOWS /** Handle to the section created to map the file. */ HANDLE hSection; #endif } KRDRFILEPREP, *PKRDRFILEPREP; /** * The file provier instance for native files. */ typedef struct KRDRFILE { /** The file reader vtable. */ KRDR Core; /** The file handle. */ #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS int File; #elif K_OS == K_OS_OS2 HFILE File; #elif K_OS == K_OS_WINDOWS HANDLE File; #else # error "Port me!" #endif /** The current file offset. */ KFOFF off; /** The file size. */ KFOFF cb; /** Array where we stuff the mapping area data. */ KRDRFILEPREP aPreps[4]; /** The number of current preps. */ KU32 cPreps; /** Number of mapping references. */ KI32 cMappings; /** The memory mapping. */ void *pvMapping; /** The filename. */ char szFilename[1]; } KRDRFILE, *PKRDRFILE; /******************************************************************************* * Internal Functions * *******************************************************************************/ static void krdrFileDone(PKRDR pRdr); static int krdrFileUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments); static int krdrFileGenericUnmap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments); static int krdrFileProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect); static int krdrFileGenericProtect(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect); static int krdrFileRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments); static int krdrFileGenericRefresh(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments); static int krdrFileMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed); static int krdrFileGenericMap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed); static KSIZE krdrFilePageSize(PKRDR pRdr); static const char *krdrFileName(PKRDR pRdr); static KIPTR krdrFileNativeFH(PKRDR pRdr); static KFOFF krdrFileTell(PKRDR pRdr); static KFOFF krdrFileSize(PKRDR pRdr); static int krdrFileAllUnmap(PKRDR pRdr, const void *pvBits); static int krdrFileAllMap(PKRDR pRdr, const void **ppvBits); static int krdrFileRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off); static int krdrFileDestroy(PKRDR pRdr); static int krdrFileCreate(PPKRDR ppRdr, const char *pszFilename); /******************************************************************************* * Global Variables * *******************************************************************************/ /** Native file provider operations. */ const KRDROPS g_kRdrFileOps = { "native file", NULL, krdrFileCreate, krdrFileDestroy, krdrFileRead, krdrFileAllMap, krdrFileAllUnmap, krdrFileSize, krdrFileTell, krdrFileName, krdrFileNativeFH, krdrFilePageSize, krdrFileMap, krdrFileRefresh, krdrFileProtect, krdrFileUnmap, krdrFileDone, 42 }; #if K_OS == K_OS_WINDOWS /** * Converts a kLdr segment protection to NT protection for a mapping. * * @returns Nt page protection. * @param enmProt kLdr protection. */ static ULONG krdrFileGetNtMapProt(KPROT enmProt) { switch (enmProt) { case KPROT_NOACCESS: return PAGE_NOACCESS; case KPROT_READONLY: return PAGE_READONLY; case KPROT_READWRITE: return PAGE_READWRITE; case KPROT_WRITECOPY: return PAGE_WRITECOPY; case KPROT_EXECUTE: return PAGE_EXECUTE; case KPROT_EXECUTE_READ: return PAGE_EXECUTE_READ; case KPROT_EXECUTE_READWRITE: return PAGE_EXECUTE_READWRITE; case KPROT_EXECUTE_WRITECOPY: return PAGE_EXECUTE_WRITECOPY; default: return ~(ULONG)0; } } /** * Converts a kLdr segment protection to NT protection for a allocation. * * @returns Nt page protection. * @param enmProt kLdr protection. */ static ULONG krdrFileGetNtAllocProt(KPROT enmProt) { switch (enmProt) { case KPROT_NOACCESS: return PAGE_NOACCESS; case KPROT_READONLY: return PAGE_READONLY; case KPROT_WRITECOPY: case KPROT_READWRITE: return PAGE_READWRITE; case KPROT_EXECUTE: return PAGE_EXECUTE; case KPROT_EXECUTE_READ: return PAGE_EXECUTE_READ; case KPROT_EXECUTE_WRITECOPY: case KPROT_EXECUTE_READWRITE: return PAGE_EXECUTE_READWRITE; default: return ~(ULONG)0; } } #endif /** @copydoc KRDROPS::pfnDone */ static void krdrFileDone(PKRDR pRdr) { } /** * Finds a prepared mapping region. * * @returns Pointer to the aPrep entry. * @param pFile The instance data. * @param pv The base of the region. */ static PKRDRFILEPREP krdrFileFindPrepExact(PKRDRFILE pFile, void *pv) { KI32 i = pFile->cPreps; while (i-- > 0) if (pFile->aPreps[i].pv == pv) return &pFile->aPreps[i]; return NULL; } /** @copydoc KRDROPS::pfnUnmap */ static int krdrFileUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments) { PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; PKRDRFILEPREP pPrep = krdrFileFindPrepExact(pRdrFile, pvBase); int rc; if (!pPrep) return KERR_INVALID_PARAMETER; #if K_OS == K_OS_WINDOWS if (pPrep->hSection != NULL) { /** @todo implement me. */ return -1; } #endif rc = krdrFileGenericUnmap(pRdr, pPrep, cSegments, paSegments); /* remove the mapping data on success. */ if (!rc) { pRdrFile->cPreps--; if (pPrep != &pRdrFile->aPreps[pRdrFile->cPreps]) *pPrep = pRdrFile->aPreps[pRdrFile->cPreps]; } return rc; } /** Generic implementation of krdrFileUnmap. */ static int krdrFileGenericUnmap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments) { krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */); return kHlpPageFree(pPrep->pv, pPrep->cb); } /** @copydoc KRDROPS::pfnProtect */ static int krdrFileProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect) { PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; PKRDRFILEPREP pPrep = krdrFileFindPrepExact(pRdrFile, pvBase); if (!pPrep) return KERR_INVALID_PARAMETER; #if K_OS == K_OS_WINDOWS if (pPrep->hSection != NULL) { /** @todo implement me. */ return -1; } #endif return krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, fUnprotectOrProtect); } /** Generic implementation of krdrFileProtect. */ static int krdrFileGenericProtect(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect) { KU32 i; /* * Iterate the segments and apply memory protection changes. */ for (i = 0; i < cSegments; i++) { int rc; void *pv; KPROT enmProt; if (paSegments[i].RVA == NIL_KLDRADDR) continue; /* calc new protection. */ enmProt = (KPROT)paSegments[i].enmProt; /** @todo drop cast */ if (fUnprotectOrProtect) { switch (enmProt) { case KPROT_NOACCESS: case KPROT_READONLY: case KPROT_READWRITE: case KPROT_WRITECOPY: enmProt = KPROT_READWRITE; break; case KPROT_EXECUTE: case KPROT_EXECUTE_READ: case KPROT_EXECUTE_READWRITE: case KPROT_EXECUTE_WRITECOPY: enmProt = KPROT_EXECUTE_READWRITE; break; default: kRdrAssert(!"bad enmProt"); return -1; } } else { /* copy on write -> normal write. */ if (enmProt == KPROT_EXECUTE_WRITECOPY) enmProt = KPROT_EXECUTE_READWRITE; else if (enmProt == KPROT_WRITECOPY) enmProt = KPROT_READWRITE; } pv = (KU8 *)pPrep->pv + paSegments[i].RVA; rc = kHlpPageProtect(pv, paSegments[i].cbMapped, enmProt); if (rc) break; } return 0; } /** @copydoc KRDROPS::pfnRefresh */ static int krdrFileRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments) { PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; PKRDRFILEPREP pPrep = krdrFileFindPrepExact(pRdrFile, pvBase); if (!pPrep) return KERR_INVALID_PARAMETER; #if K_OS == K_OS_WINDOWS if (pPrep->hSection != NULL) { /** @todo implement me. */ return -1; } #endif return krdrFileGenericRefresh(pRdr, pPrep, cSegments, paSegments); } /** Generic implementation of krdrFileRefresh. */ static int krdrFileGenericRefresh(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments) { int rc; int rc2; KU32 i; /* * Make everything writable again. */ rc = krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */); if (rc) { krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */); return rc; } /* * Clear everything. */ /** @todo only zero the areas not covered by raw file bits. */ kHlpMemSet(pPrep->pv, 0, pPrep->cb); /* * Reload all the segments. * We could possibly skip some segments, but we currently have * no generic way of figuring out which at the moment. */ for (i = 0; i < cSegments; i++) { void *pv; if ( paSegments[i].RVA == NIL_KLDRADDR || paSegments[i].cbFile <= 0) continue; pv = (KU8 *)pPrep->pv + paSegments[i].RVA; rc = pRdr->pOps->pfnRead(pRdr, pv, paSegments[i].cbFile, paSegments[i].offFile); if (rc) break; } /* * Protect the bits again. */ rc2 = krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */); if (rc2 && rc) rc = rc2; return rc; } /** @copydoc KRDROPS::pfnMap */ static int krdrFileMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed) { PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; PKRDRFILEPREP pPrep = &pRdrFile->aPreps[pRdrFile->cPreps]; KLDRSIZE cbTotal; const KSIZE cbPage = pRdr->pOps->pfnPageSize(pRdr); int rc; KU32 i; if (pRdrFile->cPreps >= K_ELEMENTS(pRdrFile->aPreps)) return KRDR_ERR_TOO_MANY_MAPPINGS; /* * Calc the total mapping space needed. */ cbTotal = 0; for (i = 0; i < cSegments; i++) { KLDRSIZE uRVASegmentEnd; if (paSegments[i].RVA == NIL_KLDRADDR) continue; uRVASegmentEnd = paSegments[i].RVA + paSegments[i].cbMapped; if (cbTotal < uRVASegmentEnd) cbTotal = uRVASegmentEnd; } pPrep->cb = (KSIZE)cbTotal; if (pPrep->cb != cbTotal) return KLDR_ERR_ADDRESS_OVERFLOW; pPrep->cb = (pPrep->cb + (cbPage - 1)) & ~(cbPage- 1); #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS /** @todo */ #elif K_OS == K_OS_WINDOWS /* * The NT memory mapped file API sucks in a lot of ways. Unless you're actually * trying to map a PE image and the kernel can parse the file for it self, the * API just isn't up to scratch. * * Problems: * 1. Reserving memory for the views is risky because you can't reserve and * map into the reserved space. So, other threads might grab the memory * before we get to it. * 2. The page aligning of file offsets makes it impossible to map most * executable images since these are commonly sector aligned. * 3. When mapping a read+execute file, its not possible to create section * larger than the file since the section size is bound to the data file * size. This wouldn't have been such a problem if it was possible to * map views beyond the section restriction, i.e. have a file size and * view size. * 4. Only x86 can map views at page granularity it seems, and that only * using an undocument flag. The default granularity is 64KB. * 5. There is more crappyness here... * * So, first we'll have to check if we can the file using the crappy NT APIs. * Chances are we can't. */ for (i = 0; i < cSegments; i++) { if (paSegments[i].RVA == NIL_KLDRADDR) continue; /* The file backing of the segments must be page aligned. */ if ( paSegments[i].cbFile > 0 && paSegments[i].offFile & (cbPage - 1)) break; /* Only page alignment gaps between the file size and the mapping size. */ if ( paSegments[i].cbFile > 0 && (paSegments[i].cbFile & ~(cbPage - 1)) != (paSegments[i].cbMapped & ~(cbPage - 1)) ) break; /* The mapping addresses of the segments must be page aligned. * Non-x86 will probably require 64KB alignment here. */ if (paSegments[i].RVA & (cbPage - 1)) break; /* If we do have to allocate the segment it's RVA must be 64KB aligned. */ if ( paSegments[i].cbFile > 0 && (paSegments[i].RVA & 0xffff)) break; } /** @todo if this is a PE image, we might just try a SEC_IMAGE mapping. It'll work if the host and image machines matches. */ if (i == cSegments) { /* WOW! it may work out! Incredible! */ SIZE_T ViewSize; LARGE_INTEGER SectionOffset; LARGE_INTEGER MaxiumSize; NTSTATUS Status; PVOID pv; MaxiumSize.QuadPart = pRdr->pOps->pfnSize(pRdr); if (MaxiumSize.QuadPart > (LONGLONG)cbTotal) MaxiumSize.QuadPart = cbTotal; Status = NtCreateSection(&pPrep->hSection, SECTION_MAP_EXECUTE | SECTION_MAP_READ, /* desired access */ NULL, /* object attributes */ &MaxiumSize, PAGE_EXECUTE_WRITECOPY, /* page attributes */ SEC_COMMIT, /* section attributes */ pRdrFile->File); if (!NT_SUCCESS(Status)) return (int)Status; /* * Determin the base address. */ if (fFixed) pPrep->pv = *ppvBase; else { pv = NULL; ViewSize = (KSIZE)cbTotal; Status = NtAllocateVirtualMemory(NtCurrentProcess(), &pv, 0, /* ZeroBits */ &ViewSize, MEM_RESERVE, PAGE_READONLY); if (NT_SUCCESS(Status)) { pPrep->pv = *ppvBase = pv; ViewSize = 0; Status = NtFreeVirtualMemory(NtCurrentProcess(), &pv, &ViewSize, MEM_RELEASE); } if (!NT_SUCCESS(Status)) { NtClose(pPrep->hSection); return Status; } } /* * Map the segments. */ for (i = 0; i < cSegments; i++) { ULONG fPageProt; if (paSegments[i].RVA == NIL_KLDRADDR) continue; pv = (KU8 *)pPrep->pv + paSegments[i].RVA; if (paSegments[i].cbFile > 0) { SectionOffset.QuadPart = paSegments[i].offFile; ViewSize = paSegments[i].cbFile; fPageProt = krdrFileGetNtMapProt(paSegments[i].enmProt); /* STATUS_MAPPED_ALIGNMENT STATUS_CONFLICTING_ADDRESSES STATUS_INVALID_VIEW_SIZE */ Status = NtMapViewOfSection(pPrep->hSection, NtCurrentProcess(), &pv, 0, /* ZeroBits */ 0, /* CommitSize */ &SectionOffset, /* SectionOffset */ &ViewSize, ViewUnmap, MEM_DOS_LIM, /* AllocationType */ fPageProt); /* do we have to zero anything? */ if ( NT_SUCCESS(Status) && 0/*later*/) { /*ULONG OldPageProt = 0; NtProtectVirtualMemory(NtCurrentProcess(), &pv, &ViewSize, , */ } } else { ViewSize = paSegments[i].cbMapped; fPageProt = krdrFileGetNtAllocProt(paSegments[i].enmProt); Status = NtAllocateVirtualMemory(NtCurrentProcess(), &pv, 0, /* ZeroBits */ &ViewSize, MEM_COMMIT, fPageProt); } if (!NT_SUCCESS(Status)) break; } /* * On success, commit the mapping and return. */ if (NT_SUCCESS(Status)) { pRdrFile->cPreps++; return 0; } /* bail out and fall back on the generic code. */ while (i-- > 0) { PVOID pv; if (paSegments[i].RVA == NIL_KLDRADDR) continue; pv = (KU8 *)pPrep->pv + paSegments[i].RVA; if (paSegments[i].cbFile > 0) NtUnmapViewOfSection(NtCurrentProcess(), pv); else NtFreeVirtualMemory(NtCurrentProcess(), &pv, NULL, MEM_RELEASE); } NtClose(pPrep->hSection); } /* else: fall back to the generic code */ pPrep->hSection = NULL; #endif /* * Use the generic map emulation. */ pPrep->pv = fFixed ? *ppvBase : NULL; rc = krdrFileGenericMap(pRdr, pPrep, cSegments, paSegments, fFixed); if (!rc) { *ppvBase = pPrep->pv; pRdrFile->cPreps++; } return rc; } /** Generic implementation of krdrFileMap. */ static int krdrFileGenericMap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed) { int rc; KU32 i; /* * Generic mapping code using kHlpPageAlloc(), kHlpPageFree() and kHlpPageProtect(). */ rc = kHlpPageAlloc(&pPrep->pv, pPrep->cb, KPROT_EXECUTE_READWRITE, fFixed); if (rc) return rc; /* * Load the data. */ for (i = 0; i < cSegments; i++) { void *pv; if ( paSegments[i].RVA == NIL_KLDRADDR || paSegments[i].cbFile <= 0) continue; pv = (KU8 *)pPrep->pv + paSegments[i].RVA; rc = pRdr->pOps->pfnRead(pRdr, pv, paSegments[i].cbFile, paSegments[i].offFile); if (rc) break; } /* * Set segment protection. */ if (!rc) { rc = krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */); if (!rc) return 0; krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */); } /* bailout */ kHlpPageFree(pPrep->pv, pPrep->cb); return rc; } /** @copydoc KRDROPS::pfnPageSize */ static KSIZE krdrFilePageSize(PKRDR pRdr) { #if K_OS == K_OS_DARWIN return 0x1000; /** @todo find some header somewhere... */ #elif K_OS == K_OS_LINUX return 0x1000; /** @todo find some header somewhere... */ #elif K_OS == K_OS_OS2 /* The page size on OS/2 wont change anytime soon. :-) */ return 0x1000; #elif K_OS == K_OS_WINDOWS SYSTEM_INFO SysInfo; GetSystemInfo(&SysInfo); return SysInfo.dwPageSize; /*return SysInfo.dwAllocationGranularity;*/ #else # error "port me" #endif } /** @copydoc KRDROPS::pfnName */ static const char *krdrFileName(PKRDR pRdr) { PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; return &pRdrFile->szFilename[0]; } static KIPTR krdrFileNativeFH(PKRDR pRdr) { PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_OS2 \ || K_OS == K_OS_SOLARIS \ || K_OS == K_OS_WINDOWS return (KIPTR)pRdrFile->File; #else # error "port me" #endif } /** @copydoc KRDROPS::pfnTell */ static KFOFF krdrFileTell(PKRDR pRdr) { PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; /* * If the offset is undefined, try figure out what it is. */ if (pRdrFile->off == -1) { #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS pRdrFile->off = kHlpSys_lseek(pRdrFile->File, SEEK_CUR, 0); if (pRdrFile->off < 0) pRdrFile->off = -1; #elif K_OS == K_OS_OS2 ULONG ulNew; APIRET rc = DosSetFilePtr(pRdrFile->File, 0, FILE_CURRENT, &ulNew); if (rc) return -1; pRdrFile->off = ulNew; #elif K_OS == K_OS_WINDOWS LONG offHigh = 0; LONG offLow; int rc; SetLastError(0); offLow = SetFilePointer(pRdrFile->File, 0, &offHigh, FILE_CURRENT); rc = GetLastError(); if (rc) return -1; pRdrFile->off = ((KFOFF)offHigh << 32) | offLow; #else # error "port me." #endif } return pRdrFile->off; } /** @copydoc KRDROPS::pfnSize */ static KFOFF krdrFileSize(PKRDR pRdr) { PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; return pRdrFile->cb; } /** @copydoc KRDROPS::pfnAllUnmap */ static int krdrFileAllUnmap(PKRDR pRdr, const void *pvBits) { PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; /* check for underflow */ if (pRdrFile->cMappings <= 0) return KERR_INVALID_PARAMETER; /* decrement usage counter, free mapping if no longer in use. */ if (!--pRdrFile->cMappings) { kHlpFree(pRdrFile->pvMapping); pRdrFile->pvMapping = NULL; } return 0; } /** @copydoc KRDROPS::pfnAllMap */ static int krdrFileAllMap(PKRDR pRdr, const void **ppvBits) { PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; /* * Do we need to map it? */ if (!pRdrFile->pvMapping) { int rc; KFOFF cbFile = pRdrFile->Core.pOps->pfnSize(pRdr); KSIZE cb = (KSIZE)cbFile; if (cb != cbFile) return KERR_NO_MEMORY; pRdrFile->pvMapping = kHlpAlloc(cb); if (!pRdrFile->pvMapping) return KERR_NO_MEMORY; rc = pRdrFile->Core.pOps->pfnRead(pRdr, pRdrFile->pvMapping, cb, 0); if (rc) { kHlpFree(pRdrFile->pvMapping); pRdrFile->pvMapping = NULL; return rc; } pRdrFile->cMappings = 0; } *ppvBits = pRdrFile->pvMapping; pRdrFile->cMappings++; return 0; } /** @copydoc KRDROPS::pfnRead */ static int krdrFileRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off) { PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; /* * Do a seek if needed. */ if (pRdrFile->off != off) { #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS pRdrFile->off = kHlpSys_lseek(pRdrFile->File, SEEK_SET, off); if (pRdrFile->off < 0) { int rc = (int)-pRdrFile->off; pRdrFile->off = -1; return -rc; } #elif K_OS == K_OS_OS2 ULONG ulNew; APIRET rc; rc = DosSetFilePtr(pRdrFile->File, off, FILE_BEGIN, &ulNew); if (rc) { pRdrFile->off = -1; return rc; } #elif K_OS == K_OS_WINDOWS LONG offHigh; LONG offLow; offHigh = (LONG)(off >> 32); offLow = SetFilePointer(pRdrFile->File, (LONG)off, &offHigh, FILE_BEGIN); if ( offLow != (LONG)off || offHigh != (LONG)(off >> 32)) { int rc = GetLastError(); if (!rc) rc = KERR_GENERAL_FAILURE; pRdrFile->off = -1; return rc; } #else # error "port me." #endif } /* * Do the read. */ #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS { KSSIZE cbRead; cbRead = kHlpSys_read(pRdrFile->File, pvBuf, cb); if (cbRead != cb) { pRdrFile->off = -1; if (cbRead < 0) return -cbRead; return KERR_GENERAL_FAILURE; } } #elif K_OS == K_OS_OS2 { ULONG cbRead = 0; APIRET rc = DosRead(pRdrFile->File, pvBuf, cb, &cbRead); if (rc) { pRdrFile->off = -1; return rc; } if (cbRead != cb) { pRdrFile->off = -1; return KERR_GENERAL_FAILURE; } } #elif K_OS == K_OS_WINDOWS { DWORD cbRead = 0; if (!ReadFile(pRdrFile->File, pvBuf, cb, &cbRead, NULL)) { int rc = GetLastError(); if (!rc) rc = KERR_GENERAL_FAILURE; pRdrFile->off = -1; return rc; } if (cbRead != cb) { pRdrFile->off = -1; return KERR_GENERAL_FAILURE; } } #else # error "port me." #endif pRdrFile->off = off + cb; return 0; } /** @copydoc KRDROPS::pfnDestroy */ static int krdrFileDestroy(PKRDR pRdr) { PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; int rc; #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS rc = kHlpSys_close(pRdrFile->File); #elif K_OS == K_OS_OS2 rc = DosClose(pRdrFile->File); #elif K_OS == K_OS_WINDOWS rc = 0; if (!CloseHandle(pRdrFile->File)) rc = GetLastError(); #else # error "port me" #endif if (pRdrFile->pvMapping) { kHlpFree(pRdrFile->pvMapping); pRdrFile->pvMapping = NULL; } kHlpFree(pRdr); return rc; } /** @copydoc KRDROPS::pfnCreate */ static int krdrFileCreate(PPKRDR ppRdr, const char *pszFilename) { KSIZE cchFilename; PKRDRFILE pRdrFile; /* * Open the file, determin its size and correct filename. */ #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS int File; KFOFF cb; KFOFF rc; char szFilename[1024]; cchFilename = kHlpStrLen(pszFilename); if (cchFilename >= sizeof(szFilename)) return KERR_OUT_OF_RANGE; kHlpMemCopy(szFilename, pszFilename, cchFilename + 1); /** @todo normalize the filename. */ # ifdef O_BINARY File = kHlpSys_open(pszFilename, O_RDONLY | O_BINARY, 0); # else File = kHlpSys_open(pszFilename, O_RDONLY, 0); # endif if (File < 0) return -File; cb = kHlpSys_lseek(File, SEEK_END, 0); rc = kHlpSys_lseek(File, SEEK_SET, 0); if ( cb < 0 || rc < 0) { kHlpSys_close(File); return cb < 0 ? -cb : -rc; } #elif K_OS == K_OS_OS2 ULONG ulAction = 0; FILESTATUS3 Info; APIRET rc; HFILE File = 0; KFOFF cb; char szFilename[CCHMAXPATH]; if ((uintptr_t)pszFilename >= 0x20000000) { char *psz; cchFilename = kHlpStrLen(szFilename); psz = (char *)kHlpAllocA(cchFilename + 1); kHlpMemCopy(psz, pszFilename, cchFilename + 1); pszFilename = psz; } rc = DosOpen((PCSZ)pszFilename, &File, &ulAction, 0, FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW, OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY | OPEN_FLAGS_RANDOMSEQUENTIAL, NULL); if (rc) return rc; rc = DosQueryPathInfo((PCSZ)pszFilename, FIL_QUERYFULLNAME, szFilename, sizeof(szFilename)); if (rc) { DosClose(File); return rc; } rc = DosQueryFileInfo(File, FIL_STANDARD, &Info, sizeof(Info)); if (rc) { DosClose(File); return rc; } cb = Info.cbFile; #elif K_OS == K_OS_WINDOWS SECURITY_ATTRIBUTES SecAttr; DWORD High; DWORD Low; int rc; HANDLE File; KFOFF cb; char szFilename[MAX_PATH]; SecAttr.bInheritHandle = FALSE; SecAttr.lpSecurityDescriptor = NULL; SecAttr.nLength = 0; File = CreateFile(pszFilename, GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_READ, &SecAttr, OPEN_EXISTING, 0, NULL); if (File == INVALID_HANDLE_VALUE) return GetLastError(); if (!GetFullPathName(pszFilename, sizeof(szFilename), szFilename, NULL)) { rc = GetLastError(); CloseHandle(File); return rc; } SetLastError(0); Low = GetFileSize(File, &High); rc = GetLastError(); if (rc) { CloseHandle(File); return rc; } cb = ((KFOFF)High << 32) | Low; #else # error "port me" #endif /* * Allocate the reader instance. */ cchFilename = kHlpStrLen(szFilename); pRdrFile = (PKRDRFILE)kHlpAlloc(sizeof(*pRdrFile) + cchFilename); if (!pRdrFile) { #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS kHlpSys_close(File); #elif K_OS == K_OS_OS2 DosClose(File); #elif K_OS == K_OS_WINDOWS CloseHandle(File); #else # error "port me" #endif return KERR_NO_MEMORY; } /* * Initialize it and return successfully. */ pRdrFile->Core.u32Magic = KRDR_MAGIC; pRdrFile->Core.pOps = &g_kRdrFileOps; pRdrFile->File = File; pRdrFile->cb = cb; pRdrFile->off = 0; pRdrFile->cPreps = 0; pRdrFile->cMappings = 0; pRdrFile->pvMapping = NULL; kHlpMemCopy(&pRdrFile->szFilename[0], szFilename, cchFilename + 1); *ppRdr = &pRdrFile->Core; return 0; } kbuild-3149/src/lib/kStuff/Config.kmk0000644000175000017500000001157013252530254017421 0ustar locutuslocutus# $Id: Config.kmk 29 2009-07-01 20:30:29Z bird $ ## @file # kBuild configuration for kStuff # # # Copyright (c) 2006-2007 Knut St. Osmundsen # # 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. # # # This is where we install during the build. # PATH_INS := $(PATH_OUT)/kStuff # # Templates for the kStuff. # TEMPLATE_kStuff = kStuff Template TEMPLATE_kStuff_TOOL = GXX3 TEMPLATE_kStuff_TOOL.darwin = GXX4MACHO TEMPLATE_kStuff_TOOL.os2 = GXX3OMF TEMPLATE_kStuff_TOOL.solaris = GXX3PLAIN TEMPLATE_kStuff_TOOL.win.x86 = VCC70 TEMPLATE_kStuff_TOOL.win.amd64 = VCC80AMD64 TEMPLATE_kStuff_SDKS.win.x86 = WINPSDK W2K3DDKX86 TEMPLATE_kStuff_SDKS.win.amd64 = WINPSDK W2K3DDKAMD64 TEMPLATE_kStuff_DEFS.freebsd = KS_OS_FREEBSD TEMPLATE_kStuff_DEFS.darwin = KS_OS_DARWIN TEMPLATE_kStuff_DEFS.linux = KS_OS_LINUX TEMPLATE_kStuff_DEFS.netbsd = KS_OS_NETBSD TEMPLATE_kStuff_DEFS.openbsd = KS_OS_OPENBSD TEMPLATE_kStuff_DEFS.os2 = KS_OS_OS2 TEMPLATE_kStuff_DEFS.solaris = KS_OS_SOLARIS TEMPLATE_kStuff_DEFS.win = KS_OS_WINDOWS _CRT_SECURE_NO_DEPRECATE _CRT_NONSTDC_NO_WARNINGS TEMPLATE_kStuff_DEFS.x86 = KS_BITS=32 TEMPLATE_kStuff_DEFS.amd64 = KS_BITS=64 TEMPLATE_kStuff_INCS = $(PATH_ROOT)/include TEMPLATE_kStuff_ASTOOL = YASM TEMPLATE_kStuff_ASTOOL.os2 = NASM TEMPLATE_kStuff_ASFLAGS.freebsd = -f elf TEMPLATE_kStuff_ASFLAGS.linux = -f elf TEMPLATE_kStuff_ASFLAGS.os2 = -f omf TEMPLATE_kStuff_ASFLAGS.win.x86 = -f win32 -g cv8 TEMPLATE_kStuff_ASFLAGS.win.amd64= -f win64 -g cv8 TEMPLATE_kStuff_CFLAGS.darwin = -g -fno-common TEMPLATE_kStuff_CFLAGS.freebsd = -g TEMPLATE_kStuff_CFLAGS.linux = -g TEMPLATE_kStuff_CFLAGS.os2 = -g TEMPLATE_kStuff_CFLAGS.win = -Zi -Zl -W3 -GF -GR- TEMPLATE_kStuff_CFLAGS.win.x86 = -MD TEMPLATE_kStuff_CFLAGS.win.amd64 = -MT ifneq ($(BUILD_TYPE),debug) TEMPLATE_kStuff_CFLAGS.freebsd += -O3 TEMPLATE_kStuff_CFLAGS.linux += -O3 TEMPLATE_kStuff_CFLAGS.os2 += -O3 TEMPLATE_kStuff_CFLAGS.win += -O2b2 else TEMPLATE_kStuff_CFLAGS.win += -Od endif TEMPLATE_kStuff_CXXFLAGS.darwin = -g -fno-exceptions -fno-common TEMPLATE_kStuff_CXXFLAGS.freebsd = -g -fno-exceptions TEMPLATE_kStuff_CXXFLAGS.linux = -g -fno-exceptions TEMPLATE_kStuff_CXXFLAGS.os2 = -g -fno-exceptions TEMPLATE_kStuff_CXXFLAGS.win = -Zi -Zl -W3 -GF -GR- TEMPLATE_kStuff_CXXFLAGS.win.x86 = -MD TEMPLATE_kStuff_CXXFLAGS.win.amd64 = -MT ifneq ($(BUILD_TYPE),debug) TEMPLATE_kStuff_CXXFLAGS.freebsd+= -O3 TEMPLATE_kStuff_CXXFLAGS.linux += -O3 TEMPLATE_kStuff_CXXFLAGS.os2 += -O3 TEMPLATE_kStuff_CXXFLAGS.win += -O2b2 else TEMPLATE_kStuff_CXXFLAGS.win += -Od endif TEMPLATE_kStuff_LDFLAGS.freebsd = -g TEMPLATE_kStuff_LDFLAGS.linux = -g TEMPLATE_kStuff_LDFLAGS.os2 = -g TEMPLATE_kStuff_LDFLAGS.win = /DEBUG /NODEFAULTLIB TEMPLATE_kStuff_LIBS.freebsd = TEMPLATE_kStuff_LIBS.linux = TEMPLATE_kStuff_LIBS.os2 = TEMPLATE_kStuff_LIBS.win = \ $(PATH_SDK_WINPSDK_LIB)/psapi.Lib TEMPLATE_kStuff_LIBS.win.x86 = \ $(PATH_TOOL_VCC70_LIB)/msvcrt.lib \ $(PATH_TOOL_VCC70_LIB)/msvcprt.lib \ $(PATH_TOOL_VCC70_LIB)/oldnames.lib \ $(PATH_SDK_W2K3DDKX86_LIB)/ntdll.lib TEMPLATE_kStuff_LIBS.win.amd64 = \ $(PATH_TOOL_VCC80AMD64_LIB)/libcmt.lib \ $(PATH_TOOL_VCC80AMD64_LIB)/oldnames.lib \ $(PATH_SDK_W2K3DDKAMD64_LIB)/ntdll.lib TEMPLATE_kStuffEXE = kStuff Executable Template TEMPLATE_kStuffEXE_EXTENDS = kStuff TEMPLATE_kStuffEXE_DEFS = $(TEMPLATE_kStuff) KS_EXE_TARGET TEMPLATE_kStuffLIB = kStuff Library Template TEMPLATE_kStuffLIB_EXTENDS = kStuff TEMPLATE_kStuffLIB_DEFS = $(TEMPLATE_kStuff) KS_LIB_TARGET TEMPLATE_kStuffDLL = kStuff DLL Template TEMPLATE_kStuffDLL_EXTENDS = kStuff TEMPLATE_kStuffDLL_DEFS = $(TEMPLATE_kStuff) KS_DLL_TARGET TEMPLATE_kStuffDLL_LDFLAGS.os2 = $(TEMPLATE_kStuff_LDFLAGS.os2) -Zdll kbuild-3149/src/lib/kStuff/kDbg/0000755000175000017500000000000013252530254016353 5ustar locutuslocutuskbuild-3149/src/lib/kStuff/kDbg/kDbgModPE.cpp0000644000175000017500000003336513252530254020625 0ustar locutuslocutus/* $Id: kDbgModPE.cpp 29 2009-07-01 20:30:29Z bird $ */ /** @file * kDbg - The Debug Info Reader, PE Module (Generic). */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "kDbg.h" #include "kDbgInternal.h" #include #include /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * A dbghelp based PE debug reader. */ typedef struct KDBGMODPE { /** The common module core. */ KDBGMOD Core; /** The image size. */ uint32_t cbImage; /** The number of sections. (We've added the implicit header section.) */ int32_t cSections; /** The section headers (variable size). The first section is the * implicit header section.*/ IMAGE_SECTION_HEADER aSections[1]; } KDBGMODPE, *PKDBGMODPE; /** * Calcs the RVA for a segment:offset address. * * @returns IPRT status code. * * @param pModPe The PE debug module instance. * @param iSegment The segment number. Special segments are dealt with as well. * @param off The segment offset. * @param puRVA Where to store the RVA on success. */ static int kDbgModPeSegOffToRVA(PKDBGMODPE pModPe, int32_t iSegment, KDBGADDR off, uint32_t *puRVA) { if (iSegment >= 0) { kDbgAssertMsgReturn(iSegment < pModPe->cSections, ("iSegment=%x cSections=%x\n", iSegment, pModPe->cSections), KDBG_ERR_INVALID_ADDRESS); kDbgAssertMsgReturn(off < pModPe->aSections[iSegment].Misc.VirtualSize, ("off=" PRI_KDBGADDR " VirtualSize=%x\n", off, pModPe->aSections[iSegment].Misc.VirtualSize), KDBG_ERR_INVALID_ADDRESS); *puRVA = pModPe->aSections[iSegment].VirtualAddress + (uint32_t)off; return 0; } if (iSegment == KDBGSEG_RVA) { kDbgAssertMsgReturn(off < pModPe->cbImage, ("off=" PRI_KDBGADDR ", cbImage=%x\n", off, pModPe->cbImage), KDBG_ERR_INVALID_ADDRESS); *puRVA = (uint32_t)off; return 0; } kDbgAssertMsgFailedReturn(("iSegment=%d\n", iSegment), KDBG_ERR_INVALID_ADDRESS); } /** * Calcs the segment:offset address for a RVA. * * @returns IPRT status code. * * @param pModPe The PE debug module instance. * @param uRVA The RVA. * @param piSegment Where to store the segment number. * @param poff Where to store the segment offset. */ static int kDbgModPeRVAToSegOff(PKDBGMODPE pModPe, uint32_t uRVA, int32_t *piSegment, KDBGADDR *poff) { kDbgAssertMsgReturn(uRVA < pModPe->cbImage, ("uRVA=%x, cbImage=%x\n", uRVA, pModPe->cbImage), KDBG_ERR_INVALID_ADDRESS); for (int32_t iSegment = 0; iSegment < pModPe->cSections; iSegment++) { /** @todo should probably be less strict about address in the alignment gaps. */ uint32_t off = uRVA - pModPe->aSections[iSegment].VirtualAddress; if (off < pModPe->aSections[iSegment].Misc.VirtualSize) { *poff = off; *piSegment = iSegment; return 0; } } kDbgAssertMsgFailedReturn(("uRVA=%x\n", uRVA), KDBG_ERR_INVALID_ADDRESS); } /** * @copydoc KDBGMODOPS::pfnQueryLine */ static int kDbgModPeQueryLine(PKDBGMOD pMod, int32_t iSegment, KDBGADDR off, PKDBGLINE pLine) { PKDBGMODPE pModPe = (PKDBGMODPE)pMod; /* * Translate the address to an RVA. */ uint32_t uRVA; int rc = kDbgModPeSegOffToRVA(pModPe, iSegment, off, &uRVA); if (!rc) { #if 0 DWORD64 off; IMAGEHLP_LINE64 Line; Line.SizeOfStruct = sizeof(Line); if (g_pfnSymGetLineFromAddr64(pModPe->hSymInst, pModPe->ImageBase + uRVA, &off, &Line)) { pLine->RVA = (KDBGADDR)(Line.Address - pModPe->ImageBase); rc = kDbgModPeRVAToSegOff(pModPe, pLine->RVA, &pLine->iSegment, &pLine->offSegment); pLine->iLine = Line.LineNumber; pLine->cchFile = strlen(Line.FileName); if (pLine->cchFile >= sizeof(pLine->szFile)) pLine->cchFile = sizeof(pLine->szFile) - 1; memcpy(pLine->szFile, Line.FileName, pLine->cchFile + 1); } else { DWORD Err = GetLastError(); rc = kDbgModPeConvWinError(Err); } #endif rc = KERR_NOT_IMPLEMENTED; } return rc; } /** * @copydoc KDBGMODOPS::pfnQuerySymbol */ static int kDbgModPeQuerySymbol(PKDBGMOD pMod, int32_t iSegment, KDBGADDR off, PKDBGSYMBOL pSym) { PKDBGMODPE pModPe = (PKDBGMODPE)pMod; /* * Translate the address to an RVA. */ uint32_t uRVA; int rc = kDbgModPeSegOffToRVA(pModPe, iSegment, off, &uRVA); if (!rc) { #if 0 DWORD64 off; union { SYMBOL_INFO Sym; char achBuffer[sizeof(SYMBOL_INFO) + KDBG_SYMBOL_MAX]; } Buf; Buf.Sym.SizeOfStruct = sizeof(SYMBOL_INFO); Buf.Sym.MaxNameLen = KDBG_SYMBOL_MAX; if (g_pfnSymFromAddr(pModPe->hSymInst, pModPe->ImageBase + uRVA, &off, &Buf.Sym)) { pSym->cb = Buf.Sym.Size; pSym->fFlags = 0; if (Buf.Sym.Flags & SYMFLAG_FUNCTION) pSym->fFlags |= KDBGSYM_FLAGS_CODE; else if (Buf.Sym.Flags & SYMFLAG_CONSTANT) pSym->fFlags |= KDBGSYM_FLAGS_ABS; /** @todo SYMFLAG_CONSTANT must be tested - documentation is too brief to say what is really meant here.*/ else pSym->fFlags |= KDBGSYM_FLAGS_DATA; if (Buf.Sym.Flags & SYMFLAG_EXPORT) pSym->fFlags |= KDBGSYM_FLAGS_EXPORTED; if ((Buf.Sym.Flags & (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT)) == (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT)) { pSym->iSegment = KDBGSEG_ABS; pSym->offSegment = (KDBGADDR)Buf.Sym.Value; pSym->RVA = (KDBGADDR)Buf.Sym.Value; } else { pSym->RVA = (KDBGADDR)(Buf.Sym.Address - pModPe->ImageBase); rc = kDbgModPeRVAToSegOff(pModPe, pSym->RVA, &pSym->iSegment, &pSym->offSegment); } pSym->cchName = (uint16_t)Buf.Sym.NameLen; if (pSym->cchName >= sizeof(pSym->szName)) pSym->cchName = sizeof(pSym->szName) - 1; memcpy(pSym->szName, Buf.Sym.Name, Buf.Sym.NameLen); pSym->szName[Buf.Sym.NameLen] = '\0'; } else { DWORD Err = GetLastError(); rc = kDbgModPeConvWinError(Err); } #endif rc = KERR_NOT_IMPLEMENTED; } return rc; } /** * @copydoc KDBGMODOPS::pfnClose */ static int kDbgModPeClose(PKDBGMOD pMod) { PKDBGMODPE pModPe = (PKDBGMODPE)pMod; //if (g_pfnSymCleanup(pModPe->hSymInst)) // return 0; // //DWORD Err = GetLastError(); //int rc = kDbgModPeConvWinError(Err); //kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%Rrc\n", Err, rc)); //return rc; return KERR_NOT_IMPLEMENTED; } /** * Opens the debug info for a PE image using the windows dbghelp library. * * @returns IPRT status code. * * @param pFile The handle to the module. * @param offHdr The offset of the PE header. * @param pszModulePath The path to the module. * @param ppDbgMod Where to store the module handle. * */ int kdbgModPEOpen(PKDBGHLPFILE pFile, int64_t offHdr, const char *pszModulePath, PKDBGMOD *ppDbgMod) { /* * We need to read the section headers and get the image size. */ IMAGE_FILE_HEADER FHdr; int rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, FileHeader), &FHdr, sizeof(FHdr)); kDbgAssertRCReturn(rc, rc); uint32_t cbImage; if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)) rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.SizeOfImage), &cbImage, sizeof(cbImage)); else if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64)) rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.SizeOfImage), &cbImage, sizeof(cbImage)); else kDbgAssertFailedReturn(KDBG_ERR_BAD_EXE_FORMAT); kDbgAssertRCReturn(rc, rc); /* * Allocate the module and read/construct the section headers. */ PKDBGMODPE pModPe = (PKDBGMODPE)kDbgHlpAlloc(KDBG_OFFSETOF(KDBGMODPE, aSections[FHdr.NumberOfSections + 2])); kDbgAssertReturn(pModPe, KERR_NO_MEMORY); pModPe->Core.u32Magic = KDBGMOD_MAGIC; pModPe->Core.pOps = &g_kDbgModPeOps; pModPe->Core.pFile = pFile; pModPe->cbImage = cbImage; pModPe->cSections = 1 + FHdr.NumberOfSections; rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader) + FHdr.SizeOfOptionalHeader, &pModPe->aSections[1], sizeof(pModPe->aSections[0]) * FHdr.NumberOfSections); if (!rc) { PIMAGE_SECTION_HEADER pSH = &pModPe->aSections[0]; memcpy(pSH->Name, "headers", sizeof(pSH->Name)); pSH->Misc.VirtualSize = pModPe->aSections[1].VirtualAddress; pSH->VirtualAddress = 0; pSH->SizeOfRawData = pSH->Misc.VirtualSize; pSH->PointerToRawData = 0; pSH->PointerToRelocations = 0; pSH->PointerToLinenumbers = 0; pSH->NumberOfRelocations = 0; pSH->NumberOfLinenumbers = 0; pSH->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ; uint32_t uTheEnd = pModPe->aSections[FHdr.NumberOfSections].VirtualAddress + pModPe->aSections[FHdr.NumberOfSections].Misc.VirtualSize; if (uTheEnd < cbImage) { pSH = &pModPe->aSections[pModPe->cSections++]; memcpy(pSH->Name, "tail\0\0\0", sizeof(pSH->Name)); pSH->Misc.VirtualSize = cbImage - uTheEnd; pSH->VirtualAddress = uTheEnd; pSH->SizeOfRawData = pSH->Misc.VirtualSize; pSH->PointerToRawData = 0; pSH->PointerToRelocations = 0; pSH->PointerToLinenumbers = 0; pSH->NumberOfRelocations = 0; pSH->NumberOfLinenumbers = 0; pSH->Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_READ; } #if 0 /* * Find a new dbghelp handle. * * We assume 4GB of handles outlast most debugging sessions, or in anyways that * when we start reusing handles they are no longer in use. :-) */ static volatile uint32_t s_u32LastHandle = 1; HANDLE hSymInst = (HANDLE)ASMAtomicIncU32(&s_u32LastHandle); while ( hSymInst == INVALID_HANDLE_VALUE || hSymInst == (HANDLE)0 || hSymInst == GetCurrentProcess()) hSymInst = (HANDLE)ASMAtomicIncU32(&s_u32LastHandle); /* * Initialize dbghelp and try open the specified module. */ if (g_pfnSymInitialize(hSymInst, NULL, FALSE)) { g_pfnSymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_AUTO_PUBLICS | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS); kDbgHlpSeek(pFile, 0); /* don't know if this is required or not... */ DWORD64 ImageBase = g_pfnSymLoadModule64(hSymInst, (HANDLE)File, pszModulePath, NULL, 0x00400000, 0); if (ImageBase) { pModPe->hSymInst = hSymInst; pModPe->ImageBase = ImageBase; *ppDbgMod = &pModPe->Core; return rc; } DWORD Err = GetLastError(); rc = kDbgModPeConvWinError(Err); kDbgAssertMsgFailed(("SymLoadModule64 failed: Err=%d rc=%Rrc\n", Err, rc)); g_pfnSymCleanup(hSymInst); } else { DWORD Err = GetLastError(); rc = kDbgModPeConvWinError(Err); kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%Rrc\n", Err, rc)); } #endif rc = KERR_NOT_IMPLEMENTED; } else kDbgAssertRC(rc); kDbgHlpFree(pModPe); return rc; } /** * Methods for a PE module. */ const KDBGMODOPS g_kDbgModPeOps = { "PE", kDbgModPeClose, kDbgModPeQuerySymbol, kDbgModPeQueryLine }; kbuild-3149/src/lib/kStuff/kDbg/kDbgHlpCrt.cpp0000644000175000017500000001221613252530254021045 0ustar locutuslocutus/* $Id: kDbgHlpCrt.cpp 77 2016-06-22 17:03:55Z bird $ */ /** @file * kDbg - The Debug Info Reader, Helpers, CRT Based Implementation. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "kDbgHlp.h" #include "kDbg.h" #include #include #include #include #ifdef _MSC_VER # include #endif /** * The stdio base implementation of KDBGHLPFILE. */ typedef struct KDBGHLPFILE { /** Pointer to the stdio file stream. */ FILE *pStrm; } KDBGHLPFILE; /** @def HAVE_FSEEKO * Define HAVE_FSEEKO to indicate that fseeko and ftello should be used. */ #if !defined(_MSC_VER) # define HAVE_FSEEKO #endif void *kDbgHlpAlloc(size_t cb) { return malloc(cb); } void *kDbgHlpAllocZ(size_t cb) { return calloc(1, cb); } void *kDbgHlpAllocDup(const void *pv, size_t cb) { void *pvNew = malloc(cb); if (pvNew) memcpy(pvNew, pv, cb); return pvNew; } void *kDbgHlpReAlloc(void *pv, size_t cb) { return realloc(pv, cb); } void kDbgHlpFree(void *pv) { free(pv); } int kDbgHlpCrtConvErrno(int rc) { switch (rc) { case 0: return 0; case EINVAL: return KERR_INVALID_PARAMETER; case ENOMEM: return KERR_NO_MEMORY; case EISDIR: case ENOENT: return KERR_FILE_NOT_FOUND; default: return KERR_GENERAL_FAILURE; } } int kDbgHlpOpenRO(const char *pszFilename, PKDBGHLPFILE *ppFile) { PKDBGHLPFILE pFile = (PKDBGHLPFILE)kDbgHlpAlloc(sizeof(*pFile)); if (!pFile) return KERR_NO_MEMORY; pFile->pStrm = fopen(pszFilename, "rb"); if (pFile->pStrm) { *ppFile = pFile; return 0; } return kDbgHlpCrtConvErrno(errno); } void kDbgHlpClose(PKDBGHLPFILE pFile) { if (pFile) { fclose(pFile->pStrm); pFile->pStrm = NULL; kDbgHlpFree(pFile); } } uintptr_t kDbgHlpNativeFileHandle(PKDBGHLPFILE pFile) { int fd = fileno(pFile->pStrm); #ifdef _MSC_VER return _get_osfhandle(fd); #else return fd; #endif } int64_t kDbgHlpFileSize(PKDBGHLPFILE pFile) { int64_t cbFile; int64_t offCur = kDbgHlpTell(pFile); if (offCur >= 0) { if (kDbgHlpSeekByEnd(pFile, 0) == 0) cbFile = kDbgHlpTell(pFile); else cbFile = -1; kDbgHlpSeek(pFile, offCur); } else cbFile = -1; return cbFile; } int kDbgHlpReadAt(PKDBGHLPFILE pFile, int64_t off, void *pv, size_t cb) { int rc = kDbgHlpSeek(pFile, off); if (!rc) rc = kDbgHlpRead(pFile, pv, cb); return rc; } int kDbgHlpRead(PKDBGHLPFILE pFile, void *pv, size_t cb) { if (fread(pv, cb, 1, pFile->pStrm) == 1) return 0; return -1; } int kDbgHlpSeek(PKDBGHLPFILE pFile, int64_t off) { #ifdef HAVE_FSEEKO if (!fseeko(pFile->pStrm, off, SEEK_SET)) return 0; #else long l = (long)off; if (l != off) return KERR_OUT_OF_RANGE; if (!fseek(pFile->pStrm, l, SEEK_SET)) return 0; #endif return kDbgHlpCrtConvErrno(errno); } int kDbgHlpSeekByCur(PKDBGHLPFILE pFile, int64_t off) { #ifdef HAVE_FSEEKO if (!fseeko(pFile->pStrm, off, SEEK_CUR)) return 0; #else long l = (long)off; if (l != off) return KERR_OUT_OF_RANGE; if (!fseek(pFile->pStrm, l, SEEK_CUR)) return 0; #endif return kDbgHlpCrtConvErrno(errno); } int kDbgHlpSeekByEnd(PKDBGHLPFILE pFile, int64_t off) { #ifdef HAVE_FSEEKO if (!fseeko(pFile->pStrm, -off, SEEK_END)) return 0; #else long l = (long)off; if (l != off) return KERR_OUT_OF_RANGE; if (!fseek(pFile->pStrm, -l, SEEK_END)) return 0; #endif return kDbgHlpCrtConvErrno(errno); } int64_t kDbgHlpTell(PKDBGHLPFILE pFile) { #ifdef HAVE_FSEEKO return ftello(pFile->pStrm); #else return ftell(pFile->pStrm); #endif } kbuild-3149/src/lib/kStuff/kDbg/Makefile.kmk0000644000175000017500000000421213252530254020573 0ustar locutuslocutus# $Id: Makefile.kmk 29 2009-07-01 20:30:29Z bird $ ## @file # kDbg - The Debug Info Reader, sub-makefile. # # # Copyright (c) 2006-2007 Knut St. Osmundsen # # 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. # DEPTH ?= .. SUB_DEPTH = .. include $(PATH_KBUILD)/subheader.kmk # # kDbg - The profiler module. # #DLLS += kDbg - disabled for now. kDbg_TEMPLATE = kStuffDLL kDbg_DEFS = KDBG_BUILDING KDBG_RESIDES_IN_DLL kDbg_SOURCES := \ kDbgModule.cpp \ kDbgModLdr.cpp \ kDbgLine.cpp \ kDbgSymbol.cpp kDbg_SOURCES.win += \ kDbgModWinDbgHelp.cpp # # kDbgStatic - The profiler module. # LIBRARIES += kDbgStatic kDbgStatic_TEMPLATE = kStuffLIB kDbgStatic_DEFS = KDBG_BUILDING kDbgStatic_SOURCES = $(kDbg_SOURCES) kDbgStatic_SOURCES.win = $(kDbg_SOURCES.win) # # kDbgDump - Test program which dumps whatever is thrown at it. # PROGRAMS += kDbgDump kDbgDump_TEMPLATE = kStuffEXE kDbgDump_SOURCES = kDbgDump.cpp kDbgDump_LIBS = \ $(TARGET_kDbgStatic) \ $(subst kDbg,kLdr,$(TARGET_kDbgStatic)) \ $(subst kDbg,kRdr,$(TARGET_kDbgStatic)) \ $(subst kDbg,kHlpCRT,$(TARGET_kDbgStatic)) # Generate the rules include $(PATH_KBUILD)/subfooter.kmk kbuild-3149/src/lib/kStuff/kDbg/kDbgDump.cpp0000644000175000017500000001223513252530254020557 0ustar locutuslocutus/* $Id: kDbgDump.cpp 29 2009-07-01 20:30:29Z bird $ */ /** @file * kDbgDump - Debug Info Dumper. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include /******************************************************************************* * Global Variables * *******************************************************************************/ /** @name Options * @{ */ static int g_fGlobalSyms = 1; static int g_fPrivateSyms = 1; static int g_fLineNumbers = 0; /** @} */ /** * Dumps one file. * * @returns main exit status. * @param pszFile The file to dump (path to it). */ static int DumpFile(const char *pszFile) { PKDBGMOD pDbgMod; int rc = kDbgModuleOpen(&pDbgMod, pszFile, NULL); if (rc) { printf("kDbgDump: error: kDbgModuleOpen('%s',) failed with rc=%d.\n", pszFile, rc); return 1; } return 0; } /** * Prints the version number * @return 0 */ static int ShowVersion() { printf("kDbgDump v0.0.1\n"); return 0; } /** * Prints the program syntax. * * @returns 1 * @param argv0 The program name. */ static int ShowSyntax(const char *argv0) { ShowVersion(); printf("syntax: %s [options] \n" "\n", argv0); return 1; } int main(int argc, char **argv) { int rcRet = 0; /* * Parse arguments. */ int fArgsDone = 0; for (int i = 1; i < argc; i++) { const char *psz = argv[i]; if (!fArgsDone && psz[0] == '-' && psz[1]) { /* convert long option to short. */ if (*++psz == '-') { psz++; if (!*psz) /* -- */ { fArgsDone = 1; continue; } if (!strcmp(psz, "line-numbers")) psz = "l"; else if (!strcmp(psz, "no-line-numbers")) psz = "L"; else if (!strcmp(psz, "global-syms") || !strcmp(psz, "public-syms")) psz = "g"; else if (!strcmp(psz, "no-global-syms") || !strcmp(psz, "no-public-syms")) psz = "G"; else if (!strcmp(psz, "privat-syms") || !strcmp(psz, "local-syms")) psz = "p"; else if (!strcmp(psz, "no-privat-syms") || !strcmp(psz, "no-local-syms")) psz = "P"; else if (!strcmp(psz, "version")) psz = "v"; else if (!strcmp(psz, "help")) psz = "h"; else { fprintf(stderr, "%s: syntax error: unknown option '--%s'\n", argv[0], psz); return 1; } } /* eat short options. */ while (*psz) switch (*psz++) { case 'l': g_fLineNumbers = 1; break; case 'L': g_fLineNumbers = 0; break; case 'p': g_fPrivateSyms = 1; break; case 'P': g_fPrivateSyms = 0; break; case 'g': g_fGlobalSyms = 1; break; case 'G': g_fGlobalSyms = 0; break; case '?': case 'H': case 'h': return ShowSyntax(argv[0]); case 'v': return ShowVersion(); default: fprintf(stderr, "%s: syntax error: unknown option '-%c'.\n", argv[0], psz[-1]); return 1; } } else { /* Dump does it's own bitching if something goes wrong. */ int rc = DumpFile(psz); if (rc && !rcRet) rc = rcRet; } } return rcRet; } kbuild-3149/src/lib/kStuff/kDbg/kDbgModule.cpp0000644000175000017500000003714313252530254021104 0ustar locutuslocutus/* $Id: kDbgModule.cpp 29 2009-07-01 20:30:29Z bird $ */ /** @file * kDbg - The Debug Info Reader, Module API. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "kDbgInternal.h" #include #include /******************************************************************************* * Global Variables * *******************************************************************************/ /** * The built-in debug module readers. */ static PCKDBGMODOPS const g_aBuiltIns[] = { #if K_OS == K_OS_WINDOWS &g_kDbgModWinDbgHelpOpen, #endif &g_kDbgModLdr, // &g_kDbgModCv8, // &g_kDbgModDwarf, // &g_kDbgModHll, // &g_kDbgModStabs, // &g_kDbgModSym, // &g_kDbgModMapILink, // &g_kDbgModMapMSLink, // &g_kDbgModMapNm, // &g_kDbgModMapWLink }; /** * The debug module readers registered at runtime. */ static PKDBGMODOPS g_pHead = NULL; /** * Register a debug module reader with the kDbgModule component. * * Dynamically registered readers are kept in FIFO order, and external * readers will be tried after the builtin ones. * * Like all other kDbg APIs serializing is left to the caller. * * @returns 0 on success. * @returns KERR_INVALID_POINTER if pOps is missing bits. * @returns KERR_INVALID_PARAMETER if pOps is already in the list. * @param pOps The reader method table, kDbg takes owner ship of * this. This must be writeable as the pNext pointer * will be update. It must also stick around for as * long as kDbg is in use. */ KDBG_DECL(int) kDbgModuleRegisterReader(PKDBGMODOPS pOps) { /* * Validate input. */ kDbgAssertPtrReturn(pOps, KERR_INVALID_POINTER); kDbgAssertPtrReturn(pOps->pszName, KERR_INVALID_POINTER); kDbgAssertPtrReturn(pOps->pfnOpen, KERR_INVALID_POINTER); kDbgAssertPtrReturn(pOps->pfnClose, KERR_INVALID_POINTER); kDbgAssertPtrReturn(pOps->pfnQuerySymbol, KERR_INVALID_POINTER); kDbgAssertPtrReturn(pOps->pfnQueryLine, KERR_INVALID_POINTER); kDbgAssertPtrReturn(pOps->pszName2, KERR_INVALID_POINTER); if (kHlpStrComp(pOps->pszName, pOps->pszName2)) return KERR_INVALID_PARAMETER; kDbgAssertReturn(pOps->pNext == NULL, KERR_INVALID_PARAMETER); /* * Link it into the list. */ if (!g_pHead) g_pHead = pOps; else { PKDBGMODOPS pPrev = g_pHead; while (pPrev->pNext) pPrev = pPrev->pNext; kDbgAssertReturn(pPrev != pOps, KERR_INVALID_PARAMETER); pPrev->pNext = pOps; } return 0; } /** * Deregister a debug module reader previously registered using * the kDbgModuleRegisterReader API. * * Deregistering a reader does not mean that non of its functions * will be called after successful return, it only means that it * will no longer be subjected to new module. * * @returns 0 on success. * @returns KERR_INVALID_POINTER if pOps isn't a valid pointer. * @returns KERR_INVALID_PARAMETER if pOps wasn't registered. * @param pOps The debug module method table to deregister. */ KDBG_DECL(int) kDbgModuleDeregisterReader(PKDBGMODOPS pOps) { /* * Validate the pointer. */ kDbgAssertPtrReturn(pOps, KERR_INVALID_POINTER); /* * Find it in the list and unlink it. */ if (g_pHead == pOps) g_pHead = pOps->pNext; else { PKDBGMODOPS pPrev = g_pHead; while (pPrev && pPrev->pNext != pOps) pPrev = pPrev->pNext; if (!pPrev) return KERR_INVALID_PARAMETER; pPrev->pNext = pOps->pNext; } pOps->pNext = NULL; return 0; } /** * Worker for the kDbgModuleOpen* APIs. * * This will make sure the reader is buffered. I will also take care of * closing the reader opened by kDbgModuleOpen on failure. * * @returns 0 on success. An appropriate kErrors status code on failure. * @param ppDbgMod Where to store the new debug module reader instance. * @param pRdr The file provider. * @param fCloseRdr Whether pRdr should be close or not. This applies both * to the failure path and to the success path, where it'll * be close when the module is closed by kDbgModuleClose(). * @param off The offset into the file where the debug info is supposed * to be found. * This is 0 if the entire file is the subject. * @param cb The size of the debug info part of the file. * This is KFOFF_MAX if the entire file is the subject. * @param pLdrMod An optional kLdrMod association. */ static int kdbgModuleOpenWorker(PPKDBGMOD ppDbgMod, PKRDR pRdr, KBOOL fCloseRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod) { /* * If the reader isn't buffered create a buffered wrapper for it. */ int rc; PKRDR pRdrWrapped = NULL; if (!kRdrBufIsBuffered(pRdr)) { rc = kRdrBufWrap(&pRdrWrapped, pRdr, fCloseRdr); if (rc) { if (fCloseRdr) kRdrClose(pRdr); return rc; } pRdr = pRdrWrapped; } /* * Walk the built-in table and the list of registered readers * and let each of them have a go at the file. Stop and return * on the first one returning successfully. */ rc = KDBG_ERR_UNKOWN_FORMAT; for (KSIZE i = 0; i < K_ELEMENTS(g_aBuiltIns); i++) if (g_aBuiltIns[i]->pfnOpen) { int rc2 = g_aBuiltIns[i]->pfnOpen(ppDbgMod, pRdr, fCloseRdr, off, cb, pLdrMod); if (!rc2) return 0; if (rc2 != KDBG_ERR_UNKOWN_FORMAT && rc == KDBG_ERR_UNKOWN_FORMAT) rc = rc2; } for (PKDBGMODOPS pCur = g_pHead; pCur; pCur = pCur->pNext) if (pCur->pfnOpen) { int rc2 = pCur->pfnOpen(ppDbgMod, pRdr, fCloseRdr, off, cb, pLdrMod); if (!rc2) return 0; if (rc2 != KDBG_ERR_UNKOWN_FORMAT && rc == KDBG_ERR_UNKOWN_FORMAT) rc = rc2; } if (pRdrWrapped) kRdrClose(pRdrWrapped); else if (fCloseRdr) kRdrClose(pRdr); return rc; } /** * Opens a debug module reader for the specified file or file section * * @returns kStuff status code. * @param ppDbgMod Where to store the debug module reader handle. * @param pRdr The file reader. * @param off The offset of the file section. If the entire file, pass 0. * @param cb The size of the file section. If the entire file, pass KFOFF_MAX. * @param pLdrMod Associated kLdr module that the kDbg component can use to * verify and suplement the debug info found in the file specified * by pszFilename. The module will be used by kDbg for as long as * the returned kDbg module remains open. * This is an optional parameter, pass NULL if no kLdr module at hand. */ KDBG_DECL(int) kDbgModuleOpenFilePart(PPKDBGMOD ppDbgMod, PKRDR pRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod) { /* * Validate input. */ kDbgAssertPtrReturn(ppDbgMod, KERR_INVALID_POINTER); kDbgAssertPtrReturn(pRdr, KERR_INVALID_POINTER); kDbgAssertPtrNullReturn(pLdrMod, KERR_INVALID_POINTER); kDbgAssertMsgReturn(off >= 0 && off < KFOFF_MAX, (KFOFF_PRI "\n", off), KERR_INVALID_OFFSET); kDbgAssertMsgReturn(cb >= 0 && cb <= KFOFF_MAX, (KFOFF_PRI "\n", cb), KERR_INVALID_SIZE); kDbgAssertMsgReturn(off + cb > off, ("off=" KFOFF_PRI " cb=" KFOFF_PRI "\n", off, cb), KERR_INVALID_RANGE); *ppDbgMod = NULL; /* * Hand it over to the internal worker. */ return kdbgModuleOpenWorker(ppDbgMod, pRdr, K_FALSE /* fCloseRdr */, off, cb, pLdrMod); } /** * Opens a debug module reader for the specified file. * * @returns kStuff status code. * @param ppDbgMod Where to store the debug module reader handle. * @param pRdr The file reader. * @param pLdrMod Associated kLdr module that the kDbg component can use to * verify and suplement the debug info found in the file specified * by pszFilename. The module will be used by kDbg for as long as * the returned kDbg module remains open. * This is an optional parameter, pass NULL if no kLdr module at hand. */ KDBG_DECL(int) kDbgModuleOpenFile(PPKDBGMOD ppDbgMod, PKRDR pRdr, struct KLDRMOD *pLdrMod) { return kDbgModuleOpenFilePart(ppDbgMod, pRdr, 0, KFOFF_MAX, pLdrMod); } /** * Opens the debug info for a specified executable module. * * @returns kStuff status code. * @param ppDbgMod Where to store the debug module handle. * @param pszFilename The name of the file containing debug info and/or which * debug info is wanted. * @param pLdrMod Associated kLdr module that the kDbg component can use to * verify and suplement the debug info found in the file specified * by pszFilename. The module will be used by kDbg for as long as * the returned kDbg module remains open. * This is an optional parameter, pass NULL if no kLdr module at hand. */ KDBG_DECL(int) kDbgModuleOpen(PPKDBGMOD ppDbgMod, const char *pszFilename, struct KLDRMOD *pLdrMod) { /* * Validate input. */ kDbgAssertPtrReturn(ppDbgMod, KERR_INVALID_POINTER); kDbgAssertPtrReturn(pszFilename, KERR_INVALID_POINTER); kDbgAssertMsgReturn(*pszFilename, ("%p\n", pszFilename), KERR_INVALID_PARAMETER); kDbgAssertPtrNullReturn(pLdrMod, KERR_INVALID_POINTER); *ppDbgMod = NULL; /* * Open the file and see if we can read it. */ PKRDR pRdr; int rc = kRdrBufOpen(&pRdr, pszFilename); if (rc) return rc; rc = kdbgModuleOpenWorker(ppDbgMod, pRdr, K_TRUE /* fCloseRdr */, 0, KFOFF_MAX, pLdrMod); return rc; } /** * Closes the module. * * @returns IPRT status code. * @param pMod The module handle. */ KDBG_DECL(int) kDbgModuleClose(PKDBGMOD pMod) { KDBGMOD_VALIDATE(pMod); int rc = pMod->pOps->pfnClose(pMod); if (!rc) { pMod->u32Magic++; kHlpFree(pMod); } return rc; } /** * Gets a symbol by segment:offset. * This will be approximated to the nearest symbol if there is no exact match. * * @returns IPRT status code. * @param pMod The module. * @param iSegment The segment this offset is relative to. * The -1 segment is special, it means that the addres is relative to * the image base. The image base is where the first bit of the image * is mapped during load. * @param off The offset into the segment. * @param pSym Where to store the symbol details. */ KDBG_DECL(int) kDbgModuleQuerySymbol(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGSYMBOL pSym) { KDBGMOD_VALIDATE(pMod); kDbgAssertPtrReturn(pSym, KERR_INVALID_POINTER); return pMod->pOps->pfnQuerySymbol(pMod, iSegment, off, pSym); } /** * Gets & allocates a symbol by segment:offset. * This will be approximated to the nearest symbol if there is no exact match. * * @returns IPRT status code. * @param pMod The module. * @param iSegment The segment this offset is relative to. * The -1 segment is special, it means that the addres is relative to * the image base. The image base is where the first bit of the image * is mapped during load. * @param off The offset into the segment. * @param ppSym Where to store the pointer to the symbol info. * Free the returned symbol using kDbgSymbolFree(). */ KDBG_DECL(int) kDbgModuleQuerySymbolA(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PPKDBGSYMBOL ppSym) { kDbgAssertPtrReturn(ppSym, KERR_INVALID_POINTER); KDBGSYMBOL Sym; int rc = kDbgModuleQuerySymbol(pMod, iSegment, off, &Sym); if (!rc) { *ppSym = kDbgSymbolDup(&Sym); if (!*ppSym) rc = KERR_NO_MEMORY; } else *ppSym = NULL; return rc; } /** * Gets a line number entry by segment:offset. * This will be approximated to the nearest line number there is no exact match. * * @returns IPRT status code. * @param pMod The module. * @param iSegment The segment this offset is relative to. * The -1 segment is special, it means that the addres is relative to * the image base. The image base is where the first bit of the image * is mapped during load. * @param off The offset into the segment. * @param pLine Where to store the line number details. */ KDBG_DECL(int) kDbgModuleQueryLine(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGLINE pLine) { KDBGMOD_VALIDATE(pMod); kDbgAssertPtrReturn(pLine, KERR_INVALID_POINTER); return pMod->pOps->pfnQueryLine(pMod, iSegment, off, pLine); } /** * Gets & allocates a line number entry by segment:offset. * This will be approximated to the nearest line number there is no exact match. * * @returns IPRT status code. * @param pMod The module. * @param iSegment The segment this offset is relative to. * The -1 segment is special, it means that the addres is relative to * the image base. The image base is where the first bit of the image * is mapped during load. * @param off The offset into the segment. * @param ppLine Where to store the pointer to the line number info. * Free the returned line number using kDbgLineFree(). */ KDBG_DECL(int) kDbgModuleQueryLineA(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PPKDBGLINE ppLine) { kDbgAssertPtrReturn(ppLine, KERR_INVALID_POINTER); KDBGLINE Line; int rc = kDbgModuleQueryLine(pMod, iSegment, off, &Line); if (!rc) { *ppLine = kDbgLineDup(&Line); if (!*ppLine) rc = KERR_NO_MEMORY; } else *ppLine = NULL; return rc; } kbuild-3149/src/lib/kStuff/kDbg/kDbgSymbol.cpp0000644000175000017500000000522213252530254021115 0ustar locutuslocutus/* $Id: kDbgSymbol.cpp 29 2009-07-01 20:30:29Z bird $ */ /** @file * kDbg - The Debug Info Reader, Symbols. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "kDbgInternal.h" #include /** * Duplicates a symbol. * * To save heap space, the returned symbol will not own more heap space than * it strictly need to. So, it's not possible to append stuff to the symbol * or anything of that kind. * * @returns Pointer to the duplicate. * This must be freed using kDbgSymbolFree(). * @param pSymbol The symbol to be duplicated. */ KDBG_DECL(PKDBGSYMBOL) kDbgSymbolDup(PCKDBGSYMBOL pSymbol) { kDbgAssertPtrReturn(pSymbol, NULL); KSIZE cb = K_OFFSETOF(KDBGSYMBOL, szName[pSymbol->cchName + 1]); PKDBGSYMBOL pNewSymbol = (PKDBGSYMBOL)kHlpDup(pSymbol, cb); if (pNewSymbol) pNewSymbol->cbSelf = cb; return pNewSymbol; } /** * Frees a symbol obtained from the kDbg API. * * @returns 0 on success. * @returns KERR_INVALID_POINTER if pSymbol isn't a valid pointer. * * @param pSymbol The symbol to be freed. The null pointer is ignored. */ KDBG_DECL(int) kDbgSymbolFree(PKDBGSYMBOL pSymbol) { if (!pSymbol) { kDbgAssertPtrReturn(pSymbol, KERR_INVALID_POINTER); pSymbol->cbSelf = 0; kHlpFree(pSymbol); } return 0; } kbuild-3149/src/lib/kStuff/kDbg/kDbgInternal.h0000644000175000017500000001315513252530254021075 0ustar locutuslocutus/* $Id: kDbgInternal.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kDbg - The Debug Info Reader, Internal Header. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___kDbgInternal_h___ #define ___kDbgInternal_h___ #include #include #include #include /** @defgroup grp_kDbgInternal Internal * @internal * @addtogroup grp_kDbg * @{ */ /** @def KDBG_STRICT * If defined the kDbg assertions and other runtime checks will be enabled. */ #ifdef K_ALL_STRICT # undef KDBG_STRICT # define KDBG_STRICT #endif /** @name Our Assert macros * @{ */ #ifdef KDBG_STRICT # define kDbgAssert(expr) kHlpAssert(expr) # define kDbgAssertReturn(expr, rcRet) kHlpAssertReturn(expr, rcRet) # define kDbgAssertReturnVoid(expr) kHlpAssertReturnVoid(expr) # define kDbgAssertMsg(expr, msg) kHlpAssertMsg(expr, msg) # define kDbgAssertMsgReturn(expr, msg, rcRet) kHlpAssertMsgReturn(expr, msg, rcRet) # define kDbgAssertMsgReturnVoid(expr, msg) kHlpAssertMsgReturnVoid(expr, msg) #else /* !KDBG_STRICT */ # define kDbgAssert(expr) do { } while (0) # define kDbgAssertReturn(expr, rcRet) do { if (!(expr)) return (rcRet); } while (0) # define kDbgAssertMsg(expr, msg) do { } while (0) # define kDbgAssertMsgReturn(expr, msg, rcRet) do { if (!(expr)) return (rcRet); } while (0) #endif /* !KDBG_STRICT */ #define kDbgAssertPtr(ptr) kDbgAssertMsg(K_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr))) #define kDbgAssertPtrReturn(ptr, rcRet) kDbgAssertMsgReturn(K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet)) #define kDbgAssertPtrReturnVoid(ptr) kDbgAssertMsgReturnVoid(K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet))) #define kDbgAssertPtrNull(ptr) kDbgAssertMsg(!(ptr) || K_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr))) #define kDbgAssertPtrNullReturn(ptr, rcRet) kDbgAssertMsgReturn(!(ptr) || K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet)) #define kDbgAssertPtrNullReturnVoid(ptr) kDbgAssertMsgReturnVoid(!(ptr) || K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet))) #define kDbgAssertRC(rc) kDbgAssertMsg((rc) == 0, ("%s = %d\n", #rc, (rc))) #define kDbgAssertRCReturn(rc, rcRet) kDbgAssertMsgReturn((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet)), (rcRet)) #define kDbgAssertRCReturnVoid(rc) kDbgAssertMsgReturnVoid((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet))) #define kDbgAssertFailed() kDbgAssert(0) #define kDbgAssertFailedReturn(rcRet) kDbgAssertReturn(0, (rcRet)) #define kDbgAssertFailedReturnVoid() kDbgAssertReturnVoid(0) #define kDbgAssertMsgFailed(msg) kDbgAssertMsg(0, msg) #define kDbgAssertMsgFailedReturn(msg, rcRet) kDbgAssertMsgReturn(0, msg, (rcRet)) #define kDbgAssertMsgFailedReturnVoid(msg) kDbgAssertMsgReturnVoid(0, msg) /** @} */ /** Return / crash validation of a reader argument. */ #define KDBGMOD_VALIDATE_EX(pDbgMod, rc) \ do { \ kDbgAssertPtrReturn((pDbgMod), (rc)); \ kDbgAssertReturn((pDbgMod)->u32Magic == KDBGMOD_MAGIC, (rc)); \ kDbgAssertReturn((pDbgMod)->pOps != NULL, (rc)); \ } while (0) /** Return / crash validation of a reader argument. */ #define KDBGMOD_VALIDATE(pDbgMod) \ do { \ kDbgAssertPtrReturn((pDbgMod), KERR_INVALID_POINTER); \ kDbgAssertReturn((pDbgMod)->u32Magic == KDBGMOD_MAGIC, KERR_INVALID_HANDLE); \ kDbgAssertReturn((pDbgMod)->pOps != NULL, KERR_INVALID_HANDLE); \ } while (0) /** Return / crash validation of a reader argument. */ #define KDBGMOD_VALIDATE_VOID(pDbgMod) \ do { \ kDbgAssertPtrReturnVoid((pDbgMod)); \ kDbgAssertReturnVoid((pDbgMod)->u32Magic == KDBGMOD_MAGIC); \ kDbgAssertReturnVoid((pDbgMod)->pOps != NULL); \ } while (0) #ifdef __cplusplus extern "C" { #endif /** @name Built-in Debug Module Readers * @{ */ extern KDBGMODOPS const g_kDbgModWinDbgHelpOpen; extern KDBGMODOPS const g_kDbgModLdr; extern KDBGMODOPS const g_kDbgModCv8; extern KDBGMODOPS const g_kDbgModDwarf; extern KDBGMODOPS const g_kDbgModHll; extern KDBGMODOPS const g_kDbgModStabs; extern KDBGMODOPS const g_kDbgModSym; extern KDBGMODOPS const g_kDbgModMapILink; extern KDBGMODOPS const g_kDbgModMapMSLink; extern KDBGMODOPS const g_kDbgModMapNm; extern KDBGMODOPS const g_kDbgModMapWLink; /** @} */ #ifdef __cplusplus } #endif /** @} */ #endif kbuild-3149/src/lib/kStuff/kDbg/kDbgModLdr.cpp0000644000175000017500000000601113252530254021026 0ustar locutuslocutus/* $Id: kDbgModLdr.cpp 29 2009-07-01 20:30:29Z bird $ */ /** @file * kDbg - The Debug Info Reader, kLdr Based. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include "kDbgInternal.h" /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * A kLdr based debug reader. */ typedef struct KDBGMODLDR { /** The common module core. */ KDBGMOD Core; /** Pointer to the loader module. */ PKLDRMOD pLdrMod; } KDBGMODLDR, *PKDBGMODLDR; /** * @copydoc KDBGMODOPS::pfnQueryLine */ static int kDbgModLdrQueryLine(PKDBGMOD pMod, KI32 iSegment, KDBGADDR uOffset, PKDBGLINE pLine) { //PKDBGMODLDR pThis = (PKDBGMODLDR)pMod; return KERR_NOT_IMPLEMENTED; } /** * @copydoc KDBGMODOPS::pfnQuerySymbol */ static int kDbgModLdrQuerySymbol(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGSYMBOL pSym) { //PKDBGMODLDR pThis = (PKDBGMODLDR)pMod; return KERR_NOT_IMPLEMENTED; } /** * @copydoc KDBGMODOPS::pfnClose */ static int kDbgModLdrClose(PKDBGMOD pMod) { //PKDBGMODLDr pThis = (PKDBGMODLDR)pMod; return KERR_NOT_IMPLEMENTED; } /** * @copydocs KDBGMODOPS::pfnOpen. */ static int kDbgModLdrOpen(PKDBGMOD *ppMod, PKRDR pRdr, KBOOL fCloseRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod) { return KERR_NOT_IMPLEMENTED; } /** * Methods for a PE module. */ const KDBGMODOPS g_kDbgModLdr = { "kLdr", NULL, kDbgModLdrOpen, kDbgModLdrClose, kDbgModLdrQuerySymbol, kDbgModLdrQueryLine, "kLdr" }; kbuild-3149/src/lib/kStuff/kDbg/kDbgLine.cpp0000644000175000017500000000517713252530254020550 0ustar locutuslocutus/* $Id: kDbgLine.cpp 29 2009-07-01 20:30:29Z bird $ */ /** @file * kDbg - The Debug Info Read, Line Numbers. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "kDbgInternal.h" #include /** * Duplicates a line number. * * To save heap space, the returned line number will not own more heap space * than it strictly need to. So, it's not possible to append stuff to the symbol * or anything of that kind. * * @returns Pointer to the duplicate. * This must be freed using kDbgSymbolFree(). * @param pLine The line number to be duplicated. */ KDBG_DECL(PKDBGLINE) kDbgLineDup(PCKDBGLINE pLine) { kDbgAssertPtrReturn(pLine, NULL); KSIZE cb = K_OFFSETOF(KDBGLINE, szFile[pLine->cchFile + 1]); PKDBGLINE pNewLine = (PKDBGLINE)kHlpDup(pLine, cb); if (pNewLine) pNewLine->cbSelf = cb; return pNewLine; } /** * Frees a line number obtained from the kDbg API. * * @returns 0 on success. * @returns KERR_INVALID_POINTER if pLine isn't a valid pointer. * * @param pLine The line number to be freed. The null pointer is ignored. */ KDBG_DECL(int) kDbgLineFree(PKDBGLINE pLine) { if (pLine) { kDbgAssertPtrReturn(pLine, KERR_INVALID_POINTER); pLine->cbSelf = 0; kHlpFree(pLine); } return 0; } kbuild-3149/src/lib/kStuff/kDbg/kDbgSpace.cpp0000644000175000017500000001373113252530254020707 0ustar locutuslocutus/* $Id: kDbgSpace.cpp 29 2009-07-01 20:30:29Z bird $ */ /** @file * kDbg - The Debug Info Reader, Address Space Manager. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "kDbgInternal.h" #include #include #include /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** Pointer to a name space module. */ typedef struct KDBGSPACEMOD *PKDBGSPACEMOD; /** * Tracks a module segment in the address space. * * These segments are organized in two trees, by address in the * KDBGSPACE::pSegRoot tree and by selector value in the * KDBGSPACE::pSegSelRoot tree. * * While the debug module reader could easily provide us with * segment names and it could perhaps be interesting to lookup * a segment by its name in some situations, this has been * considered too much bother for now. :-) */ typedef struct KDBGSPACESEG { /** The module segment index. */ KI32 iSegment; /** The address space module structure this segment belongs to. */ PKDBGSPACEMOD pSpaceMod; } KDBGSPACESEG; typedef KDBGSPACESEG *PKDBGSPACESEG; /** * Track a module in the name space. * * Each module in the address space can be addressed efficiently * by module name. The module name has to be unique. */ typedef struct KDBGSPACEMOD { /** The module name hash. */ KU32 u32Hash; /** The length of the module name. */ KU32 cchName; /** The module name. */ char *pszName; /** The next module in the same bucket. */ PKDBGSPACEMOD pNext; /** Pointer to the debug module reader. */ PKDBGMOD pMod; /** The number of segments. */ KU32 cSegs; /** The segment array. (variable length) */ KDBGSPACESEG aSegs[1]; } KDBGSPACEMOD; typedef struct KDBGCACHEDSYM *PKDBGCACHEDSYM; /** * A cached symbol. */ typedef struct KDBGCACHEDSYM { /** The symbol name hash. */ KU32 u32Hash; /** The next symbol in the same bucket. */ PKDBGCACHEDSYM pNext; /** The next symbol belonging to the same module as this. */ PKDBGCACHEDSYM pNextMod; /** The cached symbol information. */ KDBGSYMBOL Sym; } KDBGCACHEDSYM; /** * A symbol cache. */ typedef struct KDBGSYMCACHE { /** The symbol cache magic. (KDBGSYMCACHE_MAGIC) */ KU32 u32Magic; /** The maximum number of symbols.*/ KU32 cMax; /** The current number of symbols.*/ KU32 cCur; /** The number of hash buckets. */ KU32 cBuckets; /** The address lookup tree. */ PKDBGADDRAVL pAddrTree; /** Array of hash buckets. * The size is selected according to the cache size. */ PKDBGCACHEDSYM *paBuckets[1]; } KDBGSYMCACHE; typedef KDBGSYMCACHE *PKDBGSYMCACHE; /** * A user symbol record. * * The user symbols are organized in the KDBGSPACE::pUserRoot tree * and form an overlay that overrides the debug info retrieved from * the KDBGSPACE::pSegRoot tree. * * In the current implementation the user symbols are unique and * one would have to first delete a symbol in order to add another * at the same address. This may be changed later, perhaps. */ typedef struct KDBGSPACEUSERSYM { } KDBGSPACEUSERSYM; typedef KDBGSPACEUSERSYM *PKDBGSPACEUSERSYM; /** * Address space. */ typedef struct KDBGSPACE { /** The addresspace magic. (KDBGSPACE_MAGIC) */ KU32 u32Magic; /** User defined address space identifier or data pointer. */ KUPTR uUser; /** The name of the address space. (Optional) */ const char *pszName; } KDBGSPACE; /** Pointer to an address space. */ typedef struct KDBGSPACE *PKDBGSPACE; /** Pointer to an address space pointer. */ typedef PKDBGSPACE *PPKDBGSPACE; KDBG_DECL(int) kDbgSpaceCreate(PPDBGSPACE ppSpace, KDBGADDR LowAddr, DBGADDR HighAddr, KUPTR uUser, const char *pszName) { /* * Validate input. */ kDbgAssertPtrReturn(ppSpace); *ppSpace = NULL; kDbgAssertPtrNullReturn(pszName); kDbgAssertReturn(LowAddr < HighAddr); /* * Create and initialize the address space. */ PKDBGSPACE pSpace = (PKDBGSPACE)kHlpAlloc(sizeof(*pSpace)); if (!pSpace) return KERR_NO_MEMORY; pSpace->u32Magic = KDBGSPACE_MAGIC; pSpace->uUser = uUser; pSpace->pszName = pszName; } kbuild-3149/src/lib/kStuff/kDbg/kDbgHlp.h0000644000175000017500000002227713252530254020051 0ustar locutuslocutus/* $Id: kDbgHlp.h 78 2016-07-13 15:52:04Z bird $ */ /** @file * kDbg - The Debug Info Reader, Internal Header. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___kDbgHlp_h___ #define ___kDbgHlp_h___ #include #ifdef __cplusplus extern "C" { #endif /** @defgroup grp_kDbgHlpHeap kDbg Internal Heap APIs. * @internal * @{ */ /** * Allocates memory. * * @returns Pointer to the allocated memory. * NULL on failure. * @param cb The number of bytes to allocate. */ void *kDbgHlpAlloc(size_t cb); /** * Allocates memory like kDbgHlpAlloc, except that it's zeroed. * * @returns Pointer to the allocated memory. * NULL on failure. * @param cb The number of bytes to allocate. */ void *kDbgHlpAllocZ(size_t cb); /** * Combination of kDbgHlpAlloc and memcpy. * * @returns Pointer to the duplicate. * NULL on failure. * * @param pv The memory to be duplicate. * @param cb The size of the block. */ void *kDbgHlpAllocDup(const void *pv, size_t cb); /** * Reallocates a memory block returned by kDbgHlpAlloc, kDbgHlpAllocZ * kDbgHlpAllocDup or this function. * * The content of new memory added to the memory block is undefined. * * @returns Pointer to the allocated memory. * NULL on failure, the old block remains intact. * @param pv The memory block to reallocate. * If NULL this function will work like kDbgHlpAlloc. * @param cb The number of bytes to allocate. * If 0 this function will work like kDbgHlpFree. */ void *kDbgHlpRealloc(void *pv, size_t cb); /** * Frees memory allocated by kDbgHlpAlloc, kDbgHlpAllocZ * kDbgHlpAllocDup, or kDbgHlpRealloc. * * @param pv */ void kDbgHlpFree(void *pv); /** @} */ /** @defgroup grp_kDbgHlpFile kDbg Internal File Access APIs. * @internal * @{ */ /** * Opens the specified file as read-only, buffered if possible. * * @returns 0 on success, or the appropriate KDBG_ERR_* on failure. * * @param pszFilename The file to open. * @param ppFile Where to store the handle to the open file. */ int kDbgHlpOpenRO(const char *pszFilename, PKDBGHLPFILE *ppFile); /** * Closes a file opened by kDbgHlpOpenRO. * * @param pFile The file handle. */ void kDbgHlpClose(PKDBGHLPFILE pFile); /** * Gets the native file handle. * * @return The native file handle. * -1 on failure. * @param pFile The file handle. */ uintptr_t kDbgHlpNativeFileHandle(PKDBGHLPFILE pFile); /** * Gets the size of an open file. * * @returns The file size in bytes on success. * On failure -1 is returned. * @param pFile The file handle. */ int64_t kDbgHlpFileSize(PKDBGHLPFILE pFile); /** * Reads a number of bytes at a specified file location. * * This will change the current file position to off + cb on success, * while on failure the position will be undefined. * * @returns The file size in bytes on success. * On failure -1 is returned. * @param pFile The file handle. * @param off Where to read. * @param pv Where to store the data. * @param cb How much to read. */ int kDbgHlpReadAt(PKDBGHLPFILE pFile, int64_t off, void *pv, size_t cb); /** * Reads a number of bytes at the current file position. * * This will advance the current file position by cb bytes on success * while on failure the position will be undefined. * * @returns The file size in bytes on success. * On failure -1 is returned. * @param pFile The file handle. * @param pv Where to store the data. * @param cb How much to read. * @param off Where to read. */ int kDbgHlpRead(PKDBGHLPFILE pFile, void *pv, size_t cb); /** * Sets the current file position. * * @returns 0 on success, and KDBG_ERR_* on failure. * @param pFile The file handle. * @param off The desired file position. */ int kDbgHlpSeek(PKDBGHLPFILE pFile, int64_t off); /** * Move the file position relative to the current one. * * @returns 0 on success, and KDBG_ERR_* on failure. * @param pFile The file handle. * @param off How much to move the file position by. */ int kDbgHlpSeekByCur(PKDBGHLPFILE pFile, int64_t off); /** * Move the file position relative to the end of the file. * * @returns 0 on success, and KDBG_ERR_* on failure. * @param pFile The file handle. * @param off The offset relative to the end, positive number. */ int kDbgHlpSeekByEnd(PKDBGHLPFILE pFile, int64_t off); /** * Gets the current file position. * * @returns The current file position on success. * -1 on failure. * @param pFile The file handle. */ int64_t kDbgHlpTell(PKDBGHLPFILE pFile); /** @} */ /** @defgroup grp_kDbgHlpAssert kDbg Internal Assertion Macros. * @internal * @{ */ #ifdef _MSC_VER # define kDbgAssertBreakpoint() do { __debugbreak(); } while (0) #else # define kDbgAssertBreakpoint() do { __asm__ __volatile__ ("int3"); } while (0) #endif /** * Helper function that displays the first part of the assertion message. * * @param pszExpr The expression. * @param pszFile The file name. * @param iLine The line number is the file. * @param pszFunction The function name. */ void kDbgAssertMsg1(const char *pszExpr, const char *pszFile, unsigned iLine, const char *pszFunction); /** * Helper function that displays custom assert message. * * @param pszFormat Format string that get passed to vprintf. * @param ... Format arguments. */ void kDbgAssertMsg2(const char *pszFormat, ...); #ifdef KDBG_STRICT # define kDbgAssert(expr) \ do { \ if (!(expr)) \ { \ kDbgAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ kDbgAssertBreakpoint(); \ } \ } while (0) # define kDbgAssertReturn(expr, rcRet) \ do { \ if (!(expr)) \ { \ kDbgAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ kDbgAssertBreakpoint(); \ return (rcRet); \ } \ } while (0) # define kDbgAssertMsg(expr, msg) \ do { \ if (!(expr)) \ { \ kDbgAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ kDbgAssertMsg2 msg; \ kDbgAssertBreakpoint(); \ } \ } while (0) # define kDbgAssertMsgReturn(expr, msg, rcRet) \ do { \ if (!(expr)) \ { \ kDbgAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ kDbgAssertMsg2 msg; \ kDbgAssertBreakpoint(); \ return (rcRet); \ } \ } while (0) #else /* !KDBG_STRICT */ # define kDbgAssert(expr) do { } while (0) # define kDbgAssertReturn(expr, rcRet) do { if (!(expr)) return (rcRet); } while (0) # define kDbgAssertMsg(expr, msg) do { } while (0) # define kDbgAssertMsgReturn(expr, msg, rcRet) do { if (!(expr)) return (rcRet); } while (0) #endif /* !KDBG_STRICT */ #define kDbgAssertPtr(ptr) kDbgAssertMsg(KDBG_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr))) #define kDbgAssertPtrReturn(ptr, rcRet) kDbgAssertMsgReturn(KDBG_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet)) #define kDbgAssertPtrNull(ptr) kDbgAssertMsg(!(ptr) || KDBG_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr))) #define kDbgAssertPtrNullReturn(ptr, rcRet) kDbgAssertMsgReturn(!(ptr) || KDBG_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet)) #define kDbgAssertRC(rc) kDbgAssertMsg((rc) == 0, ("%s = %d\n", #rc, (rc))) #define kDbgAssertRCReturn(rc, rcRet) kDbgAssertMsgReturn((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet)), (rcRet)) #define kDbgAssertFailed() kDbgAssert(0) #define kDbgAssertFailedReturn(rcRet) kDbgAssertReturn(0, (rcRet)) #define kDbgAssertMsgFailed(msg) kDbgAssertMsg(0, msg) #define kDbgAssertMsgFailedReturn(msg, rcRet) kDbgAssertMsgReturn(0, msg, (rcRet)) /** @} */ #ifdef __cplusplus } #endif #endif kbuild-3149/src/lib/kStuff/kDbg/kDbgModWinDbgHelp.cpp0000644000175000017500000006247113252530254022304 0ustar locutuslocutus/* $Id: kDbgModWinDbgHelp.cpp 29 2009-07-01 20:30:29Z bird $ */ /** @file * kDbg - The Debug Info Reader, DbgHelp Based Reader. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #define _IMAGEHLP64 #include #include "kDbgInternal.h" #include #include /******************************************************************************* * Global Variables * *******************************************************************************/ /** The dbghelp.dll module handle. */ static HMODULE g_hDbgHelp = NULL; /** Pointer to the dbhelp.dll SymInitialize function. */ static BOOL (WINAPI *g_pfnSymInitialize)(IN HANDLE,IN LPSTR,IN BOOL); /** Pointer to the dbhelp.dll SymCleanup function. */ static BOOL (WINAPI *g_pfnSymCleanup)(IN HANDLE); /** Pointer to the dbhelp.dll SymSetOptions function. */ static DWORD (WINAPI *g_pfnSymSetOptions)(IN DWORD); /** Pointer to the dbhelp.dll SymLoadModule64 function. */ static DWORD64 (WINAPI *g_pfnSymLoadModule64)(IN HANDLE, IN HANDLE, IN PCSTR, IN PCSTR ModuleName, IN DWORD64, IN DWORD); /** Pointer to the dbhelp.dll SymFromAddr function. */ static DWORD (WINAPI *g_pfnSymFromAddr)(IN HANDLE, IN DWORD64, OUT PDWORD64, OUT PSYMBOL_INFO); /** Pointer to the dbhelp.dll SymGetLineFromAddr64 function. */ static DWORD (WINAPI *g_pfnSymGetLineFromAddr64)(IN HANDLE, IN DWORD64, OUT PDWORD64, OUT PIMAGEHLP_LINE64); /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * A dbghelp based PE debug reader. */ typedef struct KDBGMODDBGHELP { /** The common module core. */ KDBGMOD Core; /** The image base. */ DWORD64 ImageBase; /** The "process" handle we present dbghelp. */ HANDLE hSymInst; /** The image size. */ KU32 cbImage; /** The number of sections. (We've added the implicit header section.) */ KI32 cSections; /** The section headers (variable size). The first section is the * implicit header section.*/ IMAGE_SECTION_HEADER aSections[1]; } KDBGMODDBGHELP, *PKDBGMODDBGHELP; /** * Convers a Windows error to kDbg error code. * * @returns kDbg status code. * @param rc The Windows error. */ static int kdbgModDHConvWinError(DWORD rc) { switch (rc) { case 0: return 0; default: return KERR_GENERAL_FAILURE; } } /** * Calcs the RVA for a segment:offset address. * * @returns IPRT status code. * * @param pModDH The PE debug module instance. * @param iSegment The segment number. Special segments are dealt with as well. * @param off The segment offset. * @param puRVA Where to store the RVA on success. */ static int kdbgModDHSegOffToRVA(PKDBGMODDBGHELP pModDH, KI32 iSegment, KDBGADDR off, KU32 *puRVA) { if (iSegment >= 0) { kDbgAssertMsgReturn(iSegment < pModDH->cSections, ("iSegment=%x cSections=%x\n", iSegment, pModDH->cSections), KDBG_ERR_INVALID_ADDRESS); kDbgAssertMsgReturn(off < pModDH->aSections[iSegment].Misc.VirtualSize, ("off=" PRI_KDBGADDR " VirtualSize=%x\n", off, pModDH->aSections[iSegment].Misc.VirtualSize), KDBG_ERR_INVALID_ADDRESS); *puRVA = pModDH->aSections[iSegment].VirtualAddress + (KU32)off; return 0; } if (iSegment == KDBGSEG_RVA) { kDbgAssertMsgReturn(off < pModDH->cbImage, ("off=" PRI_KDBGADDR ", cbImage=%x\n", off, pModDH->cbImage), KDBG_ERR_INVALID_ADDRESS); *puRVA = (KU32)off; return 0; } kDbgAssertMsgFailedReturn(("iSegment=%d\n", iSegment), KDBG_ERR_INVALID_ADDRESS); } /** * Calcs the segment:offset address for a RVA. * * @returns IPRT status code. * * @param pModDH The PE debug module instance. * @param uRVA The RVA. * @param piSegment Where to store the segment number. * @param poff Where to store the segment offset. */ static int kdbgModDHRVAToSegOff(PKDBGMODDBGHELP pModDH, KU32 uRVA, KI32 *piSegment, KDBGADDR *poff) { kDbgAssertMsgReturn(uRVA < pModDH->cbImage, ("uRVA=%x, cbImage=%x\n", uRVA, pModDH->cbImage), KDBG_ERR_INVALID_ADDRESS); for (KI32 iSegment = 0; iSegment < pModDH->cSections; iSegment++) { /** @todo should probably be less strict about address in the alignment gaps. */ KU32 off = uRVA - pModDH->aSections[iSegment].VirtualAddress; if (off < pModDH->aSections[iSegment].Misc.VirtualSize) { *poff = off; *piSegment = iSegment; return 0; } } kDbgAssertMsgFailedReturn(("uRVA=%x\n", uRVA), KDBG_ERR_INVALID_ADDRESS); } /** * @copydoc KDBGMODOPS::pfnQueryLine */ static int kdbgModDHQueryLine(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGLINE pLine) { PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)pMod; /* * Translate the address to an RVA. */ KU32 uRVA; int rc = kdbgModDHSegOffToRVA(pModDH, iSegment, off, &uRVA); if (!rc) { DWORD64 off; IMAGEHLP_LINE64 Line; Line.SizeOfStruct = sizeof(Line); if (g_pfnSymGetLineFromAddr64(pModDH->hSymInst, pModDH->ImageBase + uRVA, &off, &Line)) { pLine->RVA = (KDBGADDR)(Line.Address - pModDH->ImageBase); rc = kdbgModDHRVAToSegOff(pModDH, (KU32)pLine->RVA, &pLine->iSegment, &pLine->offSegment); pLine->iLine = Line.LineNumber; KSIZE cchFile = kHlpStrLen(Line.FileName); pLine->cchFile = cchFile < sizeof(pLine->szFile) ? (KU16)cchFile : (KU16)sizeof(pLine->szFile) - 1; kHlpMemCopy(pLine->szFile, Line.FileName, pLine->cchFile); pLine->szFile[pLine->cchFile] = '\0'; } else { DWORD Err = GetLastError(); rc = kdbgModDHConvWinError(Err); } } return rc; } /** * @copydoc KDBGMODOPS::pfnQuerySymbol */ static int kdbgModDHQuerySymbol(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGSYMBOL pSym) { PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)pMod; /* * Translate the address to an RVA. */ KU32 uRVA; int rc = kdbgModDHSegOffToRVA(pModDH, iSegment, off, &uRVA); if (!rc) { DWORD64 off; union { SYMBOL_INFO Sym; char achBuffer[sizeof(SYMBOL_INFO) + KDBG_SYMBOL_MAX]; } Buf; Buf.Sym.SizeOfStruct = sizeof(SYMBOL_INFO); Buf.Sym.MaxNameLen = KDBG_SYMBOL_MAX; if (g_pfnSymFromAddr(pModDH->hSymInst, pModDH->ImageBase + uRVA, &off, &Buf.Sym)) { pSym->cb = Buf.Sym.Size; pSym->Address = NIL_KDBGADDR; pSym->fFlags = 0; if (Buf.Sym.Flags & SYMFLAG_FUNCTION) pSym->fFlags |= KDBGSYM_FLAGS_CODE; else if (Buf.Sym.Flags & SYMFLAG_CONSTANT) pSym->fFlags |= KDBGSYM_FLAGS_ABS; /** @todo SYMFLAG_CONSTANT must be tested - documentation is too brief to say what is really meant here.*/ else pSym->fFlags |= KDBGSYM_FLAGS_DATA; if (Buf.Sym.Flags & SYMFLAG_EXPORT) pSym->fFlags |= KDBGSYM_FLAGS_EXPORTED; if ((Buf.Sym.Flags & (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT)) == (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT)) { pSym->iSegment = KDBGSEG_ABS; pSym->offSegment = (KDBGADDR)Buf.Sym.Value; pSym->RVA = (KDBGADDR)Buf.Sym.Value; } else { pSym->RVA = (KDBGADDR)(Buf.Sym.Address - pModDH->ImageBase); rc = kdbgModDHRVAToSegOff(pModDH, (KU32)pSym->RVA, &pSym->iSegment, &pSym->offSegment); } pSym->cchName = (KU16)Buf.Sym.NameLen; if (pSym->cchName >= sizeof(pSym->szName)) pSym->cchName = sizeof(pSym->szName) - 1; kHlpMemCopy(pSym->szName, Buf.Sym.Name, Buf.Sym.NameLen); pSym->szName[Buf.Sym.NameLen] = '\0'; } else { DWORD Err = GetLastError(); rc = kdbgModDHConvWinError(Err); } } return rc; } /** * @copydoc KDBGMODOPS::pfnClose */ static int kdbgModDHClose(PKDBGMOD pMod) { PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)pMod; if (g_pfnSymCleanup(pModDH->hSymInst)) return 0; DWORD Err = GetLastError(); int rc = kdbgModDHConvWinError(Err); kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%d\n", Err, rc)); return rc; } /** * Checks if the specified dbghelp.dll is usable. * * @returns IPRT status code. * * @param pszPath the path to the dbghelp.dll. */ static int kdbgModDHTryDbgHelp(const char *pszPath, KU32 *pu32FileVersionMS, KU32 *pu32FileVersionLS) { int rc; DWORD dwHandle = 0; DWORD cb = GetFileVersionInfoSize(pszPath, &dwHandle); if (cb > 0) { void *pvBuf = alloca(cb); if (GetFileVersionInfo(pszPath, dwHandle, cb, pvBuf)) { UINT cbValue = 0; VS_FIXEDFILEINFO *pFileInfo; if (VerQueryValue(pvBuf, "\\", (void **)&pFileInfo, &cbValue)) { /** @todo somehow reject 64-bit .dlls when in 32-bit mode... dwFileOS is completely useless. */ if ( *pu32FileVersionMS < pFileInfo->dwFileVersionMS || ( *pu32FileVersionMS == pFileInfo->dwFileVersionMS && *pu32FileVersionLS > pFileInfo->dwFileVersionLS)) { *pu32FileVersionMS = pFileInfo->dwFileVersionMS; *pu32FileVersionLS = pFileInfo->dwFileVersionLS; } if (pFileInfo->dwFileVersionMS >= 0x60004) rc = 0; else rc = KDBG_ERR_DBGHLP_VERSION_MISMATCH; } else rc = KERR_GENERAL_FAILURE; } else rc = kdbgModDHConvWinError(GetLastError()); } else rc = kdbgModDHConvWinError(GetLastError()); return rc; } /** * Find the dbghelp.dll */ static int kdbgModDHFindDbgHelp(char *pszPath, KSIZE cchPath) { /* * Try the current directory. */ KU32 FileVersionMS = 0; KU32 FileVersionLS = 0; int rc = KERR_GENERAL_FAILURE; static char s_szDbgHelp[] = "\\dbghelp.dll"; if (GetCurrentDirectory((DWORD)(cchPath - sizeof(s_szDbgHelp) + 1), pszPath)) { strcat(pszPath, s_szDbgHelp); int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS); if (!rc2) return rc2; if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH) rc = rc2; } /* * Try the application directory. */ if (GetModuleFileName(NULL, pszPath, (DWORD)(cchPath - sizeof(s_szDbgHelp) + 1))) { kHlpStrCat(kHlpStrRChr(pszPath, '\\'), s_szDbgHelp); int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS); if (!rc) return rc2; if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH) rc = rc2; } /* * Try the windows directory. */ if (GetSystemDirectory(pszPath, (DWORD)(cchPath - sizeof(s_szDbgHelp) + 1))) { kHlpStrCat(pszPath, s_szDbgHelp); int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS); if (!rc2) return rc2; if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH) rc = rc2; } /* * Try the windows directory. */ if (GetWindowsDirectory(pszPath, (DWORD)(cchPath - sizeof(s_szDbgHelp) + 1))) { kHlpStrCat(pszPath, s_szDbgHelp); int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS); if (!rc2) return rc2; if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH) rc = rc2; } /* * Try the path. */ /** @todo find the actual path specs, I'm probably not doing this 100% correctly here. */ DWORD cb = GetEnvironmentVariable("PATH", NULL, 0) + 64; char *pszSearchPath = (char *) alloca(cb); if (GetEnvironmentVariable("PATH", pszSearchPath, cb) < cb) { char *psz = pszSearchPath; while (*psz) { /* find the end of the path. */ char *pszEnd = kHlpStrChr(psz, ';'); if (!pszEnd) pszEnd = kHlpStrChr(psz, '\0'); if (pszEnd != psz) { /* construct filename and try it out */ kHlpMemCopy(pszPath, psz, pszEnd - psz); kHlpMemCopy(&pszPath[pszEnd - psz], s_szDbgHelp, sizeof(s_szDbgHelp)); int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS); if (!rc2) return rc2; if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH) rc = rc2; } /* next path */ if (!*pszEnd) break; psz = pszEnd + 1; } } if (rc == KDBG_ERR_DBGHLP_VERSION_MISMATCH) kDbgAssertMsgFailed(("dbghelp.dll found, but it was ancient! The highest file version found was 0x%08x'%08x.\n" "This program require a file version of at least 0x00060004'00000000. Please download\n" "the latest windbg and use the dbghelp.dll from that package. Just put it somewhere in\n" "the PATH and we'll find it.\n", FileVersionMS, FileVersionLS)); else kDbgAssertMsgFailed(("dbghelp.dll was not found! Download the latest windbg and use the dbghelp.dll\n" "from that package - just put it somewhere in the PATH and we'll find it.\n")); return rc; } /** * Loads the dbghelp.dll, check that it's the right version, and * resolves all the symbols we need. * * @returns IPRT status code. */ static int kdbgModDHLoadDbgHelp(void) { if (g_hDbgHelp) return 0; /* primitive locking - make some useful API for this kind of spinning! */ static volatile long s_lLock = 0; while (InterlockedCompareExchange(&s_lLock, 1, 0)) while (s_lLock) Sleep(1); if (g_hDbgHelp) { InterlockedExchange(&s_lLock, 0); return 0; } /* * Load it - try current dir first. */ char szPath[260]; int rc = kdbgModDHFindDbgHelp(szPath, sizeof(szPath)); if (rc) { InterlockedExchange(&s_lLock, 0); return rc; } HMODULE hmod = LoadLibraryEx(szPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); if (!hmod) { DWORD Err = GetLastError(); int rc = kdbgModDHConvWinError(Err); InterlockedExchange(&s_lLock, 0); kDbgAssertMsgFailedReturn(("Failed to load '%s', Err=%d rc=%d\n", szPath, Err, rc), rc); } /* * Check the API version (too). */ LPAPI_VERSION (WINAPI *pfnImagehlpApiVersion)(VOID); FARPROC *ppfn = (FARPROC *)&pfnImagehlpApiVersion; *ppfn = GetProcAddress(hmod, "ImagehlpApiVersion"); if (*ppfn) { LPAPI_VERSION pVersion = pfnImagehlpApiVersion(); if ( pVersion && ( pVersion->MajorVersion > 4 || (pVersion->MajorVersion == 4 && pVersion->MinorVersion > 0) || (pVersion->MajorVersion == 4 && pVersion->MinorVersion == 0 && pVersion->Revision >= 5) ) ) { /* * Resolve the entrypoints we need. */ static const struct { const char *pszName; FARPROC *ppfn; } s_aFunctions[] = { { "SymInitialize", (FARPROC *)&g_pfnSymInitialize }, { "SymCleanup", (FARPROC *)&g_pfnSymCleanup }, { "SymSetOptions", (FARPROC *)&g_pfnSymSetOptions }, { "SymLoadModule64", (FARPROC *)&g_pfnSymLoadModule64 }, { "SymFromAddr", (FARPROC *)&g_pfnSymFromAddr }, { "SymFromAddr", (FARPROC *)&g_pfnSymFromAddr }, { "SymGetLineFromAddr64", (FARPROC *)&g_pfnSymGetLineFromAddr64 }, }; for (unsigned i = 0; i < K_ELEMENTS(s_aFunctions); i++) { FARPROC pfn = GetProcAddress(hmod, s_aFunctions[i].pszName); if (!pfn) { DWORD Err = GetLastError(); rc = kdbgModDHConvWinError(Err); kDbgAssertMsgFailed(("Failed to resolve %s in dbghelp, Err=%d rc=%d\n", s_aFunctions[i].pszName, Err, rc)); break; } *s_aFunctions[i].ppfn = pfn; } if (!rc) { g_hDbgHelp = hmod; Sleep(1); InterlockedExchange(&s_lLock, 0); return 0; } } else { rc = KDBG_ERR_DBGHLP_VERSION_MISMATCH; kDbgAssertMsgFailed(("ImagehlpApiVersion -> %p and MajorVersion=%d.\n", pVersion, pVersion ? pVersion->MajorVersion : 0)); } } else { DWORD Err = GetLastError(); rc = kdbgModDHConvWinError(Err); kDbgAssertMsgFailed(("Failed to resolve ImagehlpApiVersionEx in dbghelp, Err=%d rc=%d\n", Err, rc)); } FreeLibrary(hmod); InterlockedExchange(&s_lLock, 0); return rc; } /** * @copydoc KDBGMODOPS::pfnOpen */ static int kdbgModDHOpen(PKDBGMOD *ppMod, PKRDR pRdr, KBOOL fCloseRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod) { /* * This reader doesn't support partial files. * Also weed out small files early on as they cannot be * PE images and will only cause read errors */ if ( off != 0 || cb != KFOFF_MAX) return KDBG_ERR_UNKOWN_FORMAT; if (kRdrSize(pRdr) < sizeof(IMAGE_NT_HEADERS32) + sizeof(IMAGE_SECTION_HEADER)) return KDBG_ERR_UNKOWN_FORMAT; /* * We need to read the section headers and get the image size. */ /* Find the PE header magic. */ KU32 offHdr = 0; KU32 u32Magic; int rc = kRdrRead(pRdr, &u32Magic, sizeof(u32Magic), 0); kDbgAssertRCReturn(rc, rc); if ((KU16)u32Magic == IMAGE_DOS_SIGNATURE) { rc = kRdrRead(pRdr, &offHdr, sizeof(offHdr), K_OFFSETOF(IMAGE_DOS_HEADER, e_lfanew)); kDbgAssertRCReturn(rc, rc); if (!offHdr) return KDBG_ERR_FORMAT_NOT_SUPPORTED; if ( offHdr < sizeof(IMAGE_DOS_SIGNATURE) || offHdr >= kRdrSize(pRdr) - 4) return KDBG_ERR_BAD_EXE_FORMAT; rc = kRdrRead(pRdr, &u32Magic, sizeof(u32Magic), offHdr); kDbgAssertRCReturn(rc, rc); } if (u32Magic != IMAGE_NT_SIGNATURE) return KDBG_ERR_FORMAT_NOT_SUPPORTED; /* read the file header and the image size in the optional header.. */ IMAGE_FILE_HEADER FHdr; rc = kRdrRead(pRdr, &FHdr, sizeof(FHdr), offHdr + K_OFFSETOF(IMAGE_NT_HEADERS32, FileHeader)); kDbgAssertRCReturn(rc, rc); KU32 cbImage; if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)) rc = kRdrRead(pRdr, &cbImage, sizeof(cbImage), offHdr + K_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.SizeOfImage)); else if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64)) rc = kRdrRead(pRdr, &cbImage, sizeof(cbImage), offHdr + K_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.SizeOfImage)); else kDbgAssertFailedReturn(KDBG_ERR_BAD_EXE_FORMAT); kDbgAssertRCReturn(rc, rc); /* * Load dbghelp.dll. */ rc = kdbgModDHLoadDbgHelp(); if (rc) return rc; /* * Allocate the module and read/construct the section headers. */ PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)kHlpAlloc(K_OFFSETOF(KDBGMODDBGHELP, aSections[FHdr.NumberOfSections + 2])); kDbgAssertReturn(pModDH, KERR_NO_MEMORY); pModDH->Core.u32Magic = KDBGMOD_MAGIC; pModDH->Core.pOps = &g_kDbgModWinDbgHelpOpen; pModDH->Core.pRdr = pRdr; pModDH->Core.fCloseRdr = fCloseRdr; pModDH->Core.pLdrMod = pLdrMod; pModDH->cbImage = cbImage; pModDH->cSections = 1 + FHdr.NumberOfSections; rc = kRdrRead(pRdr, &pModDH->aSections[1], sizeof(pModDH->aSections[0]) * FHdr.NumberOfSections, offHdr + K_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader) + FHdr.SizeOfOptionalHeader); if (!rc) { PIMAGE_SECTION_HEADER pSH = &pModDH->aSections[0]; kHlpMemCopy(pSH->Name, "headers", sizeof(pSH->Name)); pSH->Misc.VirtualSize = pModDH->aSections[1].VirtualAddress; pSH->VirtualAddress = 0; pSH->SizeOfRawData = pSH->Misc.VirtualSize; pSH->PointerToRawData = 0; pSH->PointerToRelocations = 0; pSH->PointerToLinenumbers = 0; pSH->NumberOfRelocations = 0; pSH->NumberOfLinenumbers = 0; pSH->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ; KU32 uTheEnd = pModDH->aSections[FHdr.NumberOfSections].VirtualAddress + pModDH->aSections[FHdr.NumberOfSections].Misc.VirtualSize; if (uTheEnd < cbImage) { pSH = &pModDH->aSections[pModDH->cSections++]; kHlpMemCopy(pSH->Name, "tail\0\0\0", sizeof(pSH->Name)); pSH->Misc.VirtualSize = cbImage - uTheEnd; pSH->VirtualAddress = uTheEnd; pSH->SizeOfRawData = pSH->Misc.VirtualSize; pSH->PointerToRawData = 0; pSH->PointerToRelocations = 0; pSH->PointerToLinenumbers = 0; pSH->NumberOfRelocations = 0; pSH->NumberOfLinenumbers = 0; pSH->Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_READ; } /* * Find a new dbghelp handle. * * We assume 4GB of handles outlast most debugging sessions, or in anyways that * when we start reusing handles they are no longer in use. :-) */ static volatile long s_u32LastHandle = 1; HANDLE hSymInst = (HANDLE)InterlockedIncrement(&s_u32LastHandle); while ( hSymInst == INVALID_HANDLE_VALUE || hSymInst == (HANDLE)0 || hSymInst == GetCurrentProcess()) hSymInst = (HANDLE)InterlockedIncrement(&s_u32LastHandle); /* * Initialize dbghelp and try open the specified module. */ if (g_pfnSymInitialize(hSymInst, NULL, FALSE)) { g_pfnSymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_AUTO_PUBLICS | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS); KIPTR NativeFH = kRdrNativeFH(pRdr); DWORD64 ImageBase = g_pfnSymLoadModule64(hSymInst, NativeFH == -1 ? NULL : (HANDLE)NativeFH, kRdrName(pRdr), NULL, 0x00400000, 0); if (ImageBase) { pModDH->hSymInst = hSymInst; pModDH->ImageBase = ImageBase; *ppMod = &pModDH->Core; return rc; } DWORD Err = GetLastError(); rc = kdbgModDHConvWinError(Err); kDbgAssertMsgFailed(("SymLoadModule64 failed: Err=%d rc=%d\n", Err, rc)); g_pfnSymCleanup(hSymInst); } else { DWORD Err = GetLastError(); rc = kdbgModDHConvWinError(Err); kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%d\n", Err, rc)); } } else kDbgAssertRC(rc); kHlpFree(pModDH); return rc; } /** * Methods for a PE module. */ KDBGMODOPS const g_kDbgModWinDbgHelpOpen = { "Windows DbgHelp", NULL, kdbgModDHOpen, kdbgModDHClose, kdbgModDHQuerySymbol, kdbgModDHQueryLine, "Windows DbgHelp" }; kbuild-3149/src/lib/kStuff/Copyright0000644000175000017500000000214413252530254017400 0ustar locutuslocutusAll kStuff files are: Copyright (c) 2006-2008 Knut St. Osmundsen 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. kbuild-3149/src/lib/kStuff/kErr/0000755000175000017500000000000013252530254016407 5ustar locutuslocutuskbuild-3149/src/lib/kStuff/kErr/Makefile.kmk0000644000175000017500000000366513252530254020642 0ustar locutuslocutus# $Id: Makefile.kmk 29 2009-07-01 20:30:29Z bird $ ## @file # kErr - The Status Code API, sub-makefile. # # # Copyright (c) 2006-2007 Knut St. Osmundsen # # 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. # DEPTH ?= .. SUB_DEPTH = .. include $(PATH_KBUILD)/subheader.kmk # # kHlpBaseStatic # LIBRARIES += kErrStatic kErrStatic_TEMPLATE = kStuffLIB kErrStatic_SOURCES = \ kErrName.c kErrName.c_DEPS = $(PATH_TARGET)/kErrNameConsts.h kErrName.c_INCS = $(PATH_TARGET) # # Generate case statements for kErrName(). # $(PATH_TARGET)/kErrNameConsts.h: $(PATH_SUB_ROOT)/include/k/kErrors.h $(MAKEFILE_CURRENT) | $(call DIRDEP,$(PATH_TARGET)) $(RM) -f $@ $(SED) \ -e '/^#define *\(K[A-Z_]*ERR_[^ ()]*\) .*$$/!d' \ -e 's/^#define *\(K[A-Z_]*ERR_[^ ()]*\) .*$$/ERR_CONST(\1)/' \ -e '/K[A-Z_]*ERR_[A-Z0-9_]*BASE/d' \ -e '/K[A-Z_]*ERR_[A-Z0-9_]*END/d' \ $< > $@ # Generate the rules include $(PATH_KBUILD)/subfooter.kmk kbuild-3149/src/lib/kStuff/kErr/kErrName.c0000644000175000017500000000371713252530254020267 0ustar locutuslocutus/* $Id: kErrName.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kErr - Status Code API, kErrName. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include /** * Translate the error code into a string containing * the error constant. * * @returns Read only string with the constant name. * @param rc The kErrors status code. */ KERR_DECL(const char *) kErrName(int rc) { switch (rc) { case 0: return "SUCCESS"; #define ERR_CONST(c) case c: return #c; #include "kErrNameConsts.h" #undef ERR_CONST default: return "KERR_UNKNOWN_ERROR"; } } kbuild-3149/src/lib/kStuff/kHlp/0000755000175000017500000000000013252530254016402 5ustar locutuslocutuskbuild-3149/src/lib/kStuff/kHlp/Makefile.kmk0000644000175000017500000000637013252530254020631 0ustar locutuslocutus# $Id: Makefile.kmk 29 2009-07-01 20:30:29Z bird $ ## @file # kHlp - The Helper API, sub-makefile. # # # Copyright (c) 2006-2007 Knut St. Osmundsen # # 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. # DEPTH ?= .. SUB_DEPTH = .. include $(PATH_KBUILD)/subheader.kmk # # kHlpBaseStatic # LIBRARIES += kHlpBareStatic kHlpBareStatic_TEMPLATE = kStuffLIB kHlpBareStatic_SOURCES = \ Generic/kHlpMemChr.c \ Generic/kHlpMemComp.c \ Generic/kHlpMemPComp.c \ Generic/kHlpMemICompAscii.c \ Generic/kHlpMemCopy.c \ Generic/kHlpMemPCopy.c \ Generic/kHlpMemMove.c \ Generic/kHlpMemPMove.c \ Generic/kHlpMemSet.c \ Generic/kHlpMemPSet.c \ Generic/kHlpStrCat.c \ Generic/kHlpStrPCat.c \ Generic/kHlpStrNCat.c \ Generic/kHlpStrNPCat.c \ Generic/kHlpStrChr.c \ Generic/kHlpStrRChr.c \ Generic/kHlpStrComp.c \ Generic/kHlpStrPComp.c \ Generic/kHlpStrNComp.c \ Generic/kHlpStrNPComp.c \ Generic/kHlpStrICompAscii.c \ Generic/kHlpStrIPCompAscii.c \ Generic/kHlpStrNICompAscii.c \ Generic/kHlpStrNIPCompAscii.c \ Generic/kHlpStrCopy.c \ Generic/kHlpStrPCopy.c \ Generic/kHlpStrLen.c \ Generic/kHlpStrNLen.c \ Generic/kHlpInt2Ascii.c \ \ Generic/kHlpGetEnvUZ.c \ \ Generic/kHlpGetExt.c \ Generic/kHlpGetFilename.c \ Generic/kHlpIsFilenameOnly.c \ \ Generic/kHlpPage.c \ \ Bare/kHlpBareAssert.c \ Bare/kHlpBareHeap.c \ Bare/kHlpBareEnv.c \ Bare/kHlpBareProcess.c \ Bare/kHlpBareThread.c \ kHlpBareStatic_SOURCES.darwin = \ Bare/kHlpSys-darwin.c # # kCrtStatic # LIBRARIES += kHlpCRTStatic kHlpCRTStatic_TEMPLATE = kStuffLIB kHlpCRTStatic_SOURCES = \ Generic/kHlpMemPComp.c \ Generic/kHlpMemICompAscii.c \ Generic/kHlpStrPCat.c \ Generic/kHlpStrNPCat.c \ Generic/kHlpStrPComp.c \ Generic/kHlpStrNPComp.c \ Generic/kHlpStrICompAscii.c \ Generic/kHlpStrIPCompAscii.c \ Generic/kHlpStrNICompAscii.c \ Generic/kHlpStrNIPCompAscii.c \ Generic/kHlpStrPCopy.c \ Generic/kHlpStrNLen.c \ Generic/kHlpInt2Ascii.c \ \ Generic/kHlpGetEnvUZ.c \ \ Generic/kHlpGetExt.c \ Generic/kHlpGetFilename.c \ Generic/kHlpIsFilenameOnly.c \ \ Generic/kHlpPage.c \ \ CRT/kHlpCRTAlloc.cpp \ CRT/kHlpCRTEnv.cpp \ CRT/kHlpCRTString.cpp \ kHlpCRTStatic_SOURCES.darwin = \ Bare/kHlpSys-darwin.c # Generate the rules include $(PATH_KBUILD)/subfooter.kmk kbuild-3149/src/lib/kStuff/kHlp/Bare/0000755000175000017500000000000013252530254017253 5ustar locutuslocutuskbuild-3149/src/lib/kStuff/kHlp/Bare/kHlpBare-gcc.c0000644000175000017500000001172113252530254021643 0ustar locutuslocutus/* $Id: kHlpBare-gcc.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpBare - The Dynamic Loader, Helper Functions for GCC. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #include #include "kHlp.h" /******************************************************************************* * Global Variables * *******************************************************************************/ void *memchr(const void *pv, int ch, KSIZE cb) { const char *pb = pv; while (cb-- > 0) { if (*pb == ch) return (void *)pb; pb++; } return 0; } int memcmp(const void *pv1, const void *pv2, KSIZE cb) { /* * Pointer size pointer size. */ if ( cb > 16 && !((KUPTR)pv1 & (sizeof(void *) - 1)) && !((KUPTR)pv2 & (sizeof(void *) - 1)) ) { const KUPTR *pu1 = pv1; const KUPTR *pu2 = pv2; while (cb >= sizeof(KUPTR)) { const KUPTR u1 = *pu1++; const KUPTR u2 = *pu2++; if (u1 != u2) return u1 > u2 ? 1 : -1; cb -= sizeof(KUPTR); } if (!cb) return 0; pv1 = (const void *)pu1; pv2 = (const void *)pu2; } /* * Byte by byte. */ if (cb) { const unsigned char *pb1 = pv1; const unsigned char *pb2 = pv2; while (cb-- > 0) { const unsigned char b1 = *pb1++; const unsigned char b2 = *pb2++; if (b1 != b2) return b1 > b2 ? 1 : -1; } } return 0; } void *memcpy(void *pv1, const void *pv2, KSIZE cb) { void *pv1Start = pv1; /* * Pointer size pointer size. */ if ( cb > 16 && !((KUPTR)pv1 & (sizeof(void *) - 1)) && !((KUPTR)pv2 & (sizeof(void *) - 1)) ) { KUPTR *pu1 = pv1; const KUPTR *pu2 = pv2; while (cb >= sizeof(KUPTR)) { cb -= sizeof(KUPTR); *pu1++ = *pu2++; } if (!cb) return 0; pv1 = (void *)pu1; pv2 = (const void *)pu2; } /* * byte by byte */ if (cb) { unsigned char *pb1 = pv1; const unsigned char *pb2 = pv2; while (cb-- > 0) *pb1++ = *pb2++; } return pv1Start; } void *memset(void *pv, int ch, KSIZE cb) { void *pvStart = pv; /* * Pointer size pointer size. */ if ( cb > 16 && !((KUPTR)pv & (sizeof(void *) - 1))) { KUPTR *pu = pv; KUPTR u = ch | (ch << 8); u |= u << 16; #if K_ARCH_BITS >= 64 u |= u << 32; #endif #if K_ARCH_BITS >= 128 u |= u << 64; #endif while (cb >= sizeof(KUPTR)) { cb -= sizeof(KUPTR); *pu++ = u; } } /* * Byte by byte */ if (cb) { unsigned char *pb = pv; while (cb-- > 0) *pb++ = ch; } return pvStart; } int strcmp(const char *psz1, const char *psz2) { for (;;) { const char ch1 = *psz1++; const char ch2 = *psz2++; if (ch1 != ch2) return (int)ch1 - (int)ch2; if (!ch1) return 0; } } int strncmp(const char *psz1, const char *psz2, KSIZE cch) { while (cch-- > 0) { const char ch1 = *psz1++; const char ch2 = *psz2++; if (ch1 != ch2) return (int)ch1 - (int)ch2; if (!ch1) break; } return 0; } char *strchr(const char *psz, int ch) { for (;;) { const char chCur = *psz; if (chCur == ch) return (char *)psz; if (!chCur) return 0; psz++; } } KSIZE strlen(const char *psz) { const char *pszStart = psz; while (*psz) psz++; return psz - pszStart; } kbuild-3149/src/lib/kStuff/kHlp/Bare/kHlpBareEnv.c0000644000175000017500000000571013252530254021563 0ustar locutuslocutus/* $Id: kHlpBareEnv.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpBare - Environment Manipulation. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #if K_OS == K_OS_DARWIN #elif K_OS == K_OS_LINUX #elif K_OS == K_OS_OS2 # define INCL_BASE # define INCL_ERRORS # include #elif K_OS == K_OS_WINDOWS # include #else # error "port me" #endif KHLP_DECL(int) kHlpGetEnv(const char *pszVar, char *pszVal, KSIZE cchVal) { #if K_OS == K_OS_DARWIN /** @todo need to figure out where the stuff is or how it's inherited on darwin ... */ return KERR_ENVVAR_NOT_FOUND; #elif K_OS == K_OS_LINUX /** @todo either read /proc/self/environ or figure out where in the memory the initial environment is... */ return KERR_ENVVAR_NOT_FOUND; #elif K_OS == K_OS_OS2 PSZ pszValue = NULL; int rc; *pszVal = '\0'; rc = DosScanEnv((PCSZ)pszVar, &pszValue); if (!rc) { KSIZE cch = kHlpStrLen((const char *)pszValue); if (cchVal > cch) kHlpMemCopy(pszVal, pszValue, cch + 1); else rc = KERR_BUFFER_OVERFLOW; } else rc = KERR_ENVVAR_NOT_FOUND; return rc; #elif K_OS == K_OS_WINDOWS DWORD cch; SetLastError(0); cch = GetEnvironmentVariable(pszVar, pszVal, cchVal); if (cch > 0 && cch < cchVal) return 0; *pszVal = '\0'; if (cch >= cchVal) return KERR_BUFFER_OVERFLOW; if (GetLastError() == ERROR_ENVVAR_NOT_FOUND) return KERR_ENVVAR_NOT_FOUND; return GetLastError(); #else # error "Port me" #endif } kbuild-3149/src/lib/kStuff/kHlp/Bare/kHlpBareThread.c0000644000175000017500000000552613252530254022247 0ustar locutuslocutus/* $Id: kHlpBareThread.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpBare - Thread Manipulation. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #if K_OS == K_OS_DARWIN # include #elif K_OS == K_OS_LINUX # include #elif K_OS == K_OS_OS2 # define INCL_BASE # define INCL_ERRORS # include #elif K_OS == K_OS_WINDOWS # include #else # error "port me" #endif /** * Sleep for a number of milliseconds. * @param cMillies Number of milliseconds to sleep. */ void kHlpSleep(unsigned cMillies) { #if K_OS == K_OS_DARWIN static struct mach_timebase_info s_Info; static KBOOL s_fNanoseconds = K_UNKNOWN; KU64 uNow = mach_absolute_time(); KU64 uDeadline; KU64 uPeriod; if (s_fNanoseconds == K_UNKNOWN) { if (mach_timebase_info(&s_Info)) s_fNanoseconds = K_TRUE; /* the easy way out */ else if (s_Info.denom == s_Info.numer) s_fNanoseconds = K_TRUE; else s_fNanoseconds = K_FALSE; } uPeriod = (KU64)cMillies * 1000 * 1000; if (!s_fNanoseconds) uPeriod = (double)uPeriod * s_Info.denom / s_Info.numer; /* Use double to avoid 32-bit trouble. */ uDeadline = uNow + uPeriod; mach_wait_until(uDeadline); #elif K_OS == K_OS_LINUX /** @todo find the right syscall... */ #elif K_OS == K_OS_OS2 DosSleep(cMillies); #elif K_OS == K_OS_WINDOWS Sleep(cMillies); #else usleep(cMillies * 1000); #endif } kbuild-3149/src/lib/kStuff/kHlp/Bare/kHlpBareAssert.c0000644000175000017500000000755613252530254022306 0ustar locutuslocutus/* $Id: kHlpBareAssert.c 82 2016-08-22 21:01:51Z bird $ */ /** @file * kHlpBare - Assert Backend. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS # include #elif K_OS == K_OS_OS2 # define INCL_BASE # define INCL_ERRORS # include #elif K_OS == K_OS_WINDOWS # include #else # error "port me" #endif /** * Writes a assert string with unix lineendings. * * @param pszMsg The string. */ static void kHlpAssertWrite(const char *pszMsg) { #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS KSIZE cchMsg = kHlpStrLen(pszMsg); kHlpSys_write(2 /* stderr */, pszMsg, cchMsg); #elif K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS /* * Line by line. */ ULONG cbWritten; const char *pszNl = kHlpStrChr(pszMsg, '\n'); while (pszNl) { cbWritten = pszNl - pszMsg; # if K_OS == K_OS_OS2 if (cbWritten) DosWrite((HFILE)2, pszMsg, cbWritten, &cbWritten); DosWrite((HFILE)2, "\r\n", 2, &cbWritten); # else /* K_OS == K_OS_WINDOWS */ if (cbWritten) WriteFile((HANDLE)STD_ERROR_HANDLE, pszMsg, cbWritten, &cbWritten, NULL); WriteFile((HANDLE)STD_ERROR_HANDLE, "\r\n", 2, &cbWritten, NULL); # endif /* next */ pszMsg = pszNl + 1; pszNl = kHlpStrChr(pszMsg, '\n'); } /* * Remaining incomplete line. */ if (*pszMsg) { cbWritten = kHlpStrLen(pszMsg); # if K_OS == K_OS_OS2 DosWrite((HFILE)2, pszMsg, cbWritten, &cbWritten); # else /* K_OS == K_OS_WINDOWS */ WriteFile((HANDLE)STD_ERROR_HANDLE, pszMsg, cbWritten, &cbWritten, NULL); # endif } #else # error "port me" #endif } KHLP_DECL(void) kHlpAssertMsg1(const char *pszExpr, const char *pszFile, unsigned iLine, const char *pszFunction) { char szLine[16]; kHlpAssertWrite("\n!!!kLdr Assertion Failed!!!\nExpression: "); kHlpAssertWrite(pszExpr); kHlpAssertWrite("\nAt: "); kHlpAssertWrite(pszFile); kHlpAssertWrite("("); kHlpAssertWrite(kHlpInt2Ascii(szLine, sizeof(szLine), iLine, 10)); kHlpAssertWrite(") "); kHlpAssertWrite(pszFunction); kHlpAssertWrite("\n"); } KHLP_DECL(void) kHlpAssertMsg2(const char *pszFormat, ...) { kHlpAssertWrite(pszFormat); } kbuild-3149/src/lib/kStuff/kHlp/Bare/Makefile.kup0000644000175000017500000000000013252530254021477 0ustar locutuslocutuskbuild-3149/src/lib/kStuff/kHlp/Bare/kHlpBareProcess.c0000644000175000017500000000460513252530254022453 0ustar locutuslocutus/* $Id: kHlpBareProcess.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpBare - Process Management */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS # include #elif K_OS == K_OS_OS2 # define INCL_BASE # define INCL_ERRORS # include #elif K_OS == K_OS_WINDOWS # include #else # error "port me" #endif /** * Terminate the process. * * @param rc The exit status. */ void kHlpExit(int rc) { for (;;) { #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS kHlpSys_exit(rc); #elif K_OS == K_OS_OS2 DosExit(EXIT_PROCESS, rc); #elif K_OS == K_OS_WINDOWS TerminateProcess(GetCurrentProcess(), rc); #else # error "Port me" #endif kHlpAssert(!"Impossible"); } } kbuild-3149/src/lib/kStuff/kHlp/Bare/kHlpBareHeap.c0000644000175000017500000005011713252530254021711 0ustar locutuslocutus/* $Id: kHlpBareHeap.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpBare - Heap. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #define KHLPHEAP_STRICT /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #if K_OS == K_OS_OS2 # define INCL_BASE # define INCL_ERRORS # include #elif K_OS == K_OS_WINDOWS # include #else # include #endif /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * A heap block. */ typedef struct KHLPHEAPBLOCK { /** Next block in the global list. */ struct KHLPHEAPBLOCK *pNext; /** Previous block in the global list. */ struct KHLPHEAPBLOCK *pPrev; /** The size of this block including this header. */ KSIZE cb; /** The flags. */ KSIZE fFlags; } KHLPHEAPBLOCK, *PKHLPHEAPBLOCK; /** Indicates whether the block is free (set) or allocated (clear). */ #define KHLPHEAPBLOCK_FLAG_FREE ((KSIZE)1) /** Valid flag mask. */ #define KHLPHEAPBLOCK_FLAG_MASK ((KSIZE)1) /** Checks if the block is freed. */ #define KHLPHEAPBLOCK_IS_FREE(pB) ( (pB)->fFlags & KHLPHEAPBLOCK_FLAG_FREE ) /** Check if the block is allocated. */ #define KHLPHEAPBLOCK_IS_ALLOCATED(pB) !KHLPHEAPBLOCK_IS_FREE(pB) /** Checks if the two blocks are adjacent. * Assumes pB1 < pB2. */ #define KHLPHEAPBLOCK_IS_ADJACENT(pB1, pB2) \ ( ((KUPTR)(pB1) + (pB1)->cb) == (KUPTR)(pB2) ) /** The block alignment. */ #define KHLPHEAPBLOCK_ALIGNMENT sizeof(KHLPHEAPBLOCK) /** @def KHLPHEAP_ASSERT * Heap assertion. */ /** @def KHLPHEAP_ASSERT_BLOCK * Assert that a heap block is valid. */ /** @def KHLPHEAP_ASSERT_FREE * Assert that a heap free block is valid. */ #ifdef KHLPHEAP_STRICT # define KHLPHEAP_ASSERT(expr) kHlpAssert(expr) # define KHLPHEAP_ASSERT_BLOCK(pHeap, pBlock) \ do { \ KHLPHEAP_ASSERT(!((pBlock)->fFlags & ~KHLPHEAPBLOCK_FLAG_MASK)); \ KHLPHEAP_ASSERT(!((pBlock)->cb & (KHLPHEAPBLOCK_ALIGNMENT - 1))); \ KHLPHEAP_ASSERT((KUPTR)(pBlock)->pPrev < (KUPTR)(pBlock)); \ KHLPHEAP_ASSERT((KUPTR)(pBlock)->pNext > (KUPTR)(pBlock) || !(pBlock)->pNext); \ } while (0) # define KHLPHEAP_ASSERT_FREE(pHeap, pFree) \ do { \ KHLPHEAP_ASSERT_BLOCK(pHeap, &(pFree)->Core); \ KHLPHEAP_ASSERT((KUPTR)(pFree)->pPrev < (KUPTR)(pFree)); \ KHLPHEAP_ASSERT((KUPTR)(pFree)->pNext > (KUPTR)(pFree) || !(pFree)->pNext); \ } while (0) #else # define KHLPHEAP_ASSERT(expr) do { } while (0) # define KHLPHEAP_ASSERT_BLOCK(pH, pB) do { } while (0) # define KHLPHEAP_ASSERT_FREE(pH, pF) do { } while (0) #endif /** * A free heap block. */ typedef struct KHLPHEAPFREE { /** The core bit which we have in common with used blocks. */ KHLPHEAPBLOCK Core; /** The next free block. */ struct KHLPHEAPFREE *pNext; /** The previous free block. */ struct KHLPHEAPFREE *pPrev; } KHLPHEAPFREE, *PKHLPHEAPFREE; /** * A heap segment. */ typedef struct KHLPHEAPSEG { /** The base address of the segment. */ void *pvBase; /** The length of the segment (in bytes). */ KSIZE cb; } KHLPHEAPSEG, *PKHLPHEAPSEG; /** * Bundle of heap segments. */ typedef struct KHLPHEAPSEGS { /** Pointer to the next segment bundle. */ struct KHLPHEAPSEGS *pNext; /** The number of segments used. */ KU32 cSegs; /** Array of chunks. */ KHLPHEAPSEG aSegs[64]; } KHLPHEAPSEGS, *PKHLPHEAPSEGS; /** * Heap anchor block. */ typedef struct KHLPHEAPANCHOR { /** Head of the block list. */ PKHLPHEAPBLOCK pHead; /** Tail of the block list. */ PKHLPHEAPBLOCK pTail; /** Head of the free list. */ PKHLPHEAPFREE pFreeHead; /** Head segment bundle. * The order of this list is important, but a bit peculiar. * Logically, SegsHead::pNext is the tail pointer. */ KHLPHEAPSEGS SegsHead; } KHLPHEAPANCHOR, *PKHLPHEAPANCHOR; /******************************************************************************* * Global Variables * *******************************************************************************/ /** The heap anchor block. */ static KHLPHEAPANCHOR g_Heap; /******************************************************************************* * Internal Functions * *******************************************************************************/ static int khlpHeapInit(PKHLPHEAPANCHOR pHeap); static void khlpHeapDelete(PKHLPHEAPANCHOR pHeap); static void * khlpHeapAlloc(PKHLPHEAPANCHOR pHeap, KSIZE cb); static void khlpHeapFree(PKHLPHEAPANCHOR pHeap, void *pv); static KSIZE khlpHeapBlockSize(PKHLPHEAPANCHOR pHeap, void *pv); static void khlpHeapDonate(PKHLPHEAPANCHOR pHeap, void *pv, KSIZE cb); static int khlpHeapSegAlloc(PKHLPHEAPSEG pSeg, KSIZE cb); static void khlpHeapSegFree(PKHLPHEAPSEG pSeg); /** * Initializes the kLdr heap. * * @returns 0 on success, non-zero OS specific status code on failure. */ KHLP_DECL(int) kHlpHeapInit(void) { return khlpHeapInit(&g_Heap); } /** * Terminates the kLdr heap. */ KHLP_DECL(void) kHlpHeapTerm(void) { khlpHeapDelete(&g_Heap); } KHLP_DECL(void *) kHlpAlloc(KSIZE cb) { return khlpHeapAlloc(&g_Heap, cb); } KHLP_DECL(void *) kHlpAllocZ(KSIZE cb) { void *pv = khlpHeapAlloc(&g_Heap, cb); if (pv) kHlpMemSet(pv, 0, cb); return pv; } KHLP_DECL(void *) kHlpDup(const void *pv, KSIZE cb) { void *pvNew = khlpHeapAlloc(&g_Heap, cb); if (pvNew) kHlpMemCopy(pvNew, pv, cb); return pvNew; } KHLP_DECL(char *) kHlpStrDup(const char *psz) { return (char *)kHlpDup(psz, kHlpStrLen(psz) + 1); } KHLP_DECL(void *) kHlpRealloc(void *pv, KSIZE cb) { void *pvNew; if (!cb) { kHlpFree(pv); pvNew = NULL; } else if (!pv) pvNew = khlpHeapAlloc(&g_Heap, cb); else { KSIZE cbToCopy = khlpHeapBlockSize(&g_Heap, pv); pvNew = khlpHeapAlloc(&g_Heap, cb); if (pvNew) { kHlpMemCopy(pvNew, pv, cb); kHlpFree(pv); } } return pvNew; } KHLP_DECL(void) kHlpFree(void *pv) { khlpHeapFree(&g_Heap, pv); } /** * Donates memory to the heap. * * @param pv The address of the memory. * @param cb The amount of memory. */ KHLP_DECL(void) kHlpHeapDonate(void *pv, KSIZE cb) { khlpHeapDonate(&g_Heap, pv, cb); } /** * Initializes the heap anchor. * * @returns 0 on success, non-zero on failure. * @param pHeap The heap anchor to be initialized. */ static int khlpHeapInit(PKHLPHEAPANCHOR pHeap) { pHeap->pHead = NULL; pHeap->pTail = NULL; pHeap->pFreeHead = NULL; pHeap->SegsHead.pNext = NULL; pHeap->SegsHead.cSegs = 0; return 0; } /** * Deletes a heap. * This will free all resources (memory) associated with the heap. * * @param pHeap The heap to be deleted. */ static void khlpHeapDelete(PKHLPHEAPANCHOR pHeap) { /* * Free the segments, LIFO order. * The head element is the last to be free, while the * head.pNext is really the tail pointer - neat or what? */ while ( pHeap->SegsHead.cSegs || pHeap->SegsHead.pNext) { /* find the tail. */ KU32 iSeg; PKHLPHEAPSEGS pSegs = pHeap->SegsHead.pNext; if (!pSegs) pSegs = &pHeap->SegsHead; else { pHeap->SegsHead.pNext = pSegs->pNext; pSegs->pNext = NULL; } /* free the segments */ iSeg = pSegs->cSegs; while (iSeg-- > 0) khlpHeapSegFree(&pSegs->aSegs[iSeg]); pSegs->cSegs = 0; } /* Zap the anchor. */ pHeap->pHead = NULL; pHeap->pTail = NULL; pHeap->pFreeHead = NULL; pHeap->SegsHead.pNext = NULL; pHeap->SegsHead.cSegs = 0; } /** * Internal heap block allocator. */ static void * kldrHeapAllocSub(PKHLPHEAPANCHOR pHeap, KSIZE cb) { /* * Find a fitting free block. */ const KSIZE cbReq = K_ALIGN_Z(cb + sizeof(KHLPHEAPBLOCK), KHLPHEAPBLOCK_ALIGNMENT); PKHLPHEAPFREE pCur = pHeap->pFreeHead; while (pCur) { if (pCur->Core.cb >= cbReq) { if (pCur->Core.cb != cbReq) { /* check and see if there is a better match close by. */ PKHLPHEAPFREE pCur2 = pCur->pNext; unsigned i = 16; while (i-- > 0 && pCur2) { if (pCur2->Core.cb >= cbReq) { if (pCur2->Core.cb == cbReq) { pCur = pCur2; break; } if (pCur2->Core.cb < pCur->Core.cb) pCur = pCur2; } /* next */ KHLPHEAP_ASSERT_FREE(pHeap, pCur2); pCur2 = pCur2->pNext; } } break; } /* next */ KHLPHEAP_ASSERT_FREE(pHeap, pCur); pCur = pCur->pNext; } if (!pCur) return NULL; KHLPHEAP_ASSERT_FREE(pHeap, pCur); /* * Do we need to split out a block? */ if (pCur->Core.cb - cbReq >= KHLPHEAPBLOCK_ALIGNMENT * 2) { PKHLPHEAPBLOCK pNew; pCur->Core.cb -= cbReq; pNew = (PKHLPHEAPBLOCK)((KUPTR)pCur + pCur->Core.cb); pNew->fFlags = 0; pNew->cb = cbReq; pNew->pNext = pCur->Core.pNext; if (pNew->pNext) pNew->pNext->pPrev = pNew; else pHeap->pTail = pNew; pNew->pPrev = &pCur->Core; pCur->Core.pNext = pNew; KHLPHEAP_ASSERT_FREE(pHeap, pCur); KHLPHEAP_ASSERT_BLOCK(pHeap, pNew); return pNew + 1; } /* * No, just unlink it from the free list and return. */ if (pCur->pNext) pCur->pNext->pPrev = pCur->pPrev; if (pCur->pPrev) pCur->pPrev->pNext = pCur->pNext; else pHeap->pFreeHead = pCur->pNext; pCur->Core.fFlags &= ~KHLPHEAPBLOCK_FLAG_FREE; KHLPHEAP_ASSERT_BLOCK(pHeap, &pCur->Core); return &pCur->Core + 1; } /** * Allocate a heap block. * * @returns Pointer to the allocated heap block on success. On failure NULL is returned. * @param pHeap The heap. * @param cb The requested heap block size. */ static void * khlpHeapAlloc(PKHLPHEAPANCHOR pHeap, KSIZE cb) { void *pv; /* adjust the requested block size. */ cb = K_ALIGN_Z(cb, KHLPHEAPBLOCK_ALIGNMENT); if (!cb) cb = KHLPHEAPBLOCK_ALIGNMENT; /* try allocate the block. */ pv = kldrHeapAllocSub(pHeap, cb); if (!pv) { /* * Failed, add another segment and try again. */ KHLPHEAPSEG Seg; if (khlpHeapSegAlloc(&Seg, cb + sizeof(KHLPHEAPSEGS) + sizeof(KHLPHEAPBLOCK) * 16)) return NULL; /* donate before insterting the segment, this makes sure we got heap to expand the segment list. */ khlpHeapDonate(pHeap, Seg.pvBase, Seg.cb); /* insert the segment. */ if (pHeap->SegsHead.cSegs < sizeof(pHeap->SegsHead.aSegs) / sizeof(pHeap->SegsHead.aSegs[0])) pHeap->SegsHead.aSegs[pHeap->SegsHead.cSegs++] = Seg; else if ( pHeap->SegsHead.pNext && pHeap->SegsHead.pNext->cSegs < sizeof(pHeap->SegsHead.aSegs) / sizeof(pHeap->SegsHead.aSegs[0])) pHeap->SegsHead.pNext->aSegs[pHeap->SegsHead.pNext->cSegs++] = Seg; else { PKHLPHEAPSEGS pSegs = (PKHLPHEAPSEGS)kldrHeapAllocSub(pHeap, sizeof(*pSegs)); KHLPHEAP_ASSERT(pSegs); pSegs->pNext = pHeap->SegsHead.pNext; pHeap->SegsHead.pNext = pSegs; pSegs->aSegs[0] = Seg; pSegs->cSegs = 1; } /* retry (should succeed) */ pv = kldrHeapAllocSub(pHeap, cb); KHLPHEAP_ASSERT(pv); } return pv; } /** * Frees a heap block. * * @param pHeap The heap. * @param pv The pointer returned by khlpHeapAlloc(). */ static void khlpHeapFree(PKHLPHEAPANCHOR pHeap, void *pv) { PKHLPHEAPFREE pFree, pLeft, pRight; /* ignore NULL pointers. */ if (!pv) return; pFree = (PKHLPHEAPFREE)((PKHLPHEAPBLOCK)pv - 1); KHLPHEAP_ASSERT_BLOCK(pHeap, &pFree->Core); KHLPHEAP_ASSERT(KHLPHEAPBLOCK_IS_ALLOCATED(&pFree->Core)); /* * Merge or link with left node? */ pLeft = (PKHLPHEAPFREE)pFree->Core.pPrev; if ( pLeft && KHLPHEAPBLOCK_IS_FREE(&pLeft->Core) && KHLPHEAPBLOCK_IS_ADJACENT(&pLeft->Core, &pFree->Core) ) { /* merge left */ pLeft->Core.pNext = pFree->Core.pNext; if (pFree->Core.pNext) pFree->Core.pNext->pPrev = &pLeft->Core; else pHeap->pTail = &pLeft->Core; pLeft->Core.cb += pFree->Core.cb; pFree->Core.fFlags = ~0; pFree = pLeft; } else { /* link left */ while (pLeft && !KHLPHEAPBLOCK_IS_FREE(&pLeft->Core)) pLeft = (PKHLPHEAPFREE)pLeft->Core.pPrev; if (pLeft) { pFree->pPrev = pLeft; pFree->pNext = pLeft->pNext; if (pLeft->pNext) pLeft->pNext->pPrev = pFree; pLeft->pNext = pFree; } else { pFree->pPrev = NULL; pFree->pNext = pHeap->pFreeHead; if (pHeap->pFreeHead) pHeap->pFreeHead->pPrev = pFree; pHeap->pFreeHead = pFree; } pFree->Core.fFlags |= KHLPHEAPBLOCK_FLAG_FREE; } KHLPHEAP_ASSERT_FREE(pHeap, pFree); /* * Merge right? */ pRight = (PKHLPHEAPFREE)pFree->Core.pNext; if ( pRight && KHLPHEAPBLOCK_IS_FREE(&pRight->Core) && KHLPHEAPBLOCK_IS_ADJACENT(&pFree->Core, pRight) ) { /* unlink pRight from the global list. */ pFree->Core.pNext = pRight->Core.pNext; if (pRight->Core.pNext) pRight->Core.pNext->pPrev = &pFree->Core; else pHeap->pTail = &pFree->Core; /* unlink pRight from the free list. */ pFree->pNext = pRight->pNext; if (pRight->pNext) pRight->pNext->pPrev = pFree; /* update size and invalidate pRight. */ pFree->Core.cb += pRight->Core.cb; pRight->Core.fFlags = ~0; } } /** * Calcs the size of a heap block. * * @returns The block size (in bytes). * @param pHeap The heap. * @param pv Pointer to an in-use heap block. */ static KSIZE khlpHeapBlockSize(PKHLPHEAPANCHOR pHeap, void *pv) { PKHLPHEAPBLOCK pBlock = (PKHLPHEAPBLOCK)pv - 1; KHLPHEAP_ASSERT_BLOCK(pHeap, pBlock); KHLPHEAP_ASSERT(KHLPHEAPBLOCK_IS_ALLOCATED(pBlock)); return (KU8 *)pBlock->pNext - (KU8 *)pv; } /** * Donates memory to the heap. * * The donated memory is returned to the donator when the heap is deleted. * * @param pHeap The heap * @param pv The pointer to the donated memory. * @param cb Size of the donated memory. */ static void khlpHeapDonate(PKHLPHEAPANCHOR pHeap, void *pv, KSIZE cb) { PKHLPHEAPBLOCK pBlock; /* * Don't bother with small donations. */ if (cb < KHLPHEAPBLOCK_ALIGNMENT * 4) return; /* * Align the donation on a heap block boundrary. */ if ((KUPTR)pv & (KHLPHEAPBLOCK_ALIGNMENT - 1)) { cb -= (KUPTR)pv & 31; pv = K_ALIGN_P(pv, KHLPHEAPBLOCK_ALIGNMENT); } cb &= ~(KSIZE)(KHLPHEAPBLOCK_ALIGNMENT - 1); /* * Create an allocated block, link it and free it. */ pBlock = (PKHLPHEAPBLOCK)pv; pBlock->pNext = NULL; pBlock->pPrev = NULL; pBlock->cb = cb; pBlock->fFlags = 0; /* insert */ if ((KUPTR)pBlock < (KUPTR)pHeap->pHead) { /* head */ pBlock->pNext = pHeap->pHead; pHeap->pHead->pPrev = pBlock; pHeap->pHead = pBlock; } else if ((KUPTR)pBlock > (KUPTR)pHeap->pTail) { if (pHeap->pTail) { /* tail */ pBlock->pPrev = pHeap->pTail; pHeap->pTail->pNext = pBlock; pHeap->pTail = pBlock; } else { /* first */ pHeap->pHead = pBlock; pHeap->pTail = pBlock; } } else { /* in list (unlikely) */ PKHLPHEAPBLOCK pPrev = pHeap->pHead; PKHLPHEAPBLOCK pCur = pPrev->pNext; for (;;) { KHLPHEAP_ASSERT_BLOCK(pHeap, pCur); if ((KUPTR)pCur > (KUPTR)pBlock) break; pPrev = pCur; pCur = pCur->pNext; } pBlock->pNext = pCur; pBlock->pPrev = pPrev; pPrev->pNext = pBlock; pCur->pPrev = pBlock; } KHLPHEAP_ASSERT_BLOCK(pHeap, pBlock); /* free it */ khlpHeapFree(pHeap, pBlock + 1); } /** * Allocates a new segment. * * @returns 0 on success, non-zero OS status code on failure. * @param pSeg Where to put the info about the allocated segment. * @param cbMin The minimum segment size. */ static int khlpHeapSegAlloc(PKHLPHEAPSEG pSeg, KSIZE cbMin) { #if K_OS == K_OS_OS2 APIRET rc; pSeg->cb = (cbMin + 0xffff) & ~(KSIZE)0xffff; pSeg->pvBase = NULL; rc = DosAllocMem(&pSeg->pvBase, pSeg->cb, PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_ANY); if (rc == ERROR_INVALID_PARAMETER) rc = DosAllocMem(&pSeg->pvBase, pSeg->cb, PAG_COMMIT | PAG_READ | PAG_WRITE); if (rc) { pSeg->pvBase = NULL; pSeg->cb = 0; return rc; } #elif K_OS == K_OS_WINDOWS pSeg->cb = (cbMin + 0xffff) & ~(KSIZE)0xffff; pSeg->pvBase = VirtualAlloc(NULL, pSeg->cb, MEM_COMMIT, PAGE_READWRITE); if (!pSeg->pvBase) { pSeg->cb = 0; return GetLastError(); } #else int rc; pSeg->cb = (cbMin + 0xffff) & ~(KSIZE)0xffff; pSeg->pvBase = NULL; rc = kHlpPageAlloc(&pSeg->pvBase, pSeg->cb, KPROT_READWRITE, K_FALSE); if (rc) { pSeg->pvBase = NULL; pSeg->cb = 0; return rc; } #endif return 0; } /** * Frees a segment. * * @param pSeg The segment to be freed. */ static void khlpHeapSegFree(PKHLPHEAPSEG pSeg) { #if K_OS == K_OS_OS2 APIRET rc = DosFreeMem(pSeg->pvBase); KHLPHEAP_ASSERT(!rc); (void)rc; #elif K_OS == K_OS_WINDOWS BOOL fRc = VirtualFree(pSeg->pvBase, 0 /*pSeg->cb*/, MEM_RELEASE); KHLPHEAP_ASSERT(fRc); (void)fRc; #else int rc = kHlpPageFree(pSeg->pvBase, pSeg->cb); KHLPHEAP_ASSERT(!rc); (void)rc; #endif } kbuild-3149/src/lib/kStuff/kHlp/Bare/kHlpSys-darwin.c0000644000175000017500000002446213252530254022306 0ustar locutuslocutus/* $Id: kHlpSys-darwin.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpBare - */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #include #include #include #include #include #include #define USE_DARWIN_SYSCALLS #if K_ARCH == K_ARCH_X86_32 # define DARWIN_SYSCALL(name, code) \ asm("\ .text \n\ .globl _" #name " \n\ _" #name ": \n\ mov $ " #code ", %eax \n\ call 1f \n\ 1: \n\ pop %edx \n\ mov %esp, %ecx \n\ sysenter \n\ jnae 2f \n\ ret \n\ 2: \n\ neg %eax \n\ ret \n\ ") # define DARWIN_SYSCALL_RET64(name, code) \ asm("\ .text \n\ .globl _" #name " \n\ _" #name ": \n\ mov $ " #code ", %eax \n\ int $0x80 \n\ jnae 2f \n\ ret \n\ 2: \n\ neg %eax \n\ mov $0xffffffff, %edx \n\ ret \n\ ") # define DARWIN_SYSCALL_NOERR(name, code) \ asm("\ .text \n\ .globl _" #name " \n\ _" #name ": \n\ mov $ " #code ", %eax \n\ call 1f \n\ 1: \n\ pop %edx \n\ mov %esp, %ecx \n\ sysenter \n\ ret \n\ ") #elif K_ARCH == K_ARCH_AMD64 # define DARWIN_SYSCALL(name, code) \ asm("\ .text \n\ .globl _" #name " \n\ _" #name ": \n\ mov $ " #code ", %eax \n\ mov %rcx, %r10 \n\ sysenter \n\ jnae 2f \n\ ret \n\ 2: \n\ neg %eax \n\ movsx %eax, %rax \n\ ret \n\ ") # define DARWIN_SYSCALL_RET64(name, code) DARWIN_SYSCALL_RET(name, code) # define DARWIN_SYSCALL_NOERR(name, code) \ asm("\ .text \n\ .globl _" #name " \n\ _" #name ": \n\ mov $ " #code ", %eax \n\ mov %rcx, %r10 \n\ sysenter \n\ ret \n\ ") #else # error later... #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_readlink, 0x000c003a); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_readlink, 0x0200003a); #else KSSIZE kHlpSys_readlink(const char *pszPath, char *pszBuf, KSIZE cbBuf) { KSSIZE cbRet = readlink(pszPath, pszBuf, cbBuf); return cbRet >= 0 ? cbRet : -errno; } #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_open, 0x000c0005); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_open, 0x02000005); #else int kHlpSys_open(const char *filename, int flags, int mode) { int fd = open(filename, flags, mode); return fd >= 0 ? fd : -errno; } #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_close, 0x000c0006); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_close, 0x02000006); #else int kHlpSys_close(int fd) { if (!close(fd)) return 0; return -errno; } #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL_RET64(kHlpSys_lseek, 0x000000c7); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL_RET64(kHlpSys_lseek, 0x020000c7); #else KFOFF kHlpSys_lseek(int fd, int whench, KFOFF off) { KFOFF offRet = lseek(fd, whench, off); return offRet >= 0 ? offRet : -errno; } #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_read, 0x000c0003); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_read, 0x02000003); #else KSSIZE kHlpSys_read(int fd, void *pvBuf, KSIZE cbBuf) { KSSIZE cbRead = read(fd, pvBuf, cbBuf); return cbRead >= 0 ? cbRead : -errno; } #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_write, 0x000c0004); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_write, 0x02000004); #else KSSIZE kHlpSys_write(int fd, const void *pvBuf, KSIZE cbBuf) { KSSIZE cbWritten = write(fd, pvBuf, cbBuf); return cbWritten >= 0 ? cbWritten : -errno; } #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_mmap, 0x020000c5); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_mmap, 0x020000c5); #else void *kHlpSys_mmap(void *addr, KSIZE len, int prot, int flags, int fd, KI64 off) { void *pv = mmap(addr, len, prot, flags, fd, off); return pv != (void *)-1 ? pv : errno < 256 ? (void *)(long)errno : (void *)(long)ENOMEM; } #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_mprotect, 0x000c004a); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_mprotect, 0x0200004a); #else int kHlpSys_mprotect(void *addr, KSIZE len, int prot) { if (!mprotect(addr, len, prot)) return 0; return -errno; } #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_munmap, 0x00080049); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_munmap, 0x02000049); #else int kHlpSys_munmap(void *addr, KSIZE len) { if (!munmap(addr, len)) return 0; return -errno; } #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_exit, 0x00040001); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(kHlpSys_exit, 0x02000001); #else void kHlpSys_exit(int rc) { _Exit(rc); } #endif /* * Some other stuff we'll be needing - Move to an appropriate place? */ #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL_NOERR(mach_task_self, 0xffffffe4); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL_NOERR(mach_task_self, 0xffffffe4); #endif //#if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) //DARWIN_SYSCALL(semaphore_create, 0x00040001); //#elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) //DARWIN_SYSCALL(semaphore_create, 0x02000001); //#endif #ifdef USE_DARWIN_SYSCALLS kern_return_t semaphore_create(task_t t, semaphore_t *ps, int p, int v) { return 0; } #endif //#if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) //DARWIN_SYSCALL(semaphore_destroy, 0x00040001); //#elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) //DARWIN_SYSCALL(semaphore_destroy, 0x02000001); //#endif #ifdef USE_DARWIN_SYSCALLS kern_return_t semaphore_destroy(task_t t, semaphore_t s) { return 0; } #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(semaphore_wait, 0xffffffdc); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(semaphore_wait, 0xffffffdc); #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(semaphore_signal, 0xffffffdf); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(semaphore_signal, 0xffffffdf); #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(mach_wait_until, 0xffffffa6); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(mach_wait_until, 0xffffffa6); #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(mach_timebase_info, 0xffffffa7); #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) DARWIN_SYSCALL(mach_timebase_info, 0xffffffa7); #endif #if K_ARCH == K_ARCH_X86_32 && defined(USE_DARWIN_SYSCALLS) asm("\n\ .text \n\ .globl _mach_absolute_time \n\ _mach_absolute_time: \n\ mov $0xffff1700, %edx \n\ jmp *%edx\n"); /* common page stuff. */ #elif K_ARCH == K_ARCH_AMD64 && defined(USE_DARWIN_SYSCALLS) #endif void *dlopen(const char *pszModule, int fFlags) { return NULL; } int dlclose(void *pvMod) { } void *dlsym(void *pvMod, const char *pszSymbol) { return NULL; } kbuild-3149/src/lib/kStuff/kHlp/Generic/0000755000175000017500000000000013252530254017756 5ustar locutuslocutuskbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpStrIPCompAscii.c0000644000175000017500000000400713252530254023533 0ustar locutuslocutus/* $Id: kHlpStrIPCompAscii.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrIPCompAscii. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(char *) kHlpStrIPCompAscii(const char *psz1, const char *psz2) { for (;;) { char ch1 = *psz1; char ch2 = *psz2; if (ch1 != ch2) { if (ch1 <= 'Z' && ch1 >= 'A') ch1 += 'a' - 'A'; if (ch2 <= 'Z' && ch2 >= 'A') ch2 += 'a' - 'A'; if (ch1 != ch2) return (char *)psz1; } if (!ch1) return (char *)psz1; psz1++; psz2++; } } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpMemPMove.c0000644000175000017500000000505013252530254022426 0ustar locutuslocutus/* $Id: kHlpMemPMove.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpMemPMove. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(void *) kHlpMemPMove(void *pv1, const void *pv2, KSIZE cb) { union { void *pv; KU8 *pb; KUPTR *pu; } u1; union { const void *pv; volatile KU8 *pb; volatile KUPTR *pu; } u2; u1.pv = pv1; u2.pv = pv2; if ((KUPTR)u1.pb <= (KUPTR)u2.pb) { /* forwards copy */ if (cb >= 32) { while (cb > sizeof(KUPTR)) { KUPTR u = *u2.pu++; *u1.pu++ = u; cb -= sizeof(KUPTR); } } while (cb-- > 0) { KU8 b = *u2.pb++; *u1.pb++ = b; } return u1.pb; } /* backwards copy */ u1.pb += cb; u2.pb += cb; if (cb >= 32) { while (cb > sizeof(KUPTR)) { KUPTR u = *--u2.pu; *--u1.pu = u; cb -= sizeof(KUPTR); } } while (cb-- > 0) { KU8 b = *--u2.pb; *--u1.pb = b; } return (KU8 *)pv1 + cb; } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpStrNPCat.c0000644000175000017500000000346013252530254022402 0ustar locutuslocutus/* $Id: kHlpStrNPCat.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrNPCat. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(char *) kHlpStrNPCat(char *pszDst, const char *pszSrc, KSIZE cb) { char ch; while (*pszDst != '\0') pszDst++; while (cb-- > 0) { ch = *pszSrc++; if (!ch) break; *pszDst++ = ch; } *pszDst = '\0'; return pszDst; } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpStrChr.c0000644000175000017500000000350413252530254022150 0ustar locutuslocutus/* $Id: kHlpStrChr.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrChr. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(char *) kHlpStrChr(const char *psz, int ch) { if (!ch) { while (*psz) psz++; return (char *)psz; } for (;;) { int chCur = *psz; if (chCur == ch) return (char *)psz; if (!chCur) return NULL; psz++; } } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpStrPCat.c0000644000175000017500000000336113252530254022264 0ustar locutuslocutus/* $Id: kHlpStrPCat.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrPCat. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(char *) kHlpStrPCat(char *pszDst, const char *psz2) { char ch; while (*pszDst != '\0') pszDst++; do { ch = *psz2++; *pszDst++ = ch; } while (ch != '\0'); return pszDst - 1; } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpGetExt.c0000644000175000017500000000517213252530254022146 0ustar locutuslocutus/* $Id: kHlpGetExt.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpPath - kHlpGetExt and kHlpGetSuff. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include /** * Gets the filename suffix. * * @returns Pointer to where the suffix starts within the string pointed to by pszFilename. * @returns Pointer to the terminator char if no suffix. * @param pszFilename The filename to parse. */ KHLP_DECL(char *) kHlpGetSuff(const char *pszFilename) { const char *pszDot = NULL; pszFilename = kHlpGetFilename(pszFilename); for (;;) { char ch = *pszFilename; if (ch == '.') { while ((ch = *++pszFilename) == '.') /* nothing */; if (ch) pszDot = pszFilename - 1; } if (!ch) return (char *)(pszDot ? pszDot : pszFilename); pszFilename++; } } /** * Gets the filename extention. * * @returns Pointer to where the extension starts within the string pointed to by pszFilename. * @returns Pointer to the terminator char if no extension. * @param pszFilename The filename to parse. */ KHLP_DECL(char *) kHlpGetExt(const char *pszFilename) { char *psz = kHlpGetSuff(pszFilename); return *psz ? psz + 1 : psz; } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpPage.c0000644000175000017500000002432513252530254021623 0ustar locutuslocutus/* $Id: kHlpPage.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlp - Generic Page Memory Functions. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS # include # include #elif K_OS == K_OS_OS2 # define INCL_BASE # define INCL_ERRORS # include #elif K_OS == K_OS_WINDOWS # include #else # error "port me" #endif /******************************************************************************* * Global Variables * *******************************************************************************/ #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS /* nothing */ #elif K_OS == K_OS_OS2 /** The base of the loader stub object. * The OS/2 exe stub consists of a single data object. When allocating memory * for an executable, we'll have to reuse this. */ static void *g_pvStub = NULL; /** The size of the stub object - 0 if no stub. */ static KSIZE g_cbStub = 0; #elif K_OS == K_OS_WINDOWS /** The system info. */ static SYSTEM_INFO g_SystemInfo; #else # error "port me" #endif #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS static int kHlpPageProtToNative(KPROT enmProt) { switch (enmProt) { case KPROT_NOACCESS: return PROT_NONE; case KPROT_READONLY: return PROT_READ; case KPROT_READWRITE: return PROT_READ | PROT_WRITE; case KPROT_EXECUTE: return PROT_EXEC; case KPROT_EXECUTE_READ: return PROT_EXEC | PROT_READ; case KPROT_EXECUTE_READWRITE: return PROT_EXEC | PROT_READ | PROT_WRITE; default: kHlpAssert(0); return ~0U; } } #elif K_OS == K_OS_OS2 static ULONG kHlpPageProtToNative(KPROT enmProt) { switch (enmProt) { case KPROT_NOACCESS: return PAG_EXECUTE | PAG_READ | PAG_WRITE; case KPROT_READONLY: return PAG_COMMIT | PAG_READ; case KPROT_READWRITE: return PAG_COMMIT | PAG_READ | PAG_WRITE; case KPROT_EXECUTE: return PAG_COMMIT | PAG_EXECUTE; case KPROT_EXECUTE_READ: return PAG_COMMIT | PAG_EXECUTE | PAG_READ; case KPROT_EXECUTE_READWRITE: return PAG_COMMIT | PAG_EXECUTE | PAG_READ | PAG_WRITE; default: kHlpAssert(0); return ~0U; } } #elif K_OS == K_OS_WINDOWS static DWORD kHlpPageProtToNative(KPROT enmProt) { switch (enmProt) { case KPROT_NOACCESS: return PAGE_NOACCESS; case KPROT_READONLY: return PAGE_READONLY; case KPROT_READWRITE: return PAGE_READWRITE; case KPROT_EXECUTE: return PAGE_EXECUTE; case KPROT_EXECUTE_READ: return PAGE_EXECUTE_READ; case KPROT_EXECUTE_READWRITE: return PAGE_EXECUTE_READWRITE; default: kHlpAssert(0); return ~0U; } } #endif /** * Allocate a chunk of memory with page granularity. * * @returns 0 on success, non-zero OS status code on failure. * @param ppv Where to store the address of the allocated memory. * If fFixed is set, *ppv will on entry contain the desired address (page aligned). * @param cb Number of bytes. Page aligned. * @param enmProt The new protection. Copy-on-write is invalid. */ KHLP_DECL(int) kHlpPageAlloc(void **ppv, KSIZE cb, KPROT enmProt, KBOOL fFixed) { #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS void *pv; pv = kHlpSys_mmap(fFixed ? *ppv : NULL, cb, kHlpPageProtToNative(enmProt), fFixed ? MAP_FIXED | MAP_ANON: MAP_ANON, -1, 0); if ((KIPTR)pv < 256) { kHlpAssert(0); return (int)(KIPTR)pv; /** @todo convert errno to kErrors */ } *ppv = pv; return 0; #elif K_OS == K_OS_OS2 APIRET rc; ULONG fFlags = kHlpPageProtToNative(enmProt); if (!fFixed) { /* simple */ rc = DosAllocMem(ppv, cb, fFlags | OBJ_ANY); if (rc == ERROR_INVALID_PARAMETER) rc = DosAllocMem(ppv, cb, fFlags); } else { /* not so simple. */ /** @todo I've got code for this in libc somewhere. */ rc = -1; } if (!rc) return 0; kHlpAssert(0); return rc; #elif K_OS == K_OS_WINDOWS /* (We don't have to care about the stub here, because the stub will be unmapped before we get here.) */ int rc; DWORD fProt = kHlpPageProtToNative(enmProt); if (!g_SystemInfo.dwPageSize) GetSystemInfo(&g_SystemInfo); *ppv = VirtualAlloc(fFixed ? *ppv : NULL, cb, MEM_COMMIT, fProt); if (*ppv != NULL) return 0; rc = GetLastError(); kHlpAssert(0); return rc; #else # error "port me" #endif } /** * Change the protection of one or more pages in an allocation. * * (This will of course only work correctly on memory allocated by kHlpPageAlloc().) * * @returns 0 on success, non-zero OS status code on failure. * @param pv First page. Page aligned. * @param cb Number of bytes. Page aligned. * @param enmProt The new protection. Copy-on-write is invalid. */ KHLP_DECL(int) kHlpPageProtect(void *pv, KSIZE cb, KPROT enmProt) { #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS int rc; rc = kHlpSys_mprotect(pv, cb, kHlpPageProtToNative(enmProt)); if (!rc) return 0; /** @todo convert errno -> kErrors */ kHlpAssert(0); return rc; #elif K_OS == K_OS_OS2 APIRET rc; ULONG fFlags = kHlpPageProtToNative(enmProt); /* * The non-stub pages. */ rc = DosSetMem(pv, cb, fFlags); if (rc && fFlags != PAG_DECOMMIT) rc = DosSetMem(pv, cb, fFlags | PAG_COMMIT); if (rc) { /* Try page by page. */ while (cb > 0) { rc = DosSetMem(pv, 0x1000, fFlags); if (rc && fFlags != PAG_DECOMMIT) rc = DosSetMem(pv, 0x1000, fFlags | PAG_COMMIT); if (rc) return rc; pv = (void *)((KUPTR)pv + 0x1000); cb -= 0x1000; } } kHlpAssert(!rc); return rc; #elif K_OS == K_OS_WINDOWS DWORD fOldProt = 0; DWORD fProt = kHlpPageProtToNative(enmProt); int rc = 0; if (!VirtualProtect(pv, cb, fProt, &fOldProt)) { rc = GetLastError(); kHlpAssert(0); } return rc; #else # error "port me" #endif } /** * Free memory allocated by kHlpPageAlloc(). * * @returns 0 on success, non-zero OS status code on failure. * @param pv The address returned by kHlpPageAlloc(). * @param cb The byte count requested from kHlpPageAlloc(). */ KHLP_DECL(int) kHlpPageFree(void *pv, KSIZE cb) { #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS int rc; rc = kHlpSys_munmap(pv, cb); if (!rc) return 0; /** @todo convert errno -> kErrors */ return rc; #elif K_OS == K_OS_OS2 APIRET rc; /* * Deal with any portion overlapping with the stub. */ KUPTR offStub = (KUPTR)pv - (KUPTR)g_pvStub; if (offStub < g_cbStub) { /* decommit the pages in the stub. */ KSIZE cbStub = K_MIN(g_cbStub - offStub, cb); rc = DosSetMem(pv, cbStub, PAG_DECOMMIT); if (rc) { /* Page by page, ignoring errors after the first success. */ while (cbStub > 0) { if (!DosSetMem(pv, 0x1000, PAG_DECOMMIT)) rc = 0; pv = (void *)((KUPTR)pv + 0x1000); cbStub -= 0x1000; cb -= 0x1000; } if (rc) { kHlpAssert(!rc); return rc; } } else { cb -= cbStub; if (!cb) return 0; pv = (void *)((KUPTR)pv + cbStub); } } /* * Free the object. */ rc = DosFreeMem(pv); kHlpAssert(!rc); return rc; #elif K_OS == K_OS_WINDOWS /* * Free the object. */ int rc = 0; if (!VirtualFree(pv, 0 /*cb*/, MEM_RELEASE)) { rc = GetLastError(); kHlpAssert(0); } return rc; #else # error "port me" #endif } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpMemCopy.c0000644000175000017500000000377713252530254022330 0ustar locutuslocutus/* $Id: kHlpMemCopy.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpMemCopy. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(void *) kHlpMemCopy(void *pv1, const void *pv2, KSIZE cb) { union { void *pv; KU8 *pb; KUPTR *pu; } u1; union { const void *pv; const KU8 *pb; const KUPTR *pu; } u2; u1.pv = pv1; u2.pv = pv2; if (cb >= 32) { while (cb > sizeof(KUPTR)) { cb -= sizeof(KUPTR); *u1.pu++ = *u2.pu++; } } while (cb-- > 0) *u1.pb++ = *u2.pb++; return pv1; } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpStrPComp.c0000644000175000017500000000344213252530254022453 0ustar locutuslocutus/* $Id: kHlpStrPComp.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrPComp. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(char *) kHlpStrPComp(const char *psz1, const char *psz2) { for (;;) { char ch1 = *psz1; char ch2 = *psz2; if (ch1 != ch2) return (char *)psz1; if (!ch1) return NULL; psz1++; psz2++; } } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpIsFilenameOnly.c0000644000175000017500000000415013252530254023617 0ustar locutuslocutus/* $Id: kHlpIsFilenameOnly.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpPath - kHlpIsFilenameOnly. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include /** * Checks if this is only a filename or if it contains any kind * of drive, directory, or server specs. * * @returns 1 if this is a filename only. * @returns 0 of it's isn't only a filename. * @param pszFilename The filename to parse. */ KHLP_DECL(int) kHlpIsFilenameOnly(const char *pszFilename) { for (;;) { const char ch = *pszFilename++; #if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS if (ch == '/' || ch == '\\' || ch == ':') #else if (ch == '/') #endif return 0; if (!ch) return 1; } } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpMemPComp.c0000644000175000017500000000415513252530254022423 0ustar locutuslocutus/* $Id: kHlpMemPComp.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpMemPComp. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(void *) kHlpMemPComp(const void *pv1, const void *pv2, KSIZE cb) { union { const void *pv; const KU8 *pb; const KUPTR *pu; } u1, u2; u1.pv = pv1; u2.pv = pv2; if (cb >= 32) { while (cb > sizeof(KUPTR)) { if (*u1.pu != *u2.pu) break; /* over to mr. byte-by-byte */ u1.pu++; u2.pu++; cb -= sizeof(KUPTR); } } while (cb-- > 0) { if (u1.pb != u2.pb) return (void *)u1.pb; u1.pb++; u2.pb++; } return NULL; } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpStrNIPCompAscii.c0000644000175000017500000000404013252530254023646 0ustar locutuslocutus/* $Id: kHlpStrNIPCompAscii.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrNIPCompAscii. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(char *) kHlpStrNIPCompAscii(const char *psz1, const char *psz2, KSIZE cb) { while (cb-- > 0) { char ch1 = *psz1; char ch2 = *psz2; if (ch1 != ch2) { if (ch1 <= 'Z' && ch1 >= 'A') ch1 += 'a' - 'A'; if (ch2 <= 'Z' && ch2 >= 'A') ch2 += 'a' - 'A'; if (ch1 != ch2) return (char *)psz1; } if (!ch1) break; psz1++; psz2++; } return NULL; } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpMemMove.c0000644000175000017500000000513213252530254022307 0ustar locutuslocutus/* $Id: kHlpMemMove.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpMemMove. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(void *) kHlpMemMove(void *pv1, const void *pv2, KSIZE cb) { union { void *pv; KU8 *pb; KUPTR *pu; } u1; union { const void *pv; volatile KU8 *pb; volatile KUPTR *pu; } u2; u1.pv = pv1; u2.pv = pv2; if ((KUPTR)u1.pb <= (KUPTR)u2.pb) { /* forward copy */ if (cb >= 32) { while (cb > sizeof(KUPTR)) { KUPTR u = *u2.pu++; *u1.pu++ = u; cb -= sizeof(KUPTR); } } while (cb-- > 0) { KU8 b = *u2.pb++; *u1.pb++ = b; } } else { /* backwards copy */ u1.pb += cb; u2.pb += cb; if (cb >= 32) { while (cb > sizeof(KUPTR)) { KUPTR u = *--u2.pu; *--u1.pu = u; cb -= sizeof(KUPTR); } } while (cb-- > 0) { KU8 b = *--u2.pb; *--u1.pb = b; } } return pv1; } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpMemChr.c0000644000175000017500000000337313252530254022122 0ustar locutuslocutus/* $Id: kHlpMemChr.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpMemChr. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(void *) kHlpMemChr(const void *pv1, int ch, KSIZE cb) { const KU8 b = ch; const KU8 *pb = (const KU8 *)pv1; while (cb-- > 0) { if (*pb == b) return (void *)pb; pb++; } return NULL; } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpGetEnvUZ.c0000644000175000017500000000604713252530254022417 0ustar locutuslocutus/* $Id: kHlpGetEnvUZ.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpEnv - kHlpGetEnvUZ. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include /** * Gets an environment variable and converts it to a KSIZE. * * @returns 0 and *pcb on success. * @returns On failure see kHlpGetEnv. * @param pszVar The name of the variable. * @param pcb Where to put the value. */ KHLP_DECL(int) kHlpGetEnvUZ(const char *pszVar, KSIZE *pcb) { KSIZE cb; unsigned uBase; char szVal[64]; KSIZE cchVal = sizeof(szVal); const char *psz; int rc; *pcb = 0; rc = kHlpGetEnv(pszVar, szVal, cchVal); if (rc) return rc; /* figure out the base. */ uBase = 10; psz = szVal; if ( *psz == '0' && (psz[1] == 'x' || psz[1] == 'X')) { uBase = 16; psz += 2; } /* convert it up to the first unknown char. */ cb = 0; for(;;) { const char ch = *psz; unsigned uDigit; if (!ch) break; else if (ch >= '0' && ch <= '9') uDigit = ch - '0'; else if (ch >= 'a' && ch <= 'z') uDigit = ch - 'a' + 10; else if (ch >= 'A' && ch <= 'Z') uDigit = ch - 'A' + 10; else break; if (uDigit >= uBase) break; /* add the digit */ cb *= uBase; cb += uDigit; psz++; } /* check for unit */ if (*psz == 'm' || *psz == 'M') cb *= 1024*1024; else if (*psz == 'k' ||*psz == 'K') cb *= 1024; else if (*psz == 'g' || *psz == 'G') cb *= 1024*1024*1024; *pcb = cb; return 0; } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpGetFilename.c0000644000175000017500000000472713252530254023133 0ustar locutuslocutus/* $Id: kHlpGetFilename.c 85 2016-09-06 03:21:04Z bird $ */ /** @file * kHlpPath - kHlpGetFilename. */ /* * Copyright (c) 2006-2016 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include /** * Get the pointer to the filename part of the name. * * @returns Pointer to where the filename starts within the string pointed to by pszFilename. * @returns Pointer to the terminator char if no filename. * @param pszFilename The filename to parse. */ KHLP_DECL(char *) kHlpGetFilename(const char *pszFilename) { const char *pszLast = pszFilename; for (;;) { char ch = *pszFilename; #if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS if (ch == '/' || ch == '\\' || ch == ':') { while ((ch = *++pszFilename) == '/' || ch == '\\' || ch == ':') /* nothing */; pszLast = pszFilename; } #else if (ch == '/') { while ((ch = *++pszFilename) == '/') /* betsuni */; pszLast = pszFilename; } #endif if (ch) pszFilename++; else return (char *)pszLast; } } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpMemPCopy.c0000644000175000017500000000400413252530254022430 0ustar locutuslocutus/* $Id: kHlpMemPCopy.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpMemPCopy. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(void *) kHlpMemPCopy(void *pv1, const void *pv2, KSIZE cb) { union { void *pv; KU8 *pb; KUPTR *pu; } u1; union { const void *pv; const KU8 *pb; const KUPTR *pu; } u2; u1.pv = pv1; u2.pv = pv2; if (cb >= 32) { while (cb > sizeof(KUPTR)) { cb -= sizeof(KUPTR); *u1.pu++ = *u2.pu++; } } while (cb-- > 0) *u1.pb++ = *u2.pb++; return u1.pb; } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpMemICompAscii.c0000644000175000017500000000462213252530254023364 0ustar locutuslocutus/* $Id: kHlpMemICompAscii.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpMemICompAscii. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(int) kHlpMemICompAscii(const void *pv1, const void *pv2, KSIZE cb) { union { const void *pv; const KU8 *pb; const KUPTR *pu; } u1, u2; u1.pv = pv1; u2.pv = pv2; if (cb >= 32) { while (cb > sizeof(KUPTR)) { if (*u1.pu != *u2.pu) break; /* hand it on to the byte-by-byte routine. */ u1.pu++; u2.pu++; cb -= sizeof(KUPTR); } } while (cb-- > 0) { if (u1.pb != u2.pb) { KU8 ch1 = *u1.pb; KU8 ch2 = *u2.pb; if (ch1 <= 'Z' && ch1 >= 'A') ch1 += 'a' - 'A'; if (ch2 <= 'Z' && ch2 >= 'A') ch2 += 'a' - 'A'; if (ch1 != ch2) return ch1 > ch2 ? 1 : -1; } u1.pb++; u2.pb++; } return 0; } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpStrComp.c0000644000175000017500000000343613252530254022336 0ustar locutuslocutus/* $Id: kHlpStrComp.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrComp. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(int) kHlpStrComp(const char *psz1, const char *psz2) { for (;;) { char ch1 = *psz1; char ch2 = *psz2; if (ch1 != ch2) return ch1 > ch2 ? 1 : -1; if (!ch1) return 0; psz1++; psz2++; } } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpStrNICompAscii.c0000644000175000017500000000403313252530254023530 0ustar locutuslocutus/* $Id: kHlpStrNICompAscii.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrNICompAscii. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(int) kHlpStrNICompAscii(const char *psz1, const char *psz2, KSIZE cb) { while (cb-- > 0) { char ch1 = *psz1; char ch2 = *psz2; if (ch1 != ch2) { if (ch1 <= 'Z' && ch1 >= 'A') ch1 += 'a' - 'A'; if (ch2 <= 'Z' && ch2 >= 'A') ch2 += 'a' - 'A'; if (ch1 != ch2) return ch1 > ch2 ? 1 : -1; } if (!ch1) break; psz1++; psz2++; } return 0; } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpStrCopy.c0000644000175000017500000000327013252530254022346 0ustar locutuslocutus/* $Id: kHlpStrCopy.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrCopy. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(char *) kHlpStrCopy(char *pszDst, const char *pszSrc) { char ch; char *psz = pszDst; do *psz++ = ch = *pszSrc; while (ch); return pszDst; } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpStrNComp.c0000644000175000017500000000347513252530254022457 0ustar locutuslocutus/* $Id: kHlpStrNComp.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrNComp. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(int) kHlpStrNComp(const char *psz1, const char *psz2, KSIZE cb) { while (cb-- > 0) { char ch1 = *psz1; char ch2 = *psz2; if (ch1 != ch2) return ch1 > ch2 ? 1 : -1; if (!ch1) break; psz1++; psz2++; } return 0; } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpInt2Ascii.c0000644000175000017500000000510613252530254022530 0ustar locutuslocutus/* $Id: kHlpInt2Ascii.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpInt2Ascii. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include /** * Converts an signed integer to an ascii string. * * @returns psz. * @param psz Pointer to the output buffer. * @param cch The size of the output buffer. * @param lVal The value. * @param iBase The base to format it. (2,8,10 or 16) */ KHLP_DECL(char *) kHlpInt2Ascii(char *psz, KSIZE cch, long lVal, unsigned iBase) { static const char s_szDigits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; char *pszRet = psz; if (cch >= (lVal < 0 ? 3U : 2U) && psz) { /* prefix */ if (lVal < 0) { *psz++ = '-'; cch--; lVal = -lVal; } /* the digits */ do { *psz++ = s_szDigits[lVal % iBase]; cch--; lVal /= iBase; } while (lVal && cch > 1); /* overflow indicator */ if (lVal) psz[-1] = '+'; } else if (!pszRet) return pszRet; else if (cch < 1 || !pszRet) return pszRet; else *psz++ = '+'; *psz = '\0'; return pszRet; } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpStrNLen.c0000644000175000017500000000326313252530254022272 0ustar locutuslocutus/* $Id: kHlpStrNLen.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrNLen. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(KSIZE) kHlpStrNLen(const char *psz, KSIZE cchMax) { const char *pszEnd = psz; while (cchMax-- > 0 && *pszEnd) pszEnd++; return pszEnd - psz; } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpMemPSet.c0000644000175000017500000000413513252530254022256 0ustar locutuslocutus/* $Id: kHlpMemPSet.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpMemPSet. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(void *) kHlpMemPSet(void *pv1, int ch, KSIZE cb) { union { void *pv; KU8 *pb; KUPTR *pu; } u1; u1.pv = pv1; if (cb >= 32) { KUPTR u = ch & 0xff; #if K_ARCH_BITS > 8 u |= u << 8; #endif #if K_ARCH_BITS > 16 u |= u << 16; #endif #if K_ARCH_BITS > 32 u |= u << 32; #endif #if K_ARCH_BITS > 64 u |= u << 64; #endif while (cb > sizeof(KUPTR)) { cb -= sizeof(KUPTR); *u1.pu++ = u; } } while (cb-- > 0) *u1.pb++ = ch; return u1.pb; } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpStrNPComp.c0000644000175000017500000000350113252530254022565 0ustar locutuslocutus/* $Id: kHlpStrNPComp.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrNPComp. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(char *) kHlpStrNPComp(const char *psz1, const char *psz2, KSIZE cb) { while (cb-- > 0) { char ch1 = *psz1; char ch2 = *psz2; if (ch1 != ch2) return (char *)psz1; if (!ch1) break; psz1++; psz2++; } return NULL; } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpMemComp.c0000644000175000017500000000415013252530254022276 0ustar locutuslocutus/* $Id: kHlpMemComp.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpMemComp. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(int) kHlpMemComp(const void *pv1, const void *pv2, KSIZE cb) { union { const void *pv; const KU8 *pb; const KUPTR *pu; } u1, u2; u1.pv = pv1; u2.pv = pv2; if (cb >= 32) { while (cb > sizeof(KUPTR)) { cb -= sizeof(KUPTR); if (*u1.pu != *u2.pu) return *u1.pu > *u2.pu ? 1 : -1; u1.pu++; u2.pu++; } } while (cb-- > 0) { if (u1.pb != u2.pb) return u1.pb > u2.pb ? 1 : -1; u1.pb++; u2.pb++; } return 0; } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpStrRChr.c0000644000175000017500000000357213252530254022277 0ustar locutuslocutus/* $Id: kHlpStrRChr.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrRChr. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(char *) kHlpStrRChr(const char *psz, int ch) { char *pszLast; if (!ch) { while (*psz) psz++; return (char *)psz; } pszLast = NULL; for (;;) { int chCur = *psz; if (chCur == ch) pszLast = (char *)psz; else if (!chCur) return pszLast; psz++; } } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpStrPCopy.c0000644000175000017500000000325413252530254022470 0ustar locutuslocutus/* $Id: kHlpStrPCopy.c 83 2016-08-30 18:38:12Z bird $ */ /** @file * kHlpString - kHlpStrPCopy. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(char *) kHlpStrPCopy(char *pszDst, const char *pszSrc) { char ch; do *pszDst++ = ch = *pszSrc++; while (ch); return pszDst - 1; } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpStrNCat.c0000644000175000017500000000347613252530254022271 0ustar locutuslocutus/* $Id: kHlpStrNCat.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrNCat. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(char *) kHlpStrNCat(char *psz1, const char *psz2, KSIZE cb) { char ch; char *pszDst = psz1; while (*pszDst != '\0') pszDst++; while (cb-- > 0) { ch = *psz2++; if (!ch) break; *pszDst++ = ch; } *pszDst = '\0'; return psz1; } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpMemSet.c0000644000175000017500000000412713252530254022137 0ustar locutuslocutus/* $Id: kHlpMemSet.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpMemSet. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(void *) kHlpMemSet(void *pv1, int ch, KSIZE cb) { union { void *pv; KU8 *pb; KUPTR *pu; } u1; u1.pv = pv1; if (cb >= 32) { KUPTR u = ch & 0xff; #if K_ARCH_BITS > 8 u |= u << 8; #endif #if K_ARCH_BITS > 16 u |= u << 16; #endif #if K_ARCH_BITS > 32 u |= u << 32; #endif #if K_ARCH_BITS > 64 u |= u << 64; #endif while (cb > sizeof(KUPTR)) { cb -= sizeof(KUPTR); *u1.pu++ = u; } } while (cb-- > 0) *u1.pb++ = ch; return pv1; } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpStrLen.c0000644000175000017500000000322213252530254022147 0ustar locutuslocutus/* $Id: kHlpStrLen.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrLen. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(KSIZE) kHlpStrLen(const char *psz) { const char *pszEnd = psz; while (*pszEnd) pszEnd++; return pszEnd - psz; } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpStrCat.c0000644000175000017500000000337713252530254022153 0ustar locutuslocutus/* $Id: kHlpStrCat.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrCat. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(char *) kHlpStrCat(char *psz1, const char *psz2) { char ch; char *pszDst = psz1; while (*pszDst != '\0') pszDst++; do { ch = *psz2++; *pszDst++ = ch; } while (ch != '\0'); return psz1; } kbuild-3149/src/lib/kStuff/kHlp/Generic/kHlpStrICompAscii.c0000644000175000017500000000377313252530254023424 0ustar locutuslocutus/* $Id: kHlpStrICompAscii.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - kHlpStrICompAscii. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include KHLP_DECL(int) kHlpStrICompAscii(const char *psz1, const char *psz2) { for (;;) { char ch1 = *psz1; char ch2 = *psz2; if (ch1 != ch2) { if (ch1 <= 'Z' && ch1 >= 'A') ch1 += 'a' - 'A'; if (ch2 <= 'Z' && ch2 >= 'A') ch2 += 'a' - 'A'; if (ch1 != ch2) return ch1 > ch2 ? 1 : -1; } if (!ch1) return 0; psz1++; psz2++; } } kbuild-3149/src/lib/kStuff/kHlp/CRT/0000755000175000017500000000000013252530254017032 5ustar locutuslocutuskbuild-3149/src/lib/kStuff/kHlp/CRT/kHlpCRTAlloc.cpp0000644000175000017500000000421513252530254021762 0ustar locutuslocutus/* $Id: kHlpCRTAlloc.cpp 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpAlloc - Memory Allocation, CRT based implementation. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include KHLP_DECL(void *) kHlpAlloc(KSIZE cb) { return malloc(cb); } KHLP_DECL(void *) kHlpAllocZ(KSIZE cb) { return calloc(1, cb); } KHLP_DECL(void *) kHlpDup(const void *pv, KSIZE cb) { void *pvDup = kHlpAlloc(cb); if (pvDup) return memcpy(pvDup, pv, cb); return NULL; } KHLP_DECL(char *) kHlpStrDup(const char *psz) { size_t cb = strlen(psz) + 1; return (char *)kHlpDup(psz, cb); } KHLP_DECL(void *) kHlpRealloc(void *pv, KSIZE cb) { return realloc(pv, cb); } KHLP_DECL(void) kHlpFree(void *pv) { if (pv) free(pv); } kbuild-3149/src/lib/kStuff/kHlp/CRT/kHlpCRTString.cpp0000644000175000017500000000674613252530254022211 0ustar locutuslocutus/* $Id: kHlpCRTString.cpp 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - String And Memory Routines, CRT based implementation. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #ifndef kHlpMemChr void *kHlpMemChr(const void *pv, int ch, KSIZE cb) { return (void *)memchr(pv, ch, cb); } #endif #ifndef kHlpMemComp int kHlpMemComp(const void *pv1, const void *pv2, KSIZE cb) { return memcmp(pv1, pv2, cb); } #endif #ifndef kHlpMemCopy void *kHlpMemCopy(void *pv1, const void *pv2, KSIZE cb) { return memcpy(pv1, pv2, cb); } #endif #ifndef kHlpMemPCopy void *kHlpMemPCopy(void *pv1, const void *pv2, KSIZE cb) { return (KU8 *)memcpy(pv1, pv2, cb) + cb; } #endif #ifndef kHlpMemMove void *kHlpMemMove(void *pv1, const void *pv2, KSIZE cb) { return memmove(pv1, pv2, cb); } #endif #ifndef kHlpMemPMove void *kHlpMemPMove(void *pv1, const void *pv2, KSIZE cb) { return (KU8 *)memmove(pv1, pv2, cb) + cb; } #endif #ifndef kHlpMemSet void *kHlpMemSet(void *pv1, int ch, KSIZE cb) { return memset(pv1, ch, cb); } #endif #ifndef kHlpMemPSet void *kHlpMemPSet(void *pv1, int ch, KSIZE cb) { return (KU8 *)memset(pv1, ch, cb) + cb; } #endif #ifndef kHlpStrCat char *kHlpStrCat(char *psz1, const char *psz2) { return strcat(psz1, psz2); } #endif #ifndef kHlpStrNCat char *kHlpStrNCat(char *psz1, const char *psz2, KSIZE cb) { return strncat(psz1, psz2, cb); } #endif #ifndef kHlpStrChr char *kHlpStrChr(const char *psz, int ch) { return (char *)strchr(psz, ch); } #endif #ifndef kHlpStrRChr char *kHlpStrRChr(const char *psz, int ch) { return (char *)strrchr(psz, ch); } #endif #ifndef kHlpStrComp int kHlpStrComp(const char *psz1, const char *psz2) { return strcmp(psz1, psz2); } #endif #ifndef kHlpStrNComp int kHlpStrNComp(const char *psz1, const char *psz2, KSIZE cch) { return strncmp(psz1, psz2, cch); } #endif #ifndef kHlpStrCopy char *kHlpStrCopy(char *psz1, const char *psz2) { return strcpy(psz1, psz2); } #endif #ifndef kHlpStrLen KSIZE kHlpStrLen(const char *psz1) { return strlen(psz1); } #endif kbuild-3149/src/lib/kStuff/kHlp/CRT/kHlpCRTEnv.cpp0000644000175000017500000000376113252530254021465 0ustar locutuslocutus/* $Id: kHlpCRTEnv.cpp 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpEnv - Environment Manipulation. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #include KHLP_DECL(int) kHlpGetEnv(const char *pszVar, char *pszVal, KSIZE cchVal) { int rc = 0; const char *pszValue = getenv(pszVar); if (pszValue) { KSIZE cch = kHlpStrLen((const char *)pszValue); if (cchVal > cch) kHlpMemCopy(pszVal, pszValue, cch + 1); else rc = KERR_BUFFER_OVERFLOW; } else rc = KERR_ENVVAR_NOT_FOUND; return rc; } kbuild-3149/src/lib/kStuff/include/0000755000175000017500000000000013252530253017126 5ustar locutuslocutuskbuild-3149/src/lib/kStuff/include/k/0000755000175000017500000000000013252530253017360 5ustar locutuslocutuskbuild-3149/src/lib/kStuff/include/k/kHlpDefs.h0000644000175000017500000000335713252530253021241 0ustar locutuslocutus/* $Id: kHlpDefs.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpDefs - Helper Definitions. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___k_kHlpDefs_h___ #define ___k_kHlpDefs_h___ #include /** @defgroup grp_kHlpDefs - Definitions * @addtogroup grp_kHlp * @{ */ /** @def KHLP_DECL * Declares a kHlp function according to build context. * @param type The return type. */ #if defined(KHLP_BUILDING_DYNAMIC) # define KHLP_DECL(type) K_DECL_EXPORT(type) #elif defined(KHLP_BUILT_DYNAMIC) # define KHLP_DECL(type) K_DECL_IMPORT(type) #else # define KHLP_DECL(type) type #endif /** @} */ #endif kbuild-3149/src/lib/kStuff/include/k/kAvloU32.h0000644000175000017500000000503513252530253021102 0ustar locutuslocutus/* $Id: kAvloU32.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kAvl - AVL Tree Implementation, KU32 keys, Offset Based. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___k_kAvloU32_h___ #define ___k_kAvloU32_h___ typedef KI32 KAVLOU32PTR; typedef struct KAVLOU32 { KU32 u32; KU8 cFloorsToGo; KAVLOU32PTR offLeft; KAVLOU32PTR offRight; } KAVLOU32, *PKAVLOU32, **PPKAVLOU32; #define mKey u32 #define mHeight cFloorsToGo #define mpLeft offLeft #define mpRight offRight /*#define KAVL_EQUAL_ALLOWED*/ #define KAVL_CHECK_FOR_EQUAL_INSERT #define KAVL_MAX_STACK 32 /*#define KAVL_RANGE */ #define KAVL_OFFSET #define KAVL_STD_KEY_COMP #define KAVLKEY KU32 #define KAVLTREEPTR KAVLOU32PTR #define KAVLNODE KAVLOU32 #define KAVL_FN(name) kAvloU32 ## name #define KAVL_TYPE(prefix,name) prefix ## KAVLOU32 ## name #define KAVL_INT(name) KAVLOU32INT ## name #define KAVL_DECL(rettype) K_DECL_INLINE(rettype) #include #include #include #include #include #include #include #include #include #endif kbuild-3149/src/lib/kStuff/include/k/kAvlTmpl/0000755000175000017500000000000013252530253021112 5ustar locutuslocutuskbuild-3149/src/lib/kStuff/include/k/kAvlTmpl/kAvlBase.h0000644000175000017500000005440613252530253022764 0ustar locutuslocutus/* $Id: kAvlBase.h 36 2009-11-09 22:49:02Z bird $ */ /** @file * kAvlTmpl - Templated AVL Trees, The Mandatory Base Code. */ /* * Copyright (c) 2001-2009 Knut St. Osmundsen * * 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. */ /** @page pg_kAvlTmpl Template Configuration. * * This is a templated implementation of AVL trees in C. The template * parameters relates to the kind of key used and how duplicates are * treated. * * \#define KAVL_EQUAL_ALLOWED * Define this to tell us that equal keys are allowed. * Then Equal keys will be put in a list pointed to by KAVLNODE::pList. * This is by default not defined. * * \#define KAVL_CHECK_FOR_EQUAL_INSERT * Define this to enable insert check for equal nodes. * This is by default not defined. * * \#define KAVL_MAX_STACK * Use this to specify the max number of stack entries the stack will use when * inserting and removing nodes from the tree. The size should be something like * log2() + 3 * Must be defined. * * \#define KAVL_RANGE * Define this to enable key ranges. * * \#define KAVL_OFFSET * Define this to link the tree together using self relative offset * instead of memory pointers, thus making the entire tree relocatable * provided all the nodes - including the root node variable - are moved * the exact same distance. * * \#define KAVL_LOOKTHRU * Define this to employ a lookthru cache (direct) to speed up lookup for * some usage patterns. The value should be the number of members of the * array. * * \#define KAVL_LOOKTHRU_HASH(Key) * Define this to specify a more efficient translation of the key into * a lookthru array index. The default is key % size. * For some key types this is required as the default will not compile. * * \#define KAVL_LOCKED * Define this if you wish for the tree to be locked via the * KAVL_WRITE_LOCK, KAVL_WRITE_UNLOCK, KAVL_READ_LOCK and * KAVL_READ_UNLOCK macros. If not defined the tree will not be subject * do any kind of locking and the problem of concurrency is left the user. * * \#define KAVL_WRITE_LOCK(pRoot) * Lock the tree for writing. * * \#define KAVL_WRITE_UNLOCK(pRoot) * Counteracts KAVL_WRITE_LOCK. * * \#define KAVL_READ_LOCK(pRoot) * Lock the tree for reading. * * \#define KAVL_READ_UNLOCK(pRoot) * Counteracts KAVL_READ_LOCK. * * \#define KAVLKEY * Define this to the name of the AVL key type. * * \#define KAVL_STD_KEY_COMP * Define this to use the standard key compare macros. If not set all the * compare operations for KAVLKEY have to be defined: KAVL_G, KAVL_E, KAVL_NE, * KAVL_R_IS_IDENTICAL, KAVL_R_IS_INTERSECTING and KAVL_R_IS_IN_RANGE. The * latter three are only required when KAVL_RANGE is defined. * * \#define KAVLNODE * Define this to the name (typedef) of the AVL node structure. This * structure must have a mpLeft, mpRight, mKey and mHeight member. * If KAVL_RANGE is defined a mKeyLast is also required. * If KAVL_EQUAL_ALLOWED is defined a mpList member is required. * It's possible to use other member names by redefining the names. * * \#define KAVLTREEPTR * Define this to the name (typedef) of the tree pointer type. This is * required when KAVL_OFFSET is defined. When not defined it defaults * to KAVLNODE *. * * \#define KAVLROOT * Define this to the name (typedef) of the AVL root structure. This * is optional. However, if specified it must at least have a mpRoot * member of KAVLTREEPTR type. If KAVL_LOOKTHRU is non-zero a * maLookthru[KAVL_LOOKTHRU] member of the KAVLTREEPTR type is also * required. * * \#define KAVL_FN * Use this to alter the names of the AVL functions. * Must be defined. * * \#define KAVL_TYPE(prefix, name) * Use this to make external type names and unique. The prefix may be empty. * Must be defined. * * \#define KAVL_INT(name) * Use this to make internal type names and unique. The prefix may be empty. * Must be defined. * * \#define KAVL_DECL(rettype) * Function declaration macro that should be set according to the scope * the instantiated template should have. For instance an inlined scope * (private or public) should K_DECL_INLINE(rettype) here. * * This version of the kAVL tree offers the option of inlining the entire * implementation. This depends on the compiler doing a decent job in both * making use of the inlined code and to eliminate const variables. */ /******************************************************************************* * Internal Functions * *******************************************************************************/ #include #include #include /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ #define KAVL_HEIGHTOF(pNode) ((KU8)((pNode) != NULL ? (pNode)->mHeight : 0)) /** @def KAVL_GET_POINTER * Reads a 'pointer' value. * * @returns The native pointer. * @param pp Pointer to the pointer to read. * @internal */ /** @def KAVL_GET_POINTER_NULL * Reads a 'pointer' value which can be KAVL_NULL. * * @returns The native pointer. * @returns NULL pointer if KAVL_NULL. * @param pp Pointer to the pointer to read. * @internal */ /** @def KAVL_SET_POINTER * Writes a 'pointer' value. * For offset-based schemes offset relative to pp is calculated and assigned to *pp. * * @returns stored pointer. * @param pp Pointer to where to store the pointer. * @param p Native pointer to assign to *pp. * @internal */ /** @def KAVL_SET_POINTER_NULL * Writes a 'pointer' value which can be KAVL_NULL. * * For offset-based schemes offset relative to pp is calculated and assigned to *pp, * if p is not KAVL_NULL of course. * * @returns stored pointer. * @param pp Pointer to where to store the pointer. * @param pp2 Pointer to where to pointer to assign to pp. This can be KAVL_NULL * @internal */ #ifndef KAVLTREEPTR # define KAVLTREEPTR KAVLNODE * #endif #ifndef KAVLROOT # define KAVLROOT KAVL_TYPE(,ROOT) # define KAVL_NEED_KAVLROOT #endif #ifdef KAVL_LOOKTHRU # ifndef KAVL_LOOKTHRU_HASH # define KAVL_LOOKTHRU_HASH(Key) ( (Key) % (KAVL_LOOKTHRU) ) # endif #elif defined(KAVL_LOOKTHRU_HASH) # error "KAVL_LOOKTHRU_HASH without KAVL_LOOKTHRU!" #endif #ifdef KAVL_LOOKTHRU # define KAVL_LOOKTHRU_INVALIDATE_NODE(pRoot, pNode, Key) \ do { \ KAVLTREEPTR **ppEntry = &pRoot->maLookthru[KAVL_LOOKTHRU_HASH(Key)]; \ if ((pNode) == KAVL_GET_POINTER_NULL(ppEntry)) \ *ppEntry = KAVL_NULL; \ } while (0) #else # define KAVL_LOOKTHRU_INVALIDATE_NODE(pRoot, pNode, Key) do { } while (0) #endif #ifndef KAVL_LOCKED # define KAVL_WRITE_LOCK(pRoot) do { } while (0) # define KAVL_WRITE_UNLOCK(pRoot) do { } while (0) # define KAVL_READ_LOCK(pRoot) do { } while (0) # define KAVL_READ_UNLOCK(pRoot) do { } while (0) #endif #ifdef KAVL_OFFSET # define KAVL_GET_POINTER(pp) ( (KAVLNODE *)((KIPTR)(pp) + *(pp)) ) # define KAVL_GET_POINTER_NULL(pp) ( *(pp) != KAVL_NULL ? KAVL_GET_POINTER(pp) : NULL ) # define KAVL_SET_POINTER(pp, p) ( (*(pp)) = ((KIPTR)(p) - (KIPTR)(pp)) ) # define KAVL_SET_POINTER_NULL(pp, pp2) ( (*(pp)) = *(pp2) != KAVL_NULL ? (KIPTR)KAVL_GET_POINTER(pp2) - (KIPTR)(pp) : KAVL_NULL ) #else # define KAVL_GET_POINTER(pp) ( *(pp) ) # define KAVL_GET_POINTER_NULL(pp) ( *(pp) ) # define KAVL_SET_POINTER(pp, p) ( (*(pp)) = (p) ) # define KAVL_SET_POINTER_NULL(pp, pp2) ( (*(pp)) = *(pp2) ) #endif /** @def KAVL_NULL * The NULL 'pointer' equivalent. */ #ifdef KAVL_OFFSET # define KAVL_NULL 0 #else # define KAVL_NULL NULL #endif #ifdef KAVL_STD_KEY_COMP # define KAVL_G(key1, key2) ( (key1) > (key2) ) # define KAVL_E(key1, key2) ( (key1) == (key2) ) # define KAVL_NE(key1, key2) ( (key1) != (key2) ) # ifdef KAVL_RANGE # define KAVL_R_IS_IDENTICAL(key1B, key2B, key1E, key2E) ( (key1B) == (key2B) && (key1E) == (key2E) ) # define KAVL_R_IS_INTERSECTING(key1B, key2B, key1E, key2E) ( (key1B) <= (key2E) && (key1E) >= (key2B) ) # define KAVL_R_IS_IN_RANGE(key1B, key1E, key2) KAVL_R_IS_INTERSECTING(key1B, key2, key1E, key2) # endif #endif #ifndef KAVL_RANGE # define KAVL_R_IS_INTERSECTING(key1B, key2B, key1E, key2E) KAVL_E(key1B, key2B) # define KAVL_R_IS_IDENTICAL(key1B, key2B, key1E, key2E) KAVL_E(key1B, key2B) #endif /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * Stack used to avoid recursive calls during insert and removal. */ typedef struct { unsigned cEntries; KAVLTREEPTR *aEntries[KAVL_MAX_STACK]; } KAVL_INT(STACK); /** * The callback used by the Destroy and DoWithAll functions. */ typedef int (* KAVL_TYPE(PFN,CALLBACK))(KAVLNODE *, void *); #ifdef KAVL_NEED_KAVLROOT /** * The AVL root structure. */ typedef struct { KAVLTREEPTR mpRoot; # ifdef KAVL_LOOKTHRU KAVLTREEPTR maLookthru[KAVL_LOOKTHRU]; # endif } KAVLROOT; #endif /** * Rewinds a stack of node pointer pointers, rebalancing the tree. * * @param pStack Pointer to stack to rewind. * @sketch LOOP thru all stack entries * BEGIN * Get pointer to pointer to node (and pointer to node) from the stack. * IF 2 higher left subtree than in right subtree THEN * BEGIN * IF higher (or equal) left-sub-subtree than right-sub-subtree THEN * * n+2|n+3 * / \ / \ * n+2 n ==> n+1 n+1|n+2 * / \ / \ * n+1 n|n+1 n|n+1 n * * Or with keys: * * 4 2 * / \ / \ * 2 5 ==> 1 4 * / \ / \ * 1 3 3 5 * * ELSE * * n+2 * / \ / \ * n+2 n n+1 n+1 * / \ ==> / \ / \ * n n+1 n L R n * / \ * L R * * Or with keys: * 6 4 * / \ / \ * 2 7 ==> 2 6 * / \ / \ / \ * 1 4 1 3 5 7 * / \ * 3 5 * END * ELSE IF 2 higher in right subtree than in left subtree THEN * BEGIN * Same as above but left <==> right. (invert the picture) * ELSE * IF correct height THEN break * ELSE correct height. * END */ K_DECL_INLINE(void) KAVL_FN(Rebalance)(KAVL_INT(STACK) *pStack) { while (pStack->cEntries > 0) { KAVLTREEPTR *ppNode = pStack->aEntries[--pStack->cEntries]; KAVLNODE *pNode = KAVL_GET_POINTER(ppNode); KAVLNODE *pLeftNode = KAVL_GET_POINTER_NULL(&pNode->mpLeft); KU8 uLeftHeight = KAVL_HEIGHTOF(pLeftNode); KAVLNODE *pRightNode = KAVL_GET_POINTER_NULL(&pNode->mpRight); KU8 uRightHeight = KAVL_HEIGHTOF(pRightNode); if (uRightHeight + 1 < uLeftHeight) { KAVLNODE *pLeftLeftNode = KAVL_GET_POINTER_NULL(&pLeftNode->mpLeft); KAVLNODE *pLeftRightNode = KAVL_GET_POINTER_NULL(&pLeftNode->mpRight); KU8 uLeftRightHeight = KAVL_HEIGHTOF(pLeftRightNode); if (KAVL_HEIGHTOF(pLeftLeftNode) >= uLeftRightHeight) { KAVL_SET_POINTER_NULL(&pNode->mpLeft, &pLeftNode->mpRight); KAVL_SET_POINTER(&pLeftNode->mpRight, pNode); pLeftNode->mHeight = (KU8)(1 + (pNode->mHeight = (KU8)(1 + uLeftRightHeight))); KAVL_SET_POINTER(ppNode, pLeftNode); } else { KAVL_SET_POINTER_NULL(&pLeftNode->mpRight, &pLeftRightNode->mpLeft); KAVL_SET_POINTER_NULL(&pNode->mpLeft, &pLeftRightNode->mpRight); KAVL_SET_POINTER(&pLeftRightNode->mpLeft, pLeftNode); KAVL_SET_POINTER(&pLeftRightNode->mpRight, pNode); pLeftNode->mHeight = pNode->mHeight = uLeftRightHeight; pLeftRightNode->mHeight = uLeftHeight; KAVL_SET_POINTER(ppNode, pLeftRightNode); } } else if (uLeftHeight + 1 < uRightHeight) { KAVLNODE *pRightLeftNode = KAVL_GET_POINTER_NULL(&pRightNode->mpLeft); KU8 uRightLeftHeight = KAVL_HEIGHTOF(pRightLeftNode); KAVLNODE *pRightRightNode = KAVL_GET_POINTER_NULL(&pRightNode->mpRight); if (KAVL_HEIGHTOF(pRightRightNode) >= uRightLeftHeight) { KAVL_SET_POINTER_NULL(&pNode->mpRight, &pRightNode->mpLeft); KAVL_SET_POINTER(&pRightNode->mpLeft, pNode); pRightNode->mHeight = (KU8)(1 + (pNode->mHeight = (KU8)(1 + uRightLeftHeight))); KAVL_SET_POINTER(ppNode, pRightNode); } else { KAVL_SET_POINTER_NULL(&pRightNode->mpLeft, &pRightLeftNode->mpRight); KAVL_SET_POINTER_NULL(&pNode->mpRight, &pRightLeftNode->mpLeft); KAVL_SET_POINTER(&pRightLeftNode->mpRight, pRightNode); KAVL_SET_POINTER(&pRightLeftNode->mpLeft, pNode); pRightNode->mHeight = pNode->mHeight = uRightLeftHeight; pRightLeftNode->mHeight = uRightHeight; KAVL_SET_POINTER(ppNode, pRightLeftNode); } } else { KU8 uHeight = (KU8)(K_MAX(uLeftHeight, uRightHeight) + 1); if (uHeight == pNode->mHeight) break; pNode->mHeight = uHeight; } } } /** * Initializes the root of the AVL-tree. * * @param pTree Pointer to the root structure. */ KAVL_DECL(void) KAVL_FN(Init)(KAVLROOT *pRoot) { #ifdef KAVL_LOOKTHRU unsigned i; #endif pRoot->mpRoot = KAVL_NULL; #ifdef KAVL_LOOKTHRU for (i = 0; i < (KAVL_LOOKTHRU); i++) pRoot->maLookthru[i] = KAVL_NULL; #endif } /** * Inserts a node into the AVL-tree. * @returns K_TRUE if inserted. * K_FALSE if node exists in tree. * @param pRoot Pointer to the AVL-tree root structure. * @param pNode Pointer to the node which is to be added. * @sketch Find the location of the node (using binary tree algorithm.): * LOOP until NULL leaf pointer * BEGIN * Add node pointer pointer to the AVL-stack. * IF new-node-key < node key THEN * left * ELSE * right * END * Fill in leaf node and insert it. * Rebalance the tree. */ KAVL_DECL(KBOOL) KAVL_FN(Insert)(KAVLROOT *pRoot, KAVLNODE *pNode) { KAVL_INT(STACK) AVLStack; KAVLTREEPTR *ppCurNode = &pRoot->mpRoot; register KAVLKEY Key = pNode->mKey; #ifdef KAVL_RANGE register KAVLKEY KeyLast = pNode->mKeyLast; #endif #ifdef KAVL_RANGE if (Key > KeyLast) return K_FALSE; #endif KAVL_WRITE_LOCK(pRoot); AVLStack.cEntries = 0; while (*ppCurNode != KAVL_NULL) { register KAVLNODE *pCurNode = KAVL_GET_POINTER(ppCurNode); kHlpAssert(AVLStack.cEntries < KAVL_MAX_STACK); AVLStack.aEntries[AVLStack.cEntries++] = ppCurNode; #ifdef KAVL_EQUAL_ALLOWED if (KAVL_R_IS_IDENTICAL(pCurNode->mKey, Key, pCurNode->mKeyLast, KeyLast)) { /* * If equal then we'll use a list of equal nodes. */ pNode->mpLeft = pNode->mpRight = KAVL_NULL; pNode->mHeight = 0; KAVL_SET_POINTER_NULL(&pNode->mpList, &pCurNode->mpList); KAVL_SET_POINTER(&pCurNode->mpList, pNode); KAVL_WRITE_UNLOCK(pRoot); return K_TRUE; } #endif #ifdef KAVL_CHECK_FOR_EQUAL_INSERT if (KAVL_R_IS_INTERSECTING(pCurNode->mKey, Key, pCurNode->mKeyLast, KeyLast)) { KAVL_WRITE_UNLOCK(pRoot); return K_FALSE; } #endif if (KAVL_G(pCurNode->mKey, Key)) ppCurNode = &pCurNode->mpLeft; else ppCurNode = &pCurNode->mpRight; } pNode->mpLeft = pNode->mpRight = KAVL_NULL; #ifdef KAVL_EQUAL_ALLOWED pNode->mpList = KAVL_NULL; #endif pNode->mHeight = 1; KAVL_SET_POINTER(ppCurNode, pNode); KAVL_FN(Rebalance)(&AVLStack); KAVL_WRITE_UNLOCK(pRoot); return K_TRUE; } /** * Removes a node from the AVL-tree. * @returns Pointer to the node. * @param pRoot Pointer to the AVL-tree root structure. * @param Key Key value of the node which is to be removed. * @sketch Find the node which is to be removed: * LOOP until not found * BEGIN * Add node pointer pointer to the AVL-stack. * IF the keys matches THEN break! * IF remove key < node key THEN * left * ELSE * right * END * IF found THEN * BEGIN * IF left node not empty THEN * BEGIN * Find the right most node in the left tree while adding the pointer to the pointer to it's parent to the stack: * Start at left node. * LOOP until right node is empty * BEGIN * Add to stack. * go right. * END * Link out the found node. * Replace the node which is to be removed with the found node. * Correct the stack entry for the pointer to the left tree. * END * ELSE * BEGIN * Move up right node. * Remove last stack entry. * END * Balance tree using stack. * END * return pointer to the removed node (if found). */ KAVL_DECL(KAVLNODE *) KAVL_FN(Remove)(KAVLROOT *pRoot, KAVLKEY Key) { KAVL_INT(STACK) AVLStack; KAVLTREEPTR *ppDeleteNode = &pRoot->mpRoot; register KAVLNODE *pDeleteNode; KAVL_WRITE_LOCK(pRoot); AVLStack.cEntries = 0; for (;;) { if (*ppDeleteNode == KAVL_NULL) { KAVL_WRITE_UNLOCK(pRoot); return NULL; } pDeleteNode = KAVL_GET_POINTER(ppDeleteNode); kHlpAssert(AVLStack.cEntries < KAVL_MAX_STACK); AVLStack.aEntries[AVLStack.cEntries++] = ppDeleteNode; if (KAVL_E(pDeleteNode->mKey, Key)) break; if (KAVL_G(pDeleteNode->mKey, Key)) ppDeleteNode = &pDeleteNode->mpLeft; else ppDeleteNode = &pDeleteNode->mpRight; } if (pDeleteNode->mpLeft != KAVL_NULL) { /* find the rightmost node in the left tree. */ const unsigned iStackEntry = AVLStack.cEntries; KAVLTREEPTR *ppLeftLeast = &pDeleteNode->mpLeft; register KAVLNODE *pLeftLeast = KAVL_GET_POINTER(ppLeftLeast); while (pLeftLeast->mpRight != KAVL_NULL) { kHlpAssert(AVLStack.cEntries < KAVL_MAX_STACK); AVLStack.aEntries[AVLStack.cEntries++] = ppLeftLeast; ppLeftLeast = &pLeftLeast->mpRight; pLeftLeast = KAVL_GET_POINTER(ppLeftLeast); } /* link out pLeftLeast */ KAVL_SET_POINTER_NULL(ppLeftLeast, &pLeftLeast->mpLeft); /* link it in place of the delete node. */ KAVL_SET_POINTER_NULL(&pLeftLeast->mpLeft, &pDeleteNode->mpLeft); KAVL_SET_POINTER_NULL(&pLeftLeast->mpRight, &pDeleteNode->mpRight); pLeftLeast->mHeight = pDeleteNode->mHeight; KAVL_SET_POINTER(ppDeleteNode, pLeftLeast); AVLStack.aEntries[iStackEntry] = &pLeftLeast->mpLeft; } else { KAVL_SET_POINTER_NULL(ppDeleteNode, &pDeleteNode->mpRight); AVLStack.cEntries--; } KAVL_FN(Rebalance)(&AVLStack); KAVL_LOOKTHRU_INVALIDATE_NODE(pRoot, pDeleteNode, Key); KAVL_WRITE_UNLOCK(pRoot); return pDeleteNode; } kbuild-3149/src/lib/kStuff/include/k/kAvlTmpl/kAvlGetBestFit.h0000644000175000017500000000740313252530253024105 0ustar locutuslocutus/* $Id: kAvlGetBestFit.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kAvlTmpl - Templated AVL Trees, Get Best Fitting Node. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * 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. */ /** * Finds the best fitting node in the tree for the given Key value. * * @returns Pointer to the best fitting node found. * @param pRoot Pointer to the AVL-tree root structure. * @param Key The Key of which is to be found a best fitting match for.. * @param fAbove K_TRUE: Returned node is have the closest key to Key from above. * K_FALSE: Returned node is have the closest key to Key from below. * @sketch The best fitting node is always located in the searchpath above you. * >= (above): The node where you last turned left. * <= (below): the node where you last turned right. */ KAVL_DECL(KAVLNODE *) KAVL_FN(GetBestFit)(KAVLROOT *pRoot, KAVLKEY Key, KBOOL fAbove) { register KAVLNODE *pNode; KAVLNODE *pNodeLast; KAVL_READ_LOCK(pLook); if (pRoot->mpRoot == KAVL_NULL) { KAVL_READ_UNLOCK(pLook); return NULL; } pNode = KAVL_GET_POINTER(&pRoot->mpRoot); pNodeLast = NULL; if (fAbove) { /* pNode->mKey >= Key */ while (KAVL_NE(pNode->mKey, Key)) { if (KAVL_G(pNode->mKey, Key)) { if (pNode->mpLeft == KAVL_NULL) { KAVL_READ_UNLOCK(pLook); return pNode; } pNodeLast = pNode; pNode = KAVL_GET_POINTER(&pNode->mpLeft); } else { if (pNode->mpRight == KAVL_NULL) { KAVL_READ_UNLOCK(pLook); return pNodeLast; } pNode = KAVL_GET_POINTER(&pNode->mpRight); } } } else { /* pNode->mKey <= Key */ while (KAVL_NE(pNode->mKey, Key)) { if (KAVL_G(pNode->mKey, Key)) { if (pNode->mpLeft == KAVL_NULL) { KAVL_READ_UNLOCK(pLook); return pNodeLast; } pNode = KAVL_GET_POINTER(&pNode->mpLeft); } else { if (pNode->mpRight == KAVL_NULL) { KAVL_READ_UNLOCK(pLook); return pNode; } pNodeLast = pNode; pNode = KAVL_GET_POINTER(&pNode->mpRight); } } } /* perfect match or nothing. */ KAVL_READ_UNLOCK(pLook); return pNode; } kbuild-3149/src/lib/kStuff/include/k/kAvlTmpl/kAvlDestroy.h0000644000175000017500000001033513252530253023534 0ustar locutuslocutus/* $Id: kAvlDestroy.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kAvlTmpl - Templated AVL Trees, Destroy the tree. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * 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. */ /** * Destroys the specified tree, starting with the root node and working our way down. * * @returns 0 on success. * @returns Return value from callback on failure. On failure, the tree will be in * an unbalanced condition and only further calls to the Destroy should be * made on it. Note that the node we fail on will be considered dead and * no action is taken to link it back into the tree. * @param pRoot Pointer to the AVL-tree root structure. * @param pfnCallBack Pointer to callback function. * @param pvUser User parameter passed on to the callback function. */ KAVL_DECL(int) KAVL_FN(Destroy)(KAVLROOT *pRoot, KAVL_TYPE(PFN,CALLBACK) pfnCallBack, void *pvUser) { #ifdef KAVL_LOOKTHRU unsigned i; #endif unsigned cEntries; KAVLNODE *apEntries[KAVL_MAX_STACK]; int rc; KAVL_WRITE_LOCK(pRoot); if (pRoot->mpRoot == KAVL_NULL) { KAVL_WRITE_UNLOCK(pRoot); return 0; } #ifdef KAVL_LOOKTHRU /* * Kill the lookthru cache. */ for (i = 0; i < (KAVL_LOOKTHRU); i++) pRoot->maLookthru[i] = KAVL_NULL; #endif cEntries = 1; apEntries[0] = KAVL_GET_POINTER(&pRoot->mpRoot); while (cEntries > 0) { /* * Process the subtrees first. */ KAVLNODE *pNode = apEntries[cEntries - 1]; if (pNode->mpLeft != KAVL_NULL) apEntries[cEntries++] = KAVL_GET_POINTER(&pNode->mpLeft); else if (pNode->mpRight != KAVL_NULL) apEntries[cEntries++] = KAVL_GET_POINTER(&pNode->mpRight); else { #ifdef KAVL_EQUAL_ALLOWED /* * Process nodes with the same key. */ while (pNode->pList != KAVL_NULL) { KAVLNODE *pEqual = KAVL_GET_POINTER(&pNode->pList); KAVL_SET_POINTER(&pNode->pList, KAVL_GET_POINTER_NULL(&pEqual->pList)); pEqual->pList = KAVL_NULL; rc = pfnCallBack(pEqual, pvUser); if (rc) { KAVL_WRITE_UNLOCK(pRoot); return rc; } } #endif /* * Unlink the node. */ if (--cEntries > 0) { KAVLNODE *pParent = apEntries[cEntries - 1]; if (KAVL_GET_POINTER(&pParent->mpLeft) == pNode) pParent->mpLeft = KAVL_NULL; else pParent->mpRight = KAVL_NULL; } else pRoot->mpRoot = KAVL_NULL; kHlpAssert(pNode->mpLeft == KAVL_NULL); kHlpAssert(pNode->mpRight == KAVL_NULL); rc = pfnCallBack(pNode, pvUser); if (rc) { KAVL_WRITE_UNLOCK(pRoot); return rc; } } } /* while */ kHlpAssert(pRoot->mpRoot == KAVL_NULL); KAVL_WRITE_UNLOCK(pRoot); return 0; } kbuild-3149/src/lib/kStuff/include/k/kAvlTmpl/kAvlUndef.h0000644000175000017500000000421013252530253023137 0ustar locutuslocutus/* $Id: kAvlUndef.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kAvlTmpl - Undefines All Macros (both config and temp). */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /* * The configuration. */ #undef KAVL_EQUAL_ALLOWED #undef KAVL_CHECK_FOR_EQUAL_INSERT #undef KAVL_MAX_STACK #undef KAVL_RANGE #undef KAVL_OFFSET #undef KAVL_STD_KEY_COMP #undef KAVL_LOOKTHRU #undef KAVL_LOOKTHRU_HASH #undef KAVL_LOCKED #undef KAVL_WRITE_LOCK #undef KAVL_WRITE_UNLOCK #undef KAVL_READ_LOCK #undef KAVL_READ_UNLOCK #undef KAVLKEY #undef KAVLNODE #undef KAVLTREEPTR #undef KAVLROOT #undef KAVL_FN #undef KAVL_TYPE #undef KAVL_INT #undef KAVL_DECL #undef mKey #undef mKeyLast #undef mHeight #undef mpLeft #undef mpRight #undef mpList #undef mpRoot #undef maLookthru /* * The internal macros. */ #undef KAVL_HEIGHTOF #undef KAVL_GET_POINTER #undef KAVL_GET_POINTER_NULL #undef KAVL_SET_POINTER #undef KAVL_SET_POINTER_NULL #undef KAVL_NULL #undef KAVL_G #undef KAVL_E #undef KAVL_NE #undef KAVL_R_IS_IDENTICAL #undef KAVL_R_IS_INTERSECTING #undef KAVL_R_IS_IN_RANGE kbuild-3149/src/lib/kStuff/include/k/kAvlTmpl/kAvlGetWithParent.h0000644000175000017500000000454013252530253024631 0ustar locutuslocutus/* $Id: kAvlGetWithParent.h 34 2009-11-08 19:38:40Z bird $ */ /** @file * kAvlTmpl - Templated AVL Trees, Get Node With Parent. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * 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. */ /** * Gets a node from the tree and its parent node (if any). * The tree remains unchanged. * * @returns Pointer to the node holding the given key. * @param pRoot Pointer to the AVL-tree root structure. * @param ppParent Pointer to a variable which will hold the pointer to the partent node on * return. When no node is found, this will hold the last searched node. * @param Key Key value of the node which is to be found. */ KAVL_DECL(KAVLNODE *) KAVL_FN(GetWithParent)(KAVLROOT *pRoot, KAVLNODE **ppParent, KAVLKEY Key) { register KAVLNODE *pNode; register KAVLNODE *pParent; KAVL_READ_LOCK(pRoot); pParent = NULL; pNode = KAVL_GET_POINTER_NULL(&pRoot->mpRoot); while ( pNode != NULL && KAVL_NE(pNode->mKey, Key)) { pParent = pNode; if (KAVL_G(pNode->mKey, Key)) pNode = KAVL_GET_POINTER_NULL(&pNode->mpLeft); else pNode = KAVL_GET_POINTER_NULL(&pNode->mpRight); } KAVL_READ_UNLOCK(pRoot); *ppParent = pParent; return pNode; } kbuild-3149/src/lib/kStuff/include/k/kAvlTmpl/kAvlRemoveBestFit.h0000644000175000017500000000561713252530253024630 0ustar locutuslocutus/* $Id: kAvlRemoveBestFit.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kAvlTmpl - Templated AVL Trees, Remove Best Fitting Node. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * 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. */ /** * Finds the best fitting node in the tree for the given Key value and removes the node. * * @returns Pointer to the removed node. * @param pRoot Pointer to the AVL-tree root structure. * @param Key The Key of which is to be found a best fitting match for.. * @param fAbove K_TRUE: Returned node is have the closest key to Key from above. * K_FALSE: Returned node is have the closest key to Key from below. * * @remark This implementation uses GetBestFit and then Remove and might therefore * not be the most optimal kind of implementation, but it reduces the complexity * code size, and the likelyhood for bugs. */ KAVL_DECL(KAVLNODE *) KAVL_FN(RemoveBestFit)(KAVLROOT *pRoot, KAVLKEY Key, KBOOL fAbove) { /* * If we find anything we'll have to remove the node and return it. * Now, if duplicate keys are allowed we'll remove a duplicate before * removing the in-tree node as this is way cheaper. */ KAVLNODE *pNode = KAVL_FN(GetBestFit)(pRoot, Key, fAbove); if (pNode != NULL) { #ifdef KAVL_EQUAL_ALLOWED KAVL_WRITE_LOCK(pRoot); /** @todo the locking isn't quite sane here. :-/ */ if (pNode->mpList != KAVL_NULL) { KAVLNODE *pRet = KAVL_GET_POINTER(&pNode->mpList); KAVL_SET_POINTER_NULL(&pNode->mpList, &pRet->mpList); KAVL_LOOKTHRU_INVALIDATE_NODE(pRoot, pNode, pNode->mKey); KAVL_WRITE_UNLOCK(pRoot); return pRet; } KAVL_WRITE_UNLOCK(pRoot); #endif pNode = KAVL_FN(Remove)(pRoot, pNode->mKey); } return pNode; } kbuild-3149/src/lib/kStuff/include/k/kAvlTmpl/kAvlEnum.h0000644000175000017500000001461213252530253023011 0ustar locutuslocutus/* $Id: kAvlEnum.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kAvlTmpl - Templated AVL Trees, Node Enumeration. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * Enumeration control data. * * This is initialized by BeginEnum and used by GetNext to figure out what * to do next. */ typedef struct KAVL_TYPE(,ENUMDATA) { KBOOL fFromLeft; KI8 cEntries; KU8 achFlags[KAVL_MAX_STACK]; KAVLNODE * aEntries[KAVL_MAX_STACK]; } KAVL_TYPE(,ENUMDATA), *KAVL_TYPE(P,ENUMDATA); /** * Ends an enumeration. * * The purpose of this function is to unlock the tree should the * AVL implementation include locking. It's good practice to call * it anyway even if the tree doesn't do any locking. * * @param pEnumData Pointer to enumeration control data. */ KAVL_DECL(void) KAVL_FN(EndEnum)(KAVL_TYPE(,ENUMDATA) *pEnumData) { KAVLROOT pRoot = pEnumData->pRoot; pEnumData->pRoot = NULL; if (pRoot) KAVL_READ_UNLOCK(pEnumData->pRoot); } /** * Get the next node in the tree enumeration. * * The current implementation of this function willl not walk the mpList * chain like the DoWithAll function does. This may be changed later. * * @returns Pointer to the next node in the tree. * NULL is returned when the end of the tree has been reached, * it is not necessary to call EndEnum in this case. * @param pEnumData Pointer to enumeration control data. */ KAVL_DECL(KAVLNODE *) KAVL_FN(GetNext)(KAVL_TYPE(,ENUMDATA) *pEnumData) { if (pEnumData->fFromLeft) { /* from left */ while (pEnumData->cEntries > 0) { KAVLNODE *pNode = pEnumData->aEntries[pEnumData->cEntries - 1]; /* left */ if (pEnumData->achFlags[pEnumData->cEntries - 1] == 0) { pEnumData->achFlags[pEnumData->cEntries - 1]++; if (pNode->mpLeft != KAVL_NULL) { pEnumData->achFlags[pEnumData->cEntries] = 0; /* 0 left, 1 center, 2 right */ pEnumData->aEntries[pEnumData->cEntries++] = KAVL_GET_POINTER(&pNode->mpLeft); continue; } } /* center */ if (pEnumData->achFlags[pEnumData->cEntries - 1] == 1) { pEnumData->achFlags[pEnumData->cEntries - 1]++; return pNode; } /* right */ pEnumData->cEntries--; if (pNode->mpRight != KAVL_NULL) { pEnumData->achFlags[pEnumData->cEntries] = 0; pEnumData->aEntries[pEnumData->cEntries++] = KAVL_GET_POINTER(&pNode->mpRight); } } /* while */ } else { /* from right */ while (pEnumData->cEntries > 0) { KAVLNODE *pNode = pEnumData->aEntries[pEnumData->cEntries - 1]; /* right */ if (pEnumData->achFlags[pEnumData->cEntries - 1] == 0) { pEnumData->achFlags[pEnumData->cEntries - 1]++; if (pNode->mpRight != KAVL_NULL) { pEnumData->achFlags[pEnumData->cEntries] = 0; /* 0 right, 1 center, 2 left */ pEnumData->aEntries[pEnumData->cEntries++] = KAVL_GET_POINTER(&pNode->mpRight); continue; } } /* center */ if (pEnumData->achFlags[pEnumData->cEntries - 1] == 1) { pEnumData->achFlags[pEnumData->cEntries - 1]++; return pNode; } /* left */ pEnumData->cEntries--; if (pNode->mpLeft != KAVL_NULL) { pEnumData->achFlags[pEnumData->cEntries] = 0; pEnumData->aEntries[pEnumData->cEntries++] = KAVL_GET_POINTER(&pNode->mpLeft); } } /* while */ } /* * Call EndEnum. */ KAVL_FN(EndEnum)(pEnumData); return NULL; } /** * Starts an enumeration of all nodes in the given AVL tree. * * The current implementation of this function will not walk the mpList * chain like the DoWithAll function does. This may be changed later. * * @returns Pointer to the first node in the enumeration. * If NULL is returned the tree is empty calling EndEnum isn't * strictly necessary (although it will do no harm). * @param pRoot Pointer to the AVL-tree root structure. * @param pEnumData Pointer to enumeration control data. * @param fFromLeft K_TRUE: Left to right. * K_FALSE: Right to left. */ KAVL_DECL(KAVLNODE *) KAVL_FN(BeginEnum)(KAVLROOT *pRoot, KAVL_TYPE(,ENUMDATA) *pEnumData, KBOOL fFromLeft) { KAVL_READ_LOCK(pRoot); pEnumData->pRoot = pRoot; if (pRoot->mpRoot != KAVL_NULL) { pEnumData->fFromLeft = fFromLeft; pEnumData->cEntries = 1; pEnumData->aEntries[0] = KAVL_GET_POINTER(pRoot->mpRoot); pEnumData->achFlags[0] = 0; } else pEnumData->cEntries = 0; return KAVL_FN(GetNext)(pEnumData); } kbuild-3149/src/lib/kStuff/include/k/kAvlTmpl/kAvlGet.h0000644000175000017500000000536313252530253022627 0ustar locutuslocutus/* $Id: kAvlGet.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kAvlTmpl - Templated AVL Trees, Get a Node. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * 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. */ /** * Gets a node from the tree (does not remove it!) * * @returns Pointer to the node holding the given key. * @param pRoot Pointer to the AVL-tree root structure. * @param Key Key value of the node which is to be found. */ KAVL_DECL(KAVLNODE *) KAVL_FN(Get)(KAVLROOT *pRoot, KAVLKEY Key) { KAVLNODE *pNode; #ifdef KAVL_LOOKTHRU_CACHE KAVLTREEPTR *ppEntry; #endif KAVL_READ_LOCK(pRoot); if (pRoot->mpRoot == KAVL_NULL) { KAVL_READ_UNLOCK(pRoot); return NULL; } #ifdef KAVL_LOOKTHRU_CACHE ppEntry = &pRoot->maLookthru[KAVL_LOOKTHRU_HASH(Key)]; pNode = KAVL_GET_POINTER_NULL(ppEntry); if (!pNode || KAVL_NE(pNode->mKey, Key)) #endif { pNode = KAVL_GET_POINTER(&pRoot->mpRoot); while (KAVL_NE(pNode->mKey, Key)) { if (KAVL_G(pNode->mKey, Key)) { if (pNode->mpLeft == KAVL_NULL) { KAVL_READ_UNLOCK(pRoot); return NULL; } pNode = KAVL_GET_POINTER(&pNode->mpLeft); } else { if (pNode->mpRight == KAVL_NULL) { KAVL_READ_UNLOCK(pRoot); return NULL; } pNode = KAVL_GET_POINTER(&pNode->mpRight); } } #ifdef KAVL_LOOKTHRU_CACHE KAVL_SET_POINTER(ppEntry, pNode); #endif } KAVL_READ_UNLOCK(pRoot); return pNode; } kbuild-3149/src/lib/kStuff/include/k/kAvlTmpl/kAvlDoWithAll.h0000644000175000017500000001301713252530253023732 0ustar locutuslocutus/* $Id: kAvlDoWithAll.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kAvlTmpl - Templated AVL Trees, The Callback Iterator. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * Stack used by DoWithAll to avoid recusive function calls. */ typedef struct { unsigned cEntries; KAVLNODE *aEntries[KAVL_MAX_STACK]; char achFlags[KAVL_MAX_STACK]; KAVLROOT pRoot; } KAVL_INT(STACK2); /** * Iterates thru all nodes in the given tree. * * @returns 0 on success. Return from callback on failure. * @param pRoot Pointer to the AVL-tree root structure. * @param fFromLeft K_TRUE: Left to right. * K_FALSE: Right to left. * @param pfnCallBack Pointer to callback function. * @param pvUser User parameter passed on to the callback function. */ KAVL_DECL(int) KAVL_FN(DoWithAll)(KAVLROOT *pRoot, KBOOL fFromLeft, KAVL_TYPE(PFN,CALLBACK) pfnCallBack, void *pvUser) { KAVL_INT(STACK2) AVLStack; KAVLNODE *pNode; #ifdef KAVL_EQUAL_ALLOWED KAVLNODE *pEqual; #endif int rc; KAVL_READ_LOCK(pRoot); if (pRoot->mpRoot == KAVL_NULL) { KAVL_READ_UNLOCK(pRoot); return 0; } AVLStack.cEntries = 1; AVLStack.achFlags[0] = 0; AVLStack.aEntries[0] = KAVL_GET_POINTER(&pRoot->mpRoot); if (fFromLeft) { /* from left */ while (AVLStack.cEntries > 0) { pNode = AVLStack.aEntries[AVLStack.cEntries - 1]; /* left */ if (!AVLStack.achFlags[AVLStack.cEntries - 1]++) { if (pNode->mpLeft != KAVL_NULL) { AVLStack.achFlags[AVLStack.cEntries] = 0; /* 0 first, 1 last */ AVLStack.aEntries[AVLStack.cEntries++] = KAVL_GET_POINTER(&pNode->mpLeft); continue; } } /* center */ rc = pfnCallBack(pNode, pvUser); if (rc) return rc; #ifdef KAVL_EQUAL_ALLOWED if (pNode->mpList != KAVL_NULL) for (pEqual = KAVL_GET_POINTER(&pNode->mpList); pEqual; pEqual = KAVL_GET_POINTER_NULL(&pEqual->mpList)) { rc = pfnCallBack(pEqual, pvUser); if (rc) { KAVL_READ_UNLOCK(pRoot); return rc; } } #endif /* right */ AVLStack.cEntries--; if (pNode->mpRight != KAVL_NULL) { AVLStack.achFlags[AVLStack.cEntries] = 0; AVLStack.aEntries[AVLStack.cEntries++] = KAVL_GET_POINTER(&pNode->mpRight); } } /* while */ } else { /* from right */ while (AVLStack.cEntries > 0) { pNode = AVLStack.aEntries[AVLStack.cEntries - 1]; /* right */ if (!AVLStack.achFlags[AVLStack.cEntries - 1]++) { if (pNode->mpRight != KAVL_NULL) { AVLStack.achFlags[AVLStack.cEntries] = 0; /* 0 first, 1 last */ AVLStack.aEntries[AVLStack.cEntries++] = KAVL_GET_POINTER(&pNode->mpRight); continue; } } /* center */ rc = pfnCallBack(pNode, pvUser); if (rc) return rc; #ifdef KAVL_EQUAL_ALLOWED if (pNode->mpList != KAVL_NULL) for (pEqual = KAVL_GET_POINTER(&pNode->mpList); pEqual; pEqual = KAVL_GET_POINTER_NULL(&pEqual->pList)) { rc = pfnCallBack(pEqual, pvUser); if (rc) { KAVL_READ_UNLOCK(pRoot); return rc; } } #endif /* left */ AVLStack.cEntries--; if (pNode->mpLeft != KAVL_NULL) { AVLStack.achFlags[AVLStack.cEntries] = 0; AVLStack.aEntries[AVLStack.cEntries++] = KAVL_GET_POINTER(&pNode->mpLeft); } } /* while */ } KAVL_READ_UNLOCK(pRoot); return 0; } kbuild-3149/src/lib/kStuff/include/k/kAvlTmpl/kAvlRemove2.h0000644000175000017500000001065213252530253023424 0ustar locutuslocutus/* $Id: kAvlRemove2.h 34 2009-11-08 19:38:40Z bird $ */ /** @file * kAvlTmpl - Templated AVL Trees, Remove A Specific Node. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * 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. */ /** * Removes the specified node from the tree. * * @returns Pointer to the removed node (NULL if not in the tree) * @param pRoot Pointer to the AVL-tree root structure. * @param Key The Key of which is to be found a best fitting match for.. * * @remark This implementation isn't the most efficient, but this short and * easier to manage. */ KAVL_DECL(KAVLNODE *) KAVL_FN(Remove2)(KAVLROOT *pRoot, KAVLNODE *pNode) { #ifdef KAVL_EQUAL_ALLOWED /* * Find the right node by key and see if it's what we want. */ KAVLNODE *pParent; KAVLNODE *pCurNode = KAVL_FN(GetWithParent)(pRoot, pNode->mKey, &pParent); if (!pCurNode) return NULL; KAVL_WRITE_LOCK(pRoot); /** @todo the locking here isn't 100% sane. The only way to archive that is by no calling worker functions. */ if (pCurNode != pNode) { /* * It's not the one we want, but it could be in the duplicate list. */ while (pCurNode->mpList != KAVL_NULL) { KAVLNODE *pNext = KAVL_GET_POINTER(&pCurNode->mpList); if (pNext == pNode) { KAVL_SET_POINTER_NULL(&pCurNode->mpList, KAVL_GET_POINTER_NULL(&pNode->mpList)); pNode->mpList = KAVL_NULL; KAVL_LOOKTHRU_INVALIDATE_NODE(pRoot, pNode, pNode->mKey); KAVL_WRITE_UNLOCK(pRoot); return pNode; } pCurNode = pNext; } KAVL_WRITE_UNLOCK(pRoot); return NULL; } /* * Ok, it's the one we want alright. * * Simply remove it if it's the only one with they Key, * if there are duplicates we'll have to unlink it and * insert the first duplicate in our place. */ if (pNode->mpList == KAVL_NULL) { KAVL_WRITE_UNLOCK(pRoot); KAVL_FN(Remove)(pRoot, pNode->mKey); } else { KAVLNODE *pNewUs = KAVL_GET_POINTER(&pNode->mpList); pNewUs->mHeight = pNode->mHeight; if (pNode->mpLeft != KAVL_NULL) KAVL_SET_POINTER(&pNewUs->mpLeft, KAVL_GET_POINTER(&pNode->mpLeft)) else pNewUs->mpLeft = KAVL_NULL; if (pNode->mpRight != KAVL_NULL) KAVL_SET_POINTER(&pNewUs->mpRight, KAVL_GET_POINTER(&pNode->mpRight)) else pNewUs->mpRight = KAVL_NULL; if (pParent) { if (KAVL_GET_POINTER_NULL(&pParent->mpLeft) == pNode) KAVL_SET_POINTER(&pParent->mpLeft, pNewUs); else KAVL_SET_POINTER(&pParent->mpRight, pNewUs); } else KAVL_SET_POINTER(&pRoot->mpRoot, pNewUs); KAVL_LOOKTHRU_INVALIDATE_NODE(pRoot, pNode, pNode->mKey); KAVL_WRITE_UNLOCK(pRoot); } return pNode; #else /* * Delete it, if we got the wrong one, reinsert it. * * This ASSUMS that the caller is NOT going to hand us a lot * of wrong nodes but just uses this API for his convenience. */ KAVLNODE *pRemovedNode = KAVL_FN(Remove)(pRoot, pNode->mKey); if (pRemovedNode == pNode) return pRemovedNode; KAVL_FN(Insert)(pRoot, pRemovedNode); return NULL; #endif } kbuild-3149/src/lib/kStuff/include/k/kErr.h0000644000175000017500000000401613252530253020435 0ustar locutuslocutus/* $Id: kErr.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kErr - Status Code API. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___k_kErr_h___ #define ___k_kErr_h___ /** @defgroup grp_kErr kErr - Status Code API * @{ */ /** @def KERR_DECL * Declares a kRdr function according to build context. * @param type The return type. */ #if defined(KERR_BUILDING_DYNAMIC) # define KERR_DECL(type) K_DECL_EXPORT(type) #elif defined(KRDR_BUILT_DYNAMIC) # define KERR_DECL(type) K_DECL_IMPORT(type) #else # define KERR_DECL(type) type #endif #ifdef __cplusplus extern "C" { #endif KERR_DECL(const char *) kErrName(int rc); KERR_DECL(int) kErrFromErrno(int); KERR_DECL(int) kErrFromOS2(unsigned long rcOs2); KERR_DECL(int) kErrFromNtStatus(long rcNtStatus); KERR_DECL(int) kErrFromMach(int rcMach); KERR_DECL(int) kErrFromDarwin(int rcDarwin); #ifdef __cplusplus } #endif /** @} */ #endif kbuild-3149/src/lib/kStuff/include/k/kLdrFmts/0000755000175000017500000000000013252530253021106 5ustar locutuslocutuskbuild-3149/src/lib/kStuff/include/k/kLdrFmts/mach-o.h0000644000175000017500000013321313252530253022426 0ustar locutuslocutus/* $Id: mach-o.h 63 2013-10-30 02:00:14Z bird $ */ /** @file * Mach-0 structures, types and defines. */ /* * Copyright (c) 2006-2012 Knut St. Osmundsen * * 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. */ #ifndef ___k_kLdrFmts_mach_o_h___ #define ___k_kLdrFmts_mach_o_h___ #include #include /** @defgroup grp_mach_o The Mach-O Structures, Types, and Defines. * @{ */ #ifndef IMAGE_FAT_SIGNATURE /** The FAT signature (universal binaries). */ # define IMAGE_FAT_SIGNATURE KU32_C(0xcafebabe) #endif #ifndef IMAGE_FAT_SIGNATURE_OE /** The FAT signature (universal binaries), other endian. */ # define IMAGE_FAT_SIGNATURE_OE KU32_C(0xbebafeca) #endif /** * The fat header found at the start of universal binaries. * It is followed by \a nfat_arch numbers of \a fat_arch structures. */ typedef struct fat_header { KU32 magic; KU32 nfat_arch; } fat_header_t; /** * Description of fat file item. */ typedef struct fat_arch { KI32 cputype; KI32 cpusubtype; KU32 offset; KU32 size; KU32 align; /**< Power of 2. */ } fat_arch_t; #ifndef IMAGE_MACHO32_SIGNATURE /** The 32-bit Mach-O signature. */ # define IMAGE_MACHO32_SIGNATURE KU32_C(0xfeedface) #endif #ifndef IMAGE_MACHO32_SIGNATURE_OE /** The 32-bit Mach-O signature, other endian. */ # define IMAGE_MACHO32_SIGNATURE_OE KU32_C(0xcefaedfe) #endif #define MH_MAGIC IMAGE_MACHO32_SIGNATURE #define MH_CIGAM IMAGE_MACHO32_SIGNATURE_OE /** * 32-bit Mach-O header. * This is followed by \a ncmds number of load commands. * @see mach_header_64 */ typedef struct mach_header_32 { KU32 magic; KI32 cputype; KI32 cpusubtype; KU32 filetype; KU32 ncmds; KU32 sizeofcmds; KU32 flags; } mach_header_32_t; #ifndef IMAGE_MACHO64_SIGNATURE /** The 64-bit Mach-O signature. */ # define IMAGE_MACHO64_SIGNATURE KU32_C(0xfeedfacf) #endif #ifndef IMAGE_MACHO64_SIGNATURE_OE /** The 64-bit Mach-O signature, other endian. */ # define IMAGE_MACHO64_SIGNATURE_OE KU32_C(0xfefaedfe) #endif #define MH_MAGIC_64 IMAGE_MACHO64_SIGNATURE #define MH_CIGAM_64 IMAGE_MACHO64_SIGNATURE_OE /** * 64-bit Mach-O header. * This is followed by \a ncmds number of load commands. * @see mach_header */ typedef struct mach_header_64 { KU32 magic; KI32 cputype; KI32 cpusubtype; KU32 filetype; KU32 ncmds; KU32 sizeofcmds; KU32 flags; KU32 reserved; /**< (for proper struct and command alignment I guess) */ } mach_header_64_t; /** @name File types (mach_header_64::filetype, mach_header_32::filetype) * @{ */ #define MH_OBJECT KU32_C(1) /**< Object (relocatable). */ #define MH_EXECUTE KU32_C(2) /**< Executable (demand paged). */ #define MH_FVMLIB KU32_C(3) /**< Fixed VM shared library. */ #define MH_CORE KU32_C(4) /**< Core file. */ #define MH_PRELOAD KU32_C(5) /**< Preloaded executable. */ #define MH_DYLIB KU32_C(6) /**< Dynamically bound shared library. */ #define MH_DYLINKER KU32_C(7) /**< Dynamic linker. */ #define MH_BUNDLE KU32_C(8) /**< Dymamically bound bundle. */ #define MH_DYLIB_STUB KU32_C(9) /**< Shared library stub for static linking. */ #define MH_DSYM KU32_C(10)/**< Debug symbols. */ #define MH_KEXT_BUNDLE KU32_C(11)/**< Kernel extension (introduced with the AMD64 kernel). */ /** @} */ /** @name Mach-O Header flags (mach_header_64::flags, mach_header_32::flags) * @{ */ #define MH_NOUNDEFS KU32_C(0x00000001) /**< No undefined symbols. */ #define MH_INCRLINK KU32_C(0x00000002) /**< Partial increment link output. */ #define MH_DYLDLINK KU32_C(0x00000004) /**< Food for the dynamic linker, not for ld. */ #define MH_BINDATLOAD KU32_C(0x00000008) /**< Bind all undefined symbols at load time. */ #define MH_PREBOUND KU32_C(0x00000010) /**< Contains prebound undefined symbols. */ #define MH_SPLIT_SEGS KU32_C(0x00000020) /**< Read-only and read-write segments are split. */ #define MH_LAZY_INIT KU32_C(0x00000040) /**< Obsolete flag for doing lazy init when data is written. */ #define MH_TWOLEVEL KU32_C(0x00000080) /**< Uses two-level name space bindings. */ #define MH_FORCE_FLAT KU32_C(0x00000100) /**< Task: The executable forces all images to use flat name space bindings. */ #define MH_NOMULTIDEFS KU32_C(0x00000200) /**< No multiple symbol definitions, safe to use two-level namespace hints. */ #define MH_NOFIXPREBINDING KU32_C(0x00000400) /**< The dynamic linker should not notify the prebinding agent about this executable. */ #define MH_PREBINDABLE KU32_C(0x00000800) /**< Not prebound, but it can be. Invalid if MH_PREBOUND is set. */ #define MH_ALLMODSBOUND KU32_C(0x00001000) /**< Binds to all two-level namespace modules of preqs. Requires MH_PREBINDABLE and MH_TWOLEVEL to be set. */ #define MH_SUBSECTIONS_VIA_SYMBOLS KU32_C(0x00002000) /**< Safe to divide sections into sub-sections via symbols for dead code stripping. */ #define MH_CANONICAL KU32_C(0x00004000) /**< Canonicalized via unprebind. */ #define MH_WEAK_DEFINES KU32_C(0x00008000) /**< The (finally) linked image has weak symbols. */ #define MH_BINDS_TO_WEAK KU32_C(0x00010000) /**< The (finally) linked image uses weak symbols. */ #define MH_ALLOW_STACK_EXECUTION KU32_C(0x00020000) /**< Task: allow stack execution. (MH_EXECUTE only) */ #define MH_ROOT_SAFE KU32_C(0x00040000) /**< Binary safe for root execution. */ #define MH_SETUID_SAFE KU32_C(0x00080000) /**< Binary safe for set-uid execution. */ #define MH_NO_REEXPORTED_DYLIBS KU32_C(0x00100000) /**< No reexported dylibs. */ #define MH_PIE KU32_C(0x00200000) /**< Address space randomization. (MH_EXECUTE only) */ #define MH_DEAD_STRIPPABLE_DYLIB KU32_C(0x00400000) /**< Drop dylib dependency if not used. (MH_DYLIB only) */ #define MH_HAS_TLV_DESCRIPTORS KU32_C(0x00800000) /**< Has a S_TRHEAD_LOCAL_VARIABLES section. TLS support. */ #define MH_NO_HEAP_EXECUTION KU32_C(0x01000000) /**< Task: no heap execution. (MH_EXECUTE only) */ #define MH_VALID_FLAGS KU32_C(0x01ffffff) /**< Mask containing the defined flags. */ /** @} */ /** @name CPU types / bits (mach_header_64::cputype, mach_header_32::cputype, fat_arch::cputype) * @{ */ #define CPU_ARCH_MASK KI32_C(0xff000000) #define CPU_ARCH_ABI64 KI32_C(0x01000000) #define CPU_TYPE_ANY KI32_C(-1) #define CPU_TYPE_VAX KI32_C(1) #define CPU_TYPE_MC680x0 KI32_C(6) #define CPU_TYPE_X86 KI32_C(7) #define CPU_TYPE_I386 CPU_TYPE_X86 #define CPU_TYPE_X86_64 (CPU_TYPE_X86 | CPU_ARCH_ABI64) #define CPU_TYPE_MC98000 KI32_C(10) #define CPU_TYPE_HPPA KI32_C(11) #define CPU_TYPE_MC88000 KI32_C(13) #define CPU_TYPE_SPARC KI32_C(14) #define CPU_TYPE_I860 KI32_C(15) #define CPU_TYPE_POWERPC KI32_C(18) #define CPU_TYPE_POWERPC64 (CPU_TYPE_POWERPC | CPU_ARCH_ABI64) /** @} */ /** @name CPU subtypes (mach_header_64::cpusubtype, mach_header_32::cpusubtype, fat_arch::cpusubtype) * @{ */ #define CPU_SUBTYPE_MULTIPLE KI32_C(-1) #define CPU_SUBTYPE_LITTLE_ENDIAN KI32_C(0) /**< figure this one out. */ #define CPU_SUBTYPE_BIG_ENDIAN KI32_C(1) /**< ditto */ /* VAX */ #define CPU_SUBTYPE_VAX_ALL KI32_C(0) #define CPU_SUBTYPE_VAX780 KI32_C(1) #define CPU_SUBTYPE_VAX785 KI32_C(2) #define CPU_SUBTYPE_VAX750 KI32_C(3) #define CPU_SUBTYPE_VAX730 KI32_C(4) #define CPU_SUBTYPE_UVAXI KI32_C(5) #define CPU_SUBTYPE_UVAXII KI32_C(6) #define CPU_SUBTYPE_VAX8200 KI32_C(7) #define CPU_SUBTYPE_VAX8500 KI32_C(8) #define CPU_SUBTYPE_VAX8600 KI32_C(9) #define CPU_SUBTYPE_VAX8650 KI32_C(10) #define CPU_SUBTYPE_VAX8800 KI32_C(11) #define CPU_SUBTYPE_UVAXIII KI32_C(12) /* MC680xx */ #define CPU_SUBTYPE_MC680x0_ALL KI32_C(1) #define CPU_SUBTYPE_MC68030 KI32_C(1) #define CPU_SUBTYPE_MC68040 KI32_C(2) #define CPU_SUBTYPE_MC68030_ONLY KI32_C(3) /* I386 */ #define CPU_SUBTYPE_INTEL(fam, model) ( (KI32)(((model) << 4) | (fam)) ) #define CPU_SUBTYPE_INTEL_FAMILY(subtype) ( (subtype) & 0xf ) #define CPU_SUBTYPE_INTEL_MODEL(subtype) ( (subtype) >> 4 ) #define CPU_SUBTYPE_INTEL_FAMILY_MAX 0xf #define CPU_SUBTYPE_INTEL_MODEL_ALL 0 #define CPU_SUBTYPE_I386_ALL CPU_SUBTYPE_INTEL(3, 0) #define CPU_SUBTYPE_386 CPU_SUBTYPE_INTEL(3, 0) #define CPU_SUBTYPE_486 CPU_SUBTYPE_INTEL(4, 0) #define CPU_SUBTYPE_486SX CPU_SUBTYPE_INTEL(4, 8) #define CPU_SUBTYPE_586 CPU_SUBTYPE_INTEL(5, 0) #define CPU_SUBTYPE_PENT CPU_SUBTYPE_INTEL(5, 0) #define CPU_SUBTYPE_PENTPRO CPU_SUBTYPE_INTEL(6, 1) #define CPU_SUBTYPE_PENTII_M3 CPU_SUBTYPE_INTEL(6, 3) #define CPU_SUBTYPE_PENTII_M5 CPU_SUBTYPE_INTEL(6, 5) #define CPU_SUBTYPE_CELERON CPU_SUBTYPE_INTEL(7, 6) #define CPU_SUBTYPE_CELERON_MOBILE CPU_SUBTYPE_INTEL(7, 7) #define CPU_SUBTYPE_PENTIUM_3 CPU_SUBTYPE_INTEL(8, 0) #define CPU_SUBTYPE_PENTIUM_3_M CPU_SUBTYPE_INTEL(8, 1) #define CPU_SUBTYPE_PENTIUM_3_XEON CPU_SUBTYPE_INTEL(8, 2) #define CPU_SUBTYPE_PENTIUM_M CPU_SUBTYPE_INTEL(9, 0) #define CPU_SUBTYPE_PENTIUM_4 CPU_SUBTYPE_INTEL(10, 0) #define CPU_SUBTYPE_PENTIUM_4_M CPU_SUBTYPE_INTEL(10, 1) #define CPU_SUBTYPE_ITANIUM CPU_SUBTYPE_INTEL(11, 0) #define CPU_SUBTYPE_ITANIUM_2 CPU_SUBTYPE_INTEL(11, 1) #define CPU_SUBTYPE_XEON CPU_SUBTYPE_INTEL(12, 0) #define CPU_SUBTYPE_XEON_MP CPU_SUBTYPE_INTEL(12, 1) /* X86 */ #define CPU_SUBTYPE_X86_ALL KI32_C(3) /* CPU_SUBTYPE_I386_ALL */ #define CPU_SUBTYPE_X86_64_ALL KI32_C(3) /* CPU_SUBTYPE_I386_ALL */ #define CPU_SUBTYPE_X86_ARCH1 KI32_C(4) /* CPU_SUBTYPE_I486_ALL */ /* MIPS */ #define CPU_SUBTYPE_MIPS_ALL KI32_C(0) #define CPU_SUBTYPE_MIPS_R2300 KI32_C(1) #define CPU_SUBTYPE_MIPS_R2600 KI32_C(2) #define CPU_SUBTYPE_MIPS_R2800 KI32_C(3) #define CPU_SUBTYPE_MIPS_R2000a KI32_C(4) #define CPU_SUBTYPE_MIPS_R2000 KI32_C(5) #define CPU_SUBTYPE_MIPS_R3000a KI32_C(6) #define CPU_SUBTYPE_MIPS_R3000 KI32_C(7) /* MC98000 (PowerPC) */ #define CPU_SUBTYPE_MC98000_ALL KI32_C(0) #define CPU_SUBTYPE_MC98601 KI32_C(1) /* HP-PA */ #define CPU_SUBTYPE_HPPA_ALL KI32_C(0) #define CPU_SUBTYPE_HPPA_7100 KI32_C(0) #define CPU_SUBTYPE_HPPA_7100LC KI32_C(1) /* MC88000 */ #define CPU_SUBTYPE_MC88000_ALL KI32_C(0) #define CPU_SUBTYPE_MC88100 KI32_C(1) #define CPU_SUBTYPE_MC88110 KI32_C(2) /* SPARC */ #define CPU_SUBTYPE_SPARC_ALL KI32_C(0) /* I860 */ #define CPU_SUBTYPE_I860_ALL KI32_C(0) #define CPU_SUBTYPE_I860_860 KI32_C(1) /* PowerPC */ #define CPU_SUBTYPE_POWERPC_ALL KI32_C(0) #define CPU_SUBTYPE_POWERPC_601 KI32_C(1) #define CPU_SUBTYPE_POWERPC_602 KI32_C(2) #define CPU_SUBTYPE_POWERPC_603 KI32_C(3) #define CPU_SUBTYPE_POWERPC_603e KI32_C(4) #define CPU_SUBTYPE_POWERPC_603ev KI32_C(5) #define CPU_SUBTYPE_POWERPC_604 KI32_C(6) #define CPU_SUBTYPE_POWERPC_604e KI32_C(7) #define CPU_SUBTYPE_POWERPC_620 KI32_C(8) #define CPU_SUBTYPE_POWERPC_750 KI32_C(9) #define CPU_SUBTYPE_POWERPC_7400 KI32_C(10) #define CPU_SUBTYPE_POWERPC_7450 KI32_C(11) #define CPU_SUBTYPE_POWERPC_Max KI32_C(10) #define CPU_SUBTYPE_POWERPC_SCVger KI32_C(11) #define CPU_SUBTYPE_POWERPC_970 KI32_C(100) /* Subtype capability / feature bits, added in 10.5. X86 only? */ #define CPU_SUBTYPE_MASK KU32_C(0xff000000) #define CPU_SUBTYPE_LIB64 KU32_C(0x8000000) /** @} */ /** @defgroup grp_macho_o_lc Load Commands * @{ */ /** * The load command common core structure. * * After the Mach-O header follows an array of variable sized * load command which all has this header in common. */ typedef struct load_command { KU32 cmd; /**< The load command id. */ KU32 cmdsize; /**< The size of the command (including this header). */ } load_command_t; /** @name Load Command IDs (load_command::cmd) * @{ */ /** Flag that when set requires the dynamic linker to fail if it doesn't * grok the command. The dynamic linker will otherwise ignore commands it * doesn't understand. Introduced with Mac OS X 10.1. */ #define LC_REQ_DYLD KU32_C(0x80000000) #define LC_SEGMENT_32 KU32_C(0x01) /**< Segment to be mapped (32-bit). See segment_command_32. */ #define LC_SYMTAB KU32_C(0x02) /**< 'stab' symbol table. See symtab_command. */ #define LC_SYMSEG KU32_C(0x03) /**< Obsoleted gdb symbol table. */ #define LC_THREAD KU32_C(0x04) /**< Thread. See thread_command. */ #define LC_UNIXTHREAD KU32_C(0x05) /**< Unix thread (includes stack and stuff). See thread_command. */ #define LC_LOADFVMLIB KU32_C(0x06) /**< Load a specified fixed VM shared library (obsolete?). See fvmlib_command. */ #define LC_IDFVMLIB KU32_C(0x07) /**< Fixed VM shared library id (obsolete?). See fvmlib_command. */ #define LC_IDENT KU32_C(0x08) /**< Identification info (obsolete). See ident_command. */ #define LC_FVMFILE KU32_C(0x09) /**< Fixed VM file inclusion (internal). See fvmfile_command. */ #define LC_PREPAGE KU32_C(0x0a) /**< Prepage command (internal). See ?? */ #define LC_DYSYMTAB KU32_C(0x0b) /**< Symbol table for dynamic linking. See dysymtab_command. */ #define LC_LOAD_DYLIB KU32_C(0x0c) /**< Load a dynamically linked shared library. See dylib_command. */ #define LC_ID_DYLIB KU32_C(0x0d) /**< Dynamically linked share library ident. See dylib_command. */ #define LC_LOAD_DYLINKER KU32_C(0x0e) /**< Load a dynamical link editor. See dylinker_command. */ #define LC_ID_DYLINKER KU32_C(0x0f) /**< Dynamic link editor ident. See dylinker_command. */ #define LC_PREBOUND_DYLIB KU32_C(0x10) /**< Prebound modules for dynamically linking of a shared lib. See prebound_dylib_command. */ #define LC_ROUTINES KU32_C(0x11) /**< Image routines. See routines_command_32. */ #define LC_SUB_FRAMEWORK KU32_C(0x12) /**< Sub framework. See sub_framework_command. */ #define LC_SUB_UMBRELLA KU32_C(0x13) /**< Sub umbrella. See sub_umbrella_command. */ #define LC_SUB_CLIENT KU32_C(0x14) /**< Sub client. See sub_client_command. */ #define LC_SUB_LIBRARY KU32_C(0x15) /**< Sub library. See sub_library_command. */ #define LC_TWOLEVEL_HINTS KU32_C(0x16) /**< Two-level namespace lookup hints. See twolevel_hints_command. */ #define LC_PREBIND_CKSUM KU32_C(0x17) /**< Prebind checksum. See prebind_cksum_command. */ #define LC_LOAD_WEAK_DYLIB (KU32_C(0x18) | LC_REQ_DYLD) /**< Dylib that can be missing, all symbols weak. See dylib_command. */ #define LC_SEGMENT_64 KU32_C(0x19) /**< segment to be mapped (64-bit). See segment_command_32. */ #define LC_ROUTINES_64 KU32_C(0x1a) /**< Image routines (64-bit). See routines_command_32. */ #define LC_UUID KU32_C(0x1b) /**< The UUID of the object module. See uuid_command. */ #define LC_RPATH (KU32_C(0x1c) | LC_REQ_DYLD) /**< Runpth additions. See rpath_command. */ #define LC_CODE_SIGNATURE KU32_C(0x1d) /**< Code signature location. See linkedit_data_command. */ #define LC_SEGMENT_SPLIT_INFO KU32_C(0x1e)/**< Segment split info location. See linkedit_data_command. */ #define LC_REEXPORT_DYLIB (KU32_C(0x1f) | LC_REQ_DYLD)/**< Load and re-export the given dylib - DLL forwarding. See dylib_command. */ #define LC_LAZY_LOAD_DYLIB KU32_C(0x20) /**< Delays loading of the given dylib until used. See dylib_command? */ #define LC_ENCRYPTION_INFO KU32_C(0x21) /**< Segment encryption information. See encryption_info_command. */ #define LC_DYLD_INFO KU32_C(0x22) /**< Compressed dylib relocation information, alternative present. See dyld_info_command. */ #define LC_DYLD_INFO_ONLY (KU32_C(0x22) | LC_REQ_DYLD) /**< Compressed dylib relocation information, no alternative. See dyld_info_command. */ #define LC_LOAD_UPWARD_DYLIB KU32_C(0x23) /**< ???? */ #define LC_VERSION_MIN_MACOSX KU32_C(0x24) /**< The image requires the given Mac OS X version. See version_min_command. */ #define LC_VERSION_MIN_IPHONEOS KU32_C(0x25) /**< The image requires the given iOS version. See version_min_command. */ #define LC_FUNCTION_STARTS KU32_C(0x26) /**< Where to find the compress function start addresses. See linkedit_data_command. */ #define LC_DYLD_ENVIRONMENT KU32_C(0x27) /**< Environment variable for the dynamic linker. See dylinker_command. */ #define LC_MAIN (KU32_C(0x28) | LC_REQ_DYLD) /**< Simpler alternative to LC_UNIXTHREAD. */ #define LC_DATA_IN_CODE KU32_C(0x29) /**< Table of data in the the text section. */ #define LC_SOURCE_VERSION KU32_C(0x2a) /**< Source code revision / version hint. */ #define LC_DYLIB_CODE_SIGN_DRS KU32_C(0x2b) /**< Code signing designated requirements copied from dylibs prequisites. */ /** @} */ /** * Load Command String. */ typedef struct lc_str { /** Offset of the string relative to the load_command structure. * The string is zero-terminated. the size of the load command * is zero padded up to a multiple of 4 bytes. */ KU32 offset; } lc_str_t; /** * Segment load command (32-bit). */ typedef struct segment_command_32 { KU32 cmd; /**< LC_SEGMENT */ KU32 cmdsize; /**< sizeof(self) + sections. */ char segname[16]; /**< The segment name. */ KU32 vmaddr; /**< Memory address of this segment. */ KU32 vmsize; /**< Size of this segment. */ KU32 fileoff; /**< The file location of the segment. */ KU32 filesize; /**< The file size of the segment. */ KU32 maxprot; /**< Maximum VM protection. */ KU32 initprot; /**< Initial VM protection. */ KU32 nsects; /**< Number of section desciptors following this structure. */ KU32 flags; /**< Flags (SG_*). */ } segment_command_32_t; /** * Segment load command (64-bit). * Same as segment_command_32 except 4 members has been blown up to 64-bit. */ typedef struct segment_command_64 { KU32 cmd; /**< LC_SEGMENT */ KU32 cmdsize; /**< sizeof(self) + sections. */ char segname[16]; /**< The segment name. */ KU64 vmaddr; /**< Memory address of this segment. */ KU64 vmsize; /**< Size of this segment. */ KU64 fileoff; /**< The file location of the segment. */ KU64 filesize; /**< The file size of the segment. */ KU32 maxprot; /**< Maximum VM protection. */ KU32 initprot; /**< Initial VM protection. */ KU32 nsects; /**< Number of section desciptors following this structure. */ KU32 flags; /**< Flags (SG_*). */ } segment_command_64_t; /** @name Segment flags (segment_command_64::flags, segment_command_32::flags) * @{ */ /** Map the file bits in the top end of the memory area for the segment * instead of the low end. Intended for stacks in core dumps. * The part of the segment memory not covered by file bits will be zeroed. */ #define SG_HIGHVM KU32_C(0x00000001) /** This segment is the virtual memory allocated by a fixed VM library. * (Used for overlap checking in the linker.) */ #define SG_FVMLIB KU32_C(0x00000002) /** No relocations for or symbols that's relocated to in this segment. * The segment can therefore safely be replaced. */ #define SG_NORELOC KU32_C(0x00000004) /** The segment is protected. * The first page isn't protected if it starts at file offset 0 * (so that the mach header and this load command can be easily mapped). */ #define SG_PROTECTED_VERSION_1 KU32_C(0x00000008) /** @} */ /** * 32-bit section (part of a segment load command). */ typedef struct section_32 { char sectname[16]; /**< The section name. */ char segname[16]; /**< The name of the segment this section goes into. */ KU32 addr; /**< The memory address of this section. */ KU32 size; /**< The size of this section. */ KU32 offset; /**< The file offset of this section. */ KU32 align; /**< The section alignment (**2). */ KU32 reloff; /**< The file offset of the relocations. */ KU32 nreloc; /**< The number of relocations. */ KU32 flags; /**< The section flags; section type and attribs */ KU32 reserved1; /**< Reserved / offset / index. */ KU32 reserved2; /**< Reserved / count / sizeof. */ } section_32_t; /** * 64-bit section (part of a segment load command). */ typedef struct section_64 { char sectname[16]; /**< The section name. */ char segname[16]; /**< The name of the segment this section goes into. */ KU64 addr; /**< The memory address of this section. */ KU64 size; /**< The size of this section. */ KU32 offset; /**< The file offset of this section. */ KU32 align; /**< The section alignment (**2). */ KU32 reloff; /**< The file offset of the relocations. */ KU32 nreloc; /**< The number of relocations. */ KU32 flags; /**< The section flags; section type and attribs */ KU32 reserved1; /**< Reserved / offset / index. */ KU32 reserved2; /**< Reserved / count / sizeof. */ KU32 reserved3; /**< (Just) Reserved. */ } section_64_t; /** @name Section flags (section_64::flags, section_32::flags) * @{ */ /** Section type mask. */ #define SECTION_TYPE KU32_C(0x000000ff) /** Regular section. */ #define S_REGULAR 0x00 /** Zero filled section. */ #define S_ZEROFILL 0x01 /** C literals. */ #define S_CSTRING_LITERALS 0x02 /** 4 byte literals. */ #define S_4BYTE_LITERALS 0x03 /** 8 byte literals. */ #define S_8BYTE_LITERALS 0x04 /** Pointer to literals. */ #define S_LITERAL_POINTERS 0x05 /** Section containing non-lazy symbol pointers. * Reserved1 == start index in the indirect symbol table. */ #define S_NON_LAZY_SYMBOL_POINTERS 0x06 /** Section containing lazy symbol pointers. * Reserved1 == start index in the indirect symbol table. */ #define S_LAZY_SYMBOL_POINTERS 0x07 /** Section containing symbol stubs. * Reserved2 == stub size. */ #define S_SYMBOL_STUBS 0x08 /** Section containing function pointers for module initialization. . */ #define S_MOD_INIT_FUNC_POINTERS 0x09 /** Section containing function pointers for module termination. . */ #define S_MOD_TERM_FUNC_POINTERS 0x0a /** Section containing symbols that are to be coalesced. */ #define S_COALESCED 0x0b /** Zero filled section that be larger than 4GB. */ #define S_GB_ZEROFILL 0x0c /** Section containing pairs of function pointers for interposing. */ #define S_INTERPOSING 0x0d /** 16 byte literals. */ #define S_16BYTE_LITERALS 0x0e /** DTrace byte code / definitions (DOF = DTrace object format). */ #define S_DTRACE_DOF 0x0f /** Section containing pointers to symbols in lazily loaded dylibs. */ #define S_LAZY_DYLIB_SYMBOL_POINTERS 0x10 /** Section attribute mask. */ #define SECTION_ATTRIBUTES KU32_C(0xffffff00) /** User settable attribute mask. */ #define SECTION_ATTRIBUTES_USR KU32_C(0xff000000) /** Pure instruction (code). */ #define S_ATTR_PURE_INSTRUCTIONS KU32_C(0x80000000) /** ranlib, ignore my symbols... */ #define S_ATTR_NO_TOC KU32_C(0x40000000) /** May strip static symbols when linking int a MH_DYLDLINK file. */ #define S_ATTR_STRIP_STATIC_SYMS KU32_C(0x20000000) /** No dead stripping. */ #define S_ATTR_NO_DEAD_STRIP KU32_C(0x10000000) /** Live support. */ #define S_ATTR_LIVE_SUPPORT KU32_C(0x08000000) /** Contains self modifying code (generally i386 code stub for dyld). */ #define S_ATTR_SELF_MODIFYING_CODE KU32_C(0x04000000) /** Debug info (DWARF usually). */ #define S_ATTR_DEBUG KU32_C(0x02000000) /** System settable attribute mask. */ #define SECTION_ATTRIBUTES_SYS KU32_C(0x00ffff00) /** Contains some instructions (code). */ #define S_ATTR_SOME_INSTRUCTIONS KU32_C(0x00000400) /** Has external relocations. */ #define S_ATTR_EXT_RELOC KU32_C(0x00000200) /** Has internal (local) relocations. */ #define S_ATTR_LOC_RELOC KU32_C(0x00000100) /** @} */ /** @name Known Segment and Section Names. * Some of these implies special linker behaviour. * @{ */ /** Page zero - not-present page for catching invalid access. (MH_EXECUTE typically) */ #define SEG_PAGEZERO "__PAGEZERO" /** Traditional UNIX text segment. * Defaults to R-X. */ #define SEG_TEXT "__TEXT" /** The text part of SEG_TEXT. */ #define SECT_TEXT "__text" /** The fvmlib initialization. */ #define SECT_FVMLIB_INIT0 "__fvmlib_init0" /** The section following the fvmlib initialization. */ #define SECT_FVMLIB_INIT1 "__fvmlib_init1" /** The traditional UNIX data segment. (DGROUP to DOS and OS/2 people.) */ #define SEG_DATA "__DATA" /** The initialized data section. */ #define SECT_DATA "__data" /** The uninitialized data section. */ #define SECT_BSS "__bss" /** The common symbol section. */ #define SECT_COMMON "__common" /** Objective-C runtime segment. */ #define SEG_OBJC "__OBJC" /** Objective-C symbol table section. */ #define SECT_OBJC_SYMBOLS "__symbol_table" /** Objective-C module information section. */ #define SECT_OBJC_MODULES "__module_info" /** Objective-C string table section. */ #define SECT_OBJC_STRINGS "__selector_strs" /** Objective-C string table section. */ #define SECT_OBJC_REFS "__selector_refs" /** Icon segment. */ #define SEG_ICON "__ICON" /** The icon headers. */ #define SECT_ICON_HEADER "__header" /** The icons in the TIFF format. */ #define SECT_ICON_TIFF "__tiff" /** ld -seglinkedit segment containing all the structs create and maintained * by the linker. MH_EXECUTE and MH_FVMLIB only. */ #define SEG_LINKEDIT "__LINKEDIT" /** The unix stack segment. */ #define SEG_UNIXSTACK "__UNIXSTACK" /** The segment for the self modifying code for dynamic linking. * Implies RWX permissions. */ #define SEG_IMPORT "__IMPORT" /** @} */ /** @todo fvmlib */ /** @todo fvmlib_command (LC_IDFVMLIB or LC_LOADFVMLIB) */ /** @todo dylib */ /** @todo dylib_command (LC_ID_DYLIB, LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB, * LC_REEXPORT_DYLIB, LC_LAZY_LOAD_DYLIB) */ /** @todo sub_framework_command (LC_SUB_FRAMEWORK) */ /** @todo sub_client_command (LC_SUB_CLIENT) */ /** @todo sub_umbrella_command (LC_SUB_UMBRELLA) */ /** @todo sub_library_command (LC_SUB_LIBRARY) */ /** @todo prebound_dylib_command (LC_PREBOUND_DYLIB) */ /** @todo dylinker_command (LC_ID_DYLINKER or LC_LOAD_DYLINKER, * LC_DYLD_ENVIRONMENT) */ /** * Thread command. * * State description of a thread that is to be created. The description * is made up of a number of state structures preceded by a 32-bit flavor * and 32-bit count field stating the kind of stat structure and it's size * in KU32 items respecitvly. * * LC_UNIXTHREAD differs from LC_THREAD in that it implies stack creation * and that it's started with the typical main(int, char **, char **) frame * on the stack. */ typedef struct thread_command { KU32 cmd; /**< LC_UNIXTHREAD or LC_THREAD. */ KU32 cmdsize; /**< The size of the command (including this header). */ } thread_command_t; /** @todo routines_command (LC_ROUTINES) */ /** @todo routines_command_64 (LC_ROUTINES_64) */ /** * Symbol table command. * Contains a.out style symbol table with some tricks. */ typedef struct symtab_command { KU32 cmd; /**< LC_SYMTAB */ KU32 cmdsize; /** sizeof(symtab_command_t) */ KU32 symoff; /** The file offset of the symbol table. */ KU32 nsyms; /** The number of symbols in the symbol table. */ KU32 stroff; /** The file offset of the string table. */ KU32 strsize; /** The size of the string table. */ } symtab_command_t; /** @todo dysymtab_command (LC_DYSYMTAB) */ /** @todo dylib_table_of_contents */ /** @todo dylib_module_32 */ /** @todo dylib_module_64 */ /** @todo dylib_reference */ /** @todo twolevel_hints_command (LC_TWOLEVEL_HINTS) */ /** @todo twolevel_hint */ /** @todo prebind_cksum_command (LC_PREBIND_CKSUM) */ /** * UUID generated by ld. */ typedef struct uuid_command { KU32 cmd; /**< LC_UUID */ KU32 cmdsize; /**< sizeof(uuid_command_t) */ KU8 uuid[16]; /** The UUID bytes. */ } uuid_command_t; /** @todo symseg_command (LC_SYMSEG) */ /** @todo ident_command (LC_IDENT) */ /** @todo fvmfile_command (LC_FVMFILE) */ /** @todo rpath_command (LC_RPATH) */ typedef struct linkedit_data_command { KU32 cmd; /**< LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS */ KU32 cmdsize; /**< size of this structure. */ KU32 dataoff; /**< Offset into the file of the data. */ KU32 datasize; /**< The size of the data. */ } linkedit_data_command_t; /** @todo encryption_info_command (LC_ENCRYPTION_INFO) */ /** @todo dyld_info_command (LC_DYLD_INFO, LC_DYLD_INFO_ONLY) */ typedef struct version_min_command { KU32 cmd; /**< LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS */ KU32 cmdsize; /**< size of this structure. */ KU32 version; /**< 31..16=major, 15..8=minor, 7..0=patch. */ KU32 reserved; /**< MBZ. */ } version_min_command_t; /** @} */ /** @defgroup grp_macho_o_syms Symbol Table * @{ */ /** * The 32-bit Mach-O version of the nlist structure. * * This differs from the a.out nlist struct in that the unused n_other field * was renamed to n_sect and used for keeping the relevant section number. * @remark This structure is not name mach_nlist_32 in the Apple headers, but nlist. */ typedef struct macho_nlist_32 { union { KI32 n_strx; /**< Offset (index) into the string table. 0 means "". */ } n_un; KU8 n_type; /**< Symbol type. */ KU8 n_sect; /**< Section number of NO_SECT. */ KI16 n_desc; /**< Type specific, debug info details mostly.*/ KU32 n_value; /**< The symbol value or stab offset. */ } macho_nlist_32_t; /** * The 64-bit Mach-O version of the nlist structure. * @see macho_nlist_32 */ typedef struct macho_nlist_64 { union { KU32 n_strx; /**< Offset (index) into the string table. 0 means "". */ } n_un; KU8 n_type; /**< Symbol type. */ KU8 n_sect; /**< Section number of NO_SECT. */ KI16 n_desc; /**< Type specific, debug info details mostly.*/ KU64 n_value; /**< The symbol value or stab offset. */ } macho_nlist_64_t; /** @name Symbol Type Constants (macho_nlist_32_t::n_type, macho_nlist_64_t::n_type) * * In the Mach-O world n_type is somewhat similar to a.out, meaning N_EXT, N_UNDF, N_ABS * and the debug symbols are essentially the same, but the remaining stuff is different. * The main reason for this is that the encoding of section has been moved to n_sect * to permit up to 255 sections instead of the fixed 3 a.out sections (not counting * the abs symbols and set vectors). * * To avoid confusion with a.out the Mach-O constants has been fitted with a MACHO_ * prefix here. * * Common symbols (aka communal symbols and comdefs) are represented by * n_type = MACHO_N_EXT | MACHO_N_UNDF, n_sect = NO_SECT and n_value giving * the size. * * * Symbol table entries can be inserted directly in the assembly code using * this notation: * @code * .stabs "n_name", n_type, n_sect, n_desc, n_value * @endcode * * (1) The line number is optional, GCC doesn't set it. * (2) The type is optional, GCC doesn't set it. * (3) The binutil header is "skeptical" about the line. I'm skeptical about the whole thing... :-) * (M) Mach-O specific? * (S) Sun specific? * @{ */ /* Base masks. */ #define MACHO_N_EXT KU8_C(0x01) /**< External symbol (when set) (N_EXT). */ #define MACHO_N_TYPE KU8_C(0x0e) /**< Symbol type (N_TYPE without the 8th bit). */ #define MACHO_N_PEXT KU8_C(0x10) /**< Private extern symbol (when set). (M) */ #define MACHO_N_STAB KU8_C(0xe0) /**< Debug symbol mask (N_STAB). */ /* MACHO_N_TYPE values. */ #define MACHO_N_UNDF KU8_C(0x00) /**< MACHO_N_TYPE: Undefined symbol (N_UNDF). n_sect = NO_SECT. */ #define MACHO_N_ABS KU8_C(0x02) /**< MACHO_N_TYPE: Absolute symbol (N_UNDF). n_sect = NO_SECT. */ #define MACHO_N_INDR KU8_C(0x0a) /**< MACHO_N_TYPE: Indirect symbol, n_value is the index of the symbol. (M) */ #define MACHO_N_PBUD KU8_C(0x0c) /**< MACHO_N_TYPE: Prebound undefined symbo (defined in a dylib). (M) */ #define MACHO_N_SECT KU8_C(0x0e) /**< MACHO_N_TYPE: Defined in the section given by n_sects. (M) */ /* Debug symbols. */ #define MACHO_N_GSYM KU8_C(0x20) /**< Global variable. "name",, NO_SECT, type, 0 (2) */ #define MACHO_N_FNAME KU8_C(0x22) /**< Function name (F77). "name",, NO_SECT, 0, 0 */ #define MACHO_N_FUN KU8_C(0x24) /**< Function / text var. "name",, section, line, address (1) */ #define MACHO_N_STSYM KU8_C(0x26) /**< Static data symbol. "name",, section, type, address (2) */ #define MACHO_N_LCSYM KU8_C(0x28) /**< static bss symbol. "name",, section, type, address (2) */ /* omits N_MAIN and N_ROSYM. */ #define MACHO_N_BNSYM KU8_C(0x2e) /**< Begin nsect symbol. 0,, section, 0, address (M) */ #define MACHO_N_PC KU8_C(0x30) /**< Global pascal symbol. "name",, NO_SECT, subtype?, line (3) */ /* omits N_NSYMS, N_NOMAP and N_OBJ. */ #define MACHO_N_OPT KU8_C(0x3c) /**< Options for the debugger related to the language of the source file. "options?",,,, */ #define MACHO_N_RSYM KU8_C(0x40) /**< Register variable. "name",, NO_SECT, type, register */ /* omits N_M2C */ #define MACHO_N_SLINE KU8_C(0x44) /**< Source line. 0,, section, line, address */ /* omits N_DSLINE, N_BSLINE / N_BROWS, N_DEFD and N_FLINE. */ #define MACHO_N_ENSYM KU8_C(0x4e) /**< End nsect symbol. 0,, section, 0, address (M) */ /* omits N_EHDECL / N_MOD2 and N_CATCH. */ #define MACHO_N_SSYM KU8_C(0x60) /**< Struct/union element. "name",, NO_SECT, type, offset */ /* omits N_ENDM */ #define MACHO_N_SO KU8_C(0x64) /**< Source file name. "fname",, section, 0, address */ #define MACHO_N_OSO KU8_C(0x66) /**< Object file name. "fname",, 0, 0, st_mtime (M?) */ /* omits N_ALIAS */ #define MACHO_N_LSYM KU8_C(0x80) /**< Stack variable. "name",, NO_SECT, type, frame_offset */ #define MACHO_N_BINCL KU8_C(0x82) /**< Begin #include. "fname",, NO_SECT, 0, sum? */ #define MACHO_N_SOL KU8_C(0x84) /**< #included file. "fname",, section, 0, start_address (S) */ #define MACHO_N_PARAMS KU8_C(0x86) /**< Compiler params. "params",, NO_SECT, 0, 0 */ #define MACHO_N_VERSION KU8_C(0x88) /**< Compiler version. "version",, NO_SECT, 0, 0 */ #define MACHO_N_OLEVEL KU8_C(0x8A) /**< Compiler -O level. "level",, NO_SECT, 0, 0 */ #define MACHO_N_PSYM KU8_C(0xa0) /**< Parameter variable. "name",, NO_SECT, type, frame_offset */ #define MACHO_N_EINCL KU8_C(0xa2) /**< End #include. "fname",, NO_SECT, 0, 0 (S) */ #define MACHO_N_ENTRY KU8_C(0xa4) /**< Alternate entry point. "name",, section, line, address */ #define MACHO_N_LBRAC KU8_C(0xc0) /**< Left bracket. 0,, NO_SECT, nesting_level, address */ #define MACHO_N_EXCL KU8_C(0xc2) /**< Deleted include file. "fname",, NO_SECT, 0, sum? (S) */ /* omits N_SCOPE */ #define MACHO_N_RBRAC KU8_C(0xe0) /**< Right bracket. 0,, NO_SECT, nesting_level, address */ #define MACHO_N_BCOMM KU8_C(0xe2) /**< Begin common. "name",, NO_SECT?, 0, 0 */ #define MACHO_N_ECOMM KU8_C(0xe4) /**< End common. "name",, section, 0, 0 */ #define MACHO_N_ECOML KU8_C(0xe8) /**< End local common. 0,, section, 0, address */ #define MACHO_N_LENG KU8_C(0xfe) /**< Length-value of the preceding entry. "name",, NO_SECT, 0, length */ /** @} */ /** @name Symbol Description Bits (macho_nlist_32_t::n_desc, macho_nlist_64_t::n_desc) * * Mach-O puts the n_desc field to a number of uses, like lazy binding , library * ordinal numbers for -twolevel_namespace, stripping and weak symbol handling. * * @remark The REFERENCE_FLAGS_* are really not flags in the normal sense (bit), * they are more like enum values. * @{ */ #define REFERENCE_TYPE KU16_C(0x000f) /**< The reference type mask. */ #define REFERENCE_FLAG_UNDEFINED_NON_LAZY 0 /**< Normal undefined symbol. */ #define REFERENCE_FLAG_UNDEFINED_LAZY 1 /**< Lazy undefined symbol. */ #define REFERENCE_FLAG_DEFINED 2 /**< Defined symbol (dynamic linking). */ #define REFERENCE_FLAG_PRIVATE_DEFINED 3 /**< Defined private symbol (dynamic linking). */ #define REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY 4 /**< Normal undefined private symbol. */ #define REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY 5 /**< Lazy undefined private symbol. */ #define REFERENCED_DYNAMICALLY KU16_C(0x0010) /**< Don't strip. */ /** Get the dynamic library ordinal. */ #define GET_LIBRARY_ORDINAL(n_desc) \ (((n_desc) >> 8) & 0xff) /** Set the dynamic library ordinal. */ #define SET_LIBRARY_ORDINAL(n_desc, ordinal) \ (n_desc) = (((n_desc) & 0xff) | (((ordinal) & 0xff) << 8)) #define SELF_LIBRARY_ORDINAL 0x00 /**< Special ordinal for refering to onself. */ #define MAX_LIBRARY_ORDINAL 0xfd /**< Maximum ordinal number. */ #define DYNAMIC_LOOKUP_ORDINAL 0xfe /**< Special ordinal number for dynamic lookup. (Mac OS X 10.3 and later) */ #define EXECUTABLE_ORDINAL 0xff /**< Special ordinal number for the executable. */ /** Only MH_OBJECT: Never dead strip me! */ #define N_NO_DEAD_STRIP KU16_C(0x0020) /** Not MH_OBJECT: Discarded symbol. */ #define N_DESC_DISCARDED KU16_C(0x0020) /** Weak external symbol. Symbol can be missing, in which case it's will have the value 0. */ #define N_WEAK_REF KU16_C(0x0040) /** Weak symbol definition. The symbol can be overridden by another weak * symbol already present or by a non-weak (strong) symbol definition. * Currently only supported for coalesed symbols. * @remark This bit means something differently for undefined symbols, see N_REF_TO_WEAK. */ #define N_WEAK_DEF KU16_C(0x0080) /** Reference to a weak symbol, resolve using flat namespace searching. * @remark This bit means something differently for defined symbols, see N_WEAK_DEF. */ #define N_REF_TO_WEAK KU16_C(0x0080) /** @} */ /** @} */ /** @defgroup grp_macho_o_relocs Relocations * @{ */ /** * Relocation entry. * * Differs from a.out in the meaning of r_symbolnum when r_extern=0 and * that r_pad is made into r_type. * * @remark This structure and type has been prefixed with macho_ to avoid * confusion with the original a.out type. */ typedef struct macho_relocation_info { KI32 r_address; /**< Section relative address of the fixup. The top bit (signed) indicates that this is a scattered relocation if set, see scattered_relocation_info_t. */ KU32 r_symbolnum : 24, /**< r_extern=1: Symbol table index, relocate with the address of this symbol. r_extern=0: Section ordinal, relocate with the address of this section. */ r_pcrel : 1, /**< PC (program counter) relative fixup; subtract the fixup address. */ r_length : 2, /**< Fixup length: 0=KU8, 1=KU16, 2=KU32, 3=KU64. */ r_extern : 1, /**< External or internal fixup, decides the r_symbolnum interpretation.. */ r_type : 4; /**< Relocation type; 0 is standard, non-zero are machine specific. */ } macho_relocation_info_t; /** Special section ordinal value for absolute relocations. */ #define R_ABS 0 /** Flag in r_address indicating that the relocation is of the * scattered_relocation_info_t kind and not macho_relocation_info_t. */ #define R_SCATTERED KU32_C(0x80000000) /** * Scattered relocation. * * This is a hack mainly for RISC machines which restricts section size * to 16MB among other things. * * The reason for the big/little endian differences here is of course because * of the R_SCATTERED mask and the way bitfields are implemented by the * C/C++ compilers. */ typedef struct scattered_relocation_info { #if K_ENDIAN == K_ENDIAN_LITTLE KU32 r_address : 24, /**< Section relative address of the fixup. (macho_relocation_info_t::r_address) */ r_type : 4, /**< Relocation type; 0 is standard, non-zero are machine specific. (macho_relocation_info_t::r_type) */ r_length : 2, /**< Fixup length: 0=KU8, 1=KU16, 2=KU32, 3=KU64. (macho_relocation_info_t::r_length) */ r_pcrel : 1, /**< PC (program counter) relative fixup; subtract the fixup address. (macho_relocation_info_t::r_pcrel) */ r_scattered : 1; /**< Set if scattered relocation, clear if normal relocation. */ #elif K_ENDIAN == K_ENDIAN_BIG KU32 r_scattered : 1, /**< Set if scattered relocation, clear if normal relocation. */ r_pcrel : 1, /**< PC (program counter) relative fixup; subtract the fixup address. (macho_relocation_info_t::r_pcrel) */ r_length : 2, /**< Fixup length: 0=KU8, 1=KU16, 2=KU32, 3=KU64. (macho_relocation_info_t::r_length) */ r_type : 4, /**< Relocation type; 0 is standard, non-zero are machine specific. (macho_relocation_info_t::r_type) */ r_address : 24; /**< Section relative address of the fixup. (macho_relocation_info_t::r_address) */ #else # error "Neither K_ENDIAN isn't LITTLE or BIG!" #endif KI32 r_value; /**< The value the fixup is refering to (without offset added). */ } scattered_relocation_info_t; /** * Relocation type values for a generic implementation (for r_type). */ typedef enum reloc_type_generic { GENERIC_RELOC_VANILLA = 0, /**< Standard relocation. */ GENERIC_RELOC_PAIR, /**< Follows GENERIC_RELOC_SECTDIFF. */ GENERIC_RELOC_SECTDIFF, /**< ??? */ GENERIC_RELOC_PB_LA_PTR, /**< Prebound lazy pointer whatever that. */ GENERIC_RELOC_LOCAL_SECTDIFF /**< ??? */ } reloc_type_generic_t; /** * Relocation type values for AMD64 (for r_type). */ typedef enum reloc_type_x86_64 { X86_64_RELOC_UNSIGNED = 0, /**< Absolute address. */ X86_64_RELOC_SIGNED, /**< Signed displacement. */ X86_64_RELOC_BRANCH, /**< Branch displacement (jmp/call, adj by size). */ X86_64_RELOC_GOT_LOAD, /**< GOT entry load. */ X86_64_RELOC_GOT, /**< GOT reference. */ X86_64_RELOC_SUBTRACTOR, /**< ??. */ X86_64_RELOC_SIGNED_1, /**< Signed displacement with a -1 added. */ X86_64_RELOC_SIGNED_2, /**< Signed displacement with a -2 added. */ X86_64_RELOC_SIGNED_4 /**< Signed displacement with a -4 added. */ } reloc_type_x86_64_t; /** @} */ /** @} */ #endif kbuild-3149/src/lib/kStuff/include/k/kLdrFmts/lx.h0000644000175000017500000003610113252530253021703 0ustar locutuslocutus/* $Id $ */ /** @file * LX structures, types and defines. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___k_kLdrFmts_lx_h___ #define ___k_kLdrFmts_lx_h___ #include #include #ifndef IMAGE_OS2_SIGNATURE_LX /** LX signature ("LX") */ # define IMAGE_LX_SIGNATURE K_LE2H_U16('L' | ('X' << 8)) #endif #pragma pack(1) /** * Linear eXecutable header. * This structure is exactly 196 bytes long. */ struct e32_exe { KU8 e32_magic[2]; KU8 e32_border; KU8 e32_worder; KU32 e32_level; KU16 e32_cpu; KU16 e32_os; KU32 e32_ver; KU32 e32_mflags; KU32 e32_mpages; KU32 e32_startobj; KU32 e32_eip; KU32 e32_stackobj; KU32 e32_esp; KU32 e32_pagesize; KU32 e32_pageshift; /** The size of the fixup section. * The fixup section consists of the fixup page table, the fixup record table, * the import module table, and the import procedure name table. */ KU32 e32_fixupsize; KU32 e32_fixupsum; /** The size of the resident loader section. * This includes the object table, the object page map table, the resource table, the resident name table, * the entry table, the module format directives table, and the page checksum table (?). */ KU32 e32_ldrsize; /** The checksum of the loader section. 0 if not calculated. */ KU32 e32_ldrsum; /** The offset of the object table relative to this structure. */ KU32 e32_objtab; /** Count of objects. */ KU32 e32_objcnt; /** The offset of the object page map table relative to this structure. */ KU32 e32_objmap; /** The offset of the object iterated pages (whatever this is used for) relative to the start of the file. */ KU32 e32_itermap; /** The offset of the resource table relative to this structure. */ KU32 e32_rsrctab; /** The number of entries in the resource table. */ KU32 e32_rsrccnt; /** The offset of the resident name table relative to this structure. */ KU32 e32_restab; /** The offset of the entry (export) table relative to this structure. */ KU32 e32_enttab; /** The offset of the module format directives table relative to this structure. */ KU32 e32_dirtab; /** The number of entries in the module format directives table. */ KU32 e32_dircnt; /** The offset of the fixup page table relative to this structure. */ KU32 e32_fpagetab; /** The offset of the fixup record table relative to this structure. */ KU32 e32_frectab; /** The offset of the import module name table relative to this structure. */ KU32 e32_impmod; /** The number of entries in the import module name table. */ KU32 e32_impmodcnt; /** The offset of the import procedure name table relative to this structure. */ KU32 e32_impproc; /** The offset of the page checksum table relative to this structure. */ KU32 e32_pagesum; /** The offset of the data pages relative to the start of the file. */ KU32 e32_datapage; /** The number of preload pages (ignored). */ KU32 e32_preload; /** The offset of the non-resident name table relative to the start of the file. */ KU32 e32_nrestab; /** The size of the non-resident name table. */ KU32 e32_cbnrestab; KU32 e32_nressum; KU32 e32_autodata; KU32 e32_debuginfo; KU32 e32_debuglen; KU32 e32_instpreload; KU32 e32_instdemand; KU32 e32_heapsize; KU32 e32_stacksize; KU8 e32_res3[20]; }; /** e32_magic[0] */ #define E32MAGIC1 'L' /** e32_magic[1] */ #define E32MAGIC2 'X' /** MAKEWORD(e32_magic[0], e32_magic[1]) */ #define E32MAGIC 0x584c /** e32_border - little endian */ #define E32LEBO 0 /** e32_border - big endian */ #define E32BEBO 1 /** e32_worder - little endian */ #define E32LEWO 0 /** e32_worder - big endian */ #define E32BEWO 1 /** e32_level */ #define E32LEVEL KU32_C(0) /** e32_cpu - 80286 */ #define E32CPU286 1 /** e32_cpu - 80386 */ #define E32CPU386 2 /** e32_cpu - 80486 */ #define E32CPU486 3 /** e32_pagesize */ #define OBJPAGELEN KU32_C(0x1000) /** @name e32_mflags * @{ */ /** App Type: Fullscreen only. */ #define E32NOPMW KU32_C(0x00000100) /** App Type: PM API. */ #define E32PMAPI KU32_C(0x00000300) /** App Type: PM VIO compatible. */ #define E32PMW KU32_C(0x00000200) /** Application type mask. */ #define E32APPMASK KU32_C(0x00000300) /** Executable module. */ #define E32MODEXE KU32_C(0x00000000) /** Dynamic link library (DLL / library) module. */ #define E32MODDLL KU32_C(0x00008000) /** Protected memory DLL. */ #define E32PROTDLL KU32_C(0x00010000) /** Physical Device Driver. */ #define E32MODPDEV KU32_C(0x00020000) /** Virtual Device Driver. */ #define E32MODVDEV KU32_C(0x00028000) /** Device driver */ #define E32DEVICE E32MODPDEV /** Dynamic link library (DLL / library) module. */ #define E32NOTP E32MODDLL /** Protected memory DLL. */ #define E32MODPROTDLL (E32MODDLL | E32PROTDLL) /** Module Type mask. */ #define E32MODMASK KU32_C(0x00038000) /** Not loadable (linker error). */ #define E32NOLOAD KU32_C(0x00002000) /** No internal fixups. */ #define E32NOINTFIX KU32_C(0x00000010) /** No external fixups (i.e. imports). */ #define E32NOEXTFIX KU32_C(0x00000020) /** System DLL, no internal fixups. */ #define E32SYSDLL KU32_C(0x00000008) /** Global (set) or per instance (cleared) library initialization. */ #define E32LIBINIT KU32_C(0x00000004) /** Global (set) or per instance (cleared) library termination. */ #define E32LIBTERM KU32_C(0x40000000) /** Indicates when set in an executable that the process isn't SMP safe. */ #define E32NOTMPSAFE KU32_C(0x00080000) /** @} */ /** @name Relocations (aka Fixups). * @{ */ typedef union _offset { KU16 offset16; KU32 offset32; } offset; /** A relocation. * @remark this structure isn't very usable since LX relocations comes in too many size variations. */ struct r32_rlc { KU8 nr_stype; KU8 nr_flags; KI16 r32_soff; KU16 r32_objmod; union targetid { offset intref; union extfixup { offset proc; KU32 ord; } extref; struct addfixup { KU16 entry; offset addval; } addfix; } r32_target; KU16 r32_srccount; KU16 r32_chain; }; /** @name Some attempt at size constanstants. * @{ */ #define RINTSIZE16 8 #define RINTSIZE32 10 #define RORDSIZE 8 #define RNAMSIZE16 8 #define RNAMSIZE32 10 #define RADDSIZE16 10 #define RADDSIZE32 12 /** @} */ /** @name nr_stype (source flags) * @{ */ #define NRSBYT 0x00 #define NRSSEG 0x02 #define NRSPTR 0x03 #define NRSOFF 0x05 #define NRPTR48 0x06 #define NROFF32 0x07 #define NRSOFF32 0x08 #define NRSTYP 0x0f #define NRSRCMASK 0x0f #define NRALIAS 0x10 #define NRCHAIN 0x20 /** @} */ /** @name nr_flags (target flags) * @{ */ #define NRRINT 0x00 #define NRRORD 0x01 #define NRRNAM 0x02 #define NRRENT 0x03 #define NRRTYP 0x03 #define NRADD 0x04 #define NRICHAIN 0x08 #define NR32BITOFF 0x10 #define NR32BITADD 0x20 #define NR16OBJMOD 0x40 #define NR8BITORD 0x80 /** @} */ /** @} */ /** @name The Object Table (aka segment table) * @{ */ /** The Object Table Entry. */ struct o32_obj { /** The size of the object. */ KU32 o32_size; /** The base address of the object. */ KU32 o32_base; /** Object flags. */ KU32 o32_flags; /** Page map index. */ KU32 o32_pagemap; /** Page map size. (doesn't need to be o32_size >> page shift). */ KU32 o32_mapsize; /** Reserved */ KU32 o32_reserved; }; /** @name o32_flags * @{ */ /** Read access. */ #define OBJREAD KU32_C(0x00000001) /** Write access. */ #define OBJWRITE KU32_C(0x00000002) /** Execute access. */ #define OBJEXEC KU32_C(0x00000004) /** Resource object. */ #define OBJRSRC KU32_C(0x00000008) /** The object is discarable (i.e. don't swap, just load in pages from the executable). * This overlaps a bit with object type. */ #define OBJDISCARD KU32_C(0x00000010) /** The object is shared. */ #define OBJSHARED KU32_C(0x00000020) /** The object has preload pages. */ #define OBJPRELOAD KU32_C(0x00000040) /** The object has invalid pages. */ #define OBJINVALID KU32_C(0x00000080) /** Non-permanent, link386 bug. */ #define LNKNONPERM KU32_C(0x00000600) /** Non-permanent, correct 'value'. */ #define OBJNONPERM KU32_C(0x00000000) /** Obj Type: The object is permanent and swappable. */ #define OBJPERM KU32_C(0x00000100) /** Obj Type: The object is permanent and resident (i.e. not swappable). */ #define OBJRESIDENT KU32_C(0x00000200) /** Obj Type: The object is resident and contigious. */ #define OBJCONTIG KU32_C(0x00000300) /** Obj Type: The object is permanent and long locable. */ #define OBJDYNAMIC KU32_C(0x00000400) /** Object type mask. */ #define OBJTYPEMASK KU32_C(0x00000700) /** x86: The object require an 16:16 alias. */ #define OBJALIAS16 KU32_C(0x00001000) /** x86: Big/Default selector setting, i.e. toggle 32-bit or 16-bit. */ #define OBJBIGDEF KU32_C(0x00002000) /** x86: conforming selector setting (weird stuff). */ #define OBJCONFORM KU32_C(0x00004000) /** x86: IOPL. */ #define OBJIOPL KU32_C(0x00008000) /** @} */ /** A Object Page Map Entry. */ struct o32_map { /** The file offset of the page. */ KU32 o32_pagedataoffset; /** The number of bytes of raw page data. */ KU16 o32_pagesize; /** Per page flags describing how the page is encoded in the file. */ KU16 o32_pageflags; }; /** @name o32 o32_pageflags * @{ */ /** Raw page (uncompressed) in the file. */ #define VALID KU16_C(0x0000) /** RLE encoded page in file. */ #define ITERDATA KU16_C(0x0001) /** Invalid page, nothing in the file. */ #define INVALID KU16_C(0x0002) /** Zero page, nothing in file. */ #define ZEROED KU16_C(0x0003) /** range of pages (what is this?) */ #define RANGE KU16_C(0x0004) /** Compressed page in file. */ #define ITERDATA2 KU16_C(0x0005) /** @} */ /** Iteration Record format (RLE compressed page). */ struct LX_Iter { /** Number of iterations. */ KU16 LX_nIter; /** The number of bytes that's being iterated. */ KU16 LX_nBytes; /** The bytes. */ KU8 LX_Iterdata; }; /** @} */ /** A Resource Table Entry */ struct rsrc32 { /** Resource Type. */ KU16 type; /** Resource ID. */ KU16 name; /** Resource size in bytes. */ KU32 cb; /** The index of the object containing the resource. */ KU16 obj; /** Offset of the resource that within the object. */ KU32 offset; }; /** @name The Entry Table (aka Export Table) * @{ */ /** Entry bundle. * Header descripting up to 255 entries that follows immediatly after this structure. */ struct b32_bundle { /** The number of entries. */ KU8 b32_cnt; /** The type of bundle. */ KU8 b32_type; /** The index of the object containing these entry points. */ KU16 b32_obj; }; /** @name b32_type * @{ */ /** Empty bundle, filling up unused ranges of ordinals. */ #define EMPTY 0x00 /** 16-bit offset entry point. */ #define ENTRY16 0x01 /** 16-bit callgate entry point. */ #define GATE16 0x02 /** 32-bit offset entry point. */ #define ENTRY32 0x03 /** Forwarder entry point. */ #define ENTRYFWD 0x04 /** Typing information present indicator. */ #define TYPEINFO 0x80 /** @} */ /** Entry point. */ struct e32_entry { /** Entry point flags */ KU8 e32_flags; /* Entry point flags */ union entrykind { /** ENTRY16 or ENTRY32. */ offset e32_offset; /** GATE16 */ struct callgate { /** Offset into segment. */ KU16 offset; /** The callgate selector */ KU16 callgate; } e32_callgate; /** ENTRYFWD */ struct fwd { /** Module ordinal number (i.e. into the import module table). */ KU16 modord; /** Procedure name or ordinal number. */ KU32 value; } e32_fwd; } e32_variant; }; /** @name e32_flags * @{ */ /** Exported entry (set) or private entry (clear). */ #define E32EXPORT 0x01 /** Uses shared data. */ #define E32SHARED 0x02 /** Parameter word count mask. */ #define E32PARAMS 0xf8 /** ENTRYFWD: Imported by ordinal (set) or by name (clear). */ #define FWD_ORDINAL 0x01 /** @} */ /** @name dunno * @{ */ #define FIXENT16 3 #define FIXENT32 5 #define GATEENT16 5 #define FWDENT 7 /** @} */ #pragma pack() #endif kbuild-3149/src/lib/kStuff/include/k/kLdrFmts/pe.h0000644000175000017500000004323113252530253021666 0ustar locutuslocutus/* $Id: pe.h 92 2016-09-08 15:31:37Z bird $ */ /** @file * PE structures, types and defines. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___k_kLdrFmts_pe_h___ #define ___k_kLdrFmts_pe_h___ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ #ifndef IMAGE_NT_SIGNATURE # define IMAGE_NT_SIGNATURE K_LE2H_U32('P' | ('E' << 8)) #endif /* file header */ #define IMAGE_FILE_MACHINE_UNKNOWN 0x0000 #define IMAGE_FILE_MACHINE_I386 0x014c #define IMAGE_FILE_MACHINE_AMD64 0x8664 #define IMAGE_FILE_MACHINE_ARM 0x01c0 #define IMAGE_FILE_MACHINE_ARMNT 0x01c4 #define IMAGE_FILE_MACHINE_ARM64 0xaa64 #define IMAGE_FILE_MACHINE_EBC 0x0ebc #define IMAGE_FILE_RELOCS_STRIPPED 0x0001 #define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 #define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 #define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 #define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 #define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 #define IMAGE_FILE_16BIT_MACHINE 0x0040 #define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 #define IMAGE_FILE_32BIT_MACHINE 0x0100 #define IMAGE_FILE_DEBUG_STRIPPED 0x0200 #define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 #define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 #define IMAGE_FILE_SYSTEM 0x1000 #define IMAGE_FILE_DLL 0x2000 #define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 #define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 /** Raw UUID byte for the ANON_OBJECT_HEADER_BIGOBJ::ClassID value. * These make out {d1baa1c7-baee-4ba9-af20-faf66aa4dcb8}. */ #define ANON_OBJECT_HEADER_BIGOBJ_CLS_ID_BYTES \ 0xc7, 0xa1, 0xba, 0xd1,/*-*/ 0xee, 0xba,/*-*/ 0xa9, 0x4b,/*-*/ 0xaf, 0x20,/*-*/ 0xfa, 0xf6, 0x6a, 0xa4, 0xdc, 0xb8 /* optional header */ #define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10B #define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20B #define IMAGE_SUBSYSTEM_UNKNOWN 0x0 #define IMAGE_SUBSYSTEM_NATIVE 0x1 #define IMAGE_SUBSYSTEM_WINDOWS_GUI 0x2 #define IMAGE_SUBSYSTEM_WINDOWS_CUI 0x3 #define IMAGE_SUBSYSTEM_OS2_GUI 0x4 #define IMAGE_SUBSYSTEM_OS2_CUI 0x5 #define IMAGE_SUBSYSTEM_POSIX_CUI 0x7 #define IMAGE_LIBRARY_PROCESS_INIT 0x0001 #define IMAGE_LIBRARY_PROCESS_TERM 0x0002 #define IMAGE_LIBRARY_THREAD_INIT 0x0004 #define IMAGE_LIBRARY_THREAD_TERM 0x0008 #define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200 #define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400 #define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800 #define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 #define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000 #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 0x10 #define IMAGE_DIRECTORY_ENTRY_EXPORT 0x0 #define IMAGE_DIRECTORY_ENTRY_IMPORT 0x1 #define IMAGE_DIRECTORY_ENTRY_RESOURCE 0x2 #define IMAGE_DIRECTORY_ENTRY_EXCEPTION 0x3 #define IMAGE_DIRECTORY_ENTRY_SECURITY 0x4 #define IMAGE_DIRECTORY_ENTRY_BASERELOC 0x5 #define IMAGE_DIRECTORY_ENTRY_DEBUG 0x6 #define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 0x7 #define IMAGE_DIRECTORY_ENTRY_COPYRIGHT IMAGE_DIRECTORY_ENTRY_ARCHITECTURE #define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 0x8 #define IMAGE_DIRECTORY_ENTRY_TLS 0x9 #define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 0xa #define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 0xb #define IMAGE_DIRECTORY_ENTRY_IAT 0xc #define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 0xd #define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 0xe /* section header */ #define IMAGE_SIZEOF_SHORT_NAME 0x8 #define IMAGE_SCN_TYPE_REG 0x00000000 #define IMAGE_SCN_TYPE_DSECT 0x00000001 #define IMAGE_SCN_TYPE_NOLOAD 0x00000002 #define IMAGE_SCN_TYPE_GROUP 0x00000004 #define IMAGE_SCN_TYPE_NO_PAD 0x00000008 #define IMAGE_SCN_TYPE_COPY 0x00000010 #define IMAGE_SCN_CNT_CODE 0x00000020 #define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 #define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 #define IMAGE_SCN_LNK_OTHER 0x00000100 #define IMAGE_SCN_LNK_INFO 0x00000200 #define IMAGE_SCN_TYPE_OVER 0x00000400 #define IMAGE_SCN_LNK_REMOVE 0x00000800 #define IMAGE_SCN_LNK_COMDAT 0x00001000 #define IMAGE_SCN_MEM_PROTECTED 0x00004000 #define IMAGE_SCN_NO_DEFER_SPEC_EXC 0x00004000 #define IMAGE_SCN_GPREL 0x00008000 #define IMAGE_SCN_MEM_FARDATA 0x00008000 #define IMAGE_SCN_MEM_SYSHEAP 0x00010000 #define IMAGE_SCN_MEM_PURGEABLE 0x00020000 #define IMAGE_SCN_MEM_16BIT 0x00020000 #define IMAGE_SCN_MEM_LOCKED 0x00040000 #define IMAGE_SCN_MEM_PRELOAD 0x00080000 #define IMAGE_SCN_ALIGN_1BYTES 0x00100000 #define IMAGE_SCN_ALIGN_2BYTES 0x00200000 #define IMAGE_SCN_ALIGN_4BYTES 0x00300000 #define IMAGE_SCN_ALIGN_8BYTES 0x00400000 #define IMAGE_SCN_ALIGN_16BYTES 0x00500000 #define IMAGE_SCN_ALIGN_32BYTES 0x00600000 #define IMAGE_SCN_ALIGN_64BYTES 0x00700000 #define IMAGE_SCN_ALIGN_128BYTES 0x00800000 #define IMAGE_SCN_ALIGN_256BYTES 0x00900000 #define IMAGE_SCN_ALIGN_512BYTES 0x00A00000 #define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000 #define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000 #define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000 #define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000 #define IMAGE_SCN_ALIGN_MASK 0x00F00000 #define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 #define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 #define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 #define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 #define IMAGE_SCN_MEM_SHARED 0x10000000 #define IMAGE_SCN_MEM_EXECUTE 0x20000000 #define IMAGE_SCN_MEM_READ 0x40000000 #define IMAGE_SCN_MEM_WRITE 0x80000000 /* relocations */ #define IMAGE_REL_BASED_ABSOLUTE 0x0 #define IMAGE_REL_BASED_HIGH 0x1 #define IMAGE_REL_BASED_LOW 0x2 #define IMAGE_REL_BASED_HIGHLOW 0x3 #define IMAGE_REL_BASED_HIGHADJ 0x4 #define IMAGE_REL_BASED_MIPS_JMPADDR 0x5 #define IMAGE_REL_BASED_SECTION 0x6 #define IMAGE_REL_BASED_REL32 0x7 /*#define IMAGE_REL_BASED_RESERVED1 0x8 */ #define IMAGE_REL_BASED_MIPS_JMPADDR16 0x9 #define IMAGE_REL_BASED_IA64_IMM64 0x9 #define IMAGE_REL_BASED_DIR64 0xa #define IMAGE_REL_BASED_HIGH3ADJ 0xb /* imports */ #define IMAGE_ORDINAL_FLAG32 0x80000000 #define IMAGE_ORDINAL32(ord) ((ord) & 0xffff) #define IMAGE_SNAP_BY_ORDINAL32(ord) (!!((ord) & IMAGE_ORDINAL_FLAG32)) #define IMAGE_ORDINAL_FLAG64 0x8000000000000000ULL #define IMAGE_ORDINAL64(ord) ((ord) & 0xffff) #define IMAGE_SNAP_BY_ORDINAL64(ord) (!!((ord) & IMAGE_ORDINAL_FLAG64)) /* dll/tls entry points argument */ #define DLL_PROCESS_DETACH 0 #define DLL_PROCESS_ATTACH 1 #define DLL_THREAD_ATTACH 2 #define DLL_THREAD_DETACH 3 /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ #pragma pack(4) typedef struct _IMAGE_FILE_HEADER { KU16 Machine; KU16 NumberOfSections; KU32 TimeDateStamp; KU32 PointerToSymbolTable; KU32 NumberOfSymbols; KU16 SizeOfOptionalHeader; KU16 Characteristics; } IMAGE_FILE_HEADER; typedef IMAGE_FILE_HEADER *PIMAGE_FILE_HEADER; typedef struct _ANON_OBJECT_HEADER { KU16 Sig1; KU16 Sig2; KU16 Version; /**< >= 1 */ KU16 Machine; KU32 TimeDataStamp; KU8 ClassID[16]; KU32 SizeOfData; } ANON_OBJECT_HEADER; typedef ANON_OBJECT_HEADER *PANON_OBJECT_HEADER; typedef struct _ANON_OBJECT_HEADER_V2 { KU16 Sig1; KU16 Sig2; KU16 Version; /**< >= 2 */ KU16 Machine; KU32 TimeDataStamp; KU8 ClassID[16]; KU32 SizeOfData; /* New fields for Version >= 2: */ KU32 Flags; KU32 MetaDataSize; /**< CLR metadata */ KU32 MetaDataOffset; } ANON_OBJECT_HEADER_V2; typedef ANON_OBJECT_HEADER_V2 *PANON_OBJECT_HEADER_V2; typedef struct _ANON_OBJECT_HEADER_BIGOBJ { KU16 Sig1; KU16 Sig2; KU16 Version; /**< >= 2 */ KU16 Machine; KU32 TimeDataStamp; KU8 ClassID[16]; /**< ANON_OBJECT_HEADER_BIGOBJ_CLS_ID_BYTES */ KU32 SizeOfData; /* New fields for Version >= 2: */ KU32 Flags; KU32 MetaDataSize; /**< CLR metadata */ KU32 MetaDataOffset; /* Specific for bigobj: */ KU32 NumberOfSections; KU32 PointerToSymbolTable; KU32 NumberOfSymbols; } ANON_OBJECT_HEADER_BIGOBJ; typedef ANON_OBJECT_HEADER_BIGOBJ *PANON_OBJECT_HEADER_BIGOBJ; typedef struct _IMAGE_DATA_DIRECTORY { KU32 VirtualAddress; KU32 Size; } IMAGE_DATA_DIRECTORY; typedef IMAGE_DATA_DIRECTORY *PIMAGE_DATA_DIRECTORY; typedef struct _IMAGE_OPTIONAL_HEADER32 { KU16 Magic; KU8 MajorLinkerVersion; KU8 MinorLinkerVersion; KU32 SizeOfCode; KU32 SizeOfInitializedData; KU32 SizeOfUninitializedData; KU32 AddressOfEntryPoint; KU32 BaseOfCode; KU32 BaseOfData; KU32 ImageBase; KU32 SectionAlignment; KU32 FileAlignment; KU16 MajorOperatingSystemVersion; KU16 MinorOperatingSystemVersion; KU16 MajorImageVersion; KU16 MinorImageVersion; KU16 MajorSubsystemVersion; KU16 MinorSubsystemVersion; KU32 Win32VersionValue; KU32 SizeOfImage; KU32 SizeOfHeaders; KU32 CheckSum; KU16 Subsystem; KU16 DllCharacteristics; KU32 SizeOfStackReserve; KU32 SizeOfStackCommit; KU32 SizeOfHeapReserve; KU32 SizeOfHeapCommit; KU32 LoaderFlags; KU32 NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; } IMAGE_OPTIONAL_HEADER32; typedef IMAGE_OPTIONAL_HEADER32 *PIMAGE_OPTIONAL_HEADER32; typedef struct _IMAGE_OPTIONAL_HEADER64 { KU16 Magic; KU8 MajorLinkerVersion; KU8 MinorLinkerVersion; KU32 SizeOfCode; KU32 SizeOfInitializedData; KU32 SizeOfUninitializedData; KU32 AddressOfEntryPoint; KU32 BaseOfCode; KU64 ImageBase; KU32 SectionAlignment; KU32 FileAlignment; KU16 MajorOperatingSystemVersion; KU16 MinorOperatingSystemVersion; KU16 MajorImageVersion; KU16 MinorImageVersion; KU16 MajorSubsystemVersion; KU16 MinorSubsystemVersion; KU32 Win32VersionValue; KU32 SizeOfImage; KU32 SizeOfHeaders; KU32 CheckSum; KU16 Subsystem; KU16 DllCharacteristics; KU64 SizeOfStackReserve; KU64 SizeOfStackCommit; KU64 SizeOfHeapReserve; KU64 SizeOfHeapCommit; KU32 LoaderFlags; KU32 NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; } IMAGE_OPTIONAL_HEADER64; typedef IMAGE_OPTIONAL_HEADER64 *PIMAGE_OPTIONAL_HEADER64; typedef struct _IMAGE_NT_HEADERS { KU32 Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER32 OptionalHeader; } IMAGE_NT_HEADERS32; typedef IMAGE_NT_HEADERS32 *PIMAGE_NT_HEADERS32; typedef struct _IMAGE_NT_HEADERS64 { KU32 Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER64 OptionalHeader; } IMAGE_NT_HEADERS64; typedef IMAGE_NT_HEADERS64 *PIMAGE_NT_HEADERS64; typedef struct _IMAGE_SECTION_HEADER { KU8 Name[IMAGE_SIZEOF_SHORT_NAME]; union { KU32 PhysicalAddress; KU32 VirtualSize; } Misc; KU32 VirtualAddress; KU32 SizeOfRawData; KU32 PointerToRawData; KU32 PointerToRelocations; KU32 PointerToLinenumbers; KU16 NumberOfRelocations; KU16 NumberOfLinenumbers; KU32 Characteristics; } IMAGE_SECTION_HEADER; typedef IMAGE_SECTION_HEADER *PIMAGE_SECTION_HEADER; typedef struct _IMAGE_BASE_RELOCATION { KU32 VirtualAddress; KU32 SizeOfBlock; } IMAGE_BASE_RELOCATION; typedef IMAGE_BASE_RELOCATION *PIMAGE_BASE_RELOCATION; typedef struct _IMAGE_EXPORT_DIRECTORY { KU32 Characteristics; KU32 TimeDateStamp; KU16 MajorVersion; KU16 MinorVersion; KU32 Name; KU32 Base; KU32 NumberOfFunctions; KU32 NumberOfNames; KU32 AddressOfFunctions; KU32 AddressOfNames; KU32 AddressOfNameOrdinals; } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; typedef struct _IMAGE_IMPORT_DESCRIPTOR { union { KU32 Characteristics; KU32 OriginalFirstThunk; } u; KU32 TimeDateStamp; KU32 ForwarderChain; KU32 Name; KU32 FirstThunk; } IMAGE_IMPORT_DESCRIPTOR; typedef IMAGE_IMPORT_DESCRIPTOR *PIMAGE_IMPORT_DESCRIPTOR; typedef struct _IMAGE_IMPORT_BY_NAME { KU16 Hint; KU8 Name[1]; } IMAGE_IMPORT_BY_NAME; typedef IMAGE_IMPORT_BY_NAME *PIMAGE_IMPORT_BY_NAME; /* The image_thunk_data32/64 structures are not very helpful except for getting RSI. keep them around till all the code has been converted. */ typedef struct _IMAGE_THUNK_DATA64 { union { KU64 ForwarderString; KU64 Function; KU64 Ordinal; KU64 AddressOfData; } u1; } IMAGE_THUNK_DATA64; typedef IMAGE_THUNK_DATA64 *PIMAGE_THUNK_DATA64; typedef struct _IMAGE_THUNK_DATA32 { union { KU32 ForwarderString; KU32 Function; KU32 Ordinal; KU32 AddressOfData; } u1; } IMAGE_THUNK_DATA32; typedef IMAGE_THUNK_DATA32 *PIMAGE_THUNK_DATA32; typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32 { KU32 Size; KU32 TimeDateStamp; KU16 MajorVersion; KU16 MinorVersion; KU32 GlobalFlagsClear; KU32 GlobalFlagsSet; KU32 CriticalSectionDefaultTimeout; KU32 DeCommitFreeBlockThreshold; KU32 DeCommitTotalFreeThreshold; KU32 LockPrefixTable; KU32 MaximumAllocationSize; KU32 VirtualMemoryThreshold; KU32 ProcessHeapFlags; KU32 ProcessAffinityMask; KU16 CSDVersion; KU16 Reserved1; KU32 EditList; KU32 SecurityCookie; KU32 SEHandlerTable; KU32 SEHandlerCount; } IMAGE_LOAD_CONFIG_DIRECTORY32; typedef IMAGE_LOAD_CONFIG_DIRECTORY32 PIMAGE_LOAD_CONFIG_DIRECTORY32; typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64 { KU32 Size; KU32 TimeDateStamp; KU16 MajorVersion; KU16 MinorVersion; KU32 GlobalFlagsClear; KU32 GlobalFlagsSet; KU32 CriticalSectionDefaultTimeout; KU64 DeCommitFreeBlockThreshold; KU64 DeCommitTotalFreeThreshold; KU64 LockPrefixTable; KU64 MaximumAllocationSize; KU64 VirtualMemoryThreshold; KU64 ProcessAffinityMask; KU32 ProcessHeapFlags; KU16 CSDVersion; KU16 Reserved1; KU64 EditList; KU64 SecurityCookie; KU64 SEHandlerTable; KU64 SEHandlerCount; } IMAGE_LOAD_CONFIG_DIRECTORY64; typedef IMAGE_LOAD_CONFIG_DIRECTORY64 *PIMAGE_LOAD_CONFIG_DIRECTORY64; typedef struct _IMAGE_DEBUG_DIRECTORY { KU32 Characteristics; KU32 TimeDateStamp; KU16 MajorVersion; KU16 MinorVersion; KU32 Type; KU32 SizeOfData; KU32 AddressOfRawData; KU32 PointerToRawData; } IMAGE_DEBUG_DIRECTORY; typedef IMAGE_DEBUG_DIRECTORY *PIMAGE_DEBUG_DIRECTORY; #define IMAGE_DEBUG_TYPE_UNKNOWN 0 #define IMAGE_DEBUG_TYPE_COFF 1 #define IMAGE_DEBUG_TYPE_CODEVIEW 2 /* 4.0 */ #define IMAGE_DEBUG_TYPE_FPO 3 /* FPO = frame pointer omission */ #define IMAGE_DEBUG_TYPE_MISC 4 #define IMAGE_DEBUG_TYPE_EXCEPTION 5 #define IMAGE_DEBUG_TYPE_FIXUP 6 #define IMAGE_DEBUG_TYPE_BORLAND 9 typedef struct _IMAGE_TLS_DIRECTORY32 { KU32 StartAddressOfRawData; KU32 EndAddressOfRawData; KU32 AddressOfIndex; KU32 AddressOfCallBacks; KU32 SizeOfZeroFill; KU32 Characteristics; } IMAGE_TLS_DIRECTORY32; typedef IMAGE_TLS_DIRECTORY32 *PIMAGE_TLS_DIRECTORY32; typedef struct _IMAGE_TLS_DIRECTORY64 { KU64 StartAddressOfRawData; KU64 EndAddressOfRawData; KU64 AddressOfIndex; KU64 AddressOfCallBacks; KU32 SizeOfZeroFill; KU32 Characteristics; } IMAGE_TLS_DIRECTORY64; typedef IMAGE_TLS_DIRECTORY64 *PIMAGE_TLS_DIRECTORY64; #pragma pack() #endif kbuild-3149/src/lib/kStuff/include/k/kLdrFmts/mz.h0000644000175000017500000000404213252530253021705 0ustar locutuslocutus/* $Id: mz.h 31 2009-07-01 21:08:06Z bird $ */ /** @file * MZ structures, types and defines. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___k_kLdrFmts_mz_h___ #define ___k_kLdrFmts_mz_h___ #include #include #pragma pack(1) /* not required */ typedef struct _IMAGE_DOS_HEADER { KU16 e_magic; KU16 e_cblp; KU16 e_cp; KU16 e_crlc; KU16 e_cparhdr; KU16 e_minalloc; KU16 e_maxalloc; KU16 e_ss; KU16 e_sp; KU16 e_csum; KU16 e_ip; KU16 e_cs; KU16 e_lfarlc; KU16 e_ovno; KU16 e_res[4]; KU16 e_oemid; KU16 e_oeminfo; KU16 e_res2[10]; KU32 e_lfanew; } IMAGE_DOS_HEADER; typedef IMAGE_DOS_HEADER *PIMAGE_DOS_HEADER; #ifndef IMAGE_DOS_SIGNATURE # define IMAGE_DOS_SIGNATURE K_LE2H_U16('M' | ('Z' << 8)) #endif #pragma pack() #endif kbuild-3149/src/lib/kStuff/include/k/kCpu.h0000644000175000017500000000402013252530253020427 0ustar locutuslocutus/* $Id: kCpu.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kCpu - The CPU and Architecture API. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___k_kCpu_h___ #define ___k_kCpu_h___ #include #include #include /** @defgroup grp_kCpu kCpu - The CPU And Architecture API * @{ */ /** @def KCPU_DECL * Declares a kCpu function according to build context. * @param type The return type. */ #if defined(KCPU_BUILDING_DYNAMIC) # define KCPU_DECL(type) K_DECL_EXPORT(type) #elif defined(KCPU_BUILT_DYNAMIC) # define KCPU_DECL(type) K_DECL_IMPORT(type) #else # define KCPU_DECL(type) type #endif #ifdef __cplusplus extern "C" { #endif KCPU_DECL(void) kCpuGetArchAndCpu(PKCPUARCH penmArch, PKCPU penmCpu); KCPU_DECL(int) kCpuCompare(KCPUARCH enmCodeArch, KCPU enmCodeCpu, KCPUARCH enmArch, KCPU enmCpu); #ifdef __cplusplus } #endif /** @} */ #endif kbuild-3149/src/lib/kStuff/include/k/kHlp.h0000644000175000017500000000317213252530253020432 0ustar locutuslocutus/* $Id: kHlp.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlp - Helpers, All Of Them. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___k_kHlp_h___ #define ___k_kHlp_h___ #include #include #include #include #include #include #include #include #include #include #include /** @defgroup grp_kHlp kHlp - Helper Functions * @{ */ /** @} */ #endif kbuild-3149/src/lib/kStuff/include/k/kHlpThread.h0000644000175000017500000000311713252530253021561 0ustar locutuslocutus/* $Id: kHlpThread.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpThread - Thread Manipulation. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___k_kHlpThread_h___ #define ___k_kHlpThread_h___ #include #include /** @defgroup grp_kHlpThread kHlpThread - Thread Management * @addtogroup grp_kHlp * @{*/ #ifdef __cplusplus extern "C" { #endif KHLP_DECL(void) kHlpSleep(unsigned cMillies); #ifdef __cplusplus } #endif /** @} */ #endif kbuild-3149/src/lib/kStuff/include/k/kHlpEnv.h0000644000175000017500000000324113252530253021100 0ustar locutuslocutus/* $Id: kHlpEnv.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpEnv - Environment Manipulation. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___k_kHlpEnv_h___ #define ___k_kHlpEnv_h___ #include #include /** @defgroup grp_kHlpEnv kHlpEnv - Environment Manipulation * @addtogroup grp_kHlp * @{*/ #ifdef __cplusplus extern "C" { #endif KHLP_DECL(int) kHlpGetEnv(const char *pszVar, char *pszVal, KSIZE cchVal); KHLP_DECL(int) kHlpGetEnvUZ(const char *pszVar, KSIZE *pcb); #ifdef __cplusplus } #endif /** @} */ #endif kbuild-3149/src/lib/kStuff/include/k/kRbU32.h0000644000175000017500000000443013252530253020542 0ustar locutuslocutus/* $Id: kRbU32.h 35 2009-11-08 19:39:03Z bird $ */ /** @file * kRb - Red-Black Tree Implementation, KU32 keys. */ /* * Copyright (c) 2006-2009 Knut St. Osmundsen * * 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. */ #ifndef ___k_kRbU32_h___ #define ___k_kRbU32_h___ typedef struct KRBU32 { KU32 mKey; KBOOL mfRed; struct KRBU32 *mpLeft; struct KRBU32 *mpRight; } KRBU32; typedef KRBU32 *PRBU32; typedef KRBU32 **PPRBU32; /*#define KRB_EQUAL_ALLOWED*/ #define KRB_CHECK_FOR_EQUAL_INSERT /*#define KRB_RANGE */ /*#define KRB_OFFSET */ #define KRB_MAX_STACK 48 #define KRB_STD_KEY_COMP #define KRBKEY KU32 #define KRBNODE KRBU32 #define KRB_FN(name) kRbU32 ## name #define KRB_TYPE(prefix,name) prefix ## KRBU32 ## name #define KRB_INT(name) KRBU32INT ## name #define KRB_DECL(rettype) K_DECL_INLINE(rettype) #include #include #include #include #include #include #include #include #include #endif kbuild-3149/src/lib/kStuff/include/k/kMagics.h0000644000175000017500000000311013252530253021102 0ustar locutuslocutus/* $Id: kMagics.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kMagics - Various Magic Constants. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___k_kMagics_h___ #define ___k_kMagics_h___ /** The magic for KRDR::u32Magic. (Katsu Aki (Katsuaki Nakamura)) * @ingroup grp_kRdrAll */ #define KRDR_MAGIC 0x19610919 /** The magic value for the debug module structure. (Some manga artist) * @ingroup grp_kDbgAll */ #define KDBGMOD_MAGIC 0x19200501 #endif kbuild-3149/src/lib/kStuff/include/k/kHlpString.h0000644000175000017500000001200713252530253021616 0ustar locutuslocutus/* $Id: kHlpString.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpString - String And Memory Routines. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___k_kHlpString_h___ #define ___k_kHlpString_h___ #include #include #if 0 /* optimize / fix this later */ #ifdef __GNUC__ /** memchr */ # define kHlpMemChr(a,b,c) __builtin_memchr(a,b,c) /** memcmp */ # define kHlpMemComp(a,b,c) __builtin_memcmp(a,b,c) /** memcpy */ # define kHlpMemCopy(a,b,c) __builtin_memcpy(a,b,c) /** memset */ # define kHlpMemSet(a,b,c) __builtin_memset(a,b,c) /** strchr */ # define kHlpStrChr(a, b) __builtin_strchr(a, b) /** strcmp */ # define kHlpStrComp(a, b) __builtin_strcmp(a, b) /** strncmp */ # define kHlpStrNComp(a,b,c) __builtin_strncmp(a, b, c) /** strlen */ # define kHlpStrLen(a) __builtin_strlen(a) #elif defined(_MSC_VER) # pragma intrinsic(memcmp, memcpy, memset, strcmp, strlen) /** memcmp */ # define kHlpMemComp(a,b,c) memcmp(a,b,c) /** memcpy */ # define kHlpMemCopy(a,b,c) memcpy(a,b,c) /** memset */ # define kHlpMemSet(a,b,c) memset(a,b,c) /** strcmp */ # define kHlpStrComp(a, b) strcmp(a, b) /** strlen */ # define kHlpStrLen(a) strlen(a) #else # error "Port Me" #endif #endif /* disabled */ #ifdef __cplusplus extern "C" { #endif #ifndef kHlpMemChr KHLP_DECL(void *) kHlpMemChr(const void *pv, int ch, KSIZE cb); #endif #ifndef kHlpMemComp KHLP_DECL(int) kHlpMemComp(const void *pv1, const void *pv2, KSIZE cb); #endif #ifndef kHlpMemComp KHLP_DECL(void *) kHlpMemPComp(const void *pv1, const void *pv2, KSIZE cb); #endif #ifndef kHlpMemCopy KHLP_DECL(void *) kHlpMemCopy(void *pv1, const void *pv2, KSIZE cb); #endif #ifndef kHlpMemPCopy KHLP_DECL(void *) kHlpMemPCopy(void *pv1, const void *pv2, KSIZE cb); #endif #ifndef kHlpMemMove KHLP_DECL(void *) kHlpMemMove(void *pv1, const void *pv2, KSIZE cb); #endif #ifndef kHlpMemPMove KHLP_DECL(void *) kHlpMemPMove(void *pv1, const void *pv2, KSIZE cb); #endif #ifndef kHlpMemSet KHLP_DECL(void *) kHlpMemSet(void *pv1, int ch, KSIZE cb); #endif #ifndef kHlpMemPSet KHLP_DECL(void *) kHlpMemPSet(void *pv1, int ch, KSIZE cb); #endif KHLP_DECL(int) kHlpMemICompAscii(const void *pv1, const void *pv2, KSIZE cb); #ifndef kHlpStrCat KHLP_DECL(char *) kHlpStrCat(char *psz1, const char *psz2); #endif #ifndef kHlpStrPCat KHLP_DECL(char *) kHlpStrPCat(char *psz1, const char *psz2); #endif #ifndef kHlpStrNCat KHLP_DECL(char *) kHlpStrNCat(char *psz1, const char *psz2, KSIZE cb); #endif #ifndef kHlpStrPNCat KHLP_DECL(char *) kHlpStrNPCat(char *psz1, const char *psz2, KSIZE cb); #endif #ifndef kHlpStrChr KHLP_DECL(char *) kHlpStrChr(const char *psz, int ch); #endif #ifndef kHlpStrRChr KHLP_DECL(char *) kHlpStrRChr(const char *psz, int ch); #endif #ifndef kHlpStrComp KHLP_DECL(int) kHlpStrComp(const char *psz1, const char *psz2); #endif KHLP_DECL(char *) kHlpStrPComp(const char *psz1, const char *psz2); #ifndef kHlpStrNComp KHLP_DECL(int) kHlpStrNComp(const char *psz1, const char *psz2, KSIZE cch); #endif KHLP_DECL(char *) kHlpStrNPComp(const char *psz1, const char *psz2, KSIZE cch); KHLP_DECL(int) kHlpStrICompAscii(const char *pv1, const char *pv2); KHLP_DECL(char *) kHlpStrIPCompAscii(const char *pv1, const char *pv2); KHLP_DECL(int) kHlpStrNICompAscii(const char *pv1, const char *pv2, KSIZE cch); KHLP_DECL(char *) kHlpStrNIPCompAscii(const char *pv1, const char *pv2, KSIZE cch); #ifndef kHlpStrCopy KHLP_DECL(char *) kHlpStrCopy(char *psz1, const char *psz2); #endif #ifndef kHlpStrPCopy KHLP_DECL(char *) kHlpStrPCopy(char *psz1, const char *psz2); #endif #ifndef kHlpStrLen KHLP_DECL(KSIZE) kHlpStrLen(const char *psz1); #endif #ifndef kHlpStrNLen KHLP_DECL(KSIZE) kHlpStrNLen(const char *psz, KSIZE cchMax); #endif KHLP_DECL(char *) kHlpInt2Ascii(char *psz, KSIZE cch, long lVal, unsigned iBase); #ifdef __cplusplus } #endif #endif kbuild-3149/src/lib/kStuff/include/k/kRbTmpl/0000755000175000017500000000000013252530253020733 5ustar locutuslocutuskbuild-3149/src/lib/kStuff/include/k/kRbTmpl/kRbDestroy.h0000644000175000017500000001031213252530253023171 0ustar locutuslocutus/* $Id: kRbDestroy.h 35 2009-11-08 19:39:03Z bird $ */ /** @file * kRbTmpl - Templated Red-Black Trees, Destroy the tree. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * 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. */ /** * Destroys the specified tree, starting with the root node and working our way down. * * @returns 0 on success. * @returns Return value from callback on failure. On failure, the tree will be in * an unbalanced condition and only further calls to the Destroy should be * made on it. Note that the node we fail on will be considered dead and * no action is taken to link it back into the tree. * @param pRoot Pointer to the Red-Back tree's root structure. * @param pfnCallBack Pointer to callback function. * @param pvUser User parameter passed on to the callback function. */ KRB_DECL(int) KRB_FN(Destroy)(KRBROOT *pRoot, KRB_TYPE(PFN,CALLBACK) pfnCallBack, void *pvUser) { #ifdef KRB_CACHE_SIZE unsigned i; #endif unsigned cEntries; KRBNODE *apEntries[KRB_MAX_STACK]; int rc; KRB_WRITE_LOCK(pRoot); if (pRoot->mpRoot == KRB_NULL) { KRB_WRITE_UNLOCK(pRoot); return 0; } #ifdef KRB_CACHE_SIZE /* * Kill the lookthru cache. */ for (i = 0; i < (KRB_CACHE_SIZE); i++) pRoot->maLookthru[i] = KRB_NULL; #endif cEntries = 1; apEntries[0] = KRB_GET_POINTER(&pRoot->mpRoot); while (cEntries > 0) { /* * Process the subtrees first. */ KRBNODE *pNode = apEntries[cEntries - 1]; if (pNode->mpLeft != KRB_NULL) apEntries[cEntries++] = KRB_GET_POINTER(&pNode->mpLeft); else if (pNode->mpRight != KRB_NULL) apEntries[cEntries++] = KRB_GET_POINTER(&pNode->mpRight); else { #ifdef KRB_EQUAL_ALLOWED /* * Process nodes with the same key. */ while (pNode->pList != KRB_NULL) { KRBNODE *pEqual = KRB_GET_POINTER(&pNode->pList); KRB_SET_POINTER(&pNode->pList, KRB_GET_POINTER_NULL(&pEqual->pList)); pEqual->pList = KRB_NULL; rc = pfnCallBack(pEqual, pvUser); if (rc) { KRB_WRITE_UNLOCK(pRoot); return rc; } } #endif /* * Unlink the node. */ if (--cEntries > 0) { KRBNODE *pParent = apEntries[cEntries - 1]; if (KRB_GET_POINTER(&pParent->mpLeft) == pNode) pParent->mpLeft = KRB_NULL; else pParent->mpRight = KRB_NULL; } else pRoot->mpRoot = KRB_NULL; kHlpAssert(pNode->mpLeft == KRB_NULL); kHlpAssert(pNode->mpRight == KRB_NULL); rc = pfnCallBack(pNode, pvUser); if (rc) { KRB_WRITE_UNLOCK(pRoot); return rc; } } } /* while */ kHlpAssert(pRoot->mpRoot == KRB_NULL); KRB_WRITE_UNLOCK(pRoot); return 0; } kbuild-3149/src/lib/kStuff/include/k/kRbTmpl/kRbRemove2.h0000644000175000017500000001060613252530253023065 0ustar locutuslocutus/* $Id: kRbRemove2.h 35 2009-11-08 19:39:03Z bird $ */ /** @file * kRbTmpl - Templated Red-Black Trees, Remove A Specific Node. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * 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. */ /** * Removes the specified node from the tree. * * @returns Pointer to the removed node (NULL if not in the tree) * @param pRoot Pointer to the Red-Back tree's root structure. * @param Key The Key of which is to be found a best fitting match for.. * * @remark This implementation isn't the most efficient, but this short and * easier to manage. */ KRB_DECL(KRBNODE *) KRB_FN(Remove2)(KRBROOT *pRoot, KRBNODE *pNode) { #ifdef KRB_EQUAL_ALLOWED /* * Find the right node by key and see if it's what we want. */ KRBNODE *pParent; KRBNODE *pCurNode = KRB_FN(GetWithParent)(pRoot, pNode->mKey, &pParent); if (!pCurNode) return NULL; KRB_WRITE_LOCK(pRoot); /** @todo the locking here isn't 100% sane. The only way to archive that is by no calling worker functions. */ if (pCurNode != pNode) { /* * It's not the one we want, but it could be in the duplicate list. */ while (pCurNode->mpList != KRB_NULL) { KRBNODE *pNext = KRB_GET_POINTER(&pCurNode->mpList); if (pNext == pNode) { KRB_SET_POINTER_NULL(&pCurNode->mpList, KRB_GET_POINTER_NULL(&pNode->mpList)); pNode->mpList = KRB_NULL; KRB_CACHE_INVALIDATE_NODE(pRoot, pNode, pNode->mKey); KRB_WRITE_UNLOCK(pRoot); return pNode; } pCurNode = pNext; } KRB_WRITE_UNLOCK(pRoot); return NULL; } /* * Ok, it's the one we want alright. * * Simply remove it if it's the only one with they Key, * if there are duplicates we'll have to unlink it and * insert the first duplicate in our place. */ if (pNode->mpList == KRB_NULL) { KRB_WRITE_UNLOCK(pRoot); KRB_FN(Remove)(pRoot, pNode->mKey); } else { KRBNODE *pNewUs = KRB_GET_POINTER(&pNode->mpList); pNewUs->mHeight = pNode->mHeight; if (pNode->mpLeft != KRB_NULL) KRB_SET_POINTER(&pNewUs->mpLeft, KRB_GET_POINTER(&pNode->mpLeft)) else pNewUs->mpLeft = KRB_NULL; if (pNode->mpRight != KRB_NULL) KRB_SET_POINTER(&pNewUs->mpRight, KRB_GET_POINTER(&pNode->mpRight)) else pNewUs->mpRight = KRB_NULL; if (pParent) { if (KRB_GET_POINTER_NULL(&pParent->mpLeft) == pNode) KRB_SET_POINTER(&pParent->mpLeft, pNewUs); else KRB_SET_POINTER(&pParent->mpRight, pNewUs); } else KRB_SET_POINTER(&pRoot->mpRoot, pNewUs); KRB_CACHE_INVALIDATE_NODE(pRoot, pNode, pNode->mKey); KRB_WRITE_UNLOCK(pRoot); } return pNode; #else /* * Delete it, if we got the wrong one, reinsert it. * * This ASSUMS that the caller is NOT going to hand us a lot * of wrong nodes but just uses this API for his convenience. */ KRBNODE *pRemovedNode = KRB_FN(Remove)(pRoot, pNode->mKey); if (pRemovedNode == pNode) return pRemovedNode; KRB_FN(Insert)(pRoot, pRemovedNode); return NULL; #endif } kbuild-3149/src/lib/kStuff/include/k/kRbTmpl/kRbEnum.h0000644000175000017500000001457313252530253022461 0ustar locutuslocutus/* $Id: kRbEnum.h 35 2009-11-08 19:39:03Z bird $ */ /** @file * kRbTmpl - Templated Red-Black Trees, Node Enumeration. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * Enumeration control data. * * This is initialized by BeginEnum and used by GetNext to figure out what * to do next. */ typedef struct KRB_TYPE(,ENUMDATA) { KBOOL fFromLeft; KI8 cEntries; KU8 achFlags[KRB_MAX_STACK]; KRBNODE * aEntries[KRB_MAX_STACK]; } KRB_TYPE(,ENUMDATA), *KRB_TYPE(P,ENUMDATA); /** * Ends an enumeration. * * The purpose of this function is to unlock the tree should the Red-Black tree * implementation include locking. It's good practice to call it anyway even if * the tree doesn't do any locking. * * @param pEnumData Pointer to enumeration control data. */ KRB_DECL(void) KRB_FN(EndEnum)(KRB_TYPE(,ENUMDATA) *pEnumData) { KRBROOT pRoot = pEnumData->pRoot; pEnumData->pRoot = NULL; if (pRoot) KRB_READ_UNLOCK(pEnumData->pRoot); } /** * Get the next node in the tree enumeration. * * The current implementation of this function willl not walk the mpList * chain like the DoWithAll function does. This may be changed later. * * @returns Pointer to the next node in the tree. * NULL is returned when the end of the tree has been reached, * it is not necessary to call EndEnum in this case. * @param pEnumData Pointer to enumeration control data. */ KRB_DECL(KRBNODE *) KRB_FN(GetNext)(KRB_TYPE(,ENUMDATA) *pEnumData) { if (pEnumData->fFromLeft) { /* from left */ while (pEnumData->cEntries > 0) { KRBNODE *pNode = pEnumData->aEntries[pEnumData->cEntries - 1]; /* left */ if (pEnumData->achFlags[pEnumData->cEntries - 1] == 0) { pEnumData->achFlags[pEnumData->cEntries - 1]++; if (pNode->mpLeft != KRB_NULL) { pEnumData->achFlags[pEnumData->cEntries] = 0; /* 0 left, 1 center, 2 right */ pEnumData->aEntries[pEnumData->cEntries++] = KRB_GET_POINTER(&pNode->mpLeft); continue; } } /* center */ if (pEnumData->achFlags[pEnumData->cEntries - 1] == 1) { pEnumData->achFlags[pEnumData->cEntries - 1]++; return pNode; } /* right */ pEnumData->cEntries--; if (pNode->mpRight != KRB_NULL) { pEnumData->achFlags[pEnumData->cEntries] = 0; pEnumData->aEntries[pEnumData->cEntries++] = KRB_GET_POINTER(&pNode->mpRight); } } /* while */ } else { /* from right */ while (pEnumData->cEntries > 0) { KRBNODE *pNode = pEnumData->aEntries[pEnumData->cEntries - 1]; /* right */ if (pEnumData->achFlags[pEnumData->cEntries - 1] == 0) { pEnumData->achFlags[pEnumData->cEntries - 1]++; if (pNode->mpRight != KRB_NULL) { pEnumData->achFlags[pEnumData->cEntries] = 0; /* 0 right, 1 center, 2 left */ pEnumData->aEntries[pEnumData->cEntries++] = KRB_GET_POINTER(&pNode->mpRight); continue; } } /* center */ if (pEnumData->achFlags[pEnumData->cEntries - 1] == 1) { pEnumData->achFlags[pEnumData->cEntries - 1]++; return pNode; } /* left */ pEnumData->cEntries--; if (pNode->mpLeft != KRB_NULL) { pEnumData->achFlags[pEnumData->cEntries] = 0; pEnumData->aEntries[pEnumData->cEntries++] = KRB_GET_POINTER(&pNode->mpLeft); } } /* while */ } /* * Call EndEnum. */ KRB_FN(EndEnum)(pEnumData); return NULL; } /** * Starts an enumeration of all nodes in the given tree. * * The current implementation of this function will not walk the mpList * chain like the DoWithAll function does. This may be changed later. * * @returns Pointer to the first node in the enumeration. * If NULL is returned the tree is empty calling EndEnum isn't * strictly necessary (although it will do no harm). * @param pRoot Pointer to the Red-Back tree's root structure. * @param pEnumData Pointer to enumeration control data. * @param fFromLeft K_TRUE: Left to right. * K_FALSE: Right to left. */ KRB_DECL(KRBNODE *) KRB_FN(BeginEnum)(KRBROOT *pRoot, KRB_TYPE(,ENUMDATA) *pEnumData, KBOOL fFromLeft) { KRB_READ_LOCK(pRoot); pEnumData->pRoot = pRoot; if (pRoot->mpRoot != KRB_NULL) { pEnumData->fFromLeft = fFromLeft; pEnumData->cEntries = 1; pEnumData->aEntries[0] = KRB_GET_POINTER(pRoot->mpRoot); pEnumData->achFlags[0] = 0; } else pEnumData->cEntries = 0; return KRB_FN(GetNext)(pEnumData); } kbuild-3149/src/lib/kStuff/include/k/kRbTmpl/kRbBase.h0000644000175000017500000004611713252530253022426 0ustar locutuslocutus/* $Id: kRbBase.h 38 2009-11-10 00:01:38Z bird $ */ /** @file * kRbTmpl - Templated Red-Black Trees, The Mandatory Base Code. */ /* * Copyright (c) 2001-2009 Knut St. Osmundsen * * 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. */ /** @page pg_kAvlTmpl Template Configuration. * * This is a templated implementation of Red-Black trees in C. The template * parameters relates to the kind of key used and how duplicates are treated. * * \#define KRB_EQUAL_ALLOWED * Define this to tell us that equal keys are allowed. * Then Equal keys will be put in a list pointed to by KRBNODE::pList. * This is by default not defined. * * \#define KRB_CHECK_FOR_EQUAL_INSERT * Define this to enable insert check for equal nodes. * This is by default not defined. * * \#define KRB_MAX_STACK * Use this to specify the max number of stack entries the stack will use when * inserting and removing nodes from the tree. The size should be something like * log2() + 3 * Must be defined. * * \#define KRB_RANGE * Define this to enable key ranges. * * \#define KRB_OFFSET * Define this to link the tree together using self relative offset * instead of memory pointers, thus making the entire tree relocatable * provided all the nodes - including the root node variable - are moved * the exact same distance. * * \#define KRB_CACHE_SIZE * Define this to employ a lookthru cache (direct) to speed up lookup for * some usage patterns. The value should be the number of members of the array. * * \#define KRB_CACHE_HASH(Key) * Define this to specify a more efficient translation of the key into * a lookthru array index. The default is key % size. * For some key types this is required as the default will not compile. * * \#define KRB_LOCKED * Define this if you wish for the tree to be locked via the * KRB_WRITE_LOCK, KRB_WRITE_UNLOCK, KRB_READ_LOCK and * KRB_READ_UNLOCK macros. If not defined the tree will not be subject * do any kind of locking and the problem of concurrency is left the user. * * \#define KRB_WRITE_LOCK(pRoot) * Lock the tree for writing. * * \#define KRB_WRITE_UNLOCK(pRoot) * Counteracts KRB_WRITE_LOCK. * * \#define KRB_READ_LOCK(pRoot) * Lock the tree for reading. * * \#define KRB_READ_UNLOCK(pRoot) * Counteracts KRB_READ_LOCK. * * \#define KRBKEY * Define this to the name of the AVL key type. * * \#define KRB_STD_KEY_COMP * Define this to use the standard key compare macros. If not set all the * compare operations for KRBKEY have to be defined: KRB_CMP_G, KRB_CMP_E, KRB_CMP_NE, * KRB_R_IS_IDENTICAL, KRB_R_IS_INTERSECTING and KRB_R_IS_IN_RANGE. The * latter three are only required when KRB_RANGE is defined. * * \#define KRBNODE * Define this to the name (typedef) of the AVL node structure. This * structure must have a mpLeft, mpRight, mKey and mHeight member. * If KRB_RANGE is defined a mKeyLast is also required. * If KRB_EQUAL_ALLOWED is defined a mpList member is required. * It's possible to use other member names by redefining the names. * * \#define KRBTREEPTR * Define this to the name (typedef) of the tree pointer type. This is * required when KRB_OFFSET is defined. When not defined it defaults * to KRBNODE *. * * \#define KRBROOT * Define this to the name (typedef) of the AVL root structure. This * is optional. However, if specified it must at least have a mpRoot * member of KRBTREEPTR type. If KRB_CACHE_SIZE is non-zero a * maLookthru[KRB_CACHE_SIZE] member of the KRBTREEPTR type is also * required. * * \#define KRB_FN * Use this to alter the names of the AVL functions. * Must be defined. * * \#define KRB_TYPE(prefix, name) * Use this to make external type names and unique. The prefix may be empty. * Must be defined. * * \#define KRB_INT(name) * Use this to make internal type names and unique. The prefix may be empty. * Must be defined. * * \#define KRB_DECL(rettype) * Function declaration macro that should be set according to the scope * the instantiated template should have. For instance an inlined scope * (private or public) should K_DECL_INLINE(rettype) here. * * This version of the kAVL tree offers the option of inlining the entire * implementation. This depends on the compiler doing a decent job in both * making use of the inlined code and to eliminate const variables. */ /******************************************************************************* * Internal Functions * *******************************************************************************/ #include #include #include /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** @def KRB_GET_POINTER * Reads a 'pointer' value. * * @returns The native pointer. * @param pp Pointer to the pointer to read. * @internal */ /** @def KRB_GET_POINTER_NULL * Reads a 'pointer' value which can be KRB_NULL. * * @returns The native pointer. * @returns NULL pointer if KRB_NULL. * @param pp Pointer to the pointer to read. * @internal */ /** @def KRB_SET_POINTER * Writes a 'pointer' value. * For offset-based schemes offset relative to pp is calculated and assigned to *pp. * * @returns stored pointer. * @param pp Pointer to where to store the pointer. * @param p Native pointer to assign to *pp. * @internal */ /** @def KRB_SET_POINTER_NULL * Writes a 'pointer' value which can be KRB_NULL. * * For offset-based schemes offset relative to pp is calculated and assigned to *pp, * if p is not KRB_NULL of course. * * @returns stored pointer. * @param pp Pointer to where to store the pointer. * @param pp2 Pointer to where to pointer to assign to pp. This can be KRB_NULL * @internal */ #ifndef KRBTREEPTR # define KRBTREEPTR KRBNODE * #endif #ifndef KRBROOT # define KRBROOT KRB_TYPE(,ROOT) # define KRB_NEED_KRBROOT #endif #ifdef KRB_CACHE_SIZE # ifndef KRB_CACHE_HASH # define KRB_CACHE_HASH(Key) ( (Key) % (KRB_CACHE_SIZE) ) # endif #elif defined(KRB_CACHE_HASH) # error "KRB_CACHE_HASH without KRB_CACHE_SIZE!" #endif #ifdef KRB_CACHE_SIZE # define KRB_CACHE_INVALIDATE_NODE(pRoot, pNode, Key) \ do { \ KRBTREEPTR **ppEntry = &pRoot->maLookthru[KRB_CACHE_HASH(Key)]; \ if ((pNode) == KRB_GET_POINTER_NULL(ppEntry)) \ *ppEntry = KRB_NULL; \ } while (0) #else # define KRB_CACHE_INVALIDATE_NODE(pRoot, pNode, Key) do { } while (0) #endif #ifndef KRB_LOCKED # define KRB_WRITE_LOCK(pRoot) do { } while (0) # define KRB_WRITE_UNLOCK(pRoot) do { } while (0) # define KRB_READ_LOCK(pRoot) do { } while (0) # define KRB_READ_UNLOCK(pRoot) do { } while (0) #endif #ifdef KRB_OFFSET # define KRB_GET_POINTER(pp) ( (KRBNODE *)((KIPTR)(pp) + *(pp)) ) # define KRB_GET_POINTER_NULL(pp) ( *(pp) != KRB_NULL ? KRB_GET_POINTER(pp) : NULL ) # define KRB_SET_POINTER(pp, p) ( (*(pp)) = ((KIPTR)(p) - (KIPTR)(pp)) ) # define KRB_SET_POINTER_NULL(pp, pp2) ( (*(pp)) = *(pp2) != KRB_NULL ? (KIPTR)KRB_GET_POINTER(pp2) - (KIPTR)(pp) : KRB_NULL ) #else # define KRB_GET_POINTER(pp) ( *(pp) ) # define KRB_GET_POINTER_NULL(pp) ( *(pp) ) # define KRB_SET_POINTER(pp, p) ( (*(pp)) = (p) ) # define KRB_SET_POINTER_NULL(pp, pp2) ( (*(pp)) = *(pp2) ) #endif /** @def KRB_NULL * The NULL 'pointer' equivalent. */ #ifdef KRB_OFFSET # define KRB_NULL 0 #else # define KRB_NULL NULL #endif #ifdef KRB_STD_KEY_COMP # define KRB_CMP_G(key1, key2) ( (key1) > (key2) ) # define KRB_CMP_E(key1, key2) ( (key1) == (key2) ) # define KRB_CMP_NE(key1, key2) ( (key1) != (key2) ) # ifdef KRB_RANGE # define KRB_R_IS_IDENTICAL(key1B, key2B, key1E, key2E) ( (key1B) == (key2B) && (key1E) == (key2E) ) # define KRB_R_IS_INTERSECTING(key1B, key2B, key1E, key2E) ( (key1B) <= (key2E) && (key1E) >= (key2B) ) # define KRB_R_IS_IN_RANGE(key1B, key1E, key2) KRB_R_IS_INTERSECTING(key1B, key2, key1E, key2) # endif #endif #ifndef KRB_RANGE # define KRB_R_IS_INTERSECTING(key1B, key2B, key1E, key2E) KRB_CMP_E(key1B, key2B) # define KRB_R_IS_IDENTICAL(key1B, key2B, key1E, key2E) KRB_CMP_E(key1B, key2B) #endif /** Is the node red or black? * @returns true / false * @param pNode Pointer to the node in question. * @remarks All NULL pointers are considered black leaf nodes. */ #define KRB_IS_RED(pNode) ( (pNode) != NULL && (pNode)->mfIsRed ) /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * Stack used to avoid recursive calls during insert and removal. */ typedef struct { unsigned cEntries; KRBTREEPTR *aEntries[KRB_MAX_STACK]; } KRB_INT(STACK); /** * The callback used by the Destroy and DoWithAll functions. */ typedef int (* KRB_TYPE(PFN,CALLBACK))(KRBNODE *, void *); #ifdef KRB_NEED_KRBROOT /** * The Red-Black tree root structure. */ typedef struct { KRBTREEPTR mpRoot; # ifdef KRB_CACHE_SIZE KRBTREEPTR maLookthru[KRB_CACHE_SIZE]; # endif } KRBROOT; #endif /** * Initializes the root of the Red-Black tree. * * @param pTree Pointer to the root structure. */ KRB_DECL(void) KRB_FN(Init)(KRBROOT *pRoot) { #ifdef KRB_CACHE_SIZE unsigned i; #endif pRoot->mpRoot = KRB_NULL; #ifdef KRB_CACHE_SIZE for (i = 0; i < (KRB_CACHE_SIZE); i++) pRoot->maLookthru[i] = KRB_NULL; #endif } /** * Rotates the tree to the left (shift direction) and recolors the nodes. * * @pre * * 2 4 * / \ / \ * 1 4 ==> 2 5 * / \ / \ * 3 5 1 3 * * @endpre * * @returns The new root node. * @param pRoot The root node. * * @remarks This will not update any pointer to the root node! */ K_DECL_INLINE(KRBNODE *) KAVL_FN(RotateLeft)(KRBNODE *pRoot) { KRBNODE *pNewRoot = pRoot->mRight; pRoot->mRight = pNewRoot->mLeft; pNewRoot->mLeft = pRoot; pRoot->mfIsRed = 1; pNewRoot->mfIsRed = 0; return pNewRoot; } /** * Rotates the tree to the right (shift direction) and recolors the nodes. * * @pre * * 4 2 * / \ / \ * 2 5 ==> 1 4 * / \ / \ * 1 3 3 5 * * @endpre * * @returns The new root node. * @param pRoot The root node. * * @remarks This will not update any pointer to the root node! */ K_DECL_INLINE(KRBNODE *) KAVL_FN(RotateRight)(KRBNODE *pRoot) { KRBNODE *pNewRoot = pRoot->mLeft; pRoot->mLeft = pNewRoot->mRight; pNewRoot->mRight = pRoot; pRoot->mfIsRed = 1; pNewRoot->mfIsRed = 0; return pNewRoot; } /** * Performs a double left rotation with recoloring. * * @pre * * 2 2 4 * / \ / \ / \ * 1 6 ==> 1 4 ==> 2 6 * / \ / \ / \ / \ * 4 7 3 6 1 3 5 7 * / \ / \ * 3 5 5 7 * @endpre * * @returns The new root node. * @param pRoot The root node. * * @remarks This will not update any pointer to the root node! */ K_DECL_INLINE(KRBNODE *) KAVL_FN(DoubleRotateLeft)(KRBNODE *pRoot) { pRoot->mRight = KAVL_FN(RotateRight)(pRoot->mRight); return KAVL_FN(RotateLeft)(pRoot); } /** * Performs a double right rotation with recoloring. * * @pre * 6 6 4 * / \ / \ / \ * 2 7 4 7 2 6 * / \ ==> / \ ==> / \ / \ * 1 4 2 5 1 3 5 7 * / \ / \ * 3 5 1 3 * * @endpre * * @returns The new root node. * @param pRoot The root node. * * @remarks This will not update any pointer to the root node! */ K_DECL_INLINE(KRBNODE *) KAVL_FN(DoubleRotateRight)(KRBNODE *pRoot) { pRoot->mLeft = KAVL_FN(RotateLeft)(pRoot->mLeft); return KAVL_FN(RotateRight)(pRoot); } /** * Inserts a node into the Red-Black tree. * @returns K_TRUE if inserted. * K_FALSE if node exists in tree. * @param pRoot Pointer to the Red-Back tree's root structure. * @param pNode Pointer to the node which is to be added. */ KRB_DECL(KBOOL) KRB_FN(Insert)(KRBROOT *pRoot, KRBNODE *pNode) { KRBTREEPTR *ppCurNode = &pRoot->mpRoot; register KRBKEY Key = pNode->mKey; #ifdef KRB_RANGE register KRBKEY KeyLast = pNode->mKeyLast; #endif #ifdef KRB_RANGE if (Key > KeyLast) return K_FALSE; #endif KRB_WRITE_LOCK(pRoot); Stack.cEntries = 0; while (*ppCurNode != KRB_NULL) { register KRBNODE *pCurNode = KRB_GET_POINTER(ppCurNode); kHlpAssert(Stack.cEntries < KRB_MAX_STACK); Stack.aEntries[Stack.cEntries++] = ppCurNode; #ifdef KRB_EQUAL_ALLOWED if (KRB_R_IS_IDENTICAL(pCurNode->mKey, Key, pCurNode->mKeyLast, KeyLast)) { /* * If equal then we'll use a list of equal nodes. */ pNode->mpLeft = pNode->mpRight = KRB_NULL; pNode->mHeight = 0; KRB_SET_POINTER_NULL(&pNode->mpList, &pCurNode->mpList); KRB_SET_POINTER(&pCurNode->mpList, pNode); KRB_WRITE_UNLOCK(pRoot); return K_TRUE; } #endif #ifdef KRB_CHECK_FOR_EQUAL_INSERT if (KRB_R_IS_INTERSECTING(pCurNode->mKey, Key, pCurNode->mKeyLast, KeyLast)) { KRB_WRITE_UNLOCK(pRoot); return K_FALSE; } #endif if (KRB_CMP_G(pCurNode->mKey, Key)) ppCurNode = &pCurNode->mpLeft; else ppCurNode = &pCurNode->mpRight; } pNode->mpLeft = pNode->mpRight = KRB_NULL; #ifdef KRB_EQUAL_ALLOWED pNode->mpList = KRB_NULL; #endif pNode->mHeight = 1; KRB_SET_POINTER(ppCurNode, pNode); KRB_FN(Rebalance)(&Stack); KRB_WRITE_UNLOCK(pRoot); return K_TRUE; } /** * Removes a node from the Red-Black tree. * @returns Pointer to the node. * @param pRoot Pointer to the Red-Back tree's root structure. * @param Key Key value of the node which is to be removed. * @sketch Find the node which is to be removed: * LOOP until not found * BEGIN * Add node pointer pointer to the AVL-stack. * IF the keys matches THEN break! * IF remove key < node key THEN * left * ELSE * right * END * IF found THEN * BEGIN * IF left node not empty THEN * BEGIN * Find the right most node in the left tree while adding the pointer to the pointer to it's parent to the stack: * Start at left node. * LOOP until right node is empty * BEGIN * Add to stack. * go right. * END * Link out the found node. * Replace the node which is to be removed with the found node. * Correct the stack entry for the pointer to the left tree. * END * ELSE * BEGIN * Move up right node. * Remove last stack entry. * END * Balance tree using stack. * END * return pointer to the removed node (if found). */ KRB_DECL(KRBNODE *) KRB_FN(Remove)(KRBROOT *pRoot, KRBKEY Key) { KRB_INT(STACK) Stack; KRBTREEPTR *ppDeleteNode = &pRoot->mpRoot; register KRBNODE *pDeleteNode; KRB_WRITE_LOCK(pRoot); Stack.cEntries = 0; for (;;) { if (*ppDeleteNode == KRB_NULL) { KRB_WRITE_UNLOCK(pRoot); return NULL; } pDeleteNode = KRB_GET_POINTER(ppDeleteNode); kHlpAssert(Stack.cEntries < KRB_MAX_STACK); Stack.aEntries[Stack.cEntries++] = ppDeleteNode; if (KRB_CMP_E(pDeleteNode->mKey, Key)) break; if (KRB_CMP_G(pDeleteNode->mKey, Key)) ppDeleteNode = &pDeleteNode->mpLeft; else ppDeleteNode = &pDeleteNode->mpRight; } if (pDeleteNode->mpLeft != KRB_NULL) { /* find the rightmost node in the left tree. */ const unsigned iStackEntry = Stack.cEntries; KRBTREEPTR *ppLeftLeast = &pDeleteNode->mpLeft; register KRBNODE *pLeftLeast = KRB_GET_POINTER(ppLeftLeast); while (pLeftLeast->mpRight != KRB_NULL) { kHlpAssert(Stack.cEntries < KRB_MAX_STACK); Stack.aEntries[Stack.cEntries++] = ppLeftLeast; ppLeftLeast = &pLeftLeast->mpRight; pLeftLeast = KRB_GET_POINTER(ppLeftLeast); } /* link out pLeftLeast */ KRB_SET_POINTER_NULL(ppLeftLeast, &pLeftLeast->mpLeft); /* link it in place of the delete node. */ KRB_SET_POINTER_NULL(&pLeftLeast->mpLeft, &pDeleteNode->mpLeft); KRB_SET_POINTER_NULL(&pLeftLeast->mpRight, &pDeleteNode->mpRight); pLeftLeast->mHeight = pDeleteNode->mHeight; KRB_SET_POINTER(ppDeleteNode, pLeftLeast); Stack.aEntries[iStackEntry] = &pLeftLeast->mpLeft; } else { KRB_SET_POINTER_NULL(ppDeleteNode, &pDeleteNode->mpRight); Stack.cEntries--; } KRB_FN(Rebalance)(&Stack); KRB_CACHE_INVALIDATE_NODE(pRoot, pDeleteNode, Key); KRB_WRITE_UNLOCK(pRoot); return pDeleteNode; } kbuild-3149/src/lib/kStuff/include/k/kRbTmpl/kRbGetWithParent.h0000644000175000017500000000454413252530253024277 0ustar locutuslocutus/* $Id: kRbGetWithParent.h 35 2009-11-08 19:39:03Z bird $ */ /** @file * kRbTmpl - Templated Red-Black Trees, Get Node With Parent. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * 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. */ /** * Gets a node from the tree and its parent node (if any). * The tree remains unchanged. * * @returns Pointer to the node holding the given key. * @param pRoot Pointer to the Red-Back tree's root structure. * @param ppParent Pointer to a variable which will hold the pointer to the partent node on * return. When no node is found, this will hold the last searched node. * @param Key Key value of the node which is to be found. */ KRB_DECL(KRBNODE *) KRB_FN(GetWithParent)(KRBROOT *pRoot, KRBNODE **ppParent, KRBKEY Key) { register KRBNODE *pNode; register KRBNODE *pParent; KRB_READ_LOCK(pRoot); pParent = NULL; pNode = KRB_GET_POINTER_NULL(&pRoot->mpRoot); while ( pNode != NULL && KRB_CMP_NE(pNode->mKey, Key)) { pParent = pNode; if (KRB_CMP_G(pNode->mKey, Key)) pNode = KRB_GET_POINTER_NULL(&pNode->mpLeft); else pNode = KRB_GET_POINTER_NULL(&pNode->mpRight); } KRB_READ_UNLOCK(pRoot); *ppParent = pParent; return pNode; } kbuild-3149/src/lib/kStuff/include/k/kRbTmpl/kRbRemoveBestFit.h0000644000175000017500000000560613252530253024270 0ustar locutuslocutus/* $Id: kRbRemoveBestFit.h 35 2009-11-08 19:39:03Z bird $ */ /** @file * kRbTmpl - Templated Red-Black Trees, Remove Best Fitting Node. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * 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. */ /** * Finds the best fitting node in the tree for the given Key value and removes the node. * * @returns Pointer to the removed node. * @param pRoot Pointer to the Red-Back tree's root structure. * @param Key The Key of which is to be found a best fitting match for.. * @param fAbove K_TRUE: Returned node is have the closest key to Key from above. * K_FALSE: Returned node is have the closest key to Key from below. * * @remark This implementation uses GetBestFit and then Remove and might therefore * not be the most optimal kind of implementation, but it reduces the complexity * code size, and the likelyhood for bugs. */ KRB_DECL(KRBNODE *) KRB_FN(RemoveBestFit)(KRBROOT *pRoot, KRBKEY Key, KBOOL fAbove) { /* * If we find anything we'll have to remove the node and return it. * Now, if duplicate keys are allowed we'll remove a duplicate before * removing the in-tree node as this is way cheaper. */ KRBNODE *pNode = KRB_FN(GetBestFit)(pRoot, Key, fAbove); if (pNode != NULL) { #ifdef KRB_EQUAL_ALLOWED KRB_WRITE_LOCK(pRoot); /** @todo the locking isn't quite sane here. :-/ */ if (pNode->mpList != KRB_NULL) { KRBNODE *pRet = KRB_GET_POINTER(&pNode->mpList); KRB_SET_POINTER_NULL(&pNode->mpList, &pRet->mpList); KRB_CACHE_INVALIDATE_NODE(pRoot, pNode, pNode->mKey); KRB_WRITE_UNLOCK(pRoot); return pRet; } KRB_WRITE_UNLOCK(pRoot); #endif pNode = KRB_FN(Remove)(pRoot, pNode->mKey); } return pNode; } kbuild-3149/src/lib/kStuff/include/k/kRbTmpl/kRbDoWithAll.h0000644000175000017500000001263213252530253023376 0ustar locutuslocutus/* $Id: kRbDoWithAll.h 35 2009-11-08 19:39:03Z bird $ */ /** @file * kRbTmpl - Templated Red-Black Trees, The Callback Iterator. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * Stack used by DoWithAll to avoid recusive function calls. */ typedef struct { unsigned cEntries; KRBNODE *aEntries[KRB_MAX_STACK]; char achFlags[KRB_MAX_STACK]; KRBROOT pRoot; } KRB_INT(STACK2); /** * Iterates thru all nodes in the given tree. * * @returns 0 on success. Return from callback on failure. * @param pRoot Pointer to the Red-Back tree's root structure. * @param fFromLeft K_TRUE: Left to right. * K_FALSE: Right to left. * @param pfnCallBack Pointer to callback function. * @param pvUser User parameter passed on to the callback function. */ KRB_DECL(int) KRB_FN(DoWithAll)(KRBROOT *pRoot, KBOOL fFromLeft, KRB_TYPE(PFN,CALLBACK) pfnCallBack, void *pvUser) { KRB_INT(STACK2) Stack; KRBNODE *pNode; #ifdef KRB_EQUAL_ALLOWED KRBNODE *pEqual; #endif int rc; KRB_READ_LOCK(pRoot); if (pRoot->mpRoot == KRB_NULL) { KRB_READ_UNLOCK(pRoot); return 0; } Stack.cEntries = 1; Stack.achFlags[0] = 0; Stack.aEntries[0] = KRB_GET_POINTER(&pRoot->mpRoot); if (fFromLeft) { /* from left */ while (Stack.cEntries > 0) { pNode = Stack.aEntries[Stack.cEntries - 1]; /* left */ if (!Stack.achFlags[Stack.cEntries - 1]++) { if (pNode->mpLeft != KRB_NULL) { Stack.achFlags[Stack.cEntries] = 0; /* 0 first, 1 last */ Stack.aEntries[Stack.cEntries++] = KRB_GET_POINTER(&pNode->mpLeft); continue; } } /* center */ rc = pfnCallBack(pNode, pvUser); if (rc) return rc; #ifdef KRB_EQUAL_ALLOWED if (pNode->mpList != KRB_NULL) for (pEqual = KRB_GET_POINTER(&pNode->mpList); pEqual; pEqual = KRB_GET_POINTER_NULL(&pEqual->mpList)) { rc = pfnCallBack(pEqual, pvUser); if (rc) { KRB_READ_UNLOCK(pRoot); return rc; } } #endif /* right */ Stack.cEntries--; if (pNode->mpRight != KRB_NULL) { Stack.achFlags[Stack.cEntries] = 0; Stack.aEntries[Stack.cEntries++] = KRB_GET_POINTER(&pNode->mpRight); } } /* while */ } else { /* from right */ while (Stack.cEntries > 0) { pNode = Stack.aEntries[Stack.cEntries - 1]; /* right */ if (!Stack.achFlags[Stack.cEntries - 1]++) { if (pNode->mpRight != KRB_NULL) { Stack.achFlags[Stack.cEntries] = 0; /* 0 first, 1 last */ Stack.aEntries[Stack.cEntries++] = KRB_GET_POINTER(&pNode->mpRight); continue; } } /* center */ rc = pfnCallBack(pNode, pvUser); if (rc) return rc; #ifdef KRB_EQUAL_ALLOWED if (pNode->mpList != KRB_NULL) for (pEqual = KRB_GET_POINTER(&pNode->mpList); pEqual; pEqual = KRB_GET_POINTER_NULL(&pEqual->pList)) { rc = pfnCallBack(pEqual, pvUser); if (rc) { KRB_READ_UNLOCK(pRoot); return rc; } } #endif /* left */ Stack.cEntries--; if (pNode->mpLeft != KRB_NULL) { Stack.achFlags[Stack.cEntries] = 0; Stack.aEntries[Stack.cEntries++] = KRB_GET_POINTER(&pNode->mpLeft); } } /* while */ } KRB_READ_UNLOCK(pRoot); return 0; } kbuild-3149/src/lib/kStuff/include/k/kRbTmpl/kRbGet.h0000644000175000017500000000534013252530253022264 0ustar locutuslocutus/* $Id: kRbGet.h 35 2009-11-08 19:39:03Z bird $ */ /** @file * kRbTmpl - Templated Red-Black Trees, Get a Node. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * 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. */ /** * Gets a node from the tree (does not remove it!) * * @returns Pointer to the node holding the given key. * @param pRoot Pointer to the Red-Back tree's root structure. * @param Key Key value of the node which is to be found. */ KRB_DECL(KRBNODE *) KRB_FN(Get)(KRBROOT *pRoot, KRBKEY Key) { KRBNODE *pNode; #ifdef KRB_CACHE_SIZE KRBTREEPTR *ppEntry; #endif KRB_READ_LOCK(pRoot); if (pRoot->mpRoot == KRB_NULL) { KRB_READ_UNLOCK(pRoot); return NULL; } #ifdef KRB_CACHE_SIZE ppEntry = &pRoot->maLookthru[KRB_CACHE_HASH(Key)]; pNode = KRB_GET_POINTER_NULL(ppEntry); if (!pNode || KRB_CMP_NE(pNode->mKey, Key)) #endif { pNode = KRB_GET_POINTER(&pRoot->mpRoot); while (KRB_CMP_NE(pNode->mKey, Key)) { if (KRB_CMP_G(pNode->mKey, Key)) { if (pNode->mpLeft == KRB_NULL) { KRB_READ_UNLOCK(pRoot); return NULL; } pNode = KRB_GET_POINTER(&pNode->mpLeft); } else { if (pNode->mpRight == KRB_NULL) { KRB_READ_UNLOCK(pRoot); return NULL; } pNode = KRB_GET_POINTER(&pNode->mpRight); } } #ifdef KRB_CACHE_SIZE KRB_SET_POINTER(ppEntry, pNode); #endif } KRB_READ_UNLOCK(pRoot); return pNode; } kbuild-3149/src/lib/kStuff/include/k/kRbTmpl/kRbGetBestFit.h0000644000175000017500000000740213252530253023546 0ustar locutuslocutus/* $Id: kRbGetBestFit.h 35 2009-11-08 19:39:03Z bird $ */ /** @file * kRbTmpl - Templated Red-Black Trees, Get Best Fitting Node. */ /* * Copyright (c) 1999-2009 Knut St. Osmundsen * * 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. */ /** * Finds the best fitting node in the tree for the given Key value. * * @returns Pointer to the best fitting node found. * @param pRoot Pointer to the Red-Back tree's root structure. * @param Key The Key of which is to be found a best fitting match for.. * @param fAbove K_TRUE: Returned node is have the closest key to Key from above. * K_FALSE: Returned node is have the closest key to Key from below. * @sketch The best fitting node is always located in the searchpath above you. * >= (above): The node where you last turned left. * <= (below): the node where you last turned right. */ KRB_DECL(KRBNODE *) KRB_FN(GetBestFit)(KRBROOT *pRoot, KRBKEY Key, KBOOL fAbove) { register KRBNODE *pNode; KRBNODE *pNodeLast; KRB_READ_LOCK(pLook); if (pRoot->mpRoot == KRB_NULL) { KRB_READ_UNLOCK(pLook); return NULL; } pNode = KRB_GET_POINTER(&pRoot->mpRoot); pNodeLast = NULL; if (fAbove) { /* pNode->mKey >= Key */ while (KRB_CMP_NE(pNode->mKey, Key)) { if (KRB_CMP_G(pNode->mKey, Key)) { if (pNode->mpLeft == KRB_NULL) { KRB_READ_UNLOCK(pLook); return pNode; } pNodeLast = pNode; pNode = KRB_GET_POINTER(&pNode->mpLeft); } else { if (pNode->mpRight == KRB_NULL) { KRB_READ_UNLOCK(pLook); return pNodeLast; } pNode = KRB_GET_POINTER(&pNode->mpRight); } } } else { /* pNode->mKey <= Key */ while (KRB_CMP_NE(pNode->mKey, Key)) { if (KRB_CMP_G(pNode->mKey, Key)) { if (pNode->mpLeft == KRB_NULL) { KRB_READ_UNLOCK(pLook); return pNodeLast; } pNode = KRB_GET_POINTER(&pNode->mpLeft); } else { if (pNode->mpRight == KRB_NULL) { KRB_READ_UNLOCK(pLook); return pNode; } pNodeLast = pNode; pNode = KRB_GET_POINTER(&pNode->mpRight); } } } /* perfect match or nothing. */ KRB_READ_UNLOCK(pLook); return pNode; } kbuild-3149/src/lib/kStuff/include/k/kRbTmpl/kRbUndef.h0000644000175000017500000000415013252530253022604 0ustar locutuslocutus/* $Id: kRbUndef.h 35 2009-11-08 19:39:03Z bird $ */ /** @file * kRbTmpl - Undefines All Macros (both config and temp). */ /* * Copyright (c) 2006-2009 Knut St. Osmundsen * * 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. */ /* * The configuration. */ #undef KRB_EQUAL_ALLOWED #undef KRB_CHECK_FOR_EQUAL_INSERT #undef KRB_MAX_STACK #undef KRB_RANGE #undef KRB_OFFSET #undef KRB_STD_KEY_COMP #undef KRB_CACHE_SIZE #undef KRB_CACHE_HASH #undef KRB_LOCKED #undef KRB_WRITE_LOCK #undef KRB_WRITE_UNLOCK #undef KRB_READ_LOCK #undef KRB_READ_UNLOCK #undef KRBKEY #undef KRBNODE #undef KRBTREEPTR #undef KRBROOT #undef KRB_FN #undef KRB_TYPE #undef KRB_INT #undef KRB_DECL #undef mKey #undef mKeyLast #undef mfIsRed #undef mpLeft #undef mpRight #undef mpList #undef mpRoot #undef maLookthru #undef KRB_CMP_G #undef KRB_CMP_E #undef KRB_CMP_NE #undef KRB_R_IS_IDENTICAL #undef KRB_R_IS_INTERSECTING #undef KRB_R_IS_IN_RANGE /* * Internal ones. */ #undef KRB_IS_RED #undef KRB_NULL #undef KRB_GET_POINTER #undef KRB_GET_POINTER_NULL #undef KRB_SET_POINTER #undef KRB_SET_POINTER_NULL kbuild-3149/src/lib/kStuff/include/k/kRbTmpl/kRbAssert.h0000644000175000017500000001107413252530253023007 0ustar locutuslocutus/* $Id: kRbAssert.h 38 2009-11-10 00:01:38Z bird $ */ /** @file * kRbTmpl - Templated Red-Black Trees, Assert Valid Tree. */ /* * Copyright (c) 2009 Knut St. Osmundsen * * 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. */ /** * Internal helper for KRB_FN(Assert) * * @returns The number of black nodes. -1 is return if the tree is invalid. * @param pRoot The root of the (sub-)tree to assert. */ K_DECL_INLINE(int) KRB_FN(AssertRecurse)(KRBNODE *pRoot) { int cLeft; int cRight; if (!pRoot) /* leafs are black. */ return 1; #ifdef KRB_EQUAL_ALLOWED /* equal nodes are equal :) */ if (pNode->mpList != KRB_NULL) { KRBROOT *pEqual; for (pEqual = KRB_GET_POINTER(&pNode->mpList); pEqual; pEqual = KRB_GET_POINTER_NULL(&pEqual->mpList)) kHlpAssertReturn(K_CMP_E(pEqual->mKey, pNode->mKey), -1); } #endif /* binary tree. */ kHlpAssertReturn(pRoot->mpLeft != KRB_NULL && KRB_CMP_G(KRB_GET_POINTER(&pRoot->mpLeft)->mpKey, pRoot->mKey), -1); kHlpAssertReturn(pRoot->mpRight != KRB_NULL && KRB_CMP_G(pRoot->mKey, KRB_GET_POINTER(&pRoot->mpRigth)->mpKey), -1); /* both children of red nodes are black. */ kHlpAssertReturn(!KRB_IS_RED(pRoot) || (!KRB_IS_RED(pRoot->mpLeft) && !KRB_IS_RED(pRoot->mpRight)), -1); /* all paths to leafs contains the same number of black nodes. */ cLeft = KRB_FN(AssertRecurse)(KRB_GET_POINTER_NULL(&pRoot->mpLeft)); cRight = KRB_FN(AssertRecurse)(KRB_GET_POINTER_NULL(&pRoot->mpRight)); kHlpAssertMsgReturn(cLeft == cRight || cLeft == -1 || cRight == -1, ("%d vs. %d\n", cLeft, cRight), -1); return cLeft + !KRB_IS_RED(pRoot); } /** * Asserts the validity of the Red-Black tree. * * This method is using recursion and may therefore consume quite a bit of stack * on a large tree. * * @returns K_TRUE if valid. * @returns K_FALSE if invalid, assertion raised on each violation. * @param pRoot Pointer to the Red-Back tree's root structure. */ KRB_DECL(KBOOL) KRB_FN(Assert)(KRBROOT *pRoot) { KBOOL fRc = K_TRUE; #ifdef KRB_CACHE_SIZE unsigned i; #endif KRBNODE *pNode; KRB_READ_LOCK(pRoot); if (pRoot->mpRoot == KRB_NULL) { KRB_READ_UNLOCK(pRoot); return 0; } #ifdef KRB_CACHE_SIZE /* * Validate the cache. */ for (i = 0; i < (KRB_CACHE_SIZE); i++) if (pRoot->maLookthru[i] != KRB_NULL) { KRBNODE pCache = KRB_GET_POINTER(&pRoot->maLookthru[i]); /** @todo ranges */ kHlpAssertMsgStmt(i == KRB_CACHE_HASH(pCache->Key), ("Invalid cache entry %u, hashed to %u\n", i, KRB_CACHE_HASH(pCache->Key)), fRc = K_FALSE); pNode = KRB_GET_POINTER(&pRoot->mpRoot); while (pNode) { if (KRB_CMP_E(pCache->mKey, pNode->mKey)) { kHlpAssertMsgStmt(pNode == pCache, ("Invalid cache entry %u=%p, found %p\n", i, pCache, pNode), fRc = K_FALSE); break; } if (KRB_CMP_G(pCache->mKey, pNode->mKey)) pNode = KRB_GET_POINTER_NULL(&pNode->mRight); else pNode = KRB_GET_POINTER_NULL(&pNode->mLeft); } kHlpAssertMsgStmt(pNode, ("Invalid cache entry %u/%p - not found\n", i, pCache), fRc = K_FALSE); } #endif /* * Recurse thru the tree. */ if (KRB_FN(AssertRecurse)(KRB_GET_POINTER(&pRoot->mpRoot)) == -1) fRc = K_FALSE; KRB_READ_UNLOCK(pRoot); return fRc; } kbuild-3149/src/lib/kStuff/include/k/kDbgAll.h0000644000175000017500000001404213252530253021032 0ustar locutuslocutus/* $Id: kDbgAll.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kDbg - The Debug Info Read, All Details and Dependencies Included. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___k_kDbgAll_h___ #define ___k_kDbgAll_h___ #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** @defgroup grp_kDbgAll All * @addtogroup grp_kDbg * @{ */ /** * The debug module method table. */ typedef struct KDBGMODOPS { /** The name of the reader. */ const char *pszName; /** Pointer to the next debug module readers. * This is only used for dynamically registered readers. */ struct KDBGMODOPS *pNext; /** * Tries to open the module. * * @returns 0 on success, KDBG_ERR on failure. * @param ppMod Where to store the module that's been opened. * @param pRdr The file provider. * @param fCloseRdrs Whether the reader should be closed or not when the module is destroyed. * @param off The file offset of the debug info. This is 0 if there isn't * any specfic debug info section and the reader should start * looking for debug info at the start of the file. * @param cb The size of the debug info in the file. INT64_MAX if we don't * know or there isn't any particular debug info section in the file. * @param pLdrMod The associated loader module. This can be NULL. */ int (*pfnOpen)(PKDBGMOD *ppMod, PKRDR pRdr, KBOOL fCloseRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod); /** * Closes the module. * * This should free all resources associated with the module * except the pMod which is freed by the caller. * * @returns IPRT status code. * @param pMod The module. */ int (*pfnClose)(PKDBGMOD pMod); /** * Gets a symbol by segment:offset. * This will be approximated to the nearest symbol if there is no exact match. * * @returns 0 on success. KLDR_ERR_* on failure. * @param pMod The module. * @param iSegment The segment this offset is relative to. * The -1 segment is special, it means that the addres is relative to * the image base. The image base is where the first bit of the image * is mapped during load. * @param off The offset into the segment. * @param pSym Where to store the symbol details. */ int (*pfnQuerySymbol)(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGSYMBOL pSym); /** * Gets a line number entry by segment:offset. * This will be approximated to the nearest line number there is no exact match. * * @returns 0 on success. KLDR_ERR_* on failure. * @param pMod The module. * @param iSegment The segment this offset is relative to. * The -1 segment is special, it means that the addres is relative to * the image base. The image base is where the first bit of the image * is mapped during load. * @param off The offset into the segment. * @param pLine Where to store the line number details. */ int (*pfnQueryLine)(PKDBGMOD pMod, KI32 iSegment, KDBGADDR uOffset, PKDBGLINE pLine); /** This is just to make sure you've initialized all the fields. * Must be identical to pszName. */ const char *pszName2; } KDBGMODOPS; /** Pointer to a module method table. */ typedef KDBGMODOPS *PKDBGMODOPS; /** Pointer to a const module method table. */ typedef const KDBGMODOPS *PCKDBGMODOPS; /** * Register a debug module reader with the kDbgModule component. * * Dynamically registered readers are kept in FIFO order, and external * readers will be tried after the builtin ones. * * @returns 0 on success. * @returns KERR_INVALID_POINTER if pOps is missing bits. * @returns KERR_INVALID_PARAMETER if pOps is already in the list. * @param pOps The reader method table, kDbg takes owner ship of * this. This must be writeable as the pNext pointer * will be update. It must also stick around for as * long as kDbg is in use. */ KDBG_DECL(int) kDbgModuleRegisterReader(PKDBGMODOPS pOps); /** * Internal representation of a debug module. */ typedef struct KDBGMOD { /** Magic value (KDBGMOD_MAGIC). */ KI32 u32Magic; /** Pointer to the method table. */ PCKDBGMODOPS pOps; /** The file provider for the file containing the debug info. */ PKRDR pRdr; /** Whether or not to close pRdr. */ KBOOL fCloseRdr; /** The associated kLdr module. This may be NULL. */ PKLDRMOD pLdrMod; } KDBGMOD; /** @}*/ #ifdef __cplusplus } #endif #endif kbuild-3149/src/lib/kStuff/include/k/kRdrAll.h0000644000175000017500000001017513252530253021070 0ustar locutuslocutus/* $Id: kRdrAll.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kRdr - The File Provider, All Details and Dependencies Included. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___k_kRdrAll_h___ #define ___k_kRdrAll_h___ #include #include #include #ifdef __cplusplus extern "C" { #endif /** @defgroup grp_kRdrAll All * @addtogroup grp_kRdr * @{ */ /** * File provider instance operations. */ typedef struct KRDROPS { /** The name of this file provider. */ const char *pszName; /** Pointer to the next file provider. */ const struct KRDROPS *pNext; /** Try create a new file provider instance. * * @returns 0 on success, OS specific error code on failure. * @param ppRdr Where to store the file provider instance. * @param pszFilename The filename to open. */ int (* pfnCreate)( PPKRDR ppRdr, const char *pszFilename); /** Destroy the file provider instance. * * @returns 0 on success, OS specific error code on failure. * On failure, the file provider instance will be in an indeterminate state - don't touch it! * @param pRdr The file provider instance. */ int (* pfnDestroy)( PKRDR pRdr); /** @copydoc kRdrRead */ int (* pfnRead)( PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off); /** @copydoc kRdrAllMap */ int (* pfnAllMap)( PKRDR pRdr, const void **ppvBits); /** @copydoc kRdrAllUnmap */ int (* pfnAllUnmap)(PKRDR pRdr, const void *pvBits); /** @copydoc kRdrSize */ KFOFF (* pfnSize)( PKRDR pRdr); /** @copydoc kRdrTell */ KFOFF (* pfnTell)( PKRDR pRdr); /** @copydoc kRdrName */ const char * (* pfnName)(PKRDR pRdr); /** @copydoc kRdrNativeFH */ KIPTR (* pfnNativeFH)(PKRDR pRdr); /** @copydoc kRdrPageSize */ KSIZE (* pfnPageSize)(PKRDR pRdr); /** @copydoc kRdrMap */ int (* pfnMap)( PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed); /** @copydoc kRdrRefresh */ int (* pfnRefresh)( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments); /** @copydoc kRdrProtect */ int (* pfnProtect)( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect); /** @copydoc kRdrUnmap */ int (* pfnUnmap)( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments); /** @copydoc kRdrDone */ void (* pfnDone)( PKRDR pRdr); /** The usual non-zero dummy that makes sure we've initialized all members. */ KU32 u32Dummy; } KRDROPS; /** Pointer to file provider operations. */ typedef KRDROPS *PKRDROPS; /** Pointer to const file provider operations. */ typedef const KRDROPS *PCKRDROPS; /** * File provider instance core. */ typedef struct KRDR { /** Magic number (KRDR_MAGIC). */ KU32 u32Magic; /** Pointer to the file provider operations. */ PCKRDROPS pOps; } KRDR; void kRdrAddProvider(PKRDROPS pAdd); /** @} */ #ifdef __cplusplus } #endif #endif kbuild-3149/src/lib/kStuff/include/k/kHlpPath.h0000644000175000017500000000337513252530253021254 0ustar locutuslocutus/* $Id: kHlpPath.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpPath - Path Manipulation. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___k_kHlpPath_h___ #define ___k_kHlpPath_h___ #include #include /** @defgroup grp_kHlpPath kHlpPath - Path Manipulation * @addtogroup grp_kHlp * @{*/ #ifdef __cplusplus extern "C" { #endif KHLP_DECL(char *) kHlpGetFilename(const char *pszFilename); KHLP_DECL(char *) kHlpGetSuff(const char *pszFilename); KHLP_DECL(char *) kHlpGetExt(const char *pszFilename); KHLP_DECL(int) kHlpIsFilenameOnly(const char *pszFilename); #ifdef __cplusplus } #endif /** @} */ #endif kbuild-3149/src/lib/kStuff/include/k/kHlpSys.h0000644000175000017500000000456513252530253021140 0ustar locutuslocutus/* $Id: kHlpSys.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpSys - System Call Prototypes. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___k_kHlpSys_h___ #define ___k_kHlpSys_h___ #include #include /** @defgroup grp_kHlpSys kHlpSys - System Call Prototypes * @addtogroup grp_kHlp * @{*/ #ifdef __cplusplus extern "C" { #endif /* common unix stuff. */ #if K_OS == K_OS_DARWIN \ || K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS KSSIZE kHlpSys_readlink(const char *pszPath, char *pszBuf, KSIZE cbBuf); int kHlpSys_open(const char *filename, int flags, int mode); int kHlpSys_close(int fd); KFOFF kHlpSys_lseek(int fd, int whench, KFOFF off); KSSIZE kHlpSys_read(int fd, void *pvBuf, KSIZE cbBuf); KSSIZE kHlpSys_write(int fd, const void *pvBuf, KSIZE cbBuf); void *kHlpSys_mmap(void *addr, KSIZE len, int prot, int flags, int fd, KI64 off); int kHlpSys_mprotect(void *addr, KSIZE len, int prot); int kHlpSys_munmap(void *addr, KSIZE len); void kHlpSys_exit(int rc); #endif /* specific */ #if K_OS == K_OS_DARWIN #elif K_OS == K_OS_LINUX #endif #ifdef __cplusplus } #endif /** @} */ #endif kbuild-3149/src/lib/kStuff/include/k/kDbg.h0000644000175000017500000001723113252530253020404 0ustar locutuslocutus/* $Id: kDbg.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kDbg - The Debug Info Reader. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___k_kDbg_h___ #define ___k_kDbg_h___ #include #include #include #ifdef __cplusplus extern "C" { #endif /** @defgroup grp_kDbg Debug Info Reader * @{ */ /** @def KDBG_DECL * Declares a kDbg function according to build context. * @param type The return type. */ #if defined(KDBG_BUILDING_DYNAMIC) # define KDBG_DECL(type) K_DECL_EXPORT(type) #elif defined(KDBG_BUILT_DYNAMIC) # define KDBG_DECL(type) K_DECL_IMPORT(type) #else # define KDBG_DECL(type) type #endif /** The kDbg address type. */ typedef KU64 KDBGADDR; /** Pointer to a kDbg address. */ typedef KDBGADDR *PKDBGADDR; /** Pointer to a const kDbg address. */ typedef const KDBGADDR *PCKDBGADDR; /** @def KDBGADDR_PRI * printf format type. */ #define KDBGADDR_PRI KX64_PRI /** @def KDBGADDR_MAX * Max kDbg address value. */ #define KDBGADDR_MAX KU64_C(0xfffffffffffffffe) /** @def KDBGADDR_C * kDbg address constant. * @param c The constant value. */ #define KDBGADDR_C(c) KU64_C(c) /** NIL address. */ #define NIL_KDBGADDR KU64_MAX /** @name Special Segments * @{ */ /** Relative Virtual Address. * The specified offset is relative to the image base. The image base is the lowest memory * address used by the image when loaded with the address assignments indicated in the image. */ #define KDBGSEG_RVA (-1) /** Absolute segment. The offset isn't relative to anything. */ #define KDBGSEG_ABS (-2) /** @} */ /** The max filename path length used by the debug reader. */ #define KDBG_PATH_MAX 260 /** * Line number details. */ typedef struct KDBGLINE { /** The relative virtual address. */ KDBGADDR RVA; /** The offset into the segment. */ KDBGADDR offSegment; /** The segment number. */ KI32 iSegment; /** The Line number. */ KU32 iLine; /** The actual size of this structure. */ KU16 cbSelf; /** The length of the filename. */ KU16 cchFile; /** The name of the file this line number relates to. */ char szFile[KDBG_PATH_MAX]; } KDBGLINE; /** Pointer to line number details. */ typedef KDBGLINE *PKDBGLINE; /** Pointer to const line number details. */ typedef const KDBGLINE *PCKDBGLINE; /** Pointer to a pointer to line number details. */ typedef PKDBGLINE *PPKDBGLINE; /** * Duplicates a line number. * * To save heap space, the returned line number will not own more heap space * than it strictly need to. So, it's not possible to append stuff to the symbol * or anything of that kind. * * @returns Pointer to the duplicate. * This must be freed using RTDbgSymbolFree(). * @param pLine The line number to be duplicated. */ KDBG_DECL(PKDBGLINE) kDbgLineDup(PCKDBGLINE pLine); /** * Frees a line number obtained from the RTDbg API. * * @returns VINF_SUCCESS on success. * @returns KERR_INVALID_POINTER if a NULL pointer or an !KDBG_VALID_PTR() is passed in. * * @param pLine The line number to be freed. */ KDBG_DECL(int) kDbgLineFree(PKDBGLINE pLine); /** @name Symbol Flags. * @{ */ /** The symbol is weak. */ #define KDBGSYM_FLAGS_WEAK KU32_C(0x00000000) /** The symbol is absolute. * (This also indicated by the segment number.) */ #define KDBGSYM_FLAGS_ABS KU32_C(0x00000001) /** The symbol is exported. */ #define KDBGSYM_FLAGS_EXPORTED KU32_C(0x00000002) /** The symbol is a function/method/procedure/whatever-executable-code. */ #define KDBGSYM_FLAGS_CODE KU32_C(0x00000004) /** The symbol is some kind of data. */ #define KDBGSYM_FLAGS_DATA KU32_C(0x00000008) /** @} */ /** The max symbol name length used by the debug reader. */ #define KDBG_SYMBOL_MAX 384 /** * Symbol details. */ typedef struct KDBGSYMBOL { /** The adddress of this symbol in the relevant space. * This is NIL_KDBGADDR unless the information was * returned by a kDbgSpace API. */ KDBGADDR Address; /** The relative virtual address. */ KDBGADDR RVA; /** The symbol size. * This is not a reliable field, it could be a bad guess. Ignore if zero. */ KDBGADDR cb; /** The offset into the segment. */ KDBGADDR offSegment; /** The segment number. */ KI32 iSegment; /** The symbol flags. */ KU32 fFlags; /** @todo type info. */ /** The actual size of this structure. */ KU16 cbSelf; /** The length of the symbol name. */ KU16 cchName; /** The symbol name. */ char szName[KDBG_SYMBOL_MAX]; } KDBGSYMBOL; /** Pointer to symbol details. */ typedef KDBGSYMBOL *PKDBGSYMBOL; /** Pointer to const symbol details. */ typedef const KDBGSYMBOL *PCKDBGSYMBOL; /** Pointer to a pointer to symbol details. */ typedef PKDBGSYMBOL *PPKDBGSYMBOL; /** * Duplicates a symbol. * * To save heap space, the returned symbol will not own more heap space than * it strictly need to. So, it's not possible to append stuff to the symbol * or anything of that kind. * * @returns Pointer to the duplicate. * This must be freed using kDbgSymbolFree(). * @param pSymbol The symbol to be freed. */ KDBG_DECL(PKDBGSYMBOL) kDbgSymbolDup(PCKDBGSYMBOL pSymbol); /** * Frees a symbol obtained from the kDbg API. * * @returns VINF_SUCCESS on success. * @returns KERR_INVALID_POINTER if a NULL pointer or an !KDBG_VALID_PTR() is passed in. * * @param pSymbol The symbol to be freed. */ KDBG_DECL(int) kDbgSymbolFree(PKDBGSYMBOL pSymbol); /** Pointer to a debug module. */ typedef struct KDBGMOD *PKDBGMOD; /** Pointer to a debug module pointer. */ typedef PKDBGMOD *PPKDBGMOD; KDBG_DECL(int) kDbgModuleOpen(PPKDBGMOD ppDbgMod, const char *pszFilename, struct KLDRMOD *pLdrMod); KDBG_DECL(int) kDbgModuleOpenFile(PPKDBGMOD ppDbgMod, PKRDR pRdr, struct KLDRMOD *pLdrMod); KDBG_DECL(int) kDbgModuleOpenFilePart(PPKDBGMOD ppDbgMod, PKRDR pRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod); KDBG_DECL(int) kDbgModuleClose(PKDBGMOD pMod); KDBG_DECL(int) kDbgModuleQuerySymbol(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGSYMBOL pSym); KDBG_DECL(int) kDbgModuleQuerySymbolA(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PPKDBGSYMBOL ppSym); KDBG_DECL(int) kDbgModuleQueryLine(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGLINE pLine); KDBG_DECL(int) kDbgModuleQueryLineA(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PPKDBGLINE ppLine); /** @} */ #ifdef __cplusplus } #endif #endif kbuild-3149/src/lib/kStuff/include/k/kAvlU32.h0000644000175000017500000000442613252530253020726 0ustar locutuslocutus/* $Id: kAvlU32.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kAvl - AVL Tree Implementation, KU32 keys. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___k_kAvlU32_h___ #define ___k_kAvlU32_h___ typedef struct KAVLU32 { KU32 mKey; KU8 mHeight; struct KAVLU32 *mpLeft; struct KAVLU32 *mpRight; } KAVLU32, *PKAVLU32, **PPKAVLU32; /*#define KAVL_EQUAL_ALLOWED*/ #define KAVL_CHECK_FOR_EQUAL_INSERT #define KAVL_MAX_STACK 32 /*#define KAVL_RANGE */ /*#define KAVL_OFFSET */ #define KAVL_STD_KEY_COMP #define KAVLKEY KU32 #define KAVLNODE KAVLU32 #define KAVL_FN(name) kAvlU32 ## name #define KAVL_TYPE(prefix,name) prefix ## KAVLU32 ## name #define KAVL_INT(name) KAVLU32INT ## name #define KAVL_DECL(rettype) K_DECL_INLINE(rettype) #include #include #include #include #include #include #include #include #include #endif kbuild-3149/src/lib/kStuff/include/k/kDbgBase.h0000644000175000017500000002122113252530253021171 0ustar locutuslocutus/* $Id: kDbgBase.h 40 2010-02-02 16:02:15Z bird $ */ /** @file * kDbg - The Debug Info Reader, Base Definitions and Typedefs. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___kDbgBase_h___ #define ___kDbgBase_h___ #include #include /** @defgroup grp_kDbgBase kDbgBase - Base Definitions And Typedefs * @{ */ /* * kDbg depend on size_t, [u]intNN_t, [u]intptr_t and some related constants. * If KDBG_ALREADY_INCLUDED_STD_TYPES or KCOMMON_ALREADY_INCLUDED_STD_TYPES * is defined, these has already been defined. */ #if !defined(KDBG_ALREADY_INCLUDED_STD_TYPES) && !defined(KCOMMON_ALREADY_INCLUDED_STD_TYPES) # define KCOMMON_ALREADY_INCLUDED_STD_TYPES 1 # include # include # ifdef _MSC_VER typedef signed char int8_t; typedef unsigned char uint8_t; typedef signed short int16_t; typedef unsigned short uint16_t; typedef signed int int32_t; typedef unsigned int uint32_t; typedef signed __int64 int64_t; typedef unsigned __int64 uint64_t; typedef int64_t intmax_t; typedef uint64_t uintmax_t; # define UINT8_C(c) (c) # define UINT16_C(c) (c) # define UINT32_C(c) (c ## U) # define UINT64_C(c) (c ## ULL) # define INT8_C(c) (c) # define INT16_C(c) (c) # define INT32_C(c) (c) # define INT64_C(c) (c ## LL) # define INT8_MIN (INT8_C(-0x7f) - 1) # define INT16_MIN (INT16_C(-0x7fff) - 1) # define INT32_MIN (INT32_C(-0x7fffffff) - 1) # define INT64_MIN (INT64_C(-0x7fffffffffffffff) - 1) # define INT8_MAX INT8_C(0x7f) # define INT16_MAX INT16_C(0x7fff) # define INT32_MAX INT32_C(0x7fffffff) # define INT64_MAX INT64_C(0x7fffffffffffffff) # define UINT8_MAX UINT8_C(0xff) # define UINT16_MAX UINT16_C(0xffff) # define UINT32_MAX UINT32_C(0xffffffff) # define UINT64_MAX UINT64_C(0xffffffffffffffff) # else # include # endif #endif /* !KDBG_ALREADY_INCLUDED_STD_TYPES && !KCOMMON_ALREADY_INCLUDED_STD_TYPES */ /** @def KDBG_CALL * The calling convention used by the kDbg functions. */ #if defined(_MSC_VER) || defined(__OS2__) # define KDBG_CALL __cdecl #else # define KDBG_CALL #endif #ifdef DOXYGEN_RUNNING /** @def KDBG_BUILDING * Define KDBG_BUILDING to indicate that kDbg is being built. */ # define KDBG_BUILDING /** @def KDBG_RESIDES_IN_DLL * Define KDBG_RESIDES_IN_DLL to indicate that kDbg resides in a DLL. */ # define KDBG_RESIDES_IN_DLL #endif /** @def KDBG_DECL * Macro for defining public functions. */ #if defined(KDBG_RESIDES_IN_DLL) \ && (defined(_MSC_VER) || defined(__OS2__)) # ifdef KDBG_BUILDING # define KDBG_DECL(type) __declspec(dllexport) type # else # define KDBG_DECL(type) __declspec(dllimport) type # endif #else # define KDBG_DECL(type) type #endif /** @def KDBG_INLINE * Macro for defining an inline function. */ #ifdef __cplusplus # if defined(__GNUC__) # define KDBG_INLINE(type) static inline type # else # define KDBG_INLINE(type) inline type # endif #else # if defined(__GNUC__) # define KDBG_INLINE(type) static __inline__ type # elif defined(_MSC_VER) # define KDBG_INLINE(type) _inline type # else # error "Port me" # endif #endif /** The kDbg address type. */ typedef uint64_t KDBGADDR; /** Pointer to a kLdr address. */ typedef KDBGADDR *PKDBGADDR; /** Pointer to a const kLdr address. */ typedef const KDBGADDR *PCKDBGADDR; /** NIL address. */ #define NIL_KDBGADDR (~(uint64_t)0) /** @def PRI_KDBGADDR * printf format type. */ #ifdef _MSC_VER # define PRI_KDBGADDR "I64x" #else # define PRI_KDBGADDR "llx" #endif /** Get the minimum of two values. */ #define KDBG_MIN(a, b) ((a) <= (b) ? (a) : (b)) /** Get the maximum of two values. */ #define KDBG_MAX(a, b) ((a) >= (b) ? (a) : (b)) /** Calculate the offset of a structure member. */ #define KDBG_OFFSETOF(strct, memb) ( (size_t)( &((strct *)0)->memb ) ) /** Align a size_t value. */ #define KDBG_ALIGN_Z(val, align) ( ((val) + ((align) - 1)) & ~(size_t)((align) - 1) ) /** Align a void * value. */ #define KDBG_ALIGN_P(pv, align) ( (void *)( ((uintptr_t)(pv) + ((align) - 1)) & ~(uintptr_t)((align) - 1) ) ) /** Align a size_t value. */ #define KDBG_ALIGN_ADDR(val, align) ( ((val) + ((align) - 1)) & ~(KDBGADDR)((align) - 1) ) /** Number of elements in an array. */ #define KDBG_ELEMENTS(a) ( sizeof(a) / sizeof((a)[0]) ) /** @def KDBG_VALID_PTR * Checks if the specified pointer is a valid address or not. */ #define KDBG_VALID_PTR(ptr) ( (uintptr_t)(ptr) + 0x1000U >= 0x2000U ) /** @def KDBG_LITTLE_ENDIAN * The kDbg build is for a little endian target. */ /** @def KDBG_BIG_ENDIAN * The kDbg build is for a big endian target. */ #if !defined(KDBG_LITTLE_ENDIAN) && !defined(KDBG_BIG_ENDIAN) # define KDBG_LITTLE_ENDIAN #endif #ifdef DOXYGEN_RUNNING # define KDBG_BIG_ENDIAN #endif /** @name Endian Conversion * @{ */ /** @def KDBG_E2E_U16 * Convert the endian of an unsigned 16-bit value. */ # define KDBG_E2E_U16(u16) ( (uint16_t) (((u16) >> 8) | ((u16) << 8)) ) /** @def KDBG_E2E_U32 * Convert the endian of an unsigned 32-bit value. */ # define KDBG_E2E_U32(u32) ( ( ((u32) & UINT32_C(0xff000000)) >> 24 ) \ | ( ((u32) & UINT32_C(0x00ff0000)) >> 8 ) \ | ( ((u32) & UINT32_C(0x0000ff00)) << 8 ) \ | ( ((u32) & UINT32_C(0x000000ff)) << 24 ) \ ) /** @def KDBG_E2E_U64 * Convert the endian of an unsigned 64-bit value. */ # define KDBG_E2E_U64(u64) ( ( ((u64) & UINT64_C(0xff00000000000000)) >> 56 ) \ | ( ((u64) & UINT64_C(0x00ff000000000000)) >> 40 ) \ | ( ((u64) & UINT64_C(0x0000ff0000000000)) >> 24 ) \ | ( ((u64) & UINT64_C(0x000000ff00000000)) >> 8 ) \ | ( ((u64) & UINT64_C(0x00000000ff000000)) << 8 ) \ | ( ((u64) & UINT64_C(0x0000000000ff0000)) << 24 ) \ | ( ((u64) & UINT64_C(0x000000000000ff00)) << 40 ) \ | ( ((u64) & UINT64_C(0x00000000000000ff)) << 56 ) \ ) /** @def KDBG_LE2H_U16 * Unsigned 16-bit little-endian to host endian. */ /** @def KDBG_LE2H_U32 * Unsigned 32-bit little-endian to host endian. */ /** @def KDBG_LE2H_U64 * Unsigned 64-bit little-endian to host endian. */ /** @def KDBG_BE2H_U16 * Unsigned 16-bit big-endian to host endian. */ /** @def KDBG_BE2H_U32 * Unsigned 32-bit big-endian to host endian. */ /** @def KDBG_BE2H_U64 * Unsigned 64-bit big-endian to host endian. */ #ifdef KDBG_LITTLE_ENDIAN # define KDBG_LE2H_U16(u16) ((uint16_t)(u16)) # define KDBG_LE2H_U32(u32) ((uint32_t)(u32)) # define KDBG_LE2H_U64(u64) ((uint32_t)(u32)) # define KDBG_BE2H_U16(u16) KDBG_E2E_U16(u16) # define KDBG_BE2H_U32(u32) KDBG_E2E_U32(u32) # define KDBG_BE2H_U64(u64) KDBG_E2E_U64(u64) #elif defined(KDBG_BIG_ENDIAN) # define KDBG_LE2H_U16(u16) KDBG_E2E_U16(u16) # define KDBG_LE2H_U32(u32) KDBG_E2E_U32(u32) # define KDBG_LE2H_U32(u64) KDBG_E2E_U64(u64) # define KDBG_BE2H_U16(u16) ((uint16_t)(u16)) # define KDBG_BE2H_U32(u32) ((uint32_t)(u32)) # define KDBG_BE2H_U64(u64) ((uint32_t)(u32)) #else # error "KDBG_BIG_ENDIAN or KDBG_LITTLE_ENDIAN is supposed to be defined." #endif /** @} */ /** @} */ #endif kbuild-3149/src/lib/kStuff/include/k/kHlpAssert.h0000644000175000017500000003041013252530253021607 0ustar locutuslocutus/* $Id: kHlpAssert.h 101 2017-10-02 10:37:39Z bird $ */ /** @file * kHlpAssert - Assertion Macros. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___kHlpAssert_h___ #define ___kHlpAssert_h___ #include #ifdef __cplusplus extern "C" { #endif /** @defgroup grp_kHlpAssert - Assertion Macros * @addtogroup grp_kHlp * @{ */ /** @def K_STRICT * Assertions are enabled when K_STRICT is \#defined. */ /** @def kHlpAssertBreakpoint * Emits a breakpoint instruction or somehow triggers a debugger breakpoint. */ #ifdef _MSC_VER # define kHlpAssertBreakpoint() do { __debugbreak(); } while (0) #elif defined(__GNUC__) && K_OS == K_OS_SOLARIS && (K_ARCH == K_ARCH_AMD64 || K_ARCH == K_ARCH_X86_32) # define kHlpAssertBreakpoint() do { __asm__ __volatile__ ("int $3"); } while (0) #elif defined(__GNUC__) && (K_ARCH == K_ARCH_AMD64 || K_ARCH == K_ARCH_X86_32 || K_ARCH == K_ARCH_X86_16) # define kHlpAssertBreakpoint() do { __asm__ __volatile__ ("int3"); } while (0) #else # error "Port Me" #endif /** @def K_FUNCTION * Undecorated function name macro expanded by the compiler. */ #if defined(__GNUC__) # define K_FUNCTION __func__ #else # define K_FUNCTION __FUNCTION__ #endif #ifdef K_STRICT # define kHlpAssert(expr) \ do { \ if (!(expr)) \ { \ kHlpAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ kHlpAssertBreakpoint(); \ } \ } while (0) # define kHlpAssertStmt(expr, stmt) \ do { \ if (!(expr)) \ { \ kHlpAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ kHlpAssertBreakpoint(); \ stmt; \ } \ } while (0) # define kHlpAssertReturn(expr, rcRet) \ do { \ if (!(expr)) \ { \ kHlpAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ kHlpAssertBreakpoint(); \ return (rcRet); \ } \ } while (0) # define kHlpAssertStmtReturn(expr, stmt, rcRet) \ do { \ if (!(expr)) \ { \ kHlpAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ kHlpAssertBreakpoint(); \ stmt; \ return (rcRet); \ } \ } while (0) # define kHlpAssertReturnVoid(expr) \ do { \ if (!(expr)) \ { \ kHlpAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ kHlpAssertBreakpoint(); \ return; \ } \ } while (0) # define kHlpAssertStmtReturnVoid(expr, stmt) \ do { \ if (!(expr)) \ { \ kHlpAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ kHlpAssertBreakpoint(); \ stmt; \ return; \ } \ } while (0) # define kHlpAssertMsg(expr, msg) \ do { \ if (!(expr)) \ { \ kHlpAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ kHlpAssertMsg2 msg; \ kHlpAssertBreakpoint(); \ } \ } while (0) # define kHlpAssertMsgStmt(expr, msg, stmt) \ do { \ if (!(expr)) \ { \ kHlpAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ kHlpAssertMsg2 msg; \ kHlpAssertBreakpoint(); \ stmt; \ } \ } while (0) # define kHlpAssertMsgReturn(expr, msg, rcRet) \ do { \ if (!(expr)) \ { \ kHlpAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ kHlpAssertMsg2 msg; \ kHlpAssertBreakpoint(); \ return (rcRet); \ } \ } while (0) # define kHlpAssertMsgStmtReturn(expr, msg, stmt, rcRet) \ do { \ if (!(expr)) \ { \ kHlpAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ kHlpAssertMsg2 msg; \ kHlpAssertBreakpoint(); \ stmt; \ return (rcRet); \ } \ } while (0) # define kHlpAssertMsgReturnVoid(expr, msg) \ do { \ if (!(expr)) \ { \ kHlpAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ kHlpAssertMsg2 msg; \ kHlpAssertBreakpoint(); \ return; \ } \ } while (0) # define kHlpAssertMsgStmtReturnVoid(expr, msg, stmt) \ do { \ if (!(expr)) \ { \ kHlpAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \ kHlpAssertMsg2 msg; \ kHlpAssertBreakpoint(); \ stmt; \ return; \ } \ } while (0) /* Same as above, only no expression. */ # define kHlpAssertFailed() \ do { \ kHlpAssertMsg1("failed", __FILE__, __LINE__, K_FUNCTION); \ kHlpAssertBreakpoint(); \ } while (0) # define kHlpAssertFailedStmt(stmt) \ do { \ kHlpAssertMsg1("failed", __FILE__, __LINE__, K_FUNCTION); \ kHlpAssertBreakpoint(); \ stmt; \ } while (0) # define kHlpAssertFailedReturn(rcRet) \ do { \ kHlpAssertMsg1("failed", __FILE__, __LINE__, K_FUNCTION); \ kHlpAssertBreakpoint(); \ return (rcRet); \ } while (0) # define kHlpAssertFailedStmtReturn(stmt, rcRet) \ do { \ kHlpAssertMsg1("failed", __FILE__, __LINE__, K_FUNCTION); \ kHlpAssertBreakpoint(); \ stmt; \ return (rcRet); \ } while (0) # define kHlpAssertFailedReturnVoid() \ do { \ kHlpAssertMsg1("failed", __FILE__, __LINE__, K_FUNCTION); \ kHlpAssertBreakpoint(); \ return; \ } while (0) # define kHlpAssertFailedStmtReturnVoid(stmt) \ do { \ kHlpAssertMsg1("failed", __FILE__, __LINE__, K_FUNCTION); \ kHlpAssertBreakpoint(); \ stmt; \ return; \ } while (0) # define kHlpAssertMsgFailed(msg) \ do { \ kHlpAssertMsg1("failed", __FILE__, __LINE__, K_FUNCTION); \ kHlpAssertMsg2 msg; \ kHlpAssertBreakpoint(); \ } while (0) # define kHlpAssertMsgFailedStmt(msg, stmt) \ do { \ kHlpAssertMsg1("failed", __FILE__, __LINE__, K_FUNCTION); \ kHlpAssertMsg2 msg; \ kHlpAssertBreakpoint(); \ stmt; \ } while (0) # define kHlpAssertMsgFailedReturn(msg, rcRet) \ do { \ kHlpAssertMsg1("failed", __FILE__, __LINE__, K_FUNCTION); \ kHlpAssertMsg2 msg; \ kHlpAssertBreakpoint(); \ return (rcRet); \ } while (0) # define kHlpAssertMsgFailedStmtReturn(msg, stmt, rcRet) \ do { \ kHlpAssertMsg1("failed", __FILE__, __LINE__, K_FUNCTION); \ kHlpAssertMsg2 msg; \ kHlpAssertBreakpoint(); \ stmt; \ return (rcRet); \ } while (0) # define kHlpAssertMsgFailedReturnVoid(msg) \ do { \ kHlpAssertMsg1("failed", __FILE__, __LINE__, K_FUNCTION); \ kHlpAssertMsg2 msg; \ kHlpAssertBreakpoint(); \ return; \ } while (0) # define kHlpAssertMsgFailedStmtReturnVoid(msg, stmt) \ do { \ kHlpAssertMsg1("failed", __FILE__, __LINE__, K_FUNCTION); \ kHlpAssertMsg2 msg; \ kHlpAssertBreakpoint(); \ stmt; \ return; \ } while (0) #else /* !K_STRICT */ # define kHlpAssert(expr) do { } while (0) # define kHlpAssertStmt(expr, stmt) do { if (!(expr)) { stmt; } } while (0) # define kHlpAssertReturn(expr, rcRet) do { if (!(expr)) return (rcRet); } while (0) # define kHlpAssertStmtReturn(expr, stmt, rcRet) do { if (!(expr)) { stmt; return (rcRet); } } while (0) # define kHlpAssertReturnVoid(expr) do { if (!(expr)) return; } while (0) # define kHlpAssertStmtReturnVoid(expr, stmt) do { if (!(expr)) { stmt; return; } } while (0) # define kHlpAssertMsg(expr, msg) do { } while (0) # define kHlpAssertMsgStmt(expr, msg, stmt) do { if (!(expr)) { stmt; } } while (0) # define kHlpAssertMsgReturn(expr, msg, rcRet) do { if (!(expr)) return (rcRet); } while (0) # define kHlpAssertMsgStmtReturn(expr, msg, stmt, rcRet) do { if (!(expr)) { stmt; return (rcRet); } } while (0) # define kHlpAssertMsgReturnVoid(expr, msg) do { if (!(expr)) return; } while (0) # define kHlpAssertMsgStmtReturnVoid(expr, msg, stmt) do { if (!(expr)) { stmt; return; } } while (0) /* Same as above, only no expression: */ # define kHlpAssertFailed() do { } while (0) # define kHlpAssertFailedStmt(stmt) do { stmt; } while (0) # define kHlpAssertFailedReturn(rcRet) do { return (rcRet); } while (0) # define kHlpAssertFailedStmtReturn(stmt, rcRet) do { stmt; return (rcRet); } while (0) # define kHlpAssertFailedReturnVoid() do { return; } while (0) # define kHlpAssertFailedStmtReturnVoid(stmt) do { stmt; return; } while (0) # define kHlpAssertMsgFailed(msg) do { } while (0) # define kHlpAssertMsgFailedStmt(msg, stmt) do { stmt; } while (0) # define kHlpAssertMsgFailedReturn(msg, rcRet) do { return (rcRet); } while (0) # define kHlpAssertMsgFailedStmtReturn(msg, stmt, rcRet) do { { stmt; return (rcRet); } } while (0) # define kHlpAssertMsgFailedReturnVoid(msg) do { return; } while (0) # define kHlpAssertMsgFailedStmtReturnVoid(msg, stmt) do { stmt; return; } while (0) #endif /* !K_STRICT */ #define kHlpAssertPtr(ptr) kHlpAssertMsg(K_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr))) #define kHlpAssertPtrReturn(ptr, rcRet) kHlpAssertMsgReturn(K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet)) #define kHlpAssertPtrReturn(ptr, rcRet) kHlpAssertMsgReturn(K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet)) #define kHlpAssertPtrReturnVoid(ptr) kHlpAssertMsgReturnVoid(K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet))) #define kHlpAssertPtrNull(ptr) kHlpAssertMsg(!(ptr) || K_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr))) #define kHlpAssertPtrNullReturn(ptr, rcRet) kHlpAssertMsgReturn(!(ptr) || K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet)) #define kHlpAssertPtrNullReturnVoid(ptr) kHlpAssertMsgReturnVoid(!(ptr) || K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet))) #define kHlpAssertRC(rc) kHlpAssertMsg((rc) == 0, ("%s = %d\n", #rc, (rc))) #define kHlpAssertRCReturn(rc, rcRet) kHlpAssertMsgReturn((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet)), (rcRet)) #define kHlpAssertRCReturnVoid(rc) kHlpAssertMsgReturnVoid((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet))) /** * Helper function that displays the first part of the assertion message. * * @param pszExpr The expression. * @param pszFile The file name. * @param iLine The line number is the file. * @param pszFunction The function name. * @internal */ KHLP_DECL(void) kHlpAssertMsg1(const char *pszExpr, const char *pszFile, unsigned iLine, const char *pszFunction); /** * Helper function that displays custom assert message. * * @param pszFormat Format string that get passed to vprintf. * @param ... Format arguments. * @internal */ KHLP_DECL(void) kHlpAssertMsg2(const char *pszFormat, ...); /** @} */ #ifdef __cplusplus } #endif #endif kbuild-3149/src/lib/kStuff/include/k/kAvlrU32.h0000644000175000017500000000463613252530253021113 0ustar locutuslocutus/* $Id: kAvlrU32.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kAvl - AVL Tree Implementation, KU32 key ranges. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___k_kAvlrU32_h___ #define ___k_kAvlrU32_h___ typedef struct KAVLRU32 { KU32 u32Start; KU32 u32Last; struct KAVLRU32 *mpLeft; struct KAVLRU32 *mpRight; KU8 mHeight; } KAVLRU32, *PKAVLRU32, **PPKAVLRU32; #define mKey u32Start #define mKeyLast u32Last /*#define KAVL_EQUAL_ALLOWED*/ #define KAVL_CHECK_FOR_EQUAL_INSERT #define KAVL_MAX_STACK 32 #define KAVL_RANGE /*#define KAVL_OFFSET */ #define KAVL_STD_KEY_COMP #define KAVLKEY KU32 #define KAVLNODE KAVLRU32 #define KAVL_FN(name) kAvlrU32 ## name #define KAVL_TYPE(prefix,name) prefix ## KAVLRU32 ## name #define KAVL_INT(name) KAVLRU32INT ## name #define KAVL_DECL(rettype) K_DECL_INLINE(rettype) #include #include #include #include #include #include #include #include #include #endif kbuild-3149/src/lib/kStuff/include/k/kDefs.h0000644000175000017500000004710513252530253020574 0ustar locutuslocutus/* $Id: kDefs.h 105 2017-11-21 23:55:40Z bird $ */ /** @file * kTypes - Defines and Macros. */ /* * Copyright (c) 2006-2017 Knut St. Osmundsen * * 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. */ #ifndef ___k_kDefs_h___ #define ___k_kDefs_h___ /** @defgroup grp_kDefs kDefs - Defines and Macros * @{ */ /** @name Operative System Identifiers. * These are the value that the K_OS \#define can take. * @{ */ /** Unknown OS. */ #define K_OS_UNKNOWN 0 /** Darwin - aka Mac OS X. */ #define K_OS_DARWIN 1 /** DragonFly BSD. */ #define K_OS_DRAGONFLY 2 /** FreeBSD. */ #define K_OS_FREEBSD 3 /** GNU/Hurd. */ #define K_OS_GNU_HURD 4 /** GNU/kFreeBSD. */ #define K_OS_GNU_KFBSD 5 /** GNU/kNetBSD or GNU/NetBSD or whatever the decide to call it. */ #define K_OS_GNU_KNBSD 6 /** Haiku. */ #define K_OS_HAIKU 7 /** Linux. */ #define K_OS_LINUX 8 /** NetBSD. */ #define K_OS_NETBSD 9 /** NT (native). */ #define K_OS_NT 10 /** OpenBSD*/ #define K_OS_OPENBSD 11 /** OS/2 */ #define K_OS_OS2 12 /** Solaris */ #define K_OS_SOLARIS 13 /** Windows. */ #define K_OS_WINDOWS 14 /** The max K_OS_* value (exclusive). */ #define K_OS_MAX 15 /** @} */ /** @def K_OS * Indicates which OS we're targetting. It's a \#define with is * assigned one of the K_OS_* defines above. * * So to test if we're on FreeBSD do the following: * @code * #if K_OS == K_OS_FREEBSD * some_funky_freebsd_specific_stuff(); * #endif * @endcode */ #ifndef K_OS # if defined(__APPLE__) # define K_OS K_OS_DARWIN # elif defined(__DragonFly__) # define K_OS K_OS_DRAGONFLY # elif defined(__FreeBSD__) # define K_OS K_OS_FREEBSD # elif defined(__FreeBSD_kernel__) # define K_OS K_OS_GNU_KFBSD # elif defined(__gnu_hurd__) # define K_OS K_OS_GNU_HURD # elif defined(__gnu_linux__) # define K_OS K_OS_LINUX # elif defined(__NetBSD__) /*??*/ # define K_OS K_OS_NETBSD # elif defined(__NetBSD_kernel__) # define K_OS K_OS_GNU_KNBSD # elif defined(__OpenBSD__) /*??*/ # define K_OS K_OS_OPENBSD # elif defined(__OS2__) # define K_OS K_OS_OS2 # elif defined(__sun__) || defined(__SunOS__) || defined(__sun) || defined(__SunOS) # define K_OS K_OS_SOLARIS # elif defined(_WIN32) || defined(_WIN64) # define K_OS K_OS_WINDOWS # elif defined(__haiku__) || defined(__HAIKU__) # define K_OS K_OS_HAIKU # else # error "Port Me" # endif #endif #if K_OS < K_OS_UNKNOWN || K_OS >= K_OS_MAX # error "Invalid K_OS value." #endif /** @name Architecture bit width. * @{ */ #define K_ARCH_BIT_8 0x0100 /**< 8-bit */ #define K_ARCH_BIT_16 0x0200 /**< 16-bit */ #define K_ARCH_BIT_32 0x0400 /**< 32-bit */ #define K_ARCH_BIT_64 0x0800 /**< 64-bit */ #define K_ARCH_BIT_128 0x1000 /**< 128-bit */ #define K_ARCH_BIT_MASK 0x1f00 /**< The bit mask. */ #define K_ARCH_BIT_SHIFT 5 /**< Shift count for producing the width in bits. */ #define K_ARCH_BYTE_SHIFT 8 /**< Shift count for producing the width in bytes. */ /** @} */ /** @name Architecture Endianness. * @{ */ #define K_ARCH_END_LITTLE 0x2000 /**< Little-endian. */ #define K_ARCH_END_BIG 0x4000 /**< Big-endian. */ #define K_ARCH_END_BI 0x6000 /**< Bi-endian, can be switched. */ #define K_ARCH_END_MASK 0x6000 /**< The endian mask. */ #define K_ARCH_END_SHIFT 13 /**< Shift count for converting between this K_ENDIAN_*. */ /** @} */ /** @name Architecture Identifiers. * These are the value that the K_ARCH \#define can take. *@{ */ /** Unknown CPU architecture. */ #define K_ARCH_UNKNOWN ( 0 ) /** Clone or Intel 16-bit x86. */ #define K_ARCH_X86_16 ( 1 | K_ARCH_BIT_16 | K_ARCH_END_LITTLE) /** Clone or Intel 32-bit x86. */ #define K_ARCH_X86_32 ( 1 | K_ARCH_BIT_32 | K_ARCH_END_LITTLE) /** AMD64 (including clones). */ #define K_ARCH_AMD64 ( 2 | K_ARCH_BIT_64 | K_ARCH_END_LITTLE) /** Itanic (64-bit). */ #define K_ARCH_IA64 ( 3 | K_ARCH_BIT_64 | K_ARCH_END_BI) /** ALPHA (64-bit). */ #define K_ARCH_ALPHA ( 4 | K_ARCH_BIT_64 | K_ARCH_END_BI) /** ALPHA limited to 32-bit. */ #define K_ARCH_ALPHA_32 ( 4 | K_ARCH_BIT_32 | K_ARCH_END_BI) /** 32-bit ARM. */ #define K_ARCH_ARM_32 ( 5 | K_ARCH_BIT_32 | K_ARCH_END_BI) /** 64-bit ARM. */ #define K_ARCH_ARM_64 ( 5 | K_ARCH_BIT_64 | K_ARCH_END_BI) /** Motorola 68000 (32-bit). */ #define K_ARCH_M68K ( 6 | K_ARCH_BIT_32 | K_ARCH_END_BIG) /** 32-bit MIPS. */ #define K_ARCH_MIPS_32 ( 7 | K_ARCH_BIT_32 | K_ARCH_END_BI) /** 64-bit MIPS. */ #define K_ARCH_MIPS_64 ( 7 | K_ARCH_BIT_64 | K_ARCH_END_BI) /** 32-bit PA-RISC. */ #define K_ARCH_PARISC_32 ( 8 | K_ARCH_BIT_32 | K_ARCH_END_BI) /** 64-bit PA-RISC. */ #define K_ARCH_PARISC_64 ( 8 | K_ARCH_BIT_64 | K_ARCH_END_BI) /** 32-bit PowerPC. */ #define K_ARCH_POWERPC_32 ( 9 | K_ARCH_BIT_32 | K_ARCH_END_BI) /** 64-bit PowerPC. */ #define K_ARCH_POWERPC_64 ( 9 | K_ARCH_BIT_64 | K_ARCH_END_BI) /** 32(31)-bit S390. */ #define K_ARCH_S390_32 (10 | K_ARCH_BIT_32 | K_ARCH_END_BIG) /** 64-bit S390. */ #define K_ARCH_S390_64 (10 | K_ARCH_BIT_64 | K_ARCH_END_BIG) /** 32-bit SuperH. */ #define K_ARCH_SH_32 (11 | K_ARCH_BIT_32 | K_ARCH_END_BI) /** 64-bit SuperH. */ #define K_ARCH_SH_64 (11 | K_ARCH_BIT_64 | K_ARCH_END_BI) /** 32-bit SPARC. */ #define K_ARCH_SPARC_32 (12 | K_ARCH_BIT_32 | K_ARCH_END_BIG) /** 64-bit SPARC. */ #define K_ARCH_SPARC_64 (12 | K_ARCH_BIT_64 | K_ARCH_END_BI) /** The end of the valid architecture values (exclusive). */ #define K_ARCH_MAX (12+1) /** @} */ /** @def K_ARCH * The value of this \#define indicates which architecture we're targetting. */ #ifndef K_ARCH /* detection based on compiler defines. */ # if defined(__amd64__) || defined(__x86_64__) || defined(__AMD64__) || defined(_M_X64) || defined(__amd64) # define K_ARCH K_ARCH_AMD64 # elif defined(__i386__) || defined(__x86__) || defined(__X86__) || defined(_M_IX86) || defined(__i386) # define K_ARCH K_ARCH_X86_32 # elif defined(__ia64__) || defined(__IA64__) || defined(_M_IA64) # define K_ARCH K_ARCH_IA64 # elif defined(__alpha__) # define K_ARCH K_ARCH_ALPHA # elif defined(__arm__) || defined(__arm32__) # define K_ARCH K_ARCH_ARM_32 # elif defined(__aarch64__) || defined(__arm64__) # define K_ARCH K_ARCH_ARM_64 # elif defined(__hppa__) && defined(__LP64__) # define K_ARCH K_ARCH_PARISC_64 # elif defined(__hppa__) # define K_ARCH K_ARCH_PARISC_32 # elif defined(__m68k__) # define K_ARCH K_ARCH_M68K # elif defined(__mips64) # define K_ARCH K_ARCH_MIPS_64 # elif defined(__mips__) # define K_ARCH K_ARCH_MIPS_32 # elif defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__) # define K_ARCH K_ARCH_POWERPC_64 # elif defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) # define K_ARCH K_ARCH_POWERPC_32 # elif defined(__sparcv9__) || defined(__sparcv9) # define K_ARCH K_ARCH_SPARC_64 # elif defined(__sparc__) || defined(__sparc) # define K_ARCH K_ARCH_SPARC_32 # elif defined(__s390x__) # define K_ARCH K_ARCH_S390_64 # elif defined(__s390__) # define K_ARCH K_ARCH_S390_32 # elif defined(__sh__) # if !defined(__SH5__) # define K_ARCH K_ARCH_SH_32 # else # if __SH5__ == 64 # define K_ARCH K_ARCH_SH_64 # else # define K_ARCH K_ARCH_SH_32 # endif # endif # else # error "Port Me" # endif #else /* validate the user specified value. */ # if (K_ARCH & K_ARCH_BIT_MASK) != K_ARCH_BIT_8 \ && (K_ARCH & K_ARCH_BIT_MASK) != K_ARCH_BIT_16 \ && (K_ARCH & K_ARCH_BIT_MASK) != K_ARCH_BIT_32 \ && (K_ARCH & K_ARCH_BIT_MASK) != K_ARCH_BIT_64 \ && (K_ARCH & K_ARCH_BIT_MASK) != K_ARCH_BIT_128 # error "Invalid K_ARCH value (bit)" # endif # if (K_ARCH & K_ARCH_END_MASK) != K_ARCH_END_LITTLE \ && (K_ARCH & K_ARCH_END_MASK) != K_ARCH_END_BIG \ && (K_ARCH & K_ARCH_END_MASK) != K_ARCH_END_BI # error "Invalid K_ARCH value (endian)" # endif # if (K_ARCH & ~(K_ARCH_BIT_MASK | K_ARCH_BIT_END_MASK)) < K_ARCH_UNKNOWN \ || (K_ARCH & ~(K_ARCH_BIT_MASK | K_ARCH_BIT_END_MASK)) >= K_ARCH_MAX # error "Invalid K_ARCH value" # endif #endif /** @def K_ARCH_IS_VALID * Check if the architecture identifier is valid. * @param arch The K_ARCH_* define to examin. */ #define K_ARCH_IS_VALID(arch) ( ( ((arch) & K_ARCH_BIT_MASK) == K_ARCH_BIT_8 \ || ((arch) & K_ARCH_BIT_MASK) == K_ARCH_BIT_16 \ || ((arch) & K_ARCH_BIT_MASK) == K_ARCH_BIT_32 \ || ((arch) & K_ARCH_BIT_MASK) == K_ARCH_BIT_64 \ || ((arch) & K_ARCH_BIT_MASK) == K_ARCH_BIT_128) \ && \ ( ((arch) & K_ARCH_END_MASK) == K_ARCH_END_LITTLE \ || ((arch) & K_ARCH_END_MASK) == K_ARCH_END_BIG \ || ((arch) & K_ARCH_END_MASK) == K_ARCH_END_BI) \ && \ ( ((arch) & ~(K_ARCH_BIT_MASK | K_ARCH_END_MASK)) >= K_ARCH_UNKNOWN \ && ((arch) & ~(K_ARCH_BIT_MASK | K_ARCH_END_MASK)) < K_ARCH_MAX) \ ) /** @def K_ARCH_BITS_EX * Determin the architure byte width of the specified architecture. * @param arch The K_ARCH_* define to examin. */ #define K_ARCH_BITS_EX(arch) ( ((arch) & K_ARCH_BIT_MASK) >> K_ARCH_BIT_SHIFT ) /** @def K_ARCH_BYTES_EX * Determin the architure byte width of the specified architecture. * @param arch The K_ARCH_* define to examin. */ #define K_ARCH_BYTES_EX(arch) ( ((arch) & K_ARCH_BIT_MASK) >> K_ARCH_BYTE_SHIFT ) /** @def K_ARCH_ENDIAN_EX * Determin the K_ENDIAN value for the specified architecture. * @param arch The K_ARCH_* define to examin. */ #define K_ARCH_ENDIAN_EX(arch) ( ((arch) & K_ARCH_END_MASK) >> K_ARCH_END_SHIFT ) /** @def K_ARCH_BITS * Determin the target architure bit width. */ #define K_ARCH_BITS K_ARCH_BITS_EX(K_ARCH) /** @def K_ARCH_BYTES * Determin the target architure byte width. */ #define K_ARCH_BYTES K_ARCH_BYTES_EX(K_ARCH) /** @def K_ARCH_ENDIAN * Determin the target K_ENDIAN value. */ #define K_ARCH_ENDIAN K_ARCH_ENDIAN_EX(K_ARCH) /** @name Endianness Identifiers. * These are the value that the K_ENDIAN \#define can take. * @{ */ #define K_ENDIAN_LITTLE 1 /**< Little-endian. */ #define K_ENDIAN_BIG 2 /**< Big-endian. */ #define K_ENDIAN_BI 3 /**< Bi-endian, can be switched. Only used with K_ARCH. */ /** @} */ /** @def K_ENDIAN * The value of this \#define indicates the target endianness. * * @remark It's necessary to define this (or add the necessary deduction here) * on bi-endian architectures. */ #ifndef K_ENDIAN /* use K_ARCH if possible. */ # if K_ARCH_ENDIAN != K_ENDIAN_BI # define K_ENDIAN K_ARCH_ENDIAN # elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) # if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ # define K_ENDIAN K_ARCH_LITTLE # elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ # define K_ENDIAN K_ARCH_BIG # else # error "Port Me or define K_ENDIAN." # endif # else # error "Port Me or define K_ENDIAN." # endif #else /* validate the user defined value. */ # if K_ENDIAN != K_ENDIAN_LITTLE && K_ENDIAN != K_ENDIAN_BIG # error "K_ENDIAN must either be defined as K_ENDIAN_LITTLE or as K_ENDIAN_BIG." # endif #endif /** @name Endian Conversion * @{ */ /** @def K_E2E_U16 * Convert the endian of an unsigned 16-bit value. */ # define K_E2E_U16(u16) ( (KU16) (((u16) >> 8) | ((u16) << 8)) ) /** @def K_E2E_U32 * Convert the endian of an unsigned 32-bit value. */ # define K_E2E_U32(u32) ( ( ((u32) & KU32_C(0xff000000)) >> 24 ) \ | ( ((u32) & KU32_C(0x00ff0000)) >> 8 ) \ | ( ((u32) & KU32_C(0x0000ff00)) << 8 ) \ | ( ((u32) & KU32_C(0x000000ff)) << 24 ) \ ) /** @def K_E2E_U64 * Convert the endian of an unsigned 64-bit value. */ # define K_E2E_U64(u64) ( ( ((u64) & KU64_C(0xff00000000000000)) >> 56 ) \ | ( ((u64) & KU64_C(0x00ff000000000000)) >> 40 ) \ | ( ((u64) & KU64_C(0x0000ff0000000000)) >> 24 ) \ | ( ((u64) & KU64_C(0x000000ff00000000)) >> 8 ) \ | ( ((u64) & KU64_C(0x00000000ff000000)) << 8 ) \ | ( ((u64) & KU64_C(0x0000000000ff0000)) << 24 ) \ | ( ((u64) & KU64_C(0x000000000000ff00)) << 40 ) \ | ( ((u64) & KU64_C(0x00000000000000ff)) << 56 ) \ ) /** @def K_LE2H_U16 * Unsigned 16-bit little-endian to host endian. */ /** @def K_LE2H_U32 * Unsigned 32-bit little-endian to host endian. */ /** @def K_LE2H_U64 * Unsigned 64-bit little-endian to host endian. */ /** @def K_BE2H_U16 * Unsigned 16-bit big-endian to host endian. */ /** @def K_BE2H_U32 * Unsigned 32-bit big-endian to host endian. */ /** @def K_BE2H_U64 * Unsigned 64-bit big-endian to host endian. */ #if K_ENDIAN == K_ENDIAN_LITTLE # define K_LE2H_U16(u16) ((KU16)(u16)) # define K_LE2H_U32(u32) ((KU32)(u32)) # define K_LE2H_U64(u64) ((KU64)(u32)) # define K_BE2H_U16(u16) K_E2E_U16(u16) # define K_BE2H_U32(u32) K_E2E_U32(u32) # define K_BE2H_U64(u64) K_E2E_U64(u64) #else # define K_LE2H_U16(u16) K_E2E_U16(u16) # define K_LE2H_U32(u32) K_E2E_U32(u32) # define K_LE2H_U64(u64) K_E2E_U64(u64) # define K_BE2H_U16(u16) ((KU16)(u16)) # define K_BE2H_U32(u32) ((KU32)(u32)) # define K_BE2H_U64(u64) ((KU64)(u32)) #endif /** @def K_INLINE * How to say 'inline' in both C and C++ dialects. * @param type The return type. */ #ifdef __cplusplus # if defined(__GNUC__) # define K_INLINE static inline # else # define K_INLINE inline # endif #else # if defined(__GNUC__) # define K_INLINE static __inline__ # elif defined(_MSC_VER) # define K_INLINE static __inline # else # error "Port Me" # endif #endif /** @def K_EXPORT * What to put in front of an exported function. */ #if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS # define K_EXPORT __declspec(dllexport) #else # define K_EXPORT #endif /** @def K_IMPORT * What to put in front of an imported function. */ #if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS # define K_IMPORT __declspec(dllimport) #else # define K_IMPORT extern #endif /** @def K_DECL_EXPORT * Declare an exported function. * @param type The return type. */ #define K_DECL_EXPORT(type) K_EXPORT type /** @def K_DECL_IMPORT * Declare an import function. * @param type The return type. */ #define K_DECL_IMPORT(type) K_IMPORT type /** @def K_DECL_INLINE * Declare an inline function. * @param type The return type. * @remark Don't use on (class) methods. */ #define K_DECL_INLINE(type) K_INLINE type /** Get the minimum of two values. */ #define K_MIN(a, b) ( (a) <= (b) ? (a) : (b) ) /** Get the maximum of two values. */ #define K_MAX(a, b) ( (a) >= (b) ? (a) : (b) ) /** Calculate the offset of a structure member. */ #define K_OFFSETOF(strct, memb) ( (KSIZE)( &((strct *)0)->memb ) ) /** Align a size_t value. */ #define K_ALIGN_Z(val, align) ( ((val) + ((align) - 1)) & ~(KSIZE)((align) - 1) ) /** Align a void * value. */ #define K_ALIGN_P(pv, align) ( (void *)( ((KUPTR)(pv) + ((align) - 1)) & ~(KUPTR)((align) - 1) ) ) /** Number of elements in an array. */ #define K_ELEMENTS(a) ( sizeof(a) / sizeof((a)[0]) ) /** Checks if the specified pointer is a valid address or not. */ #define K_VALID_PTR(ptr) ( (KUPTR)(ptr) + 0x1000U >= 0x2000U ) /** Makes a 32-bit bit mask. */ #define K_BIT32(bit) ( KU32_C(1) << (bit)) /** Makes a 64-bit bit mask. */ #define K_BIT64(bit) ( KU64_C(1) << (bit)) /** Shuts up unused parameter and unused variable warnings. */ #define K_NOREF(var) ( (void)(var) ) /** @name Parameter validation macros * @{ */ /** Return/Crash validation of a string argument. */ #define K_VALIDATE_STRING(str) \ do { \ if (!K_VALID_PTR(str)) \ return KERR_INVALID_POINTER; \ kHlpStrLen(str); \ } while (0) /** Return/Crash validation of an optional string argument. */ #define K_VALIDATE_OPTIONAL_STRING(str) \ do { \ if (str) \ K_VALIDATE_STRING(str); \ } while (0) /** Return/Crash validation of an output buffer. */ #define K_VALIDATE_BUFFER(buf, cb) \ do { \ if (!K_VALID_PTR(buf)) \ return KERR_INVALID_POINTER; \ if ((cb) != 0) \ { \ KU8 __b; \ KU8 volatile *__pb = (KU8 volatile *)(buf); \ KSIZE __cbPage1 = 0x1000 - ((KUPTR)(__pb) & 0xfff); /* ASSUMES page size! */ \ __b = *__pb; *__pb = 0xff; *__pb = __b; \ if ((cb) > __cbPage1) \ { \ KSIZE __cb = (cb) - __cbPage1; \ __pb -= __cbPage1; \ for (;;) \ { \ __b = *__pb; *__pb = 0xff; *__pb = __b; \ if (__cb < 0x1000) \ break; \ __pb += 0x1000; \ __cb -= 0x1000; \ } \ } \ } \ else \ return KERR_INVALID_PARAMETER; \ } while (0) /** Return/Crash validation of an optional output buffer. */ #define K_VALIDATE_OPTIONAL_BUFFER(buf, cb) \ do { \ if ((buf) && (cb) != 0) \ K_VALIDATE_BUFFER(buf, cb); \ } while (0) /** Return validation of an enum argument. */ #define K_VALIDATE_ENUM(arg, enumname) \ do { \ if ((arg) <= enumname##_INVALID || (arg) >= enumname##_END) \ return KERR_INVALID_PARAMETER; \ } while (0) /** Return validation of a flags argument. */ #define K_VALIDATE_FLAGS(arg, AllowedMask) \ do { \ if ((arg) & ~(AllowedMask)) \ return KERR_INVALID_PARAMETER; \ } while (0) /** @} */ /** @def NULL * The nil pointer value. */ #ifndef NULL # ifdef __cplusplus # define NULL 0 # else # define NULL ((void *)0) # endif #endif /** @} */ #endif kbuild-3149/src/lib/kStuff/include/k/kRdr.h0000644000175000017500000000633413252530253020441 0ustar locutuslocutus/* $Id: kRdr.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kRdr - The File Provider. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___kRdr_h___ #define ___kRdr_h___ #include #include /** @defgroup grp_kRdr kRdr - The File Provider * @{ */ /** @def KRDR_DECL * Declares a kRdr function according to build context. * @param type The return type. */ #if defined(KRDR_BUILDING_DYNAMIC) # define KRDR_DECL(type) K_DECL_EXPORT(type) #elif defined(KRDR_BUILT_DYNAMIC) # define KRDR_DECL(type) K_DECL_IMPORT(type) #else # define KRDR_DECL(type) type #endif #ifdef __cplusplus extern "C" { #endif KRDR_DECL(int) kRdrOpen( PPKRDR ppRdr, const char *pszFilename); KRDR_DECL(int) kRdrClose( PKRDR pRdr); KRDR_DECL(int) kRdrRead( PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off); KRDR_DECL(int) kRdrAllMap( PKRDR pRdr, const void **ppvBits); KRDR_DECL(int) kRdrAllUnmap( PKRDR pRdr, const void *pvBits); KRDR_DECL(KFOFF) kRdrSize( PKRDR pRdr); KRDR_DECL(KFOFF) kRdrTell( PKRDR pRdr); KRDR_DECL(const char *) kRdrName( PKRDR pRdr); KRDR_DECL(KIPTR) kRdrNativeFH( PKRDR pRdr); KRDR_DECL(KSIZE) kRdrPageSize( PKRDR pRdr); KRDR_DECL(int) kRdrMap( PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed); KRDR_DECL(int) kRdrRefresh( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments); KRDR_DECL(int) kRdrProtect( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect); KRDR_DECL(int) kRdrUnmap( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments); KRDR_DECL(void) kRdrDone( PKRDR pRdr); KRDR_DECL(int) kRdrBufOpen(PPKRDR ppRdr, const char *pszFilename); KRDR_DECL(int) kRdrBufWrap(PPKRDR ppRdr, PKRDR pRdr, KBOOL fCloseIt); KRDR_DECL(KBOOL) kRdrBufIsBuffered(PKRDR pRdr); KRDR_DECL(int) kRdrBufLine(PKRDR pRdr, char *pszLine, KSIZE cbLine); KRDR_DECL(int) kRdrBufLineEx(PKRDR pRdr, char *pszLine, KSIZE *pcbLine); KRDR_DECL(const char *) kRdrBufLineQ(PKRDR pRdr); #ifdef __cplusplus } #endif /** @} */ #endif kbuild-3149/src/lib/kStuff/include/k/kErrors.h0000644000175000017500000004064513252530253021171 0ustar locutuslocutus/* $Id: kErrors.h 58 2013-10-12 20:18:21Z bird $ */ /** @file * kErrors - Status Codes. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___k_kErrors_h___ #define ___k_kErrors_h___ /** @defgroup grp_kErrors Status Codes. * @{ */ /** The base of the kErrors status codes. */ #define KERR_BASE 42000 /** @name General * @{ */ /** The base of the general status codes. */ #define KERR_GENERAL_BASE (KERR_BASE) /** Generic error. */ #define KERR_GENERAL_FAILURE (KERR_GENERAL_BASE + 1) /** Out of memory. */ #define KERR_NO_MEMORY (KERR_GENERAL_BASE + 2) /** Hit some unimplemented functionality - feel free to implement it :-) . */ #define KERR_NOT_IMPLEMENTED (KERR_GENERAL_BASE + 3) /** An environment variable wasn't found. */ #define KERR_ENVVAR_NOT_FOUND (KERR_GENERAL_BASE + 4) /** Buffer overflow. */ #define KERR_BUFFER_OVERFLOW (KERR_GENERAL_BASE + 5) /** @}*/ /** @name Input Validation * @{ */ /** The base of the input validation status codes. */ #define KERR_INPUT_BASE (KERR_GENERAL_BASE + 6) /** An API was given an invalid parameter. */ #define KERR_INVALID_PARAMETER (KERR_INPUT_BASE + 0) /** A pointer argument is not valid. */ #define KERR_INVALID_POINTER (KERR_INPUT_BASE + 1) /** A handle argument is not valid. */ #define KERR_INVALID_HANDLE (KERR_INPUT_BASE + 2) /** An offset argument is not valid. */ #define KERR_INVALID_OFFSET (KERR_INPUT_BASE + 3) /** A size argument is not valid. */ #define KERR_INVALID_SIZE (KERR_INPUT_BASE + 4) /** A range argument is not valid. */ #define KERR_INVALID_RANGE (KERR_INPUT_BASE + 5) /** A parameter is out of range. */ #define KERR_OUT_OF_RANGE (KERR_INPUT_BASE + 6) /** @} */ /** @name File System and I/O * @{ */ /** The base of the file system and I/O status cdoes. */ #define KERR_FILE_SYSTEM_AND_IO_BASE (KERR_INPUT_BASE + 7) /** The specified file was not found. */ #define KERR_FILE_NOT_FOUND (KERR_FILE_SYSTEM_AND_IO_BASE + 0) /** End of file. */ #define KERR_EOF (KERR_FILE_SYSTEM_AND_IO_BASE + 1) /** @} */ /** @name kDbg Specific * @{ */ /** The base of the kDbg specific status codes. */ #define KDBG_ERR_BASE (KERR_FILE_SYSTEM_AND_IO_BASE + 2) /** The (module) format isn't known to use. */ #define KDBG_ERR_UNKOWN_FORMAT (KDBG_ERR_BASE + 0) /** The (module) format isn't supported by this kDbg build. */ #define KDBG_ERR_FORMAT_NOT_SUPPORTED (KDBG_ERR_BASE + 1) /** The (module) format isn't supported by this kDbg build. */ #define KDBG_ERR_BAD_EXE_FORMAT (KDBG_ERR_BASE + 2) /** A specified address or an address found in the debug info is invalid. */ #define KDBG_ERR_INVALID_ADDRESS (KDBG_ERR_BASE + 3) /** The dbghelp.dll is too old or something like that. */ #define KDBG_ERR_DBGHLP_VERSION_MISMATCH (KDBG_ERR_BASE + 4) /** @} */ /** @name kRdr Specific * @{ */ /** the base of the kRdr specific status codes. */ #define KRDR_ERR_BASE (KDBG_ERR_BASE + 5) /** The file reader can't take more concurrent mappings. */ #define KRDR_ERR_TOO_MANY_MAPPINGS (KRDR_ERR_BASE + 0) /** The pRdr instance passed to a kRdrBuf* API isn't a buffered instance. */ #define KRDR_ERR_NOT_BUFFERED_RDR (KRDR_ERR_BASE + 1) /** The line is too long to fit in the buffer passed to kRdrBufLine or kRdrBufLineEx. */ #define KRDR_ERR_LINE_TOO_LONG (KRDR_ERR_BASE + 2) /** @} */ /** @name kLdr Specific * @{ */ /** The base of the kLdr specific status codes. */ #define KLDR_ERR_BASE (KRDR_ERR_BASE + 3) /** The image format is unknown. */ #define KLDR_ERR_UNKNOWN_FORMAT (KLDR_ERR_BASE + 0) /** The MZ image format isn't supported by this kLdr build. */ #define KLDR_ERR_MZ_NOT_SUPPORTED (KLDR_ERR_BASE + 1) /** The NE image format isn't supported by this kLdr build. */ #define KLDR_ERR_NE_NOT_SUPPORTED (KLDR_ERR_BASE + 2) /** The LX image format isn't supported by this kLdr build. */ #define KLDR_ERR_LX_NOT_SUPPORTED (KLDR_ERR_BASE + 3) /** The LE image format isn't supported by this kLdr build. */ #define KLDR_ERR_LE_NOT_SUPPORTED (KLDR_ERR_BASE + 4) /** The PE image format isn't supported by this kLdr build. */ #define KLDR_ERR_PE_NOT_SUPPORTED (KLDR_ERR_BASE + 5) /** The ELF image format isn't supported by this kLdr build. */ #define KLDR_ERR_ELF_NOT_SUPPORTED (KLDR_ERR_BASE + 6) /** The mach-o image format isn't supported by this kLdr build. */ #define KLDR_ERR_MACHO_NOT_SUPPORTED (KLDR_ERR_BASE + 7) /** The FAT image format isn't supported by this kLdr build or * a direct open was attempt without going thru the FAT file provider. * FAT images are also known as Universal Binaries. */ #define KLDR_ERR_FAT_NOT_SUPPORTED (KLDR_ERR_BASE + 8) /** The a.out image format isn't supported by this kLdr build. */ #define KLDR_ERR_AOUT_NOT_SUPPORTED (KLDR_ERR_BASE + 9) /** The module wasn't loaded dynamically. */ #define KLDR_ERR_NOT_LOADED_DYNAMICALLY (KLDR_ERR_BASE + 10) /** The module wasn't found. */ #define KLDR_ERR_MODULE_NOT_FOUND (KLDR_ERR_BASE + 11) /** A prerequisit module wasn't found. */ #define KLDR_ERR_PREREQUISITE_MODULE_NOT_FOUND (KLDR_ERR_BASE + 12) /** The module is being terminated and can therefore not be loaded. */ #define KLDR_ERR_MODULE_TERMINATING (KLDR_ERR_BASE + 13) /** A prerequisit module is being terminated and can therefore not be loaded. */ #define KLDR_ERR_PREREQUISITE_MODULE_TERMINATING (KLDR_ERR_BASE + 14) /** The module initialization failed. */ #define KLDR_ERR_MODULE_INIT_FAILED (KLDR_ERR_BASE + 15) /** The initialization of a prerequisite module failed. */ #define KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED (KLDR_ERR_BASE + 16) /** The module has already failed initialization and can't be attempted reloaded until * after we've finished garbage collection. */ #define KLDR_ERR_MODULE_INIT_FAILED_ALREADY (KLDR_ERR_BASE + 17) /** A prerequisite module has already failed initialization and can't be attempted * reloaded until after we've finished garbage collection. */ #define KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED_ALREADY (KLDR_ERR_BASE + 18) /** Prerequisite recursed too deeply. */ #define KLDR_ERR_PREREQUISITE_RECURSED_TOO_DEEPLY (KLDR_ERR_BASE + 19) /** Failed to allocate the main stack. */ #define KLDR_ERR_MAIN_STACK_ALLOC_FAILED (KLDR_ERR_BASE + 20) /** Symbol not found. */ #define KLDR_ERR_SYMBOL_NOT_FOUND (KLDR_ERR_BASE + 21) /** A forward symbol was encountered but the caller didn't provide any means to resolve it. */ #define KLDR_ERR_FORWARDER_SYMBOL (KLDR_ERR_BASE + 22) /** Encountered a bad fixup. */ #define KLDR_ERR_BAD_FIXUP (KLDR_ERR_BASE + 23) /** The import ordinal was out of bounds. */ #define KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS (KLDR_ERR_BASE + 24) /** A forwarder chain was too long. */ #define KLDR_ERR_TOO_LONG_FORWARDER_CHAIN (KLDR_ERR_BASE + 25) /** The module has no debug info. */ #define KLDR_ERR_NO_DEBUG_INFO (KLDR_ERR_BASE + 26) /** The module is already mapped. * kLdrModMap() can only be called once (without kLdrModUnmap() in between). */ #define KLDR_ERR_ALREADY_MAPPED (KLDR_ERR_BASE + 27) /** The module was not mapped. * kLdrModUnmap() should not called without being preceeded by a kLdrModMap(). */ #define KLDR_ERR_NOT_MAPPED (KLDR_ERR_BASE + 28) /** Couldn't fit the address value into the field. Typically a relocation kind of error. */ #define KLDR_ERR_ADDRESS_OVERFLOW (KLDR_ERR_BASE + 29) /** Couldn't fit a calculated size value into the native size type of the host. */ #define KLDR_ERR_SIZE_OVERFLOW (KLDR_ERR_BASE + 30) /** Thread attach failed. */ #define KLDR_ERR_THREAD_ATTACH_FAILED (KLDR_ERR_BASE + 31) /** The module wasn't a DLL or object file. */ #define KLDR_ERR_NOT_DLL (KLDR_ERR_BASE + 32) /** The module wasn't an EXE. */ #define KLDR_ERR_NOT_EXE (KLDR_ERR_BASE + 33) /** Not implemented yet. */ #define KLDR_ERR_TODO (KLDR_ERR_BASE + 34) /** No image matching the requested CPU. */ #define KLDR_ERR_CPU_ARCH_MISMATCH (KLDR_ERR_BASE + 35) /** Invalid FAT image header. */ #define KLDR_ERR_FAT_INVALID (KLDR_ERR_BASE + 36) /** Unsupported CPU subtype found in a FAT entry. */ #define KLDR_ERR_FAT_UNSUPPORTED_CPU_SUBTYPE (KLDR_ERR_BASE + 37) /** The image has no UUID. */ #define KLDR_ERR_NO_IMAGE_UUID (KLDR_ERR_BASE + 38) /** Duplicate segment name. */ #define KLDR_ERR_DUPLICATE_SEGMENT_NAME (KLDR_ERR_BASE + 39) /** @} */ /** @name kLdrModPE Specific * @{ */ /** The base of the kLdrModPE specific status codes. */ #define KLDR_ERR_PE_BASE (KLDR_ERR_BASE + 40) /** The machine isn't supported by the interpreter. */ #define KLDR_ERR_PE_UNSUPPORTED_MACHINE (KLDR_ERR_PE_BASE + 0) /** The file handler isn't valid. */ #define KLDR_ERR_PE_BAD_FILE_HEADER (KLDR_ERR_PE_BASE + 1) /** The the optional headers isn't valid. */ #define KLDR_ERR_PE_BAD_OPTIONAL_HEADER (KLDR_ERR_PE_BASE + 2) /** One of the section headers aren't valid. */ #define KLDR_ERR_PE_BAD_SECTION_HEADER (KLDR_ERR_PE_BASE + 3) /** Bad forwarder entry. */ #define KLDR_ERR_PE_BAD_FORWARDER (KLDR_ERR_PE_BASE + 4) /** Forwarder module not found in the import descriptor table. */ #define KLDR_ERR_PE_FORWARDER_IMPORT_NOT_FOUND (KLDR_ERR_PE_BASE + 5) /** Bad PE fixups. */ #define KLDR_ERR_PE_BAD_FIXUP (KLDR_ERR_PE_BASE + 6) /** Bad PE import (thunk). */ #define KLDR_ERR_PE_BAD_IMPORT (KLDR_ERR_PE_BASE + 7) /** @} */ /** @name kLdrModLX Specific * @{ */ /** The base of the kLdrModLX specific status codes. */ #define KLDR_ERR_LX_BASE (KLDR_ERR_PE_BASE + 8) /** validation of LX header failed. */ #define KLDR_ERR_LX_BAD_HEADER (KLDR_ERR_LX_BASE + 0) /** validation of the loader section (in the LX header) failed. */ #define KLDR_ERR_LX_BAD_LOADER_SECTION (KLDR_ERR_LX_BASE + 1) /** validation of the fixup section (in the LX header) failed. */ #define KLDR_ERR_LX_BAD_FIXUP_SECTION (KLDR_ERR_LX_BASE + 2) /** validation of the LX object table failed. */ #define KLDR_ERR_LX_BAD_OBJECT_TABLE (KLDR_ERR_LX_BASE + 3) /** A bad page map entry was encountered. */ #define KLDR_ERR_LX_BAD_PAGE_MAP (KLDR_ERR_LX_BASE + 4) /** Bad iterdata (EXEPACK) data. */ #define KLDR_ERR_LX_BAD_ITERDATA (KLDR_ERR_LX_BASE + 5) /** Bad iterdata2 (EXEPACK2) data. */ #define KLDR_ERR_LX_BAD_ITERDATA2 (KLDR_ERR_LX_BASE + 6) /** Bad bundle data. */ #define KLDR_ERR_LX_BAD_BUNDLE (KLDR_ERR_LX_BASE + 7) /** No soname. */ #define KLDR_ERR_LX_NO_SONAME (KLDR_ERR_LX_BASE + 8) /** Bad soname. */ #define KLDR_ERR_LX_BAD_SONAME (KLDR_ERR_LX_BASE + 9) /** Bad forwarder entry. */ #define KLDR_ERR_LX_BAD_FORWARDER (KLDR_ERR_LX_BASE + 10) /** internal fixup chain isn't implemented yet. */ #define KLDR_ERR_LX_NRICHAIN_NOT_SUPPORTED (KLDR_ERR_LX_BASE + 11) /** @} */ /** @name kLdrModMachO Specific * @{ */ /** The base of the kLdrModMachO specific status codes. */ #define KLDR_ERR_MACHO_BASE (KLDR_ERR_LX_BASE + 12) /** Only native endian Mach-O files are supported. */ #define KLDR_ERR_MACHO_OTHER_ENDIAN_NOT_SUPPORTED (KLDR_ERR_MACHO_BASE + 0) /** The Mach-O header is bad or contains new and unsupported features. */ #define KLDR_ERR_MACHO_BAD_HEADER (KLDR_ERR_MACHO_BASE + 1) /** The file type isn't supported. */ #define KLDR_ERR_MACHO_UNSUPPORTED_FILE_TYPE (KLDR_ERR_MACHO_BASE + 2) /** The machine (cputype / cpusubtype combination) isn't supported. */ #define KLDR_ERR_MACHO_UNSUPPORTED_MACHINE (KLDR_ERR_MACHO_BASE + 3) /** Bad load command(s). */ #define KLDR_ERR_MACHO_BAD_LOAD_COMMAND (KLDR_ERR_MACHO_BASE + 4) /** Encountered an unknown load command.*/ #define KLDR_ERR_MACHO_UNKNOWN_LOAD_COMMAND (KLDR_ERR_MACHO_BASE + 5) /** Encountered a load command that's not implemented.*/ #define KLDR_ERR_MACHO_UNSUPPORTED_LOAD_COMMAND (KLDR_ERR_MACHO_BASE + 6) /** Bad section. */ #define KLDR_ERR_MACHO_BAD_SECTION (KLDR_ERR_MACHO_BASE + 7) /** Encountered a section type that's not implemented.*/ #define KLDR_ERR_MACHO_UNSUPPORTED_SECTION (KLDR_ERR_MACHO_BASE + 8) /** Encountered a init function section. */ #define KLDR_ERR_MACHO_UNSUPPORTED_INIT_SECTION (KLDR_ERR_MACHO_BASE + 9) /** Encountered a term function section. */ #define KLDR_ERR_MACHO_UNSUPPORTED_TERM_SECTION (KLDR_ERR_MACHO_BASE + 10) /** Encountered a section type that's not known to the loader. (probably invalid) */ #define KLDR_ERR_MACHO_UNKNOWN_SECTION (KLDR_ERR_MACHO_BASE + 11) /** The sections aren't ordered by segment as expected by the loader. */ #define KLDR_ERR_MACHO_BAD_SECTION_ORDER (KLDR_ERR_MACHO_BASE + 12) /** The image is 32-bit and contains 64-bit load commands or vise versa. */ #define KLDR_ERR_MACHO_BIT_MIX (KLDR_ERR_MACHO_BASE + 13) /** Bad MH_OBJECT file. */ #define KLDR_ERR_MACHO_BAD_OBJECT_FILE (KLDR_ERR_MACHO_BASE + 14) /** Bad symbol table entry. */ #define KLDR_ERR_MACHO_BAD_SYMBOL (KLDR_ERR_MACHO_BASE + 15) /** Unsupported fixup type. */ #define KLDR_ERR_MACHO_UNSUPPORTED_FIXUP_TYPE (KLDR_ERR_MACHO_BASE + 16) /** Both debug and non-debug sections in segment. */ #define KLDR_ERR_MACHO_MIXED_DEBUG_SECTION_FLAGS (KLDR_ERR_MACHO_BASE + 17) /** The segment bits are non-contiguous in the file. */ #define KLDR_ERR_MACHO_NON_CONT_SEG_BITS (KLDR_ERR_MACHO_BASE + 18) /** @} */ /** @name kCpu Specific * @{ */ /** The base of the kCpu specific status codes. */ #define KCPU_ERR_BASE (KLDR_ERR_MACHO_BASE + 19) /** The specified ARCH+CPU pairs aren't compatible. */ #define KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE (KCPU_ERR_BASE + 0) /** @} */ /** End of the valid status codes. */ #define KERR_END (KCPU_ERR_BASE + 1) /** @}*/ #endif kbuild-3149/src/lib/kStuff/include/k/kHlpAlloc.h0000644000175000017500000000455713252530253021415 0ustar locutuslocutus/* $Id: kHlpAlloc.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpAlloc - Memory Allocation. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___k_kHlpAlloc_h___ #define ___k_kHlpAlloc_h___ #include #include /** @defgroup grp_kHlpAlloc kHlpAlloc - Memory Allocation * @addtogroup grp_kHlp * @{*/ /** @def kHlpAllocA * The alloca() wrapper. */ #ifdef __GNUC__ # define kHlpAllocA(a) __builtin_alloca(a) #elif defined(_MSC_VER) # include # define kHlpAllocA(a) alloca(a) #else # error "Port Me." #endif #ifdef __cplusplus extern "C" { #endif KHLP_DECL(void *) kHlpAlloc(KSIZE cb); KHLP_DECL(void *) kHlpAllocZ(KSIZE cb); KHLP_DECL(void *) kHlpDup(const void *pv, KSIZE cb); KHLP_DECL(char *) kHlpStrDup(const char *psz); KHLP_DECL(void *) kHlpRealloc(void *pv, KSIZE cb); KHLP_DECL(void) kHlpFree(void *pv); KHLP_DECL(int) kHlpPageAlloc(void **ppv, KSIZE cb, KPROT enmProt, KBOOL fFixed); KHLP_DECL(int) kHlpPageProtect(void *pv, KSIZE cb, KPROT enmProt); KHLP_DECL(int) kHlpPageFree(void *pv, KSIZE cb); KHLP_DECL(int) kHlpHeapInit(void); KHLP_DECL(void) kHlpHeapTerm(void); KHLP_DECL(void) kHlpHeapDonate(void *pv, KSIZE cb); #ifdef __cplusplus } #endif /** @} */ #endif kbuild-3149/src/lib/kStuff/include/k/kLdr.h0000644000175000017500000011704413252530253020434 0ustar locutuslocutus/* $Id: kLdr.h 81 2016-08-18 22:10:38Z bird $ */ /** @file * kLdr - The Dynamic Loader. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___k_kLdr_h___ #define ___k_kLdr_h___ #ifdef __cplusplus extern "C" { #endif /* * Include the base typedefs and macros. */ #include #include #include /** @defgroup grp_kLdrBasic kLdr Basic Types * @{ */ /** The kLdr address type. */ typedef KU64 KLDRADDR; /** Pointer to a kLdr address. */ typedef KLDRADDR *PKLDRADDR; /** Pointer to a const kLdr address. */ typedef const KLDRADDR *PCKLDRADDR; /** NIL address. */ #define NIL_KLDRADDR (~(KU64)0) /** @def PRI_KLDRADDR * printf format type. */ #ifdef _MSC_VER # define PRI_KLDRADDR "I64x" #else # define PRI_KLDRADDR "llx" #endif /** Align a KSIZE value. */ #define KLDR_ALIGN_ADDR(val, align) ( ((val) + ((align) - 1)) & ~(KLDRADDR)((align) - 1) ) /** The kLdr size type. */ typedef KU64 KLDRSIZE; /** Pointer to a kLdr size. */ typedef KLDRSIZE *PKLDRSIZE; /** Pointer to a const kLdr size. */ typedef const KLDRSIZE *PCKLDRSIZE; /** @def PRI_KLDRSIZE * printf format type. */ #ifdef _MSC_VER # define PRI_KLDRSIZE "I64x" #else # define PRI_KLDRSIZE "llx" #endif /** The kLdr file offset type. */ typedef long KLDRFOFF; /** Pointer to a kLdr file offset type. */ typedef KLDRFOFF *PKLDRFOFF; /** Pointer to a const kLdr file offset type. */ typedef const KLDRFOFF *PCKLDRFOFF; /** @def PRI_KLDRFOFF * printf format type. */ #define PRI_KLDRFOFF "lx" /** * Union of all the integer types. */ typedef union KLDRU { KI8 i8; /**< KI8 view. */ KU8 u8; /**< KU8 view. */ KI16 i16; /**< KI16 view. */ KU16 u16; /**< KU16 view. */ KI32 i32; /**< KI32 view. */ KU32 u32; /**< KU32 view. */ KI64 i64; /**< KI64 view. */ KU64 u64; /**< KU64 view. */ KI8 ai8[8]; /**< KI8 array view . */ KU8 au8[8]; /**< KU8 array view. */ KI16 ai16[4];/**< KI16 array view . */ KU16 au16[4];/**< KU16 array view. */ KI32 ai32[2];/**< KI32 array view . */ KU32 au32[2];/**< KU32 array view. */ signed char ch; /**< signed char view. */ unsigned char uch; /**< unsigned char view. */ signed short s; /**< signed short view. */ unsigned short us; /**< unsigned short view. */ signed int i; /**< signed int view. */ unsigned int u; /**< unsigned int view. */ signed long l; /**< signed long view. */ unsigned long ul; /**< unsigned long view. */ void *pv; /**< void pointer view. */ KLDRADDR Addr; /**< kLdr address view. */ KLDRSIZE Size; /**< kLdr size view. */ } KLDRU; /** Pointer to an integer union. */ typedef KLDRU *PKLDRU; /** Pointer to a const integer union. */ typedef const KLDRU *PCKLDRU; /** * Union of pointers to all the integer types. */ typedef union KLDRPU { KI8 *pi8; /**< KI8 view. */ KU8 *pu8; /**< KU8 view. */ KI16 *pi16; /**< KI16 view. */ KU16 *pu16; /**< KU16 view. */ KI32 *pi32; /**< KI32 view. */ KU32 *pu32; /**< KU32 view. */ KI64 *pi64; /**< KI64 view. */ KU64 *pu64; /**< KU64 view. */ signed char *pch; /**< signed char view. */ unsigned char *puch; /**< unsigned char view. */ signed short *ps; /**< signed short view. */ unsigned short *pus; /**< unsigned short view. */ signed int *pi; /**< signed int view. */ unsigned int *pu; /**< unsigned int view. */ signed long *pl; /**< signed long view. */ unsigned long *pul; /**< unsigned long view. */ void *pv; /**< void pointer view. */ } KLDRPU; /** Pointer to an integer pointer union. */ typedef KLDRPU *PKLDRPU; /** Pointer to a const integer pointer union. */ typedef const KLDRPU *PCKLDRPU; /** @} */ /** @defgroup grp_kLdrMod kLdrMod - The executable image intepreter * @{ */ /** * Debug info type (from the loader point of view). */ typedef enum KLDRDBGINFOTYPE { /** The usual invalid enum value. */ KLDRDBGINFOTYPE_INVALID = 0, /** Unknown debug info format. */ KLDRDBGINFOTYPE_UNKNOWN, /** Stabs. */ KLDRDBGINFOTYPE_STABS, /** Debug With Arbitrary Record Format (DWARF). */ KLDRDBGINFOTYPE_DWARF, /** Microsoft Codeview debug info. */ KLDRDBGINFOTYPE_CODEVIEW, /** Watcom debug info. */ KLDRDBGINFOTYPE_WATCOM, /** IBM High Level Language debug info.. */ KLDRDBGINFOTYPE_HLL, /** The end of the valid debug info values (exclusive). */ KLDRDBGINFOTYPE_END, /** Blow the type up to 32-bit. */ KLDRDBGINFOTYPE_32BIT_HACK = 0x7fffffff } KLDRDBGINFOTYPE; /** Pointer to a kLdr debug info type. */ typedef KLDRDBGINFOTYPE *PKLDRDBGINFOTYPE; /** * Stack information. */ typedef struct KLDRSTACKINFO { /** The base address of the stack (sub) segment. * Set this to NIL_KLDRADDR if the module doesn't include any stack segment. */ KLDRADDR Address; /** The base address of the stack (sub) segment, link address. * Set this to NIL_KLDRADDR if the module doesn't include any stack (sub)segment. */ KLDRADDR LinkAddress; /** The stack size of the main thread. * If no stack (sub)segment in the module, this is the stack size of the main thread. * If the module doesn't contain this kind of information this field will be set to 0. */ KLDRSIZE cbStack; /** The stack size of non-main threads. * If the module doesn't contain this kind of information this field will be set to 0. */ KLDRSIZE cbStackThread; } KLDRSTACKINFO; /** Pointer to stack information. */ typedef KLDRSTACKINFO *PKLDRSTACKINFO; /** Pointer to const stack information. */ typedef const KLDRSTACKINFO *PCKLDRSTACKINFO; /** * Loader segment. */ typedef struct KLDRSEG { /** Variable free to use for the kLdr user. */ void *pvUser; /** The segment name. (Might not be zero terminated!) */ const char *pchName; /** The length of the segment name. */ KU32 cchName; /** The flat selector to use for the segment (i.e. data/code). * Primarily a way for the user to specify selectors for the LX/LE and NE interpreters. */ KU16 SelFlat; /** The 16-bit selector to use for the segment. * Primarily a way for the user to specify selectors for the LX/LE and NE interpreters. */ KU16 Sel16bit; /** Segment flags. */ KU32 fFlags; /** The segment protection. */ KPROT enmProt; /** The size of the segment. */ KLDRSIZE cb; /** The required segment alignment. * The to 0 if the segment isn't supposed to be mapped. */ KLDRADDR Alignment; /** The link address. * Set to NIL_KLDRADDR if the segment isn't supposed to be * mapped or if the image doesn't have link addresses. */ KLDRADDR LinkAddress; /** File offset of the segment. * Set to -1 if no file backing (like BSS). */ KLDRFOFF offFile; /** Size of the file bits of the segment. * Set to -1 if no file backing (like BSS). */ KLDRFOFF cbFile; /** The relative virtual address when mapped. * Set to NIL_KLDRADDR if the segment isn't supposed to be mapped. */ KLDRADDR RVA; /** The size of the segment including the alignment gap up to the next segment when mapped. */ KSIZE cbMapped; /** The address the segment was mapped at by kLdrModMap(). * Set to 0 if not mapped. */ KUPTR MapAddress; } KLDRSEG; /** @name Segment flags * @{ */ /** The segment is 16-bit. When not set the default of the target architecture is assumed. */ #define KLDRSEG_FLAG_16BIT 1 /** The segment requires a 16-bit selector alias. (OS/2) */ #define KLDRSEG_FLAG_OS2_ALIAS16 2 /** Conforming segment (x86 weirdness). (OS/2) */ #define KLDRSEG_FLAG_OS2_CONFORM 4 /** IOPL (ring-2) segment. (OS/2) */ #define KLDRSEG_FLAG_OS2_IOPL 8 /** @} */ /** * Loader module format. */ typedef enum KLDRFMT { /** The usual invalid 0 format. */ KLDRFMT_INVALID = 0, /** The native OS loader. */ KLDRFMT_NATIVE, /** The AOUT loader. */ KLDRFMT_AOUT, /** The ELF loader. */ KLDRFMT_ELF, /** The LX loader. */ KLDRFMT_LX, /** The Mach-O loader. */ KLDRFMT_MACHO, /** The PE loader. */ KLDRFMT_PE, /** The end of the valid format values (exclusive). */ KLDRFMT_END, /** Hack to blow the type up to 32-bit. */ KLDRFMT_32BIT_HACK = 0x7fffffff } KLDRFMT; /** * Loader module type. */ typedef enum KLDRTYPE { /** The usual invalid 0 type. */ KLDRTYPE_INVALID = 0, /** Object file. */ KLDRTYPE_OBJECT, /** Executable module, fixed load address. */ KLDRTYPE_EXECUTABLE_FIXED, /** Executable module, relocatable, non-fixed load address. */ KLDRTYPE_EXECUTABLE_RELOCATABLE, /** Executable module, position independent code, non-fixed load address. */ KLDRTYPE_EXECUTABLE_PIC, /** Shared library, fixed load address. * Typically a system library. */ KLDRTYPE_SHARED_LIBRARY_FIXED, /** Shared library, relocatable, non-fixed load address. */ KLDRTYPE_SHARED_LIBRARY_RELOCATABLE, /** Shared library, position independent code, non-fixed load address. */ KLDRTYPE_SHARED_LIBRARY_PIC, /** DLL that contains no code or data only imports and exports. (Chiefly OS/2.) */ KLDRTYPE_FORWARDER_DLL, /** Core or dump. */ KLDRTYPE_CORE, /** Debug module (debug info with empty code & data segments). */ KLDRTYPE_DEBUG_INFO, /** The end of the valid types values (exclusive). */ KLDRTYPE_END, /** Hack to blow the type up to 32-bit. */ KLDRTYPE_32BIT_HACK = 0x7fffffff } KLDRTYPE; /** * Loader endian indicator. */ typedef enum KLDRENDIAN { /** The usual invalid endian. */ KLDRENDIAN_INVALID, /** Little endian. */ KLDRENDIAN_LITTLE, /** Bit endian. */ KLDRENDIAN_BIG, /** Endianness doesn't have a meaning in the context. */ KLDRENDIAN_NA, /** The end of the valid endian values (exclusive). */ KLDRENDIAN_END, /** Hack to blow the type up to 32-bit. */ KLDRENDIAN_32BIT_HACK = 0x7fffffff } KLDRENDIAN; /** @name KLDRMOD::fFlags * @{ */ /** The link address doesn't form a contiguous image, from the first to the * last segment. */ #define KLDRMOD_FLAGS_NON_CONTIGUOUS_LINK_ADDRS K_BIT32(0) /** @} */ /** Pointer to a module interpreter method table. */ typedef struct KLDRMODOPS *PKLDRMODOPS; /** Pointer to const module interpreter methods table. */ typedef const struct KLDRMODOPS *PCKLDRMODOPS; /** * Module interpreter instance. * All members are read only unless you're kLdrMod or the module interpreter. */ typedef struct KLDRMOD { /** Magic number (KLDRMOD_MAGIC). */ KU32 u32Magic; /** The format of this module. */ KLDRFMT enmFmt; /** The type of module. */ KLDRTYPE enmType; /** The CPU architecture this module was built for. */ KCPUARCH enmArch; /** The minium cpu this module was built for. * This might not be accurate, so use kLdrModCanExecuteOn() to check. */ KCPU enmCpu; /** The endian used by the module. */ KLDRENDIAN enmEndian; /** Module falgs. */ KU32 fFlags; /** The filename length (bytes). */ KU32 cchFilename; /** The filename. */ const char *pszFilename; /** The module name. */ const char *pszName; /** The module name length (bytes). */ KU32 cchName; /** The number of segments in the module. */ KU32 cSegments; /** Pointer to the loader methods. * Not meant for calling directly thru! */ PCKLDRMODOPS pOps; /** Pointer to the read instance. (Can be NULL after kLdrModDone().)*/ PKRDR pRdr; /** The module data. */ void *pvData; /** Segments. (variable size, can be zero) */ KLDRSEG aSegments[1]; } KLDRMOD, *PKLDRMOD, **PPKLDRMOD; /** The magic for KLDRMOD::u32Magic. (Kosuke Fujishima) */ #define KLDRMOD_MAGIC 0x19640707 /** Special base address value alias for the link address. */ #define KLDRMOD_BASEADDRESS_LINK (~(KLDRADDR)1) /** Special base address value alias for the actual load address (must be mapped). */ #define KLDRMOD_BASEADDRESS_MAP (~(KLDRADDR)2) /** Special import module ordinal value used to indicate that there is no * specific module associated with the requested symbol. */ #define NIL_KLDRMOD_IMPORT (~(KU32)0) /** Special symbol ordinal value used to indicate that the symbol * only has a string name. */ #define NIL_KLDRMOD_SYM_ORDINAL (~(KU32)0) /** @name Load symbol kind flags. * @{ */ /** The bitness doesn't matter. */ #define KLDRSYMKIND_NO_BIT 0x00000000 /** 16-bit symbol. */ #define KLDRSYMKIND_16BIT 0x00000001 /** 32-bit symbol. */ #define KLDRSYMKIND_32BIT 0x00000002 /** 64-bit symbol. */ #define KLDRSYMKIND_64BIT 0x00000003 /** Mask out the bit.*/ #define KLDRSYMKIND_BIT_MASK 0x00000003 /** We don't know the type of symbol. */ #define KLDRSYMKIND_NO_TYPE 0x00000000 /** The symbol is a code object (method/function/procedure/whateveryouwannacallit). */ #define KLDRSYMKIND_CODE 0x00000010 /** The symbol is a data object. */ #define KLDRSYMKIND_DATA 0x00000020 /** Mask out the symbol type. */ #define KLDRSYMKIND_TYPE_MASK 0x00000030 /** Valid symbol kind mask. */ #define KLDRSYMKIND_MASK 0x00000033 /** Weak symbol. */ #define KLDRSYMKIND_WEAK 0x00000100 /** Forwarder symbol. */ #define KLDRSYMKIND_FORWARDER 0x00000200 /** Request a flat symbol address. */ #define KLDRSYMKIND_REQ_FLAT 0x00000000 /** Request a segmented symbol address. */ #define KLDRSYMKIND_REQ_SEGMENTED 0x40000000 /** Request type mask. */ #define KLDRSYMKIND_REQ_TYPE_MASK 0x40000000 /** @} */ /** @name kLdrModEnumSymbols flags. * @{ */ /** Returns ALL kinds of symbols. The default is to only return public/exported symbols. */ #define KLDRMOD_ENUM_SYMS_FLAGS_ALL 0x00000001 /** @} */ /** * Callback for resolving imported symbols when applying fixups. * * @returns 0 on success and *pValue and *pfKind filled. * @returns Non-zero OS specific or kLdr status code on failure. * * @param pMod The module which fixups are begin applied. * @param iImport The import module ordinal number or NIL_KLDRMOD_IMPORT. * @param iSymbol The symbol ordinal number or NIL_KLDRMOD_SYM_ORDINAL. * @param pchSymbol The symbol name. Can be NULL if iSymbol isn't nil. Doesn't have to be null-terminated. * @param cchSymbol The length of the symbol. * @param pszVersion The symbol version. NULL if not versioned. * @param puValue Where to store the symbol value. * @param pfKind Where to store the symbol kind flags. * @param pvUser The user parameter specified to the relocation function. */ typedef int FNKLDRMODGETIMPORT(PKLDRMOD pMod, KU32 iImport, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, PKLDRADDR puValue, KU32 *pfKind, void *pvUser); /** Pointer to a import callback. */ typedef FNKLDRMODGETIMPORT *PFNKLDRMODGETIMPORT; /** * Symbol enumerator callback. * * @returns 0 if enumeration should continue. * @returns non-zero if the enumeration should stop. This status code will then be returned by kLdrModEnumSymbols(). * * @param pMod The module which symbols are being enumerated.s * @param iSymbol The symbol ordinal number or NIL_KLDRMOD_SYM_ORDINAL. * @param pchSymbol The symbol name. This can be NULL if there is a symbol ordinal. * This can also be an empty string if the symbol doesn't have a name * or it's name has been stripped. * Important, this doesn't have to be a null-terminated string. * @param cchSymbol The length of the symbol. * @param pszVersion The symbol version. NULL if not versioned. * @param uValue The symbol value. * @param fKind The symbol kind flags. * @param pvUser The user parameter specified to kLdrModEnumSymbols(). */ typedef int FNKLDRMODENUMSYMS(PKLDRMOD pMod, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, KLDRADDR uValue, KU32 fKind, void *pvUser); /** Pointer to a symbol enumerator callback. */ typedef FNKLDRMODENUMSYMS *PFNKLDRMODENUMSYMS; /** * Debug info enumerator callback. * * @returns 0 to continue the enumeration. * @returns non-zero if the enumeration should stop. This status code will then be returned by kLdrModEnumDbgInfo(). * * @param pMod The module. * @param iDbgInfo The debug info ordinal number / id. * @param enmType The debug info type. * @param iMajorVer The major version number of the debug info format. -1 if unknow - implies invalid iMinorVer. * @param iMinorVer The minor version number of the debug info format. -1 when iMajorVer is -1. * @param pszPartNm The name of the debug info part, NULL if not applicable. * @param offFile The file offset *if* this type has one specific location in the executable image file. * This is -1 if there isn't any specific file location. * @param LinkAddress The link address of the debug info if it's loadable. NIL_KLDRADDR if not loadable. * @param cb The size of the debug information. -1 is used if this isn't applicable. * @param pszExtFile This points to the name of an external file containing the debug info. * This is NULL if there isn't any external file. * @param pvUser The user parameter specified to kLdrModEnumDbgInfo. */ typedef int FNKLDRENUMDBG(PKLDRMOD pMod, KU32 iDbgInfo, KLDRDBGINFOTYPE enmType, KI16 iMajorVer, KI16 iMinorVer, const char *pszPartNm, KLDRFOFF offFile, KLDRADDR LinkAddress, KLDRSIZE cb, const char *pszExtFile, void *pvUser); /** Pointer to a debug info enumerator callback. */ typedef FNKLDRENUMDBG *PFNKLDRENUMDBG; /** * Resource enumerator callback. * * @returns 0 to continue the enumeration. * @returns non-zero if the enumeration should stop. This status code will then be returned by kLdrModEnumResources(). * * @param pMod The module. * @param idType The resource type id. NIL_KLDRMOD_RSRC_TYPE_ID if no type id. * @param pszType The resource type name. NULL if no type name. * @param idName The resource id. NIL_KLDRMOD_RSRC_NAME_ID if no id. * @param pszName The resource name. NULL if no name. * @param idLang The language id. * @param AddrRsrc The address value for the resource. * @param cbRsrc The size of the resource. * @param pvUser The user parameter specified to kLdrModEnumDbgInfo. */ typedef int FNKLDRENUMRSRC(PKLDRMOD pMod, KU32 idType, const char *pszType, KU32 idName, const char *pszName, KU32 idLang, KLDRADDR AddrRsrc, KLDRSIZE cbRsrc, void *pvUser); /** Pointer to a resource enumerator callback. */ typedef FNKLDRENUMRSRC *PFNKLDRENUMRSRC; /** NIL resource name ID. */ #define NIL_KLDRMOD_RSRC_NAME_ID ( ~(KU32)0 ) /** NIL resource type ID. */ #define NIL_KLDRMOD_RSRC_TYPE_ID ( ~(KU32)0 ) /** @name Language ID * * Except for the special IDs #defined here, the values are considered * format specific for now since it's only used by the PE resources. * * @{ */ /** NIL language ID. */ #define NIL_KLDR_LANG_ID ( ~(KU32)0 ) /** Special language id value for matching any language. */ #define KLDR_LANG_ID_ANY ( ~(KU32)1 ) /** Special language id value indicating language neutral. */ #define KLDR_LANG_ID_NEUTRAL ( ~(KU32)2 ) /** Special language id value indicating user default language. */ #define KLDR_LANG_ID_USER_DEFAULT ( ~(KU32)3 ) /** Special language id value indicating system default language. */ #define KLDR_LANG_ID_SYS_DEFAULT ( ~(KU32)4 ) /** Special language id value indicating default custom locale. */ #define KLDR_LANG_ID_CUSTOM_DEFAULT ( ~(KU32)5 ) /** Special language id value indicating unspecified custom locale. */ #define KLDR_LANG_ID_CUSTOM_UNSPECIFIED ( ~(KU32)6 ) /** Special language id value indicating default custom MUI locale. */ #define KLDR_LANG_ID_UI_CUSTOM_DEFAULT ( ~(KU32)7 ) /** @} */ /** @name Module Open Flags * @{ */ /** Indicates that we won't be loading the module, we're just getting * information (like symbols and line numbers) out of it. */ #define KLDRMOD_OPEN_FLAGS_FOR_INFO K_BIT32(0) /** Mask of valid flags. */ #define KLDRMOD_OPEN_FLAGS_VALID_MASK KU32_C(0x00000001) /** @} */ int kLdrModOpen(const char *pszFilename, KU32 fFlags, KCPUARCH enmCpuArch, PPKLDRMOD ppMod); int kLdrModOpenFromRdr(PKRDR pRdr, KU32 fFlags, KCPUARCH enmCpuArch, PPKLDRMOD ppMod); int kLdrModOpenNative(const char *pszFilename, PPKLDRMOD ppMod); int kLdrModOpenNativeByHandle(KUPTR uHandle, PPKLDRMOD ppMod); int kLdrModClose(PKLDRMOD pMod); int kLdrModQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind); int kLdrModEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser); int kLdrModGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName); KI32 kLdrModNumberOfImports(PKLDRMOD pMod, const void *pvBits); int kLdrModCanExecuteOn(PKLDRMOD pMod, const void *pvBits, KCPUARCH enmArch, KCPU enmCpu); int kLdrModGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo); int kLdrModQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress); int kLdrModQueryImageUuid(PKLDRMOD pMod, const void *pvBits, void *pvUuid, KSIZE cbUuid); int kLdrModQueryResource(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 idType, const char *pszType, KU32 idName, const char *pszName, KU32 idLang, PKLDRADDR pAddrRsrc, KSIZE *pcbRsrc); int kLdrModEnumResources(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 idType, const char *pszType, KU32 idName, const char *pszName, KU32 idLang, PFNKLDRENUMRSRC pfnCallback, void *pvUser); int kLdrModEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser); int kLdrModHasDbgInfo(PKLDRMOD pMod, const void *pvBits); int kLdrModMostlyDone(PKLDRMOD pMod); /** @name Operations On The Internally Managed Mapping * @{ */ int kLdrModMap(PKLDRMOD pMod); int kLdrModUnmap(PKLDRMOD pMod); int kLdrModReload(PKLDRMOD pMod); int kLdrModFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); /** @} */ /** @name Operations On The Externally Managed Mappings * @{ */ KLDRADDR kLdrModSize(PKLDRMOD pMod); int kLdrModGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); int kLdrModRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); /** @} */ /** @name Operations on both internally and externally managed mappings. * @{ */ /** Special pvMapping value to pass to kLdrModAllocTLS, * kLdrModFreeTLS, kLdrModCallInit, kLdrModCallTerm, and kLdrModCallThread that * specifies the internal mapping (kLdrModMap). */ #define KLDRMOD_INT_MAP ((void *)~(KUPTR)0) int kLdrModAllocTLS(PKLDRMOD pMod, void *pvMapping); void kLdrModFreeTLS(PKLDRMOD pMod, void *pvMapping); int kLdrModCallInit(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle); int kLdrModCallTerm(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle); int kLdrModCallThread(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle, unsigned fAttachingOrDetaching); /** @} */ /** * The loader module operation. */ typedef struct KLDRMODOPS { /** The name of this module interpreter. */ const char *pszName; /** Pointer to the next module interpreter. */ PCKLDRMODOPS pNext; /** * Create a loader module instance interpreting the executable image found * in the specified file provider instance. * * @returns 0 on success and *ppMod pointing to a module instance. * On failure, a non-zero OS specific error code is returned. * @param pOps Pointer to the registered method table. * @param pRdr The file provider instance to use. * @param fFlags Flags, MBZ. * @param enmCpuArch The desired CPU architecture. KCPUARCH_UNKNOWN means * anything goes, but with a preference for the current * host architecture. * @param offNewHdr The offset of the new header in MZ files. -1 if not found. * @param ppMod Where to store the module instance pointer. */ int (* pfnCreate)(PCKLDRMODOPS pOps, PKRDR pRdr, KU32 fFlags, KCPUARCH enmCpuArch, KLDRFOFF offNewHdr, PPKLDRMOD ppMod); /** * Destroys an loader module instance. * * The caller is responsible for calling kLdrModUnmap() and kLdrFreeTLS() first. * * @returns 0 on success, non-zero on failure. The module instance state * is unknown on failure, it's best not to touch it. * @param pMod The module. */ int (* pfnDestroy)(PKLDRMOD pMod); /** @copydoc kLdrModQuerySymbol */ int (* pfnQuerySymbol)(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind); /** @copydoc kLdrModEnumSymbols */ int (* pfnEnumSymbols)(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser); /** @copydoc kLdrModGetImport */ int (* pfnGetImport)(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName); /** @copydoc kLdrModNumberOfImports */ KI32 (* pfnNumberOfImports)(PKLDRMOD pMod, const void *pvBits); /** @copydoc kLdrModCanExecuteOn */ int (* pfnCanExecuteOn)(PKLDRMOD pMod, const void *pvBits, KCPUARCH enmArch, KCPU enmCpu); /** @copydoc kLdrModGetStackInfo */ int (* pfnGetStackInfo)(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo); /** @copydoc kLdrModQueryMainEntrypoint */ int (* pfnQueryMainEntrypoint)(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress); /** @copydoc kLdrModQueryImageUuid */ int (* pfnQueryImageUuid)(PKLDRMOD pMod, const void *pvBits, void *pvUuid, KSIZE pcbUuid); /** @copydoc kLdrModQueryResource */ int (* pfnQueryResource)(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 idType, const char *pszType, KU32 idName, const char *pszName, KU32 idLang, PKLDRADDR pAddrRsrc, KSIZE *pcbRsrc); /** @copydoc kLdrModEnumResources */ int (* pfnEnumResources)(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 idType, const char *pszType, KU32 idName, const char *pszName, KU32 idLang, PFNKLDRENUMRSRC pfnCallback, void *pvUser); /** @copydoc kLdrModEnumDbgInfo */ int (* pfnEnumDbgInfo)(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser); /** @copydoc kLdrModHasDbgInfo */ int (* pfnHasDbgInfo)(PKLDRMOD pMod, const void *pvBits); /** @copydoc kLdrModMap */ int (* pfnMap)(PKLDRMOD pMod); /** @copydoc kLdrModUnmap */ int (* pfnUnmap)(PKLDRMOD pMod); /** @copydoc kLdrModAllocTLS */ int (* pfnAllocTLS)(PKLDRMOD pMod, void *pvMapping); /** @copydoc kLdrModFreeTLS */ void (*pfnFreeTLS)(PKLDRMOD pMod, void *pvMapping); /** @copydoc kLdrModReload */ int (* pfnReload)(PKLDRMOD pMod); /** @copydoc kLdrModFixupMapping */ int (* pfnFixupMapping)(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); /** @copydoc kLdrModCallInit */ int (* pfnCallInit)(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle); /** @copydoc kLdrModCallTerm */ int (* pfnCallTerm)(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle); /** @copydoc kLdrModCallThread */ int (* pfnCallThread)(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle, unsigned fAttachingOrDetaching); /** @copydoc kLdrModSize */ KLDRADDR (* pfnSize)(PKLDRMOD pMod); /** @copydoc kLdrModGetBits */ int (* pfnGetBits)(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); /** @copydoc kLdrModRelocateBits */ int (* pfnRelocateBits)(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); /** @copydoc kLdrModMostlyDone */ int (* pfnMostlyDone)(PKLDRMOD pMod); /** Dummy which should be assigned a non-zero value. */ KU32 uEndOfStructure; } KLDRMODOPS; /** @} */ /** @defgroup grp_kLdrDyld kLdrDyld - The dynamic loader * @{ */ /** The handle to a dynamic loader module. */ typedef struct KLDRDYLDMOD *HKLDRMOD; /** Pointer to the handle to a dynamic loader module. */ typedef HKLDRMOD *PHKLDRMOD; /** NIL handle value. */ #define NIL_HKLDRMOD ((HKLDRMOD)0) /** * File search method. * * In addition to it's own way of finding files, kLdr emulates * the methods employed by the most popular systems. */ typedef enum KLDRDYLDSEARCH { /** The usual invalid file search method. */ KLDRDYLD_SEARCH_INVALID = 0, /** Uses the kLdr file search method. * @todo invent me. */ KLDRDYLD_SEARCH_KLDR, /** Use the emulation closest to the host system. */ KLDRDYLD_SEARCH_HOST, /** Emulate the OS/2 file search method. * On non-OS/2 systems, BEGINLIBPATH, LIBPATH, ENDLIBPATH and LIBPATHSTRICT are * taken form the environment. */ KLDRDYLD_SEARCH_OS2, /** Emulate the standard window file search method. */ KLDRDYLD_SEARCH_WINDOWS, /** Emulate the alternative window file search method. */ KLDRDYLD_SEARCH_WINDOWS_ALTERED, /** Emulate the most common UNIX file search method. */ KLDRDYLD_SEARCH_UNIX_COMMON, /** End of the valid file search method values. */ KLDRDYLD_SEARCH_END, /** Hack to blow the type up to 32-bit. */ KLDRDYLD_SEARCH_32BIT_HACK = 0x7fffffff } KLDRDYLDSEARCH; /** @name kLdrDyldLoad and kLdrDyldFindByName flags. * @{ */ /** The symbols in the module should be loaded into the global unix namespace. * If not specified, the symbols are local and can only be referenced directly. */ #define KLDRYDLD_LOAD_FLAGS_GLOBAL_SYMBOLS 0x00000001 /** The symbols in the module should be loaded into the global unix namespace and * it's symbols should take precedence over all currently loaded modules. * This implies KLDRYDLD_LOAD_FLAGS_GLOBAL_SYMBOLS. */ #define KLDRYDLD_LOAD_FLAGS_DEEP_SYMBOLS 0x00000002 /** The module shouldn't be found by a global module search. * If not specified, the module can be found by unspecified module searches, * typical used when loading import/dep modules. */ #define KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE 0x00000004 /** Do a recursive initialization calls instead of defering them to the outermost call. */ #define KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT 0x00000008 /** We're loading the executable module. * @internal */ #define KLDRDYLD_LOAD_FLAGS_EXECUTABLE 0x40000000 /** @} */ int kLdrDyldLoad(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PHKLDRMOD phMod, char *pszErr, KSIZE cchErr); int kLdrDyldUnload(HKLDRMOD hMod); int kLdrDyldFindByName(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PHKLDRMOD phMod); int kLdrDyldFindByAddress(KUPTR Address, PHKLDRMOD phMod, KU32 *piSegment, KUPTR *poffSegment); int kLdrDyldGetName(HKLDRMOD hMod, char *pszName, KSIZE cchName); int kLdrDyldGetFilename(HKLDRMOD hMod, char *pszFilename, KSIZE cchFilename); int kLdrDyldQuerySymbol(HKLDRMOD hMod, KU32 uSymbolOrdinal, const char *pszSymbolName, const char *pszSymbolVersion, KUPTR *pValue, KU32 *pfKind); int kLdrDyldQueryResource(HKLDRMOD hMod, KU32 idType, const char *pszType, KU32 idName, const char *pszName, KU32 idLang, void **pvRsrc, KSIZE *pcbRsrc); int kLdrDyldEnumResources(HKLDRMOD hMod, KU32 idType, const char *pszType, KU32 idName, const char *pszName, KU32 idLang, PFNKLDRENUMRSRC pfnCallback, void *pvUser); /** @name OS/2 like API * @{ */ #if defined(__OS2__) # define KLDROS2API _System #else # define KLDROS2API #endif int kLdrDosLoadModule(char *pszObject, KSIZE cbObject, const char *pszModule, PHKLDRMOD phMod); int kLdrDosFreeModule(HKLDRMOD hMod); int kLdrDosQueryModuleHandle(const char *pszModname, PHKLDRMOD phMod); int kLdrDosQueryModuleName(HKLDRMOD hMod, KSIZE cchName, char *pszName); int kLdrDosQueryProcAddr(HKLDRMOD hMod, KU32 iOrdinal, const char *pszProcName, void **ppvProcAddr); int kLdrDosQueryProcType(HKLDRMOD hMod, KU32 iOrdinal, const char *pszProcName, KU32 *pfProcType); int kLdrDosQueryModFromEIP(PHKLDRMOD phMod, KU32 *piObject, KSIZE cbName, char *pszName, KUPTR *poffObject, KUPTR ulEIP); int kLdrDosReplaceModule(const char *pszOldModule, const char *pszNewModule, const char *pszBackupModule); int kLdrDosGetResource(HKLDRMOD hMod, KU32 idType, KU32 idName, void **pvResAddr); int kLdrDosQueryResourceSize(HKLDRMOD hMod, KU32 idType, KU32 idName, KU32 *pcb); int kLdrDosFreeResource(void *pvResAddr); /** @} */ /** @name POSIX like API * @{ */ HKLDRMOD kLdrDlOpen(const char *pszLibrary, int fFlags); const char *kLdrDlError(void); void * kLdrDlSym(HKLDRMOD hMod, const char *pszSymbol); int kLdrDlClose(HKLDRMOD hMod); /** @todo GNU extensions */ /** @} */ /** @name Win32 like API * @{ */ #if defined(_MSC_VER) # define KLDRWINAPI __stdcall #else # define KLDRWINAPI #endif HKLDRMOD KLDRWINAPI kLdrWLoadLibrary(const char *pszFilename); HKLDRMOD KLDRWINAPI kLdrWLoadLibraryEx(const char *pszFilename, void *hFileReserved, KU32 fFlags); KU32 KLDRWINAPI kLdrWGetModuleFileName(HKLDRMOD hMod, char *pszModName, KSIZE cchModName); HKLDRMOD KLDRWINAPI kLdrWGetModuleHandle(const char *pszFilename); int KLDRWINAPI kLdrWGetModuleHandleEx(KU32 fFlags, const char *pszFilename, HKLDRMOD hMod); void * KLDRWINAPI kLdrWGetProcAddress(HKLDRMOD hMod, const char *pszProcName); KU32 KLDRWINAPI kLdrWGetDllDirectory(KSIZE cchDir, char *pszDir); int KLDRWINAPI kLdrWSetDllDirectory(const char *pszDir); int KLDRWINAPI kLdrWFreeLibrary(HKLDRMOD hMod); int KLDRWINAPI kLdrWDisableThreadLibraryCalls(HKLDRMOD hMod); /** The handle to a resource that's been found. */ typedef struct KLDRWRSRCFOUND *HKLDRWRSRCFOUND; /** The handle to a loaded resource. */ typedef struct KLDRWRSRCLOADED *HKLDRWRSRCLOADED; HKLDRWRSRCFOUND KLDRWINAPI kLdrWFindResource(HKLDRMOD hMod, const char *pszType, const char *pszName); HKLDRWRSRCFOUND KLDRWINAPI kLdrWFindResourceEx(HKLDRMOD hMod, const char *pszType, const char *pszName, KU16 idLang); KU32 KLDRWINAPI kLdrWSizeofResource(HKLDRMOD hMod, HKLDRWRSRCFOUND hFoundRsrc); HKLDRWRSRCLOADED KLDRWINAPI kLdrWLoadResource(HKLDRMOD hMod, HKLDRWRSRCFOUND hFoundRsrc); void *KLDRWINAPI kLdrWLockResource(HKLDRMOD hMod, HKLDRWRSRCLOADED hLoadedRsrc); int KLDRWINAPI kLdrWFreeResource(HKLDRMOD hMod, HKLDRWRSRCLOADED hLoadedRsrc); typedef int (KLDRWINAPI *PFNKLDRWENUMRESTYPE)(HKLDRMOD hMod, const char *pszType, KUPTR uUser); int KLDRWINAPI kLdrWEnumResourceTypes(HKLDRMOD hMod, PFNKLDRWENUMRESTYPE pfnEnum, KUPTR uUser); int KLDRWINAPI kLdrWEnumResourceTypesEx(HKLDRMOD hMod, PFNKLDRWENUMRESTYPE pfnEnum, KUPTR uUser, KU32 fFlags, KU16 idLang); typedef int (KLDRWINAPI *PFNKLDRWENUMRESNAME)(HKLDRMOD hMod, const char *pszType, char *pszName, KUPTR uUser); int KLDRWINAPI kLdrWEnumResourceNames(HKLDRMOD hMod, const char *pszType, PFNKLDRWENUMRESNAME pfnEnum, KUPTR uUser); int KLDRWINAPI kLdrWEnumResourceNamesEx(HKLDRMOD hMod, const char *pszType, PFNKLDRWENUMRESNAME pfnEnum, KUPTR uUser, KU32 fFlags, KU16 idLang); typedef int (KLDRWINAPI *PFNKLDRWENUMRESLANG)(HKLDRMOD hMod, const char *pszType, const char *pszName, KU16 idLang, KUPTR uUser); int KLDRWINAPI kLdrWEnumResourceLanguages(HKLDRMOD hMod, const char *pszType, const char *pszName, PFNKLDRWENUMRESLANG pfnEnum, KUPTR uUser); int KLDRWINAPI kLdrWEnumResourceLanguagesEx(HKLDRMOD hMod, const char *pszType, const char *pszName, PFNKLDRWENUMRESLANG pfnEnum, KUPTR uUser, KU32 fFlags, KU16 idLang); /** @} */ /** @name Process Bootstrapping * @{ */ /** * Argument package from the stub. */ typedef struct KLDREXEARGS { /** Load & search flags, some which will become defaults. */ KU32 fFlags; /** The default search method. */ KLDRDYLDSEARCH enmSearch; /** The executable file that the stub is supposed to load. */ char szExecutable[260]; /** The default prefix used when searching for DLLs. */ char szDefPrefix[16]; /** The default suffix used when searching for DLLs. */ char szDefSuffix[16]; /** The LD_LIBRARY_PATH prefix for the process.. */ char szLibPath[4096 - sizeof(KU32) - sizeof(KLDRDYLDSEARCH) - 16 - 16 - 260]; } KLDREXEARGS, *PKLDREXEARGS; /** Pointer to a const argument package from the stub. */ typedef const KLDREXEARGS *PCKLDREXEARGS; void kLdrLoadExe(PCKLDREXEARGS pArgs, void *pvOS); /** @todo fix this mess... */ void kLdrDyldLoadExe(PCKLDREXEARGS pArgs, void *pvOS); /** @} */ /** @} */ /** @} */ #ifdef __cplusplus } #endif #endif kbuild-3149/src/lib/kStuff/include/k/kHlpProcess.h0000644000175000017500000000310713252530253021767 0ustar locutuslocutus/* $Id: kHlpProcess.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpProcess - Process Management. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___k_kHlpProcess_h___ #define ___k_kHlpProcess_h___ #include #include /** @defgroup grp_kHlpProcess kHlpProcess - Process Management * @addtogroup grp_kHlp * @{*/ #ifdef __cplusplus extern "C" { #endif KHLP_DECL(void) kHlpExit(int rc); #ifdef __cplusplus } #endif /** @} */ #endif kbuild-3149/src/lib/kStuff/include/k/kHlpSem.h0000644000175000017500000000277313252530253021105 0ustar locutuslocutus/* $Id: kHlpSem.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kHlpSem - Semaphores. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___k_kHlpSem_h___ #define ___k_kHlpSem_h___ #include #include /** @defgroup grp_kHlpSem kHlpSem - Semaphore * @addtogroup grp_kHlp * @{*/ #ifdef __cplusplus extern "C" { #endif #ifdef __cplusplus } #endif /** @} */ #endif kbuild-3149/src/lib/kStuff/include/k/kTypes.h0000644000175000017500000004450113252530253021014 0ustar locutuslocutus/* $Id: kTypes.h 95 2016-09-26 07:23:08Z bird $ */ /** @file * kTypes - Typedefs And Related Constants And Macros. */ /* * Copyright (c) 2006-2009 Knut St. Osmundsen * * 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. */ #ifndef ___k_kTypes_h___ #define ___k_kTypes_h___ #include /** @defgroup grp_kTypes kTypes - Typedefs And Related Constants And Macros * @{ */ /** @typedef KI64 * 64-bit signed integer. */ /** @typedef KU64 * 64-bit unsigned integer. */ /** @def KI64_C * 64-bit signed integer constant. * @param c The constant value. */ /** @def KU64_C * 64-bit unsigned integer constant. * @param c The constant value. */ /** @def KI64_PRI * 64-bit signed integer printf format. */ /** @def KU64_PRI * 64-bit unsigned integer printf format. */ /** @def KX64_PRI * 64-bit signed and unsigned integer hexadecimal printf format. */ /** @typedef KI32 * 32-bit signed integer. */ /** @typedef KU32 * 32-bit unsigned integer. */ /** @def KI32_C * 32-bit signed integer constant. * @param c The constant value. */ /** @def KU32_C * 32-bit unsigned integer constant. * @param c The constant value. */ /** @def KI32_PRI * 32-bit signed integer printf format. */ /** @def KU32_PRI * 32-bit unsigned integer printf format. */ /** @def KX32_PRI * 32-bit signed and unsigned integer hexadecimal printf format. */ /** @typedef KI16 * 16-bit signed integer. */ /** @typedef KU16 * 16-bit unsigned integer. */ /** @def KI16_C * 16-bit signed integer constant. * @param c The value. */ /** @def KU16_C * 16-bit unsigned integer constant. * @param c The value. */ /** @def KI16_PRI * 16-bit signed integer printf format. */ /** @def KU16_PRI * 16-bit unsigned integer printf format. */ /** @def KX16_PRI * 16-bit signed and unsigned integer hexadecimal printf format. */ /** @typedef KI8 * 8-bit signed integer. */ /** @typedef KU8 * 8-bit unsigned integer. */ /** @def KI8_C * 8-bit signed integer constant. * @param c The constant value. */ /** @def KU8_C * 8-bit unsigned integer constant. * @param c The constant value. */ /** @def KI8_PRI * 8-bit signed integer printf format. */ /** @def KU8_PRI * 8-bit unsigned integer printf format. */ /** @def KX8_PRI * 8-bit signed and unsigned integer hexadecimal printf format. */ /** @typedef KSIZE * Memory size type; unsigned integer. */ /** @typedef KSSIZE * Memory size type; signed integer. */ /** @def KSIZE_C * Memory size constant. * @param c The constant value. */ /** @def KSSIZE_C * Memory size constant. * @param c The constant value. */ /** @def KSIZE_MAX * Memory size max constant.*/ /** @def KSSIZE_MAX * Memory size max constant.*/ /** @def KSSIZE_MIN * Memory size min constant.*/ /** @def KSIZE_PRI * Memory size default printf format (hex). */ /** @def KSIZE_PRI_U * Memory size unsigned decimal printf format. */ /** @def KSIZE_PRI_I * Memory size signed decimal printf format. */ /** @def KSIZE_PRI_X * Memory size hexadecimal printf format. */ /** @def KSSIZE_PRI * Memory size default printf format (hex). */ /** @def KSSIZE_PRI_U * Memory size unsigned decimal printf format. */ /** @def KSSIZE_PRI_I * Memory size signed decimal printf format. */ /** @def KSSIZE_PRI_X * Memory size hexadecimal printf format. */ /** @typedef KIPTR * Signed integer type capable of containing a pointer value. */ /** @typedef KUPTR * Unsigned integer type capable of containing a pointer value. */ /** @def KIPTR_C * Signed pointer constant. * @param c The constant value. */ /** @def KUPTR_C * Unsigned pointer constant. * @param c The constant value. */ /** @def KIPTR_MAX * Signed pointer max constant.*/ /** @def KIPTR_MIN * Signed pointer min constant.*/ /** @def KUPTR_MAX * Unsigned pointer max constant.*/ /** @def KIPTR_PRI * Signed pointer printf format. */ /** @def KUPTR_PRI * Unsigned pointer printf format. */ #if K_ARCH_BITS == 32 /* ASSUMES int == long == 32-bit, short == 16-bit, char == 8-bit. */ # ifdef _MSC_VER typedef signed __int64 KI64; typedef unsigned __int64 KU64; #define KI64_PRI "I64d" #define KU64_PRI "I64u" #define KX64_PRI "I64x" # else typedef signed long long int KI64; typedef unsigned long long int KU64; #define KI64_PRI "lld" #define KU64_PRI "llu" #define KX64_PRI "llx" # endif typedef signed int KI32; typedef unsigned int KU32; typedef signed short int KI16; typedef unsigned short int KU16; typedef signed char KI8; typedef unsigned char KU8; #define KI64_C(c) (c ## LL) #define KU64_C(c) (c ## ULL) #define KI32_C(c) (c) #define KU32_C(c) (c ## U) #define KI16_C(c) (c) #define KU16_C(c) (c) #define KI8_C(c) (c) #define KU8_C(c) (c) #define KI32_PRI "d" #define KU32_PRI "u" #define KX32_PRI "x" #define KI16_PRI "d" #define KU16_PRI "u" #define KX16_PRI "x" #define KI8_PRI "d" #define KU8_PRI "u" #define KX8_PRI "x" typedef KI32 KSSIZE; #define KSSIZE(c) KI32_C(c) #define KSSIZE_MAX KI32_MAX #define KSSIZE_MIN KI32_MIN #define KSSIZE_PRI KX32_PRI typedef KU32 KSIZE; #define KSIZE_C(c) KU32_C(c) #define KSIZE_MAX KU32_MAX #define KSIZE_PRI KX32_PRI #define KSIZE_PRI_U KU32_PRI #define KSIZE_PRI_I KI32_PRI #define KSIZE_PRI_X KX32_PRI #define KIPTR_C(c) KI32_C(c) typedef KI32 KIPTR; #define KIPTR_MAX KI32_MAX #define KIPTR_MIN KI32_MIN #define KIPTR_PRI KX32_PRI typedef KU32 KUPTR; #define KUPTR_C(c) KU32_C(c) #define KUPTR_MAX KU32_MAX #define KUPTR_PRI KX32_PRI #elif K_ARCH_BITS == 64 # if K_OS == K_OS_WINDOWS # if _MSC_VER typedef signed __int64 KI64; typedef unsigned __int64 KU64; # define KI64_PRI "I64d" # define KU64_PRI "I64u" # define KX64_PRI "I64x" # else typedef signed long long int KI64; typedef unsigned long long int KU64; # define KI64_PRI "lld" # define KU64_PRI "llu" # define KX64_PRI "llx" # endif # define KI64_C(c) (c ## LL) # define KU64_C(c) (c ## ULL) # else typedef signed long int KI64; typedef unsigned long int KU64; # define KI64_C(c) (c ## L) # define KU64_C(c) (c ## UL) # define KI64_PRI "ld" # define KU64_PRI "lu" # define KX64_PRI "lx" # endif typedef signed int KI32; typedef unsigned int KU32; typedef signed short KI16; typedef unsigned short KU16; typedef signed char KI8; typedef unsigned char KU8; #define KI32_C(c) (c) #define KU32_C(c) (c ## U) #define KI16_C(c) (c) #define KU16_C(c) (c) #define KI8_C(c) (c) #define KU8_C(c) (c) #define KI32_PRI "d" #define KU32_PRI "u" #define KX32_PRI "x" #define KI16_PRI "d" #define KU16_PRI "u" #define KX16_PRI "x" #define KI8_PRI "d" #define KU8_PRI "u" #define KX8_PRI "x" typedef KI64 KSSIZE; #define KSSIZE(c) KI64_C(c) #define KSSIZE_MAX KI64_MAX #define KSSIZE_MIN KI64_MIN #define KSSIZE_PRI KX64_PRI #define KSSIZE_PRI_U KU64_PRI #define KSSIZE_PRI_I KI64_PRI #define KSSIZE_PRI_X KX64_PRI typedef KU64 KSIZE; #define KSIZE_C(c) KU64_C(c) #define KSIZE_MAX KU64_MAX #define KSIZE_PRI_U KU64_PRI #define KSIZE_PRI_I KI64_PRI #define KSIZE_PRI_X KX64_PRI #define KSIZE_PRI KX64_PRI typedef KI64 KIPTR; #define KIPTR_C(c) KI64_C(c) #define KIPTR_MAX KI64_MAX #define KIPTR_MIN KI64_MIN #define KIPTR_PRI KX64_PRI typedef KU64 KUPTR; #define KUPTR_C(c) KU64_C(c) #define KUPTR_MAX KU64_MAX #define KUPTR_PRI KX64_PRI #else # error "Port Me" #endif /** Min KI8 value. */ #define KI8_MIN (KI8_C(-0x7f) - 1) /** Min KI16 value. */ #define KI16_MIN (KI16_C(-0x7fff) - 1) /** Min KI32 value. */ #define KI32_MIN (KI32_C(-0x7fffffff) - 1) /** Min KI64 value. */ #define KI64_MIN (KI64_C(-0x7fffffffffffffff) - 1) /** Max KI8 value. */ #define KI8_MAX KI8_C(0x7f) /** Max KI16 value. */ #define KI16_MAX KI16_C(0x7fff) /** Max KI32 value. */ #define KI32_MAX KI32_C(0x7fffffff) /** Max KI64 value. */ #define KI64_MAX KI64_C(0x7fffffffffffffff) /** Max KU8 value. */ #define KU8_MAX KU8_C(0xff) /** Max KU16 value. */ #define KU16_MAX KU16_C(0xffff) /** Max KU32 value. */ #define KU32_MAX KU32_C(0xffffffff) /** Max KU64 value. */ #define KU64_MAX KU64_C(0xffffffffffffffff) /** File offset. */ typedef KI64 KFOFF; /** Pointer a file offset. */ typedef KFOFF *PFOFF; /** Pointer a const file offset. */ typedef KFOFF *PCFOFF; /** The min value for the KFOFF type. */ #define KFOFF_MIN KI64_MIN /** The max value for the KFOFF type. */ #define KFOFF_MAX KI64_MAX /** File offset contstant. * @param c The constant value. */ #define KFOFF_C(c) KI64_C(c) /** File offset printf format. */ #define KFOFF_PRI KI64_PRI /** * Memory Protection. */ typedef enum KPROT { /** The usual invalid 0. */ KPROT_INVALID = 0, /** No access (page not present). */ KPROT_NOACCESS, /** Read only. */ KPROT_READONLY, /** Read & write. */ KPROT_READWRITE, /** Read & copy on write. */ KPROT_WRITECOPY, /** Execute only. */ KPROT_EXECUTE, /** Execute & read. */ KPROT_EXECUTE_READ, /** Execute, read & write. */ KPROT_EXECUTE_READWRITE, /** Execute, read & copy on write. */ KPROT_EXECUTE_WRITECOPY, /** The usual end value. (exclusive) */ KPROT_END, /** Blow the type up to 32-bits. */ KPROT_32BIT_HACK = 0x7fffffff } KPROT; /** Pointer to a memory protection enum. */ typedef KPROT *PKPROT; /** Pointer to a const memory protection enum. */ typedef KPROT const *PCKPROT; /** Boolean. * This can be used as a tri-state type, but then you *must* do == checks. */ typedef KI8 KBOOL; /** Pointer to a boolean value. */ typedef KBOOL *PKBOOL; /** Pointer to a const boolean value. */ typedef KBOOL const *PCKBOOL; /** Maxium value the KBOOL type can hold (officially). */ #define KBOOL_MIN KI8_C(-1) /** Maxium value the KBOOL type can hold (officially). */ #define KBOOL_MAX KI8_C(1) /** The KBOOL printf format. */ #define KBOOL_PRI KU8_PRI /** Boolean true constant. */ #define K_TRUE KI8_C(1) /** Boolean false constant. */ #define K_FALSE KI8_C(0) /** Boolean unknown constant (the third state). */ #define K_UNKNOWN KI8_C(-1) /** * Integer union. */ typedef union KUINT { KFOFF iBig; /**< The biggest member. */ KBOOL fBool; /**< Boolean. */ KU8 b; /**< unsigned 8-bit. */ KU8 u8; /**< unsigned 8-bit. */ KI8 i8; /**< signed 8-bit. */ KU16 u16; /**< unsigned 16-bit. */ KI16 i16; /**< signed 16-bit. */ KU32 u32; /**< unsigned 32-bit. */ KI32 i32; /**< signed 32-bit. */ KU64 u64; /**< unsigned 64-bit. */ KI64 i64; /**< signed 64-bit. */ KSIZE cbUnsign; /**< unsigned size. */ KSSIZE cbSign; /**< signed size. */ KFOFF offFile; /**< file offset. */ KUPTR uPtr; /**< unsigned pointer. */ KIPTR iPtr; /**< signed pointer. */ void *pv; /**< void pointer. */ char ch; /**< char. */ unsigned char uch; /**< unsigned char. */ signed char chSigned; /**< signed char. */ unsigned short uShort; /**< Unsigned short. */ signed short iShort; /**< Signed short. */ unsigned int uInt; /**< Unsigned int. */ signed int iInt; /**< Signed int. */ unsigned long uLong; /**< Unsigned long. */ signed long iLong; /**< Signed long. */ } KUINT; /** * Integer pointer union. */ typedef union KPUINT { KFOFF *piBig; /**< The biggest member. */ KBOOL *pfBool; /**< Boolean. */ KU8 *pb; /**< unsigned 8-bit. */ KU8 *pu8; /**< unsigned 8-bit. */ KI8 *pi8; /**< signed 8-bit. */ KU16 *pu16; /**< unsigned 16-bit. */ KI16 *pi16; /**< signed 16-bit. */ KU32 *pu32; /**< unsigned 32-bit. */ KI32 *pi32; /**< signed 32-bit. */ KU64 *pu64; /**< unsigned 64-bit. */ KI64 *pi64; /**< signed 64-bit. */ KSIZE *pcbUnsign; /**< unsigned size. */ KSSIZE *pcbSign; /**< signed size. */ KFOFF *poffFile; /**< file offset. */ KUPTR *puPtr; /**< unsigned pointer. */ KIPTR *piPtr; /**< signed pointer. */ void **ppv; /**< void pointer pointer. */ void *pv; /**< void pointer. */ char *pch; /**< char. */ char *psz; /**< zero terminated string. */ unsigned char *puch; /**< unsigned char. */ signed char *pchSigned; /**< signed char. */ unsigned short *puShort; /**< Unsigned short. */ signed short *piShort; /**< Signed short. */ unsigned int *puInt; /**< Unsigned int. */ signed int *piInt; /**< Signed int. */ unsigned long *puLong; /**< Unsigned long. */ signed long *piLong; /**< Signed long. */ } KPUINT; /** * Integer const pointer union. */ typedef union KPCUINT { KFOFF const *piBig; /**< The biggest member. */ KBOOL const *pfBool; /**< Boolean. */ KU8 const *pb; /**< byte. */ KU8 const *pu8; /**< unsigned 8-bit. */ KI8 const *pi8; /**< signed 8-bit. */ KU16 const *pu16; /**< unsigned 16-bit. */ KI16 const *pi16; /**< signed 16-bit. */ KU32 const *pu32; /**< unsigned 32-bit. */ KI32 const *pi32; /**< signed 32-bit. */ KU64 const *pu64; /**< unsigned 64-bit. */ KI64 const *pi64; /**< signed 64-bit. */ KSIZE const *pcbUnsign; /**< unsigned size. */ KSSIZE const *pcbSign; /**< signed size. */ KFOFF const *poffFile; /**< file offset. */ KUPTR const *puPtr; /**< unsigned pointer. */ KIPTR const *piPtr; /**< signed pointer. */ void const **ppv; /**< void pointer pointer. */ void const *pv; /**< void pointer. */ char const *pch; /**< char. */ char const *psz; /**< zero terminated string. */ unsigned char const *puch; /**< unsigned char. */ signed char const *pchSigned; /**< signed char. */ unsigned short const *puShort; /**< Unsigned short. */ signed short const *piShort; /**< Signed short. */ unsigned int const *puInt; /**< Unsigned int. */ signed int const *piInt; /**< Signed int. */ unsigned long const *puLong; /**< Unsigned long. */ signed long const *piLong; /**< Signed long. */ } KPCUINT; /** @name Forward Declarations / Handle Types. * @{ */ /** Pointer to a file provider instance. */ typedef struct KRDR *PKRDR; /** Pointer to a file provider instance pointer. */ typedef struct KRDR **PPKRDR; /** Pointer to a loader segment. */ typedef struct KLDRSEG *PKLDRSEG; /** Pointer to a loader segment. */ typedef const struct KLDRSEG *PCKLDRSEG; /** @} */ /** @} */ #endif kbuild-3149/src/lib/kStuff/include/k/kCpus.h0000644000175000017500000001016213252530253020616 0ustar locutuslocutus/* $Id: kCpus.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kCpus - CPU Identifiers. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___k_kCpus_h___ #define ___k_kCpus_h___ /** @defgroup grp_kCpus kCpus - CPU Identifiers * @see the kCpu API for functions operating on the CPU type. * @{ */ /** * CPU Architectures. * * The constants used by this enum has the same values as * the K_ARCH_* #defines defined by k/kDefs.h. */ typedef enum KCPUARCH { /** @copydoc K_ARCH_UNKNOWN */ KCPUARCH_UNKNOWN = K_ARCH_UNKNOWN, /** @copydoc K_ARCH_X86_16 */ KCPUARCH_X86_16 = K_ARCH_X86_16, /** @copydoc K_ARCH_X86_32 */ KCPUARCH_X86_32 = K_ARCH_X86_32, /** @copydoc K_ARCH_AMD64 */ KCPUARCH_AMD64 = K_ARCH_AMD64, /** @copydoc K_ARCH_IA64 */ KCPUARCH_IA64 = K_ARCH_IA64, /** @copydoc K_ARCH_ALPHA */ KCPUARCH_ALPHA = K_ARCH_ALPHA, /** @copydoc K_ARCH_ALPHA_32 */ KCPUARCH_ALPHA_32 = K_ARCH_ALPHA_32, /** @copydoc K_ARCH_ARM_32 */ KCPUARCH_ARM_32 = K_ARCH_ARM_32, /** @copydoc K_ARCH_ARM_64 */ KCPUARCH_ARM_64 = K_ARCH_ARM_64, /** @copydoc K_ARCH_MIPS_32 */ KCPUARCH_MIPS_32 = K_ARCH_MIPS_32, /** @copydoc K_ARCH_MIPS_64 */ KCPUARCH_MIPS_64 = K_ARCH_MIPS_64, /** @copydoc K_ARCH_POWERPC_32 */ KCPUARCH_POWERPC_32 = K_ARCH_POWERPC_32, /** @copydoc K_ARCH_POWERPC_64 */ KCPUARCH_POWERPC_64 = K_ARCH_POWERPC_64, /** @copydoc K_ARCH_SPARC_32 */ KCPUARCH_SPARC_32 = K_ARCH_SPARC_32, /** @copydoc K_ARCH_SPARC_64 */ KCPUARCH_SPARC_64 = K_ARCH_SPARC_64, /** Hack to blow the type up to 32-bit. */ KCPUARCH_32BIT_HACK = 0x7fffffff } KCPUARCH; /** Pointer to a CPU architecture type. */ typedef KCPUARCH *PKCPUARCH; /** Pointer to a const CPU architecture type. */ typedef const KCPUARCH *PCKCPUARCH; /** * CPU models. */ typedef enum KCPU { /** The usual invalid cpu. */ KCPU_INVALID = 0, /** @name K_ARCH_X86_16 * @{ */ KCPU_I8086, KCPU_I8088, KCPU_I80186, KCPU_I80286, KCPU_I386_16, KCPU_I486_16, KCPU_I486SX_16, KCPU_I586_16, KCPU_I686_16, KCPU_P4_16, KCPU_CORE2_16, KCPU_K6_16, KCPU_K7_16, KCPU_K8_16, KCPU_FIRST_X86_16 = KCPU_I8086, KCPU_LAST_X86_16 = KCPU_K8_16, /** @} */ /** @name K_ARCH_X86_32 * @{ */ KCPU_X86_32_BLEND, KCPU_I386, KCPU_I486, KCPU_I486SX, KCPU_I586, KCPU_I686, KCPU_P4, KCPU_CORE2_32, KCPU_K6, KCPU_K7, KCPU_K8_32, KCPU_FIRST_X86_32 = KCPU_I386, KCPU_LAST_X86_32 = KCPU_K8_32, /** @} */ /** @name K_ARCH_AMD64 * @{ */ KCPU_AMD64_BLEND, KCPU_K8, KCPU_P4_64, KCPU_CORE2, KCPU_FIRST_AMD64 = KCPU_K8, KCPU_LAST_AMD64 = KCPU_CORE2, /** @} */ /** The end of the valid cpu values (exclusive). */ KCPU_END, /** Hack to blow the type up to 32-bit. */ KCPU_32BIT_HACK = 0x7fffffff } KCPU; /** Pointer to a CPU type. */ typedef KCPU *PKCPU; /** Pointer to a const CPU type. */ typedef const KCPU *PCKCPU; /** @} */ #endif kbuild-3149/src/lib/kStuff/kTable/0000755000175000017500000000000013252530254016706 5ustar locutuslocutuskbuild-3149/src/lib/kStuff/kTable/testcase/0000755000175000017500000000000013252530254020521 5ustar locutuslocutuskbuild-3149/src/lib/kStuff/kLdr/0000755000175000017500000000000013252530254016400 5ustar locutuslocutuskbuild-3149/src/lib/kStuff/kLdr/kLdrModNative.c0000644000175000017500000011305713252530253021255 0ustar locutuslocutus/* $Id: kLdrModNative.c 82 2016-08-22 21:01:51Z bird $ */ /** @file * kLdr - The Module Interpreter for the Native Loaders. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include "kLdrInternal.h" #if K_OS == K_OS_OS2 # define INCL_BASE # include # ifndef LIBPATHSTRICT # define LIBPATHSTRICT 3 # endif extern APIRET DosQueryHeaderInfo(HMODULE hmod, ULONG ulIndex, PVOID pvBuffer, ULONG cbBuffer, ULONG ulSubFunction); # define QHINF_EXEINFO 1 /* NE exeinfo. */ # define QHINF_READRSRCTBL 2 /* Reads from the resource table. */ # define QHINF_READFILE 3 /* Reads from the executable file. */ # define QHINF_LIBPATHLENGTH 4 /* Gets the libpath length. */ # define QHINF_LIBPATH 5 /* Gets the entire libpath. */ # define QHINF_FIXENTRY 6 /* NE only */ # define QHINF_STE 7 /* NE only */ # define QHINF_MAPSEL 8 /* NE only */ #elif K_OS == K_OS_WINDOWS # undef IMAGE_NT_SIGNATURE # undef IMAGE_DOS_SIGNATURE # include # ifndef IMAGE_SCN_TYPE_NOLOAD # define IMAGE_SCN_TYPE_NOLOAD 0x00000002 # endif /*#elif defined(__NT__) #include */ #elif K_OS == K_OS_DARWIN # include # include #else # error "port me" #endif /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** @def KLDRMODNATIVE_STRICT * Define KLDRMODNATIVE_STRICT to enabled strict checks in KLDRMODNATIVE. */ #define KLDRMODNATIVE_STRICT 1 /** @def KLDRMODNATIVE_ASSERT * Assert that an expression is true when KLDR_STRICT is defined. */ #ifdef KLDRMODNATIVE_STRICT # define KLDRMODNATIVE_ASSERT(expr) kHlpAssert(expr) #else # define KLDRMODNATIVE_ASSERT(expr) do {} while (0) #endif #if K_OS == K_OS_WINDOWS /** @def KLDRMODNATIVE_RVA2TYPE * Converts a RVA to a pointer of the specified type. * @param pvBits The bits (image base). * @param uRVA The image relative virtual address. * @param type The type to cast to. */ # define KLDRMODNATIVE_RVA2TYPE(pvBits, uRVA, type) \ ( (type) ((KUPTR)(pvBits) + (uRVA)) ) #endif /* PE OSes */ /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * Instance data for the module interpreter for the Native Loaders. */ typedef struct KLDRMODNATIVE { /** Pointer to the module. (Follows the section table.) */ PKLDRMOD pMod; /** Reserved flags. */ KU32 f32Reserved; /** The number of imported modules. * If ~(KU32)0 this hasn't been determined yet. */ KU32 cImportModules; #if K_OS == K_OS_OS2 /** The module handle. */ HMODULE hmod; #elif K_OS == K_OS_WINDOWS /** The module handle. */ HANDLE hmod; /** Pointer to the NT headers. */ const IMAGE_NT_HEADERS *pNtHdrs; /** Pointer to the section header array. */ const IMAGE_SECTION_HEADER *paShdrs; #elif K_OS == K_OS_DARWIN /** The dlopen() handle.*/ void *pvMod; #else # error "Port me" #endif } KLDRMODNATIVE, *PKLDRMODNATIVE; /******************************************************************************* * Internal Functions * *******************************************************************************/ static KI32 kldrModNativeNumberOfImports(PKLDRMOD pMod, const void *pvBits); /********************************************************************************************************************************* * Global Variables * *********************************************************************************************************************************/ extern KLDRMODOPS g_kLdrModNativeOps; /** * Use native loader to load the file opened by pRdr. * * @returns 0 on success and *ppMod pointing to a module instance. * On failure, a non-zero OS specific error code is returned. * @param pOps Pointer to the registered method table. * @param pRdr The file provider instance to use. * @param offNewHdr The offset of the new header in MZ files. -1 if not found. * @param ppMod Where to store the module instance pointer. */ static int kldrModNativeCreate(PCKLDRMODOPS pOps, PKRDR pRdr, KU32 fFlags, KCPUARCH enmCpuArch, KLDRFOFF offNewHdr, PPKLDRMOD ppMod) { int rc = kLdrModOpenNative(kRdrName(pRdr), ppMod); if (rc) return rc; rc = kRdrClose(pRdr); KLDRMODNATIVE_ASSERT(!rc); return 0; } /** * Loads a module using the native module loader. * * @returns 0 on success. * @returns non-zero native or kLdr status code on failure. * @param pszFilename The filename or module name to be loaded. * @param ppMod Where to store the module interpreter instance pointer. */ int kLdrModOpenNative(const char *pszFilename, PPKLDRMOD ppMod) { int rc; /* * Load the image. */ #if K_OS == K_OS_OS2 HMODULE hmod; rc = DosLoadModule(NULL, 0, (PCSZ)pszFilename, &hmod); if (rc) return rc; rc = kLdrModOpenNativeByHandle((KUPTR)hmod, ppMod); if (rc) DosFreeModule(hmod); #elif K_OS == K_OS_WINDOWS HMODULE hmod; hmod = LoadLibrary(pszFilename); if (!hmod) return GetLastError(); rc = kLdrModOpenNativeByHandle((KUPTR)hmod, ppMod); if (rc) FreeLibrary(hmod); #elif K_OS == K_OS_DARWIN void *pvMod; pvMod = dlopen(pszFilename, 0); if (!pvMod) return ENOENT; rc = kLdrModOpenNativeByHandle((KUPTR)pvMod, ppMod); if (rc) dlclose(pvMod); #else # error "Port me" #endif return rc; } /** * Creates a native module interpret for an already module already * loaded by the native loader. * * @returns 0 on success. * @returns non-zero native or kLdr status code on failure. * @param pszFilename The filename or module name to be loaded. * @param ppMod Where to store the module interpreter instance pointer. * @remark This will not make the native loader increment the load count. */ int kLdrModOpenNativeByHandle(KUPTR uHandle, PPKLDRMOD ppMod) { KSIZE cb; KU32 cchFilename; KU32 cSegments; PKLDRMOD pMod; PKLDRMODNATIVE pModNative; /* * Delcare variables, parse the module header or whatever and determin the * size of the module instance. */ #if K_OS == K_OS_OS2 char szFilename[CCHMAXPATH]; int rc; /* get the filename. */ rc = DosQueryModuleName((HMODULE)uHandle, sizeof(szFilename), szFilename); if (rc) { KLDRMODNATIVE_ASSERT(rc); szFilename[0] = '\0'; } /* get the segment count. */ /** @todo DosQueryHeaderInfo should be able to get us what we want on OS/2. */ cSegments = 1; #elif K_OS == K_OS_WINDOWS DWORD dw; char szFilename[MAX_PATH]; const IMAGE_NT_HEADERS *pNtHdrs; const IMAGE_SECTION_HEADER *paShdrs; const IMAGE_DOS_HEADER *pDosHdr = (const IMAGE_DOS_HEADER *)uHandle; unsigned i; /* get the filename. */ dw = GetModuleFileName((HANDLE)uHandle, szFilename, sizeof(szFilename)); if (dw <= 0) { KLDRMODNATIVE_ASSERT(dw <= 0); szFilename[0] = '\0'; } /* get the segment count. */ if (pDosHdr->e_magic == IMAGE_DOS_SIGNATURE) pNtHdrs = (const IMAGE_NT_HEADERS *)((KUPTR)pDosHdr + pDosHdr->e_lfanew); else pNtHdrs = (const IMAGE_NT_HEADERS *)pDosHdr; if (pNtHdrs->Signature != IMAGE_NT_SIGNATURE) { KLDRMODNATIVE_ASSERT(!"bad signature"); return KLDR_ERR_UNKNOWN_FORMAT; } if (pNtHdrs->FileHeader.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER)) { KLDRMODNATIVE_ASSERT(!"bad optional header size"); return KLDR_ERR_UNKNOWN_FORMAT; } cSegments = pNtHdrs->FileHeader.NumberOfSections + 1; paShdrs = (const IMAGE_SECTION_HEADER *)(pNtHdrs + 1); #elif K_OS == K_OS_DARWIN char szFilename[1] = ""; cSegments = 0; /** @todo Figure out the Mac OS X dynamic loader. */ #else # error "Port me" #endif /* * Calc the instance size, allocate and initialize it. */ cchFilename = (KU32)kHlpStrLen(szFilename); cb = K_ALIGN_Z(sizeof(KLDRMODNATIVE), 16) + K_OFFSETOF(KLDRMOD, aSegments[cSegments]) + cchFilename + 1; pModNative = (PKLDRMODNATIVE)kHlpAlloc(cb); if (!pModNative) return KERR_NO_MEMORY; /* KLDRMOD */ pMod = (PKLDRMOD)((KU8 *)pModNative + K_ALIGN_Z(sizeof(KLDRMODNATIVE), 16)); pMod->pvData = pModNative; pMod->pRdr = NULL; pMod->pOps = NULL; /* set upon success. */ pMod->cSegments = cSegments; pMod->cchFilename = cchFilename; pMod->pszFilename = (char *)&pMod->aSegments[pMod->cSegments]; kHlpMemCopy((char *)pMod->pszFilename, szFilename, cchFilename + 1); pMod->pszName = kHlpGetFilename(pMod->pszFilename); /** @todo get soname */ pMod->cchName = cchFilename - (KU32)(pMod->pszName - pMod->pszFilename); pMod->fFlags = 0; #if defined(__i386__) || defined(__X86__) || defined(_M_IX86) pMod->enmCpu = KCPU_I386; pMod->enmArch = KCPUARCH_X86_32; pMod->enmEndian = KLDRENDIAN_LITTLE; #elif defined(__X86_64__) || defined(__x86_64__) || defined(__AMD64__) || defined(_M_IX64) pMod->enmCpu = KCPU_K8; pMod->enmArch = KCPUARCH_AMD64; pMod->enmEndian = KLDRENDIAN_LITTLE; #else # error "Port me" #endif pMod->enmFmt = KLDRFMT_NATIVE; pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE; pMod->u32Magic = 0; /* set upon success. */ /* KLDRMODNATIVE */ pModNative->pMod = pMod; pModNative->f32Reserved = 0; pModNative->cImportModules = ~(KU32)0; /* * Set native instance data. */ #if K_OS == K_OS_OS2 pModNative->hmod = (HMODULE)uHandle; /* just fake a segment for now. */ pMod->aSegments[0].pvUser = NULL; pMod->aSegments[0].pchName = "fake"; pMod->aSegments[0].cchName = sizeof("fake") - 1; pMod->aSegments[0].enmProt = KPROT_NOACCESS; pMod->aSegments[0].cb = 0; pMod->aSegments[0].Alignment = 0; pMod->aSegments[0].LinkAddress = NIL_KLDRADDR; pMod->aSegments[0].offFile = -1; pMod->aSegments[0].cbFile = 0; pMod->aSegments[0].RVA = NIL_KLDRADDR; pMod->aSegments[0].cbMapped = 0; pMod->aSegments[0].MapAddress = 0; #elif K_OS == K_OS_WINDOWS pModNative->hmod = (HMODULE)uHandle; pModNative->pNtHdrs = pNtHdrs; pModNative->paShdrs = paShdrs; if (pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL) pMod->enmType = !(pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) ? KLDRTYPE_SHARED_LIBRARY_RELOCATABLE : KLDRTYPE_SHARED_LIBRARY_FIXED; else pMod->enmType = !(pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) ? KLDRTYPE_EXECUTABLE_RELOCATABLE : KLDRTYPE_EXECUTABLE_FIXED; /* The implied headers section. */ pMod->aSegments[0].pvUser = NULL; pMod->aSegments[0].pchName = "TheHeaders"; pMod->aSegments[0].cchName = sizeof("TheHeaders") - 1; pMod->aSegments[0].enmProt = KPROT_READONLY; pMod->aSegments[0].cb = pNtHdrs->OptionalHeader.SizeOfHeaders; pMod->aSegments[0].Alignment = pNtHdrs->OptionalHeader.SectionAlignment; pMod->aSegments[0].LinkAddress = pNtHdrs->OptionalHeader.ImageBase; pMod->aSegments[0].offFile = 0; pMod->aSegments[0].cbFile = pNtHdrs->OptionalHeader.SizeOfHeaders; pMod->aSegments[0].RVA = 0; if (pMod->cSegments > 1) pMod->aSegments[0].cbMapped = paShdrs[0].VirtualAddress; else pMod->aSegments[0].cbMapped = pNtHdrs->OptionalHeader.SizeOfHeaders; pMod->aSegments[0].MapAddress = uHandle; /* The section headers. */ for (i = 0; i < pNtHdrs->FileHeader.NumberOfSections; i++) { const char *pch; KU32 cchSegName; /* unused */ pMod->aSegments[i + 1].pvUser = NULL; /* name */ pMod->aSegments[i + 1].pchName = pch = &paShdrs[i].Name[0]; cchSegName = IMAGE_SIZEOF_SHORT_NAME; while ( cchSegName > 0 && (pch[cchSegName - 1] == ' ' || pch[cchSegName - 1] == '\0')) cchSegName--; pMod->aSegments[i + 1].cchName = cchSegName; /* size and addresses */ if (!(paShdrs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD)) { pMod->aSegments[i + 1].cb = paShdrs[i].Misc.VirtualSize; pMod->aSegments[i + 1].RVA = paShdrs[i].VirtualAddress; pMod->aSegments[i + 1].LinkAddress = paShdrs[i].VirtualAddress + pNtHdrs->OptionalHeader.ImageBase; pMod->aSegments[i + 1].MapAddress = paShdrs[i].VirtualAddress + uHandle; pMod->aSegments[i + 1].cbMapped = paShdrs[i].Misc.VirtualSize; if (i + 2 < pMod->cSegments) pMod->aSegments[i + 1].cbMapped = paShdrs[i + 1].VirtualAddress - paShdrs[i].VirtualAddress; } else { pMod->aSegments[i + 1].cb = 0; pMod->aSegments[i + 1].cbMapped = 0; pMod->aSegments[i + 1].LinkAddress = NIL_KLDRADDR; pMod->aSegments[i + 1].RVA = 0; pMod->aSegments[i + 1].MapAddress = 0; } /* file location */ pMod->aSegments[i + 1].offFile = paShdrs[i].PointerToRawData; pMod->aSegments[i + 1].cbFile = paShdrs[i].SizeOfRawData; if ( pMod->aSegments[i + 1].cbMapped > 0 /* if mapped */ && (KLDRSIZE)pMod->aSegments[i + 1].cbFile > pMod->aSegments[i + 1].cbMapped) pMod->aSegments[i + 1].cbFile = (KLDRFOFF)pMod->aSegments[i + 1].cbMapped; /* protection */ switch ( paShdrs[i].Characteristics & (IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) { case 0: case IMAGE_SCN_MEM_SHARED: pMod->aSegments[i + 1].enmProt = KPROT_NOACCESS; break; case IMAGE_SCN_MEM_READ: case IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_SHARED: pMod->aSegments[i + 1].enmProt = KPROT_READONLY; break; case IMAGE_SCN_MEM_WRITE: case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ: pMod->aSegments[i + 1].enmProt = KPROT_WRITECOPY; break; case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED: case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ: pMod->aSegments[i + 1].enmProt = KPROT_READWRITE; break; case IMAGE_SCN_MEM_EXECUTE: case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_SHARED: pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE; break; case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ: case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_SHARED: pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE_READ; break; case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE: case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ: pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE_WRITECOPY; break; case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED: case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ: pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE_READWRITE; break; } /* alignment. */ switch (paShdrs[i].Characteristics & IMAGE_SCN_ALIGN_MASK) { case 0: /* hope this is right... */ pMod->aSegments[i + 1].Alignment = pNtHdrs->OptionalHeader.SectionAlignment; break; case IMAGE_SCN_ALIGN_1BYTES: pMod->aSegments[i + 1].Alignment = 1; break; case IMAGE_SCN_ALIGN_2BYTES: pMod->aSegments[i + 1].Alignment = 2; break; case IMAGE_SCN_ALIGN_4BYTES: pMod->aSegments[i + 1].Alignment = 4; break; case IMAGE_SCN_ALIGN_8BYTES: pMod->aSegments[i + 1].Alignment = 8; break; case IMAGE_SCN_ALIGN_16BYTES: pMod->aSegments[i + 1].Alignment = 16; break; case IMAGE_SCN_ALIGN_32BYTES: pMod->aSegments[i + 1].Alignment = 32; break; case IMAGE_SCN_ALIGN_64BYTES: pMod->aSegments[i + 1].Alignment = 64; break; case IMAGE_SCN_ALIGN_128BYTES: pMod->aSegments[i + 1].Alignment = 128; break; case IMAGE_SCN_ALIGN_256BYTES: pMod->aSegments[i + 1].Alignment = 256; break; case IMAGE_SCN_ALIGN_512BYTES: pMod->aSegments[i + 1].Alignment = 512; break; case IMAGE_SCN_ALIGN_1024BYTES: pMod->aSegments[i + 1].Alignment = 1024; break; case IMAGE_SCN_ALIGN_2048BYTES: pMod->aSegments[i + 1].Alignment = 2048; break; case IMAGE_SCN_ALIGN_4096BYTES: pMod->aSegments[i + 1].Alignment = 4096; break; case IMAGE_SCN_ALIGN_8192BYTES: pMod->aSegments[i + 1].Alignment = 8192; break; default: kHlpAssert(0); pMod->aSegments[i + 1].Alignment = 0; break; } } #elif K_OS == K_OS_DARWIN /** @todo Figure out the Mac OS X dynamic loader. */ #else # error "Port me" #endif /* * We're done. */ pMod->u32Magic = KLDRMOD_MAGIC; pMod->pOps = &g_kLdrModNativeOps; *ppMod = pMod; return 0; } /** @copydoc KLDRMODOPS::pfnDestroy */ static int kldrModNativeDestroy(PKLDRMOD pMod) { PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData; int rc; #if K_OS == K_OS_OS2 rc = DosFreeModule(pModNative->hmod); #elif K_OS == K_OS_WINDOWS if (FreeLibrary(pModNative->hmod)) rc = 0; else rc = GetLastError(); #elif K_OS == K_OS_DARWIN dlclose(pModNative->pvMod); #else # error "Port me" #endif pMod->u32Magic = 0; pMod->pOps = NULL; kHlpFree(pModNative); return rc; } /** @copydoc kLdrModQuerySymbol */ static int kldrModNativeQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind) { PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData; const char *pszSymbol = pchSymbol; #if K_OS == K_OS_OS2 APIRET rc; PFN pfn; #elif K_OS == K_OS_WINDOWS FARPROC pfn; #elif K_OS == K_OS_DARWIN void *pfn; #else # error "Port me" #endif /* make stack copy of the symbol if it isn't zero terminated. */ if (pszSymbol && pszSymbol[cchSymbol]) { char *pszCopy = kHlpAllocA(cchSymbol + 1); kHlpMemCopy(pszCopy, pchSymbol, cchSymbol); pszCopy[cchSymbol] = '\0'; pszSymbol = pszCopy; } #if K_OS == K_OS_OS2 if (!pchSymbol && iSymbol >= 0x10000) return KLDR_ERR_SYMBOL_NOT_FOUND; if (puValue) { rc = DosQueryProcAddr(pModNative->hmod, pszSymbol ? 0 : iSymbol, (PCSZ)pszSymbol, &pfn); if (rc) return rc == ERROR_PROC_NOT_FOUND ? KLDR_ERR_SYMBOL_NOT_FOUND : rc; *puValue = (KUPTR)pfn; } if (pfKind) { ULONG ulProcType; rc = DosQueryProcType(pModNative->hmod, pszSymbol ? 0 : iSymbol, (PCSZ)pszSymbol, &ulProcType); if (rc) { if (puValue) *puValue = 0; return rc == ERROR_PROC_NOT_FOUND ? KLDR_ERR_SYMBOL_NOT_FOUND : rc; } *pfKind = (ulProcType & PT_32BIT ? KLDRSYMKIND_32BIT : KLDRSYMKIND_16BIT) | KLDRSYMKIND_NO_TYPE; } #elif K_OS == K_OS_WINDOWS if (!pszSymbol && iSymbol >= 0x10000) return KLDR_ERR_SYMBOL_NOT_FOUND; pfn = GetProcAddress(pModNative->hmod, pszSymbol ? pszSymbol : (const char *)(KUPTR)iSymbol); if (puValue) *puValue = (KUPTR)pfn; if (pfKind) *pfKind = (pModNative->pNtHdrs->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32) ? KLDRSYMKIND_32BIT : KLDRSYMKIND_16BIT) | KLDRSYMKIND_NO_TYPE; #elif K_OS == K_OS_DARWIN if (!pszSymbol && iSymbol != NIL_KLDRMOD_SYM_ORDINAL) return KLDR_ERR_SYMBOL_NOT_FOUND; pfn = dlsym(pModNative->pvMod, pszSymbol); if (!pfn) return KLDR_ERR_SYMBOL_NOT_FOUND; if (puValue) *puValue = (KUPTR)pfn; if (pfKind) *pfKind = (sizeof(KUPTR) == 4 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT) | KLDRSYMKIND_NO_TYPE; #else # error "Port me" #endif return 0; } /** @copydoc kLdrModEnumSymbols */ static int kldrModNativeEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser) { PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData; #if K_OS == K_OS_OS2 /** @todo implement export enumeration on OS/2. */ (void)pModNative; return ERROR_NOT_SUPPORTED; #elif K_OS == K_OS_WINDOWS || defined(__NT__) const KU32 *paFunctions; const IMAGE_EXPORT_DIRECTORY *pExpDir; const KU32 *paRVANames; const KU16 *paOrdinals; KU32 iFunction; KU32 cFunctions; KU32 cNames; int rc; /* * Make sure we've got mapped bits and resolve any base address aliases. */ if ( pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size < sizeof(IMAGE_EXPORT_DIRECTORY)) return 0; /* no exports to enumerate, return success. */ pExpDir = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress, PIMAGE_EXPORT_DIRECTORY); /* * Enumerate the ordinal exports. */ paRVANames = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, pExpDir->AddressOfNames, const KU32 *); paOrdinals = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, pExpDir->AddressOfNameOrdinals, const KU16 *); paFunctions = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, pExpDir->AddressOfFunctions, const KU32 *); cFunctions = pExpDir->NumberOfFunctions; cNames = pExpDir->NumberOfNames; for (iFunction = 0; iFunction < cFunctions; iFunction++) { unsigned fFoundName; KU32 iName; const KU32 uRVA = paFunctions[iFunction]; const KLDRADDR uValue = BaseAddress + uRVA; KU32 fKind = (pModNative->pNtHdrs->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32) ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT) | KLDRSYMKIND_NO_TYPE; if ( uRVA - pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress < pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size) fKind |= KLDRSYMKIND_FORWARDER; /* * Any symbol names? */ fFoundName = 0; for (iName = 0; iName < cNames; iName++) { const char *pszName; if (paOrdinals[iName] != iFunction) continue; fFoundName = 1; pszName = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, paRVANames[iName], const char *); rc = pfnCallback(pMod, iFunction + pExpDir->Base, pszName, strlen(pszName), NULL, uValue, fKind, pvUser); if (rc) return rc; } /* * If no names, call once with the ordinal only. */ if (!fFoundName) { rc = pfnCallback(pMod, iFunction + pExpDir->Base, NULL, 0, NULL, uValue, fKind, pvUser); if (rc) return rc; } } return 0; #elif K_OS == K_OS_DARWIN /** @todo implement enumeration on darwin. */ (void)pModNative; return KLDR_ERR_TODO; #else # error "Port me" #endif } /** @copydoc kLdrModGetImport */ static int kldrModNativeGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName) { PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData; #if K_OS == K_OS_OS2 /** @todo implement import enumeration on OS/2. */ (void)pModNative; return ERROR_NOT_SUPPORTED; #elif K_OS == K_OS_WINDOWS || defined(__NT__) const IMAGE_IMPORT_DESCRIPTOR *pImpDesc; const char *pszImportName; KSIZE cchImportName; int rc; /* * Simple bounds check. */ if (iImport >= (KU32)kldrModNativeNumberOfImports(pMod, pvBits)) return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS; /* * Get the name. */ pImpDesc = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + sizeof(IMAGE_IMPORT_DESCRIPTOR) * iImport, const IMAGE_IMPORT_DESCRIPTOR *); pszImportName = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, pImpDesc->Name, const char *); cchImportName = kHlpStrLen(pszImportName); if (cchImportName < cchName) { kHlpMemCopy(pszName, pszImportName, cchImportName + 1); rc = 0; } else { kHlpMemCopy(pszName, pszImportName, cchName); if (cchName) pszName[cchName - 1] = '\0'; rc = KERR_BUFFER_OVERFLOW; } return rc; #elif K_OS == K_OS_DARWIN /** @todo Implement import enumeration on darwin. */ (void)pModNative; return KLDR_ERR_TODO; #else # error "Port me" #endif } /** @copydoc kLdrModNumberOfImports */ static KI32 kldrModNativeNumberOfImports(PKLDRMOD pMod, const void *pvBits) { PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData; #if K_OS == K_OS_OS2 /** @todo implement import counting on OS/2. */ (void)pModNative; return -1; #elif K_OS == K_OS_WINDOWS || defined(__NT__) if (pModNative->cImportModules == ~(KU32)0) { /* * We'll have to walk the import descriptors to figure out their number. */ pModNative->cImportModules = 0; if ( pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size && pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress) { const IMAGE_IMPORT_DESCRIPTOR *pImpDesc; pImpDesc = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, const IMAGE_IMPORT_DESCRIPTOR *); while (pImpDesc->Name && pImpDesc->FirstThunk) { pModNative->cImportModules++; pImpDesc++; } } } return pModNative->cImportModules; #elif K_OS == K_OS_DARWIN /** @todo Implement import counting on Darwin. */ (void)pModNative; return -1; #else # error "Port me" #endif } /** @copydoc kLdrModGetStackInfo */ static int kldrModNativeGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo) { PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData; #if K_OS == K_OS_OS2 /** @todo implement stack info on OS/2. */ (void)pModNative; return ERROR_NOT_SUPPORTED; #elif K_OS == K_OS_WINDOWS || defined(__NT__) pStackInfo->Address = NIL_KLDRADDR; pStackInfo->LinkAddress = NIL_KLDRADDR; pStackInfo->cbStack = pStackInfo->cbStackThread = pModNative->pNtHdrs->OptionalHeader.SizeOfStackReserve; return 0; #elif K_OS == K_OS_DARWIN /** @todo Implement stack info on Darwin. */ (void)pModNative; return KLDR_ERR_TODO; #else # error "Port me" #endif } /** @copydoc kLdrModQueryMainEntrypoint */ static int kldrModNativeQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress) { PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData; #if K_OS == K_OS_OS2 /** @todo implement me on OS/2. */ (void)pModNative; return ERROR_NOT_SUPPORTED; #elif K_OS == K_OS_WINDOWS || defined(__NT__) /* * Convert the address from the header. */ *pMainEPAddress = pModNative->pNtHdrs->OptionalHeader.AddressOfEntryPoint ? BaseAddress + pModNative->pNtHdrs->OptionalHeader.AddressOfEntryPoint : NIL_KLDRADDR; return 0; #elif K_OS == K_OS_DARWIN /** @todo Implement me on Darwin. */ (void)pModNative; return KLDR_ERR_TODO; #else # error "Port me" #endif } /** @copydoc kLdrModEnumDbgInfo */ static int kldrModNativeEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser) { PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData; #if K_OS == K_OS_OS2 /** @todo implement me on OS/2. */ (void)pModNative; return ERROR_NOT_SUPPORTED; #elif K_OS == K_OS_WINDOWS || defined(__NT__) const IMAGE_DEBUG_DIRECTORY *pDbgDir; KU32 iDbgInfo; KU32 cb; int rc; /* * Check that there is a debug directory first. */ cb = pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size; if ( cb < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */ || !pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress) return 0; /* * Enumerate the debug directory. */ pDbgDir = KLDRMODNATIVE_RVA2TYPE(pModNative->hmod, pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress, const IMAGE_DEBUG_DIRECTORY *); for (iDbgInfo = 0;; iDbgInfo++, pDbgDir++, cb -= sizeof(IMAGE_DEBUG_DIRECTORY)) { KLDRDBGINFOTYPE enmDbgInfoType; /* convert the type. */ switch (pDbgDir->Type) { case IMAGE_DEBUG_TYPE_UNKNOWN: case IMAGE_DEBUG_TYPE_FPO: case IMAGE_DEBUG_TYPE_COFF: /*stabs dialect??*/ case IMAGE_DEBUG_TYPE_MISC: case IMAGE_DEBUG_TYPE_EXCEPTION: case IMAGE_DEBUG_TYPE_FIXUP: case IMAGE_DEBUG_TYPE_BORLAND: default: enmDbgInfoType = KLDRDBGINFOTYPE_UNKNOWN; break; case IMAGE_DEBUG_TYPE_CODEVIEW: enmDbgInfoType = KLDRDBGINFOTYPE_CODEVIEW; break; } rc = pfnCallback(pMod, iDbgInfo, enmDbgInfoType, pDbgDir->MajorVersion, pDbgDir->MinorVersion, NULL /*pszPartNm*/, pDbgDir->PointerToRawData ? pDbgDir->PointerToRawData : -1, pDbgDir->AddressOfRawData ? pDbgDir->AddressOfRawData : NIL_KLDRADDR, pDbgDir->SizeOfData, NULL /*pszExtFile*/, pvUser); if (rc) break; /* next */ if (cb <= sizeof(IMAGE_DEBUG_DIRECTORY)) break; } return rc; #elif K_OS == K_OS_DARWIN /** @todo Implement me on Darwin. */ (void)pModNative; return KLDR_ERR_TODO; #else # error "Port me" #endif } /** @copydoc kLdrModHasDbgInfo */ static int kldrModNativeHasDbgInfo(PKLDRMOD pMod, const void *pvBits) { PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData; #if K_OS == K_OS_OS2 /** @todo implement me on OS/2. */ (void)pModNative; return KLDR_ERR_NO_DEBUG_INFO; #elif K_OS == K_OS_WINDOWS || defined(__NT__) /* * Base this entirely on the presence of a debug directory. */ if ( pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */ || !pModNative->pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress) return KLDR_ERR_NO_DEBUG_INFO; return 0; #elif K_OS == K_OS_DARWIN /** @todo Implement me on Darwin. */ (void)pModNative; return KLDR_ERR_NO_DEBUG_INFO; #else # error "Port me" #endif } /** @copydoc kLdrModMap */ static int kldrModNativeMap(PKLDRMOD pMod) { return 0; } /** @copydoc kLdrModUnmap */ static int kldrModNativeUnmap(PKLDRMOD pMod) { return 0; } /** @copydoc kLdrModAllocTLS */ static int kldrModNativeAllocTLS(PKLDRMOD pMod, void *pvMapping) { return 0; } /** @copydoc kLdrModFreeTLS */ static void kldrModNativeFreeTLS(PKLDRMOD pMod, void *pvMapping) { } /** @copydoc kLdrModReload */ static int kldrModNativeReload(PKLDRMOD pMod) { return 0; } /** @copydoc kLdrModFixupMapping */ static int kldrModNativeFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) { return 0; } /** @copydoc kLdrModCallInit */ static int kldrModNativeCallInit(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle) { return 0; } /** @copydoc kLdrModCallTerm */ static int kldrModNativeCallTerm(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle) { return 0; } /** @copydoc kLdrModCallThread */ static int kldrModNativeCallThread(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle, unsigned fAttachingOrDetaching) { return 0; } /** @copydoc kLdrModSize */ static KLDRADDR kldrModNativeSize(PKLDRMOD pMod) { #if K_OS == K_OS_OS2 return 0; /* don't bother */ #elif K_OS == K_OS_WINDOWS || defined(__NT__) /* just because we can. */ PKLDRMODNATIVE pModNative = (PKLDRMODNATIVE)pMod->pvData; return pModNative->pNtHdrs->OptionalHeader.SizeOfImage; #elif K_OS == K_OS_DARWIN /** @todo Implement me on Darwin. */ return 0; #else # error "Port me" #endif } /** @copydoc kLdrModGetBits */ static int kldrModNativeGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) { #if K_OS == K_OS_OS2 return ERROR_NOT_SUPPORTED; /* don't bother */ #elif K_OS == K_OS_WINDOWS || defined(__NT__) return ERROR_NOT_SUPPORTED; /* don't bother even if we could implement this. */ #elif K_OS == K_OS_DARWIN return KLDR_ERR_TODO; /* don't bother. */ #else # error "Port me" #endif } /** @copydoc kLdrModRelocateBits */ static int kldrModNativeRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) { #if K_OS == K_OS_OS2 return ERROR_NOT_SUPPORTED; /* don't bother */ #elif K_OS == K_OS_WINDOWS || defined(__NT__) return ERROR_NOT_SUPPORTED; /* don't bother even if we could implement this. */ #elif K_OS == K_OS_DARWIN return KLDR_ERR_TODO; /* don't bother. */ #else # error "Port me" #endif } /** * The native module interpreter method table. */ KLDRMODOPS g_kLdrModNativeOps = { "Native", NULL, kldrModNativeCreate, kldrModNativeDestroy, kldrModNativeQuerySymbol, kldrModNativeEnumSymbols, kldrModNativeGetImport, kldrModNativeNumberOfImports, NULL /* can execute one is optional */, kldrModNativeGetStackInfo, kldrModNativeQueryMainEntrypoint, NULL /* pfnQueryImageUuid */, NULL /* fixme */, NULL /* fixme */, kldrModNativeEnumDbgInfo, kldrModNativeHasDbgInfo, kldrModNativeMap, kldrModNativeUnmap, kldrModNativeAllocTLS, kldrModNativeFreeTLS, kldrModNativeReload, kldrModNativeFixupMapping, kldrModNativeCallInit, kldrModNativeCallTerm, kldrModNativeCallThread, kldrModNativeSize, kldrModNativeGetBits, kldrModNativeRelocateBits, NULL /* fixme */, 42 /* the end */ }; kbuild-3149/src/lib/kStuff/kLdr/Makefile.kmk0000644000175000017500000001320713252530253020623 0ustar locutuslocutus# $Id: Makefile.kmk 29 2009-07-01 20:30:29Z bird $ ## @file # kLdr - The Dynamic Loader, sub-makefile. # # # Copyright (c) 2006-2007 Knut St. Osmundsen # # 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. # DEPTH ?= .. SUB_DEPTH = .. include $(PATH_KBUILD)/subheader.kmk #todo: include $(PATH_SUB_CURRENT)/testcase/Makefile.kmk # # Template for testcases. # TEMPLATE_TST = Testcase template ifeq ($(BUILD_TARGET),win) ifeq ($(BUILD_TARGET_ARCH), x86) TEMPLATE_TST_TOOL = VCC70 TEMPLATE_TST_CFLAGS = -W3 -Zi -Zl -MD TEMPLATE_TST_LIBS = $(PATH_TOOL_VCC70_LIB)/msvcrt.lib else TEMPLATE_TST_TOOL = VCC80AMD64 TEMPLATE_TST_CFLAGS = -W3 -Zi -Zl -MD TEMPLATE_TST_LIBS = $(PATH_TOOL_VCC80AMD64_LIB)/msvcrt.lib endif TEMPLATE_TST_CFLAGS.release = -O2 TEMPLATE_TST_ASFLAGS = -f win TEMPLATE_TST_DEFS = __WIN__ TEMPLATE_TST_SDKS = WINPSDK W2K3DDK else ifeq ($(BUILD_TARGET),os2) TEMPLATE_TST_TOOL = GCC3OMF TEMPLATE_TST_ASFLAGS = -f obj TEMPLATE_TST_LIBS = os2 gcc end else ifeq ($(BUILD_TARGET),darwin) TEMPLATE_TST_TOOL = GCC4MACHO TEMPLATE_TST_ASFLAGS = -f macho TEMPLATE_TST_LIBS = #os2 gcc end else TEMPLATE_TST_TOOL = GCC3 TEMPLATE_TST_ASFLAGS = -f elf TEMPLATE_TST_LIBS = gcc endif TEMPLATE_TST_CFLAGS = -Wall -pedantic -g -std=gnu99 TEMPLATE_TST_CFLAGS.release = -O2 TEMPLATE_TST_LDFLAGS = endif TEMPLATE_TST_INCS := $(PATH_SUB_CURRENT) $(PATH_SUB_ROOT)/include # # The kLdr DLL. # DLLS += kLdr kLdr_ASTOOL = NASM ifeq ($(BUILD_TARGET),win) ifeq ($(BUILD_TARGET_ARCH),x86) kLdr_TOOL = VCC70 kLdr_CFLAGS = -W3 -Zl -ML kLdr_LDFLAGS = -Entry:DllMain@12 -Debug kLdr_LIBS = \ $(PATH_TOOL_VCC70_LIB)/LIBC.lib \ $(PATH_SDK_W2K3DDKX86_LIB)/ntdll.lib else kLdr_TOOL = VCC80AMD64 kLdr_ASTOOL = YASM kLdr_CFLAGS = -W3 -Zl -MT kLdr_LDFLAGS = -Entry:DllMain -Debug kLdr_LIBS = \ $(PATH_TOOL_VCC80AMD64_LIB)/LIBCMT.lib \ $(PATH_SDK_W2K3DDKAMD64_LIB)/ntdll.lib endif kLdr_ASFLAGS = -f win kLdr_DEFS = __WIN__ kLdr_SDKS.x86 = WIN32SDK W2K3DDKX86 kLdr_SDKS.amd64 = WIN64SDK W2K3DDKAMD64 else ifeq ($(BUILD_TARGET),os2) kLdr_TOOL = GCC3OMF kLdr_ASFLAGS = -f obj kLdr_LIBS = os2 gcc end else ifeq ($(BUILD_TARGET),darwin) kLdr_TOOL = GCC4MACHO kLdr_ASFLAGS = -f macho kLdr_LIBS = #os2 gcc end else kLdr_TOOL = GCC3 kLdr_ASFLAGS = -f elf kLdr_LIBS = gcc endif kLdr_CFLAGS = -Wall -pedantic kLdr_LDFLAGS = -nostdlib endif kLdr_INCS := $(PATH_SUB_CURRENT) $(PATH_SUB_ROOT)/include kLdr_SOURCES = \ kLdr.c \ kLdrDyld.c \ kLdrDyldFind.c \ kLdrDyldMod.c \ kLdrDyldOS.c \ kLdrDyLdSem.c \ kLdrMod.c \ kLdrModLX.c \ kLdrModMachO.c \ kLdrModNative.c \ kLdrModPE.c kLdr_SOURCES.os2 = \ kLdr-os2.def \ kLdr-os2.c \ kLdrA-os2.asm kLdr_SOURCES.win = \ kLdr-win.def \ kLdr-win.c kLdr_LIBS += \ $(PATH_LIB)/kRdrStatic$(SUFF_LIB) \ $(PATH_LIB)/kCpuStatic$(SUFF_LIB) \ $(PATH_LIB)/kHlpBareStatic$(SUFF_LIB) \ $(PATH_LIB)/kErrStatic$(SUFF_LIB) # # A static edition of kLdr. # LIBRARIES += kLdrStatic kLdrStatic_TEMPLATE = kStuffLIB kLdrStatic_SDKS.win = WINPSDK W2K3DDK kLdrStatic_INCS := $(PATH_SUB_CURRENT) $(PATH_SUB_ROOT)/include kLdrStatic_DEFS.darwin = __DARWIN__ kLdrStatic_DEFS.os2 = __OS2__ kLdrStatic_DEFS.win = __WIN__ kLdrStatic_SOURCES = $(kLdr_SOURCES) # # The OS/2 stub program. # PROGRAMS.os2 = kLdrExeStub-os2 kLdrExeStub-os2_TOOL = GCC3OMF kLdrExeStub-os2_ASTOOL = NASM kLdrExeStub-os2_ASFLAGS = -f obj #kLdrExeStub-os2_LDFLAGS = -nostdlib kLdrExeStub-os2_LDFLAGS = -nostdlib -Zstack 64 kLdrExeStub-os2_LIBS = $(TARGET_kLdr) #kLdrExeStub-os2_SOURCES = kLdrExeStub-os2.asm kLdrExeStub-os2_SOURCES = kLdrExeStub-os2A.asm kLdrExeStub-os2.c # # The Windows stub program. # PROGRAMS.win = kLdrExeStub-win kLdrExeStub-win_TOOL.win.x86 = VCC70 kLdrExeStub-win_TOOL.win.amd64 = VCC80AMD64 kLdrExeStub-win_SDKS.x86 = WIN32SDK kLdrExeStub-win_SDKS.amd64 = WIN64SDK kLdrExeStub-win_INCS := $(PATH_SUB_CURRENT) $(PATH_SUB_ROOT)/include kLdrExeStub-win_DEFS = __WIN__ kLdrExeStub-win_CFLAGS = -W3 -Zl kLdrExeStub-win_CFLAGS.debug = -Zi kLdrExeStub-win_LDFLAGS = -Entry:WindowsMain -SubSystem:Console -FIXED:NO kLdrExeStub-win_LIBS = $(TARGET_kLdr:.dll=.lib) kLdrExeStub-win_SOURCES = kLdrExeStub-win.c ## ## The (stub) utility. ## #PROGRAMS = kLdrUtil # # Heap testcase. # #PROGRAMS += tstkLdrHeap tstkLdrHeap_TEMPLATE = TST tstkLdrHeap_SOURCES = \ tstkLdrHeap.c \ kHlp.c \ kHlpHeap.c \ kHlpMem.c \ kHlpPath.c \ kHlpSem.c \ kHlpStr.c \ # # Heap testcase. # PROGRAMS += tstkLdrMod tstkLdrMod_TEMPLATE = TST tstkLdrMod_SOURCES = \ tstkLdrMod.c ifeq ($(BUILD_TARGET),win) tstkLdrMod_LIBS = $(TARGET_kLdr:.dll=.lib) else tstkLdrMod_LIBS = $(TARGET_kLdr) endif # Generate rules. include $(PATH_KBUILD)/subfooter.kmk kbuild-3149/src/lib/kStuff/kLdr/kLdrExeStub-win.c0000644000175000017500000000435713252530253021543 0ustar locutuslocutus/* $Id: kLdrExeStub-win.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - Windows Loader Stub. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include "kLdrInternal.h" /******************************************************************************* * Global Variables * *******************************************************************************/ /** The stub arguments. */ static const KLDREXEARGS g_Args = { /* .fFlags = */ KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT, /* .enmSearch = */ KLDRDYLD_SEARCH_WINDOWS, /* .szExecutable = */ "tst-0", /* just while testing */ /* .szDefPrefix = */ "", /* .szDefSuffix = */ "", /* .szLibPath = */ "" }; /** * Windows 'main'. */ int WindowsMain(void) { kLdrDyldLoadExe(&g_Args, NULL); /* won't happen */ return 0; } kbuild-3149/src/lib/kStuff/kLdr/kLdrInternal.h0000644000175000017500000004004413252530253021143 0ustar locutuslocutus/* $Id: kLdrInternal.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - The Dynamic Loader, internal header. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___kLdrInternal_h___ #define ___kLdrInternal_h___ #include #include #ifdef __cplusplus extern "C" { #endif #if !defined(__X86__) && !defined(__AMD64__) # if defined(__i386__) || defined(_M_IX86) # define __X86__ # elif defined(__x86_64__) || defined(_M_X64) || defined(__AMD64__) || defined(_M_AMD64) # define __AMD64__ # else # error "can't figure out the target arch." # endif #endif /* ignore definitions in winnt.h */ #undef IMAGE_DOS_SIGNATURE #undef IMAGE_NT_SIGNATURE /** @name Signatures we know * @{ */ /** ELF signature ("\x7fELF"). */ #define IMAGE_ELF_SIGNATURE K_LE2H_U32(0x7f | ('E' << 8) | ((KU32)'L' << 16) | ((KU32)'F' << 24)) /** PE signature ("PE\0\0"). */ #define IMAGE_NT_SIGNATURE K_LE2H_U32('P' | ('E' << 8)) /** LX signature ("LX") */ #define IMAGE_LX_SIGNATURE K_LE2H_U16('L' | ('X' << 8)) /** LE signature ("LE") */ #define IMAGE_LE_SIGNATURE K_LE2H_U16('L' | ('E' << 8)) /** NE signature ("NE") */ #define IMAGE_NE_SIGNATURE K_LE2H_U16('N' | ('E' << 8)) /** MZ signature ("MZ"). */ #define IMAGE_DOS_SIGNATURE K_LE2H_U16('M' | ('Z' << 8)) /** The FAT signature (universal binaries). */ #define IMAGE_FAT_SIGNATURE KU32_C(0xcafebabe) /** The FAT signature (universal binaries), other endian. */ #define IMAGE_FAT_SIGNATURE_OE KU32_C(0xbebafeca) /** The 32-bit Mach-O signature. */ #define IMAGE_MACHO32_SIGNATURE KU32_C(0xfeedface) /** The 32-bit Mach-O signature, other endian. */ #define IMAGE_MACHO32_SIGNATURE_OE KU32_C(0xcefaedfe) /** The 64-bit Mach-O signature. */ #define IMAGE_MACHO64_SIGNATURE KU32_C(0xfeedfacf) /** The 64-bit Mach-O signature, other endian. */ #define IMAGE_MACHO64_SIGNATURE_OE KU32_C(0xfefaedfe) /** @} */ /** @defgroup grp_kLdrInternal Internals * @internal * @{ */ /** * The state of a dynamic loader module. * @image html KLDRSTATE.gif "The state diagram" */ typedef enum KLDRSTATE { /** The usual invalid 0 enum. */ KLDRSTATE_INVALID = 0, /** The module has just been opened and linked into the load list. * * Prev state: - * Next state: MAPPED, PENDING_DESTROY */ KLDRSTATE_OPEN, /** The module segments has been mapped into the process memory. * * Prev state: OPEN * Next state: LOADED_PREREQUISITES, PENDING_DESTROY */ KLDRSTATE_MAPPED, /** The module has been reloaded and needs to be fixed up again. * This can occure when the loader is called recursivly. * * The reason RELOADED modules must go back to the PENDING_GC state is * because we want to guard against uninit order issues, and therefore * doesn't unmap modules untill all pending termintation callbacks has * been executed. * * Prev state: PENDING_GC * Next state: RELOADED_LOADED_PREREQUISITES, PENDING_GC */ KLDRSTATE_RELOADED, /** The immediate prerequisites have been loaded. * * Prev state: MAPPED * Next state: FIXED_UP, PENDING_DESTROY */ KLDRSTATE_LOADED_PREREQUISITES, /** The immediate prerequisites have been loaded for a reloaded module. * * Prev state: RELOADED * Next state: RELOADED_FIXED_UP, PENDING_GC */ KLDRSTATE_RELOADED_LOADED_PREREQUISITES, /** Fixups has been applied. * * Prev state: LOADED_PREREQUISITES * Next state: PENDING_INITIALIZATION, PENDING_DESTROY */ KLDRSTATE_FIXED_UP, /** Fixups has been applied. * * Prev state: RELOADED_LOADED_PREREQUISITES * Next state: PENDING_INITIALIZATION, PENDING_GC */ KLDRSTATE_RELOADED_FIXED_UP, /** Pending initialization. * While the module is in this state the loader is in reentrant mode. * * Prev state: FIXED_UP, RELOADED_FIXED_UP * Next state: INITIALIZATION, PENDING_GC */ KLDRSTATE_PENDING_INITIALIZATION, /** Initializing. * While the module is in this state the loader is in reentrant mode. * * Prev state: PENDING_INITIALIZATION * Next state: GOOD, PENDING_GC */ KLDRSTATE_INITIALIZING, /** Initialization failed. * * This is somewhat similar to PENDING_GC except that, a module * in this state cannot be reloaded untill we've done GC. This ensures * that a init failure during recursive loading is propagated up. * * While the module is in this state the loader is in reentrant mode. * * Prev state: INITIALIZING * Next state: GC */ KLDRSTATE_INITIALIZATION_FAILED, /** The module has been successfully loaded and initialized. * While the module is in this state the loader can be in reentrant * or 'unused' mode. * * Prev state: INITIALIZING * Next state: PENDING_TERMINATION */ KLDRSTATE_GOOD, /** Pending termination, reference count is 0. * While the module is in this state the loader is in reentrant mode. * Prerequisite modules are dropped when a module enters this state. * * Prev state: GOOD * Next state: TERMINATING, GOOD */ KLDRSTATE_PENDING_TERMINATION, /** Terminating, reference count is still 0. * While the module is in this state the loader is in reentrant mode. * * Prev state: PENDING_TERMINATION * Next state: PENDING_GC */ KLDRSTATE_TERMINATING, /** Pending garbage collection. * Prerequisite modules are dropped when a module enters this state (if not done already). * * Prev state: TERMINATING, PENDING_INITIALIZATION, INITIALIZATION_FAILED * Next state: GC, RELOADED */ KLDRSTATE_PENDING_GC, /** Being garbage collected. * * Prev state: PENDING_GC, INITIALIZATION_FAILED * Next state: PENDING_DESTROY, DESTROYED */ KLDRSTATE_GC, /** The module has be unlinked, but there are still stack references to it. * * Prev state: GC, FIXED_UP, LOADED_PREREQUISITES, MAPPED, OPEN * Next state: DESTROYED */ KLDRSTATE_PENDING_DESTROY, /** The module has been destroyed but not freed yet. * * This happens when a module ends up being destroyed when cRefs > 0. The * module structure will be freed when cRefs reaches 0. * * Prev state: GC, PENDING_DESTROY */ KLDRSTATE_DESTROYED, /** The end of valid states (exclusive) */ KLDRSTATE_END = KLDRSTATE_DESTROYED, /** The usual 32-bit blowup. */ KLDRSTATE_32BIT_HACK = 0x7fffffff } KLDRSTATE; /** * Dynamic loader module. */ typedef struct KLDRDYLDMOD { /** Magic number. */ KU32 u32MagicHead; /** The module state. */ KLDRSTATE enmState; /** The module. */ PKLDRMOD pMod; /** The module handle. */ HKLDRMOD hMod; /** The total number of references. */ KU32 cRefs; /** The number of dependency references. */ KU32 cDepRefs; /** The number of dynamic load references. */ KU32 cDynRefs; /** Set if this is the executable module. * When clear, the module is a shared object or relocatable object. */ KU32 fExecutable : 1; /** Global DLL (set) or specific DLL (clear). */ KU32 fGlobalOrSpecific : 1; /** Whether the module contains bindable symbols in the global unix namespace. */ KU32 fBindable : 1; /** Set if linked into the global init list. */ KU32 fInitList : 1; /** Already loaded or checked prerequisites. * This flag is used when loading prerequisites, when set it means that * this module is already seen and shouldn't be processed again. */ KU32 fAlreadySeen : 1; /** Set if the module is currently mapped. * This is used to avoid unnecessary calls to kLdrModUnmap during cleanup. */ KU32 fMapped : 1; /** Set if TLS allocation has been done. (part of the mapping). */ KU32 fAllocatedTLS : 1; /** Reserved for future use. */ KU32 f25Reserved : 25; /** The load list linkage. */ struct { /** The next module in the list. */ struct KLDRDYLDMOD *pNext; /** The prev module in the list. */ struct KLDRDYLDMOD *pPrev; } Load; /** The initialization and termination list linkage. * If non-recursive initialization is used, the module will be pushed on * the initialization list. * A module will be linked into the termination list upon a successful * return from module initialization. */ struct { /** The next module in the list. */ struct KLDRDYLDMOD *pNext; /** The prev module in the list. */ struct KLDRDYLDMOD *pPrev; } InitTerm; /** The bind order list linkage. * The module is not in this list when fBindable is clear. */ struct { /** The next module in the list. */ struct KLDRDYLDMOD *pNext; /** The prev module in the list. */ struct KLDRDYLDMOD *pPrev; } Bind; /** The number of prerequisite modules in the prereq array. */ KU32 cPrereqs; /** Pointer to an array of prerequisite module pointers. * This array is only filled when in the states starting with * KLDRSTATE_LOADED_PREREQUISITES thru KLDRSTATE_GOOD. */ struct KLDRDYLDMOD **papPrereqs; /** Magic number. */ KU32 u32MagicTail; } KLDRDYLDMOD, *PKLDRDYLDMOD, **PPKLDRDYLDMOD; /** KLDRDYLDMOD magic value. (Fuyumi Soryo) */ #define KLDRDYMOD_MAGIC 0x19590106 /** Return / crash validation of a module handle argument. */ #define KLDRDYLD_VALIDATE_HKLDRMOD(hMod) \ do { \ if ( (hMod) == NIL_HKLDRMOD \ || (hMod)->u32MagicHead != KLDRDYMOD_MAGIC \ || (hMod)->u32MagicTail != KLDRDYMOD_MAGIC) \ { \ return KERR_INVALID_HANDLE; \ } \ } while (0) int kldrInit(void); void kldrTerm(void); int kldrDyldInit(void); void kldrDyldTerm(void); void kldrDyldDoLoadExe(PKLDRDYLDMOD pExe); int kldrDyldFailure(int rc, const char *pszFormat, ...); int kldrDyldOSStartExe(KUPTR uMainEntrypoint, void *pvStack, KSIZE cbStack); void *kldrDyldOSAllocStack(KSIZE cb); int kldrDyldFindInit(void); int kldrDyldFindNewModule(const char *pszName, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRDYLDMOD ppMod); int kldrDyldFindExistingModule(const char *pszName, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRDYLDMOD ppMod); int kldrDyldGetPrerequisite(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PKLDRDYLDMOD pDep, PPKLDRDYLDMOD ppMod); int kldrDyldModCreate(PKRDR pRdr, KU32 fFlags, PPKLDRDYLDMOD ppMod); void kldrDyldModDestroy(PKLDRDYLDMOD pMod); void kldrDyldModAddRef(PKLDRDYLDMOD pMod); void kldrDyldModDeref(PKLDRDYLDMOD pMod); void kldrDyldModAddDep(PKLDRDYLDMOD pMod, PKLDRDYLDMOD pDep); void kldrDyldModRemoveDep(PKLDRDYLDMOD pMod, PKLDRDYLDMOD pDep); int kldrDyldModDynamicLoad(PKLDRDYLDMOD pMod); int kldrDyldModDynamicUnload(PKLDRDYLDMOD pMod); void kldrDyldModMarkGlobal(PKLDRDYLDMOD pMod); void kldrDyldModMarkSpecific(PKLDRDYLDMOD pMod); void kldrDyldModSetBindable(PKLDRDYLDMOD pMod, unsigned fDeep); void kldrDyldModClearBindable(PKLDRDYLDMOD pMod); int kldrDyldModMap(PKLDRDYLDMOD pMod); int kldrDyldModUnmap(PKLDRDYLDMOD pMod); int kldrDyldModLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags); int kldrDyldModCheckPrerequisites(PKLDRDYLDMOD pMod); void kldrDyldModUnloadPrerequisites(PKLDRDYLDMOD pMod); int kldrDyldModFixup(PKLDRDYLDMOD pMod); int kldrDyldModCallInit(PKLDRDYLDMOD pMod); void kldrDyldModCallTerm(PKLDRDYLDMOD pMod); int kldrDyldModReload(PKLDRDYLDMOD pMod); int kldrDyldModAttachThread(PKLDRDYLDMOD pMod); void kldrDyldModDetachThread(PKLDRDYLDMOD pMod); int kldrDyldModGetMainStack(PKLDRDYLDMOD pMod, void **ppvStack, KSIZE *pcbStack); int kldrDyldModStartExe(PKLDRDYLDMOD pMod); int kldrDyldModGetName(PKLDRDYLDMOD pMod, char *pszName, KSIZE cchName); int kldrDyldModGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, KSIZE cchFilename); int kldrDyldModQuerySymbol(PKLDRDYLDMOD pMod, KU32 uSymbolOrdinal, const char *pszSymbolName, KUPTR *puValue, KU32 *pfKind); /** Pointer to the head module (the executable). * (This is exported, so no prefix.) */ extern PKLDRDYLDMOD kLdrDyldHead; /** Pointer to the tail module. * (This is exported, so no prefix.) */ extern PKLDRDYLDMOD kLdrDyldTail; /** Pointer to the head module of the initialization list. * The outermost load call will pop elements from this list in LIFO order (i.e. * from the tail). The list is only used during non-recursive initialization * and may therefore share the pNext/pPrev members with the termination list * since we don't push a module onto the termination list untill it has been * successfully initialized. */ extern PKLDRDYLDMOD g_pkLdrDyldInitHead; /** Pointer to the tail module of the initalization list. */ extern PKLDRDYLDMOD g_pkLdrDyldInitTail; /** Pointer to the head module of the termination order list. */ extern PKLDRDYLDMOD g_pkLdrDyldTermHead; /** Pointer to the tail module of the termination order list. */ extern PKLDRDYLDMOD g_pkLdrDyldTermTail; /** Pointer to the head module of the bind order list. * The modules in this list makes up the global namespace used when binding symbol unix fashion. */ extern PKLDRDYLDMOD g_pkLdrDyldBindHead; /** Pointer to the tail module of the bind order list. */ extern PKLDRDYLDMOD g_pkLdrDyldBindTail; /** Indicates that the other MainStack globals have been filled in. */ extern unsigned g_fkLdrDyldDoneMainStack; /** Whether the stack was allocated seperatly or was part of the executable. */ extern unsigned g_fkLdrDyldMainStackAllocated; /** Pointer to the main stack object. */ extern void *g_pvkLdrDyldMainStack; /** The size of the main stack object. */ extern KSIZE g_cbkLdrDyldMainStack; /** The global error buffer. */ extern char g_szkLdrDyldError[1024]; extern char kLdrDyldExePath[8192]; extern char kLdrDyldLibraryPath[8192]; extern char kLdrDyldDefPrefix[16]; extern char kLdrDyldDefSuffix[16]; extern int g_fBootstrapping; /** @name The Loader semaphore * @{ */ int kLdrDyldSemInit(void); void kLdrDyldSemTerm(void); int kLdrDyldSemRequest(void); void kLdrDyldSemRelease(void); /** @} */ /** @name Module interpreter method tables * @{ */ extern KLDRMODOPS g_kLdrModLXOps; extern KLDRMODOPS g_kLdrModMachOOps; extern KLDRMODOPS g_kLdrModNativeOps; extern KLDRMODOPS g_kLdrModPEOps; /** @} */ /** @} */ #ifdef __cplusplus } #endif #endif kbuild-3149/src/lib/kStuff/kLdr/testcase/0000755000175000017500000000000013252530253020212 5ustar locutuslocutuskbuild-3149/src/lib/kStuff/kLdr/testcase/tst-2-d.c0000644000175000017500000000021213252530253021543 0ustar locutuslocutus#include "tst.h" const char *g_pszName = "d"; MY_IMPORT(int) FuncA(void); MY_EXPORT(int) FuncD(void) { return FuncA(); } kbuild-3149/src/lib/kStuff/kLdr/testcase/Makefile.kmk0000644000175000017500000002246113252530253022440 0ustar locutuslocutus# $Id: Makefile.kmk 29 2009-07-01 20:30:29Z bird $ ## @file # kBuild Makefile for the kLdr testcases. # # # Copyright (c) 2006-2007 Knut St. Osmundsen # # 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. # # generate rules. DEPTH ?= ../.. SUB_DEPTH = ../.. include $(PATH_KBUILD)/subheader.kmk # # Templates for the testcases. # TEMPLATE_TST = Testcase template ifeq ($(BUILD_TARGET),win) ifeq ($(BUILD_TARGET_ARCH),x86) TEMPLATE_TST_TOOL = VCC70 TEMPLATE_TST_CFLAGS = -W3 -Zi -Zl -MD TEMPLATE_TST_CXXFLAGS = -W3 -Zi -Zl -MD TEMPLATE_TST_LIBS = \ $(PATH_TOOL_VCC70_LIB)/oldnames.lib \ $(PATH_TOOL_VCC70_LIB)/msvcrt.lib else TEMPLATE_TST_TOOL = VCC80AMD64 TEMPLATE_TST_CFLAGS = -W3 -Zi -Zl -MD TEMPLATE_TST_CXXFLAGS = -W3 -Zi -Zl -MD TEMPLATE_TST_LIBS = \ $(PATH_TOOL_VCC80AMD64_LIB)/oldnames.lib \ $(PATH_TOOL_VCC80AMD64_LIB)/msvcrt.lib endif TEMPLATE_TST_CFLAGS.release = -O2 TEMPLATE_TST_CXXFLAGS.release = -O2 TEMPLATE_TST_ASFLAGS = -f win TEMPLATE_TST_DEFS = __WIN__ TEMPLATE_TST_SDKS.x86 = WIN32SDK TEMPLATE_TST_SDKS.amd64 = WIN64SDK else TEMPLATE_TST_CFLAGS = -Wall -pedantic -g TEMPLATE_TST_CFLAGS.release = -O2 TEMPLATE_TST_LDFLAGS = ifneq ($(filter os2,$(BUILD_TARGET)),) TEMPLATE_TST_TOOL = GCC3OMF TEMPLATE_TST_ASFLAGS = -f obj TEMPLATE_TST_LIBS = os2 gcc end else ifneq ($(filter darwin,$(BUILD_TARGET)),) TEMPLATE_TST_TOOL = GCC4MACHO TEMPLATE_TST_ASFLAGS = -f macho TEMPLATE_TST_DEFS = __DARWIN__ TEMPLATE_TST_LIBS = else TEMPLATE_TST_TOOL = GCC3 TEMPLATE_TST_ASFLAGS = -f elf TEMPLATE_TST_LIBS = gcc endif endif TEMPLATE_TST_INCS := $(PATH_SUB_CURRENT) $(PATH_SUB_ROOT)/include TEMPLATE_TSTPROG = Testcase program template TEMPLATE_TSTPROG_EXTENDS = TST TEMPLATE_TSTDLL = Testcase dll template TEMPLATE_TSTDLL_EXTENDS = TST TEMPLATE_TSTBARE = Bare bone testcase template ifeq ($(BUILD_TARGET),win) ifeq ($(BUILD_TARGET_ARCH),x86) TEMPLATE_TSTBARE_TOOL = VCC70 else TEMPLATE_TSTBARE_TOOL = VCC80AMD64 endif TEMPLATE_TSTBARE_CFLAGS = -W3 -Zi -Zl TEMPLATE_TSTBARE_CFLAGS.release = -O2 TEMPLATE_TSTBARE_CXXFLAGS = -W3 -Zi -Zl TEMPLATE_TSTBARE_CXXFLAGS.release = -O2 TEMPLATE_TSTBARE_ASFLAGS = -f win TEMPLATE_TSTBARE_DEFS = __WIN__ TEMPLATE_TSTBARE_SDKS.x86 = WIN32SDK TEMPLATE_TSTBARE_SDKS.amd64 = WIN64SDK else TEMPLATE_TSTBARE_CFLAGS = -Wall -pedantic -g TEMPLATE_TSTBARE_CFLAGS.release = -O2 TEMPLATE_TSTBARE_LDFLAGS = -nostdlib -lgcc ifeq ($(filter-out os2,$(BUILD_TARGET)),) TEMPLATE_TSTBARE_TOOL = GCC3OMF TEMPLATE_TSTBARE_ASFLAGS = -f obj TEMPLATE_TSTBARE_ASTOOL = NASM TEMPLATE_TSTBARE_DEFS = main=main_wrapped TEMPLATE_TSTBARE_LIBS = os2 else ifeq ($(filter-out darwin,$(BUILD_TARGET)),) TEMPLATE_TSTBARE_TOOL = GCC4MACHO TEMPLATE_TSTBARE_ASFLAGS = -f macho TEMPLATE_TSTBARE_ASTOOL = NASM TEMPLATE_TSTBARE_DEFS = __DARWIN__ TEMPLATE_TSTBARE_LIBS = TEMPLATE_TSTBARE_CFLAGS += -static -fno-common TEMPLATE_TSTBARE_LDFLAGS += -nostdlib -r else TEMPLATE_TSTBARE_TOOL = GCC3 TEMPLATE_TSTBARE_ASFLAGS = -f elf TEMPLATE_TSTBARE_LIBS = gcc endif endif TEMPLATE_TSTBARE_INCS := $(PATH_SUB_CURRENT) $(PATH_SUB_ROOT)/include TEMPLATE_TSTBAREPROG = Bare bone testcase program template TEMPLATE_TSTBAREPROG_EXTENDS = TSTBARE ifneq ($(filter win win32 win64,$(BUILD_TARGET)),) TEMPLATE_TSTBAREPROG_LDFLAGS += -Entry:WindowsMain -FIXED:NO else TEMPLATE_TSTBAREPROG_LDFLAGS.nt += -FIXED:NO endif TEMPLATE_TSTBAREDLL = Bare bone testcase dll template TEMPLATE_TSTBAREDLL_EXTENDS = TSTBARE ifeq ($(BUILD_TARGET),win) TEMPLATE_TSTBAREDLL_LDFLAGS += -Entry:DllMain else ifeq ($(BUILD_TARGET),darwin) # TEMPLATE_TSTBAREDLL_CFLAGS += -dynamiclib # TEMPLATE_TSTBAREDLL_LDFLAGS += -dynamiclib endif # # tst-0: four dlls, three of which depends on the 4th and no external dependencies. # The purpose of this testcase is to debug the dynamic loader without # messing with the native loader at all. # PROGRAMS += tst-0 tst-0-driver DLLS += tst-0-a tst-0-b tst-0-c tst-0-d tst-0-driver_TEMPLATE = TSTPROG tst-0-driver_SOURCES = tst-0-driver.c tst-0-a_TEMPLATE = TSTBAREDLL tst-0-a_SOURCES = tst-0-a.c tstDllMainStub.c tst-0-a_SOURCES.os2= tstDllMainStub-os2.asm tst-0-b_TEMPLATE = TSTBAREDLL tst-0-b_SOURCES = tst-0-b.c tstDllMainStub.c tst-0-b_SOURCES.os2= tstDllMainStub-os2.asm tst-0-c_TEMPLATE = TSTBAREDLL tst-0-c_SOURCES = tst-0-c.c tstDllMainStub.c tst-0-c_SOURCES.os2= tstDllMainStub-os2.asm tst-0-d_TEMPLATE = TSTBAREDLL tst-0-d_SOURCES = tst-0-d.c tstDllMainStub.c tst-0-d_SOURCES.os2= tstDllMainStub-os2.asm tst-0_TEMPLATE = TSTBAREPROG tst-0_SOURCES = tst-0.c tstExeMainStub.c tst-0_SOURCES.os2= tstExeMainStub-os2.asm ifeq ($(BUILD_TARGET),win) tst-0-driver_LIBS= $(PATH_LIB)/kLdr.lib tst-0-a_LIBS = $(PATH_TARGET)/tst-0-d/tst-0-d.lib tst-0-b_LIBS = $(PATH_TARGET)/tst-0-d/tst-0-d.lib tst-0-c_LIBS = $(PATH_TARGET)/tst-0-d/tst-0-d.lib tst-0_LIBS = $(TARGET_tst-0-a:.dll=.lib) $(TARGET_tst-0-b:.dll=.lib) $(TARGET_tst-0-c:.dll=.lib) else tst-0-driver_LIBS= $(PATH_DLL)/kLdr$(SUFF_DLL) tst-0-a_LIBS = $(subst -a,-d,$(TARGET_tst-0-a)) tst-0-b_LIBS = $(subst -b,-d,$(TARGET_tst-0-b)) tst-0-c_LIBS = $(subst -c,-d,$(TARGET_tst-0-c)) tst-0_LIBS = $(TARGET_tst-0-a) $(TARGET_tst-0-b) $(TARGET_tst-0-c) endif # # tst-1: four dlls, three of which depends on the 4th and the testcase depends on those three again. # PROGRAMS += tst-1 DLLS += tst-1-a tst-1-b tst-1-c tst-1-d tst-1-a_TEMPLATE = TSTDLL tst-1-a_SOURCES = tst-1-a.c tstDllMain.c tst-1-b_TEMPLATE = TSTDLL tst-1-b_SOURCES = tst-1-b.c tstDllMain.c tst-1-c_TEMPLATE = TSTDLL tst-1-c_SOURCES = tst-1-c.c tstDllMain.c tst-1-d_TEMPLATE = TSTDLL tst-1-d_SOURCES = tst-1-d.c tstDllMain.c tst-1_TEMPLATE = TSTPROG tst-1_SOURCES = tst-1.c ifeq ($(BUILD_TARGET),win) tst-1-a_LIBS = $(PATH_TARGET)/tst-1-d/tst-1-d.lib tst-1-b_LIBS = $(PATH_TARGET)/tst-1-d/tst-1-d.lib tst-1-c_LIBS = $(PATH_TARGET)/tst-1-d/tst-1-d.lib tst-1_LIBS = $(TARGET_tst-1-a:.dll=.lib) $(TARGET_tst-1-b:.dll=.lib) $(TARGET_tst-1-c:.dll=.lib) else tst-1-a_LIBS = $(subst -a,-d,$(TARGET_tst-1-a)) tst-1-b_LIBS = $(subst -b,-d,$(TARGET_tst-1-b)) tst-1-c_LIBS = $(subst -c,-d,$(TARGET_tst-1-c)) tst-1_LIBS = $(TARGET_tst-1-a) $(TARGET_tst-1-b) $(TARGET_tst-1-c) endif # # tst-2: four dlls, three of which depends on the 1st, and the testcase depends on those all of them. # PROGRAMS += tst-2 DLLS += tst-2-a tst-2-b tst-2-c tst-2-d tst-2-a_TEMPLATE = TSTDLL tst-2-a_SOURCES = tst-2-a.c tstDllMain.c tst-2-b_TEMPLATE = TSTDLL tst-2-b_SOURCES = tst-2-b.c tstDllMain.c tst-2-c_TEMPLATE = TSTDLL tst-2-c_SOURCES = tst-2-c.c tstDllMain.c tst-2-d_TEMPLATE = TSTDLL tst-2-d_SOURCES = tst-2-d.c tstDllMain.c tst-2_TEMPLATE = TSTPROG tst-2_SOURCES = tst-2.c ifeq ($(BUILD_TARGET),win) tst-2-b_LIBS = $(PATH_TARGET)/tst-2-a/tst-2-a.lib tst-2-c_LIBS = $(PATH_TARGET)/tst-2-a/tst-2-a.lib tst-2-d_LIBS = $(PATH_TARGET)/tst-2-a/tst-2-a.lib tst-2_LIBS = $(TARGET_tst-2-b:.dll=.lib) $(TARGET_tst-2-c:.dll=.lib) $(TARGET_tst-2-d:.dll=.lib) $(TARGET_tst-2-a:.dll=.lib) else tst-2-b_LIBS = $(subst -b,-a,$(TARGET_tst-2-b)) tst-2-c_LIBS = $(subst -c,-a,$(TARGET_tst-2-c)) tst-2-d_LIBS = $(subst -d,-a,$(TARGET_tst-2-d)) tst-2_LIBS = $(TARGET_tst-2-a) $(TARGET_tst-2-b) $(TARGET_tst-2-c) $(TARGET_tst-2-d) endif # # tst-3: Single module. # PROGRAMS += tst-3-driver ifeq ($(BUILD_TARGET),darwin) SYSMODS += tst-3 else DLLS += tst-3 LIBRARIES.win += tst-3-imp LIBRARIES.os2 += tst-3-imp endif tst-3_TEMPLATE = TSTBAREDLL tst-3_SOURCES = tst-3.c tst-3-ext.c tstDllMainStub.c tst-3_SOURCES.os2= tstDllMainStub-os2.asm tst-3_LIBS.os2 = $(TARGET_tst-3-imp) tst-3_LIBS.win = $(TARGET_tst-3-imp) tst-3-imp_TEMPLATE = TSTBAREDLL tst-3-imp_SOURCES.win = tst-3-imp-win.def tst-3-imp_SOURCES.os2 = tst-3-imp-os2.def tst-3-driver_TEMPLATE = TSTPROG tst-3-driver_SOURCES = tst-3-driver.c ifeq ($(BUILD_TARGET),win) tst-3-driver_LIBS = $(PATH_LIB)/kLdr.lib else tst-3-driver_LIBS = $(PATH_DLL)/kLdr$(SUFF_DLL) endif # generate rules. include $(PATH_KBUILD)/subfooter.kmk kbuild-3149/src/lib/kStuff/kLdr/testcase/tst-1-c.c0000644000175000017500000000021213252530253021541 0ustar locutuslocutus#include "tst.h" const char *g_pszName = "c"; MY_IMPORT(int) FuncD(void); MY_EXPORT(int) FuncC(void) { return FuncD(); } kbuild-3149/src/lib/kStuff/kLdr/testcase/tst-3-driver.c0000644000175000017500000001531413252530253022625 0ustar locutuslocutus/* $Id: tst-3-driver.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - Dynamic Loader testcase no. 3, Driver. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "tst.h" #include #include #include #include #include #ifdef _MSC_VER # include #endif /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** Select the appropriate KLDRSYMKIND bit define. */ #define MY_KLDRSYMKIND_BITS ( sizeof(void *) == 4 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT ) /******************************************************************************* * Global Variables * *******************************************************************************/ /** The numbers of errors. */ static int g_cErrors = 0; /** * Report failure. */ static int Failure(const char *pszFormat, ...) { va_list va; g_cErrors++; printf("tst-3-driver: "); va_start(va, pszFormat); vprintf(pszFormat, va); va_end(va); printf("\n"); return 1; } /** * External symbol used by the testcase module. */ static int Tst3Ext(int iFortyTwo) { if (iFortyTwo != 42) return 256; return 42; } /** * Callback for resolving the Tst3Ext import. */ static int GetImport(PKLDRMOD pMod, KU32 iImport, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, PKLDRADDR puValue, KU32 *pfKind, void *pvUser) { if (*pfKind != KLDRSYMKIND_REQ_FLAT) return -1; if ( !strncmp(pchSymbol, "Tst3Ext", strlen("Tst3Ext")) || !strncmp(pchSymbol, "_Tst3Ext", strlen("_Tst3Ext"))) { *puValue = (KUPTR)&Tst3Ext; *pfKind = KLDRSYMKIND_CODE | (sizeof(pfKind) == 4 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT); return 0; } return -2; } /** * Performs the tests on one module. * @returns non sense. */ int TestModule(const char *pszFile) { PKLDRMOD pMod; KLDRSIZE cbImage; void *pvBits; int rc; printf("tst-3-driver: testing '%s'...\n", pszFile); /* open it. */ rc = kLdrModOpen(pszFile, &pMod); if (rc) return Failure("kLdrModOpen(%s,) -> %#d (%s)\n", pszFile, rc, kErrName(rc)); /* get bits. */ cbImage = kLdrModSize(pMod); pvBits = malloc((KSIZE)cbImage + 0xfff); if (pvBits) { void *pvBits2 = (void *)( ((KUPTR)pvBits + 0xfff) & ~(KUPTR)0xfff ); KLDRADDR BaseAddress = (KUPTR)pvBits2; rc = kLdrModGetBits(pMod, pvBits2, BaseAddress, GetImport, NULL); if (!rc) { KLDRADDR EntryPoint; /* call into it */ rc = kLdrModQuerySymbol(pMod, pvBits2, BaseAddress, NIL_KLDRMOD_SYM_ORDINAL, "_Tst3", strlen("_Tst3"), NULL, NULL, NULL, &EntryPoint, NULL); if (rc == KLDR_ERR_SYMBOL_NOT_FOUND) rc = kLdrModQuerySymbol(pMod, pvBits2, BaseAddress, NIL_KLDRMOD_SYM_ORDINAL, "Tst3", strlen("Tst3"), NULL, NULL, NULL, &EntryPoint, NULL); if (!rc) { int (*pfnEntryPoint)(int) = (int (*)(int)) ((KUPTR)EntryPoint); rc = pfnEntryPoint(42); if (rc == 42) { /* relocate twice and try again. */ rc = kLdrModRelocateBits(pMod, pvBits2, BaseAddress + 0x22000, BaseAddress, GetImport, NULL); if (!rc) { rc = kLdrModRelocateBits(pMod, pvBits2, BaseAddress, BaseAddress + 0x22000, GetImport, NULL); if (!rc) { rc = pfnEntryPoint(42); if (rc == 42) { printf("tst-3-driver: success.\n"); } else Failure("pfnEntryPoint(42) -> %d (2nd)\n", rc); } else Failure("kLdrModRelocateBits(,,, + 0x22000,,,) -> %#x (%s)\n", rc, kErrName(rc)); } else Failure("kLdrModRelocateBits(,, + 0x22000,,,,) -> %#x (%s)\n", rc, kErrName(rc)); } else Failure("pfnEntryPoint(42) -> %d (1st)\n", rc); } else Failure("kLdrModQuerySymbol -> %#x (%s)\n", rc, kErrName(rc)); } else Failure("kLdrModGetBits -> %#x (%s)\n", rc, kErrName(rc)); free(pvBits); } else Failure("malloc(%lx) -> NULL\n", (long)cbImage); /* clean up */ rc = kLdrModClose(pMod); if (rc) Failure("kLdrModOpen(%s,) -> %#x (%s)\n", pszFile, rc, kErrName(rc)); return 0; } int main(int argc, char **argv) { int i; /* * Test all the given modules (requires arguments). */ for (i = 1; i < argc; i++) { TestModule(argv[i]); } /* * Summary */ if (!g_cErrors) printf("tst-3-driver: SUCCESS\n"); else printf("tst-3-driver: FAILURE - %d errors\n", g_cErrors); return !!g_cErrors; } kbuild-3149/src/lib/kStuff/kLdr/testcase/tst-1-a.c0000644000175000017500000000021213252530253021537 0ustar locutuslocutus#include "tst.h" const char *g_pszName = "a"; MY_IMPORT(int) FuncD(void); MY_EXPORT(int) FuncA(void) { return FuncD(); } kbuild-3149/src/lib/kStuff/kLdr/testcase/tst-3-imp-win.def0000644000175000017500000000246213252530253023226 0ustar locutuslocutus; $Id: tst-3-imp-win.def 29 2009-07-01 20:30:29Z bird $ ;; @file ; kLdr - Dynamic Loader testcase no. 3, Fake module import library - Windows. ; ; ; Copyright (c) 2006-2007 Knut St. Osmundsen ; ; 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. ; LIBRARY tst-3-imp EXPORTS Tst3Ext kbuild-3149/src/lib/kStuff/kLdr/testcase/tst-2.c0000644000175000017500000000055313252530253021332 0ustar locutuslocutus#include "tst.h" MY_IMPORT(int) FuncA(void); MY_IMPORT(int) FuncB(void); MY_IMPORT(int) FuncC(void); MY_IMPORT(int) FuncD(void); int main() { printf("graph:\n" " tst-2 -> b -> a\n" " c -> a\n" " d -> a\n" " a\n"); return FuncA() + FuncB() + FuncC() + FuncD(); } kbuild-3149/src/lib/kStuff/kLdr/testcase/tst-0-driver.c0000644000175000017500000005236113252530253022625 0ustar locutuslocutus/* $Id: tst-0-driver.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - Dynamic Loader testcase no. 0, Driver. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "tst.h" #include #include #include #include /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** Select the appropriate KLDRSYMKIND bit define. */ #define MY_KLDRSYMKIND_BITS ( sizeof(void *) == 4 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT ) /******************************************************************************* * Global Variables * *******************************************************************************/ /** The numbers of errors. */ static int g_cErrors = 0; /** * Report failure. */ static int Failure(const char *pszFormat, ...) { va_list va; g_cErrors++; printf("tst-0-driver: "); va_start(va, pszFormat); vprintf(pszFormat, va); va_end(va); printf("\n"); return 1; } int main(int argc, char **argv) { const char *pszErrInit = "Error, szErr wasn't zapped"; char szErr[512]; char szBuf[512]; char *psz; KSIZE cch; HKLDRMOD hMod; int rc; /* * The first thing to do is a simple load / unload test * using the tst-0-a library (it'll drag in tst-0-d). */ printf("tst-0-driver: Basic API test using 'tst-0-a'...\n"); hMod = (HKLDRMOD)0xffffeeee; strcpy(szErr, pszErrInit); rc = kLdrDyldLoad("tst-0-a", NULL, NULL, KLDRDYLD_SEARCH_HOST, KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT, &hMod, szErr, sizeof(szErr)); if (rc) Failure("kLdrDyldLoad(\"tst-0\",...) failed, rc=%d (%#x). szErr='%s'.\n", rc, rc, szErr); if (!strcmp(szErr, pszErrInit)) Failure("szErr wasn't set.\n"); if (hMod == (HKLDRMOD)0xffffeeee) Failure("hMod wasn't set.\n"); if (hMod == NIL_HKLDRMOD && !rc) Failure("rc=0 but hMod=NIL_HKLDRMOD\n"); if (!rc) { HKLDRMOD hMod2; HKLDRMOD hMod3; printf("tst-0-driver: hMod=%p ('tst-0-a')\n", (void *)hMod); /* * Simple test of kLdrDyldFindByName. */ hMod2 = (HKLDRMOD)0xffffeeee; rc = kLdrDyldFindByName("tst-0", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod2); if (!rc) Failure("kLdrDyldFindByName(\"tst-0\",,,) didn't fail!\n"); if (rc && hMod2 != NIL_HKLDRMOD) Failure("hMod2 wasn't set correctly on kLdrDyldFindByName failure!\n"); hMod2 = (HKLDRMOD)0xffffeeee; rc = kLdrDyldFindByName("tst-0-a", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod2); if (rc) Failure("kLdrDyldFindByName(\"tst-0-a\",,,) failed, rc=%d (%#x)\n", rc, rc); if (!rc && hMod2 != hMod) Failure("kLdrDyldFindByName(\"tst-0-a\",,,) returned the wrong module handle: %p instead of %p\n", (void *)hMod2, (void *)hMod); hMod2 = (HKLDRMOD)0xffffeeee; rc = kLdrDyldFindByName("tst-0-d", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod2); if (!rc) printf("tst-0-driver: hMod2=%p ('tst-0-d')\n", (void *)hMod2); else Failure("kLdrDyldFindByName(\"tst-0-d\",,,) failed, rc=%d (%#x)\n", rc, rc); /* * Get the name and filename for each of the two modules. */ rc = kLdrDyldGetName(hMod2, szBuf, sizeof(szBuf)); if (!rc) { printf("tst-0-driver: name: '%s' ('tst-0-d')\n", szBuf); psz = strstr(szBuf, "-0-"); if ( !psz || strnicmp(psz, "-0-d", sizeof("-0-d") - 1)) Failure("kLdrDyldGetName(\"tst-0-d\",,,) -> '%s': pattern '-0-d' not found\n", szBuf); /* overflow test. */ cch = strlen(szBuf); szBuf[cch + 1] = szBuf[cch] = szBuf[cch - 1] = 'x'; szBuf[cch + 2] = '\0'; rc = kLdrDyldGetName(hMod2, szBuf, cch); if (rc == KERR_BUFFER_OVERFLOW) { if (!szBuf[0]) Failure("kLdrDyldGetName didn't return partial result on overflow\n"); else if (szBuf[cch - 1]) Failure("kLdrDyldGetName didn't terminate partial result correctly overflow: '%s'\n", szBuf); else if (szBuf[cch] != 'x') Failure("kLdrDyldGetName exceeded the buffer limit on partial overflow: '%s'\n", szBuf); } else Failure("kLdrDyldGetName(\"tst-0-d\",,,) -> rc=%d (%#x) instead of KERR_BUFFER_OVERFLOW\n", rc, rc); /* check that we can query the module by the returned name. */ rc = kLdrDyldGetName(hMod2, szBuf, sizeof(szBuf)); if (!rc) { hMod3 = (HKLDRMOD)0xffffeeee; rc = kLdrDyldFindByName(szBuf, NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod3); if (rc || hMod3 != hMod2) Failure("kLdrDyldFindByName(\"%s\",,,) failed, rc=%d (%#x) hMod3=%p hMod2=%p\n", szBuf, rc, rc, (void *)hMod3, (void *)hMod2); } else Failure("kLdrDyldGetName(\"tst-0-d\",,,) failed (b), rc=%d (%#x)\n", rc, rc); } else Failure("kLdrDyldGetName(\"tst-0-d\",,,) failed, rc=%d (%#x)\n", rc, rc); rc = kLdrDyldGetFilename(hMod2, szBuf, sizeof(szBuf)); if (!rc) { printf("tst-0-driver: filename: '%s' ('tst-0-d')\n", szBuf); /* overflow test. */ cch = strlen(szBuf); szBuf[cch + 1] = szBuf[cch] = szBuf[cch - 1] = 'x'; szBuf[cch + 2] = '\0'; rc = kLdrDyldGetFilename(hMod2, szBuf, cch); if (rc == KERR_BUFFER_OVERFLOW) { if (!szBuf[0]) Failure("kLdrDyldGetFilename didn't return partial result on overflow\n"); else if (szBuf[cch - 1]) Failure("kLdrDyldGetFilename didn't terminate partial result correctly overflow: '%s'\n", szBuf); else if (szBuf[cch] != 'x') Failure("kLdrDyldGetFilename exceeded the buffer limit on partial overflow: '%s'\n", szBuf); } else Failure("kLdrDyldGetFilename(\"tst-0-d\",,,) -> rc=%d (%#x) instead of KERR_BUFFER_OVERFLOW\n", rc, rc); /* check that we can query the module by the returned filename. */ rc = kLdrDyldGetFilename(hMod2, szBuf, sizeof(szBuf)); if (!rc) { hMod3 = (HKLDRMOD)0xffffeeee; rc = kLdrDyldFindByName(szBuf, NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod3); if (rc || hMod3 != hMod2) Failure("kLdrDyldFindByName(\"%s\",,,) failed, rc=%d (%#x) hMod3=%p hMod2=%p\n", szBuf, rc, rc, (void *)hMod3, (void *)hMod2); } else Failure("kLdrDyldGetName(\"tst-0-d\",,,) failed (b), rc=%d (%#x)\n", rc, rc); } else Failure("kLdrDyldGetFilename(\"tst-0-d\",,,) failed, rc=%d (%#x)\n", rc, rc); /* the other module */ rc = kLdrDyldGetName(hMod, szBuf, sizeof(szBuf)); if (!rc) { printf("tst-0-driver: name: '%s' ('tst-0-a')\n", szBuf); psz = strstr(szBuf, "-0-"); if ( !psz || strnicmp(psz, "-0-a", sizeof("-0-a") - 1)) Failure("kLdrDyldGetName(\"tst-0-a\",,,) -> '%s': pattern '-0-a' not found\n", szBuf); /* check that we can query the module by the returned name. */ hMod3 = (HKLDRMOD)0xffffeeee; rc = kLdrDyldFindByName(szBuf, NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod3); if (rc || hMod3 != hMod) Failure("kLdrDyldFindByName(\"%s\",,,) failed, rc=%d (%#x) hMod3=%p hMod=%p\n", szBuf, rc, rc, (void *)hMod3, (void *)hMod); } else Failure("kLdrDyldGetName(\"tst-0-a\",,,) failed, rc=%d (%#x)\n", rc, rc); rc = kLdrDyldGetFilename(hMod, szBuf, sizeof(szBuf)); if (!rc) { printf("tst-0-driver: filename: '%s' ('tst-0-a')\n", szBuf); /* check that we can query the module by the returned filename. */ hMod3 = (HKLDRMOD)0xffffeeee; rc = kLdrDyldFindByName(szBuf, NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod3); if (rc || hMod3 != hMod) Failure("kLdrDyldFindByName(\"%s\",,,) failed, rc=%d (%#x) hMod3=%p hMod=%p\n", szBuf, rc, rc, (void *)hMod3, (void *)hMod); } else Failure("kLdrDyldGetFilename(\"tst-0-a\",,,) failed, rc=%d (%#x)\n", rc, rc); /* * Resolve the symbol exported by each of the two modules and call them. */ if (!g_cErrors) { KUPTR uValue; KU32 fKind; fKind = 0xffeeffee; uValue = ~(KUPTR)42; rc = kLdrDyldQuerySymbol(hMod, NIL_KLDRMOD_SYM_ORDINAL, MY_NAME("FuncA"), NULL, &uValue, &fKind); if (!rc) { if (uValue == ~(KUPTR)42) Failure("kLdrDyldQuerySymbol(\"tst-0-a\",,\"FuncA\",): uValue wasn't set.\n"); if (fKind == 0xffeeffee) Failure("kLdrDyldQuerySymbol(\"tst-0-a\",,\"FuncA\",): fKind wasn't set.\n"); if ( (fKind & KLDRSYMKIND_BIT_MASK) != KLDRSYMKIND_NO_BIT && (fKind & KLDRSYMKIND_BIT_MASK) != MY_KLDRSYMKIND_BITS) Failure("fKind=%#x indicates a different code 'bit' mode than we running at.\n", fKind); if ( (fKind & KLDRSYMKIND_TYPE_MASK) != KLDRSYMKIND_NO_TYPE && (fKind & KLDRSYMKIND_TYPE_MASK) != KLDRSYMKIND_CODE) Failure("fKind=%#x indicates that \"FuncA\" isn't code.\n", fKind); if (fKind & KLDRSYMKIND_FORWARDER) Failure("fKind=%#x indicates that \"FuncA\" is a forwarder. it isn't.\n", fKind); /* call it. */ if (!g_cErrors) { int (*pfnFuncA)(void) = (int (*)(void))uValue; rc = pfnFuncA(); if (rc != 0x42000042) Failure("FuncA returned %#x expected 0x42000042\n", rc); } /* * Test kLdrDyldFindByAddress now that we've got an address. */ hMod3 = (HKLDRMOD)0xeeeeffff; rc = kLdrDyldFindByAddress(uValue, &hMod3, NULL, NULL); if (!rc) { KUPTR offSegment; KU32 iSegment; if (hMod3 != hMod) Failure("kLdrDyldFindByAddress(%#p/*FuncA*/, \"tst-0-a\",,,) return incorrect hMod3=%p instead of %p.\n", uValue, hMod3, hMod); hMod3 = (HKLDRMOD)0xeeeeffff; iSegment = 0x42424242; rc = kLdrDyldFindByAddress(uValue, &hMod3, &iSegment, &offSegment); if (!rc) { if (hMod3 != hMod) Failure("Bad hMod3 on 2nd kLdrDyldFindByAddress call.\n"); if (iSegment > 0x1000) /* safe guess */ Failure("Bad iSegment=%#x\n", iSegment); if (offSegment > 0x100000) /* guesswork */ Failure("Bad offSegment=%p\n", (void *)offSegment); } else Failure("kLdrDyldFindByAddress(%#p/*FuncA*/, \"tst-0-a\",,,) failed (b), rc=%d (%#x)\n", uValue, rc, rc); /* negative test */ hMod3 = (HKLDRMOD)0xeeeeffff; iSegment = 0x42424242; offSegment = 0x87654321; rc = kLdrDyldFindByAddress(~(KUPTR)16, &hMod3, &iSegment, &offSegment); if (!rc) Failure("negative kLdrDyldFindByAddress test returned successfully!\n"); if (iSegment != ~(KU32)0) Failure("negative kLdrDyldFindByAddress: bad iSegment=%#x\n", iSegment); if (offSegment != ~(KUPTR)0) Failure("negative kLdrDyldFindByAddress: bad offSegment=%p\n", (void *)offSegment); if (hMod3 != NIL_HKLDRMOD) Failure("negative kLdrDyldFindByAddress: bad hMod3=%p\n", (void *)hMod3); } else Failure("kLdrDyldFindByAddress(%#p/*FuncA*/, \"tst-0-a\",,,) failed, rc=%d (%#x)\n", uValue, rc, rc); } else Failure("kLdrDyldQuerySymbol(\"tst-0-a\",,\"FuncA\",) failed, rc=%d (%#x)\n", rc, rc); fKind = 0xffeeffee; uValue = ~(KUPTR)42; rc = kLdrDyldQuerySymbol(hMod2, NIL_KLDRMOD_SYM_ORDINAL, MY_NAME("FuncD"), NULL, &uValue, &fKind); if (!rc) { if (uValue == ~(KUPTR)42) Failure("kLdrDyldQuerySymbol(\"tst-0-d\",,\"FuncD\",): uValue wasn't set.\n"); if (fKind == 0xffeeffee) Failure("kLdrDyldQuerySymbol(\"tst-0-d\",,\"FuncD\",): fKind wasn't set.\n"); if ( (fKind & KLDRSYMKIND_BIT_MASK) != KLDRSYMKIND_NO_BIT && (fKind & KLDRSYMKIND_BIT_MASK) != MY_KLDRSYMKIND_BITS) Failure("fKind=%#x indicates a different code 'bit' mode than we running at.\n", fKind); if ( (fKind & KLDRSYMKIND_TYPE_MASK) != KLDRSYMKIND_NO_TYPE && (fKind & KLDRSYMKIND_TYPE_MASK) != KLDRSYMKIND_CODE) Failure("fKind=%#x indicates that \"FuncD\" isn't code.\n", fKind); if (fKind & KLDRSYMKIND_FORWARDER) Failure("fKind=%#x indicates that \"FuncD\" is a forwarder. it isn't.\n", fKind); /* call it. */ if (!g_cErrors) { int (*pfnFuncD)(void) = (int (*)(void))uValue; rc = pfnFuncD(); if (rc != 0x42000000) Failure("FuncD returned %#x expected 0x42000000\n", rc); } /* use the address to get the module handle. */ hMod3 = (HKLDRMOD)0xeeeeffff; rc = kLdrDyldFindByAddress(uValue, &hMod3, NULL, NULL); if (!rc) { if (hMod3 != hMod2) Failure("kLdrDyldFindByAddress(%#p/*FuncD*/,,,) return incorrect hMod3=%p instead of %p.\n", uValue, hMod3, hMod2); } else Failure("kLdrDyldFindByAddress(%#p/*FuncD*/,,,) failed, rc=%d (%#x)\n", uValue, rc, rc); } else Failure("kLdrDyldQuerySymbol(\"tst-0-a\",,\"FuncA\",) failed, rc=%d (%#x)\n", rc, rc); } /* * Finally unload it. */ rc = kLdrDyldUnload(hMod); if (rc) Failure("kLdrDyldUnload() failed. rc=%d (%#x)\n", rc, rc); if (!rc) { rc = kLdrDyldFindByName("tst-0-d", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod2); if (rc != KLDR_ERR_MODULE_NOT_FOUND) Failure("kLdrDyldFindByName(\"tst-0-d\",,,) return rc=%d (%#x), expected KLDR_ERR_MODULE_NOT_FOUND\n", rc, rc); rc = kLdrDyldFindByName("tst-0-a", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod2); if (rc != KLDR_ERR_MODULE_NOT_FOUND) Failure("kLdrDyldFindByName(\"tst-0-a\",,,) return rc=%d (%#x), expected KLDR_ERR_MODULE_NOT_FOUND\n", rc, rc); } } /* * Now do what tst-0 would do; load the three dlls, resolve and call their functions. */ if (!g_cErrors) { HKLDRMOD hModA; int (*pfnFuncA)(void); HKLDRMOD hModB; int (*pfnFuncB)(void); HKLDRMOD hModC; int (*pfnFuncC)(void); KUPTR uValue; rc = kLdrDyldLoad("tst-0-a", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hModA, NULL, 0); if (rc) Failure("kLdrDyldLoad(\"tst-0-a\",,,,) -> %d (%#x)\n", rc, rc); if (!rc) { rc = kLdrDyldLoad("tst-0-b", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hModB, szErr, sizeof(szErr)); if (rc) Failure("kLdrDyldLoad(\"tst-0-b\",,,,) -> %d (%#x) szErr='%s'\n", rc, rc, szErr); } if (!rc) { rc = kLdrDyldLoad("tst-0-c", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hModC, szErr, sizeof(szErr)); if (rc) Failure("kLdrDyldLoad(\"tst-0-c\",,,,) -> %d (%#x) szErr='%s'\n", rc, rc, szErr); } if (!rc) { rc = kLdrDyldQuerySymbol(hModA, NIL_KLDRMOD_SYM_ORDINAL, MY_NAME("FuncA"), NULL, &uValue, NULL); if (!rc) pfnFuncA = (int (*)(void))uValue; else Failure("kLdrDyldQuerySymbol(,,\"FuncA\",,) -> %d (%#x)\n", rc, rc); } if (!rc) { rc = kLdrDyldQuerySymbol(hModB, NIL_KLDRMOD_SYM_ORDINAL, MY_NAME("FuncB"), NULL, &uValue, NULL); if (!rc) pfnFuncB = (int (*)(void))uValue; else Failure("kLdrDyldQuerySymbol(,,\"FuncB\",,) -> %d (%#x)\n", rc, rc); } if (!rc) { rc = kLdrDyldQuerySymbol(hModC, NIL_KLDRMOD_SYM_ORDINAL, MY_NAME("FuncC"), NULL, &uValue, NULL); if (!rc) pfnFuncC = (int (*)(void))uValue; else Failure("kLdrDyldQuerySymbol(,,\"FuncA\",,) -> %d (%#x)\n", rc, rc); } if (!rc) { int u = pfnFuncA() | pfnFuncB() | pfnFuncC(); if (u == 0x42424242) printf("tst-0-driver: FuncA/B/C => %#x (correct)\n", u); else Failure("FuncA/B/C => %#x\n", u); rc = kLdrDyldUnload(hModA); if (rc) Failure("Unload A failed, rc=%d (%#x)\n", rc, rc); u = pfnFuncB() | pfnFuncC(); if (u != 0x42424200) Failure("FuncB/C returns %#x instead of 0x42424200 after unloading A\n", u); rc = kLdrDyldUnload(hModB); if (rc) Failure("Unload B failed, rc=%d (%#x)\n", rc, rc); u = pfnFuncC(); if (u != 0x42420000) Failure("FuncC returns %#x instead of 0x42420000 after unloading A\n", u); rc = kLdrDyldUnload(hModC); if (rc) Failure("Unload C failed, rc=%d (%#x)\n", rc, rc); rc = kLdrDyldFindByName("tst-0-d", NULL, NULL, KLDRDYLD_SEARCH_HOST, 0, &hMod); if (rc != KLDR_ERR_MODULE_NOT_FOUND) Failure("Query for \"tst-0-d\" after unloading A,B and C returns rc=%d (%#x) instead of KLDR_ERR_MODULE_NOT_FOUND\n", rc, rc); } } /* * Now invoke the executable stub which launches the tst-0 program. */ if (!g_cErrors) { /// @todo } /* * Summary */ if (!g_cErrors) printf("tst-0-driver: SUCCESS\n"); else printf("tst-0-driver: FAILURE - %d errors\n", g_cErrors); return !!g_cErrors; } kbuild-3149/src/lib/kStuff/kLdr/testcase/tst-0-d.c0000644000175000017500000000021513252530253021544 0ustar locutuslocutus#include "tst.h" const char *g_pszName = "d"; MY_EXPORT(int) FuncD(void) { return g_pszName[0] == 'd' ? 0x42000000 : 0x1000; } kbuild-3149/src/lib/kStuff/kLdr/testcase/tst-3-ext.c0000644000175000017500000000257113252530253022133 0ustar locutuslocutus/* $Id: tst-3-ext.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - Dynamic Loader testcase no. 3, 2nd object module. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #include "tst.h" extern int g_i1; int Tst3Sub(int iFortyTwo) { return iFortyTwo * 11 * g_i1; } kbuild-3149/src/lib/kStuff/kLdr/testcase/tst-0.c0000644000175000017500000000033513252530253021326 0ustar locutuslocutus#include "tst.h" MY_IMPORT(int) FuncA(void); MY_IMPORT(int) FuncB(void); MY_IMPORT(int) FuncC(void); int main() { unsigned u; u = FuncA() | FuncB() | FuncC(); return u == 0x42424242 ? 0 : 1; } kbuild-3149/src/lib/kStuff/kLdr/testcase/tst-3-imp-os2.def0000644000175000017500000000246013252530253023132 0ustar locutuslocutus; $Id: tst-3-imp-os2.def 29 2009-07-01 20:30:29Z bird $ ;; @file ; kLdr - Dynamic Loader testcase no. 3, Fake module import library - OS/2. ; ; ; Copyright (c) 2006-2007 Knut St. Osmundsen ; ; 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. ; LIBRARY tst-3-imp EXPORTS _Tst3Ext kbuild-3149/src/lib/kStuff/kLdr/testcase/bin/0000755000175000017500000000000013252530253020762 5ustar locutuslocutuskbuild-3149/src/lib/kStuff/kLdr/testcase/bin/tst-3.dll.win.x860000644000175000017500000000600013252530253023645 0ustar locutuslocutusMZÿÿ¸@Ⱥ´ Í!¸LÍ!This program cannot be run in DOS mode. $ÁEðÜ…$ž…$ž…$ž€(Æ$ž…$Ÿ„$ž€(Á†$ž€(„$ž€(Ä„$žRich…$žPEL&;ÒEà!  P P€ A, (@4  .textb `.rdata% @@.data 0@À.reloc@@ @BU‹ìQƒ}*t3Àéƒ=0t ¸éƒ=0t ¸éï=00t ¸éÙ= 00t ¸éËEPèăĉEü‹MQÿ 0ƒÄ9Eüt ¸阋URèŃĉEüƒ}ü*t¸ë|‹EPÿ0ƒÄ‰Eüƒ}ü*t¸ë_ÇEüë ‹MüƒÁ‰Mü}üs‹Uü¾‚ 0…Àt¸ë/ë×¾ 0…Éu¾!0…Òu ¾1…Àt¸ ë¸*‹å]ÃÌÌÌÌÌÌU‹ì‹EkÀ ¯0]ÃÌÌÌÌÌÌÌÌÌÌÌÌÌÌU‹ì¸] ÿ% \ &;ÒEaÄ ÄT f \ Tst3Exttst-3-imp.dll&;ÒE² ¨ ¬ ° ¼ tst-3.dllTst3RSDSåw$ôÓãM´Éì8`J0G:\coding\libc\trunk\out\win.x86\debug\obj\kLdr\testcase\tst-3\tst-3.pdb00\$0&090=0O0S0x0°0è0ü011<1^100 00kbuild-3149/src/lib/kStuff/kLdr/testcase/bin/tst-3.rel.darwin.x860000644000175000017500000000536013252530253024353 0ustar locutuslocutusÎúíþl `ˆP__text__TEXT:ˆØ__data__DATA<ÄX__common__DATA`pQ<´PU‰åSƒìƒ}*t1ÀƒÄ[]Ã=L…¿ƒ=H…¼=DL…Ž=@%uLÇ$*èΉÃÇ$*ÿ@9ÃumÇ$*èŠÿÿÿƒø*uzÇ$*ÿ<ƒø*t¸éxÿÿÿ¸énÿÿÿ€=`uº`¹_9ÑtG¶BƒÂ„Àtñ¸éBÿÿÿ¸é8ÿÿÿ¸é.ÿÿÿ¸é$ÿÿÿ¸éÿÿÿ¸éÿÿÿ€=au €=_t ¸ éôþÿÿ¸*éêþÿÿU‰å‹U¯L’B]Ã%L  ` `° `«£„rP bSEA51$.P UddÌfÍ<Ü€.D-D0DJD2D4"D6/D8?D:KD;YD=jD>vD@{DAˆD8—DD¡DC´DD¸DFÃD6ÍD;×D2áD4ëD>õDFÿê$-ö ,@.€;À<à%=$%N%> J V !c€r $† 'š )ª€¹€Õ€ä€€.d%/d%gd%ªf«<º€.%D!%D!+D#8È$!%×  è€$N:d:dLd”f•<¤€²dL% `LH <.@<DC_Tst3_g_achBss_g_i1_g_i2_g_pfnTst3Ext_g_pfnTst3Sub_g_pi1_Tst3Ext_Tst3Sub/Users/bird/vax/gdrive/coding/libc/trunk/kLdr/testcase//Users/bird/vax/gdrive/coding/libc/trunk/kLdr/testcase/tst-3.cgcc2_compiled.:t(0,1)=(0,1)Tst3:F(0,2)iFortyTwo:p(0,2)rc:r(0,2)int:t(0,2)=r(0,2);-2147483648;2147483647;g_i1:G(0,2)g_i2:G(0,2)g_pi1:G(0,3):t(0,3)=*(0,2)g_pfnTst3Sub:G(0,4)g_pfnTst3Ext:G(0,4)g_achBss:G(0,5):t(0,4)=*(0,6):t(0,5)=ar(0,7);0;255;(0,8):t(0,6)=f(0,2)long unsigned int:t(0,7)=r(0,7);0;037777777777;char:t(0,8)=r(0,8);0;127;/Users/bird/vax/gdrive/coding/libc/trunk/kLdr/testcase//Users/bird/vax/gdrive/coding/libc/trunk/kLdr/testcase/tst-3-ext.cgcc2_compiled.:t(0,1)=(0,1)Tst3Sub:F(0,2)iFortyTwo:p(0,2)int:t(0,2)=r(0,2);-2147483648;2147483647;/Users/bird/vax/gdrive/coding/libc/trunk/kLdr/testcase//Users/bird/vax/gdrive/coding/libc/trunk/kLdr/testcase/tstDllMainStub.cgcc2_compiled.:t(0,1)=(0,1)kbuild-3149/src/lib/kStuff/kLdr/testcase/tst-0-b.c0000644000175000017500000000026413252530253021546 0ustar locutuslocutus#include "tst.h" const char *g_pszName = "b"; MY_IMPORT(int) FuncD(void); MY_EXPORT(int) FuncB(void) { return FuncD() | (g_pszName[0] == 'b' ? 0x4200 : 0x0010); } kbuild-3149/src/lib/kStuff/kLdr/testcase/tst-1.c0000644000175000017500000000047313252530253021332 0ustar locutuslocutus#include "tst.h" #include MY_IMPORT(int) FuncA(void); MY_IMPORT(int) FuncB(void); MY_IMPORT(int) FuncC(void); int main() { printf("graph:\n" " tst-1 -> a -> d\n" " b -> d\n" " c -> d\n"); return FuncA() + FuncB() + FuncC(); } kbuild-3149/src/lib/kStuff/kLdr/testcase/tst-2-b.c0000644000175000017500000000021213252530253021541 0ustar locutuslocutus#include "tst.h" const char *g_pszName = "b"; MY_IMPORT(int) FuncA(void); MY_EXPORT(int) FuncB(void) { return FuncA(); } kbuild-3149/src/lib/kStuff/kLdr/testcase/tst-1-b.c0000644000175000017500000000021213252530253021540 0ustar locutuslocutus#include "tst.h" const char *g_pszName = "b"; MY_IMPORT(int) FuncD(void); MY_EXPORT(int) FuncB(void) { return FuncD(); } kbuild-3149/src/lib/kStuff/kLdr/testcase/tst-0-c.c0000644000175000017500000000026613252530253021551 0ustar locutuslocutus#include "tst.h" const char *g_pszName = "c"; MY_IMPORT(int) FuncD(void); MY_EXPORT(int) FuncC(void) { return FuncD() | (g_pszName[0] == 'c' ? 0x420000 : 0x0100); } kbuild-3149/src/lib/kStuff/kLdr/testcase/tst-2-c.c0000644000175000017500000000021213252530253021542 0ustar locutuslocutus#include "tst.h" const char *g_pszName = "c"; MY_IMPORT(int) FuncA(void); MY_EXPORT(int) FuncC(void) { return FuncA(); } kbuild-3149/src/lib/kStuff/kLdr/testcase/tst-2-a.c0000644000175000017500000000014513252530253021545 0ustar locutuslocutus#include "tst.h" const char *g_pszName = "a"; MY_EXPORT(int) FuncA(void) { return 0; } kbuild-3149/src/lib/kStuff/kLdr/testcase/tst.h0000644000175000017500000000344213252530253021200 0ustar locutuslocutus/* $Id: tst.h 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr testcase header. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #ifndef ___tst_h___ #define ___tst_h___ #include #include #if K_OS == K_OS_OS2 \ || K_OS == K_OS_WINDOWS # define MY_EXPORT(type) __declspec(dllexport) type /*# define MY_IMPORT(type) extern __declspec(dllimport) type*/ # define MY_IMPORT(type) extern type #else # define MY_EXPORT(type) type # define MY_IMPORT(type) extern type #endif #if K_OS == K_OS_OS2 \ || K_OS == K_OS_DARWIN # define MY_NAME(a) "_" a #else # define MY_NAME(a) a #endif extern const char *g_pszName; #endif kbuild-3149/src/lib/kStuff/kLdr/testcase/tstExeMainStub.c0000644000175000017500000000463013252530253023300 0ustar locutuslocutus/* $Id: tstExeMainStub.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr testcase - DLL Stub. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "tst.h" #if K_OS == K_OS_OS2 # define INCL_BASE # include #elif K_OS == K_OS_WINDOWS /* nothing */ #elif K_OS == K_OS_NT # include /** @todo fix the nt port. */ #else # error "port me" #endif extern int main(); #if K_OS == K_OS_OS2 /** * OS/2 'main'. */ ULONG _System OS2Main(HMODULE hmod, ULONG fFlag, ULONG ulReserved, PSZ pszzEnv, PSZ pszzCmdLine) { int rc; rc = main(); return rc; } #elif K_OS == K_OS_WINDOWS /** * Windows'main' */ int WindowsMain(void) { int rc; rc = main(); return rc; } #elif K_OS == K_OS_NT /** * Windows NT 'main' */ VOID NtProcess(HANDLE hDllHandle, DWORD dwReason, LPVOID lpReserved) { int rc; rc = main(); /* (no way around this) */ for (;;) ZwTerminateProcess(NtCurrentProcess(), rc); } #else # error "port me" #endif kbuild-3149/src/lib/kStuff/kLdr/testcase/tstDllMain.c0000644000175000017500000001157013252530253022435 0ustar locutuslocutus/* $Id: tstDllMain.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr testcase. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "tst.h" #if K_OS == K_OS_OS2 # define INCL_BASE # include # include #elif K_OS == K_OS_WINDOWS # include # include #elif K_OS == K_OS_DARWIN # include # include #else # error "port me" #endif /******************************************************************************* * Internal Functions * *******************************************************************************/ void tstWrite(const char *psz); #if K_OS == K_OS_OS2 /** * OS/2 DLL 'main' */ ULONG _System _DLL_InitTerm(HMODULE hmod, ULONG fFlags) { switch (fFlags) { case 0: tstWrite("init: "); tstWrite(g_pszName); tstWrite("\n"); return TRUE; case 1: tstWrite("term: "); tstWrite(g_pszName); tstWrite("\n"); return TRUE; default: tstWrite("!invalid!: "); tstWrite(g_pszName); tstWrite("\n"); return FALSE; } } #elif K_OS == K_OS_WINDOWS /** * OS/2 DLL 'main' */ BOOL __stdcall DllMain(HANDLE hDllHandle, DWORD dwReason, LPVOID lpReserved) { switch (dwReason) { case DLL_PROCESS_ATTACH: tstWrite("init: "); tstWrite(g_pszName); tstWrite("\n"); return TRUE; case DLL_PROCESS_DETACH: tstWrite("term: "); tstWrite(g_pszName); tstWrite("\n"); return TRUE; case DLL_THREAD_ATTACH: tstWrite("thread init: "); tstWrite(g_pszName); tstWrite("\n"); return TRUE; case DLL_THREAD_DETACH: tstWrite("thread term: "); tstWrite(g_pszName); tstWrite("\n"); return TRUE; default: tstWrite("!invalid!: "); tstWrite(g_pszName); tstWrite("\n"); return FALSE; } } #elif K_OS == K_OS_DARWIN /* later */ #else # error "port me" #endif /** * Writes a string with unix lineendings. * * @param pszMsg The string. */ void tstWrite(const char *pszMsg) { #if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS /* * Line by line. */ ULONG cbWritten; const char *pszNl = strchr(pszMsg, '\n'); while (pszNl) { cbWritten = pszNl - pszMsg; #if K_OS == K_OS_OS2 if (cbWritten) DosWrite((HFILE)2, pszMsg, cbWritten, &cbWritten); DosWrite((HFILE)2, "\r\n", 2, &cbWritten); #else if (cbWritten) WriteFile((HANDLE)STD_ERROR_HANDLE, pszMsg, cbWritten, &cbWritten, NULL); WriteFile((HANDLE)STD_ERROR_HANDLE, "\r\n", 2, &cbWritten, NULL); #endif /* next */ pszMsg = pszNl + 1; pszNl = strchr(pszMsg, '\n'); } /* * Remaining incomplete line. */ if (*pszMsg) { cbWritten = strlen(pszMsg); #if K_OS == K_OS_OS2 DosWrite((HFILE)2, pszMsg, cbWritten, &cbWritten); #else WriteFile((HANDLE)STD_ERROR_HANDLE, pszMsg, cbWritten, &cbWritten, NULL); #endif } #elif K_OS == K_OS_DARWIN write(STDERR_FILENO, pszMsg, strlen(pszMsg)); #else # error "port me" #endif } kbuild-3149/src/lib/kStuff/kLdr/testcase/tstExeMainStub-os2.asm0000644000175000017500000000262113252530253024335 0ustar locutuslocutus; $Id: tstExeMainStub-os2.asm 29 2009-07-01 20:30:29Z bird $ ;; @file ; kLdr - OS/2 entry point thingy... ; ; ; Copyright (c) 2006-2007 Knut St. Osmundsen ; ; 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. ; segment TEXT32 public CLASS=CODE align=16 use32 extern OS2Main ..start: jmp OS2Main segment DATA32 stack CLASS=DATA align=16 use32 global WEAK$ZERO WEAK$ZERO EQU 0 kbuild-3149/src/lib/kStuff/kLdr/testcase/tstDllMainStub-os2.asm0000644000175000017500000000263513252530253024334 0ustar locutuslocutus; $Id: tstDllMainStub-os2.asm 29 2009-07-01 20:30:29Z bird $ ;; @file ; kLdr - OS/2 entry point thingy... ; ; ; Copyright (c) 2006-2007 Knut St. Osmundsen ; ; 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. ; segment TEXT32 public CLASS=CODE align=16 use32 extern _DLL_InitTerm ..start: jmp _DLL_InitTerm segment DATA32 stack CLASS=DATA align=16 use32 global WEAK$ZERO WEAK$ZERO EQU 0 kbuild-3149/src/lib/kStuff/kLdr/testcase/tst-3.c0000644000175000017500000000417213252530253021334 0ustar locutuslocutus/* $Id: tst-3.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - Dynamic Loader testcase no. 3, Driver. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ #include "tst.h" int g_i1 = 1; int g_i2 = 2; int *g_pi1 = &g_i1; extern int Tst3Sub(int); int (*g_pfnTst3Sub)(int) = &Tst3Sub; MY_IMPORT(int) Tst3Ext(int); int (*g_pfnTst3Ext)(int) = &Tst3Ext; char g_achBss[256]; MY_EXPORT(int) Tst3(int iFortyTwo) { int rc; if (iFortyTwo != 42) return 0; if (g_i1 != 1) return 1; if (g_i2 != 2) return 2; if (g_pi1 != &g_i1) return 3; if (g_pfnTst3Sub != &Tst3Sub) return 4; rc = Tst3Sub(iFortyTwo); if (rc != g_pfnTst3Sub(iFortyTwo)) return 5; rc = Tst3Ext(iFortyTwo); if (rc != 42) return 6; rc = g_pfnTst3Ext(iFortyTwo); if (rc != 42) return 7; for (rc = 0; rc < sizeof(g_achBss); rc++) if (g_achBss[rc]) return 8; if (g_achBss[0] || g_achBss[1] || g_achBss[255]) return 9; return 42; } kbuild-3149/src/lib/kStuff/kLdr/testcase/tst-0-a.c0000644000175000017500000000026213252530253021543 0ustar locutuslocutus#include "tst.h" const char *g_pszName = "a"; MY_IMPORT(int) FuncD(void); MY_EXPORT(int) FuncA(void) { return FuncD() | (g_pszName[0] == 'a' ? 0x42 : 0x0001); } kbuild-3149/src/lib/kStuff/kLdr/testcase/tstDllMainStub.c0000644000175000017500000000413713252530253023274 0ustar locutuslocutus/* $Id: tstDllMainStub.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr testcase - DLL Stub. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "tst.h" #if K_OS == K_OS_OS2 # define INCL_BASE # include #elif K_OS == K_OS_WINDOWS # include #elif K_OS == K_OS_DARWIN /* later */ #else # error "port me" #endif #if K_OS == K_OS_OS2 /** * OS/2 DLL 'main' */ ULONG _System _DLL_InitTerm(HMODULE hmod, ULONG fFlag) { return TRUE; } #elif K_OS == K_OS_WINDOWS /** * Window DLL 'main' */ BOOL __stdcall DllMain(HANDLE hDllHandle, DWORD dwReason, LPVOID lpReserved) { return TRUE; } #elif K_OS == K_OS_DARWIN /* later */ #else # error "port me" #endif kbuild-3149/src/lib/kStuff/kLdr/testcase/tst-1-d.c0000644000175000017500000000014513252530253021547 0ustar locutuslocutus#include "tst.h" const char *g_pszName = "d"; MY_EXPORT(int) FuncD(void) { return 0; } kbuild-3149/src/lib/kStuff/kLdr/kLdrModPE.c0000644000175000017500000021530513252530253020332 0ustar locutuslocutus/* $Id: kLdrModPE.c 89 2016-09-07 13:32:53Z bird $ */ /** @file * kLdr - The Module Interpreter for the Portable Executable (PE) Format. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include "kLdrInternal.h" #include /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** @def KLDRMODPE_STRICT * Define KLDRMODPE_STRICT to enabled strict checks in KLDRMODPE. */ #define KLDRMODPE_STRICT 1 /** @def KLDRMODPE_ASSERT * Assert that an expression is true when KLDR_STRICT is defined. */ #ifdef KLDRMODPE_STRICT # define KLDRMODPE_ASSERT(expr) kHlpAssert(expr) #else # define KLDRMODPE_ASSERT(expr) do {} while (0) #endif /** @def KLDRMODPE_RVA2TYPE * Converts a RVA to a pointer of the specified type. * @param pvBits The bits (image base). * @param uRVA The image relative virtual address. * @param type The type to cast to. */ #define KLDRMODPE_RVA2TYPE(pvBits, uRVA, type) \ ( (type) ((KUPTR)(pvBits) + (KUPTR)(uRVA)) ) /** @def KLDRMODPE_VALID_RVA * Checks that the specified RVA value is non-zero and within the bounds of the image. * @returns true/false. * @param pModPE The PE module interpreter instance. * @param uRVA The RVA to validate. */ #define KLDRMODPE_VALID_RVA(pModPE, uRVA) \ ( (uRVA) && (uRVA) < (pModPE)->Hdrs.OptionalHeader.SizeOfImage ) /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * Instance data for the PE module interpreter. */ typedef struct KLDRMODPE { /** Pointer to the module. (Follows the section table.) */ PKLDRMOD pMod; /** Pointer to the RDR mapping of the raw file bits. NULL if not mapped. */ const void *pvBits; /** Pointer to the user mapping. */ const void *pvMapping; /** Reserved flags. */ KU32 f32Reserved; /** The number of imported modules. * If ~(KU32)0 this hasn't been determined yet. */ KU32 cImportModules; /** The offset of the NT headers. */ KLDRFOFF offHdrs; /** Copy of the NT headers. */ IMAGE_NT_HEADERS64 Hdrs; /** The section header table . */ IMAGE_SECTION_HEADER aShdrs[1]; } KLDRMODPE, *PKLDRMODPE; /******************************************************************************* * Internal Functions * *******************************************************************************/ static KI32 kldrModPENumberOfImports(PKLDRMOD pMod, const void *pvBits); static int kldrModPERelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); static int kldrModPEDoCreate(PKRDR pRdr, KLDRFOFF offNewHdr, PKLDRMODPE *ppMod); /*static void kldrModPEDoLoadConfigConversion(PIMAGE_LOAD_CONFIG_DIRECTORY64 pLoadCfg); */ static int kLdrModPEDoOptionalHeaderValidation(PKLDRMODPE pModPE); static int kLdrModPEDoSectionHeadersValidation(PKLDRMODPE pModPE); static void kldrModPEDoOptionalHeaderConversion(PIMAGE_OPTIONAL_HEADER64 pOptionalHeader); static int kldrModPEDoForwarderQuery(PKLDRMODPE pModPE, const void *pvBits, const char *pszForwarder, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser, PKLDRADDR puValue, KU32 *pfKind); static int kldrModPEDoFixups(PKLDRMODPE pModPE, void *pvMapping, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress); static int kldrModPEDoImports32Bit(PKLDRMODPE pModPE, void *pvMapping, const IMAGE_IMPORT_DESCRIPTOR *pImpDesc, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); static int kldrModPEDoImports64Bit(PKLDRMODPE pModPE, void *pvMapping, const IMAGE_IMPORT_DESCRIPTOR *pImpDesc, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); static int kldrModPEDoImports(PKLDRMODPE pModPE, void *pvMapping, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); static int kldrModPEDoCallDLL(PKLDRMODPE pModPE, void *pvMapping, unsigned uOp, KUPTR uHandle); static int kldrModPEDoCallTLS(PKLDRMODPE pModPE, void *pvMapping, unsigned uOp, KUPTR uHandle); static KI32 kldrModPEDoCall(KUPTR uEntrypoint, KUPTR uHandle, KU32 uOp, void *pvReserved); /** * Create a loader module instance interpreting the executable image found * in the specified file provider instance. * * @returns 0 on success and *ppMod pointing to a module instance. * On failure, a non-zero OS specific error code is returned. * @param pOps Pointer to the registered method table. * @param pRdr The file provider instance to use. * @param fFlags Flags, MBZ. * @param enmCpuArch The desired CPU architecture. KCPUARCH_UNKNOWN means * anything goes, but with a preference for the current * host architecture. * @param offNewHdr The offset of the new header in MZ files. -1 if not found. * @param ppMod Where to store the module instance pointer. */ static int kldrModPECreate(PCKLDRMODOPS pOps, PKRDR pRdr, KU32 fFlags, KCPUARCH enmCpuArch, KLDRFOFF offNewHdr, PPKLDRMOD ppMod) { PKLDRMODPE pModPE; int rc; K_NOREF(fFlags); /* * Create the instance data and do a minimal header validation. */ rc = kldrModPEDoCreate(pRdr, offNewHdr, &pModPE); if (!rc) { /* * Match up against the requested CPU architecture. */ if ( enmCpuArch == KCPUARCH_UNKNOWN || pModPE->pMod->enmArch == enmCpuArch) { pModPE->pMod->pOps = pOps; pModPE->pMod->u32Magic = KLDRMOD_MAGIC; *ppMod = pModPE->pMod; return 0; } rc = KLDR_ERR_CPU_ARCH_MISMATCH; } kHlpFree(pModPE); return rc; } /** * Separate function for reading creating the PE module instance to * simplify cleanup on failure. */ static int kldrModPEDoCreate(PKRDR pRdr, KLDRFOFF offNewHdr, PKLDRMODPE *ppModPE) { struct { KU32 Signature; IMAGE_FILE_HEADER FileHdr; } s; PKLDRMODPE pModPE; PKLDRMOD pMod; KSIZE cb; KSIZE cchFilename; KLDRFOFF off; KU32 i; int rc; *ppModPE = NULL; /* * Read the signature and file header. */ rc = kRdrRead(pRdr, &s, sizeof(s), offNewHdr > 0 ? offNewHdr : 0); if (rc) return rc; if (s.Signature != IMAGE_NT_SIGNATURE) return KLDR_ERR_UNKNOWN_FORMAT; /* sanity checks. */ if ( s.FileHdr.NumberOfSections > 4096 || ( s.FileHdr.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER32) && s.FileHdr.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER64)) || !(s.FileHdr.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) ) return KLDR_ERR_PE_BAD_FILE_HEADER; if ( s.FileHdr.Machine != IMAGE_FILE_MACHINE_I386 && s.FileHdr.Machine != IMAGE_FILE_MACHINE_AMD64 ) return KLDR_ERR_PE_UNSUPPORTED_MACHINE; /* * Calc the instance size, allocate and initialize it. */ cchFilename = kHlpStrLen(kRdrName(pRdr)); cb = K_ALIGN_Z(K_OFFSETOF(KLDRMODPE, aShdrs[s.FileHdr.NumberOfSections]), 16) + K_OFFSETOF(KLDRMOD, aSegments[s.FileHdr.NumberOfSections + 1]) + cchFilename + 1; pModPE = (PKLDRMODPE)kHlpAlloc(cb); if (!pModPE) return KERR_NO_MEMORY; *ppModPE = pModPE; /* KLDRMOD */ pMod = (PKLDRMOD)((KU8 *)pModPE + K_ALIGN_Z(K_OFFSETOF(KLDRMODPE, aShdrs[s.FileHdr.NumberOfSections]), 16)); pMod->pvData = pModPE; pMod->pRdr = pRdr; pMod->pOps = NULL; /* set upon success. */ pMod->cSegments = s.FileHdr.NumberOfSections + 1; pMod->cchFilename = (KU32)cchFilename; pMod->pszFilename = (char *)&pMod->aSegments[pMod->cSegments]; kHlpMemCopy((char *)pMod->pszFilename, kRdrName(pRdr), cchFilename + 1); pMod->pszName = kHlpGetFilename(pMod->pszFilename); pMod->cchName = (KU32)(cchFilename - (pMod->pszName - pMod->pszFilename)); pMod->fFlags = 0; switch (s.FileHdr.Machine) { case IMAGE_FILE_MACHINE_I386: pMod->enmCpu = KCPU_I386; pMod->enmArch = KCPUARCH_X86_32; pMod->enmEndian = KLDRENDIAN_LITTLE; break; case IMAGE_FILE_MACHINE_AMD64: pMod->enmCpu = KCPU_K8; pMod->enmArch = KCPUARCH_AMD64; pMod->enmEndian = KLDRENDIAN_LITTLE; break; default: kHlpAssert(0); break; } pMod->enmFmt = KLDRFMT_PE; if (s.FileHdr.Characteristics & IMAGE_FILE_DLL) pMod->enmType = !(s.FileHdr.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) ? KLDRTYPE_SHARED_LIBRARY_RELOCATABLE : KLDRTYPE_SHARED_LIBRARY_FIXED; else pMod->enmType = !(s.FileHdr.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) ? KLDRTYPE_EXECUTABLE_RELOCATABLE : KLDRTYPE_EXECUTABLE_FIXED; pMod->u32Magic = 0; /* set upon success. */ /* KLDRMODPE */ pModPE->pMod = pMod; pModPE->pvBits = NULL; pModPE->pvMapping = NULL; pModPE->f32Reserved = 0; pModPE->cImportModules = ~(KU32)0; pModPE->offHdrs = offNewHdr >= 0 ? offNewHdr : 0; pModPE->Hdrs.Signature = s.Signature; pModPE->Hdrs.FileHeader = s.FileHdr; /* * Read the optional header and the section table. */ off = pModPE->offHdrs + sizeof(pModPE->Hdrs.Signature) + sizeof(pModPE->Hdrs.FileHeader); rc = kRdrRead(pRdr, &pModPE->Hdrs.OptionalHeader, pModPE->Hdrs.FileHeader.SizeOfOptionalHeader, off); if (rc) return rc; if (pModPE->Hdrs.FileHeader.SizeOfOptionalHeader != sizeof(pModPE->Hdrs.OptionalHeader)) kldrModPEDoOptionalHeaderConversion(&pModPE->Hdrs.OptionalHeader); off += pModPE->Hdrs.FileHeader.SizeOfOptionalHeader; rc = kRdrRead(pRdr, &pModPE->aShdrs[0], sizeof(IMAGE_SECTION_HEADER) * pModPE->Hdrs.FileHeader.NumberOfSections, off); if (rc) return rc; /* * Validate the two. */ rc = kLdrModPEDoOptionalHeaderValidation(pModPE); if (rc) return rc; for (i = 0; i < pModPE->Hdrs.FileHeader.NumberOfSections; i++) { rc = kLdrModPEDoSectionHeadersValidation(pModPE); if (rc) return rc; } /* * Setup the KLDRMOD segment array. */ /* The implied headers section. */ pMod->aSegments[0].pvUser = NULL; pMod->aSegments[0].pchName = "TheHeaders"; pMod->aSegments[0].cchName = sizeof("TheHeaders") - 1; pMod->aSegments[0].enmProt = KPROT_READONLY; pMod->aSegments[0].cb = pModPE->Hdrs.OptionalHeader.SizeOfHeaders; pMod->aSegments[0].Alignment = pModPE->Hdrs.OptionalHeader.SectionAlignment; pMod->aSegments[0].LinkAddress = pModPE->Hdrs.OptionalHeader.ImageBase; pMod->aSegments[0].offFile = 0; pMod->aSegments[0].cbFile = pModPE->Hdrs.OptionalHeader.SizeOfHeaders; pMod->aSegments[0].RVA = 0; if (pMod->cSegments > 1) pMod->aSegments[0].cbMapped = pModPE->aShdrs[0].VirtualAddress; else pMod->aSegments[0].cbMapped = pModPE->Hdrs.OptionalHeader.SizeOfHeaders; pMod->aSegments[0].MapAddress = 0; /* The section headers. */ for (i = 0; i < pModPE->Hdrs.FileHeader.NumberOfSections; i++) { const char *pch; KU32 cb2; /* unused */ pMod->aSegments[i + 1].pvUser = NULL; pMod->aSegments[i + 1].MapAddress = 0; pMod->aSegments[i + 1].SelFlat = 0; pMod->aSegments[i + 1].Sel16bit = 0; pMod->aSegments[i + 1].fFlags = 0; /* name */ pMod->aSegments[i + 1].pchName = pch = (const char *)&pModPE->aShdrs[i].Name[0]; cb2 = IMAGE_SIZEOF_SHORT_NAME; while ( cb2 > 0 && (pch[cb2 - 1] == ' ' || pch[cb2 - 1] == '\0')) cb2--; pMod->aSegments[i + 1].cchName = cb2; /* size and addresses */ if (!(pModPE->aShdrs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD)) { /* Kluge to deal with wlink ".reloc" sections that has a VirtualSize of 0 bytes. */ cb2 = pModPE->aShdrs[i].Misc.VirtualSize; if (!cb2) cb2 = K_ALIGN_Z(pModPE->aShdrs[i].SizeOfRawData, pModPE->Hdrs.OptionalHeader.SectionAlignment); pMod->aSegments[i + 1].cb = pModPE->aShdrs[i].Misc.VirtualSize; pMod->aSegments[i + 1].LinkAddress = pModPE->aShdrs[i].VirtualAddress + pModPE->Hdrs.OptionalHeader.ImageBase; pMod->aSegments[i + 1].RVA = pModPE->aShdrs[i].VirtualAddress; pMod->aSegments[i + 1].cbMapped = cb2; if (i + 2 < pMod->cSegments) pMod->aSegments[i + 1].cbMapped= pModPE->aShdrs[i + 1].VirtualAddress - pModPE->aShdrs[i].VirtualAddress; } else { pMod->aSegments[i + 1].cb = 0; pMod->aSegments[i + 1].cbMapped = 0; pMod->aSegments[i + 1].LinkAddress = NIL_KLDRADDR; pMod->aSegments[i + 1].RVA = 0; } /* file location */ pMod->aSegments[i + 1].offFile = pModPE->aShdrs[i].PointerToRawData; pMod->aSegments[i + 1].cbFile = pModPE->aShdrs[i].SizeOfRawData; if ( pMod->aSegments[i + 1].cbMapped > 0 /* if mapped */ && (KLDRSIZE)pMod->aSegments[i + 1].cbFile > pMod->aSegments[i + 1].cbMapped) pMod->aSegments[i + 1].cbFile = (KLDRFOFF)(pMod->aSegments[i + 1].cbMapped); /* protection */ switch ( pModPE->aShdrs[i].Characteristics & (IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) { case 0: case IMAGE_SCN_MEM_SHARED: pMod->aSegments[i + 1].enmProt = KPROT_NOACCESS; break; case IMAGE_SCN_MEM_READ: case IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_SHARED: pMod->aSegments[i + 1].enmProt = KPROT_READONLY; break; case IMAGE_SCN_MEM_WRITE: case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ: pMod->aSegments[i + 1].enmProt = KPROT_WRITECOPY; break; case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED: case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ: pMod->aSegments[i + 1].enmProt = KPROT_READWRITE; break; case IMAGE_SCN_MEM_EXECUTE: case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_SHARED: pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE; break; case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ: case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_SHARED: pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE_READ; break; case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE: case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ: pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE_WRITECOPY; break; case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED: case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ: pMod->aSegments[i + 1].enmProt = KPROT_EXECUTE_READWRITE; break; } /* alignment. */ switch (pModPE->aShdrs[i].Characteristics & IMAGE_SCN_ALIGN_MASK) { case 0: /* hope this is right... */ pMod->aSegments[i + 1].Alignment = pModPE->Hdrs.OptionalHeader.SectionAlignment; break; case IMAGE_SCN_ALIGN_1BYTES: pMod->aSegments[i + 1].Alignment = 1; break; case IMAGE_SCN_ALIGN_2BYTES: pMod->aSegments[i + 1].Alignment = 2; break; case IMAGE_SCN_ALIGN_4BYTES: pMod->aSegments[i + 1].Alignment = 4; break; case IMAGE_SCN_ALIGN_8BYTES: pMod->aSegments[i + 1].Alignment = 8; break; case IMAGE_SCN_ALIGN_16BYTES: pMod->aSegments[i + 1].Alignment = 16; break; case IMAGE_SCN_ALIGN_32BYTES: pMod->aSegments[i + 1].Alignment = 32; break; case IMAGE_SCN_ALIGN_64BYTES: pMod->aSegments[i + 1].Alignment = 64; break; case IMAGE_SCN_ALIGN_128BYTES: pMod->aSegments[i + 1].Alignment = 128; break; case IMAGE_SCN_ALIGN_256BYTES: pMod->aSegments[i + 1].Alignment = 256; break; case IMAGE_SCN_ALIGN_512BYTES: pMod->aSegments[i + 1].Alignment = 512; break; case IMAGE_SCN_ALIGN_1024BYTES: pMod->aSegments[i + 1].Alignment = 1024; break; case IMAGE_SCN_ALIGN_2048BYTES: pMod->aSegments[i + 1].Alignment = 2048; break; case IMAGE_SCN_ALIGN_4096BYTES: pMod->aSegments[i + 1].Alignment = 4096; break; case IMAGE_SCN_ALIGN_8192BYTES: pMod->aSegments[i + 1].Alignment = 8192; break; default: kHlpAssert(0); pMod->aSegments[i + 1].Alignment = 0; break; } } /* * We're done. */ *ppModPE = pModPE; return 0; } /** * Converts a 32-bit optional header to a 64-bit one * * @param pOptHdr The optional header to convert. */ static void kldrModPEDoOptionalHeaderConversion(PIMAGE_OPTIONAL_HEADER64 pOptHdr) { /* volatile everywhere! */ IMAGE_OPTIONAL_HEADER32 volatile *pOptHdr32 = (IMAGE_OPTIONAL_HEADER32 volatile *)pOptHdr; IMAGE_OPTIONAL_HEADER64 volatile *pOptHdr64 = pOptHdr; KU32 volatile *pu32Dst; KU32 volatile *pu32Src; KU32 volatile *pu32SrcLast; KU32 u32; /* From LoaderFlags and out the difference is 4 * 32-bits. */ pu32Dst = (KU32 *)&pOptHdr64->DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] - 1; pu32Src = (KU32 *)&pOptHdr32->DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] - 1; pu32SrcLast = (KU32 *)&pOptHdr32->LoaderFlags; while (pu32Src >= pu32SrcLast) *pu32Dst-- = *pu32Src--; /* The previous 4 fields are 32/64 and needs special attention. */ pOptHdr64->SizeOfHeapCommit = pOptHdr32->SizeOfHeapCommit; pOptHdr64->SizeOfHeapReserve = pOptHdr32->SizeOfHeapReserve; pOptHdr64->SizeOfStackCommit = pOptHdr32->SizeOfStackCommit; u32 = pOptHdr32->SizeOfStackReserve; pOptHdr64->SizeOfStackReserve = u32; /* * The rest matches except for BaseOfData which has been merged into ImageBase in the 64-bit version. * Thus, ImageBase needs some special treatement. It will probably work fine assigning one to the * other since this is all declared volatile, but taking now chances, we'll use a temp variable. */ u32 = pOptHdr32->ImageBase; pOptHdr64->ImageBase = u32; } #if 0 /** * Converts a 32-bit load config directory to a 64 bit one. * * @param pOptHdr The load config to convert. */ static void kldrModPEDoLoadConfigConversion(PIMAGE_LOAD_CONFIG_DIRECTORY64 pLoadCfg) { /* volatile everywhere! */ IMAGE_LOAD_CONFIG_DIRECTORY32 volatile *pLoadCfg32 = (IMAGE_LOAD_CONFIG_DIRECTORY32 volatile *)pLoadCfg; IMAGE_LOAD_CONFIG_DIRECTORY64 volatile *pLoadCfg64 = pLoadCfg; KU32 u32; pLoadCfg64->SEHandlerCount = pLoadCfg32->SEHandlerCount; pLoadCfg64->SEHandlerTable = pLoadCfg32->SEHandlerTable; pLoadCfg64->SecurityCookie = pLoadCfg32->SecurityCookie; pLoadCfg64->EditList = pLoadCfg32->EditList; pLoadCfg64->Reserved1 = pLoadCfg32->Reserved1; pLoadCfg64->CSDVersion = pLoadCfg32->CSDVersion; /* (ProcessHeapFlags switched place with ProcessAffinityMask, but we're * more than 16 byte off by now so it doesn't matter.) */ pLoadCfg64->ProcessHeapFlags = pLoadCfg32->ProcessHeapFlags; pLoadCfg64->ProcessAffinityMask = pLoadCfg32->ProcessAffinityMask; pLoadCfg64->VirtualMemoryThreshold = pLoadCfg32->VirtualMemoryThreshold; pLoadCfg64->MaximumAllocationSize = pLoadCfg32->MaximumAllocationSize; pLoadCfg64->LockPrefixTable = pLoadCfg32->LockPrefixTable; pLoadCfg64->DeCommitTotalFreeThreshold = pLoadCfg32->DeCommitTotalFreeThreshold; u32 = pLoadCfg32->DeCommitFreeBlockThreshold; pLoadCfg64->DeCommitFreeBlockThreshold = u32; /* the remainder matches. */ } #endif /** * Internal worker which validates the section headers. */ static int kLdrModPEDoOptionalHeaderValidation(PKLDRMODPE pModPE) { const unsigned fIs32Bit = pModPE->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32); /* the magic */ if ( pModPE->Hdrs.OptionalHeader.Magic != (fIs32Bit ? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC)) return KLDR_ERR_PE_BAD_OPTIONAL_HEADER; /** @todo validate more */ return 0; } /** * Internal worker which validates the section headers. */ static int kLdrModPEDoSectionHeadersValidation(PKLDRMODPE pModPE) { /** @todo validate shdrs */ K_NOREF(pModPE); return 0; } /** @copydoc KLDRMODOPS::pfnDestroy */ static int kldrModPEDestroy(PKLDRMOD pMod) { PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; int rc = 0; KLDRMODPE_ASSERT(!pModPE->pvMapping); if (pMod->pRdr) { rc = kRdrClose(pMod->pRdr); pMod->pRdr = NULL; } pMod->u32Magic = 0; pMod->pOps = NULL; kHlpFree(pModPE); return rc; } /** * Performs the mapping of the image. * * This can be used to do the internal mapping as well as the * user requested mapping. fForReal indicates which is desired. * * @returns 0 on success, non-zero OS or kLdr status code on failure. * @param pModPE The interpreter module instance * @param fForReal If set, do the user mapping. if clear, do the internal mapping. */ static int kldrModPEDoMap(PKLDRMODPE pModPE, unsigned fForReal) { PKLDRMOD pMod = pModPE->pMod; KBOOL fFixed; void *pvBase; int rc; KU32 i; /* * Map it. */ /* fixed image? */ fFixed = fForReal && ( pMod->enmType == KLDRTYPE_EXECUTABLE_FIXED || pMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED); if (!fFixed) pvBase = NULL; else { pvBase = (void *)(KUPTR)pMod->aSegments[0].LinkAddress; if ((KUPTR)pvBase != pMod->aSegments[0].LinkAddress) return KLDR_ERR_ADDRESS_OVERFLOW; } /* try do the prepare */ rc = kRdrMap(pMod->pRdr, &pvBase, pMod->cSegments, pMod->aSegments, fFixed); if (rc) return rc; /* * Update the segments with their map addresses. */ if (fForReal) { for (i = 0; i < pMod->cSegments; i++) { if (pMod->aSegments[i].RVA != NIL_KLDRADDR) pMod->aSegments[i].MapAddress = (KUPTR)pvBase + (KUPTR)pMod->aSegments[i].RVA; } pModPE->pvMapping = pvBase; } else pModPE->pvBits = pvBase; return 0; } /** * Unmaps a image mapping. * * This can be used to do the internal mapping as well as the * user requested mapping. fForReal indicates which is desired. * * @returns 0 on success, non-zero OS or kLdr status code on failure. * @param pModPE The interpreter module instance * @param pvMapping The mapping to unmap. */ static int kldrModPEDoUnmap(PKLDRMODPE pModPE, const void *pvMapping) { PKLDRMOD pMod = pModPE->pMod; int rc; KU32 i; /* * Try unmap the image. */ rc = kRdrUnmap(pMod->pRdr, (void *)pvMapping, pMod->cSegments, pMod->aSegments); if (rc) return rc; /* * Update the segments to reflect that they aren't mapped any longer. */ if (pModPE->pvMapping == pvMapping) { pModPE->pvMapping = NULL; for (i = 0; i < pMod->cSegments; i++) pMod->aSegments[i].MapAddress = 0; } if (pModPE->pvBits == pvMapping) pModPE->pvBits = NULL; return 0; } /** * Gets usable bits and the right base address. * * @returns 0 on success. * @returns A non-zero status code if the BaseAddress isn't right or some problem is encountered * featch in a temp mapping the bits. * @param pModPE The interpreter module instance * @param ppvBits The bits address, IN & OUT. * @param pBaseAddress The base address, IN & OUT. Optional. */ static int kldrModPEBitsAndBaseAddress(PKLDRMODPE pModPE, const void **ppvBits, PKLDRADDR pBaseAddress) { int rc = 0; /* * Correct the base address. * * We don't use the base address for interpreting the bits in this * interpreter, which makes things relativly simple. */ if (pBaseAddress) { if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP) *pBaseAddress = pModPE->pMod->aSegments[0].MapAddress; else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK) *pBaseAddress = pModPE->Hdrs.OptionalHeader.ImageBase; } /* * Get bits. */ if (ppvBits && !*ppvBits) { if (pModPE->pvMapping) *ppvBits = pModPE->pvMapping; else if (pModPE->pvBits) *ppvBits = pModPE->pvBits; else { /* create an internal mapping. */ rc = kldrModPEDoMap(pModPE, 0 /* not for real */); if (rc) return rc; KLDRMODPE_ASSERT(pModPE->pvBits); *ppvBits = pModPE->pvBits; } } return 0; } /** @copydoc kLdrModQuerySymbol */ static int kldrModPEQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind) { PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; const KU32 *paExportRVAs; const IMAGE_EXPORT_DIRECTORY *pExpDir; KU32 iExpOrd; KU32 uRVA; int rc; /* * Make sure we've got mapped bits and resolve any base address aliases. */ rc = kldrModPEBitsAndBaseAddress(pModPE, &pvBits, &BaseAddress); if (rc) return rc; if ( pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size < sizeof(IMAGE_EXPORT_DIRECTORY)) return KLDR_ERR_SYMBOL_NOT_FOUND; if (pszVersion && *pszVersion) return KLDR_ERR_SYMBOL_NOT_FOUND; pExpDir = KLDRMODPE_RVA2TYPE(pvBits, pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress, PIMAGE_EXPORT_DIRECTORY); if (!pchSymbol) { /* * Simple, calculate the unbased ordinal and bounds check it. */ iExpOrd = iSymbol - pExpDir->Base; if (iExpOrd >= K_MAX(pExpDir->NumberOfNames, pExpDir->NumberOfFunctions)) return KLDR_ERR_SYMBOL_NOT_FOUND; } else { /* * Do a binary search for the name. * (The name table is sorted in ascending ordered by the linker.) */ const KU32 *paRVANames = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfNames, const KU32 *); const KU16 *paOrdinals = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfNameOrdinals, const KU16 *); KI32 iStart = 1; /* one based binary searching is simpler. */ KI32 iEnd = pExpDir->NumberOfNames; for (;;) { KI32 i; int diff; const char *pszName; /* done? */ if (iStart > iEnd) { #ifdef KLDRMODPE_STRICT /* Make sure the linker and we both did our job right. */ for (i = 0; i < (KI32)pExpDir->NumberOfNames; i++) { pszName = KLDRMODPE_RVA2TYPE(pvBits, paRVANames[i], const char *); KLDRMODPE_ASSERT(kHlpStrNComp(pszName, pchSymbol, cchSymbol) || pszName[cchSymbol]); KLDRMODPE_ASSERT(i == 0 || kHlpStrComp(pszName, KLDRMODPE_RVA2TYPE(pvBits, paRVANames[i - 1], const char *))); } #endif return KLDR_ERR_SYMBOL_NOT_FOUND; } i = (iEnd - iStart) / 2 + iStart; pszName = KLDRMODPE_RVA2TYPE(pvBits, paRVANames[i - 1], const char *); diff = kHlpStrNComp(pszName, pchSymbol, cchSymbol); if (!diff) diff = pszName[cchSymbol] - 0; if (diff < 0) iStart = i + 1; /* The symbol must be after the current name. */ else if (diff) iEnd = i - 1; /* The symbol must be before the current name. */ else { iExpOrd = paOrdinals[i - 1]; /* match! */ break; } } } /* * Lookup the address in the 'symbol' table. */ paExportRVAs = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfFunctions, const KU32 *); uRVA = paExportRVAs[iExpOrd]; if ( uRVA - pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress < pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size) return kldrModPEDoForwarderQuery(pModPE, pvBits, KLDRMODPE_RVA2TYPE(pvBits, uRVA, const char *), pfnGetForwarder, pvUser, puValue, pfKind); /* * Set the return value. */ if (puValue) *puValue = BaseAddress + uRVA; if (pfKind) *pfKind = (pModPE->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32) ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT) | KLDRSYMKIND_NO_TYPE; return 0; } /** * Deal with a forwarder entry. * * We do this seprately from kldrModPEQuerySymbol because the code is clumsy (as is all PE code * thanks to the descriptive field names), and because it uses quite a bit more stack and we're * trying to avoid allocating stack unless we have to. * * @returns See kLdrModQuerySymbol. * @param pModPE The PE module interpreter instance. * @param pvBits Where to read the image from. * @param pszForwarder The forwarder entry name. * @param pfnGetForwarder The callback for resolving forwarder symbols. (optional) * @param pvUser The user argument for the callback. * @param puValue Where to put the value. (optional) * @param pfKind Where to put the symbol kind. (optional) */ static int kldrModPEDoForwarderQuery(PKLDRMODPE pModPE, const void *pvBits, const char *pszForwarder, PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind) { const IMAGE_IMPORT_DESCRIPTOR *paImpDir; KU32 iImpModule; KU32 cchImpModule; const char *pszSymbol; KU32 iSymbol; int rc; if (!pfnGetForwarder) return KLDR_ERR_FORWARDER_SYMBOL; /* * Separate the name into a module name and a symbol name or ordinal. * * The module name ends at the first dot ('.'). * After the dot follows either a symbol name or a hash ('#') + ordinal. */ pszSymbol = pszForwarder; while (*pszSymbol != '.') pszSymbol++; if (!*pszSymbol) return KLDR_ERR_PE_BAD_FORWARDER; cchImpModule = (KU32)(pszSymbol - pszForwarder); pszSymbol++; /* skip the dot */ if (!*pszSymbol) return KLDR_ERR_PE_BAD_FORWARDER; if (*pszSymbol == '#') { unsigned uBase; pszSymbol++; /* skip the hash */ /* base detection */ uBase = 10; if (pszSymbol[0] == '0' && (pszSymbol[1] == 'x' || pszSymbol[1] == 'X')) { uBase = 16; pszSymbol += 2; } /* ascii to integer */ iSymbol = 0; for (;;) { /* convert char to digit. */ unsigned uDigit = *pszSymbol++; if (uDigit >= '0' && uDigit <= '9') uDigit -= '0'; else if (uDigit >= 'a' && uDigit <= 'z') uDigit -= 'a' + 10; else if (uDigit >= 'A' && uDigit <= 'Z') uDigit -= 'A' + 10; else if (!uDigit) break; else return KLDR_ERR_PE_BAD_FORWARDER; if (uDigit >= uBase) return KLDR_ERR_PE_BAD_FORWARDER; /* insert the digit */ iSymbol *= uBase; iSymbol += uDigit; } pszSymbol = NULL; /* no symbol name. */ } else iSymbol = NIL_KLDRMOD_SYM_ORDINAL; /* no ordinal number. */ /* * Find the import module name. * * We ASSUME the linker will make sure there is an import * entry for the module... not sure if this is right though. */ if ( !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress) return KLDR_ERR_PE_FORWARDER_IMPORT_NOT_FOUND; paImpDir = KLDRMODPE_RVA2TYPE(pvBits, pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, const IMAGE_IMPORT_DESCRIPTOR *); kldrModPENumberOfImports(pModPE->pMod, pvBits); for (iImpModule = 0; iImpModule < pModPE->cImportModules; iImpModule++) { const char *pszName = KLDRMODPE_RVA2TYPE(pvBits, paImpDir[iImpModule].Name, const char *); KSIZE cchName = kHlpStrLen(pszName); if ( ( cchName == cchImpModule || ( cchName > cchImpModule && pszName[cchImpModule] == '.' && (pszName[cchImpModule + 1] == 'd' || pszName[cchImpModule + 1] == 'D') && (pszName[cchImpModule + 2] == 'l' || pszName[cchImpModule + 2] == 'L') && (pszName[cchImpModule + 3] == 'l' || pszName[cchImpModule + 3] == 'L')) ) && kHlpMemICompAscii(pszName, pszForwarder, cchImpModule) ) { /* * Now the rest is up to the callback (almost). */ rc = pfnGetForwarder(pModPE->pMod, iImpModule, iSymbol, pszSymbol, pszSymbol ? kHlpStrLen(pszSymbol) : 0, NULL, puValue, pfKind, pvUser); if (!rc && pfKind) *pfKind |= KLDRSYMKIND_FORWARDER; return rc; } } return KLDR_ERR_PE_FORWARDER_IMPORT_NOT_FOUND; } /** @copydoc kLdrModEnumSymbols */ static int kldrModPEEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser) { PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; const KU32 *paFunctions; const IMAGE_EXPORT_DIRECTORY *pExpDir; const KU32 *paRVANames; const KU16 *paOrdinals; KU32 iFunction; KU32 cFunctions; KU32 cNames; int rc; K_NOREF(fFlags); /* * Make sure we've got mapped bits and resolve any base address aliases. */ rc = kldrModPEBitsAndBaseAddress(pModPE, &pvBits, &BaseAddress); if (rc) return rc; if ( pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size < sizeof(IMAGE_EXPORT_DIRECTORY)) return 0; /* no exports to enumerate, return success. */ pExpDir = KLDRMODPE_RVA2TYPE(pvBits, pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress, PIMAGE_EXPORT_DIRECTORY); /* * Enumerate the ordinal exports. */ paRVANames = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfNames, const KU32 *); paOrdinals = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfNameOrdinals, const KU16 *); paFunctions = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfFunctions, const KU32 *); cFunctions = pExpDir->NumberOfFunctions; cNames = pExpDir->NumberOfNames; for (iFunction = 0; iFunction < cFunctions; iFunction++) { unsigned fFoundName; KU32 iName; const KU32 uRVA = paFunctions[iFunction]; const KLDRADDR uValue = BaseAddress + uRVA; KU32 fKind = (pModPE->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32) ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT) | KLDRSYMKIND_NO_TYPE; if ( uRVA - pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress < pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size) fKind |= KLDRSYMKIND_FORWARDER; /* * Any symbol names? */ fFoundName = 0; for (iName = 0; iName < cNames; iName++) { const char *pszName; if (paOrdinals[iName] != iFunction) continue; fFoundName = 1; pszName = KLDRMODPE_RVA2TYPE(pvBits, paRVANames[iName], const char *); rc = pfnCallback(pMod, iFunction + pExpDir->Base, pszName, kHlpStrLen(pszName), NULL, uValue, fKind, pvUser); if (rc) return rc; } /* * If no names, call once with the ordinal only. */ if (!fFoundName) { rc = pfnCallback(pMod, iFunction + pExpDir->Base, NULL, 0, NULL, uValue, fKind, pvUser); if (rc) return rc; } } return 0; } /** @copydoc kLdrModGetImport */ static int kldrModPEGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName) { PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; const IMAGE_IMPORT_DESCRIPTOR *pImpDesc; const char *pszImportName; KSIZE cchImportName; int rc; /* * Make sure we've got mapped bits and resolve any base address aliases. */ rc = kldrModPEBitsAndBaseAddress(pModPE, &pvBits, NULL); if (rc) return rc; /* * Simple bounds check. */ if (iImport >= (KU32)kldrModPENumberOfImports(pMod, pvBits)) return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS; /* * Get the name. */ pImpDesc = KLDRMODPE_RVA2TYPE(pvBits, pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + sizeof(IMAGE_IMPORT_DESCRIPTOR) * iImport, const IMAGE_IMPORT_DESCRIPTOR *); pszImportName = KLDRMODPE_RVA2TYPE(pvBits, pImpDesc->Name, const char *); cchImportName = kHlpStrLen(pszImportName); if (cchImportName < cchName) { kHlpMemCopy(pszName, pszImportName, cchImportName + 1); rc = 0; } else { kHlpMemCopy(pszName, pszImportName, cchName); if (cchName) pszName[cchName - 1] = '\0'; rc = KERR_BUFFER_OVERFLOW; } return rc; } /** @copydoc kLdrModNumberOfImports */ static KI32 kldrModPENumberOfImports(PKLDRMOD pMod, const void *pvBits) { PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; if (pModPE->cImportModules == ~(KU32)0) { /* * We'll have to walk the import descriptors to figure out their number. * First, make sure we've got mapped bits. */ if (kldrModPEBitsAndBaseAddress(pModPE, &pvBits, NULL)) return -1; pModPE->cImportModules = 0; if ( pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size && pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress) { const IMAGE_IMPORT_DESCRIPTOR *pImpDesc; pImpDesc = KLDRMODPE_RVA2TYPE(pvBits, pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, const IMAGE_IMPORT_DESCRIPTOR *); while (pImpDesc->Name && pImpDesc->FirstThunk) { pModPE->cImportModules++; pImpDesc++; } } } return pModPE->cImportModules; } /** @copydoc kLdrModGetStackInfo */ static int kldrModPEGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo) { PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; K_NOREF(pvBits); K_NOREF(BaseAddress); pStackInfo->Address = NIL_KLDRADDR; pStackInfo->LinkAddress = NIL_KLDRADDR; pStackInfo->cbStack = pStackInfo->cbStackThread = pModPE->Hdrs.OptionalHeader.SizeOfStackReserve; return 0; } /** @copydoc kLdrModQueryMainEntrypoint */ static int kldrModPEQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress) { PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; int rc; K_NOREF(pvBits); /* * Resolve base address alias if any. */ rc = kldrModPEBitsAndBaseAddress(pModPE, NULL, &BaseAddress); if (rc) return rc; /* * Convert the address from the header. */ *pMainEPAddress = pModPE->Hdrs.OptionalHeader.AddressOfEntryPoint ? BaseAddress + pModPE->Hdrs.OptionalHeader.AddressOfEntryPoint : NIL_KLDRADDR; return 0; } /** @copydoc kLdrModEnumDbgInfo */ static int kldrModPEEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser) { PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; const IMAGE_DEBUG_DIRECTORY *pDbgDir; KU32 iDbgInfo; KU32 cb; int rc; /* * Check that there is a debug directory first. */ cb = pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size; if ( cb < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */ || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress) return 0; /* * Make sure we've got mapped bits. */ rc = kldrModPEBitsAndBaseAddress(pModPE, &pvBits, NULL); if (rc) return rc; /* * Enumerate the debug directory. */ pDbgDir = KLDRMODPE_RVA2TYPE(pvBits, pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress, const IMAGE_DEBUG_DIRECTORY *); for (iDbgInfo = 0;; iDbgInfo++, pDbgDir++, cb -= sizeof(IMAGE_DEBUG_DIRECTORY)) { KLDRDBGINFOTYPE enmDbgInfoType; /* convert the type. */ switch (pDbgDir->Type) { case IMAGE_DEBUG_TYPE_UNKNOWN: case IMAGE_DEBUG_TYPE_FPO: case IMAGE_DEBUG_TYPE_COFF: /*stabs dialect??*/ case IMAGE_DEBUG_TYPE_MISC: case IMAGE_DEBUG_TYPE_EXCEPTION: case IMAGE_DEBUG_TYPE_FIXUP: case IMAGE_DEBUG_TYPE_BORLAND: default: enmDbgInfoType = KLDRDBGINFOTYPE_UNKNOWN; break; case IMAGE_DEBUG_TYPE_CODEVIEW: enmDbgInfoType = KLDRDBGINFOTYPE_CODEVIEW; break; } rc = pfnCallback(pMod, iDbgInfo, enmDbgInfoType, pDbgDir->MajorVersion, pDbgDir->MinorVersion, NULL, pDbgDir->PointerToRawData ? (KLDRFOFF)pDbgDir->PointerToRawData : -1, pDbgDir->AddressOfRawData ? pDbgDir->AddressOfRawData : NIL_KLDRADDR, pDbgDir->SizeOfData, NULL, pvUser); if (rc) break; /* next */ if (cb <= sizeof(IMAGE_DEBUG_DIRECTORY)) break; } return rc; } /** @copydoc kLdrModHasDbgInfo */ static int kldrModPEHasDbgInfo(PKLDRMOD pMod, const void *pvBits) { PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; K_NOREF(pvBits); /* * Base this entirely on the presence of a debug directory. */ if ( pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */ || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress) return KLDR_ERR_NO_DEBUG_INFO; return 0; } /** @copydoc kLdrModMap */ static int kldrModPEMap(PKLDRMOD pMod) { PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; int rc; /* * Already mapped? */ if (pModPE->pvMapping) return KLDR_ERR_ALREADY_MAPPED; /* * We've got a common worker which does this. */ rc = kldrModPEDoMap(pModPE, 1 /* the real thing */); if (rc) return rc; KLDRMODPE_ASSERT(pModPE->pvMapping); return 0; } /** @copydoc kLdrModUnmap */ static int kldrModPEUnmap(PKLDRMOD pMod) { PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; int rc; /* * Mapped? */ if (!pModPE->pvMapping) return KLDR_ERR_NOT_MAPPED; /* * We've got a common worker which does this. */ rc = kldrModPEDoUnmap(pModPE, pModPE->pvMapping); if (rc) return rc; KLDRMODPE_ASSERT(!pModPE->pvMapping); return 0; } /** @copydoc kLdrModAllocTLS */ static int kldrModPEAllocTLS(PKLDRMOD pMod, void *pvMapping) { PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; /* * Mapped? */ if (pvMapping == KLDRMOD_INT_MAP) { pvMapping = (void *)pModPE->pvMapping; if (!pvMapping) return KLDR_ERR_NOT_MAPPED; } /* * If no TLS directory then there is nothing to do. */ if ( !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress) return 0; /** @todo implement TLS. */ return -1; } /** @copydoc kLdrModFreeTLS */ static void kldrModPEFreeTLS(PKLDRMOD pMod, void *pvMapping) { PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; /* * Mapped? */ if (pvMapping == KLDRMOD_INT_MAP) { pvMapping = (void *)pModPE->pvMapping; if (!pvMapping) return; } /* * If no TLS directory then there is nothing to do. */ if ( !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress) return; /** @todo implement TLS. */ return; } /** @copydoc kLdrModReload */ static int kldrModPEReload(PKLDRMOD pMod) { PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; /* * Mapped? */ if (!pModPE->pvMapping) return KLDR_ERR_NOT_MAPPED; /* the file provider does it all */ return kRdrRefresh(pMod->pRdr, (void *)pModPE->pvMapping, pMod->cSegments, pMod->aSegments); } /** @copydoc kLdrModFixupMapping */ static int kldrModPEFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) { PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; int rc, rc2; /* * Mapped? */ if (!pModPE->pvMapping) return KLDR_ERR_NOT_MAPPED; /* * Before doing anything we'll have to make all pages writable. */ rc = kRdrProtect(pMod->pRdr, (void *)pModPE->pvMapping, pMod->cSegments, pMod->aSegments, 1 /* unprotect */); if (rc) return rc; /* * Apply base relocations. */ rc = kldrModPEDoFixups(pModPE, (void *)pModPE->pvMapping, (KUPTR)pModPE->pvMapping, pModPE->Hdrs.OptionalHeader.ImageBase); /* * Resolve imports. */ if (!rc) rc = kldrModPEDoImports(pModPE, (void *)pModPE->pvMapping, pfnGetImport, pvUser); /* * Restore protection. */ rc2 = kRdrProtect(pMod->pRdr, (void *)pModPE->pvMapping, pMod->cSegments, pMod->aSegments, 0 /* protect */); if (!rc && rc2) rc = rc2; return rc; } /** * Applies base relocations to a (unprotected) image mapping. * * @returns 0 on success, non-zero kLdr status code on failure. * @param pModPE The PE module interpreter instance. * @param pvMapping The mapping to fixup. * @param NewBaseAddress The address to fixup the mapping to. * @param OldBaseAddress The address the mapping is currently fixed up to. */ static int kldrModPEDoFixups(PKLDRMODPE pModPE, void *pvMapping, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress) { const KLDRADDR Delta = NewBaseAddress - OldBaseAddress; KU32 cbLeft = pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; const IMAGE_BASE_RELOCATION *pBR, *pFirstBR; /* * Don't don anything if the delta is 0 or there aren't any relocations. */ if ( !Delta || !cbLeft || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress) return 0; /* * Process the fixups block by block. * (These blocks appears to be 4KB on all archs despite the native page size.) */ pBR = pFirstBR = KLDRMODPE_RVA2TYPE(pvMapping, pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress, const IMAGE_BASE_RELOCATION *); while ( cbLeft > sizeof(IMAGE_BASE_RELOCATION) && pBR->SizeOfBlock >= sizeof(IMAGE_BASE_RELOCATION) /* paranoia */) { union { KU8 *pu8; KU16 *pu16; KU32 *pu32; KU64 *pu64; } uChunk, u; const KU16 *poffFixup = (const KU16 *)(pBR + 1); const KU32 cbBlock = K_MIN(cbLeft, pBR->SizeOfBlock) - sizeof(IMAGE_BASE_RELOCATION); /* more caution... */ KU32 cFixups = cbBlock / sizeof(poffFixup[0]); uChunk.pu8 = KLDRMODPE_RVA2TYPE(pvMapping, pBR->VirtualAddress, KU8 *); /* * Loop thru the fixups in this chunk. */ while (cFixups > 0) { u.pu8 = uChunk.pu8 + (*poffFixup & 0xfff); switch (*poffFixup >> 12) /* ordered by value. */ { /* 0 - Alignment placeholder. */ case IMAGE_REL_BASED_ABSOLUTE: break; /* 1 - 16-bit, add 2nd 16-bit part of the delta. (rare) */ case IMAGE_REL_BASED_HIGH: *u.pu16 += (KU16)(Delta >> 16); break; /* 2 - 16-bit, add 1st 16-bit part of the delta. (rare) */ case IMAGE_REL_BASED_LOW: *u.pu16 += (KU16)Delta; break; /* 3 - 32-bit, add delta. (frequent in 32-bit images) */ case IMAGE_REL_BASED_HIGHLOW: *u.pu32 += (KU32)Delta; break; /* 4 - 16-bit, add 2nd 16-bit of the delta, sign adjust for the lower 16-bit. one arg. (rare) */ case IMAGE_REL_BASED_HIGHADJ: { KI32 i32; if (cFixups <= 1) return KLDR_ERR_PE_BAD_FIXUP; i32 = (KU32)*u.pu16 << 16; i32 |= *++poffFixup; cFixups--; /* the addend argument */ i32 += (KU32)Delta; i32 += 0x8000; *u.pu16 = (KU16)(i32 >> 16); break; } /* 5 - 32-bit MIPS JMPADDR, no implemented. */ case IMAGE_REL_BASED_MIPS_JMPADDR: *u.pu32 = (*u.pu32 & 0xc0000000) | ((KU32)((*u.pu32 << 2) + (KU32)Delta) >> 2); break; /* 6 - Intra section? Reserved value in later specs. Not implemented. */ case IMAGE_REL_BASED_SECTION: KLDRMODPE_ASSERT(!"SECTION"); return KLDR_ERR_PE_BAD_FIXUP; /* 7 - Relative intra section? Reserved value in later specs. Not implemented. */ case IMAGE_REL_BASED_REL32: KLDRMODPE_ASSERT(!"SECTION"); return KLDR_ERR_PE_BAD_FIXUP; /* 8 - reserved according to binutils... */ case 8: KLDRMODPE_ASSERT(!"RESERVERED8"); return KLDR_ERR_PE_BAD_FIXUP; /* 9 - IA64_IMM64 (/ MIPS_JMPADDR16), no specs nor need to support the platform yet. * Bet this requires more code than all the other fixups put together in good IA64 spirit :-) */ case IMAGE_REL_BASED_IA64_IMM64: KLDRMODPE_ASSERT(!"IA64_IMM64 / MIPS_JMPADDR16"); return KLDR_ERR_PE_BAD_FIXUP; /* 10 - 64-bit, add delta. (frequently in 64-bit images) */ case IMAGE_REL_BASED_DIR64: *u.pu64 += (KU64)Delta; break; /* 11 - 16-bit, add 3rd 16-bit of the delta, sign adjust for the lower 32-bit. two args. (rare) */ case IMAGE_REL_BASED_HIGH3ADJ: { KI64 i64; if (cFixups <= 2) return KLDR_ERR_PE_BAD_FIXUP; i64 = (KU64)*u.pu16 << 32 | ((KU32)poffFixup[2] << 16) | poffFixup[1]; i64 += Delta; i64 += 0x80008000UL; *u.pu16 = (KU16)(i64 >> 32); /* skip the addends arguments */ poffFixup += 2; cFixups -= 2; break; } /* the rest are yet to be defined.*/ default: return KLDR_ERR_PE_BAD_FIXUP; } /* * Next relocation. */ poffFixup++; cFixups--; } /* * Next block. */ cbLeft -= pBR->SizeOfBlock; pBR = (PIMAGE_BASE_RELOCATION)((KUPTR)pBR + pBR->SizeOfBlock); } return 0; } /** * Resolves imports. * * @returns 0 on success, non-zero kLdr status code on failure. * @param pModPE The PE module interpreter instance. * @param pvMapping The mapping which imports should be resolved. * @param pfnGetImport The callback for resolving an imported symbol. * @param pvUser User argument to the callback. */ static int kldrModPEDoImports(PKLDRMODPE pModPE, void *pvMapping, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) { const IMAGE_IMPORT_DESCRIPTOR *pImpDesc; /* * If no imports, there is nothing to do. */ kldrModPENumberOfImports(pModPE->pMod, pvMapping); if (!pModPE->cImportModules) return 0; pImpDesc = KLDRMODPE_RVA2TYPE(pvMapping, pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, const IMAGE_IMPORT_DESCRIPTOR *); if (pModPE->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)) return kldrModPEDoImports32Bit(pModPE, pvMapping, pImpDesc, pfnGetImport, pvUser); return kldrModPEDoImports64Bit(pModPE, pvMapping, pImpDesc, pfnGetImport, pvUser); } /** * Resolves imports, 32-bit image. * * @returns 0 on success, non-zero kLdr status code on failure. * @param pModPE The PE module interpreter instance. * @param pvMapping The mapping which imports should be resolved. * @param pImpDesc Pointer to the first import descriptor. * @param pfnGetImport The callback for resolving an imported symbol. * @param pvUser User argument to the callback. */ static int kldrModPEDoImports32Bit(PKLDRMODPE pModPE, void *pvMapping, const IMAGE_IMPORT_DESCRIPTOR *pImpDesc, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) { PKLDRMOD pMod = pModPE->pMod; KU32 iImp; /* * Iterate the import descriptors. */ for (iImp = 0; iImp < pModPE->cImportModules; iImp++, pImpDesc++) { PIMAGE_THUNK_DATA32 pFirstThunk = KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->FirstThunk, PIMAGE_THUNK_DATA32); const IMAGE_THUNK_DATA32 *pThunk = pImpDesc->u.OriginalFirstThunk ? KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->u.OriginalFirstThunk, const IMAGE_THUNK_DATA32 *) : KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->FirstThunk, const IMAGE_THUNK_DATA32 *); /* Iterate the thunks. */ while (pThunk->u1.Ordinal != 0) { KLDRADDR Value; KU32 fKind = KLDRSYMKIND_REQ_FLAT; int rc; /* Ordinal or name import? */ if (IMAGE_SNAP_BY_ORDINAL32(pThunk->u1.Ordinal)) rc = pfnGetImport(pMod, iImp, IMAGE_ORDINAL32(pThunk->u1.Ordinal), NULL, 0, NULL, &Value, &fKind, pvUser); else if (KLDRMODPE_VALID_RVA(pModPE, pThunk->u1.Ordinal)) { const IMAGE_IMPORT_BY_NAME *pName = KLDRMODPE_RVA2TYPE(pvMapping, pThunk->u1.Ordinal, const IMAGE_IMPORT_BY_NAME *); rc = pfnGetImport(pMod, iImp, NIL_KLDRMOD_SYM_ORDINAL, (const char *)pName->Name, kHlpStrLen((const char *)pName->Name), NULL, &Value, &fKind, pvUser); } else { KLDRMODPE_ASSERT(!"bad 32-bit import"); return KLDR_ERR_PE_BAD_IMPORT; } if (rc) return rc; /* Apply it. */ pFirstThunk->u1.Function = (KU32)Value; if (pFirstThunk->u1.Function != Value) { KLDRMODPE_ASSERT(!"overflow"); return KLDR_ERR_ADDRESS_OVERFLOW; } /* next */ pThunk++; pFirstThunk++; } } return 0; } /** * Resolves imports, 64-bit image. * * @returns 0 on success, non-zero kLdr status code on failure. * @param pModPE The PE module interpreter instance. * @param pvMapping The mapping which imports should be resolved. * @param pImpDesc Pointer to the first import descriptor. * @param pfnGetImport The callback for resolving an imported symbol. * @param pvUser User argument to the callback. */ static int kldrModPEDoImports64Bit(PKLDRMODPE pModPE, void *pvMapping, const IMAGE_IMPORT_DESCRIPTOR *pImpDesc, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) { PKLDRMOD pMod = pModPE->pMod; KU32 iImp; /* * Iterate the import descriptors. */ for (iImp = 0; iImp < pModPE->cImportModules; iImp++, pImpDesc++) { PIMAGE_THUNK_DATA64 pFirstThunk = KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->FirstThunk, PIMAGE_THUNK_DATA64); const IMAGE_THUNK_DATA64 *pThunk = pImpDesc->u.OriginalFirstThunk ? KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->u.OriginalFirstThunk, const IMAGE_THUNK_DATA64 *) : KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->FirstThunk, const IMAGE_THUNK_DATA64 *); /* Iterate the thunks. */ while (pThunk->u1.Ordinal != 0) { KLDRADDR Value; KU32 fKind = KLDRSYMKIND_REQ_FLAT; int rc; /* Ordinal or name import? */ if (IMAGE_SNAP_BY_ORDINAL64(pThunk->u1.Ordinal)) rc = pfnGetImport(pMod, iImp, (KU32)IMAGE_ORDINAL64(pThunk->u1.Ordinal), NULL, 0, NULL, &Value, &fKind, pvUser); else if (KLDRMODPE_VALID_RVA(pModPE, pThunk->u1.Ordinal)) { const IMAGE_IMPORT_BY_NAME *pName = KLDRMODPE_RVA2TYPE(pvMapping, pThunk->u1.Ordinal, const IMAGE_IMPORT_BY_NAME *); rc = pfnGetImport(pMod, iImp, NIL_KLDRMOD_SYM_ORDINAL, (const char *)pName->Name, kHlpStrLen((const char *)pName->Name), NULL, &Value, &fKind, pvUser); } else { KLDRMODPE_ASSERT(!"bad 64-bit import"); return KLDR_ERR_PE_BAD_IMPORT; } if (rc) return rc; /* Apply it. */ pFirstThunk->u1.Function = Value; /* next */ pThunk++; pFirstThunk++; } } return 0; } /** @copydoc kLdrModCallInit */ static int kldrModPECallInit(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle) { PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; int rc; /* * Mapped? */ if (pvMapping == KLDRMOD_INT_MAP) { pvMapping = (void *)pModPE->pvMapping; if (!pvMapping) return KLDR_ERR_NOT_MAPPED; } /* * Do TLS callbacks first and then call the init/term function if it's a DLL. */ rc = kldrModPEDoCallTLS(pModPE, pvMapping, DLL_PROCESS_ATTACH, uHandle); if ( !rc && (pModPE->Hdrs.FileHeader.Characteristics & IMAGE_FILE_DLL)) { rc = kldrModPEDoCallDLL(pModPE, pvMapping, DLL_PROCESS_ATTACH, uHandle); if (rc) kldrModPEDoCallTLS(pModPE, pvMapping, DLL_PROCESS_DETACH, uHandle); } return rc; } /** * Call the DLL entrypoint. * * @returns 0 on success. * @returns KLDR_ERR_MODULE_INIT_FAILED or KLDR_ERR_THREAD_ATTACH_FAILED on failure. * @param pModPE The PE module interpreter instance. * @param pvMapping The module mapping to use (resolved). * @param uOp The operation (DLL_*). * @param uHandle The module handle to present. */ static int kldrModPEDoCallDLL(PKLDRMODPE pModPE, void *pvMapping, unsigned uOp, KUPTR uHandle) { int rc; /* * If no entrypoint there isn't anything to be done. */ if (!pModPE->Hdrs.OptionalHeader.AddressOfEntryPoint) return 0; /* * Invoke the entrypoint and convert the boolean result to a kLdr status code. */ rc = kldrModPEDoCall((KUPTR)pvMapping + pModPE->Hdrs.OptionalHeader.AddressOfEntryPoint, uHandle, uOp, NULL); if (rc) rc = 0; else if (uOp == DLL_PROCESS_ATTACH) rc = KLDR_ERR_MODULE_INIT_FAILED; else if (uOp == DLL_THREAD_ATTACH) rc = KLDR_ERR_THREAD_ATTACH_FAILED; else /* detach: ignore failures */ rc = 0; return rc; } /** * Call the TLS entrypoints. * * @returns 0 on success. * @returns KLDR_ERR_THREAD_ATTACH_FAILED on failure. * @param pModPE The PE module interpreter instance. * @param pvMapping The module mapping to use (resolved). * @param uOp The operation (DLL_*). * @param uHandle The module handle to present. */ static int kldrModPEDoCallTLS(PKLDRMODPE pModPE, void *pvMapping, unsigned uOp, KUPTR uHandle) { /** @todo implement TLS support. */ K_NOREF(pModPE); K_NOREF(pvMapping); K_NOREF(uOp); K_NOREF(uHandle); return 0; } /** * Do a 3 parameter callback. * * @returns 32-bit callback return. * @param uEntrypoint The address of the function to be called. * @param uHandle The first argument, the module handle. * @param uOp The second argumnet, the reason we're calling. * @param pvReserved The third argument, reserved argument. (figure this one out) */ static KI32 kldrModPEDoCall(KUPTR uEntrypoint, KUPTR uHandle, KU32 uOp, void *pvReserved) { KI32 rc; /** @todo try/except */ #if defined(__X86__) || defined(__i386__) || defined(_M_IX86) /* * Be very careful. * Not everyone will have got the calling convention right. */ # ifdef __GNUC__ __asm__ __volatile__( "pushl %2\n\t" "pushl %1\n\t" "pushl %0\n\t" "lea 12(%%esp), %2\n\t" "call *%3\n\t" "movl %2, %%esp\n\t" : "=a" (rc) : "d" (uOp), "S" (0), "c" (uEntrypoint), "0" (uHandle)); # elif defined(_MSC_VER) __asm { mov eax, [uHandle] mov edx, [uOp] mov ecx, 0 mov ebx, [uEntrypoint] push edi mov edi, esp push ecx push edx push eax call ebx mov esp, edi pop edi mov [rc], eax } # else # error "port me!" # endif #elif defined(__AMD64__) || defined(__x86_64__) || defined(_M_IX86) /* * For now, let's just get the work done... */ /** @todo Deal with GCC / MSC differences in some sensible way. */ int (*pfn)(KUPTR uHandle, KU32 uOp, void *pvReserved); pfn = (int (*)(KUPTR uHandle, KU32 uOp, void *pvReserved))uEntrypoint; rc = pfn(uHandle, uOp, NULL); #else # error "port me" #endif K_NOREF(pvReserved); return rc; } /** @copydoc kLdrModCallTerm */ static int kldrModPECallTerm(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle) { PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; /* * Mapped? */ if (pvMapping == KLDRMOD_INT_MAP) { pvMapping = (void *)pModPE->pvMapping; if (!pvMapping) return KLDR_ERR_NOT_MAPPED; } /* * Do TLS callbacks first. */ kldrModPEDoCallTLS(pModPE, pvMapping, DLL_PROCESS_DETACH, uHandle); if (pModPE->Hdrs.FileHeader.Characteristics & IMAGE_FILE_DLL) kldrModPEDoCallDLL(pModPE, pvMapping, DLL_PROCESS_DETACH, uHandle); return 0; } /** @copydoc kLdrModCallThread */ static int kldrModPECallThread(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle, unsigned fAttachingOrDetaching) { PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; unsigned uOp = fAttachingOrDetaching ? DLL_THREAD_ATTACH : DLL_THREAD_DETACH; int rc; /* * Mapped? */ if (pvMapping == KLDRMOD_INT_MAP) { pvMapping = (void *)pModPE->pvMapping; if (!pvMapping) return KLDR_ERR_NOT_MAPPED; } /* * Do TLS callbacks first and then call the init/term function if it's a DLL. */ rc = kldrModPEDoCallTLS(pModPE, pvMapping, uOp, uHandle); if (!fAttachingOrDetaching) rc = 0; if ( !rc && (pModPE->Hdrs.FileHeader.Characteristics & IMAGE_FILE_DLL)) { rc = kldrModPEDoCallDLL(pModPE, pvMapping, uOp, uHandle); if (!fAttachingOrDetaching) rc = 0; if (rc) kldrModPEDoCallTLS(pModPE, pvMapping, uOp, uHandle); } return rc; } /** @copydoc kLdrModSize */ static KLDRADDR kldrModPESize(PKLDRMOD pMod) { PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; return pModPE->Hdrs.OptionalHeader.SizeOfImage; } /** @copydoc kLdrModGetBits */ static int kldrModPEGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) { PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; KU32 i; int rc; /* * Zero the entire buffer first to simplify things. */ kHlpMemSet(pvBits, 0, pModPE->Hdrs.OptionalHeader.SizeOfImage); /* * Iterate the segments and read the data within them. */ for (i = 0; i < pMod->cSegments; i++) { /* skip it? */ if ( pMod->aSegments[i].cbFile == -1 || pMod->aSegments[i].offFile == -1 || pMod->aSegments[i].LinkAddress == NIL_KLDRADDR || !pMod->aSegments[i].Alignment) continue; rc = kRdrRead(pMod->pRdr, (KU8 *)pvBits + (pMod->aSegments[i].LinkAddress - pModPE->Hdrs.OptionalHeader.ImageBase), pMod->aSegments[i].cbFile, pMod->aSegments[i].offFile); if (rc) return rc; } /* * Perform relocations. */ return kldrModPERelocateBits(pMod, pvBits, BaseAddress, pModPE->Hdrs.OptionalHeader.ImageBase, pfnGetImport, pvUser); } /** @copydoc kLdrModRelocateBits */ static int kldrModPERelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) { PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData; int rc; /* * Call workers to do the jobs. */ rc = kldrModPEDoFixups(pModPE, pvBits, NewBaseAddress, OldBaseAddress); if (!rc) rc = kldrModPEDoImports(pModPE, pvBits, pfnGetImport, pvUser); return rc; } /** * The PE module interpreter method table. */ KLDRMODOPS g_kLdrModPEOps = { "PE", NULL, kldrModPECreate, kldrModPEDestroy, kldrModPEQuerySymbol, kldrModPEEnumSymbols, kldrModPEGetImport, kldrModPENumberOfImports, NULL /* can execute one is optional */, kldrModPEGetStackInfo, kldrModPEQueryMainEntrypoint, NULL /* pfnQueryImageUuid */, NULL, /** @todo resources */ NULL, /** @todo resources */ kldrModPEEnumDbgInfo, kldrModPEHasDbgInfo, kldrModPEMap, kldrModPEUnmap, kldrModPEAllocTLS, kldrModPEFreeTLS, kldrModPEReload, kldrModPEFixupMapping, kldrModPECallInit, kldrModPECallTerm, kldrModPECallThread, kldrModPESize, kldrModPEGetBits, kldrModPERelocateBits, NULL, /** @todo mostly done */ 42 /* the end */ }; kbuild-3149/src/lib/kStuff/kLdr/kLdr-os2.c0000644000175000017500000000377513252530254020155 0ustar locutuslocutus/* $Id: kLdr-os2.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - The Dynamic Loader, OS/2 Specifics. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #define INCL_BASE #include #include #include "kLdrInternal.h" /** * The DLL main function. * * @returns TRUE / FALSE. * @param hmod The dll handle. * @param fFlags Flags. */ ULONG _System _DLL_InitTerm(HMODULE hmod, ULONG fFlags) { switch (fFlags) { case 0: { int rc = kldrInit(); return rc == 0; } case 1: kldrTerm(); return TRUE; default: return FALSE; } } kbuild-3149/src/lib/kStuff/kLdr/kLdr.c0000644000175000017500000001045313252530254017443 0ustar locutuslocutus/* $Id: kLdr.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - The Dynamic Loader. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /** @mainpage kLdr - The Dynamic Loader * * The purpose of kLdr is to provide a generic interface for querying * information about and loading executable image modules. * * kLdr defines the term executable image to include all kinds of files that contains * binary code that can be executed on a CPU - linker objects (OBJs/Os), shared * objects (SOs), dynamic link libraries (DLLs), executables (EXEs), and all kinds * of kernel modules / device drivers (SYSs). * * kLdr provides two types of services: * -# Inspect or/and load individual modules (kLdrMod). * -# Work as a dynamic loader - construct and maintain an address space (kLdrDy). * * The kLdrMod API works on KLDRMOD structures where all the internals are exposed, while * the kLdrDy API works opque KLDRDY structures. KLDRDY are in reality simple wrappers * around KLDRMOD with some extra linking and attributes. * */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include "kLdrInternal.h" /******************************************************************************* * Global Variables * *******************************************************************************/ /** Flag indicating whether we've initialized the loader or not. * * 0 if not initialized. * -1 if we're initializing or terminating. * 1 if we've successfully initialized it. * -2 if initialization failed. */ static int volatile g_fInitialized; /** * Initializes the loader. * @returns 0 on success, non-zero OS status code on failure. */ int kldrInit(void) { int rc; /* check we're already good. */ if (g_fInitialized == 1) return 0; /* a tiny serialization effort. */ for (;;) { if (g_fInitialized == 1) return 0; if (g_fInitialized == -2) return -1; /** @todo atomic test and set if we care. */ if (g_fInitialized == 0) { g_fInitialized = -1; break; } kHlpSleep(1); } /* * Do the initialization. */ rc = kHlpHeapInit(); if (!rc) { rc = kLdrDyldSemInit(); if (!rc) { rc = kldrDyldInit(); if (!rc) { g_fInitialized = 1; return 0; } kLdrDyldSemTerm(); } kHlpHeapTerm(); } g_fInitialized = -2; return rc; } /** * Terminates the loader. */ void kldrTerm(void) { /* can't terminate unless it's initialized. */ if (g_fInitialized != 1) return; g_fInitialized = -1; /* * Do the termination. */ kLdrDyldSemTerm(); kHlpHeapTerm(); /* done */ g_fInitialized = 0; } kbuild-3149/src/lib/kStuff/kLdr/kLdrExeStub-os2A.asm0000644000175000017500000000263513252530254022106 0ustar locutuslocutus; $Id: kLdrExeStub-os2A.asm 29 2009-07-01 20:30:29Z bird $ ;; @file ; kLdr - OS/2 Loader Stub, entry point thingy... ; ; ; Copyright (c) 2006-2007 Knut St. Osmundsen ; ; 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. ; segment TEXT32 public CLASS=CODE align=16 use32 extern OS2Main ..start: jmp OS2Main segment DATA32 stack CLASS=DATA align=16 use32 global WEAK$ZERO WEAK$ZERO EQU 0 kbuild-3149/src/lib/kStuff/kLdr/kLdrA-os2.asm0000644000175000017500000000374513252530253020610 0ustar locutuslocutus; $Id: kLdrA-os2.asm 29 2009-07-01 20:30:29Z bird $ ;; @file ; kLdr - The Dynamic Loader, OS/2 Assembly Helpers. ; ; ; Copyright (c) 2006-2007 Knut St. Osmundsen ; ; 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. ; segment TEXT32 public align=16 CLASS=CODE use32 ; ; _DLL_InitTerm ; ..start: extern _DLL_InitTerm jmp _DLL_InitTerm ; ; kLdrLoadExe wrapper which loads the bootstrap stack. ; global _kLdrDyldLoadExe _kLdrDyldLoadExe: push ebp mov ebp, esp ; switch stack. ; extern _abStack ; lea esp, [_abStack + 8192 - 4] push dword [ebp + 8 + 20] push dword [ebp + 8 + 16] push dword [ebp + 8 + 12] push dword [ebp + 8 + 8] ; call worker on the new stack. extern _kldrDyldLoadExe call _kldrDyldLoadExe ; we shouldn't return! we_re_not_supposed_to_get_here: int3 int3 jmp short we_re_not_supposed_to_get_here kbuild-3149/src/lib/kStuff/kLdr/tstkLdrMod.c0000644000175000017500000005531513252530253020643 0ustar locutuslocutus/* $Id: tstkLdrMod.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - Module interpreter testcase. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #include #include #include #include /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** The default base address used in the tests. */ #define MY_BASEADDRESS 0x2400000 /******************************************************************************* * Global Variables * *******************************************************************************/ /** The numbers of errors. */ static int g_cErrors = 0; /** * Report failure. */ static int Failure(const char *pszFormat, ...) { va_list va; g_cErrors++; printf("tstLdrMod: "); va_start(va, pszFormat); vprintf(pszFormat, va); va_end(va); printf("\n"); return 1; } /** Dummy import resolver callback. */ static int BasicTestsGetImport(PKLDRMOD pMod, KU32 iImport, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, PKLDRADDR puValue, KU32 *pfKind, void *pvUser) { *puValue = 0xdeadface; *pfKind = KLDRSYMKIND_NO_BIT | KLDRSYMKIND_NO_TYPE; return 0; } /** * Verbose memcmp(). */ static int TestMemComp(const void *pv1, const void *pv2, KSIZE cb) { KSIZE off; const KU8 *pb1 = (const KU8 *)pv1; const KU8 *pb2 = (const KU8 *)pv2; if (!memcmp(pb1, pb2, cb)) return 0; printf("Mismatching blocks pv1=%p pv2=%p cb=%#x:\n", pv1, pv2, cb); for (off = 0; off < cb; off++) { if (pb1[off] == pb2[off]) continue; printf("%08x %02x != %02x\n", off, pb1[off], pb2[off]); } return memcmp(pb1, pb2, cb); /* lazy */ } /** * Performs basic relocation tests. */ static int BasicTestsRelocate(PKLDRMOD pMod, void *pvBits, void *pvBits2) { const KSIZE cbImage = (KSIZE)kLdrModSize(pMod); int rc; printf("* Relocation test...\n"); /* * Get the same bits again to check that we get the same result. */ memset(pvBits2, 0xfe, cbImage); rc = kLdrModGetBits(pMod, pvBits2, (KUPTR)pvBits, BasicTestsGetImport, NULL); if (rc) return Failure("failed to get image bits, rc=%d (%s) (a)", rc, kErrName(rc)); if (TestMemComp(pvBits2, pvBits, cbImage)) return Failure("relocation test failed, mismatching bits (a)"); /* * Short relocation round trip. */ rc = kLdrModRelocateBits(pMod, pvBits2, 0x1000, (KUPTR)pvBits, BasicTestsGetImport, NULL); if (rc) return Failure("failed to relocate, rc=%d (%s) (b1)", rc, kErrName(rc)); rc = kLdrModRelocateBits(pMod, pvBits2, (KUPTR)pvBits, 0x1000, BasicTestsGetImport, NULL); if (rc) return Failure("failed to relocate, rc=%d (%s) (b2)", rc, kErrName(rc)); if (TestMemComp(pvBits2, pvBits, cbImage)) return Failure("relocation test failed, mismatching bits (b)"); /* * Longer trip where we also check the intermediate results. */ /* stage one */ rc = kLdrModRelocateBits(pMod, pvBits, 0x1000000, (KUPTR)pvBits, BasicTestsGetImport, NULL); if (rc) return Failure("failed to relocate, rc=%d (%s) (c1)", rc, kErrName(rc)); memset(pvBits2, 0xfe, cbImage); rc = kLdrModGetBits(pMod, pvBits2, 0x1000000, BasicTestsGetImport, NULL); if (rc) return Failure("failed to get image bits, rc=%d (%s) (c1)", rc, kErrName(rc)); if (TestMemComp(pvBits2, pvBits, cbImage)) return Failure("relocation test failed, mismatching bits (c1)"); /* stage two */ rc = kLdrModRelocateBits(pMod, pvBits, ~(KUPTR)0x1010000, 0x1000000, BasicTestsGetImport, NULL); if (rc) return Failure("failed to relocate, rc=%d (%s) (c2)", rc, kErrName(rc)); memset(pvBits2, 0xef, cbImage); rc = kLdrModGetBits(pMod, pvBits2, ~(KUPTR)0x1010000, BasicTestsGetImport, NULL); if (rc) return Failure("failed to get image bits, rc=%d (%s) (c2)", rc, kErrName(rc)); if (TestMemComp(pvBits2, pvBits, cbImage)) return Failure("relocation test failed, mismatching bits (c2)"); /* stage three */ rc = kLdrModRelocateBits(pMod, pvBits, MY_BASEADDRESS, ~(KUPTR)0x1010000, BasicTestsGetImport, NULL); if (rc) return Failure("failed to relocate, rc=%d (%s) (c3)", rc, kErrName(rc)); memset(pvBits2, 0xef, cbImage); rc = kLdrModGetBits(pMod, pvBits2, MY_BASEADDRESS, BasicTestsGetImport, NULL); if (rc) return Failure("failed to get image bits, rc=%d (%s) (c3)", rc, kErrName(rc)); if (TestMemComp(pvBits2, pvBits, cbImage)) return Failure("relocation test failed, mismatching bits (c3)"); /* stage four */ rc = kLdrModRelocateBits(pMod, pvBits, ~(KUPTR)0 / 2 - 0x10000, MY_BASEADDRESS, BasicTestsGetImport, NULL); if (rc) return Failure("failed to relocate, rc=%d %(s) (c4)", rc, kErrName(rc)); memset(pvBits2, 0xdc, cbImage); rc = kLdrModGetBits(pMod, pvBits2, ~(KUPTR)0 / 2 - 0x10000, BasicTestsGetImport, NULL); if (rc) return Failure("failed to get image bits, rc=%d (%s) (c4)", rc, kErrName(rc)); if (TestMemComp(pvBits2, pvBits, cbImage)) return Failure("relocation test failed, mismatching bits (c4)"); /* return */ rc = kLdrModRelocateBits(pMod, pvBits, (KUPTR)pvBits, ~(KUPTR)0 / 2 - 0x10000, BasicTestsGetImport, NULL); if (rc) return Failure("failed to relocate, rc=%d (%s) (c5)", rc, kErrName(rc)); memset(pvBits2, 0xcd, cbImage); rc = kLdrModGetBits(pMod, pvBits2, (KUPTR)pvBits, BasicTestsGetImport, NULL); if (rc) return Failure("failed to get image bits, rc=%d (%s) (c5)", rc, kErrName(rc)); if (TestMemComp(pvBits2, pvBits, cbImage)) return Failure("relocation test failed, mismatching bits (c5)"); return 0; } /** * Dump symbols and check that we can query each of them recursivly. */ static int BasicTestsEnumSymCallback(PKLDRMOD pMod, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, KLDRADDR uValue, KU32 fKind, void *pvUser) { KLDRADDR uValue2; KU32 fKind2; int rc; /* dump */ printf("#0x%08x: %016" PRI_KLDRADDR " %#08x", iSymbol, uValue, fKind); if (pchSymbol) printf(" %.*s", cchSymbol, pchSymbol); printf("\n"); /* query by ordinal */ if (iSymbol != NIL_KLDRMOD_SYM_ORDINAL) { fKind2 = 0; rc = kLdrModQuerySymbol(pMod, pvUser, MY_BASEADDRESS, iSymbol, NULL, 0, NULL, NULL, NULL, &uValue2, &fKind2); if (rc) return Failure("Couldn't find symbol %#x (%.*s) by ordinal. rc=%d (%s)", iSymbol, cchSymbol, pchSymbol, rc, kErrName(rc)); if (uValue != uValue2) return Failure("Symbol %#x (%.*s): Value mismatch %016" PRI_KLDRADDR " != %016" PRI_KLDRADDR " (enum!=query/ord) pvBits=%p", iSymbol, cchSymbol, pchSymbol, uValue, uValue2, pvUser); if (fKind != fKind2) return Failure("Symbol %#x (%.*s): Kind mismatch %#x != %#x (enum!=query/ord) pvBits=%p", iSymbol, cchSymbol, pchSymbol, fKind, fKind2, pvUser); } /* query by name. */ if (pchSymbol) { fKind2 = 0; rc = kLdrModQuerySymbol(pMod, pvUser, MY_BASEADDRESS, NIL_KLDRMOD_SYM_ORDINAL, pchSymbol, cchSymbol, pszVersion, NULL, NULL, &uValue2, &fKind2); if (rc) return Failure("Couldn't find symbol %#x (%.*s) by name. rc=%d (%s)", iSymbol, cchSymbol, pchSymbol, rc, kErrName(rc)); if (uValue != uValue2) return Failure("Symbol %#x (%.*s): Value mismatch %016" PRI_KLDRADDR " != %016" PRI_KLDRADDR " (enum!=query/name) pvBits=%p", iSymbol, cchSymbol, pchSymbol, uValue, uValue2, pvUser); if (fKind != fKind2) return Failure("Symbol %#x (%.*s): Kind mismatch %#x != %#x (enum!=query/name) pvBits=%p", iSymbol, cchSymbol, pchSymbol, fKind, fKind2, pvUser); } return 0; } /** * Dump debugger information and check it for correctness. */ static int BasicTestEnumDbgInfoCallback(PKLDRMOD pMod, KU32 iDbgInfo, KLDRDBGINFOTYPE enmType, KI16 iMajorVer, KI16 iMinorVer, KLDRFOFF offFile, KLDRADDR LinkAddress, KLDRSIZE cb, const char *pszExtFile, void *pvUser) { printf("#0x%08x: enmType=%d %d.%d offFile=0x%" PRI_KLDRADDR " LinkAddress=%" PRI_KLDRADDR " cb=%" PRI_KLDRSIZE " pvUser=%p\n", iDbgInfo, enmType, iMajorVer, iMinorVer, (KLDRADDR)offFile, LinkAddress, cb, pvUser); if (pszExtFile) printf(" pszExtFile=%p '%s'\n", pszExtFile, pszExtFile); if (enmType >= KLDRDBGINFOTYPE_END || enmType <= KLDRDBGINFOTYPE_INVALID) return Failure("Bad enmType"); if (pvUser != NULL) return Failure("pvUser"); return 0; } /** * Performs the basic module loader test on the specified module and image bits. */ static int BasicTestsSub2(PKLDRMOD pMod, void *pvBits) { KI32 cImports; KI32 i; int rc; KU32 fKind; KLDRADDR Value; KLDRADDR MainEPAddress; KLDRSTACKINFO StackInfo; printf("* Testing queries with pvBits=%p...\n", pvBits); /* * Get the import modules. */ cImports = kLdrModNumberOfImports(pMod, pvBits); printf("cImports=%d\n", cImports); if (cImports < 0) return Failure("failed to query the number of import, cImports=%d", cImports); for (i = 0; i < cImports; i++) { char szImportModule[260]; rc = kLdrModGetImport(pMod, pvBits, i, szImportModule, sizeof(szImportModule)); if (rc) return Failure("failed to get import module name, rc=%d (%s). (%.260s)", rc, kErrName(rc), szImportModule); printf("import #%d: '%s'\n", i, szImportModule); } /* * Query stack info. */ StackInfo.Address = ~(KLDRADDR)42; StackInfo.LinkAddress = ~(KLDRADDR)42; StackInfo.cbStack = ~(KLDRSIZE)42; StackInfo.cbStackThread = ~(KLDRSIZE)42; rc = kLdrModGetStackInfo(pMod, pvBits, MY_BASEADDRESS, &StackInfo); if (rc) return Failure("kLdrModGetStackInfo failed with rc=%d (%s)", rc, kErrName(rc)); printf("Stack: Address=%016" PRI_KLDRADDR " LinkAddress=%016" PRI_KLDRADDR "\n" " cbStack=%016" PRI_KLDRSIZE " cbStackThread=%016" PRI_KLDRSIZE "\n", StackInfo.Address, StackInfo.LinkAddress, StackInfo.cbStack, StackInfo.cbStackThread); if (StackInfo.Address == ~(KLDRADDR)42) return Failure("Bad StackInfo.Address"); if (StackInfo.LinkAddress == ~(KLDRADDR)42) return Failure("Bad StackInfo.LinkAddress"); if (StackInfo.cbStack == ~(KLDRSIZE)42) return Failure("Bad StackInfo.cbStack"); if (StackInfo.cbStackThread == ~(KLDRSIZE)42) return Failure("Bad StackInfo.cbStackThread"); /* * Query entrypoint. */ MainEPAddress = ~(KLDRADDR)42; rc = kLdrModQueryMainEntrypoint(pMod, pvBits, MY_BASEADDRESS, &MainEPAddress); if (rc) return Failure("kLdrModQueryMainEntrypoint failed with rc=%d (%s)", rc, kErrName(rc)); printf("Entrypoint: %016" PRI_KLDRADDR "\n", MainEPAddress); if (MainEPAddress == ~(KLDRADDR)42) return Failure("MainEPAddress wasn't set."); if (MainEPAddress != NIL_KLDRADDR && MainEPAddress < MY_BASEADDRESS) return Failure("Bad MainEPAddress (a)."); if (MainEPAddress != NIL_KLDRADDR && MainEPAddress >= MY_BASEADDRESS + kLdrModSize(pMod)) return Failure("Bad MainEPAddress (b)."); /* * Debugger information. */ rc = kLdrModHasDbgInfo(pMod, pvBits); if (!rc) printf("Has Debugger Information\n"); else if (rc == KLDR_ERR_NO_DEBUG_INFO) printf("NO Debugger Information\n"); else return Failure("kLdrModHasDbgInfo failed with rc=%d (%s)", rc, kErrName(rc)); rc = kLdrModEnumDbgInfo(pMod, pvBits, BasicTestEnumDbgInfoCallback, NULL); if (rc) return Failure("kLdrModEnumDbgInfo failed with rc=%d (%s)", rc, kErrName(rc)); /* * Negative symbol query tests. */ fKind = 0; Value = 0x0badc0de; rc = kLdrModQuerySymbol(pMod, pvBits, MY_BASEADDRESS, NIL_KLDRMOD_SYM_ORDINAL - 20, NULL, 0, NULL, NULL, NULL, &Value, &fKind); if (rc) { if (Value != 0) return Failure("Value wasn't cleared on failure."); } fKind = 0; Value = 0x0badc0de; rc = kLdrModQuerySymbol(pMod, pvBits, MY_BASEADDRESS, NIL_KLDRMOD_SYM_ORDINAL, NULL, 0, NULL, NULL, NULL, &Value, &fKind); if (!rc) return Failure("NIL ordinal succeeded!"); if (Value != 0) return Failure("Value wasn't cleared on failure."); /* * Enumerate and query all symbols. */ printf("\n" "Symbols:\n"); rc = kLdrModEnumSymbols(pMod, pvBits, MY_BASEADDRESS, 0, BasicTestsEnumSymCallback, pvBits); if (rc) return Failure("kLdrModEnumSymbols failed with rc=%d (%s)", rc, kErrName(rc)); /*int kLdrModCanExecuteOn(PKLDRMOD pMod, const void *pvBits, KCPUARCH enmArch, KCPU enmCpu); */ return 0; } /** * Performs the basic module loader test on the specified module */ static int BasicTestsSub(PKLDRMOD pMod) { int rc; KU32 i; void *pvBits; KSIZE cbImage; /* * Check/dump the module structure. */ printf("pMod=%p u32Magic=%#x cSegments=%d\n", (void *)pMod, pMod->u32Magic, pMod->cSegments); printf("enmType=%d enmFmt=%d enmArch=%d enmCpu=%d enmEndian=%d\n", pMod->enmType, pMod->enmFmt, pMod->enmArch, pMod->enmCpu, pMod->enmEndian); printf("Filename: %s (%d bytes)\n", pMod->pszFilename, pMod->cchFilename); printf(" Name: %s (%d bytes)\n", pMod->pszName, pMod->cchName); printf("\n"); if (pMod->u32Magic != KLDRMOD_MAGIC) return Failure("Bad u32Magic"); if (strlen(pMod->pszFilename) != pMod->cchFilename) return Failure("Bad cchFilename"); if (strlen(pMod->pszName) != pMod->cchName) return Failure("Bad cchName"); if (pMod->enmFmt >= KLDRFMT_END || pMod->enmFmt <= KLDRFMT_INVALID) return Failure("Bad enmFmt"); if (pMod->enmType >= KLDRTYPE_END || pMod->enmType <= KLDRTYPE_INVALID) return Failure("Bad enmType: %d", pMod->enmType); if (!K_ARCH_IS_VALID(pMod->enmArch)) return Failure("Bad enmArch"); if (pMod->enmCpu >= KCPU_END || pMod->enmCpu <= KCPU_INVALID) return Failure("Bad enmCpu"); if (pMod->enmEndian >= KLDRENDIAN_END || pMod->enmEndian <= KLDRENDIAN_INVALID) return Failure("Bad enmEndian"); for (i = 0; i < pMod->cSegments; i++) { printf("seg #%d: pvUser=%p enmProt=%d Name: '%.*s' (%d bytes)\n", i, pMod->aSegments[i].pvUser, pMod->aSegments[i].enmProt, pMod->aSegments[i].cchName, pMod->aSegments[i].pchName, pMod->aSegments[i].cchName); printf("LinkAddress: %016" PRI_KLDRADDR " cb: %016" PRI_KLDRSIZE " Alignment=%08" PRI_KLDRADDR " \n", pMod->aSegments[i].LinkAddress, pMod->aSegments[i].cb, pMod->aSegments[i].Alignment); printf(" RVA: %016" PRI_KLDRADDR " cbMapped: %016" PRI_KLDRSIZE " MapAddress=%p\n", pMod->aSegments[i].RVA, (KLDRSIZE)pMod->aSegments[i].cbMapped, (void *)pMod->aSegments[i].MapAddress); printf(" offFile: %016" PRI_KLDRADDR " cbFile: %016" PRI_KLDRSIZE "\n", (KLDRADDR)pMod->aSegments[i].offFile, (KLDRSIZE)pMod->aSegments[i].cbFile); printf("\n"); if (pMod->aSegments[i].pvUser != NULL) return Failure("Bad pvUser"); if (pMod->aSegments[i].enmProt >= KPROT_END || pMod->aSegments[i].enmProt <= KPROT_INVALID) return Failure("Bad enmProt"); if (pMod->aSegments[i].MapAddress != 0) return Failure("Bad MapAddress"); if (pMod->aSegments[i].cbMapped < pMod->aSegments[i].cb) return Failure("Bad cbMapped (1)"); if (pMod->aSegments[i].cbMapped && !pMod->aSegments[i].Alignment) return Failure("Bad cbMapped (2)"); if (pMod->aSegments[i].cbMapped > kLdrModSize(pMod)) return Failure("Bad cbMapped (3)"); if ( pMod->aSegments[i].Alignment && (pMod->aSegments[i].RVA & (pMod->aSegments[i].Alignment - 1))) return Failure("Bad RVA (1)"); if (pMod->aSegments[i].RVA != NIL_KLDRADDR && !pMod->aSegments[i].Alignment) return Failure("Bad RVA (2)"); if ( pMod->aSegments[i].RVA != NIL_KLDRADDR && pMod->aSegments[i].RVA >= kLdrModSize(pMod)) return Failure("Bad RVA (3)"); if ( pMod->aSegments[i].RVA != NIL_KLDRADDR && pMod->aSegments[i].RVA + pMod->aSegments[i].cbMapped > kLdrModSize(pMod)) return Failure("Bad RVA/cbMapped (4)"); if (pMod->aSegments[i].LinkAddress != NIL_KLDRADDR && !pMod->aSegments[i].Alignment) return Failure("Bad LinkAddress"); if ( pMod->aSegments[i].LinkAddress != NIL_KLDRADDR && (pMod->aSegments[i].LinkAddress) & (pMod->aSegments[i].Alignment - 1)) return Failure("Bad LinkAddress alignment"); if (pMod->aSegments[i].offFile != -1 && pMod->aSegments[i].cbFile == -1) return Failure("Bad offFile"); if (pMod->aSegments[i].offFile == -1 && pMod->aSegments[i].cbFile != -1) return Failure("Bad cbFile"); } /* * Get image the size and query the image bits. */ printf("* Testing user mapping...\n"); cbImage = (KSIZE)kLdrModSize(pMod); if (cbImage != kLdrModSize(pMod)) return Failure("aborting test because the image is too huge!"); pvBits = malloc((KSIZE)cbImage); if (!pvBits) return Failure("failed to allocate %d bytes for the image", cbImage); rc = kLdrModGetBits(pMod, pvBits, (KUPTR)pvBits, BasicTestsGetImport, NULL); if (rc) return Failure("failed to get image bits, rc=%d (%s)", rc, kErrName(rc)); /* * Another cleanup nesting. */ rc = BasicTestsSub2(pMod, pvBits); if (!rc) { /* * Test relocating the bits in a few different ways before we're done with them. */ void *pvBits2 = malloc((KSIZE)cbImage); if (pvBits2) { rc = BasicTestsRelocate(pMod, pvBits, pvBits2); free(pvBits2); } else rc = Failure("failed to allocate %d bytes for the 2nd image", cbImage); } free(pvBits); return rc; } /** * Tests the mapping related api, after mapping. */ static int BasicTestsSubMap2(PKLDRMOD pMod) { int rc; rc = kLdrModFixupMapping(pMod, BasicTestsGetImport, NULL); if (rc) return Failure("kLdrModFixupMapping (a) failed, rc=%d (%s)", rc, kErrName(rc)); rc = kLdrModReload(pMod); if (rc) return Failure("kLdrModReload (a) failed, rc=%d (%s)", rc, kErrName(rc)); rc = kLdrModReload(pMod); if (rc) return Failure("kLdrModReload (b) failed, rc=%d (%s)", rc, kErrName(rc)); rc = kLdrModFixupMapping(pMod, BasicTestsGetImport, NULL); if (rc) return Failure("kLdrModFixupMapping (b) failed, rc=%d (%s)", rc, kErrName(rc)); rc = kLdrModAllocTLS(pMod); if (rc) return Failure("kLdrModAllocTLS (a) failed, rc=%d (%s)", rc, kErrName(rc)); kLdrModFreeTLS(pMod); rc = kLdrModAllocTLS(pMod); if (rc) return Failure("kLdrModAllocTLS (b) failed, rc=%d (%s)", rc, kErrName(rc)); kLdrModFreeTLS(pMod); /* * Repeat the BasicTestsSub2 with pvBits as NULL to test module * interpreters that can utilize the mapping. */ rc = BasicTestsSub2(pMod, NULL); if (rc) return Failure("BasicTestsSub2 in Map2 failed, rc=%d (%s)", rc, kErrName(rc)); return 0; } /** * Tests the mapping related api. */ static int BasicTestsSubMap(PKLDRMOD pMod) { int rc, rc2; printf("* Mapping tests...\n"); rc = kLdrModMap(pMod); if (rc) return Failure("kLdrModMap failed, rc=%d (%s)", rc, kErrName(rc)); rc = BasicTestsSubMap2(pMod); rc2 = kLdrModUnmap(pMod); if (rc2) { Failure("kLdrModUnmap failed, rc=%d (%s)", rc2, kErrName(rc2)); rc = rc ? rc : rc2; } printf("* Mapping tests done.\n"); return rc; } /** * Performs basic module loader tests on the specified file. */ static int BasicTests(const char *pszFilename) { PKLDRMOD pMod; int rc, rc2; printf("tstLdrMod: Testing '%s'", pszFilename); rc = kLdrModOpen(pszFilename, &pMod); if (!rc) { rc = BasicTestsSub(pMod); if (!rc) rc = BasicTestsSubMap(pMod); if (!rc) rc = BasicTestsSub2(pMod, NULL); rc2 = kLdrModClose(pMod); if (rc2) Failure("failed to close '%s', rc=%d (%s)", pszFilename, rc, kErrName(rc)); if (rc2 && !rc) rc = rc2; } else Failure("Failed to open '%s', rc=%d (%s)", pszFilename, rc, kErrName(rc)); return rc ? 1 : 0; } int main(int argc, char **argv) { BasicTests(argv[argc-1]); if (!g_cErrors) printf("tstLdrMod: SUCCESS\n"); else printf("tstLdrMod: FAILURE - %d errors\n", g_cErrors); return !!g_cErrors; } kbuild-3149/src/lib/kStuff/kLdr/kLdr-win.def0000644000175000017500000000533713252530253020556 0ustar locutuslocutus; $Id: kLdr-win.def 29 2009-07-01 20:30:29Z bird $ ;; @file ; kLdr - The Dynamic Loader, Windows Linker Definition File. ; ; ; Copyright (c) 2006-2007 Knut St. Osmundsen ; ; 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. ; LIBRARY kLdr EXPORTS ; The file reader API kRdrAddProvider kRdrOpen kRdrClose kRdrRead kRdrAllMap kRdrAllUnmap kRdrSize kRdrTell kRdrName kRdrPageSize kRdrMap kRdrRefresh kRdrProtect kRdrUnmap kRdrDone ; The module interpreter API kLdrModOpen kLdrModOpenFromRdr kLdrModOpenNative kLdrModOpenNativeByHandle kLdrModClose kLdrModQuerySymbol kLdrModEnumSymbols kLdrModGetImport kLdrModNumberOfImports kLdrModCanExecuteOn kLdrModGetStackInfo kLdrModQueryMainEntrypoint kLdrModEnumDbgInfo kLdrModHasDbgInfo kLdrModMap kLdrModUnmap kLdrModAllocTLS kLdrModFreeTLS kLdrModReload kLdrModFixupMapping kLdrModCallInit kLdrModCallTerm kLdrModCallThread kLdrModSize kLdrModGetBits kLdrModRelocateBits ; Process Bootstrapping kLdrDyldLoadExe ; Dynamic loading kLdrDyldLoad kLdrDyldUnload kLdrDyldFindByName kLdrDyldFindByAddress kLdrDyldGetName kLdrDyldGetFilename kLdrDyldQuerySymbol ; OS/2 API wrappers: ; kLdrLoadModule ; kLdrFreeModule ; kLdrQueryModuleHandle ; kLdrQueryModuleName ; kLdrQueryProcAddr ; kLdrQueryProcType ; kLdrQueryModFromEIP ; kLdrReplaceModule ; kLdrGetResource ; kLdrFreeResource ; kLdrQueryResourceSize ; dlfcn API wrappers: ; _kLdrDlOpen ; _kLdrDlClose ; _kLdrDlError ; _kLdrDlSym ; _kLdrDlFunc ; Error APIs: kErrName kbuild-3149/src/lib/kStuff/kLdr/kLdrExeStub-os2.asm0000644000175000017500000000431713252530254022004 0ustar locutuslocutus; $Id: kLdrExeStub-os2.asm 29 2009-07-01 20:30:29Z bird $ ;; @file ; kLdr - OS/2 Loader Stub. ; ; This file contains a 64kb code/data/stack segment which is used to kick off ; the loader dll that loads the process. ; ; ; Copyright (c) 2006-2007 Knut St. Osmundsen ; ; 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. ; struc KLDRARGS .fFlags resd 1 .enmSearch resd 1 .szExecutable resb 260 .szDefPrefix resb 16 .szDefSuffix resb 16 .szLibPath resb (4096 - (4 + 4 + 16 + 16 + 260)) endstruc extern _kLdrDyldLoadExe segment DATA32 stack CLASS=DATA align=16 use32 ..start: push args jmp _kLdrDyldLoadExe ; ; Argument structure. ; align 4 args: istruc KLDRARGS at KLDRARGS.fFlags, dd 0 at KLDRARGS.enmSearch, dd 2 ;KLDRDYLD_SEARCH_HOST at KLDRARGS.szDefPrefix, db '' at KLDRARGS.szDefSuffix, db '.dll' ; at KLDRARGS.szExecutable, db 'tst-0.exe' at KLDRARGS.szLibPath, db '' iend segment STACK32 stack CLASS=STACK align=16 use32 ; pad up to 64KB. resb 60*1024 global WEAK$ZERO WEAK$ZERO EQU 0 group DGROUP, DATA32 STACK32 kbuild-3149/src/lib/kStuff/kLdr/Doxyfile0000644000175000017500000014417313252530254020120 0ustar locutuslocutus# Doxyfile 1.5.0 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = kLdr # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = docs # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, # Italian, Japanese, Japanese-en (Japanese with English messages), Korean, # Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, # Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # This tag can be used to specify the encoding used in the generated output. # The encoding is not always determined by the language that is chosen, # but also whether or not the output is meant for Windows or non-Windows users. # In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES # forces the Windows encoding (this is the default for the Windows binary), # whereas setting the tag to NO uses a Unix-style encoding (the default for # all platforms other than Windows). USE_WINDOWS_ENCODING = YES # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like the Qt-style comments (thus requiring an # explicit @brief command for a brief description. JAVADOC_AUTOBRIEF = YES # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. # If set to NO, the detailed description appears after the member # documentation. DETAILS_AT_TOP = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to # include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = YES # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = NO # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from the # version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py FILE_PATTERNS = *.c *.h # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = tst* # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = tg # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = NO # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. Otherwise they will link to the documentstion. REFERENCES_LINK_SOURCE = NO # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = NO #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = YES # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = NO # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will # generate a caller dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable caller graphs for selected # functions only using the \callergraph command. CALLER_GRAPH = YES # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_WIDTH = 1024 # The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_HEIGHT = 1024 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that a graph may be further truncated if the graph's # image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH # and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), # the graph is not depth-constrained. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, which results in a white background. # Warning: Depending on the platform used, enabling this option may lead to # badly anti-aliased labels on the edges of a graph (i.e. they become hard to # read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO kbuild-3149/src/lib/kStuff/kLdr/kLdr-os2.def0000644000175000017500000000546613252530253020467 0ustar locutuslocutus; $Id: kLdr-os2.def 29 2009-07-01 20:30:29Z bird $ ;; @file ; kLdr - The Dynamic Loader, OS/2 Linker Definition File. ; ; ; Copyright (c) 2006-2007 Knut St. Osmundsen ; ; 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. ; LIBRARY kLdr INITINSTANCE TERMINSTANCE DATA MULTIPLE EXPORTS ; The file reader API _kRdrAddProvider _kRdrOpen _kRdrClose _kRdrRead _kRdrAllMap _kRdrAllUnmap _kRdrSize _kRdrTell _kRdrName _kRdrPageSize _kRdrMap _kRdrRefresh _kRdrProtect _kRdrUnmap _kRdrDone ; The module interpreter API _kLdrModOpen _kLdrModOpenFromRdr _kLdrModOpenNative _kLdrModOpenNativeByHandle _kLdrModClose _kLdrModQuerySymbol _kLdrModEnumSymbols _kLdrModGetImport _kLdrModNumberOfImports _kLdrModCanExecuteOn _kLdrModGetStackInfo _kLdrModQueryMainEntrypoint _kLdrModEnumDbgInfo _kLdrModHasDbgInfo _kLdrModMap _kLdrModUnmap _kLdrModAllocTLS _kLdrModFreeTLS _kLdrModReload _kLdrModFixupMapping _kLdrModCallInit _kLdrModCallTerm _kLdrModCallThread _kLdrModSize _kLdrModGetBits _kLdrModRelocateBits ; Process Bootstrapping _kLdrDyldLoadExe ; Dynamic loading _kLdrDyldLoad _kLdrDyldUnload _kLdrDyldFindByName _kLdrDyldFindByAddress _kLdrDyldGetName _kLdrDyldGetFilename _kLdrDyldQuerySymbol ; OS/2 API wrappers: ; kLdrLoadModule ; kLdrFreeModule ; kLdrQueryModuleHandle ; kLdrQueryModuleName ; kLdrQueryProcAddr ; kLdrQueryProcType ; kLdrQueryModFromEIP ; kLdrReplaceModule ; kLdrGetResource ; kLdrFreeResource ; kLdrQueryResourceSize ; dlfcn API wrappers: ; _kLdrDlOpen ; _kLdrDlClose ; _kLdrDlError ; _kLdrDlSym ; _kLdrDlFunc ; Error APIs: _kErrStr kbuild-3149/src/lib/kStuff/kLdr/kLdrDyldFind.c0000644000175000017500000011405013252530253021056 0ustar locutuslocutus/* $Id: kLdrDyldFind.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - The Dynamic Loader, File Searching Methods. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include "kLdrInternal.h" #if K_OS == K_OS_LINUX # include #elif K_OS == K_OS_OS2 # define INCL_BASE # define INCL_ERRORS # include # ifndef LIBPATHSTRICT # define LIBPATHSTRICT 3 # endif extern APIRET APIENTRY DosQueryHeaderInfo(HMODULE hmod, ULONG ulIndex, PVOID pvBuffer, ULONG cbBuffer, ULONG ulSubFunction); # define QHINF_EXEINFO 1 /* NE exeinfo. */ # define QHINF_READRSRCTBL 2 /* Reads from the resource table. */ # define QHINF_READFILE 3 /* Reads from the executable file. */ # define QHINF_LIBPATHLENGTH 4 /* Gets the libpath length. */ # define QHINF_LIBPATH 5 /* Gets the entire libpath. */ # define QHINF_FIXENTRY 6 /* NE only */ # define QHINF_STE 7 /* NE only */ # define QHINF_MAPSEL 8 /* NE only */ #elif K_OS == K_OS_WINDOWS # undef IMAGE_DOS_SIGNATURE # undef IMAGE_NT_SIGNATURE # include #endif /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** @def KLDRDYLDFIND_STRICT * Define KLDRDYLDFIND_STRICT to enabled strict checks in kLdrDyldFind. */ #define KLDRDYLDFIND_STRICT 1 /** @def KLDRDYLDFIND_ASSERT * Assert that an expression is true when KLDRDYLDFIND_STRICT is defined. */ #ifdef KLDRDYLDFIND_STRICT # define KLDRDYLDFIND_ASSERT(expr) kHlpAssert(expr) #else # define KLDRDYLDFIND_ASSERT(expr) do {} while (0) #endif /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * Search arguments. * This avoids a bunch of unnecessary string lengths and calculations. */ typedef struct KLDRDYLDFINDARGS { const char *pszName; KSIZE cchName; const char *pszPrefix; KSIZE cchPrefix; const char *pszSuffix; KSIZE cchSuffix; KSIZE cchMaxLength; KLDRDYLDSEARCH enmSearch; KU32 fFlags; PPKRDR ppRdr; } KLDRDYLDFINDARGS, *PKLDRDYLDFINDARGS; typedef const KLDRDYLDFINDARGS *PCKLDRDYLDFINDARGS; /******************************************************************************* * Global Variables * *******************************************************************************/ /** @name The kLdr search method parameters. * @{ */ /** The kLdr EXE search path. * During EXE searching the it's initialized with the values of the KLDR_PATH and * the PATH env.vars. Both ';' and ':' can be used as separators. */ char kLdrDyldExePath[8192]; /** The kLdr DLL search path. * During initialization the KLDR_LIBRARY_PATH env.var. and the path in the * executable stub is appended. Both ';' and ':' can be used as separators. */ char kLdrDyldLibraryPath[8192]; /** The kLdr application directory. * This is initialized when the executable is 'loaded' or by a kLdr user. */ char kLdrDyldAppDir[260]; /** The default kLdr DLL prefix. * This is initialized with the KLDR_DEF_PREFIX env.var. + the prefix in the executable stub. */ char kLdrDyldDefPrefix[16]; /** The default kLdr DLL suffix. * This is initialized with the KLDR_DEF_SUFFIX env.var. + the prefix in the executable stub. */ char kLdrDyldDefSuffix[16]; /** @} */ /** @name The OS/2 search method parameters. * @{ */ /** The OS/2 LIBPATH. * This is queried from the os2krnl on OS/2, while on other systems initialized using * the KLDR_OS2_LIBPATH env.var. */ char kLdrDyldOS2Libpath[2048]; /** The OS/2 LIBPATHSTRICT ("T" or '\0'). * This is queried from the os2krnl on OS/2, while on other systems initialized using * the KLDR_OS2_LIBPATHSTRICT env.var. */ char kLdrDyldOS2LibpathStrict[8]; /** The OS/2 BEGINLIBPATH. * This is queried from the os2krnl on OS/2, while on other systems initialized using * the KLDR_OS2_BEGINLIBPATH env.var. */ char kLdrDyldOS2BeginLibpath[2048]; /** The OS/2 ENDLIBPATH. * This is queried from the os2krnl on OS/2, while on other systems initialized using * the KLDR_OS2_ENDLIBPATH env.var. */ char kLdrDyldOS2EndLibpath[2048]; /** @} */ /** @name The Windows search method parameters. * @{ */ /** The Windows application directory. * This is initialized when the executable is 'loaded' or by a kLdr user. */ char kLdrDyldWindowsAppDir[260]; /** The Windows system directory. * This is queried from the Win32/64 subsystem on Windows, while on other systems * initialized using the KLDR_WINDOWS_SYSTEM_DIR env.var. */ char kLdrDyldWindowsSystemDir[260]; /** The Windows directory. * This is queried from the Win32/64 subsystem on Windows, while on other systems * initialized using the KLDR_WINDOWS_DIR env.var. */ char kLdrDyldWindowsDir[260]; /** The Windows path. * This is queried from the PATH env.var. on Windows, while on other systems * initialized using the KLDR_WINDOWS_PATH env.var. and falling back on * the PATH env.var. if it wasn't found. */ char kLdrDyldWindowsPath[8192]; /** @} */ /** @name The Common Unix search method parameters. * @{ */ /** The Common Unix library path. * Initialized from the env.var. KLDR_UNIX_LIBRARY_PATH or LD_LIBRARY_PATH or the * former wasn't found. */ char kLdrDyldUnixLibraryPath[8192]; /** The Common Unix system library path. */ char kLdrDyldUnixSystemLibraryPath[1024] = "/lib;/usr/lib"; /** @} */ /** @todo Deal with DT_RUNPATH and DT_RPATH. */ /** @todo ld.so.cache? */ /******************************************************************************* * Internal Functions * *******************************************************************************/ static int kldrDyldFindDoDllSearch(const char *pszName, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKRDR ppRdr); static int kldrDyldFindDoExeSearch(const char *pszName, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKRDR ppRdr); static int kldrDyldFindTryOpen(const char *pszFilename, PPKRDR ppRdr); static int kldrDyldFindTryOpenPath(const char *pchPath, KSIZE cchPath, PCKLDRDYLDFINDARGS pArgs); static int kldrDyldFindEnumeratePath(const char *pszSearchPath, PCKLDRDYLDFINDARGS pArgs); static int kldrDyldFindGetDefaults(KLDRDYLDSEARCH *penmSearch, const char **pszPrefix, const char **pszSuffix, const char *pszName, KU32 fFlags); /** * Initializes the find paths. * * @returns 0 on success, non-zero on failure. */ int kldrDyldFindInit(void) { KSIZE cch; int rc; char szTmp[sizeof(kLdrDyldDefSuffix)]; /* * The kLdr search parameters. */ rc = kHlpGetEnv("KLDR_LIBRARY_PATH", kLdrDyldLibraryPath, sizeof(kLdrDyldLibraryPath)); rc = kHlpGetEnv("KLDR_DEF_PREFIX", szTmp, sizeof(szTmp)); if (!rc) kHlpMemCopy(kLdrDyldDefPrefix, szTmp, sizeof(szTmp)); rc = kHlpGetEnv("KLDR_DEF_SUFFIX", szTmp, sizeof(szTmp)); if (!rc) kHlpMemCopy(kLdrDyldDefSuffix, szTmp, sizeof(szTmp)); /* * The OS/2 search parameters. */ #if K_OS == K_OS_OS2 rc = DosQueryHeaderInfo(NULLHANDLE, 0, kLdrDyldOS2Libpath, sizeof(kLdrDyldOS2Libpath), QHINF_LIBPATH); if (rc) return rc; rc = DosQueryExtLIBPATH((PSZ)kLdrDyldOS2LibpathStrict, LIBPATHSTRICT); if (rc) kLdrDyldOS2LibpathStrict[0] = '\0'; rc = DosQueryExtLIBPATH((PSZ)kLdrDyldOS2BeginLibpath, BEGIN_LIBPATH); if (rc) kLdrDyldOS2BeginLibpath[0] = '\0'; rc = DosQueryExtLIBPATH((PSZ)kLdrDyldOS2EndLibpath, END_LIBPATH); if (rc) kLdrDyldOS2EndLibpath[0] = '\0'; #else kHlpGetEnv("KLDR_OS2_LIBPATH", kLdrDyldOS2Libpath, sizeof(kLdrDyldOS2Libpath)); kHlpGetEnv("KLDR_OS2_LIBPATHSTRICT", kLdrDyldOS2LibpathStrict, sizeof(kLdrDyldOS2LibpathStrict)); if ( kLdrDyldOS2LibpathStrict[0] == 'T' || kLdrDyldOS2LibpathStrict[0] == 't') kLdrDyldOS2LibpathStrict[0] = 'T'; else kLdrDyldOS2LibpathStrict[0] = '\0'; kLdrDyldOS2LibpathStrict[1] = '\0'; kHlpGetEnv("KLDR_OS2_BEGINLIBPATH", kLdrDyldOS2BeginLibpath, sizeof(kLdrDyldOS2BeginLibpath)); kHlpGetEnv("KLDR_OS2_ENDLIBPATH", kLdrDyldOS2EndLibpath, sizeof(kLdrDyldOS2EndLibpath)); #endif /* * The windows search parameters. */ #if K_OS == K_OS_WINDOWS cch = GetSystemDirectory(kLdrDyldWindowsSystemDir, sizeof(kLdrDyldWindowsSystemDir)); if (cch >= sizeof(kLdrDyldWindowsSystemDir)) return (rc = GetLastError()) ? rc : -1; cch = GetWindowsDirectory(kLdrDyldWindowsDir, sizeof(kLdrDyldWindowsDir)); if (cch >= sizeof(kLdrDyldWindowsDir)) return (rc = GetLastError()) ? rc : -1; kHlpGetEnv("PATH", kLdrDyldWindowsPath, sizeof(kLdrDyldWindowsPath)); #else kHlpGetEnv("KLDR_WINDOWS_SYSTEM_DIR", kLdrDyldWindowsSystemDir, sizeof(kLdrDyldWindowsSystemDir)); kHlpGetEnv("KLDR_WINDOWS_DIR", kLdrDyldWindowsDir, sizeof(kLdrDyldWindowsDir)); rc = kHlpGetEnv("KLDR_WINDOWS_PATH", kLdrDyldWindowsPath, sizeof(kLdrDyldWindowsPath)); if (rc) kHlpGetEnv("PATH", kLdrDyldWindowsPath, sizeof(kLdrDyldWindowsPath)); #endif /* * The Unix search parameters. */ rc = kHlpGetEnv("KLDR_UNIX_LIBRARY_PATH", kLdrDyldUnixLibraryPath, sizeof(kLdrDyldUnixLibraryPath)); if (rc) kHlpGetEnv("LD_LIBRARY_PATH", kLdrDyldUnixLibraryPath, sizeof(kLdrDyldUnixLibraryPath)); (void)cch; return 0; } /** * Lazily initialize the two application directory paths. */ static void kldrDyldFindLazyInitAppDir(void) { if (!kLdrDyldAppDir[0]) { #if K_OS == K_OS_DARWIN /** @todo implement this! */ kLdrDyldWindowsAppDir[0] = kLdrDyldAppDir[0] = '.'; kLdrDyldWindowsAppDir[1] = kLdrDyldAppDir[1] = '\0'; #elif K_OS == K_OS_LINUX KSSIZE cch = kHlpSys_readlink("/proc/self/exe", kLdrDyldAppDir, sizeof(kLdrDyldAppDir) - 1); if (cch > 0) { kLdrDyldAppDir[cch] = '\0'; *kHlpGetFilename(kLdrDyldAppDir) = '\0'; kHlpMemCopy(kLdrDyldWindowsAppDir, kLdrDyldAppDir, sizeof(kLdrDyldAppDir)); } else { kLdrDyldWindowsAppDir[0] = kLdrDyldAppDir[0] = '.'; kLdrDyldWindowsAppDir[1] = kLdrDyldAppDir[1] = '\0'; } #elif K_OS == K_OS_OS2 PPIB pPib; PTIB pTib; APIRET rc; DosGetInfoBlocks(&pTib, &pPib); rc = DosQueryModuleName(pPib->pib_hmte, sizeof(kLdrDyldAppDir), kLdrDyldAppDir); if (!rc) { *kHlpGetFilename(kLdrDyldAppDir) = '\0'; kHlpMemCopy(kLdrDyldWindowsAppDir, kLdrDyldAppDir, sizeof(kLdrDyldAppDir)); } else { kLdrDyldWindowsAppDir[0] = kLdrDyldAppDir[0] = '.'; kLdrDyldWindowsAppDir[1] = kLdrDyldAppDir[1] = '\0'; } #elif K_OS == K_OS_WINDOWS DWORD dwSize = GetModuleFileName(NULL /* the executable */, kLdrDyldAppDir, sizeof(kLdrDyldAppDir)); if (dwSize > 0) { *kHlpGetFilename(kLdrDyldAppDir) = '\0'; kHlpMemCopy(kLdrDyldWindowsAppDir, kLdrDyldAppDir, sizeof(kLdrDyldAppDir)); } else { kLdrDyldWindowsAppDir[0] = kLdrDyldAppDir[0] = '.'; kLdrDyldWindowsAppDir[1] = kLdrDyldAppDir[1] = '\0'; } #else # error "Port me" #endif } } /** * Locates and opens a module using the specified search method. * * @returns 0 and *ppMod on success, non-zero OS specific error on failure. * * @param pszName Partial or complete name, it's specific to the search method to determin which. * @param pszPrefix Prefix than can be used when searching. * @param pszSuffix Suffix than can be used when searching. * @param enmSearch The file search method to apply. * @param fFlags Search flags. * @param ppMod Where to store the file provider instance on success. */ int kldrDyldFindNewModule(const char *pszName, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRDYLDMOD ppMod) { int rc; PKRDR pRdr = NULL; *ppMod = NULL; /* * If this isn't just a filename, we the caller has specified a file * that should be opened directly and not a module name to be searched for. */ if (!kHlpIsFilenameOnly(pszName)) rc = kldrDyldFindTryOpen(pszName, &pRdr); else if (!(fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE)) rc = kldrDyldFindDoDllSearch(pszName, pszPrefix, pszSuffix, enmSearch, fFlags, &pRdr); else rc = kldrDyldFindDoExeSearch(pszName, pszPrefix, pszSuffix, enmSearch, fFlags, &pRdr); if (!rc) { #ifdef KLDRDYLDFIND_STRICT /* Sanity check of kldrDyldFindExistingModule. */ if (fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE) { const char *pszFilename = kRdrName(pRdr); const KSIZE cchFilename = kHlpStrLen(pszFilename); PKLDRDYLDMOD pCur; for (pCur = kLdrDyldHead; pCur; pCur = pCur->Load.pNext) KLDRDYLDFIND_ASSERT( pCur->pMod->cchFilename != cchFilename || kHlpMemComp(pCur->pMod->pszFilename, pszFilename, cchFilename)); } #endif /* * Check for matching non-global modules that should be promoted. */ if (!(fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE)) { const char *pszFilename = kRdrName(pRdr); const KSIZE cchFilename = kHlpStrLen(pszFilename); PKLDRDYLDMOD pCur; for (pCur = kLdrDyldHead; pCur; pCur = pCur->Load.pNext) { if ( !pCur->fGlobalOrSpecific && pCur->pMod->cchFilename == cchFilename && !kHlpMemComp(pCur->pMod->pszFilename, pszFilename, cchFilename)) { kRdrClose(pRdr); kldrDyldModMarkGlobal(pCur); *ppMod = pCur; return 0; } KLDRDYLDFIND_ASSERT( pCur->pMod->cchFilename != cchFilename || kHlpMemComp(pCur->pMod->pszFilename, pszFilename, cchFilename)); } } /* * Create a new module. */ rc = kldrDyldModCreate(pRdr, fFlags, ppMod); if (rc) kRdrClose(pRdr); } return rc; } /** * Searches for a DLL file using the specified method. * * @returns 0 on success and *ppMod pointing to the new module. * @returns KLDR_ERR_MODULE_NOT_FOUND if the specified file couldn't be opened. * @returns non-zero kLdr or OS specific status code on other failures. * @param pszName The name. * @param pszPrefix The prefix, optional. * @param pszSuffix The suffix, optional. * @param enmSearch The search method. * @param fFlags The load/search flags. * @param ppRdr Where to store the pointer to the file provider instance on success. */ static int kldrDyldFindDoDllSearch(const char *pszName, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKRDR ppRdr) { int rc; KLDRDYLDFINDARGS Args; /* * Initialize the argument structure and resolve defaults. */ Args.enmSearch = enmSearch; Args.pszPrefix = pszPrefix; Args.pszSuffix = pszSuffix; rc = kldrDyldFindGetDefaults(&Args.enmSearch, &Args.pszPrefix, &Args.pszSuffix, pszName, fFlags); if (rc) return rc; Args.pszName = pszName; Args.cchName = kHlpStrLen(pszName); Args.cchPrefix = Args.pszPrefix ? kHlpStrLen(Args.pszPrefix) : 0; Args.cchSuffix = Args.pszSuffix ? kHlpStrLen(Args.pszSuffix) : 0; Args.cchMaxLength = Args.cchName + Args.cchSuffix + Args.cchPrefix; Args.fFlags = fFlags; Args.ppRdr = ppRdr; /* * Apply the specified search method. */ /** @todo get rid of the strlen() on the various paths here! */ switch (Args.enmSearch) { case KLDRDYLD_SEARCH_KLDR: { kldrDyldFindLazyInitAppDir(); if (kLdrDyldAppDir[0] != '\0') { rc = kldrDyldFindTryOpenPath(kLdrDyldAppDir, kHlpStrLen(kLdrDyldAppDir), &Args); if (rc != KLDR_ERR_MODULE_NOT_FOUND) break; } rc = kldrDyldFindTryOpenPath(".", 1, &Args); if (rc != KLDR_ERR_MODULE_NOT_FOUND) break; rc = kldrDyldFindEnumeratePath(kLdrDyldLibraryPath, &Args); break; } case KLDRDYLD_SEARCH_OS2: { rc = kldrDyldFindEnumeratePath(kLdrDyldOS2BeginLibpath, &Args); if (rc != KLDR_ERR_MODULE_NOT_FOUND) break; rc = kldrDyldFindEnumeratePath(kLdrDyldOS2Libpath, &Args); if (rc != KLDR_ERR_MODULE_NOT_FOUND) break; rc = kldrDyldFindEnumeratePath(kLdrDyldOS2EndLibpath, &Args); break; } case KLDRDYLD_SEARCH_WINDOWS: case KLDRDYLD_SEARCH_WINDOWS_ALTERED: { kldrDyldFindLazyInitAppDir(); rc = kldrDyldFindTryOpenPath(kLdrDyldWindowsAppDir, kHlpStrLen(kLdrDyldWindowsAppDir), &Args); if (rc != KLDR_ERR_MODULE_NOT_FOUND) break; if (Args.enmSearch == KLDRDYLD_SEARCH_WINDOWS_ALTERED) { rc = kldrDyldFindTryOpenPath(".", 1, &Args); if (rc != KLDR_ERR_MODULE_NOT_FOUND) break; } rc = kldrDyldFindTryOpenPath(kLdrDyldWindowsSystemDir, kHlpStrLen(kLdrDyldWindowsSystemDir), &Args); if (rc != KLDR_ERR_MODULE_NOT_FOUND) break; rc = kldrDyldFindTryOpenPath(kLdrDyldWindowsDir, kHlpStrLen(kLdrDyldWindowsDir), &Args); if (rc != KLDR_ERR_MODULE_NOT_FOUND) break; if (Args.enmSearch == KLDRDYLD_SEARCH_WINDOWS) { rc = kldrDyldFindTryOpenPath(".", 1, &Args); if (rc != KLDR_ERR_MODULE_NOT_FOUND) break; } rc = kldrDyldFindEnumeratePath(kLdrDyldWindowsPath, &Args); break; } case KLDRDYLD_SEARCH_UNIX_COMMON: { rc = kldrDyldFindEnumeratePath(kLdrDyldUnixLibraryPath, &Args); if (rc == KLDR_ERR_MODULE_NOT_FOUND) break; rc = kldrDyldFindEnumeratePath(kLdrDyldUnixSystemLibraryPath, &Args); break; } default: kHlpAssert(!"internal error"); return -1; } return rc; } /** * Searches for an EXE file using the specified method. * * @returns 0 on success and *ppMod pointing to the new module. * @returns KLDR_ERR_MODULE_NOT_FOUND if the specified file couldn't be opened. * @returns non-zero kLdr or OS specific status code on other failures. * @param pszName The name. * @param pszPrefix The prefix, optional. * @param pszSuffix The suffix, optional. * @param enmSearch The search method. * @param fFlags The load/search flags. * @param ppRdr Where to store the pointer to the file provider instance on success. */ static int kldrDyldFindDoExeSearch(const char *pszName, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKRDR ppRdr) { int rc; KLDRDYLDFINDARGS Args; /* * Initialize the argument structure and resolve defaults. */ Args.enmSearch = enmSearch; Args.pszPrefix = pszPrefix; Args.pszSuffix = pszSuffix; rc = kldrDyldFindGetDefaults(&Args.enmSearch, &Args.pszPrefix, &Args.pszSuffix, pszName, fFlags); if (rc) return rc; Args.pszName = pszName; Args.cchName = kHlpStrLen(pszName); Args.cchPrefix = Args.pszPrefix ? kHlpStrLen(Args.pszPrefix) : 0; Args.cchSuffix = Args.pszSuffix ? kHlpStrLen(Args.pszSuffix) : 0; Args.cchMaxLength = Args.cchName + Args.cchSuffix + Args.cchPrefix; Args.fFlags = fFlags; Args.ppRdr = ppRdr; /* * If we're bootstrapping a process, we'll start by looking in the * application directory and the check out the path. */ if (g_fBootstrapping) { kldrDyldFindLazyInitAppDir(); if (kLdrDyldAppDir[0] != '\0') { rc = kldrDyldFindTryOpenPath(kLdrDyldAppDir, kHlpStrLen(kLdrDyldAppDir), &Args); if (rc != KLDR_ERR_MODULE_NOT_FOUND) return rc; } } /* * Search the EXE search path. Initialize it the first time around. */ if (!kLdrDyldExePath[0]) { KSIZE cch; kHlpGetEnv("KLDR_EXE_PATH", kLdrDyldExePath, sizeof(kLdrDyldExePath) - 10); cch = kHlpStrLen(kLdrDyldExePath); kLdrDyldExePath[cch++] = ';'; kHlpGetEnv("PATH", &kLdrDyldExePath[cch], sizeof(kLdrDyldExePath) - cch); } return kldrDyldFindEnumeratePath(kLdrDyldExePath, &Args); } /** * Try open the specfied file. * * @returns 0 on success and *ppMod pointing to the new module. * @returns KLDR_ERR_MODULE_NOT_FOUND if the specified file couldn't be opened. * @returns non-zero kLdr or OS specific status code on other failures. * @param pszFilename The filename. * @param ppRdr Where to store the pointer to the new module. */ static int kldrDyldFindTryOpen(const char *pszFilename, PPKRDR ppRdr) { int rc; /* * Try open the file. */ rc = kRdrOpen(ppRdr, pszFilename); if (!rc) return 0; /** @todo deal with return codes properly. */ if (rc >= KERR_BASE && rc <= KERR_END) return rc; return KLDR_ERR_MODULE_NOT_FOUND; } /** * Composes a filename from the specified directory path, * prefix (optional), name and suffix (optional, will try with and without). * * @param pchPath The directory path - this doesn't have to be null terminated. * @param cchPath The length of the path. * @param pArgs The search argument structure. * * @returns See kldrDyldFindTryOpen */ static int kldrDyldFindTryOpenPath(const char *pchPath, KSIZE cchPath, PCKLDRDYLDFINDARGS pArgs) { static char s_szFilename[1024]; char *psz; int rc; /* * Ignore any attempts at opening empty paths. * This can happen when a *Dir globals is empty. */ if (!cchPath) return KLDR_ERR_MODULE_NOT_FOUND; /* ignore */ /* * Limit check first. */ if (cchPath + 1 + pArgs->cchMaxLength >= sizeof(s_szFilename)) { KLDRDYLDFIND_ASSERT(!"too long"); return KLDR_ERR_MODULE_NOT_FOUND; /* ignore */ } /* * The directory path. */ kHlpMemCopy(s_szFilename, pchPath, cchPath); psz = &s_szFilename[cchPath]; if (psz[-1] != '/' #if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS && psz[-1] != '\\' && psz[-1] != ':' #endif ) *psz++ = '/'; /* * The name. */ if (pArgs->cchPrefix) { kHlpMemCopy(psz, pArgs->pszPrefix, pArgs->cchPrefix); psz += pArgs->cchPrefix; } kHlpMemCopy(psz, pArgs->pszName, pArgs->cchName); psz += pArgs->cchName; if (pArgs->cchSuffix) { kHlpMemCopy(psz, pArgs->pszSuffix, pArgs->cchSuffix); psz += pArgs->cchSuffix; } *psz = '\0'; /* * Try open it. */ rc = kldrDyldFindTryOpen(s_szFilename, pArgs->ppRdr); /* If we're opening an executable, try again without the suffix.*/ if ( rc && pArgs->cchSuffix && (pArgs->fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE)) { psz -= pArgs->cchSuffix; *psz = '\0'; rc = kldrDyldFindTryOpen(s_szFilename, pArgs->ppRdr); } return rc; } /** * Enumerates the specfied path. * * @returns Any return code from the kldrDyldFindTryOpenPath() which isn't KLDR_ERR_MODULE_NOT_FOUND. * @returns KLDR_ERR_MODULE_NOT_FOUND if the end of the search path was reached. * @param pszSearchPath The search path to enumeare. * @param pArgs The search argument structure. */ static int kldrDyldFindEnumeratePath(const char *pszSearchPath, PCKLDRDYLDFINDARGS pArgs) { const char *psz = pszSearchPath; for (;;) { const char *pszEnd; KSIZE cchPath; /* * Trim. */ while (*psz == ';' || *psz == ':') psz++; if (*psz == '\0') return KLDR_ERR_MODULE_NOT_FOUND; /* * Find the end. */ pszEnd = psz + 1; while ( *pszEnd != '\0' && *pszEnd != ';' #if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS && ( *pszEnd != ':' || ( pszEnd - psz == 1 && ( (*psz >= 'A' && *psz <= 'Z') || (*psz >= 'a' && *psz <= 'z') ) ) ) #else && *pszEnd != ':' #endif ) pszEnd++; /* * If not empty path, try open the module using it. */ cchPath = pszEnd - psz; if (cchPath > 0) { int rc; rc = kldrDyldFindTryOpenPath(psz, cchPath, pArgs); if (rc != KLDR_ERR_MODULE_NOT_FOUND) return rc; } /* next */ psz = pszEnd; } } /** * Resolve default search method, prefix and suffix. * * @returns 0 on success, KERR_INVALID_PARAMETER on failure. * @param penmSearch The search method. In/Out. * @param ppszPrefix The prefix. In/Out. * @param ppszSuffix The suffix. In/Out. * @param pszName The name. In. * @param fFlags The load/search flags. */ static int kldrDyldFindGetDefaults(KLDRDYLDSEARCH *penmSearch, const char **ppszPrefix, const char **ppszSuffix, const char *pszName, KU32 fFlags) { unsigned fCaseSensitive; /* * Fixup search method alias. */ if (*penmSearch == KLDRDYLD_SEARCH_HOST) #if K_OS == K_OS_DARWIN /** @todo *penmSearch = KLDRDYLD_SEARCH_DARWIN; */ *penmSearch = KLDRDYLD_SEARCH_UNIX_COMMON; #elif K_OS == K_OS_FREEBSD \ || K_OS == K_OS_LINUX \ || K_OS == K_OS_NETBSD \ || K_OS == K_OS_OPENBSD \ || K_OS == K_OS_SOLARIS *penmSearch = KLDRDYLD_SEARCH_UNIX_COMMON; #elif K_OS == K_OS_OS2 *penmSearch = KLDRDYLD_SEARCH_OS2; #elif K_OS == K_OS_WINDOWS *penmSearch = KLDRDYLD_SEARCH_WINDOWS; #else # error "Port me" #endif /* * Apply search method specific prefix/suffix. */ switch (*penmSearch) { case KLDRDYLD_SEARCH_KLDR: if (!*ppszPrefix && kLdrDyldDefPrefix[0]) *ppszPrefix = kLdrDyldDefPrefix; if (!*ppszSuffix && kLdrDyldDefSuffix[0]) *ppszSuffix = kLdrDyldDefSuffix; fCaseSensitive = 1; break; case KLDRDYLD_SEARCH_OS2: if (!*ppszSuffix) *ppszSuffix = !(fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE) ? ".dll" : ".exe"; fCaseSensitive = 0; break; case KLDRDYLD_SEARCH_WINDOWS: case KLDRDYLD_SEARCH_WINDOWS_ALTERED: if (!*ppszSuffix) *ppszSuffix = !(fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE) ? ".dll" : ".exe"; fCaseSensitive = 0; break; case KLDRDYLD_SEARCH_UNIX_COMMON: fCaseSensitive = 1; break; default: KLDRDYLDFIND_ASSERT(!"invalid search method"); return KERR_INVALID_PARAMETER; } /* * Drop the suffix if it's already included in the name. */ if (*ppszSuffix) { const KSIZE cchName = kHlpStrLen(pszName); const KSIZE cchSuffix = kHlpStrLen(*ppszSuffix); if ( cchName > cchSuffix && ( fCaseSensitive ? !kHlpMemComp(pszName + cchName - cchSuffix, *ppszSuffix, cchSuffix) : !kHlpMemICompAscii(pszName + cchName - cchSuffix, *ppszSuffix, cchSuffix)) ) *ppszSuffix = NULL; } return 0; } /** * Locates an already open module using the specified search method. * * @returns 0 and *ppMod on success, non-zero OS specific error on failure. * * @param pszName Partial or complete name, it's specific to the search method to determin which. * @param pszPrefix Prefix than can be used when searching. * @param pszSuffix Suffix than can be used when searching. * @param enmSearch The file search method to apply. * @param fFlags Search flags. * @param ppMod Where to store the file provider instance on success. */ int kldrDyldFindExistingModule(const char *pszName, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRDYLDMOD ppMod) { int rc; unsigned fOS2LibpathStrict; *ppMod = NULL; /* * Don't bother if no modules are loaded yet. */ if (!kLdrDyldHead) return KLDR_ERR_MODULE_NOT_FOUND; /* * Defaults. */ rc = kldrDyldFindGetDefaults(&enmSearch, &pszPrefix, &pszSuffix, pszName, fFlags); if (rc) return rc; /* * If this isn't just a filename, the caller has specified a file * that should be opened directly and not a module name to be searched for. * * In order to do the right thing we'll have to open the file and get the * correct filename for it. * * The OS/2 libpath strict method require us to find the correct DLL first. */ fOS2LibpathStrict = 0; if ( !kHlpIsFilenameOnly(pszName) || (fOS2LibpathStrict = ( enmSearch == KLDRDYLD_SEARCH_OS2 && kLdrDyldOS2LibpathStrict[0] == 'T') ) ) { PKRDR pRdr; if (fOS2LibpathStrict) rc = kldrDyldFindDoDllSearch(pszName, pszPrefix, pszSuffix, enmSearch, fFlags, &pRdr); else rc = kldrDyldFindTryOpen(pszName, &pRdr); if (!rc) { /* do a filename based search. */ const char *pszFilename = kRdrName(pRdr); const KSIZE cchFilename = kHlpStrLen(pszFilename); PKLDRDYLDMOD pCur; rc = KLDR_ERR_MODULE_NOT_FOUND; for (pCur = kLdrDyldHead; pCur; pCur = pCur->Load.pNext) { if ( pCur->pMod->cchFilename == cchFilename && !kHlpMemComp(pCur->pMod->pszFilename, pszFilename, cchFilename)) { *ppMod = pCur; rc = 0; break; } } kRdrClose(pRdr); } } else { const KSIZE cchName = kHlpStrLen(pszName); const KSIZE cchPrefix = pszPrefix ? kHlpStrLen(pszPrefix) : 0; const KSIZE cchSuffix = pszSuffix ? kHlpStrLen(pszSuffix) : 0; const char *pszNameSuffix = kHlpGetSuff(pszName); PKLDRDYLDMOD pCur = kLdrDyldHead; /* * Some of the methods are case insensitive (ASCII), others are case sensitive. * To avoid having todo indirect calls to the compare functions here, we split * ways even if it means a lot of duplicate code. */ if ( enmSearch == KLDRDYLD_SEARCH_OS2 || enmSearch == KLDRDYLD_SEARCH_WINDOWS || enmSearch == KLDRDYLD_SEARCH_WINDOWS_ALTERED) { const unsigned fNameHasSuffix = pszNameSuffix && kHlpStrLen(pszNameSuffix) == cchSuffix && !kHlpMemICompAscii(pszNameSuffix, pszName + cchName - cchSuffix, cchSuffix); for (; pCur; pCur = pCur->Load.pNext) { /* match global / specific */ if ( !pCur->fGlobalOrSpecific && !(fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE)) continue; /* match name */ if ( pCur->pMod->cchName == cchName && !kHlpMemICompAscii(pCur->pMod->pszName, pszName, cchName)) break; if (cchPrefix) { if ( pCur->pMod->cchName == cchName + cchPrefix && !kHlpMemICompAscii(pCur->pMod->pszName, pszPrefix, cchPrefix) && !kHlpMemICompAscii(pCur->pMod->pszName + cchPrefix, pszName, cchName)) break; } if (cchSuffix) { if ( pCur->pMod->cchName == cchName + cchSuffix && !kHlpMemICompAscii(pCur->pMod->pszName + cchName, pszSuffix, cchSuffix) && !kHlpMemICompAscii(pCur->pMod->pszName, pszName, cchName)) break; if ( fNameHasSuffix && pCur->pMod->cchName == cchName - cchSuffix && !kHlpMemICompAscii(pCur->pMod->pszName, pszName, cchName - cchSuffix)) break; if (cchPrefix) { if ( pCur->pMod->cchName == cchName + cchPrefix + cchSuffix && !kHlpMemICompAscii(pCur->pMod->pszName, pszPrefix, cchPrefix) && !kHlpMemICompAscii(pCur->pMod->pszName + cchPrefix, pszName, cchName) && !kHlpMemICompAscii(pCur->pMod->pszName + cchPrefix + cchName, pszSuffix, cchSuffix)) break; if ( fNameHasSuffix && pCur->pMod->cchName == cchName + cchPrefix - cchSuffix && !kHlpMemICompAscii(pCur->pMod->pszName, pszPrefix, cchPrefix) && !kHlpMemICompAscii(pCur->pMod->pszName + cchPrefix, pszName, cchName - cchSuffix)) break; } } } } else { const unsigned fNameHasSuffix = pszNameSuffix && kHlpStrLen(pszNameSuffix) == cchSuffix && kHlpMemComp(pszNameSuffix, pszName + cchName - cchSuffix, cchSuffix); for (; pCur; pCur = pCur->Load.pNext) { /* match global / specific */ if ( !pCur->fGlobalOrSpecific && !(fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE)) continue; /* match name */ if ( pCur->pMod->cchName == cchName && !kHlpMemComp(pCur->pMod->pszName, pszName, cchName)) break; if (cchPrefix) { if ( pCur->pMod->cchName == cchName + cchPrefix && !kHlpMemComp(pCur->pMod->pszName, pszPrefix, cchPrefix) && !kHlpMemComp(pCur->pMod->pszName + cchPrefix, pszName, cchName)) break; } if (cchSuffix) { if ( pCur->pMod->cchName == cchName + cchSuffix && !kHlpMemComp(pCur->pMod->pszName + cchName, pszSuffix, cchSuffix) && !kHlpMemComp(pCur->pMod->pszName, pszName, cchName)) break; if ( fNameHasSuffix && pCur->pMod->cchName == cchName - cchSuffix && !kHlpMemComp(pCur->pMod->pszName, pszName, cchName - cchSuffix)) break; if (cchPrefix) { if ( pCur->pMod->cchName == cchName + cchPrefix + cchSuffix && !kHlpMemComp(pCur->pMod->pszName, pszPrefix, cchPrefix) && !kHlpMemComp(pCur->pMod->pszName + cchPrefix, pszName, cchName) && !kHlpMemComp(pCur->pMod->pszName + cchPrefix + cchName, pszSuffix, cchSuffix)) break; if ( pCur->pMod->cchName == cchName + cchPrefix - cchSuffix && !kHlpMemComp(pCur->pMod->pszName, pszPrefix, cchPrefix) && !kHlpMemComp(pCur->pMod->pszName + cchPrefix, pszName, cchName - cchSuffix)) break; } } } } /* search result. */ if (pCur) { *ppMod = pCur; rc = 0; } else rc = KLDR_ERR_MODULE_NOT_FOUND; } return rc; } kbuild-3149/src/lib/kStuff/kLdr/kLdrHlp.h0000644000175000017500000000042513252530254020112 0ustar locutuslocutus int kldrHlpGetEnv(const char *pszVar, char *pszVal, KSIZE cchVal); int kldrHlpGetEnvUZ(const char *pszVar, KSIZE *pcb); void kldrHlpExit(int rc); void kldrHlpSleep(unsigned cMillies); char *kldrHlpInt2Ascii(char *psz, KSIZE cch, long lVal, unsigned iBase); kbuild-3149/src/lib/kStuff/kLdr/tg/0000755000175000017500000000000013252530254017012 5ustar locutuslocutuskbuild-3149/src/lib/kStuff/kLdr/tg/KLDRSTATE.txvstc0000644000175000017500000011461313252530254021632 0ustar locutuslocutus kbuild-3149/src/lib/kStuff/kLdr/tg/kLdr.tws0000644000175000017500000000025413252530254020446 0ustar locutuslocutusworkspace.diagram.active = workspace.diagram.open.0 = kbuild-3149/src/lib/kStuff/kLdr/tg/default.txvpck0000644000175000017500000000044013252530254021675 0ustar locutuslocutus kbuild-3149/src/lib/kStuff/kLdr/tg/kLdr.tpr0000644000175000017500000000370713252530254020444 0ustar locutuslocutus[Project] Language=cpp Root.0=$PROJECT_DIR$ Root.0.access=writable Root.0.file_types=cpp_source;cpp_header;diagram Root.0.package_prefix= Version=3.0 projectfile.encoding=MS932 Root.1=$TGH$/jdk/jre/lib/rt.jar Root.1.access=import Root.1.non_removable= [workspace] Developer.CodingWorkspace={{0,2,-1,0,0,0,0,0,0,1,0,50,75,25,-1,-1,-1,-1}${0,1,-1,0,0,0,0,1,0,1,0,50,75,25,-1,-1,-1,-1}${0,3,-1,0,0,0,0,1,0,1,0,66,50,25,-1,-1,-1,-1}${0,3,-1,0,0,0,0,1,0,1,0,66,50,25,-1,-1,-1,-1}${0,-1,-1,0,0,0,0,0,0,1,0,5,5,5,-1,-1,-1,-1}${0,5,-1,0,0,0,0,0,0,1,0,50,50,25,-1,-1,-1,-1}${0,4,-1,0,0,0,0,1,0,1,1,66,50,25,-1,-1,-1,-1}${0,7,-1,0,0,0,0,0,0,1,0,50,50,75,-1,-1,-1,-1}} Developer.DebugWorkspace={{0,2,-1,0,0,0,0,0,0,1,0,50,75,25,-1,-1,-1,-1}${0,1,-1,0,0,0,0,1,0,1,1,50,75,25,-1,-1,-1,-1}${0,3,-1,0,0,0,0,0,0,1,0,50,50,25,-1,-1,-1,-1}${0,3,-1,0,0,0,0,0,0,1,0,50,50,25,-1,-1,-1,-1}${0,-1,-1,0,0,0,0,0,0,1,0,5,5,5,-1,-1,-1,-1}${0,4,-1,0,0,0,0,0,0,1,0,50,50,25,-1,-1,-1,-1}${0,0,-1,0,0,0,0,1,0,1,0,75,5,5,-1,-1,-1,-1}${0,7,-1,0,0,0,0,0,0,1,0,50,50,75,-1,-1,-1,-1}} Developer.DesignWorkspace={{0,2,-1,0,0,0,0,1,0,1,0,50,75,22,-1,-1,-1,-1}${0,1,-1,0,0,0,0,0,0,1,0,50,75,22,-1,-1,-1,-1}${0,3,-1,0,0,0,0,1,0,1,0,50,50,22,-1,-1,-1,-1}${0,3,-1,0,0,0,0,1,0,1,0,50,50,22,-1,-1,-1,-1}${0,-1,-1,0,0,0,0,0,0,1,0,5,5,5,-1,-1,-1,-1}${0,4,-1,0,0,0,0,1,0,1,1,50,50,22,-1,-1,-1,-1}${0,0,-1,0,0,0,0,0,0,1,0,75,5,5,-1,-1,-1,-1}${0,7,-1,0,0,0,0,0,0,1,0,50,50,75,-1,-1,-1,-1}} Developer.kLdr={{0,2,-1,0,0,0,0,1,0,1,1,50,75,22,-1,-1,-1,-1}${0,1,-1,0,0,0,0,0,0,1,0,50,75,22,-1,-1,-1,-1}${0,3,-1,0,0,0,0,1,0,1,0,50,50,22,-1,-1,-1,-1}${0,3,-1,0,0,0,0,1,0,1,0,50,50,22,-1,-1,-1,-1}${0,-1,-1,0,0,0,0,0,0,1,0,5,5,5,-1,-1,-1,-1}${0,4,-1,0,0,0,0,1,0,1,0,50,50,22,-1,-1,-1,-1}${0,0,-1,0,0,0,0,0,0,1,0,75,5,5,-1,-1,-1,-1}${0,7,-1,0,0,0,0,0,0,1,0,50,50,75,-1,-1,-1,-1}} names.Developer={kLdr,DesignWorkspace,CodingWorkspace,DebugWorkspace} [vcs] provider.class=CVS LAN [lastOpenProjectName] Developer=kLdr [model] showDiagramContents=true kbuild-3149/src/lib/kStuff/kLdr/tg/KLDRSTATE.gif0000644000175000017500000003372613252530254021051 0ustar locutuslocutusGIF89adf÷ÿÿÿ€,dfþH° Áƒ*\Ȱ¡Ã‡@œH±¢Å‹3jÜȱ£Ç CŠI²¤É“¨\‰²¥Ë—0cÊœI³¦Í›8G®Ü©2§ÏŸ@ƒ J´¨Ñšÿl´N6ƒzôÒ Ý[ÑLG}eÒRWí‘Ó0¡lõÖa!Ô\ÓˆñØd{í’Öa÷hvªT§­pQkŸ”¨ÒnÇw×é‚]·þ‹·i57Ý{³x·Eƒ7]©ÞŸX8ÞRý xâ(.Þµä©:¹”S$@Ùœ“}øç—«ýÔ礗nú騧®zê¡cÕê°—îx촷α_™Ûbî9ñ®û†¾3ù{ÂÁ9|θ|_Å+¯`óR:¿-ôYJŸ,õ°Zÿ+ö½1Ýù÷à‡/þøä—Ý{òKs¿\ðêGè½è8µöû5²þÑòg?óô‹}>ÿ郟ðô’?P8û« ~L¶ªNlwÿS Ã*P7 ” Ä¦×² b0‚ôÐ:£ j0b|˜à@xBnï]+ŒŸ—T8BFŽ…\YÊ@äÁݘ0‡þ|¡[ôC¾ŒxG¼¡ ˜D 5qDE ¡ÑzÈ›(¥|X¬Êu²ÈÅ,†ÇŠ?¡bË #Æ]Œ8lUtʈ4î q€ñi1ãÆ4ú=lj#‰³¤¤ ‹"Ù¡ÕvÞˆ”ˆ0‹ŽTyÜS‚-cCWSäq½^’eqjÖÌä3Ä^ñq8Øš&Gé,fq2ˆŒ³%«çI2LdÎzɺ&ÉÚôñQ!—.c2Wii‹v ¦®\‰Ë]Êrƒ½ª%múh•!ó˜Îtaª”éa‘XÄì¿ö4°1&“š¯¹e± %±n ,`Ò$âhMã9Ä•Û4& Kö•uN”$þ,æÈ^éH_ÚÓFí,¤'!ö-Xt—OLÎ?ÉÏrîSO³ŒfB¹Ð*´’ï„Y¤4ÉÉSm>l(µšEJkÁÉ”ÏB%EÁiÑ%ÈŒÔIE[3G“€ô“. L'(S–Ò17ÝËÕÌ…®@ª%«Ì^ÞôÔ™6­#(tä°x—Ôî-µ85-IPµªÃimr˜œ")JfC«^(YõSS“Öž*–}h>s)QzÎ/§Wl;ų֩=ta“¼äéM³ºS§WÝ«a¶ªÇxžZ›Bg­Ð)BVž5Œ]ÌlUúzÍz–‹œuÔ_ÙO~Ú`½ìõZM¾úŸpuþ,¼:Xw‘£‡Íkb[»ØÐ"ª«·«>K 3¦S¨xE+kêÚcí·©El¶^ËÖ¦R÷¥ñ]U³¶Üß´uW¾…ÍvÝ·[æööº¶¼¨eýÞÐ|wAíuÍxï:]¦6·:óEn}±j]Uöî³dënK{ àX¿¹Uny½Û_"!8ººeo|;óÞìN3kË/Ró†^ÒT8’ŽK†Õ»ÞLξù† ]é6îÄ“L1Œ-3â亸U¤c·§9ãî°¸ÄD™(Z-'Ç2Ç›©±j…²9sÎtÑi²“§¼ÙÒqFÉ 6 í¶Ìå.÷:^³˜ÇÜåýX©£#³þéf§æ/W§Ípf3œU',Cx5ýûâ™ ‹#—ÇÏm±s‹íh=ÿyÏÜ þÌ#h :ÏgD4y éï4Í3\ô¡7lc)þ¬Ðh¹4ŸñÀMËÄfµ¥-iúfzЬæô’á¢ê:šÚ¦¨.K­ëSwZÄ•¶µ¯gý–]kÇØcu¢)]jò({Ò¯þt¯qýkZ›×²Î²§q†l±<ÛÕ}¾ö±[Mn;5ÛÐÃÖ6°ÏélßùÑì^µ»½íN[«¹”¸9oG×{cÝVL¹Óîx ›ÚÄNõ®Ø\1<ŽýÆ´µÇøpó:\Þ§w óYÃÊŽ;â£.6ÇþSèq~gÜßJ‚a £ê_/Þ,—¹0Žpuo¼¬/Ä9~^óGwy?ÿøÉ%ÄŠÇ8è&ï¹Æ‹-dVùëàø®¶’šÞ@ªë˜çQg¶¦uDþ—Ê`Çb¨ÃNö²s16]×cÂ!h£+¼QC9ѯ¬oþ´õÛi_j>ìvsŸ,ïz×¶¦ ©MQÇ<£ÎUQ3u•Ê©úu!“µú v\býÝåÐö÷à-ïÀwG¤Ãa¤¢ï`p¿JVÚ›ÔVÄ?)ÀŒk{ˆh²³7m¿xýå§>S€ªàKþ[WÓÂ5®sllG M»NôvÌ#]Ë_PÚš °ëå8Û/0ï‹¡Òú—žÝ|k_ªÏ$[Û$"Ä/ìg[Æ"[·ªåGÞWX(}#G~åG€¨u„uZ¸€çz™7w YãWx(|”EN(J‘G{*b°7Næ$‚x‚ïg‚38‚¶²|±eN8}¶e ÅXA–}ý·}¡”5¨r(XX3 Å€ž·@NM=8WÜYÈx!È„ø„Bó.n^gsgV…Qò71hõw€…~|H~%~óä~à·†9ˆ„?ø†÷g…ú'…¯W†ž÷þ#-3ã2.Ã|}8J¾§|’(\ñ—|3†r—G>؈Ñ'‰›X{X-ÀʼnÅÇ@‘‰µŠÖˆ–Ø‚„ˆˆÏuˆd(póŠ X]µˆ}˜7‹…H‹=c‹r‡‹¿¨‹È‹°è^˜Ø‹û!„ØUŒD(R•ŒÇXÌxc†È»˜dÒhŒÔ¸Y§t(ÇæÙèÕaàx‹âxeäèŒæØŽ±xá¸fWX\eú¸áƒÿ—ŽÁ¸ŽÚŒÊhç¨`î˜òXgþ¨vr¡WŽ éÖñhw UϨ‘fÈŽ9ô‘«%‘)–‘ÿø(ÉH$ùóè‘sˆþ "é'‹Ù`­' 3¹z¹v%9Ži’뱓>É’E¹È”7¹E+ùx?y6fGSMÙ“:)eü¨#Ké”/919 DÙ‘Ti“-9sÓ•*9•¢5‘H)”ÝqaÀç•nx7– ”h éfL1—jI‘y—a’z¹—Y9y<ùD–xÝ8˜KÁ—O!}÷%‰‘y,“)—…™–9a•WÙ™;ecÁ™ž9šúšÄø˜tys¶š¬Ùštv®›²9›´;fé’ØHµI:r¶›³ù¾œŸÓ›ÂYœqù–}Y—ë¶u膚ÉémûÖrÏ™’¤Æœí6E¨u°þvk¸¹•~·\—š§ÒÆk ’)gp؆C¥hàٜݩŽ"§žBçœöùvÖIsñó™ŸPwžl‰Ÿïy÷  7çŸëY ~ùoÄso*ž¾8 úù ì wúŸ ʟ鉠õ¹Ÿ9qštŠžz¡ :¢ªkѹsšÑÆmš¡ÚŸ&Ú¡ª É¶¢Òá˜(Z¢åžŠ—ð¢Ò‰£ãù¢öfž2J¢ßù£ðy£=ZwóGrªw¢Pz¥ŠY¥97¥Vº¤)ŠvÏ$s(¢Xªœ~g~4¦E¥Aª‹‡×@JH¦^š™j¤sN§kZ¦GÚBG…)3‡¡fʤ ‡tþ×S"• <ª§ÎE¨BÔ§W×¢íy’ç§“c˜Ft¨ÎQ©(f¤Ô9¤5*§ú¥°Bš„¡J¦ vv©BŠŽuºF‰¡©Õ¦Zi¯ú¨±êc¬j”ÍØ8Õ²Šzžê¢® y<8PšÈ6¿Š'‹€³:UÇŠxÉ*¬ÀJ§„7{4yÓJKËÊS;s­œÇ’Û*†lg­5‰„÷*ÜäˆÅT©Á:…¡4|¨hRŸx|’²®¨~±…¥a®4„ÏZ.x.ô÷y– €‡Û…†ê†³ÅKäÚ¯»Z«ùN*؃c€Ét°Ìjø—„ZøXº‡úšN¿$±´j˜¶Ê¯‡þ‚4¤±ï˜îXÏ"Y6øJ<˜‡#Eƒk~_¹¡Ã©+K‡oȰ/¦ ¨”åÊ…%G²¤U‚àg´‹´"³Ø:±*[¬¿'°[€oꊺpXØ}{¨‡U¨{iز‡÷³>ª¨ÄŠ®ÔÚ°çÔ‰%µ¯Ÿ§´ˆI´”¸ŠžH¯¢¨øZŠ|k¨ÏÁ¶Mê¶B«µb)†x‹²ä)‡Õе𩏹 ¹ ‡¤`¹);¹p{2V‹¹8™«’«¬½zŸ[plwºCû©ò –Ma¸fF–ªK¹¬«¡‹ûº³Ë ÷ʼn:§•»—¹»œˆ¼#¹¹¤©Z1ÄËtÉkË{˜¼z»Þ ¼«¹Ãþ[½¾Ê¦A«½G»FÞ+ Ü‹¸ã 7ÏÛ¶¼{¾®½¿Ûºj¢¾¡¾ðÛ¾YK¿3ŠcØ+º©›¿ã¯Tqµûu¹À:¿ÓK±îk¿æË¿O"» Œ¨þ›­«‹¨¬¢ ì¸å;ªÒÛ˜,¥×kÁä;¤)`!%»Í[v°œ£l½¼§)üb+ ûÛÀ·úµ ½Ý{œ7À3LªçZÀ|Œ™ïêŠ?|§7º9¬Á<,À…¡bì»Æ ø[Ä#ìZO¼ÀUÄÈÛ*—9IÁªH6ÅÌÄ"!š¤išÌ¡Æ%|V–·hü¯Maœ«yvœÇb¾Jœ®NášþÄ©fߡDzCÈqÌÇsü¿3 £JzÆ]|ÃŒ ¤ÛÛªÂ뤊Ão ª–<¡T<ÉȪyÚɘœ¥› ¨V<ÄgqÄö¤¢üÁŸ\Ê]êÈžœ“°l£­|Ë,L¤,úÈŠü¸I*É£Œ©ºÛq¬,ËÁ|›‘\̧l»‡ûËÊÜÄ@¡µ,ªË|¿è p1jÌ®LËÉ|ÉÛ\¿šÜÍœ¬Í¸Lú¼£}·„ÂHõÆîl1Ù\Í‚Ê`‰¬=DûÍœ‹«³lÏ¥·Ïù¼>éÌÏŽjÀÌÜÃø,Ð[{ÐàŠÎõŒÐ…UÎÐ ÅäìÐ^,ÏѼLÍϽ;Ñ Eq.Úy-ÌÑrÌ¥"Ò!Íþ¾ÉüEµi‰¦)½Ðþ|¼¿ Ó©dÓ1ÝË3-Óm§ÚºÄ9 ÁǬÒöõµÊjÔA-Ô ]Ñ{…ÔŒãÔIíÇCMÐüŨŒdÕQ­ÓS ÎG7ÐxƒÕYÂ+¸:Æ©TaÖaí¬c-ÒúƒÖ–¤Ê·ÓÐýLF$­==ÒÓÁÎi-ÖÑy=š{­ÔkMÉF¬×­Î}ÍÒd؇ЃMÔ‹ ØØxÍËdÉØ“Í´[ýϑ홙}};ÍÔñüÙ•MÕólʤí×mÍÏœÚdýئÝÈ®­ØªÚ¼5Û° ڌڸ½Ú´}Ú±ÜÛ„ýÛ «­RíWÁrÏhr×µÍÛMǰþ%Òp½brÜæ8×rë|tËOGt±êÚ1¹‡±­(@¶­Õïág«°G±4û²ñç°ë³õSך=m(ˆ#ë‡cKAZ‡‚ø€xjÞ›MÓøMzI؈#Øß‚e³ï±öw*n]!ÎMÜÂæ³ /ÞXc«‰! ‡Žm7ö­Ö¦†áíÚµ¬H°îíáMH%W®sÝ”žoê„뉂[&ŠGPn|£(3¨ã–Í×›ÕK]5þÚ±fä¹6IÎÖ\ÖÂ-ÝÎÓC¹ÝSåJ^Ðn4áYNâ¥]å›ZÝ—òäÃ-Û_nàM®æÝñÎQi×#S4fÝÒcæ¾íºêÈ{„ʃélîèM(/jˆ.þ„階ÊA–Ä4î!H¦ÔŠ®„ß ñØ •^? ß!ò.Øtt1Æ4Œ®EQÂQF¯¢‘'wÌq w$ò wúH!—,²É ÓÛÏÆ™ÌI+‘\ñIÿš|¨Ë+¿ÌéHí(ŒÑË*ÁD3&1Ã$ÓE3‡LSÇ5qJþ’H…îŒ3O“æÌ’>'ñ„SO7û¬qË?TÐù„ÒP.U4Òõõ±Í)%ÅtFJ±”Ò;D?5TQG%µTSOE5UUW5Só%¯SÌ%ŒVW½‚U¦:7³µÖ[¹ËUMKëµ°bÝmÓ1emŒ¹ŸÞ|±9ô˜:Ùùì#ÑÑYV®´ÀÚå”e“Yb¡¼S£tñtRi×…ÔKwÛ=“[q{ VDs s–Þ*¡=àwý}“=pï \:‡5]&~XÚ–ØàpÆWa‰ë¬_Šÿ­øÓ‰?V·â0¸ã7ŽU[É<.d™e6säš-NYå×òÅö9ïþž`w!¾ù]œu^ÙÞ ö5Ö˜»d·&våmµhzFzg–ueZ°j…¥嬵VºPŸyåUä“s»ã­Áv9ÃÁe»m´Ë®t߆1¤ÛîÓxÞ³ëÀ¾®Ul¿ÝƛӸ!#Ükÿ»eovîÇ!ùm})'–UÏ?=tÑE¿sÆ5ïyÒ-¯Ût~Q\ï¦/ìÛu¹_–ó×ù.Ýö½%×òìmyoÝ÷ÁaJv¯Y7¾rÜËÕý÷ ko^z¸'>sâ«ßø¥•?~{îgç:Êèɇúñõ<ùó—ç}tùç§¿~ûïŸ÷ççŸ}æÇn\ì¼g6Õ!nz(+Þ½þè¾òe+{·;`ï0¶@’´¯‚‚ ߃è&A!µÊ6cý·ºý!á·˜@†Ç…sû› 1øÂhƒ¤’Jæu³üÅ+D)|ŸŸ°W@Q+ˆZ! [H2›í‡5`Þ‚hàÏŠW´bqØÁüElfVƒ! £¨¸–F‹gDcÕ¸F6¶Ño„#+“µ¬Ž9¤8D!Ê&Ž„ã 9HB®cTÚ´ŒH—Eöqs|4ЗÙô ­‰ÿšdfôx½àñOÃÎÔB†£¨ñm“ì¤#‹”IÓ±#œ¡·$¹>Úœ2uß›"ˆ\ ¹]R²„¿´Ð,iþyD[ ’é¥õ†I­b20•‘¼R2í&Í`Ž1we”Ó2±BÍ9Zzؼ”6›ÂÍíñ™È9‘¦NYz“¹ £8™)Fsâœe’ç8›yAóÝsPù¼ëI@UÚ  =0ŠNaô˜ u§ §e%vª¬¢ÝЍBËùI‡>Ôyi7)ÚQžK£¨,¨’HjÏÈ-”ŒžäÒJY J—^¦«”)AµRN¦4›9})M{ªS†F¨AÝiM¿ySƒu©BE)Q5ÕP§ž4>…gÓYÕwê§Q-ªJAxQIi‰ÝSjW™º(•´•«%2+DÓŠU·âÔdoeLÌ’:þT)úS—ˆÄk^ñøÑ¹ZU«­Y`ý“Xò©am*cKÉÖ±6õ)[g6YÕUÖ¤_½%4cZJÎNŠ´ëc§úÉÓ–­µlj1+ÚG‘ÕZjójaA{XŠvѵ/ñ-jCÛ×µþô·ýSa™Ù aѹÏߢ ;]ê×—»].m  Û"t\Ú®j_™šîζAåE®pèZ\í?è%îxøËôò6·Ç±®HKz¢îmœç{5x‘…öv²|ì.‡»µí—°µãݘӎwÒãžv’ÇfèO)úÝ}.ï¸?Yáëûãíþw·»Yé_Ÿ¸áé¾o¨O¾ðöúŒßN6'þžòR <ºÏ¾Å´^êC6}¹·žú®¯>æ´žë_{i÷Øây§:·ÿ*Þ¼÷ðþl…¯z`ŸáÇÿ=èm¿üÚ7ŸíïŽ~Ùzä3žø×?z›³.}îž<Ú?Ïó«lüB{æ·Ï4éß³A¿Ëžì´7»ÐåXùí[üQ_¿×Ë¿µ3?r#¯:3$É«¹ð‹¿þ+½ýã¿LŽ:·@Ü>,@”¿uK¢ ì< |ºŽÑ½õ¤ìœu;AT<($D¤©9¤ªê+Dñ»¦‚<5äÃ'DÂü§G<ÄH\DêAGÔÃD”@FlÁÑĤÄAœÄîSÀ˜BÄRTÄStB< §NdÅOÔD¿QÔ¼H–¤I—lE˜¬ÇM,ÉÄFP Á¢üÆXŒ+Äž¬E£I‰+×cCïJ>[tÊiÔ¬hJ‚$Êy´Ê£ 'hÜÊ|ÜÅ”TÆ…|"nËš,KŸÄÉ•4ˆ1Ik´Iu¼Àü§~Dɬ|ɦôÊFœ’^«CŒ¬K´¼Ky|"ÁÜK¨D?¿ŒÉ³”lKÆÌ”I’¼É$?dÊ›”D ¤Ë$ËÍ4ËœdÈ´ÑÁþÔŒ®«œžÆôLoº©4LÓäËδKÏûGÛŒ¸Ç$ÌÉ|ÍSL9ÙtLÀHÒtËÏÄ˪ä"Í43à•ÛÔË[œÍ´\ÌßíQfmPQ]Uý,¿pU$1»PNƒG6UÊÊtU{ÅWm}¸[µ@´…WŽ]NF“Ø}Ë4üÒïÃX+]Q8]Q#íÒ|ÍU½WseÕ„=YUëW€•²?›ÒÝÖ«ÖŠ%Îb·pUQ^«1ú¼::ZƒØzý–Š„Y õÙ‡ûÕ˜ÍHH•Ún¥Ø™ÕÀo!Ô¦ Ù0-Xœ#UÜ8ÂirZ ÜQ™ýVN=Û¶Ö][Ã+[aü@^JÛq%YÔÀÁZõÛSáÁcÍÛ  Un%Œ.DÜÄ…#׉[EÍÖå Åu#.”ÜAòÆÔ‘ÝÚÚ<.0­ ¨E×e-ÎÎZþ„MUÇ…\Î%]]M×hÛ;íÍÕ ÝQݬ=XÕ•]Ûµ²de]ÑÝÜÝ\øáÝÒ Þ%^ÃÝ]×õ\õÒãÕݵPÈޕЙt^¶Ù‚EÞmÈêU[¡Å^é½Ý>åÞâµX¹…M\_ßåZÍ•UOM_í%X9Ýð5Þ÷íÞõý^âÝNµ_ú-_Ô]ÞºÉþÅ\­mßSí_ФÖåÍ^Øåßv`Óe_åeÞ¿‚`õ•àü_^Ý nÙ©¥àžÖ ôà aó]T÷½à>ÝÌ…ßö`ž`V`ŽáÁÅ`8àµM`Öàç`Ü-a¦ÝŸµÞý¥Þ!N]á aðåþàúÍP%þà"Þ ~a(ÖÎÆáéÕá`ËöaùâÎÊ/¾á°e`'¾bÊŒNÞbÿ`"Ö Kã7~âÂUãSË:FcƒaÂeLÅìa;^ã½5(Avã>áÇâéaNî ã‰Ebò›G®ÞHfd?.d!æãžÕ_ >¼¿eÏa\Bâ6åˆÅ[EÎãN嵄ÛW^bPVe\Vþdžåÿ5A­Ó6nbÆ_1>âûÍ`MÎe¸¨Z>fI6fJ>aþPÓ÷|2ª¡ÐŽ´æwÕåg•åFþãfb6+P‚ PICÐcSf´Åe+>ßu.'~MÐ/žQ3ŽŠeÍøþuf½…f*f ¢]Ó e±yÞå¾pÖ{n[bÞg8Žf¸ZØxFÙ ¥g¢³ç]`dvå’•êf£ngOv[¡¦ê1îé¨Þ˜Öi™&é¬jë³jŒæé¯èøå´&œÞÞfj~æpV×uŠê^Ù·®j¨ëIFeÝ„=¶¶áaÎg@Nèä½<½¾j¢Žc¥F@À†aÁžé²®iMBjºÞ븦åËN?Çþ݃ì¦Ögþ¹¾XÄ&ë·na.í§N꺦J¬6‹ ®nk¯^jv.iÈŽ¼ÕÖlÂîk¬õ¿±ökÓþfÔvjÛãì¦m‹ëÝ6 $íà¶íåfn|y[alšVî³æe rƒÎW½Y›5³-²‡Åñ£®â_so®W ƒqAWZ¦5ô'/mF"s#wóæß«›n…†ëF¯òê ð2—ð¹«p íEÇlJ§ ñ×qfäH¿cCîêNNt>ówõ¾%¡,hð „ 2lèð!Ĉ`ñ"ÆŒ7rìèñ#È"G’,i#€“*W²Ü˜²%̘&_ʬió&Ê”4qòìéÓ"Š?‡-ês§Ñ¤‘*mš‘©Ó¨-^„*õêР±ríþzÔ«R«`¿Ž-ë’*J³jaj]ëö­K¸<ÅÊZ×+ZtïÖmË÷/^À1÷ I¸ðͼqÿõ»ô0ãÈ!!K~ZY%åË=3kvêø)çÎCW&}Ù´h¶©×~0p5l¨ÏŽ\;vÉÛ¸k:V¼ûwUàz…/&¾ÙøÕ¶¾‘ãÖ Ø¹`èÌÓNoT"öìÚ·sïîý;øð«»&oSºùÊѧË^îû¾íÏ'Ú;~}ÏÓñÃåOÜ}­½–Ÿmû‘ p¶×ZU ˜˜Õ9ØÜƒ› ÕÑr¾5a`j8Ó‡‰]¨‡!®T"W(v¥¢h,'`†&ºåbT4Jeciþ2ÊtŸŽÏEøc9•P1ÉÈá(Ù’»]'”QJ9%•UZiÐG ©åIëq)sM†õåpd’Ä£™j‰YÔšFµ]š†”‘qZ—ä‹v–§§zsæÄgrxþ§ç›©1ø' w†™¥…¶ègƒ‰Ö(¨pŽòe©f0bä¦zب¤KXg¨öQš ¡¥êUd§Z¶Ê£q¾J›WÚz+®¹ê e¬iΊ˜—ª*¬Y¿ªI,Pmåš±&6Kæ³cE{—VËÒ9m~Ø©íŠÄVk-¢ÈþÄ-§€’[ַ껨¸î%ºîŠÊBÚnRð:+)©C $/¸ôŽéoŠ¡Öº+þÁRò;/À¦&<¬À;ü0ÄK<1Å[|1 g¥ñÄbüñÅß‚<2Éòr<éÉŠ¦ÌæÊå¶ìæË Ç¢½4Ï<îÍ6çLÖΞöL`ÍýàÐ?ƒh´ÏH«¦ô|EÍ4}P§ç4ÐRÛeu¯Xw©5f\Ÿêµz`ç&vždŸi¶HT›­v€hOæöol7 wØtÇ&÷‚vo©·¡|ïíwp€&x™„ïi8“ˆn8Þ^7nÞã•R”âpV9ª‹^9µœcžùáŸ#-º’‚Ót:ç>^NøK­§®ºâ¤;Iùæ¯Ãç9ë´Ëþóî’箓íáþ{íÁo8<ëùïîêŒ+¿þ|·Í3}çÒóY0öS¦Þ;è©â‹<âܳ$þŽÖOェäæþÝè³¶Ü€ý…¾™Ž¢¾8¦A»ûèZV{þö7?P!©8—ê—ÝØ·¾þI«A®{é¦ÀÕL0m3ú߯· ¶ˆÌ Rò—1´qpp,àæîן®~Ðêüž—"’­„™ò`¨4è6ž‡ø¢¡Øx˜£z ˆ`bâˆ(,’Ð…_Bb—Œè8'r Š3‘"׬,¾ ‹ZÓbaÀèÀ쑱J^Äšaç«v1±…æ{¡¸ÚXC*ºŠg´Z…§ÄôÝQjy¼Í5BîìÕ“•#HÈžþLˆŒ£Ÿâ7Ç7>1‘‘’ ·eÉEB­‘·Ûc©žTÆQ’Ò;™Ô×&=I=ý€ò‡£Rå*aÖÊ.F’“±LÙaY“å–4•¥._Žî]9ä1'i®\Š,™ÊÔÀJ)͆8Ì™ATUɲ©Ímr“—Ö<¢Çº™M‘‰³œû¦ˆÎuž‡ì|'¬ÏyŽÏô¼çÑÔ‰Ï}ÖMŸüügárÐÐt=èäŠÐƒê²X EhCý÷P‚F´hE?xQ~f´Cå¨=?ŠÏŽFO¤# ©IçIRVÒ®¥)EçJU–—²3¦*S!M¿iÓ….§ëÜé¿èS Tþ¨Cu&P륻£•xIeª#¼§BU~ΣjUwÕ¬"¥\¥'§)Ö‡|Õ[Æü^YC Lµ¦­³ d[ëøVuIrlÅóHAò)³¸>²¯z5 ivÂé¯~­ß‰&?x{b쟌:Å è5Ž­¬æ¶fØ5ίԹZZ:-•Y.},SkÚžâ4Š›Elg1DüµT¨¢U-j?‹[Ü‚ö®¹‰àku”GÔ@%¯==®mk{ÚÖÍöZ¼MímäÜ 7±U.r±Û[Ýn)¹Kn§›58jö¹Ííh³»ZÁÒV½*l-fÂ+Þ¯¡²kgyo¤n[ÛË6×þ99c›Ùøw¾Ô…«DeI¤¸j±MQ]76ù6xPÂ¥KG¥[á©éË*¦ð†ãæ*ß|˜Á!æðáJŸ¸}õ pMÜb µÆ6¾ñvX<㾽ط®ÜñS<àËÈeëp-iälux)J^òÜ.ìYHÊ"攇ŸleÈ8ÉTÞrÞ„|Ú`‚ÅЂñu\æ0âÇZ^séz\b8ªŠ*>f•élB$›7ÆzfWb4ç?ÙY~3¡g‡e'9ѾãsBÓœgGÓæÌCÆ3¥»ggÓ2ÓqkóíéÊYÔ£¾¡˜9-ÈIŸÛ"±©[Ä@g¹Ñ²þ&µŒê4è[ïYÊ%3¯{Mk/#KÃÁŽê«/ýãc÷°Ô¶f¶m@mãXC;vhvµ_——ŒV+Ûžƒu±…émçý Ïjw! £Ët¡›zªlf»ÝÍLdÆ{•Ñ”ö4«YïXš³ßþî÷¾“ùï‘sàâ ¸x±Šp¿)|ázk¸Ã1ñ‰—›âWõÅñŒƒ“ã߸ǿr‹ƒ|ä~4ùÄKŽr¥©|åFk¹Ës„Ã|æ+c¯²mîiœYç­Æ¯Ï ô [¿D/ziÎk£+ýÖSmºÐËSs¨û+ÂT?µÕ¯>ê©kÝPøu×јðŸœ­d¹YÏ.sûô×0I“þ°Úo† ž[°nbuÜÓ÷ý6–¹Og–w%I• qýêsÇàs›\Ôm×–'Â{ÞÍŽ3îž7ñ¨ |ÎqRØÈßœeŸíïb±{ùk¥ãç97ç+¹×Ê—É»£/Þ-ùÔ_Ïó¢Çüqsßx£žöšd{]¿m þ¿‘ Kï}ï2T+ùÊ®°¥åüçßëÙÔg#µ¯?vëk_ï~î>ö¹þP~½üÆ?lÃ={ô/ÿûìO_ößÏYõËþâ¯ÿƒe5}ü—Èüw«ûý‚5Êþ `œÑŸ þ­_2™ú1`FYŒA`†Y0`jÚªa`j zSúʼ`ï¦É½™_é[ ê‰Áµ  ^Ì 6Ì BLÁÍ 6Å TáàfžZ¦þ … aY!^Ùr•&¡‹1aU-¡òX2N!óY¡OU!ÎÚÒ”vááGÑÝŠá±hNš¡C‰žRT{µ!C%º!ëÍá?1Ôßå¡^r”ãýa2e žT!Þ!–â=—"ªTÅ5â ö™éAbð˜qM"%nÏ…^&“%^bv¢§$Dæ‰"ò D)š¢=D*ª¢<±bϹ¢íô]¤ÉâòˆE(Ú¢ÝI¢.ÊÛ%õ¢'¢;kbuild-3149/src/lib/kStuff/kLdr/kLdrDyldOS.c0000644000175000017500000000721113252530253020517 0ustar locutuslocutus/* $Id: kLdrDyldOS.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - The Dynamic Loader, OS specific operations. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include "kLdrInternal.h" #if K_OS == K_OS_OS2 # define INCL_BASE # define INCL_ERRORS # include #elif K_OS == K_OS_WINDOWS # undef IMAGE_DOS_SIGNATURE # undef IMAGE_NT_SIGNATURE # include #else # include #endif /** * Allocates a stack. * * @returns Pointer to the stack. NULL on allocation failure (assumes out of memory). * @param cb The size of the stack. This shall be page aligned. * If 0, a OS specific default stack size will be employed. */ void *kldrDyldOSAllocStack(KSIZE cb) { #if K_OS == K_OS_OS2 APIRET rc; PVOID pv; if (!cb) cb = 1 * 1024*1024; /* 1MB */ rc = DosAllocMem(&pv, cb, OBJ_TILE | PAG_COMMIT | PAG_WRITE | PAG_READ); if (rc == NO_ERROR) return pv; return NULL; #elif K_OS == K_OS_WINDOWS if (!cb) cb = 1 *1024*1024; /* 1MB */ return VirtualAlloc(NULL, cb, MEM_COMMIT, PAGE_READWRITE); #else void *pv; if (!cb) cb = 1 * 1024*1024; /* 1MB */ if (!kHlpPageAlloc(&pv, cb, KPROT_READWRITE, K_FALSE)) return pv; return NULL; #endif } /** * Invokes the main executable entry point with whatever * parameters specific to the host OS and/or module format. * * @returns * @param uMainEPAddress The address of the main entry point. * @param pvStack Pointer to the stack object. * @param cbStack The size of the stack object. */ int kldrDyldOSStartExe(KUPTR uMainEPAddress, void *pvStack, KSIZE cbStack) { #if K_OS == K_OS_WINDOWS /* * Invoke the entrypoint on the current stack for now. * Deal with other formats and stack switching another day. */ int rc; int (*pfnEP)(void); pfnEP = (int (*)(void))uMainEPAddress; rc = pfnEP(); TerminateProcess(GetCurrentProcess(), rc); kHlpAssert(!"TerminateProcess failed"); for (;;) TerminateProcess(GetCurrentProcess(), rc); #endif return -1; } void kldrDyldDoLoadExeStackSwitch(PKLDRDYLDMOD pExe, void *pvStack, KSIZE cbStack) { /*kHlpAssert(!"not implemented");*/ /** @todo implement this properly! */ kldrDyldDoLoadExe(pExe); } kbuild-3149/src/lib/kStuff/kLdr/kLdrModLX.c0000644000175000017500000026055613252530253020361 0ustar locutuslocutus/* $Id: kLdrModLX.c 102 2017-10-02 10:45:31Z bird $ */ /** @file * kLdr - The Module Interpreter for the Linear eXecutable (LX) Format. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include "kLdrInternal.h" #include /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** @def KLDRMODLX_STRICT * Define KLDRMODLX_STRICT to enabled strict checks in KLDRMODLX. */ #define KLDRMODLX_STRICT 1 /** @def KLDRMODLX_ASSERT * Assert that an expression is true when KLDR_STRICT is defined. */ #ifdef KLDRMODLX_STRICT # define KLDRMODLX_ASSERT(expr) kHlpAssert(expr) #else # define KLDRMODLX_ASSERT(expr) do {} while (0) #endif /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * Instance data for the LX module interpreter. */ typedef struct KLDRMODLX { /** Pointer to the module. (Follows the section table.) */ PKLDRMOD pMod; /** Pointer to the user mapping. */ const void *pvMapping; /** The size of the mapped LX image. */ KSIZE cbMapped; /** Reserved flags. */ KU32 f32Reserved; /** The offset of the LX header. */ KLDRFOFF offHdr; /** Copy of the LX header. */ struct e32_exe Hdr; /** Pointer to the loader section. * Allocated together with this strcture. */ const KU8 *pbLoaderSection; /** Pointer to the last byte in the loader section. */ const KU8 *pbLoaderSectionLast; /** Pointer to the object table in the loader section. */ const struct o32_obj *paObjs; /** Pointer to the object page map table in the loader section. */ const struct o32_map *paPageMappings; /** Pointer to the resource table in the loader section. */ const struct rsrc32 *paRsrcs; /** Pointer to the resident name table in the loader section. */ const KU8 *pbResNameTab; /** Pointer to the entry table in the loader section. */ const KU8 *pbEntryTab; /** Pointer to the non-resident name table. */ KU8 *pbNonResNameTab; /** Pointer to the last byte in the non-resident name table. */ const KU8 *pbNonResNameTabLast; /** Pointer to the fixup section. */ KU8 *pbFixupSection; /** Pointer to the last byte in the fixup section. */ const KU8 *pbFixupSectionLast; /** Pointer to the fixup page table within pvFixupSection. */ const KU32 *paoffPageFixups; /** Pointer to the fixup record table within pvFixupSection. */ const KU8 *pbFixupRecs; /** Pointer to the import module name table within pvFixupSection. */ const KU8 *pbImportMods; /** Pointer to the import module name table within pvFixupSection. */ const KU8 *pbImportProcs; } KLDRMODLX, *PKLDRMODLX; /******************************************************************************* * Internal Functions * *******************************************************************************/ static int kldrModLXHasDbgInfo(PKLDRMOD pMod, const void *pvBits); static int kldrModLXRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); static int kldrModLXDoCreate(PKRDR pRdr, KLDRFOFF offNewHdr, PKLDRMODLX *ppModLX); static const KU8 *kldrModLXDoNameTableLookupByOrdinal(const KU8 *pbNameTable, KSSIZE cbNameTable, KU32 iOrdinal); static int kldrModLXDoNameLookup(PKLDRMODLX pModLX, const char *pchSymbol, KSIZE cchSymbol, KU32 *piSymbol); static const KU8 *kldrModLXDoNameTableLookupByName(const KU8 *pbNameTable, KSSIZE cbNameTable, const char *pchSymbol, KSIZE cchSymbol); static int kldrModLXDoLoadBits(PKLDRMODLX pModLX, void *pvBits); static int kldrModLXDoIterDataUnpacking(KU8 *pbDst, const KU8 *pbSrc, int cbSrc); static int kldrModLXDoIterData2Unpacking(KU8 *pbDst, const KU8 *pbSrc, int cbSrc); static void kLdrModLXMemCopyW(KU8 *pbDst, const KU8 *pbSrc, int cb); static int kldrModLXDoProtect(PKLDRMODLX pModLX, void *pvBits, unsigned fUnprotectOrProtect); static int kldrModLXDoCallDLL(PKLDRMODLX pModLX, void *pvMapping, unsigned uOp, KUPTR uHandle); static int kldrModLXDoForwarderQuery(PKLDRMODLX pModLX, const struct e32_entry *pEntry, PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind); static int kldrModLXDoLoadFixupSection(PKLDRMODLX pModLX); static KI32 kldrModLXDoCall(KUPTR uEntrypoint, KUPTR uHandle, KU32 uOp, void *pvReserved); static int kldrModLXDoReloc(KU8 *pbPage, int off, KLDRADDR PageAddress, const struct r32_rlc *prlc, int iSelector, KLDRADDR uValue, KU32 fKind); /** * Create a loader module instance interpreting the executable image found * in the specified file provider instance. * * @returns 0 on success and *ppMod pointing to a module instance. * On failure, a non-zero OS specific error code is returned. * @param pOps Pointer to the registered method table. * @param pRdr The file provider instance to use. * @param fFlags Flags, MBZ. * @param enmCpuArch The desired CPU architecture. KCPUARCH_UNKNOWN means * anything goes, but with a preference for the current * host architecture. * @param offNewHdr The offset of the new header in MZ files. -1 if not found. * @param ppMod Where to store the module instance pointer. */ static int kldrModLXCreate(PCKLDRMODOPS pOps, PKRDR pRdr, KU32 fFlags, KCPUARCH enmCpuArch, KLDRFOFF offNewHdr, PPKLDRMOD ppMod) { PKLDRMODLX pModLX; int rc; K_NOREF(fFlags); /* * Create the instance data and do a minimal header validation. */ rc = kldrModLXDoCreate(pRdr, offNewHdr, &pModLX); if (!rc) { /* * Match up against the requested CPU architecture. */ if ( enmCpuArch == KCPUARCH_UNKNOWN || pModLX->pMod->enmArch == enmCpuArch) { pModLX->pMod->pOps = pOps; pModLX->pMod->u32Magic = KLDRMOD_MAGIC; *ppMod = pModLX->pMod; return 0; } rc = KLDR_ERR_CPU_ARCH_MISMATCH; } kHlpFree(pModLX); return rc; } /** * Separate function for reading creating the LX module instance to * simplify cleanup on failure. */ static int kldrModLXDoCreate(PKRDR pRdr, KLDRFOFF offNewHdr, PKLDRMODLX *ppModLX) { struct e32_exe Hdr; PKLDRMODLX pModLX; PKLDRMOD pMod; KSIZE cb; KSIZE cchFilename; KU32 off, offEnd; KU32 i; int rc; int fCanOptimizeMapping; KU32 NextRVA; *ppModLX = NULL; /* * Read the signature and file header. */ rc = kRdrRead(pRdr, &Hdr, sizeof(Hdr), offNewHdr > 0 ? offNewHdr : 0); if (rc) return rc; if ( Hdr.e32_magic[0] != E32MAGIC1 || Hdr.e32_magic[1] != E32MAGIC2) return KLDR_ERR_UNKNOWN_FORMAT; /* We're not interested in anything but x86 images. */ if ( Hdr.e32_level != E32LEVEL || Hdr.e32_border != E32LEBO || Hdr.e32_worder != E32LEWO || Hdr.e32_cpu < E32CPU286 || Hdr.e32_cpu > E32CPU486 || Hdr.e32_pagesize != OBJPAGELEN ) return KLDR_ERR_LX_BAD_HEADER; /* Some rough sanity checks. */ offEnd = kRdrSize(pRdr) >= (KLDRFOFF)~(KU32)16 ? ~(KU32)16 : (KU32)kRdrSize(pRdr); if ( Hdr.e32_itermap > offEnd || Hdr.e32_datapage > offEnd || Hdr.e32_nrestab > offEnd || Hdr.e32_nrestab + Hdr.e32_cbnrestab > offEnd || Hdr.e32_ldrsize > offEnd - offNewHdr - sizeof(Hdr) || Hdr.e32_fixupsize > offEnd - offNewHdr - sizeof(Hdr) || Hdr.e32_fixupsize + Hdr.e32_ldrsize > offEnd - offNewHdr - sizeof(Hdr)) return KLDR_ERR_LX_BAD_HEADER; /* Verify the loader section. */ offEnd = Hdr.e32_objtab + Hdr.e32_ldrsize; if (Hdr.e32_objtab < sizeof(Hdr)) return KLDR_ERR_LX_BAD_LOADER_SECTION; off = Hdr.e32_objtab + sizeof(struct o32_obj) * Hdr.e32_objcnt; if (off > offEnd) return KLDR_ERR_LX_BAD_LOADER_SECTION; if ( Hdr.e32_objmap && (Hdr.e32_objmap < off || Hdr.e32_objmap > offEnd)) return KLDR_ERR_LX_BAD_LOADER_SECTION; if ( Hdr.e32_rsrccnt && ( Hdr.e32_rsrctab < off || Hdr.e32_rsrctab > offEnd || Hdr.e32_rsrctab + sizeof(struct rsrc32) * Hdr.e32_rsrccnt > offEnd)) return KLDR_ERR_LX_BAD_LOADER_SECTION; if ( Hdr.e32_restab && (Hdr.e32_restab < off || Hdr.e32_restab > offEnd - 2)) return KLDR_ERR_LX_BAD_LOADER_SECTION; if ( Hdr.e32_enttab && (Hdr.e32_enttab < off || Hdr.e32_enttab >= offEnd)) return KLDR_ERR_LX_BAD_LOADER_SECTION; if ( Hdr.e32_dircnt && (Hdr.e32_dirtab < off || Hdr.e32_dirtab > offEnd - 2)) return KLDR_ERR_LX_BAD_LOADER_SECTION; /* Verify the fixup section. */ off = offEnd; offEnd = off + Hdr.e32_fixupsize; if ( Hdr.e32_fpagetab && (Hdr.e32_fpagetab < off || Hdr.e32_fpagetab > offEnd)) { /* * wlink mixes the fixup section and the loader section. */ off = Hdr.e32_fpagetab; offEnd = off + Hdr.e32_fixupsize; Hdr.e32_ldrsize = off - Hdr.e32_objtab; } if ( Hdr.e32_frectab && (Hdr.e32_frectab < off || Hdr.e32_frectab > offEnd)) return KLDR_ERR_LX_BAD_FIXUP_SECTION; if ( Hdr.e32_impmod && (Hdr.e32_impmod < off || Hdr.e32_impmod > offEnd || Hdr.e32_impmod + Hdr.e32_impmodcnt > offEnd)) return KLDR_ERR_LX_BAD_FIXUP_SECTION; if ( Hdr.e32_impproc && (Hdr.e32_impproc < off || Hdr.e32_impproc > offEnd)) return KLDR_ERR_LX_BAD_FIXUP_SECTION; /* * Calc the instance size, allocate and initialize it. */ cchFilename = kHlpStrLen(kRdrName(pRdr)); cb = K_ALIGN_Z(sizeof(KLDRMODLX), 8) + K_ALIGN_Z(K_OFFSETOF(KLDRMOD, aSegments[Hdr.e32_objcnt + 1]), 8) + K_ALIGN_Z(cchFilename + 1, 8) + Hdr.e32_ldrsize + 2; /* +2 for two extra zeros. */ pModLX = (PKLDRMODLX)kHlpAlloc(cb); if (!pModLX) return KERR_NO_MEMORY; *ppModLX = pModLX; /* KLDRMOD */ pMod = (PKLDRMOD)((KU8 *)pModLX + K_ALIGN_Z(sizeof(KLDRMODLX), 8)); pMod->pvData = pModLX; pMod->pRdr = pRdr; pMod->pOps = NULL; /* set upon success. */ pMod->cSegments = Hdr.e32_objcnt; pMod->cchFilename = (KU32)cchFilename; pMod->pszFilename = (char *)K_ALIGN_P(&pMod->aSegments[pMod->cSegments], 8); kHlpMemCopy((char *)pMod->pszFilename, kRdrName(pRdr), cchFilename + 1); pMod->pszName = NULL; /* finalized further down */ pMod->cchName = 0; pMod->fFlags = 0; switch (Hdr.e32_cpu) { case E32CPU286: pMod->enmCpu = KCPU_I80286; pMod->enmArch = KCPUARCH_X86_16; break; case E32CPU386: pMod->enmCpu = KCPU_I386; pMod->enmArch = KCPUARCH_X86_32; break; case E32CPU486: pMod->enmCpu = KCPU_I486; pMod->enmArch = KCPUARCH_X86_32; break; } pMod->enmEndian = KLDRENDIAN_LITTLE; pMod->enmFmt = KLDRFMT_LX; switch (Hdr.e32_mflags & E32MODMASK) { case E32MODEXE: pMod->enmType = !(Hdr.e32_mflags & E32NOINTFIX) ? KLDRTYPE_EXECUTABLE_RELOCATABLE : KLDRTYPE_EXECUTABLE_FIXED; break; case E32MODDLL: case E32PROTDLL: case E32MODPROTDLL: pMod->enmType = !(Hdr.e32_mflags & E32SYSDLL) ? KLDRTYPE_SHARED_LIBRARY_RELOCATABLE : KLDRTYPE_SHARED_LIBRARY_FIXED; break; case E32MODPDEV: case E32MODVDEV: pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE; break; } pMod->u32Magic = 0; /* set upon success. */ /* KLDRMODLX */ pModLX->pMod = pMod; pModLX->pvMapping = 0; pModLX->cbMapped = 0; pModLX->f32Reserved = 0; pModLX->offHdr = offNewHdr >= 0 ? offNewHdr : 0; kHlpMemCopy(&pModLX->Hdr, &Hdr, sizeof(Hdr)); pModLX->pbLoaderSection = K_ALIGN_P(pMod->pszFilename + pMod->cchFilename + 1, 16); pModLX->pbLoaderSectionLast = pModLX->pbLoaderSection + pModLX->Hdr.e32_ldrsize - 1; pModLX->paObjs = NULL; pModLX->paPageMappings = NULL; pModLX->paRsrcs = NULL; pModLX->pbResNameTab = NULL; pModLX->pbEntryTab = NULL; pModLX->pbNonResNameTab = NULL; pModLX->pbNonResNameTabLast = NULL; pModLX->pbFixupSection = NULL; pModLX->pbFixupSectionLast = NULL; pModLX->paoffPageFixups = NULL; pModLX->pbFixupRecs = NULL; pModLX->pbImportMods = NULL; pModLX->pbImportProcs = NULL; /* * Read the loader data. */ rc = kRdrRead(pRdr, (void *)pModLX->pbLoaderSection, pModLX->Hdr.e32_ldrsize, pModLX->Hdr.e32_objtab + pModLX->offHdr); if (rc) return rc; ((KU8 *)pModLX->pbLoaderSectionLast)[1] = 0; ((KU8 *)pModLX->pbLoaderSectionLast)[2] = 0; if (pModLX->Hdr.e32_objcnt) pModLX->paObjs = (const struct o32_obj *)pModLX->pbLoaderSection; if (pModLX->Hdr.e32_objmap) pModLX->paPageMappings = (const struct o32_map *)(pModLX->pbLoaderSection + pModLX->Hdr.e32_objmap - pModLX->Hdr.e32_objtab); if (pModLX->Hdr.e32_rsrccnt) pModLX->paRsrcs = (const struct rsrc32 *)(pModLX->pbLoaderSection + pModLX->Hdr.e32_rsrctab - pModLX->Hdr.e32_objtab); if (pModLX->Hdr.e32_restab) pModLX->pbResNameTab = pModLX->pbLoaderSection + pModLX->Hdr.e32_restab - pModLX->Hdr.e32_objtab; if (pModLX->Hdr.e32_enttab) pModLX->pbEntryTab = pModLX->pbLoaderSection + pModLX->Hdr.e32_enttab - pModLX->Hdr.e32_objtab; /* * Get the soname from the resident name table. * Very convenient that it's the 0 ordinal, because then we get a * free string terminator. * (The table entry consists of a pascal string followed by a 16-bit ordinal.) */ if (pModLX->pbResNameTab) pMod->pszName = (const char *)kldrModLXDoNameTableLookupByOrdinal(pModLX->pbResNameTab, pModLX->pbLoaderSectionLast - pModLX->pbResNameTab + 1, 0); if (!pMod->pszName) return KLDR_ERR_LX_NO_SONAME; pMod->cchName = *(const KU8 *)pMod->pszName++; if (pMod->cchName != kHlpStrLen(pMod->pszName)) return KLDR_ERR_LX_BAD_SONAME; /* * Quick validation of the object table. */ cb = 0; for (i = 0; i < pMod->cSegments; i++) { if (pModLX->paObjs[i].o32_base & (OBJPAGELEN - 1)) return KLDR_ERR_LX_BAD_OBJECT_TABLE; if (pModLX->paObjs[i].o32_base + pModLX->paObjs[i].o32_size <= pModLX->paObjs[i].o32_base) return KLDR_ERR_LX_BAD_OBJECT_TABLE; if (pModLX->paObjs[i].o32_mapsize > (pModLX->paObjs[i].o32_size + (OBJPAGELEN - 1))) return KLDR_ERR_LX_BAD_OBJECT_TABLE; if ( pModLX->paObjs[i].o32_mapsize && ( (KU8 *)&pModLX->paPageMappings[pModLX->paObjs[i].o32_pagemap] > pModLX->pbLoaderSectionLast || (KU8 *)&pModLX->paPageMappings[pModLX->paObjs[i].o32_pagemap + pModLX->paObjs[i].o32_mapsize] > pModLX->pbLoaderSectionLast)) return KLDR_ERR_LX_BAD_OBJECT_TABLE; if (i > 0 && !(pModLX->paObjs[i].o32_flags & OBJRSRC)) { if (pModLX->paObjs[i].o32_base <= pModLX->paObjs[i - 1].o32_base) return KLDR_ERR_LX_BAD_OBJECT_TABLE; if (pModLX->paObjs[i].o32_base < pModLX->paObjs[i - 1].o32_base + pModLX->paObjs[i - 1].o32_mapsize) return KLDR_ERR_LX_BAD_OBJECT_TABLE; } } /* * Check if we can optimize the mapping by using a different * object alignment. The linker typically uses 64KB alignment, * we can easily get away with page alignment in most cases. */ fCanOptimizeMapping = !(Hdr.e32_mflags & (E32NOINTFIX | E32SYSDLL)); NextRVA = 0; /* * Setup the KLDRMOD segment array. */ for (i = 0; i < pMod->cSegments; i++) { /* unused */ pMod->aSegments[i].pvUser = NULL; pMod->aSegments[i].MapAddress = 0; pMod->aSegments[i].pchName = NULL; pMod->aSegments[i].cchName = 0; pMod->aSegments[i].offFile = -1; pMod->aSegments[i].cbFile = -1; pMod->aSegments[i].SelFlat = 0; pMod->aSegments[i].Sel16bit = 0; /* flags */ pMod->aSegments[i].fFlags = 0; if (pModLX->paObjs[i].o32_flags & OBJBIGDEF) pMod->aSegments[i].fFlags = KLDRSEG_FLAG_16BIT; if (pModLX->paObjs[i].o32_flags & OBJALIAS16) pMod->aSegments[i].fFlags = KLDRSEG_FLAG_OS2_ALIAS16; if (pModLX->paObjs[i].o32_flags & OBJCONFORM) pMod->aSegments[i].fFlags = KLDRSEG_FLAG_OS2_CONFORM; if (pModLX->paObjs[i].o32_flags & OBJIOPL) pMod->aSegments[i].fFlags = KLDRSEG_FLAG_OS2_IOPL; /* size and addresses */ pMod->aSegments[i].Alignment = OBJPAGELEN; pMod->aSegments[i].cb = pModLX->paObjs[i].o32_size; pMod->aSegments[i].LinkAddress = pModLX->paObjs[i].o32_base; pMod->aSegments[i].RVA = NextRVA; if ( fCanOptimizeMapping || i + 1 >= pMod->cSegments || (pModLX->paObjs[i].o32_flags & OBJRSRC) || (pModLX->paObjs[i + 1].o32_flags & OBJRSRC)) pMod->aSegments[i].cbMapped = K_ALIGN_Z(pModLX->paObjs[i].o32_size, OBJPAGELEN); else pMod->aSegments[i].cbMapped = pModLX->paObjs[i + 1].o32_base - pModLX->paObjs[i].o32_base; NextRVA += (KU32)pMod->aSegments[i].cbMapped; /* protection */ switch ( pModLX->paObjs[i].o32_flags & (OBJSHARED | OBJREAD | OBJWRITE | OBJEXEC)) { case 0: case OBJSHARED: pMod->aSegments[i].enmProt = KPROT_NOACCESS; break; case OBJREAD: case OBJREAD | OBJSHARED: pMod->aSegments[i].enmProt = KPROT_READONLY; break; case OBJWRITE: case OBJWRITE | OBJREAD: pMod->aSegments[i].enmProt = KPROT_WRITECOPY; break; case OBJWRITE | OBJSHARED: case OBJWRITE | OBJSHARED | OBJREAD: pMod->aSegments[i].enmProt = KPROT_READWRITE; break; case OBJEXEC: case OBJEXEC | OBJSHARED: pMod->aSegments[i].enmProt = KPROT_EXECUTE; break; case OBJEXEC | OBJREAD: case OBJEXEC | OBJREAD | OBJSHARED: pMod->aSegments[i].enmProt = KPROT_EXECUTE_READ; break; case OBJEXEC | OBJWRITE: case OBJEXEC | OBJWRITE | OBJREAD: pMod->aSegments[i].enmProt = KPROT_EXECUTE_WRITECOPY; break; case OBJEXEC | OBJWRITE | OBJSHARED: case OBJEXEC | OBJWRITE | OBJSHARED | OBJREAD: pMod->aSegments[i].enmProt = KPROT_EXECUTE_READWRITE; break; } if ((pModLX->paObjs[i].o32_flags & (OBJREAD | OBJWRITE | OBJEXEC | OBJRSRC)) == OBJRSRC) pMod->aSegments[i].enmProt = KPROT_READONLY; /*pMod->aSegments[i].f16bit = !(pModLX->paObjs[i].o32_flags & OBJBIGDEF) pMod->aSegments[i].fIOPL = !(pModLX->paObjs[i].o32_flags & OBJIOPL) pMod->aSegments[i].fConforming = !(pModLX->paObjs[i].o32_flags & OBJCONFORM) */ } /* set the mapping size */ pModLX->cbMapped = NextRVA; /* * We're done. */ *ppModLX = pModLX; return 0; } /** @copydoc KLDRMODOPS::pfnDestroy */ static int kldrModLXDestroy(PKLDRMOD pMod) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; int rc = 0; KLDRMODLX_ASSERT(!pModLX->pvMapping); if (pMod->pRdr) { rc = kRdrClose(pMod->pRdr); pMod->pRdr = NULL; } if (pModLX->pbNonResNameTab) { kHlpFree(pModLX->pbNonResNameTab); pModLX->pbNonResNameTab = NULL; } if (pModLX->pbFixupSection) { kHlpFree(pModLX->pbFixupSection); pModLX->pbFixupSection = NULL; } pMod->u32Magic = 0; pMod->pOps = NULL; kHlpFree(pModLX); return rc; } /** * Resolved base address aliases. * * @param pModLX The interpreter module instance * @param pBaseAddress The base address, IN & OUT. */ static void kldrModLXResolveBaseAddress(PKLDRMODLX pModLX, PKLDRADDR pBaseAddress) { if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP) *pBaseAddress = pModLX->pMod->aSegments[0].MapAddress; else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK) *pBaseAddress = pModLX->pMod->aSegments[0].LinkAddress; } /** @copydoc kLdrModQuerySymbol */ static int kldrModLXQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; KU32 iOrdinal; int rc; const struct b32_bundle *pBundle; K_NOREF(pvBits); K_NOREF(pszVersion); /* * Give up at once if there is no entry table. */ if (!pModLX->Hdr.e32_enttab) return KLDR_ERR_SYMBOL_NOT_FOUND; /* * Translate the symbol name into an ordinal. */ if (pchSymbol) { rc = kldrModLXDoNameLookup(pModLX, pchSymbol, cchSymbol, &iSymbol); if (rc) return rc; } /* * Iterate the entry table. * (The entry table is made up of bundles of similar exports.) */ iOrdinal = 1; pBundle = (const struct b32_bundle *)pModLX->pbEntryTab; while (pBundle->b32_cnt && iOrdinal <= iSymbol) { static const KSIZE s_cbEntry[] = { 0, 3, 5, 5, 7 }; /* * Check for a hit first. */ iOrdinal += pBundle->b32_cnt; if (iSymbol < iOrdinal) { KU32 offObject; const struct e32_entry *pEntry = (const struct e32_entry *)((KUPTR)(pBundle + 1) + (iSymbol - (iOrdinal - pBundle->b32_cnt)) * s_cbEntry[pBundle->b32_type]); /* * Calculate the return address. */ kldrModLXResolveBaseAddress(pModLX, &BaseAddress); switch (pBundle->b32_type) { /* empty bundles are place holders unused ordinal ranges. */ case EMPTY: return KLDR_ERR_SYMBOL_NOT_FOUND; /* e32_flags + a 16-bit offset. */ case ENTRY16: offObject = pEntry->e32_variant.e32_offset.offset16; if (pfKind) *pfKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_NO_TYPE; break; /* e32_flags + a 16-bit offset + a 16-bit callgate selector. */ case GATE16: offObject = pEntry->e32_variant.e32_callgate.offset; if (pfKind) *pfKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_CODE; break; /* e32_flags + a 32-bit offset. */ case ENTRY32: offObject = pEntry->e32_variant.e32_offset.offset32; if (pfKind) *pfKind = KLDRSYMKIND_32BIT; break; /* e32_flags + 16-bit import module ordinal + a 32-bit procname or ordinal. */ case ENTRYFWD: return kldrModLXDoForwarderQuery(pModLX, pEntry, pfnGetForwarder, pvUser, puValue, pfKind); default: /* anyone actually using TYPEINFO will end up here. */ KLDRMODLX_ASSERT(!"Bad bundle type"); return KLDR_ERR_LX_BAD_BUNDLE; } /* * Validate the object number and calc the return address. */ if ( pBundle->b32_obj <= 0 || pBundle->b32_obj > pMod->cSegments) return KLDR_ERR_LX_BAD_BUNDLE; if (puValue) *puValue = BaseAddress + offObject + pMod->aSegments[pBundle->b32_obj - 1].RVA; return 0; } /* * Skip the bundle. */ if (pBundle->b32_type > ENTRYFWD) { KLDRMODLX_ASSERT(!"Bad type"); /** @todo figure out TYPEINFO. */ return KLDR_ERR_LX_BAD_BUNDLE; } if (pBundle->b32_type == 0) pBundle = (const struct b32_bundle *)((const KU8 *)pBundle + 2); else pBundle = (const struct b32_bundle *)((const KU8 *)(pBundle + 1) + s_cbEntry[pBundle->b32_type] * pBundle->b32_cnt); } return KLDR_ERR_SYMBOL_NOT_FOUND; } /** * Do name lookup. * * @returns See kLdrModQuerySymbol. * @param pModLX The module to lookup the symbol in. * @param pchSymbol The symbol to lookup. * @param cchSymbol The symbol name length. * @param piSymbol Where to store the symbol ordinal. */ static int kldrModLXDoNameLookup(PKLDRMODLX pModLX, const char *pchSymbol, KSIZE cchSymbol, KU32 *piSymbol) { /* * First do a hash table lookup. */ /** @todo hash name table for speed. */ /* * Search the name tables. */ const KU8 *pbName = kldrModLXDoNameTableLookupByName(pModLX->pbResNameTab, pModLX->pbLoaderSectionLast - pModLX->pbResNameTab + 1, pchSymbol, cchSymbol); if (!pbName) { if (!pModLX->pbNonResNameTab) { /* lazy load it */ /** @todo non-resident name table. */ } if (pModLX->pbNonResNameTab) pbName = kldrModLXDoNameTableLookupByName(pModLX->pbResNameTab, pModLX->pbNonResNameTabLast - pModLX->pbResNameTab + 1, pchSymbol, cchSymbol); } if (!pbName) return KLDR_ERR_SYMBOL_NOT_FOUND; *piSymbol = *(const KU16 *)(pbName + 1 + *pbName); return 0; } #if 0 /** * Hash a symbol using the algorithm from sdbm. * * The following was is the documenation of the orignal sdbm functions: * * This algorithm was created for sdbm (a public-domain reimplementation of * ndbm) database library. it was found to do well in scrambling bits, * causing better distribution of the keys and fewer splits. it also happens * to be a good general hashing function with good distribution. the actual * function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below * is the faster version used in gawk. [there is even a faster, duff-device * version] the magic constant 65599 was picked out of thin air while * experimenting with different constants, and turns out to be a prime. * this is one of the algorithms used in berkeley db (see sleepycat) and * elsewhere. */ static KU32 kldrModLXDoHash(const char *pchSymbol, KU8 cchSymbol) { KU32 hash = 0; int ch; while ( cchSymbol-- > 0 && (ch = *(unsigned const char *)pchSymbol++)) hash = ch + (hash << 6) + (hash << 16) - hash; return hash; } #endif /** * Lookup a name table entry by name. * * @returns Pointer to the name table entry if found. * @returns NULL if not found. * @param pbNameTable Pointer to the name table that should be searched. * @param cbNameTable The size of the name table. * @param pchSymbol The name of the symbol we're looking for. * @param cchSymbol The length of the symbol name. */ static const KU8 *kldrModLXDoNameTableLookupByName(const KU8 *pbNameTable, KSSIZE cbNameTable, const char *pchSymbol, KSIZE cchSymbol) { /* * Determin the namelength up front so we can skip anything which doesn't matches the length. */ KU8 cbSymbol8Bit = (KU8)cchSymbol; if (cbSymbol8Bit != cchSymbol) return NULL; /* too long. */ /* * Walk the name table. */ while (*pbNameTable != 0 && cbNameTable > 0) { const KU8 cbName = *pbNameTable; cbNameTable -= cbName + 1 + 2; if (cbNameTable < 0) break; if ( cbName == cbSymbol8Bit && !kHlpMemComp(pbNameTable + 1, pchSymbol, cbName)) return pbNameTable; /* next entry */ pbNameTable += cbName + 1 + 2; } return NULL; } /** * Deal with a forwarder entry. * * @returns See kLdrModQuerySymbol. * @param pModLX The PE module interpreter instance. * @param pEntry The forwarder entry. * @param pfnGetForwarder The callback for resolving forwarder symbols. (optional) * @param pvUser The user argument for the callback. * @param puValue Where to put the value. (optional) * @param pfKind Where to put the symbol kind. (optional) */ static int kldrModLXDoForwarderQuery(PKLDRMODLX pModLX, const struct e32_entry *pEntry, PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind) { int rc; KU32 iSymbol; const char *pchSymbol; KU8 cchSymbol; if (!pfnGetForwarder) return KLDR_ERR_FORWARDER_SYMBOL; /* * Validate the entry import module ordinal. */ if ( !pEntry->e32_variant.e32_fwd.modord || pEntry->e32_variant.e32_fwd.modord > pModLX->Hdr.e32_impmodcnt) return KLDR_ERR_LX_BAD_FORWARDER; /* * Figure out the parameters. */ if (pEntry->e32_flags & FWD_ORDINAL) { iSymbol = pEntry->e32_variant.e32_fwd.value; pchSymbol = NULL; /* no symbol name. */ cchSymbol = 0; } else { const KU8 *pbName; /* load the fixup section if necessary. */ if (!pModLX->pbImportProcs) { rc = kldrModLXDoLoadFixupSection(pModLX); if (rc) return rc; } /* Make name pointer. */ pbName = pModLX->pbImportProcs + pEntry->e32_variant.e32_fwd.value; if ( pbName >= pModLX->pbFixupSectionLast || pbName < pModLX->pbFixupSection || !*pbName) return KLDR_ERR_LX_BAD_FORWARDER; /* check for '#' name. */ if (pbName[1] == '#') { KU8 cbLeft = *pbName; const KU8 *pb = pbName + 1; unsigned uBase; /* base detection */ uBase = 10; if ( cbLeft > 1 && pb[1] == '0' && (pb[2] == 'x' || pb[2] == 'X')) { uBase = 16; pb += 2; cbLeft -= 2; } /* ascii to integer */ iSymbol = 0; while (cbLeft-- > 0) { /* convert char to digit. */ unsigned uDigit = *pb++; if (uDigit >= '0' && uDigit <= '9') uDigit -= '0'; else if (uDigit >= 'a' && uDigit <= 'z') uDigit -= 'a' + 10; else if (uDigit >= 'A' && uDigit <= 'Z') uDigit -= 'A' + 10; else if (!uDigit) break; else return KLDR_ERR_LX_BAD_FORWARDER; if (uDigit >= uBase) return KLDR_ERR_LX_BAD_FORWARDER; /* insert the digit */ iSymbol *= uBase; iSymbol += uDigit; } if (!iSymbol) return KLDR_ERR_LX_BAD_FORWARDER; pchSymbol = NULL; /* no symbol name. */ cchSymbol = 0; } else { pchSymbol = (char *)pbName + 1; cchSymbol = *pbName; iSymbol = NIL_KLDRMOD_SYM_ORDINAL; } } /* * Resolve the forwarder. */ rc = pfnGetForwarder(pModLX->pMod, pEntry->e32_variant.e32_fwd.modord - 1, iSymbol, pchSymbol, cchSymbol, NULL, puValue, pfKind, pvUser); if (!rc && pfKind) *pfKind |= KLDRSYMKIND_FORWARDER; return rc; } /** * Loads the fixup section from the executable image. * * The fixup section isn't loaded until it's accessed. It's also freed by kLdrModDone(). * * @returns 0 on success, non-zero kLdr or native status code on failure. * @param pModLX The PE module interpreter instance. */ static int kldrModLXDoLoadFixupSection(PKLDRMODLX pModLX) { int rc; KU32 off; void *pv; pv = kHlpAlloc(pModLX->Hdr.e32_fixupsize); if (!pv) return KERR_NO_MEMORY; off = pModLX->Hdr.e32_objtab + pModLX->Hdr.e32_ldrsize; rc = kRdrRead(pModLX->pMod->pRdr, pv, pModLX->Hdr.e32_fixupsize, off + pModLX->offHdr); if (!rc) { pModLX->pbFixupSection = pv; pModLX->pbFixupSectionLast = pModLX->pbFixupSection + pModLX->Hdr.e32_fixupsize; KLDRMODLX_ASSERT(!pModLX->paoffPageFixups); if (pModLX->Hdr.e32_fpagetab) pModLX->paoffPageFixups = (const KU32 *)(pModLX->pbFixupSection + pModLX->Hdr.e32_fpagetab - off); KLDRMODLX_ASSERT(!pModLX->pbFixupRecs); if (pModLX->Hdr.e32_frectab) pModLX->pbFixupRecs = pModLX->pbFixupSection + pModLX->Hdr.e32_frectab - off; KLDRMODLX_ASSERT(!pModLX->pbImportMods); if (pModLX->Hdr.e32_impmod) pModLX->pbImportMods = pModLX->pbFixupSection + pModLX->Hdr.e32_impmod - off; KLDRMODLX_ASSERT(!pModLX->pbImportProcs); if (pModLX->Hdr.e32_impproc) pModLX->pbImportProcs = pModLX->pbFixupSection + pModLX->Hdr.e32_impproc - off; } else kHlpFree(pv); return rc; } /** @copydoc kLdrModEnumSymbols */ static int kldrModLXEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; const struct b32_bundle *pBundle; KU32 iOrdinal; int rc = 0; K_NOREF(pvBits); K_NOREF(fFlags); kldrModLXResolveBaseAddress(pModLX, &BaseAddress); /* * Enumerate the entry table. * (The entry table is made up of bundles of similar exports.) */ iOrdinal = 1; pBundle = (const struct b32_bundle *)pModLX->pbEntryTab; while (pBundle->b32_cnt && iOrdinal) { static const KSIZE s_cbEntry[] = { 0, 3, 5, 5, 7 }; /* * Enum the entries in the bundle. */ if (pBundle->b32_type != EMPTY) { const struct e32_entry *pEntry; KSIZE cbEntry; KLDRADDR BundleRVA; unsigned cLeft; /* Validate the bundle. */ switch (pBundle->b32_type) { case ENTRY16: case GATE16: case ENTRY32: if ( pBundle->b32_obj <= 0 || pBundle->b32_obj > pMod->cSegments) return KLDR_ERR_LX_BAD_BUNDLE; BundleRVA = pMod->aSegments[pBundle->b32_obj - 1].RVA; break; case ENTRYFWD: BundleRVA = 0; break; default: /* anyone actually using TYPEINFO will end up here. */ KLDRMODLX_ASSERT(!"Bad bundle type"); return KLDR_ERR_LX_BAD_BUNDLE; } /* iterate the bundle entries. */ cbEntry = s_cbEntry[pBundle->b32_type]; pEntry = (const struct e32_entry *)(pBundle + 1); cLeft = pBundle->b32_cnt; while (cLeft-- > 0) { KLDRADDR uValue; KU32 fKind; int fFoundName; const KU8 *pbName; /* * Calc the symbol value and kind. */ switch (pBundle->b32_type) { /* e32_flags + a 16-bit offset. */ case ENTRY16: uValue = BaseAddress + BundleRVA + pEntry->e32_variant.e32_offset.offset16; fKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_NO_TYPE; break; /* e32_flags + a 16-bit offset + a 16-bit callgate selector. */ case GATE16: uValue = BaseAddress + BundleRVA + pEntry->e32_variant.e32_callgate.offset; fKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_CODE; break; /* e32_flags + a 32-bit offset. */ case ENTRY32: uValue = BaseAddress + BundleRVA + pEntry->e32_variant.e32_offset.offset32; fKind = KLDRSYMKIND_32BIT; break; /* e32_flags + 16-bit import module ordinal + a 32-bit procname or ordinal. */ case ENTRYFWD: uValue = 0; /** @todo implement enumeration of forwarders properly. */ fKind = KLDRSYMKIND_FORWARDER; break; default: /* shut up gcc. */ uValue = 0; fKind = KLDRSYMKIND_NO_BIT | KLDRSYMKIND_NO_TYPE; break; } /* * Any symbol names? */ fFoundName = 0; /* resident name table. */ pbName = pModLX->pbResNameTab; if (pbName) { do { pbName = kldrModLXDoNameTableLookupByOrdinal(pbName, pModLX->pbLoaderSectionLast - pbName + 1, iOrdinal); if (!pbName) break; fFoundName = 1; rc = pfnCallback(pMod, iOrdinal, (const char *)pbName + 1, *pbName, NULL, uValue, fKind, pvUser); if (rc) return rc; /* skip to the next entry */ pbName += 1 + *pbName + 2; } while (pbName < pModLX->pbLoaderSectionLast); } /* resident name table. */ pbName = pModLX->pbNonResNameTab; /** @todo lazy load the non-resident name table. */ if (pbName) { do { pbName = kldrModLXDoNameTableLookupByOrdinal(pbName, pModLX->pbNonResNameTabLast - pbName + 1, iOrdinal); if (!pbName) break; fFoundName = 1; rc = pfnCallback(pMod, iOrdinal, (const char *)pbName + 1, *pbName, NULL, uValue, fKind, pvUser); if (rc) return rc; /* skip to the next entry */ pbName += 1 + *pbName + 2; } while (pbName < pModLX->pbLoaderSectionLast); } /* * If no names, call once with the ordinal only. */ if (!fFoundName) { rc = pfnCallback(pMod, iOrdinal, NULL, 0, NULL, uValue, fKind, pvUser); if (rc) return rc; } /* next */ iOrdinal++; pEntry = (const struct e32_entry *)((KUPTR)pEntry + cbEntry); } } /* * The next bundle. */ if (pBundle->b32_type > ENTRYFWD) { KLDRMODLX_ASSERT(!"Bad type"); /** @todo figure out TYPEINFO. */ return KLDR_ERR_LX_BAD_BUNDLE; } if (pBundle->b32_type == 0) pBundle = (const struct b32_bundle *)((const KU8 *)pBundle + 2); else pBundle = (const struct b32_bundle *)((const KU8 *)(pBundle + 1) + s_cbEntry[pBundle->b32_type] * pBundle->b32_cnt); } return 0; } /** * Lookup a name table entry by ordinal. * * @returns Pointer to the name table entry if found. * @returns NULL if not found. * @param pbNameTable Pointer to the name table that should be searched. * @param cbNameTable The size of the name table. * @param iOrdinal The ordinal to search for. */ static const KU8 *kldrModLXDoNameTableLookupByOrdinal(const KU8 *pbNameTable, KSSIZE cbNameTable, KU32 iOrdinal) { while (*pbNameTable != 0 && cbNameTable > 0) { const KU8 cbName = *pbNameTable; KU32 iName; cbNameTable -= cbName + 1 + 2; if (cbNameTable < 0) break; iName = *(pbNameTable + cbName + 1) | ((unsigned)*(pbNameTable + cbName + 2) << 8); if (iName == iOrdinal) return pbNameTable; /* next entry */ pbNameTable += cbName + 1 + 2; } return NULL; } /** @copydoc kLdrModGetImport */ static int kldrModLXGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; const KU8 *pb; int rc; K_NOREF(pvBits); /* * Validate */ if (iImport >= pModLX->Hdr.e32_impmodcnt) return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS; /* * Lazy loading the fixup section. */ if (!pModLX->pbImportMods) { rc = kldrModLXDoLoadFixupSection(pModLX); if (rc) return rc; } /* * Iterate the module import table until we reach the requested import ordinal. */ pb = pModLX->pbImportMods; while (iImport-- > 0) pb += *pb + 1; /* * Copy out the result. */ if (*pb < cchName) { kHlpMemCopy(pszName, pb + 1, *pb); pszName[*pb] = '\0'; rc = 0; } else { kHlpMemCopy(pszName, pb + 1, cchName); if (cchName) pszName[cchName - 1] = '\0'; rc = KERR_BUFFER_OVERFLOW; } return rc; } /** @copydoc kLdrModNumberOfImports */ static KI32 kldrModLXNumberOfImports(PKLDRMOD pMod, const void *pvBits) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; K_NOREF(pvBits); return pModLX->Hdr.e32_impmodcnt; } /** @copydoc kLdrModGetStackInfo */ static int kldrModLXGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; const KU32 i = pModLX->Hdr.e32_stackobj; K_NOREF(pvBits); if ( i && i <= pMod->cSegments && pModLX->Hdr.e32_esp <= pMod->aSegments[i - 1].LinkAddress + pMod->aSegments[i - 1].cb && pModLX->Hdr.e32_stacksize && pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize >= pMod->aSegments[i - 1].LinkAddress) { kldrModLXResolveBaseAddress(pModLX, &BaseAddress); pStackInfo->LinkAddress = pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize; pStackInfo->Address = BaseAddress + pMod->aSegments[i - 1].RVA + pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize - pMod->aSegments[i - 1].LinkAddress; } else { pStackInfo->Address = NIL_KLDRADDR; pStackInfo->LinkAddress = NIL_KLDRADDR; } pStackInfo->cbStack = pModLX->Hdr.e32_stacksize; pStackInfo->cbStackThread = 0; return 0; } /** @copydoc kLdrModQueryMainEntrypoint */ static int kldrModLXQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; K_NOREF(pvBits); /* * Convert the address from the header. */ kldrModLXResolveBaseAddress(pModLX, &BaseAddress); *pMainEPAddress = pModLX->Hdr.e32_startobj && pModLX->Hdr.e32_startobj <= pMod->cSegments && pModLX->Hdr.e32_eip < pMod->aSegments[pModLX->Hdr.e32_startobj - 1].cb ? BaseAddress + pMod->aSegments[pModLX->Hdr.e32_startobj - 1].RVA + pModLX->Hdr.e32_eip : NIL_KLDRADDR; return 0; } /** @copydoc kLdrModEnumDbgInfo */ static int kldrModLXEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser) { /*PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;*/ K_NOREF(pfnCallback); K_NOREF(pvUser); /* * Quit immediately if no debug info. */ if (kldrModLXHasDbgInfo(pMod, pvBits)) return 0; #if 0 /* * Read the debug info and look for familiar magics and structures. */ /** @todo */ #endif return 0; } /** @copydoc kLdrModHasDbgInfo */ static int kldrModLXHasDbgInfo(PKLDRMOD pMod, const void *pvBits) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; K_NOREF(pvBits); /* * Don't curretnly bother with linkers which doesn't advertise it in the header. */ if ( !pModLX->Hdr.e32_debuginfo || !pModLX->Hdr.e32_debuglen) return KLDR_ERR_NO_DEBUG_INFO; return 0; } /** @copydoc kLdrModMap */ static int kldrModLXMap(PKLDRMOD pMod) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; unsigned fFixed; void *pvBase; int rc; /* * Already mapped? */ if (pModLX->pvMapping) return KLDR_ERR_ALREADY_MAPPED; /* * Allocate memory for it. */ /* fixed image? */ fFixed = pMod->enmType == KLDRTYPE_EXECUTABLE_FIXED || pMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED; if (!fFixed) pvBase = NULL; else { pvBase = (void *)(KUPTR)pMod->aSegments[0].LinkAddress; if ((KUPTR)pvBase != pMod->aSegments[0].LinkAddress) return KLDR_ERR_ADDRESS_OVERFLOW; } rc = kHlpPageAlloc(&pvBase, pModLX->cbMapped, KPROT_EXECUTE_READWRITE, fFixed); if (rc) return rc; /* * Load the bits, apply page protection, and update the segment table. */ rc = kldrModLXDoLoadBits(pModLX, pvBase); if (!rc) rc = kldrModLXDoProtect(pModLX, pvBase, 0 /* protect */); if (!rc) { KU32 i; for (i = 0; i < pMod->cSegments; i++) { if (pMod->aSegments[i].RVA != NIL_KLDRADDR) pMod->aSegments[i].MapAddress = (KUPTR)pvBase + (KUPTR)pMod->aSegments[i].RVA; } pModLX->pvMapping = pvBase; } else kHlpPageFree(pvBase, pModLX->cbMapped); return rc; } /** * Loads the LX pages into the specified memory mapping. * * @returns 0 on success. * @returns non-zero kLdr or OS status code on failure. * * @param pModLX The LX module interpreter instance. * @param pvBits Where to load the bits. */ static int kldrModLXDoLoadBits(PKLDRMODLX pModLX, void *pvBits) { const PKRDR pRdr = pModLX->pMod->pRdr; KU8 *pbTmpPage = NULL; int rc = 0; KU32 i; /* * Iterate the segments. */ for (i = 0; i < pModLX->Hdr.e32_objcnt; i++) { const struct o32_obj * const pObj = &pModLX->paObjs[i]; const KU32 cPages = (KU32)(pModLX->pMod->aSegments[i].cbMapped / OBJPAGELEN); KU32 iPage; KU8 *pbPage = (KU8 *)pvBits + (KUPTR)pModLX->pMod->aSegments[i].RVA; /* * Iterate the page map pages. */ for (iPage = 0; !rc && iPage < pObj->o32_mapsize; iPage++, pbPage += OBJPAGELEN) { const struct o32_map *pMap = &pModLX->paPageMappings[iPage + pObj->o32_pagemap - 1]; switch (pMap->o32_pageflags) { case VALID: if (pMap->o32_pagesize == OBJPAGELEN) rc = kRdrRead(pRdr, pbPage, OBJPAGELEN, pModLX->Hdr.e32_datapage + (pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift)); else if (pMap->o32_pagesize < OBJPAGELEN) { rc = kRdrRead(pRdr, pbPage, pMap->o32_pagesize, pModLX->Hdr.e32_datapage + (pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift)); kHlpMemSet(pbPage + pMap->o32_pagesize, 0, OBJPAGELEN - pMap->o32_pagesize); } else rc = KLDR_ERR_LX_BAD_PAGE_MAP; break; case ITERDATA: case ITERDATA2: /* make sure we've got a temp page .*/ if (!pbTmpPage) { pbTmpPage = kHlpAlloc(OBJPAGELEN + 256); if (!pbTmpPage) break; } /* validate the size. */ if (pMap->o32_pagesize > OBJPAGELEN + 252) { rc = KLDR_ERR_LX_BAD_PAGE_MAP; break; } /* read it and ensure 4 extra zero bytes. */ rc = kRdrRead(pRdr, pbTmpPage, pMap->o32_pagesize, pModLX->Hdr.e32_datapage + (pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift)); if (rc) break; kHlpMemSet(pbTmpPage + pMap->o32_pagesize, 0, 4); /* unpack it into the image page. */ if (pMap->o32_pageflags == ITERDATA2) rc = kldrModLXDoIterData2Unpacking(pbPage, pbTmpPage, pMap->o32_pagesize); else rc = kldrModLXDoIterDataUnpacking(pbPage, pbTmpPage, pMap->o32_pagesize); break; case INVALID: /* we're probably not dealing correctly with INVALID pages... */ case ZEROED: kHlpMemSet(pbPage, 0, OBJPAGELEN); break; case RANGE: KLDRMODLX_ASSERT(!"RANGE"); /* Falls through. */ default: rc = KLDR_ERR_LX_BAD_PAGE_MAP; break; } } if (rc) break; /* * Zero the remaining pages. */ if (iPage < cPages) kHlpMemSet(pbPage, 0, (cPages - iPage) * OBJPAGELEN); } if (pbTmpPage) kHlpFree(pbTmpPage); return rc; } /** * Unpacks iterdata (aka EXEPACK). * * @returns 0 on success, non-zero kLdr status code on failure. * @param pbDst Where to put the uncompressed data. (Assumes OBJPAGELEN size.) * @param pbSrc The compressed source data. * @param cbSrc The file size of the compressed data. The source buffer * contains 4 additional zero bytes. */ static int kldrModLXDoIterDataUnpacking(KU8 *pbDst, const KU8 *pbSrc, int cbSrc) { const struct LX_Iter *pIter = (const struct LX_Iter *)pbSrc; int cbDst = OBJPAGELEN; /* Validate size of data. */ if (cbSrc >= (int)OBJPAGELEN - 2) return KLDR_ERR_LX_BAD_ITERDATA; /* * Expand the page. */ while (cbSrc > 0 && pIter->LX_nIter) { if (pIter->LX_nBytes == 1) { /* * Special case - one databyte. */ cbDst -= pIter->LX_nIter; if (cbDst < 0) return KLDR_ERR_LX_BAD_ITERDATA; cbSrc -= 4 + 1; if (cbSrc < -4) return KLDR_ERR_LX_BAD_ITERDATA; kHlpMemSet(pbDst, pIter->LX_Iterdata, pIter->LX_nIter); pbDst += pIter->LX_nIter; pIter++; } else { /* * General. */ int i; cbDst -= pIter->LX_nIter * pIter->LX_nBytes; if (cbDst < 0) return KLDR_ERR_LX_BAD_ITERDATA; cbSrc -= 4 + pIter->LX_nBytes; if (cbSrc < -4) return KLDR_ERR_LX_BAD_ITERDATA; for (i = pIter->LX_nIter; i > 0; i--, pbDst += pIter->LX_nBytes) kHlpMemCopy(pbDst, &pIter->LX_Iterdata, pIter->LX_nBytes); pIter = (struct LX_Iter *)((char*)pIter + 4 + pIter->LX_nBytes); } } /* * Zero remainder of the page. */ if (cbDst > 0) kHlpMemSet(pbDst, 0, cbDst); return 0; } /** * Unpacks iterdata (aka EXEPACK). * * @returns 0 on success, non-zero kLdr status code on failure. * @param pbDst Where to put the uncompressed data. (Assumes OBJPAGELEN size.) * @param pbSrc The compressed source data. * @param cbSrc The file size of the compressed data. The source buffer * contains 4 additional zero bytes. */ static int kldrModLXDoIterData2Unpacking(KU8 *pbDst, const KU8 *pbSrc, int cbSrc) { int cbDst = OBJPAGELEN; while (cbSrc > 0) { /* * Bit 0 and 1 is the encoding type. */ switch (*pbSrc & 0x03) { /* * * 0 1 2 3 4 5 6 7 * type | | * ---------------- * cb * * Bits 2-7 is, if not zero, the length of an uncompressed run * starting at the following byte. * * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 * type | | | | | | * ---------------- ---------------------- ----------------------- * zero cb char to multiply * * If the bits are zero, the following two bytes describes a 1 byte interation * run. First byte is count, second is the byte to copy. A count of zero is * means end of data, and we simply stops. In that case the rest of the data * should be zero. */ case 0: { if (*pbSrc) { const int cb = *pbSrc >> 2; cbDst -= cb; if (cbDst < 0) return KLDR_ERR_LX_BAD_ITERDATA2; cbSrc -= cb + 1; if (cbSrc < 0) return KLDR_ERR_LX_BAD_ITERDATA2; kHlpMemCopy(pbDst, ++pbSrc, cb); pbDst += cb; pbSrc += cb; } else if (cbSrc < 2) return KLDR_ERR_LX_BAD_ITERDATA2; else { const int cb = pbSrc[1]; if (!cb) goto l_endloop; cbDst -= cb; if (cbDst < 0) return KLDR_ERR_LX_BAD_ITERDATA2; cbSrc -= 3; if (cbSrc < 0) return KLDR_ERR_LX_BAD_ITERDATA2; kHlpMemSet(pbDst, pbSrc[2], cb); pbDst += cb; pbSrc += 3; } break; } /* * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 * type | | | | | | * ---- ------- ------------------------- * cb1 cb2 - 3 offset * * Two bytes layed out as described above, followed by cb1 bytes of data to be copied. * The cb2(+3) and offset describes an amount of data to be copied from the expanded * data relative to the current position. The data copied as you would expect it to be. */ case 1: { cbSrc -= 2; if (cbSrc < 0) return KLDR_ERR_LX_BAD_ITERDATA2; else { const unsigned off = ((unsigned)pbSrc[1] << 1) | (*pbSrc >> 7); const int cb1 = (*pbSrc >> 2) & 3; const int cb2 = ((*pbSrc >> 4) & 7) + 3; pbSrc += 2; cbSrc -= cb1; if (cbSrc < 0) return KLDR_ERR_LX_BAD_ITERDATA2; cbDst -= cb1; if (cbDst < 0) return KLDR_ERR_LX_BAD_ITERDATA2; kHlpMemCopy(pbDst, pbSrc, cb1); pbDst += cb1; pbSrc += cb1; if (off > OBJPAGELEN - (unsigned)cbDst) return KLDR_ERR_LX_BAD_ITERDATA2; cbDst -= cb2; if (cbDst < 0) return KLDR_ERR_LX_BAD_ITERDATA2; kHlpMemMove(pbDst, pbDst - off, cb2); pbDst += cb2; } break; } /* * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 * type | | | | * ---- ---------------------------------- * cb-3 offset * * Two bytes layed out as described above. * The cb(+3) and offset describes an amount of data to be copied from the expanded * data relative to the current position. * * If offset == 1 the data is not copied as expected, but in the memcpyw manner. */ case 2: { cbSrc -= 2; if (cbSrc < 0) return KLDR_ERR_LX_BAD_ITERDATA2; else { const unsigned off = ((unsigned)pbSrc[1] << 4) | (*pbSrc >> 4); const int cb = ((*pbSrc >> 2) & 3) + 3; pbSrc += 2; if (off > OBJPAGELEN - (unsigned)cbDst) return KLDR_ERR_LX_BAD_ITERDATA2; cbDst -= cb; if (cbDst < 0) return KLDR_ERR_LX_BAD_ITERDATA2; kLdrModLXMemCopyW(pbDst, pbDst - off, cb); pbDst += cb; } break; } /* * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 * type | | | | | | * ---------- ---------------- ---------------------------------- * cb1 cb2 offset * * Three bytes layed out as described above, followed by cb1 bytes of data to be copied. * The cb2 and offset describes an amount of data to be copied from the expanded * data relative to the current position. * * If offset == 1 the data is not copied as expected, but in the memcpyw manner. */ case 3: { cbSrc -= 3; if (cbSrc < 0) return KLDR_ERR_LX_BAD_ITERDATA2; else { const int cb1 = (*pbSrc >> 2) & 0xf; const int cb2 = ((pbSrc[1] & 0xf) << 2) | (*pbSrc >> 6); const unsigned off = ((unsigned)pbSrc[2] << 4) | (pbSrc[1] >> 4); pbSrc += 3; cbSrc -= cb1; if (cbSrc < 0) return KLDR_ERR_LX_BAD_ITERDATA2; cbDst -= cb1; if (cbDst < 0) return KLDR_ERR_LX_BAD_ITERDATA2; kHlpMemCopy(pbDst, pbSrc, cb1); pbDst += cb1; pbSrc += cb1; if (off > OBJPAGELEN - (unsigned)cbDst) return KLDR_ERR_LX_BAD_ITERDATA2; cbDst -= cb2; if (cbDst < 0) return KLDR_ERR_LX_BAD_ITERDATA2; kLdrModLXMemCopyW(pbDst, pbDst - off, cb2); pbDst += cb2; } break; } } /* type switch. */ } /* unpack loop */ l_endloop: /* * Zero remainder of the page. */ if (cbDst > 0) kHlpMemSet(pbDst, 0, cbDst); return 0; } /** * Special memcpy employed by the iterdata2 algorithm. * * Emulate a 16-bit memcpy (copying 16-bit at a time) and the effects this * has if src is very close to the destination. * * @param pbDst Destination pointer. * @param pbSrc Source pointer. Will always be <= pbDst. * @param cb Amount of data to be copied. * @remark This assumes that unaligned word and dword access is fine. */ static void kLdrModLXMemCopyW(KU8 *pbDst, const KU8 *pbSrc, int cb) { switch (pbDst - pbSrc) { case 0: case 1: case 2: case 3: /* 16-bit copy (unaligned) */ if (cb & 1) *pbDst++ = *pbSrc++; for (cb >>= 1; cb > 0; cb--, pbDst += 2, pbSrc += 2) *(KU16 *)pbDst = *(const KU16 *)pbSrc; break; default: /* 32-bit copy (unaligned) */ if (cb & 1) *pbDst++ = *pbSrc++; if (cb & 2) { *(KU16 *)pbDst = *(const KU16 *)pbSrc; pbDst += 2; pbSrc += 2; } for (cb >>= 2; cb > 0; cb--, pbDst += 4, pbSrc += 4) *(KU32 *)pbDst = *(const KU32 *)pbSrc; break; } } /** * Unprotects or protects the specified image mapping. * * @returns 0 on success. * @returns non-zero kLdr or OS status code on failure. * * @param pModLX The LX module interpreter instance. * @param pvBits The mapping to protect. * @param UnprotectOrProtect If 1 unprotect (i.e. make all writable), otherwise * protect according to the object table. */ static int kldrModLXDoProtect(PKLDRMODLX pModLX, void *pvBits, unsigned fUnprotectOrProtect) { KU32 i; PKLDRMOD pMod = pModLX->pMod; /* * Change object protection. */ for (i = 0; i < pMod->cSegments; i++) { int rc; void *pv; KPROT enmProt; /* calc new protection. */ enmProt = pMod->aSegments[i].enmProt; if (fUnprotectOrProtect) { switch (enmProt) { case KPROT_NOACCESS: case KPROT_READONLY: case KPROT_READWRITE: case KPROT_WRITECOPY: enmProt = KPROT_READWRITE; break; case KPROT_EXECUTE: case KPROT_EXECUTE_READ: case KPROT_EXECUTE_READWRITE: case KPROT_EXECUTE_WRITECOPY: enmProt = KPROT_EXECUTE_READWRITE; break; default: KLDRMODLX_ASSERT(!"bad enmProt"); return -1; } } else { /* copy on write -> normal write. */ if (enmProt == KPROT_EXECUTE_WRITECOPY) enmProt = KPROT_EXECUTE_READWRITE; else if (enmProt == KPROT_WRITECOPY) enmProt = KPROT_READWRITE; } /* calc the address and set page protection. */ pv = (KU8 *)pvBits + pMod->aSegments[i].RVA; rc = kHlpPageProtect(pv, pMod->aSegments[i].cbMapped, enmProt); if (rc) break; /** @todo the gap page should be marked NOACCESS! */ } return 0; } /** @copydoc kLdrModUnmap */ static int kldrModLXUnmap(PKLDRMOD pMod) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; KU32 i; int rc; /* * Mapped? */ if (!pModLX->pvMapping) return KLDR_ERR_NOT_MAPPED; /* * Free the mapping and update the segments. */ rc = kHlpPageFree((void *)pModLX->pvMapping, pModLX->cbMapped); KLDRMODLX_ASSERT(!rc); pModLX->pvMapping = NULL; for (i = 0; i < pMod->cSegments; i++) pMod->aSegments[i].MapAddress = 0; return rc; } /** @copydoc kLdrModAllocTLS */ static int kldrModLXAllocTLS(PKLDRMOD pMod, void *pvMapping) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; /* no tls, just do the error checking. */ if ( pvMapping == KLDRMOD_INT_MAP && pModLX->pvMapping) return KLDR_ERR_NOT_MAPPED; return 0; } /** @copydoc kLdrModFreeTLS */ static void kldrModLXFreeTLS(PKLDRMOD pMod, void *pvMapping) { /* no tls. */ K_NOREF(pMod); K_NOREF(pvMapping); } /** @copydoc kLdrModReload */ static int kldrModLXReload(PKLDRMOD pMod) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; int rc, rc2; /* * Mapped? */ if (!pModLX->pvMapping) return KLDR_ERR_NOT_MAPPED; /* * Before doing anything we'll have to make all pages writable. */ rc = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 1 /* unprotect */); if (rc) return rc; /* * Load the bits again. */ rc = kldrModLXDoLoadBits(pModLX, (void *)pModLX->pvMapping); /* * Restore protection. */ rc2 = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 0 /* protect */); if (!rc && rc2) rc = rc2; return rc; } /** @copydoc kLdrModFixupMapping */ static int kldrModLXFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; int rc, rc2; /* * Mapped? */ if (!pModLX->pvMapping) return KLDR_ERR_NOT_MAPPED; /* * Before doing anything we'll have to make all pages writable. */ rc = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 1 /* unprotect */); if (rc) return rc; /* * Apply fixups and resolve imports. */ rc = kldrModLXRelocateBits(pMod, (void *)pModLX->pvMapping, (KUPTR)pModLX->pvMapping, pMod->aSegments[0].LinkAddress, pfnGetImport, pvUser); /* * Restore protection. */ rc2 = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 0 /* protect */); if (!rc && rc2) rc = rc2; return rc; } /** @copydoc kLdrModCallInit */ static int kldrModLXCallInit(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; int rc; /* * Mapped? */ if (pvMapping == KLDRMOD_INT_MAP) { pvMapping = (void *)pModLX->pvMapping; if (!pvMapping) return KLDR_ERR_NOT_MAPPED; } /* * Do TLS callbacks first and then call the init/term function if it's a DLL. */ if ((pModLX->Hdr.e32_mflags & E32MODMASK) == E32MODDLL) rc = kldrModLXDoCallDLL(pModLX, pvMapping, 0 /* attach */, uHandle); else rc = 0; return rc; } /** * Call the DLL entrypoint. * * @returns 0 on success. * @returns KLDR_ERR_MODULE_INIT_FAILED or KLDR_ERR_THREAD_ATTACH_FAILED on failure. * @param pModLX The LX module interpreter instance. * @param pvMapping The module mapping to use (resolved). * @param uOp The operation (DLL_*). * @param uHandle The module handle to present. */ static int kldrModLXDoCallDLL(PKLDRMODLX pModLX, void *pvMapping, unsigned uOp, KUPTR uHandle) { int rc; /* * If no entrypoint there isn't anything to be done. */ if ( !pModLX->Hdr.e32_startobj || pModLX->Hdr.e32_startobj > pModLX->Hdr.e32_objcnt) return 0; /* * Invoke the entrypoint and convert the boolean result to a kLdr status code. */ rc = kldrModLXDoCall((KUPTR)pvMapping + (KUPTR)pModLX->pMod->aSegments[pModLX->Hdr.e32_startobj - 1].RVA + pModLX->Hdr.e32_eip, uHandle, uOp, NULL); if (rc) rc = 0; else if (uOp == 0 /* attach */) rc = KLDR_ERR_MODULE_INIT_FAILED; else /* detach: ignore failures */ rc = 0; return rc; } /** * Do a 3 parameter callback. * * @returns 32-bit callback return. * @param uEntrypoint The address of the function to be called. * @param uHandle The first argument, the module handle. * @param uOp The second argumnet, the reason we're calling. * @param pvReserved The third argument, reserved argument. (figure this one out) */ static KI32 kldrModLXDoCall(KUPTR uEntrypoint, KUPTR uHandle, KU32 uOp, void *pvReserved) { #if defined(__X86__) || defined(__i386__) || defined(_M_IX86) KI32 rc; /** @todo try/except */ /* * Paranoia. */ # ifdef __GNUC__ __asm__ __volatile__( "pushl %2\n\t" "pushl %1\n\t" "pushl %0\n\t" "lea 12(%%esp), %2\n\t" "call *%3\n\t" "movl %2, %%esp\n\t" : "=a" (rc) : "d" (uOp), "S" (0), "c" (uEntrypoint), "0" (uHandle)); # elif defined(_MSC_VER) __asm { mov eax, [uHandle] mov edx, [uOp] mov ecx, 0 mov ebx, [uEntrypoint] push edi mov edi, esp push ecx push edx push eax call ebx mov esp, edi pop edi mov [rc], eax } # else # error "port me!" # endif K_NOREF(pvReserved); return rc; #else K_NOREF(uEntrypoint); K_NOREF(uHandle); K_NOREF(uOp); K_NOREF(pvReserved); return KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE; #endif } /** @copydoc kLdrModCallTerm */ static int kldrModLXCallTerm(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; /* * Mapped? */ if (pvMapping == KLDRMOD_INT_MAP) { pvMapping = (void *)pModLX->pvMapping; if (!pvMapping) return KLDR_ERR_NOT_MAPPED; } /* * Do the call. */ if ((pModLX->Hdr.e32_mflags & E32MODMASK) == E32MODDLL) kldrModLXDoCallDLL(pModLX, pvMapping, 1 /* detach */, uHandle); return 0; } /** @copydoc kLdrModCallThread */ static int kldrModLXCallThread(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle, unsigned fAttachingOrDetaching) { /* no thread attach/detach callout. */ K_NOREF(pMod); K_NOREF(pvMapping); K_NOREF(uHandle); K_NOREF(fAttachingOrDetaching); return 0; } /** @copydoc kLdrModSize */ static KLDRADDR kldrModLXSize(PKLDRMOD pMod) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; return pModLX->cbMapped; } /** @copydoc kLdrModGetBits */ static int kldrModLXGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; int rc; /* * Load the image bits. */ rc = kldrModLXDoLoadBits(pModLX, pvBits); if (rc) return rc; /* * Perform relocations. */ return kldrModLXRelocateBits(pMod, pvBits, BaseAddress, pMod->aSegments[0].LinkAddress, pfnGetImport, pvUser); } /** @copydoc kLdrModRelocateBits */ static int kldrModLXRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) { PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData; KU32 iSeg; int rc; /* * Do we need to to *anything*? */ if ( NewBaseAddress == OldBaseAddress && NewBaseAddress == pModLX->paObjs[0].o32_base && !pModLX->Hdr.e32_impmodcnt) return 0; /* * Load the fixup section. */ if (!pModLX->pbFixupSection) { rc = kldrModLXDoLoadFixupSection(pModLX); if (rc) return rc; } /* * Iterate the segments. */ for (iSeg = 0; iSeg < pModLX->Hdr.e32_objcnt; iSeg++) { const struct o32_obj * const pObj = &pModLX->paObjs[iSeg]; KLDRADDR PageAddress = NewBaseAddress + pModLX->pMod->aSegments[iSeg].RVA; KU32 iPage; KU8 *pbPage = (KU8 *)pvBits + (KUPTR)pModLX->pMod->aSegments[iSeg].RVA; /* * Iterate the page map pages. */ for (iPage = 0, rc = 0; !rc && iPage < pObj->o32_mapsize; iPage++, pbPage += OBJPAGELEN, PageAddress += OBJPAGELEN) { const KU8 * const pbFixupRecEnd = pModLX->pbFixupRecs + pModLX->paoffPageFixups[iPage + pObj->o32_pagemap]; const KU8 *pb = pModLX->pbFixupRecs + pModLX->paoffPageFixups[iPage + pObj->o32_pagemap - 1]; KLDRADDR uValue = NIL_KLDRADDR; KU32 fKind = 0; int iSelector; /* sanity */ if (pbFixupRecEnd < pb) return KLDR_ERR_BAD_FIXUP; if (pbFixupRecEnd - 1 > pModLX->pbFixupSectionLast) return KLDR_ERR_BAD_FIXUP; if (pb < pModLX->pbFixupSection) return KLDR_ERR_BAD_FIXUP; /* * Iterate the fixup record. */ while (pb < pbFixupRecEnd) { union _rel { const KU8 * pb; const struct r32_rlc *prlc; } u; u.pb = pb; pb += 3 + (u.prlc->nr_stype & NRCHAIN ? 0 : 1); /* place pch at the 4th member. */ /* * Figure out the target. */ switch (u.prlc->nr_flags & NRRTYP) { /* * Internal fixup. */ case NRRINT: { KU16 iTrgObject; KU32 offTrgObject; /* the object */ if (u.prlc->nr_flags & NR16OBJMOD) { iTrgObject = *(const KU16 *)pb; pb += 2; } else iTrgObject = *pb++; iTrgObject--; if (iTrgObject >= pModLX->Hdr.e32_objcnt) return KLDR_ERR_BAD_FIXUP; /* the target */ if ((u.prlc->nr_stype & NRSRCMASK) != NRSSEG) { if (u.prlc->nr_flags & NR32BITOFF) { offTrgObject = *(const KU32 *)pb; pb += 4; } else { offTrgObject = *(const KU16 *)pb; pb += 2; } /* calculate the symbol info. */ uValue = offTrgObject + NewBaseAddress + pMod->aSegments[iTrgObject].RVA; } else uValue = NewBaseAddress + pMod->aSegments[iTrgObject].RVA; if ( (u.prlc->nr_stype & NRALIAS) || (pMod->aSegments[iTrgObject].fFlags & KLDRSEG_FLAG_16BIT)) iSelector = pMod->aSegments[iTrgObject].Sel16bit; else iSelector = pMod->aSegments[iTrgObject].SelFlat; fKind = 0; break; } /* * Import by symbol ordinal. */ case NRRORD: { KU16 iModule; KU32 iSymbol; /* the module ordinal */ if (u.prlc->nr_flags & NR16OBJMOD) { iModule = *(const KU16 *)pb; pb += 2; } else iModule = *pb++; iModule--; if (iModule >= pModLX->Hdr.e32_impmodcnt) return KLDR_ERR_BAD_FIXUP; #if 1 if (u.prlc->nr_flags & NRICHAIN) return KLDR_ERR_BAD_FIXUP; #endif /* . */ if (u.prlc->nr_flags & NR32BITOFF) { iSymbol = *(const KU32 *)pb; pb += 4; } else if (!(u.prlc->nr_flags & NR8BITORD)) { iSymbol = *(const KU16 *)pb; pb += 2; } else iSymbol = *pb++; /* resolve it. */ rc = pfnGetImport(pMod, iModule, iSymbol, NULL, 0, NULL, &uValue, &fKind, pvUser); if (rc) return rc; iSelector = -1; break; } /* * Import by symbol name. */ case NRRNAM: { KU32 iModule; KU16 offSymbol; const KU8 *pbSymbol; /* the module ordinal */ if (u.prlc->nr_flags & NR16OBJMOD) { iModule = *(const KU16 *)pb; pb += 2; } else iModule = *pb++; iModule--; if (iModule >= pModLX->Hdr.e32_impmodcnt) return KLDR_ERR_BAD_FIXUP; #if 1 if (u.prlc->nr_flags & NRICHAIN) return KLDR_ERR_BAD_FIXUP; #endif /* . */ if (u.prlc->nr_flags & NR32BITOFF) { offSymbol = *(const KU32 *)pb; pb += 4; } else if (!(u.prlc->nr_flags & NR8BITORD)) { offSymbol = *(const KU16 *)pb; pb += 2; } else offSymbol = *pb++; pbSymbol = pModLX->pbImportProcs + offSymbol; if ( pbSymbol < pModLX->pbImportProcs || pbSymbol > pModLX->pbFixupSectionLast) return KLDR_ERR_BAD_FIXUP; /* resolve it. */ rc = pfnGetImport(pMod, iModule, NIL_KLDRMOD_SYM_ORDINAL, (const char *)pbSymbol + 1, *pbSymbol, NULL, &uValue, &fKind, pvUser); if (rc) return rc; iSelector = -1; break; } case NRRENT: KLDRMODLX_ASSERT(!"NRRENT"); /* Falls through. */ default: iSelector = -1; break; } /* addend */ if (u.prlc->nr_flags & NRADD) { if (u.prlc->nr_flags & NR32BITADD) { uValue += *(const KU32 *)pb; pb += 4; } else { uValue += *(const KU16 *)pb; pb += 2; } } /* * Deal with the 'source' (i.e. the place that should be modified - very logical). */ if (!(u.prlc->nr_stype & NRCHAIN)) { int off = u.prlc->r32_soff; /* common / simple */ if ( (u.prlc->nr_stype & NRSRCMASK) == NROFF32 && off >= 0 && off <= (int)OBJPAGELEN - 4) *(KU32 *)&pbPage[off] = (KU32)uValue; else if ( (u.prlc->nr_stype & NRSRCMASK) == NRSOFF32 && off >= 0 && off <= (int)OBJPAGELEN - 4) *(KU32 *)&pbPage[off] = (KU32)(uValue - (PageAddress + off + 4)); else { /* generic */ rc = kldrModLXDoReloc(pbPage, off, PageAddress, u.prlc, iSelector, uValue, fKind); if (rc) return rc; } } else if (!(u.prlc->nr_flags & NRICHAIN)) { const KI16 *poffSrc = (const KI16 *)pb; KU8 c = u.pb[2]; /* common / simple */ if ((u.prlc->nr_stype & NRSRCMASK) == NROFF32) { while (c-- > 0) { int off = *poffSrc++; if (off >= 0 && off <= (int)OBJPAGELEN - 4) *(KU32 *)&pbPage[off] = (KU32)uValue; else { rc = kldrModLXDoReloc(pbPage, off, PageAddress, u.prlc, iSelector, uValue, fKind); if (rc) return rc; } } } else if ((u.prlc->nr_stype & NRSRCMASK) == NRSOFF32) { while (c-- > 0) { int off = *poffSrc++; if (off >= 0 && off <= (int)OBJPAGELEN - 4) *(KU32 *)&pbPage[off] = (KU32)(uValue - (PageAddress + off + 4)); else { rc = kldrModLXDoReloc(pbPage, off, PageAddress, u.prlc, iSelector, uValue, fKind); if (rc) return rc; } } } else { while (c-- > 0) { rc = kldrModLXDoReloc(pbPage, *poffSrc++, PageAddress, u.prlc, iSelector, uValue, fKind); if (rc) return rc; } } pb = (const KU8 *)poffSrc; } else { /* This is a pain because it will require virgin pages on a relocation. */ KLDRMODLX_ASSERT(!"NRICHAIN"); return KLDR_ERR_LX_NRICHAIN_NOT_SUPPORTED; } } } } return 0; } /** * Applies the relocation to one 'source' in a page. * * This takes care of the more esotic case while the common cases * are dealt with seperately. * * @returns 0 on success, non-zero kLdr status code on failure. * @param pbPage The page in which to apply the fixup. * @param off Page relative offset of where to apply the offset. * @param uValue The target value. * @param fKind The target kind. */ static int kldrModLXDoReloc(KU8 *pbPage, int off, KLDRADDR PageAddress, const struct r32_rlc *prlc, int iSelector, KLDRADDR uValue, KU32 fKind) { #pragma pack(1) /* just to be sure */ union { KU8 ab[6]; KU32 off32; KU16 off16; KU8 off8; struct { KU16 off; KU16 Sel; } Far16; struct { KU32 off; KU16 Sel; } Far32; } uData; #pragma pack() const KU8 *pbSrc; KU8 *pbDst; KU8 cb; K_NOREF(fKind); /* * Compose the fixup data. */ switch (prlc->nr_stype & NRSRCMASK) { case NRSBYT: uData.off8 = (KU8)uValue; cb = 1; break; case NRSSEG: if (iSelector == -1) { /* fixme */ } uData.off16 = iSelector; cb = 2; break; case NRSPTR: if (iSelector == -1) { /* fixme */ } uData.Far16.off = (KU16)uValue; uData.Far16.Sel = iSelector; cb = 4; break; case NRSOFF: uData.off16 = (KU16)uValue; cb = 2; break; case NRPTR48: if (iSelector == -1) { /* fixme */ } uData.Far32.off = (KU32)uValue; uData.Far32.Sel = iSelector; cb = 6; break; case NROFF32: uData.off32 = (KU32)uValue; cb = 4; break; case NRSOFF32: uData.off32 = (KU32)(uValue - (PageAddress + off + 4)); cb = 4; break; default: return KLDR_ERR_LX_BAD_FIXUP_SECTION; /** @todo fix error, add more checks! */ } /* * Apply it. This is sloooow... */ pbSrc = &uData.ab[0]; pbDst = pbPage + off; while (cb-- > 0) { if (off > (int)OBJPAGELEN) break; if (off >= 0) *pbDst = *pbSrc; pbSrc++; pbDst++; } return 0; } /** * The LX module interpreter method table. */ KLDRMODOPS g_kLdrModLXOps = { "LX", NULL, kldrModLXCreate, kldrModLXDestroy, kldrModLXQuerySymbol, kldrModLXEnumSymbols, kldrModLXGetImport, kldrModLXNumberOfImports, NULL /* can execute one is optional */, kldrModLXGetStackInfo, kldrModLXQueryMainEntrypoint, NULL /* pfnQueryImageUuid */, NULL /* fixme */, NULL /* fixme */, kldrModLXEnumDbgInfo, kldrModLXHasDbgInfo, kldrModLXMap, kldrModLXUnmap, kldrModLXAllocTLS, kldrModLXFreeTLS, kldrModLXReload, kldrModLXFixupMapping, kldrModLXCallInit, kldrModLXCallTerm, kldrModLXCallThread, kldrModLXSize, kldrModLXGetBits, kldrModLXRelocateBits, NULL /* fixme: pfnMostlyDone */, 42 /* the end */ }; kbuild-3149/src/lib/kStuff/kLdr/kLdrMod.c0000644000175000017500000010563413252530253020110 0ustar locutuslocutus/* $Id: kLdrMod.c 81 2016-08-18 22:10:38Z bird $ */ /** @file * kLdr - The Module Interpreter. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include "kLdrInternal.h" #include #include #if 1 /* testing headers */ # include # include # include #endif /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** @def KLDRMOD_STRICT * Define KLDRMOD_STRICT to enabled strict checks in KLDRMOD. */ #define KLDRMOD_STRICT 1 /** @def KLDRMOD_ASSERT * Assert that an expression is true when KLDR_STRICT is defined. */ #ifdef KLDRMOD_STRICT # define KLDRMOD_ASSERT(expr) kHlpAssert(expr) #else # define KLDRMOD_ASSERT(expr) do {} while (0) #endif /** Return / crash validation of a module argument. */ #define KLDRMOD_VALIDATE_EX(pMod, rc) \ do { \ if ( (pMod)->u32Magic != KLDRMOD_MAGIC \ || (pMod)->pOps == NULL \ )\ { \ return (rc); \ } \ } while (0) /** Return / crash validation of a module argument. */ #define KLDRMOD_VALIDATE(pMod) \ KLDRMOD_VALIDATE_EX(pMod, KERR_INVALID_PARAMETER) /** Return / crash validation of a module argument. */ #define KLDRMOD_VALIDATE_VOID(pMod) \ do { \ if ( (pMod)->u32Magic != KLDRMOD_MAGIC \ || (pMod)->pOps == NULL \ )\ { \ return; \ } \ } while (0) /******************************************************************************* * Global Variables * *******************************************************************************/ /** The list of module interpreters. */ static PCKLDRMODOPS g_pModInterpreterHead = NULL; /******************************************************************************* * Internal Functions * *******************************************************************************/ /** * Open a executable image by file name. * * @returns 0 on success and *ppMod pointing to a module instance. * On failure, a non-zero OS specific error code is returned. * @param pszFilename The filename to open. * @param fFlags Flags, MBZ. * @param enmCpuArch The desired CPU architecture. KCPUARCH_UNKNOWN means * anything goes, but with a preference for the current * host architecture. * @param ppMod Where to store the module handle. */ int kLdrModOpen(const char *pszFilename, KU32 fFlags, KCPUARCH enmCpuArch, PPKLDRMOD ppMod) { /* * Open the file using a bit provider. */ PKRDR pRdr; int rc = kRdrOpen(&pRdr, pszFilename); if (!rc) { rc = kLdrModOpenFromRdr(pRdr, fFlags, enmCpuArch, ppMod); if (!rc) return 0; kRdrClose(pRdr); } return rc; } /** * Select image from the FAT according to the enmCpuArch and fFlag. * * @returns 0 on success and *poffHdr set to the image header. * On failure, a non-zero error code is returned. * * @param pRdr The file provider instance to use. * @param fFlags Flags, MBZ. * @param enmCpuArch The desired CPU architecture. KCPUARCH_UNKNOWN means * anything goes, but with a preference for the current * host architecture. * @param u32Magic The FAT magic. * @param poffHdr Where to store the offset of the selected image. */ static int kldrModOpenFromRdrSelectImageFromFAT(PKRDR pRdr, KU32 fFlags, KCPUARCH enmCpuArch, KU32 u32Magic, KLDRFOFF *poffHdr) { int rcRet = KLDR_ERR_CPU_ARCH_MISMATCH; KLDRFOFF off = *poffHdr + sizeof(KU32); KLDRFOFF offEndFAT; KBOOL fCpuArchWhatever; KU32 cArchs; KU32 iArch; int rc; K_NOREF(fFlags); /* Read fat_header_t::nfat_arch. */ rc = kRdrRead(pRdr, &cArchs, sizeof(cArchs), off); if (rc) return rc; off += sizeof(KU32); if (u32Magic == IMAGE_FAT_SIGNATURE_OE) cArchs = K_E2E_U32(cArchs); if (cArchs == 0) return KLDR_ERR_FAT_INVALID; /* Deal with KCPUARCH_UNKNOWN. */ fCpuArchWhatever = enmCpuArch == KCPUARCH_UNKNOWN; if (fCpuArchWhatever) { KCPU enmCpuIgnored; kCpuGetArchAndCpu(&enmCpuArch, &enmCpuIgnored); } /* * Iterate the architecture list. */ offEndFAT = off + cArchs * sizeof(fat_arch_t); for (iArch = 0; iArch < cArchs; iArch++) { KCPUARCH enmEntryArch; fat_arch_t Arch; rc = kRdrRead(pRdr, &Arch, sizeof(Arch), off); if (rc) return rc; off += sizeof(Arch); if (u32Magic == IMAGE_FAT_SIGNATURE_OE) { Arch.cputype = K_E2E_U32(Arch.cputype); Arch.cpusubtype = K_E2E_U32(Arch.cpusubtype); Arch.offset = K_E2E_U32(Arch.offset); Arch.size = K_E2E_U32(Arch.size); Arch.align = K_E2E_U32(Arch.align); } /* Simple validation. */ if ( (KLDRFOFF)Arch.offset < offEndFAT || (KLDRFOFF)Arch.offset >= kRdrSize(pRdr) || Arch.align >= 32 || Arch.offset & ((KU32_C(1) << Arch.align) - KU32_C(1))) return KLDR_ERR_FAT_INVALID; /* deal with the cputype and cpusubtype. (See similar code in kLdrModMachO.c.) */ switch (Arch.cputype) { case CPU_TYPE_X86: enmEntryArch = KCPUARCH_X86_32; switch (Arch.cpusubtype) { case CPU_SUBTYPE_I386_ALL: /*case CPU_SUBTYPE_386: ^^ ;*/ case CPU_SUBTYPE_486: case CPU_SUBTYPE_486SX: /*case CPU_SUBTYPE_586: vv */ case CPU_SUBTYPE_PENT: case CPU_SUBTYPE_PENTPRO: case CPU_SUBTYPE_PENTII_M3: case CPU_SUBTYPE_PENTII_M5: case CPU_SUBTYPE_CELERON: case CPU_SUBTYPE_CELERON_MOBILE: case CPU_SUBTYPE_PENTIUM_3: case CPU_SUBTYPE_PENTIUM_3_M: case CPU_SUBTYPE_PENTIUM_3_XEON: case CPU_SUBTYPE_PENTIUM_M: case CPU_SUBTYPE_PENTIUM_4: case CPU_SUBTYPE_PENTIUM_4_M: case CPU_SUBTYPE_XEON: case CPU_SUBTYPE_XEON_MP: break; default: return KLDR_ERR_FAT_UNSUPPORTED_CPU_SUBTYPE; } break; case CPU_TYPE_X86_64: enmEntryArch = KCPUARCH_AMD64; switch (Arch.cpusubtype & ~CPU_SUBTYPE_MASK) { case CPU_SUBTYPE_X86_64_ALL: break; default: return KLDR_ERR_FAT_UNSUPPORTED_CPU_SUBTYPE; } break; default: enmEntryArch = KCPUARCH_UNKNOWN; break; } /* * Finally the actual image selecting. * * Return immediately on a perfect match. Otherwise continue looking, * if we're none too picky, remember the first image in case we don't * get lucky. */ if (enmEntryArch == enmCpuArch) { *poffHdr = Arch.offset; return 0; } if ( fCpuArchWhatever && rcRet == KLDR_ERR_CPU_ARCH_MISMATCH) { *poffHdr = Arch.offset; rcRet = 0; } } return rcRet; } /** * Open a executable image from a file provider instance. * * @returns 0 on success and *ppMod pointing to a module instance. * On failure, a non-zero OS specific error code is returned. * @param pRdr The file provider instance to use. * On success, the ownership of the instance is taken by the * module and the caller must not ever touch it again. * (The instance is not closed on failure, the call has to do that.) * @param fFlags Flags, MBZ. * @param enmCpuArch The desired CPU architecture. KCPUARCH_UNKNOWN means * anything goes, but with a preference for the current * host architecture. * @param ppMod Where to store the module handle. */ int kLdrModOpenFromRdr(PKRDR pRdr, KU32 fFlags, KCPUARCH enmCpuArch, PPKLDRMOD ppMod) { union { KU32 u32; KU16 u16; KU16 au16[2]; KU8 au8[4]; } u; KLDRFOFF offHdr = 0; int rc; kHlpAssertReturn(!(fFlags & ~KLDRMOD_OPEN_FLAGS_VALID_MASK), KERR_INVALID_PARAMETER); for (;;) { /* * Try figure out what kind of image this is. * Always read the 'new header' if we encounter MZ. */ rc = kRdrRead(pRdr, &u, sizeof(u), offHdr); if (rc) return rc; if ( u.u16 == IMAGE_DOS_SIGNATURE && kRdrSize(pRdr) > (KFOFF)sizeof(IMAGE_DOS_HEADER)) { rc = kRdrRead(pRdr, &u, sizeof(u.u32), K_OFFSETOF(IMAGE_DOS_HEADER, e_lfanew)); if (rc) return rc; if ((KLDRFOFF)u.u32 < kRdrSize(pRdr)) { offHdr = u.u32; rc = kRdrRead(pRdr, &u, sizeof(u.u32), offHdr); if (rc) return rc; } else u.u16 = IMAGE_DOS_SIGNATURE; } /* * Handle FAT images too here (one only). */ if ( ( u.u32 == IMAGE_FAT_SIGNATURE || u.u32 == IMAGE_FAT_SIGNATURE_OE) && offHdr == 0) { rc = kldrModOpenFromRdrSelectImageFromFAT(pRdr, fFlags, enmCpuArch, u.u32, &offHdr); if (rc) return rc; if (offHdr) continue; } break; } /* * Use the magic to select the appropriate image interpreter head on. */ if (u.u16 == IMAGE_DOS_SIGNATURE) rc = KLDR_ERR_MZ_NOT_SUPPORTED; else if (u.u16 == IMAGE_NE_SIGNATURE) rc = KLDR_ERR_NE_NOT_SUPPORTED; else if (u.u16 == IMAGE_LX_SIGNATURE) rc = g_kLdrModLXOps.pfnCreate(&g_kLdrModLXOps, pRdr, fFlags, enmCpuArch, offHdr, ppMod); else if (u.u16 == IMAGE_LE_SIGNATURE) rc = KLDR_ERR_LE_NOT_SUPPORTED; else if (u.u32 == IMAGE_NT_SIGNATURE) rc = g_kLdrModPEOps.pfnCreate(&g_kLdrModPEOps, pRdr, fFlags, enmCpuArch, offHdr, ppMod); else if ( u.u32 == IMAGE_MACHO32_SIGNATURE || u.u32 == IMAGE_MACHO32_SIGNATURE_OE || u.u32 == IMAGE_MACHO64_SIGNATURE || u.u32 == IMAGE_MACHO64_SIGNATURE_OE) rc = g_kLdrModMachOOps.pfnCreate(&g_kLdrModMachOOps, pRdr, fFlags, enmCpuArch, offHdr, ppMod); else if (u.u32 == IMAGE_ELF_SIGNATURE) rc = KLDR_ERR_ELF_NOT_SUPPORTED; else rc = KLDR_ERR_UNKNOWN_FORMAT; /* * If no head on hit, let each interpreter have a go. */ if (rc) { PCKLDRMODOPS pOps; for (pOps = g_pModInterpreterHead; pOps; pOps = pOps->pNext) { int rc2 = pOps->pfnCreate(pOps, pRdr, fFlags, enmCpuArch, offHdr, ppMod); if (!rc2) return rc; } *ppMod = NULL; } return rc; } /** * Closes an open module. * * The caller is responsible for calling kLdrModUnmap() and kLdrFreeTLS() * before closing the module. * * @returns 0 on success, non-zero on failure. The module instance state * is unknown on failure, it's best not to touch it. * @param pMod The module. */ int kLdrModClose(PKLDRMOD pMod) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnDestroy(pMod); } /** * Queries a symbol by name or ordinal number. * * @returns 0 and *puValue and *pfKind on success. * KLDR_ERR_SYMBOL_NOT_FOUND is returned if the symbol wasn't found. * Other failures could stem from bad executable format failures, * read failure in case pvBits isn't specified and no mapping should be used. * @param pMod The module. * @param pvBits Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress. * This can be used by some module interpreters to reduce memory consumption. * @param BaseAddress The module base address to use when calculating the symbol value. * There are two special values that can be used: * KLDRMOD_BASEADDRESS_LINK and KLDRMOD_BASEADDRESS_MAP. * @param iSymbol The symbol ordinal. (optional) * @param pchSymbol The symbol name. (optional) * Important, this doesn't have to be a null-terminated string. * @param cchSymbol The length of the symbol name. * @param pszVersion The symbol version. NULL if not versioned. * @param pfnGetForwarder The callback to use when resolving a forwarder symbol. This is optional * and if not specified KLDR_ERR_FORWARDER is returned instead. * @param pvUser The user argument for the pfnGetForwarder callback. * @param puValue Where to store the symbol value. (optional) * @param pfKind On input one of the KLDRSYMKIND_REQ_* #defines. * On output the symbol kind. (optional) */ int kLdrModQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind) { KLDRMOD_VALIDATE(pMod); if (!puValue && !pfKind) return KERR_INVALID_PARAMETER; if (puValue) *puValue = 0; if (pfKind) K_VALIDATE_FLAGS(*pfKind, KLDRSYMKIND_REQ_SEGMENTED); return pMod->pOps->pfnQuerySymbol(pMod, pvBits, BaseAddress, iSymbol, pchSymbol, cchSymbol, pszVersion, pfnGetForwarder, pvUser, puValue, pfKind); } /** * Enumerate the symbols in the module. * * @returns 0 on success and non-zero a status code on failure. * @param pMod The module which symbols should be enumerated. * @param pvBits Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress. * This can be used by some module interpreters to reduce memory consumption. * @param BaseAddress The module base address to use when calculating the symbol values. * There are two special values that could be can: * KLDRMOD_BASEADDRESS_LINK and KLDRMOD_BASEADDRESS_MAP. * @param fFlags The enumeration flags. A combination of the KLDRMOD_ENUM_SYMS_FLAGS_* \#defines. * @param pfnCallback The enumeration callback function. * @param pvUser The user argument to the callback function. */ int kLdrModEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser) { KLDRMOD_VALIDATE(pMod); K_VALIDATE_FLAGS(fFlags, KLDRMOD_ENUM_SYMS_FLAGS_ALL); return pMod->pOps->pfnEnumSymbols(pMod, pvBits, BaseAddress, fFlags, pfnCallback, pvUser); } /** * Get the name of an import module by ordinal number. * * @returns 0 and name in pszName on success. * On buffer overruns KERR_BUFFER_OVERFLOW will be returned. * On other failures and appropriate error code is returned. * @param pMod The module. * @param pvBits Optional pointer to bits returned by kLdrModGetBits(). * This can be used by some module interpreters to reduce memory consumption. * @param iImport The import module ordinal number. * @param pszName Where to store the name. * @param cchName The size of the name buffer. */ int kLdrModGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnGetImport(pMod, pvBits, iImport, pszName, cchName); } /** * Get the number of import modules. * * @returns The number of import modules. -1 if something really bad happens. * @param pMod The module. * @param pvBits Optional pointer to bits returned by kLdrModGetBits(). * This can be used by some module interpreters to reduce memory consumption. */ KI32 kLdrModNumberOfImports(PKLDRMOD pMod, const void *pvBits) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnNumberOfImports(pMod, pvBits); } /** * Checks if this module can be executed by the specified arch+cpu. * * @returns 0 if it can, KCPU_ERR_ARCH_CPU_NOT_COMPATIBLE if it can't. * Other failures may occur and cause other return values. * @param pMod The module. * @param pvBits Optional pointer to bits returned by kLdrModGetBits(). * This can be used by some module interpreters to reduce memory consumption. * @param enmArch The CPU architecture. * @param enmCpu The CPU series/model. */ int kLdrModCanExecuteOn(PKLDRMOD pMod, const void *pvBits, KCPUARCH enmArch, KCPU enmCpu) { KLDRMOD_VALIDATE(pMod); if (pMod->pOps->pfnCanExecuteOn) return pMod->pOps->pfnCanExecuteOn(pMod, pvBits, enmArch, enmCpu); return kCpuCompare(pMod->enmArch, pMod->enmCpu, enmArch, enmCpu); } /** * Gets the image stack info. * * @returns 0 on success, non-zero on failure. * @param pMod * @param pvBits Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress. * This can be used by some module interpreters to reduce memory consumption. * @param BaseAddress The module base address to use when calculating the stack address. * There are two special values that can be used: * KLDRMOD_BASEADDRESS_LINK and KLDRMOD_BASEADDRESS_MAP. * @param pStackInfo The stack information. */ int kLdrModGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnGetStackInfo(pMod, pvBits, BaseAddress, pStackInfo); } /** * Queries the main entrypoint of the module. * * Only executable are supposed to have an main entrypoint, though some object and DLL * formats will also allow this. * * @returns 0 and *pMainEPAddress on success. Non-zero status code on failure. * @param pMod The module. * @param pvBits Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress. * This can be used by some module interpreters to reduce memory consumption. * @param BaseAddress The module base address to use when calculating the entrypoint address. * There are two special values that can be used: * KLDRMOD_BASEADDRESS_LINK and KLDRMOD_BASEADDRESS_MAP. * @param pMainEPAddress Where to store the entry point address. */ int kLdrModQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress) { KLDRMOD_VALIDATE(pMod); *pMainEPAddress = 0; return pMod->pOps->pfnQueryMainEntrypoint(pMod, pvBits, BaseAddress, pMainEPAddress); } /** * Queries the image UUID, if the image has one. * * @returns 0 and *pvUuid. Non-zero status code on failure. * @param pMod The module. * @param pvBits Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress. * This can be used by some module interpreters to reduce memory consumption. * @param pvUuid Where to store the UUID. * @param cbUuid Size of the UUID buffer, must be at least 16 bytes. */ int kLdrModQueryImageUuid(PKLDRMOD pMod, const void *pvBits, void *pvUuid, KSIZE cbUuid) { KLDRMOD_VALIDATE(pMod); if (cbUuid < 16) return KERR_INVALID_SIZE; if (pMod->pOps->pfnQueryImageUuid) return pMod->pOps->pfnQueryImageUuid(pMod, pvBits, pvUuid, cbUuid); return KLDR_ERR_NO_IMAGE_UUID; } /** * Queries info about a resource. * * If there are multiple resources matching the criteria, the best or * first match will be return. * * * @returns 0 on success. * @returns Whatever non-zero status returned by pfnCallback (enumeration was stopped). * @returns non-zero kLdr or native status code on failure. * * @param pMod The module. * @param pvBits Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress. * This can be used by some module interpreters to reduce memory consumption. * @param BaseAddress The module base address to use when calculating the resource addresses. * There are two special values that can be used: * KLDRMOD_BASEADDRESS_LINK and KLDRMOD_BASEADDRESS_MAP. * @param idType The resource type id to match if not NIL_KLDRMOD_RSRC_TYPE_ID. * @param pszType The resource type name to match if no NULL. * @param idName The resource name id to match if not NIL_KLDRMOD_RSRC_NAME_ID. * @param pszName The resource name to match if not NULL. * @param idLang The language id to match. * @param pfnCallback The callback function. * @param pvUser The user argument for the callback. */ int kLdrModQueryResource(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 idType, const char *pszType, KU32 idName, const char *pszName, KU32 idLang, PKLDRADDR pAddrRsrc, KSIZE *pcbRsrc) { KLDRMOD_VALIDATE(pMod); if (!pAddrRsrc && !pcbRsrc) return KERR_INVALID_PARAMETER; if (pAddrRsrc) *pAddrRsrc = NIL_KLDRADDR; if (pcbRsrc) *pcbRsrc = 0; return pMod->pOps->pfnQueryResource(pMod, pvBits, BaseAddress, idType, pszType, idName, pszName, idLang, pAddrRsrc, pcbRsrc); } /** * Enumerates the resources matching the specfied criteria. * * * @returns 0 on success. * @returns Whatever non-zero status returned by pfnCallback (enumeration was stopped). * @returns non-zero kLdr or native status code on failure. * * @param pMod The module. * @param pvBits Optional pointer to bits returned by kLdrModGetBits() currently located at BaseAddress. * This can be used by some module interpreters to reduce memory consumption. * @param BaseAddress The module base address to use when calculating the resource addresses. * There are two special values that can be used: * KLDRMOD_BASEADDRESS_LINK and KLDRMOD_BASEADDRESS_MAP. * @param idType The resource type id to match if not NIL_KLDRMOD_RSRC_TYPE_ID. * @param pszType The resource type name to match if no NULL. * @param idName The resource name id to match if not NIL_KLDRMOD_RSRC_NAME_ID. * @param pszName The resource name to match if not NULL. * @param idLang The language id to match. * @param pfnCallback The callback function. * @param pvUser The user argument for the callback. */ int kLdrModEnumResources(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 idType, const char *pszType, KU32 idName, const char *pszName, KU32 idLang, PFNKLDRENUMRSRC pfnCallback, void *pvUser) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnEnumResources(pMod, pvBits, BaseAddress, idType, pszType, idName, pszName, idLang, pfnCallback, pvUser); } /** * Enumerate the debug info formats contained in the executable image. * * @returns 0 on success, non-zero OS or kLdr status code on failure, or non-zero callback status. * @param pMod The module. * @param pvBits Optional pointer to bits returned by kLdrModGetBits(). * This can be used by some module interpreters to reduce memory consumption. * @param pfnCallback The callback function. * @param pvUser The user argument. * @see pg_kDbg for the debug info reader. */ int kLdrModEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnEnumDbgInfo(pMod, pvBits, pfnCallback, pvUser); } /** * Checks if the module has debug info embedded or otherwise associated with it. * * @returns 0 if it has debug info, KLDR_ERR_NO_DEBUG_INFO if no debug info, * and non-zero OS or kLdr status code on failure. * @param pMod The module. * @param pvBits Optional pointer to bits returned by kLdrModGetBits(). * This can be used by some module interpreters to reduce memory consumption. */ int kLdrModHasDbgInfo(PKLDRMOD pMod, const void *pvBits) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnHasDbgInfo(pMod, pvBits); } /** * May free up some resources held by the module. * * @todo define exactly what it possible to do after this call. * * @returns 0 on success, KLDR_ERR_* on failure. * @param pMod The module. */ int kLdrModMostlyDone(PKLDRMOD pMod) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnMostlyDone(pMod); } /** * Maps the module into the memory of the caller. * * On success the actual addresses for the segments can be found in MapAddress * member of each segment in the segment array. * * @returns 0 on success, non-zero OS or kLdr status code on failure. * @param pMod The module to be mapped. * @remark kLdr only supports one mapping at a time of a module. */ int kLdrModMap(PKLDRMOD pMod) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnMap(pMod); } /** * Unmaps a module previously mapped by kLdrModMap(). * * @returns 0 on success, non-zero OS or kLdr status code on failure. * @param pMod The module to unmap. */ int kLdrModUnmap(PKLDRMOD pMod) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnUnmap(pMod); } /** * Reloads all dirty pages in a module previously mapped by kLdrModMap(). * * The module interpreter may omit code pages if it can safely apply code * fixups again in a subsequent kLdrModFixupMapping() call. * * The caller is responsible for freeing TLS before calling this function. * * @returns 0 on success, non-zero OS or kLdr status code on failure. * @param pMod The module. */ int kLdrModReload(PKLDRMOD pMod) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnReload(pMod); } /** * Fixup the mapping made by kLdrModMap(). * * The caller is only responsible for not calling this function more than * once without doing kLDrModReload() inbetween. * * @returns 0 on success, non-zero OS or kLdr status code on failure. * @param pMod The module. * @param pfnGetImport The callback for resolving external (imported) symbols. * @param pvUser The callback user argument. */ int kLdrModFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnFixupMapping(pMod, pfnGetImport, pvUser); } /** * Get the size of the mapped module. * * @returns The size of the mapped module (in bytes). * @param pMod The module. */ KLDRADDR kLdrModSize(PKLDRMOD pMod) { KLDRMOD_VALIDATE_EX(pMod, 0); return pMod->pOps->pfnSize(pMod); } /** * Gets the module bits. * * The module interpreter will fill a mapping allocated by the caller with the * module bits reallocated to the specified address. * * @returns 0 on succes, non-zero OS or kLdr status code on failure. * @param pMod The module. * @param pvBits Where to put the bits. * @param BaseAddress The base address that should correspond to the first byte in pvBits * upon return. * @param pfnGetImport The callback ufor resolving external (imported) symbols. * @param pvUser The callback user argument. */ int kLdrModGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnGetBits(pMod, pvBits, BaseAddress, pfnGetImport, pvUser); } /** * Relocates the module bits previously obtained by kLdrModGetBits(). * * @returns 0 on succes, non-zero OS or kLdr status code on failure. * @param pMod The module. * @param pvBits Where to put the bits. * @param NewBaseAddress The new base address. * @param OldBaseAddress The old base address (i.e. the one specified to kLdrModGetBits() or as * NewBaseAddressto the previous kLdrModRelocateBits() call). * @param pfnGetImport The callback ufor resolving external (imported) symbols. * @param pvUser The callback user argument. */ int kLdrModRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnRelocateBits(pMod, pvBits, NewBaseAddress, OldBaseAddress, pfnGetImport, pvUser); } /** * Allocates Thread Local Storage for module mapped by kLdrModMap(). * * Calling kLdrModAllocTLS() more than once without calling kLdrModFreeTLS() * between each invocation is not supported. * * @returns 0 on success, non-zero OS or kLdr status code on failure. * @param pMod The module. * @param pvMapping The external mapping address or RTLDRMOD_INT_MAP. */ int kLdrModAllocTLS(PKLDRMOD pMod, void *pvMapping) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnAllocTLS(pMod, pvMapping); } /** * Frees Thread Local Storage previously allocated by kLdrModAllocTLS(). * * The caller is responsible for only calling kLdrModFreeTLS() once * after calling kLdrModAllocTLS(). * * @returns 0 on success, non-zero OS or kLdr status code on failure. * @param pMod The module. * @param pvMapping The external mapping address or RTLDRMOD_INT_MAP. */ void kLdrModFreeTLS(PKLDRMOD pMod, void *pvMapping) { KLDRMOD_VALIDATE_VOID(pMod); pMod->pOps->pfnFreeTLS(pMod, pvMapping); } /** * Call the module initializiation function of a mapped module (if any). * * @returns 0 on success or no init function, non-zero on init function failure or invalid pMod. * @param pMod The module. * @param pvMapping The external mapping address or RTLDRMOD_INT_MAP. * @param uHandle The module handle to use if any of the init functions requires the module handle. */ int kLdrModCallInit(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnCallInit(pMod, pvMapping, uHandle); } /** * Call the module termination function of a mapped module (if any). * * @returns 0 on success or no term function, non-zero on invalid pMod. * @param pMod The module. * @param pvMapping The external mapping address or RTLDRMOD_INT_MAP. * @param uHandle The module handle to use if any of the term functions requires the module handle. * * @remark Termination function failure will be ignored by the module interpreter. */ int kLdrModCallTerm(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle) { KLDRMOD_VALIDATE(pMod); return pMod->pOps->pfnCallTerm(pMod, pvMapping, uHandle); } /** * Call the thread attach or detach function of a mapped module (if any). * * Any per-thread TLS initialization/termination will have to be done at this time too. * * @returns 0 on success or no attach/detach function, non-zero on attach failure or invalid pMod. * @param pMod The module. * @param pvMapping The external mapping address or RTLDRMOD_INT_MAP. * @param uHandle The module handle to use if any of the thread attach/detach functions * requires the module handle. * * @remark Detach function failure will be ignored by the module interpreter. */ int kLdrModCallThread(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle, unsigned fAttachingOrDetaching) { KLDRMOD_VALIDATE(pMod); K_VALIDATE_FLAGS(fAttachingOrDetaching, 1); return pMod->pOps->pfnCallThread(pMod, pvMapping, uHandle, fAttachingOrDetaching); } kbuild-3149/src/lib/kStuff/kLdr/kLdr-win.c0000644000175000017500000000454013252530253020235 0ustar locutuslocutus/* $Id: kLdr-win.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - The Dynamic Loader, Windows Specifics. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include "kLdrInternal.h" /** * The DLL main function. * * @returns TRUE / FALSE. * @param hDllHandle The dll handle. * @param dwReason The reason we're being called. * @param lpReserved Reserved. */ BOOL __stdcall DllMain(HANDLE hDllHandle, DWORD dwReason, LPVOID lpReserved) { switch (dwReason) { case DLL_PROCESS_ATTACH: { int rc = kldrInit(); return rc == 0; } case DLL_PROCESS_DETACH: kldrTerm(); return TRUE; case DLL_THREAD_ATTACH: { //int rc = kLdrDyldThreadAttach(); //return rc == 0; return TRUE; } case DLL_THREAD_DETACH: //kLdrDyldThreadDetach(); return TRUE; default: return FALSE; } } kbuild-3149/src/lib/kStuff/kLdr/kLdrDyldSem.c0000644000175000017500000001175713252530253020734 0ustar locutuslocutus/* $Id: kLdrDyldSem.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - The Dynamic Loader, Semaphore Helper Functions. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #if K_OS == K_OS_DARWIN # include # undef mach_task_self /* don't use the macro (if we're using bare helpers ) */ #elif K_OS == K_OS_OS2 # define INCL_BASE # define INCL_ERRORS # include #elif K_OS == K_OS_WINDOWS # include #else # error "port me" #endif /******************************************************************************* * Global Variables * *******************************************************************************/ #if K_OS == K_OS_DARWIN /** The loader sempahore. */ static semaphore_t g_Semaphore = MACH_PORT_NULL; #elif K_OS == K_OS_OS2 /** The loader sempahore. */ static HMTX g_hmtx; #elif K_OS == K_OS_WINDOWS /** The loader sempahore. */ static CRITICAL_SECTION g_CritSect; #else # error "port me" #endif /** * Initializes the loader semaphore. * * @returns 0 on success, non-zero OS status code on failure. */ int kLdrDyldSemInit(void) { #if K_OS == K_OS_DARWIN kern_return_t krc; krc = semaphore_create(mach_task_self(), &g_Semaphore, SYNC_POLICY_FIFO, 0); if (krc != KERN_SUCCESS) return krc; #elif K_OS == K_OS_OS2 APIRET rc; g_hmtx = NULLHANDLE; rc = DosCreateMutexSem(NULL, &g_hmtx, 0, FALSE); if (rc) return rc; #elif K_OS == K_OS_WINDOWS InitializeCriticalSection(&g_CritSect); #else # error "port me" #endif return 0; } /** * Terminates the loader semaphore. */ void kLdrDyldSemTerm(void) { #if K_OS == K_OS_DARWIN kern_return_t krc; semaphore_t Semaphore = g_Semaphore; g_Semaphore = MACH_PORT_NULL; krc = semaphore_destroy(mach_task_self(), Semaphore); kHlpAssert(krc == KERN_SUCCESS); (void)krc; #elif K_OS == K_OS_OS2 HMTX hmtx = g_hmtx; g_hmtx = NULLHANDLE; DosCloseMutexSem(hmtx); #elif K_OS == K_OS_WINDOWS DeleteCriticalSection(&g_CritSect); #else # error "port me" #endif } /** * Requests the loader sempahore ownership. * This can be done recursivly. * * @returns 0 on success, non-zero OS status code on failure. */ int kLdrDyldSemRequest(void) { #if K_OS == K_OS_DARWIN /* not sure about this... */ kern_return_t krc; do krc = semaphore_wait(g_Semaphore); while (krc == KERN_ABORTED); if (krc == KERN_SUCCESS) return 0; return krc; #elif K_OS == K_OS_OS2 APIRET rc = DosRequestMutexSem(g_hmtx, 5000); if (rc == ERROR_TIMEOUT || rc == ERROR_SEM_TIMEOUT || rc == ERROR_INTERRUPT) { unsigned i = 0; do { /** @todo check for deadlocks etc. */ rc = DosRequestMutexSem(g_hmtx, 1000); } while ( ( rc == ERROR_TIMEOUT || rc == ERROR_SEM_TIMEOUT || rc == ERROR_INTERRUPT) && i++ < 120); } return rc; #elif K_OS == K_OS_WINDOWS EnterCriticalSection(&g_CritSect); return 0; #else # error "port me" #endif } /** * Releases the loader semaphore ownership. * The caller is responsible for making sure it's the semaphore owner! */ void kLdrDyldSemRelease(void) { #if K_OS == K_OS_DARWIN /* not too sure about this... */ kern_return_t krc = semaphore_signal(g_Semaphore); kHlpAssert(krc == KERN_SUCCESS); (void)krc; #elif K_OS == K_OS_OS2 APIRET rc = DosReleaseMutexSem(g_hmtx); kHlpAssert(!rc); (void)rc; #elif K_OS == K_OS_WINDOWS LeaveCriticalSection(&g_CritSect); #else # error "port me" #endif } kbuild-3149/src/lib/kStuff/kLdr/kLdrModMachO.c0000644000175000017500000043712513252530253021023 0ustar locutuslocutus/* $Id: kLdrModMachO.c 102 2017-10-02 10:45:31Z bird $ */ /** @file * kLdr - The Module Interpreter for the MACH-O format. */ /* * Copyright (c) 2006-2013 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include "kLdrInternal.h" #include /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** @def KLDRMODMACHO_STRICT * Define KLDRMODMACHO_STRICT to enabled strict checks in KLDRMODMACHO. */ #define KLDRMODMACHO_STRICT 1 /** @def KLDRMODMACHO_ASSERT * Assert that an expression is true when KLDR_STRICT is defined. */ #ifdef KLDRMODMACHO_STRICT # define KLDRMODMACHO_ASSERT(expr) kHlpAssert(expr) #else # define KLDRMODMACHO_ASSERT(expr) do {} while (0) #endif /** @def KLDRMODMACHO_CHECK_RETURN * Checks that an expression is true and return if it isn't. * This is a debug aid. */ #ifdef KLDRMODMACHO_STRICT2 # define KLDRMODMACHO_CHECK_RETURN(expr, rc) kHlpAssertReturn(expr, rc) #else # define KLDRMODMACHO_CHECK_RETURN(expr, rc) do { if (!(expr)) { return (rc); } } while (0) #endif /** @def KLDRMODMACHO_CHECK_RETURN * Checks that an expression is true and return if it isn't. * This is a debug aid. */ #ifdef KLDRMODMACHO_STRICT2 # define KLDRMODMACHO_FAILED_RETURN(rc) kHlpAssertFailedReturn(rc) #else # define KLDRMODMACHO_FAILED_RETURN(rc) return (rc) #endif /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * Mach-O section details. */ typedef struct KLDRMODMACHOSECT { /** The size of the section (in bytes). */ KLDRSIZE cb; /** The link address of this section. */ KLDRADDR LinkAddress; /** The RVA of this section. */ KLDRADDR RVA; /** The file offset of this section. * This is -1 if the section doesn't have a file backing. */ KLDRFOFF offFile; /** The number of fixups. */ KU32 cFixups; /** The array of fixups. (lazy loaded) */ macho_relocation_info_t *paFixups; /** The file offset of the fixups for this section. * This is -1 if the section doesn't have any fixups. */ KLDRFOFF offFixups; /** Mach-O section flags. */ KU32 fFlags; /** kLdr segment index. */ KU32 iSegment; /** Pointer to the Mach-O section structure. */ void *pvMachoSection; } KLDRMODMACHOSECT, *PKLDRMODMACHOSECT; /** * Extra per-segment info. * * This is corresponds to a kLdr segment, not a Mach-O segment! */ typedef struct KLDRMODMACHOSEG { /** The orignal segment number (in case we had to resort it). */ KU32 iOrgSegNo; /** The number of sections in the segment. */ KU32 cSections; /** Pointer to the sections belonging to this segment. * The array resides in the big memory chunk allocated for * the module handle, so it doesn't need freeing. */ PKLDRMODMACHOSECT paSections; } KLDRMODMACHOSEG, *PKLDRMODMACHOSEG; /** * Instance data for the Mach-O MH_OBJECT module interpreter. * @todo interpret the other MH_* formats. */ typedef struct KLDRMODMACHO { /** Pointer to the module. (Follows the section table.) */ PKLDRMOD pMod; /** Pointer to the RDR file mapping of the raw file bits. NULL if not mapped. */ const void *pvBits; /** Pointer to the user mapping. */ void *pvMapping; /** The module open flags. */ KU32 fOpenFlags; /** The offset of the image. (FAT fun.) */ KLDRFOFF offImage; /** The link address. */ KLDRADDR LinkAddress; /** The size of the mapped image. */ KLDRADDR cbImage; /** Whether we're capable of loading the image. */ KBOOL fCanLoad; /** Whether we're creating a global offset table segment. * This dependes on the cputype and image type. */ KBOOL fMakeGot; /** The size of a indirect GOT jump stub entry. * This is 0 if not needed. */ KU8 cbJmpStub; /** Effective file type. If the original was a MH_OBJECT file, the * corresponding MH_DSYM needs the segment translation of a MH_OBJECT too. * The MH_DSYM normally has a separate __DWARF segment, but this is * automatically skipped during the transation. */ KU8 uEffFileType; /** Pointer to the load commands. (endian converted) */ KU8 *pbLoadCommands; /** The Mach-O header. (endian converted) * @remark The reserved field is only valid for real 64-bit headers. */ mach_header_64_t Hdr; /** The offset of the symbol table. */ KLDRFOFF offSymbols; /** The number of symbols. */ KU32 cSymbols; /** The pointer to the loaded symbol table. */ void *pvaSymbols; /** The offset of the string table. */ KLDRFOFF offStrings; /** The size of the of the string table. */ KU32 cchStrings; /** Pointer to the loaded string table. */ char *pchStrings; /** The image UUID, all zeros if not found. */ KU8 abImageUuid[16]; /** The RVA of the Global Offset Table. */ KLDRADDR GotRVA; /** The RVA of the indirect GOT jump stubs. */ KLDRADDR JmpStubsRVA; /** The number of sections. */ KU32 cSections; /** Pointer to the section array running in parallel to the Mach-O one. */ PKLDRMODMACHOSECT paSections; /** Array of segments parallel to the one in KLDRMOD. */ KLDRMODMACHOSEG aSegments[1]; } KLDRMODMACHO, *PKLDRMODMACHO; /******************************************************************************* * Internal Functions * *******************************************************************************/ #if 0 static KI32 kldrModMachONumberOfImports(PKLDRMOD pMod, const void *pvBits); #endif static int kldrModMachORelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); static int kldrModMachODoCreate(PKRDR pRdr, KLDRFOFF offImage, KU32 fOpenFlags, PKLDRMODMACHO *ppMod); static int kldrModMachOPreParseLoadCommands(KU8 *pbLoadCommands, const mach_header_32_t *pHdr, PKRDR pRdr, KLDRFOFF offImage, KU32 fOpenFlags, KU32 *pcSegments, KU32 *pcSections, KU32 *pcbStringPool, PKBOOL pfCanLoad, PKLDRADDR pLinkAddress, KU8 *puEffFileType); static int kldrModMachOParseLoadCommands(PKLDRMODMACHO pModMachO, char *pbStringPool, KU32 cbStringPool); static int kldrModMachOAdjustBaseAddress(PKLDRMODMACHO pModMachO, PKLDRADDR pBaseAddress); /*static int kldrModMachOLoadLoadCommands(PKLDRMODMACHO pModMachO);*/ static int kldrModMachOLoadObjSymTab(PKLDRMODMACHO pModMachO); static int kldrModMachOLoadFixups(PKLDRMODMACHO pModMachO, KLDRFOFF offFixups, KU32 cFixups, macho_relocation_info_t **ppaFixups); static int kldrModMachOMapVirginBits(PKLDRMODMACHO pModMachO); static int kldrModMachODoQuerySymbol32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms, const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol, KU32 cchSymbol, PKLDRADDR puValue, KU32 *pfKind); static int kldrModMachODoQuerySymbol64Bit(PKLDRMODMACHO pModMachO, const macho_nlist_64_t *paSyms, KU32 cSyms, const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol, KU32 cchSymbol, PKLDRADDR puValue, KU32 *pfKind); static int kldrModMachODoEnumSymbols32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms, const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress, KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser); static int kldrModMachODoEnumSymbols64Bit(PKLDRMODMACHO pModMachO, const macho_nlist_64_t *paSyms, KU32 cSyms, const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress, KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser); static int kldrModMachOObjDoImports(PKLDRMODMACHO pModMachO, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser); static int kldrModMachOObjDoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress); static int kldrModMachOFixupSectionGeneric32Bit(PKLDRMODMACHO pModMachO, KU8 *pbSectBits, PKLDRMODMACHOSECT pFixupSect, macho_nlist_32_t *paSyms, KU32 cSyms, KLDRADDR NewBaseAddress); static int kldrModMachOFixupSectionAMD64(PKLDRMODMACHO pModMachO, KU8 *pbSectBits, PKLDRMODMACHOSECT pFixupSect, macho_nlist_64_t *paSyms, KU32 cSyms, KLDRADDR NewBaseAddress); static int kldrModMachOMakeGOT(PKLDRMODMACHO pModMachO, void *pvBits, KLDRADDR NewBaseAddress); /*static int kldrModMachODoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress); static int kldrModMachODoImports(PKLDRMODMACHO pModMachO, void *pvMapping, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);*/ /** * Create a loader module instance interpreting the executable image found * in the specified file provider instance. * * @returns 0 on success and *ppMod pointing to a module instance. * On failure, a non-zero OS specific error code is returned. * @param pOps Pointer to the registered method table. * @param pRdr The file provider instance to use. * @param fFlags Flags, MBZ. * @param enmCpuArch The desired CPU architecture. KCPUARCH_UNKNOWN means * anything goes, but with a preference for the current * host architecture. * @param offNewHdr The offset of the new header in MZ files. -1 if not found. * @param ppMod Where to store the module instance pointer. */ static int kldrModMachOCreate(PCKLDRMODOPS pOps, PKRDR pRdr, KU32 fFlags, KCPUARCH enmCpuArch, KLDRFOFF offNewHdr, PPKLDRMOD ppMod) { PKLDRMODMACHO pModMachO; int rc; /* * Create the instance data and do a minimal header validation. */ rc = kldrModMachODoCreate(pRdr, offNewHdr == -1 ? 0 : offNewHdr, fFlags, &pModMachO); if (!rc) { /* * Match up against the requested CPU architecture. */ if ( enmCpuArch == KCPUARCH_UNKNOWN || pModMachO->pMod->enmArch == enmCpuArch) { pModMachO->pMod->pOps = pOps; pModMachO->pMod->u32Magic = KLDRMOD_MAGIC; *ppMod = pModMachO->pMod; return 0; } rc = KLDR_ERR_CPU_ARCH_MISMATCH; } if (pModMachO) { kHlpFree(pModMachO->pbLoadCommands); kHlpFree(pModMachO); } return rc; } /** * Separate function for reading creating the Mach-O module instance to * simplify cleanup on failure. */ static int kldrModMachODoCreate(PKRDR pRdr, KLDRFOFF offImage, KU32 fOpenFlags, PKLDRMODMACHO *ppModMachO) { union { mach_header_32_t Hdr32; mach_header_64_t Hdr64; } s; PKLDRMODMACHO pModMachO; PKLDRMOD pMod; KU8 *pbLoadCommands; KU32 cSegments = 0; /* (MSC maybe used uninitialized) */ KU32 cSections = 0; /* (MSC maybe used uninitialized) */ KU32 cbStringPool = 0; /* (MSC maybe used uninitialized) */ KSIZE cchFilename; KSIZE cb; KBOOL fMakeGot; KBOOL fCanLoad = K_TRUE; KLDRADDR LinkAddress = NIL_KLDRADDR; /* (MSC maybe used uninitialized) */ KU8 cbJmpStub; KU8 uEffFileType = 0; /* (MSC maybe used uninitialized) */ int rc; *ppModMachO = NULL; kHlpAssert(&s.Hdr32.magic == &s.Hdr64.magic); kHlpAssert(&s.Hdr32.flags == &s.Hdr64.flags); /* * Read the Mach-O header. */ rc = kRdrRead(pRdr, &s, sizeof(s), offImage); if (rc) return rc; if ( s.Hdr32.magic != IMAGE_MACHO32_SIGNATURE && s.Hdr32.magic != IMAGE_MACHO64_SIGNATURE ) { if ( s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE_OE || s.Hdr32.magic == IMAGE_MACHO64_SIGNATURE_OE) return KLDR_ERR_MACHO_OTHER_ENDIAN_NOT_SUPPORTED; return KLDR_ERR_UNKNOWN_FORMAT; } /* sanity checks. */ if ( s.Hdr32.sizeofcmds > kRdrSize(pRdr) - sizeof(mach_header_32_t) || s.Hdr32.sizeofcmds < sizeof(load_command_t) * s.Hdr32.ncmds || (s.Hdr32.flags & ~MH_VALID_FLAGS)) return KLDR_ERR_MACHO_BAD_HEADER; switch (s.Hdr32.cputype) { case CPU_TYPE_X86: fMakeGot = K_FALSE; cbJmpStub = 0; break; case CPU_TYPE_X86_64: fMakeGot = s.Hdr32.filetype == MH_OBJECT; cbJmpStub = fMakeGot ? 8 : 0; break; default: return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE; } if ( s.Hdr32.filetype != MH_OBJECT && s.Hdr32.filetype != MH_EXECUTE && s.Hdr32.filetype != MH_DYLIB && s.Hdr32.filetype != MH_BUNDLE && s.Hdr32.filetype != MH_DSYM && s.Hdr32.filetype != MH_KEXT_BUNDLE) return KLDR_ERR_MACHO_UNSUPPORTED_FILE_TYPE; /* * Read and pre-parse the load commands to figure out how many segments we'll be needing. */ pbLoadCommands = kHlpAlloc(s.Hdr32.sizeofcmds); if (!pbLoadCommands) return KERR_NO_MEMORY; rc = kRdrRead(pRdr, pbLoadCommands, s.Hdr32.sizeofcmds, s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE || s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE_OE ? sizeof(mach_header_32_t) + offImage : sizeof(mach_header_64_t) + offImage); if (!rc) rc = kldrModMachOPreParseLoadCommands(pbLoadCommands, &s.Hdr32, pRdr, offImage, fOpenFlags, &cSegments, &cSections, &cbStringPool, &fCanLoad, &LinkAddress, &uEffFileType); if (rc) { kHlpFree(pbLoadCommands); return rc; } cSegments += fMakeGot; /* * Calc the instance size, allocate and initialize it. */ cchFilename = kHlpStrLen(kRdrName(pRdr)); cb = K_ALIGN_Z( K_OFFSETOF(KLDRMODMACHO, aSegments[cSegments]) + sizeof(KLDRMODMACHOSECT) * cSections, 16) + K_OFFSETOF(KLDRMOD, aSegments[cSegments]) + cchFilename + 1 + cbStringPool; pModMachO = (PKLDRMODMACHO)kHlpAlloc(cb); if (!pModMachO) return KERR_NO_MEMORY; *ppModMachO = pModMachO; pModMachO->pbLoadCommands = pbLoadCommands; pModMachO->offImage = offImage; /* KLDRMOD */ pMod = (PKLDRMOD)((KU8 *)pModMachO + K_ALIGN_Z( K_OFFSETOF(KLDRMODMACHO, aSegments[cSegments]) + sizeof(KLDRMODMACHOSECT) * cSections, 16)); pMod->pvData = pModMachO; pMod->pRdr = pRdr; pMod->pOps = NULL; /* set upon success. */ pMod->cSegments = cSegments; pMod->cchFilename = (KU32)cchFilename; pMod->pszFilename = (char *)&pMod->aSegments[pMod->cSegments]; kHlpMemCopy((char *)pMod->pszFilename, kRdrName(pRdr), cchFilename + 1); pMod->pszName = kHlpGetFilename(pMod->pszFilename); pMod->cchName = (KU32)(cchFilename - (pMod->pszName - pMod->pszFilename)); pMod->fFlags = 0; switch (s.Hdr32.cputype) { case CPU_TYPE_X86: pMod->enmArch = KCPUARCH_X86_32; pMod->enmEndian = KLDRENDIAN_LITTLE; switch (s.Hdr32.cpusubtype) { case CPU_SUBTYPE_I386_ALL: pMod->enmCpu = KCPU_X86_32_BLEND; break; /*case CPU_SUBTYPE_386: ^^ pMod->enmCpu = KCPU_I386; break;*/ case CPU_SUBTYPE_486: pMod->enmCpu = KCPU_I486; break; case CPU_SUBTYPE_486SX: pMod->enmCpu = KCPU_I486SX; break; /*case CPU_SUBTYPE_586: vv */ case CPU_SUBTYPE_PENT: pMod->enmCpu = KCPU_I586; break; case CPU_SUBTYPE_PENTPRO: case CPU_SUBTYPE_PENTII_M3: case CPU_SUBTYPE_PENTII_M5: case CPU_SUBTYPE_CELERON: case CPU_SUBTYPE_CELERON_MOBILE: case CPU_SUBTYPE_PENTIUM_3: case CPU_SUBTYPE_PENTIUM_3_M: case CPU_SUBTYPE_PENTIUM_3_XEON: pMod->enmCpu = KCPU_I686; break; case CPU_SUBTYPE_PENTIUM_M: case CPU_SUBTYPE_PENTIUM_4: case CPU_SUBTYPE_PENTIUM_4_M: case CPU_SUBTYPE_XEON: case CPU_SUBTYPE_XEON_MP: pMod->enmCpu = KCPU_P4; break; break; default: /* Hack for kextutil output. */ if ( s.Hdr32.cpusubtype == 0 && s.Hdr32.filetype == MH_OBJECT) break; return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE; } break; case CPU_TYPE_X86_64: pMod->enmArch = KCPUARCH_AMD64; pMod->enmEndian = KLDRENDIAN_LITTLE; switch (s.Hdr32.cpusubtype & ~CPU_SUBTYPE_MASK) { case CPU_SUBTYPE_X86_64_ALL: pMod->enmCpu = KCPU_AMD64_BLEND; break; default: return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE; } break; default: return KLDR_ERR_MACHO_UNSUPPORTED_MACHINE; } pMod->enmFmt = KLDRFMT_MACHO; switch (s.Hdr32.filetype) { case MH_OBJECT: pMod->enmType = KLDRTYPE_OBJECT; break; case MH_EXECUTE: pMod->enmType = KLDRTYPE_EXECUTABLE_FIXED; break; case MH_DYLIB: pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE; break; case MH_BUNDLE: pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE; break; case MH_KEXT_BUNDLE:pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE; break; case MH_DSYM: pMod->enmType = KLDRTYPE_DEBUG_INFO; break; default: return KLDR_ERR_MACHO_UNSUPPORTED_FILE_TYPE; } pMod->u32Magic = 0; /* set upon success. */ /* KLDRMODMACHO */ pModMachO->pMod = pMod; pModMachO->pvBits = NULL; pModMachO->pvMapping = NULL; pModMachO->fOpenFlags = fOpenFlags; pModMachO->Hdr = s.Hdr64; if ( s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE || s.Hdr32.magic == IMAGE_MACHO32_SIGNATURE_OE) pModMachO->Hdr.reserved = 0; pModMachO->LinkAddress = LinkAddress; pModMachO->cbImage = 0; pModMachO->fCanLoad = fCanLoad; pModMachO->fMakeGot = fMakeGot; pModMachO->cbJmpStub = cbJmpStub; pModMachO->uEffFileType = uEffFileType; pModMachO->offSymbols = 0; pModMachO->cSymbols = 0; pModMachO->pvaSymbols = NULL; pModMachO->offStrings = 0; pModMachO->cchStrings = 0; pModMachO->pchStrings = NULL; kHlpMemSet(pModMachO->abImageUuid, 0, sizeof(pModMachO->abImageUuid)); pModMachO->GotRVA = NIL_KLDRADDR; pModMachO->JmpStubsRVA = NIL_KLDRADDR; pModMachO->cSections = cSections; pModMachO->paSections = (PKLDRMODMACHOSECT)&pModMachO->aSegments[pModMachO->pMod->cSegments]; /* * Setup the KLDRMOD segment array. */ rc = kldrModMachOParseLoadCommands(pModMachO, (char *)pMod->pszFilename + pMod->cchFilename + 1, cbStringPool); if (rc) return rc; /* * We're done. */ return 0; } /** * Converts, validates and preparses the load commands before we carve * out the module instance. * * The conversion that's preformed is format endian to host endian. The * preparsing has to do with segment counting, section counting and string pool * sizing. * * Segment are created in two different ways, depending on the file type. * * For object files there is only one segment command without a given segment * name. The sections inside that segment have different segment names and are * not sorted by their segname attribute. We create one segment for each * section, with the segment name being 'segname.sectname' in order to hopefully * keep the names unique. Debug sections does not get segments. * * For non-object files, one kLdr segment is created for each Mach-O segment. * Debug segments is not exposed by kLdr via the kLdr segment table, but via the * debug enumeration callback API. * * @returns 0 on success. * @returns KLDR_ERR_MACHO_* on failure. * @param pbLoadCommands The load commands to parse. * @param pHdr The header. * @param pRdr The file reader. * @param offImage The image header (FAT fun). * @param pcSegments Where to store the segment count. * @param pcSegments Where to store the section count. * @param pcbStringPool Where to store the string pool size. * @param pfCanLoad Where to store the can-load-image indicator. * @param pLinkAddress Where to store the image link address (i.e. the * lowest segment address). */ static int kldrModMachOPreParseLoadCommands(KU8 *pbLoadCommands, const mach_header_32_t *pHdr, PKRDR pRdr, KLDRFOFF offImage, KU32 fOpenFlags, KU32 *pcSegments, KU32 *pcSections, KU32 *pcbStringPool, PKBOOL pfCanLoad, PKLDRADDR pLinkAddress, KU8 *puEffFileType) { union { KU8 *pb; load_command_t *pLoadCmd; segment_command_32_t *pSeg32; segment_command_64_t *pSeg64; thread_command_t *pThread; symtab_command_t *pSymTab; uuid_command_t *pUuid; } u; const KU64 cbFile = kRdrSize(pRdr) - offImage; KU32 cSegments = 0; KU32 cSections = 0; KSIZE cbStringPool = 0; KU32 cLeft = pHdr->ncmds; KU32 cbLeft = pHdr->sizeofcmds; KU8 *pb = pbLoadCommands; int cSegmentCommands = 0; int cSymbolTabs = 0; int fConvertEndian = pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE || pHdr->magic == IMAGE_MACHO64_SIGNATURE_OE; KU8 uEffFileType = *puEffFileType = pHdr->filetype; *pcSegments = 0; *pcSections = 0; *pcbStringPool = 0; *pfCanLoad = K_TRUE; *pLinkAddress = ~(KLDRADDR)0; while (cLeft-- > 0) { u.pb = pb; /* * Convert and validate command header. */ KLDRMODMACHO_CHECK_RETURN(cbLeft >= sizeof(load_command_t), KLDR_ERR_MACHO_BAD_LOAD_COMMAND); if (fConvertEndian) { u.pLoadCmd->cmd = K_E2E_U32(u.pLoadCmd->cmd); u.pLoadCmd->cmdsize = K_E2E_U32(u.pLoadCmd->cmdsize); } KLDRMODMACHO_CHECK_RETURN(u.pLoadCmd->cmdsize <= cbLeft, KLDR_ERR_MACHO_BAD_LOAD_COMMAND); cbLeft -= u.pLoadCmd->cmdsize; pb += u.pLoadCmd->cmdsize; /* * Convert endian if needed, parse and validate the command. */ switch (u.pLoadCmd->cmd) { case LC_SEGMENT_32: { segment_command_32_t *pSrcSeg = (segment_command_32_t *)u.pLoadCmd; section_32_t *pFirstSect = (section_32_t *)(pSrcSeg + 1); section_32_t *pSect = pFirstSect; KU32 cSectionsLeft = pSrcSeg->nsects; KU64 offSect = 0; /* Convert and verify the segment. */ KLDRMODMACHO_CHECK_RETURN(u.pLoadCmd->cmdsize >= sizeof(segment_command_32_t), KLDR_ERR_MACHO_BAD_LOAD_COMMAND); KLDRMODMACHO_CHECK_RETURN( pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE || pHdr->magic == IMAGE_MACHO32_SIGNATURE, KLDR_ERR_MACHO_BIT_MIX); if (fConvertEndian) { pSrcSeg->vmaddr = K_E2E_U32(pSrcSeg->vmaddr); pSrcSeg->vmsize = K_E2E_U32(pSrcSeg->vmsize); pSrcSeg->fileoff = K_E2E_U32(pSrcSeg->fileoff); pSrcSeg->filesize = K_E2E_U32(pSrcSeg->filesize); pSrcSeg->maxprot = K_E2E_U32(pSrcSeg->maxprot); pSrcSeg->initprot = K_E2E_U32(pSrcSeg->initprot); pSrcSeg->nsects = K_E2E_U32(pSrcSeg->nsects); pSrcSeg->flags = K_E2E_U32(pSrcSeg->flags); } /* Validation code shared with the 64-bit variant. */ #define VALIDATE_AND_ADD_SEGMENT(a_cBits) \ do { \ KBOOL fSkipSeg = !kHlpStrComp(pSrcSeg->segname, "__DWARF") /* Note: Not for non-object files. */ \ || ( !kHlpStrComp(pSrcSeg->segname, "__CTF") /* Their CTF tool did/does weird things, */ \ && pSrcSeg->vmsize == 0) /* overlapping vmaddr and zero vmsize. */ \ || (cSectionsLeft > 0 && (pFirstSect->flags & S_ATTR_DEBUG)); \ \ /* MH_DSYM files for MH_OBJECT files must have MH_OBJECT segment translation. */ \ if ( uEffFileType == MH_DSYM \ && cSegmentCommands == 0 \ && pSrcSeg->segname[0] == '\0') \ *puEffFileType = uEffFileType = MH_OBJECT; \ \ KLDRMODMACHO_CHECK_RETURN( pSrcSeg->filesize == 0 \ || ( pSrcSeg->fileoff <= cbFile \ && (KU64)pSrcSeg->fileoff + pSrcSeg->filesize <= cbFile), \ KLDR_ERR_MACHO_BAD_LOAD_COMMAND); \ KLDRMODMACHO_CHECK_RETURN( pSrcSeg->filesize <= pSrcSeg->vmsize \ || (fSkipSeg && !kHlpStrComp(pSrcSeg->segname, "__CTF") /* see above */), \ KLDR_ERR_MACHO_BAD_LOAD_COMMAND); \ KLDRMODMACHO_CHECK_RETURN(!(~pSrcSeg->maxprot & pSrcSeg->initprot), \ KLDR_ERR_MACHO_BAD_LOAD_COMMAND); \ KLDRMODMACHO_CHECK_RETURN(!(pSrcSeg->flags & ~(SG_HIGHVM | SG_FVMLIB | SG_NORELOC | SG_PROTECTED_VERSION_1)), \ KLDR_ERR_MACHO_BAD_LOAD_COMMAND); \ KLDRMODMACHO_CHECK_RETURN( pSrcSeg->nsects * sizeof(section_##a_cBits##_t) \ <= u.pLoadCmd->cmdsize - sizeof(segment_command_##a_cBits##_t), \ KLDR_ERR_MACHO_BAD_LOAD_COMMAND); \ KLDRMODMACHO_CHECK_RETURN( uEffFileType != MH_OBJECT \ || cSegmentCommands == 0 \ || ( cSegmentCommands == 1 \ && uEffFileType == MH_OBJECT \ && pHdr->filetype == MH_DSYM \ && fSkipSeg), \ KLDR_ERR_MACHO_BAD_OBJECT_FILE); \ cSegmentCommands++; \ \ /* Add the segment, if not object file. */ \ if (!fSkipSeg && uEffFileType != MH_OBJECT) \ { \ cbStringPool += kHlpStrNLen(&pSrcSeg->segname[0], sizeof(pSrcSeg->segname)) + 1; \ cSegments++; \ if (cSegments == 1) /* The link address is set by the first segment. */ \ *pLinkAddress = pSrcSeg->vmaddr; \ } \ } while (0) VALIDATE_AND_ADD_SEGMENT(32); /* * Convert, validate and parse the sections. */ cSectionsLeft = pSrcSeg->nsects; pFirstSect = pSect = (section_32_t *)(pSrcSeg + 1); while (cSectionsLeft-- > 0) { if (fConvertEndian) { pSect->addr = K_E2E_U32(pSect->addr); pSect->size = K_E2E_U32(pSect->size); pSect->offset = K_E2E_U32(pSect->offset); pSect->align = K_E2E_U32(pSect->align); pSect->reloff = K_E2E_U32(pSect->reloff); pSect->nreloc = K_E2E_U32(pSect->nreloc); pSect->flags = K_E2E_U32(pSect->flags); pSect->reserved1 = K_E2E_U32(pSect->reserved1); pSect->reserved2 = K_E2E_U32(pSect->reserved2); } /* Validation code shared with the 64-bit variant. */ #define VALIDATE_AND_ADD_SECTION(a_cBits) \ do { \ int fFileBits; \ \ /* validate */ \ if (uEffFileType != MH_OBJECT) \ KLDRMODMACHO_CHECK_RETURN(!kHlpStrComp(pSect->segname, pSrcSeg->segname),\ KLDR_ERR_MACHO_BAD_SECTION); \ \ switch (pSect->flags & SECTION_TYPE) \ { \ case S_ZEROFILL: \ KLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, KLDR_ERR_MACHO_BAD_SECTION); \ KLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, KLDR_ERR_MACHO_BAD_SECTION); \ fFileBits = 0; \ break; \ case S_REGULAR: \ case S_CSTRING_LITERALS: \ case S_COALESCED: \ case S_4BYTE_LITERALS: \ case S_8BYTE_LITERALS: \ case S_16BYTE_LITERALS: \ KLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, KLDR_ERR_MACHO_BAD_SECTION); \ KLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, KLDR_ERR_MACHO_BAD_SECTION); \ fFileBits = 1; \ break; \ \ case S_SYMBOL_STUBS: \ KLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, KLDR_ERR_MACHO_BAD_SECTION); \ /* reserved2 == stub size. 0 has been seen (corecrypto.kext) */ \ KLDRMODMACHO_CHECK_RETURN(pSect->reserved2 < 64, KLDR_ERR_MACHO_BAD_SECTION); \ fFileBits = 1; \ break; \ \ case S_NON_LAZY_SYMBOL_POINTERS: \ case S_LAZY_SYMBOL_POINTERS: \ case S_LAZY_DYLIB_SYMBOL_POINTERS: \ /* (reserved 1 = is indirect symbol table index) */ \ KLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, KLDR_ERR_MACHO_BAD_SECTION); \ *pfCanLoad = K_FALSE; \ fFileBits = -1; /* __DATA.__got in the 64-bit mach_kernel has bits, any things without bits? */ \ break; \ \ case S_MOD_INIT_FUNC_POINTERS: \ /** @todo this requires a query API or flag... (e.g. C++ constructors) */ \ KLDRMODMACHO_CHECK_RETURN(fOpenFlags & KLDRMOD_OPEN_FLAGS_FOR_INFO, \ KLDR_ERR_MACHO_UNSUPPORTED_INIT_SECTION); \ /* Falls through. */ \ case S_MOD_TERM_FUNC_POINTERS: \ /** @todo this requires a query API or flag... (e.g. C++ destructors) */ \ KLDRMODMACHO_CHECK_RETURN(fOpenFlags & KLDRMOD_OPEN_FLAGS_FOR_INFO, \ KLDR_ERR_MACHO_UNSUPPORTED_TERM_SECTION); \ KLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, KLDR_ERR_MACHO_BAD_SECTION); \ KLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, KLDR_ERR_MACHO_BAD_SECTION); \ fFileBits = 1; \ break; /* ignored */ \ \ case S_LITERAL_POINTERS: \ case S_DTRACE_DOF: \ KLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, KLDR_ERR_MACHO_BAD_SECTION); \ KLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, KLDR_ERR_MACHO_BAD_SECTION); \ fFileBits = 1; \ break; \ \ case S_INTERPOSING: \ case S_GB_ZEROFILL: \ KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_UNSUPPORTED_SECTION); \ \ default: \ KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_UNKNOWN_SECTION); \ } \ KLDRMODMACHO_CHECK_RETURN(!(pSect->flags & ~( S_ATTR_PURE_INSTRUCTIONS | S_ATTR_NO_TOC | S_ATTR_STRIP_STATIC_SYMS \ | S_ATTR_NO_DEAD_STRIP | S_ATTR_LIVE_SUPPORT | S_ATTR_SELF_MODIFYING_CODE \ | S_ATTR_DEBUG | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_EXT_RELOC \ | S_ATTR_LOC_RELOC | SECTION_TYPE)), \ KLDR_ERR_MACHO_BAD_SECTION); \ KLDRMODMACHO_CHECK_RETURN((pSect->flags & S_ATTR_DEBUG) == (pFirstSect->flags & S_ATTR_DEBUG), \ KLDR_ERR_MACHO_MIXED_DEBUG_SECTION_FLAGS); \ \ KLDRMODMACHO_CHECK_RETURN(pSect->addr - pSrcSeg->vmaddr <= pSrcSeg->vmsize, \ KLDR_ERR_MACHO_BAD_SECTION); \ KLDRMODMACHO_CHECK_RETURN( pSect->addr - pSrcSeg->vmaddr + pSect->size <= pSrcSeg->vmsize \ || !kHlpStrComp(pSrcSeg->segname, "__CTF") /* see above */, \ KLDR_ERR_MACHO_BAD_SECTION); \ KLDRMODMACHO_CHECK_RETURN(pSect->align < 31, \ KLDR_ERR_MACHO_BAD_SECTION); \ /* Workaround for buggy ld64 (or as, llvm, ++) that produces a misaligned __TEXT.__unwind_info. */ \ /* Seen: pSect->align = 4, pSect->addr = 0x5ebe14. Just adjust the alignment down. */ \ if ( ((K_BIT32(pSect->align) - KU32_C(1)) & pSect->addr) \ && pSect->align == 4 \ && kHlpStrComp(pSect->sectname, "__unwind_info") == 0) \ pSect->align = 2; \ KLDRMODMACHO_CHECK_RETURN(!((K_BIT32(pSect->align) - KU32_C(1)) & pSect->addr), \ KLDR_ERR_MACHO_BAD_SECTION); \ KLDRMODMACHO_CHECK_RETURN(!((K_BIT32(pSect->align) - KU32_C(1)) & pSrcSeg->vmaddr), \ KLDR_ERR_MACHO_BAD_SECTION); \ \ /* Adjust the section offset before we check file offset. */ \ offSect = (offSect + K_BIT64(pSect->align) - KU64_C(1)) & ~(K_BIT64(pSect->align) - KU64_C(1)); \ if (pSect->addr) \ { \ KLDRMODMACHO_CHECK_RETURN(offSect <= pSect->addr - pSrcSeg->vmaddr, KLDR_ERR_MACHO_BAD_SECTION); \ if (offSect < pSect->addr - pSrcSeg->vmaddr) \ offSect = pSect->addr - pSrcSeg->vmaddr; \ } \ \ if (fFileBits && pSect->offset == 0 && pSrcSeg->fileoff == 0 && pHdr->filetype == MH_DSYM) \ fFileBits = 0; \ if (fFileBits) \ { \ if (uEffFileType != MH_OBJECT) \ { \ KLDRMODMACHO_CHECK_RETURN(pSect->offset == pSrcSeg->fileoff + offSect, \ KLDR_ERR_MACHO_NON_CONT_SEG_BITS); \ KLDRMODMACHO_CHECK_RETURN(pSect->offset - pSrcSeg->fileoff <= pSrcSeg->filesize, \ KLDR_ERR_MACHO_BAD_SECTION); \ } \ KLDRMODMACHO_CHECK_RETURN(pSect->offset <= cbFile, \ KLDR_ERR_MACHO_BAD_SECTION); \ KLDRMODMACHO_CHECK_RETURN((KU64)pSect->offset + pSect->size <= cbFile, \ KLDR_ERR_MACHO_BAD_SECTION); \ } \ else \ KLDRMODMACHO_CHECK_RETURN(pSect->offset == 0, KLDR_ERR_MACHO_BAD_SECTION); \ \ if (!pSect->nreloc) \ KLDRMODMACHO_CHECK_RETURN(!pSect->reloff, \ KLDR_ERR_MACHO_BAD_SECTION); \ else \ { \ KLDRMODMACHO_CHECK_RETURN(pSect->reloff <= cbFile, \ KLDR_ERR_MACHO_BAD_SECTION); \ KLDRMODMACHO_CHECK_RETURN( (KU64)pSect->reloff \ + (KLDRFOFF)pSect->nreloc * sizeof(macho_relocation_info_t) \ <= cbFile, \ KLDR_ERR_MACHO_BAD_SECTION); \ } \ \ /* Validate against file type (pointless?) and count the section, for object files add segment. */ \ switch (uEffFileType) \ { \ case MH_OBJECT: \ if ( !(pSect->flags & S_ATTR_DEBUG) \ && kHlpStrComp(pSect->segname, "__DWARF")) \ { \ cbStringPool += kHlpStrNLen(&pSect->segname[0], sizeof(pSect->segname)) + 1; \ cbStringPool += kHlpStrNLen(&pSect->sectname[0], sizeof(pSect->sectname)) + 1; \ cSegments++; \ if (cSegments == 1) /* The link address is set by the first segment. */ \ *pLinkAddress = pSect->addr; \ } \ /* Falls through. */ \ case MH_EXECUTE: \ case MH_DYLIB: \ case MH_BUNDLE: \ case MH_DSYM: \ case MH_KEXT_BUNDLE: \ cSections++; \ break; \ default: \ KLDRMODMACHO_FAILED_RETURN(KERR_INVALID_PARAMETER); \ } \ \ /* Advance the section offset, since we're also aligning it. */ \ offSect += pSect->size; \ } while (0) /* VALIDATE_AND_ADD_SECTION */ VALIDATE_AND_ADD_SECTION(32); /* next */ pSect++; } break; } case LC_SEGMENT_64: { segment_command_64_t *pSrcSeg = (segment_command_64_t *)u.pLoadCmd; section_64_t *pFirstSect = (section_64_t *)(pSrcSeg + 1); section_64_t *pSect = pFirstSect; KU32 cSectionsLeft = pSrcSeg->nsects; KU64 offSect = 0; /* Convert and verify the segment. */ KLDRMODMACHO_CHECK_RETURN(u.pLoadCmd->cmdsize >= sizeof(segment_command_64_t), KLDR_ERR_MACHO_BAD_LOAD_COMMAND); KLDRMODMACHO_CHECK_RETURN( pHdr->magic == IMAGE_MACHO64_SIGNATURE_OE || pHdr->magic == IMAGE_MACHO64_SIGNATURE, KLDR_ERR_MACHO_BIT_MIX); if (fConvertEndian) { pSrcSeg->vmaddr = K_E2E_U64(pSrcSeg->vmaddr); pSrcSeg->vmsize = K_E2E_U64(pSrcSeg->vmsize); pSrcSeg->fileoff = K_E2E_U64(pSrcSeg->fileoff); pSrcSeg->filesize = K_E2E_U64(pSrcSeg->filesize); pSrcSeg->maxprot = K_E2E_U32(pSrcSeg->maxprot); pSrcSeg->initprot = K_E2E_U32(pSrcSeg->initprot); pSrcSeg->nsects = K_E2E_U32(pSrcSeg->nsects); pSrcSeg->flags = K_E2E_U32(pSrcSeg->flags); } VALIDATE_AND_ADD_SEGMENT(64); /* * Convert, validate and parse the sections. */ while (cSectionsLeft-- > 0) { if (fConvertEndian) { pSect->addr = K_E2E_U64(pSect->addr); pSect->size = K_E2E_U64(pSect->size); pSect->offset = K_E2E_U32(pSect->offset); pSect->align = K_E2E_U32(pSect->align); pSect->reloff = K_E2E_U32(pSect->reloff); pSect->nreloc = K_E2E_U32(pSect->nreloc); pSect->flags = K_E2E_U32(pSect->flags); pSect->reserved1 = K_E2E_U32(pSect->reserved1); pSect->reserved2 = K_E2E_U32(pSect->reserved2); } VALIDATE_AND_ADD_SECTION(64); /* next */ pSect++; } break; } /* LC_SEGMENT_64 */ case LC_SYMTAB: { KSIZE cbSym; if (fConvertEndian) { u.pSymTab->symoff = K_E2E_U32(u.pSymTab->symoff); u.pSymTab->nsyms = K_E2E_U32(u.pSymTab->nsyms); u.pSymTab->stroff = K_E2E_U32(u.pSymTab->stroff); u.pSymTab->strsize = K_E2E_U32(u.pSymTab->strsize); } /* verify */ cbSym = pHdr->magic == IMAGE_MACHO32_SIGNATURE || pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE ? sizeof(macho_nlist_32_t) : sizeof(macho_nlist_64_t); if ( u.pSymTab->symoff >= cbFile || (KU64)u.pSymTab->symoff + u.pSymTab->nsyms * cbSym > cbFile) KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND); if ( u.pSymTab->stroff >= cbFile || (KU64)u.pSymTab->stroff + u.pSymTab->strsize > cbFile) KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND); /* only one string in objects, please. */ cSymbolTabs++; if ( uEffFileType == MH_OBJECT && cSymbolTabs != 1) KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_OBJECT_FILE); break; } case LC_DYSYMTAB: /** @todo deal with this! */ break; case LC_THREAD: case LC_UNIXTHREAD: { KU32 *pu32 = (KU32 *)(u.pb + sizeof(load_command_t)); KU32 cItemsLeft = (u.pThread->cmdsize - sizeof(load_command_t)) / sizeof(KU32); while (cItemsLeft) { /* convert & verify header items ([0] == flavor, [1] == KU32 count). */ if (cItemsLeft < 2) KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND); if (fConvertEndian) { pu32[0] = K_E2E_U32(pu32[0]); pu32[1] = K_E2E_U32(pu32[1]); } if (pu32[1] + 2 > cItemsLeft) KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND); /* convert & verify according to flavor. */ switch (pu32[0]) { /** @todo */ default: break; } /* next */ cItemsLeft -= pu32[1] + 2; pu32 += pu32[1] + 2; } break; } case LC_UUID: if (u.pUuid->cmdsize != sizeof(uuid_command_t)) KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND); /** @todo Check anything here need converting? */ break; case LC_CODE_SIGNATURE: if (u.pUuid->cmdsize != sizeof(linkedit_data_command_t)) KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND); break; case LC_VERSION_MIN_MACOSX: case LC_VERSION_MIN_IPHONEOS: if (u.pUuid->cmdsize != sizeof(version_min_command_t)) KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND); break; case LC_SOURCE_VERSION: /* Harmless. It just gives a clue regarding the source code revision/version. */ case LC_DATA_IN_CODE: /* Ignore */ case LC_DYLIB_CODE_SIGN_DRS:/* Ignore */ /** @todo valid command size. */ break; case LC_FUNCTION_STARTS: /** @todo dylib++ */ /* Ignore for now. */ break; case LC_ID_DYLIB: /** @todo dylib */ case LC_LOAD_DYLIB: /** @todo dylib */ case LC_LOAD_DYLINKER: /** @todo dylib */ case LC_TWOLEVEL_HINTS: /** @todo dylib */ case LC_LOAD_WEAK_DYLIB: /** @todo dylib */ case LC_ID_DYLINKER: /** @todo dylib */ case LC_RPATH: /** @todo dylib */ case LC_SEGMENT_SPLIT_INFO: /** @todo dylib++ */ case LC_REEXPORT_DYLIB: /** @todo dylib */ case LC_DYLD_INFO: /** @todo dylib */ case LC_DYLD_INFO_ONLY: /** @todo dylib */ case LC_LOAD_UPWARD_DYLIB: /** @todo dylib */ case LC_DYLD_ENVIRONMENT: /** @todo dylib */ case LC_MAIN: /** @todo parse this and find and entry point or smth. */ /** @todo valid command size. */ if (!(fOpenFlags & KLDRMOD_OPEN_FLAGS_FOR_INFO)) KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_UNSUPPORTED_LOAD_COMMAND); *pfCanLoad = K_FALSE; break; case LC_LOADFVMLIB: case LC_IDFVMLIB: case LC_IDENT: case LC_FVMFILE: case LC_PREPAGE: case LC_PREBOUND_DYLIB: case LC_ROUTINES: case LC_ROUTINES_64: case LC_SUB_FRAMEWORK: case LC_SUB_UMBRELLA: case LC_SUB_CLIENT: case LC_SUB_LIBRARY: case LC_PREBIND_CKSUM: case LC_SYMSEG: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_UNSUPPORTED_LOAD_COMMAND); default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_UNKNOWN_LOAD_COMMAND); } } /* be strict. */ if (cbLeft) KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_LOAD_COMMAND); switch (uEffFileType) { case MH_OBJECT: case MH_EXECUTE: case MH_DYLIB: case MH_BUNDLE: case MH_DSYM: case MH_KEXT_BUNDLE: if (!cSegments) KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_OBJECT_FILE); break; } *pcSegments = cSegments; *pcSections = cSections; *pcbStringPool = (KU32)cbStringPool; return 0; } /** * Parses the load commands after we've carved out the module instance. * * This fills in the segment table and perhaps some other properties. * * @returns 0 on success. * @returns KLDR_ERR_MACHO_* on failure. * @param pModMachO The module. * @param pbStringPool The string pool * @param cbStringPool The size of the string pool. */ static int kldrModMachOParseLoadCommands(PKLDRMODMACHO pModMachO, char *pbStringPool, KU32 cbStringPool) { union { const KU8 *pb; const load_command_t *pLoadCmd; const segment_command_32_t *pSeg32; const segment_command_64_t *pSeg64; const symtab_command_t *pSymTab; const uuid_command_t *pUuid; } u; KU32 cLeft = pModMachO->Hdr.ncmds; KU32 cbLeft = pModMachO->Hdr.sizeofcmds; const KU8 *pb = pModMachO->pbLoadCommands; PKLDRSEG pDstSeg = &pModMachO->pMod->aSegments[0]; PKLDRMODMACHOSEG pSegExtra = &pModMachO->aSegments[0]; PKLDRMODMACHOSECT pSectExtra = pModMachO->paSections; const KU32 cSegments = pModMachO->pMod->cSegments; PKLDRSEG pSegItr; K_NOREF(cbStringPool); while (cLeft-- > 0) { u.pb = pb; cbLeft -= u.pLoadCmd->cmdsize; pb += u.pLoadCmd->cmdsize; /* * Convert endian if needed, parse and validate the command. */ switch (u.pLoadCmd->cmd) { case LC_SEGMENT_32: { const segment_command_32_t *pSrcSeg = (const segment_command_32_t *)u.pLoadCmd; section_32_t *pFirstSect = (section_32_t *)(pSrcSeg + 1); section_32_t *pSect = pFirstSect; KU32 cSectionsLeft = pSrcSeg->nsects; /* Adds a segment, used by the macro below and thus shared with the 64-bit segment variant. */ #define NEW_SEGMENT(a_cBits, a_achName1, a_fObjFile, a_achName2, a_SegAddr, a_cbSeg, a_fFileBits, a_offFile, a_cbFile) \ do { \ pDstSeg->pvUser = NULL; \ pDstSeg->pchName = pbStringPool; \ pDstSeg->cchName = (KU32)kHlpStrNLen(a_achName1, sizeof(a_achName1)); \ kHlpMemCopy(pbStringPool, a_achName1, pDstSeg->cchName); \ pbStringPool += pDstSeg->cchName; \ if (a_fObjFile) \ { /* MH_OBJECT: Add '.sectname' - sections aren't sorted by segments. */ \ KSIZE cchName2 = kHlpStrNLen(a_achName2, sizeof(a_achName2)); \ *pbStringPool++ = '.'; \ kHlpMemCopy(pbStringPool, a_achName2, cchName2); \ pbStringPool += cchName2; \ pDstSeg->cchName += (KU32)cchName2; \ } \ *pbStringPool++ = '\0'; \ pDstSeg->SelFlat = 0; \ pDstSeg->Sel16bit = 0; \ pDstSeg->fFlags = 0; \ pDstSeg->enmProt = KPROT_EXECUTE_WRITECOPY; /** @todo fixme! */ \ pDstSeg->cb = (a_cbSeg); \ pDstSeg->Alignment = 1; /* updated while parsing sections. */ \ pDstSeg->LinkAddress = (a_SegAddr); \ if (a_fFileBits) \ { \ pDstSeg->offFile = (KLDRFOFF)((a_offFile) + pModMachO->offImage); \ pDstSeg->cbFile = (KLDRFOFF)(a_cbFile); \ } \ else \ { \ pDstSeg->offFile = -1; \ pDstSeg->cbFile = -1; \ } \ pDstSeg->RVA = (a_SegAddr) - pModMachO->LinkAddress; \ pDstSeg->cbMapped = 0; \ pDstSeg->MapAddress = 0; \ \ pSegExtra->iOrgSegNo = (KU32)(pSegExtra - &pModMachO->aSegments[0]); \ pSegExtra->cSections = 0; \ pSegExtra->paSections = pSectExtra; \ } while (0) /* Closes the new segment - part of NEW_SEGMENT. */ #define CLOSE_SEGMENT() \ do { \ pSegExtra->cSections = (KU32)(pSectExtra - pSegExtra->paSections); \ pSegExtra++; \ pDstSeg++; \ } while (0) /* Shared with the 64-bit variant. */ #define ADD_SEGMENT_AND_ITS_SECTIONS(a_cBits) \ do { \ KBOOL fAddSegOuter = K_FALSE; \ \ /* \ * Check that the segment name is unique. We couldn't do that \ * in the preparsing stage. \ */ \ if (pModMachO->uEffFileType != MH_OBJECT) \ for (pSegItr = &pModMachO->pMod->aSegments[0]; pSegItr != pDstSeg; pSegItr++) \ if (!kHlpStrNComp(pSegItr->pchName, pSrcSeg->segname, sizeof(pSrcSeg->segname))) \ KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_DUPLICATE_SEGMENT_NAME); \ \ /* \ * Create a new segment, unless we're supposed to skip this one. \ */ \ if ( pModMachO->uEffFileType != MH_OBJECT \ && (cSectionsLeft == 0 || !(pFirstSect->flags & S_ATTR_DEBUG)) \ && kHlpStrComp(pSrcSeg->segname, "__DWARF") \ && kHlpStrComp(pSrcSeg->segname, "__CTF") ) \ { \ NEW_SEGMENT(a_cBits, pSrcSeg->segname, K_FALSE /*a_fObjFile*/, 0 /*a_achName2*/, \ pSrcSeg->vmaddr, pSrcSeg->vmsize, \ pSrcSeg->filesize != 0, pSrcSeg->fileoff, pSrcSeg->filesize); \ fAddSegOuter = K_TRUE; \ } \ \ /* \ * Convert and parse the sections. \ */ \ while (cSectionsLeft-- > 0) \ { \ /* New segment if object file. */ \ KBOOL fAddSegInner = K_FALSE; \ if ( pModMachO->uEffFileType == MH_OBJECT \ && !(pSect->flags & S_ATTR_DEBUG) \ && kHlpStrComp(pSrcSeg->segname, "__DWARF") \ && kHlpStrComp(pSrcSeg->segname, "__CTF") ) \ { \ kHlpAssert(!fAddSegOuter); \ NEW_SEGMENT(a_cBits, pSect->segname, K_TRUE /*a_fObjFile*/, pSect->sectname, \ pSect->addr, pSect->size, \ pSect->offset != 0, pSect->offset, pSect->size); \ fAddSegInner = K_TRUE; \ } \ \ /* Section data extract. */ \ pSectExtra->cb = pSect->size; \ pSectExtra->RVA = pSect->addr - pDstSeg->LinkAddress; \ pSectExtra->LinkAddress = pSect->addr; \ if (pSect->offset) \ pSectExtra->offFile = pSect->offset + pModMachO->offImage; \ else \ pSectExtra->offFile = -1; \ pSectExtra->cFixups = pSect->nreloc; \ pSectExtra->paFixups = NULL; \ if (pSect->nreloc) \ pSectExtra->offFixups = pSect->reloff + pModMachO->offImage; \ else \ pSectExtra->offFixups = -1; \ pSectExtra->fFlags = pSect->flags; \ pSectExtra->iSegment = (KU32)(pSegExtra - &pModMachO->aSegments[0]); \ pSectExtra->pvMachoSection = pSect; \ \ /* Update the segment alignment, if we're not skipping it. */ \ if ( (fAddSegOuter || fAddSegInner) \ && pDstSeg->Alignment < ((KLDRADDR)1 << pSect->align)) \ pDstSeg->Alignment = (KLDRADDR)1 << pSect->align; \ \ /* Next section, and if object file next segment. */ \ pSectExtra++; \ pSect++; \ if (fAddSegInner) \ CLOSE_SEGMENT(); \ } \ \ /* Close the segment and advance. */ \ if (fAddSegOuter) \ CLOSE_SEGMENT(); \ } while (0) /* ADD_SEGMENT_AND_ITS_SECTIONS */ ADD_SEGMENT_AND_ITS_SECTIONS(32); break; } case LC_SEGMENT_64: { const segment_command_64_t *pSrcSeg = (const segment_command_64_t *)u.pLoadCmd; section_64_t *pFirstSect = (section_64_t *)(pSrcSeg + 1); section_64_t *pSect = pFirstSect; KU32 cSectionsLeft = pSrcSeg->nsects; ADD_SEGMENT_AND_ITS_SECTIONS(64); break; } case LC_SYMTAB: switch (pModMachO->uEffFileType) { case MH_OBJECT: case MH_EXECUTE: case MH_DYLIB: /** @todo ??? */ case MH_BUNDLE: /** @todo ??? */ case MH_DSYM: case MH_KEXT_BUNDLE: pModMachO->offSymbols = u.pSymTab->symoff + pModMachO->offImage; pModMachO->cSymbols = u.pSymTab->nsyms; pModMachO->offStrings = u.pSymTab->stroff + pModMachO->offImage; pModMachO->cchStrings = u.pSymTab->strsize; break; } break; case LC_UUID: kHlpMemCopy(pModMachO->abImageUuid, u.pUuid->uuid, sizeof(pModMachO->abImageUuid)); break; default: break; } /* command switch */ } /* while more commands */ kHlpAssert(pDstSeg == &pModMachO->pMod->aSegments[cSegments - pModMachO->fMakeGot]); /* * Adjust mapping addresses calculating the image size. */ { KBOOL fLoadLinkEdit = K_FALSE; PKLDRMODMACHOSECT pSectExtraItr; KLDRADDR uNextRVA = 0; KLDRADDR cb; KU32 cSegmentsToAdjust = cSegments - pModMachO->fMakeGot; KU32 c; for (;;) { /* Check if there is __DWARF segment at the end and make sure it's left out of the RVA negotiations and image loading. */ if ( cSegmentsToAdjust > 0 && !kHlpStrComp(pModMachO->pMod->aSegments[cSegmentsToAdjust - 1].pchName, "__DWARF")) { cSegmentsToAdjust--; pModMachO->pMod->aSegments[cSegmentsToAdjust].RVA = NIL_KLDRADDR; pModMachO->pMod->aSegments[cSegmentsToAdjust].cbMapped = 0; continue; } /* If we're skipping the __LINKEDIT segment, check for it and adjust the number of segments we'll be messing with here. ASSUMES it's last (by now anyway). */ if ( !fLoadLinkEdit && cSegmentsToAdjust > 0 && !kHlpStrComp(pModMachO->pMod->aSegments[cSegmentsToAdjust - 1].pchName, "__LINKEDIT")) { cSegmentsToAdjust--; pModMachO->pMod->aSegments[cSegmentsToAdjust].RVA = NIL_KLDRADDR; pModMachO->pMod->aSegments[cSegmentsToAdjust].cbMapped = 0; continue; } break; } /* Adjust RVAs. */ c = cSegmentsToAdjust; for (pDstSeg = &pModMachO->pMod->aSegments[0]; c-- > 0; pDstSeg++) { cb = pDstSeg->RVA - uNextRVA; if (cb >= 0x00100000) /* 1MB */ { pDstSeg->RVA = uNextRVA; pModMachO->pMod->fFlags |= KLDRMOD_FLAGS_NON_CONTIGUOUS_LINK_ADDRS; } uNextRVA = pDstSeg->RVA + KLDR_ALIGN_ADDR(pDstSeg->cb, pDstSeg->Alignment); } /* Calculate the cbMapping members. */ c = cSegmentsToAdjust; for (pDstSeg = &pModMachO->pMod->aSegments[0]; c-- > 1; pDstSeg++) { cb = pDstSeg[1].RVA - pDstSeg->RVA; pDstSeg->cbMapped = (KSIZE)cb == cb ? (KSIZE)cb : KSIZE_MAX; } cb = KLDR_ALIGN_ADDR(pDstSeg->cb, pDstSeg->Alignment); pDstSeg->cbMapped = (KSIZE)cb == cb ? (KSIZE)cb : KSIZE_MAX; /* Set the image size. */ pModMachO->cbImage = pDstSeg->RVA + cb; /* Fixup the section RVAs (internal). */ c = cSegmentsToAdjust; uNextRVA = pModMachO->cbImage; pDstSeg = &pModMachO->pMod->aSegments[0]; for (pSectExtraItr = pModMachO->paSections; pSectExtraItr != pSectExtra; pSectExtraItr++) { if (pSectExtraItr->iSegment < c) pSectExtraItr->RVA += pDstSeg[pSectExtraItr->iSegment].RVA; else { pSectExtraItr->RVA = uNextRVA; uNextRVA += KLDR_ALIGN_ADDR(pSectExtraItr->cb, 64); } } } /* * Make the GOT segment if necessary. */ if (pModMachO->fMakeGot) { KU32 cbPtr = ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE) ? sizeof(KU32) : sizeof(KU64); KU32 cbGot = pModMachO->cSymbols * cbPtr; KU32 cbJmpStubs; pModMachO->GotRVA = pModMachO->cbImage; if (pModMachO->cbJmpStub) { cbGot = K_ALIGN_Z(cbGot, 64); pModMachO->JmpStubsRVA = pModMachO->GotRVA + cbGot; cbJmpStubs = pModMachO->cbJmpStub * pModMachO->cSymbols; } else { pModMachO->JmpStubsRVA = NIL_KLDRADDR; cbJmpStubs = 0; } pDstSeg = &pModMachO->pMod->aSegments[cSegments - 1]; pDstSeg->pvUser = NULL; pDstSeg->pchName = "GOT"; pDstSeg->cchName = 3; pDstSeg->SelFlat = 0; pDstSeg->Sel16bit = 0; pDstSeg->fFlags = 0; pDstSeg->enmProt = KPROT_READONLY; pDstSeg->cb = cbGot + cbJmpStubs; pDstSeg->Alignment = 64; pDstSeg->LinkAddress = pModMachO->LinkAddress + pModMachO->GotRVA; pDstSeg->offFile = -1; pDstSeg->cbFile = -1; pDstSeg->RVA = pModMachO->GotRVA; pDstSeg->cbMapped = (KSIZE)KLDR_ALIGN_ADDR(cbGot + cbJmpStubs, pDstSeg->Alignment); pDstSeg->MapAddress = 0; pSegExtra->iOrgSegNo = KU32_MAX; pSegExtra->cSections = 0; pSegExtra->paSections = NULL; pModMachO->cbImage += pDstSeg->cbMapped; } return 0; } /** @copydoc KLDRMODOPS::pfnDestroy */ static int kldrModMachODestroy(PKLDRMOD pMod) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; int rc = 0; KU32 i, j; KLDRMODMACHO_ASSERT(!pModMachO->pvMapping); i = pMod->cSegments; while (i-- > 0) { j = pModMachO->aSegments[i].cSections; while (j-- > 0) { kHlpFree(pModMachO->aSegments[i].paSections[j].paFixups); pModMachO->aSegments[i].paSections[j].paFixups = NULL; } } if (pMod->pRdr) { rc = kRdrClose(pMod->pRdr); pMod->pRdr = NULL; } pMod->u32Magic = 0; pMod->pOps = NULL; kHlpFree(pModMachO->pbLoadCommands); pModMachO->pbLoadCommands = NULL; kHlpFree(pModMachO->pchStrings); pModMachO->pchStrings = NULL; kHlpFree(pModMachO->pvaSymbols); pModMachO->pvaSymbols = NULL; kHlpFree(pModMachO); return rc; } /** * Gets the right base address. * * @returns 0 on success. * @returns A non-zero status code if the BaseAddress isn't right. * @param pModMachO The interpreter module instance * @param pBaseAddress The base address, IN & OUT. Optional. */ static int kldrModMachOAdjustBaseAddress(PKLDRMODMACHO pModMachO, PKLDRADDR pBaseAddress) { /* * Adjust the base address. */ if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP) *pBaseAddress = pModMachO->pMod->aSegments[0].MapAddress; else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK) *pBaseAddress = pModMachO->LinkAddress; return 0; } /** * Resolves a linker generated symbol. * * The Apple linker generates symbols indicating the start and end of sections * and segments. This function checks for these and returns the right value. * * @returns 0 or KLDR_ERR_SYMBOL_NOT_FOUND. * @param pModMachO The interpreter module instance. * @param pMod The generic module instance. * @param pchSymbol The symbol. * @param cchSymbol The length of the symbol. * @param BaseAddress The base address to apply when calculating the * value. * @param puValue Where to return the symbol value. */ static int kldrModMachOQueryLinkerSymbol(PKLDRMODMACHO pModMachO, PKLDRMOD pMod, const char *pchSymbol, KSIZE cchSymbol, KLDRADDR BaseAddress, PKLDRADDR puValue) { /* * Match possible name prefixes. */ static const struct { const char *pszPrefix; KU8 cchPrefix; KBOOL fSection; KBOOL fStart; } s_aPrefixes[] = { { "section$start$", (KU8)sizeof("section$start$") - 1, K_TRUE, K_TRUE }, { "section$end$", (KU8)sizeof("section$end$") - 1, K_TRUE, K_FALSE}, { "segment$start$", (KU8)sizeof("segment$start$") - 1, K_FALSE, K_TRUE }, { "segment$end$", (KU8)sizeof("segment$end$") - 1, K_FALSE, K_FALSE}, }; KSIZE cchSectName = 0; const char *pchSectName = ""; KSIZE cchSegName = 0; const char *pchSegName = NULL; KU32 iPrefix = K_ELEMENTS(s_aPrefixes) - 1; KU32 iSeg; KLDRADDR uValue; for (;;) { KU8 const cchPrefix = s_aPrefixes[iPrefix].cchPrefix; if ( cchSymbol > cchPrefix && kHlpStrNComp(pchSymbol, s_aPrefixes[iPrefix].pszPrefix, cchPrefix) == 0) { pchSegName = pchSymbol + cchPrefix; cchSegName = cchSymbol - cchPrefix; break; } /* next */ if (!iPrefix) return KLDR_ERR_SYMBOL_NOT_FOUND; iPrefix--; } /* * Split the remainder into segment and section name, if necessary. */ if (s_aPrefixes[iPrefix].fSection) { pchSectName = kHlpMemChr(pchSegName, '$', cchSegName); if (!pchSectName) return KLDR_ERR_SYMBOL_NOT_FOUND; cchSegName = pchSectName - pchSegName; pchSectName++; cchSectName = cchSymbol - (pchSectName - pchSymbol); } /* * Locate the segment. */ if (!pMod->cSegments) return KLDR_ERR_SYMBOL_NOT_FOUND; for (iSeg = 0; iSeg < pMod->cSegments; iSeg++) { if ( pMod->aSegments[iSeg].cchName >= cchSegName && kHlpMemComp(pMod->aSegments[iSeg].pchName, pchSegName, cchSegName) == 0) { section_32_t const *pSect; if ( pMod->aSegments[iSeg].cchName == cchSegName && pModMachO->Hdr.filetype != MH_OBJECT /* Good enough for __DWARF segs in MH_DHSYM, I hope. */) break; pSect = (section_32_t *)pModMachO->aSegments[iSeg].paSections[0].pvMachoSection; if ( pModMachO->uEffFileType == MH_OBJECT && pMod->aSegments[iSeg].cchName > cchSegName + 1 && pMod->aSegments[iSeg].pchName[cchSegName] == '.' && kHlpStrNComp(&pMod->aSegments[iSeg].pchName[cchSegName + 1], pSect->sectname, sizeof(pSect->sectname)) == 0 && pMod->aSegments[iSeg].cchName - cchSegName - 1 <= sizeof(pSect->sectname) ) break; } } if (iSeg >= pMod->cSegments) return KLDR_ERR_SYMBOL_NOT_FOUND; if (!s_aPrefixes[iPrefix].fSection) { /* * Calculate the segment start/end address. */ uValue = pMod->aSegments[iSeg].RVA; if (!s_aPrefixes[iPrefix].fStart) uValue += pMod->aSegments[iSeg].cb; } else { /* * Locate the section. */ KU32 iSect = pModMachO->aSegments[iSeg].cSections; if (!iSect) return KLDR_ERR_SYMBOL_NOT_FOUND; for (;;) { section_32_t *pSect = (section_32_t *)pModMachO->aSegments[iSeg].paSections[iSect].pvMachoSection; if ( cchSectName <= sizeof(pSect->sectname) && kHlpMemComp(pSect->sectname, pchSectName, cchSectName) == 0 && ( cchSectName == sizeof(pSect->sectname) || pSect->sectname[cchSectName] == '\0') ) break; /* next */ if (!iSect) return KLDR_ERR_SYMBOL_NOT_FOUND; iSect--; } uValue = pModMachO->aSegments[iSeg].paSections[iSect].RVA; if (!s_aPrefixes[iPrefix].fStart) uValue += pModMachO->aSegments[iSeg].paSections[iSect].cb; } /* * Convert from RVA to load address. */ uValue += BaseAddress; if (puValue) *puValue = uValue; return 0; } /** @copydoc kLdrModQuerySymbol */ static int kldrModMachOQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, KU32 *pfKind) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; int rc; K_NOREF(pvBits); K_NOREF(pszVersion); K_NOREF(pfnGetForwarder); K_NOREF(pvUser); /* * Resolve defaults. */ rc = kldrModMachOAdjustBaseAddress(pModMachO, &BaseAddress); if (rc) return rc; /* * Refuse segmented requests for now. */ KLDRMODMACHO_CHECK_RETURN( !pfKind || (*pfKind & KLDRSYMKIND_REQ_TYPE_MASK) == KLDRSYMKIND_REQ_FLAT, KLDR_ERR_TODO); /* * Take action according to file type. */ if ( pModMachO->Hdr.filetype == MH_OBJECT || pModMachO->Hdr.filetype == MH_EXECUTE /** @todo dylib, execute, dsym: symbols */ || pModMachO->Hdr.filetype == MH_DYLIB || pModMachO->Hdr.filetype == MH_BUNDLE || pModMachO->Hdr.filetype == MH_DSYM || pModMachO->Hdr.filetype == MH_KEXT_BUNDLE) { rc = kldrModMachOLoadObjSymTab(pModMachO); if (!rc) { if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE) rc = kldrModMachODoQuerySymbol32Bit(pModMachO, (macho_nlist_32_t *)pModMachO->pvaSymbols, pModMachO->cSymbols, pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, iSymbol, pchSymbol, (KU32)cchSymbol, puValue, pfKind); else rc = kldrModMachODoQuerySymbol64Bit(pModMachO, (macho_nlist_64_t *)pModMachO->pvaSymbols, pModMachO->cSymbols, pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, iSymbol, pchSymbol, (KU32)cchSymbol, puValue, pfKind); } /* * Check for link-editor generated symbols and supply what we can. * * As small service to clients that insists on adding a '_' prefix * before querying symbols, we will ignore the prefix. */ if ( rc == KLDR_ERR_SYMBOL_NOT_FOUND && cchSymbol > sizeof("section$end$") - 1 && ( pchSymbol[0] == 's' || (pchSymbol[1] == 's' && pchSymbol[0] == '_') ) && kHlpMemChr(pchSymbol, '$', cchSymbol) ) { if (pchSymbol[0] == '_') rc = kldrModMachOQueryLinkerSymbol(pModMachO, pMod, pchSymbol + 1, cchSymbol - 1, BaseAddress, puValue); else rc = kldrModMachOQueryLinkerSymbol(pModMachO, pMod, pchSymbol, cchSymbol, BaseAddress, puValue); } } else rc = KLDR_ERR_TODO; return rc; } /** * Lookup a symbol in a 32-bit symbol table. * * @returns See kLdrModQuerySymbol. * @param pModMachO * @param paSyms Pointer to the symbol table. * @param cSyms Number of symbols in the table. * @param pchStrings Pointer to the string table. * @param cchStrings Size of the string table. * @param BaseAddress Adjusted base address, see kLdrModQuerySymbol. * @param iSymbol See kLdrModQuerySymbol. * @param pchSymbol See kLdrModQuerySymbol. * @param cchSymbol See kLdrModQuerySymbol. * @param puValue See kLdrModQuerySymbol. * @param pfKind See kLdrModQuerySymbol. */ static int kldrModMachODoQuerySymbol32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms, const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol, KU32 cchSymbol, PKLDRADDR puValue, KU32 *pfKind) { /* * Find a valid symbol matching the search criteria. */ if (iSymbol == NIL_KLDRMOD_SYM_ORDINAL) { /* simplify validation. */ if (cchStrings <= cchSymbol) return KLDR_ERR_SYMBOL_NOT_FOUND; cchStrings -= cchSymbol; /* external symbols are usually at the end, so search the other way. */ for (iSymbol = cSyms - 1; iSymbol != KU32_MAX; iSymbol--) { const char *psz; /* Skip irrellevant and non-public symbols. */ if (paSyms[iSymbol].n_type & MACHO_N_STAB) continue; if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF) continue; if (!(paSyms[iSymbol].n_type & MACHO_N_EXT)) /*??*/ continue; if (paSyms[iSymbol].n_type & MACHO_N_PEXT) /*??*/ continue; /* get name */ if (!paSyms[iSymbol].n_un.n_strx) continue; if ((KU32)paSyms[iSymbol].n_un.n_strx >= cchStrings) continue; psz = &pchStrings[paSyms[iSymbol].n_un.n_strx]; if (psz[cchSymbol]) continue; if (kHlpMemComp(psz, pchSymbol, cchSymbol)) continue; /* match! */ break; } if (iSymbol == KU32_MAX) return KLDR_ERR_SYMBOL_NOT_FOUND; } else { if (iSymbol >= cSyms) return KLDR_ERR_SYMBOL_NOT_FOUND; if (paSyms[iSymbol].n_type & MACHO_N_STAB) return KLDR_ERR_SYMBOL_NOT_FOUND; if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF) return KLDR_ERR_SYMBOL_NOT_FOUND; } /* * Calc the return values. */ if (pfKind) { if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE) *pfKind = KLDRSYMKIND_32BIT | KLDRSYMKIND_NO_TYPE; else *pfKind = KLDRSYMKIND_64BIT | KLDRSYMKIND_NO_TYPE; if (paSyms[iSymbol].n_desc & N_WEAK_DEF) *pfKind |= KLDRSYMKIND_WEAK; } switch (paSyms[iSymbol].n_type & MACHO_N_TYPE) { case MACHO_N_SECT: { PKLDRMODMACHOSECT pSect; KLDRADDR offSect; KLDRMODMACHO_CHECK_RETURN((KU32)(paSyms[iSymbol].n_sect - 1) < pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); pSect = &pModMachO->paSections[paSyms[iSymbol].n_sect - 1]; offSect = paSyms[iSymbol].n_value - pSect->LinkAddress; KLDRMODMACHO_CHECK_RETURN( offSect <= pSect->cb || ( paSyms[iSymbol].n_sect == 1 /* special hack for __mh_execute_header */ && offSect == 0U - pSect->RVA && pModMachO->uEffFileType != MH_OBJECT), KLDR_ERR_MACHO_BAD_SYMBOL); if (puValue) *puValue = BaseAddress + pSect->RVA + offSect; if ( pfKind && (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE))) *pfKind = (*pfKind & ~KLDRSYMKIND_TYPE_MASK) | KLDRSYMKIND_CODE; break; } case MACHO_N_ABS: if (puValue) *puValue = paSyms[iSymbol].n_value; /*if (pfKind) pfKind |= KLDRSYMKIND_ABS;*/ break; case MACHO_N_PBUD: case MACHO_N_INDR: /** @todo implement indirect and prebound symbols. */ default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); } return 0; } /** * Lookup a symbol in a 64-bit symbol table. * * @returns See kLdrModQuerySymbol. * @param pModMachO * @param paSyms Pointer to the symbol table. * @param cSyms Number of symbols in the table. * @param pchStrings Pointer to the string table. * @param cchStrings Size of the string table. * @param BaseAddress Adjusted base address, see kLdrModQuerySymbol. * @param iSymbol See kLdrModQuerySymbol. * @param pchSymbol See kLdrModQuerySymbol. * @param cchSymbol See kLdrModQuerySymbol. * @param puValue See kLdrModQuerySymbol. * @param pfKind See kLdrModQuerySymbol. */ static int kldrModMachODoQuerySymbol64Bit(PKLDRMODMACHO pModMachO, const macho_nlist_64_t *paSyms, KU32 cSyms, const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress, KU32 iSymbol, const char *pchSymbol, KU32 cchSymbol, PKLDRADDR puValue, KU32 *pfKind) { /* * Find a valid symbol matching the search criteria. */ if (iSymbol == NIL_KLDRMOD_SYM_ORDINAL) { /* simplify validation. */ if (cchStrings <= cchSymbol) return KLDR_ERR_SYMBOL_NOT_FOUND; cchStrings -= cchSymbol; /* external symbols are usually at the end, so search the other way. */ for (iSymbol = cSyms - 1; iSymbol != KU32_MAX; iSymbol--) { const char *psz; /* Skip irrellevant and non-public symbols. */ if (paSyms[iSymbol].n_type & MACHO_N_STAB) continue; if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF) continue; if (!(paSyms[iSymbol].n_type & MACHO_N_EXT)) /*??*/ continue; if (paSyms[iSymbol].n_type & MACHO_N_PEXT) /*??*/ continue; /* get name */ if (!paSyms[iSymbol].n_un.n_strx) continue; if ((KU32)paSyms[iSymbol].n_un.n_strx >= cchStrings) continue; psz = &pchStrings[paSyms[iSymbol].n_un.n_strx]; if (psz[cchSymbol]) continue; if (kHlpMemComp(psz, pchSymbol, cchSymbol)) continue; /* match! */ break; } if (iSymbol == KU32_MAX) return KLDR_ERR_SYMBOL_NOT_FOUND; } else { if (iSymbol >= cSyms) return KLDR_ERR_SYMBOL_NOT_FOUND; if (paSyms[iSymbol].n_type & MACHO_N_STAB) return KLDR_ERR_SYMBOL_NOT_FOUND; if ((paSyms[iSymbol].n_type & MACHO_N_TYPE) == MACHO_N_UNDF) return KLDR_ERR_SYMBOL_NOT_FOUND; } /* * Calc the return values. */ if (pfKind) { if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE) *pfKind = KLDRSYMKIND_32BIT | KLDRSYMKIND_NO_TYPE; else *pfKind = KLDRSYMKIND_64BIT | KLDRSYMKIND_NO_TYPE; if (paSyms[iSymbol].n_desc & N_WEAK_DEF) *pfKind |= KLDRSYMKIND_WEAK; } switch (paSyms[iSymbol].n_type & MACHO_N_TYPE) { case MACHO_N_SECT: { PKLDRMODMACHOSECT pSect; KLDRADDR offSect; KLDRMODMACHO_CHECK_RETURN((KU32)(paSyms[iSymbol].n_sect - 1) < pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); pSect = &pModMachO->paSections[paSyms[iSymbol].n_sect - 1]; offSect = paSyms[iSymbol].n_value - pSect->LinkAddress; KLDRMODMACHO_CHECK_RETURN( offSect <= pSect->cb || ( paSyms[iSymbol].n_sect == 1 /* special hack for __mh_execute_header */ && offSect == 0U - pSect->RVA && pModMachO->uEffFileType != MH_OBJECT), KLDR_ERR_MACHO_BAD_SYMBOL); if (puValue) *puValue = BaseAddress + pSect->RVA + offSect; if ( pfKind && (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE))) *pfKind = (*pfKind & ~KLDRSYMKIND_TYPE_MASK) | KLDRSYMKIND_CODE; break; } case MACHO_N_ABS: if (puValue) *puValue = paSyms[iSymbol].n_value; /*if (pfKind) pfKind |= KLDRSYMKIND_ABS;*/ break; case MACHO_N_PBUD: case MACHO_N_INDR: /** @todo implement indirect and prebound symbols. */ default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); } return 0; } /** @copydoc kLdrModEnumSymbols */ static int kldrModMachOEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; int rc; K_NOREF(pvBits); /* * Resolve defaults. */ rc = kldrModMachOAdjustBaseAddress(pModMachO, &BaseAddress); if (rc) return rc; /* * Take action according to file type. */ if ( pModMachO->Hdr.filetype == MH_OBJECT || pModMachO->Hdr.filetype == MH_EXECUTE /** @todo dylib, execute, dsym: symbols */ || pModMachO->Hdr.filetype == MH_DYLIB || pModMachO->Hdr.filetype == MH_BUNDLE || pModMachO->Hdr.filetype == MH_DSYM || pModMachO->Hdr.filetype == MH_KEXT_BUNDLE) { rc = kldrModMachOLoadObjSymTab(pModMachO); if (!rc) { if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE) rc = kldrModMachODoEnumSymbols32Bit(pModMachO, (macho_nlist_32_t *)pModMachO->pvaSymbols, pModMachO->cSymbols, pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, fFlags, pfnCallback, pvUser); else rc = kldrModMachODoEnumSymbols64Bit(pModMachO, (macho_nlist_64_t *)pModMachO->pvaSymbols, pModMachO->cSymbols, pModMachO->pchStrings, pModMachO->cchStrings, BaseAddress, fFlags, pfnCallback, pvUser); } } else KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); return rc; } /** * Enum a 32-bit symbol table. * * @returns See kLdrModQuerySymbol. * @param pModMachO * @param paSyms Pointer to the symbol table. * @param cSyms Number of symbols in the table. * @param pchStrings Pointer to the string table. * @param cchStrings Size of the string table. * @param BaseAddress Adjusted base address, see kLdrModEnumSymbols. * @param fFlags See kLdrModEnumSymbols. * @param pfnCallback See kLdrModEnumSymbols. * @param pvUser See kLdrModEnumSymbols. */ static int kldrModMachODoEnumSymbols32Bit(PKLDRMODMACHO pModMachO, const macho_nlist_32_t *paSyms, KU32 cSyms, const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress, KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser) { const KU32 fKindBase = pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT; KU32 iSym; int rc; /* * Iterate the symbol table. */ for (iSym = 0; iSym < cSyms; iSym++) { KU32 fKind; KLDRADDR uValue; const char *psz; KSIZE cch; /* Skip debug symbols and undefined symbols. */ if (paSyms[iSym].n_type & MACHO_N_STAB) continue; if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF) continue; /* Skip non-public symbols unless they are requested explicitly. */ if (!(fFlags & KLDRMOD_ENUM_SYMS_FLAGS_ALL)) { if (!(paSyms[iSym].n_type & MACHO_N_EXT)) /*??*/ continue; if (paSyms[iSym].n_type & MACHO_N_PEXT) /*??*/ continue; if (!paSyms[iSym].n_un.n_strx) continue; } /* * Gather symbol info */ /* name */ KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_un.n_strx < cchStrings, KLDR_ERR_MACHO_BAD_SYMBOL); psz = &pchStrings[paSyms[iSym].n_un.n_strx]; cch = kHlpStrLen(psz); if (!cch) psz = NULL; /* kind & value */ fKind = fKindBase; if (paSyms[iSym].n_desc & N_WEAK_DEF) fKind |= KLDRSYMKIND_WEAK; switch (paSyms[iSym].n_type & MACHO_N_TYPE) { case MACHO_N_SECT: { PKLDRMODMACHOSECT pSect; KLDRMODMACHO_CHECK_RETURN((KU32)(paSyms[iSym].n_sect - 1) < pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); pSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1]; uValue = paSyms[iSym].n_value - pSect->LinkAddress; KLDRMODMACHO_CHECK_RETURN( uValue <= pSect->cb || ( paSyms[iSym].n_sect == 1 /* special hack for __mh_execute_header */ && uValue == 0U - pSect->RVA && pModMachO->uEffFileType != MH_OBJECT), KLDR_ERR_MACHO_BAD_SYMBOL); uValue += BaseAddress + pSect->RVA; if (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE)) fKind |= KLDRSYMKIND_CODE; else fKind |= KLDRSYMKIND_NO_TYPE; break; } case MACHO_N_ABS: uValue = paSyms[iSym].n_value; fKind |= KLDRSYMKIND_NO_TYPE /*KLDRSYMKIND_ABS*/; break; case MACHO_N_PBUD: case MACHO_N_INDR: /** @todo implement indirect and prebound symbols. */ default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); } /* * Do callback. */ rc = pfnCallback(pModMachO->pMod, iSym, psz, cch, NULL, uValue, fKind, pvUser); if (rc) return rc; } return 0; } /** * Enum a 64-bit symbol table. * * @returns See kLdrModQuerySymbol. * @param pModMachO * @param paSyms Pointer to the symbol table. * @param cSyms Number of symbols in the table. * @param pchStrings Pointer to the string table. * @param cchStrings Size of the string table. * @param BaseAddress Adjusted base address, see kLdrModEnumSymbols. * @param fFlags See kLdrModEnumSymbols. * @param pfnCallback See kLdrModEnumSymbols. * @param pvUser See kLdrModEnumSymbols. */ static int kldrModMachODoEnumSymbols64Bit(PKLDRMODMACHO pModMachO, const macho_nlist_64_t *paSyms, KU32 cSyms, const char *pchStrings, KU32 cchStrings, KLDRADDR BaseAddress, KU32 fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser) { const KU32 fKindBase = pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE || pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE ? KLDRSYMKIND_64BIT : KLDRSYMKIND_32BIT; KU32 iSym; int rc; /* * Iterate the symbol table. */ for (iSym = 0; iSym < cSyms; iSym++) { KU32 fKind; KLDRADDR uValue; const char *psz; KSIZE cch; /* Skip debug symbols and undefined symbols. */ if (paSyms[iSym].n_type & MACHO_N_STAB) continue; if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF) continue; /* Skip non-public symbols unless they are requested explicitly. */ if (!(fFlags & KLDRMOD_ENUM_SYMS_FLAGS_ALL)) { if (!(paSyms[iSym].n_type & MACHO_N_EXT)) /*??*/ continue; if (paSyms[iSym].n_type & MACHO_N_PEXT) /*??*/ continue; if (!paSyms[iSym].n_un.n_strx) continue; } /* * Gather symbol info */ /* name */ KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_un.n_strx < cchStrings, KLDR_ERR_MACHO_BAD_SYMBOL); psz = &pchStrings[paSyms[iSym].n_un.n_strx]; cch = kHlpStrLen(psz); if (!cch) psz = NULL; /* kind & value */ fKind = fKindBase; if (paSyms[iSym].n_desc & N_WEAK_DEF) fKind |= KLDRSYMKIND_WEAK; switch (paSyms[iSym].n_type & MACHO_N_TYPE) { case MACHO_N_SECT: { PKLDRMODMACHOSECT pSect; KLDRMODMACHO_CHECK_RETURN((KU32)(paSyms[iSym].n_sect - 1) < pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); pSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1]; uValue = paSyms[iSym].n_value - pSect->LinkAddress; KLDRMODMACHO_CHECK_RETURN( uValue <= pSect->cb || ( paSyms[iSym].n_sect == 1 /* special hack for __mh_execute_header */ && uValue == 0U - pSect->RVA && pModMachO->uEffFileType != MH_OBJECT), KLDR_ERR_MACHO_BAD_SYMBOL); uValue += BaseAddress + pSect->RVA; if (pSect->fFlags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SELF_MODIFYING_CODE)) fKind |= KLDRSYMKIND_CODE; else fKind |= KLDRSYMKIND_NO_TYPE; break; } case MACHO_N_ABS: uValue = paSyms[iSym].n_value; fKind |= KLDRSYMKIND_NO_TYPE /*KLDRSYMKIND_ABS*/; break; case MACHO_N_PBUD: case MACHO_N_INDR: /** @todo implement indirect and prebound symbols. */ default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); } /* * Do callback. */ rc = pfnCallback(pModMachO->pMod, iSym, psz, cch, NULL, uValue, fKind, pvUser); if (rc) return rc; } return 0; } /** @copydoc kLdrModGetImport */ static int kldrModMachOGetImport(PKLDRMOD pMod, const void *pvBits, KU32 iImport, char *pszName, KSIZE cchName) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; K_NOREF(pvBits); K_NOREF(iImport); K_NOREF(pszName); K_NOREF(cchName); if (pModMachO->Hdr.filetype == MH_OBJECT) return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS; /* later */ return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS; } /** @copydoc kLdrModNumberOfImports */ static KI32 kldrModMachONumberOfImports(PKLDRMOD pMod, const void *pvBits) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; K_NOREF(pvBits); if (pModMachO->Hdr.filetype == MH_OBJECT) return 0; /* later */ return 0; } /** @copydoc kLdrModGetStackInfo */ static int kldrModMachOGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo) { /*PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;*/ K_NOREF(pMod); K_NOREF(pvBits); K_NOREF(BaseAddress); pStackInfo->Address = NIL_KLDRADDR; pStackInfo->LinkAddress = NIL_KLDRADDR; pStackInfo->cbStack = pStackInfo->cbStackThread = 0; /* later */ return 0; } /** @copydoc kLdrModQueryMainEntrypoint */ static int kldrModMachOQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress) { #if 0 PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; int rc; /* * Resolve base address alias if any. */ rc = kldrModMachOBitsAndBaseAddress(pModMachO, NULL, &BaseAddress); if (rc) return rc; /* * Convert the address from the header. */ *pMainEPAddress = pModMachO->Hdrs.OptionalHeader.AddressOfEntryPoint ? BaseAddress + pModMachO->Hdrs.OptionalHeader.AddressOfEntryPoint : NIL_KLDRADDR; #else *pMainEPAddress = NIL_KLDRADDR; K_NOREF(pvBits); K_NOREF(BaseAddress); K_NOREF(pMod); #endif return 0; } /** @copydoc kLdrModQueryImageUuid */ static int kldrModMachOQueryImageUuid(PKLDRMOD pMod, const void *pvBits, void *pvUuid, KSIZE cbUuid) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; K_NOREF(pvBits); kHlpMemSet(pvUuid, 0, cbUuid); if (kHlpMemComp(pvUuid, pModMachO->abImageUuid, sizeof(pModMachO->abImageUuid)) == 0) return KLDR_ERR_NO_IMAGE_UUID; kHlpMemCopy(pvUuid, pModMachO->abImageUuid, sizeof(pModMachO->abImageUuid)); return 0; } /** @copydoc kLdrModEnumDbgInfo */ static int kldrModMachOEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; int rc = 0; KU32 iSect; K_NOREF(pvBits); for (iSect = 0; iSect < pModMachO->cSections; iSect++) { section_32_t *pMachOSect = pModMachO->paSections[iSect].pvMachoSection; /* (32-bit & 64-bit starts the same way) */ char szTmp[sizeof(pMachOSect->sectname) + 1]; if (kHlpStrComp(pMachOSect->segname, "__DWARF")) continue; kHlpMemCopy(szTmp, pMachOSect->sectname, sizeof(pMachOSect->sectname)); szTmp[sizeof(pMachOSect->sectname)] = '\0'; rc = pfnCallback(pMod, iSect, KLDRDBGINFOTYPE_DWARF, 0, 0, szTmp, pModMachO->paSections[iSect].offFile, pModMachO->paSections[iSect].LinkAddress, pModMachO->paSections[iSect].cb, NULL, pvUser); if (rc != 0) break; } return rc; } /** @copydoc kLdrModHasDbgInfo */ static int kldrModMachOHasDbgInfo(PKLDRMOD pMod, const void *pvBits) { /*PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData;*/ #if 0 /* * Base this entirely on the presence of a debug directory. */ if ( pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */ || !pModMachO->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress) return KLDR_ERR_NO_DEBUG_INFO; return 0; #else K_NOREF(pMod); K_NOREF(pvBits); return KLDR_ERR_NO_DEBUG_INFO; #endif } /** @copydoc kLdrModMap */ static int kldrModMachOMap(PKLDRMOD pMod) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; unsigned fFixed; KU32 i; void *pvBase; int rc; if (!pModMachO->fCanLoad) return KLDR_ERR_TODO; /* * Already mapped? */ if (pModMachO->pvMapping) return KLDR_ERR_ALREADY_MAPPED; /* * Map it. */ /* fixed image? */ fFixed = pMod->enmType == KLDRTYPE_EXECUTABLE_FIXED || pMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED; if (!fFixed) pvBase = NULL; else { pvBase = (void *)(KUPTR)pMod->aSegments[0].LinkAddress; if ((KUPTR)pvBase != pMod->aSegments[0].LinkAddress) return KLDR_ERR_ADDRESS_OVERFLOW; } /* try do the prepare */ rc = kRdrMap(pMod->pRdr, &pvBase, pMod->cSegments, pMod->aSegments, fFixed); if (rc) return rc; /* * Update the segments with their map addresses. */ for (i = 0; i < pMod->cSegments; i++) { if (pMod->aSegments[i].RVA != NIL_KLDRADDR) pMod->aSegments[i].MapAddress = (KUPTR)pvBase + (KUPTR)pMod->aSegments[i].RVA; } pModMachO->pvMapping = pvBase; return 0; } /** @copydoc kLdrModUnmap */ static int kldrModMachOUnmap(PKLDRMOD pMod) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; KU32 i; int rc; /* * Mapped? */ if (!pModMachO->pvMapping) return KLDR_ERR_NOT_MAPPED; /* * Try unmap the image. */ rc = kRdrUnmap(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments); if (rc) return rc; /* * Update the segments to reflect that they aren't mapped any longer. */ pModMachO->pvMapping = NULL; for (i = 0; i < pMod->cSegments; i++) pMod->aSegments[i].MapAddress = 0; return 0; } /** @copydoc kLdrModAllocTLS */ static int kldrModMachOAllocTLS(PKLDRMOD pMod, void *pvMapping) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; /* * Mapped? */ if ( pvMapping == KLDRMOD_INT_MAP && !pModMachO->pvMapping ) return KLDR_ERR_NOT_MAPPED; return 0; } /** @copydoc kLdrModFreeTLS */ static void kldrModMachOFreeTLS(PKLDRMOD pMod, void *pvMapping) { K_NOREF(pMod); K_NOREF(pvMapping); } /** @copydoc kLdrModReload */ static int kldrModMachOReload(PKLDRMOD pMod) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; /* * Mapped? */ if (!pModMachO->pvMapping) return KLDR_ERR_NOT_MAPPED; /* the file provider does it all */ return kRdrRefresh(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments); } /** @copydoc kLdrModFixupMapping */ static int kldrModMachOFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; int rc, rc2; /* * Mapped? */ if (!pModMachO->pvMapping) return KLDR_ERR_NOT_MAPPED; /* * Before doing anything we'll have to make all pages writable. */ rc = kRdrProtect(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments, 1 /* unprotect */); if (rc) return rc; /* * Resolve imports and apply base relocations. */ rc = kldrModMachORelocateBits(pMod, pModMachO->pvMapping, (KUPTR)pModMachO->pvMapping, pModMachO->LinkAddress, pfnGetImport, pvUser); /* * Restore protection. */ rc2 = kRdrProtect(pMod->pRdr, pModMachO->pvMapping, pMod->cSegments, pMod->aSegments, 0 /* protect */); if (!rc && rc2) rc = rc2; return rc; } /** * MH_OBJECT: Resolves undefined symbols (imports). * * @returns 0 on success, non-zero kLdr status code on failure. * @param pModMachO The Mach-O module interpreter instance. * @param pfnGetImport The callback for resolving an imported symbol. * @param pvUser User argument to the callback. */ static int kldrModMachOObjDoImports(PKLDRMODMACHO pModMachO, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) { const KU32 cSyms = pModMachO->cSymbols; KU32 iSym; int rc; /* * Ensure that we've got the symbol table and section fixups handy. */ rc = kldrModMachOLoadObjSymTab(pModMachO); if (rc) return rc; /* * Iterate the symbol table and resolve undefined symbols. * We currently ignore REFERENCE_TYPE. */ if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE) { macho_nlist_32_t *paSyms = (macho_nlist_32_t *)pModMachO->pvaSymbols; for (iSym = 0; iSym < cSyms; iSym++) { /* skip stabs */ if (paSyms[iSym].n_type & MACHO_N_STAB) continue; if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF) { const char *pszSymbol; KSIZE cchSymbol; KU32 fKind = KLDRSYMKIND_REQ_FLAT; KLDRADDR Value = NIL_KLDRADDR; /** @todo Implement N_REF_TO_WEAK. */ KLDRMODMACHO_CHECK_RETURN(!(paSyms[iSym].n_desc & N_REF_TO_WEAK), KLDR_ERR_TODO); /* Get the symbol name. */ KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_un.n_strx < pModMachO->cchStrings, KLDR_ERR_MACHO_BAD_SYMBOL); pszSymbol = &pModMachO->pchStrings[paSyms[iSym].n_un.n_strx]; cchSymbol = kHlpStrLen(pszSymbol); /* Check for linker defined symbols relating to sections and segments. */ if ( cchSymbol > sizeof("section$end$") - 1 && *pszSymbol == 's' && kHlpMemChr(pszSymbol, '$', cchSymbol)) rc = kldrModMachOQueryLinkerSymbol(pModMachO, pModMachO->pMod, pszSymbol, cchSymbol, BaseAddress, &Value); else rc = KLDR_ERR_SYMBOL_NOT_FOUND; /* Ask the user for an address to the symbol. */ if (rc) rc = pfnGetImport(pModMachO->pMod, NIL_KLDRMOD_IMPORT, iSym, pszSymbol, cchSymbol, NULL, &Value, &fKind, pvUser); if (rc) { /* weak reference? */ if (!(paSyms[iSym].n_desc & N_WEAK_REF)) break; Value = 0; } /* Update the symbol. */ paSyms[iSym].n_value = (KU32)Value; if (paSyms[iSym].n_value != Value) { rc = KLDR_ERR_ADDRESS_OVERFLOW; break; } } else if (paSyms[iSym].n_desc & N_WEAK_DEF) { /** @todo implement weak symbols. */ /*return KLDR_ERR_TODO; - ignored for now. */ } } } else { /* (Identical to the 32-bit code, just different paSym type. (and n_strx is unsigned)) */ macho_nlist_64_t *paSyms = (macho_nlist_64_t *)pModMachO->pvaSymbols; for (iSym = 0; iSym < cSyms; iSym++) { /* skip stabs */ if (paSyms[iSym].n_type & MACHO_N_STAB) continue; if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF) { const char *pszSymbol; KSIZE cchSymbol; KU32 fKind = KLDRSYMKIND_REQ_FLAT; KLDRADDR Value = NIL_KLDRADDR; /** @todo Implement N_REF_TO_WEAK. */ KLDRMODMACHO_CHECK_RETURN(!(paSyms[iSym].n_desc & N_REF_TO_WEAK), KLDR_ERR_TODO); /* Get the symbol name. */ KLDRMODMACHO_CHECK_RETURN(paSyms[iSym].n_un.n_strx < pModMachO->cchStrings, KLDR_ERR_MACHO_BAD_SYMBOL); pszSymbol = &pModMachO->pchStrings[paSyms[iSym].n_un.n_strx]; cchSymbol = kHlpStrLen(pszSymbol); /* Check for linker defined symbols relating to sections and segments. */ if ( cchSymbol > sizeof("section$end$") - 1 && *pszSymbol == 's' && kHlpMemChr(pszSymbol, '$', cchSymbol)) rc = kldrModMachOQueryLinkerSymbol(pModMachO, pModMachO->pMod, pszSymbol, cchSymbol, BaseAddress, &Value); else rc = KLDR_ERR_SYMBOL_NOT_FOUND; /* Ask the user for an address to the symbol. */ if (rc) rc = pfnGetImport(pModMachO->pMod, NIL_KLDRMOD_IMPORT, iSym, pszSymbol, cchSymbol, NULL, &Value, &fKind, pvUser); if (rc) { /* weak reference? */ if (!(paSyms[iSym].n_desc & N_WEAK_REF)) break; Value = 0; } /* Update the symbol. */ paSyms[iSym].n_value = Value; if (paSyms[iSym].n_value != Value) { rc = KLDR_ERR_ADDRESS_OVERFLOW; break; } } else if (paSyms[iSym].n_desc & N_WEAK_DEF) { /** @todo implement weak symbols. */ /*return KLDR_ERR_TODO; - ignored for now. */ } } } return rc; } /** * MH_OBJECT: Applies base relocations to a (unprotected) image mapping. * * @returns 0 on success, non-zero kLdr status code on failure. * @param pModMachO The Mach-O module interpreter instance. * @param pvMapping The mapping to fixup. * @param NewBaseAddress The address to fixup the mapping to. * @param OldBaseAddress The address the mapping is currently fixed up to. */ static int kldrModMachOObjDoFixups(PKLDRMODMACHO pModMachO, void *pvMapping, KLDRADDR NewBaseAddress) { KU32 iSeg; int rc; /* * Ensure that we've got the symbol table and section fixups handy. */ rc = kldrModMachOLoadObjSymTab(pModMachO); if (rc) return rc; /* * Iterate over the segments and their sections and apply fixups. */ for (iSeg = rc = 0; !rc && iSeg < pModMachO->pMod->cSegments; iSeg++) { PKLDRMODMACHOSEG pSeg = &pModMachO->aSegments[iSeg]; KU32 iSect; for (iSect = 0; iSect < pSeg->cSections; iSect++) { PKLDRMODMACHOSECT pSect = &pSeg->paSections[iSect]; KU8 *pbSectBits; /* skip sections without fixups. */ if (!pSect->cFixups) continue; /* lazy load (and endian convert) the fixups. */ if (!pSect->paFixups) { rc = kldrModMachOLoadFixups(pModMachO, pSect->offFixups, pSect->cFixups, &pSect->paFixups); if (rc) break; } /* * Apply the fixups. */ pbSectBits = (KU8 *)pvMapping + (KUPTR)pSect->RVA; if (pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE) /** @todo this aint right. */ rc = kldrModMachOFixupSectionGeneric32Bit(pModMachO, pbSectBits, pSect, (macho_nlist_32_t *)pModMachO->pvaSymbols, pModMachO->cSymbols, NewBaseAddress); else if ( pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE && pModMachO->Hdr.cputype == CPU_TYPE_X86_64) rc = kldrModMachOFixupSectionAMD64(pModMachO, pbSectBits, pSect, (macho_nlist_64_t *)pModMachO->pvaSymbols, pModMachO->cSymbols, NewBaseAddress); else KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); if (rc) break; } } return rc; } /** * Applies generic fixups to a section in an image of the same endian-ness * as the host CPU. * * @returns 0 on success, non-zero kLdr status code on failure. * @param pModMachO The Mach-O module interpreter instance. * @param pbSectBits Pointer to the section bits. * @param pFixupSect The section being fixed up. * @param NewBaseAddress The new base image address. */ static int kldrModMachOFixupSectionGeneric32Bit(PKLDRMODMACHO pModMachO, KU8 *pbSectBits, PKLDRMODMACHOSECT pFixupSect, macho_nlist_32_t *paSyms, KU32 cSyms, KLDRADDR NewBaseAddress) { const macho_relocation_info_t *paFixups = pFixupSect->paFixups; const KU32 cFixups = pFixupSect->cFixups; KSIZE cbSectBits = (KSIZE)pFixupSect->cb; const KU8 *pbSectVirginBits; KU32 iFixup; KLDRPU uFixVirgin; KLDRPU uFix; KLDRADDR SymAddr = ~(KLDRADDR)0; int rc; /* * Find the virgin bits. */ if (pFixupSect->offFile != -1) { rc = kldrModMachOMapVirginBits(pModMachO); if (rc) return rc; pbSectVirginBits = (const KU8 *)pModMachO->pvBits + pFixupSect->offFile; } else pbSectVirginBits = NULL; /* * Iterate the fixups and apply them. */ for (iFixup = 0; iFixup < cFixups; iFixup++) { union { macho_relocation_info_t r; scattered_relocation_info_t s; } Fixup; Fixup.r = paFixups[iFixup]; if (!(Fixup.r.r_address & R_SCATTERED)) { /* sanity */ if ((KU32)Fixup.r.r_address >= cbSectBits) return KLDR_ERR_BAD_FIXUP; /* calc fixup addresses. */ uFix.pv = pbSectBits + Fixup.r.r_address; uFixVirgin.pv = pbSectVirginBits ? (KU8 *)pbSectVirginBits + Fixup.r.r_address : 0; /* * Calc the symbol value. */ /* Calc the linked symbol address / addend. */ switch (Fixup.r.r_length) { /** @todo Deal with unaligned accesses on non x86 platforms. */ case 0: SymAddr = *uFixVirgin.pi8; break; case 1: SymAddr = *uFixVirgin.pi16; break; case 2: SymAddr = *uFixVirgin.pi32; break; case 3: SymAddr = *uFixVirgin.pi64; break; } if (Fixup.r.r_pcrel) SymAddr += Fixup.r.r_address + pFixupSect->LinkAddress; /* Add symbol / section address. */ if (Fixup.r.r_extern) { const macho_nlist_32_t *pSym; if (Fixup.r.r_symbolnum >= cSyms) return KLDR_ERR_BAD_FIXUP; pSym = &paSyms[Fixup.r.r_symbolnum]; if (pSym->n_type & MACHO_N_STAB) return KLDR_ERR_BAD_FIXUP; switch (pSym->n_type & MACHO_N_TYPE) { case MACHO_N_SECT: { PKLDRMODMACHOSECT pSymSect; KLDRMODMACHO_CHECK_RETURN((KU32)pSym->n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); pSymSect = &pModMachO->paSections[pSym->n_sect - 1]; SymAddr += pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress; break; } case MACHO_N_UNDF: case MACHO_N_ABS: SymAddr += pSym->n_value; break; case MACHO_N_INDR: case MACHO_N_PBUD: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_SYMBOL); } } else if (Fixup.r.r_symbolnum != R_ABS) { PKLDRMODMACHOSECT pSymSect; if (Fixup.r.r_symbolnum > pModMachO->cSections) return KLDR_ERR_BAD_FIXUP; pSymSect = &pModMachO->paSections[Fixup.r.r_symbolnum - 1]; SymAddr -= pSymSect->LinkAddress; SymAddr += pSymSect->RVA + NewBaseAddress; } /* adjust for PC relative */ if (Fixup.r.r_pcrel) SymAddr -= Fixup.r.r_address + pFixupSect->RVA + NewBaseAddress; } else { PKLDRMODMACHOSECT pSymSect; KU32 iSymSect; KLDRADDR Value; /* sanity */ KLDRMODMACHO_ASSERT(Fixup.s.r_scattered); if ((KU32)Fixup.s.r_address >= cbSectBits) return KLDR_ERR_BAD_FIXUP; /* calc fixup addresses. */ uFix.pv = pbSectBits + Fixup.s.r_address; uFixVirgin.pv = pbSectVirginBits ? (KU8 *)pbSectVirginBits + Fixup.s.r_address : 0; /* * Calc the symbol value. */ /* The addend is stored in the code. */ switch (Fixup.s.r_length) { case 0: SymAddr = *uFixVirgin.pi8; break; case 1: SymAddr = *uFixVirgin.pi16; break; case 2: SymAddr = *uFixVirgin.pi32; break; case 3: SymAddr = *uFixVirgin.pi64; break; } if (Fixup.s.r_pcrel) SymAddr += Fixup.s.r_address; Value = Fixup.s.r_value; SymAddr -= Value; /* (-> addend only) */ /* Find the section number from the r_value. */ pSymSect = NULL; for (iSymSect = 0; iSymSect < pModMachO->cSections; iSymSect++) { KLDRADDR off = Value - pModMachO->paSections[iSymSect].LinkAddress; if (off < pModMachO->paSections[iSymSect].cb) { pSymSect = &pModMachO->paSections[iSymSect]; break; } else if (off == pModMachO->paSections[iSymSect].cb) /* edge case */ pSymSect = &pModMachO->paSections[iSymSect]; } if (!pSymSect) return KLDR_ERR_BAD_FIXUP; /* Calc the symbol address. */ SymAddr += Value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress; if (Fixup.s.r_pcrel) SymAddr -= Fixup.s.r_address + pFixupSect->RVA + NewBaseAddress; Fixup.r.r_length = ((scattered_relocation_info_t *)&paFixups[iFixup])->r_length; Fixup.r.r_type = ((scattered_relocation_info_t *)&paFixups[iFixup])->r_type; } /* * Write back the fixed up value. */ if (Fixup.r.r_type == GENERIC_RELOC_VANILLA) { switch (Fixup.r.r_length) { case 0: *uFix.pu8 = (KU8)SymAddr; break; case 1: *uFix.pu16 = (KU16)SymAddr; break; case 2: *uFix.pu32 = (KU32)SymAddr; break; case 3: *uFix.pu64 = (KU64)SymAddr; break; } } else if (Fixup.r.r_type <= GENERIC_RELOC_LOCAL_SECTDIFF) return KLDR_ERR_MACHO_UNSUPPORTED_FIXUP_TYPE; else return KLDR_ERR_BAD_FIXUP; } return 0; } /** * Applies AMD64 fixups to a section. * * @returns 0 on success, non-zero kLdr status code on failure. * @param pModMachO The Mach-O module interpreter instance. * @param pbSectBits Pointer to the section bits. * @param pFixupSect The section being fixed up. * @param NewBaseAddress The new base image address. */ static int kldrModMachOFixupSectionAMD64(PKLDRMODMACHO pModMachO, KU8 *pbSectBits, PKLDRMODMACHOSECT pFixupSect, macho_nlist_64_t *paSyms, KU32 cSyms, KLDRADDR NewBaseAddress) { const macho_relocation_info_t *paFixups = pFixupSect->paFixups; const KU32 cFixups = pFixupSect->cFixups; KSIZE cbSectBits = (KSIZE)pFixupSect->cb; const KU8 *pbSectVirginBits; KU32 iFixup; KLDRPU uFixVirgin; KLDRPU uFix; KLDRADDR SymAddr; int rc; /* * Find the virgin bits. */ if (pFixupSect->offFile != -1) { rc = kldrModMachOMapVirginBits(pModMachO); if (rc) return rc; pbSectVirginBits = (const KU8 *)pModMachO->pvBits + pFixupSect->offFile; } else pbSectVirginBits = NULL; /* * Iterate the fixups and apply them. */ for (iFixup = 0; iFixup < cFixups; iFixup++) { union { macho_relocation_info_t r; scattered_relocation_info_t s; } Fixup; Fixup.r = paFixups[iFixup]; /* AMD64 doesn't use scattered fixups. */ KLDRMODMACHO_CHECK_RETURN(!(Fixup.r.r_address & R_SCATTERED), KLDR_ERR_BAD_FIXUP); /* sanity */ KLDRMODMACHO_CHECK_RETURN((KU32)Fixup.r.r_address < cbSectBits, KLDR_ERR_BAD_FIXUP); /* calc fixup addresses. */ uFix.pv = pbSectBits + Fixup.r.r_address; uFixVirgin.pv = pbSectVirginBits ? (KU8 *)pbSectVirginBits + Fixup.r.r_address : 0; /* * Calc the symbol value. */ /* Calc the linked symbol address / addend. */ switch (Fixup.r.r_length) { /** @todo Deal with unaligned accesses on non x86 platforms. */ case 2: SymAddr = *uFixVirgin.pi32; break; case 3: SymAddr = *uFixVirgin.pi64; break; default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_BAD_FIXUP); } /* Add symbol / section address. */ if (Fixup.r.r_extern) { const macho_nlist_64_t *pSym; KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_symbolnum < cSyms, KLDR_ERR_BAD_FIXUP); pSym = &paSyms[Fixup.r.r_symbolnum]; KLDRMODMACHO_CHECK_RETURN(!(pSym->n_type & MACHO_N_STAB), KLDR_ERR_BAD_FIXUP); switch (Fixup.r.r_type) { /* GOT references just needs to have their symbol verified. Later, we'll optimize GOT building here using a parallel sym->got array. */ case X86_64_RELOC_GOT_LOAD: case X86_64_RELOC_GOT: switch (pSym->n_type & MACHO_N_TYPE) { case MACHO_N_SECT: case MACHO_N_UNDF: case MACHO_N_ABS: break; case MACHO_N_INDR: case MACHO_N_PBUD: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_SYMBOL); } SymAddr = sizeof(KU64) * Fixup.r.r_symbolnum + pModMachO->GotRVA + NewBaseAddress; KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_length == 2, KLDR_ERR_BAD_FIXUP); SymAddr -= 4; break; /* Verify the r_pcrel field for signed fixups on the way into the default case. */ case X86_64_RELOC_BRANCH: case X86_64_RELOC_SIGNED: case X86_64_RELOC_SIGNED_1: case X86_64_RELOC_SIGNED_2: case X86_64_RELOC_SIGNED_4: KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP); /* Falls through. */ default: { /* Adjust with fixup specific addend and vierfy unsigned/r_pcrel. */ switch (Fixup.r.r_type) { case X86_64_RELOC_UNSIGNED: KLDRMODMACHO_CHECK_RETURN(!Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP); break; case X86_64_RELOC_BRANCH: KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_length == 2, KLDR_ERR_BAD_FIXUP); SymAddr -= 4; break; case X86_64_RELOC_SIGNED: case X86_64_RELOC_SIGNED_1: case X86_64_RELOC_SIGNED_2: case X86_64_RELOC_SIGNED_4: SymAddr -= 4; break; default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_BAD_FIXUP); } switch (pSym->n_type & MACHO_N_TYPE) { case MACHO_N_SECT: { PKLDRMODMACHOSECT pSymSect; KLDRMODMACHO_CHECK_RETURN((KU32)pSym->n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); pSymSect = &pModMachO->paSections[pSym->n_sect - 1]; SymAddr += pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress; break; } case MACHO_N_UNDF: /* branch to an external symbol may have to take a short detour. */ if ( Fixup.r.r_type == X86_64_RELOC_BRANCH && SymAddr + Fixup.r.r_address + pFixupSect->RVA + NewBaseAddress - pSym->n_value + KU64_C(0x80000000) >= KU64_C(0xffffff20)) SymAddr += pModMachO->cbJmpStub * Fixup.r.r_symbolnum + pModMachO->JmpStubsRVA + NewBaseAddress; else SymAddr += pSym->n_value; break; case MACHO_N_ABS: SymAddr += pSym->n_value; break; case MACHO_N_INDR: case MACHO_N_PBUD: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_SYMBOL); } break; } /* * This is a weird customer, it will always be follows by an UNSIGNED fixup. */ case X86_64_RELOC_SUBTRACTOR: { macho_relocation_info_t Fixup2; /* Deal with the SUBTRACT symbol first, by subtracting it from SymAddr. */ switch (pSym->n_type & MACHO_N_TYPE) { case MACHO_N_SECT: { PKLDRMODMACHOSECT pSymSect; KLDRMODMACHO_CHECK_RETURN((KU32)pSym->n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); pSymSect = &pModMachO->paSections[pSym->n_sect - 1]; SymAddr -= pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress; break; } case MACHO_N_UNDF: case MACHO_N_ABS: SymAddr -= pSym->n_value; break; case MACHO_N_INDR: case MACHO_N_PBUD: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_SYMBOL); } /* Load the 2nd fixup, check sanity. */ iFixup++; KLDRMODMACHO_CHECK_RETURN(!Fixup.r.r_pcrel && iFixup < cFixups, KLDR_ERR_BAD_FIXUP); Fixup2 = paFixups[iFixup]; KLDRMODMACHO_CHECK_RETURN( Fixup2.r_address == Fixup.r.r_address && Fixup2.r_length == Fixup.r.r_length && Fixup2.r_type == X86_64_RELOC_UNSIGNED && !Fixup2.r_pcrel && Fixup2.r_symbolnum < cSyms, KLDR_ERR_BAD_FIXUP); if (Fixup2.r_extern) { KLDRMODMACHO_CHECK_RETURN(Fixup2.r_symbolnum < cSyms, KLDR_ERR_BAD_FIXUP); pSym = &paSyms[Fixup2.r_symbolnum]; KLDRMODMACHO_CHECK_RETURN(!(pSym->n_type & MACHO_N_STAB), KLDR_ERR_BAD_FIXUP); /* Add it's value to SymAddr. */ switch (pSym->n_type & MACHO_N_TYPE) { case MACHO_N_SECT: { PKLDRMODMACHOSECT pSymSect; KLDRMODMACHO_CHECK_RETURN((KU32)pSym->n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); pSymSect = &pModMachO->paSections[pSym->n_sect - 1]; SymAddr += pSym->n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress; break; } case MACHO_N_UNDF: case MACHO_N_ABS: SymAddr += pSym->n_value; break; case MACHO_N_INDR: case MACHO_N_PBUD: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_MACHO_BAD_SYMBOL); } } else if (Fixup2.r_symbolnum != R_ABS) { PKLDRMODMACHOSECT pSymSect; KLDRMODMACHO_CHECK_RETURN(Fixup2.r_symbolnum <= pModMachO->cSections, KLDR_ERR_BAD_FIXUP); pSymSect = &pModMachO->paSections[Fixup2.r_symbolnum - 1]; SymAddr += pSymSect->RVA + NewBaseAddress; } else KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_BAD_FIXUP); } break; } } else { /* verify against fixup type and make adjustments */ switch (Fixup.r.r_type) { case X86_64_RELOC_UNSIGNED: KLDRMODMACHO_CHECK_RETURN(!Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP); break; case X86_64_RELOC_BRANCH: KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP); SymAddr += 4; /* dunno what the assmbler/linker really is doing here... */ break; case X86_64_RELOC_SIGNED: case X86_64_RELOC_SIGNED_1: case X86_64_RELOC_SIGNED_2: case X86_64_RELOC_SIGNED_4: KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_pcrel, KLDR_ERR_BAD_FIXUP); break; /*case X86_64_RELOC_GOT_LOAD:*/ /*case X86_64_RELOC_GOT: */ /*case X86_64_RELOC_SUBTRACTOR: - must be r_extern=1 says as. */ default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_BAD_FIXUP); } if (Fixup.r.r_symbolnum != R_ABS) { PKLDRMODMACHOSECT pSymSect; KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_symbolnum <= pModMachO->cSections, KLDR_ERR_BAD_FIXUP); pSymSect = &pModMachO->paSections[Fixup.r.r_symbolnum - 1]; SymAddr -= pSymSect->LinkAddress; SymAddr += pSymSect->RVA + NewBaseAddress; if (Fixup.r.r_pcrel) SymAddr += Fixup.r.r_address; } } /* adjust for PC relative */ if (Fixup.r.r_pcrel) SymAddr -= Fixup.r.r_address + pFixupSect->RVA + NewBaseAddress; /* * Write back the fixed up value. */ switch (Fixup.r.r_length) { case 3: *uFix.pu64 = (KU64)SymAddr; break; case 2: KLDRMODMACHO_CHECK_RETURN(Fixup.r.r_pcrel || Fixup.r.r_type == X86_64_RELOC_SUBTRACTOR, KLDR_ERR_BAD_FIXUP); KLDRMODMACHO_CHECK_RETURN((KI32)SymAddr == (KI64)SymAddr, KLDR_ERR_ADDRESS_OVERFLOW); *uFix.pu32 = (KU32)SymAddr; break; default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_BAD_FIXUP); } } return 0; } /** * Loads the symbol table for a MH_OBJECT file. * * The symbol table is pointed to by KLDRMODMACHO::pvaSymbols. * * @returns 0 on success, non-zero kLdr status code on failure. * @param pModMachO The Mach-O module interpreter instance. */ static int kldrModMachOLoadObjSymTab(PKLDRMODMACHO pModMachO) { int rc = 0; if ( !pModMachO->pvaSymbols && pModMachO->cSymbols) { KSIZE cbSyms; KSIZE cbSym; void *pvSyms; void *pvStrings; /* sanity */ KLDRMODMACHO_CHECK_RETURN( pModMachO->offSymbols && (!pModMachO->cchStrings || pModMachO->offStrings), KLDR_ERR_MACHO_BAD_OBJECT_FILE); /* allocate */ cbSym = pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE ? sizeof(macho_nlist_32_t) : sizeof(macho_nlist_64_t); cbSyms = pModMachO->cSymbols * cbSym; KLDRMODMACHO_CHECK_RETURN(cbSyms / cbSym == pModMachO->cSymbols, KLDR_ERR_SIZE_OVERFLOW); rc = KERR_NO_MEMORY; pvSyms = kHlpAlloc(cbSyms); if (pvSyms) { if (pModMachO->cchStrings) pvStrings = kHlpAlloc(pModMachO->cchStrings); else pvStrings = kHlpAllocZ(4); if (pvStrings) { /* read */ rc = kRdrRead(pModMachO->pMod->pRdr, pvSyms, cbSyms, pModMachO->offSymbols); if (!rc && pModMachO->cchStrings) rc = kRdrRead(pModMachO->pMod->pRdr, pvStrings, pModMachO->cchStrings, pModMachO->offStrings); if (!rc) { pModMachO->pvaSymbols = pvSyms; pModMachO->pchStrings = (char *)pvStrings; /* perform endian conversion? */ if (pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE) { KU32 cLeft = pModMachO->cSymbols; macho_nlist_32_t *pSym = (macho_nlist_32_t *)pvSyms; while (cLeft-- > 0) { pSym->n_un.n_strx = K_E2E_U32(pSym->n_un.n_strx); pSym->n_desc = (KI16)K_E2E_U16(pSym->n_desc); pSym->n_value = K_E2E_U32(pSym->n_value); pSym++; } } else if (pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE) { KU32 cLeft = pModMachO->cSymbols; macho_nlist_64_t *pSym = (macho_nlist_64_t *)pvSyms; while (cLeft-- > 0) { pSym->n_un.n_strx = K_E2E_U32(pSym->n_un.n_strx); pSym->n_desc = (KI16)K_E2E_U16(pSym->n_desc); pSym->n_value = K_E2E_U64(pSym->n_value); pSym++; } } return 0; } kHlpFree(pvStrings); } kHlpFree(pvSyms); } } else KLDRMODMACHO_ASSERT(pModMachO->pchStrings || pModMachO->Hdr.filetype == MH_DSYM); return rc; } /** * Loads the fixups at the given address and performs endian * conversion if necessary. * * @returns 0 on success, non-zero kLdr status code on failure. * @param pModMachO The Mach-O module interpreter instance. * @param offFixups The file offset of the fixups. * @param cFixups The number of fixups to load. * @param ppaFixups Where to put the pointer to the allocated fixup array. */ static int kldrModMachOLoadFixups(PKLDRMODMACHO pModMachO, KLDRFOFF offFixups, KU32 cFixups, macho_relocation_info_t **ppaFixups) { macho_relocation_info_t *paFixups; KSIZE cbFixups; int rc; /* allocate the memory. */ cbFixups = cFixups * sizeof(*paFixups); KLDRMODMACHO_CHECK_RETURN(cbFixups / sizeof(*paFixups) == cFixups, KLDR_ERR_SIZE_OVERFLOW); paFixups = (macho_relocation_info_t *)kHlpAlloc(cbFixups); if (!paFixups) return KERR_NO_MEMORY; /* read the fixups. */ rc = kRdrRead(pModMachO->pMod->pRdr, paFixups, cbFixups, offFixups); if (!rc) { *ppaFixups = paFixups; /* do endian conversion if necessary. */ if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE || pModMachO->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE) { KU32 iFixup; for (iFixup = 0; iFixup < cFixups; iFixup++) { KU32 *pu32 = (KU32 *)&paFixups[iFixup]; pu32[0] = K_E2E_U32(pu32[0]); pu32[1] = K_E2E_U32(pu32[1]); } } } else kHlpFree(paFixups); return rc; } /** * Maps the virgin file bits into memory if not already done. * * @returns 0 on success, non-zero kLdr status code on failure. * @param pModMachO The Mach-O module interpreter instance. */ static int kldrModMachOMapVirginBits(PKLDRMODMACHO pModMachO) { int rc = 0; if (!pModMachO->pvBits) rc = kRdrAllMap(pModMachO->pMod->pRdr, &pModMachO->pvBits); return rc; } /** @copydoc kLdrModCallInit */ static int kldrModMachOCallInit(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle) { /* later */ K_NOREF(pMod); K_NOREF(pvMapping); K_NOREF(uHandle); return 0; } /** @copydoc kLdrModCallTerm */ static int kldrModMachOCallTerm(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle) { /* later */ K_NOREF(pMod); K_NOREF(pvMapping); K_NOREF(uHandle); return 0; } /** @copydoc kLdrModCallThread */ static int kldrModMachOCallThread(PKLDRMOD pMod, void *pvMapping, KUPTR uHandle, unsigned fAttachingOrDetaching) { /* Relevant for Mach-O? */ K_NOREF(pMod); K_NOREF(pvMapping); K_NOREF(uHandle); K_NOREF(fAttachingOrDetaching); return 0; } /** @copydoc kLdrModSize */ static KLDRADDR kldrModMachOSize(PKLDRMOD pMod) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; return pModMachO->cbImage; } /** @copydoc kLdrModGetBits */ static int kldrModMachOGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; KU32 i; int rc; if (!pModMachO->fCanLoad) return KLDR_ERR_TODO; /* * Zero the entire buffer first to simplify things. */ kHlpMemSet(pvBits, 0, (KSIZE)pModMachO->cbImage); /* * When possible use the segment table to load the data. */ for (i = 0; i < pMod->cSegments; i++) { /* skip it? */ if ( pMod->aSegments[i].cbFile == -1 || pMod->aSegments[i].offFile == -1 || pMod->aSegments[i].LinkAddress == NIL_KLDRADDR || !pMod->aSegments[i].Alignment) continue; rc = kRdrRead(pMod->pRdr, (KU8 *)pvBits + pMod->aSegments[i].RVA, pMod->aSegments[i].cbFile, pMod->aSegments[i].offFile); if (rc) return rc; } /* * Perform relocations. */ return kldrModMachORelocateBits(pMod, pvBits, BaseAddress, pModMachO->LinkAddress, pfnGetImport, pvUser); } /** @copydoc kLdrModRelocateBits */ static int kldrModMachORelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser) { PKLDRMODMACHO pModMachO = (PKLDRMODMACHO)pMod->pvData; int rc; K_NOREF(OldBaseAddress); /* * Call workers to do the jobs. */ if (pModMachO->Hdr.filetype == MH_OBJECT) { rc = kldrModMachOObjDoImports(pModMachO, NewBaseAddress, pfnGetImport, pvUser); if (!rc) rc = kldrModMachOObjDoFixups(pModMachO, pvBits, NewBaseAddress); } else rc = KLDR_ERR_TODO; /*{ rc = kldrModMachODoFixups(pModMachO, pvBits, NewBaseAddress, OldBaseAddress, pfnGetImport, pvUser); if (!rc) rc = kldrModMachODoImports(pModMachO, pvBits, pfnGetImport, pvUser); }*/ /* * Construct the global offset table if necessary, it's always the last * segment when present. */ if (!rc && pModMachO->fMakeGot) rc = kldrModMachOMakeGOT(pModMachO, pvBits, NewBaseAddress); return rc; } /** * Builds the GOT. * * Assumes the symbol table has all external symbols resolved correctly and that * the bits has been cleared up front. */ static int kldrModMachOMakeGOT(PKLDRMODMACHO pModMachO, void *pvBits, KLDRADDR NewBaseAddress) { KU32 iSym = pModMachO->cSymbols; if ( pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE || pModMachO->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE) { macho_nlist_32_t const *paSyms = (macho_nlist_32_t const *)pModMachO->pvaSymbols; KU32 *paGOT = (KU32 *)((KU8 *)pvBits + pModMachO->GotRVA); while (iSym-- > 0) switch (paSyms[iSym].n_type & MACHO_N_TYPE) { case MACHO_N_SECT: { PKLDRMODMACHOSECT pSymSect; KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); pSymSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1]; paGOT[iSym] = (KU32)(paSyms[iSym].n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress); break; } case MACHO_N_UNDF: case MACHO_N_ABS: paGOT[iSym] = paSyms[iSym].n_value; break; } } else { macho_nlist_64_t const *paSyms = (macho_nlist_64_t const *)pModMachO->pvaSymbols; KU64 *paGOT = (KU64 *)((KU8 *)pvBits + pModMachO->GotRVA); while (iSym-- > 0) { switch (paSyms[iSym].n_type & MACHO_N_TYPE) { case MACHO_N_SECT: { PKLDRMODMACHOSECT pSymSect; KLDRMODMACHO_CHECK_RETURN((KU32)paSyms[iSym].n_sect - 1 <= pModMachO->cSections, KLDR_ERR_MACHO_BAD_SYMBOL); pSymSect = &pModMachO->paSections[paSyms[iSym].n_sect - 1]; paGOT[iSym] = paSyms[iSym].n_value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress; break; } case MACHO_N_UNDF: case MACHO_N_ABS: paGOT[iSym] = paSyms[iSym].n_value; break; } } if (pModMachO->JmpStubsRVA != NIL_KLDRADDR) { iSym = pModMachO->cSymbols; switch (pModMachO->Hdr.cputype) { /* * AMD64 is simple since the GOT and the indirect jmps are parallel * arrays with entries of the same size. The relative offset will * be the the same for each entry, kind of nice. :-) */ case CPU_TYPE_X86_64: { KU64 *paJmps = (KU64 *)((KU8 *)pvBits + pModMachO->JmpStubsRVA); KI32 off; KU64 u64Tmpl; union { KU8 ab[8]; KU64 u64; } Tmpl; /* create the template. */ off = (KI32)(pModMachO->GotRVA - (pModMachO->JmpStubsRVA + 6)); Tmpl.ab[0] = 0xff; /* jmp [GOT-entry wrt RIP] */ Tmpl.ab[1] = 0x25; Tmpl.ab[2] = off & 0xff; Tmpl.ab[3] = (off >> 8) & 0xff; Tmpl.ab[4] = (off >> 16) & 0xff; Tmpl.ab[5] = (off >> 24) & 0xff; Tmpl.ab[6] = 0xcc; Tmpl.ab[7] = 0xcc; u64Tmpl = Tmpl.u64; /* copy the template to every jmp table entry. */ while (iSym-- > 0) paJmps[iSym] = u64Tmpl; break; } default: KLDRMODMACHO_FAILED_RETURN(KLDR_ERR_TODO); } } } return 0; } /** * The Mach-O module interpreter method table. */ KLDRMODOPS g_kLdrModMachOOps = { "Mach-O", NULL, kldrModMachOCreate, kldrModMachODestroy, kldrModMachOQuerySymbol, kldrModMachOEnumSymbols, kldrModMachOGetImport, kldrModMachONumberOfImports, NULL /* can execute one is optional */, kldrModMachOGetStackInfo, kldrModMachOQueryMainEntrypoint, kldrModMachOQueryImageUuid, NULL, NULL, kldrModMachOEnumDbgInfo, kldrModMachOHasDbgInfo, kldrModMachOMap, kldrModMachOUnmap, kldrModMachOAllocTLS, kldrModMachOFreeTLS, kldrModMachOReload, kldrModMachOFixupMapping, kldrModMachOCallInit, kldrModMachOCallTerm, kldrModMachOCallThread, kldrModMachOSize, kldrModMachOGetBits, kldrModMachORelocateBits, NULL, /** @todo mostly done */ 42 /* the end */ }; kbuild-3149/src/lib/kStuff/kLdr/kLdrDyldMod.c0000644000175000017500000011157113252530253020722 0ustar locutuslocutus/* $Id: kLdrDyldMod.c 81 2016-08-18 22:10:38Z bird $ */ /** @file * kLdr - The Dynamic Loader, Dyld module methods. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include "kLdrInternal.h" /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** @def KLDRDYLDMOD_STRICT * Define KLDRDYLDMOD_STRICT to enabled strict checks in kLdrDyld. */ #define KLDRDYLDMOD_STRICT 1 /** @def KLDRDYLDMOD_ASSERT * Assert that an expression is true when KLDRDYLD_STRICT is defined. */ #ifdef KLDRDYLDMOD_STRICT # define KLDRDYLDMOD_ASSERT(expr) kHlpAssert(expr) #else # define KLDRDYLDMOD_ASSERT(expr) do {} while (0) #endif /******************************************************************************* * Internal Functions * *******************************************************************************/ static void kldrDyldModUnlink(PKLDRDYLDMOD pMod); /** * Creates a module from the specified file provider instance. * * @returns 0 on success and *ppMod pointing to the new instance. * On failure a non-zero kLdr status code is returned. * @param pRdr The file provider instance. * @param fFlags Load/search flags. * @param ppMod Where to put the pointer to the new module on success. */ int kldrDyldModCreate(PKRDR pRdr, KU32 fFlags, PPKLDRDYLDMOD ppMod) { PKLDRDYLDMOD pMod; PKLDRMOD pRawMod; int rc; *ppMod = NULL; /** @todo deal with fFlags (exec/dll) */ /** @todo Check up the cpu architecture. */ /* * Try open an module interpreter. */ rc = kLdrModOpenFromRdr(pRdr, 0 /*fFlags*/, KCPUARCH_UNKNOWN, &pRawMod); if (rc) return kldrDyldFailure(rc, "%s: %rc", kRdrName(pRdr), rc); /* * Match the module aginst the load flags. */ switch (pRawMod->enmType) { case KLDRTYPE_EXECUTABLE_FIXED: case KLDRTYPE_EXECUTABLE_RELOCATABLE: case KLDRTYPE_EXECUTABLE_PIC: if (!(fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE)) { kLdrModClose(pRawMod); return KLDR_ERR_NOT_EXE; } break; case KLDRTYPE_OBJECT: /* We can handle these as DLLs. */ case KLDRTYPE_SHARED_LIBRARY_FIXED: case KLDRTYPE_SHARED_LIBRARY_RELOCATABLE: case KLDRTYPE_SHARED_LIBRARY_PIC: case KLDRTYPE_FORWARDER_DLL: if (fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE) { kLdrModClose(pRawMod); return KLDR_ERR_NOT_DLL; } break; default: KLDRDYLDMOD_ASSERT(!"Bad enmType!"); case KLDRTYPE_CORE: return fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE ? KLDR_ERR_NOT_EXE : KLDR_ERR_NOT_DLL; } /* * Allocate a new dyld module. */ pMod = (PKLDRDYLDMOD)kHlpAlloc(sizeof(*pMod)); if (pMod) { pMod->enmState = KLDRSTATE_OPEN; pMod->pMod = pRawMod; pMod->hMod = pMod; pMod->cDepRefs = pMod->cDynRefs = pMod->cRefs = 0; switch (pRawMod->enmType) { case KLDRTYPE_EXECUTABLE_FIXED: case KLDRTYPE_EXECUTABLE_RELOCATABLE: case KLDRTYPE_EXECUTABLE_PIC: pMod->fExecutable = 1; break; default: pMod->fExecutable = 0; break; } pMod->fGlobalOrSpecific = 0; pMod->fBindable = 0; pMod->fInitList = 0; pMod->fAlreadySeen = 0; pMod->fMapped = 0; pMod->fAllocatedTLS = 0; pMod->f25Reserved = 0; pMod->InitTerm.pNext = NULL; pMod->InitTerm.pPrev = NULL; pMod->Bind.pNext = NULL; pMod->Bind.pPrev = NULL; pMod->cPrereqs = 0; pMod->papPrereqs = NULL; pMod->u32MagicHead = KLDRDYMOD_MAGIC; pMod->u32MagicTail = KLDRDYMOD_MAGIC; /* it. */ pMod->Load.pNext = NULL; pMod->Load.pPrev = kLdrDyldTail; if (kLdrDyldTail) kLdrDyldTail->Load.pNext = pMod; else kLdrDyldHead = pMod; kLdrDyldTail = pMod; /* deal with the remaining flags. */ if (fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE) kldrDyldModMarkSpecific(pMod); else kldrDyldModMarkGlobal(pMod); if (fFlags & KLDRYDLD_LOAD_FLAGS_GLOBAL_SYMBOLS) kldrDyldModSetBindable(pMod, 0 /* not deep binable */); else kldrDyldModClearBindable(pMod); /* * We're good. */ *ppMod = pMod; rc = 0; } else { kLdrModClose(pRawMod); rc = KERR_NO_MEMORY; } return rc; } /** * Creates a module for a native module. * * @returns 0 on success and *ppMod pointing to the new instance. * On failure a non-zero kLdr status code is returned. * @param hNativeModule The native handle. * @param ppMod Where to put the pointer to the new module on success. * @remark This function ain't finalized yet. */ int kldrDyldModCreateNative(KUPTR hNativeModule) { #if 0 /* * Check if this module is already loaded by the native OS loader. */ rc = kld { #if K_OS == K_OS_OS2 HMODULE hmod = NULLHANDLE; APIRET rc = DosQueryModuleHandle(kRdrName(pRdr), &hmod); if (!rc) #elif K_OS == K_OS_WINDOWS HMODULE hmod = NULL; if (GetModuleHandle(kRdrName(pRdr)) #else # error "Port me" #endif } #endif return -1; } /** * Destroys a module pending destruction. * * @param pMod The module in question. */ void kldrDyldModDestroy(PKLDRDYLDMOD pMod) { int rc; /* * Validate the state. */ switch (pMod->enmState) { case KLDRSTATE_PENDING_DESTROY: case KLDRSTATE_GC: break; default: KLDRDYLDMOD_ASSERT(!"Invalid state"); break; } KLDRDYLDMOD_ASSERT(!pMod->fInitList); KLDRDYLDMOD_ASSERT(!pMod->cDynRefs); KLDRDYLDMOD_ASSERT(!pMod->cDepRefs); /* * Ensure that the module is unmapped. */ if (pMod->fAllocatedTLS) { kLdrModFreeTLS(pMod->pMod, KLDRMOD_INT_MAP); pMod->fAllocatedTLS = 0; } if (pMod->fMapped) { rc = kLdrModUnmap(pMod->pMod); KLDRDYLDMOD_ASSERT(!rc); pMod->fMapped = 0; } /* * Ensure it's unlinked from all chains. */ if (pMod->enmState < KLDRSTATE_PENDING_DESTROY) kldrDyldModUnlink(pMod); /* * Free everything associated with the module. */ /* the prerequisite array. */ if (pMod->papPrereqs) { KU32 i = pMod->cPrereqs; while (i-- > 0) { KLDRDYLDMOD_ASSERT(pMod->papPrereqs[i] == NULL); pMod->papPrereqs[i] = NULL; } kHlpFree(pMod->papPrereqs); pMod->papPrereqs = NULL; pMod->cPrereqs = 0; } /* the module interpreter. */ if (pMod->pMod) { rc = kLdrModClose(pMod->pMod); KLDRDYLDMOD_ASSERT(!rc); pMod->pMod = NULL; } /* * Finally, change the module state and free the module if * there are not more references to it. If somebody is still * referencing it, postpone the freeing to Deref. */ pMod->enmState = KLDRSTATE_DESTROYED; if (!pMod->cRefs) { pMod->u32MagicHead = 1; pMod->u32MagicTail = 2; kHlpFree(pMod); } } /** * Unlinks the module from any list it might be in. * It is assumed that the module is at least linked into the load list. * * @param pMod The moduel. */ static void kldrDyldModUnlink(PKLDRDYLDMOD pMod) { /* load list */ if (pMod->Load.pNext) pMod->Load.pNext->Load.pPrev = pMod->Load.pPrev; else kLdrDyldTail = pMod->Load.pPrev; if (pMod->Load.pPrev) pMod->Load.pPrev->Load.pNext = pMod->Load.pNext; else kLdrDyldHead = pMod->Load.pNext; /* bind list */ if (pMod->fBindable) kldrDyldModClearBindable(pMod); /* init term */ if (pMod->fInitList) { KLDRDYLDMOD_ASSERT(pMod->enmState < KLDRSTATE_INITIALIZATION_FAILED); pMod->fInitList = 0; if (pMod->InitTerm.pNext) pMod->InitTerm.pNext->InitTerm.pPrev = pMod->InitTerm.pPrev; else g_pkLdrDyldInitTail = pMod->InitTerm.pPrev; if (pMod->InitTerm.pPrev) pMod->InitTerm.pPrev->InitTerm.pNext = pMod->InitTerm.pNext; else g_pkLdrDyldInitHead = pMod->InitTerm.pNext; } else if (pMod->enmState > KLDRSTATE_INITIALIZATION_FAILED) { KLDRDYLDMOD_ASSERT(pMod->enmState >= KLDRSTATE_GOOD); if (pMod->InitTerm.pNext) pMod->InitTerm.pNext->InitTerm.pPrev = pMod->InitTerm.pPrev; else g_pkLdrDyldTermTail = pMod->InitTerm.pPrev; if (pMod->InitTerm.pPrev) pMod->InitTerm.pPrev->InitTerm.pNext = pMod->InitTerm.pNext; else g_pkLdrDyldTermHead = pMod->InitTerm.pNext; } pMod->InitTerm.pNext = NULL; pMod->InitTerm.pPrev = NULL; } /** * Marks a module as bindable, i.e. it'll be considered when * resolving names the unix way. * * @param pMod The module. * @param fDeep When set the module will be inserted at the head of the * module list used to resolve symbols. This means that the * symbols in this module will be prefered of all the other * modules. */ void kldrDyldModSetBindable(PKLDRDYLDMOD pMod, unsigned fDeep) { KLDRDYLDMOD_ASSERT(pMod->enmState >= KLDRSTATE_OPEN && pMod->enmState < KLDRSTATE_PENDING_GC); if (!pMod->fBindable) { pMod->fBindable = 1; if (!fDeep) { pMod->Bind.pNext = NULL; pMod->Bind.pPrev = g_pkLdrDyldBindTail; if (g_pkLdrDyldBindTail) g_pkLdrDyldBindTail->Bind.pNext = pMod; else g_pkLdrDyldBindHead = pMod; g_pkLdrDyldBindTail = pMod; } else { pMod->Bind.pPrev = NULL; pMod->Bind.pNext = g_pkLdrDyldBindHead; if (g_pkLdrDyldBindHead) g_pkLdrDyldBindHead->Bind.pPrev = pMod; else g_pkLdrDyldBindTail = pMod; g_pkLdrDyldBindHead = pMod; } } } /** * Marks a module as not bindable, i.e. it will not be considered when * resolving names the unix way. * * @param pMod The module. */ void kldrDyldModClearBindable(PKLDRDYLDMOD pMod) { KLDRDYLDMOD_ASSERT(pMod->enmState >= KLDRSTATE_OPEN && pMod->enmState < KLDRSTATE_PENDING_DESTROY); if (pMod->fBindable) { pMod->fBindable = 0; if (pMod->Bind.pPrev) pMod->Bind.pPrev->Bind.pNext = pMod->Bind.pNext; else g_pkLdrDyldBindHead = pMod->Bind.pNext; if (pMod->Bind.pNext) pMod->Bind.pNext->Bind.pPrev = pMod->Bind.pPrev; else g_pkLdrDyldBindTail = pMod->Bind.pPrev; pMod->Bind.pNext = NULL; pMod->Bind.pPrev = NULL; } } /** * Marks the module as global instead of being specific. * * A global module can be a matching result when the request * doesn't specify a path. A specific module will not match * unless the path also matches. * * @param pMod The module. */ void kldrDyldModMarkGlobal(PKLDRDYLDMOD pMod) { pMod->fGlobalOrSpecific = 1; } /** * Marks the module as specific instead of global. * * See kldrDyldModMarkGlobal for an explanation of the two terms. * * @param pMod The module. */ void kldrDyldModMarkSpecific(PKLDRDYLDMOD pMod) { pMod->fGlobalOrSpecific = 0; } /** * Adds a reference to the module making sure it won't be freed just yet. * * @param pMod The module. */ void kldrDyldModAddRef(PKLDRDYLDMOD pMod) { pMod->cRefs++; } /** * Dereference a module. * * @param pMod */ void kldrDyldModDeref(PKLDRDYLDMOD pMod) { /* validate input */ KLDRDYLDMOD_ASSERT(pMod->cRefs > 0); KLDRDYLDMOD_ASSERT(pMod->cRefs >= pMod->cDepRefs + pMod->cDynRefs); KLDRDYLDMOD_ASSERT(pMod->enmState > KLDRSTATE_INVALID && pMod->enmState <= KLDRSTATE_END); /* decrement. */ if (pMod->cRefs > 0) pMod->cRefs--; /* execute delayed freeing. */ if ( pMod->enmState == KLDRSTATE_DESTROYED && !pMod->cRefs) { pMod->u32MagicHead = 1; pMod->u32MagicTail = 2; kHlpFree(pMod); } } /** * Increment the count of modules depending on this module. * * @param pMod The module. * @param pDep The module which depends on us. */ void kldrDyldModAddDep(PKLDRDYLDMOD pMod, PKLDRDYLDMOD pDep) { (void)pDep; /* validate state */ switch (pMod->enmState) { case KLDRSTATE_MAPPED: case KLDRSTATE_RELOADED: case KLDRSTATE_LOADED_PREREQUISITES: case KLDRSTATE_RELOADED_LOADED_PREREQUISITES: case KLDRSTATE_PENDING_INITIALIZATION: case KLDRSTATE_INITIALIZING: case KLDRSTATE_GOOD: break; default: KLDRDYLDMOD_ASSERT(!"invalid state"); break; } KLDRDYLDMOD_ASSERT(pMod->enmState > KLDRSTATE_INVALID && pMod->enmState <= KLDRSTATE_END); pMod->cRefs++; pMod->cDepRefs++; } /** * Drop a dependency. * * @param pMod The module. * @param pDep The module which depends on us. */ void kldrDyldModRemoveDep(PKLDRDYLDMOD pMod, PKLDRDYLDMOD pDep) { KLDRDYLDMOD_ASSERT(pMod->cDepRefs > 0); if (pMod->cDepRefs == 0) return; KLDRDYLDMOD_ASSERT(pMod->cDepRefs <= pMod->cRefs); KLDRDYLDMOD_ASSERT(pMod->enmState >= KLDRSTATE_MAPPED && pMod->enmState <= KLDRSTATE_PENDING_DESTROY); pMod->cRefs--; pMod->cDepRefs--; if ( pMod->cDepRefs > 0 || pMod->cDynRefs > 0) return; /* * The module should be unloaded. */ kldrDyldModUnloadPrerequisites(pMod); } /** * Increment the dynamic load count. * * @returns 0 * @param pMod The module. */ int kldrDyldModDynamicLoad(PKLDRDYLDMOD pMod) { KLDRDYLDMOD_ASSERT( pMod->enmState == KLDRSTATE_GOOD || pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION || pMod->enmState == KLDRSTATE_INITIALIZING); pMod->cRefs++; pMod->cDynRefs++; return 0; } /** * Decrement the dynamic load count of the module and unload the module * if the total reference count reaches zero. * * This may cause a cascade of unloading to occure. See kldrDyldModUnloadPrerequisites(). * * @returns status code. * @retval 0 on success. * @retval KLDR_ERR_NOT_LOADED_DYNAMICALLY if the module wasn't loaded dynamically. * @param pMod The module to unload. */ int kldrDyldModDynamicUnload(PKLDRDYLDMOD pMod) { if (pMod->cDynRefs == 0) return KLDR_ERR_NOT_LOADED_DYNAMICALLY; KLDRDYLDMOD_ASSERT(pMod->cDynRefs <= pMod->cRefs); KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_GOOD); pMod->cRefs--; pMod->cDynRefs--; if ( pMod->cDynRefs > 0 || pMod->cDepRefs > 0) return 0; /* * The module should be unloaded. */ kldrDyldModUnloadPrerequisites(pMod); return 0; } /** * Worker for kldrDyldModUnloadPrerequisites. * * @returns The number of modules that now can be unloaded. * @param pMod The module in question. */ static KU32 kldrDyldModUnloadPrerequisitesOne(PKLDRDYLDMOD pMod) { PKLDRDYLDMOD pMod2; KU32 cToUnload = 0; KU32 i; KLDRDYLDMOD_ASSERT(pMod->papPrereqs || !pMod->cPrereqs); /* * Release the one in this module. */ for (i = 0; i < pMod->cPrereqs; i++) { pMod2 = pMod->papPrereqs[i]; if (pMod2) { pMod->papPrereqs[i] = NULL; /* do the derefering ourselves or we'll end up in a recursive loop here. */ KLDRDYLDMOD_ASSERT(pMod2->cDepRefs > 0); KLDRDYLDMOD_ASSERT(pMod2->cRefs >= pMod2->cDepRefs); pMod2->cDepRefs--; pMod2->cRefs--; cToUnload += !pMod2->cDepRefs && !pMod2->cDynRefs; } } /* * Change the state */ switch (pMod->enmState) { case KLDRSTATE_LOADED_PREREQUISITES: case KLDRSTATE_FIXED_UP: pMod->enmState = KLDRSTATE_PENDING_DESTROY; kldrDyldModUnlink(pMod); break; case KLDRSTATE_PENDING_INITIALIZATION: pMod->enmState = KLDRSTATE_PENDING_GC; break; case KLDRSTATE_RELOADED_FIXED_UP: case KLDRSTATE_RELOADED_LOADED_PREREQUISITES: case KLDRSTATE_GOOD: pMod->enmState = KLDRSTATE_PENDING_TERMINATION; break; case KLDRSTATE_INITIALIZATION_FAILED: break; default: KLDRDYLDMOD_ASSERT(!"invalid state"); break; } return cToUnload; } /** * This is the heart of the unload code. * * It will recursivly (using the load list) initiate module unloading * of all affected modules. * * This function will cause a state transition to PENDING_DESTROY, PENDING_GC * or PENDING_TERMINATION depending on the module state. There is one exception * to this, and that's INITIALIZATION_FAILED, where the state will not be changed. * * @param pMod The module which prerequisites should be unloaded. */ void kldrDyldModUnloadPrerequisites(PKLDRDYLDMOD pMod) { KU32 cToUnload; /* sanity */ #ifdef KLDRDYLD_STRICT { PKLDRDYLDMOD pMod2; for (pMod2 = kLdrDyldHead; pMod2; pMod2 = pMod2->Load.pNext) KLDRDYLDMOD_ASSERT(pMod2->enmState != KLDRSTATE_GOOD || pMod2->cRefs); } #endif KLDRDYLDMOD_ASSERT(pMod->papPrereqs); /* * Unload prereqs of the module we're called on first. */ cToUnload = kldrDyldModUnloadPrerequisitesOne(pMod); /* * Iterate the load list in a cyclic manner until there are no more * modules that can be pushed on into unloading. */ while (cToUnload) { cToUnload = 0; for (pMod = kLdrDyldHead; pMod; pMod = pMod->Load.pNext) { if ( pMod->cDepRefs || pMod->cDynRefs || pMod->enmState >= KLDRSTATE_PENDING_TERMINATION || pMod->enmState < KLDRSTATE_LOADED_PREREQUISITES) continue; cToUnload += kldrDyldModUnloadPrerequisitesOne(pMod); } } } /** * Loads the prerequisite modules this module depends on. * * To find each of the prerequisite modules this method calls * kldrDyldGetPrerequisite() and it will make sure the modules * are added to the load stack frame. * * @returns 0 on success, non-zero native OS or kLdr status code on failure. * The state is changed to LOADED_PREREQUISITES or RELOADED_LOADED_PREREQUISITES. * @param pMod The module. * @param pszPrefix Prefix to use when searching. * @param pszSuffix Suffix to use when searching. * @param enmSearch Method to use when locating the module and any modules it may depend on. * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines. */ int kldrDyldModLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags) { KI32 cPrereqs; KU32 i; int rc = 0; /* sanity */ switch (pMod->enmState) { case KLDRSTATE_MAPPED: case KLDRSTATE_RELOADED: break; default: KLDRDYLDMOD_ASSERT(!"invalid state"); return -1; } /* * Query number of prerequiste modules and allocate the array. */ cPrereqs = kLdrModNumberOfImports(pMod->pMod, NULL); kHlpAssert(cPrereqs >= 0); if (pMod->cPrereqs != cPrereqs) { KLDRDYLDMOD_ASSERT(!pMod->papPrereqs); pMod->papPrereqs = (PPKLDRDYLDMOD)kHlpAllocZ(sizeof(pMod->papPrereqs[0]) * cPrereqs); if (!pMod->papPrereqs) return KERR_NO_MEMORY; pMod->cPrereqs = cPrereqs; } else KLDRDYLDMOD_ASSERT(pMod->papPrereqs || !pMod->cPrereqs); /* * Iterate the prerequisites and load them. */ for (i = 0; i < pMod->cPrereqs; i++) { static char s_szPrereq[260]; PKLDRDYLDMOD pPrereqMod; KLDRDYLDMOD_ASSERT(pMod->papPrereqs[i] == NULL); rc = kLdrModGetImport(pMod->pMod, NULL, i, s_szPrereq, sizeof(s_szPrereq)); if (rc) break; rc = kldrDyldGetPrerequisite(s_szPrereq, pszPrefix, pszSuffix, enmSearch, fFlags, pMod, &pPrereqMod); if (rc) break; pMod->papPrereqs[i] = pPrereqMod; } /* change the state regardless of what happend. */ if (pMod->enmState == KLDRSTATE_MAPPED) pMod->enmState = KLDRSTATE_LOADED_PREREQUISITES; else pMod->enmState = KLDRSTATE_RELOADED_LOADED_PREREQUISITES; return rc; } /** * Maps an open module. * * On success the module will be in the MAPPED state. * * @returns 0 on success, non-zero native OS or kLdr status code on failure. * @param pMod The module which needs to be unmapped and set pending for destruction. */ int kldrDyldModMap(PKLDRDYLDMOD pMod) { int rc; /* sanity */ KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_OPEN); KLDRDYLDMOD_ASSERT(!pMod->fMapped); if (pMod->fMapped) return 0; /* do the job. */ rc = kLdrModMap(pMod->pMod); if (!rc) { rc = kLdrModAllocTLS(pMod->pMod, KLDRMOD_INT_MAP); if (!rc) { /** @todo TLS */ pMod->fMapped = 1; pMod->enmState = KLDRSTATE_MAPPED; } else kLdrModUnmap(pMod->pMod); } return rc; } /** * Unmaps the module, unlinks it from everywhere marks it PENDING_DESTROY. * * @returns 0 on success, non-zero native OS or kLdr status code on failure. * @param pMod The module which needs to be unmapped and set pending for destruction. */ int kldrDyldModUnmap(PKLDRDYLDMOD pMod) { int rc; /* sanity */ KLDRDYLDMOD_ASSERT(pMod->cRefs > 0); KLDRDYLDMOD_ASSERT(pMod->fMapped); switch (pMod->enmState) { case KLDRSTATE_MAPPED: case KLDRSTATE_GC: case KLDRSTATE_PENDING_DESTROY: break; default: KLDRDYLDMOD_ASSERT(!"invalid state"); return -1; } /* do the job. */ if (pMod->fAllocatedTLS) { kLdrModFreeTLS(pMod->pMod, KLDRMOD_INT_MAP); pMod->fAllocatedTLS = 0; } rc = kLdrModUnmap(pMod->pMod); if (!rc) { pMod->fMapped = 0; if (pMod->enmState < KLDRSTATE_PENDING_DESTROY) { pMod->enmState = KLDRSTATE_PENDING_DESTROY; kldrDyldModUnlink(pMod); } } return rc; } /** * Reloads the module. * * Reloading means that all modified pages are restored to their original * state. Whether this includes the code segments depends on whether the fixups * depend on the addend in the place they are fixing up - so it's format specific. * * @returns 0 on success, non-zero native OS or kLdr status code on failure. * @param pMod The module which needs to be unmapped and set pending for destruction. */ int kldrDyldModReload(PKLDRDYLDMOD pMod) { int rc; /* sanity */ KLDRDYLDMOD_ASSERT(pMod->cRefs > 0); KLDRDYLDMOD_ASSERT(pMod->fMapped); switch (pMod->enmState) { case KLDRSTATE_MAPPED: case KLDRSTATE_GC: case KLDRSTATE_PENDING_DESTROY: break; default: KLDRDYLDMOD_ASSERT(!"invalid state"); return -1; } /* Free TLS before reloading. */ if (pMod->fAllocatedTLS) { kLdrModFreeTLS(pMod->pMod, KLDRMOD_INT_MAP); pMod->fAllocatedTLS = 0; } /* Let the module interpreter do the reloading of the mapping. */ rc = kLdrModReload(pMod->pMod); if (!rc) { rc = kLdrModAllocTLS(pMod->pMod, KLDRMOD_INT_MAP); if (!rc) { pMod->fAllocatedTLS = 1; pMod->enmState = KLDRSTATE_RELOADED; } } return rc; } /** * @copydoc FNKLDRMODGETIMPORT * pvUser points to the KLDRDYLDMOD. */ static int kldrDyldModFixupGetImportCallback(PKLDRMOD pMod, KU32 iImport, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, PKLDRADDR puValue, KU32 *pfKind, void *pvUser) { static int s_cRecursiveCalls = 0; PKLDRDYLDMOD pDyldMod = (PKLDRDYLDMOD)pvUser; int rc; /* guard against too deep forwarder recursion. */ if (s_cRecursiveCalls >= 5) return KLDR_ERR_TOO_LONG_FORWARDER_CHAIN; s_cRecursiveCalls++; if (iImport != NIL_KLDRMOD_IMPORT) { /* specific import module search. */ PKLDRDYLDMOD pPrereqMod; KLDRDYLDMOD_ASSERT(iImport < pDyldMod->cPrereqs); pPrereqMod = pDyldMod->papPrereqs[iImport]; KLDRDYLDMOD_ASSERT(pPrereqMod); KLDRDYLDMOD_ASSERT(pPrereqMod->u32MagicHead == KLDRDYMOD_MAGIC); KLDRDYLDMOD_ASSERT(pPrereqMod->u32MagicTail == KLDRDYMOD_MAGIC); KLDRDYLDMOD_ASSERT(pPrereqMod->enmState < KLDRSTATE_TERMINATING); rc = kLdrModQuerySymbol(pPrereqMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP, iSymbol, pchSymbol, cchSymbol, pszVersion, kldrDyldModFixupGetImportCallback, pPrereqMod, puValue, pfKind); if (rc) { if (pchSymbol) kldrDyldFailure(rc, "%s[%d]->%s.%.*s%s", pDyldMod->pMod->pszName, iImport, pPrereqMod->pMod->pszName, cchSymbol, pchSymbol, pszVersion ? pszVersion : ""); else kldrDyldFailure(rc, "%s[%d]->%s.%d%s", pDyldMod->pMod->pszName, iImport, pPrereqMod->pMod->pszName, iSymbol, pszVersion ? pszVersion : ""); } } else { /* bind list search. */ unsigned fFound = 0; PKLDRDYLDMOD pBindMod = g_pkLdrDyldBindHead; rc = 0; while (pBindMod) { KU32 fKind; KLDRADDR uValue; rc = kLdrModQuerySymbol(pBindMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP, iSymbol, pchSymbol, cchSymbol, pszVersion, kldrDyldModFixupGetImportCallback, pBindMod, &uValue, &fKind); if ( !rc && ( !fFound || !(fKind & KLDRSYMKIND_WEAK) ) ) { *pfKind = fKind; *puValue = uValue; fFound = 1; if (!(fKind & KLDRSYMKIND_WEAK)) break; } /* next */ pBindMod = pBindMod->Bind.pNext; } rc = fFound ? 0 : KLDR_ERR_SYMBOL_NOT_FOUND; if (!fFound) { if (pchSymbol) kldrDyldFailure(rc, "%s->%.*s%s", pDyldMod->pMod->pszName, cchSymbol, pchSymbol, pszVersion ? pszVersion : ""); else kldrDyldFailure(rc, "%s->%d%s", pDyldMod->pMod->pszName, iSymbol, pszVersion ? pszVersion : ""); } } s_cRecursiveCalls--; return rc; } /** * Applies fixups to a module which prerequisistes has been * successfully loaded. * * @returns 0 on success, non-zero native OS or kLdr status code on failure. * @param pMod The module which needs to be unmapped and set pending for destruction. */ int kldrDyldModFixup(PKLDRDYLDMOD pMod) { int rc; /* sanity */ KLDRDYLDMOD_ASSERT(pMod->cRefs > 0); KLDRDYLDMOD_ASSERT( pMod->enmState == KLDRSTATE_LOADED_PREREQUISITES || pMod->enmState == KLDRSTATE_RELOADED_LOADED_PREREQUISITES); /* do the job */ rc = kLdrModFixupMapping(pMod->pMod, kldrDyldModFixupGetImportCallback, pMod);/** @todo fixme. */ if (!rc) pMod->enmState = KLDRSTATE_FIXED_UP; return rc; } /** * Calls the module initialization entry point if any. * * This is considered to be a module specific thing and leave if * to the module interpreter. They will have to deal with different * module init practices between platforms should there be any. * * @returns 0 and state changed to GOOD on success. * Non-zero OS or kLdr status code and status changed to INITIALIZATION_FAILED on failure. * @param pMod The module that should be initialized. */ int kldrDyldModCallInit(PKLDRDYLDMOD pMod) { int rc; KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION); KLDRDYLDMOD_ASSERT(!pMod->fInitList); pMod->enmState = KLDRSTATE_INITIALIZING; rc = kLdrModCallInit(pMod->pMod, KLDRMOD_INT_MAP, (KUPTR)pMod->hMod); if (!rc) { pMod->enmState = KLDRSTATE_GOOD; /* push it onto the termination list.*/ pMod->InitTerm.pPrev = NULL; pMod->InitTerm.pNext = g_pkLdrDyldTermHead; if (g_pkLdrDyldTermHead) g_pkLdrDyldTermHead->InitTerm.pPrev = pMod; else g_pkLdrDyldTermTail = pMod; g_pkLdrDyldTermHead = pMod; } else pMod->enmState = KLDRSTATE_INITIALIZATION_FAILED; return rc; } /** * Calls the module termination entry point if any. * * This'll change the module status to PENDING_GC. * * @param pMod The module that should be initialized. */ void kldrDyldModCallTerm(PKLDRDYLDMOD pMod) { KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_TERMINATION); pMod->enmState = KLDRSTATE_TERMINATING; kLdrModCallTerm(pMod->pMod, KLDRMOD_INT_MAP, (KUPTR)pMod->hMod); pMod->enmState = KLDRSTATE_PENDING_GC; /* unlinking on destruction. */ } /** * Calls the thread attach entry point if any. * * @returns 0 on success, non-zero on failure. * @param pMod The module. */ int kldrDyldModAttachThread(PKLDRDYLDMOD pMod) { KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_GOOD); return kLdrModCallThread(pMod->pMod, KLDRMOD_INT_MAP, (KUPTR)pMod->hMod, 1 /* attach */); } /** * Calls the thread detach entry point if any. * * @returns 0 on success, non-zero on failure. * @param pMod The module. */ void kldrDyldModDetachThread(PKLDRDYLDMOD pMod) { KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_GOOD); kLdrModCallThread(pMod->pMod, KLDRMOD_INT_MAP, (KUPTR)pMod->hMod, 0 /* detach */); } /** * Gets the main stack, allocate it if necessary. * * @returns 0 on success, non-zero native OS or kLdr status code on failure. * @param pMod The module. * @param ppvStack Where to store the address of the stack (lowest address). * @param pcbStack Where to store the size of the stack. */ int kldrDyldModGetMainStack(PKLDRDYLDMOD pMod, void **ppvStack, KSIZE *pcbStack) { int rc = 0; KLDRSTACKINFO StackInfo; KLDRDYLDMOD_ASSERT(pMod->fExecutable); /* * Since we might have to allocate the stack ourselves, and there will only * ever be one main stack, we'll be keeping the main stack info in globals. */ if (!g_fkLdrDyldDoneMainStack) { rc = kLdrModGetStackInfo(pMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP, &StackInfo); if (!rc) { /* check if there is a stack size override/default. */ KSIZE cbDefOverride; if (kHlpGetEnvUZ("KLDR_MAIN_STACK_SIZE", &cbDefOverride)) cbDefOverride = 0; /* needs allocating? */ if ( StackInfo.LinkAddress == NIL_KLDRADDR || StackInfo.cbStack < cbDefOverride) { KSIZE cbStack = (KSIZE)K_MAX(StackInfo.cbStack, cbDefOverride); g_pvkLdrDyldMainStack = kldrDyldOSAllocStack(cbStack); if (g_pvkLdrDyldMainStack) { g_cbkLdrDyldMainStack = cbStack; g_fkLdrDyldMainStackAllocated = 1; } else rc = KLDR_ERR_MAIN_STACK_ALLOC_FAILED; } else { KLDRDYLDMOD_ASSERT(StackInfo.Address != NIL_KLDRADDR); KLDRDYLDMOD_ASSERT(StackInfo.cbStack > 0); g_fkLdrDyldMainStackAllocated = 0; g_pvkLdrDyldMainStack = (void *)(KUPTR)StackInfo.Address; KLDRDYLDMOD_ASSERT((KUPTR)g_pvkLdrDyldMainStack == StackInfo.Address); g_cbkLdrDyldMainStack = (KSIZE)StackInfo.cbStack; KLDRDYLDMOD_ASSERT(StackInfo.cbStack == g_cbkLdrDyldMainStack); } } if (!rc) g_fkLdrDyldDoneMainStack = 1; } if (!rc) { if (ppvStack) *ppvStack = g_pvkLdrDyldMainStack; if (pcbStack) *pcbStack = g_cbkLdrDyldMainStack; } return rc; } /** * This starts the executable module. * * @returns non-zero OS or kLdr status code on failure. * (won't return on success.) * @param pMod The executable module. */ int kldrDyldModStartExe(PKLDRDYLDMOD pMod) { int rc; KLDRADDR MainEPAddress; void *pvStack; KSIZE cbStack; KLDRDYLDMOD_ASSERT(pMod->fExecutable); rc = kLdrModQueryMainEntrypoint(pMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP, &MainEPAddress); if (rc) return rc; rc = kldrDyldModGetMainStack(pMod, &pvStack, &cbStack); if (rc) return rc; return kldrDyldOSStartExe((KUPTR)MainEPAddress, pvStack, cbStack); } /** * Gets the module name. * * @returns 0 on success, KERR_BUFFER_OVERFLOW on failure. * @param pMod The module. * @param pszName Where to store the name. * @param cchName The size of the name buffer. */ int kldrDyldModGetName(PKLDRDYLDMOD pMod, char *pszName, KSIZE cchName) { KSIZE cch = K_MIN(cchName, pMod->pMod->cchName + 1); if (cch) { kHlpMemCopy(pszName, pMod->pMod->pszName, cch - 1); pszName[cch - 1] = '\0'; } return cchName <= pMod->pMod->cchName ? KERR_BUFFER_OVERFLOW : 0; } /** * Gets the module filename. * * @returns 0 on success, KERR_BUFFER_OVERFLOW on failure. * @param pMod The module. * @param pszFilename Where to store the filename. * @param cchFilename The size of the filename buffer. */ int kldrDyldModGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, KSIZE cchFilename) { KSIZE cch = K_MIN(cchFilename, pMod->pMod->cchFilename + 1); if (cch) { kHlpMemCopy(pszFilename, pMod->pMod->pszFilename, cch - 1); pszFilename[cch - 1] = '\0'; } return cchFilename <= pMod->pMod->cchFilename ? KERR_BUFFER_OVERFLOW : 0; } /** * Gets the address/value of a symbol in the specified module. * * @returns 0 on success, KLDR_ERR_SYMBOL_NOT_FOUND on failure. * @param pMod The module. * @param uSymbolOrdinal The symbol ordinal 0. This is ignored if the name is non-zero. * @param pszSymbolName The symbol name. Can be NULL. * @param puValue Where to store the value. optional. * @param pfKind Where to store the symbol kind. optional. */ int kldrDyldModQuerySymbol(PKLDRDYLDMOD pMod, KU32 uSymbolOrdinal, const char *pszSymbolName, KUPTR *puValue, KU32 *pfKind) { int rc; KLDRADDR uValue = 0; KU32 fKind = 0; rc = kLdrModQuerySymbol(pMod->pMod, NULL, KLDRMOD_BASEADDRESS_MAP, uSymbolOrdinal, pszSymbolName, kHlpStrLen(pszSymbolName), NULL, kldrDyldModFixupGetImportCallback, pMod, &uValue, &fKind); if (!rc) { if (puValue) { *puValue = (KUPTR)uValue; KLDRDYLDMOD_ASSERT(*puValue == uValue); } if (pfKind) *pfKind = fKind; } return rc; } kbuild-3149/src/lib/kStuff/kLdr/tstkLdrHeap.c0000644000175000017500000001321113252530253020766 0ustar locutuslocutus/* $Id: tstkLdrHeap.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - Heap testcase. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #include /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ #define CHECK_FATAL(expr) \ do { if (!(expr)) { printf("tstkLdrHeap(%d): FATAL FAILURE - %s\n", __LINE__, #expr); return 1; } \ } while (0) #define CHECK(expr) \ do { if (!(expr)) { printf("tstkLdrHeap(%d): ERROR - %s\n", __LINE__, #expr); cErrors++; kHlpAssertBreakpoint();} \ } while (0) /** * Get a random size. * @returns random size. */ static unsigned RandSize(void) { unsigned i = (unsigned)rand() % (256*1024 - 1); return i ? i : 1; } /** * Get a random index. * @returns random index. * @param cEntries The number of entries in the table. */ static unsigned RandIdx(unsigned cEntries) { unsigned i = (unsigned)rand(); while (i >= cEntries) i >>= 1; return i; } #if 0 # define kHlpAlloc(a) malloc(a) # define kHlpFree(a) free(a) #endif int main() { int cErrors = 0; int rc; #define MAX_ALLOCS 256 static struct { void *pv; unsigned cb; } s_aAllocs[MAX_ALLOCS]; unsigned cAllocs; unsigned i; unsigned j; /* * Some simple init / term. */ rc = kHlpHeapInit(); CHECK_FATAL(!rc); kHlpHeapTerm(); rc = kHlpHeapInit(); CHECK_FATAL(!rc); kHlpHeapTerm(); /* * Simple alloc all, free all in FIFO order. */ rc = kHlpHeapInit(); CHECK_FATAL(!rc); /* 1. allocate all slots. */ for (i = 0; i < MAX_ALLOCS; i++) { s_aAllocs[i].cb = RandSize(); s_aAllocs[i].pv = kHlpAlloc(s_aAllocs[i].cb); CHECK(s_aAllocs[i].pv); } /* 2. free all slots. */ for (i = 0; i < MAX_ALLOCS; i++) kHlpFree(s_aAllocs[i].pv); /* terminate */ kHlpHeapTerm(); /* * Simple alloc all, free all in LIFO order. */ rc = kHlpHeapInit(); CHECK_FATAL(!rc); /* 1. allocate all slots. */ for (i = 0; i < MAX_ALLOCS; i++) { s_aAllocs[i].cb = RandSize(); s_aAllocs[i].pv = kHlpAlloc(s_aAllocs[i].cb); CHECK(s_aAllocs[i].pv); } /* 2. free all slots. */ i = MAX_ALLOCS; while (i-- > 0) kHlpFree(s_aAllocs[i].pv); /* terminate */ kHlpHeapTerm(); /* * Bunch of allocations, free half, allocate and free in pairs, free all. */ rc = kHlpHeapInit(); CHECK_FATAL(!rc); /* 1. allocate all slots. */ for (i = 0; i < MAX_ALLOCS; i++) { s_aAllocs[i].cb = RandSize(); s_aAllocs[i].pv = kHlpAlloc(s_aAllocs[i].cb); CHECK(s_aAllocs[i].pv); } cAllocs = MAX_ALLOCS; /* 2. free half (random order). */ while (cAllocs > MAX_ALLOCS / 2) { i = RandIdx(cAllocs); kHlpFree(s_aAllocs[i].pv); cAllocs--; if (i != cAllocs) s_aAllocs[i] = s_aAllocs[cAllocs]; } /* 3. lots of alloc and free activity. */ for (j = 0; j < MAX_ALLOCS * 32; j++) { /* allocate */ unsigned cMax = RandIdx(MAX_ALLOCS / 4) + 1; while (cAllocs < MAX_ALLOCS && cMax-- > 0) { i = cAllocs; s_aAllocs[i].cb = RandSize(); s_aAllocs[i].pv = kHlpAlloc(s_aAllocs[i].cb); CHECK(s_aAllocs[i].pv); cAllocs++; } /* free */ cMax = RandIdx(MAX_ALLOCS / 4) + 1; while (cAllocs > MAX_ALLOCS / 2 && cMax-- > 0) { i = RandIdx(cAllocs); kHlpFree(s_aAllocs[i].pv); cAllocs--; if (i != cAllocs) s_aAllocs[i] = s_aAllocs[cAllocs]; } } /* 4. free all */ while (cAllocs > 0) { i = RandIdx(cAllocs); kHlpFree(s_aAllocs[i].pv); cAllocs--; if (i != cAllocs) s_aAllocs[i] = s_aAllocs[cAllocs]; } /* terminate */ kHlpHeapTerm(); /* summary */ if (!cErrors) printf("tstkLdrHeap: SUCCESS\n"); else printf("tstkLdrHeap: FAILURE - %d errors\n", cErrors); return !!cErrors; } kbuild-3149/src/lib/kStuff/kLdr/kLdrDyld.c0000644000175000017500000013665713252530253020276 0ustar locutuslocutus/* $Id: kLdrDyld.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - The Dynamic Loader. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include "kLdrInternal.h" /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** @def KLDRDYLD_STRICT * Define KLDRDYLD_STRICT to enabled strict checks in kLdrDyld. */ #define KLDRDYLD_STRICT 1 /** @def KLDRDYLD_ASSERT * Assert that an expression is true when KLDRDYLD_STRICT is defined. */ #ifdef KLDRDYLD_STRICT # define KLDRDYLD_ASSERT(expr) kHlpAssert(expr) #else # define KLDRDYLD_ASSERT(expr) do {} while (0) #endif /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /******************************************************************************* * Global Variables * *******************************************************************************/ /** Pointer to the executable module. * (This is exported, so no prefix.) */ PKLDRDYLDMOD kLdrDyldExe = NULL; /** Pointer to the head module (the executable). * (This is exported, so no prefix.) */ PKLDRDYLDMOD kLdrDyldHead = NULL; /** Pointer to the tail module. * (This is exported, so no prefix.) */ PKLDRDYLDMOD kLdrDyldTail = NULL; /** Pointer to the head module of the initialization list. * The outermost load call will pop elements from this list in LIFO order (i.e. * from the tail). The list is only used during non-recursive initialization * and may therefore share the pNext/pPrev members with the termination list * since we don't push a module onto the termination list untill it has been * successfully initialized. */ PKLDRDYLDMOD g_pkLdrDyldInitHead; /** Pointer to the tail module of the initalization list.*/ PKLDRDYLDMOD g_pkLdrDyldInitTail; /** Pointer to the head module of the termination order list. * This is a LIFO just like the the init list. */ PKLDRDYLDMOD g_pkLdrDyldTermHead; /** Pointer to the tail module of the termination order list. */ PKLDRDYLDMOD g_pkLdrDyldTermTail; /** Pointer to the head module of the bind order list. * The modules in this list makes up the global namespace used when binding symbol unix fashion. */ PKLDRDYLDMOD g_pkLdrDyldBindHead; /** Pointer to the tail module of the bind order list. */ PKLDRDYLDMOD g_pkLdrDyldBindTail; /** Flag indicating bootstrap time. * When set the error behaviour changes. Any kind of serious failure * is fatal and will terminate the process. */ int g_fBootstrapping; /** The global error buffer. */ char g_szkLdrDyldError[1024]; /** The default flags. */ KU32 kLdrDyldFlags = 0; /** The default search method. */ KLDRDYLDSEARCH kLdrDyldSearch = KLDRDYLD_SEARCH_HOST; /** @name The main stack. * @{ */ /** Indicates that the other MainStack globals have been filled in. */ unsigned g_fkLdrDyldDoneMainStack = 0; /** Whether the stack was allocated seperatly or was part of the executable. */ unsigned g_fkLdrDyldMainStackAllocated = 0; /** Pointer to the main stack object. */ void *g_pvkLdrDyldMainStack = NULL; /** The size of the main stack object. */ KSIZE g_cbkLdrDyldMainStack = 0; /** @} */ /** The load stack. * This contains frames with modules affected by active loads. * * Each kLdrDyldLoad and kLdrDyldLoadExe call will create a new stack frame containing * all the modules involved in the operation. The modules will be ordered in recursive * init order within the frame. */ static PPKLDRDYLDMOD g_papStackMods; /** The number of used entries in the g_papStackMods array. */ static KU32 g_cStackMods; /** The number of entries allocated for the g_papStackMods array. */ static KU32 g_cStackModsAllocated; /** Number of active load calls. */ static KU32 g_cActiveLoadCalls; /** Number of active unload calls. */ static KU32 g_cActiveUnloadCalls; /** Total number of load calls. */ static KU32 g_cTotalLoadCalls; /** Total mumber of unload calls. */ static KU32 g_cTotalUnloadCalls; /** Boolean flag indicating that GC is active. */ static KU32 g_fActiveGC; /******************************************************************************* * Internal Functions * *******************************************************************************/ /** @name API worker routines. * @internal * @{ */ void kldrDyldDoLoadExeStackSwitch(PKLDRDYLDMOD pExe, void *pvStack, KSIZE cbStack); static int kldrDyldDoLoad(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRDYLDMOD ppMod, char *pszErr, KSIZE cchErr); static int kldrDyldDoLoad2(PKLDRDYLDMOD pLoadedMod, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags); static int kldrDyldDoLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags); static int kldrDyldDoUnload(PKLDRDYLDMOD pMod); static int kldrDyldDoFindByName(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRDYLDMOD ppMod); static int kldrDyldDoFindByAddress(KUPTR Address, PPKLDRDYLDMOD ppMod, KU32 *piSegment, KUPTR *poffSegment); static int kldrDyldDoGetName(PKLDRDYLDMOD pMod, char *pszName, KSIZE cchName); static int kldrDyldDoGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, KSIZE cchFilename); static int kldrDyldDoQuerySymbol(PKLDRDYLDMOD pMod, KU32 uSymbolOrdinal, const char *pszSymbolName, KUPTR *pValue, KU32 *pfKind); /** @} */ /** @name Misc load/unload workers * @internal * @{ */ static void kldrDyldDoModuleTerminationAndGarabageCollection(void); /** @} */ /** @name The load stack. * @internal * @{ */ static KU32 kldrDyldStackNewFrame(PKLDRDYLDMOD pMod); static int kldrDyldStackAddModule(PKLDRDYLDMOD pMod); static int kldrDyldStackFrameCompleted(void); static void kldrDyldStackCleanupOne(PKLDRDYLDMOD pMod, int rc); static void kldrDyldStackDropFrame(KU32 iLoad1st, KU32 iLoadEnd, int rc); /** @} */ static int kldrDyldCopyError(int rc, char *pszErr, KSIZE cchErr); /** * Initialize the dynamic loader. */ int kldrDyldInit(void) { kLdrDyldHead = kLdrDyldTail = NULL; g_pkLdrDyldTermHead = g_pkLdrDyldTermTail = NULL; g_pkLdrDyldBindHead = g_pkLdrDyldBindTail = NULL; kLdrDyldFlags = 0; g_szkLdrDyldError[0] = '\0'; g_fkLdrDyldDoneMainStack = 0; g_fkLdrDyldMainStackAllocated = 0; g_pvkLdrDyldMainStack = NULL; g_cbkLdrDyldMainStack = 0; return kldrDyldFindInit(); } /** * Terminate the dynamic loader. */ void kldrDyldTerm(void) { } /** * Bootstrap an executable. * * This is called from the executable stub to replace the stub and run the * executable specified in the argument package. * * Since this is boostrap time there isn't anything to return to. So, instead * the process will be terminated upon failure. * * We also have to keep in mind that this function is called on a small, small, * stack and therefore any kind of large stack objects or deep recursions must * be avoided. Since loading the executable will involve more or less all * operations in the loader, this restriction really applies everywhere. * * @param pArgs Pointer to the argument package residing in the executable stub. * @param pvOS OS specific argument. */ #ifndef __OS2__ /* kLdrDyldLoadExe is implemented in assembly on OS/2. */ void kLdrDyldLoadExe(PCKLDREXEARGS pArgs, void *pvOS) #else void kldrDyldLoadExe(PCKLDREXEARGS pArgs, void *pvOS) #endif { void *pvStack; KSIZE cbStack; PKLDRDYLDMOD pExe; int rc; /* * Indicate that we're boostrapping and ensure that initialization was successful. */ g_fBootstrapping = 1; rc = kldrInit(); if (rc) kldrDyldFailure(rc, "Init failure, rc=%d", rc); /* * Validate the argument package. */ if (pArgs->fFlags & ~( KLDRYDLD_LOAD_FLAGS_GLOBAL_SYMBOLS | KLDRYDLD_LOAD_FLAGS_DEEP_SYMBOLS | KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT | KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE)) kldrDyldFailure(KERR_INVALID_PARAMETER, "Bad fFlags=%#x", pArgs->fFlags); if ( pArgs->enmSearch <= KLDRDYLD_SEARCH_INVALID || pArgs->enmSearch >= KLDRDYLD_SEARCH_END) kldrDyldFailure(KERR_INVALID_PARAMETER, "Bad enmSearch=%d", pArgs->enmSearch); /* * Set defaults. */ kLdrDyldFlags |= (pArgs->fFlags & KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT); kLdrDyldSearch = pArgs->enmSearch; /** @todo make sense of this default prefix/suffix stuff. */ if (pArgs->szDefPrefix[0] != '\0') kHlpMemCopy(kLdrDyldDefPrefix, pArgs->szDefPrefix, K_MIN(sizeof(pArgs->szDefPrefix), sizeof(kLdrDyldDefPrefix))); if (pArgs->szDefSuffix[0] != '\0') kHlpMemCopy(kLdrDyldDefSuffix, pArgs->szDefSuffix, K_MIN(sizeof(pArgs->szDefSuffix), sizeof(kLdrDyldDefSuffix))); /** @todo append that path to the one for the specified search method. */ /** @todo create a function for doing this, an exposed api preferably. */ /* append path */ cbStack = sizeof(kLdrDyldLibraryPath) - kHlpStrLen(kLdrDyldLibraryPath); /* borrow cbStack for a itty bit. */ kHlpMemCopy(kLdrDyldLibraryPath, pArgs->szLibPath, K_MIN(sizeof(pArgs->szLibPath), cbStack)); kLdrDyldLibraryPath[sizeof(kLdrDyldLibraryPath) - 1] = '\0'; /* * Make sure we own the loader semaphore (necessary for init). */ rc = kLdrDyldSemRequest(); if (rc) kldrDyldFailure(rc, "Sem req. failure, rc=%d", rc); /* * Open and map the executable module before we join paths with kLdrDyldLoad(). */ rc = kldrDyldFindNewModule(pArgs->szExecutable, NULL, NULL, pArgs->enmSearch, pArgs->fFlags | KLDRDYLD_LOAD_FLAGS_EXECUTABLE, &pExe); if (rc) kldrDyldFailure(rc, "Can't find/open the executable '%s', rc=%d", pArgs->szExecutable, rc); rc = kldrDyldModMap(pExe); if (rc) kldrDyldFailure(rc, "Failed to map the executable '%s', rc=%d", pExe->pMod->pszFilename, rc); kLdrDyldExe = pExe; /* * Query the stack and go to OS specific code to * setup and switch stack. The OS specific code will call us * back at kldrDyldDoLoadExe. */ rc = kldrDyldModGetMainStack(pExe, &pvStack, &cbStack); if (rc) kldrDyldFailure(rc, "Failed to map the executable '%s', rc=%d", pExe->pMod->pszFilename, rc); kldrDyldDoLoadExeStackSwitch(pExe, pvStack, cbStack); kldrDyldFailure(-1, "Failed to setup the stack for '%s'.", pExe->pMod->pszFilename); } /** * Loads a module into the current process. * * @returns 0 on success, non-zero native OS status code or kLdr status code on failure. * @param pszDll The name of the dll to open. * @param pszPrefix Prefix to use when searching. * @param pszSuffix Suffix to use when searching. * @param enmSearch Method to use when locating the module and any modules it may depend on. * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines. * @param phMod Where to store the handle to the loaded module. * @param pszErr Where to store extended error information. (optional) * @param cchErr The size of the buffer pointed to by pszErr. */ int kLdrDyldLoad(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PHKLDRMOD phMod, char *pszErr, KSIZE cchErr) { int rc; /* validate arguments and initialize return values. */ if (pszErr && cchErr) *pszErr = '\0'; *phMod = NIL_HKLDRMOD; K_VALIDATE_STRING(pszDll); K_VALIDATE_OPTIONAL_STRING(pszPrefix); K_VALIDATE_OPTIONAL_STRING(pszSuffix); K_VALIDATE_ENUM(enmSearch, KLDRDYLD_SEARCH); K_VALIDATE_OPTIONAL_BUFFER(pszErr, cchErr); /* get the semaphore and do the job. */ rc = kLdrDyldSemRequest(); if (!rc) { PKLDRDYLDMOD pMod = NULL; g_cTotalLoadCalls++; g_cActiveLoadCalls++; rc = kldrDyldDoLoad(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod, pszErr, cchErr); g_cActiveLoadCalls--; kldrDyldDoModuleTerminationAndGarabageCollection(); kLdrDyldSemRelease(); *phMod = pMod ? pMod->hMod : NIL_HKLDRMOD; } return rc; } /** * Unloads a module loaded by kLdrDyldLoad. * * @returns 0 on success, non-zero native OS status code or kLdr status code on failure. * @param hMod Module handle. */ int kLdrDyldUnload(HKLDRMOD hMod) { int rc; /* validate */ KLDRDYLD_VALIDATE_HKLDRMOD(hMod); /* get sem & do work */ rc = kLdrDyldSemRequest(); if (!rc) { g_cTotalUnloadCalls++; g_cActiveUnloadCalls++; rc = kldrDyldDoUnload(hMod); g_cActiveUnloadCalls--; kldrDyldDoModuleTerminationAndGarabageCollection(); kLdrDyldSemRelease(); } return rc; } /** * Finds a module by name or filename. * * This call does not increase any reference counters and must not be * paired with kLdrDyldUnload() like kLdrDyldLoad(). * * @returns 0 on success. * @returns KLDR_ERR_MODULE_NOT_FOUND or some I/O error on failure. * @param pszDll The name of the dll to look for. * @param pszPrefix Prefix than can be used when searching. * @param pszSuffix Suffix than can be used when searching. * @param enmSearch Method to use when locating the module. * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines. * @param phMod Where to store the handle of the module on success. */ int kLdrDyldFindByName(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PHKLDRMOD phMod) { int rc; /* validate & initialize */ *phMod = NIL_HKLDRMOD; K_VALIDATE_STRING(pszDll); /* get sem & do work */ rc = kLdrDyldSemRequest(); if (!rc) { PKLDRDYLDMOD pMod = NULL; rc = kldrDyldDoFindByName(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod); kLdrDyldSemRelease(); *phMod = pMod ? pMod->hMod : NIL_HKLDRMOD; } return rc; } /** * Finds a module by address. * * This call does not increase any reference counters and must not be * paired with kLdrDyldUnload() like kLdrDyldLoad(). * * @returns 0 on success. * @returns KLDR_ERR_MODULE_NOT_FOUND on failure. * @param Address The address believed to be within some module. * @param phMod Where to store the module handle on success. * @param piSegment Where to store the segment number. (optional) * @param poffSegment Where to store the offset into the segment. (optional) */ int kLdrDyldFindByAddress(KUPTR Address, PHKLDRMOD phMod, KU32 *piSegment, KUPTR *poffSegment) { int rc; /* validate & initialize */ *phMod = NIL_HKLDRMOD; if (piSegment) *piSegment = ~(KU32)0; if (poffSegment) *poffSegment = ~(KUPTR)0; /* get sem & do work */ rc = kLdrDyldSemRequest(); if (!rc) { PKLDRDYLDMOD pMod = NULL; rc = kldrDyldDoFindByAddress(Address, &pMod, piSegment, poffSegment); kLdrDyldSemRelease(); *phMod = pMod ? pMod->hMod : NIL_HKLDRMOD; } return rc; } /** * Gets the module name. * * @returns 0 on success and pszName filled with the name. * @returns KERR_INVALID_HANDLE or KERR_BUFFER_OVERFLOW on failure. * @param hMod The module handle. * @param pszName Where to put the name. * @param cchName The size of the name buffer. * @see kLdrDyldGetFilename */ int kLdrDyldGetName(HKLDRMOD hMod, char *pszName, KSIZE cchName) { int rc; /* validate */ if (pszName && cchName) *pszName = '\0'; KLDRDYLD_VALIDATE_HKLDRMOD(hMod); K_VALIDATE_BUFFER(pszName, cchName); /* get sem & do work */ rc = kLdrDyldSemRequest(); if (!rc) { rc = kldrDyldDoGetName(hMod, pszName, cchName); kLdrDyldSemRelease(); } return rc; } /** * Gets the module filename. * * @returns 0 on success and pszFilename filled with the name. * @returns KERR_INVALID_HANDLE or KERR_BUFFER_OVERFLOW on failure. * @param hMod The module handle. * @param pszFilename Where to put the filename. * @param cchFilename The size of the filename buffer. * @see kLdrDyldGetName */ int kLdrDyldGetFilename(HKLDRMOD hMod, char *pszFilename, KSIZE cchFilename) { int rc; /* validate & initialize */ if (pszFilename && cchFilename); *pszFilename = '\0'; KLDRDYLD_VALIDATE_HKLDRMOD(hMod); K_VALIDATE_BUFFER(pszFilename, cchFilename); /* get sem & do work */ rc = kLdrDyldSemRequest(); if (!rc) { rc = kldrDyldDoGetFilename(hMod, pszFilename, cchFilename); kLdrDyldSemRelease(); } return rc; } /** * Queries the value and type of a symbol. * * @returns 0 on success and pValue and pfKind set. * @returns KERR_INVALID_HANDLE or KLDR_ERR_SYMBOL_NOT_FOUND on failure. * @param hMod The module handle. * @param uSymbolOrdinal The symbol ordinal. This is ignored if pszSymbolName is non-zero. * @param pszSymbolName The symbol name. * @param pszSymbolVersion The symbol version. Optional. * @param pValue Where to put the symbol value. Optional if pfKind is non-zero. * @param pfKind Where to put the symbol kind flags. Optional if pValue is non-zero. */ int kLdrDyldQuerySymbol(HKLDRMOD hMod, KU32 uSymbolOrdinal, const char *pszSymbolName, const char *pszSymbolVersion, KUPTR *pValue, KU32 *pfKind) { int rc; /* validate & initialize */ if (pfKind) *pfKind = 0; if (pValue) *pValue = 0; if (!pfKind && !pValue) return KERR_INVALID_PARAMETER; KLDRDYLD_VALIDATE_HKLDRMOD(hMod); K_VALIDATE_OPTIONAL_STRING(pszSymbolName); /* get sem & do work */ rc = kLdrDyldSemRequest(); if (!rc) { rc = kldrDyldDoQuerySymbol(hMod, uSymbolOrdinal, pszSymbolName, pValue, pfKind); kLdrDyldSemRelease(); } return rc; } /** * Worker kLdrDoLoadExe(). * Used after we've switch to the final process stack. * * @param pExe The executable module. * @internal */ void kldrDyldDoLoadExe(PKLDRDYLDMOD pExe) { int rc; /* * Load the executable module with its prerequisites and initialize them. */ g_cActiveLoadCalls++; rc = kldrDyldDoLoad2(pExe, NULL, NULL, kLdrDyldSearch, kLdrDyldFlags | KLDRDYLD_LOAD_FLAGS_EXECUTABLE); if (rc) kldrDyldFailure(rc, "load 2 failed for '%s', rc=%d", pExe->pMod->pszFilename); g_cActiveLoadCalls--; kldrDyldDoModuleTerminationAndGarabageCollection(); /* * Invoke the executable entry point. */ kldrDyldModStartExe(pExe); kldrDyldFailure(-1, "failed to invoke main!"); } /** * Worker for kLdrDyldLoad() and helper for kLdrDyldLoadExe(). * @internal */ static int kldrDyldDoLoad(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRDYLDMOD ppMod, char *pszErr, KSIZE cchErr) { int rc; /* * Try find the module among the ones that's already loaded. */ rc = kldrDyldFindExistingModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, ppMod); if (!rc) { switch ((*ppMod)->enmState) { /* * Prerequisites are ok, so nothing to do really. */ case KLDRSTATE_GOOD: case KLDRSTATE_INITIALIZING: return kldrDyldModDynamicLoad(*ppMod); /* * The module can't be loaded because it failed to initialize. */ case KLDRSTATE_INITIALIZATION_FAILED: return KLDR_ERR_MODULE_INIT_FAILED_ALREADY; /* * Prerequisites needs loading / reattaching and the module * (may depending on fFlags) needs to be initialized. */ case KLDRSTATE_PENDING_INITIALIZATION: break; /* * Prerequisites needs to be loaded again */ case KLDRSTATE_PENDING_TERMINATION: break; /* * The module has been terminated so it need to be reloaded, have it's * prereqs loaded, fixed up and initialized before we can use it again. */ case KLDRSTATE_PENDING_GC: rc = kldrDyldModReload(*ppMod); if (rc) return kldrDyldCopyError(rc, pszErr, cchErr); break; /* * Forget it, we don't know how to deal with re-initialization here. */ case KLDRSTATE_TERMINATING: KLDRDYLD_ASSERT(!"KLDR_ERR_MODULE_TERMINATING"); return KLDR_ERR_MODULE_TERMINATING; /* * Invalid state. */ default: KLDRDYLD_ASSERT(!"invalid state"); break; } } else { /* * We'll have to load it from file. */ rc = kldrDyldFindNewModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, ppMod); if (rc) return kldrDyldCopyError(rc, pszErr, cchErr); rc = kldrDyldModMap(*ppMod); } /* * Join cause with kLdrDyldLoadExe. */ if (!rc) rc = kldrDyldDoLoad2(*ppMod, pszPrefix, pszSuffix, enmSearch, fFlags); else kldrDyldStackCleanupOne(*ppMod, rc); /* * Copy any error or warning to the error buffer. */ return kldrDyldCopyError(rc, pszErr, cchErr); } /** * 2nd half of kLdrDyldLoad() and kLdrDyldLoadExe(). * * @internal */ static int kldrDyldDoLoad2(PKLDRDYLDMOD pLoadedMod, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags) { /* * Load prerequisites. */ KU32 i; KU32 iLoad1st = kldrDyldStackNewFrame(pLoadedMod); int rc = kldrDyldDoLoadPrerequisites(pLoadedMod, pszPrefix, pszSuffix, enmSearch, fFlags); KU32 iLoadEnd = kldrDyldStackFrameCompleted(); if (rc) { kldrDyldModAddRef(pLoadedMod); kldrDyldStackCleanupOne(pLoadedMod, rc); /* in case it didn't get pushed onto the stack. */ kldrDyldModDeref(pLoadedMod); } /* * Apply fixups. */ for (i = iLoad1st; !rc && i < iLoadEnd; i++) { PKLDRDYLDMOD pMod = g_papStackMods[i]; if ( pMod->enmState == KLDRSTATE_LOADED_PREREQUISITES || pMod->enmState == KLDRSTATE_RELOADED_LOADED_PREREQUISITES) rc = kldrDyldModFixup(pMod); } /* * Advance fixed up module onto initialization. */ for (i = iLoad1st; !rc && i < iLoadEnd; i++) { PKLDRDYLDMOD pMod = g_papStackMods[i]; if ( pMod->enmState == KLDRSTATE_FIXED_UP || pMod->enmState == KLDRSTATE_RELOADED_FIXED_UP) pMod->enmState = KLDRSTATE_PENDING_INITIALIZATION; KLDRDYLD_ASSERT( pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION || pMod->enmState == KLDRSTATE_GOOD); } /* * Call the initializers if we're loading in recursive mode or * if we're the outermost load call. */ if (fFlags & KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT) { for (i = iLoad1st; !rc && i < iLoadEnd; i++) { PKLDRDYLDMOD pMod = g_papStackMods[i]; if (pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION) rc = kldrDyldModCallInit(pMod); else if (pMod->enmState == KLDRSTATE_INITIALIZATION_FAILED) rc = KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED_ALREADY; else KLDRDYLD_ASSERT(g_papStackMods[i]->enmState == KLDRSTATE_GOOD); } #ifdef KLDRDYLD_STRICT for (i = iLoad1st; !rc && i < iLoadEnd; i++) KLDRDYLD_ASSERT(g_papStackMods[i]->enmState == KLDRSTATE_GOOD); #endif } else if (g_cActiveLoadCalls <= 1) { while (!rc && g_pkLdrDyldInitHead) { PKLDRDYLDMOD pMod = g_pkLdrDyldInitHead; g_pkLdrDyldInitHead = pMod->InitTerm.pNext; if (pMod->InitTerm.pNext) pMod->InitTerm.pNext->InitTerm.pPrev = NULL; else g_pkLdrDyldInitTail = NULL; pMod->fInitList = 0; rc = kldrDyldModCallInit(pMod); } } /* * Complete the load by incrementing the dynamic load count of the * requested module (return handle is already set). */ if (!rc) { if (fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE) { pLoadedMod->cDepRefs++; /* just make it stick. */ pLoadedMod->cRefs++; } else rc = kldrDyldModDynamicLoad(pLoadedMod); } kldrDyldStackDropFrame(iLoad1st, iLoadEnd, rc); return rc; } /** * kldrDyldDoLoad() helper which will load prerequisites and * build the initialization array / list. * * @returns 0 on success, non-zero error code on failure. * @param pMod The module to start at. * @param pszPrefix Prefix to use when searching. * @param pszSuffix Suffix to use when searching. * @param enmSearch Method to use when locating the module and any modules it may depend on. * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines. */ static int kldrDyldDoLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags) { static struct { /** The module. */ PKLDRDYLDMOD pMod; /** The number of prerequisite modules left to process. * This starts at ~0U to inidicate that we need to load/check prerequisistes. */ unsigned cLeft; } s_aEntries[64]; unsigned cEntries; int rc = 0; /* Prerequisites are always global and they just aren't executables. */ fFlags &= ~(KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE | KLDRDYLD_LOAD_FLAGS_EXECUTABLE); /* push the first entry. */ s_aEntries[0].pMod = pMod; s_aEntries[0].cLeft = ~0U; cEntries = 1; /* * The recursion loop. */ while (!rc && cEntries > 0) { const unsigned i = cEntries - 1; pMod = s_aEntries[i].pMod; if (s_aEntries[i].cLeft == ~0U) { /* * Load prerequisite modules. */ switch (pMod->enmState) { /* * Load immediate prerequisite modules and push the ones needing * attention onto the stack. */ case KLDRSTATE_MAPPED: case KLDRSTATE_RELOADED: case KLDRSTATE_PENDING_TERMINATION: rc = kldrDyldModLoadPrerequisites(pMod, pszPrefix, pszSuffix, enmSearch, fFlags); KLDRDYLD_ASSERT( pMod->enmState == KLDRSTATE_GOOD || pMod->enmState == KLDRSTATE_RELOADED_LOADED_PREREQUISITES || pMod->enmState == KLDRSTATE_LOADED_PREREQUISITES || rc); if (!rc) s_aEntries[i].cLeft = pMod->cPrereqs; break; /* * Check its prerequisite modules the first time around. */ case KLDRSTATE_PENDING_INITIALIZATION: if (pMod->fAlreadySeen) break; pMod->fAlreadySeen = 1; s_aEntries[i].cLeft = pMod->cPrereqs; break; /* * These are ok. */ case KLDRSTATE_LOADED_PREREQUISITES: case KLDRSTATE_RELOADED_LOADED_PREREQUISITES: case KLDRSTATE_INITIALIZING: case KLDRSTATE_GOOD: s_aEntries[i].cLeft = 0; break; /* * All other stats are invalid. */ default: KLDRDYLD_ASSERT(!"invalid state"); break; } } else if (s_aEntries[i].cLeft > 0) { /* * Recurse down into the next prereq. */ KLDRDYLD_ASSERT(s_aEntries[i].cLeft <= pMod->cPrereqs); if (cEntries < sizeof(s_aEntries) / sizeof(s_aEntries[0])) { s_aEntries[cEntries].cLeft = ~(KU32)0; s_aEntries[cEntries].pMod = pMod->papPrereqs[pMod->cPrereqs - s_aEntries[i].cLeft]; s_aEntries[i].cLeft--; cEntries++; } else rc = KLDR_ERR_PREREQUISITE_RECURSED_TOO_DEEPLY; } else { /* * We're done with this module, record it for init/cleanup. */ cEntries--; if (pMod->enmState != KLDRSTATE_GOOD) { kldrDyldStackAddModule(pMod); if ( !(fFlags & KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT) && !pMod->fInitList) { pMod->fInitList = 1; pMod->InitTerm.pNext = NULL; pMod->InitTerm.pPrev = g_pkLdrDyldInitTail; if (g_pkLdrDyldInitTail) g_pkLdrDyldInitTail->InitTerm.pNext = pMod; else g_pkLdrDyldInitHead = pMod; g_pkLdrDyldInitTail = pMod; } } } } return rc; } /** * Gets prerequisite module. * * This will try load the requested module if necessary, returning it in the MAPPED state. * * @returns 0 on success. * @returns KLDR_ERR_MODULE_NOT_FOUND or I/O error on failure. * @param pszDll The name of the dll to look for. * @param pszPrefix Prefix than can be used when searching. * @param pszSuffix Suffix than can be used when searching. * @param enmSearch Method to use when locating the module. * @param fFlags Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines. * @param pDep The depentant module. * @param ppMod Where to put the module we get. */ int kldrDyldGetPrerequisite(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PKLDRDYLDMOD pDep, PPKLDRDYLDMOD ppMod) { int rc; PKLDRDYLDMOD pMod; *ppMod = NULL; /* * Try find the module among the ones that's already loaded. * * This is very similar to the kldrDyldDoLoad code, except it has to deal with * a couple of additional states and occurs only during prerequisite loading * and the action taken is a little bit different. */ rc = kldrDyldFindExistingModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod); if (!rc) { switch (pMod->enmState) { /* * These are good. */ case KLDRSTATE_MAPPED: case KLDRSTATE_RELOADED: case KLDRSTATE_LOADED_PREREQUISITES: case KLDRSTATE_RELOADED_LOADED_PREREQUISITES: case KLDRSTATE_PENDING_INITIALIZATION: case KLDRSTATE_INITIALIZING: case KLDRSTATE_GOOD: case KLDRSTATE_PENDING_TERMINATION: break; /* * The module has been terminated so it need to be reloaded, have it's * prereqs loaded, fixed up and initialized before we can use it again. */ case KLDRSTATE_PENDING_GC: rc = kldrDyldModReload(pMod); break; /* * The module can't be loaded because it failed to initialize already. */ case KLDRSTATE_INITIALIZATION_FAILED: rc = KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED; break; /* * Forget it, no idea how to deal with re-initialization. */ case KLDRSTATE_TERMINATING: return KLDR_ERR_PREREQUISITE_MODULE_TERMINATING; /* * Invalid state. */ default: KLDRDYLD_ASSERT(!"invalid state"); break; } } else { /* * We'll have to load it from file. */ rc = kldrDyldFindNewModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, &pMod); if (!rc) rc = kldrDyldModMap(pMod); } /* * On success add dependency. */ if (!rc) { kldrDyldModAddDep(pMod, pDep); *ppMod = pMod; } return rc; } /** * Starts a new load stack frame. * * @returns Where the new stack frame starts. * @param pLoadMod The module being loaded (only used for asserting). */ static KU32 kldrDyldStackNewFrame(PKLDRDYLDMOD pLoadMod) { /* * Clear the fAlreadySeen flags. */ PKLDRDYLDMOD pMod = kLdrDyldHead; while (pMod) { pMod->fAlreadySeen = 0; #ifdef KLDRDYLD_ASSERT switch (pMod->enmState) { case KLDRSTATE_MAPPED: case KLDRSTATE_RELOADED: /* only the just loaded module can be in this state. */ KLDRDYLD_ASSERT(pMod == pLoadMod); break; case KLDRSTATE_PENDING_INITIALIZATION: case KLDRSTATE_INITIALIZING: case KLDRSTATE_PENDING_TERMINATION: case KLDRSTATE_PENDING_GC: case KLDRSTATE_TERMINATING: case KLDRSTATE_INITIALIZATION_FAILED: case KLDRSTATE_PENDING_DESTROY: /* requires recursion. */ KLDRDYLD_ASSERT(g_cActiveLoadCalls + g_cActiveLoadCalls + g_fActiveGC > 1); break; case KLDRSTATE_GOOD: /* requires nothing. */ break; default: KLDRDYLD_ASSERT(!"Invalid state"); break; } #endif /* next */ pMod = pMod->Load.pNext; } return g_cStackMods; } /** * Records the module. * * @return 0 on success, KERR_NO_MEMORY if we can't expand the table. * @param pMod The module to record. */ static int kldrDyldStackAddModule(PKLDRDYLDMOD pMod) { /* * Grow the stack if necessary. */ if (g_cStackMods + 1 > g_cStackModsAllocated) { KU32 cNew = g_cStackModsAllocated ? g_cStackModsAllocated * 2 : 128; void *pvOld = g_papStackMods; void *pvNew = kHlpAlloc(cNew * sizeof(g_papStackMods[0])); if (!pvNew) return KERR_NO_MEMORY; kHlpMemCopy(pvNew, pvOld, g_cStackMods * sizeof(g_papStackMods[0])); g_papStackMods = (PPKLDRDYLDMOD)pvNew; kHlpFree(pvOld); } /* * Add a reference and push the module onto the stack. */ kldrDyldModAddRef(pMod); g_papStackMods[g_cStackMods++] = pMod; return 0; } /** * The frame has been completed. * * @returns Where the frame ends. */ static int kldrDyldStackFrameCompleted(void) { return g_cStackMods; } /** * Worker routine for kldrDyldStackDropFrame() and kldrDyldDoLoad(). * * @param pMod The module to perform cleanups on. * @param rc Used for state verification. */ static void kldrDyldStackCleanupOne(PKLDRDYLDMOD pMod, int rc) { switch (pMod->enmState) { /* * Just push it along to the PENDING_DESTROY state. */ case KLDRSTATE_MAPPED: KLDRDYLD_ASSERT(rc); kldrDyldModUnmap(pMod); KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY); break; /* * Move back to PENDING_GC. */ case KLDRSTATE_RELOADED: KLDRDYLD_ASSERT(rc); pMod->enmState = KLDRSTATE_PENDING_GC; break; /* * Unload prerequisites and unmap the modules. */ case KLDRSTATE_LOADED_PREREQUISITES: case KLDRSTATE_FIXED_UP: KLDRDYLD_ASSERT(rc); kldrDyldModUnloadPrerequisites(pMod); KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY); kldrDyldModUnmap(pMod); KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY); break; /* * Unload prerequisites and push it back to PENDING_GC. */ case KLDRSTATE_RELOADED_LOADED_PREREQUISITES: case KLDRSTATE_RELOADED_FIXED_UP: kldrDyldModUnloadPrerequisites(pMod); KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_GC); break; /* * Nothing to do, just asserting sanity. */ case KLDRSTATE_INITIALIZING: /* Implies there is another load going on. */ KLDRDYLD_ASSERT(g_cActiveLoadCalls > 1); break; case KLDRSTATE_TERMINATING: /* GC in progress. */ KLDRDYLD_ASSERT(g_fActiveGC); break; case KLDRSTATE_PENDING_TERMINATION: case KLDRSTATE_PENDING_INITIALIZATION: case KLDRSTATE_PENDING_GC: case KLDRSTATE_PENDING_DESTROY: KLDRDYLD_ASSERT(rc); break; case KLDRSTATE_GOOD: break; /* * Bad states. */ default: KLDRDYLD_ASSERT(!"drop frame bad state (a)"); break; } } /** * Done with the stack frame, dereference all the modules in it. * * @param iLoad1st The start of the stack frame. * @param iLoadEnd The end of the stack frame. * @param rc Used for state verification. */ static void kldrDyldStackDropFrame(KU32 iLoad1st, KU32 iLoadEnd, int rc) { KU32 i; KLDRDYLD_ASSERT(iLoad1st <= g_cStackMods); KLDRDYLD_ASSERT(iLoadEnd == g_cStackMods); /* * First pass: Do all the cleanups we can, but don't destroy anything just yet. */ i = iLoadEnd; while (i-- > iLoad1st) { PKLDRDYLDMOD pMod = g_papStackMods[i]; kldrDyldStackCleanupOne(pMod, rc); } /* * Second pass: Release the references so modules pending destruction * can be completely removed. */ for (i = iLoad1st; i < iLoadEnd ; i++) { PKLDRDYLDMOD pMod = g_papStackMods[i]; /* * Revalidate the module state. */ switch (pMod->enmState) { case KLDRSTATE_INITIALIZING: case KLDRSTATE_TERMINATING: case KLDRSTATE_PENDING_TERMINATION: case KLDRSTATE_PENDING_INITIALIZATION: case KLDRSTATE_PENDING_GC: case KLDRSTATE_PENDING_DESTROY: case KLDRSTATE_GOOD: break; default: KLDRDYLD_ASSERT(!"drop frame bad state (b)"); break; } /* * Release it. */ kldrDyldModDeref(pMod); } /* * Drop the stack frame. */ g_cStackMods = iLoad1st; } /** * Do garbage collection. * * This isn't doing anything unless it's called from the last * load or unload call. */ static void kldrDyldDoModuleTerminationAndGarabageCollection(void) { PKLDRDYLDMOD pMod; /* * We don't do anything until we're got rid of all recursive calls. * This will ensure that we get the most optimal termination order and * that we don't unload anything too early. */ if (g_cActiveLoadCalls || g_cActiveUnloadCalls || g_fActiveGC) return; g_fActiveGC = 1; do { /* * 1. Release prerequisites for any left over modules. */ for (pMod = kLdrDyldHead; pMod; pMod = pMod->Load.pNext) { kldrDyldModAddRef(pMod); switch (pMod->enmState) { case KLDRSTATE_GOOD: case KLDRSTATE_PENDING_GC: case KLDRSTATE_PENDING_TERMINATION: break; case KLDRSTATE_INITIALIZATION_FAILED: /* just in case */ case KLDRSTATE_PENDING_INITIALIZATION: kldrDyldModUnloadPrerequisites(pMod); break; default: KLDRDYLD_ASSERT(!"invalid GC state (a)"); break; } kldrDyldModDeref(pMod); } /* * 2. Do init calls until we encounter somebody calling load/unload. */ for (pMod = g_pkLdrDyldTermHead; pMod; pMod = pMod->InitTerm.pNext) { int fRestart = 0; kldrDyldModAddRef(pMod); switch (pMod->enmState) { case KLDRSTATE_GOOD: case KLDRSTATE_PENDING_GC: break; case KLDRSTATE_PENDING_TERMINATION: { const KU32 cTotalLoadCalls = g_cTotalLoadCalls; const KU32 cTotalUnloadCalls = g_cTotalUnloadCalls; kldrDyldModCallTerm(pMod); fRestart = cTotalLoadCalls != g_cTotalLoadCalls || cTotalUnloadCalls != g_cTotalUnloadCalls; break; } default: KLDRDYLD_ASSERT(!"invalid GC state (b)"); break; } kldrDyldModDeref(pMod); if (fRestart) break; } } while (pMod); /* * Unmap and destroy modules pending for GC. */ pMod = kLdrDyldHead; while (pMod) { PKLDRDYLDMOD pNext = pMod->Load.pNext; kldrDyldModAddRef(pMod); switch (pMod->enmState) { case KLDRSTATE_INITIALIZATION_FAILED: case KLDRSTATE_PENDING_GC: KLDRDYLD_ASSERT(!pMod->cDepRefs); KLDRDYLD_ASSERT(!pMod->cDynRefs); pMod->enmState = KLDRSTATE_GC; kldrDyldModUnmap(pMod); KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY); kldrDyldModDestroy(pMod); KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_DESTROYED); break; case KLDRSTATE_GOOD: break; default: KLDRDYLD_ASSERT(!"invalid GC state (c)"); break; } kldrDyldModDeref(pMod); /* next */ pMod = pNext; } g_fActiveGC = 0; } /** * Worker for kLdrDyldUnload(). * @internal */ static int kldrDyldDoUnload(PKLDRDYLDMOD pMod) { return kldrDyldModDynamicUnload(pMod); } /** * Worker for kLdrDyldFindByName(). * @internal */ static int kldrDyldDoFindByName(const char *pszDll, const char *pszPrefix, const char *pszSuffix, KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRDYLDMOD ppMod) { return kldrDyldFindExistingModule(pszDll, pszPrefix, pszSuffix, enmSearch, fFlags, ppMod); } /** * Worker for kLdrDyldFindByAddress(). * @internal */ static int kldrDyldDoFindByAddress(KUPTR Address, PPKLDRDYLDMOD ppMod, KU32 *piSegment, KUPTR *poffSegment) { /* Scan the segments of each module in the load list. */ PKLDRDYLDMOD pMod = kLdrDyldHead; while (pMod) { KU32 iSeg; for (iSeg = 0; iSeg < pMod->pMod->cSegments; iSeg++) { KLDRADDR off = (KLDRADDR)Address - pMod->pMod->aSegments[iSeg].MapAddress; if (off < pMod->pMod->aSegments[iSeg].cb) { *ppMod = pMod->hMod; if (piSegment) *piSegment = iSeg; if (poffSegment) *poffSegment = (KUPTR)off; return 0; } } /* next */ pMod = pMod->Load.pNext; } return KLDR_ERR_MODULE_NOT_FOUND; } /** * Worker for kLdrDyldGetName(). * @internal */ static int kldrDyldDoGetName(PKLDRDYLDMOD pMod, char *pszName, KSIZE cchName) { return kldrDyldModGetName(pMod, pszName, cchName); } /** * Worker for kLdrDyldGetFilename(). * @internal */ static int kldrDyldDoGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, KSIZE cchFilename) { return kldrDyldModGetFilename(pMod, pszFilename, cchFilename); } /** * Worker for kLdrDyldQuerySymbol(). * @internal */ static int kldrDyldDoQuerySymbol(PKLDRDYLDMOD pMod, KU32 uSymbolOrdinal, const char *pszSymbolName, KUPTR *pValue, KU32 *pfKind) { return kldrDyldModQuerySymbol(pMod, uSymbolOrdinal, pszSymbolName, pValue, pfKind); } /** * Panic / failure * * @returns rc if we're in a position where we can return. * @param rc Return code. * @param pszFormat Message string. Limited fprintf like formatted. * @param ... Message string arguments. */ int kldrDyldFailure(int rc, const char *pszFilename, ...) { /** @todo print it. */ if (g_fBootstrapping); kHlpExit(1); return rc; } /** * Copies the error string to the user buffer. * * @returns rc. * @param rc The status code. * @param pszErr Where to copy the error string to. * @param cchErr The size of the destination buffer. */ static int kldrDyldCopyError(int rc, char *pszErr, KSIZE cchErr) { KSIZE cchToCopy; /* if no error string, format the rc into a string. */ if (!g_szkLdrDyldError[0] && rc) kHlpInt2Ascii(g_szkLdrDyldError, sizeof(g_szkLdrDyldError), rc, 10); /* copy it if we got something. */ if (cchErr && pszErr && g_szkLdrDyldError[0]) { cchToCopy = kHlpStrLen(g_szkLdrDyldError); if (cchToCopy >= cchErr) cchToCopy = cchErr - 1; kHlpMemCopy(pszErr, g_szkLdrDyldError, cchToCopy); pszErr[cchToCopy] = '\0'; } return rc; } kbuild-3149/src/lib/kStuff/kLdr/kLdrExeStub-os2.c0000644000175000017500000000435413252530254021447 0ustar locutuslocutus/* $Id: kLdrExeStub-os2.c 29 2009-07-01 20:30:29Z bird $ */ /** @file * kLdr - OS/2 C Loader Stub. */ /* * Copyright (c) 2006-2007 Knut St. Osmundsen * * 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. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include /******************************************************************************* * Global Variables * *******************************************************************************/ /** The stub arguments. */ static const KLDREXEARGS g_Args = { /* .fFlags = */ KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT, /* .enmSearch = */ KLDRDYLD_SEARCH_OS2, /* .szExecutable = */ "tst-0", /* just while testing */ /* .szDefPrefix = */ "", /* .szDefSuffix = */ ".dll", /* .szLibPath = */ "" }; /** * OS/2 'main'. */ int _System OS2Main(HMODULE hmod, ULONG ulReserved, PCH pszzEnv, PCH pszzCmdLine) { return kLdrDyldLoadExe(&g_Args, &hmod); } kbuild-3149/src/lib/test-eintr-bug-2.c0000644000175000017500000000722513252530204017417 0ustar locutuslocutus /******************************************************************************* * Header Files * *******************************************************************************/ #define _BSD_SOURCE #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include /******************************************************************************* * Global Variables * *******************************************************************************/ /** The number of signals. */ static volatile long g_cSigs = 0; /** Number of signals received on threads other than the main one. */ static volatile long g_cSigsOther = 0; /** Whether to shutdown or not. */ static volatile int g_fShutdown = 0; /** The handle of the main thread. */ static pthread_t g_hMainThread; static void SigHandler(int iSig) { g_cSigs++; if (pthread_self() != g_hMainThread) g_cSigsOther++; (void)iSig; } static void NanoSleep(unsigned long cNanoSecs) { struct timespec Ts; Ts.tv_sec = 0; Ts.tv_nsec = cNanoSecs; nanosleep(&Ts, NULL); } static void *ThreadProc(void *pvIgnored) { int volatile i = 0; while (!g_fShutdown) { // NanoSleep(850); if (g_fShutdown) break; pthread_kill(g_hMainThread, SIGALRM); for (i = 6666; i > 0; i--) /* nothing */; } return NULL; } int main(int argc, char **argv) { void (*rcSig)(int); pthread_t hThread; char szName[1024]; int i; int rc; /* * Set up the signal handlers. */ rcSig = bsd_signal(SIGALRM, SigHandler); if (rcSig != SIG_ERR) rcSig = bsd_signal(SIGCHLD, SigHandler); if (rcSig == SIG_ERR) { fprintf(stderr, "bsd_signal failed: %s\n", strerror(errno)); return 1; } if (argc == 2) /* testing... */ { siginterrupt(SIGALRM, 1); siginterrupt(SIGCHLD, 1); } /* * Kick off a thread that will signal us like there was no tomorrow. */ g_hMainThread = pthread_self(); rc = pthread_create(&hThread, NULL, ThreadProc, NULL); if (rc != 0) { fprintf(stderr, "pthread_create failed: %s\n", strerror(rc)); return 1; } /* * Do path related stuff. */ snprintf(szName, sizeof(szName), "%s-test2", argv[0]); for (i = 0; i < 100*1000*1000; i++) { struct stat St; int fd; rc = stat(argv[0], &St); if (rc == 0 || errno != EINTR) rc = stat(szName, &St); if (errno == EINTR && rc != 0) { printf("iteration %d: stat: %u\n", i, errno); break; } fd = open(szName, O_CREAT | O_RDWR, 0666); if (errno == EINTR && fd < 0) { printf("iteration %d: open: %u\n", i, errno); break; } close(fd); rc = unlink(szName); if (errno == EINTR && rc != 0) { printf("iteration %d: unlink: %u\n", i, errno); break; } /* Show progress info */ if ((i % 100000) == 0) { printf("."); if ((i % 1000000) == 0) printf("[%d/%ld/%ld]\n", i, g_cSigs, g_cSigsOther); fflush(stdout); } } g_fShutdown = 1; if (rc) printf("No EINTR in %d iterations - system is working nicely!\n", i); NanoSleep(10000000); return rc ? 1 : 0; } kbuild-3149/src/lib/test-eintr-bug-1.c0000644000175000017500000000436613252530204017421 0ustar locutuslocutus /******************************************************************************* * Header Files * *******************************************************************************/ //#define _XOPEN_SOURCE //#define _BSD_SOURCE #include #include #include #include #include #include volatile unsigned long g_cInts = 0; static void SigAlaramHandler(int iSig) { g_cInts++; (void)iSig; } int main(int argc, char **argv) { struct itimerval TmrVal; void (*rcSig)(int); int i; int rc; char szName[256]; /* * Set up the timer signal. */ rcSig = bsd_signal(SIGALRM, SigAlaramHandler); if (rcSig == SIG_ERR) { fprintf(stderr, "bsd_signal failed: %s\n", strerror(errno)); return 1; } if (argc == 2) /* testing... */ siginterrupt(SIGALRM, 1); memset(&TmrVal, '\0', sizeof(TmrVal)); TmrVal.it_interval.tv_sec = TmrVal.it_value.tv_sec = 0; TmrVal.it_interval.tv_usec = TmrVal.it_value.tv_usec = 1; rc = setitimer(ITIMER_REAL, &TmrVal, NULL); if (rc != 0) { fprintf(stderr, "setitimer failed: %s\n", strerror(errno)); return 1; } printf("interval %d.%06d\n", (int)TmrVal.it_interval.tv_sec, (int)TmrVal.it_interval.tv_usec); /* * Do path related stuff. */ snprintf(szName, sizeof(szName), "%s/fooled/you", argv[0]); for (i = 0; i < 100*1000*1000; i++) { struct stat St; rc = stat(argv[0], &St); if (rc == 0) rc = stat(szName, &St); if (rc != 0 && errno == EINTR) { printf("iteration %d: stat: %s (%u)\n", i, strerror(errno), errno); break; } if ((i % 100000) == 0) { printf("."); if ((i % 1000000) == 0) printf("[%u/%lu]", i, g_cInts); fflush(stdout); } } if (!rc) printf("No EINTR in %d iterations - system is working nicely!\n", i); TmrVal.it_interval.tv_sec = TmrVal.it_value.tv_sec = 0; TmrVal.it_interval.tv_usec = TmrVal.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &TmrVal, NULL); return rc ? 1 : 0; } kbuild-3149/src/lib/quoted_spawn.h0000644000175000017500000000313513252530204017121 0ustar locutuslocutus/* $Id: quoted_spawn.h 2851 2016-08-31 17:30:52Z bird $ */ /** @file * quote_spawn - Correctly Quote The _spawnvp arguments, windows specific. */ /* * Copyright (c) 2010-2016 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___quoted_spawn_h___ #define ___quoted_spawn_h___ #include "mytypes.h" intptr_t quoted_spawnvp(int fMode, const char *pszExecPath, const char * const *papszArgs); #endif kbuild-3149/src/lib/msc_buffered_printf.c0000644000175000017500000001763313252530204020421 0ustar locutuslocutus/* $Id: msc_buffered_printf.c 2967 2016-09-26 18:14:13Z bird $ */ /** @file * printf, vprintf, fprintf, puts, fputs console optimizations for Windows/MSC. */ /* * Copyright (c) 2016 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ #include #include #include #include #include #include #undef printf #undef vprintf #undef fprintf #undef puts #undef fputs #pragma warning(disable: 4273) /* inconsistent dll linkage*/ #ifndef KWORKER # define DLL_IMPORT __declspec(dllexport) #else # define DLL_IMPORT #endif extern size_t maybe_con_fwrite(void const *pvBuf, size_t cbUnit, size_t cUnits, FILE *pFile); /** * Replaces printf for MSC to speed up console output. * * @returns chars written on success, -1 and errno on failure. * @param pszFormat The format string. * @param ... Format arguments. */ DLL_IMPORT int __cdecl printf(const char *pszFormat, ...) { int cchRet; va_list va; va_start(va, pszFormat); cchRet = vprintf(pszFormat, va); va_end(va); return cchRet; } /** * Replaces vprintf for MSC to speed up console output. * * @returns chars written on success, -1 and errno on failure. * @param pszFormat The format string. * @param va Format arguments. */ DLL_IMPORT int __cdecl vprintf(const char *pszFormat, va_list va) { /* * If it's a TTY, try format into a stack buffer and output using our * console optimized fwrite wrapper. */ if (*pszFormat != '\0') { int fd = fileno(stdout); if (fd >= 0) { if (isatty(fd)) { char *pszTmp = (char *)alloca(16384); va_list va2 = va; int cchRet = vsnprintf(pszTmp, 16384, pszFormat, va2); if (cchRet < 16384 - 1) return (int)maybe_con_fwrite(pszTmp, cchRet, 1, stdout); } } } /* * Fallback. */ return vfprintf(stdout, pszFormat, va); } /** * Replaces fprintf for MSC to speed up console output. * * @returns chars written on success, -1 and errno on failure. * @param pFile The output file/stream. * @param pszFormat The format string. * @param va Format arguments. */ DLL_IMPORT int __cdecl fprintf(FILE *pFile, const char *pszFormat, ...) { va_list va; int cchRet; /* * If it's a TTY, try format into a stack buffer and output using our * console optimized fwrite wrapper. */ if (*pszFormat != '\0') { int fd = fileno(pFile); if (fd >= 0) { if (isatty(fd)) { char *pszTmp = (char *)alloca(16384); if (pszTmp) { va_start(va, pszFormat); cchRet = vsnprintf(pszTmp, 16384, pszFormat, va); va_end(va); if (cchRet < 16384 - 1) return (int)maybe_con_fwrite(pszTmp, cchRet, 1, pFile); } } } } /* * Fallback. */ va_start(va, pszFormat); cchRet = vfprintf(pFile, pszFormat, va); va_end(va); return cchRet; } /** * Replaces puts for MSC to speed up console output. * * @returns Units written; 0 & errno on failure. * @param pszString The string to write. (newline is appended) */ DLL_IMPORT int __cdecl puts(const char *pszString) { size_t cchString = strlen(pszString); size_t cch; /* * If it's a TTY, we convert it to a wide char string with a newline * appended right here. Going thru maybe_con_fwrite is just extra * buffering due to the added newline. */ if (*pszString != '\0') { int fd = fileno(stdout); if (fd >= 0) { if (isatty(fd)) { HANDLE hCon = (HANDLE)_get_osfhandle(fd); if ( hCon != INVALID_HANDLE_VALUE && hCon != NULL) { /* We need to append a newline, so we can just as well do the conversion here. */ size_t cwcTmp = cchString * 2 + 16 + 2; wchar_t *pawcTmp = (wchar_t *)malloc(cwcTmp * sizeof(wchar_t)); if (pawcTmp) { int cwcToWrite; static UINT s_uConsoleCp = 0; if (s_uConsoleCp == 0) s_uConsoleCp = GetConsoleCP(); cwcToWrite = MultiByteToWideChar(s_uConsoleCp, 0 /*dwFlags*/, pszString, (int)cchString, pawcTmp, (int)(cwcTmp - 2)); if (cwcToWrite > 0) { int rc; pawcTmp[cwcToWrite++] = '\n'; pawcTmp[cwcToWrite] = '\0'; /* Let the CRT do the rest. At least the Visual C++ 2010 CRT sources indicates _cputws will do the right thing we want. */ fflush(stdout); rc = _cputws(pawcTmp); free(pawcTmp); return rc; } free(pawcTmp); } } } } } /* * Fallback. */ cch = fwrite(pszString, cchString, 1, stdout); if (cch == cchString) { if (putc('\n', stdout) != EOF) return 0; } return -1; } /** * Replaces puts for MSC to speed up console output. * * @returns Units written; 0 & errno on failure. * @param pszString The string to write (no newline added). * @param pFile The output file. */ DLL_IMPORT int __cdecl fputs(const char *pszString, FILE *pFile) { size_t cchString = strlen(pszString); size_t cch = maybe_con_fwrite(pszString, cchString, 1, pFile); if (cch == cchString) return 0; return -1; } void * const __imp_printf = (void *)(uintptr_t)printf; void * const __imp_vprintf = (void *)(uintptr_t)vprintf; void * const __imp_fprintf = (void *)(uintptr_t)fprintf; void * const __imp_puts = (void *)(uintptr_t)puts; void * const __imp_fputs = (void *)(uintptr_t)fputs; kbuild-3149/src/lib/crc32.h0000644000175000017500000000017013252530204015320 0ustar locutuslocutus#ifndef ___crc32_h__ #define ___crc32_h__ #include "mytypes.h" uint32_t crc32(uint32_t, const void *, size_t); #endif kbuild-3149/src/lib/nt_fullpath.c0000644000175000017500000004475313252530204016736 0ustar locutuslocutus/* $Id: nt_fullpath.c 2849 2016-08-30 14:28:46Z bird $ */ /** @file * fixcase - fixes the case of paths, windows specific. */ /* * Copyright (c) 2004-2010 knut st. osmundsen * * This file is part of kBuild. * * kBuild 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. * * kBuild 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 kBuild. If not, see * */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #include #include #include #include "nt_fullpath.h" /* * Corrects the case of a path. * Expects a fullpath! * Added by bird for the $(abspath ) function and w32ify */ static void w32_fixcase(char *pszPath) { static char s_szLast[260]; size_t cchLast; #ifndef NDEBUG # define my_assert(expr) \ do { \ if (!(expr)) { \ printf("my_assert: %s, file %s, line %d\npszPath=%s\npsz=%s\n", \ #expr, __FILE__, __LINE__, pszPath, psz); \ __debugbreak(); \ exit(1); \ } \ } while (0) #else # define my_assert(expr) do {} while (0) #endif char *psz = pszPath; if (*psz == '/' || *psz == '\\') { if (psz[1] == '/' || psz[1] == '\\') { /* UNC */ my_assert(psz[1] == '/' || psz[1] == '\\'); my_assert(psz[2] != '/' && psz[2] != '\\'); /* skip server name */ psz += 2; while (*psz != '\\' && *psz != '/') { if (!*psz) return; *psz++ = toupper(*psz); } /* skip the share name */ psz++; my_assert(*psz != '/' && *psz != '\\'); while (*psz != '\\' && *psz != '/') { if (!*psz) return; *psz++ = toupper(*psz); } my_assert(*psz == '/' || *psz == '\\'); psz++; } else { /* Unix spec */ psz++; } } else { /* Drive letter */ my_assert(psz[1] == ':'); *psz = toupper(*psz); my_assert(psz[0] >= 'A' && psz[0] <= 'Z'); my_assert(psz[2] == '/' || psz[2] == '\\'); psz += 3; } /* * Try make use of the result from the previous call. * This is ignorant to slashes and similar, but may help even so. */ if ( s_szLast[0] == pszPath[0] && (psz - pszPath == 1 || s_szLast[1] == pszPath[1]) && (psz - pszPath <= 2 || s_szLast[2] == pszPath[2]) ) { char *pszLast = &s_szLast[psz - pszPath]; char *pszCur = psz; char *pszSrc0 = pszLast; char *pszDst0 = pszCur; for (;;) { const char ch1 = *pszCur; const char ch2 = *pszLast; if ( ch1 != ch2 && (ch1 != '\\' || ch2 != '/') && (ch1 != '/' || ch2 != '\\') && tolower(ch1) != tolower(ch2) && toupper(ch1) != toupper(ch2)) break; if (ch1 == '/' || ch1 == '\\') { psz = pszCur + 1; *pszLast = ch1; /* preserve the slashes */ } else if (ch1 == '\0') { psz = pszCur; break; } pszCur++; pszLast++; } if (psz != pszDst0) memcpy(pszDst0, pszSrc0, psz - pszDst0); } /* * Pointing to the first char after the unc or drive specifier, * or in case of a cache hit, the first non-matching char (following a slash of course). */ while (*psz) { WIN32_FIND_DATA FindFileData; HANDLE hDir; char chSaved0; char chSaved1; char *pszEnd; int iLongNameDiff; size_t cch; /* find the end of the component. */ pszEnd = psz; while (*pszEnd && *pszEnd != '/' && *pszEnd != '\\') pszEnd++; cch = pszEnd - psz; /* replace the end with "?\0" */ chSaved0 = pszEnd[0]; chSaved1 = pszEnd[1]; pszEnd[0] = '?'; pszEnd[1] = '\0'; /* find the right filename. */ hDir = FindFirstFile(pszPath, &FindFileData); pszEnd[1] = chSaved1; if (!hDir) { cchLast = psz - pszPath; memcpy(s_szLast, pszPath, cchLast + 1); s_szLast[cchLast + 1] = '\0'; pszEnd[0] = chSaved0; return; } pszEnd[0] = '\0'; while ( (iLongNameDiff = stricmp(FindFileData.cFileName, psz)) && stricmp(FindFileData.cAlternateFileName, psz)) { if (!FindNextFile(hDir, &FindFileData)) { cchLast = psz - pszPath; memcpy(s_szLast, pszPath, cchLast + 1); s_szLast[cchLast + 1] = '\0'; pszEnd[0] = chSaved0; return; } } pszEnd[0] = chSaved0; if ( iLongNameDiff /* matched the short name */ || !FindFileData.cAlternateFileName[0] /* no short name */ || !memchr(psz, ' ', cch)) /* no spaces in the matching name */ memcpy(psz, !iLongNameDiff ? FindFileData.cFileName : FindFileData.cAlternateFileName, cch); else { /* replace spacy name with the short name. */ const size_t cchAlt = strlen(FindFileData.cAlternateFileName); const size_t cchDelta = cch - cchAlt; my_assert(cchAlt > 0); if (!cchDelta) memcpy(psz, FindFileData.cAlternateFileName, cch); else { size_t cbLeft = strlen(pszEnd) + 1; if ((psz - pszPath) + cbLeft + cchAlt <= _MAX_PATH) { memmove(psz + cchAlt, pszEnd, cbLeft); pszEnd -= cchDelta; memcpy(psz, FindFileData.cAlternateFileName, cchAlt); } else fprintf(stderr, "kBuild: case & space fixed filename is growing too long (%d bytes)! '%s'\n", (psz - pszPath) + cbLeft + cchAlt, pszPath); } } my_assert(pszEnd[0] == chSaved0); FindClose(hDir); /* advance to the next component */ if (!chSaved0) { psz = pszEnd; break; } psz = pszEnd + 1; my_assert(*psz != '/' && *psz != '\\'); } /* *psz == '\0', the end. */ cchLast = psz - pszPath; memcpy(s_szLast, pszPath, cchLast + 1); #undef my_assert } #define MY_FileNameInformation 9 typedef struct _MY_FILE_NAME_INFORMATION { ULONG FileNameLength; WCHAR FileName[1]; } MY_FILE_NAME_INFORMATION, *PMY_FILE_NAME_INFORMATION; #define MY_FileInternalInformation 6 typedef struct _MY_FILE_INTERNAL_INFORMATION { LARGE_INTEGER IndexNumber; } MY_FILE_INTERNAL_INFORMATION, *PMY_FILE_INTERNAL_INFORMATION; #define MY_FileFsVolumeInformation 1 typedef struct _MY_FILE_FS_VOLUME_INFORMATION { LARGE_INTEGER VolumeCreationTime; ULONG VolumeSerialNumber; ULONG VolumeLabelLength; BOOLEAN SupportsObjects; WCHAR VolumeLabel[/*1*/128]; } MY_FILE_FS_VOLUME_INFORMATION, *PMY_FILE_FS_VOLUME_INFORMATION; #define MY_FileFsAttributeInformation 5 typedef struct _MY_FILE_FS_ATTRIBUTE_INFORMATION { ULONG FileSystemAttributes; LONG MaximumComponentNameLength; ULONG FileSystemNameLength; WCHAR FileSystemName[/*1*/64]; } MY_FILE_FS_ATTRIBUTE_INFORMATION, *PMY_FILE_FS_ATTRIBUTE_INFORMATION; #define MY_FileFsDeviceInformation 4 typedef struct MY_FILE_FS_DEVICE_INFORMATION { ULONG DeviceType; ULONG Characteristics; } MY_FILE_FS_DEVICE_INFORMATION, *PMY_FILE_FS_DEVICE_INFORMATION; #define MY_FILE_DEVICE_DISK 7 #define MY_FILE_DEVICE_DISK_FILE_SYSTEM 8 #define MY_FILE_DEVICE_FILE_SYSTEM 9 #define MY_FILE_DEVICE_VIRTUAL_DISK 36 typedef struct { union { LONG Status; PVOID Pointer; }; ULONG_PTR Information; } MY_IO_STATUS_BLOCK, *PMY_IO_STATUS_BLOCK; static BOOL g_fInitialized = FALSE; static int g_afNtfsDrives['Z' - 'A' + 1]; static MY_FILE_FS_VOLUME_INFORMATION g_aVolumeInfo['Z' - 'A' + 1]; static LONG (NTAPI *g_pfnNtQueryInformationFile)(HANDLE FileHandle, PMY_IO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, ULONG FileInformationClass); static LONG (NTAPI *g_pfnNtQueryVolumeInformationFile)(HANDLE FileHandle, PMY_IO_STATUS_BLOCK IoStatusBlock, PVOID FsInformation, ULONG Length, ULONG FsInformationClass); int nt_get_filename_info(const char *pszPath, char *pszFull, size_t cchFull) { static char abBuf[8192]; PMY_FILE_NAME_INFORMATION pFileNameInfo = (PMY_FILE_NAME_INFORMATION)abBuf; PMY_FILE_FS_VOLUME_INFORMATION pFsVolInfo = (PMY_FILE_FS_VOLUME_INFORMATION)abBuf; MY_IO_STATUS_BLOCK Ios; LONG rcNt; HANDLE hFile; int cchOut; char *psz; int iDrv; int rc; /* * Check for NtQueryInformationFile the first time around. */ if (!g_fInitialized) { g_fInitialized = TRUE; if (!getenv("KMK_DONT_USE_NT_QUERY_INFORMATION_FILE")) { *(FARPROC *)&g_pfnNtQueryInformationFile = GetProcAddress(LoadLibrary("ntdll.dll"), "NtQueryInformationFile"); *(FARPROC *)&g_pfnNtQueryVolumeInformationFile = GetProcAddress(LoadLibrary("ntdll.dll"), "NtQueryVolumeInformationFile"); } if ( g_pfnNtQueryInformationFile && g_pfnNtQueryVolumeInformationFile) { unsigned i; for (i = 0; i < sizeof(g_afNtfsDrives) / sizeof(g_afNtfsDrives[0]); i++ ) g_afNtfsDrives[i] = -1; } else { g_pfnNtQueryVolumeInformationFile = NULL; g_pfnNtQueryInformationFile = NULL; } } if (!g_pfnNtQueryInformationFile) return -1; /* * The FileNameInformation we get is relative to where the volume is mounted, * so we have to extract the driveletter prefix ourselves. * * FIXME: This will probably not work for volumes mounted in NTFS sub-directories. */ psz = pszFull; if (pszPath[0] == '\\' || pszPath[0] == '/') { /* unc or root of volume */ if ( (pszPath[1] == '\\' || pszPath[1] == '/') && (pszPath[2] != '\\' || pszPath[2] == '/')) { #if 0 /* don't bother with unc yet. */ /* unc - we get the server + name back */ *psz++ = '\\'; #endif return -1; } /* root slash */ *psz++ = _getdrive() + 'A' - 1; *psz++ = ':'; } else if (pszPath[1] == ':' && isalpha(pszPath[0])) { /* drive letter */ *psz++ = toupper(pszPath[0]); *psz++ = ':'; } else { /* relative */ *psz++ = _getdrive() + 'A' - 1; *psz++ = ':'; } iDrv = *pszFull - 'A'; /* * Fat32 doesn't return filenames with the correct case, so restrict it * to NTFS volumes for now. */ if (g_afNtfsDrives[iDrv] == -1) { /* FSCTL_GET_REPARSE_POINT? Enumerate mount points? */ g_afNtfsDrives[iDrv] = 0; psz[0] = '\\'; psz[1] = '\0'; #if 1 hFile = CreateFile(pszFull, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (hFile != INVALID_HANDLE_VALUE) { PMY_FILE_FS_ATTRIBUTE_INFORMATION pFsAttrInfo = (PMY_FILE_FS_ATTRIBUTE_INFORMATION)abBuf; memset(&Ios, 0, sizeof(Ios)); rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, abBuf, sizeof(abBuf), MY_FileFsAttributeInformation); if ( rcNt >= 0 //&& pFsAttrInfo->FileSystemNameLength == 4 && pFsAttrInfo->FileSystemName[0] == 'N' && pFsAttrInfo->FileSystemName[1] == 'T' && pFsAttrInfo->FileSystemName[2] == 'F' && pFsAttrInfo->FileSystemName[3] == 'S' && pFsAttrInfo->FileSystemName[4] == '\0') { memset(&Ios, 0, sizeof(Ios)); rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, &g_aVolumeInfo[iDrv], sizeof(MY_FILE_FS_VOLUME_INFORMATION), MY_FileFsVolumeInformation); if (rcNt >= 0) { DWORD dwDriveType = GetDriveType(pszFull); if ( dwDriveType == DRIVE_FIXED || dwDriveType == DRIVE_RAMDISK) g_afNtfsDrives[iDrv] = 1; } } CloseHandle(hFile); } #else { char szFSName[32]; if ( GetVolumeInformation(pszFull, NULL, 0, /* volume name */ NULL, /* serial number */ NULL, /* max component */ NULL, /* volume attribs */ szFSName, sizeof(szFSName)) && !strcmp(szFSName, "NTFS")) { g_afNtfsDrives[iDrv] = 1; } } #endif } if (!g_afNtfsDrives[iDrv]) return -1; /* * Try open the path and query its file name information. */ hFile = CreateFile(pszPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (hFile != INVALID_HANDLE_VALUE) { /* check that the driver letter is correct first (reparse / symlink issues). */ memset(&Ios, 0, sizeof(Ios)); rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pFsVolInfo, sizeof(*pFsVolInfo), MY_FileFsVolumeInformation); if (rcNt >= 0) { /** @todo do a quick search and try correct the drive letter? */ if ( pFsVolInfo->VolumeCreationTime.QuadPart == g_aVolumeInfo[iDrv].VolumeCreationTime.QuadPart && pFsVolInfo->VolumeSerialNumber == g_aVolumeInfo[iDrv].VolumeSerialNumber) { memset(&Ios, 0, sizeof(Ios)); rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, abBuf, sizeof(abBuf), MY_FileNameInformation); if (rcNt >= 0) { cchOut = WideCharToMultiByte(CP_ACP, 0, pFileNameInfo->FileName, pFileNameInfo->FileNameLength / sizeof(WCHAR), psz, (int)(cchFull - (psz - pszFull) - 2), NULL, NULL); if (cchOut > 0) { const char *pszEnd; #if 0 /* upper case the server and share */ if (fUnc) { for (psz++; *psz != '/' && *psz != '\\'; psz++) *psz = toupper(*psz); for (psz++; *psz != '/' && *psz != '\\'; psz++) *psz = toupper(*psz); } #endif /* add trailing slash on directories if input has it. */ pszEnd = strchr(pszPath, '\0'); if ( (pszEnd[-1] == '/' || pszEnd[-1] == '\\') && psz[cchOut - 1] != '\\' && psz[cchOut - 1] != '//') psz[cchOut++] = '\\'; /* make sure it's terminated */ psz[cchOut] = '\0'; rc = 0; } else rc = -3; } else rc = -4; } else rc = -5; } else rc = -6; CloseHandle(hFile); } else rc = -7; return rc; } /** * Somewhat similar to fullpath, except that it will fix * the case of existing path components. */ void nt_fullpath(const char *pszPath, char *pszFull, size_t cchFull) { #if 0 static int s_cHits = 0; static int s_cFallbacks = 0; #endif /* * The simple case, the file / dir / whatever exists and can be * queried without problems and spaces. */ if (nt_get_filename_info(pszPath, pszFull, cchFull) == 0) { /** @todo make nt_get_filename_info return spaceless path. */ if (strchr(pszFull, ' ')) w32_fixcase(pszFull); #if 0 fprintf(stdout, "nt #%d - %s\n", ++s_cHits, pszFull); fprintf(stdout, " #%d - %s\n", s_cHits, pszPath); #endif return; } if (g_pfnNtQueryInformationFile) { /* do _fullpath and drop off path elements until we get a hit... - later */ } /* * For now, simply fall back on the old method. */ _fullpath(pszFull, pszPath, cchFull); w32_fixcase(pszFull); #if 0 fprintf(stderr, "fb #%d - %s\n", ++s_cFallbacks, pszFull); fprintf(stderr, " #%d - %s\n", s_cFallbacks, pszPath); #endif } kbuild-3149/src/lib/dos2unix.c0000644000175000017500000002347213252530204016164 0ustar locutuslocutus/* $Id: dos2unix.c 3114 2017-10-29 18:02:04Z bird $ */ /** @file * dos2unix - Line ending conversion routines. */ /* * Copyright (c) 2017 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ #include "dos2unix.h" #include #include #include #if K_OS == K_OS_WINDOWS # include #else # include #endif #include #ifndef O_BINARY # ifdef _O_BINARY # define O_BINARY _O_BINARY # else # define O_BINARY 0 # endif #endif /********************************************************************************************************************************* * Defined Constants And Macros * *********************************************************************************************************************************/ #define STACK_BUF_SIZE 0x20000 #define DOS2UNIX_LF 0x0a #define DOS2UNIX_CR 0x0d /** * Does a line ending analysis of the given file. * * @returns 0 on success, errno value on open or read error. * @param pszFilename The path to the file * @param pfStyle Where to return the DOS2UNIX_STYLE_XXX and * DOS2UNIX_F_XXX flags. * @param pcDosEols Where to return the number of DOS end-of-line * sequences found. Optional. * @param pcUnixEols Where to return the number of UNIX end-of-line * sequences found. */ int dos2unix_analyze_file(const char *pszFilename, KU32 *pfStyle, KSIZE *pcDosEols, KSIZE *pcUnixEols) { int iRet = 0; int fd = open(pszFilename, O_RDONLY | O_BINARY); if (fd >= 0) { iRet = dos2unix_analyze_fd(fd, pfStyle, pcDosEols, pcUnixEols); close(fd); } else { iRet = errno; *pfStyle = DOS2UNIX_STYLE_NONE; if (pcUnixEols) *pcUnixEols = 0; if (pcDosEols) *pcDosEols = 0; } return iRet; } /** * Does a line ending analysis of the given file descriptor. * * @returns 0 on success, errno value on open or read error. * @param fd The file descriptor to analyze. Caller must * place this as the desired position. * @param pfStyle Where to return the DOS2UNIX_STYLE_XXX and * DOS2UNIX_F_XXX flags. * @param pcDosEols Where to return the number of DOS end-of-line * sequences found. Optional. * @param pcUnixEols Where to return the number of UNIX end-of-line * sequences found. */ int dos2unix_analyze_fd(int fd, KU32 *pfStyle, KSIZE *pcDosEols, KSIZE *pcUnixEols) { KSIZE cUnixEols = 0; KSIZE cDosEols = 0; KSIZE cLoneCrs = 0; KBOOL fPendingCr = K_FALSE; int iRet = 0; /* * Do the analysis. */ *pfStyle = DOS2UNIX_STYLE_NONE; for (;;) { char achBuf[STACK_BUF_SIZE]; int cchRead = read(fd, achBuf, sizeof(achBuf)); if (cchRead > 0) { int off = 0; if (fPendingCr) { if (achBuf[0] == DOS2UNIX_LF) { off++; cDosEols++; } else cLoneCrs++; fPendingCr = K_FALSE; } while (off < cchRead) { char ch = achBuf[off++]; if ((unsigned char)ch > (unsigned char)DOS2UNIX_CR) { /* likely */ } else if (ch == DOS2UNIX_CR) { if (off < cchRead && achBuf[off] == DOS2UNIX_CR) cDosEols++; else { fPendingCr = K_TRUE; while (off < cchRead) { ch = achBuf[off++]; if (ch != DOS2UNIX_CR) { if (ch == DOS2UNIX_LF) cDosEols++; else cLoneCrs++; fPendingCr = K_FALSE; break; } cLoneCrs++; } } } else if (ch == DOS2UNIX_LF) cUnixEols++; else if (ch == '\0') *pfStyle |= DOS2UNIX_F_BINARY; } } else { if (cchRead < 0) iRet = errno; if (fPendingCr) cLoneCrs++; break; } } /* * Set return values. */ if (cUnixEols > 0 && cDosEols == 0) *pfStyle |= DOS2UNIX_STYLE_UNIX; else if (cDosEols > 0 && cUnixEols == 0) *pfStyle |= DOS2UNIX_STYLE_DOS; else if (cDosEols != 0 && cUnixEols != 0) *pfStyle |= DOS2UNIX_STYLE_MIXED; if (pcUnixEols) *pcUnixEols = cUnixEols; if (pcDosEols) *pcDosEols = cDosEols; return iRet; } /** * Converts a buffer to unix line (LF) endings. * * @retval K_TRUE if pending CR. The caller must handle this case. * @retval K_FALSE if no pending CR. * * @param pchSrc The input buffer. * @param cchSrc Number of characters to convert from the input * buffer. * @param pchDst The output buffer. This must be at least as big as * the input. It is okay if this overlaps with the * source buffer, as long as this is at the same or a * lower address. * @param pcchDst Where to return the number of characters in the * output buffer. */ KBOOL dos2unix_convert_to_unix(const char *pchSrc, KSIZE cchSrc, char *pchDst, KSIZE *pcchDst) { KSIZE offDst = 0; while (cchSrc-- > 0) { char ch = *pchSrc++; if ((unsigned char)ch != (unsigned char)DOS2UNIX_CR) pchDst[offDst++] = ch; else if (cchSrc > 0 && *pchSrc == DOS2UNIX_LF) { pchDst[offDst++] = DOS2UNIX_LF; cchSrc--; pchSrc++; } else if (cchSrc == 0) { *pcchDst = offDst; return K_TRUE; } else pchDst[offDst++] = ch; } *pcchDst = offDst; return K_FALSE; } /** * Converts a buffer to DOS (CRLF) endings. * * @retval K_TRUE if pending CR. The caller must handle this case. * @retval K_FALSE if no pending CR. * * @param pchSrc The input buffer. * @param cchSrc Number of characters to convert from the input * buffer. * @param pchDst The output buffer. This must be at least _twice_ as * big as the input. It is okay if the top half of the * buffer overlaps with the source buffer. * @param pcchDst Where to return the number of characters in the * output buffer. */ KBOOL dos2unix_convert_to_dos(const char *pchSrc, KSIZE cchSrc, char *pchDst, KSIZE *pcchDst) { KSIZE offDst = 0; while (cchSrc-- > 0) { char ch = *pchSrc++; if ((unsigned char)ch > (unsigned char)DOS2UNIX_CR) pchDst[offDst++] = ch; else if (ch == DOS2UNIX_CR) { /* We treat CR kind of like an escape character. */ do { if (cchSrc > 0) { pchDst[offDst++] = ch; cchSrc--; ch = *pchSrc++; } else { *pcchDst = offDst; return K_TRUE; } } while (ch == DOS2UNIX_CR); pchDst[offDst++] = ch; } else if (ch == DOS2UNIX_LF) { pchDst[offDst++] = DOS2UNIX_CR; pchDst[offDst++] = DOS2UNIX_LF; } else pchDst[offDst++] = ch; } *pcchDst = offDst; return K_FALSE; } kbuild-3149/src/lib/kDep.c0000644000175000017500000003527413252530204015277 0ustar locutuslocutus/* $Id: kDep.c 3140 2018-03-14 21:28:10Z bird $ */ /** @file * kDep - Common Dependency Managemnt Code. */ /* * Copyright (c) 2004-2013 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /******************************************************************************* * Header Files * *******************************************************************************/ #ifdef KMK /* For when it gets compiled and linked into kmk. */ # include "makeint.h" #endif #include #include #include #include #include #include #include #include "k/kDefs.h" #include "k/kTypes.h" #if K_OS == K_OS_WINDOWS # define USE_WIN_MMAP # include # include # include "nt_fullpath.h" # include "nt/ntstat.h" #else # include # include # include #endif #include "kDep.h" #ifdef KWORKER extern int kwFsPathExists(const char *pszPath); #endif /********************************************************************************************************************************* * Defined Constants And Macros * *********************************************************************************************************************************/ /* For the GNU/hurd weirdo. */ #if !defined(PATH_MAX) && !defined(_MAX_PATH) # define PATH_MAX 4096 #endif /******************************************************************************* * Global Variables * *******************************************************************************/ /** List of dependencies. */ static PDEP g_pDeps = NULL; /** * Corrects all slashes to unix slashes. * * @returns pszFilename. * @param pszFilename The filename to correct. */ static char *fixslash(char *pszFilename) { char *psz = pszFilename; while ((psz = strchr(psz, '\\')) != NULL) *psz++ = '/'; return pszFilename; } #if K_OS == K_OS_OS2 /** * Corrects the case of a path. * * @param pszPath Pointer to the path, both input and output. * The buffer must be able to hold one more byte than the string length. */ static void fixcase(char *pszFilename) { return; } #elif K_OS != K_OS_WINDOWS /** * Corrects the case of a path. * * @param pszPath Pointer to the path, both input and output. */ static void fixcase(char *pszFilename) { char *psz; /* * Skip the root. */ psz = pszFilename; while (*psz == '/') psz++; /* * Iterate all the components. */ while (*psz) { char chSlash; struct stat s; char *pszStart = psz; /* * Find the next slash (or end of string) and terminate the string there. */ while (*psz != '/' && *psz) psz++; chSlash = *psz; *psz = '\0'; /* * Does this part exist? * If not we'll enumerate the directory and search for an case-insensitive match. */ if (stat(pszFilename, &s)) { struct dirent *pEntry; DIR *pDir; if (pszStart == pszFilename) pDir = opendir(*pszFilename ? pszFilename : "."); else { pszStart[-1] = '\0'; pDir = opendir(pszFilename); pszStart[-1] = '/'; } if (!pDir) { *psz = chSlash; break; /* giving up, if we fail to open the directory. */ } while ((pEntry = readdir(pDir)) != NULL) { if (!strcasecmp(pEntry->d_name, pszStart)) { strcpy(pszStart, pEntry->d_name); break; } } closedir(pDir); if (!pEntry) { *psz = chSlash; break; /* giving up if not found. */ } } /* restore the slash and press on. */ *psz = chSlash; while (*psz == '/') psz++; } return; } #endif /* !OS/2 && !Windows */ /** * 'Optimizes' and corrects the dependencies. */ void depOptimize(int fFixCase, int fQuiet, const char *pszIgnoredExt) { /* * Walk the list correct the names and re-insert them. */ size_t cchIgnoredExt = pszIgnoredExt ? strlen(pszIgnoredExt) : 0; PDEP pDepOrg = g_pDeps; PDEP pDep = g_pDeps; g_pDeps = NULL; for (; pDep; pDep = pDep->pNext) { #ifndef PATH_MAX char szFilename[_MAX_PATH + 1]; #else char szFilename[PATH_MAX + 1]; #endif char *pszFilename; #if !defined(KWORKER) && !defined(KMK) struct stat s; #endif /* * Skip some fictive names like and . */ if ( pDep->szFilename[0] == '<' && pDep->szFilename[pDep->cchFilename - 1] == '>') continue; pszFilename = pDep->szFilename; /* * Skip pszIgnoredExt if given. */ if ( pszIgnoredExt && pDep->cchFilename > cchIgnoredExt && memcmp(&pDep->szFilename[pDep->cchFilename - cchIgnoredExt], pszIgnoredExt, cchIgnoredExt) == 0) continue; #if K_OS != K_OS_OS2 && K_OS != K_OS_WINDOWS /* * Skip any drive letters from compilers running in wine. */ if (pszFilename[1] == ':') pszFilename += 2; #endif /* * The microsoft compilers are notoriously screwing up the casing. * This will screw up kmk (/ GNU Make). */ if (fFixCase) { #if K_OS == K_OS_WINDOWS nt_fullpath_cached(pszFilename, szFilename, sizeof(szFilename)); fixslash(szFilename); #else strcpy(szFilename, pszFilename); fixslash(szFilename); fixcase(szFilename); #endif pszFilename = szFilename; } /* * Check that the file exists before we start depending on it. */ #ifdef KWORKER if (!kwFsPathExists(pszFilename)) #elif defined(KMK) if (!file_exists_p(pszFilename)) #elif K_OS == K_OS_WINDOWS if (birdStatModTimeOnly(pszFilename, &s.st_mtim, 1 /*fFollowLink*/) != 0) #else if (stat(pszFilename, &s) != 0) #endif { if ( !fQuiet || errno != ENOENT || ( pszFilename[0] != '/' && pszFilename[0] != '\\' && ( !isalpha(pszFilename[0]) || pszFilename[1] != ':' || ( pszFilename[2] != '/' && pszFilename[2] != '\\'))) ) fprintf(stderr, "kDep: Skipping '%s' - %s!\n", pszFilename, strerror(errno)); continue; } /* * Insert the corrected dependency. */ depAdd(pszFilename, strlen(pszFilename)); } /* * Free the old ones. */ while (pDepOrg) { pDep = pDepOrg; pDepOrg = pDepOrg->pNext; free(pDep); } } /** * Prints the dependency chain. * * @returns Pointer to the allocated dependency. * @param pOutput Output stream. */ void depPrint(FILE *pOutput) { PDEP pDep; for (pDep = g_pDeps; pDep; pDep = pDep->pNext) fprintf(pOutput, " \\\n\t%s", pDep->szFilename); fprintf(pOutput, "\n\n"); } /** * Prints empty dependency stubs for all dependencies. */ void depPrintStubs(FILE *pOutput) { PDEP pDep; for (pDep = g_pDeps; pDep; pDep = pDep->pNext) fprintf(pOutput, "%s:\n\n", pDep->szFilename); } /* sdbm: This algorithm was created for sdbm (a public-domain reimplementation of ndbm) database library. it was found to do well in scrambling bits, causing better distribution of the keys and fewer splits. it also happens to be a good general hashing function with good distribution. the actual function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below is the faster version used in gawk. [there is even a faster, duff-device version] the magic constant 65599 was picked out of thin air while experimenting with different constants, and turns out to be a prime. this is one of the algorithms used in berkeley db (see sleepycat) and elsewhere. */ static unsigned sdbm(const char *str, size_t size) { unsigned hash = 0; int c; while (size-- > 0 && (c = *(unsigned const char *)str++)) hash = c + (hash << 6) + (hash << 16) - hash; return hash; } /** * Adds a dependency. * * @returns Pointer to the allocated dependency. * @param pszFilename The filename. Does not need to be terminated. * @param cchFilename The length of the filename. */ PDEP depAdd(const char *pszFilename, size_t cchFilename) { unsigned uHash = sdbm(pszFilename, cchFilename); PDEP pDep; PDEP pDepPrev; /* * Check if we've already got this one. */ pDepPrev = NULL; for (pDep = g_pDeps; pDep; pDepPrev = pDep, pDep = pDep->pNext) if ( pDep->uHash == uHash && pDep->cchFilename == cchFilename && !memcmp(pDep->szFilename, pszFilename, cchFilename)) return pDep; /* * Add it. */ pDep = (PDEP)malloc(sizeof(*pDep) + cchFilename); if (!pDep) { fprintf(stderr, "\nOut of memory! (requested %lx bytes)\n\n", (unsigned long)(sizeof(*pDep) + cchFilename)); exit(1); } pDep->cchFilename = cchFilename; memcpy(pDep->szFilename, pszFilename, cchFilename); pDep->szFilename[cchFilename] = '\0'; pDep->uHash = uHash; if (pDepPrev) { pDep->pNext = pDepPrev->pNext; pDepPrev->pNext = pDep; } else { pDep->pNext = g_pDeps; g_pDeps = pDep; } return pDep; } /** * Frees the current dependency chain. */ void depCleanup(void) { PDEP pDep = g_pDeps; g_pDeps = NULL; while (pDep) { PDEP pFree = pDep; pDep = pDep->pNext; free(pFree); } } /** * Performs a hexdump. */ void depHexDump(const KU8 *pb, size_t cb, size_t offBase) { const unsigned cchWidth = 16; size_t off = 0; while (off < cb) { unsigned i; printf("%s%0*lx %04lx:", off ? "\n" : "", (int)sizeof(pb) * 2, (unsigned long)offBase + (unsigned long)off, (unsigned long)off); for (i = 0; i < cchWidth && off + i < cb ; i++) printf(off + i < cb ? !(i & 7) && i ? "-%02x" : " %02x" : " ", pb[i]); while (i++ < cchWidth) printf(" "); printf(" "); for (i = 0; i < cchWidth && off + i < cb; i++) { const KU8 u8 = pb[i]; printf("%c", u8 < 127 && u8 >= 32 ? u8 : '.'); } off += cchWidth; pb += cchWidth; } printf("\n"); } /** * Reads the file specified by the pInput file stream into memory. * * @returns The address of the memory mapping on success. This must be * freed by calling depFreeFileMemory. * * @param pInput The file stream to load or map into memory. * @param pcbFile Where to return the mapping (file) size. * @param ppvOpaque Opaque data when mapping, otherwise NULL. */ void *depReadFileIntoMemory(FILE *pInput, size_t *pcbFile, void **ppvOpaque) { void *pvFile; long cbFile; /* * Figure out file size. */ #if defined(_MSC_VER) cbFile = _filelength(fileno(pInput)); if (cbFile < 0) #else if ( fseek(pInput, 0, SEEK_END) < 0 || (cbFile = ftell(pInput)) < 0 || fseek(pInput, 0, SEEK_SET)) #endif { fprintf(stderr, "kDep: error: Failed to determin file size.\n"); return NULL; } if (pcbFile) *pcbFile = cbFile; /* * Try mmap first. */ #ifdef USE_WIN_MMAP { HANDLE hMapObj = CreateFileMapping((HANDLE)_get_osfhandle(fileno(pInput)), NULL, PAGE_READONLY, 0, cbFile, NULL); if (hMapObj != NULL) { pvFile = MapViewOfFile(hMapObj, FILE_MAP_READ, 0, 0, cbFile); if (pvFile) { *ppvOpaque = hMapObj; return pvFile; } fprintf(stderr, "kDep: warning: MapViewOfFile failed, %d.\n", GetLastError()); CloseHandle(hMapObj); } else fprintf(stderr, "kDep: warning: CreateFileMapping failed, %d.\n", GetLastError()); } #endif /* * Allocate memory and read the file. */ pvFile = malloc(cbFile + 1); if (pvFile) { if (fread(pvFile, cbFile, 1, pInput)) { ((KU8 *)pvFile)[cbFile] = '\0'; *ppvOpaque = NULL; return pvFile; } fprintf(stderr, "kDep: error: Failed to read %ld bytes.\n", cbFile); free(pvFile); } else fprintf(stderr, "kDep: error: Failed to allocate %ld bytes (file mapping).\n", cbFile); return NULL; } /** * Free resources allocated by depReadFileIntoMemory. * * @param pvFile The address of the memory mapping. * @param pvOpaque The opaque value returned together with the mapping. */ void depFreeFileMemory(void *pvFile, void *pvOpaque) { #if defined(USE_WIN_MMAP) if (pvOpaque) { UnmapViewOfFile(pvFile); CloseHandle(pvOpaque); return; } #endif free(pvFile); } kbuild-3149/src/lib/maybe_con_fwrite.c0000644000175000017500000001045113252530204017716 0ustar locutuslocutus/* $Id: maybe_con_fwrite.c 2906 2016-09-09 22:15:57Z bird $ */ /** @file * maybe_con_write - Optimized console output on windows. */ /* * Copyright (c) 2016 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ #ifdef KBUILD_OS_WINDOWS # include #endif #include #include #ifdef _MSC_VER # include # include #endif /** * Drop-in fwrite replacement for optimizing console output on windows. * * * @returns Units written; 0 & errno on failure. * @param pvBuf What to write. * @param cbUnit How much to write in each unit. * @param cUnits How many units to write. * @param pFile The file to write to. */ size_t maybe_con_fwrite(void const *pvBuf, size_t cbUnit, size_t cUnits, FILE *pFile) { #ifdef KBUILD_OS_WINDOWS /* * If it's a TTY, do our own conversion to wide char and * call WriteConsoleW directly. */ if ( cbUnit > 0 && cUnits > 0 && (pFile == stdout || pFile == stderr)) { int fd = fileno(pFile); if (fd >= 0) { if (isatty(fd)) { HANDLE hCon = (HANDLE)_get_osfhandle(fd); if ( hCon != INVALID_HANDLE_VALUE && hCon != NULL) { size_t cbToWrite = cbUnit * cUnits; size_t cwcTmp = cbToWrite * 2 + 16; wchar_t *pawcTmp = (wchar_t *)malloc(cwcTmp * sizeof(wchar_t)); if (pawcTmp) { int cwcToWrite; static UINT s_uConsoleCp = 0; if (s_uConsoleCp == 0) s_uConsoleCp = GetConsoleCP(); cwcToWrite = MultiByteToWideChar(s_uConsoleCp, 0 /*dwFlags*/, pvBuf, (int)cbToWrite, pawcTmp, (int)(cwcTmp - 1)); if (cwcToWrite > 0) { int rc; pawcTmp[cwcToWrite] = '\0'; /* Let the CRT do the rest. At least the Visual C++ 2010 CRT sources indicates _cputws will do the right thing we want. */ fflush(pFile); rc = _cputws(pawcTmp); free(pawcTmp); if (rc >= 0) return cUnits; return 0; } free(pawcTmp); } } } } } #endif /* * Semi regular write handling. */ return fwrite(pvBuf, cbUnit, cUnits, pFile); } kbuild-3149/src/lib/quote_argv.h0000644000175000017500000000311113252530204016556 0ustar locutuslocutus/* $Id: quote_argv.h 2912 2016-09-14 13:36:15Z bird $ */ /** @file * quote_argv - Correctly quote argv for spawn, windows specific. */ /* * Copyright (c) 2007-2016 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ #ifndef ___quote_argv_h___ #define ___quote_argv_h___ #include "mytypes.h" extern int quote_argv(int argc, char **argv, int fWatcomBrainDamage, int fFreeOrLeak); #endif kbuild-3149/src/lib/wrapper.c0000644000175000017500000000657713252530204016100 0ustar locutuslocutus/* $Id: wrapper.c 2851 2016-08-31 17:30:52Z bird $ */ /** @file * Wrapper program for various debugging purposes. */ /* * Copyright (c) 2007-2016 knut st. osmundsen * * 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. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #ifdef _MSC_VER # include #else # include #endif int main(int argc, char **argv, char **envp) { const char *pszLogTo = getenv("WRAPPER_LOGTO"); const char *pszLogFileArgs = getenv("WRAPPER_LOGFILEARGS"); const char *pszLogEnv = getenv("WRAPPER_LOGENV"); const char *pszExec = getenv("WRAPPER_EXEC"); const char *pszSigSegv = getenv("WRAPPER_SIGSEGV"); const char *pszRetVal = getenv("WRAPPER_RETVAL"); int i; if (pszLogTo) { FILE *pLog = fopen(pszLogTo, "a"); if (pLog) { fprintf(pLog, "+++ %s pid=%ld +++\n", argv[0], (long)getpid()); for (i = 1; i < argc; i++) { fprintf(pLog, "argv[%d]: '%s'\n", i, argv[i]); if (pszLogFileArgs) { FILE *pArg = fopen(argv[i], "r"); if (pArg) { int iLine = 0; static char szLine[64*1024]; while (fgets(szLine, sizeof(szLine), pArg) && iLine++ < 42) fprintf(pLog, "%2d: %s", iLine, szLine); fclose(pArg); } } } if (pszLogEnv) for (i = 0; envp[i]; i++) fprintf(pLog, "envp[%d]: '%s'\n", i, envp[i]); fprintf(pLog, "--- %s pid=%ld ---\n", argv[0], (long)getpid()); fclose(pLog); } } if (pszSigSegv) { char *pchIllegal = (char *)1; pchIllegal[0] = '\0'; } if (pszExec) { /** @todo */ } return pszRetVal ? atol(pszRetVal) : 1; } kbuild-3149/src/lib/startuphacks-win.c0000644000175000017500000001434213252530204017714 0ustar locutuslocutus/* $Id: startuphacks-win.c 2413 2010-09-11 17:43:04Z bird $ */ /** @file * kBuild - Alternative argument parser for the windows startup code. * * @todo Update license when SED is updated. */ /* * Copyright (c) 2006-2010 knut st. osmundsen * * parse_args(): Copyright (c) 1992-1998 by Eberhard Mattes * * * This file is part of kBuild. * * kBuild is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * kBuild 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 kBuild; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include /******************************************************************************* * Internal Functions * *******************************************************************************/ static int parse_args(const char *pszSrc, char **argv, char *pchPool); /******************************************************************************* * Global Variables * *******************************************************************************/ /** argument count found by parse_args(). */ static int g_cArgs = 0; /** the argument vector, for __getmainargs(). */ static char **g_papszArgs = NULL; int __cdecl _setargv(void) { static char s_szProgramName[MAX_PATH + 1]; const char *pszCmdLine; char *pszCmdLineBuf; int cb; /* * Set the program name. */ GetModuleFileName(NULL, s_szProgramName, MAX_PATH); s_szProgramName[MAX_PATH] = '\0'; #if _MSC_VER >= 1400 && !defined(CRTDLL) && !defined(_DLL) _set_pgmptr(s_szProgramName); #endif /* * Get the commandline, use the program name if nothings available. */ pszCmdLine = (const char *)GetCommandLineA(); if (!pszCmdLine || !*pszCmdLine) pszCmdLine = s_szProgramName; /* * Parse the argument commandline emitting the unix argument vector. */ cb = parse_args(pszCmdLine, NULL, NULL); g_papszArgs = malloc(sizeof(*g_papszArgs) * (g_cArgs + 2)); if (!g_papszArgs) return -1; pszCmdLineBuf = malloc(cb); if (!pszCmdLineBuf) return -1; parse_args(pszCmdLine, g_papszArgs, pszCmdLineBuf); g_papszArgs[g_cArgs] = g_papszArgs[g_cArgs + 1] = NULL; /* set return variables */ __argc = g_cArgs; __argv = g_papszArgs; return 0; } /* when linking with the crtexe.c, the __getmainargs() call will redo the _setargv job inside the msvc*.dll. */ int __cdecl __getmainargs(int *pargc, char ***pargv, char ***penvp, int dowildcard, /*_startupinfo*/ void *startinfo) { __argc = *pargc = g_cArgs; __argv = *pargv = g_papszArgs; *penvp = _environ; return 0; } #if defined(_M_IX86) int (__cdecl * _imp____getmainargs)(int *, char ***, char ***, int, /*_startupinfo*/ void *) = __getmainargs; #else int (__cdecl * __imp___getmainargs)(int *, char ***, char ***, int, /*_startupinfo*/ void *) = __getmainargs; #endif /** * Parses the argument string passed in as pszSrc. * * @returns size of the processed arguments. * @param pszSrc Pointer to the commandline that's to be parsed. * @param argv Pointer to argument vector to put argument pointers in. NULL allowed. * @param pchPool Pointer to memory pchPool to put the arguments into. NULL allowed. */ static int parse_args(const char *pszSrc, char **argv, char *pchPool) { int bs; char chQuote; char *pfFlags; int cbArgs; #define PUTC(c) do { ++cbArgs; if (pchPool != NULL) *pchPool++ = (c); } while (0) #define PUTV do { ++g_cArgs; if (argv != NULL) *argv++ = pchPool; } while (0) #define WHITE(c) ((c) == ' ' || (c) == '\t') #define _ARG_DQUOTE 0x01 /* Argument quoted (") */ #define _ARG_RESPONSE 0x02 /* Argument read from response file */ #define _ARG_WILDCARD 0x04 /* Argument expanded from wildcard */ #define _ARG_ENV 0x08 /* Argument from environment */ #define _ARG_NONZERO 0x80 /* Always set, to avoid end of string */ g_cArgs = 0; cbArgs = 0; #if 0 /* argv[0] */ PUTC((char)_ARG_NONZERO); PUTV; for (;;) { PUTC(*pszSrc); if (*pszSrc == 0) break; ++pszSrc; } ++pszSrc; #endif for (;;) { while (WHITE(*pszSrc)) ++pszSrc; if (*pszSrc == 0) break; pfFlags = pchPool; PUTC((char)_ARG_NONZERO); PUTV; bs = 0; chQuote = 0; for (;;) { if (!chQuote ? (*pszSrc == '"' || *pszSrc == '\'') : *pszSrc == chQuote) { while (bs >= 2) { PUTC('\\'); bs -= 2; } if (bs & 1) PUTC(*pszSrc); else { chQuote = chQuote ? 0 : *pszSrc; if (pfFlags != NULL) *pfFlags |= _ARG_DQUOTE; } bs = 0; } else if (*pszSrc == '\\') ++bs; else { while (bs != 0) { PUTC('\\'); --bs; } if (*pszSrc == 0 || (WHITE(*pszSrc) && !chQuote)) break; PUTC(*pszSrc); } ++pszSrc; } PUTC(0); } return cbArgs; } kbuild-3149/src/misc/0000755000175000017500000000000013252530215014424 5ustar locutuslocutuskbuild-3149/src/misc/kmk_time.c0000644000175000017500000002511013252530215016367 0ustar locutuslocutus/* $Id: kmk_time.c 2546 2011-10-01 19:49:54Z bird $ */ /** @file * kmk_time - Time program execution. * * This is based on kmk/kmkbuiltin/redirect.c. */ /* * Copyright (c) 2007-2010 knut st. osmundsen * * This file is part of kBuild. * * kBuild 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. * * kBuild 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 kBuild. If not, see * */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #include #include #include #if defined(_MSC_VER) # include # include # include # include #else # include # include # include # include #endif #ifdef __OS2__ # define INCL_BASE # include # ifndef LIBPATHSTRICT # define LIBPATHSTRICT 3 # endif #endif #ifndef _MSC_VER static const char *my_strsignal(int signo) { #define CASE_SIG_RET_STR(sig) if (signo == SIG##sig) return #sig #ifdef SIGHUP CASE_SIG_RET_STR(HUP); #endif #ifdef SIGINT CASE_SIG_RET_STR(INT); #endif #ifdef SIGQUIT CASE_SIG_RET_STR(QUIT); #endif #ifdef SIGILL CASE_SIG_RET_STR(ILL); #endif #ifdef SIGTRAP CASE_SIG_RET_STR(TRAP); #endif #ifdef SIGABRT CASE_SIG_RET_STR(ABRT); #endif #ifdef SIGIOT CASE_SIG_RET_STR(IOT); #endif #ifdef SIGBUS CASE_SIG_RET_STR(BUS); #endif #ifdef SIGFPE CASE_SIG_RET_STR(FPE); #endif #ifdef SIGKILL CASE_SIG_RET_STR(KILL); #endif #ifdef SIGUSR1 CASE_SIG_RET_STR(USR1); #endif #ifdef SIGSEGV CASE_SIG_RET_STR(SEGV); #endif #ifdef SIGUSR2 CASE_SIG_RET_STR(USR2); #endif #ifdef SIGPIPE CASE_SIG_RET_STR(PIPE); #endif #ifdef SIGALRM CASE_SIG_RET_STR(ALRM); #endif #ifdef SIGTERM CASE_SIG_RET_STR(TERM); #endif #ifdef SIGSTKFLT CASE_SIG_RET_STR(STKFLT); #endif #ifdef SIGCHLD CASE_SIG_RET_STR(CHLD); #endif #ifdef SIGCONT CASE_SIG_RET_STR(CONT); #endif #ifdef SIGSTOP CASE_SIG_RET_STR(STOP); #endif #ifdef SIGTSTP CASE_SIG_RET_STR(TSTP); #endif #ifdef SIGTTIN CASE_SIG_RET_STR(TTIN); #endif #ifdef SIGTTOU CASE_SIG_RET_STR(TTOU); #endif #ifdef SIGURG CASE_SIG_RET_STR(URG); #endif #ifdef SIGXCPU CASE_SIG_RET_STR(XCPU); #endif #ifdef SIGXFSZ CASE_SIG_RET_STR(XFSZ); #endif #ifdef SIGVTALRM CASE_SIG_RET_STR(VTALRM); #endif #ifdef SIGPROF CASE_SIG_RET_STR(PROF); #endif #ifdef SIGWINCH CASE_SIG_RET_STR(WINCH); #endif #ifdef SIGIO CASE_SIG_RET_STR(IO); #endif #ifdef SIGPWR CASE_SIG_RET_STR(PWR); #endif #ifdef SIGSYS CASE_SIG_RET_STR(SYS); #endif #ifdef SIGBREAK CASE_SIG_RET_STR(BREAK); #endif #undef CASE_SIG_RET_STR return "???"; } #endif /* unix */ static const char *name(const char *pszName) { const char *psz = strrchr(pszName, '/'); #if defined(_MSC_VER) || defined(__OS2__) const char *psz2 = strrchr(pszName, '\\'); if (!psz2) psz2 = strrchr(pszName, ':'); if (psz2 && (!psz || psz2 > psz)) psz = psz2; #endif return psz ? psz + 1 : pszName; } static int usage(FILE *pOut, const char *argv0) { fprintf(pOut, "usage: %s [args]\n" " or: %s --help\n" " or: %s --version\n" , argv0, argv0, argv0); return 1; } int main(int argc, char **argv) { int i, j; int cTimes = 1; #if defined(_MSC_VER) FILETIME ftStart, ft; unsigned _int64 usMin, usMax, usAvg, usTotal, usCur; unsigned _int64 iStart; intptr_t rc; #else struct timeval tvStart, tv; unsigned long long usMin, usMax, usAvg, usTotal, usCur; pid_t pid; int rc; #endif int rcExit = 0; /* * Parse arguments. */ if (argc <= 1) return usage(stderr, name(argv[0])); for (i = 1; i < argc; i++) { char *psz = &argv[i][0]; if (*psz++ != '-') break; if (*psz == '-') { /* '--' ? */ if (!psz[1]) { i++; break; } /* convert to short. */ if (!strcmp(psz, "-help")) psz = "h"; else if (!strcmp(psz, "-version")) psz = "V"; else if (!strcmp(psz, "-iterations")) psz = "i"; } switch (*psz) { case 'h': usage(stdout, name(argv[0])); return 0; case 'V': printf("kmk_time - kBuild version %d.%d.%d (r%u)\n" "Copyright (C) 2007-2009 knut st. osmundsen\n", KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH, KBUILD_SVN_REV); return 0; case 'i': if (i + 1 >= argc) { fprintf(stderr, "%s: syntax error: missing iteration count\n", name(argv[0])); return 1; } cTimes = atoi(argv[++i]); if (cTimes <= 0) { fprintf(stderr, "%s: error: invalid interation count '%s'.\n", name(argv[0]), argv[i]); return 1; } break; default: fprintf(stderr, "%s: error: syntax error '%s'\n", name(argv[0]), argv[i]); return 1; } } /* * Make sure there's something to execute. */ if (i >= argc) { fprintf(stderr, "%s: syntax error: nothing to execute!\n", name(argv[0])); return usage(stderr, name(argv[0])); } /* * Execute the program the specified number of times. */ usMax = usMin = usTotal = 0; usMin--; /* wraps to max value */ for (j = 0; j < cTimes; j++) { /* * Execute the program (it's actually supposed to be a command I think, but wtf). */ #if defined(_MSC_VER) /** @todo * We'll have to find the '--' in the commandline and pass that * on to CreateProcess or spawn. Otherwise, the argument qouting * is gonna be messed up. */ GetSystemTimeAsFileTime(&ftStart); rc = _spawnvp(_P_WAIT, argv[i], &argv[i]); if (rc == -1) { fprintf(stderr, "%s: error: _spawnvp(_P_WAIT, \"%s\", ...) failed: %s\n", name(argv[0]), argv[i], strerror(errno)); return 8; } GetSystemTimeAsFileTime(&ft); iStart = ftStart.dwLowDateTime | ((unsigned _int64)ftStart.dwHighDateTime << 32); usCur = ft.dwLowDateTime | ((unsigned _int64)ft.dwHighDateTime << 32); usCur -= iStart; usCur /= 10; /* to usecs */ printf("%s: ", name(argv[0])); if (cTimes != 1) printf("#%02u ", j + 1); printf("%um%u.%06us - exit code: %d\n", (unsigned)(usCur / (60 * 1000000)), (unsigned)(usCur % (60 * 1000000)) / 1000000, (unsigned)(usCur % 1000000), rc); #else /* unix: */ gettimeofday(&tvStart, NULL); pid = fork(); if (!pid) { /* child */ execvp(argv[i], &argv[i]); fprintf(stderr, "%s: error: _execvp(\"%s\", ...) failed: %s\n", name(argv[0]), argv[i], strerror(errno)); return 8; } if (pid < 0) { fprintf(stderr, "%s: error: fork() failed: %s\n", name(argv[0]), strerror(errno)); return 9; } /* parent, wait for child. */ rc = 9; while (waitpid(pid, &rc, 0) == -1 && errno == EINTR) /* nothing */; gettimeofday(&tv, NULL); /* calc elapsed time */ tv.tv_sec -= tvStart.tv_sec; if (tv.tv_usec > tvStart.tv_usec) tv.tv_usec -= tvStart.tv_usec; else { tv.tv_sec--; tv.tv_usec = tv.tv_usec + 1000000 - tvStart.tv_usec; } usCur = tv.tv_sec * 1000000ULL + tv.tv_usec; printf("%s: ", name(argv[0])); if (cTimes != 1) printf("#%02u ", j + 1); printf("%um%u.%06us", (unsigned)(tv.tv_sec / 60), (unsigned)(tv.tv_sec % 60), (unsigned)tv.tv_usec); if (WIFEXITED(rc)) { printf(" - normal exit: %d\n", WEXITSTATUS(rc)); rc = WEXITSTATUS(rc); } # ifndef __HAIKU__ /**@todo figure how haiku signals that a core was dumped. */ else if (WIFSIGNALED(rc) && WCOREDUMP(rc)) { printf(" - dumped core: %s (%d)\n", my_strsignal(WTERMSIG(rc)), WTERMSIG(rc)); rc = 10; } # endif else if (WIFSIGNALED(rc)) { printf(" - killed by: %s (%d)\n", my_strsignal(WTERMSIG(rc)), WTERMSIG(rc)); rc = 11; } else if (WIFSTOPPED(rc)) { printf(" - stopped by: %s (%d)\n", my_strsignal(WSTOPSIG(rc)), WSTOPSIG(rc)); rc = 12; } else { printf(" unknown exit status %#x (%d)\n", rc, rc); rc = 13; } #endif /* unix */ if (rc && !rcExit) rcExit = (int)rc; /* calc min/max/avg */ usTotal += usCur; if (usMax < usCur) usMax = usCur; if (usMin > usCur) usMin = usCur; } /* * Summary if more than one run. */ if (cTimes != 1) { usAvg = usTotal / cTimes; printf("%s: avg %um%u.%06us\n", name(argv[0]), (unsigned)(usAvg / 60000000), (unsigned)(usAvg % 60000000) / 1000000, (unsigned)(usAvg % 1000000)); printf("%s: min %um%u.%06us\n", name(argv[0]), (unsigned)(usMin / 60000000), (unsigned)(usMin % 60000000) / 1000000, (unsigned)(usMin % 1000000)); printf("%s: max %um%u.%06us\n", name(argv[0]), (unsigned)(usMax / 60000000), (unsigned)(usMax % 60000000) / 1000000, (unsigned)(usMax % 1000000)); } return rcExit; } kbuild-3149/src/misc/Makefile.kmk0000644000175000017500000000202613252530215016645 0ustar locutuslocutus# $Id: Makefile.kmk 2413 2010-09-11 17:43:04Z bird $ ## @file # Sub-makefile for kmk_time. # # # Copyright (c) 2008-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # SUB_DEPTH = ../.. include $(PATH_KBUILD)/subheader.kmk PROGRAMS += kmk_time kmk_time_TEMPLATE = BIN kmk_time_DEFS = KBUILD_SVN_REV=$(KBUILD_SVN_REV) kmk_time_SOURCES = kmk_time.c include $(KBUILD_PATH)/subfooter.kmk kbuild-3149/src/fastdep/0000755000175000017500000000000013252530215015117 5ustar locutuslocutuskbuild-3149/src/fastdep/Makefile.kmk0000644000175000017500000000266613252530215017352 0ustar locutuslocutus# $Id: $ ## @file # Sub-makefile for testing the VAC308 tool / ancient dependency generator. # # # Copyright (c) 2007-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # SUB_DEPTH = ../.. include $(KBUILD_PATH)/subheader.kmk # # The base package. # PROGRAMS += fastdep fastdep_TOOL = VAC308 fastdep_SOURCES = avl.c fastdep.c fastdep_INCS = f:/toolkit/v4.52/h fastdep_LIBPATH = f:/toolkit/v4.52/lib LIBRARIES += libfastdep libfastdep_TOOL = VAC308 libfastdep_SOURCES = avl.c fastdep.c libfastdep_INCS = f:/toolkit/v4.52/h LIBRARIES += libfastdll libfastdll_TOOL = VAC308 libfastdll_SOURCES = fastdll.def DLLS += fastdll fastdll_TOOL = VAC308 fastdll_SOURCES = fastdll.def avl.c fastdep.c fastdll_INCS = f:/toolkit/v4.52/h fastdll_LIBPATH = f:/toolkit/v4.52/lib include $(FILE_KBUILD_SUB_FOOTER) kbuild-3149/src/fastdep/fastdep.c0000644000175000017500000041176513252530215016727 0ustar locutuslocutus/* $Id: fastdep.c 2413 2010-09-11 17:43:04Z bird $ * * Fast dependents. (Fast = Quick and Dirty!) * * Copyright (c) 1999-2010 knut st. osmundsen * * GPL * */ /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ #define INCL_DOSERRORS #define INCL_FILEMGR #define INCL_DOSMISC /* * Size of the \n charater (forget '\r'). * If you're compiling this under a UNICODE system this may perhaps change, * but I doubd that fastdep will work at all under a UNICODE system. ;-) */ #if defined(UNICODE) && !defined(__WIN32OS2__) #define CBNEWLINE (2) #else #define CBNEWLINE (1) #endif /* * Time stamp size. */ #define TS_SIZE (48) /******************************************************************************* * Header Files * *******************************************************************************/ #if defined(OS2FAKE) #include "os2fake.h" #else #include #endif #include #include #include #include #include #include "avl.h" #ifdef __WIN32OS2__ # define WIN32API # include #else # define ODIN32_BUILD_NR -1 #endif #ifndef INLINE # if defined(__IBMC__) # define INLINE _Inline # elif defined(__IBMCPP__) # define INLINE inline # elif defined(__WATCOMC__) # define INLINE __inline # elif defined(__WATCOM_CPLUSPLUS__) # define INLINE inline # else # error message("unknown compiler - inline keyword unknown!") # endif #endif /* * This following section is used while testing fastdep. * stdio.h should be included; string.h never included. */ /* #include #include #include */ #if 1 #include #else #include #include #endif /* */ /* */ /* #include */ #if 1 # if 1 #if 0 # include #else # if 1 #if 1 #if 0 # include #else /* */ /* */ # include #endif #endif #endif #endif #endif #endif /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ typedef struct _Options { const char * pszInclude; const char * pszExclude; BOOL fExcludeAll; const char * pszObjectExt; const char * pszObjectDir; BOOL fObjectDir; /* replace object directory? */ const char * pszRsrcExt; BOOL fObjRule; BOOL fNoObjectPath; BOOL fSrcWhenObj; BOOL fAppend; /* append to the output file, not overwrite it. */ BOOL fCheckCyclic; /* allways check for cylic dependency before inserting an dependent. */ BOOL fCacheSearchDirs; /* cache entire search dirs. */ const char * pszExcludeFiles; /* List of excluded files. */ BOOL fForceScan; /* Force scan of all files. */ } OPTIONS, *POPTIONS; /* * Language specific analysis functions type. */ typedef int ( _FNLANG) (const char *pszFilename, const char *pszNormFilename, const char *pszTS, BOOL fHeader, void **ppvRule); typedef _FNLANG *PFNLANG; /** * This struct holds the static configuration of the util. */ typedef struct _ConfigEntry { char szId[16]; /* Config ID. */ const char **papszExts; /* Pointer to an array of pointer to extentions for this handler. */ /* If NULL this is the last entry. */ int iFirstHdr; /* Index into the papszExts array of the first headerfile/copybook. */ /* Set it to the NULL element of the array if no headers for this extention. */ /* A non-header file may get a object rule. */ PFNLANG pfn; /* Pointer to handler function. */ char *pszzAddDeps; /* Pointer to an string of string of additional dependencies. */ } CONFIGENTRY, *PCONFIGENTRY; /** * Dependant Rule */ typedef struct _DepRule { AVLNODECORE avlCore; char * pszRule; /* Pointer to rule name */ int cDeps; /* Entries in the dependant array. */ char ** papszDep; /* Pointer to an array of pointers to dependants. */ BOOL fUpdated; /* If we have updated this entry during the run. */ char szTS[TS_SIZE]; /* Time stamp. */ } DEPRULE, *PDEPRULE; /** * Filename cache entry. */ #define FCACHEENTRY AVLNODECORE #define PFCACHEENTRY PAVLNODECORE /******************************************************************************* * Internal Functions * *******************************************************************************/ static void syntax(void); static int makeDependent(const char *pszFilename, const char *pszTS); static int langC_CPP(const char *pszFilename, const char *pszNormFilename, const char *pszTS, BOOL fHeader, void **ppvRule); static int langAsm( const char *pszFilename, const char *pszNormFilename, const char *pszTS, BOOL fHeader, void **ppvRule); static int langRC( const char *pszFilename, const char *pszNormFilename, const char *pszTS, BOOL fHeader, void **ppvRule); static int langCOBOL(const char *pszFilename, const char *pszNormFilename, const char *pszTS, BOOL fHeader, void **ppvRule); static int langIPF( const char *pszFilename, const char *pszNormFilename, const char *pszTS, BOOL fHeader, void **ppvRule); /* string operations */ static int strnicmpwords(const char *pszS1, const char *pszS2, int cch); /* file operations */ static char *fileNormalize(char *pszFilename); static char *fileNormalize2(const char *pszFilename, char *pszBuffer); char *filePath(const char *pszFilename, char *pszBuffer); static char *filePathSlash(const char *pszFilename, char *pszBuffer); static char *filePathSlash2(const char *pszFilename, char *pszBuffer); static char *fileName(const char *pszFilename, char *pszBuffer); static char *fileNameNoExt(const char *pszFilename, char *pszBuffer); static char *fileExt(const char *pszFilename, char *pszBuffer); /* filecache operations */ static BOOL filecacheAddFile(const char *pszFilename); static BOOL filecacheAddDir(const char *pszDir); INLINE BOOL filecacheFind(const char *pszFilename); INLINE BOOL filecacheIsDirCached(const char *pszDir); static char*filecacheFileExist(const char *pszFilename, char *pszBuffer); /* pathlist operations */ static char *pathlistFindFile(const char *pszPathList, const char *pszFilename, char *pszBuffer); static BOOL pathlistFindFile2(const char *pszPathList, const char *pszFilename); /* word operations */ static char *findEndOfWord(char *psz); #if 0 /* not used */ static char *findStartOfWord(char *psz, const char *pszStart); #endif /* file helpers */ static signed long fsize(FILE *phFile); /* text helpers */ INLINE char *trim(char *psz); INLINE char *trimR(char *psz); INLINE char *trimQuotes(char *psz); /* preprocessors */ static char *PreProcessLine(char *pszOut, const char *pszIn); /* textbuffer */ static void *textbufferCreate(const char *pszFilename); static void textbufferDestroy(void *pvBuffer); static char *textbufferNextLine(void *pvBuffer, char *psz); static char *textbufferGetNextLine(void *pvBuffer, void **ppv, char *pszLineBuffer, int cchLineBuffer); /* depend workers */ static BOOL depReadFile(const char *pszFilename, BOOL fAppend); static BOOL depWriteFile(const char *pszFilename, BOOL fWriteUpdatedOnly); static void depRemoveAll(void); static void *depAddRule(const char *pszRulePath, const char *pszName, const char *pszExt, const char *pszTS, BOOL fConvertName); static BOOL depAddDepend(void *pvRule, const char *pszDep, BOOL fCheckCyclic, BOOL fConvertName); static int depNameToReal(char *pszName); static int depNameToMake(char *pszName, int cchName, const char *pszSrc); static void depMarkNotFound(void *pvRule); static BOOL depCheckCyclic(PDEPRULE pdepRule, const char *pszDep); static BOOL depValidate(PDEPRULE pdepRule); INLINE char *depMakeTS(char *pszTS, PFILEFINDBUF3 pfindbuf3); static void depAddSrcAddDeps(void *pvRule, const char *pszz); /******************************************************************************* * Global Variables * *******************************************************************************/ /* * Pointer to the list of dependencies. */ static PDEPRULE pdepTree = NULL; /* * Filecache - tree starts here. */ static PFCACHEENTRY pfcTree = NULL; static unsigned cfcNodes = 0; static PFCACHEENTRY pfcDirTree = NULL; /* * Current directory stuff */ static char szCurDir[CCHMAXPATH]; static int aiSlashes[CCHMAXPATH]; static int cSlashes; /* * Environment variables used. * (These has the correct case.) */ static char * pszIncludeEnv; /* * Configuration stuff. */ static const char pszDefaultDepFile[] = ".depend"; static const char *apszExtC_CPP[] = {"c", "sqc", "cpp", "h", "hpp", NULL}; static const char *apszExtAsm[] = {"asm", "inc", NULL}; static const char *apszExtRC[] = {"rc", "dlg", NULL}; static const char *apszExtORC[] = {"orc", "dlg", NULL}; static const char *apszExtCOBOL[] = {"cbl", "cob", "sqb", "wbl", NULL}; static const char *apszExtIPF[] = {"ipf", "man", NULL}; static const char *apszExtIPP[] = {"ipp", NULL}; static CONFIGENTRY aConfig[] = { { "CX", apszExtC_CPP, 3, langC_CPP, NULL, }, { "AS", apszExtAsm, 1, langAsm, NULL, }, { "RC", apszExtRC, 1, langRC, NULL, }, { "ORC", apszExtORC, 1, langRC, NULL, }, { "COB", apszExtCOBOL, -1, langCOBOL, NULL, }, { "IPF", apszExtIPF, -1, langIPF, NULL, }, { "IPP", apszExtIPP, -1, langC_CPP, NULL, }, /* terminating entry */ { "", NULL, -1, NULL, NULL } }; static char szObjectDir[CCHMAXPATH]; static char szObjectExt[64] = "obj"; static char szRsrcExt[64] = "res"; static char szInclude[32768] = ";"; static char szExclude[32768] = ";"; static char szExcludeFiles[65536] = ""; OPTIONS options = { szInclude, /* pszInclude */ szExclude, /* pszExclude */ FALSE, /* fExcludeAll */ szObjectExt, /* pszObjectExt */ szObjectDir, /* pszObjectDir */ FALSE, /* fObjectDir */ szRsrcExt, /* pszRsrcExt */ TRUE, /* fObjRule */ FALSE, /* fNoObjectPath */ TRUE, /* fSrcWhenObj */ FALSE, /* fAppend */ TRUE, /* fCheckCyclic */ TRUE, /* fCacheSearchDirs */ szExcludeFiles, /* pszExcludeFiles */ FALSE /* fForceScan */ }; /** * Main function. * @returns 0 on success. * -n count of failiures. * @param * @param * @equiv * @precond * @methdesc * @result * @time * @sketch * @algo * @remark */ int main(int argc, char **argv) { int rc = 0; int argi = 1; int i; char * psz; char * psz2; const char *pszDepFile = pszDefaultDepFile; char achBuffer[4096]; szObjectDir[0] = '\0'; if (argc == 1) { syntax(); return -87; } /* * Initiate current directory stuff */ if (_getcwd(szCurDir, sizeof(szCurDir)) == NULL) { fprintf(stderr, "fatal error: failed to get current directory\n"); return -88; } strlwr(szCurDir); aiSlashes[0] = 0; for (i = 1, cSlashes; szCurDir[i] != '\0'; i++) { if (szCurDir[i] == '/') szCurDir[i] = '\\'; if (szCurDir[i] == '\\') aiSlashes[cSlashes++] = i; } if (szCurDir[i-1] != '\\') { aiSlashes[cSlashes] = i; szCurDir[i++] = '\\'; szCurDir[i] = '\0'; } /* * Initiate environment variables used: INCLUDE */ psz = getenv("INCLUDE"); if (psz != NULL) { pszIncludeEnv = strdup(psz); strlwr(pszIncludeEnv); } else pszIncludeEnv = ""; /* * Disable hard errors. */ DosError(FERR_DISABLEHARDERR | FERR_ENABLEEXCEPTION); /* * parse arguments */ while (argi < argc) { if (argv[argi][0] == '-' || argv[argi][0] == '/') { /* parameters */ switch (argv[argi][1]) { case 'A': case 'a': /* Append to the output file */ options.fAppend = argv[argi][2] != '-'; break; case 'D': case 'd': /* "-d " */ { const char *pszOld = pszDepFile; if (argv[argi][2] != '\0') pszDepFile = &argv[argi][2]; else { argi++; if (argi < argc) pszDepFile = argv[argi]; else { fprintf(stderr, "invalid parameter -d, filename missing!\n"); return -1; } } /* if dependencies are generated we'll flush them to the old filename */ if (pdepTree != NULL && pszOld != pszDepFile) { if (!depWriteFile(pszOld, !options.fAppend)) fprintf(stderr, "error: failed to write (flush) dependencies.\n"); depRemoveAll(); } break; } case 'C': /* forced directory cache 'ca' or cylic check 'cy'*/ case 'c': if (argv[argi][2] == 'a' || argv[argi][2] == 'A') options.fCacheSearchDirs = TRUE; else if ((argv[argi][2] == 'y' || argv[argi][2] == 'Y')) options.fCheckCyclic = argv[argi][3] != '-'; break; case 'E': /* list of paths. If a file is found in one of these directories the */ case 'e': /* filename will be used without the directory path. */ /* Eall<[+]|-> ? */ if (strlen(&argv[argi][1]) <= 5 && strnicmp(&argv[argi][1], "Eall", 4) == 0) { options.fExcludeAll = argv[argi][5] != '-'; break; } /* path or path list */ if (strlen(argv[argi]) > 2) psz = &argv[argi][2]; else { if (++argi >= argc) { fprintf(stderr, "syntax error! Option -e.\n"); return 1; } psz = argv[argi]; } /* check if enviroment variable */ if (*psz == '%') { psz2 = strdup(psz+1); if (psz2 != NULL && *psz2 != '\0') { if (psz2[strlen(psz2)-1] == '%') psz2[strlen(psz2)-1] = '\0'; psz = getenv(psz2); free(psz2); if (psz == NULL) break; } else { fprintf(stderr, "error: -E% is not an valid argument!\n"); return -1; } } if (psz != NULL) { strcat(szExclude, psz); strlwr(szExclude); if (szExclude[strlen(szExclude)-1] != ';') strcat(szExclude, ";"); } break; case 'f': case 'F': /* force scan of all files. */ options.fForceScan = argv[argi][2] != '-'; break; case 'I': /* optional include path. This has precedence over the INCLUDE environment variable. */ case 'i': if (strlen(argv[argi]) > 2) psz = &argv[argi][2]; else { if (++argi >= argc) { fprintf(stderr, "syntax error! Option -i.\n"); return 1; } psz = argv[argi]; } /* check if enviroment variable */ if (*psz == '%') { psz2 = strdup(psz+1); if (psz2 != NULL && *psz2 != '\0') { if (psz2[strlen(psz2)-1] == '%') psz2[strlen(psz2)-1] = '\0'; psz = getenv(psz2); free(psz2); if (psz == NULL) break; } else { fprintf(stderr, "error: -I% is not an valid argument!\n"); return -1; } } if (psz != NULL) { strcat(szInclude, psz); strlwr(szInclude); if (szInclude[strlen(szInclude)-1] != ';') strcat(szInclude, ";"); } break; case 'n': /* no object path , -N<[+]|-> */ case 'N': if (strlen(argv[argi]) <= 1+1+1) options.fNoObjectPath = argv[argi][2] != '-'; else { fprintf(stderr, "error: invalid parameter!, '%s'\n", argv[argi]); return -1; } break; case 'o': /* object base directory, Obj or Obr<[+]|-> */ case 'O': if (strlen(&argv[argi][1]) <= 4 && strnicmp(&argv[argi][1], "Obr", 3) == 0) { options.fObjRule = argv[argi][4] != '-'; break; } if (strlen(&argv[argi][1]) >= 4 && strnicmp(&argv[argi][1], "Obj", 3) == 0) { if (strlen(argv[argi]) > 4) strcpy(szObjectExt, argv[argi]+4); else { if (++argi >= argc) { fprintf(stderr, "syntax error! Option -obj.\n"); return 1; } strcpy(szObjectExt, argv[argi]); } break; } /* path: -o or -o- */ options.fObjectDir = TRUE; if (strlen(argv[argi]) > 2) { if (argv[argi][2] == '-') /* no object path */ szObjectDir[0] = '\0'; else strcpy(szObjectDir, argv[argi]+2); } else { if (++argi >= argc) { fprintf(stderr, "syntax error! Option -o.\n"); return 1; } strcpy(szObjectDir, argv[argi]); } if (szObjectDir[0] != '\0' && szObjectDir[strlen(szObjectDir)-1] != '\\' && szObjectDir[strlen(szObjectDir)-1] != '/' ) strcat(szObjectDir, "\\"); break; case 'r': case 'R': if (strlen(argv[argi]) > 2) strcpy(szRsrcExt, argv[argi]+2); else { if (++argi >= argc) { fprintf(stderr, "syntax error! Option -r.\n"); return 1; } strcpy(szRsrcExt, argv[argi]); } break; case 's': case 'S': if (!strnicmp(argv[argi]+1, "srcadd", 6)) { if (strlen(argv[argi]) > 7) psz = argv[argi]+2; else { if (++argi >= argc) { fprintf(stderr, "syntax error! Option -srcadd.\n"); return 1; } psz = argv[argi]; } if (!(psz2 = strchr(psz, ':'))) { fprintf(stderr, "syntax error! Option -srcadd malformed!\n"); return 1; } for (i = 0; aConfig[i].pfn; i++) { if ( !strnicmp(aConfig[i].szId, psz, psz2 - psz) && !aConfig[i].szId[psz2 - psz]) { int cch, cch2; if (!*++psz2) { fprintf(stderr, "error: Option -srcadd no additioanl dependancy!\n", psz2 - psz, psz); return 1; } cch = 0; psz = aConfig[i].pszzAddDeps; if (psz) { do { cch += (cch2 = strlen(psz)) + 1; psz += cch2 + 1; } while (*psz); } cch2 = strlen(psz2); aConfig[i].pszzAddDeps = realloc(aConfig[i].pszzAddDeps, cch + cch2 + 2); if (!aConfig[i].pszzAddDeps) { fprintf(stderr, "error: Out of memory!\n"); return 1; } strcpy(aConfig[i].pszzAddDeps + cch, psz2); aConfig[i].pszzAddDeps[cch + cch2 + 1] = '\0'; psz = NULL; break; } } if (psz) { fprintf(stderr, "error: Option -srcadd, invalid language id '%.*s%'\n", psz2 - psz, psz); return 1; } } else { fprintf(stderr, "syntax error! Invalid option %s\n", argv[argi]); return 1; } break; case 'x': case 'X': /* Exclude files */ psz = &achBuffer[CCHMAXPATH+8]; if (strlen(argv[argi]) > 2) strcpy(psz, &argv[argi][2]); else { if (++argi >= argc) { fprintf(stderr, "syntax error! Option -x.\n"); return 1; } strcpy(psz, argv[argi]); } while (psz != NULL && *psz != ';') { char * pszNext = strchr(psz, ';'); int cch = strlen(szExcludeFiles); if (pszNext) *pszNext++ = '\0'; if (DosQueryPathInfo(psz, FIL_QUERYFULLNAME, &szExcludeFiles[cch], CCHMAXPATH)) { fprintf(stderr, "error: Invalid exclude name\n"); return -1; } strlwr(&szExcludeFiles[cch]); strcat(&szExcludeFiles[cch], ";"); psz = pszNext; } break; case 'h': case 'H': case '?': syntax(); return 1; default: fprintf(stderr, "error: invalid parameter! '%s'\n", argv[argi]); return -1; } } else if (argv[argi][0] == '@') { /* * Parameter file (debugger parameter length restrictions led to this): * Create a textbuffer. * Parse the file and create a new parameter vector. * Set argv to the new parameter vector, argi to 0 and argc to * the parameter count. * Restrictions: Parameters enclosed in "" is not implemented. * No commandline parameters are processed after the @file */ char *pszBuffer = (char*)textbufferCreate(&argv[argi][1]); /* !ASSUMS! that pvBuffer is the file string! */ if (pszBuffer != NULL) { char **apszArgs = NULL; char *psz = pszBuffer; int i = 0; while (*psz != '\0') { /* find end of parameter word */ char *pszEnd = psz + 1; char ch = *pszEnd; while (ch != ' ' && ch != '\t' && ch != '\n' && ch != '\r' && ch != '\0') ch = *++pszEnd; /* allocate more arg array space? */ if ((i % 512) == 0) { apszArgs = realloc(apszArgs, sizeof(char*) * 512); if (apszArgs == NULL) { fprintf(stderr, "error: out of memory. (line=%d)\n", __LINE__); return -8; } } *pszEnd = '\0'; apszArgs[i++] = psz; /* next */ psz = pszEnd + 1; ch = *psz; while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') ch = *++psz; } argc = i; argi = 0; argv = apszArgs; continue; } else { fprintf(stderr, "error: could not open parameter file\n"); return -1; } } else { /* not a parameter! */ ULONG ulRc; PFILEFINDBUF3 pfindbuf3 = (PFILEFINDBUF3)(void*)&achBuffer[0]; HDIR hDir = HDIR_CREATE; ULONG cFiles = ~0UL; int i; /* * If append option is or if the forcescan option isn't is * we'll have to read the existing dep file before starting * adding new dependencies. */ if (pdepTree == NULL && (options.fAppend || !options.fForceScan)) depReadFile(pszDepFile, options.fAppend); /* * Search for the files specified. */ ulRc = DosFindFirst(argv[argi], &hDir, FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_ARCHIVED, pfindbuf3, sizeof(achBuffer), &cFiles, FIL_STANDARD); if (!options.fCacheSearchDirs) options.fCacheSearchDirs = cFiles > 25; while (ulRc == NO_ERROR) { for (i = 0; i < cFiles; i++, pfindbuf3 = (PFILEFINDBUF3)((int)pfindbuf3 + pfindbuf3->oNextEntryOffset) ) { const char * psz; char szSource[CCHMAXPATH]; BOOL fExcluded; char szTS[TS_SIZE]; /* * Make full path. */ if ((psz = strrchr(argv[argi], '\\')) || (psz = strrchr(argv[argi], '/')) || (*(psz = &argv[argi][1]) == ':')) { strncpy(szSource, argv[argi], psz - argv[argi] + 1); szSource[psz - argv[argi] + 1] = '\0'; } else szSource[0] = '\0'; strcat(szSource, pfindbuf3->achName); strlwr(szSource); fileNormalize(szSource); /* * Check if this is an excluded file. */ fExcluded = FALSE; psz = options.pszExcludeFiles; while (*psz != '\0' && *psz != ';') { const char * pszNext = strchr(psz, ';'); if (strlen(szSource) == pszNext - psz && strncmp(szSource, psz, pszNext - psz) == 0) fExcluded = TRUE; psz = pszNext + 1; } if (fExcluded) continue; /* * Analyse the file. */ depMakeTS(szTS, pfindbuf3); rc -= makeDependent(&szSource[0], szTS); } /* next file */ cFiles = ~0UL; pfindbuf3 = (PFILEFINDBUF3)(void*)&achBuffer[0]; ulRc = DosFindNext(hDir, pfindbuf3, sizeof(achBuffer), &cFiles); } DosFindClose(hDir); } /* next */ argi++; } /* Write the depend file! */ if (!depWriteFile(pszDepFile, !options.fAppend)) fprintf(stderr, "error: failed to write dependencies file!\n"); #if 0 printf("cfcNodes=%d\n", cfcNodes); #endif return rc; } /** * Displays the syntax description for this util. * @status completely implemented. * @author knut st. osmundsen */ void syntax(void) { printf( "FastDep v0.48 (build %d)\n" "Dependency scanner. Creates a makefile readable depend file.\n" " - was quick and dirty, now it's just quick -\n" "\n" "Syntax: FastDep [options] [more options [more files [...]]]\n" " or\n" " FastDep [options] @\n" "\n" "Options:\n" " -a<[+]|-> Append to the output file. Default: Overwrite.\n" " -ca Force search directory caching.\n" " Default: cache if more that 25 files are to be searched.\n" " (more than 25 in the first file expression.)\n" " -cy<[+]|-> Check for cylic dependencies. Default: -cy-\n" " -d Output filename. Default: %s\n" " -e excludepath Exclude paths. If a filename is found in any\n" " of these paths only the filename is used, not\n" " the path+filename (which is default).\n" " -eall<[+]|-> Include and source filenames, paths or no paths.\n" " -eall+: No path are added to the filename.\n" " -eall-: The filename is appended the include path\n" " was found in.\n" " Default: eall-\n" " -f<[+]|-> Force scanning of all files. If disabled we'll only scan\n" " files which are younger or up to one month older than the\n" " dependancy file (if it exists). Default: disabled\n" " -i Additional include paths. INCLUDE is searched after this.\n" " -n<[+]|-> No path for object files in the rules.\n" " -o Path were object files are placed. This path replaces the\n" " entire filename path\n" " -o- No object path\n" " -obr<[+]|-> -obr+: Object rule.\n" " -obr-: No object rule, rule for source filename is generated.\n" " -obj[ ] Object extention. Default: obj\n" " -srcadd[ ]:\n" " Additional dependants for source file of the given language\n" " type. langid: AS,CX,RC,ORC,COB,IPF\n" " This is very usfull for compiler configuration files.\n" " -r[ ] Resource binary extention. Default: res\n" " -x[ ] Files to exclude. Only exact filenames.\n" " Files to scan. Wildchars are allowed.\n" "\n" "Options and files could be mixed.\n" " copyright (c) 1999-2010 knut st. osmundsen (bird-kBuild-spamx@anduin.net)\n", ODIN32_BUILD_NR, pszDefaultDepFile ); } /** * Generates depend info on this file, these are stored internally * and written to file later. * @returns * @param pszFilename Pointer to source filename. Correct case is assumed! * @param pszTS File time stamp. * @status completely implemented. * @author knut st. osmundsen */ int makeDependent(const char *pszFilename, const char *pszTS) { int rc = -1; char szExt[CCHMAXPATH]; PCONFIGENTRY pCfg = &aConfig[0]; BOOL fHeader; /* * Find which filetype this is... */ fileExt(pszFilename, szExt); while (pCfg->papszExts != NULL) { const char **ppsz = pCfg->papszExts; while (*ppsz != NULL && stricmp(*ppsz, szExt) != 0) ppsz++; if (*ppsz != NULL) { fHeader = pCfg->iFirstHdr > 0 && &pCfg->papszExts[pCfg->iFirstHdr] <= ppsz; break; } pCfg++; } /* Found? */ if (pCfg->papszExts != NULL) { void * pvRule = NULL; char szNormFile[CCHMAXPATH]; fileNormalize2(pszFilename, szNormFile); rc = (*pCfg->pfn)(pszFilename, &szNormFile[0], pszTS, fHeader, &pvRule); if (!rc && pvRule) { if (!fHeader && pCfg->pszzAddDeps) depAddSrcAddDeps(pvRule, pCfg->pszzAddDeps); } } else { if (*fileName(pszFilename, szExt) != '.') /* these are 'hidden' files, like .cvsignore, let's ignore them. */ fprintf(stderr, "warning: '%s' has an unknown file type.\n", pszFilename); rc = 0; } return rc; } /** * Generates depend info on this C or C++ file, these are stored internally * and written to file later. * @returns 0 on success. * !0 on error. * @param pszFilename Pointer to source filename. Correct case is assumed! * @param pszNormFilename Pointer to normalized source filename. * @param pszTS File time stamp. * @parma fHeader True if header file is being scanned. * @param ppvRule Variabel to return any new rule handle. * @status completely implemented. * @author knut st. osmundsen */ int langC_CPP(const char *pszFilename, const char *pszNormFilename, const char *pszTS, BOOL fHeader, void **ppvRule) { void * pvFile; /* Text buffer pointer. */ void * pvRule; /* Handle to the current rule. */ char szBuffer[4096]; /* Max line length is 4096... should not be a problem. */ int iLine; /* Linenumber. */ void * pv = NULL; /* An index used by textbufferGetNextLine. */ BOOL fComment; /* TRUE when within a multiline comment. */ /* FALSE when not within a multiline comment. */ int iIfStack; /* StackPointer. */ struct IfStackEntry { int fIncluded : 1; /* TRUE: include this code; * FALSE: excluded */ int fIf : 1; /* TRUE: #if part of the expression. * FALSE: #else part of the expression. */ int fSupported : 1; /* TRUE: supported if/else statement * FALSE: unsupported all else[] are ignored * All code is included. */ } achIfStack[256]; char szSrcDir[CCHMAXPATH]; filePath(pszNormFilename, szSrcDir);/* determin source code directory. */ /**********************************/ /* Add the depend rule */ /**********************************/ if (options.fObjRule && !fHeader) { if (options.fNoObjectPath) pvRule = depAddRule(fileNameNoExt(pszFilename, szBuffer), NULL, options.pszObjectExt, pszTS, FALSE); else pvRule = depAddRule(options.fObjectDir ? options.pszObjectDir : filePathSlash(pszFilename, szBuffer), fileNameNoExt(pszFilename, szBuffer + CCHMAXPATH), options.pszObjectExt, pszTS, FALSE); if (options.fSrcWhenObj && pvRule) depAddDepend(pvRule, options.fExcludeAll || pathlistFindFile2(options.pszExclude, pszNormFilename) ? fileName(pszFilename, szBuffer) : pszNormFilename, options.fCheckCyclic, FALSE); } else pvRule = depAddRule(options.fExcludeAll || pathlistFindFile2(options.pszExclude, pszNormFilename) ? fileName(pszFilename, szBuffer) : pszNormFilename, NULL, NULL, pszTS, FALSE); /* duplicate rule? */ *ppvRule = pvRule; if (pvRule == NULL) return 0; /********************/ /* Make file buffer */ /********************/ pvFile = textbufferCreate(pszFilename); if (!pvFile) { fprintf(stderr, "failed to open '%s'\n", pszFilename); return -1; } /*******************/ /* find dependants */ /*******************/ /* Initiate the IF-stack, comment state and line number. */ iIfStack = 0; achIfStack[iIfStack].fIf = TRUE; achIfStack[iIfStack].fIncluded = TRUE; achIfStack[iIfStack].fSupported = TRUE; fComment = FALSE; iLine = 0; while (textbufferGetNextLine(pvFile, &pv, szBuffer, sizeof(szBuffer)) != NULL) /* line loop */ { /* search for #include */ register char *pszC; int cbLen; int i = 0; iLine++; /* skip blank chars */ cbLen = strlen(szBuffer); while (i + 2 < cbLen && (szBuffer[i] == ' ' || szBuffer[i] == '\t')) i++; /* preprocessor statement? */ if (!fComment && szBuffer[i] == '#') { /* * Preprocessor checks * We known that we have a preprocessor statment (starting with an '#' * at szBuffer[i]). * Depending on the word afterwards we'll take some different actions. * So we'll start of by extracting that word and make a string swich on it. * Note that there might be some blanks between the hash and the word. */ int cchWord; char * pszEndWord; char * pszArgument; i++; /* skip hash ('#') */ while (szBuffer[i] == '\t' || szBuffer[i] == ' ') /* skip blanks */ i++; pszArgument = pszEndWord = findEndOfWord(&szBuffer[i]); cchWord = pszEndWord - &szBuffer[i]; /* * Find the argument by skipping the blanks. */ while (*pszArgument == '\t' || *pszArgument == ' ') /* skip blanks */ pszArgument++; /* * string switch. */ if (strncmp(&szBuffer[i], "include", cchWord) == 0) { /* * #include * * Are we in a state where this file is to be included? */ if (achIfStack[iIfStack].fIncluded) { char szFullname[CCHMAXPATH]; char * psz; BOOL f = FALSE; int j; BOOL fQuote; /* extract info between "" or <> */ while (i < cbLen && !(f = (szBuffer[i] == '"' || szBuffer[i] == '<'))) i++; fQuote = szBuffer[i] == '"'; i++; /* skip '"' or '<' */ /* if invalid statement then continue with the next line! */ if (!f) continue; /* find end */ j = f = 0; while (i + j < cbLen && j < CCHMAXPATH && !(f = (szBuffer[i+j] == '"' || szBuffer[i+j] == '>'))) j++; /* if invalid statement then continue with the next line! */ if (!f) continue; /* copy filename */ strncpy(szFullname, &szBuffer[i], j); szFullname[j] = '\0'; /* ensure terminatition. */ strlwr(szFullname); /* find include file! */ psz = fQuote ? pathlistFindFile(szSrcDir, szFullname, szBuffer) : NULL; if (psz == NULL) psz = pathlistFindFile(options.pszInclude, szFullname, szBuffer); if (psz == NULL) psz = pathlistFindFile(pszIncludeEnv, szFullname, szBuffer); /* did we find the include? */ if (psz != NULL) { if (options.fExcludeAll || pathlistFindFile2(options.pszExclude, szBuffer)) { /* #include makes trouble, check for '/' and '\'. */ if (!strchr(szFullname, '/') && !strchr(szFullname, '\\')) depAddDepend(pvRule, szFullname, options.fCheckCyclic, FALSE); else fprintf(stderr, "%s(%d): warning include '%s' is ignored.\n", pszFilename, iLine, szFullname); } else depAddDepend(pvRule, szBuffer, options.fCheckCyclic, FALSE); } else { fprintf(stderr, "%s(%d): warning include file '%s' not found!\n", pszFilename, iLine, szFullname); depMarkNotFound(pvRule); } } } else /* * #if */ if (strncmp(&szBuffer[i], "if", cchWord) == 0) { /* #if 0 and #if <1-9> are supported */ pszEndWord = findEndOfWord(pszArgument); iIfStack++; if ((pszEndWord - pszArgument) == 1 && *pszArgument >= '0' && *pszArgument <= '9') { if (*pszArgument != '0') achIfStack[iIfStack].fIncluded = TRUE; else achIfStack[iIfStack].fIncluded = FALSE; } else achIfStack[iIfStack].fSupported = FALSE; achIfStack[iIfStack].fIncluded = TRUE; achIfStack[iIfStack].fIf = TRUE; } else /* * #else */ if (strncmp(&szBuffer[i], "else", cchWord) == 0) { if (achIfStack[iIfStack].fSupported) { if (achIfStack[iIfStack].fIncluded) /* ARG!! this'll prevent warning */ achIfStack[iIfStack].fIncluded = FALSE; else achIfStack[iIfStack].fIncluded = TRUE; } achIfStack[iIfStack].fIf = FALSE; } else /* * #endif */ if (strncmp(&szBuffer[i], "endif", cchWord) == 0) { /* Pop the if-stack. */ if (iIfStack > 0) iIfStack--; else fprintf(stderr, "%s(%d): If-Stack underflow!\n", pszFilename, iLine); } /* * general if and elseif implementations */ else if (strncmp(&szBuffer[i], "elseif", 6) == 0) { achIfStack[iIfStack].fSupported = FALSE; achIfStack[iIfStack].fIncluded = TRUE; } else if (strncmp(&szBuffer[i], "if", 2) == 0) { iIfStack++; achIfStack[iIfStack].fIf = TRUE; achIfStack[iIfStack].fSupported = FALSE; achIfStack[iIfStack].fIncluded = TRUE; } /* The rest of them aren't implemented yet. else if (strncmp(&szBuffer[i], "if") == 0) { } */ } /* * Comment checks. * -Start at first non-blank. * -Loop thru the line since we might have more than one * comment statement on a single line. */ pszC = &szBuffer[i]; while (pszC != NULL && *pszC != '\0') { if (fComment) pszC = strstr(pszC, "*/"); /* look for end comment mark. */ else { char *pszLC; pszLC= strstr(pszC, "//"); /* look for single line comment mark. */ pszC = strstr(pszC, "/*"); /* look for start comment mark */ if (pszLC && pszLC < pszC) /* if there is an single line comment mark before the */ break; /* muliline comment mark we'll ignore the multiline mark. */ } /* Comment mark found? */ if (pszC != NULL) { fComment = !fComment; pszC += 2; /* skip comment mark */ /* debug */ /* if (fComment) fprintf(stderr, "starts at line %d\n", iLine); else fprintf(stderr, "ends at line %d\n", iLine); */ } } } /*while*/ textbufferDestroy(pvFile); return 0; } /** * Generates depend info on this file, these are stored internally * and written to file later. * @returns 0 on success. * !0 on error. * @param pszFilename Pointer to source filename. Correct case is assumed! * @param pszNormFilename Pointer to normalized source filename. * @param pszTS File time stamp. * @parma fHeader True if header file is being scanned. * @param ppvRule Variabel to return any new rule handle. * @status completely implemented. * @author knut st. osmundsen */ int langAsm(const char *pszFilename, const char *pszNormFilename, const char *pszTS, BOOL fHeader, void **ppvRule) { void * pvFile; /* Text buffer pointer. */ void * pvRule; /* Handle to the current rule. */ char szBuffer[4096]; /* Temporary buffer (max line lenght size...) */ int iLine; /* current line number */ void * pv = NULL; /* An index used by textbufferGetNextLine. */ /**********************************/ /* Add the depend rule */ /**********************************/ if (options.fObjRule && !fHeader) { if (options.fNoObjectPath) pvRule = depAddRule(fileNameNoExt(pszFilename, szBuffer), NULL, options.pszObjectExt, pszTS, FALSE); else pvRule = depAddRule(options.fObjectDir ? options.pszObjectDir : filePathSlash(pszFilename, szBuffer), fileNameNoExt(pszFilename, szBuffer + CCHMAXPATH), options.pszObjectExt, pszTS, FALSE); if (options.fSrcWhenObj && pvRule) depAddDepend(pvRule, options.fExcludeAll || pathlistFindFile2(options.pszExclude, pszNormFilename) ? fileName(pszFilename, szBuffer) : pszNormFilename, options.fCheckCyclic, FALSE); } else pvRule = depAddRule(options.fExcludeAll || pathlistFindFile2(options.pszExclude, pszNormFilename) ? fileName(pszFilename, szBuffer) : pszNormFilename, NULL, NULL, pszTS, FALSE); /* duplicate rule? */ *ppvRule = pvRule; if (pvRule == NULL) return 0; /********************/ /* Make file buffer */ /********************/ pvFile = textbufferCreate(pszFilename); if (!pvFile) { fprintf(stderr, "failed to open '%s'\n", pszFilename); return -1; } /*******************/ /* find dependants */ /*******************/ iLine = 0; while (textbufferGetNextLine(pvFile, &pv, szBuffer, sizeof(szBuffer)) != NULL) /* line loop */ { /* search for include */ int cbLen; int i = 0; iLine++; /* skip blank chars */ cbLen = strlen(szBuffer); while (i + 9 < cbLen && (szBuffer[i] == ' ' || szBuffer[i] == '\t')) i++; /* is this an include? */ if (strnicmp(&szBuffer[i], "include", 7) == 0 && (szBuffer[i + 7] == '\t' || szBuffer[i + 7] == ' ') ) { char szFullname[CCHMAXPATH]; char *psz; int j; /* skip to first no blank char */ i += 7; while (i < cbLen && (szBuffer[i] == ' ' || szBuffer[i] == '\t')) i++; /* comment check - if comment found, no filename was given. continue. */ if (szBuffer[i] == ';') continue; /* find end */ j = 0; while (i + j < cbLen && j < CCHMAXPATH && szBuffer[i+j] != ' ' && szBuffer[i+j] != '\t' && szBuffer[i+j] != '\n' && szBuffer[i+j] != '\0' && szBuffer[i+j] != ';' && szBuffer[i+j] != '\r' ) j++; /* copy filename */ strncpy(szFullname, &szBuffer[i], j); szFullname[j] = '\0'; /* ensure terminatition. */ strlwr(szFullname); /* find include file! */ psz = pathlistFindFile(options.pszInclude, szFullname, szBuffer); if (psz == NULL) psz = pathlistFindFile(pszIncludeEnv, szFullname, szBuffer); /* Did we find the include? */ if (psz != NULL) { if (options.fExcludeAll || pathlistFindFile2(options.pszExclude, szBuffer)) { /* include sys/stats.inc makes trouble, check for '/' and '\'. */ if (!strchr(szFullname, '/') && !strchr(szFullname, '\\')) depAddDepend(pvRule, szFullname, options.fCheckCyclic, FALSE); else fprintf(stderr, "%s(%d): warning include '%s' is ignored.\n", pszFilename, iLine, szFullname); } else depAddDepend(pvRule, szBuffer, options.fCheckCyclic, FALSE); } else { fprintf(stderr, "%s(%d): warning include file '%s' not found!\n", pszFilename, iLine, szFullname); depMarkNotFound(pvRule); } } } /*while*/ textbufferDestroy(pvFile); return 0; } /** * Generates depend info on this Resource file, these are stored internally * and written to file later. * @returns 0 on success. * !0 on error. * @param pszFilename Pointer to source filename. Correct case is assumed! * @param pszNormFilename Pointer to normalized source filename. * @param pszTS File time stamp. * @parma fHeader True if header file is being scanned. * @status completely implemented. * @author knut st. osmundsen */ #if 0 int langRC(const char *pszFilename, const char *pszNormFilename, void *pvFile, BOOL fHeader) { void * pvFile; /* Text buffer pointer. */ void * pvRule; /* Handle to the current rule. */ char szBuffer[4096]; /* Temporary buffer (max line lenght size...) */ int iLine; /* current line number */ void * pv = NULL; /* An index used by textbufferGetNextLine. */ /**********************************/ /* Add the depend rule */ /**********************************/ if (options.fObjRule && !fHeader) { if (options.fNoObjectPath) pvRule = depAddRule(fileNameNoExt(pszFilename, szBuffer), NULL, options.pszRsrcExt, pszTS, FALSE); else pvRule = depAddRule(options.fObjectDir ? options.pszObjectDir : filePathSlash(pszFilename, szBuffer), fileNameNoExt(pszFilename, szBuffer + CCHMAXPATH), options.pszRsrcExt, pszTS, FALSE); if (options.fSrcWhenObj && pvRule) depAddDepend(pvRule, options.fExcludeAll || pathlistFindFile2(options.pszExclude, pszNormFilename) ? fileName(pszFilename, szBuffer) : fileNormalize2(pszFilename, szBuffer), options.fCheckCyclic, FALSE); } else pvRule = depAddRule(options.fExcludeAll || pathlistFindFile2(options.pszExclude, pszNormFilename) ? fileName(pszFilename, szBuffer) : pszNormFilename, NULL, NULL, pszTS, FALSE); /* duplicate rule? */ *ppvRule = pvRule; if (pvRule == NULL) return 0; /********************/ /* Make file buffer */ /********************/ pvFile = textbufferCreate(pszFilename); if (!pvFile) { fprintf(stderr, "failed to open '%s'\n", pszFilename); return -1; } /*******************/ /* find dependants */ /*******************/ iLine = 0; while (textbufferGetNextLine(pvFile, &pv, szBuffer, sizeof(szBuffer)) != NULL) /* line loop */ { /* search for #include */ int cbLen; int i = 0; int i1; iLine++; /* skip blank chars */ cbLen = strlen(szBuffer); while (i + 9 < cbLen && (szBuffer[i] == ' ' || szBuffer[i] == '\t')) i++; /* is this an include? */ i1 = 1; if ( strncmp(&szBuffer[i], "#include", 8) == 0 || (i1 = strnicmp(&szBuffer[i], "RCINCLUDE", 9)) == 0 || strnicmp(&szBuffer[i], "DLGINCLUDE", 10) == 0 ) { char szFullname[CCHMAXPATH]; char *psz; BOOL f = FALSE; int j; if (i1 != 0) { /* * #include , #include "file.h" or DLGINCLUDE 1 "file.h" * * extract info between "" or <> */ while (i < cbLen && !(f = (szBuffer[i] == '"' || szBuffer[i] == '<'))) i++; i++; /* skip '"' or '<' */ /* if invalid statement then continue with the next line! */ if (!f) continue; /* find end */ j = f = 0; while (i + j < cbLen && j < CCHMAXPATH && !(f = (szBuffer[i+j] == '"' || szBuffer[i+j] == '>'))) j++; /* if invalid statement then continue with the next line! */ if (!f) continue; } else { /* * RCINCLUDE ["]filename.dlg["] * Extract filename. */ /* skip to filename.dlg start - if eol will continue to loop. */ i += 9; while (szBuffer[i] == ' ' || szBuffer[i] == '\t' || szBuffer[i] == '"') i++; if (szBuffer[i] == '\0') continue; /* search to end of filename. */ j = i+1; while ( szBuffer[i+j] != ' ' && szBuffer[i+j] != '\t' && szBuffer[i+j] != '"' && szBuffer[i+j] != '\0') j++; } /* copy filename */ strncpy(szFullname, &szBuffer[i], j); szFullname[j] = '\0'; /* ensure terminatition. */ strlwr(szFullname); /* find include file! */ psz = pathlistFindFile(options.pszInclude, szFullname, szBuffer); if (psz == NULL) psz = pathlistFindFile(pszIncludeEnv, szFullname, szBuffer); /* did we find the include? */ if (psz != NULL) { if (options.fExcludeAll || pathlistFindFile2(options.pszExclude, szBuffer)) { /* #include makes trouble, check for '/' and '\'. */ if (!strchr(szFullname, '/') && !strchr(szFullname, '\\')) depAddDepend(pvRule, szFullname, options.fCheckCyclic, FALSE); else fprintf(stderr, "%s(%d): warning include '%s' is ignored.\n", pszFilename, iLine, szFullname); } else depAddDepend(pvRule, szBuffer, options.fCheckCyclic, FALSE); } else { fprintf(stderr, "%s(%d): warning include file '%s' not found!\n", pszFilename, iLine, szFullname); depMarkNotFound(pvRule); } } } /*while*/ textbufferDestroy(pvFile); return 0; } #else int langRC(const char *pszFilename, const char *pszNormFilename, const char *pszTS, BOOL fHeader, void **ppvRule) { void * pvFile; /* Text buffer pointer. */ void * pvRule; /* Handle to the current rule. */ char szBuffer[4096]; /* Max line length is 4096... should not be a problem. */ int iLine; /* Linenumber. */ void * pv = NULL; /* An index used by textbufferGetNextLine. */ BOOL fComment; /* TRUE when within a multiline comment. */ /* FALSE when not within a multiline comment. */ int iIfStack; /* StackPointer. */ struct IfStackEntry { int fIncluded : 1; /* TRUE: include this code; * FALSE: excluded */ int fIf : 1; /* TRUE: #if part of the expression. * FALSE: #else part of the expression. */ int fSupported : 1; /* TRUE: supported if/else statement * FALSE: unsupported all else[] are ignored * All code is included. */ } achIfStack[256]; /**********************************/ /* Add the depend rule */ /**********************************/ if (options.fObjRule && !fHeader) { if (options.fNoObjectPath) pvRule = depAddRule(fileNameNoExt(pszFilename, szBuffer), NULL, options.pszRsrcExt, pszTS, FALSE); else pvRule = depAddRule(options.fObjectDir ? options.pszObjectDir : filePathSlash(pszFilename, szBuffer), fileNameNoExt(pszFilename, szBuffer + CCHMAXPATH), options.pszRsrcExt, pszTS, FALSE); if (options.fSrcWhenObj && pvRule) depAddDepend(pvRule, options.fExcludeAll || pathlistFindFile2(options.pszExclude, pszNormFilename) ? fileName(pszFilename, szBuffer) : pszNormFilename, options.fCheckCyclic, FALSE); } else pvRule = depAddRule(options.fExcludeAll || pathlistFindFile2(options.pszExclude, pszNormFilename) ? fileName(pszFilename, szBuffer) : pszNormFilename, NULL, NULL, pszTS, FALSE); /* duplicate rule? */ *ppvRule = pvRule; if (pvRule == NULL) return 0; /********************/ /* Make file buffer */ /********************/ pvFile = textbufferCreate(pszFilename); if (!pvFile) { fprintf(stderr, "failed to open '%s'\n", pszFilename); return -1; } /*******************/ /* find dependants */ /*******************/ /* Initiate the IF-stack, comment state and line number. */ iIfStack = 0; achIfStack[iIfStack].fIf = TRUE; achIfStack[iIfStack].fIncluded = TRUE; achIfStack[iIfStack].fSupported = TRUE; fComment = FALSE; iLine = 0; while (textbufferGetNextLine(pvFile, &pv, szBuffer, sizeof(szBuffer)) != NULL) /* line loop */ { register char * pszC; char szFullname[CCHMAXPATH]; int cbLen; int i1 = 1; int i = 0; iLine++; /* skip blank chars */ cbLen = strlen(szBuffer); while (i + 2 < cbLen && (szBuffer[i] == ' ' || szBuffer[i] == '\t')) i++; /* preprocessor statement? */ if (!fComment && szBuffer[i] == '#') { /* * Preprocessor checks * We known that we have a preprocessor statment (starting with an '#' * at szBuffer[i]). * Depending on the word afterwards we'll take some different actions. * So we'll start of by extracting that word and make a string swich on it. * Note that there might be some blanks between the hash and the word. */ int cchWord; char * pszEndWord; char * pszArgument; i++; /* skip hash ('#') */ while (szBuffer[i] == '\t' || szBuffer[i] == ' ') /* skip blanks */ i++; pszArgument = pszEndWord = findEndOfWord(&szBuffer[i]); cchWord = pszEndWord - &szBuffer[i]; /* * Find the argument by skipping the blanks. */ while (*pszArgument == '\t' || *pszArgument == ' ') /* skip blanks */ pszArgument++; /* * string switch. */ if (strncmp(&szBuffer[i], "include", cchWord) == 0) { /* * #include * * Are we in a state where this file is to be included? */ if (achIfStack[iIfStack].fIncluded) { char *psz; BOOL f = FALSE; int j; /* extract info between "" or <> */ while (i < cbLen && !(f = (szBuffer[i] == '"' || szBuffer[i] == '<'))) i++; i++; /* skip '"' or '<' */ /* if invalid statement then continue with the next line! */ if (!f) continue; /* find end */ j = f = 0; while (i + j < cbLen && j < CCHMAXPATH && !(f = (szBuffer[i+j] == '"' || szBuffer[i+j] == '>'))) j++; /* if invalid statement then continue with the next line! */ if (!f) continue; /* copy filename */ strncpy(szFullname, &szBuffer[i], j); szFullname[j] = '\0'; /* ensure terminatition. */ strlwr(szFullname); /* find include file! */ psz = pathlistFindFile(options.pszInclude, szFullname, szBuffer); if (psz == NULL) psz = pathlistFindFile(pszIncludeEnv, szFullname, szBuffer); /* did we find the include? */ if (psz != NULL) { if (options.fExcludeAll || pathlistFindFile2(options.pszExclude, szBuffer)) { /* #include makes trouble, check for '/' and '\'. */ if (!strchr(szFullname, '/') && !strchr(szFullname, '\\')) depAddDepend(pvRule, szFullname, options.fCheckCyclic, FALSE); else fprintf(stderr, "%s(%d): warning include '%s' is ignored.\n", pszFilename, iLine, szFullname); } else depAddDepend(pvRule, szBuffer, options.fCheckCyclic, FALSE); } else { fprintf(stderr, "%s(%d): warning include file '%s' not found!\n", pszFilename, iLine, szFullname); depMarkNotFound(pvRule); } } } else /* * #if */ if (strncmp(&szBuffer[i], "if", cchWord) == 0) { /* #if 0 and #if <1-9> are supported */ pszEndWord = findEndOfWord(pszArgument); iIfStack++; if ((pszEndWord - pszArgument) == 1 && *pszArgument >= '0' && *pszArgument <= '9') { if (*pszArgument != '0') achIfStack[iIfStack].fIncluded = TRUE; else achIfStack[iIfStack].fIncluded = FALSE; } else achIfStack[iIfStack].fSupported = FALSE; achIfStack[iIfStack].fIncluded = TRUE; achIfStack[iIfStack].fIf = TRUE; } else /* * #else */ if (strncmp(&szBuffer[i], "else", cchWord) == 0) { if (achIfStack[iIfStack].fSupported) { if (achIfStack[iIfStack].fIncluded) /* ARG!! this'll prevent warning */ achIfStack[iIfStack].fIncluded = FALSE; else achIfStack[iIfStack].fIncluded = TRUE; } achIfStack[iIfStack].fIf = FALSE; } else /* * #endif */ if (strncmp(&szBuffer[i], "endif", cchWord) == 0) { /* Pop the if-stack. */ if (iIfStack > 0) iIfStack--; else fprintf(stderr, "%s(%d): If-Stack underflow!\n", pszFilename, iLine); } /* * general if and elseif implementations */ else if (strncmp(&szBuffer[i], "elseif", 6) == 0) { achIfStack[iIfStack].fSupported = FALSE; achIfStack[iIfStack].fIncluded = TRUE; } else if (strncmp(&szBuffer[i], "if", 2) == 0) { iIfStack++; achIfStack[iIfStack].fIf = TRUE; achIfStack[iIfStack].fSupported = FALSE; achIfStack[iIfStack].fIncluded = TRUE; } /* The rest of them aren't implemented yet. else if (strncmp(&szBuffer[i], "if") == 0) { } */ } else /* * Check for resource compiler directives. */ if ( !fComment && !strchr(&szBuffer[i], ',') && ( !strnicmp(&szBuffer[i], "ICON", 4) || !strnicmp(&szBuffer[i], "FONT", 4) || !strnicmp(&szBuffer[i], "BITMAP", 6) || !strnicmp(&szBuffer[i], "POINTER", 7) || !strnicmp(&szBuffer[i], "RESOURCE", 8) || !(i1 = strnicmp(&szBuffer[i], "RCINCLUDE", 9)) /*|| !strnicmp(&szBuffer[i], "DLGINCLUDE", 10) - only used by the dlgeditor */ || !strnicmp(&szBuffer[i], "DEFAULTICON", 11) ) ) { /* * RESOURCE 123 1 ["]filename.ext["] */ char szLine[1024]; char * pszFile; char chQuote = ' '; PreProcessLine(szLine, &szBuffer[i]); pszFile = &szLine[strlen(szLine)-1]; if (*pszFile == '\"' || *pszFile == '\'') { chQuote = *pszFile; *pszFile-- = '\0'; } while (*pszFile != chQuote) pszFile--; *pszFile++ = '\0'; /* We now have extracted the filename - pszFile. */ strlwr(pszFile); /* Add filename to the dependencies. */ if (i1) depAddDepend(pvRule, pszFile, options.fCheckCyclic, FALSE); else { char *psz; /* find include file! */ psz = pathlistFindFile(options.pszInclude, pszFile, szFullname); if (psz == NULL) psz = pathlistFindFile(pszIncludeEnv, pszFile, szFullname); /* did we find the include? */ if (psz != NULL) { if (options.fExcludeAll || pathlistFindFile2(options.pszExclude, szFullname)) { /* #include makes trouble, check for '/' and '\'. */ if (!strchr(pszFile, '/') && !strchr(pszFile, '\\')) depAddDepend(pvRule, pszFile, options.fCheckCyclic, FALSE); else fprintf(stderr, "%s(%d): warning include '%s' is ignored.\n", pszFilename, iLine, pszFile); } else depAddDepend(pvRule, szFullname, options.fCheckCyclic, FALSE); } else { fprintf(stderr, "%s(%d): warning include file '%s' not found!\n", pszFilename, iLine, pszFile); depMarkNotFound(pvRule); } } } /* * Comment checks. * -Start at first non-blank. * -Loop thru the line since we might have more than one * comment statement on a single line. */ pszC = &szBuffer[i]; while (pszC != NULL && *pszC != '\0') { if (fComment) pszC = strstr(pszC, "*/"); /* look for end comment mark. */ else { char *pszLC; pszLC= strstr(pszC, "//"); /* look for single line comment mark. */ pszC = strstr(pszC, "/*"); /* look for start comment mark */ if (pszLC && pszLC < pszC) /* if there is an single line comment mark before the */ break; /* muliline comment mark we'll ignore the multiline mark. */ } /* Comment mark found? */ if (pszC != NULL) { fComment = !fComment; pszC += 2; /* skip comment mark */ /* debug */ /* if (fComment) fprintf(stderr, "starts at line %d\n", iLine); else fprintf(stderr, "ends at line %d\n", iLine); */ } } } /*while*/ textbufferDestroy(pvFile); return 0; } #endif /** * Generates depend info on this COBOL file, these are stored internally * and written to file later. * @returns 0 on success. * !0 on error. * @param pszFilename Pointer to source filename. Correct case is assumed! * @param pszNormFilename Pointer to normalized source filename. * @param pszTS File time stamp. * @parma fHeader True if header file is being scanned. * @param ppvRule Variabel to return any new rule handle. * @status completely implemented. * @author knut st. osmundsen */ int langCOBOL(const char *pszFilename, const char *pszNormFilename, const char *pszTS, BOOL fHeader, void **ppvRule) { void * pvFile; /* Text buffer pointer. */ void * pvRule; /* Handle to the current rule. */ char szBuffer[4096]; /* Temporary buffer (max line lenght size...) */ int iLine; /* current line number */ void * pv = NULL; /* An index used by textbufferGetNextLine. */ /**********************************/ /* Add the depend rule */ /**********************************/ if (options.fObjRule && !fHeader) { if (options.fNoObjectPath) pvRule = depAddRule(fileNameNoExt(pszFilename, szBuffer), NULL, options.pszObjectExt, pszTS, FALSE); else pvRule = depAddRule(options.fObjectDir ? options.pszObjectDir : filePathSlash(pszFilename, szBuffer), fileNameNoExt(pszFilename, szBuffer + CCHMAXPATH), options.pszObjectExt, pszTS, FALSE); if (options.fSrcWhenObj && pvRule) depAddDepend(pvRule, options.fExcludeAll || pathlistFindFile2(options.pszExclude, pszNormFilename) ? fileName(pszFilename, szBuffer) : fileNormalize2(pszFilename, szBuffer), options.fCheckCyclic, FALSE); } else pvRule = depAddRule(options.fExcludeAll || pathlistFindFile2(options.pszExclude, pszNormFilename) ? fileName(pszFilename, szBuffer) : pszNormFilename, NULL, NULL, pszTS, FALSE); /* duplicate rule? */ *ppvRule = pvRule; if (pvRule == NULL) return 0; /********************/ /* Make file buffer */ /********************/ pvFile = textbufferCreate(pszFilename); if (!pvFile) { fprintf(stderr, "failed to open '%s'\n", pszFilename); return -1; } /*******************/ /* find dependants */ /*******************/ iLine = 0; while (textbufferGetNextLine(pvFile, &pv, szBuffer, sizeof(szBuffer)) != NULL) /* line loop */ { /* search for #include */ int cbLen; int i = 0; int i1, i2; iLine++; /* check for comment mark (column 7) */ if (szBuffer[6] == '*') continue; /* skip blank chars */ cbLen = strlen(szBuffer); while (i + 9 < cbLen && (szBuffer[i] == ' ' || szBuffer[i] == '\t')) i++; /* is this an include? */ if ( (i1 = strnicmp(&szBuffer[i], "COPY", 4)) == 0 || (i2 = strnicmpwords(&szBuffer[i], "EXEC SQL INCLUDE", 16)) == 0 ) { char szFullname[CCHMAXPATH]; char *psz; int j; /* skip statement */ i += 4; if (i1 != 0) { int y = 2; /* skip two words */ do { /* skip blanks */ while (szBuffer[i] == ' ' || szBuffer[i] == '\t') i++; /* skip word */ while (szBuffer[i] != ' ' && szBuffer[i] != '\t' && szBuffer[i] != '\0' && szBuffer[i] != '\n') i++; y--; } while (y > 0); } /* check for blank */ if (szBuffer[i] != ' ' && szBuffer[i] != '\t') /* no copybook specified... */ continue; /* skip blanks */ while (szBuffer[i] == ' ' || szBuffer[i] == '\t') i++; /* if invalid statement then continue with the next line! */ if (szBuffer[i] == '\0' || szBuffer[i] == '\n') continue; /* find end */ j = 0; while (i + j < cbLen && j < CCHMAXPATH && szBuffer[i+j] != '.' && szBuffer[i+j] != ' ' && szBuffer[i+j] != '\t' && szBuffer[i+j] != '\0' && szBuffer[i+j] != '\n' ) j++; /* if invalid statement then continue with the next line! */ if (szBuffer[i+j] != '.' && szBuffer[i+j] != ' ' && szBuffer[i] != '\t') continue; /* copy filename */ strncpy(szFullname, &szBuffer[i], j); szFullname[j] = '\0'; /* ensure terminatition. */ strlwr(szFullname); /* add extention .cpy - hardcoded for the moment. */ strcpy(&szFullname[j], ".cbl"); /* find include file! */ psz = pathlistFindFile(options.pszInclude, szFullname, szBuffer); if (!psz) { strcpy(&szFullname[j], ".cpy"); psz = pathlistFindFile(options.pszInclude, szFullname, szBuffer); } /* did we find the include? */ if (psz != NULL) { if (options.fExcludeAll || pathlistFindFile2(options.pszExclude, szBuffer)) depAddDepend(pvRule, szFullname, options.fCheckCyclic, FALSE); else depAddDepend(pvRule, szBuffer, options.fCheckCyclic, FALSE); } else { szFullname[j] = '\0'; fprintf(stderr, "%s(%d): warning copybook '%s' was not found!\n", pszFilename, iLine, szFullname); depMarkNotFound(pvRule); } } } /*while*/ textbufferDestroy(pvFile); return 0; } /** * Generates depend info on this IPF file, these are stored internally * and written to file later. * @returns 0 on success. * !0 on error. * @param pszFilename Pointer to source filename. Correct case is assumed! * @param pszNormFilename Pointer to normalized source filename. * @param pszTS File time stamp. * @param fHeader True if header file is being scanned. * @param ppvRule Variabel to return any new rule handle. * @status completely implemented. * @author knut st. osmundsen */ int langIPF( const char *pszFilename, const char *pszNormFilename, const char *pszTS, BOOL fHeader, void **ppvRule) { void * pvFile; /* Text buffer pointer. */ void * pvRule; /* Handle to the current rule. */ char szBuffer[4096]; /* Temporary buffer (max line lenght size...) */ int iLine; /* current line number */ void * pv = NULL; /* An index used by textbufferGetNextLine. */ /**********************************/ /* Add the depend rule */ /**********************************/ /*if (options.fObjRule && !fHeader) { if (options.fNoObjectPath) pvRule = depAddRule(fileNameNoExt(pszFilename, szBuffer), NULL, options.pszObjectExt, pszTS, FALSE); else pvRule = depAddRule(options.fObjectDir ? options.pszObjectDir : filePathSlash(pszFilename, szBuffer), fileNameNoExt(pszFilename, szBuffer + CCHMAXPATH), options.pszObjectExt, pszTS, FALSE); if (options.fSrcWhenObj && pvRule) depAddDepend(pvRule, options.fExcludeAll || pathlistFindFile2(options.pszExclude, pszNormFilename) ? fileName(pszFilename, szBuffer) : fileNormalize2(pszFilename, szBuffer), options.fCheckCyclic, FALSE); } else */ pvRule = depAddRule(options.fExcludeAll || pathlistFindFile2(options.pszExclude, pszNormFilename) ? fileName(pszFilename, szBuffer) : pszNormFilename, NULL, NULL, pszTS, FALSE); /* duplicate rule? */ *ppvRule = pvRule; if (pvRule == NULL) return 0; /********************/ /* Make file buffer */ /********************/ pvFile = textbufferCreate(pszFilename); if (!pvFile) { fprintf(stderr, "failed to open '%s'\n", pszFilename); return -1; } /*******************/ /* find dependants */ /*******************/ iLine = 0; while (textbufferGetNextLine(pvFile, &pv, szBuffer, sizeof(szBuffer)) != NULL) /* line loop */ { iLine++; /* is this an imbed statement? */ if (!strncmp(&szBuffer[0], ".im", 3)) { char szFullname[CCHMAXPATH]; char * psz; int i; int j; char chQuote = 0; /* skip statement and blanks */ i = 4; while (szBuffer[i] == ' ' || szBuffer[i] == '\t') i++; /* check for quotes */ if (szBuffer[i] == '\'' || szBuffer[i] == '\"') chQuote = szBuffer[i++]; /* find end */ j = 0; if (chQuote != 0) { while (szBuffer[i+j] != chQuote && szBuffer[i+j] != '\n' && szBuffer[i+j] != '\r' && szBuffer[i+j] != '\0') j++; } else { while (szBuffer[i+j] != '\n' && szBuffer[i+j] != '\r' && szBuffer[i+j] != '\0') j++; } /* find end */ if (j >= CCHMAXPATH) { fprintf(stderr, "%s(%d) warning: Filename too long ignored.\n", pszFilename, iLine); continue; } /* copy filename */ strncpy(szFullname, &szBuffer[i], j); szFullname[j] = '\0'; /* ensure terminatition. */ strlwr(szFullname); /* find include file! */ psz = filecacheFileExist(szFullname, szBuffer); /* did we find the include? */ if (psz != NULL) { if (options.fExcludeAll || pathlistFindFile2(options.pszExclude, szBuffer)) depAddDepend(pvRule, fileName(szFullname, szBuffer), options.fCheckCyclic, FALSE); else depAddDepend(pvRule, szBuffer, options.fCheckCyclic, FALSE); } else { fprintf(stderr, "%s(%d): warning imbeded file '%s' was not found!\n", pszFilename, iLine, szFullname); depMarkNotFound(pvRule); } } } /*while*/ textbufferDestroy(pvFile); fHeader = fHeader; return 0; } #define upcase(ch) \ (ch >= 'a' && ch <= 'z' ? ch - ('a' - 'A') : ch) /** * Compares words. Multiple spaces are treates as on single blank i both string when comparing them. * @returns 0 equal. (same as strnicmp) * @param pszS1 String 1 * @param pszS2 String 2 * @param cch Length to compare (relative to string 1) */ int strnicmpwords(const char *pszS1, const char *pszS2, int cch) { do { while (cch > 0 && upcase(*pszS1) == upcase(*pszS2) && *pszS1 != ' ') pszS1++, pszS2++, cch--; /* blank test and skipping */ if (cch > 0 && *pszS1 == ' ' && *pszS2 == ' ') { while (cch > 0 && *pszS1 == ' ') pszS1++, cch--; while (*pszS2 == ' ') pszS2++; } else break; } while (cch > 0); return cch == 0 ? 0 : *pszS1 - *pszS2; } /** * Normalizes the path slashes for the filename. It will partially expand paths too. * @returns pszFilename * @param pszFilename Pointer to filename string. Not empty string! * Much space to play with. */ char *fileNormalize(char *pszFilename) { char *psz = pszFilename; /* correct slashes */ while ((pszFilename = strchr(pszFilename, '//')) != NULL) *pszFilename++ = '\\'; /* expand path? */ pszFilename = psz; if (pszFilename[1] != ':') { /* relative path */ int iSlash; char szFile[CCHMAXPATH]; char * psz = szFile; strcpy(szFile, pszFilename); iSlash = *psz == '\\' ? 1 : cSlashes; while (*psz != '\0') { if (*psz == '.' && psz[1] == '.' && psz[2] == '\\') { /* up one directory */ if (iSlash > 0) iSlash--; psz += 3; } else if (*psz == '.' && psz[1] == '\\') { /* no change */ psz += 2; } else { /* completed expantion! */ strncpy(pszFilename, szCurDir, aiSlashes[iSlash]+1); strcpy(pszFilename + aiSlashes[iSlash]+1, psz); break; } } } /* else: assume full path */ return psz; } /** * Normalizes the path slashes for the filename. It will partially expand paths too. * Makes name all lower case too. * @returns pszFilename * @param pszFilename Pointer to filename string. Not empty string! * Much space to play with. * @param pszBuffer Pointer to output buffer. */ char *fileNormalize2(const char *pszFilename, char *pszBuffer) { char * psz = pszBuffer; int iSlash; if (pszFilename[1] != ':') { /* iSlash */ if (*pszFilename == '\\' || *pszFilename == '/') iSlash = 1; else iSlash = cSlashes; /* interpret . and .. */ while (*pszFilename != '\0') { if (*pszFilename == '.' && pszFilename[1] == '.' && (pszFilename[2] == '\\' || pszFilename[1] == '/')) { /* up one directory */ if (iSlash > 0) iSlash--; pszFilename += 3; } else if (*pszFilename == '.' && (pszFilename[1] == '\\' || pszFilename[1] == '/')) { /* no change */ pszFilename += 2; } else { /* completed expantion! - TODO ..\ or .\ may appare within the remaining path too... */ strncpy(pszBuffer, szCurDir, aiSlashes[iSlash]+1); strcpy(pszBuffer + aiSlashes[iSlash]+1, pszFilename); break; } } } else { /* have drive letter specified - assume ok (TODO)*/ strcpy(pszBuffer, pszFilename); } /* correct slashes */ while ((pszBuffer = strchr(pszBuffer, '//')) != NULL) *pszBuffer++ = '\\'; /* lower case it */ /*strlwr(psz);*/ return psz; } /** * Copies the path part (excluding the slash) into pszBuffer and returns * a pointer to the buffer. * If no path is found "" is returned. * @returns Pointer to pszBuffer with path. * @param pszFilename Pointer to readonly filename. * @param pszBuffer Pointer to output Buffer. * @status completely implemented. * @author knut st. osmundsen */ char *filePath(const char *pszFilename, char *pszBuffer) { char *psz = strrchr(pszFilename, '\\'); if (psz == NULL) psz = strrchr(pszFilename, '/'); if (psz == NULL) *pszBuffer = '\0'; else { strncpy(pszBuffer, pszFilename, psz - pszFilename); pszBuffer[psz - pszFilename] = '\0'; } return pszBuffer; } /** * Copies the path part including the slash into pszBuffer and returns * a pointer to the buffer. * If no path is found "" is returned. * @returns Pointer to pszBuffer with path. * @param pszFilename Pointer to readonly filename. * @param pszBuffer Pointer to output Buffer. * @status completely implemented. * @author knut st. osmundsen */ char *filePathSlash(const char *pszFilename, char *pszBuffer) { char *psz = strrchr(pszFilename, '\\'); if (psz == NULL) psz = strrchr(pszFilename, '/'); if (psz == NULL) *pszBuffer = '\0'; else { strncpy(pszBuffer, pszFilename, psz - pszFilename + 1); pszBuffer[psz - pszFilename + 1] = '\0'; } return pszBuffer; } /** * Copies the path part including the slash into pszBuffer and returns * a pointer to the buffer. If no path is found "" is returned. * The path is normalized to only use '\\'. * @returns Pointer to pszBuffer with path. * @param pszFilename Pointer to readonly filename. * @param pszBuffer Pointer to output Buffer. * @status completely implemented. * @author knut st. osmundsen */ char *filePathSlash2(const char *pszFilename, char *pszBuffer) { char *psz = strrchr(pszFilename, '\\'); if (psz == NULL) psz = strrchr(pszFilename, '/'); if (psz == NULL) *pszBuffer = '\0'; else { strncpy(pszBuffer, pszFilename, psz - pszFilename + 1); pszBuffer[psz - pszFilename + 1] = '\0'; /* normalize all '/' to '\\' */ psz = pszBuffer; while ((psz = strchr(psz, '/')) != NULL) *psz++ = '\\'; } return pszBuffer; } /** * Copies the filename (with extention) into pszBuffer and returns * a pointer to the buffer. * @returns Pointer to pszBuffer with path. * @param pszFilename Pointer to readonly filename. * @param pszBuffer Pointer to output Buffer. * @status completely implemented. * @author knut st. osmundsen */ char *fileName(const char *pszFilename, char *pszBuffer) { char *psz = strrchr(pszFilename, '\\'); if (psz == NULL) psz = strrchr(pszFilename, '/'); strcpy(pszBuffer, psz == NULL ? pszFilename : psz + 1); return pszBuffer; } /** * Copies the name part with out extention into pszBuffer and returns * a pointer to the buffer. * If no name is found "" is returned. * @returns Pointer to pszBuffer with path. * @param pszFilename Pointer to readonly filename. * @param pszBuffer Pointer to output Buffer. * @status completely implemented. * @author knut st. osmundsen */ char *fileNameNoExt(const char *pszFilename, char *pszBuffer) { char *psz = strrchr(pszFilename, '\\'); if (psz == NULL) psz = strrchr(pszFilename, '/'); strcpy(pszBuffer, psz == NULL ? pszFilename : psz + 1); psz = strrchr(pszBuffer, '.'); if (psz > pszBuffer) /* an extetion on it's own (.depend) is a filename not an extetion! */ *psz = '\0'; return pszBuffer; } /** * Copies the extention part into pszBuffer and returns * a pointer to the buffer. * If no extention is found "" is returned. * The dot ('.') is not included! * @returns Pointer to pszBuffer with path. * @param pszFilename Pointer to readonly filename. * @param pszBuffer Pointer to output Buffer. * @status completely implemented. * @author knut st. osmundsen */ char *fileExt(const char *pszFilename, char *pszBuffer) { char *psz = strrchr(pszFilename, '.'); if (psz != NULL) { if (strchr(psz, '\\') != NULL || strchr(psz, '/') != NULL) *pszBuffer = '\0'; else strcpy(pszBuffer, psz + 1); } else *pszBuffer = '\0'; return pszBuffer; } /** * Adds a file to the cache. * @returns Success indicator. * @param pszFilename Name of the file which is to be added. (with path!) */ BOOL filecacheAddFile(const char *pszFilename) { PFCACHEENTRY pfcNew; /* allocate new block and fill in data */ pfcNew = malloc(sizeof(FCACHEENTRY) + strlen(pszFilename) + 1); if (pfcNew == NULL) { fprintf(stderr, "error: out of memory! (line=%d)\n", __LINE__); return FALSE; } pfcNew->Key = (char*)(void*)pfcNew + sizeof(FCACHEENTRY); strcpy((char*)(unsigned)pfcNew->Key, pszFilename); if (!AVLInsert(&pfcTree, pfcNew)) { free(pfcNew); return TRUE; } cfcNodes++; return TRUE; } /** * Adds a file to the cache. * @returns Success indicator. * @param pszDir Name of the path which is to be added. (with slash!) */ BOOL filecacheAddDir(const char *pszDir) { PFCACHEENTRY pfcNew; APIRET rc; char szDir[CCHMAXPATH]; int cchDir; char achBuffer[32768]; PFILEFINDBUF3 pfindbuf3 = (PFILEFINDBUF3)(void*)&achBuffer[0]; HDIR hDir = HDIR_CREATE; ULONG cFiles = 0xFFFFFFF; int i; /* Make path */ filePathSlash2(pszDir, szDir); /*strlwr(szDir);*/ /* Convert name to lower case to allow faster searchs! */ cchDir = strlen(szDir); /* Add directory to pfcDirTree. */ pfcNew = malloc(sizeof(FCACHEENTRY) + cchDir + 1); if (pfcNew == NULL) { fprintf(stderr, "error: out of memory! (line=%d)\n", __LINE__); DosFindClose(hDir); return FALSE; } pfcNew->Key = (char*)(void*)pfcNew + sizeof(FCACHEENTRY); strcpy((char*)(unsigned)pfcNew->Key, szDir); AVLInsert(&pfcDirTree, pfcNew); /* Start to search directory - all files */ strcat(szDir + cchDir, "*"); rc = DosFindFirst(szDir, &hDir, FILE_NORMAL, pfindbuf3, sizeof(achBuffer), &cFiles, FIL_STANDARD); while (rc == NO_ERROR) { for (i = 0; i < cFiles; i++, pfindbuf3 = (PFILEFINDBUF3)((int)pfindbuf3 + pfindbuf3->oNextEntryOffset) ) { pfcNew = malloc(sizeof(FCACHEENTRY) + cchDir + pfindbuf3->cchName + 1); if (pfcNew == NULL) { fprintf(stderr, "error: out of memory! (line=%d)\n", __LINE__); DosFindClose(hDir); return FALSE; } pfcNew->Key = (char*)(void*)pfcNew + sizeof(FCACHEENTRY); strcpy((char*)(unsigned)pfcNew->Key, szDir); strcpy((char*)(unsigned)pfcNew->Key + cchDir, pfindbuf3->achName); strlwr((char*)(unsigned)pfcNew->Key + cchDir); /* Convert name to lower case to allow faster searchs! */ if (!AVLInsert(&pfcTree, pfcNew)) free(pfcNew); else cfcNodes++; } /* next */ cFiles = 0xFFFFFFF; pfindbuf3 = (PFILEFINDBUF3)(void*)&achBuffer[0]; rc = DosFindNext(hDir, pfindbuf3, sizeof(achBuffer), &cFiles); } DosFindClose(hDir); return TRUE; } /** * Checks if pszFilename is exists in the cache. * @return TRUE if found. FALSE if not found. * @param pszFilename Name of the file to be found. (with path!) * This is in lower case! */ INLINE BOOL filecacheFind(const char *pszFilename) { return AVLGet(&pfcTree, (AVLKEY)pszFilename) != NULL; } /** * Checks if pszFilename is exists in the cache. * @return TRUE if found. FALSE if not found. * @param pszFilename Name of the file to be found. (with path!) * This is in lower case! */ INLINE BOOL filecacheIsDirCached(const char *pszDir) { return AVLGet(&pfcDirTree, (AVLKEY)pszDir) != NULL; } /** * Checks if a file exist, uses file cache if possible. * @returns Pointer to a filename consiting of the path part + the given filename. * (pointer into pszBuffer) * NULL if file is not found. ("" in buffer) * @parma pszFilename Filename to find. * @parma pszBuffer Ouput Buffer. * @status completely implemented. * @author knut st. osmundsen */ char *filecacheFileExist(const char *pszFilename, char *pszBuffer) { APIRET rc; *pszBuffer = '\0'; fileNormalize2(pszFilename, pszBuffer); /* * Search for the file in this directory. * Search cache first */ if (!filecacheFind(pszBuffer)) { char szDir[CCHMAXPATH]; filePathSlash(pszBuffer, szDir); if (!filecacheIsDirCached(szDir)) { /* * If caching of entire dirs are enabled, we'll * add the directory to the cache and search it. */ if (options.fCacheSearchDirs && filecacheAddDir(szDir)) { if (filecacheFind(pszBuffer)) return pszBuffer; } else { FILESTATUS3 fsts3; /* ask the OS */ rc = DosQueryPathInfo(pszBuffer, FIL_STANDARD, &fsts3, sizeof(fsts3)); if (rc == NO_ERROR) { /* add file to cache. */ filecacheAddFile(pszBuffer); return pszBuffer; } } } } else return pszBuffer; return NULL; } /** * Finds a filename in a specified pathlist. * @returns Pointer to a filename consiting of the path part + the given filename. * (pointer into pszBuffer) * NULL if file is not found. ("" in buffer) * @param pszPathList Path list to search for filename. * @parma pszFilename Filename to find. * @parma pszBuffer Ouput Buffer. * @status completely implemented. * @author knut st. osmundsen */ char *pathlistFindFile(const char *pszPathList, const char *pszFilename, char *pszBuffer) { const char *psz = pszPathList; const char *pszNext = NULL; *pszBuffer = '\0'; if (pszPathList == NULL) return NULL; while (*psz != '\0') { /* find end of this path */ pszNext = strchr(psz, ';'); if (pszNext == NULL) pszNext = psz + strlen(psz); if (pszNext - psz > 0) { APIRET rc; /* make search statment */ strncpy(pszBuffer, psz, pszNext - psz); pszBuffer[pszNext - psz] = '\0'; if (pszBuffer[pszNext - psz - 1] != '\\' && pszBuffer[pszNext - psz - 1] != '/') strcpy(&pszBuffer[pszNext - psz], "\\"); strcat(pszBuffer, pszFilename); fileNormalize(pszBuffer); /* * Search for the file in this directory. * Search cache first */ if (!filecacheFind(pszBuffer)) { char szDir[CCHMAXPATH]; filePathSlash(pszBuffer, szDir); if (!filecacheIsDirCached(szDir)) { /* * If caching of entire dirs are enabled, we'll * add the directory to the cache and search it. */ if (options.fCacheSearchDirs && filecacheAddDir(szDir)) { if (filecacheFind(pszBuffer)) return pszBuffer; } else { FILESTATUS3 fsts3; /* ask the OS */ rc = DosQueryPathInfo(pszBuffer, FIL_STANDARD, &fsts3, sizeof(fsts3)); if (rc == NO_ERROR) { /* add file to cache. */ filecacheAddFile(pszBuffer); return pszBuffer; } } } } else return pszBuffer; } /* next */ if (*pszNext != ';') break; psz = pszNext + 1; } return NULL; } /** * Checks if the given filename may exist within any of the given paths. * This check only matches the filename path agianst the paths in the pathlist. * @returns TRUE: if exists. * FALSE: don't exist. * @param pszPathList Path list to search for filename. * @parma pszFilename Filename to find. The filename should be normalized! * @status completely implemented. * @author knut st. osmundsen */ BOOL pathlistFindFile2(const char *pszPathList, const char *pszFilename) { const char *psz = pszPathList; const char *pszNext = NULL; char szBuffer[CCHMAXPATH]; char szBuffer2[CCHMAXPATH]; char *pszPathToFind = &szBuffer2[0]; /* * Input checking */ if (pszPathList == NULL) return FALSE; /* * Normalize the filename and get it's path. */ filePath(pszFilename, pszPathToFind); /* * Loop thru the path list. */ while (*psz != '\0') { /* find end of this path */ pszNext = strchr(psz, ';'); if (pszNext == NULL) pszNext = psz + strlen(psz); if (pszNext - psz > 0) { char * pszPath = &szBuffer[0]; /* * Extract and normalize the path */ strncpy(pszPath, psz, pszNext - psz); pszPath[pszNext - psz] = '\0'; if (pszPath[pszNext - psz - 1] == '\\' && pszPath[pszNext - psz - 1] == '/') pszPath[pszNext - psz - 1] = '\0'; fileNormalize(pszPath); /* * Check if it matches the path of the filename */ if (strcmp(pszPath, pszPathToFind) == 0) return TRUE; } /* * Next part of the path list. */ if (*pszNext != ';') break; psz = pszNext + 1; } return FALSE; } /** * Finds the first char after word. * @returns Pointer to the first char after word. * @param psz Where to start. */ char *findEndOfWord(char *psz) { while (*psz != '\0' && ( (*psz >= 'A' && *psz <= 'Z') || (*psz >= 'a' && *psz <= 'z') || (*psz >= '0' && *psz <= '9') || *psz == '_' ) ) ++psz; return (char *)psz; } #if 0 /* not used */ /** * Find the starting char of a word * @returns Pointer to first char in word. * @param psz Where to start. * @param pszStart Where to stop. */ char *findStartOfWord(const char *psz, const char *pszStart) { const char *pszR = psz; while (psz >= pszStart && ( (*psz >= 'A' && *psz <= 'Z') || (*psz >= 'a' && *psz <= 'z') || (*psz >= '0' && *psz <= '9') || *psz == '_' ) ) pszR = psz--; return (char*)pszR; } #endif /** * Find the size of a file. * @returns Size of file. -1 on error. * @param phFile File handle. */ signed long fsize(FILE *phFile) { int ipos; signed long cb; if ((ipos = ftell(phFile)) < 0 || fseek(phFile, 0, SEEK_END) != 0 || (cb = ftell(phFile)) < 0 || fseek(phFile, ipos, SEEK_SET) != 0 ) cb = -1; return cb; } /** * Trims a string, ie. removing spaces (and tabs) from both ends of the string. * @returns Pointer to first not space or tab char in the string. * @param psz Pointer to the string which is to be trimmed. * @status completely implmented. */ INLINE char *trim(char *psz) { int i; if (psz == NULL) return NULL; while (*psz == ' ' || *psz == '\t') psz++; i = strlen(psz) - 1; while (i >= 0 && (psz[i] == ' ' || *psz == '\t')) i--; psz[i+1] = '\0'; return psz; } /** * Right trims a string, ie. removing spaces (and tabs) from the end of the stri * @returns Pointer to the string passed in. * @param psz Pointer to the string which is to be right trimmed. * @status completely implmented. */ INLINE char *trimR(char *psz) { int i; if (psz == NULL) return NULL; i = strlen(psz) - 1; while (i >= 0 && (psz[i] == ' ' || *psz == '\t')) i--; psz[i+1] = '\0'; return psz; } /** * Trims any quotes of a possibly quoted string. * @returns Pointer to the string passed in. * @param psz Pointer to the string which is to be quote-trimmed. * @status completely implmented. */ INLINE char *trimQuotes(char *psz) { int i; if (psz == NULL) return NULL; if (*psz == '\"' || *psz == '\'') psz++; i = strlen(psz) - 1; if (psz[i] == '\"' || psz[i] == '\'') psz[i] = '\0'; return psz; } /** * C/C++ preprocess a single line. Assumes that we're not starting * with at comment. * @returns Pointer to output buffer. * @param pszOut Ouput (preprocessed) string. * @param pszIn Input string. */ char *PreProcessLine(char *pszOut, const char *pszIn) { char * psz = pszOut; BOOL fComment = FALSE; BOOL fQuote = FALSE; /* * Loop thru the string. */ while (*pszIn != '\0') { if (fQuote) { *psz++ = *pszIn; if (*pszIn == '\\') { *psz++ = *++pszIn; pszIn++; } else if (*pszIn++ == '"') fQuote = FALSE; } else if (fComment) { if (*pszIn == '*' && pszIn[1] == '/') { fComment = FALSE; pszIn += 2; } else pszIn++; } else { if ( (*pszIn == '/' && pszIn[1] == '/') || *pszIn == '\0') { /* End of line. */ break; } if (*pszIn == '/' && pszIn[1] == '*') { /* Start comment */ fComment = TRUE; pszIn += 2; } else *psz++ = *pszIn++; } } /* * Trim right. */ psz--; while (psz >= pszOut && (*psz == ' ' || *psz == '\t')) psz--; psz[1] = '\0'; return pszOut; } /** * Creates a memory buffer for a text file. * @returns Pointer to file memoryblock. NULL on error. * @param pszFilename Pointer to filename string. * @remark This function is the one using most of the execution * time (DosRead + DosOpen) - about 70% of the execution time! */ void *textbufferCreate(const char *pszFilename) { void *pvFile = NULL; FILE *phFile; phFile = fopen(pszFilename, "rb"); if (phFile != NULL) { signed long cbFile = fsize(phFile); if (cbFile >= 0) { pvFile = malloc(cbFile + 1); if (pvFile != NULL) { memset(pvFile, 0, cbFile + 1); if (cbFile > 0 && fread(pvFile, 1, cbFile, phFile) == 0) { /* failed! */ free(pvFile); pvFile = NULL; } } else fprintf(stderr, "warning/error: failed to open file %s\n", pszFilename); } fclose(phFile); } return pvFile; } /** * Destroys a text textbuffer. * @param pvBuffer Buffer handle. */ void textbufferDestroy(void *pvBuffer) { free(pvBuffer); } /** * Gets the next line from an textbuffer. * @returns Pointer to the next line. * @param pvBuffer Buffer handle. * @param psz Pointer to current line. * NULL is passed in to get the first line. */ char *textbufferNextLine(void *pvBuffer, register char *psz) { register char ch; /* if first line psz is NULL. */ if (psz == NULL) return (char*)pvBuffer; /* skip till end of file or end of line. */ ch = *psz; while (ch != '\0' && ch != '\n' && ch != '\r') ch = *++psz; /* skip line end */ if (ch == '\r') ch = *++psz; if (ch == '\n') psz++; return psz; } /** * Gets the next line from an textbuffer. * (fgets for textbuffer) * @returns Pointer to pszOutBuffer. NULL when end of file. * @param pvBuffer Buffer handle. * @param ppv Pointer to a buffer index pointer. (holds the current buffer index) * Pointer to a null pointer is passed in to get the first line. * @param pszLineBuffer Output line buffer. (!= NULL) * @param cchLineBuffer Size of the output line buffer. (> 0) * @remark '\n' and '\r' are removed! */ char *textbufferGetNextLine(void *pvBuffer, void **ppv, char *pszLineBuffer, int cchLineBuffer) { char * pszLine = pszLineBuffer; char * psz = *(char**)(void*)ppv; register char ch; /* first line? */ if (psz == NULL) psz = pvBuffer; /* Copy to end of the line or end of the linebuffer. */ ch = *psz; cchLineBuffer--; /* reserve space for '\0' */ while (cchLineBuffer > 0 && ch != '\0' && ch != '\n' && ch != '\r') { *pszLine++ = ch; ch = *++psz; } *pszLine = '\0'; /* skip line end */ if (ch == '\r') ch = *++psz; if (ch == '\n') psz++; /* check if position has changed - if unchanged it's the end of file! */ if (*ppv == (void*)psz) pszLineBuffer = NULL; /* store current position */ *ppv = (void*)psz; return pszLineBuffer; } /** * Appends a depend file to the internal file. * This will update the date in the option struct. */ BOOL depReadFile(const char *pszFilename, BOOL fAppend) { void * pvFile; char * pszNext; char * pszPrev; /* Previous line, only valid when finding new rule. */ BOOL fMoreDeps = FALSE; void * pvRule = NULL; /* read depend file */ pvFile = textbufferCreate(pszFilename); if (pvFile == NULL) return FALSE; /* parse the original depend file */ pszPrev = NULL; pszNext = pvFile; while (*pszNext != '\0') { int i; int cch; char *psz; /* get the next line. */ psz = pszNext; pszNext = textbufferNextLine(pvFile, pszNext); /* * Process the current line: * Start off by terminating the line. * Trim the line, * Skip empty lines. * If not looking for more deps Then * Check if new rule starts here. * Endif * * If more deps to last rule Then * Get dependant name. * Endif */ i = -1; while (psz <= &pszNext[i] && pszNext[i] == '\n' || pszNext[i] == '\r') pszNext[i--] = '\0'; trimR(psz); cch = strlen(psz); if (cch == 0) { fMoreDeps = FALSE; continue; } if (*psz == '#') { pszPrev = psz; continue; } /* new rule? */ if (!fMoreDeps) { if (*psz != ' ' && *psz != '\t' && *psz != '\0') { i = 0; while (psz[i] != '\0') { if (psz[i] == ':' && (psz[i+1] == ' ' || psz[i+1] == '\t' || psz[i+1] == '\0' || (psz[i+1] == '\\' && psz[i+2] == '\0') ) ) { char szTS[TS_SIZE]; char * pszCont = strchr(&psz[i], '\\'); fMoreDeps = pszCont != NULL && pszCont[1] == '\0'; /* read evt. timestamp. */ szTS[0] = '\0'; if (pszPrev && strlen(pszPrev) > 25 && *pszPrev == '#') strcpy(szTS, pszPrev + 2); psz[i] = '\0'; pvRule = depAddRule(trimQuotes(trimR(psz)), NULL, NULL, szTS, TRUE); if (pvRule) ((PDEPRULE)pvRule)->fUpdated = fAppend; psz += i + 1; cch -= i + 1; break; } i++; } } pszPrev = NULL; } /* more dependants */ if (fMoreDeps) { if (cch > 0 && psz[cch-1] == '\\') { fMoreDeps = TRUE; psz[cch-1] = '\0'; } else fMoreDeps = FALSE; /* if not duplicate rule */ if (pvRule != NULL) { psz = trimQuotes(trim(psz)); if (*psz != '\0') depAddDepend(pvRule, psz, options.fCheckCyclic, TRUE); } } } /* while */ /* return succesfully */ textbufferDestroy(pvFile); return TRUE; } /** * * @returns Success indicator. * @param pszFilename Pointer to name of the output file. * @param fWriteUpdatedOnly If set we'll only write updated rules. */ BOOL depWriteFile(const char *pszFilename, BOOL fWriteUpdatedOnly) { FILE *phFile; phFile = fopen(pszFilename, "w"); if (phFile != NULL) { AVLENUMDATA EnumData; PDEPRULE pdep; static char szBuffer[0x10000]; int iBuffer = 0; int cch; /* * Write warning on top of file. */ fputs("#\n" "# This file was automatically generated by FastDep.\n" "# FastDep was written by knut st. osmundsen, and it's GPL software.\n" "#\n" "# THIS FILE SHOULD N O T BE EDITED MANUALLY!!!\n" "#\n" "# (As this may possibly make it unreadable for fastdep\n" "# and ruin the caching methods of FastDep.)\n" "#\n" "\n", phFile); /* normal dependency output */ pdep = (PDEPRULE)(void*)AVLBeginEnumTree((PPAVLNODECORE)(void*)&pdepTree, &EnumData, TRUE); while (pdep != NULL) { if (!fWriteUpdatedOnly || pdep->fUpdated) { int cchTS = strlen(pdep->szTS); int fQuoted = strpbrk(pdep->pszRule, " \t") != NULL; /* TODO/BUGBUG/FIXME: are there more special chars to look out for?? */ /* Write rule. Flush the buffer first if necessary. */ cch = strlen(pdep->pszRule); if (iBuffer + cch*3 + fQuoted * 2 + cchTS + 9 >= sizeof(szBuffer)) { fwrite(szBuffer, iBuffer, 1, phFile); iBuffer = 0; } memcpy(szBuffer + iBuffer, "# ", 2); memcpy(szBuffer + iBuffer + 2, pdep->szTS, cchTS); iBuffer += cchTS + 2; szBuffer[iBuffer++] = '\n'; if (fQuoted) szBuffer[iBuffer++] = '"'; iBuffer += depNameToMake(szBuffer + iBuffer, sizeof(szBuffer) - iBuffer, pdep->pszRule); if (fQuoted) szBuffer[iBuffer++] = '"'; strcpy(szBuffer + iBuffer++, ":"); /* write rule dependants. */ if (pdep->papszDep != NULL) { char **ppsz = pdep->papszDep; while (*ppsz != NULL) { /* flush buffer? */ fQuoted = strpbrk(*ppsz, " \t") != NULL; /* TODO/BUGBUG/FIXME: are there more special chars to look out for?? */ cch = strlen(*ppsz); if (iBuffer + cch*3 + fQuoted * 2 + 20 >= sizeof(szBuffer)) { fwrite(szBuffer, iBuffer, 1, phFile); iBuffer = 0; } strcpy(szBuffer + iBuffer, " \\\n "); iBuffer += 7; if (fQuoted) szBuffer[iBuffer++] = '"'; iBuffer += depNameToMake(szBuffer + iBuffer, sizeof(szBuffer) - iBuffer, *ppsz); if (fQuoted) szBuffer[iBuffer++] = '"'; /* next dependant */ ppsz++; } } /* Add two new lines. Flush buffer first if necessary. */ if (iBuffer + CBNEWLINE*2 >= sizeof(szBuffer)) { fwrite(szBuffer, iBuffer, 1, phFile); iBuffer = 0; } /* add 2 linefeeds */ strcpy(szBuffer + iBuffer, "\n\n"); iBuffer += CBNEWLINE*2; } /* next rule */ pdep = (PDEPRULE)(void*)AVLGetNextNode(&EnumData); } /* flush buffer. */ fwrite(szBuffer, iBuffer, 1, phFile); fclose(phFile); return TRUE; } return FALSE; } /** * Removes all nodes in the tree of dependencies. (pdepTree) */ void depRemoveAll(void) { AVLENUMDATA EnumData; PDEPRULE pdep; pdep = (PDEPRULE)(void*)AVLBeginEnumTree((PPAVLNODECORE)(void*)&pdepTree, &EnumData, TRUE); while (pdep != NULL) { /* free this */ if (pdep->papszDep != NULL) { char ** ppsz = pdep->papszDep; while (*ppsz != NULL) free(*ppsz++); free(pdep->papszDep); } free(pdep); /* next */ pdep = (PDEPRULE)(void*)AVLGetNextNode(&EnumData); } pdepTree = NULL; } /** * Adds a rule to the list of dependant rules. * @returns Rule handle. NULL if rule exists/error. * @param pszRulePath Pointer to rule text. Empty strings are banned! * This string might only contain the path of the rule. (with '\\') * @param pszName Name of the rule. * NULL if pszRulePath contains the entire rule. * @param pszExt Extention (without '.') * NULL if pszRulePath or pszRulePath and pszName contains the entire rule. * @param fConvertName If set we'll convert from makefile name to realname. */ void *depAddRule(const char *pszRulePath, const char *pszName, const char *pszExt, const char *pszTS, BOOL fConvertName) { char szRule[CCHMAXPATH*2]; PDEPRULE pNew; int cch; /* make rulename */ strcpy(szRule, pszRulePath); cch = strlen(szRule); if (pszName != NULL) { strcpy(szRule + cch, pszName); cch += strlen(szRule + cch); } if (pszExt != NULL) { strcat(szRule + cch++, "."); strcat(szRule + cch, pszExt); cch += strlen(szRule + cch); } if (fConvertName) cch = depNameToReal(szRule); /* * Allocate a new rule structure and fill in data * Note. One block for both the DEPRULE and the pszRule string. */ pNew = malloc(sizeof(DEPRULE) + cch + 1); if (pNew == NULL) { fprintf(stderr, "error: out of memory. (line=%d)\n", __LINE__); return NULL; } pNew->pszRule = (char*)(void*)(pNew + 1); strcpy(pNew->pszRule, szRule); pNew->cDeps = 0; pNew->papszDep = NULL; pNew->fUpdated = TRUE; pNew->avlCore.Key = pNew->pszRule; strcpy(pNew->szTS, pszTS); /* Insert the rule */ if (!AVLInsert((PPAVLNODECORE)(void*)&pdepTree, &pNew->avlCore)) { /* * The rule existed. * If it's allready touched (updated) during this session * there is nothing to be done. * If not force scan and it's newer than depfile-1month then * we'll use the information we've got. * Reuse the node in the tree. */ PDEPRULE pOld = (PDEPRULE)(void*)AVLGet((PPAVLNODECORE)(void*)&pdepTree, pNew->avlCore.Key); assert(pOld); free(pNew); if (pOld->fUpdated) return NULL; pOld->fUpdated = TRUE; if (!options.fForceScan && !strcmp(pOld->szTS, pszTS) && depValidate(pOld)) return NULL; strcpy(pOld->szTS, pszTS); if (pOld->papszDep) { free(pOld->papszDep); pOld->papszDep = NULL; } pOld->cDeps = 0; return pOld; } return pNew; } /** * Adds a dependant to a rule. * @returns Successindicator. TRUE = success. * FALSE = cyclic or out of memory. * @param pvRule Rule handle. * @param pszDep Pointer to dependant name * @param fCheckCyclic When set we'll check that we're not creating an cyclic dependency. * @param fConvertName If set we'll convert from makefile name to realname. */ BOOL depAddDepend(void *pvRule, const char *pszDep, BOOL fCheckCyclic, BOOL fConvertName) { PDEPRULE pdep = (PDEPRULE)pvRule; int cchDep; if (pszDep[0] == '\0') { fprintf(stderr, "warning-internal: empty dependancy filename to '%s'. Ignored.\n", pdep->pszRule); /* __interrupt(3); */ return FALSE; } if (fCheckCyclic && depCheckCyclic(pdep, pszDep)) { fprintf(stderr, "warning: Cylic dependancy caused us to ignore '%s' in rule '%s'.\n", pszDep, pdep->pszRule); return FALSE; } /* allocate more array space */ if (((pdep->cDeps) % 48) == 0) { pdep->papszDep = realloc(pdep->papszDep, sizeof(char*) * (pdep->cDeps + 50)); if (pdep->papszDep == NULL) { pdep->cDeps = 0; fprintf(stderr, "error: out of memory, (line=%d)\n", __LINE__); return FALSE; } } /* allocate string space and copy pszDep */ cchDep = strlen(pszDep) + 1; if ((pdep->papszDep[pdep->cDeps] = malloc(cchDep)) == NULL) { fprintf(stderr, "error: out of memory, (line=%d)\n", __LINE__); return FALSE; } strcpy(pdep->papszDep[pdep->cDeps], pszDep); /* convert ^# and other stuff */ if (fConvertName) depNameToReal(pdep->papszDep[pdep->cDeps]); /* terminate array and increment dep count */ pdep->papszDep[++pdep->cDeps] = NULL; /* successful! */ return TRUE; } /** * Converts from makefile filename to real filename. * @returns New name length. * @param pszName Pointer to the string to make real. */ int depNameToReal(char *pszName) { int cchNewName = strlen(pszName); int iDisplacement = 0; /* * Look for '^' and '$$'. */ while (*pszName) { if ( *pszName == '^' || (*pszName == '$' && pszName[1] == '$')) { iDisplacement--; pszName++; cchNewName--; } if (iDisplacement) pszName[iDisplacement] = *pszName; pszName++; } pszName[iDisplacement] = '\0'; return cchNewName; } /** * Converts from real filename to makefile filename. * @returns New name length. * @param pszName Output name buffer. * @param cchName Size of name buffer. * @param pszSrc Input name. */ int depNameToMake(char *pszName, int cchName, const char *pszSrc) { char *pszNameOrg = pszName; /* * Convert real name to makefile name. */ while (*pszSrc) { if ( *pszSrc == '#' || *pszSrc == '!' || (*pszSrc == '$' && pszSrc[1] != '(') || *pszSrc == '@' || *pszSrc == '-' || *pszSrc == '^' /* || *pszSrc == '(' || *pszSrc == ')' || *pszSrc == '{' || *pszSrc == '}'*/) { if (!cchName--) { fprintf(stderr, "error: buffer too small, (line=%d)\n", __LINE__); return pszName - pszNameOrg + strlen(pszName); } *pszName++ = '^'; } if (!cchName--) { fprintf(stderr, "error: buffer too small, (line=%d)\n", __LINE__); return pszName - pszNameOrg + strlen(pszName); } *pszName++ = *pszSrc++; } *pszName = '\0'; return pszName - pszNameOrg; } /** * Marks the file as one which is to be rescanned next time * since not all dependencies was found... * @param pvRule Rule handle... */ void depMarkNotFound(void *pvRule) { ((PDEPRULE)pvRule)->szTS[0] = '\0'; } /** * Checks if adding this dependent will create a cyclic dependency. * @returns TRUE: Cyclic. * FALSE: Non-cylic. * @param pdepRule Rule pszDep is to be inserted in. * @param pszDep Depend name. */ BOOL depCheckCyclic(PDEPRULE pdepRule, const char *pszDep) { #define DEPTH_FIRST 1 #ifdef DEPTH_FIRST #define DEPTH 32 #else #define DEPTH 128 #endif #define HISTORY 256 char * pszRule = pdepRule->pszRule; char ** appsz[DEPTH]; #if HISTORY char * apszHistory[HISTORY]; int iHistory; int j; int iStart; int iEnd; int iCmp; #endif PDEPRULE pdep; int i; /* self check */ if (strcmp(pdepRule->pszRule, pszDep) == 0) return TRUE; /* find rule for the dep. */ if ((pdep = (PDEPRULE)(void*)AVLGet((PPAVLNODECORE)(void*)&pdepTree, pszDep)) == NULL || pdep->papszDep == NULL) return FALSE; /* no rule, or no dependents, not cyclic */ i = 1; appsz[0] = pdep->papszDep; #ifdef HISTORY iHistory = 1; apszHistory[0] = pdep->pszRule; #endif while (i > 0) { /* pop off element */ register char ** ppsz = appsz[--i]; while (*ppsz != NULL) { /* check if equal to the main rule */ if (strcmp(pszRule, *ppsz) == 0) return TRUE; /* push onto stack (ppsz is incremented in this test!) */ if ((pdep = (PDEPRULE)(void*)AVLGet((PPAVLNODECORE)(void*)&pdepTree, *ppsz++)) != NULL && pdep->papszDep != NULL) { if (i >= DEPTH) { fprintf(stderr, "error: too deep chain (%d). pszRule=%s pszDep=%s\n", i, pszRule, pszDep); return FALSE; } #ifdef HISTORY /* * Check if in history, if so we'll skip it. */ #if 0 for (j = 0; j < iHistory; j++) if (!strcmp(apszHistory[j], pdep->pszRule)) break; if (j != iHistory) continue; /* found */ /* * Push into history - might concider make this binary sorted one day. */ if (iHistory < HISTORY) apszHistory[iHistory++] = pdep->pszRule; #else /* * Check if in history, if so we'll skip it. * (Binary search) * ASSUMES: Always something in the history! */ iEnd = iHistory - 1; iStart = 0; j = iHistory / 2; while ( (iCmp = strcmp(pdep->pszRule, apszHistory[j])) != 0 && iEnd != iStart) { if (iCmp < 0) iEnd = j - 1; else iStart = j + 1; if (iStart > iEnd) break; j = (iStart + iEnd) / 2; } if (!iCmp) continue; /* found */ /* * Push into history - might concider make this binary sorted one day. */ if (iHistory < HISTORY) { int k; if (iCmp > 0) /* Insert after. */ j++; for (k = iHistory; k > j; k--) apszHistory[k] = apszHistory[k - 1]; apszHistory[j] = pdep->pszRule; iHistory++; } #endif #endif /* * Push on to the stack. */ #ifdef DEPTH_FIRST /* dept first */ appsz[i++] = ppsz; /* save current posistion */ ppsz = pdep->papszDep; /* process new node */ #else /* complete current node first. */ appsz[i++] = pdep->papszDep; #endif } } } return FALSE; } /** * Validates that the dependencies for the file exists * in the given locations. Dependants without path is ignored. * @returns TRUE if all ok. * FALSE if one (or possibly more) dependants are non-existing. * @param pdepRule Pointer to rule we're to validate. */ BOOL depValidate(PDEPRULE pdepRule) { int i; for (i = 0; i < pdepRule->cDeps; i++) { char *psz = pdepRule->papszDep[i]; if ( !strchr(psz, '$') && ( psz[1] == ':' || strchr(psz, '\\') || strchr(psz, '/') ) ) { /* * Check existance of the file. * Search cache first */ if (!filecacheFind(psz)) { char szDir[CCHMAXPATH]; filePathSlash(psz, szDir); if (!filecacheIsDirCached(szDir)) { /* * If caching of entire dirs are enabled, we'll * add the directory to the cache and search it. */ if (options.fCacheSearchDirs && filecacheAddDir(szDir)) { if (!filecacheFind(psz)) return FALSE; } else { FILESTATUS3 fsts3; /* ask the OS */ if (DosQueryPathInfo(psz, FIL_STANDARD, &fsts3, sizeof(fsts3))) return FALSE; /* add file to cache. */ filecacheAddFile(psz); } } /* * Dir was cached, hence the file doesn't exist * and the we should rescan the source file. */ else return FALSE; } } } return TRUE; } /** * Make a timestamp from the file data provided thru the * search API. * @returns Pointer to pszTS * @param pszTS Pointer to timestamp (output). * @param pfindbuf3 Pointer to search result. */ INLINE char *depMakeTS(char *pszTS, PFILEFINDBUF3 pfindbuf3) { sprintf(pszTS, "%04d-%02d-%02d-%02d.%02d.%02d 0x%04x%04x %d", pfindbuf3->fdateLastWrite.year + 1980, pfindbuf3->fdateLastWrite.month, pfindbuf3->fdateLastWrite.day, pfindbuf3->ftimeLastWrite.hours, pfindbuf3->ftimeLastWrite.minutes, pfindbuf3->ftimeLastWrite.twosecs * 2, (ULONG)*(PUSHORT)(void*)&pfindbuf3->fdateCreation, (ULONG)*(PUSHORT)(void*)&pfindbuf3->ftimeCreation, pfindbuf3->cbFile); return pszTS; } /** * Adds the src additioanl dependenies to a rule. * @param pvRule Rule to add them to. * @param pszz Pointer to the string of strings of extra dependencies. */ void depAddSrcAddDeps(void *pvRule, const char *pszz) { while (*pszz) { depAddDepend(pvRule, pszz, FALSE, FALSE); pszz += strlen(pszz) + 1; } } /* * Testing purpose. */ #if !defined(OS2FAKE) #include #endif #ifdef OLEMANN #include "olemann.h" #endif kbuild-3149/src/fastdep/avl.h0000644000175000017500000000547613252530215016066 0ustar locutuslocutus/* $Id: avl.h 2243 2009-01-10 02:24:02Z bird $ * * AVL-Tree (lookalike) declaration. * * This AVL implementation is configurable from this headerfile. By * for example alterning the AVLKEY typedefinition an the AVL_[E] * macros you are able to create different trees. Currently you may only have * one type of trees within one program (module). * * TREETYPE: Case Sensitive Strings (Key is pointer). * * * Copyright (c) 1999-2009 knut st. osmundsen * * GPL * */ #ifndef _AVL_H_ #define _AVL_H_ #ifdef __cplusplus extern "C" { #endif /* * AVL configuration. PRIVATE! */ #define AVL_MAX_HEIGHT 19 /* Up to 2^16 nodes. */ #define AVL_MAY_TRY_INSERT_EQUAL 1 /* Ignore attempts to insert existing nodes. */ /* * AVL Compare macros */ #define AVL_L(key1, key2) (strcmp(key1, key2) < 0) #define AVL_LE(key1, key2) (strcmp(key1, key2) <= 0) #define AVL_G(key1, key2) (strcmp(key1, key2) > 0) #define AVL_GE(key1, key2) (strcmp(key1, key2) >= 0) #define AVL_E(key1, key2) (strcmp(key1, key2) == 0) #define AVL_NE(key1, key2) (strcmp(key1, key2) != 0) #define AVL_CMP(key1, key2) strcmp(key1, key2) /** * AVL key type */ typedef const char *AVLKEY; /** * AVL Core node. */ typedef struct _AVLNodeCore { AVLKEY Key; /* Key value. */ struct _AVLNodeCore * pLeft; /* Pointer to left leaf node. */ struct _AVLNodeCore * pRight; /* Pointer to right leaf node. */ unsigned char uchHeight; /* Height of this tree: max(heigth(left), heigth(right)) + 1 */ } AVLNODECORE, *PAVLNODECORE, **PPAVLNODECORE; /** * AVL Enum data - All members are PRIVATE! Don't touch! */ typedef struct _AVLEnumData { char fFromLeft; char cEntries; char achFlags[AVL_MAX_HEIGHT]; PAVLNODECORE aEntries[AVL_MAX_HEIGHT]; } AVLENUMDATA, *PAVLENUMDATA; /* * callback type */ typedef unsigned ( _PAVLCALLBACK)(PAVLNODECORE, void*); typedef _PAVLCALLBACK *PAVLCALLBACK; BOOL AVLInsert(PPAVLNODECORE ppTree, PAVLNODECORE pNode); PAVLNODECORE AVLRemove(PPAVLNODECORE ppTree, AVLKEY Key); PAVLNODECORE AVLGet(PPAVLNODECORE ppTree, AVLKEY Key); PAVLNODECORE AVLGetWithParent(PPAVLNODECORE ppTree, PPAVLNODECORE ppParent, AVLKEY Key); PAVLNODECORE AVLGetWithAdjecentNodes(PPAVLNODECORE ppTree, AVLKEY Key, PPAVLNODECORE ppLeft, PPAVLNODECORE ppRight); unsigned AVLDoWithAll(PPAVLNODECORE ppTree, int fFromLeft, PAVLCALLBACK pfnCallBack, void *pvParam); PAVLNODECORE AVLBeginEnumTree(PPAVLNODECORE ppTree, PAVLENUMDATA pEnumData, int fFromLeft); PAVLNODECORE AVLGetNextNode(PAVLENUMDATA pEnumData); PAVLNODECORE AVLGetBestFit(PPAVLNODECORE ppTree, AVLKEY Key, int fAbove); /* * Just in case NULL is undefined. */ #ifndef NULL #define NULL ((void*)0) #endif #ifdef __cplusplus } #endif #endif kbuild-3149/src/fastdep/fastdep.def0000644000175000017500000000012613252530215017224 0ustar locutuslocutusNAME fastdef WINDOWCOMPAT DESCRIPTION "Knut''s Quick and Dirty Dependency Generator" kbuild-3149/src/fastdep/os2fake-win.c0000644000175000017500000002256113252530215017416 0ustar locutuslocutus/* $Id: os2fake-win.c 2243 2009-01-10 02:24:02Z bird $ * * OS/2 Fake library for Win32. * * Copyright (c) 2001 knut st. osmundsen (knut.stange.osmundsen@mynd.no) * * GPL * */ /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ #define VALIDPTR(pv) (((PVOID)pv) >= (PVOID)0x10000 && ((PVOID)pv) <= (PVOID)0xc0000000) /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #include "os2fake.h" /******************************************************************************* * Internal Functions * *******************************************************************************/ static ULONG ConvertAttributes(DWORD dwFileAttributes); static ULONG ConvertFileTime(PFILETIME pFileTime); /** * Converts Win32 file attribute to OS/2 file attributes. * @returns OS/2 fileattributes. * @param dwFileAttributes Win32 fileattributes. */ ULONG ConvertAttributes(DWORD dwFileAttributes) { static struct _ConvAttr { ULONG ulWin; ULONG ulOs2; } aConvAttr[] = { {FILE_ATTRIBUTE_READONLY, FILE_READONLY}, {FILE_ATTRIBUTE_HIDDEN, FILE_HIDDEN}, {FILE_ATTRIBUTE_SYSTEM, FILE_SYSTEM}, {FILE_ATTRIBUTE_DIRECTORY, FILE_DIRECTORY}, {FILE_ATTRIBUTE_ARCHIVE, FILE_ARCHIVED} }; ULONG ulOS2Attr = 0; int i; for (i = 0; i < sizeof(aConvAttr) / sizeof(aConvAttr[0]); i++) if (dwFileAttributes & aConvAttr[i].ulWin) ulOS2Attr |= aConvAttr[i].ulOs2; return ulOS2Attr; } /** * Converts Win32 filetime to OS/2 filetime. * @returns OS/2 filetime. * @param pFileTime Pointer to Win32 filetime. */ ULONG ConvertFileTime(PFILETIME pFileTime) { ULONG ulOS2FileTime; SYSTEMTIME SystemTime; if ( FileTimeToSystemTime(pFileTime, &SystemTime) && SystemTime.wYear >= 1980 && SystemTime.wYear < (1980 + 0x7F)) { ulOS2FileTime = SystemTime.wDay | (SystemTime.wMonth << 5) | (((SystemTime.wYear - 1980) & 0x7F) << (5+4)) | ((SystemTime.wSecond / 2) << (16)) | (SystemTime.wMinute << (16+5)) | (SystemTime.wHour << (16+5+6)); } else ulOS2FileTime = 0; return ulOS2FileTime; } APIRET OS2ENTRY DosQueryPathInfo( PCSZ pszPathName, ULONG ulInfoLevel, PVOID pInfoBuf, ULONG cbInfoBuf) { APIRET rc; /* Return code. */ if (!VALIDPTR(pszPathName)) { fprintf(stderr, "DosQueryPathInfo: pszPathName is an invalid pointer - %p\n", pszPathName); return ERROR_INVALID_PARAMETER; } if (!VALIDPTR(pInfoBuf)) { fprintf(stderr, "DosQueryPathInfo: pInfoBuf is an invalid pointer - %p\n", pInfoBuf); return ERROR_INVALID_PARAMETER; } rc = ERROR_INVALID_PARAMETER; switch (ulInfoLevel) { case FIL_QUERYFULLNAME: { LPTSTR lpDummy; if (GetFullPathName(pszPathName, cbInfoBuf, pInfoBuf, &lpDummy) > 0) rc = NO_ERROR; else rc = GetLastError(); break; } case FIL_STANDARD: if (cbInfoBuf == sizeof(FILESTATUS3)) { WIN32_FILE_ATTRIBUTE_DATA fad; if (GetFileAttributesEx(pszPathName, GetFileExInfoStandard, &fad)) //W98, NT4 and above. { PFILESTATUS3 pfst3 = (PFILESTATUS3)(pInfoBuf); if (fad.nFileSizeHigh > 0) rc = ERROR_BAD_LENGTH; pfst3->cbFile = pfst3->cbFileAlloc = fad.nFileSizeLow; pfst3->attrFile = ConvertAttributes(fad.dwFileAttributes); *(PULONG)(&pfst3->fdateCreation) = ConvertFileTime(&fad.ftCreationTime); *(PULONG)(&pfst3->fdateLastAccess) = ConvertFileTime(&fad.ftLastAccessTime); *(PULONG)(&pfst3->fdateLastWrite) = ConvertFileTime(&fad.ftLastWriteTime); rc = NO_ERROR; } else rc = GetLastError(); } else fprintf(stderr, "DosQueryPathInfo: FIL_STANDARD - invalid structure size (cbInfoBuf=%d)\n", cbInfoBuf); break; default: fprintf(stderr, "DosQueryPathInfo: ulInfoLevel=%d not supported\n", ulInfoLevel); } return rc; } APIRET OS2ENTRY DosFindFirst( PCSZ pszFileSpec, PHDIR phdir, ULONG flAttribute, PVOID pFindBuf, ULONG cbFindBuf, PULONG pcFileNames, ULONG ulInfoLevel) { WIN32_FIND_DATA FindData; /* Win32 Find data (returned by FindFirstFile) */ APIRET rc; if (!VALIDPTR(pszFileSpec)) { fprintf(stderr, "DosFindFirst: pszFileSpec - %p\n", pszFileSpec); return ERROR_INVALID_PARAMETER; } if (!VALIDPTR(phdir)) { fprintf(stderr, "DosFindFirst: phdir - %p\n", phdir); return ERROR_INVALID_PARAMETER; } if (!VALIDPTR(pFindBuf)) { fprintf(stderr, "DosFindFirst: pfindbuf - %p\n", pFindBuf); return ERROR_INVALID_PARAMETER; } if (!VALIDPTR(pcFileNames)) { fprintf(stderr, "DosFindFirst: pcFileNames - %p\n", pcFileNames); return ERROR_INVALID_PARAMETER; } if (*phdir != HDIR_CREATE) { fprintf(stderr, "DosFindFirst: *phdir != HDIR_CREATE - 0x%08x\n", *phdir); return ERROR_INVALID_PARAMETER; } switch (ulInfoLevel) { case FIL_STANDARD: if (cbFindBuf < sizeof(FILEFINDBUF3)) { fprintf(stderr, "DosFindFirst: unsupported buffer size - %d\n", cbFindBuf); return ERROR_INVALID_PARAMETER; } break; default: fprintf(stderr, "DosFindFirst: invalid infolevel %d\n", ulInfoLevel); return ERROR_INVALID_PARAMETER; } *phdir = (HDIR)FindFirstFile(pszFileSpec, &FindData); if (*phdir != (HDIR)INVALID_HANDLE_VALUE) { PFILEFINDBUF3 pfindbuf = (PFILEFINDBUF3)pFindBuf; memcpy(pfindbuf->achName, FindData.cFileName, pfindbuf->cchName = strlen(FindData.cFileName) + 1); pfindbuf->cbFile = pfindbuf->cbFileAlloc = FindData.nFileSizeHigh > 0 ? 0xffffffff : FindData.nFileSizeLow; pfindbuf->attrFile = ConvertAttributes(FindData.dwFileAttributes); *(PULONG)(&pfindbuf->fdateCreation) = ConvertFileTime(&FindData.ftCreationTime); *(PULONG)(&pfindbuf->fdateLastAccess) = ConvertFileTime(&FindData.ftLastAccessTime); *(PULONG)(&pfindbuf->fdateLastWrite) = ConvertFileTime(&FindData.ftLastWriteTime); pfindbuf->oNextEntryOffset = 0; *pcFileNames = 1; rc = NO_ERROR; } else rc = GetLastError(); return rc; } APIRET OS2ENTRY DosFindNext( HDIR hDir, PVOID pFindBuf, ULONG cbFindBuf, PULONG pcFileNames) { WIN32_FIND_DATA FindData; /* Win32 Find data (returned by FindFirstFile) */ APIRET rc; if (!VALIDPTR(pFindBuf)) { fprintf(stderr, "DosFindNext: pfindbuf - %p\n", pFindBuf); return ERROR_INVALID_PARAMETER; } if (cbFindBuf < sizeof(FILEFINDBUF3)) { fprintf(stderr, "DosFindNext: unsupported buffer size - %d\n", cbFindBuf); return ERROR_INVALID_PARAMETER; } if (!VALIDPTR(pcFileNames)) { fprintf(stderr, "DosFindNext: pcFileNames - %p\n", pcFileNames); return ERROR_INVALID_PARAMETER; } if (FindNextFile((HANDLE)hDir, &FindData)) { PFILEFINDBUF3 pfindbuf = (PFILEFINDBUF3)pFindBuf; memcpy(pfindbuf->achName, FindData.cFileName, pfindbuf->cchName = strlen(FindData.cFileName) + 1); pfindbuf->cbFile = pfindbuf->cbFileAlloc = FindData.nFileSizeHigh > 0 ? 0xffffffff : FindData.nFileSizeLow; pfindbuf->attrFile = ConvertAttributes(FindData.dwFileAttributes); *(PULONG)(&pfindbuf->fdateCreation) = ConvertFileTime(&FindData.ftCreationTime); *(PULONG)(&pfindbuf->fdateLastAccess) = ConvertFileTime(&FindData.ftLastAccessTime); *(PULONG)(&pfindbuf->fdateLastWrite) = ConvertFileTime(&FindData.ftLastWriteTime); pfindbuf->oNextEntryOffset = 0; *pcFileNames = 1; rc = NO_ERROR; } else rc = GetLastError(); return rc; } APIRET OS2ENTRY DosFindClose( HDIR hDir) { if (FindClose((HANDLE)hDir)) return NO_ERROR; return ERROR_INVALID_HANDLE; } kbuild-3149/src/fastdep/avl.c0000644000175000017500000006405013252530215016052 0ustar locutuslocutus/* $Id: avl.c 2243 2009-01-10 02:24:02Z bird $ * * AVL-Tree (lookalike) implementation. * * Copyright (c) 1999 knut st. osmundsen * * GPL * */ /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /* * AVL helper macros. */ #define AVL_HEIGHTOF(pNode) ((unsigned char)((pNode) != NULL ? pNode->uchHeight : 0)) #define max(a,b) (((a) > (b)) ? (a) : (b)) #ifndef INLINE # if defined(__IBMC__) # define INLINE _Inline # elif defined(__IBMCPP__) # define INLINE inline # elif defined(__WATCOMC__) # define INLINE __inline # elif defined(__WATCOM_CPLUSPLUS__) # define INLINE inline # else # error message("unknown compiler - inline keyword unknown!") # endif #endif /******************************************************************************* * Internal Functions * *******************************************************************************/ #include #include "avl.h" #if defined(RING0) || defined(RING3) #include "dev32.h" #else #define SSToDS(a) (a) #endif #include "string.h" #if defined(__IBMCPP__) || defined(__IBMC__) #include #define assert(a) ((a) ? (void)0 : __interrupt(3) ) #else #include #endif /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /* * A stack used to avoid recursive calls... */ typedef struct _AVLStack { unsigned cEntries; PPAVLNODECORE aEntries[AVL_MAX_HEIGHT]; } AVLSTACK, *PAVLSTACK; typedef struct _AVLStack2 { unsigned cEntries; PAVLNODECORE aEntries[AVL_MAX_HEIGHT]; char achFlags[AVL_MAX_HEIGHT]; } AVLSTACK2, *PAVLSTACK2; /******************************************************************************* * Internal Functions * *******************************************************************************/ INLINE void AVLRebalance(PAVLSTACK pStack); /** * Inserts a node into the AVL-tree. * @returns TRUE if inserted. * FALSE if node exists in tree. * @param ppTree Pointer to the AVL-tree root node pointer. * @param pNode Pointer to the node which is to be added. * @sketch Find the location of the node (using binary three algorithm.): * LOOP until NULL leaf pointer * BEGIN * Add node pointer pointer to the AVL-stack. * IF new-node-key < node key THEN * left * ELSE * right * END * Fill in leaf node and insert it. * Rebalance the tree. * @status completely implemented. * @author knut st. osmundsen */ BOOL AVLInsert(PPAVLNODECORE ppTree, PAVLNODECORE pNode) { AVLSTACK AVLStack; PPAVLNODECORE ppCurNode = ppTree; register AVLKEY Key = pNode->Key; register PAVLNODECORE pCurNode; AVLStack.cEntries = 0; while ((pCurNode = *ppCurNode) != NULL) { assert(AVLStack.cEntries < AVL_MAX_HEIGHT); assert(pNode != pCurNode); AVLStack.aEntries[AVLStack.cEntries++] = ppCurNode; #ifdef AVL_MAY_TRY_INSERT_EQUAL /* check if equal */ if (AVL_E(pCurNode->Key, Key)) return FALSE; #endif if (AVL_G(pCurNode->Key, Key)) ppCurNode = &pCurNode->pLeft; else ppCurNode = &pCurNode->pRight; } pNode->pLeft = pNode->pRight = NULL; pNode->uchHeight = 1; *ppCurNode = pNode; AVLRebalance(SSToDS(&AVLStack)); return TRUE; } /** * Removes a node from the AVL-tree. * @returns Pointer to the node. * @param ppTree Pointer to the AVL-tree root node pointer. * @param Key Key value of the node which is to be removed. * @sketch Find the node which is to be removed: * LOOP until not found * BEGIN * Add node pointer pointer to the AVL-stack. * IF the keys matches THEN break! * IF remove key < node key THEN * left * ELSE * right * END * IF found THEN * BEGIN * IF left node not empty THEN * BEGIN * Find the right most node in the left tree while adding the pointer to the pointer to it's parent to the stack: * Start at left node. * LOOP until right node is empty * BEGIN * Add to stack. * go right. * END * Link out the found node. * Replace the node which is to be removed with the found node. * Correct the stack entry for the pointer to the left tree. * END * ELSE * BEGIN * Move up right node. * Remove last stack entry. * END * Balance tree using stack. * END * return pointer to the removed node (if found). * @status completely implemented. * @author knut st. osmundsen */ PAVLNODECORE AVLRemove(PPAVLNODECORE ppTree, AVLKEY Key) { AVLSTACK AVLStack; PPAVLNODECORE ppDeleteNode = ppTree; register PAVLNODECORE pDeleteNode; AVLStack.cEntries = 0; while ((pDeleteNode = *ppDeleteNode) != NULL) { assert(AVLStack.cEntries < AVL_MAX_HEIGHT); AVLStack.aEntries[AVLStack.cEntries++] = ppDeleteNode; #ifndef AVL_CMP if (AVL_E(pDeleteNode->Key, Key)) break; if (AVL_G(pDeleteNode->Key, Key)) ppDeleteNode = &pDeleteNode->pLeft; else ppDeleteNode = &pDeleteNode->pRight; #else { int register iDiff; if ((iDiff = AVL_CMP(pDeleteNode->Key, Key)) == 0) break; if (iDiff > 0) ppDeleteNode = &pDeleteNode->pLeft; else ppDeleteNode = &pDeleteNode->pRight; } #endif } if (pDeleteNode != NULL) { if (pDeleteNode->pLeft != NULL) { unsigned iStackEntry = AVLStack.cEntries; PPAVLNODECORE ppLeftLeast = &pDeleteNode->pLeft; register PAVLNODECORE pLeftLeast; while ((pLeftLeast = *ppLeftLeast)->pRight != NULL) /* Left most node. */ { assert(AVLStack.cEntries < AVL_MAX_HEIGHT); AVLStack.aEntries[AVLStack.cEntries++] = ppLeftLeast; ppLeftLeast = &pLeftLeast->pRight; pLeftLeast = pLeftLeast->pRight; } /* link out pLeftLeast */ *ppLeftLeast = pLeftLeast->pLeft; /* link in place of the delete node. */ pLeftLeast->pLeft = pDeleteNode->pLeft; pLeftLeast->pRight = pDeleteNode->pRight; pLeftLeast->uchHeight = pDeleteNode->uchHeight; *ppDeleteNode = pLeftLeast; AVLStack.aEntries[iStackEntry] = &pLeftLeast->pLeft; } else { *ppDeleteNode = pDeleteNode->pRight; AVLStack.cEntries--; } AVLRebalance(SSToDS(&AVLStack)); } return pDeleteNode; } /** * Gets a node from the tree (does not remove it!) * @returns Pointer to the node holding the given key. * @param ppTree Pointer to the AVL-tree root node pointer. * @param Key Key value of the node which is to be found. * @sketch * @status completely implemented. * @author knut st. osmundsen */ PAVLNODECORE AVLGet(PPAVLNODECORE ppTree, AVLKEY Key) { #ifndef AVL_CMP register PAVLNODECORE pNode = *ppTree; while (pNode != NULL && AVL_NE(pNode->Key, Key)) { if (AVL_G(pNode->Key, Key)) pNode = pNode->pLeft; else pNode = pNode->pRight; } #else register int iDiff; register PAVLNODECORE pNode = *ppTree; while (pNode != NULL && (iDiff = AVL_CMP(pNode->Key, Key)) != 0) { if (iDiff > 0) pNode = pNode->pLeft; else pNode = pNode->pRight; } #endif return pNode; } /** * Gets a node from the tree and its parent node (if any) (does not remove any nodes!) * @returns Pointer to the node holding the given key. * @param ppTree Pointer to the AVL-tree root node pointer. * @param ppParent Pointer to a variable which will hold the pointer to the partent node on * return. When no node is found, this will hold the last searched node. * @param Key Key value of the node which is to be found. * @sketch * @status completely implemented. * @author knut st. osmundsen */ PAVLNODECORE AVLGetWithParent(PPAVLNODECORE ppTree, PPAVLNODECORE ppParent, AVLKEY Key) { #ifndef AVL_CMP register PAVLNODECORE pNode = *ppTree; register PAVLNODECORE pParent = NULL; while (pNode != NULL && AVL_NE(pNode->Key, Key)) { pParent = pNode; if (AVL_G(pNode->Key, Key)) pNode = pNode->pLeft; else pNode = pNode->pRight; } #else register PAVLNODECORE pNode = *ppTree; register PAVLNODECORE pParent = NULL; register int iDiff; while (pNode != NULL && (iDiff = AVL_CMP(pNode->Key, Key)) != 0) { pParent = pNode; if (iDiff > 0) pNode = pNode->pLeft; else pNode = pNode->pRight; } #endif *ppParent = pParent; return pNode; } /** * Gets node from the tree (does not remove it!) and it's adjecent (by key value) nodes. * @returns Pointer to the node holding the given key. * @param ppTree Pointer to the AVL-tree root node pointer. * @param Key Key value of the node which is to be found. * @param ppLeft Pointer to left node pointer. * @param ppRight Pointer to right node pointer. * @sketch Find node with the given key, record search path on the stack. * IF found THEN * BEGIN * Find the right-most node in the left subtree. * Find the left-most node in the right subtree. * Rewind the stack while searching for more adjecent nodes. * END * return node with adjecent nodes. * @status completely implemented. * @author knut st. osmundsen */ PAVLNODECORE AVLGetWithAdjecentNodes(PPAVLNODECORE ppTree, AVLKEY Key, PPAVLNODECORE ppLeft, PPAVLNODECORE ppRight) { AVLSTACK AVLStack; PPAVLNODECORE ppNode = ppTree; PAVLNODECORE pNode; #ifdef AVL_CMP int iDiff; #endif AVLStack.cEntries = 0; #ifndef AVL_CMP while ((pNode = *ppNode) != NULL && AVL_NE(pNode->Key, Key)) #else while ((pNode = *ppNode) != NULL && (iDiff = AVL_CMP(pNode->Key, Key)) != 0) #endif { assert(AVLStack.cEntries < AVL_MAX_HEIGHT); AVLStack.aEntries[AVLStack.cEntries++] = ppNode; #ifndef AVL_CMP if (AVL_G(pNode->Key, Key)) #else if (iDiff > 0) #endif ppNode = &pNode->pLeft; else ppNode = &pNode->pRight; } if (pNode != NULL) { PAVLNODECORE pCurNode; /* find rigth-most node in left subtree. */ pCurNode = pNode->pLeft; if (pCurNode != NULL) while (pCurNode->pRight != NULL) pCurNode = pCurNode->pRight; *ppLeft = pCurNode; /* find left-most node in right subtree. */ pCurNode = pNode->pRight; if (pCurNode != NULL) while (pCurNode->pLeft != NULL) pCurNode = pCurNode->pLeft; *ppRight = pCurNode; /* rewind stack */ while (AVLStack.cEntries-- > 0) { pCurNode = *AVLStack.aEntries[AVLStack.cEntries]; #ifndef AVL_CMP if (AVL_L(pCurNode->Key, Key) && (*ppLeft == NULL || AVL_G(pCurNode->Key, (*ppLeft)->Key))) *ppLeft = pCurNode; else if (AVL_G(pCurNode->Key, Key) && (*ppRight == NULL || AVL_L(pCurNode->Key, (*ppRight)->Key))) *ppRight = pCurNode; #else if ((iDiff = AVL_CMP(pCurNode->Key, Key)) < 0 && (*ppLeft == NULL || AVL_G(pCurNode->Key, (*ppLeft)->Key))) *ppLeft = pCurNode; else if (iDiff > 0 && (*ppRight == NULL || AVL_L(pCurNode->Key, (*ppRight)->Key))) *ppRight = pCurNode; #endif } } else *ppLeft = *ppRight = NULL; return pNode; } /** * Iterates tru all nodes in the given tree. * @returns 0 on success. Return from callback on failiure. * @param ppTree Pointer to the AVL-tree root node pointer. * @param fFromLeft TRUE: Left to right. * FALSE: Right to left. * @param pfnCallBack Pointer to callback function. * @param pvParam Userparameter passed on to the callback function. * @status completely implemented. * @author knut st. osmundsen */ unsigned AVLDoWithAll(PPAVLNODECORE ppTree, int fFromLeft, PAVLCALLBACK pfnCallBack, void *pvParam) { AVLSTACK2 AVLStack; PAVLNODECORE pNode; unsigned rc; if (*ppTree == NULL) return 0; AVLStack.cEntries = 1; AVLStack.achFlags[0] = 0; AVLStack.aEntries[0] = *ppTree; if (fFromLeft) { /* from left */ while (AVLStack.cEntries > 0) { pNode = AVLStack.aEntries[AVLStack.cEntries - 1]; /* left */ if (!AVLStack.achFlags[AVLStack.cEntries - 1]++) { if (pNode->pLeft != NULL) { AVLStack.achFlags[AVLStack.cEntries] = 0; /* 0 first, 1 last */ AVLStack.aEntries[AVLStack.cEntries++] = pNode->pLeft; continue; } } /* center */ rc = pfnCallBack(pNode, pvParam); if (rc != 0) return rc; /* right */ AVLStack.cEntries--; if (pNode->pRight != NULL) { AVLStack.achFlags[AVLStack.cEntries] = 0; AVLStack.aEntries[AVLStack.cEntries++] = pNode->pRight; } } /* while */ } else { /* from right */ while (AVLStack.cEntries > 0) { pNode = AVLStack.aEntries[AVLStack.cEntries - 1]; /* right */ if (!AVLStack.achFlags[AVLStack.cEntries - 1]++) { if (pNode->pRight != NULL) { AVLStack.achFlags[AVLStack.cEntries] = 0; /* 0 first, 1 last */ AVLStack.aEntries[AVLStack.cEntries++] = pNode->pRight; continue; } } /* center */ rc = pfnCallBack(pNode, pvParam); if (rc != 0) return rc; /* left */ AVLStack.cEntries--; if (pNode->pLeft != NULL) { AVLStack.achFlags[AVLStack.cEntries] = 0; AVLStack.aEntries[AVLStack.cEntries++] = pNode->pLeft; } } /* while */ } return 0; } /** * Starts an enumeration of all nodes in the given AVL tree. * @returns Pointer to the first node in the tree. * @param ppTree Pointer to the AVL-tree root node pointer. * @param pEnumData Pointer to enumeration control data. * @param fFromLeft TRUE: Left to right. * FALSE: Right to left. * @status completely implemented. * @author knut st. osmundsen */ PAVLNODECORE AVLBeginEnumTree(PPAVLNODECORE ppTree, PAVLENUMDATA pEnumData, int fFromLeft) { if (*ppTree != NULL) { pEnumData->fFromLeft = (char)fFromLeft; pEnumData->cEntries = 1; pEnumData->aEntries[0] = *ppTree; pEnumData->achFlags[0] = 0; } else pEnumData->cEntries = 0; return AVLGetNextNode(pEnumData); } /** * Get the next node in the tree enumeration. * @returns Pointer to the first node in the tree. * @param pEnumData Pointer to enumeration control data. * @status completely implemented. * @author knut st. osmundsen */ PAVLNODECORE AVLGetNextNode(PAVLENUMDATA pEnumData) { PAVLNODECORE pNode; if (pEnumData->fFromLeft) { /* from left */ while (pEnumData->cEntries > 0) { pNode = pEnumData->aEntries[pEnumData->cEntries - 1]; /* left */ if (pEnumData->achFlags[pEnumData->cEntries - 1] == 0) { pEnumData->achFlags[pEnumData->cEntries - 1]++; if (pNode->pLeft != NULL) { pEnumData->achFlags[pEnumData->cEntries] = 0; /* 0 left, 1 center, 2 right */ pEnumData->aEntries[pEnumData->cEntries++] = pNode->pLeft; continue; } } /* center */ if (pEnumData->achFlags[pEnumData->cEntries - 1] == 1) { pEnumData->achFlags[pEnumData->cEntries - 1]++; return pNode; } /* right */ pEnumData->cEntries--; if (pNode->pRight != NULL) { pEnumData->achFlags[pEnumData->cEntries] = 0; pEnumData->aEntries[pEnumData->cEntries++] = pNode->pRight; } } /* while */ } else { /* from right */ while (pEnumData->cEntries > 0) { pNode = pEnumData->aEntries[pEnumData->cEntries - 1]; /* right */ if (pEnumData->achFlags[pEnumData->cEntries - 1] == 0) { pEnumData->achFlags[pEnumData->cEntries - 1]++; if (pNode->pRight != NULL) { pEnumData->achFlags[pEnumData->cEntries] = 0; /* 0 right, 1 center, 2 left */ pEnumData->aEntries[pEnumData->cEntries++] = pNode->pRight; continue; } } /* center */ if (pEnumData->achFlags[pEnumData->cEntries - 1] == 1) { pEnumData->achFlags[pEnumData->cEntries - 1]++; return pNode; } /* left */ pEnumData->cEntries--; if (pNode->pLeft != NULL) { pEnumData->achFlags[pEnumData->cEntries] = 0; pEnumData->aEntries[pEnumData->cEntries++] = pNode->pLeft; } } /* while */ } return NULL; } /** * Finds the best fitting node in the tree for the given Key value. * @returns Pointer to the best fitting node found. * @param ppTree Pointer to Pointer to the tree root node. * @param Key The Key of which is to be found a best fitting match for.. * @param fAbove TRUE: Returned node is have the closest key to Key from above. * FALSE: Returned node is have the closest key to Key from below. * @status completely implemented. * @sketch The best fitting node is always located in the searchpath above you. * >= (above): The node where you last turned left. * <= (below): the node where you last turned right. * @author knut st. osmundsen */ PAVLNODECORE AVLGetBestFit(PPAVLNODECORE ppTree, AVLKEY Key, int fAbove) { #ifdef AVL_CMP register int iDiff; #endif register PAVLNODECORE pNode = *ppTree; PAVLNODECORE pNodeLast = NULL; if (fAbove) { /* pNode->Key >= Key */ #ifndef AVL_CMP while (pNode != NULL && AVL_NE(pNode->Key, Key)) #else while (pNode != NULL && (iDiff = AVL_CMP(pNode->Key, Key)) != 0) #endif { #ifndef AVL_CMP if (AVL_G(pNode->Key, Key)) #else if (iDiff > 0) #endif { pNodeLast = pNode; pNode = pNode->pLeft; } else pNode = pNode->pRight; } } else { /* pNode->Key <= Key */ #ifndef AVL_CMP while (pNode != NULL && AVL_NE(pNode->Key, Key)) #else while (pNode != NULL && (iDiff = AVL_CMP(pNode->Key, Key)) != 0) #endif { #ifndef AVL_CMP if (AVL_L(pNode->Key, Key)) #else if (iDiff < 0) #endif { pNodeLast = pNode; pNode = pNode->pRight; } else pNode = pNode->pLeft; } } return pNode == NULL ? pNodeLast /* best fit */ : pNode /* perfect match */; } /** * Rewindes a stack of pointer to pointers to nodes, rebalancing the tree. * @param pStack Pointer to stack to rewind. * @sketch LOOP thru all stack entries * BEGIN * Get pointer to pointer to node (and pointer to node) from stack. * IF 2 higher left subtree than in right subtree THEN * BEGIN * IF higher (or equal) left-sub-subtree than right-sub-subtree THEN * * n+2|n+3 * / \ / \ * n+2 n ==> n+1 n+1|n+2 * / \ / \ * n+1 n|n+1 n|n+1 n * * Or with keys: * * 4 2 * / \ / \ * 2 5 ==> 1 4 * / \ / \ * 1 3 3 5 * * ELSE * * n+2 * / \ / \ * n+2 n n+1 n+1 * / \ ==> / \ / \ * n n+1 n L R n * / \ * L R * * Or with keys: * 6 4 * / \ / \ * 2 7 ==> 2 6 * / \ / \ / \ * 1 4 1 3 5 7 * / \ * 3 5 * END * ELSE IF 2 higher in right subtree than in left subtree THEN * BEGIN * Same as above but left <==> right. (invert the picture) * ELSE * IF correct height THEN break * ELSE correct height. * END * @status * @author knut st. osmundsen * @remark */ INLINE void AVLRebalance(PAVLSTACK pStack) { while (pStack->cEntries > 0) { PPAVLNODECORE ppNode = pStack->aEntries[--pStack->cEntries]; PAVLNODECORE pNode = *ppNode; PAVLNODECORE pLeftNode = pNode->pLeft; unsigned char uchLeftHeight = AVL_HEIGHTOF(pLeftNode); PAVLNODECORE pRightNode = pNode->pRight; unsigned char uchRightHeight = AVL_HEIGHTOF(pRightNode); if (uchRightHeight + 1 < uchLeftHeight) { PAVLNODECORE pLeftLeftNode = pLeftNode->pLeft; PAVLNODECORE pLeftRightNode = pLeftNode->pRight; unsigned char uchLeftRightHeight = AVL_HEIGHTOF(pLeftRightNode); if (AVL_HEIGHTOF(pLeftLeftNode) >= uchLeftRightHeight) { pNode->pLeft = pLeftRightNode; pLeftNode->pRight = pNode; pLeftNode->uchHeight = (unsigned char)(1 + (pNode->uchHeight = (unsigned char)(1 + uchLeftRightHeight))); *ppNode = pLeftNode; } else { pLeftNode->pRight = pLeftRightNode->pLeft; pNode->pLeft = pLeftRightNode->pRight; pLeftRightNode->pLeft = pLeftNode; pLeftRightNode->pRight = pNode; pLeftNode->uchHeight = pNode->uchHeight = uchLeftRightHeight; pLeftRightNode->uchHeight = uchLeftHeight; *ppNode = pLeftRightNode; } } else if (uchLeftHeight + 1 < uchRightHeight) { PAVLNODECORE pRightLeftNode = pRightNode->pLeft; unsigned char uchRightLeftHeight = AVL_HEIGHTOF(pRightLeftNode); PAVLNODECORE pRightRightNode = pRightNode->pRight; if (AVL_HEIGHTOF(pRightRightNode) >= uchRightLeftHeight) { pNode->pRight = pRightLeftNode; pRightNode->pLeft = pNode; pRightNode->uchHeight = (unsigned char)(1 + (pNode->uchHeight = (unsigned char)(1 + uchRightLeftHeight))); *ppNode = pRightNode; } else { pRightNode->pLeft = pRightLeftNode->pRight; pNode->pRight = pRightLeftNode->pLeft; pRightLeftNode->pRight = pRightNode; pRightLeftNode->pLeft = pNode; pRightNode->uchHeight = pNode->uchHeight = uchRightLeftHeight; pRightLeftNode->uchHeight = uchRightHeight; *ppNode = pRightLeftNode; } } else { register unsigned char uchHeight = (unsigned char)(max(uchLeftHeight, uchRightHeight) + 1); if (uchHeight == pNode->uchHeight) break; pNode->uchHeight = uchHeight; } } } kbuild-3149/src/fastdep/Makefile0000644000175000017500000000336313252530215016564 0ustar locutuslocutus# $Id: Makefile 2413 2010-09-11 17:43:04Z bird $ # # Odin32 API # # Makefile for the Quick-and-Dirty dependency utility. (FastDep) # # Copyright (c) 1999-2010 knut st. osmundsen # # GPL # !ifdef BUILD_SETUP_MAK # # Setup config # ALL_NO_DBGMEM = 1 PATH_ROOT = ..\.. !include $(PATH_ROOT)\$(BUILD_SETUP_MAK) # # Target config # TARGET_NAME = fastdep TARGET_MODE = EXE TARGET_NEEDED = 1 TARGET_PUB_BASE = $(PATH_TOOLS) TARGET_OBJS =\ $(PATH_TARGET)\fastdep.$(EXT_OBJ)\ $(PATH_TARGET)\avl.$(EXT_OBJ)\ TARGET_LIBS =\ $(LIB_OS)\ $(LIB_C_OBJ) # # Rules config # RULES_FORWARD = !include $(MAKE_INCLUDE_PROCESS) !else # # Directory macro. # ODIN32_BIN = $(ODIN32_TOOLS) # # Tell buildenvironment that we're making an VIO .exe. # Tell buildenvironment that we like to use static linked CRT. # Tell buildenvironment that we should not copy this into /bin. # EXETARGET = 1 VIO = 1 STATIC_CRT = 1 NO_MAIN_BIN_COPY = 1 # # include common definitions # !include ../../makefile.inc # # Addjust common definitions # !if "$(VAC3)" == "1" || "$(VAC36)" == "1" CFLAGS = $(CFLAGS) -W3 -Wall+ppt-ppc-inl-cnv-gnr-vft-gen-uni-ext- \ !ifdef DEBUG -O+ -Tm- !endif !endif # # Object files. Prefix with OBJDIR and one space before the '\'. # OBJS = \ $(OBJDIR)\fastdep.obj \ $(OBJDIR)\avl.obj # # Libraries. One space before the '\'. # LIBS = \ $(RTLLIB) \ os2386.lib # # Target name - name of the exe without extention and path. # TARGET = FastDep # # Includes the common rules. # !include $(ODIN32_POST_INC) # # We need all. # needed: all !endif # # NT version using Watcom C/C++. # fastdepnt.exe: wcl386 -bt=nt -l=nt -d2 /hc /"option map" -DOS2FAKE=1 -I$(WATCOM)\h\nt fastdep.c avl.c os2fake-win.c /Fe=$@ kernel32.lib kbuild-3149/src/fastdep/os2fake.h0000644000175000017500000001141013252530215016617 0ustar locutuslocutus/* $Id: os2fake.h 2243 2009-01-10 02:24:02Z bird $ * * Structures, defines and function prototypes for the OS/2 fake library. * * Copyright (c) 2001-2009 knut st. osmundsen (knut.stange.osmundsen@mynd.no) * * GPL * */ #ifndef _os2fake_h_ #define _os2fake_h_ /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ #ifndef OS2ENTRY #define OS2ENTRY #endif #ifndef CCHMAXPATHCOMP #define CCHMAXPATHCOMP 256 #endif #ifndef CCHMAXPATH #define CCHMAXPATH 260 #endif #ifndef FIL_STANDARD #define FIL_STANDARD 1 #define FIL_QUERYEASIZE 2 #define FIL_QUERYEASFROMLIST 3 #define FIL_QUERYFULLNAME 5 #endif #define FILE_NORMAL 0x0000 #define FILE_READONLY 0x0001 #define FILE_HIDDEN 0x0002 #define FILE_SYSTEM 0x0004 #define FILE_DIRECTORY 0x0010 #define FILE_ARCHIVED 0x0020 #ifndef HDIR_CREATE #define HDIR_CREATE (-1) #endif #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #ifndef NO_ERROR #define NO_ERROR 0 #endif /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ typedef char * PCH; typedef char * PSZ; typedef const char * PCSZ; typedef unsigned long ULONG; typedef ULONG * PULONG; typedef unsigned short USHORT; typedef USHORT * PUSHORT; #if !defined(_WINDEF_) typedef unsigned int UINT; typedef UINT * PUINT; typedef unsigned char UCHAR; typedef UCHAR * PUCHAR; #if !defined(CHAR) typedef char CHAR; typedef CHAR * PCHAR; #endif typedef unsigned long BOOL; typedef BOOL * PBOOL; #endif #if !defined(VOID) typedef void VOID; #endif #if !defined(_WINNT_) && !defined(PVOID) typedef VOID * PVOID; #endif typedef unsigned long HDIR; typedef HDIR * PHDIR; typedef unsigned long APIRET; typedef struct _FTIME /* ftime */ { #if defined(__IBMC__) || defined(__IBMCPP__) UINT twosecs : 5; UINT minutes : 6; UINT hours : 5; #else USHORT twosecs : 5; USHORT minutes : 6; USHORT hours : 5; #endif } FTIME; typedef FTIME *PFTIME; typedef struct _FDATE /* fdate */ { #if defined(__IBMC__) || defined(__IBMCPP__) UINT day : 5; UINT month : 4; UINT year : 7; #else USHORT day : 5; USHORT month : 4; USHORT year : 7; #endif } FDATE; typedef FDATE *PFDATE; typedef struct _FILESTATUS3 /* fsts3 */ { FDATE fdateCreation; FTIME ftimeCreation; FDATE fdateLastAccess; FTIME ftimeLastAccess; FDATE fdateLastWrite; FTIME ftimeLastWrite; ULONG cbFile; ULONG cbFileAlloc; ULONG attrFile; } FILESTATUS3; typedef FILESTATUS3 *PFILESTATUS3; typedef struct _FILEFINDBUF3 /* findbuf3 */ { ULONG oNextEntryOffset; FDATE fdateCreation; FTIME ftimeCreation; FDATE fdateLastAccess; FTIME ftimeLastAccess; FDATE fdateLastWrite; FTIME ftimeLastWrite; ULONG cbFile; ULONG cbFileAlloc; ULONG attrFile; UCHAR cchName; CHAR achName[CCHMAXPATHCOMP]; } FILEFINDBUF3; typedef FILEFINDBUF3 *PFILEFINDBUF3; /******************************************************************************* * Function Prototypes * *******************************************************************************/ APIRET OS2ENTRY DosQueryPathInfo( PCSZ pszPathName, ULONG ulInfoLevel, PVOID pInfoBuf, ULONG cbInfoBuf); APIRET OS2ENTRY DosFindFirst( PCSZ pszFileSpec, PHDIR phdir, ULONG flAttribute, PVOID pFindBuf, ULONG cbFindBuf, PULONG pcFileNames, ULONG ulInfoLevel); APIRET OS2ENTRY DosFindNext( HDIR hDir, PVOID pFindBuf, ULONG cbFindBuf, PULONG pcFileNames); APIRET OS2ENTRY DosFindClose( HDIR hDir); #endif kbuild-3149/src/kWorker/0000755000175000017500000000000013252530210015110 5ustar locutuslocutuskbuild-3149/src/kWorker/Makefile.kmk0000644000175000017500000001117313252530206017341 0ustar locutuslocutus# $Id: Makefile.kmk 3042 2017-05-11 10:23:12Z bird $ ## @file # Sub-makefile for kWorker. # # # Copyright (c) 2016 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # SUB_DEPTH = ../.. include $(PATH_KBUILD)/subheader.kmk PROGRAMS += kWorker kWorker_TEMPLATE = BIN-STATIC-THREADED kWorker_DEFS := KWORKER kWorker_DEFS.debug = K_STRICT kWorker_DEFS.release = NASSERT kWorker_SOURCES = \ kWorker.c \ ../kmk/kmkbuiltin/kDepObj.c kWorker_INCS = \ ../kmk/ \ ../kmk/kmkbuiltin kWorker_LIBS = \ $(kStuff_1_TARGET) \ $(kWorkerLib_1_TARGET) include $(KBUILD_PATH)/sdks/WINDDK71.kmk kWorker_LIBS.win = \ $(TEMPLATE_BIN-STATIC-THREADED_LIBS) \ $(PATH_SDK_WINDDK71_LIB_WNET)/ntdll.lib \ $(PATH_SDK_WINDDK71_LIB_WNET)/psapi.lib kWorker_LDFLAGS.win = \ /BASE:0x10000 /DYNAMICBASE:NO /FIXED #kWorker_LDFLAGS.win.x86 = \ # /SAFESEH:NO - doesn't help anyone. # # Stuff from ../libs. Need to rebuilt it with static CRT. # LIBRARIES += kWorkerLib kWorkerLib_TEMPLATE = LIB-STATIC-THREADED kWorkerLib_DEFPATH = ../lib # Need fix from r2837. kWorkerLib_DEFPATH := $(PATH_SUB_CURRENT)/../lib kWorkerLib_DEFS := KWORKER kWorkerLib_SOURCES = \ crc32.c \ md5.c \ kbuild_version.c \ kDep.c kWorkerLib_SOURCES.win = \ nt_fullpath.c \ nt_fullpath_cached.c \ quoted_spawn.c \ nt/nthlpcore.c \ nt/nthlpfs.c \ nt/ntdir.c \ nt/ntstat.c \ nt/ntunlink.c \ nt/kFsCache.c \ quote_argv.c \ maybe_con_write.c \ maybe_con_fwrite.c \ msc_buffered_printf.c kbuild_version.c_DEFS = KBUILD_SVN_REV=$(KBUILD_SVN_REV) # # kStuff library. # LIBRARIES += kStuff kStuff_TEMPLATE = LIB-STATIC-THREADED kStuff_DEFS.debug = K_STRICT kStuff_INCS = kStuff/include kStuff_DEFPATH = $(PATH_ROOT)/src/lib # kLdr kStuff_SOURCES += \ kStuff/kLdr/kLdr.c \ kStuff/kLdr/kLdrDyld.c \ kStuff/kLdr/kLdrDyldFind.c \ kStuff/kLdr/kLdrDyldMod.c \ kStuff/kLdr/kLdrDyldOS.c \ kStuff/kLdr/kLdrDyLdSem.c \ kStuff/kLdr/kLdrMod.c \ kStuff/kLdr/kLdrModLX.c \ kStuff/kLdr/kLdrModMachO.c \ kStuff/kLdr/kLdrModNative.c \ kStuff/kLdr/kLdrModPE.c kLdr_SOURCES.os2 += \ kStuff/kLdr/kLdr-os2.c \ kStuff/kLdr/kLdrA-os2.asm kLdr_SOURCES.win += \ kStuff/kLdr/kLdr-win.c # kRdr kStuff_SOURCES += \ kStuff/kRdr/kRdr.cpp \ kStuff/kRdr/kRdrFile.cpp \ kStuff/kRdr/kRdrBuffered.cpp # kCpu kStuff_SOURCES += \ kStuff/kCpu/kCpuCompare.c \ kStuff/kCpu/kCpuGetArchAndCpu.c # kHlp (CRT) kStuff_SOURCES += \ kStuff/kHlp/Generic/kHlpMemPComp.c \ kStuff/kHlp/Generic/kHlpMemICompAscii.c \ kStuff/kHlp/Generic/kHlpStrPCat.c \ kStuff/kHlp/Generic/kHlpStrNPCat.c \ kStuff/kHlp/Generic/kHlpStrPComp.c \ kStuff/kHlp/Generic/kHlpStrNPComp.c \ kStuff/kHlp/Generic/kHlpStrICompAscii.c \ kStuff/kHlp/Generic/kHlpStrIPCompAscii.c \ kStuff/kHlp/Generic/kHlpStrNICompAscii.c \ kStuff/kHlp/Generic/kHlpStrNIPCompAscii.c \ kStuff/kHlp/Generic/kHlpStrPCopy.c \ kStuff/kHlp/Generic/kHlpStrNLen.c \ kStuff/kHlp/Generic/kHlpInt2Ascii.c \ \ kStuff/kHlp/Generic/kHlpGetEnvUZ.c \ \ kStuff/kHlp/Generic/kHlpGetExt.c \ kStuff/kHlp/Generic/kHlpGetFilename.c \ kStuff/kHlp/Generic/kHlpIsFilenameOnly.c \ \ kStuff/kHlp/Generic/kHlpPage.c \ \ kStuff/kHlp/CRT/kHlpCRTAlloc.cpp \ kStuff/kHlp/CRT/kHlpCRTEnv.cpp \ kStuff/kHlp/CRT/kHlpCRTString.cpp kStuff_SOURCES.darwin += \ kStuff/kHlp/Bare/kHlpSys-darwin.c # # A couple of dummy DLLs we use for grabbing LDR TLS entries. # DLLS += kWorkerTls1K kWorkerTls64K kWorkerTls512K kWorkerTls1K_TEMPLATE = BIN-STATIC-THREADED kWorkerTls1K_DEFS = KWORKER_BASE=0x10000 TLS_SIZE=1024 kWorkerTls1K_SOURCES = kWorkerTlsXxxK.c kWorkerTls1K_LDFLAGS = /Entry:DummyDllEntry kWorkerTls64K_TEMPLATE = BIN-STATIC-THREADED kWorkerTls64K_DEFS = KWORKER_BASE=0x10000 TLS_SIZE=65536 kWorkerTls64K_SOURCES = kWorkerTlsXxxK.c kWorkerTls64K_LDFLAGS = /Entry:DummyDllEntry kWorkerTls512K_TEMPLATE = BIN-STATIC-THREADED kWorkerTls512K_DEFS = KWORKER_BASE=0x10000 TLS_SIZE=524288 kWorkerTls512K_SOURCES = kWorkerTlsXxxK.c kWorkerTls512K_LDFLAGS = /Entry:DummyDllEntry include $(KBUILD_PATH)/subfooter.kmk kbuild-3149/src/kWorker/tests-gpl2/0000755000175000017500000000000013252530206017121 5ustar locutuslocutuskbuild-3149/src/kWorker/kWorkerTlsXxxK.c0000644000175000017500000001105613252530206020216 0ustar locutuslocutus/* $Id: kWorkerTlsXxxK.c 3042 2017-05-11 10:23:12Z bird $ */ /** @file * kWorkerTlsXxxK - Loader TLS allocation hack DLL. */ /* * Copyright (c) 2017 knut st. osmundsen * * This file is part of kBuild. * * kBuild 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. * * kBuild 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 kBuild. If not, see * */ /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ #include /********************************************************************************************************************************* * Structures and Typedefs * *********************************************************************************************************************************/ typedef void KWLDRTLSALLOCATIONHOOK(void *hDll, ULONG idxTls, PIMAGE_TLS_CALLBACK *ppfnTlsCallback); /********************************************************************************************************************************* * Internal Functions * *********************************************************************************************************************************/ __declspec(dllexport) void __stdcall DummyTlsCallback(void *hDll, DWORD dwReason, void *pvContext); /********************************************************************************************************************************* * Global Variables * *********************************************************************************************************************************/ /** The TLS pointer array. The 2nd entry is NULL and serve to terminate the array. * The first entry can be used by kWorker if it needs to. */ __declspec(dllexport) PIMAGE_TLS_CALLBACK g_apfnTlsCallbacks[2] = { DummyTlsCallback, NULL }; /** * The TLS index. */ __declspec(dllexport) ULONG g_idxTls = ~(ULONG)0; /** * Initialization data. */ static char const g_abDummy[TLS_SIZE] = {0x42}; /** * The TLS directory entry. Not possible to get more than one from the linker * and probably also the loader doesn't want more than one anyway. */ #pragma section(".rdata$T", long, read) __declspec(allocate(".rdata$T")) const IMAGE_TLS_DIRECTORY _tls_used = { (ULONG_PTR)&g_abDummy, (ULONG_PTR)&g_abDummy + sizeof(g_abDummy), (ULONG_PTR)&g_idxTls, (ULONG_PTR)&g_apfnTlsCallbacks, 0, /* This SizeOfZeroFill bugger doesn't work on w10/amd64 from what I can tell! */ IMAGE_SCN_ALIGN_32BYTES }; /* * This is just a dummy TLS callback function. * We'll be replacing g_apfnTlsCallbacks[0] from kWorker.c after loading it. * * Note! W10 doesn't seem to want to process the TLS directory if the DLL * doesn't have any imports (to snap). */ __declspec(dllexport) void __stdcall DummyTlsCallback(void *hDll, DWORD dwReason, void *pvContext) { (void)hDll; (void)dwReason; (void)pvContext; if (dwReason == DLL_PROCESS_ATTACH) { HMODULE hModExe = (HMODULE)(ULONG_PTR)KWORKER_BASE; KWLDRTLSALLOCATIONHOOK *pfnHook = (KWLDRTLSALLOCATIONHOOK *)GetProcAddress(hModExe, "kwLdrTlsAllocationHook"); if (pfnHook) { pfnHook(hDll, g_idxTls, &g_apfnTlsCallbacks[0]); return; } __debugbreak(); } } /* * Dummy DLL entry point to avoid dragging in unnecessary CRT stuff. kWorkerTls1K!_tls_index */ BOOL __stdcall DummyDllEntry(void *hDll, DWORD dwReason, void *pvContext) { (void)hDll; (void)dwReason; (void)pvContext; return TRUE; } kbuild-3149/src/kWorker/kWorker.c0000644000175000017500000152324013252530210016707 0ustar locutuslocutus/* $Id: kWorker.c 3089 2017-10-04 13:10:41Z bird $ */ /** @file * kWorker - experimental process reuse worker for Windows. * * Note! This module must be linked statically in order to avoid * accidentally intercepting our own CRT calls. */ /* * Copyright (c) 2016 knut st. osmundsen * * This file is part of kBuild. * * kBuild 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. * * kBuild 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 kBuild. If not, see * */ /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ //#undef NDEBUG //#define K_STRICT 1 //#define KW_LOG_ENABLED #define PSAPI_VERSION 1 #include #include #include #include #include #include #include #include #include "nt/ntstat.h" #include "kbuild_version.h" #include "nt/ntstuff.h" #include #include "nt/kFsCache.h" #include "nt_fullpath.h" #include "quote_argv.h" #include "md5.h" #include "../kmk/kmkbuiltin.h" /********************************************************************************************************************************* * Defined Constants And Macros * *********************************************************************************************************************************/ /** @def WITH_TEMP_MEMORY_FILES * Enables temporary memory files for cl.exe. */ #define WITH_TEMP_MEMORY_FILES /** @def WITH_HASH_MD5_CACHE * Enables caching of MD5 sums for cl.exe. * This prevents wasting time on rehashing common headers each time * they are included. */ #define WITH_HASH_MD5_CACHE /** @def WITH_CRYPT_CTX_REUSE * Enables reusing crypt contexts. The Visual C++ compiler always creates a * context which is only used for MD5 and maybe some random bytes (VS 2010). * So, only create it once and add a reference to it instead of creating new * ones. Saves registry access among other things. */ #define WITH_CRYPT_CTX_REUSE /** @def WITH_CONSOLE_OUTPUT_BUFFERING * Enables buffering of all console output as well as removal of annoying * source file echo by cl.exe. */ #define WITH_CONSOLE_OUTPUT_BUFFERING /** @def WITH_STD_OUT_ERR_BUFFERING * Enables buffering of standard output and standard error buffer as well as * removal of annoying source file echo by cl.exe. */ #define WITH_STD_OUT_ERR_BUFFERING /** @def WITH_LOG_FILE * Log to file instead of stderr. */ #define WITH_LOG_FILE /** @def WITH_HISTORY * Keep history of the last jobs. For debugging. */ #define WITH_HISTORY /** @def WITH_FIXED_VIRTUAL_ALLOCS * Whether to pre allocate memory for known fixed VirtualAlloc calls (currently * there is only one, but an important one, from cl.exe). */ #if K_ARCH == K_ARCH_X86_32 # define WITH_FIXED_VIRTUAL_ALLOCS #endif /** @def WITH_PCH_CACHING * Enables read caching of precompiled header files. */ #if K_ARCH_BITS >= 64 # define WITH_PCH_CACHING #endif #ifndef NDEBUG # define KW_LOG_ENABLED #endif /** @def KW_LOG * Generic logging. * @param a Argument list for kwDbgPrintf */ #ifdef KW_LOG_ENABLED # define KW_LOG(a) kwDbgPrintf a #else # define KW_LOG(a) do { } while (0) #endif /** @def KWLDR_LOG * Loader related logging. * @param a Argument list for kwDbgPrintf */ #ifdef KW_LOG_ENABLED # define KWLDR_LOG(a) kwDbgPrintf a #else # define KWLDR_LOG(a) do { } while (0) #endif /** @def KWFS_LOG * FS cache logging. * @param a Argument list for kwDbgPrintf */ #ifdef KW_LOG_ENABLED # define KWFS_LOG(a) kwDbgPrintf a #else # define KWFS_LOG(a) do { } while (0) #endif /** @def KWOUT_LOG * Output related logging. * @param a Argument list for kwDbgPrintf */ #ifdef KW_LOG_ENABLED # define KWOUT_LOG(a) kwDbgPrintf a #else # define KWOUT_LOG(a) do { } while (0) #endif /** @def KWCRYPT_LOG * FS cache logging. * @param a Argument list for kwDbgPrintf */ #ifdef KW_LOG_ENABLED # define KWCRYPT_LOG(a) kwDbgPrintf a #else # define KWCRYPT_LOG(a) do { } while (0) #endif /** Converts a windows handle to a handle table index. * @note We currently just mask off the 31th bit, and do no shifting or anything * else to create an index of the handle. * @todo consider shifting by 2 or 3. */ #define KW_HANDLE_TO_INDEX(a_hHandle) ((KUPTR)(a_hHandle) & ~(KUPTR)KU32_C(0x8000000)) /** Maximum handle value we can deal with. */ #define KW_HANDLE_MAX 0x20000 /** Max temporary file size (memory backed). */ #if K_ARCH_BITS >= 64 # define KWFS_TEMP_FILE_MAX (256*1024*1024) #else # define KWFS_TEMP_FILE_MAX (64*1024*1024) #endif /** Marks unfinished code. */ #if 1 # define KWFS_TODO() do { kwErrPrintf("\nHit TODO on line %u in %s!\n", __LINE__, __FUNCTION__); fflush(stderr); __debugbreak(); } while (0) #else # define KWFS_TODO() do { kwErrPrintf("\nHit TODO on line %u in %s!\n", __LINE__, __FUNCTION__); fflush(stderr); } while (0) #endif /** User data key for tools. */ #define KW_DATA_KEY_TOOL (~(KUPTR)16381) /** User data key for a cached file. */ #define KW_DATA_KEY_CACHED_FILE (~(KUPTR)65521) /** String constant comma length. */ #define TUPLE(a_sz) a_sz, sizeof(a_sz) - 1 /********************************************************************************************************************************* * Structures and Typedefs * *********************************************************************************************************************************/ typedef enum KWLOCATION { KWLOCATION_INVALID = 0, KWLOCATION_EXE_DIR, KWLOCATION_IMPORTER_DIR, KWLOCATION_SYSTEM32, KWLOCATION_UNKNOWN_NATIVE, KWLOCATION_UNKNOWN, } KWLOCATION; typedef enum KWMODSTATE { KWMODSTATE_INVALID = 0, KWMODSTATE_NEEDS_BITS, KWMODSTATE_NEEDS_INIT, KWMODSTATE_BEING_INITED, KWMODSTATE_INIT_FAILED, KWMODSTATE_READY, } KWMODSTATE; typedef struct KWMODULE *PKWMODULE; typedef struct KWMODULE { /** Pointer to the next image. */ PKWMODULE pNext; /** The normalized path to the image. */ const char *pszPath; /** The hash of the program path. */ KU32 uHashPath; /** Number of references. */ KU32 cRefs; /** UTF-16 version of pszPath. */ const wchar_t *pwszPath; /** The offset of the filename in pszPath. */ KU16 offFilename; /** Set if executable. */ KBOOL fExe; /** Set if native module entry. */ KBOOL fNative; /** Loader module handle. */ PKLDRMOD pLdrMod; /** The windows module handle. */ HMODULE hOurMod; /** The of the loaded image bits. */ KSIZE cbImage; union { /** Data for a manually loaded image. */ struct { /** Where we load the image. */ KU8 *pbLoad; /** Virgin copy of the image. */ KU8 *pbCopy; /** Ldr pvBits argument. This is NULL till we've successfully resolved * the imports. */ void *pvBits; /** The state. */ KWMODSTATE enmState; #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_AMD64) /** The number of entries in the table. */ KU32 cFunctions; /** The function table address (in the copy). */ PRUNTIME_FUNCTION paFunctions; /** Set if we've already registered a function table already. */ KBOOL fRegisteredFunctionTable; #endif /** Set if we share memory with other executables. */ KBOOL fUseLdBuf; /** Set after the first whole image copy is done. */ KBOOL fCanDoQuick; /** Number of quick copy chunks. */ KU8 cQuickCopyChunks; /** Number of quick zero chunks. */ KU8 cQuickZeroChunks; /** Quicker image copy instructions that skips non-writable parts when * possible. Need to check fCanDoQuick, fUseLdBuf and previous executable * image. */ struct { /** The copy destination. */ KU8 *pbDst; /** The copy source. */ KU8 const *pbSrc; /** How much to copy. */ KSIZE cbToCopy; } aQuickCopyChunks[3]; /** For handling BSS and zero alignment padding when using aQuickCopyChunks. */ struct { /** Where to start zeroing. */ KU8 *pbDst; /** How much to zero. */ KSIZE cbToZero; } aQuickZeroChunks[3]; /** TLS index if one was allocated, otherwise KU32_MAX. */ KU32 idxTls; /** Offset (RVA) of the TLS initialization data. */ KU32 offTlsInitData; /** Number of bytes of TLS initialization data. */ KU32 cbTlsInitData; /** Number of allocated bytes for TLS. */ KU32 cbTlsAlloc; /** Number of TLS callbacks. */ KU32 cTlsCallbacks; /** Offset (RVA) of the TLS callback table. */ KU32 offTlsCallbacks; /** Number of imported modules. */ KSIZE cImpMods; /** Import array (variable size). */ PKWMODULE apImpMods[1]; } Manual; } u; } KWMODULE; typedef struct KWDYNLOAD *PKWDYNLOAD; typedef struct KWDYNLOAD { /** Pointer to the next in the list. */ PKWDYNLOAD pNext; /** The module handle we present to the application. * This is the LoadLibraryEx return value for special modules and the * KWMODULE.hOurMod value for the others. */ HMODULE hmod; /** The module for non-special resource stuff, NULL if special. */ PKWMODULE pMod; /** The length of the LoadLibary filename. */ KSIZE cchRequest; /** The LoadLibrary filename. */ char szRequest[1]; } KWDYNLOAD; /** * GetModuleHandle cache for system modules frequently queried. */ typedef struct KWGETMODULEHANDLECACHE { const char *pszName; KU8 cchName; KU8 cwcName; const wchar_t *pwszName; HANDLE hmod; } KWGETMODULEHANDLECACHE; typedef KWGETMODULEHANDLECACHE *PKWGETMODULEHANDLECACHE; /** * A cached file. */ typedef struct KFSWCACHEDFILE { /** The user data core. */ KFSUSERDATA Core; /** Cached file handle. */ HANDLE hCached; /** Cached file section handle. */ HANDLE hSection; /** Cached file content. */ KU8 *pbCached; /** The file size. */ KU32 cbCached; #ifdef WITH_HASH_MD5_CACHE /** Set if we've got a valid MD5 hash in abMd5Digest. */ KBOOL fValidMd5; /** The MD5 digest if fValidMd5 is set. */ KU8 abMd5Digest[16]; #endif /** Circular self reference. Prevents the object from ever going away and * keeps it handy for debugging. */ PKFSOBJ pFsObj; /** The file path (for debugging). */ char szPath[1]; } KFSWCACHEDFILE; /** Pointer to a cached filed. */ typedef KFSWCACHEDFILE *PKFSWCACHEDFILE; #ifdef WITH_HASH_MD5_CACHE /** Pointer to a MD5 hash instance. */ typedef struct KWHASHMD5 *PKWHASHMD5; /** * A MD5 hash instance. */ typedef struct KWHASHMD5 { /** The magic value. */ KUPTR uMagic; /** Pointer to the next hash handle. */ PKWHASHMD5 pNext; /** The cached file we've associated this handle with. */ PKFSWCACHEDFILE pCachedFile; /** The number of bytes we've hashed. */ KU32 cbHashed; /** Set if this has gone wrong. */ KBOOL fGoneBad; /** Set if we're in fallback mode (file not cached). */ KBOOL fFallbackMode; /** Set if we've already finalized the digest. */ KBOOL fFinal; /** The MD5 fallback context. */ struct MD5Context Md5Ctx; /** The finalized digest. */ KU8 abDigest[16]; } KWHASHMD5; /** Magic value for KWHASHMD5::uMagic (Les McCann). */ # define KWHASHMD5_MAGIC KUPTR_C(0x19350923) #endif /* WITH_HASH_MD5_CACHE */ #ifdef WITH_TEMP_MEMORY_FILES typedef struct KWFSTEMPFILESEG *PKWFSTEMPFILESEG; typedef struct KWFSTEMPFILESEG { /** File offset of data. */ KU32 offData; /** The size of the buffer pbData points to. */ KU32 cbDataAlloc; /** The segment data. */ KU8 *pbData; } KWFSTEMPFILESEG; typedef struct KWFSTEMPFILE *PKWFSTEMPFILE; typedef struct KWFSTEMPFILE { /** Pointer to the next temporary file for this run. */ PKWFSTEMPFILE pNext; /** The UTF-16 path. (Allocated after this structure.) */ const wchar_t *pwszPath; /** The path length. */ KU16 cwcPath; /** Number of active handles using this file/mapping (<= 2). */ KU8 cActiveHandles; /** Number of active mappings (mapped views) (0 or 1). */ KU8 cMappings; /** The amount of space allocated in the segments. */ KU32 cbFileAllocated; /** The current file size. */ KU32 cbFile; /** The number of segments. */ KU32 cSegs; /** Segments making up the file. */ PKWFSTEMPFILESEG paSegs; } KWFSTEMPFILE; #endif /* WITH_TEMP_MEMORY_FILES */ #ifdef WITH_CONSOLE_OUTPUT_BUFFERING /** * Console line buffer or output full buffer. */ typedef struct KWOUTPUTSTREAMBUF { /** The main output handle. */ HANDLE hOutput; /** Our backup handle. */ HANDLE hBackup; /** Set if this is a console handle and we're in line buffered mode. * When clear, we may buffer multiple lines, though try flush on line * boundraries when ever possible. */ KBOOL fIsConsole; /** Compressed GetFileType result. */ KU8 fFileType; KU8 abPadding[2]; union { /** Line buffer mode (fIsConsole == K_TRUE). */ struct { /** Amount of pending console output in wchar_t's. */ KU32 cwcBuf; /** The allocated buffer size. */ KU32 cwcBufAlloc; /** Pending console output. */ wchar_t *pwcBuf; } Con; /** Fully buffered mode (fIsConsole == K_FALSE). */ struct { /** Amount of pending output (in chars). */ KU32 cchBuf; #ifdef WITH_STD_OUT_ERR_BUFFERING /** The allocated buffer size (in chars). */ KU32 cchBufAlloc; /** Pending output. */ char *pchBuf; #endif } Fully; } u; } KWOUTPUTSTREAMBUF; /** Pointer to a console line buffer. */ typedef KWOUTPUTSTREAMBUF *PKWOUTPUTSTREAMBUF; /** * Combined console buffer of complete lines. */ typedef struct KWCONSOLEOUTPUT { /** The console output handle. * INVALID_HANDLE_VALUE if we haven't got a console and shouldn't be doing any * combined output buffering. */ HANDLE hOutput; /** The current code page for the console. */ KU32 uCodepage; /** Amount of pending console output in wchar_t's. */ KU32 cwcBuf; /** Number of times we've flushed it in any way (for cl.exe hack). */ KU32 cFlushes; /** Pending console output. */ wchar_t wszBuf[8192]; } KWCONSOLEOUTPUT; /** Pointer to a combined console buffer. */ typedef KWCONSOLEOUTPUT *PKWCONSOLEOUTPUT; #endif /* WITH_CONSOLE_OUTPUT_BUFFERING */ /** Handle type. */ typedef enum KWHANDLETYPE { KWHANDLETYPE_INVALID = 0, KWHANDLETYPE_FSOBJ_READ_CACHE, KWHANDLETYPE_FSOBJ_READ_CACHE_MAPPING, KWHANDLETYPE_TEMP_FILE, KWHANDLETYPE_TEMP_FILE_MAPPING, KWHANDLETYPE_OUTPUT_BUF } KWHANDLETYPE; /** Handle data. */ typedef struct KWHANDLE { KWHANDLETYPE enmType; /** Number of references */ KU32 cRefs; /** The current file offset. */ KU32 offFile; /** Handle access. */ KU32 dwDesiredAccess; /** The handle. */ HANDLE hHandle; /** Type specific data. */ union { /** The file system object. */ PKFSWCACHEDFILE pCachedFile; /** Temporary file handle or mapping handle. */ PKWFSTEMPFILE pTempFile; #ifdef WITH_CONSOLE_OUTPUT_BUFFERING /** Buffered output stream. */ PKWOUTPUTSTREAMBUF pOutBuf; #endif } u; } KWHANDLE; typedef KWHANDLE *PKWHANDLE; /** * Tracking one of our memory mappings. */ typedef struct KWMEMMAPPING { /** Number of references. */ KU32 cRefs; /** The mapping type (KWHANDLETYPE_FSOBJ_READ_CACHE_MAPPING or * KWHANDLETYPE_TEMP_FILE_MAPPING). */ KWHANDLETYPE enmType; /** The mapping address. */ PVOID pvMapping; /** Type specific data. */ union { /** The file system object. */ PKFSWCACHEDFILE pCachedFile; /** Temporary file handle or mapping handle. */ PKWFSTEMPFILE pTempFile; } u; } KWMEMMAPPING; /** Pointer to a memory mapping tracker. */ typedef KWMEMMAPPING *PKWMEMMAPPING; /** Pointer to a VirtualAlloc tracker entry. */ typedef struct KWVIRTALLOC *PKWVIRTALLOC; /** * Tracking an VirtualAlloc allocation. */ typedef struct KWVIRTALLOC { PKWVIRTALLOC pNext; void *pvAlloc; KSIZE cbAlloc; /** This is KU32_MAX if not a preallocated chunk. */ KU32 idxPreAllocated; } KWVIRTALLOC; /** Pointer to a heap (HeapCreate) tracker entry. */ typedef struct KWHEAP *PKWHEAP; /** * Tracking an heap (HeapCreate) */ typedef struct KWHEAP { PKWHEAP pNext; HANDLE hHeap; } KWHEAP; /** Pointer to a FlsAlloc/TlsAlloc tracker entry. */ typedef struct KWLOCALSTORAGE *PKWLOCALSTORAGE; /** * Tracking an FlsAlloc/TlsAlloc index. */ typedef struct KWLOCALSTORAGE { PKWLOCALSTORAGE pNext; KU32 idx; } KWLOCALSTORAGE; /** Pointer to an at exit callback record */ typedef struct KWEXITCALLACK *PKWEXITCALLACK; /** * At exit callback record. */ typedef struct KWEXITCALLACK { PKWEXITCALLACK pNext; _onexit_t pfnCallback; /** At exit doesn't have an exit code. */ KBOOL fAtExit; } KWEXITCALLACK; typedef enum KWTOOLTYPE { KWTOOLTYPE_INVALID = 0, KWTOOLTYPE_SANDBOXED, KWTOOLTYPE_WATCOM, KWTOOLTYPE_EXEC, KWTOOLTYPE_END } KWTOOLTYPE; typedef enum KWTOOLHINT { KWTOOLHINT_INVALID = 0, KWTOOLHINT_NONE, KWTOOLHINT_VISUAL_CPP_CL, KWTOOLHINT_VISUAL_CPP_LINK, KWTOOLHINT_END } KWTOOLHINT; /** * A kWorker tool. */ typedef struct KWTOOL { /** The user data core structure. */ KFSUSERDATA Core; /** The normalized path to the program. */ const char *pszPath; /** UTF-16 version of pszPath. */ wchar_t const *pwszPath; /** The kind of tool. */ KWTOOLTYPE enmType; union { struct { /** The main entry point. */ KUPTR uMainAddr; /** The executable. */ PKWMODULE pExe; /** List of dynamically loaded modules. * These will be kept loaded till the tool is destroyed (if we ever do that). */ PKWDYNLOAD pDynLoadHead; /** Module array sorted by hOurMod. */ PKWMODULE *papModules; /** Number of entries in papModules. */ KU32 cModules; /** Tool hint (for hacks and such). */ KWTOOLHINT enmHint; } Sandboxed; } u; } KWTOOL; /** Pointer to a tool. */ typedef struct KWTOOL *PKWTOOL; typedef struct KWSANDBOX *PKWSANDBOX; typedef struct KWSANDBOX { /** The tool currently running in the sandbox. */ PKWTOOL pTool; /** Jump buffer. */ jmp_buf JmpBuf; /** The thread ID of the main thread (owner of JmpBuf). */ DWORD idMainThread; /** Copy of the NT TIB of the main thread. */ NT_TIB TibMainThread; /** The NT_TIB::ExceptionList value inside the try case. * We restore this prior to the longjmp. */ void *pOutXcptListHead; /** The exit code in case of longjmp. */ int rcExitCode; /** Set if we're running. */ KBOOL fRunning; /** Whether to disable caching of ".pch" files. */ KBOOL fNoPchCaching; /** The command line. */ char *pszCmdLine; /** The UTF-16 command line. */ wchar_t *pwszCmdLine; /** Number of arguments in papszArgs. */ int cArgs; /** The argument vector. */ char **papszArgs; /** The argument vector. */ wchar_t **papwszArgs; /** The _pgmptr msvcrt variable. */ char *pgmptr; /** The _wpgmptr msvcrt variable. */ wchar_t *wpgmptr; /** The _initenv msvcrt variable. */ char **initenv; /** The _winitenv msvcrt variable. */ wchar_t **winitenv; /** Size of the array we've allocated (ASSUMES nobody messes with it!). */ KSIZE cEnvVarsAllocated; /** The _environ msvcrt variable. */ char **environ; /** The _wenviron msvcrt variable. */ wchar_t **wenviron; /** The shadow _environ msvcrt variable. */ char **papszEnvVars; /** The shadow _wenviron msvcrt variable. */ wchar_t **papwszEnvVars; /** Handle table. */ PKWHANDLE *papHandles; /** Size of the handle table. */ KU32 cHandles; /** Number of active handles in the table. */ KU32 cActiveHandles; /** Number of handles in the handle table that will not be freed. */ KU32 cFixedHandles; /** Total number of leaked handles. */ KU32 cLeakedHandles; /** Number of active memory mappings in paMemMappings. */ KU32 cMemMappings; /** The allocated size of paMemMappings. */ KU32 cMemMappingsAlloc; /** Memory mappings (MapViewOfFile / UnmapViewOfFile). */ PKWMEMMAPPING paMemMappings; /** Head of the list of temporary file. */ PKWFSTEMPFILE pTempFileHead; /** Head of the virtual alloc allocations. */ PKWVIRTALLOC pVirtualAllocHead; /** Head of the heap list (HeapCreate). * This is only done from images we forcibly restore. */ PKWHEAP pHeapHead; /** Head of the FlsAlloc indexes. */ PKWLOCALSTORAGE pFlsAllocHead; /** Head of the TlsAlloc indexes. */ PKWLOCALSTORAGE pTlsAllocHead; /** The at exit callback head. * This is only done from images we forcibly restore. */ PKWEXITCALLACK pExitCallbackHead; MY_UNICODE_STRING SavedCommandLine; #ifdef WITH_HASH_MD5_CACHE /** The special MD5 hash instance. */ PKWHASHMD5 pHashHead; /** ReadFile sets these while CryptHashData claims and clears them. * * This is part of the heuristics we use for MD5 caching for header files. The * observed pattern is that c1.dll/c1xx.dll first reads a chunk of a source or * header, then passes the same buffer and read byte count to CryptHashData. */ struct { /** The cached file last read from. */ PKFSWCACHEDFILE pCachedFile; /** The file offset of the last cached read. */ KU32 offRead; /** The number of bytes read last. */ KU32 cbRead; /** The buffer pointer of the last read. */ void *pvRead; } LastHashRead; #endif #ifdef WITH_CRYPT_CTX_REUSE /** Reusable crypt contexts. */ struct { /** The creation provider type. */ KU32 dwProvType; /** The creation flags. */ KU32 dwFlags; /** The length of the container name. */ KU32 cwcContainer; /** The length of the provider name. */ KU32 cwcProvider; /** The container name string. */ wchar_t *pwszContainer; /** The provider name string. */ wchar_t *pwszProvider; /** The context handle. */ HCRYPTPROV hProv; } aCryptCtxs[4]; /** Number of reusable crypt conexts in aCryptCtxs. */ KU32 cCryptCtxs; #endif #ifdef WITH_CONSOLE_OUTPUT_BUFFERING /** The internal standard output handle. */ KWHANDLE HandleStdOut; /** The internal standard error handle. */ KWHANDLE HandleStdErr; /** Standard output (and whatever else) buffer. */ KWOUTPUTSTREAMBUF StdOut; /** Standard error buffer. */ KWOUTPUTSTREAMBUF StdErr; /** Combined buffer of completed lines. */ KWCONSOLEOUTPUT Combined; #endif } KWSANDBOX; /** Replacement function entry. */ typedef struct KWREPLACEMENTFUNCTION { /** The function name. */ const char *pszFunction; /** The length of the function name. */ KSIZE cchFunction; /** The module name (optional). */ const char *pszModule; /** The replacement function or data address. */ KUPTR pfnReplacement; /** Only replace in the executable. * @todo fix the reinitialization of non-native DLLs! */ KBOOL fOnlyExe; } KWREPLACEMENTFUNCTION; typedef KWREPLACEMENTFUNCTION const *PCKWREPLACEMENTFUNCTION; #if 0 /** Replacement function entry. */ typedef struct KWREPLACEMENTDATA { /** The function name. */ const char *pszFunction; /** The length of the function name. */ KSIZE cchFunction; /** The module name (optional). */ const char *pszModule; /** Function providing the replacement. */ KUPTR (*pfnMakeReplacement)(PKWMODULE pMod, const char *pchSymbol, KSIZE cchSymbol); } KWREPLACEMENTDATA; typedef KWREPLACEMENTDATA const *PCKWREPLACEMENTDATA; #endif /********************************************************************************************************************************* * Global Variables * *********************************************************************************************************************************/ /** The sandbox data. */ static KWSANDBOX g_Sandbox; /** The module currently occupying g_abDefLdBuf. */ static PKWMODULE g_pModInLdBuf = NULL; /** The module that previuosly occupied g_abDefLdBuf. */ static PKWMODULE g_pModPrevInLdBuf = NULL; /** Module hash table. */ static PKWMODULE g_apModules[127]; /** GetModuleHandle cache. */ static KWGETMODULEHANDLECACHE g_aGetModuleHandleCache[] = { #define MOD_CACHE_STRINGS(str) str, sizeof(str) - 1, (sizeof(L##str) / sizeof(wchar_t)) - 1, L##str { MOD_CACHE_STRINGS("KERNEL32.DLL"), NULL }, { MOD_CACHE_STRINGS("mscoree.dll"), NULL }, }; /** Module pending TLS allocation. See kwLdrModuleCreateNonNativeSetupTls. */ static PKWMODULE g_pModPendingTlsAlloc = NULL; /** The file system cache. */ static PKFSCACHE g_pFsCache; /** The current directory (referenced). */ static PKFSOBJ g_pCurDirObj = NULL; #ifdef KBUILD_OS_WINDOWS /** The windows system32 directory (referenced). */ static PKFSDIR g_pWinSys32 = NULL; #endif /** Verbosity level. */ static int g_cVerbose = 2; /** Whether we should restart the worker. */ static KBOOL g_fRestart = K_FALSE; /** Whether control-C/SIGINT or Control-Break/SIGBREAK have been seen. */ static KBOOL volatile g_fCtrlC = K_FALSE; /* Further down. */ extern KWREPLACEMENTFUNCTION const g_aSandboxReplacements[]; extern KU32 const g_cSandboxReplacements; extern KWREPLACEMENTFUNCTION const g_aSandboxNativeReplacements[]; extern KU32 const g_cSandboxNativeReplacements; extern KWREPLACEMENTFUNCTION const g_aSandboxGetProcReplacements[]; extern KU32 const g_cSandboxGetProcReplacements; /** Create a larget BSS blob that with help of /IMAGEBASE:0x10000 should * cover the default executable link address of 0x400000. * @remarks Early main() makes it read+write+executable. Attempts as having * it as a separate section failed because the linker insists on * writing out every zero in the uninitialized section, resulting in * really big binaries. */ __declspec(align(0x1000)) static KU8 g_abDefLdBuf[16*1024*1024]; #ifdef WITH_LOG_FILE /** Log file handle. */ static HANDLE g_hLogFile = INVALID_HANDLE_VALUE; #endif #ifdef WITH_FIXED_VIRTUAL_ALLOCS /** Virtual address space reserved for CL.EXE heap manager. * * Visual C++ 2010 reserves a 78MB chunk of memory from cl.exe at a fixed * address. It's among other things used for precompiled headers, which * seemingly have addresses hardcoded into them and won't work if mapped * elsewhere. Thus, we have to make sure the area is available when cl.exe asks * for it. (The /Zm option may affect this allocation.) */ static struct { /** The memory address we need. */ KUPTR const uFixed; /** How much we need to fix. */ KSIZE const cbFixed; /** What we actually got, NULL if given back. */ void *pvReserved; /** Whether it is in use or not. */ KBOOL fInUse; } g_aFixedVirtualAllocs[] = { # if K_ARCH == K_ARCH_X86_32 /* Visual C++ 2010 reserves 0x04b00000 by default, and Visual C++ 2015 reserves 0x05300000. We get 0x0f000000 to handle large precompiled header files. */ { KUPTR_C( 0x11000000), KSIZE_C( 0x0f000000), NULL }, # else { KUPTR_C(0x000006BB00000000), KSIZE_C(0x000000002EE00000), NULL }, # endif }; #endif #ifdef WITH_HISTORY /** The job history. */ static char *g_apszHistory[32]; /** Index of the next history entry. */ static unsigned g_iHistoryNext = 0; #endif /** Number of jobs executed. */ static KU32 g_cJobs; /** Number of tools. */ static KU32 g_cTools; /** Number of modules. */ static KU32 g_cModules; /** Number of non-native modules. */ static KU32 g_cNonNativeModules; /** Number of read-cached files. */ static KU32 g_cReadCachedFiles; /** Total size of read-cached files. */ static KSIZE g_cbReadCachedFiles; /** Total number of ReadFile calls. */ static KSIZE g_cReadFileCalls; /** Total bytes read via ReadFile. */ static KSIZE g_cbReadFileTotal; /** Total number of read from read-cached files. */ static KSIZE g_cReadFileFromReadCached; /** Total bytes read from read-cached files. */ static KSIZE g_cbReadFileFromReadCached; /** Total number of read from in-memory temporary files. */ static KSIZE g_cReadFileFromInMemTemp; /** Total bytes read from in-memory temporary files. */ static KSIZE g_cbReadFileFromInMemTemp; /** Total number of WriteFile calls. */ static KSIZE g_cWriteFileCalls; /** Total bytes written via WriteFile. */ static KSIZE g_cbWriteFileTotal; /** Total number of written to from in-memory temporary files. */ static KSIZE g_cWriteFileToInMemTemp; /** Total bytes written to in-memory temporary files. */ static KSIZE g_cbWriteFileToInMemTemp; /********************************************************************************************************************************* * Internal Functions * *********************************************************************************************************************************/ static FNKLDRMODGETIMPORT kwLdrModuleGetImportCallback; static int kwLdrModuleResolveAndLookup(const char *pszName, PKWMODULE pExe, PKWMODULE pImporter, const char *pszSearchPath, PKWMODULE *ppMod); static KBOOL kwSandboxHandleTableEnter(PKWSANDBOX pSandbox, PKWHANDLE pHandle, HANDLE hHandle); #ifdef WITH_CONSOLE_OUTPUT_BUFFERING static void kwSandboxConsoleWriteA(PKWSANDBOX pSandbox, PKWOUTPUTSTREAMBUF pLineBuf, const char *pchBuffer, KU32 cchToWrite); #endif static PPEB kwSandboxGetProcessEnvironmentBlock(void); /** * Debug printing. * @param pszFormat Debug format string. * @param ... Format argument. */ static void kwDbgPrintfV(const char *pszFormat, va_list va) { if (g_cVerbose >= 2) { DWORD const dwSavedErr = GetLastError(); #ifdef WITH_LOG_FILE DWORD dwIgnored; char szTmp[2048]; int cchPrefix = _snprintf(szTmp, sizeof(szTmp), "%x:%x: ", GetCurrentProcessId(), GetCurrentThreadId()); int cch = vsnprintf(&szTmp[cchPrefix], sizeof(szTmp) - cchPrefix, pszFormat, va); if (cch < (int)sizeof(szTmp) - 1 - cchPrefix) cch += cchPrefix; else { cch = sizeof(szTmp) - 1; szTmp[cch] = '\0'; } if (g_hLogFile == INVALID_HANDLE_VALUE) { wchar_t wszFilename[128]; _snwprintf(wszFilename, K_ELEMENTS(wszFilename), L"kWorker-%x-%x.log", GetTickCount(), GetCurrentProcessId()); g_hLogFile = CreateFileW(wszFilename, GENERIC_WRITE, FILE_SHARE_READ, NULL /*pSecAttrs*/, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL /*hTemplateFile*/); } WriteFile(g_hLogFile, szTmp, cch, &dwIgnored, NULL /*pOverlapped*/); #else fprintf(stderr, "debug: "); vfprintf(stderr, pszFormat, va); #endif SetLastError(dwSavedErr); } } /** * Debug printing. * @param pszFormat Debug format string. * @param ... Format argument. */ static void kwDbgPrintf(const char *pszFormat, ...) { if (g_cVerbose >= 2) { va_list va; va_start(va, pszFormat); kwDbgPrintfV(pszFormat, va); va_end(va); } } /** * Debugger printing. * @param pszFormat Debug format string. * @param ... Format argument. */ static void kwDebuggerPrintfV(const char *pszFormat, va_list va) { if (IsDebuggerPresent()) { DWORD const dwSavedErr = GetLastError(); char szTmp[2048]; _vsnprintf(szTmp, sizeof(szTmp), pszFormat, va); OutputDebugStringA(szTmp); SetLastError(dwSavedErr); } } /** * Debugger printing. * @param pszFormat Debug format string. * @param ... Format argument. */ static void kwDebuggerPrintf(const char *pszFormat, ...) { va_list va; va_start(va, pszFormat); kwDebuggerPrintfV(pszFormat, va); va_end(va); } /** * Error printing. * @param pszFormat Message format string. * @param ... Format argument. */ static void kwErrPrintfV(const char *pszFormat, va_list va) { DWORD const dwSavedErr = GetLastError(); fprintf(stderr, "kWorker: error: "); vfprintf(stderr, pszFormat, va); SetLastError(dwSavedErr); } /** * Error printing. * @param pszFormat Message format string. * @param ... Format argument. */ static void kwErrPrintf(const char *pszFormat, ...) { va_list va; va_start(va, pszFormat); kwErrPrintfV(pszFormat, va); va_end(va); } /** * Error printing. * @return rc; * @param rc Return value * @param pszFormat Message format string. * @param ... Format argument. */ static int kwErrPrintfRc(int rc, const char *pszFormat, ...) { va_list va; va_start(va, pszFormat); kwErrPrintfV(pszFormat, va); va_end(va); return rc; } #ifdef K_STRICT KHLP_DECL(void) kHlpAssertMsg1(const char *pszExpr, const char *pszFile, unsigned iLine, const char *pszFunction) { DWORD const dwSavedErr = GetLastError(); fprintf(stderr, "\n" "!!Assertion failed!!\n" "Expression: %s\n" "Function : %s\n" "File: %s\n" "Line: %d\n" , pszExpr, pszFunction, pszFile, iLine); SetLastError(dwSavedErr); } KHLP_DECL(void) kHlpAssertMsg2(const char *pszFormat, ...) { DWORD const dwSavedErr = GetLastError(); va_list va; va_start(va, pszFormat); fprintf(stderr, pszFormat, va); va_end(va); SetLastError(dwSavedErr); } #endif /* K_STRICT */ /** * Hashes a string. * * @returns 32-bit string hash. * @param pszString String to hash. */ static KU32 kwStrHash(const char *pszString) { /* This algorithm was created for sdbm (a public-domain reimplementation of ndbm) database library. it was found to do well in scrambling bits, causing better distribution of the keys and fewer splits. it also happens to be a good general hashing function with good distribution. the actual function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below is the faster version used in gawk. [there is even a faster, duff-device version] the magic constant 65599 was picked out of thin air while experimenting with different constants, and turns out to be a prime. this is one of the algorithms used in berkeley db (see sleepycat) and elsewhere. */ KU32 uHash = 0; KU32 uChar; while ((uChar = (unsigned char)*pszString++) != 0) uHash = uChar + (uHash << 6) + (uHash << 16) - uHash; return uHash; } /** * Hashes a string. * * @returns The string length. * @param pszString String to hash. * @param puHash Where to return the 32-bit string hash. */ static KSIZE kwStrHashEx(const char *pszString, KU32 *puHash) { const char * const pszStart = pszString; KU32 uHash = 0; KU32 uChar; while ((uChar = (unsigned char)*pszString) != 0) { uHash = uChar + (uHash << 6) + (uHash << 16) - uHash; pszString++; } *puHash = uHash; return pszString - pszStart; } /** * Hashes a string. * * @returns The string length in wchar_t units. * @param pwszString String to hash. * @param puHash Where to return the 32-bit string hash. */ static KSIZE kwUtf16HashEx(const wchar_t *pwszString, KU32 *puHash) { const wchar_t * const pwszStart = pwszString; KU32 uHash = 0; KU32 uChar; while ((uChar = *pwszString) != 0) { uHash = uChar + (uHash << 6) + (uHash << 16) - uHash; pwszString++; } *puHash = uHash; return pwszString - pwszStart; } /** * Converts the given string to unicode. * * @returns Length of the resulting string in wchar_t's. * @param pszSrc The source string. * @param pwszDst The destination buffer. * @param cwcDst The size of the destination buffer in wchar_t's. */ static KSIZE kwStrToUtf16(const char *pszSrc, wchar_t *pwszDst, KSIZE cwcDst) { /* Just to the quick ASCII stuff for now. correct ansi code page stuff later some time. */ KSIZE offDst = 0; while (offDst < cwcDst) { char ch = *pszSrc++; pwszDst[offDst++] = ch; if (!ch) return offDst - 1; kHlpAssert((unsigned)ch < 127); } pwszDst[offDst - 1] = '\0'; return offDst; } /** * Converts the given string to UTF-16, allocating the buffer. * * @returns Pointer to the new heap allocation containing the UTF-16 version of * the source string. * @param pchSrc The source string. * @param cchSrc The length of the source string. */ static wchar_t *kwStrToUtf16AllocN(const char *pchSrc, KSIZE cchSrc) { DWORD const dwErrSaved = GetLastError(); KSIZE cwcBuf = cchSrc + 1; wchar_t *pwszBuf = (wchar_t *)kHlpAlloc(cwcBuf * sizeof(pwszBuf)); if (pwszBuf) { if (cchSrc > 0) { int cwcRet = MultiByteToWideChar(CP_ACP, 0, pchSrc, (int)cchSrc, pwszBuf, (int)cwcBuf - 1); if (cwcRet > 0) { kHlpAssert(cwcRet < (KSSIZE)cwcBuf); pwszBuf[cwcRet] = '\0'; } else { kHlpFree(pwszBuf); /* Figure the length and allocate the right buffer size. */ SetLastError(NO_ERROR); cwcRet = MultiByteToWideChar(CP_ACP, 0, pchSrc, (int)cchSrc, pwszBuf, 0); if (cwcRet) { cwcBuf = cwcRet + 2; pwszBuf = (wchar_t *)kHlpAlloc(cwcBuf * sizeof(pwszBuf)); if (pwszBuf) { SetLastError(NO_ERROR); cwcRet = MultiByteToWideChar(CP_ACP, 0, pchSrc, (int)cchSrc, pwszBuf, (int)cwcBuf - 1); if (cwcRet) { kHlpAssert(cwcRet < (KSSIZE)cwcBuf); pwszBuf[cwcRet] = '\0'; } else { kwErrPrintf("MultiByteToWideChar(,,%*.*s,,) -> dwErr=%d\n", cchSrc, cchSrc, pchSrc, GetLastError()); kHlpFree(pwszBuf); pwszBuf = NULL; } } } else { kwErrPrintf("MultiByteToWideChar(,,%*.*s,,NULL,0) -> dwErr=%d\n", cchSrc, cchSrc, pchSrc, GetLastError()); pwszBuf = NULL; } } } else pwszBuf[0] = '\0'; } SetLastError(dwErrSaved); return pwszBuf; } /** * Converts the given UTF-16 to a normal string. * * @returns Length of the resulting string. * @param pwszSrc The source UTF-16 string. * @param pszDst The destination buffer. * @param cbDst The size of the destination buffer in bytes. */ static KSIZE kwUtf16ToStr(const wchar_t *pwszSrc, char *pszDst, KSIZE cbDst) { /* Just to the quick ASCII stuff for now. correct ansi code page stuff later some time. */ KSIZE offDst = 0; while (offDst < cbDst) { wchar_t wc = *pwszSrc++; pszDst[offDst++] = (char)wc; if (!wc) return offDst - 1; kHlpAssert((unsigned)wc < 127); } pszDst[offDst - 1] = '\0'; return offDst; } /** * Converts the given UTF-16 to ASSI, allocating the buffer. * * @returns Pointer to the new heap allocation containing the ANSI version of * the source string. * @param pwcSrc The source string. * @param cwcSrc The length of the source string. */ static char *kwUtf16ToStrAllocN(const wchar_t *pwcSrc, KSIZE cwcSrc) { DWORD const dwErrSaved = GetLastError(); KSIZE cbBuf = cwcSrc + (cwcSrc >> 1) + 1; char *pszBuf = (char *)kHlpAlloc(cbBuf); if (pszBuf) { if (cwcSrc > 0) { int cchRet = WideCharToMultiByte(CP_ACP, 0, pwcSrc, (int)cwcSrc, pszBuf, (int)cbBuf - 1, NULL, NULL); if (cchRet > 0) { kHlpAssert(cchRet < (KSSIZE)cbBuf); pszBuf[cchRet] = '\0'; } else { kHlpFree(pszBuf); /* Figure the length and allocate the right buffer size. */ SetLastError(NO_ERROR); cchRet = WideCharToMultiByte(CP_ACP, 0, pwcSrc, (int)cwcSrc, pszBuf, 0, NULL, NULL); if (cchRet) { cbBuf = cchRet + 2; pszBuf = (char *)kHlpAlloc(cbBuf); if (pszBuf) { SetLastError(NO_ERROR); cchRet = WideCharToMultiByte(CP_ACP, 0, pwcSrc, (int)cwcSrc, pszBuf, (int)cbBuf - 1, NULL, NULL); if (cchRet) { kHlpAssert(cchRet < (KSSIZE)cbBuf); pszBuf[cchRet] = '\0'; } else { kwErrPrintf("WideCharToMultiByte(,,%*.*ls,,) -> dwErr=%d\n", cwcSrc, cwcSrc, pwcSrc, GetLastError()); kHlpFree(pszBuf); pszBuf = NULL; } } } else { kwErrPrintf("WideCharToMultiByte(,,%*.*ls,,NULL,0) -> dwErr=%d\n", cwcSrc, cwcSrc, pwcSrc, GetLastError()); pszBuf = NULL; } } } else pszBuf[0] = '\0'; } SetLastError(dwErrSaved); return pszBuf; } /** UTF-16 string length. */ static KSIZE kwUtf16Len(wchar_t const *pwsz) { KSIZE cwc = 0; while (*pwsz != '\0') cwc++, pwsz++; return cwc; } /** * Copy out the UTF-16 string following the convension of GetModuleFileName */ static DWORD kwUtf16CopyStyle1(wchar_t const *pwszSrc, wchar_t *pwszDst, KSIZE cwcDst) { KSIZE cwcSrc = kwUtf16Len(pwszSrc); if (cwcSrc + 1 <= cwcDst) { kHlpMemCopy(pwszDst, pwszSrc, (cwcSrc + 1) * sizeof(wchar_t)); return (DWORD)cwcSrc; } if (cwcDst > 0) { KSIZE cwcDstTmp = cwcDst - 1; pwszDst[cwcDstTmp] = '\0'; if (cwcDstTmp > 0) kHlpMemCopy(pwszDst, pwszSrc, cwcDstTmp); } SetLastError(ERROR_INSUFFICIENT_BUFFER); return (DWORD)cwcDst; } /** * Copy out the ANSI string following the convension of GetModuleFileName */ static DWORD kwStrCopyStyle1(char const *pszSrc, char *pszDst, KSIZE cbDst) { KSIZE cchSrc = kHlpStrLen(pszSrc); if (cchSrc + 1 <= cbDst) { kHlpMemCopy(pszDst, pszSrc, cchSrc + 1); return (DWORD)cchSrc; } if (cbDst > 0) { KSIZE cbDstTmp = cbDst - 1; pszDst[cbDstTmp] = '\0'; if (cbDstTmp > 0) kHlpMemCopy(pszDst, pszSrc, cbDstTmp); } SetLastError(ERROR_INSUFFICIENT_BUFFER); return (DWORD)cbDst; } /** * Normalizes the path so we get a consistent hash. * * @returns status code. * @param pszPath The path. * @param pszNormPath The output buffer. * @param cbNormPath The size of the output buffer. */ static int kwPathNormalize(const char *pszPath, char *pszNormPath, KSIZE cbNormPath) { KFSLOOKUPERROR enmError; PKFSOBJ pFsObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError); if (pFsObj) { KBOOL fRc; fRc = kFsCacheObjGetFullPathA(pFsObj, pszNormPath, cbNormPath, '\\'); kFsCacheObjRelease(g_pFsCache, pFsObj); if (fRc) return 0; return KERR_BUFFER_OVERFLOW; } return KERR_FILE_NOT_FOUND; } /** * Get the pointer to the filename part of the path. * * @returns Pointer to where the filename starts within the string pointed to by pszFilename. * @returns Pointer to the terminator char if no filename. * @param pszPath The path to parse. */ static wchar_t *kwPathGetFilenameW(const wchar_t *pwszPath) { const wchar_t *pwszLast = NULL; for (;;) { wchar_t wc = *pwszPath; #if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS if (wc == '/' || wc == '\\' || wc == ':') { while ((wc = *++pwszPath) == '/' || wc == '\\' || wc == ':') /* nothing */; pwszLast = pwszPath; } #else if (wc == '/') { while ((wc = *++pszFilename) == '/') /* betsuni */; pwszLast = pwszPath; } #endif if (!wc) return (wchar_t *)(pwszLast ? pwszLast : pwszPath); pwszPath++; } } /** * Retains a new reference to the given module * @returns pMod * @param pMod The module to retain. */ static PKWMODULE kwLdrModuleRetain(PKWMODULE pMod) { kHlpAssert(pMod->cRefs > 0); kHlpAssert(pMod->cRefs < 64); pMod->cRefs++; return pMod; } /** * Releases a module reference. * * @param pMod The module to release. */ static void kwLdrModuleRelease(PKWMODULE pMod) { if (--pMod->cRefs == 0) { /* Unlink it. */ if (!pMod->fExe) { PKWMODULE pPrev = NULL; unsigned idx = pMod->uHashPath % K_ELEMENTS(g_apModules); if (g_apModules[idx] == pMod) g_apModules[idx] = pMod->pNext; else { PKWMODULE pPrev = g_apModules[idx]; kHlpAssert(pPrev != NULL); while (pPrev->pNext != pMod) { pPrev = pPrev->pNext; kHlpAssert(pPrev != NULL); } pPrev->pNext = pMod->pNext; } } /* Release import modules. */ if (!pMod->fNative) { KSIZE idx = pMod->u.Manual.cImpMods; while (idx-- > 0) if (pMod->u.Manual.apImpMods[idx]) { kwLdrModuleRelease(pMod->u.Manual.apImpMods[idx]); pMod->u.Manual.apImpMods[idx] = NULL; } } /* Free our resources. */ kLdrModClose(pMod->pLdrMod); pMod->pLdrMod = NULL; if (!pMod->fNative) { kHlpPageFree(pMod->u.Manual.pbCopy, pMod->cbImage); kHlpPageFree(pMod->u.Manual.pbLoad, pMod->cbImage); } kHlpFree(pMod); } else kHlpAssert(pMod->cRefs < 64); } /** * Links the module into the module hash table. * * @returns pMod * @param pMod The module to link. */ static PKWMODULE kwLdrModuleLink(PKWMODULE pMod) { unsigned idx = pMod->uHashPath % K_ELEMENTS(g_apModules); pMod->pNext = g_apModules[idx]; g_apModules[idx] = pMod; return pMod; } /** * Replaces imports for this module according to g_aSandboxNativeReplacements. * * @param pMod The natively loaded module to process. */ static void kwLdrModuleDoNativeImportReplacements(PKWMODULE pMod) { KSIZE const cbImage = (KSIZE)kLdrModSize(pMod->pLdrMod); KU8 const * const pbImage = (KU8 const *)pMod->hOurMod; IMAGE_DOS_HEADER const *pMzHdr = (IMAGE_DOS_HEADER const *)pbImage; IMAGE_NT_HEADERS const *pNtHdrs; IMAGE_DATA_DIRECTORY const *pDirEnt; kHlpAssert(pMod->fNative); /* * Locate the export descriptors. */ /* MZ header. */ if (pMzHdr->e_magic == IMAGE_DOS_SIGNATURE) { kHlpAssertReturnVoid((KU32)pMzHdr->e_lfanew <= cbImage - sizeof(*pNtHdrs)); pNtHdrs = (IMAGE_NT_HEADERS const *)&pbImage[pMzHdr->e_lfanew]; } else pNtHdrs = (IMAGE_NT_HEADERS const *)pbImage; /* Check PE header. */ kHlpAssertReturnVoid(pNtHdrs->Signature == IMAGE_NT_SIGNATURE); kHlpAssertReturnVoid(pNtHdrs->FileHeader.SizeOfOptionalHeader == sizeof(pNtHdrs->OptionalHeader)); /* Locate the import descriptor array. */ pDirEnt = (IMAGE_DATA_DIRECTORY const *)&pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; if ( pDirEnt->Size > 0 && pDirEnt->VirtualAddress != 0) { const IMAGE_IMPORT_DESCRIPTOR *pImpDesc = (const IMAGE_IMPORT_DESCRIPTOR *)&pbImage[pDirEnt->VirtualAddress]; KU32 cLeft = pDirEnt->Size / sizeof(*pImpDesc); MEMORY_BASIC_INFORMATION ProtInfo = { NULL, NULL, 0, 0, 0, 0, 0 }; KU8 *pbProtRange = NULL; SIZE_T cbProtRange = 0; DWORD fOldProt = 0; KU32 const cbPage = 0x1000; BOOL fRc; kHlpAssertReturnVoid(pDirEnt->VirtualAddress < cbImage); kHlpAssertReturnVoid(pDirEnt->Size < cbImage); kHlpAssertReturnVoid(pDirEnt->VirtualAddress + pDirEnt->Size <= cbImage); /* * Walk the import descriptor array. * Note! This only works if there's a backup thunk array, otherwise we cannot get at the name. */ while ( cLeft-- > 0 && pImpDesc->Name > 0 && pImpDesc->FirstThunk > 0) { KU32 iThunk; const char * const pszImport = (const char *)&pbImage[pImpDesc->Name]; PIMAGE_THUNK_DATA paThunks = (PIMAGE_THUNK_DATA)&pbImage[pImpDesc->FirstThunk]; PIMAGE_THUNK_DATA paOrgThunks = (PIMAGE_THUNK_DATA)&pbImage[pImpDesc->OriginalFirstThunk]; kHlpAssertReturnVoid(pImpDesc->Name < cbImage); kHlpAssertReturnVoid(pImpDesc->FirstThunk < cbImage); kHlpAssertReturnVoid(pImpDesc->OriginalFirstThunk < cbImage); kHlpAssertReturnVoid(pImpDesc->OriginalFirstThunk != pImpDesc->FirstThunk); kHlpAssertReturnVoid(pImpDesc->OriginalFirstThunk); /* Iterate the thunks. */ for (iThunk = 0; paOrgThunks[iThunk].u1.Ordinal != 0; iThunk++) { KUPTR const off = paOrgThunks[iThunk].u1.Function; kHlpAssertReturnVoid(off < cbImage); if (!IMAGE_SNAP_BY_ORDINAL(off)) { IMAGE_IMPORT_BY_NAME const *pName = (IMAGE_IMPORT_BY_NAME const *)&pbImage[off]; KSIZE const cchSymbol = kHlpStrLen(pName->Name); KU32 i = g_cSandboxNativeReplacements; while (i-- > 0) if ( g_aSandboxNativeReplacements[i].cchFunction == cchSymbol && kHlpMemComp(g_aSandboxNativeReplacements[i].pszFunction, pName->Name, cchSymbol) == 0) { if ( !g_aSandboxNativeReplacements[i].pszModule || kHlpStrICompAscii(g_aSandboxNativeReplacements[i].pszModule, pszImport) == 0) { KW_LOG(("%s: replacing %s!%s\n", pMod->pLdrMod->pszName, pszImport, pName->Name)); /* The .rdata section is normally read-only, so we need to make it writable first. */ if ((KUPTR)&paThunks[iThunk] - (KUPTR)pbProtRange >= cbPage) { /* Restore previous .rdata page. */ if (fOldProt) { fRc = VirtualProtect(pbProtRange, cbProtRange, fOldProt, NULL /*pfOldProt*/); kHlpAssert(fRc); fOldProt = 0; } /* Query attributes for the current .rdata page. */ pbProtRange = (KU8 *)((KUPTR)&paThunks[iThunk] & ~(KUPTR)(cbPage - 1)); cbProtRange = VirtualQuery(pbProtRange, &ProtInfo, sizeof(ProtInfo)); kHlpAssert(cbProtRange); if (cbProtRange) { switch (ProtInfo.Protect) { case PAGE_READWRITE: case PAGE_WRITECOPY: case PAGE_EXECUTE_READWRITE: case PAGE_EXECUTE_WRITECOPY: /* Already writable, nothing to do. */ break; default: kHlpAssertMsgFailed(("%#x\n", ProtInfo.Protect)); case PAGE_READONLY: cbProtRange = cbPage; fRc = VirtualProtect(pbProtRange, cbProtRange, PAGE_READWRITE, &fOldProt); break; case PAGE_EXECUTE: case PAGE_EXECUTE_READ: cbProtRange = cbPage; fRc = VirtualProtect(pbProtRange, cbProtRange, PAGE_EXECUTE_READWRITE, &fOldProt); break; } kHlpAssertStmt(fRc, fOldProt = 0); } } paThunks[iThunk].u1.AddressOfData = g_aSandboxNativeReplacements[i].pfnReplacement; break; } } } } /* Next import descriptor. */ pImpDesc++; } if (fOldProt) { DWORD fIgnore = 0; fRc = VirtualProtect(pbProtRange, cbProtRange, fOldProt, &fIgnore); kHlpAssertMsg(fRc, ("%u\n", GetLastError())); K_NOREF(fRc); } } } /** * Creates a module from a native kLdr module handle. * * @returns Module w/ 1 reference on success, NULL on failure. * @param pLdrMod The native kLdr module. * @param pszPath The normalized path to the module. * @param cbPath The module path length with terminator. * @param uHashPath The module path hash. * @param fDoReplacements Whether to do import replacements on this * module. */ static PKWMODULE kwLdrModuleCreateForNativekLdrModule(PKLDRMOD pLdrMod, const char *pszPath, KSIZE cbPath, KU32 uHashPath, KBOOL fDoReplacements) { /* * Create the entry. */ PKWMODULE pMod = (PKWMODULE)kHlpAllocZ(sizeof(*pMod) + cbPath + cbPath * 2 * sizeof(wchar_t)); if (pMod) { pMod->pwszPath = (wchar_t *)(pMod + 1); kwStrToUtf16(pszPath, (wchar_t *)pMod->pwszPath, cbPath * 2); pMod->pszPath = (char *)kHlpMemCopy((char *)&pMod->pwszPath[cbPath * 2], pszPath, cbPath); pMod->uHashPath = uHashPath; pMod->cRefs = 1; pMod->offFilename = (KU16)(kHlpGetFilename(pszPath) - pszPath); pMod->fExe = K_FALSE; pMod->fNative = K_TRUE; pMod->pLdrMod = pLdrMod; pMod->hOurMod = (HMODULE)(KUPTR)pLdrMod->aSegments[0].MapAddress; pMod->cbImage = (KSIZE)kLdrModSize(pLdrMod); if (fDoReplacements) { DWORD const dwSavedErr = GetLastError(); kwLdrModuleDoNativeImportReplacements(pMod); SetLastError(dwSavedErr); } KW_LOG(("New module: %p LB %#010x %s (native)\n", (KUPTR)pMod->pLdrMod->aSegments[0].MapAddress, kLdrModSize(pMod->pLdrMod), pMod->pszPath)); g_cModules++; return kwLdrModuleLink(pMod); } return NULL; } /** * Creates a module using the native loader. * * @returns Module w/ 1 reference on success, NULL on failure. * @param pszPath The normalized path to the module. * @param uHashPath The module path hash. * @param fDoReplacements Whether to do import replacements on this * module. */ static PKWMODULE kwLdrModuleCreateNative(const char *pszPath, KU32 uHashPath, KBOOL fDoReplacements) { /* * Open the module and check the type. */ PKLDRMOD pLdrMod; int rc = kLdrModOpenNative(pszPath, &pLdrMod); if (rc == 0) { PKWMODULE pMod = kwLdrModuleCreateForNativekLdrModule(pLdrMod, pszPath, kHlpStrLen(pszPath) + 1, uHashPath, fDoReplacements); if (pMod) return pMod; kLdrModClose(pLdrMod); } return NULL; } /** * Sets up the quick zero & copy tables for the non-native module. * * This is a worker for kwLdrModuleCreateNonNative. * * @param pMod The module. */ static void kwLdrModuleCreateNonNativeSetupQuickZeroAndCopy(PKWMODULE pMod) { PCKLDRSEG paSegs = pMod->pLdrMod->aSegments; KU32 cSegs = pMod->pLdrMod->cSegments; KU32 iSeg; KWLDR_LOG(("Setting up quick zero & copy for %s:\n", pMod->pszPath)); pMod->u.Manual.cQuickCopyChunks = 0; pMod->u.Manual.cQuickZeroChunks = 0; for (iSeg = 0; iSeg < cSegs; iSeg++) switch (paSegs[iSeg].enmProt) { case KPROT_READWRITE: case KPROT_WRITECOPY: case KPROT_EXECUTE_READWRITE: case KPROT_EXECUTE_WRITECOPY: if (paSegs[iSeg].cbMapped) { KU32 iChunk = pMod->u.Manual.cQuickCopyChunks; if (iChunk < K_ELEMENTS(pMod->u.Manual.aQuickCopyChunks)) { /* * Check for trailing zero words. */ KSIZE cbTrailingZeros; if ( paSegs[iSeg].cbMapped >= 64 * 2 * sizeof(KSIZE) && (paSegs[iSeg].cbMapped & 7) == 0 && pMod->u.Manual.cQuickZeroChunks < K_ELEMENTS(pMod->u.Manual.aQuickZeroChunks) ) { KSIZE const *pauNatural = (KSIZE const *)&pMod->u.Manual.pbCopy[(KSIZE)paSegs[iSeg].RVA]; KSIZE cNatural = paSegs[iSeg].cbMapped / sizeof(KSIZE); KSIZE idxFirstZero = cNatural; while (idxFirstZero > 0) if (pauNatural[--idxFirstZero] == 0) { /* likely */ } else { idxFirstZero++; break; } cbTrailingZeros = (cNatural - idxFirstZero) * sizeof(KSIZE); if (cbTrailingZeros < 128) cbTrailingZeros = 0; } else cbTrailingZeros = 0; /* * Add quick copy entry. */ if (cbTrailingZeros < paSegs[iSeg].cbMapped) { pMod->u.Manual.aQuickCopyChunks[iChunk].pbDst = &pMod->u.Manual.pbLoad[(KSIZE)paSegs[iSeg].RVA]; pMod->u.Manual.aQuickCopyChunks[iChunk].pbSrc = &pMod->u.Manual.pbCopy[(KSIZE)paSegs[iSeg].RVA]; pMod->u.Manual.aQuickCopyChunks[iChunk].cbToCopy = paSegs[iSeg].cbMapped - cbTrailingZeros; pMod->u.Manual.cQuickCopyChunks = iChunk + 1; KWLDR_LOG(("aQuickCopyChunks[%u]: %#p LB %#" KSIZE_PRI " <- %p (%*.*s)\n", iChunk, pMod->u.Manual.aQuickCopyChunks[iChunk].pbDst, pMod->u.Manual.aQuickCopyChunks[iChunk].cbToCopy, pMod->u.Manual.aQuickCopyChunks[iChunk].pbSrc, paSegs[iSeg].cchName, paSegs[iSeg].cchName, paSegs[iSeg].pchName)); } /* * Add quick zero entry. */ if (cbTrailingZeros) { KU32 iZero = pMod->u.Manual.cQuickZeroChunks; pMod->u.Manual.aQuickZeroChunks[iZero].pbDst = pMod->u.Manual.aQuickCopyChunks[iChunk].pbDst + pMod->u.Manual.aQuickCopyChunks[iChunk].cbToCopy; pMod->u.Manual.aQuickZeroChunks[iZero].cbToZero = cbTrailingZeros; pMod->u.Manual.cQuickZeroChunks = iZero + 1; KWLDR_LOG(("aQuickZeroChunks[%u]: %#p LB %#" KSIZE_PRI " <- zero (%*.*s)\n", iZero, pMod->u.Manual.aQuickZeroChunks[iZero].pbDst, pMod->u.Manual.aQuickZeroChunks[iZero].cbToZero, paSegs[iSeg].cchName, paSegs[iSeg].cchName, paSegs[iSeg].pchName)); } } else { /* * We're out of quick copy table entries, so just copy the whole darn thing. * We cannot 104% guarantee that the segments are in mapping order, so this is simpler. */ kHlpAssertFailed(); pMod->u.Manual.aQuickCopyChunks[0].pbDst = pMod->u.Manual.pbLoad; pMod->u.Manual.aQuickCopyChunks[0].pbSrc = pMod->u.Manual.pbCopy; pMod->u.Manual.aQuickCopyChunks[0].cbToCopy = pMod->cbImage; pMod->u.Manual.cQuickCopyChunks = 1; KWLDR_LOG(("Quick copy not possible!\n")); return; } } break; default: break; } } /** * Called from TLS allocation DLL during DLL_PROCESS_ATTACH. * * @param hDll The DLL handle. * @param idxTls The allocated TLS index. * @param ppfnTlsCallback Pointer to the TLS callback table entry. */ __declspec(dllexport) void kwLdrTlsAllocationHook(void *hDll, ULONG idxTls, PIMAGE_TLS_CALLBACK *ppfnTlsCallback) { /* * Do the module initialization thing first. */ PKWMODULE pMod = g_pModPendingTlsAlloc; if (pMod) { PPEB pPeb = kwSandboxGetProcessEnvironmentBlock(); LIST_ENTRY *pHead; LIST_ENTRY *pCur; pMod->u.Manual.idxTls = idxTls; KWLDR_LOG(("kwLdrTlsAllocationHook: idxTls=%d (%#x) for %s\n", idxTls, idxTls, pMod->pszPath)); /* * Try sabotage the DLL name so we can load this module again. */ pHead = &pPeb->Ldr->InMemoryOrderModuleList; for (pCur = pHead->Blink; pCur != pHead; pCur = pCur->Blink) { LDR_DATA_TABLE_ENTRY *pMte; pMte = (LDR_DATA_TABLE_ENTRY *)((KUPTR)pCur - K_OFFSETOF(LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks)); if (((KUPTR)pMte->DllBase & ~(KUPTR)31) == ((KUPTR)hDll & ~(KUPTR)31)) { PUNICODE_STRING pStr = &pMte->FullDllName; KSIZE off = pStr->Length / sizeof(pStr->Buffer[0]); pStr->Buffer[--off]++; pStr->Buffer[--off]++; pStr->Buffer[--off]++; KWLDR_LOG(("kwLdrTlsAllocationHook: patched the MTE (%p) for %p\n", pMte, hDll)); break; } } } } /** * Allocates and initializes TLS variables. * * @returns 0 on success, non-zero failure. * @param pMod The module. */ static int kwLdrModuleCreateNonNativeSetupTls(PKWMODULE pMod) { KU8 *pbImg = (KU8 *)pMod->u.Manual.pbCopy; IMAGE_NT_HEADERS const *pNtHdrs; IMAGE_DATA_DIRECTORY const *pTlsDir; if (((PIMAGE_DOS_HEADER)pbImg)->e_magic == IMAGE_DOS_SIGNATURE) pNtHdrs = (PIMAGE_NT_HEADERS)&pbImg[((PIMAGE_DOS_HEADER)pbImg)->e_lfanew]; else pNtHdrs = (PIMAGE_NT_HEADERS)pbImg; kHlpAssert(pNtHdrs->Signature == IMAGE_NT_SIGNATURE); pTlsDir = &pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS]; if (pTlsDir->Size >= sizeof(IMAGE_TLS_DIRECTORY)) { PIMAGE_TLS_DIRECTORY const paEntries = (PIMAGE_TLS_DIRECTORY)&pbImg[pTlsDir->VirtualAddress]; KU32 const cEntries = pTlsDir->Size / sizeof(IMAGE_TLS_DIRECTORY); KU32 iEntry; KUPTR offIndex; KUPTR offCallbacks; KUPTR const *puCallbacks; KSIZE cbData; const wchar_t *pwszTlsDll; HMODULE hmodTlsDll; /* * Check and log. */ for (iEntry = 0; iEntry < cEntries; iEntry++) { KUPTR offIndex = (KUPTR)paEntries[iEntry].AddressOfIndex - (KUPTR)pMod->u.Manual.pbLoad; KUPTR offCallbacks = (KUPTR)paEntries[iEntry].AddressOfCallBacks - (KUPTR)pMod->u.Manual.pbLoad; KUPTR const *puCallbacks = (KUPTR const *)&pbImg[offCallbacks]; KWLDR_LOG(("TLS DIR #%u: %#x-%#x idx=@%#x (%#x) callbacks=@%#x (%#x) cbZero=%#x flags=%#x\n", iEntry, paEntries[iEntry].StartAddressOfRawData, paEntries[iEntry].EndAddressOfRawData, paEntries[iEntry].AddressOfIndex, offIndex, paEntries[iEntry].AddressOfCallBacks, offCallbacks, paEntries[iEntry].SizeOfZeroFill, paEntries[iEntry].Characteristics)); if (offIndex >= pMod->cbImage) { kwErrPrintf("TLS entry #%u in %s has an invalid index address: %p, RVA %p, image size %#x\n", iEntry, pMod->pszPath, paEntries[iEntry].AddressOfIndex, offIndex, pMod->cbImage); return -1; } if (offCallbacks >= pMod->cbImage) { kwErrPrintf("TLS entry #%u in %s has an invalid callbacks address: %p, RVA %p, image size %#x\n", iEntry, pMod->pszPath, paEntries[iEntry].AddressOfCallBacks, offCallbacks, pMod->cbImage); return -1; } while (*puCallbacks != 0) { KWLDR_LOG(("TLS DIR #%u: callback %p, RVA %#x\n", iEntry, *puCallbacks, *puCallbacks - (KUPTR)pMod->u.Manual.pbLoad)); puCallbacks++; } if (paEntries[iEntry].Characteristics > IMAGE_SCN_ALIGN_16BYTES) { kwErrPrintf("TLS entry #%u in %s has an unsupported alignment restriction: %#x\n", iEntry, pMod->pszPath, paEntries[iEntry].Characteristics); return -1; } } if (cEntries > 1) { kwErrPrintf("More than one TLS directory entry in %s: %u\n", pMod->pszPath, cEntries); return -1; } /* * Make the allocation by loading a new instance of one of the TLS dlls. * The DLL will make a call to */ offIndex = (KUPTR)paEntries[0].AddressOfIndex - (KUPTR)pMod->u.Manual.pbLoad; offCallbacks = (KUPTR)paEntries[0].AddressOfCallBacks - (KUPTR)pMod->u.Manual.pbLoad; puCallbacks = (KUPTR const *)&pbImg[offCallbacks]; cbData = paEntries[0].SizeOfZeroFill + (paEntries[0].EndAddressOfRawData - paEntries[0].StartAddressOfRawData); if (cbData <= 1024) pwszTlsDll = L"kWorkerTls1K.dll"; else if (cbData <= 65536) pwszTlsDll = L"kWorkerTls64K.dll"; else if (cbData <= 524288) pwszTlsDll = L"kWorkerTls512K.dll"; else { kwErrPrintf("TLS data size in %s is too big: %u (%#p), max 512KB\n", pMod->pszPath, (unsigned)cbData, cbData); return -1; } pMod->u.Manual.idxTls = KU32_MAX; pMod->u.Manual.offTlsInitData = (KU32)((KUPTR)paEntries[0].StartAddressOfRawData - (KUPTR)pMod->u.Manual.pbLoad); pMod->u.Manual.cbTlsInitData = (KU32)(paEntries[0].EndAddressOfRawData - paEntries[0].StartAddressOfRawData); pMod->u.Manual.cbTlsAlloc = (KU32)cbData; pMod->u.Manual.cTlsCallbacks = 0; while (puCallbacks[pMod->u.Manual.cTlsCallbacks] != 0) pMod->u.Manual.cTlsCallbacks++; pMod->u.Manual.offTlsCallbacks = pMod->u.Manual.cTlsCallbacks ? (KU32)offCallbacks : KU32_MAX; g_pModPendingTlsAlloc = pMod; hmodTlsDll = LoadLibraryExW(pwszTlsDll, NULL /*hFile*/, 0); g_pModPendingTlsAlloc = NULL; if (hmodTlsDll == NULL) { kwErrPrintf("TLS allocation failed for '%s': LoadLibraryExW(%ls) -> %u\n", pMod->pszPath, pwszTlsDll, GetLastError()); return -1; } if (pMod->u.Manual.idxTls == KU32_MAX) { kwErrPrintf("TLS allocation failed for '%s': idxTls = KU32_MAX\n", pMod->pszPath, GetLastError()); return -1; } *(KU32 *)&pMod->u.Manual.pbCopy[offIndex] = pMod->u.Manual.idxTls; KWLDR_LOG(("kwLdrModuleCreateNonNativeSetupTls: idxTls=%d hmodTlsDll=%p (%ls) cbData=%#x\n", pMod->u.Manual.idxTls, hmodTlsDll, pwszTlsDll, cbData)); } return 0; } /** * Creates a module using the our own loader. * * @returns Module w/ 1 reference on success, NULL on failure. * @param pszPath The normalized path to the module. * @param uHashPath The module path hash. * @param fExe K_TRUE if this is an executable image, K_FALSE * if not. Executable images does not get entered * into the global module table. * @param pExeMod The executable module of the process (for * resolving imports). NULL if fExe is set. * @param pszSearchPath The PATH to search for imports. Can be NULL. */ static PKWMODULE kwLdrModuleCreateNonNative(const char *pszPath, KU32 uHashPath, KBOOL fExe, PKWMODULE pExeMod, const char *pszSearchPath) { /* * Open the module and check the type. */ PKLDRMOD pLdrMod; int rc = kLdrModOpen(pszPath, 0 /*fFlags*/, (KCPUARCH)K_ARCH, &pLdrMod); if (rc == 0) { switch (pLdrMod->enmType) { case KLDRTYPE_EXECUTABLE_FIXED: case KLDRTYPE_EXECUTABLE_RELOCATABLE: case KLDRTYPE_EXECUTABLE_PIC: if (!fExe) rc = KERR_GENERAL_FAILURE; break; case KLDRTYPE_SHARED_LIBRARY_RELOCATABLE: case KLDRTYPE_SHARED_LIBRARY_PIC: case KLDRTYPE_SHARED_LIBRARY_FIXED: if (fExe) rc = KERR_GENERAL_FAILURE; break; default: rc = KERR_GENERAL_FAILURE; break; } if (rc == 0) { KI32 cImports = kLdrModNumberOfImports(pLdrMod, NULL /*pvBits*/); if (cImports >= 0) { /* * Create the entry. */ KSIZE cbPath = kHlpStrLen(pszPath) + 1; PKWMODULE pMod = (PKWMODULE)kHlpAllocZ(sizeof(*pMod) + sizeof(pMod) * cImports + cbPath + cbPath * 2 * sizeof(wchar_t)); if (pMod) { KBOOL fFixed; pMod->cRefs = 1; pMod->offFilename = (KU16)(kHlpGetFilename(pszPath) - pszPath); pMod->uHashPath = uHashPath; pMod->fExe = fExe; pMod->fNative = K_FALSE; pMod->pLdrMod = pLdrMod; pMod->u.Manual.cImpMods = (KU32)cImports; #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_AMD64) pMod->u.Manual.fRegisteredFunctionTable = K_FALSE; #endif pMod->u.Manual.fUseLdBuf = K_FALSE; pMod->u.Manual.fCanDoQuick = K_FALSE; pMod->u.Manual.cQuickZeroChunks = 0; pMod->u.Manual.cQuickCopyChunks = 0; pMod->u.Manual.idxTls = KU32_MAX; pMod->u.Manual.offTlsInitData = KU32_MAX; pMod->u.Manual.cbTlsInitData = 0; pMod->u.Manual.cbTlsAlloc = 0; pMod->u.Manual.cTlsCallbacks = 0; pMod->u.Manual.offTlsCallbacks = 0; pMod->pszPath = (char *)kHlpMemCopy(&pMod->u.Manual.apImpMods[cImports + 1], pszPath, cbPath); pMod->pwszPath = (wchar_t *)(pMod->pszPath + cbPath + (cbPath & 1)); kwStrToUtf16(pMod->pszPath, (wchar_t *)pMod->pwszPath, cbPath * 2); /* * Figure out where to load it and get memory there. */ fFixed = pLdrMod->enmType == KLDRTYPE_EXECUTABLE_FIXED || pLdrMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED; pMod->u.Manual.pbLoad = fFixed ? (KU8 *)(KUPTR)pLdrMod->aSegments[0].LinkAddress : NULL; pMod->cbImage = (KSIZE)kLdrModSize(pLdrMod); if ( !fFixed || pLdrMod->enmType != KLDRTYPE_EXECUTABLE_FIXED /* only allow fixed executables */ || (KUPTR)pMod->u.Manual.pbLoad - (KUPTR)g_abDefLdBuf >= sizeof(g_abDefLdBuf) || sizeof(g_abDefLdBuf) - (KUPTR)pMod->u.Manual.pbLoad - (KUPTR)g_abDefLdBuf < pMod->cbImage) rc = kHlpPageAlloc((void **)&pMod->u.Manual.pbLoad, pMod->cbImage, KPROT_EXECUTE_READWRITE, fFixed); else pMod->u.Manual.fUseLdBuf = K_TRUE; if (rc == 0) { rc = kHlpPageAlloc(&pMod->u.Manual.pbCopy, pMod->cbImage, KPROT_READWRITE, K_FALSE); if (rc == 0) { KI32 iImp; /* * Link the module (unless it's an executable image) and process the imports. */ pMod->hOurMod = (HMODULE)pMod->u.Manual.pbLoad; if (!fExe) kwLdrModuleLink(pMod); KW_LOG(("New module: %p LB %#010x %s (kLdr)\n", pMod->u.Manual.pbLoad, pMod->cbImage, pMod->pszPath)); KW_LOG(("TODO: .reload /f %s=%p\n", pMod->pszPath, pMod->u.Manual.pbLoad)); kwDebuggerPrintf("TODO: .reload /f %s=%p\n", pMod->pszPath, pMod->u.Manual.pbLoad); for (iImp = 0; iImp < cImports; iImp++) { char szName[1024]; rc = kLdrModGetImport(pMod->pLdrMod, NULL /*pvBits*/, iImp, szName, sizeof(szName)); if (rc == 0) { rc = kwLdrModuleResolveAndLookup(szName, pExeMod, pMod, pszSearchPath, &pMod->u.Manual.apImpMods[iImp]); if (rc == 0) continue; } break; } if (rc == 0) { rc = kLdrModGetBits(pLdrMod, pMod->u.Manual.pbCopy, (KUPTR)pMod->u.Manual.pbLoad, kwLdrModuleGetImportCallback, pMod); if (rc == 0) { #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_AMD64) /* * Find the function table. No validation here because the * loader did that already, right... */ KU8 *pbImg = (KU8 *)pMod->u.Manual.pbCopy; IMAGE_NT_HEADERS const *pNtHdrs; IMAGE_DATA_DIRECTORY const *pXcptDir; if (((PIMAGE_DOS_HEADER)pbImg)->e_magic == IMAGE_DOS_SIGNATURE) pNtHdrs = (PIMAGE_NT_HEADERS)&pbImg[((PIMAGE_DOS_HEADER)pbImg)->e_lfanew]; else pNtHdrs = (PIMAGE_NT_HEADERS)pbImg; pXcptDir = &pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION]; kHlpAssert(pNtHdrs->Signature == IMAGE_NT_SIGNATURE); if (pXcptDir->Size > 0) { pMod->u.Manual.cFunctions = pXcptDir->Size / sizeof(pMod->u.Manual.paFunctions[0]); kHlpAssert( pMod->u.Manual.cFunctions * sizeof(pMod->u.Manual.paFunctions[0]) == pXcptDir->Size); pMod->u.Manual.paFunctions = (PRUNTIME_FUNCTION)&pbImg[pXcptDir->VirtualAddress]; } else { pMod->u.Manual.cFunctions = 0; pMod->u.Manual.paFunctions = NULL; } #endif kwLdrModuleCreateNonNativeSetupQuickZeroAndCopy(pMod); rc = kwLdrModuleCreateNonNativeSetupTls(pMod); if (rc == 0) { /* * Final finish. */ pMod->u.Manual.pvBits = pMod->u.Manual.pbCopy; pMod->u.Manual.enmState = KWMODSTATE_NEEDS_BITS; g_cModules++; g_cNonNativeModules++; return pMod; } } else kwErrPrintf("kLdrModGetBits failed for %s: %#x (%d)\n", pszPath, rc, rc); } kwLdrModuleRelease(pMod); return NULL; } kHlpPageFree(pMod->u.Manual.pbLoad, pMod->cbImage); kwErrPrintf("Failed to allocate %#x bytes\n", pMod->cbImage); } else if (fFixed) kwErrPrintf("Failed to allocate %#x bytes at %p\n", pMod->cbImage, (void *)(KUPTR)pLdrMod->aSegments[0].LinkAddress); else kwErrPrintf("Failed to allocate %#x bytes\n", pMod->cbImage); } } } kLdrModClose(pLdrMod); } else kwErrPrintf("kLdrOpen failed with %#x (%d) for %s\n", rc, rc, pszPath); return NULL; } /** Implements FNKLDRMODGETIMPORT, used by kwLdrModuleCreate. */ static int kwLdrModuleGetImportCallback(PKLDRMOD pMod, KU32 iImport, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol, const char *pszVersion, PKLDRADDR puValue, KU32 *pfKind, void *pvUser) { PKWMODULE pCurMod = (PKWMODULE)pvUser; PKWMODULE pImpMod = pCurMod->u.Manual.apImpMods[iImport]; int rc; K_NOREF(pMod); if (pImpMod->fNative) rc = kLdrModQuerySymbol(pImpMod->pLdrMod, NULL /*pvBits*/, KLDRMOD_BASEADDRESS_MAP, iSymbol, pchSymbol, cchSymbol, pszVersion, NULL /*pfnGetForwarder*/, NULL /*pvUSer*/, puValue, pfKind); else rc = kLdrModQuerySymbol(pImpMod->pLdrMod, pImpMod->u.Manual.pvBits, (KUPTR)pImpMod->u.Manual.pbLoad, iSymbol, pchSymbol, cchSymbol, pszVersion, NULL /*pfnGetForwarder*/, NULL /*pvUSer*/, puValue, pfKind); if (rc == 0) { KU32 i = g_cSandboxReplacements; while (i-- > 0) if ( g_aSandboxReplacements[i].cchFunction == cchSymbol && kHlpMemComp(g_aSandboxReplacements[i].pszFunction, pchSymbol, cchSymbol) == 0) { if ( !g_aSandboxReplacements[i].pszModule || kHlpStrICompAscii(g_aSandboxReplacements[i].pszModule, &pImpMod->pszPath[pImpMod->offFilename]) == 0) { if ( pCurMod->fExe || !g_aSandboxReplacements[i].fOnlyExe) { KW_LOG(("replacing %s!%s\n",&pImpMod->pszPath[pImpMod->offFilename], g_aSandboxReplacements[i].pszFunction)); *puValue = g_aSandboxReplacements[i].pfnReplacement; } break; } } } //printf("iImport=%u (%s) %*.*s rc=%d\n", iImport, &pImpMod->pszPath[pImpMod->offFilename], cchSymbol, cchSymbol, pchSymbol, rc); KW_LOG(("iImport=%u (%s) %*.*s rc=%d\n", iImport, &pImpMod->pszPath[pImpMod->offFilename], cchSymbol, cchSymbol, pchSymbol, rc)); return rc; } /** * Gets the main entrypoint for a module. * * @returns 0 on success, KERR on failure * @param pMod The module. * @param puAddrMain Where to return the address. */ static int kwLdrModuleQueryMainEntrypoint(PKWMODULE pMod, KUPTR *puAddrMain) { KLDRADDR uLdrAddrMain; int rc = kLdrModQueryMainEntrypoint(pMod->pLdrMod, pMod->u.Manual.pvBits, (KUPTR)pMod->u.Manual.pbLoad, &uLdrAddrMain); if (rc == 0) { *puAddrMain = (KUPTR)uLdrAddrMain; return 0; } return rc; } /** * Whether to apply g_aSandboxNativeReplacements to the imports of this module. * * @returns K_TRUE/K_FALSE. * @param pszFilename The filename (no path). * @param enmLocation The location. */ static KBOOL kwLdrModuleShouldDoNativeReplacements(const char *pszFilename, KWLOCATION enmLocation) { if (enmLocation != KWLOCATION_SYSTEM32) return K_TRUE; return kHlpStrNICompAscii(pszFilename, TUPLE("msvc")) == 0 || kHlpStrNICompAscii(pszFilename, TUPLE("msdis")) == 0 || kHlpStrNICompAscii(pszFilename, TUPLE("mspdb")) == 0; } /** * Lazily initializes the g_pWinSys32 variable. */ static PKFSDIR kwLdrResolveWinSys32(void) { KFSLOOKUPERROR enmError; PKFSDIR pWinSys32; /* Get the path first. */ char szSystem32[MAX_PATH]; if (GetSystemDirectoryA(szSystem32, sizeof(szSystem32)) >= sizeof(szSystem32)) { kwErrPrintf("GetSystemDirectory failed: %u\n", GetLastError()); strcpy(szSystem32, "C:\\Windows\\System32"); } /* Look it up and verify it. */ pWinSys32 = (PKFSDIR)kFsCacheLookupA(g_pFsCache, szSystem32, &enmError); if (pWinSys32) { if (pWinSys32->Obj.bObjType == KFSOBJ_TYPE_DIR) { g_pWinSys32 = pWinSys32; return pWinSys32; } kwErrPrintf("System directory '%s' isn't of 'DIR' type: %u\n", szSystem32, g_pWinSys32->Obj.bObjType); } else kwErrPrintf("Failed to lookup system directory '%s': %u\n", szSystem32, enmError); return NULL; } /** * Whether we can load this DLL natively or not. * * @returns K_TRUE/K_FALSE. * @param pszFilename The filename (no path). * @param enmLocation The location. * @param pszFullPath The full filename and path. */ static KBOOL kwLdrModuleCanLoadNatively(const char *pszFilename, KWLOCATION enmLocation, const char *pszFullPath) { if (enmLocation == KWLOCATION_SYSTEM32) return K_TRUE; if (enmLocation == KWLOCATION_UNKNOWN_NATIVE) return K_TRUE; /* If the location is unknown, we must check if it's some dynamic loading of a SYSTEM32 DLL with a full path. We do not want to load these ourselves! */ if (enmLocation == KWLOCATION_UNKNOWN) { PKFSDIR pWinSys32 = g_pWinSys32; if (!pWinSys32) pWinSys32 = kwLdrResolveWinSys32(); if (pWinSys32) { KFSLOOKUPERROR enmError; PKFSOBJ pFsObj = kFsCacheLookupA(g_pFsCache, pszFullPath, &enmError); if (pFsObj) { KBOOL fInWinSys32 = pFsObj->pParent == pWinSys32; kFsCacheObjRelease(g_pFsCache, pFsObj); if (fInWinSys32) return K_TRUE; } } } return kHlpStrNICompAscii(pszFilename, TUPLE("msvc")) == 0 || kHlpStrNICompAscii(pszFilename, TUPLE("msdis")) == 0 || kHlpStrNICompAscii(pszFilename, TUPLE("mspdb")) == 0; } /** * Check if the path leads to a regular file (that exists). * * @returns K_TRUE / K_FALSE * @param pszPath Path to the file to check out. */ static KBOOL kwLdrModuleIsRegularFile(const char *pszPath) { /* For stuff with .DLL extensions, we can use the GetFileAttribute cache to speed this up! */ KSIZE cchPath = kHlpStrLen(pszPath); if ( cchPath > 3 && pszPath[cchPath - 4] == '.' && (pszPath[cchPath - 3] == 'd' || pszPath[cchPath - 3] == 'D') && (pszPath[cchPath - 2] == 'l' || pszPath[cchPath - 2] == 'L') && (pszPath[cchPath - 1] == 'l' || pszPath[cchPath - 1] == 'L') ) { KFSLOOKUPERROR enmError; PKFSOBJ pFsObj = kFsCacheLookupNoMissingA(g_pFsCache, pszPath, &enmError); if (pFsObj) { KBOOL fRc = pFsObj->bObjType == KFSOBJ_TYPE_FILE; kFsCacheObjRelease(g_pFsCache, pFsObj); return fRc; } } else { BirdStat_T Stat; int rc = birdStatFollowLink(pszPath, &Stat); if (rc == 0) { if (S_ISREG(Stat.st_mode)) return K_TRUE; } } return K_FALSE; } /** * Worker for kwLdrModuleResolveAndLookup that checks out one possibility. * * If the file exists, we consult the module hash table before trying to load it * off the disk. * * @returns Pointer to module on success, NULL if not found, ~(KUPTR)0 on * failure. * @param pszPath The name of the import module. * @param enmLocation The location we're searching. This is used in * the heuristics for determining if we can use the * native loader or need to sandbox the DLL. * @param pExe The executable (optional). * @param pszSearchPath The PATH to search (optional). */ static PKWMODULE kwLdrModuleTryLoadDll(const char *pszPath, KWLOCATION enmLocation, PKWMODULE pExeMod, const char *pszSearchPath) { /* * Does the file exists and is it a regular file? */ if (kwLdrModuleIsRegularFile(pszPath)) { /* * Yes! Normalize it and look it up in the hash table. */ char szNormPath[1024]; int rc = kwPathNormalize(pszPath, szNormPath, sizeof(szNormPath)); if (rc == 0) { const char *pszName; KU32 const uHashPath = kwStrHash(szNormPath); unsigned idxHash = uHashPath % K_ELEMENTS(g_apModules); PKWMODULE pMod = g_apModules[idxHash]; if (pMod) { do { if ( pMod->uHashPath == uHashPath && kHlpStrComp(pMod->pszPath, szNormPath) == 0) return kwLdrModuleRetain(pMod); pMod = pMod->pNext; } while (pMod); } /* * Not in the hash table, so we have to load it from scratch. */ pszName = kHlpGetFilename(szNormPath); if (kwLdrModuleCanLoadNatively(pszName, enmLocation, szNormPath)) pMod = kwLdrModuleCreateNative(szNormPath, uHashPath, kwLdrModuleShouldDoNativeReplacements(pszName, enmLocation)); else pMod = kwLdrModuleCreateNonNative(szNormPath, uHashPath, K_FALSE /*fExe*/, pExeMod, pszSearchPath); if (pMod) return pMod; return (PKWMODULE)~(KUPTR)0; } } return NULL; } /** * Gets a reference to the module by the given name. * * We must do the search path thing, as our hash table may multiple DLLs with * the same base name due to different tools version and similar. We'll use a * modified search sequence, though. No point in searching the current * directory for instance. * * @returns 0 on success, KERR on failure. * @param pszName The name of the import module. * @param pExe The executable (optional). * @param pImporter The module doing the importing (optional). * @param pszSearchPath The PATH to search (optional). * @param ppMod Where to return the module pointer w/ reference. */ static int kwLdrModuleResolveAndLookup(const char *pszName, PKWMODULE pExe, PKWMODULE pImporter, const char *pszSearchPath, PKWMODULE *ppMod) { KSIZE const cchName = kHlpStrLen(pszName); char szPath[1024]; char *psz; PKWMODULE pMod = NULL; KBOOL fNeedSuffix = *kHlpGetExt(pszName) == '\0' && kHlpGetFilename(pszName) == pszName; KSIZE cchSuffix = fNeedSuffix ? 4 : 0; /* The import path. */ if (pMod == NULL && pImporter != NULL) { if (pImporter->offFilename + cchName + cchSuffix >= sizeof(szPath)) return KERR_BUFFER_OVERFLOW; psz = (char *)kHlpMemPCopy(kHlpMemPCopy(szPath, pImporter->pszPath, pImporter->offFilename), pszName, cchName + 1); if (fNeedSuffix) kHlpMemCopy(psz - 1, ".dll", sizeof(".dll")); pMod = kwLdrModuleTryLoadDll(szPath, KWLOCATION_IMPORTER_DIR, pExe, pszSearchPath); } /* Application directory first. */ if (pMod == NULL && pExe != NULL && pExe != pImporter) { if (pExe->offFilename + cchName + cchSuffix >= sizeof(szPath)) return KERR_BUFFER_OVERFLOW; psz = (char *)kHlpMemPCopy(kHlpMemPCopy(szPath, pExe->pszPath, pExe->offFilename), pszName, cchName + 1); if (fNeedSuffix) kHlpMemCopy(psz - 1, ".dll", sizeof(".dll")); pMod = kwLdrModuleTryLoadDll(szPath, KWLOCATION_EXE_DIR, pExe, pszSearchPath); } /* The windows directory. */ if (pMod == NULL) { UINT cchDir = GetSystemDirectoryA(szPath, sizeof(szPath)); if ( cchDir <= 2 || cchDir + 1 + cchName + cchSuffix >= sizeof(szPath)) return KERR_BUFFER_OVERFLOW; szPath[cchDir++] = '\\'; psz = (char *)kHlpMemPCopy(&szPath[cchDir], pszName, cchName + 1); if (fNeedSuffix) kHlpMemCopy(psz - 1, ".dll", sizeof(".dll")); pMod = kwLdrModuleTryLoadDll(szPath, KWLOCATION_SYSTEM32, pExe, pszSearchPath); } /* The path. */ if ( pMod == NULL && pszSearchPath) { const char *pszCur = pszSearchPath; while (*pszCur != '\0') { /* Find the end of the component */ KSIZE cch = 0; while (pszCur[cch] != ';' && pszCur[cch] != '\0') cch++; if ( cch > 0 /* wrong, but whatever */ && cch + 1 + cchName + cchSuffix < sizeof(szPath)) { char *pszDst = kHlpMemPCopy(szPath, pszCur, cch); if ( szPath[cch - 1] != ':' && szPath[cch - 1] != '/' && szPath[cch - 1] != '\\') *pszDst++ = '\\'; pszDst = kHlpMemPCopy(pszDst, pszName, cchName); if (fNeedSuffix) pszDst = kHlpMemPCopy(pszDst, ".dll", 4); *pszDst = '\0'; pMod = kwLdrModuleTryLoadDll(szPath, KWLOCATION_SYSTEM32, pExe, pszSearchPath); if (pMod) break; } /* Advance */ pszCur += cch; while (*pszCur == ';') pszCur++; } } /* Return. */ if (pMod != NULL && pMod != (PKWMODULE)~(KUPTR)0) { *ppMod = pMod; return 0; } *ppMod = NULL; return KERR_GENERAL_FAILURE; } /** * Does the TLS memory initialization for a module on the current thread. * * @returns 0 on success, error on failure. * @param pMod The module. */ static int kwLdrCallTlsAllocateAndInit(PKWMODULE pMod) { if (pMod->u.Manual.idxTls != KU32_MAX) { PTEB pTeb = NtCurrentTeb(); void **ppvTls = *(void ***)( (KUPTR)pTeb + (sizeof(void *) == 4 ? 0x2c : 0x58) ); KU8 *pbData = (KU8 *)ppvTls[pMod->u.Manual.idxTls]; KWLDR_LOG(("%s: TLS: Initializing %#x (%#x), idxTls=%d\n", pMod->pszPath, pbData, pMod->u.Manual.cbTlsAlloc, pMod->u.Manual.cbTlsInitData, pMod->u.Manual.idxTls)); if (pMod->u.Manual.cbTlsInitData < pMod->u.Manual.cbTlsAlloc) kHlpMemSet(&pbData[pMod->u.Manual.cbTlsInitData], 0, pMod->u.Manual.cbTlsAlloc); if (pMod->u.Manual.cbTlsInitData) kHlpMemCopy(pbData, &pMod->u.Manual.pbCopy[pMod->u.Manual.offTlsInitData], pMod->u.Manual.cbTlsInitData); } return 0; } /** * Does the TLS callbacks for a module. * * @param pMod The module. * @param dwReason The callback reason. */ static void kwLdrCallTlsCallbacks(PKWMODULE pMod, DWORD dwReason) { if (pMod->u.Manual.cTlsCallbacks) { PIMAGE_TLS_CALLBACK *pCallback = (PIMAGE_TLS_CALLBACK *)&pMod->u.Manual.pbLoad[pMod->u.Manual.offTlsCallbacks]; do { KWLDR_LOG(("%s: Calling TLS callback %p(%p,%#x,0)\n", pMod->pszPath, *pCallback, pMod->hOurMod, dwReason)); (*pCallback)(pMod->hOurMod, dwReason, 0); } while (*++pCallback); } } /** * Does module initialization starting at @a pMod. * * This is initially used on the executable. Later it is used by the * LoadLibrary interceptor. * * @returns 0 on success, error on failure. * @param pMod The module to initialize. */ static int kwLdrModuleInitTree(PKWMODULE pMod) { int rc = 0; if (!pMod->fNative) { KWLDR_LOG(("kwLdrModuleInitTree: enmState=%#x idxTls=%u %s\n", pMod->u.Manual.enmState, pMod->u.Manual.idxTls, pMod->pszPath)); /* * Need to copy bits? */ if (pMod->u.Manual.enmState == KWMODSTATE_NEEDS_BITS) { if (pMod->u.Manual.fUseLdBuf) { #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_AMD64) if (g_pModInLdBuf != NULL && g_pModInLdBuf != pMod && pMod->u.Manual.fRegisteredFunctionTable) { BOOLEAN fRc = RtlDeleteFunctionTable(pMod->u.Manual.paFunctions); kHlpAssert(fRc); K_NOREF(fRc); } #endif g_pModPrevInLdBuf = g_pModInLdBuf; g_pModInLdBuf = pMod; } /* Do quick zeroing and copying when we can. */ pMod->u.Manual.fCanDoQuick = K_FALSE; if ( pMod->u.Manual.fCanDoQuick && ( !pMod->u.Manual.fUseLdBuf || g_pModPrevInLdBuf == pMod)) { /* Zero first. */ kHlpAssert(pMod->u.Manual.cQuickZeroChunks <= 3); switch (pMod->u.Manual.cQuickZeroChunks) { case 3: kHlpMemSet(pMod->u.Manual.aQuickZeroChunks[2].pbDst, 0, pMod->u.Manual.aQuickZeroChunks[2].cbToZero); case 2: kHlpMemSet(pMod->u.Manual.aQuickZeroChunks[1].pbDst, 0, pMod->u.Manual.aQuickZeroChunks[1].cbToZero); case 1: kHlpMemSet(pMod->u.Manual.aQuickZeroChunks[0].pbDst, 0, pMod->u.Manual.aQuickZeroChunks[0].cbToZero); case 0: break; } /* Then copy. */ kHlpAssert(pMod->u.Manual.cQuickCopyChunks > 0); kHlpAssert(pMod->u.Manual.cQuickCopyChunks <= 3); switch (pMod->u.Manual.cQuickCopyChunks) { case 3: kHlpMemCopy(pMod->u.Manual.aQuickCopyChunks[2].pbDst, pMod->u.Manual.aQuickCopyChunks[2].pbSrc, pMod->u.Manual.aQuickCopyChunks[2].cbToCopy); case 2: kHlpMemCopy(pMod->u.Manual.aQuickCopyChunks[1].pbDst, pMod->u.Manual.aQuickCopyChunks[1].pbSrc, pMod->u.Manual.aQuickCopyChunks[1].cbToCopy); case 1: kHlpMemCopy(pMod->u.Manual.aQuickCopyChunks[0].pbDst, pMod->u.Manual.aQuickCopyChunks[0].pbSrc, pMod->u.Manual.aQuickCopyChunks[0].cbToCopy); case 0: break; } } /* Must copy the whole image. */ else { kHlpMemCopy(pMod->u.Manual.pbLoad, pMod->u.Manual.pbCopy, pMod->cbImage); pMod->u.Manual.fCanDoQuick = K_TRUE; } pMod->u.Manual.enmState = KWMODSTATE_NEEDS_INIT; } #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_AMD64) /* * Need to register function table? */ if ( !pMod->u.Manual.fRegisteredFunctionTable && pMod->u.Manual.cFunctions > 0) { pMod->u.Manual.fRegisteredFunctionTable = RtlAddFunctionTable(pMod->u.Manual.paFunctions, pMod->u.Manual.cFunctions, (KUPTR)pMod->u.Manual.pbLoad) != FALSE; kHlpAssert(pMod->u.Manual.fRegisteredFunctionTable); } #endif if (pMod->u.Manual.enmState == KWMODSTATE_NEEDS_INIT) { /* * Must do imports first, but mark our module as being initialized to avoid * endless recursion should there be a dependency loop. */ KSIZE iImp; pMod->u.Manual.enmState = KWMODSTATE_BEING_INITED; for (iImp = 0; iImp < pMod->u.Manual.cImpMods; iImp++) { rc = kwLdrModuleInitTree(pMod->u.Manual.apImpMods[iImp]); if (rc != 0) return rc; } /* Do TLS allocations for module init? */ rc = kwLdrCallTlsAllocateAndInit(pMod); if (rc != 0) return rc; if (pMod->u.Manual.cTlsCallbacks > 0) kwLdrCallTlsCallbacks(pMod, DLL_PROCESS_ATTACH); /* Finally call the entry point. */ rc = kLdrModCallInit(pMod->pLdrMod, pMod->u.Manual.pbLoad, (KUPTR)pMod->hOurMod); if (rc == 0) pMod->u.Manual.enmState = KWMODSTATE_READY; else pMod->u.Manual.enmState = KWMODSTATE_INIT_FAILED; } } return rc; } /** * Looks up a module handle for a tool. * * @returns Referenced loader module on success, NULL on if not found. * @param pTool The tool. * @param hmod The module handle. */ static PKWMODULE kwToolLocateModuleByHandle(PKWTOOL pTool, HMODULE hmod) { KUPTR const uHMod = (KUPTR)hmod; PKWMODULE *papMods; KU32 iEnd; KU32 i; PKWDYNLOAD pDynLoad; /* The executable. */ if ( hmod == NULL || pTool->u.Sandboxed.pExe->hOurMod == hmod) return kwLdrModuleRetain(pTool->u.Sandboxed.pExe); /* * Binary lookup using the module table. */ papMods = pTool->u.Sandboxed.papModules; iEnd = pTool->u.Sandboxed.cModules; if (iEnd) { KU32 iStart = 0; i = iEnd / 2; for (;;) { KUPTR const uHModThis = (KUPTR)papMods[i]->hOurMod; if (uHMod < uHModThis) { iEnd = i--; if (iStart <= i) { } else break; } else if (uHMod != uHModThis) { iStart = ++i; if (i < iEnd) { } else break; } else return kwLdrModuleRetain(papMods[i]); i = iStart + (iEnd - iStart) / 2; } #ifndef NDEBUG iStart = pTool->u.Sandboxed.cModules; while (--iStart > 0) kHlpAssert((KUPTR)papMods[iStart]->hOurMod != uHMod); kHlpAssert(i == 0 || (KUPTR)papMods[i - 1]->hOurMod < uHMod); kHlpAssert(i == pTool->u.Sandboxed.cModules || (KUPTR)papMods[i]->hOurMod > uHMod); #endif } /* * Dynamically loaded images. */ for (pDynLoad = pTool->u.Sandboxed.pDynLoadHead; pDynLoad != NULL; pDynLoad = pDynLoad->pNext) if (pDynLoad->hmod == hmod) { if (pDynLoad->pMod) return kwLdrModuleRetain(pDynLoad->pMod); KWFS_TODO(); return NULL; } return NULL; } /** * Adds the given module to the tool import table. * * @returns 0 on success, non-zero on failure. * @param pTool The tool. * @param pMod The module. */ static int kwToolAddModule(PKWTOOL pTool, PKWMODULE pMod) { /* * Binary lookup. Locating the right slot for it, return if already there. */ KUPTR const uHMod = (KUPTR)pMod->hOurMod; PKWMODULE *papMods = pTool->u.Sandboxed.papModules; KU32 iEnd = pTool->u.Sandboxed.cModules; KU32 i; if (iEnd) { KU32 iStart = 0; i = iEnd / 2; for (;;) { KUPTR const uHModThis = (KUPTR)papMods[i]->hOurMod; if (uHMod < uHModThis) { iEnd = i; if (iStart < i) { } else break; } else if (uHMod != uHModThis) { iStart = ++i; if (i < iEnd) { } else break; } else { /* Already there in the table. */ return 0; } i = iStart + (iEnd - iStart) / 2; } #ifndef NDEBUG iStart = pTool->u.Sandboxed.cModules; while (--iStart > 0) { kHlpAssert(papMods[iStart] != pMod); kHlpAssert((KUPTR)papMods[iStart]->hOurMod != uHMod); } kHlpAssert(i == 0 || (KUPTR)papMods[i - 1]->hOurMod < uHMod); kHlpAssert(i == pTool->u.Sandboxed.cModules || (KUPTR)papMods[i]->hOurMod > uHMod); #endif } else i = 0; /* * Grow the table? */ if ((pTool->u.Sandboxed.cModules % 16) == 0) { void *pvNew = kHlpRealloc(papMods, sizeof(papMods[0]) * (pTool->u.Sandboxed.cModules + 16)); if (!pvNew) return KERR_NO_MEMORY; pTool->u.Sandboxed.papModules = papMods = (PKWMODULE *)pvNew; } /* Insert it. */ if (i != pTool->u.Sandboxed.cModules) kHlpMemMove(&papMods[i + 1], &papMods[i], (pTool->u.Sandboxed.cModules - i) * sizeof(papMods[0])); papMods[i] = kwLdrModuleRetain(pMod); pTool->u.Sandboxed.cModules++; KW_LOG(("kwToolAddModule: %u modules after adding %p=%s\n", pTool->u.Sandboxed.cModules, uHMod, pMod->pszPath)); return 0; } /** * Adds the given module and all its imports to the * * @returns 0 on success, non-zero on failure. * @param pTool The tool. * @param pMod The module. */ static int kwToolAddModuleAndImports(PKWTOOL pTool, PKWMODULE pMod) { int rc = kwToolAddModule(pTool, pMod); if (!pMod->fNative && rc == 0) { KSIZE iImp = pMod->u.Manual.cImpMods; while (iImp-- > 0) { rc = kwToolAddModuleAndImports(pTool, pMod->u.Manual.apImpMods[iImp]); if (rc == 0) { } else break; } } return 0; } /** * Creates a tool entry and inserts it. * * @returns Pointer to the tool entry. NULL on failure. * @param pToolFsObj The file object of the tool. The created tool * will be associated with it. * * A reference is donated by the caller and must be * released. * @param pszSearchPath The PATH environment variable value, or NULL. */ static PKWTOOL kwToolEntryCreate(PKFSOBJ pToolFsObj, const char *pszSearchPath) { KSIZE cwcPath = pToolFsObj->cwcParent + pToolFsObj->cwcName + 1; KSIZE cbPath = pToolFsObj->cchParent + pToolFsObj->cchName + 1; PKWTOOL pTool = (PKWTOOL)kFsCacheObjAddUserData(g_pFsCache, pToolFsObj, KW_DATA_KEY_TOOL, sizeof(*pTool) + cwcPath * sizeof(wchar_t) + cbPath); if (pTool) { KBOOL fRc; pTool->pwszPath = (wchar_t const *)(pTool + 1); fRc = kFsCacheObjGetFullPathW(pToolFsObj, (wchar_t *)pTool->pwszPath, cwcPath, '\\'); kHlpAssert(fRc); K_NOREF(fRc); pTool->pszPath = (char const *)&pTool->pwszPath[cwcPath]; fRc = kFsCacheObjGetFullPathA(pToolFsObj, (char *)pTool->pszPath, cbPath, '\\'); kHlpAssert(fRc); pTool->enmType = KWTOOLTYPE_SANDBOXED; pTool->u.Sandboxed.pExe = kwLdrModuleCreateNonNative(pTool->pszPath, kwStrHash(pTool->pszPath), K_TRUE /*fExe*/, NULL /*pEexeMod*/, pszSearchPath); if (pTool->u.Sandboxed.pExe) { int rc = kwLdrModuleQueryMainEntrypoint(pTool->u.Sandboxed.pExe, &pTool->u.Sandboxed.uMainAddr); if (rc == 0) { if (kHlpStrICompAscii(pToolFsObj->pszName, "cl.exe") == 0) pTool->u.Sandboxed.enmHint = KWTOOLHINT_VISUAL_CPP_CL; else if (kHlpStrICompAscii(pToolFsObj->pszName, "link.exe") == 0) pTool->u.Sandboxed.enmHint = KWTOOLHINT_VISUAL_CPP_LINK; else pTool->u.Sandboxed.enmHint = KWTOOLHINT_NONE; kwToolAddModuleAndImports(pTool, pTool->u.Sandboxed.pExe); } else { kwErrPrintf("Failed to get entrypoint for '%s': %u\n", pTool->pszPath, rc); kwLdrModuleRelease(pTool->u.Sandboxed.pExe); pTool->u.Sandboxed.pExe = NULL; pTool->enmType = KWTOOLTYPE_EXEC; } } else pTool->enmType = KWTOOLTYPE_EXEC; kFsCacheObjRelease(g_pFsCache, pToolFsObj); g_cTools++; return pTool; } kFsCacheObjRelease(g_pFsCache, pToolFsObj); return NULL; } /** * Looks up the given tool, creating a new tool table entry if necessary. * * @returns Pointer to the tool entry. NULL on failure (fully bitched). * @param pszExe The executable for the tool (not normalized). * @param cEnvVars Number of environment varibles. * @param papszEnvVars Environment variables. For getting the PATH. */ static PKWTOOL kwToolLookup(const char *pszExe, KU32 cEnvVars, const char **papszEnvVars) { /* * We associate the tools instances with the file system objects. * * We'd like to do the lookup without invaliding the volatile parts of the * cache, thus the double lookup here. The cache gets invalidate later on. */ KFSLOOKUPERROR enmError; PKFSOBJ pToolFsObj = kFsCacheLookupA(g_pFsCache, pszExe, &enmError); if ( !pToolFsObj || pToolFsObj->bObjType != KFSOBJ_TYPE_FILE) { kFsCacheInvalidateCustomBoth(g_pFsCache); pToolFsObj = kFsCacheLookupA(g_pFsCache, pszExe, &enmError); } if (pToolFsObj) { if (pToolFsObj->bObjType == KFSOBJ_TYPE_FILE) { const char *pszSearchPath; PKWTOOL pTool = (PKWTOOL)kFsCacheObjGetUserData(g_pFsCache, pToolFsObj, KW_DATA_KEY_TOOL); if (pTool) { kFsCacheObjRelease(g_pFsCache, pToolFsObj); return pTool; } /* * Need to create a new tool. */ pszSearchPath = NULL; while (cEnvVars-- > 0) if (_strnicmp(papszEnvVars[cEnvVars], "PATH=", 5) == 0) { pszSearchPath = &papszEnvVars[cEnvVars][5]; break; } pTool = kwToolEntryCreate(pToolFsObj, pszSearchPath); if (pTool) return pTool; kwErrPrintf("kwToolLookup(%s) -> NULL: kwToolEntryCreate failed\n", pszExe); } else { kFsCacheObjRelease(g_pFsCache, pToolFsObj); kwErrPrintf("kwToolLookup(%s) -> NULL: not file (bObjType=%d fFlags=%#x uCacheGen=%u auGenerationsMissing=[%u,%u])\n", pszExe, pToolFsObj->bObjType, pToolFsObj->fFlags, pToolFsObj->uCacheGen, g_pFsCache->auGenerationsMissing[0], g_pFsCache->auGenerationsMissing[1]); } } else kwErrPrintf("kwToolLookup(%s) -> NULL: enmError=%d\n", pszExe, enmError); return NULL; } /* * * File system cache. * File system cache. * File system cache. * */ /** * This is for kDep. */ int kwFsPathExists(const char *pszPath) { BirdTimeSpec_T TsIgnored; KFSLOOKUPERROR enmError; PKFSOBJ pFsObj = kFsCacheLookupNoMissingA(g_pFsCache, pszPath, &enmError); if (pFsObj) { kFsCacheObjRelease(g_pFsCache, pFsObj); return 1; } return birdStatModTimeOnly(pszPath, &TsIgnored, 1) == 0; } /* duplicated in dir-nt-bird.c */ void nt_fullpath_cached(const char *pszPath, char *pszFull, size_t cbFull) { KFSLOOKUPERROR enmError; PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError); if (pPathObj) { KSIZE off = pPathObj->cchParent; if (off > 0) { KSIZE offEnd = off + pPathObj->cchName; if (offEnd < cbFull) { PKFSDIR pAncestor; pszFull[off + pPathObj->cchName] = '\0'; memcpy(&pszFull[off], pPathObj->pszName, pPathObj->cchName); for (pAncestor = pPathObj->pParent; off > 0; pAncestor = pAncestor->Obj.pParent) { kHlpAssert(off > 1); kHlpAssert(pAncestor != NULL); kHlpAssert(pAncestor->Obj.cchName > 0); pszFull[--off] = '/'; off -= pAncestor->Obj.cchName; kHlpAssert(pAncestor->Obj.cchParent == off); memcpy(&pszFull[off], pAncestor->Obj.pszName, pAncestor->Obj.cchName); } kFsCacheObjRelease(g_pFsCache, pPathObj); return; } } else { if ((size_t)pPathObj->cchName + 1 < cbFull) { memcpy(pszFull, pPathObj->pszName, pPathObj->cchName); pszFull[pPathObj->cchName] = '/'; pszFull[pPathObj->cchName + 1] = '\0'; kFsCacheObjRelease(g_pFsCache, pPathObj); return; } } /* do fallback. */ kHlpAssertFailed(); kFsCacheObjRelease(g_pFsCache, pPathObj); } nt_fullpath(pszPath, pszFull, cbFull); } /** * Helper for getting the extension of a UTF-16 path. * * @returns Pointer to the extension or the terminator. * @param pwszPath The path. * @param pcwcExt Where to return the length of the extension. */ static wchar_t const *kwFsPathGetExtW(wchar_t const *pwszPath, KSIZE *pcwcExt) { wchar_t const *pwszName = pwszPath; wchar_t const *pwszExt = NULL; for (;;) { wchar_t const wc = *pwszPath++; if (wc == '.') pwszExt = pwszPath; else if (wc == '/' || wc == '\\' || wc == ':') { pwszName = pwszPath; pwszExt = NULL; } else if (wc == '\0') { if (pwszExt) { *pcwcExt = pwszPath - pwszExt - 1; return pwszExt; } *pcwcExt = 0; return pwszPath - 1; } } } /** * Parses the argument string passed in as pszSrc. * * @returns size of the processed arguments. * @param pszSrc Pointer to the commandline that's to be parsed. * @param pcArgs Where to return the number of arguments. * @param argv Pointer to argument vector to put argument pointers in. NULL allowed. * @param pchPool Pointer to memory pchPool to put the arguments into. NULL allowed. * * @remarks Lifted from startuphacks-win.c */ static int parse_args(const char *pszSrc, int *pcArgs, char **argv, char *pchPool) { int bs; char chQuote; char *pfFlags; int cbArgs; int cArgs; #define PUTC(c) do { ++cbArgs; if (pchPool != NULL) *pchPool++ = (c); } while (0) #define PUTV do { ++cArgs; if (argv != NULL) *argv++ = pchPool; } while (0) #define WHITE(c) ((c) == ' ' || (c) == '\t') #define _ARG_DQUOTE 0x01 /* Argument quoted (") */ #define _ARG_RESPONSE 0x02 /* Argument read from response file */ #define _ARG_WILDCARD 0x04 /* Argument expanded from wildcard */ #define _ARG_ENV 0x08 /* Argument from environment */ #define _ARG_NONZERO 0x80 /* Always set, to avoid end of string */ cArgs = 0; cbArgs = 0; #if 0 /* argv[0] */ PUTC((char)_ARG_NONZERO); PUTV; for (;;) { PUTC(*pszSrc); if (*pszSrc == 0) break; ++pszSrc; } ++pszSrc; #endif for (;;) { while (WHITE(*pszSrc)) ++pszSrc; if (*pszSrc == 0) break; pfFlags = pchPool; PUTC((char)_ARG_NONZERO); PUTV; bs = 0; chQuote = 0; for (;;) { if (!chQuote ? (*pszSrc == '"' /*|| *pszSrc == '\''*/) : *pszSrc == chQuote) { while (bs >= 2) { PUTC('\\'); bs -= 2; } if (bs & 1) PUTC(*pszSrc); else { chQuote = chQuote ? 0 : *pszSrc; if (pfFlags != NULL) *pfFlags |= _ARG_DQUOTE; } bs = 0; } else if (*pszSrc == '\\') ++bs; else { while (bs != 0) { PUTC('\\'); --bs; } if (*pszSrc == 0 || (WHITE(*pszSrc) && !chQuote)) break; PUTC(*pszSrc); } ++pszSrc; } PUTC(0); } *pcArgs = cArgs; return cbArgs; } /* * * Process and thread related APIs. * Process and thread related APIs. * Process and thread related APIs. * */ /** Common worker for ExitProcess(), exit() and friends. */ static void WINAPI kwSandboxDoExit(int uExitCode) { if (g_Sandbox.idMainThread == GetCurrentThreadId()) { PNT_TIB pTib = (PNT_TIB)NtCurrentTeb(); g_Sandbox.rcExitCode = (int)uExitCode; /* Before we jump, restore the TIB as we're not interested in any exception chain stuff installed by the sandboxed executable. */ *pTib = g_Sandbox.TibMainThread; pTib->ExceptionList = g_Sandbox.pOutXcptListHead; longjmp(g_Sandbox.JmpBuf, 1); } KWFS_TODO(); } /** ExitProcess replacement. */ static void WINAPI kwSandbox_Kernel32_ExitProcess(UINT uExitCode) { KW_LOG(("kwSandbox_Kernel32_ExitProcess: %u\n", uExitCode)); kwSandboxDoExit((int)uExitCode); } /** ExitProcess replacement. */ static BOOL WINAPI kwSandbox_Kernel32_TerminateProcess(HANDLE hProcess, UINT uExitCode) { if (hProcess == GetCurrentProcess()) kwSandboxDoExit(uExitCode); KWFS_TODO(); return TerminateProcess(hProcess, uExitCode); } /** Normal CRT exit(). */ static void __cdecl kwSandbox_msvcrt_exit(int rcExitCode) { KW_LOG(("kwSandbox_msvcrt_exit: %d\n", rcExitCode)); kwSandboxDoExit(rcExitCode); } /** Quick CRT _exit(). */ static void __cdecl kwSandbox_msvcrt__exit(int rcExitCode) { /* Quick. */ KW_LOG(("kwSandbox_msvcrt__exit %d\n", rcExitCode)); kwSandboxDoExit(rcExitCode); } /** Return to caller CRT _cexit(). */ static void __cdecl kwSandbox_msvcrt__cexit(int rcExitCode) { KW_LOG(("kwSandbox_msvcrt__cexit: %d\n", rcExitCode)); kwSandboxDoExit(rcExitCode); } /** Quick return to caller CRT _c_exit(). */ static void __cdecl kwSandbox_msvcrt__c_exit(int rcExitCode) { KW_LOG(("kwSandbox_msvcrt__c_exit: %d\n", rcExitCode)); kwSandboxDoExit(rcExitCode); } /** Runtime error and exit _amsg_exit(). */ static void __cdecl kwSandbox_msvcrt__amsg_exit(int iMsgNo) { KW_LOG(("\nRuntime error #%u!\n", iMsgNo)); kwSandboxDoExit(255); } /** CRT - terminate(). */ static void __cdecl kwSandbox_msvcrt_terminate(void) { KW_LOG(("\nRuntime - terminate!\n")); kwSandboxDoExit(254); } /** CRT - _onexit */ static _onexit_t __cdecl kwSandbox_msvcrt__onexit(_onexit_t pfnFunc) { //if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_LINK) { PKWEXITCALLACK pCallback; KW_LOG(("_onexit(%p)\n", pfnFunc)); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pCallback = kHlpAlloc(sizeof(*pCallback)); if (pCallback) { pCallback->pfnCallback = pfnFunc; pCallback->fAtExit = K_FALSE; pCallback->pNext = g_Sandbox.pExitCallbackHead; g_Sandbox.pExitCallbackHead = pCallback; return pfnFunc; } return NULL; } KW_LOG(("_onexit(%p) - IGNORED\n", pfnFunc)); return pfnFunc; } /** CRT - atexit */ static int __cdecl kwSandbox_msvcrt_atexit(int (__cdecl *pfnFunc)(void)) { //if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_LINK) { PKWEXITCALLACK pCallback; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); KW_LOG(("atexit(%p)\n", pfnFunc)); pCallback = kHlpAlloc(sizeof(*pCallback)); if (pCallback) { pCallback->pfnCallback = (_onexit_t)pfnFunc; pCallback->fAtExit = K_TRUE; pCallback->pNext = g_Sandbox.pExitCallbackHead; g_Sandbox.pExitCallbackHead = pCallback; return 0; } return -1; } KW_LOG(("atexit(%p) - IGNORED!\n", pfnFunc)); return 0; } /** Kernel32 - SetConsoleCtrlHandler(). */ static BOOL WINAPI kwSandbox_Kernel32_SetConsoleCtrlHandler(PHANDLER_ROUTINE pfnHandler, BOOL fAdd) { KW_LOG(("SetConsoleCtrlHandler(%p, %d) - ignoring\n")); return TRUE; } /** The CRT internal __getmainargs() API. */ static int __cdecl kwSandbox_msvcrt___getmainargs(int *pargc, char ***pargv, char ***penvp, int dowildcard, int const *piNewMode) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); *pargc = g_Sandbox.cArgs; *pargv = g_Sandbox.papszArgs; *penvp = g_Sandbox.environ; /** @todo startinfo points at a newmode (setmode) value. */ return 0; } /** The CRT internal __wgetmainargs() API. */ static int __cdecl kwSandbox_msvcrt___wgetmainargs(int *pargc, wchar_t ***pargv, wchar_t ***penvp, int dowildcard, int const *piNewMode) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); *pargc = g_Sandbox.cArgs; *pargv = g_Sandbox.papwszArgs; *penvp = g_Sandbox.wenviron; /** @todo startinfo points at a newmode (setmode) value. */ return 0; } /** Kernel32 - GetCommandLineA() */ static LPCSTR /*LPSTR*/ WINAPI kwSandbox_Kernel32_GetCommandLineA(VOID) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); return g_Sandbox.pszCmdLine; } /** Kernel32 - GetCommandLineW() */ static LPCWSTR /*LPWSTR*/ WINAPI kwSandbox_Kernel32_GetCommandLineW(VOID) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); return g_Sandbox.pwszCmdLine; } /** Kernel32 - GetStartupInfoA() */ static VOID WINAPI kwSandbox_Kernel32_GetStartupInfoA(LPSTARTUPINFOA pStartupInfo) { KW_LOG(("GetStartupInfoA\n")); GetStartupInfoA(pStartupInfo); pStartupInfo->lpReserved = NULL; pStartupInfo->lpTitle = NULL; pStartupInfo->lpReserved2 = NULL; pStartupInfo->cbReserved2 = 0; } /** Kernel32 - GetStartupInfoW() */ static VOID WINAPI kwSandbox_Kernel32_GetStartupInfoW(LPSTARTUPINFOW pStartupInfo) { KW_LOG(("GetStartupInfoW\n")); GetStartupInfoW(pStartupInfo); pStartupInfo->lpReserved = NULL; pStartupInfo->lpTitle = NULL; pStartupInfo->lpReserved2 = NULL; pStartupInfo->cbReserved2 = 0; } /** CRT - __p___argc(). */ static int * __cdecl kwSandbox_msvcrt___p___argc(void) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); return &g_Sandbox.cArgs; } /** CRT - __p___argv(). */ static char *** __cdecl kwSandbox_msvcrt___p___argv(void) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); return &g_Sandbox.papszArgs; } /** CRT - __p___sargv(). */ static wchar_t *** __cdecl kwSandbox_msvcrt___p___wargv(void) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); return &g_Sandbox.papwszArgs; } /** CRT - __p__acmdln(). */ static char ** __cdecl kwSandbox_msvcrt___p__acmdln(void) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); return (char **)&g_Sandbox.pszCmdLine; } /** CRT - __p__acmdln(). */ static wchar_t ** __cdecl kwSandbox_msvcrt___p__wcmdln(void) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); return &g_Sandbox.pwszCmdLine; } /** CRT - __p__pgmptr(). */ static char ** __cdecl kwSandbox_msvcrt___p__pgmptr(void) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); return &g_Sandbox.pgmptr; } /** CRT - __p__wpgmptr(). */ static wchar_t ** __cdecl kwSandbox_msvcrt___p__wpgmptr(void) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); return &g_Sandbox.wpgmptr; } /** CRT - _get_pgmptr(). */ static errno_t __cdecl kwSandbox_msvcrt__get_pgmptr(char **ppszValue) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); *ppszValue = g_Sandbox.pgmptr; return 0; } /** CRT - _get_wpgmptr(). */ static errno_t __cdecl kwSandbox_msvcrt__get_wpgmptr(wchar_t **ppwszValue) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); *ppwszValue = g_Sandbox.wpgmptr; return 0; } /** Just in case. */ static void kwSandbox_msvcrt__wincmdln(void) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); KWFS_TODO(); } /** Just in case. */ static void kwSandbox_msvcrt__wwincmdln(void) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); KWFS_TODO(); } /** CreateThread interceptor. */ static HANDLE WINAPI kwSandbox_Kernel32_CreateThread(LPSECURITY_ATTRIBUTES pSecAttr, SIZE_T cbStack, PTHREAD_START_ROUTINE pfnThreadProc, PVOID pvUser, DWORD fFlags, PDWORD pidThread) { HANDLE hThread = NULL; KW_LOG(("CreateThread: pSecAttr=%p (inh=%d) cbStack=%#x pfnThreadProc=%p pvUser=%p fFlags=%#x pidThread=%p\n", pSecAttr, pSecAttr ? pSecAttr->bInheritHandle : 0, cbStack, pfnThreadProc, pvUser, fFlags, pidThread)); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_LINK) { /* Allow link::DbgThread. */ hThread = CreateThread(pSecAttr, cbStack, pfnThreadProc, pvUser, fFlags, pidThread); KW_LOG(("CreateThread -> %p, *pidThread=%#x\n", hThread, pidThread ? *pidThread : 0)); } else KWFS_TODO(); return hThread; } /** _beginthread - create a new thread. */ static uintptr_t __cdecl kwSandbox_msvcrt__beginthread(void (__cdecl *pfnThreadProc)(void *), unsigned cbStack, void *pvUser) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); KWFS_TODO(); return 0; } /** _beginthreadex - create a new thread, msvcr120.dll hack for c2.dll. */ static uintptr_t __cdecl kwSandbox_msvcr120__beginthreadex(void *pvSecAttr, unsigned cbStack, unsigned (__stdcall *pfnThreadProc)(void *), void *pvUser, unsigned fCreate, unsigned *pidThread) { /* * The VC++ 12 (VS 2013) compiler pass two is now threaded. Let it do * whatever it needs to. */ KW_LOG(("kwSandbox_msvcr120__beginthreadex: pvSecAttr=%p (inh=%d) cbStack=%#x pfnThreadProc=%p pvUser=%p fCreate=%#x pidThread=%p\n", pvSecAttr, pvSecAttr ? ((LPSECURITY_ATTRIBUTES)pvSecAttr)->bInheritHandle : 0, cbStack, pfnThreadProc, pvUser, fCreate, pidThread)); if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL) { uintptr_t rcRet; static uintptr_t (__cdecl *s_pfnReal)(void *, unsigned , unsigned (__stdcall *)(void *), void *, unsigned , unsigned *); if (!s_pfnReal) { *(FARPROC *)&s_pfnReal = GetProcAddress(GetModuleHandleA("msvcr120.dll"), "_beginthreadex"); if (!s_pfnReal) { kwErrPrintf("kwSandbox_msvcr120__beginthreadex: Failed to resolve _beginthreadex in msvcr120.dll!\n"); __debugbreak(); } } rcRet = s_pfnReal(pvSecAttr, cbStack, pfnThreadProc, pvUser, fCreate, pidThread); KW_LOG(("kwSandbox_msvcr120__beginthreadex: returns %p *pidThread=%#x\n", rcRet, pidThread ? *pidThread : -1)); return rcRet; } kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); KWFS_TODO(); return 0; } /** _beginthreadex - create a new thread. */ static uintptr_t __cdecl kwSandbox_msvcrt__beginthreadex(void *pvSecAttr, unsigned cbStack, unsigned (__stdcall *pfnThreadProc)(void *), void *pvUser, unsigned fCreate, unsigned *pidThread) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); KWFS_TODO(); return 0; } /* * * Environment related APIs. * Environment related APIs. * Environment related APIs. * */ /** Kernel32 - GetEnvironmentStringsA (Watcom uses this one). */ static LPCH WINAPI kwSandbox_Kernel32_GetEnvironmentStringsA(void) { char *pszzEnv; char *pszCur; KSIZE cbNeeded = 1; KSIZE iVar = 0; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); /* Figure how space much we need first. */ while ((pszCur = g_Sandbox.papszEnvVars[iVar++]) != NULL) cbNeeded += kHlpStrLen(pszCur) + 1; /* Allocate it. */ pszzEnv = kHlpAlloc(cbNeeded); if (pszzEnv) { char *psz = pszzEnv; iVar = 0; while ((pszCur = g_Sandbox.papszEnvVars[iVar++]) != NULL) { KSIZE cbCur = kHlpStrLen(pszCur) + 1; kHlpAssert((KUPTR)(&psz[cbCur] - pszzEnv) < cbNeeded); psz = (char *)kHlpMemPCopy(psz, pszCur, cbCur); } *psz++ = '\0'; kHlpAssert(psz - pszzEnv == cbNeeded); } KW_LOG(("GetEnvironmentStringsA -> %p [%u]\n", pszzEnv, cbNeeded)); #if 0 fprintf(stderr, "GetEnvironmentStringsA: %p LB %#x\n", pszzEnv, cbNeeded); pszCur = pszzEnv; iVar = 0; while (*pszCur) { fprintf(stderr, " %u:%p=%s\n\n", iVar, pszCur, pszCur); iVar++; pszCur += kHlpStrLen(pszCur) + 1; } fprintf(stderr, " %u:%p=\n\n", iVar, pszCur); pszCur++; fprintf(stderr, "ended at %p, after %u bytes (exepcted %u)\n", pszCur, pszCur - pszzEnv, cbNeeded); #endif return pszzEnv; } /** Kernel32 - GetEnvironmentStrings */ static LPCH WINAPI kwSandbox_Kernel32_GetEnvironmentStrings(void) { KW_LOG(("GetEnvironmentStrings!\n")); return kwSandbox_Kernel32_GetEnvironmentStringsA(); } /** Kernel32 - GetEnvironmentStringsW */ static LPWCH WINAPI kwSandbox_Kernel32_GetEnvironmentStringsW(void) { wchar_t *pwszzEnv; wchar_t *pwszCur; KSIZE cwcNeeded = 1; KSIZE iVar = 0; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); /* Figure how space much we need first. */ while ((pwszCur = g_Sandbox.papwszEnvVars[iVar++]) != NULL) cwcNeeded += kwUtf16Len(pwszCur) + 1; /* Allocate it. */ pwszzEnv = kHlpAlloc(cwcNeeded * sizeof(wchar_t)); if (pwszzEnv) { wchar_t *pwsz = pwszzEnv; iVar = 0; while ((pwszCur = g_Sandbox.papwszEnvVars[iVar++]) != NULL) { KSIZE cwcCur = kwUtf16Len(pwszCur) + 1; kHlpAssert((KUPTR)(&pwsz[cwcCur] - pwszzEnv) < cwcNeeded); pwsz = (wchar_t *)kHlpMemPCopy(pwsz, pwszCur, cwcCur * sizeof(wchar_t)); } *pwsz++ = '\0'; kHlpAssert(pwsz - pwszzEnv == cwcNeeded); } KW_LOG(("GetEnvironmentStringsW -> %p [%u]\n", pwszzEnv, cwcNeeded)); return pwszzEnv; } /** Kernel32 - FreeEnvironmentStringsA */ static BOOL WINAPI kwSandbox_Kernel32_FreeEnvironmentStringsA(LPCH pszzEnv) { KW_LOG(("FreeEnvironmentStringsA: %p -> TRUE\n", pszzEnv)); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); kHlpFree(pszzEnv); return TRUE; } /** Kernel32 - FreeEnvironmentStringsW */ static BOOL WINAPI kwSandbox_Kernel32_FreeEnvironmentStringsW(LPWCH pwszzEnv) { KW_LOG(("FreeEnvironmentStringsW: %p -> TRUE\n", pwszzEnv)); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); kHlpFree(pwszzEnv); return TRUE; } /** * Grows the environment vectors (KWSANDBOX::environ, KWSANDBOX::papszEnvVars, * KWSANDBOX::wenviron, and KWSANDBOX::papwszEnvVars). * * @returns 0 on success, non-zero on failure. * @param pSandbox The sandbox. * @param cMin Minimum size, including terminator. */ static int kwSandboxGrowEnv(PKWSANDBOX pSandbox, KSIZE cMin) { void *pvNew; KSIZE const cOld = pSandbox->cEnvVarsAllocated; KSIZE cNew = cOld + 256; while (cNew < cMin) cNew += 256; pvNew = kHlpRealloc(pSandbox->environ, cNew * sizeof(pSandbox->environ[0])); if (pvNew) { pSandbox->environ = (char **)pvNew; pSandbox->environ[cOld] = NULL; pvNew = kHlpRealloc(pSandbox->papszEnvVars, cNew * sizeof(pSandbox->papszEnvVars[0])); if (pvNew) { pSandbox->papszEnvVars = (char **)pvNew; pSandbox->papszEnvVars[cOld] = NULL; pvNew = kHlpRealloc(pSandbox->wenviron, cNew * sizeof(pSandbox->wenviron[0])); if (pvNew) { pSandbox->wenviron = (wchar_t **)pvNew; pSandbox->wenviron[cOld] = NULL; pvNew = kHlpRealloc(pSandbox->papwszEnvVars, cNew * sizeof(pSandbox->papwszEnvVars[0])); if (pvNew) { pSandbox->papwszEnvVars = (wchar_t **)pvNew; pSandbox->papwszEnvVars[cOld] = NULL; pSandbox->cEnvVarsAllocated = cNew; KW_LOG(("kwSandboxGrowEnv: cNew=%d - crt: %p / %p; shadow: %p, %p\n", cNew, pSandbox->environ, pSandbox->wenviron, pSandbox->papszEnvVars, pSandbox->papwszEnvVars)); return 0; } } } } kwErrPrintf("kwSandboxGrowEnv ran out of memory! cNew=%u\n", cNew); return KERR_NO_MEMORY; } /** * Sets an environment variable, ANSI style. * * @returns 0 on success, non-zero on failure. * @param pSandbox The sandbox. * @param pchVar The variable name. * @param cchVar The length of the name. * @param pszValue The value. */ static int kwSandboxDoSetEnvA(PKWSANDBOX pSandbox, const char *pchVar, KSIZE cchVar, const char *pszValue) { /* Allocate and construct the new strings. */ KSIZE cchTmp = kHlpStrLen(pszValue); char *pszNew = (char *)kHlpAlloc(cchVar + 1 + cchTmp + 1); if (pszNew) { wchar_t *pwszNew; kHlpMemCopy(pszNew, pchVar, cchVar); pszNew[cchVar] = '='; kHlpMemCopy(&pszNew[cchVar + 1], pszValue, cchTmp); cchTmp += cchVar + 1; pszNew[cchTmp] = '\0'; pwszNew = kwStrToUtf16AllocN(pszNew, cchTmp); if (pwszNew) { /* Look it up. */ KSIZE iVar = 0; char *pszEnv; while ((pszEnv = pSandbox->papszEnvVars[iVar]) != NULL) { if ( _strnicmp(pszEnv, pchVar, cchVar) == 0 && pszEnv[cchVar] == '=') { KW_LOG(("kwSandboxDoSetEnvA: Replacing iVar=%d: %p='%s' and %p='%ls'\n" " iVar=%d: %p='%s' and %p='%ls'\n", iVar, pSandbox->papszEnvVars[iVar], pSandbox->papszEnvVars[iVar], pSandbox->papwszEnvVars[iVar], pSandbox->papwszEnvVars[iVar], iVar, pszNew, pszNew, pwszNew, pwszNew)); kHlpFree(pSandbox->papszEnvVars[iVar]); pSandbox->papszEnvVars[iVar] = pszNew; pSandbox->environ[iVar] = pszNew; kHlpFree(pSandbox->papwszEnvVars[iVar]); pSandbox->papwszEnvVars[iVar] = pwszNew; pSandbox->wenviron[iVar] = pwszNew; return 0; } iVar++; } /* Not found, do we need to grow the table first? */ if (iVar + 1 >= pSandbox->cEnvVarsAllocated) kwSandboxGrowEnv(pSandbox, iVar + 2); if (iVar + 1 < pSandbox->cEnvVarsAllocated) { KW_LOG(("kwSandboxDoSetEnvA: Adding iVar=%d: %p='%s' and %p='%ls'\n", iVar, pszNew, pszNew, pwszNew, pwszNew)); pSandbox->papszEnvVars[iVar + 1] = NULL; pSandbox->papszEnvVars[iVar] = pszNew; pSandbox->environ[iVar + 1] = NULL; pSandbox->environ[iVar] = pszNew; pSandbox->papwszEnvVars[iVar + 1] = NULL; pSandbox->papwszEnvVars[iVar] = pwszNew; pSandbox->wenviron[iVar + 1] = NULL; pSandbox->wenviron[iVar] = pwszNew; return 0; } kHlpFree(pwszNew); } kHlpFree(pszNew); } KW_LOG(("Out of memory!\n")); return 0; } /** * Sets an environment variable, UTF-16 style. * * @returns 0 on success, non-zero on failure. * @param pSandbox The sandbox. * @param pwcVar The variable name. * @param cwcVar The length of the name. * @param pwszValue The value. */ static int kwSandboxDoSetEnvW(PKWSANDBOX pSandbox, const wchar_t *pwchVar, KSIZE cwcVar, const wchar_t *pwszValue) { /* Allocate and construct the new strings. */ KSIZE cwcTmp = kwUtf16Len(pwszValue); wchar_t *pwszNew = (wchar_t *)kHlpAlloc((cwcVar + 1 + cwcTmp + 1) * sizeof(wchar_t)); if (pwszNew) { char *pszNew; kHlpMemCopy(pwszNew, pwchVar, cwcVar * sizeof(wchar_t)); pwszNew[cwcVar] = '='; kHlpMemCopy(&pwszNew[cwcVar + 1], pwszValue, cwcTmp * sizeof(wchar_t)); cwcTmp += cwcVar + 1; pwszNew[cwcVar] = '\0'; pszNew = kwUtf16ToStrAllocN(pwszNew, cwcVar); if (pszNew) { /* Look it up. */ KSIZE iVar = 0; wchar_t *pwszEnv; while ((pwszEnv = pSandbox->papwszEnvVars[iVar]) != NULL) { if ( _wcsnicmp(pwszEnv, pwchVar, cwcVar) == 0 && pwszEnv[cwcVar] == '=') { KW_LOG(("kwSandboxDoSetEnvW: Replacing iVar=%d: %p='%s' and %p='%ls'\n" " iVar=%d: %p='%s' and %p='%ls'\n", iVar, pSandbox->papszEnvVars[iVar], pSandbox->papszEnvVars[iVar], pSandbox->papwszEnvVars[iVar], pSandbox->papwszEnvVars[iVar], iVar, pszNew, pszNew, pwszNew, pwszNew)); kHlpFree(pSandbox->papszEnvVars[iVar]); pSandbox->papszEnvVars[iVar] = pszNew; pSandbox->environ[iVar] = pszNew; kHlpFree(pSandbox->papwszEnvVars[iVar]); pSandbox->papwszEnvVars[iVar] = pwszNew; pSandbox->wenviron[iVar] = pwszNew; return 0; } iVar++; } /* Not found, do we need to grow the table first? */ if (iVar + 1 >= pSandbox->cEnvVarsAllocated) kwSandboxGrowEnv(pSandbox, iVar + 2); if (iVar + 1 < pSandbox->cEnvVarsAllocated) { KW_LOG(("kwSandboxDoSetEnvW: Adding iVar=%d: %p='%s' and %p='%ls'\n", iVar, pszNew, pszNew, pwszNew, pwszNew)); pSandbox->papszEnvVars[iVar + 1] = NULL; pSandbox->papszEnvVars[iVar] = pszNew; pSandbox->environ[iVar + 1] = NULL; pSandbox->environ[iVar] = pszNew; pSandbox->papwszEnvVars[iVar + 1] = NULL; pSandbox->papwszEnvVars[iVar] = pwszNew; pSandbox->wenviron[iVar + 1] = NULL; pSandbox->wenviron[iVar] = pwszNew; return 0; } kHlpFree(pwszNew); } kHlpFree(pszNew); } KW_LOG(("Out of memory!\n")); return 0; } /** ANSI unsetenv worker. */ static int kwSandboxDoUnsetEnvA(PKWSANDBOX pSandbox, const char *pchVar, KSIZE cchVar) { KSIZE iVar = 0; char *pszEnv; while ((pszEnv = pSandbox->papszEnvVars[iVar]) != NULL) { if ( _strnicmp(pszEnv, pchVar, cchVar) == 0 && pszEnv[cchVar] == '=') { KSIZE cVars = iVar; while (pSandbox->papszEnvVars[cVars]) cVars++; kHlpAssert(pSandbox->papwszEnvVars[iVar] != NULL); kHlpAssert(pSandbox->papwszEnvVars[cVars] == NULL); KW_LOG(("kwSandboxDoUnsetEnvA: Removing iVar=%d: %p='%s' and %p='%ls'; new cVars=%d\n", iVar, pSandbox->papszEnvVars[iVar], pSandbox->papszEnvVars[iVar], pSandbox->papwszEnvVars[iVar], pSandbox->papwszEnvVars[iVar], cVars - 1)); kHlpFree(pSandbox->papszEnvVars[iVar]); pSandbox->papszEnvVars[iVar] = pSandbox->papszEnvVars[cVars]; pSandbox->environ[iVar] = pSandbox->papszEnvVars[cVars]; pSandbox->papszEnvVars[cVars] = NULL; pSandbox->environ[cVars] = NULL; kHlpFree(pSandbox->papwszEnvVars[iVar]); pSandbox->papwszEnvVars[iVar] = pSandbox->papwszEnvVars[cVars]; pSandbox->wenviron[iVar] = pSandbox->papwszEnvVars[cVars]; pSandbox->papwszEnvVars[cVars] = NULL; pSandbox->wenviron[cVars] = NULL; return 0; } iVar++; } return KERR_ENVVAR_NOT_FOUND; } /** UTF-16 unsetenv worker. */ static int kwSandboxDoUnsetEnvW(PKWSANDBOX pSandbox, const wchar_t *pwcVar, KSIZE cwcVar) { KSIZE iVar = 0; wchar_t *pwszEnv; while ((pwszEnv = pSandbox->papwszEnvVars[iVar]) != NULL) { if ( _wcsnicmp(pwszEnv, pwcVar, cwcVar) == 0 && pwszEnv[cwcVar] == '=') { KSIZE cVars = iVar; while (pSandbox->papwszEnvVars[cVars]) cVars++; kHlpAssert(pSandbox->papszEnvVars[iVar] != NULL); kHlpAssert(pSandbox->papszEnvVars[cVars] == NULL); KW_LOG(("kwSandboxDoUnsetEnvA: Removing iVar=%d: %p='%s' and %p='%ls'; new cVars=%d\n", iVar, pSandbox->papszEnvVars[iVar], pSandbox->papszEnvVars[iVar], pSandbox->papwszEnvVars[iVar], pSandbox->papwszEnvVars[iVar], cVars - 1)); kHlpFree(pSandbox->papszEnvVars[iVar]); pSandbox->papszEnvVars[iVar] = pSandbox->papszEnvVars[cVars]; pSandbox->environ[iVar] = pSandbox->papszEnvVars[cVars]; pSandbox->papszEnvVars[cVars] = NULL; pSandbox->environ[cVars] = NULL; kHlpFree(pSandbox->papwszEnvVars[iVar]); pSandbox->papwszEnvVars[iVar] = pSandbox->papwszEnvVars[cVars]; pSandbox->wenviron[iVar] = pSandbox->papwszEnvVars[cVars]; pSandbox->papwszEnvVars[cVars] = NULL; pSandbox->wenviron[cVars] = NULL; return 0; } iVar++; } return KERR_ENVVAR_NOT_FOUND; } /** ANSI getenv worker. */ static char *kwSandboxDoGetEnvA(PKWSANDBOX pSandbox, const char *pchVar, KSIZE cchVar) { KSIZE iVar = 0; char *pszEnv; while ((pszEnv = pSandbox->papszEnvVars[iVar++]) != NULL) if ( _strnicmp(pszEnv, pchVar, cchVar) == 0 && pszEnv[cchVar] == '=') return &pszEnv[cchVar + 1]; return NULL; } /** UTF-16 getenv worker. */ static wchar_t *kwSandboxDoGetEnvW(PKWSANDBOX pSandbox, const wchar_t *pwcVar, KSIZE cwcVar) { KSIZE iVar = 0; wchar_t *pwszEnv; while ((pwszEnv = pSandbox->papwszEnvVars[iVar++]) != NULL) if ( _wcsnicmp(pwszEnv, pwcVar, cwcVar) == 0 && pwszEnv[cwcVar] == '=') return &pwszEnv[cwcVar + 1]; return NULL; } /** Kernel32 - GetEnvironmentVariableA() */ static DWORD WINAPI kwSandbox_Kernel32_GetEnvironmentVariableA(LPCSTR pszVar, LPSTR pszValue, DWORD cbValue) { char *pszFoundValue; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pszFoundValue = kwSandboxDoGetEnvA(&g_Sandbox, pszVar, kHlpStrLen(pszVar)); if (pszFoundValue) { DWORD cchRet = kwStrCopyStyle1(pszFoundValue, pszValue, cbValue); KW_LOG(("GetEnvironmentVariableA: '%s' -> %u (%s)\n", pszVar, cchRet, pszFoundValue)); return cchRet; } KW_LOG(("GetEnvironmentVariableA: '%s' -> 0\n", pszVar)); SetLastError(ERROR_ENVVAR_NOT_FOUND); return 0; } /** Kernel32 - GetEnvironmentVariableW() */ static DWORD WINAPI kwSandbox_Kernel32_GetEnvironmentVariableW(LPCWSTR pwszVar, LPWSTR pwszValue, DWORD cwcValue) { wchar_t *pwszFoundValue; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pwszFoundValue = kwSandboxDoGetEnvW(&g_Sandbox, pwszVar, kwUtf16Len(pwszVar)); if (pwszFoundValue) { DWORD cchRet = kwUtf16CopyStyle1(pwszFoundValue, pwszValue, cwcValue); KW_LOG(("GetEnvironmentVariableW: '%ls' -> %u (%ls)\n", pwszVar, cchRet, pwszFoundValue)); return cchRet; } KW_LOG(("GetEnvironmentVariableW: '%ls' -> 0\n", pwszVar)); SetLastError(ERROR_ENVVAR_NOT_FOUND); return 0; } /** Kernel32 - SetEnvironmentVariableA() */ static BOOL WINAPI kwSandbox_Kernel32_SetEnvironmentVariableA(LPCSTR pszVar, LPCSTR pszValue) { int rc; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (pszValue) rc = kwSandboxDoSetEnvA(&g_Sandbox, pszVar, kHlpStrLen(pszVar), pszValue); else { kwSandboxDoUnsetEnvA(&g_Sandbox, pszVar, kHlpStrLen(pszVar)); rc = 0; //?? } if (rc == 0) { KW_LOG(("SetEnvironmentVariableA(%s,%s) -> TRUE\n", pszVar, pszValue)); return TRUE; } SetLastError(ERROR_NOT_ENOUGH_MEMORY); KW_LOG(("SetEnvironmentVariableA(%s,%s) -> FALSE!\n", pszVar, pszValue)); return FALSE; } /** Kernel32 - SetEnvironmentVariableW() */ static BOOL WINAPI kwSandbox_Kernel32_SetEnvironmentVariableW(LPCWSTR pwszVar, LPCWSTR pwszValue) { int rc; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (pwszValue) rc = kwSandboxDoSetEnvW(&g_Sandbox, pwszVar, kwUtf16Len(pwszVar), pwszValue); else { kwSandboxDoUnsetEnvW(&g_Sandbox, pwszVar, kwUtf16Len(pwszVar)); rc = 0; //?? } if (rc == 0) { KW_LOG(("SetEnvironmentVariableA(%ls,%ls) -> TRUE\n", pwszVar, pwszValue)); return TRUE; } SetLastError(ERROR_NOT_ENOUGH_MEMORY); KW_LOG(("SetEnvironmentVariableA(%ls,%ls) -> FALSE!\n", pwszVar, pwszValue)); return FALSE; } /** Kernel32 - ExpandEnvironmentStringsA() */ static DWORD WINAPI kwSandbox_Kernel32_ExpandEnvironmentStringsA(LPCSTR pszSrc, LPSTR pwszDst, DWORD cbDst) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); KWFS_TODO(); return 0; } /** Kernel32 - ExpandEnvironmentStringsW() */ static DWORD WINAPI kwSandbox_Kernel32_ExpandEnvironmentStringsW(LPCWSTR pwszSrc, LPWSTR pwszDst, DWORD cbDst) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); KWFS_TODO(); return 0; } /** CRT - _putenv(). */ static int __cdecl kwSandbox_msvcrt__putenv(const char *pszVarEqualValue) { int rc; char const *pszEqual; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pszEqual = kHlpStrChr(pszVarEqualValue, '='); if (pszEqual) { rc = kwSandboxDoSetEnvA(&g_Sandbox, pszVarEqualValue, pszEqual - pszVarEqualValue, pszEqual + 1); if (rc == 0) { } else rc = -1; } else { kwSandboxDoUnsetEnvA(&g_Sandbox, pszVarEqualValue, kHlpStrLen(pszVarEqualValue)); rc = 0; } KW_LOG(("_putenv(%s) -> %d\n", pszVarEqualValue, rc)); return rc; } /** CRT - _wputenv(). */ static int __cdecl kwSandbox_msvcrt__wputenv(const wchar_t *pwszVarEqualValue) { int rc; wchar_t const *pwszEqual; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pwszEqual = wcschr(pwszVarEqualValue, '='); if (pwszEqual) { rc = kwSandboxDoSetEnvW(&g_Sandbox, pwszVarEqualValue, pwszEqual - pwszVarEqualValue, pwszEqual + 1); if (rc == 0) { } else rc = -1; } else { kwSandboxDoUnsetEnvW(&g_Sandbox, pwszVarEqualValue, kwUtf16Len(pwszVarEqualValue)); rc = 0; } KW_LOG(("_wputenv(%ls) -> %d\n", pwszVarEqualValue, rc)); return rc; } /** CRT - _putenv_s(). */ static errno_t __cdecl kwSandbox_msvcrt__putenv_s(const char *pszVar, const char *pszValue) { char const *pszEqual; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pszEqual = kHlpStrChr(pszVar, '='); if (pszEqual == NULL) { if (pszValue) { int rc = kwSandboxDoSetEnvA(&g_Sandbox, pszVar, kHlpStrLen(pszVar), pszValue); if (rc == 0) { KW_LOG(("_putenv_s(%s,%s) -> 0\n", pszVar, pszValue)); return 0; } } else { kwSandboxDoUnsetEnvA(&g_Sandbox, pszVar, kHlpStrLen(pszVar)); KW_LOG(("_putenv_s(%ls,NULL) -> 0\n", pszVar)); return 0; } KW_LOG(("_putenv_s(%s,%s) -> ENOMEM\n", pszVar, pszValue)); return ENOMEM; } KW_LOG(("_putenv_s(%s,%s) -> EINVAL\n", pszVar, pszValue)); return EINVAL; } /** CRT - _wputenv_s(). */ static errno_t __cdecl kwSandbox_msvcrt__wputenv_s(const wchar_t *pwszVar, const wchar_t *pwszValue) { wchar_t const *pwszEqual; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pwszEqual = wcschr(pwszVar, '='); if (pwszEqual == NULL) { if (pwszValue) { int rc = kwSandboxDoSetEnvW(&g_Sandbox, pwszVar, kwUtf16Len(pwszVar), pwszValue); if (rc == 0) { KW_LOG(("_wputenv_s(%ls,%ls) -> 0\n", pwszVar, pwszValue)); return 0; } } else { kwSandboxDoUnsetEnvW(&g_Sandbox, pwszVar, kwUtf16Len(pwszVar)); KW_LOG(("_wputenv_s(%ls,NULL) -> 0\n", pwszVar)); return 0; } KW_LOG(("_wputenv_s(%ls,%ls) -> ENOMEM\n", pwszVar, pwszValue)); return ENOMEM; } KW_LOG(("_wputenv_s(%ls,%ls) -> EINVAL\n", pwszVar, pwszValue)); return EINVAL; } /** CRT - get pointer to the __initenv variable (initial environment). */ static char *** __cdecl kwSandbox_msvcrt___p___initenv(void) { KW_LOG(("__p___initenv\n")); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); KWFS_TODO(); return &g_Sandbox.initenv; } /** CRT - get pointer to the __winitenv variable (initial environment). */ static wchar_t *** __cdecl kwSandbox_msvcrt___p___winitenv(void) { KW_LOG(("__p___winitenv\n")); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); KWFS_TODO(); return &g_Sandbox.winitenv; } /** CRT - get pointer to the _environ variable (current environment). */ static char *** __cdecl kwSandbox_msvcrt___p__environ(void) { KW_LOG(("__p__environ\n")); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); return &g_Sandbox.environ; } /** CRT - get pointer to the _wenviron variable (current environment). */ static wchar_t *** __cdecl kwSandbox_msvcrt___p__wenviron(void) { KW_LOG(("__p__wenviron\n")); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); return &g_Sandbox.wenviron; } /** CRT - get the _environ variable (current environment). * @remarks Not documented or prototyped? */ static KUPTR /*void*/ __cdecl kwSandbox_msvcrt__get_environ(char ***ppapszEnviron) { KWFS_TODO(); /** @todo check the callers expectations! */ kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); *ppapszEnviron = g_Sandbox.environ; return 0; } /** CRT - get the _wenviron variable (current environment). * @remarks Not documented or prototyped? */ static KUPTR /*void*/ __cdecl kwSandbox_msvcrt__get_wenviron(wchar_t ***ppapwszEnviron) { KWFS_TODO(); /** @todo check the callers expectations! */ kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); *ppapwszEnviron = g_Sandbox.wenviron; return 0; } /* * * Loader related APIs * Loader related APIs * Loader related APIs * */ /** * Kernel32 - LoadLibraryExA() worker that loads resource files and such. */ static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryExA_Resource(PKWDYNLOAD pDynLoad, DWORD fFlags) { /* Load it first. */ HMODULE hmod = LoadLibraryExA(pDynLoad->szRequest, NULL /*hFile*/, fFlags); if (hmod) { pDynLoad->hmod = hmod; pDynLoad->pMod = NULL; /* indicates special */ pDynLoad->pNext = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead; g_Sandbox.pTool->u.Sandboxed.pDynLoadHead = pDynLoad; KW_LOG(("LoadLibraryExA(%s,,[resource]) -> %p\n", pDynLoad->szRequest, pDynLoad->hmod)); } else kHlpFree(pDynLoad); return hmod; } /** * Kernel32 - LoadLibraryExA() worker that deals with the api-ms-xxx modules. */ static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryExA_VirtualApiModule(PKWDYNLOAD pDynLoad, DWORD fFlags) { HMODULE hmod; PKWMODULE pMod; KU32 uHashPath; KSIZE idxHash; char szNormPath[256]; KSIZE cbFilename = kHlpStrLen(pDynLoad->szRequest) + 1; /* * Lower case it. */ if (cbFilename <= sizeof(szNormPath)) { kHlpMemCopy(szNormPath, pDynLoad->szRequest, cbFilename); _strlwr(szNormPath); } else { SetLastError(ERROR_FILENAME_EXCED_RANGE); return NULL; } /* * Check if it has already been loaded so we don't create an unnecessary * loader module for it. */ uHashPath = kwStrHash(szNormPath); idxHash = uHashPath % K_ELEMENTS(g_apModules); pMod = g_apModules[idxHash]; if (pMod) { do { if ( pMod->uHashPath == uHashPath && kHlpStrComp(pMod->pszPath, szNormPath) == 0) { pDynLoad->pMod = kwLdrModuleRetain(pMod); pDynLoad->hmod = pMod->hOurMod; pDynLoad->pNext = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead; g_Sandbox.pTool->u.Sandboxed.pDynLoadHead = pDynLoad; KW_LOG(("LoadLibraryExA(%s,,) -> %p [already loaded]\n", pDynLoad->szRequest, pDynLoad->hmod)); return pDynLoad->hmod; } pMod = pMod->pNext; } while (pMod); } /* * Try load it and make a kLdr module for it. */ hmod = LoadLibraryExA(szNormPath, NULL /*hFile*/, fFlags); if (hmod) { PKLDRMOD pLdrMod; int rc = kLdrModOpenNativeByHandle((KUPTR)hmod, &pLdrMod); if (rc == 0) { PKWMODULE pMod = kwLdrModuleCreateForNativekLdrModule(pLdrMod, szNormPath, cbFilename, uHashPath, K_FALSE /*fDoReplacements*/); if (pMod) { kwToolAddModuleAndImports(g_Sandbox.pTool, pMod); pDynLoad = (PKWDYNLOAD)kHlpAlloc(sizeof(*pDynLoad) + cbFilename + cbFilename * sizeof(wchar_t)); if (pDynLoad) { pDynLoad->pMod = pMod; pDynLoad->hmod = hmod; pDynLoad->pNext = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead; g_Sandbox.pTool->u.Sandboxed.pDynLoadHead = pDynLoad; KW_LOG(("LoadLibraryExA(%s,,) -> %p\n", pDynLoad->szRequest, pDynLoad->hmod)); return hmod; } KWFS_TODO(); } else KWFS_TODO(); } else KWFS_TODO(); } kHlpFree(pDynLoad); return hmod; } /** Kernel32 - LoadLibraryExA() */ static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryExA(LPCSTR pszFilename, HANDLE hFile, DWORD fFlags) { KSIZE cchFilename = kHlpStrLen(pszFilename); const char *pszSearchPath; PKWDYNLOAD pDynLoad; PKWMODULE pMod; int rc; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); /* * Deal with a couple of extremely unlikely special cases right away. */ if ( ( !(fFlags & LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE) || (fFlags & LOAD_LIBRARY_AS_IMAGE_RESOURCE)) && (hFile == NULL || hFile == INVALID_HANDLE_VALUE) ) { /* likely */ } else { KWFS_TODO(); return LoadLibraryExA(pszFilename, hFile, fFlags); } /* * Check if we've already got a dynload entry for this one. */ for (pDynLoad = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead; pDynLoad; pDynLoad = pDynLoad->pNext) if ( pDynLoad->cchRequest == cchFilename && kHlpMemComp(pDynLoad->szRequest, pszFilename, cchFilename) == 0) { if (pDynLoad->pMod) rc = kwLdrModuleInitTree(pDynLoad->pMod); else rc = 0; if (rc == 0) { KW_LOG(("LoadLibraryExA(%s,,) -> %p [cached]\n", pszFilename, pDynLoad->hmod)); return pDynLoad->hmod; } SetLastError(ERROR_DLL_INIT_FAILED); return NULL; } /* * Allocate a dynload entry for the request. */ pDynLoad = (PKWDYNLOAD)kHlpAlloc(sizeof(*pDynLoad) + cchFilename + 1); if (pDynLoad) { pDynLoad->cchRequest = cchFilename; kHlpMemCopy(pDynLoad->szRequest, pszFilename, cchFilename + 1); } else { KW_LOG(("LoadLibraryExA: Out of memory!\n")); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return NULL; } /* * Deal with resource / data DLLs. */ if (fFlags & ( DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | LOAD_LIBRARY_AS_IMAGE_RESOURCE) ) return kwSandbox_Kernel32_LoadLibraryExA_Resource(pDynLoad, fFlags); /* * Special case: api-ms-win-core-synch-l1-2-0 and friends (32-bit yasm, built with VS2015). */ if ( strnicmp(pszFilename, TUPLE("api-ms-")) == 0 && kHlpIsFilenameOnly(pszFilename)) return kwSandbox_Kernel32_LoadLibraryExA_VirtualApiModule(pDynLoad, fFlags); /* * Normal library loading. * We start by being very lazy and reusing the code for resolving imports. */ pszSearchPath = kwSandboxDoGetEnvA(&g_Sandbox, "PATH", 4); if (!kHlpIsFilenameOnly(pszFilename)) pMod = kwLdrModuleTryLoadDll(pszFilename, KWLOCATION_UNKNOWN, g_Sandbox.pTool->u.Sandboxed.pExe, pszSearchPath); else { rc = kwLdrModuleResolveAndLookup(pszFilename, g_Sandbox.pTool->u.Sandboxed.pExe, NULL /*pImporter*/, pszSearchPath, &pMod); if (rc != 0) pMod = NULL; } if (pMod && pMod != (PKWMODULE)~(KUPTR)0) { /* Enter it into the tool module table and dynamic link request cache. */ kwToolAddModuleAndImports(g_Sandbox.pTool, pMod); pDynLoad->pMod = pMod; pDynLoad->hmod = pMod->hOurMod; pDynLoad->pNext = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead; g_Sandbox.pTool->u.Sandboxed.pDynLoadHead = pDynLoad; /* * Make sure it's initialized (need to link it first since DllMain may * use loader APIs). */ rc = kwLdrModuleInitTree(pMod); if (rc == 0) { KW_LOG(("LoadLibraryExA(%s,,) -> %p\n", pszFilename, pDynLoad->hmod)); return pDynLoad->hmod; } SetLastError(ERROR_DLL_INIT_FAILED); } else { KWFS_TODO(); kHlpFree(pDynLoad); SetLastError(pMod ? ERROR_BAD_EXE_FORMAT : ERROR_MOD_NOT_FOUND); } return NULL; } /** Kernel32 - LoadLibraryExA() for native overloads */ static HMODULE WINAPI kwSandbox_Kernel32_Native_LoadLibraryExA(LPCSTR pszFilename, HANDLE hFile, DWORD fFlags) { char szPath[1024]; KWLDR_LOG(("kwSandbox_Kernel32_Native_LoadLibraryExA(%s, %p, %#x)\n", pszFilename, hFile, fFlags)); /* * We may have to help resolved unqualified DLLs living in the executable directory. */ if (kHlpIsFilenameOnly(pszFilename)) { KSIZE cchFilename = kHlpStrLen(pszFilename); KSIZE cchExePath = g_Sandbox.pTool->u.Sandboxed.pExe->offFilename; if (cchExePath + cchFilename + 1 <= sizeof(szPath)) { kHlpMemCopy(szPath, g_Sandbox.pTool->u.Sandboxed.pExe->pszPath, cchExePath); kHlpMemCopy(&szPath[cchExePath], pszFilename, cchFilename + 1); if (kwFsPathExists(szPath)) { KWLDR_LOG(("kwSandbox_Kernel32_Native_LoadLibraryExA: %s -> %s\n", pszFilename, szPath)); pszFilename = szPath; } } if (pszFilename != szPath) { KSIZE cchSuffix = 0; KBOOL fNeedSuffix = K_FALSE; const char *pszCur = kwSandboxDoGetEnvA(&g_Sandbox, "PATH", 4); while (*pszCur != '\0') { /* Find the end of the component */ KSIZE cch = 0; while (pszCur[cch] != ';' && pszCur[cch] != '\0') cch++; if ( cch > 0 /* wrong, but whatever */ && cch + 1 + cchFilename + cchSuffix < sizeof(szPath)) { char *pszDst = kHlpMemPCopy(szPath, pszCur, cch); if ( szPath[cch - 1] != ':' && szPath[cch - 1] != '/' && szPath[cch - 1] != '\\') *pszDst++ = '\\'; pszDst = kHlpMemPCopy(pszDst, pszFilename, cchFilename); if (fNeedSuffix) pszDst = kHlpMemPCopy(pszDst, ".dll", 4); *pszDst = '\0'; if (kwFsPathExists(szPath)) { KWLDR_LOG(("kwSandbox_Kernel32_Native_LoadLibraryExA: %s -> %s\n", pszFilename, szPath)); pszFilename = szPath; break; } } /* Advance */ pszCur += cch; while (*pszCur == ';') pszCur++; } } } return LoadLibraryExA(pszFilename, hFile, fFlags); } /** Kernel32 - LoadLibraryExW() */ static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryExW(LPCWSTR pwszFilename, HANDLE hFile, DWORD fFlags) { char szTmp[4096]; KSIZE cchTmp = kwUtf16ToStr(pwszFilename, szTmp, sizeof(szTmp)); if (cchTmp < sizeof(szTmp)) return kwSandbox_Kernel32_LoadLibraryExA(szTmp, hFile, fFlags); KWFS_TODO(); SetLastError(ERROR_FILENAME_EXCED_RANGE); return NULL; } /** Kernel32 - LoadLibraryA() */ static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryA(LPCSTR pszFilename) { return kwSandbox_Kernel32_LoadLibraryExA(pszFilename, NULL /*hFile*/, 0 /*fFlags*/); } /** Kernel32 - LoadLibraryW() */ static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryW(LPCWSTR pwszFilename) { char szTmp[4096]; KSIZE cchTmp = kwUtf16ToStr(pwszFilename, szTmp, sizeof(szTmp)); if (cchTmp < sizeof(szTmp)) return kwSandbox_Kernel32_LoadLibraryExA(szTmp, NULL /*hFile*/, 0 /*fFlags*/); KWFS_TODO(); SetLastError(ERROR_FILENAME_EXCED_RANGE); return NULL; } /** Kernel32 - FreeLibrary() */ static BOOL WINAPI kwSandbox_Kernel32_FreeLibrary(HMODULE hmod) { /* Ignored, we like to keep everything loaded. */ kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); return TRUE; } /** Kernel32 - GetModuleHandleA() */ static HMODULE WINAPI kwSandbox_Kernel32_GetModuleHandleA(LPCSTR pszModule) { KSIZE i; KSIZE cchModule; PKWDYNLOAD pDynLoad; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); /* * The executable. */ if (pszModule == NULL) return (HMODULE)g_Sandbox.pTool->u.Sandboxed.pExe->hOurMod; /* * Cache of system modules we've seen queried. */ cchModule = kHlpStrLen(pszModule); for (i = 0; i < K_ELEMENTS(g_aGetModuleHandleCache); i++) if ( g_aGetModuleHandleCache[i].cchName == cchModule && stricmp(pszModule, g_aGetModuleHandleCache[i].pszName) == 0) { if (g_aGetModuleHandleCache[i].hmod != NULL) return g_aGetModuleHandleCache[i].hmod; return g_aGetModuleHandleCache[i].hmod = GetModuleHandleA(pszModule); } /* * Modules we've dynamically loaded. */ for (pDynLoad = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead; pDynLoad; pDynLoad = pDynLoad->pNext) if ( pDynLoad->pMod && ( stricmp(pDynLoad->pMod->pszPath, pszModule) == 0 || stricmp(&pDynLoad->pMod->pszPath[pDynLoad->pMod->offFilename], pszModule) == 0) ) { if ( pDynLoad->pMod->fNative || pDynLoad->pMod->u.Manual.enmState == KWMODSTATE_READY) { KW_LOG(("kwSandbox_Kernel32_GetModuleHandleA(%s,,) -> %p [dynload]\n", pszModule, pDynLoad->hmod)); return pDynLoad->hmod; } SetLastError(ERROR_MOD_NOT_FOUND); return NULL; } kwErrPrintf("pszModule=%s\n", pszModule); KWFS_TODO(); SetLastError(ERROR_MOD_NOT_FOUND); return NULL; } /** Kernel32 - GetModuleHandleW() */ static HMODULE WINAPI kwSandbox_Kernel32_GetModuleHandleW(LPCWSTR pwszModule) { KSIZE i; KSIZE cwcModule; PKWDYNLOAD pDynLoad; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); /* * The executable. */ if (pwszModule == NULL) return (HMODULE)g_Sandbox.pTool->u.Sandboxed.pExe->hOurMod; /* * Cache of system modules we've seen queried. */ cwcModule = kwUtf16Len(pwszModule); for (i = 0; i < K_ELEMENTS(g_aGetModuleHandleCache); i++) if ( g_aGetModuleHandleCache[i].cwcName == cwcModule && _wcsicmp(pwszModule, g_aGetModuleHandleCache[i].pwszName) == 0) { if (g_aGetModuleHandleCache[i].hmod != NULL) return g_aGetModuleHandleCache[i].hmod; return g_aGetModuleHandleCache[i].hmod = GetModuleHandleW(pwszModule); } /* * Modules we've dynamically loaded. */ for (pDynLoad = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead; pDynLoad; pDynLoad = pDynLoad->pNext) if ( pDynLoad->pMod && ( _wcsicmp(pDynLoad->pMod->pwszPath, pwszModule) == 0 || _wcsicmp(&pDynLoad->pMod->pwszPath[pDynLoad->pMod->offFilename], pwszModule) == 0) ) /** @todo wrong offset */ { if ( pDynLoad->pMod->fNative || pDynLoad->pMod->u.Manual.enmState == KWMODSTATE_READY) { KW_LOG(("kwSandbox_Kernel32_GetModuleHandleW(%ls,,) -> %p [dynload]\n", pwszModule, pDynLoad->hmod)); return pDynLoad->hmod; } SetLastError(ERROR_MOD_NOT_FOUND); return NULL; } kwErrPrintf("pwszModule=%ls\n", pwszModule); KWFS_TODO(); SetLastError(ERROR_MOD_NOT_FOUND); return NULL; } /** Used to debug dynamically resolved procedures. */ static UINT WINAPI kwSandbox_BreakIntoDebugger(void *pv1, void *pv2, void *pv3, void *pv4) { #ifdef _MSC_VER __debugbreak(); #else KWFS_TODO(); #endif return -1; } #ifndef NDEBUG /* * This wraps up to three InvokeCompilerPassW functions and dumps their arguments to the log. */ # if K_ARCH == K_ARCH_X86_32 static char g_szInvokeCompilePassW[] = "_InvokeCompilerPassW@16"; # else static char g_szInvokeCompilePassW[] = "InvokeCompilerPassW"; # endif typedef KIPTR __stdcall FNINVOKECOMPILERPASSW(int cArgs, wchar_t **papwszArgs, KUPTR fFlags, void **phCluiInstance); typedef FNINVOKECOMPILERPASSW *PFNINVOKECOMPILERPASSW; typedef struct KWCXINTERCEPTORENTRY { PFNINVOKECOMPILERPASSW pfnOrg; PKWMODULE pModule; PFNINVOKECOMPILERPASSW pfnWrap; } KWCXINTERCEPTORENTRY; static KIPTR kwSandbox_Cx_InvokeCompilerPassW_Common(int cArgs, wchar_t **papwszArgs, KUPTR fFlags, void **phCluiInstance, KWCXINTERCEPTORENTRY *pEntry) { int i; KIPTR rcExit; KW_LOG(("%s!InvokeCompilerPassW(%d, %p, %#x, %p)\n", &pEntry->pModule->pszPath[pEntry->pModule->offFilename], cArgs, papwszArgs, fFlags, phCluiInstance)); for (i = 0; i < cArgs; i++) KW_LOG((" papwszArgs[%u]='%ls'\n", i, papwszArgs[i])); rcExit = pEntry->pfnOrg(cArgs, papwszArgs, fFlags, phCluiInstance); KW_LOG(("%s!InvokeCompilerPassW returns %d\n", &pEntry->pModule->pszPath[pEntry->pModule->offFilename], rcExit)); return rcExit; } static FNINVOKECOMPILERPASSW kwSandbox_Cx_InvokeCompilerPassW_0; static FNINVOKECOMPILERPASSW kwSandbox_Cx_InvokeCompilerPassW_1; static FNINVOKECOMPILERPASSW kwSandbox_Cx_InvokeCompilerPassW_2; static KWCXINTERCEPTORENTRY g_aCxInterceptorEntries[] = { { NULL, NULL, kwSandbox_Cx_InvokeCompilerPassW_0 }, { NULL, NULL, kwSandbox_Cx_InvokeCompilerPassW_1 }, { NULL, NULL, kwSandbox_Cx_InvokeCompilerPassW_2 }, }; static KIPTR __stdcall kwSandbox_Cx_InvokeCompilerPassW_0(int cArgs, wchar_t **papwszArgs, KUPTR fFlags, void **phCluiInstance) { return kwSandbox_Cx_InvokeCompilerPassW_Common(cArgs, papwszArgs, fFlags, phCluiInstance, &g_aCxInterceptorEntries[0]); } static KIPTR __stdcall kwSandbox_Cx_InvokeCompilerPassW_1(int cArgs, wchar_t **papwszArgs, KUPTR fFlags, void **phCluiInstance) { return kwSandbox_Cx_InvokeCompilerPassW_Common(cArgs, papwszArgs, fFlags, phCluiInstance, &g_aCxInterceptorEntries[1]); } static KIPTR __stdcall kwSandbox_Cx_InvokeCompilerPassW_2(int cArgs, wchar_t **papwszArgs, KUPTR fFlags, void **phCluiInstance) { return kwSandbox_Cx_InvokeCompilerPassW_Common(cArgs, papwszArgs, fFlags, phCluiInstance, &g_aCxInterceptorEntries[2]); } #endif /* !NDEBUG */ /** Kernel32 - GetProcAddress() */ static FARPROC WINAPI kwSandbox_Kernel32_GetProcAddress(HMODULE hmod, LPCSTR pszProc) { KSIZE i; PKWMODULE pMod; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); /* * Try locate the module. */ pMod = kwToolLocateModuleByHandle(g_Sandbox.pTool, hmod); if (pMod) { KLDRADDR uValue; int rc = kLdrModQuerySymbol(pMod->pLdrMod, pMod->fNative ? NULL : pMod->u.Manual.pvBits, pMod->fNative ? KLDRMOD_BASEADDRESS_MAP : (KUPTR)pMod->u.Manual.pbLoad, KU32_MAX /*iSymbol*/, pszProc, kHlpStrLen(pszProc), NULL /*pszVersion*/, NULL /*pfnGetForwarder*/, NULL /*pvUser*/, &uValue, NULL /*pfKind*/); if (rc == 0) { //static int s_cDbgGets = 0; KU32 cchProc = (KU32)kHlpStrLen(pszProc); KU32 i = g_cSandboxGetProcReplacements; while (i-- > 0) if ( g_aSandboxGetProcReplacements[i].cchFunction == cchProc && kHlpMemComp(g_aSandboxGetProcReplacements[i].pszFunction, pszProc, cchProc) == 0) { if ( !g_aSandboxGetProcReplacements[i].pszModule || kHlpStrICompAscii(g_aSandboxGetProcReplacements[i].pszModule, &pMod->pszPath[pMod->offFilename]) == 0) { if ( !g_aSandboxGetProcReplacements[i].fOnlyExe || (KUPTR)_ReturnAddress() - (KUPTR)g_Sandbox.pTool->u.Sandboxed.pExe->hOurMod < g_Sandbox.pTool->u.Sandboxed.pExe->cbImage) { uValue = g_aSandboxGetProcReplacements[i].pfnReplacement; KW_LOG(("GetProcAddress(%s, %s) -> %p replaced\n", pMod->pszPath, pszProc, (KUPTR)uValue)); } kwLdrModuleRelease(pMod); return (FARPROC)(KUPTR)uValue; } } #ifndef NDEBUG /* Intercept the compiler pass method, dumping arguments. */ if (kHlpStrComp(pszProc, g_szInvokeCompilePassW) == 0) { KU32 i; for (i = 0; i < K_ELEMENTS(g_aCxInterceptorEntries); i++) if ((KUPTR)g_aCxInterceptorEntries[i].pfnOrg == uValue) { uValue = (KUPTR)g_aCxInterceptorEntries[i].pfnWrap; KW_LOG(("GetProcAddress: intercepting InvokeCompilerPassW\n")); break; } if (i >= K_ELEMENTS(g_aCxInterceptorEntries)) while (i-- > 0) if (g_aCxInterceptorEntries[i].pfnOrg == NULL) { g_aCxInterceptorEntries[i].pfnOrg = (PFNINVOKECOMPILERPASSW)(KUPTR)uValue; g_aCxInterceptorEntries[i].pModule = pMod; uValue = (KUPTR)g_aCxInterceptorEntries[i].pfnWrap; KW_LOG(("GetProcAddress: intercepting InvokeCompilerPassW (new)\n")); break; } } #endif KW_LOG(("GetProcAddress(%s, %s) -> %p\n", pMod->pszPath, pszProc, (KUPTR)uValue)); kwLdrModuleRelease(pMod); //s_cDbgGets++; //if (s_cGets >= 3) // return (FARPROC)kwSandbox_BreakIntoDebugger; return (FARPROC)(KUPTR)uValue; } KWFS_TODO(); SetLastError(ERROR_PROC_NOT_FOUND); kwLdrModuleRelease(pMod); return NULL; } /* * Hmm... could be a cached module-by-name. */ for (i = 0; i < K_ELEMENTS(g_aGetModuleHandleCache); i++) if (g_aGetModuleHandleCache[i].hmod == hmod) return GetProcAddress(hmod, pszProc); KWFS_TODO(); return GetProcAddress(hmod, pszProc); } /** Kernel32 - GetModuleFileNameA() */ static DWORD WINAPI kwSandbox_Kernel32_GetModuleFileNameA(HMODULE hmod, LPSTR pszFilename, DWORD cbFilename) { PKWMODULE pMod; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pMod = kwToolLocateModuleByHandle(g_Sandbox.pTool, hmod); if (pMod != NULL) { DWORD cbRet = kwStrCopyStyle1(pMod->pszPath, pszFilename, cbFilename); kwLdrModuleRelease(pMod); return cbRet; } KWFS_TODO(); return 0; } /** Kernel32 - GetModuleFileNameW() */ static DWORD WINAPI kwSandbox_Kernel32_GetModuleFileNameW(HMODULE hmod, LPWSTR pwszFilename, DWORD cbFilename) { PKWMODULE pMod; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pMod = kwToolLocateModuleByHandle(g_Sandbox.pTool, hmod); if (pMod) { DWORD cwcRet = kwUtf16CopyStyle1(pMod->pwszPath, pwszFilename, cbFilename); kwLdrModuleRelease(pMod); return cwcRet; } KWFS_TODO(); return 0; } /** NtDll - RtlPcToFileHeader * This is necessary for msvcr100.dll!CxxThrowException. */ static PVOID WINAPI kwSandbox_ntdll_RtlPcToFileHeader(PVOID pvPC, PVOID *ppvImageBase) { PVOID pvRet; /* * Do a binary lookup of the module table for the current tool. * This will give us a */ if (g_Sandbox.fRunning) { KUPTR const uPC = (KUPTR)pvPC; PKWMODULE *papMods = g_Sandbox.pTool->u.Sandboxed.papModules; KU32 iEnd = g_Sandbox.pTool->u.Sandboxed.cModules; KU32 i; if (iEnd) { KU32 iStart = 0; i = iEnd / 2; for (;;) { KUPTR const uHModThis = (KUPTR)papMods[i]->hOurMod; if (uPC < uHModThis) { iEnd = i; if (iStart < i) { } else break; } else if (uPC != uHModThis) { iStart = ++i; if (i < iEnd) { } else break; } else { /* This isn't supposed to happen. */ break; } i = iStart + (iEnd - iStart) / 2; } /* For reasons of simplicity (= copy & paste), we end up with the module after the one we're interested in here. */ i--; if (i < g_Sandbox.pTool->u.Sandboxed.cModules && papMods[i]->pLdrMod) { KSIZE uRvaPC = uPC - (KUPTR)papMods[i]->hOurMod; if (uRvaPC < papMods[i]->cbImage) { *ppvImageBase = papMods[i]->hOurMod; pvRet = papMods[i]->hOurMod; KW_LOG(("RtlPcToFileHeader(PC=%p) -> %p, *ppvImageBase=%p [our]\n", pvPC, pvRet, *ppvImageBase)); return pvRet; } } } else i = 0; } /* * Call the regular API. */ pvRet = RtlPcToFileHeader(pvPC, ppvImageBase); KW_LOG(("RtlPcToFileHeader(PC=%p) -> %p, *ppvImageBase=%p \n", pvPC, pvRet, *ppvImageBase)); return pvRet; } /* * * File access APIs (for speeding them up). * File access APIs (for speeding them up). * File access APIs (for speeding them up). * */ /** * Converts a lookup error to a windows error code. * * @returns The windows error code. * @param enmError The lookup error. */ static DWORD kwFsLookupErrorToWindowsError(KFSLOOKUPERROR enmError) { switch (enmError) { case KFSLOOKUPERROR_NOT_FOUND: case KFSLOOKUPERROR_NOT_DIR: return ERROR_FILE_NOT_FOUND; case KFSLOOKUPERROR_PATH_COMP_NOT_FOUND: case KFSLOOKUPERROR_PATH_COMP_NOT_DIR: return ERROR_PATH_NOT_FOUND; case KFSLOOKUPERROR_PATH_TOO_LONG: return ERROR_FILENAME_EXCED_RANGE; case KFSLOOKUPERROR_OUT_OF_MEMORY: return ERROR_NOT_ENOUGH_MEMORY; default: return ERROR_PATH_NOT_FOUND; } } #ifdef WITH_TEMP_MEMORY_FILES /** * Checks for a cl.exe temporary file. * * There are quite a bunch of these. They seems to be passing data between the * first and second compiler pass. Since they're on disk, they get subjected to * AV software screening and normal file consistency rules. So, not necessarily * a very efficient way of handling reasonably small amounts of data. * * We make the files live in virtual memory by intercepting their opening, * writing, reading, closing , mapping, unmapping, and maybe some more stuff. * * @returns K_TRUE / K_FALSE * @param pwszFilename The file name being accessed. */ static KBOOL kwFsIsClTempFileW(const wchar_t *pwszFilename) { wchar_t const *pwszName = kwPathGetFilenameW(pwszFilename); if (pwszName) { /* The name starts with _CL_... */ if ( pwszName[0] == '_' && pwszName[1] == 'C' && pwszName[2] == 'L' && pwszName[3] == '_' ) { /* ... followed by 8 xdigits and ends with a two letter file type. Simplify this check by just checking that it's alpha numerical ascii from here on. */ wchar_t wc; pwszName += 4; while ((wc = *pwszName++) != '\0') { if (wc < 127 && iswalnum(wc)) { /* likely */ } else return K_FALSE; } return K_TRUE; } } return K_FALSE; } /** * Creates a handle to a temporary file. * * @returns The handle on success. * INVALID_HANDLE_VALUE and SetLastError on failure. * @param pTempFile The temporary file. * @param dwDesiredAccess The desired access to the handle. * @param fMapping Whether this is a mapping (K_TRUE) or file * (K_FALSE) handle type. */ static HANDLE kwFsTempFileCreateHandle(PKWFSTEMPFILE pTempFile, DWORD dwDesiredAccess, KBOOL fMapping) { /* * Create a handle to the temporary file. */ HANDLE hFile = INVALID_HANDLE_VALUE; HANDLE hProcSelf = GetCurrentProcess(); if (DuplicateHandle(hProcSelf, hProcSelf, hProcSelf, &hFile, SYNCHRONIZE, FALSE, 0 /*dwOptions*/)) { PKWHANDLE pHandle = (PKWHANDLE)kHlpAlloc(sizeof(*pHandle)); if (pHandle) { pHandle->enmType = !fMapping ? KWHANDLETYPE_TEMP_FILE : KWHANDLETYPE_TEMP_FILE_MAPPING; pHandle->cRefs = 1; pHandle->offFile = 0; pHandle->hHandle = hFile; pHandle->dwDesiredAccess = dwDesiredAccess; pHandle->u.pTempFile = pTempFile; if (kwSandboxHandleTableEnter(&g_Sandbox, pHandle, hFile)) { pTempFile->cActiveHandles++; kHlpAssert(pTempFile->cActiveHandles >= 1); kHlpAssert(pTempFile->cActiveHandles <= 2); KWFS_LOG(("kwFsTempFileCreateHandle: Temporary file '%ls' -> %p\n", pTempFile->pwszPath, hFile)); return hFile; } kHlpFree(pHandle); } else KWFS_LOG(("kwFsTempFileCreateHandle: Out of memory!\n")); SetLastError(ERROR_NOT_ENOUGH_MEMORY); } else KWFS_LOG(("kwFsTempFileCreateHandle: DuplicateHandle failed: err=%u\n", GetLastError())); return INVALID_HANDLE_VALUE; } static HANDLE kwFsTempFileCreateW(const wchar_t *pwszFilename, DWORD dwDesiredAccess, DWORD dwCreationDisposition) { HANDLE hFile; DWORD dwErr; /* * Check if we've got an existing temp file. * ASSUME exact same path for now. */ KSIZE const cwcFilename = kwUtf16Len(pwszFilename); PKWFSTEMPFILE pTempFile; for (pTempFile = g_Sandbox.pTempFileHead; pTempFile != NULL; pTempFile = pTempFile->pNext) { /* Since the last two chars are usually the only difference, we check them manually before calling memcmp. */ if ( pTempFile->cwcPath == cwcFilename && pTempFile->pwszPath[cwcFilename - 1] == pwszFilename[cwcFilename - 1] && pTempFile->pwszPath[cwcFilename - 2] == pwszFilename[cwcFilename - 2] && kHlpMemComp(pTempFile->pwszPath, pwszFilename, cwcFilename) == 0) break; } /* * Create a new temporary file instance if not found. */ if (pTempFile == NULL) { KSIZE cbFilename; switch (dwCreationDisposition) { case CREATE_ALWAYS: case OPEN_ALWAYS: dwErr = NO_ERROR; break; case CREATE_NEW: kHlpAssertFailed(); SetLastError(ERROR_ALREADY_EXISTS); return INVALID_HANDLE_VALUE; case OPEN_EXISTING: case TRUNCATE_EXISTING: kHlpAssertFailed(); SetLastError(ERROR_FILE_NOT_FOUND); return INVALID_HANDLE_VALUE; default: kHlpAssertFailed(); SetLastError(ERROR_INVALID_PARAMETER); return INVALID_HANDLE_VALUE; } cbFilename = (cwcFilename + 1) * sizeof(wchar_t); pTempFile = (PKWFSTEMPFILE)kHlpAlloc(sizeof(*pTempFile) + cbFilename); if (pTempFile) { pTempFile->cwcPath = (KU16)cwcFilename; pTempFile->cbFile = 0; pTempFile->cbFileAllocated = 0; pTempFile->cActiveHandles = 0; pTempFile->cMappings = 0; pTempFile->cSegs = 0; pTempFile->paSegs = NULL; pTempFile->pwszPath = (wchar_t const *)kHlpMemCopy(pTempFile + 1, pwszFilename, cbFilename); pTempFile->pNext = g_Sandbox.pTempFileHead; g_Sandbox.pTempFileHead = pTempFile; KWFS_LOG(("kwFsTempFileCreateW: Created new temporary file '%ls'\n", pwszFilename)); } else { KWFS_LOG(("kwFsTempFileCreateW: Out of memory!\n")); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return INVALID_HANDLE_VALUE; } } else { switch (dwCreationDisposition) { case OPEN_EXISTING: dwErr = NO_ERROR; break; case OPEN_ALWAYS: dwErr = ERROR_ALREADY_EXISTS ; break; case TRUNCATE_EXISTING: case CREATE_ALWAYS: kHlpAssertFailed(); pTempFile->cbFile = 0; dwErr = ERROR_ALREADY_EXISTS; break; case CREATE_NEW: kHlpAssertFailed(); SetLastError(ERROR_FILE_EXISTS); return INVALID_HANDLE_VALUE; default: kHlpAssertFailed(); SetLastError(ERROR_INVALID_PARAMETER); return INVALID_HANDLE_VALUE; } } /* * Create a handle to the temporary file. */ hFile = kwFsTempFileCreateHandle(pTempFile, dwDesiredAccess, K_FALSE /*fMapping*/); if (hFile != INVALID_HANDLE_VALUE) SetLastError(dwErr); return hFile; } #endif /* WITH_TEMP_MEMORY_FILES */ /** * Worker for kwFsIsCacheableExtensionA and kwFsIsCacheableExtensionW * * @returns K_TRUE if cacheable, K_FALSE if not. * @param wcFirst The first extension character. * @param wcSecond The second extension character. * @param wcThird The third extension character. * @param fAttrQuery Set if it's for an attribute query, clear if for * file creation. */ static KBOOL kwFsIsCacheableExtensionCommon(wchar_t wcFirst, wchar_t wcSecond, wchar_t wcThird, KBOOL fAttrQuery) { /* C++ header without an extension or a directory. */ if (wcFirst == '\0') { /** @todo exclude temporary files... */ return K_TRUE; } /* C Header: .h */ if (wcFirst == 'h' || wcFirst == 'H') { if (wcSecond == '\0') return K_TRUE; /* C++ Header: .hpp, .hxx */ if ( (wcSecond == 'p' || wcSecond == 'P') && (wcThird == 'p' || wcThird == 'P')) return K_TRUE; if ( (wcSecond == 'x' || wcSecond == 'X') && (wcThird == 'x' || wcThird == 'X')) return K_TRUE; } /* Misc starting with i. */ else if (wcFirst == 'i' || wcFirst == 'I') { if (wcSecond != '\0') { if (wcSecond == 'n' || wcSecond == 'N') { /* C++ inline header: .inl */ if (wcThird == 'l' || wcThird == 'L') return K_TRUE; /* Assembly include file: .inc */ if (wcThird == 'c' || wcThird == 'C') return K_TRUE; } } } /* Assembly header: .mac */ else if (wcFirst == 'm' || wcFirst == 'M') { if (wcSecond == 'a' || wcSecond == 'A') { if (wcThird == 'c' || wcThird == 'C') return K_TRUE; } } #ifdef WITH_PCH_CACHING /* Precompiled header: .pch */ else if (wcFirst == 'p' || wcFirst == 'P') { if (wcSecond == 'c' || wcSecond == 'C') { if (wcThird == 'h' || wcThird == 'H') return !g_Sandbox.fNoPchCaching; } } #endif #if 0 /* Experimental - need to flush these afterwards as they're highly unlikely to be used after the link is done. */ /* Linker - Object file: .obj */ if ((wcFirst == 'o' || wcFirst == 'O') && g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_LINK) { if (wcSecond == 'b' || wcSecond == 'B') { if (wcThird == 'j' || wcThird == 'J') return K_TRUE; } } #endif else if (fAttrQuery) { /* Dynamic link library: .dll */ if (wcFirst == 'd' || wcFirst == 'D') { if (wcSecond == 'l' || wcSecond == 'L') { if (wcThird == 'l' || wcThird == 'L') return K_TRUE; } } /* Executable file: .exe */ else if (wcFirst == 'e' || wcFirst == 'E') { if (wcSecond == 'x' || wcSecond == 'X') { if (wcThird == 'e' || wcThird == 'E') return K_TRUE; } } /* Response file: .rsp */ else if (wcFirst == 'r' || wcFirst == 'R') { if (wcSecond == 's' || wcSecond == 'S') { if (wcThird == 'p' || wcThird == 'P') return !g_Sandbox.fNoPchCaching; } } /* Linker: */ if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_LINK) { /* Object file: .obj */ if (wcFirst == 'o' || wcFirst == 'O') { if (wcSecond == 'b' || wcSecond == 'B') { if (wcThird == 'j' || wcThird == 'J') return K_TRUE; } } /* Library file: .lib */ else if (wcFirst == 'l' || wcFirst == 'L') { if (wcSecond == 'i' || wcSecond == 'I') { if (wcThird == 'b' || wcThird == 'B') return K_TRUE; } } /* Linker definition file: .def */ else if (wcFirst == 'd' || wcFirst == 'D') { if (wcSecond == 'e' || wcSecond == 'E') { if (wcThird == 'f' || wcThird == 'F') return K_TRUE; } } } } return K_FALSE; } /** * Checks if the file extension indicates that the file/dir is something we * ought to cache. * * @returns K_TRUE if cachable, K_FALSE if not. * @param pszExt The kHlpGetExt result. * @param fAttrQuery Set if it's for an attribute query, clear if for * file creation. */ static KBOOL kwFsIsCacheableExtensionA(const char *pszExt, KBOOL fAttrQuery) { wchar_t const wcFirst = *pszExt; if (wcFirst) { wchar_t const wcSecond = pszExt[1]; if (wcSecond) { wchar_t const wcThird = pszExt[2]; if (pszExt[3] == '\0') return kwFsIsCacheableExtensionCommon(wcFirst, wcSecond, wcThird, fAttrQuery); return K_FALSE; } return kwFsIsCacheableExtensionCommon(wcFirst, 0, 0, fAttrQuery); } return kwFsIsCacheableExtensionCommon(0, 0, 0, fAttrQuery); } /** * Checks if the extension of the given UTF-16 path indicates that the file/dir * should be cached. * * @returns K_TRUE if cachable, K_FALSE if not. * @param pwszPath The UTF-16 path to examine. * @param fAttrQuery Set if it's for an attribute query, clear if for * file creation. */ static KBOOL kwFsIsCacheablePathExtensionW(const wchar_t *pwszPath, KBOOL fAttrQuery) { KSIZE cwcExt; wchar_t const *pwszExt = kwFsPathGetExtW(pwszPath, &cwcExt); switch (cwcExt) { case 3: return kwFsIsCacheableExtensionCommon(pwszExt[0], pwszExt[1], pwszExt[2], fAttrQuery); case 2: return kwFsIsCacheableExtensionCommon(pwszExt[0], pwszExt[1], 0, fAttrQuery); case 1: return kwFsIsCacheableExtensionCommon(pwszExt[0], 0, 0, fAttrQuery); case 0: return kwFsIsCacheableExtensionCommon(0, 0, 0, fAttrQuery); } return K_FALSE; } /** * Creates a new * * @returns * @param pFsObj . * @param pwszFilename . */ static PKFSWCACHEDFILE kwFsObjCacheNewFile(PKFSOBJ pFsObj) { HANDLE hFile; MY_IO_STATUS_BLOCK Ios; MY_OBJECT_ATTRIBUTES ObjAttr; MY_UNICODE_STRING UniStr; MY_NTSTATUS rcNt; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); /* * Open the file relative to the parent directory. */ kHlpAssert(pFsObj->bObjType == KFSOBJ_TYPE_FILE); kHlpAssert(pFsObj->pParent); kHlpAssertReturn(pFsObj->pParent->hDir != INVALID_HANDLE_VALUE, NULL); Ios.Information = -1; Ios.u.Status = -1; UniStr.Buffer = (wchar_t *)pFsObj->pwszName; UniStr.Length = (USHORT)(pFsObj->cwcName * sizeof(wchar_t)); UniStr.MaximumLength = UniStr.Length + sizeof(wchar_t); MyInitializeObjectAttributes(&ObjAttr, &UniStr, OBJ_CASE_INSENSITIVE, pFsObj->pParent->hDir, NULL /*pSecAttr*/); rcNt = g_pfnNtCreateFile(&hFile, GENERIC_READ | SYNCHRONIZE, &ObjAttr, &Ios, NULL, /*cbFileInitialAlloc */ FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, /*pEaBuffer*/ 0); /*cbEaBuffer*/ if (MY_NT_SUCCESS(rcNt)) { /* * Read the whole file into memory. */ LARGE_INTEGER cbFile; if (GetFileSizeEx(hFile, &cbFile)) { if ( cbFile.QuadPart >= 0 #ifdef WITH_PCH_CACHING && ( cbFile.QuadPart < 16*1024*1024 || ( cbFile.QuadPart < 96*1024*1024 && pFsObj->cchName > 4 && !g_Sandbox.fNoPchCaching && kHlpStrICompAscii(&pFsObj->pszName[pFsObj->cchName - 4], ".pch") == 0) ) #endif ) { KU32 cbCache = (KU32)cbFile.QuadPart; HANDLE hMapping = CreateFileMappingW(hFile, NULL /*pSecAttrs*/, PAGE_READONLY, 0 /*cbMaxLow*/, 0 /*cbMaxHigh*/, NULL /*pwszName*/); if (hMapping != NULL) { KU8 *pbCache = (KU8 *)MapViewOfFile(hMapping, FILE_MAP_READ, 0 /*offFileHigh*/, 0 /*offFileLow*/, cbCache); if (pbCache) { /* * Create the cached file object. */ PKFSWCACHEDFILE pCachedFile; KU32 cbPath = pFsObj->cchParent + pFsObj->cchName + 2; pCachedFile = (PKFSWCACHEDFILE)kFsCacheObjAddUserData(g_pFsCache, pFsObj, KW_DATA_KEY_CACHED_FILE, sizeof(*pCachedFile) + cbPath); if (pCachedFile) { pCachedFile->hCached = hFile; pCachedFile->hSection = hMapping; pCachedFile->cbCached = cbCache; pCachedFile->pbCached = pbCache; pCachedFile->pFsObj = pFsObj; kFsCacheObjGetFullPathA(pFsObj, pCachedFile->szPath, cbPath, '/'); kFsCacheObjRetain(pFsObj); g_cReadCachedFiles++; g_cbReadCachedFiles += cbCache; KWFS_LOG(("Cached '%s': %p LB %#x, hCached=%p\n", pCachedFile->szPath, pbCache, cbCache, hFile)); return pCachedFile; } KWFS_LOG(("Failed to allocate KFSWCACHEDFILE structure!\n")); } else KWFS_LOG(("Failed to cache file: MapViewOfFile failed: %u\n", GetLastError())); CloseHandle(hMapping); } else KWFS_LOG(("Failed to cache file: CreateFileMappingW failed: %u\n", GetLastError())); } else KWFS_LOG(("File to big to cache! %#llx\n", cbFile.QuadPart)); } else KWFS_LOG(("File to get file size! err=%u\n", GetLastError())); g_pfnNtClose(hFile); } else KWFS_LOG(("Error opening '%ls' for caching: %#x\n", pFsObj->pwszName, rcNt)); return NULL; } /** * Kernel32 - Common code for kwFsObjCacheCreateFile and CreateFileMappingW/A. */ static KBOOL kwFsObjCacheCreateFileHandle(PKFSWCACHEDFILE pCachedFile, DWORD dwDesiredAccess, BOOL fInheritHandle, KBOOL fIsFileHandle, HANDLE *phFile) { HANDLE hProcSelf = GetCurrentProcess(); if (DuplicateHandle(hProcSelf, fIsFileHandle ? pCachedFile->hCached : pCachedFile->hSection, hProcSelf, phFile, dwDesiredAccess, fInheritHandle, 0 /*dwOptions*/)) { /* * Create handle table entry for the duplicate handle. */ PKWHANDLE pHandle = (PKWHANDLE)kHlpAlloc(sizeof(*pHandle)); if (pHandle) { pHandle->enmType = fIsFileHandle ? KWHANDLETYPE_FSOBJ_READ_CACHE : KWHANDLETYPE_FSOBJ_READ_CACHE_MAPPING; pHandle->cRefs = 1; pHandle->offFile = 0; pHandle->hHandle = *phFile; pHandle->dwDesiredAccess = dwDesiredAccess; pHandle->u.pCachedFile = pCachedFile; if (kwSandboxHandleTableEnter(&g_Sandbox, pHandle, pHandle->hHandle)) return K_TRUE; kHlpFree(pHandle); } else KWFS_LOG(("Out of memory for handle!\n")); CloseHandle(*phFile); *phFile = INVALID_HANDLE_VALUE; } else KWFS_LOG(("DuplicateHandle failed! err=%u\n", GetLastError())); return K_FALSE; } /** * Kernel32 - Common code for CreateFileW and CreateFileA. */ static KBOOL kwFsObjCacheCreateFile(PKFSOBJ pFsObj, DWORD dwDesiredAccess, BOOL fInheritHandle, HANDLE *phFile) { *phFile = INVALID_HANDLE_VALUE; /* * At the moment we only handle existing files. */ if (pFsObj->bObjType == KFSOBJ_TYPE_FILE) { PKFSWCACHEDFILE pCachedFile = (PKFSWCACHEDFILE)kFsCacheObjGetUserData(g_pFsCache, pFsObj, KW_DATA_KEY_CACHED_FILE); kHlpAssert(pFsObj->fHaveStats); if ( pCachedFile != NULL || (pCachedFile = kwFsObjCacheNewFile(pFsObj)) != NULL) { if (kwFsObjCacheCreateFileHandle(pCachedFile, dwDesiredAccess, fInheritHandle, K_TRUE /*fIsFileHandle*/, phFile)) return K_TRUE; } } /** @todo Deal with non-existing files if it becomes necessary (it's not for VS2010). */ /* Do fallback, please. */ return K_FALSE; } /** Kernel32 - CreateFileA */ static HANDLE WINAPI kwSandbox_Kernel32_CreateFileA(LPCSTR pszFilename, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES pSecAttrs, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { HANDLE hFile; /* * Check for include files and similar that we do read-only caching of. */ if (dwCreationDisposition == FILE_OPEN_IF) { if ( dwDesiredAccess == GENERIC_READ || dwDesiredAccess == FILE_GENERIC_READ) { if (dwShareMode & FILE_SHARE_READ) { if ( !pSecAttrs || ( pSecAttrs->nLength == sizeof(*pSecAttrs) && pSecAttrs->lpSecurityDescriptor == NULL ) ) { const char *pszExt = kHlpGetExt(pszFilename); if (kwFsIsCacheableExtensionA(pszExt, K_FALSE /*fAttrQuery*/)) { KFSLOOKUPERROR enmError; PKFSOBJ pFsObj; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pFsObj = kFsCacheLookupNoMissingA(g_pFsCache, pszFilename, &enmError); if (pFsObj) { KBOOL fRc = kwFsObjCacheCreateFile(pFsObj, dwDesiredAccess, pSecAttrs && pSecAttrs->bInheritHandle, &hFile); kFsCacheObjRelease(g_pFsCache, pFsObj); if (fRc) { KWFS_LOG(("CreateFileA(%s) -> %p [cached]\n", pszFilename, hFile)); return hFile; } } /* These are for nasm and yasm header searching. Cache will already have checked the directories for the file, no need to call CreateFile to do it again. */ else if (enmError == KFSLOOKUPERROR_NOT_FOUND) { KWFS_LOG(("CreateFileA(%s) -> INVALID_HANDLE_VALUE, ERROR_FILE_NOT_FOUND\n", pszFilename)); return INVALID_HANDLE_VALUE; } else if ( enmError == KFSLOOKUPERROR_PATH_COMP_NOT_FOUND || enmError == KFSLOOKUPERROR_PATH_COMP_NOT_DIR) { KWFS_LOG(("CreateFileA(%s) -> INVALID_HANDLE_VALUE, ERROR_PATH_NOT_FOUND\n", pszFilename)); return INVALID_HANDLE_VALUE; } /* fallback */ hFile = CreateFileA(pszFilename, dwDesiredAccess, dwShareMode, pSecAttrs, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); KWFS_LOG(("CreateFileA(%s) -> %p (err=%u) [fallback]\n", pszFilename, hFile, GetLastError())); return hFile; } } } } } /* * Okay, normal. */ hFile = CreateFileA(pszFilename, dwDesiredAccess, dwShareMode, pSecAttrs, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); if (hFile != INVALID_HANDLE_VALUE) { kHlpAssert( KW_HANDLE_TO_INDEX(hFile) >= g_Sandbox.cHandles || g_Sandbox.papHandles[KW_HANDLE_TO_INDEX(hFile)] == NULL); } KWFS_LOG(("CreateFileA(%s) -> %p\n", pszFilename, hFile)); return hFile; } /** Kernel32 - CreateFileW */ static HANDLE WINAPI kwSandbox_Kernel32_CreateFileW(LPCWSTR pwszFilename, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES pSecAttrs, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { HANDLE hFile; #ifdef WITH_TEMP_MEMORY_FILES /* * Check for temporary files (cl.exe only). */ if ( g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL && !(dwFlagsAndAttributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE | FILE_FLAG_BACKUP_SEMANTICS)) && !(dwDesiredAccess & (GENERIC_EXECUTE | FILE_EXECUTE)) && kwFsIsClTempFileW(pwszFilename)) { hFile = kwFsTempFileCreateW(pwszFilename, dwDesiredAccess, dwCreationDisposition); KWFS_LOG(("CreateFileW(%ls) -> %p [temp]\n", pwszFilename, hFile)); return hFile; } #endif /* * Check for include files and similar that we do read-only caching of. */ if (dwCreationDisposition == FILE_OPEN_IF) { if ( dwDesiredAccess == GENERIC_READ || dwDesiredAccess == FILE_GENERIC_READ) { if (dwShareMode & FILE_SHARE_READ) { if ( !pSecAttrs || ( pSecAttrs->nLength == sizeof(*pSecAttrs) && pSecAttrs->lpSecurityDescriptor == NULL ) ) { if (kwFsIsCacheablePathExtensionW(pwszFilename, K_FALSE /*fAttrQuery*/)) { KFSLOOKUPERROR enmError; PKFSOBJ pFsObj; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pFsObj = kFsCacheLookupNoMissingW(g_pFsCache, pwszFilename, &enmError); if (pFsObj) { KBOOL fRc = kwFsObjCacheCreateFile(pFsObj, dwDesiredAccess, pSecAttrs && pSecAttrs->bInheritHandle, &hFile); kFsCacheObjRelease(g_pFsCache, pFsObj); if (fRc) { KWFS_LOG(("CreateFileW(%ls) -> %p [cached]\n", pwszFilename, hFile)); return hFile; } } /* These are for nasm and yasm style header searching. Cache will already have checked the directories for the file, no need to call CreateFile to do it again. */ else if (enmError == KFSLOOKUPERROR_NOT_FOUND) { KWFS_LOG(("CreateFileW(%ls) -> INVALID_HANDLE_VALUE, ERROR_FILE_NOT_FOUND\n", pwszFilename)); return INVALID_HANDLE_VALUE; } else if ( enmError == KFSLOOKUPERROR_PATH_COMP_NOT_FOUND || enmError == KFSLOOKUPERROR_PATH_COMP_NOT_DIR) { KWFS_LOG(("CreateFileW(%ls) -> INVALID_HANDLE_VALUE, ERROR_PATH_NOT_FOUND\n", pwszFilename)); return INVALID_HANDLE_VALUE; } /* fallback */ hFile = CreateFileW(pwszFilename, dwDesiredAccess, dwShareMode, pSecAttrs, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); KWFS_LOG(("CreateFileW(%ls) -> %p (err=%u) [fallback]\n", pwszFilename, hFile, GetLastError())); return hFile; } } else KWFS_LOG(("CreateFileW: incompatible security attributes (nLength=%#x pDesc=%p)\n", pSecAttrs->nLength, pSecAttrs->lpSecurityDescriptor)); } else KWFS_LOG(("CreateFileW: incompatible sharing mode %#x\n", dwShareMode)); } else KWFS_LOG(("CreateFileW: incompatible desired access %#x\n", dwDesiredAccess)); } else KWFS_LOG(("CreateFileW: incompatible disposition %u\n", dwCreationDisposition)); /* * Okay, normal. */ hFile = CreateFileW(pwszFilename, dwDesiredAccess, dwShareMode, pSecAttrs, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); if (hFile != INVALID_HANDLE_VALUE) { kHlpAssert( KW_HANDLE_TO_INDEX(hFile) >= g_Sandbox.cHandles || g_Sandbox.papHandles[KW_HANDLE_TO_INDEX(hFile)] == NULL); } KWFS_LOG(("CreateFileW(%ls) -> %p\n", pwszFilename, hFile)); return hFile; } /** Kernel32 - SetFilePointer */ static DWORD WINAPI kwSandbox_Kernel32_SetFilePointer(HANDLE hFile, LONG cbMove, PLONG pcbMoveHi, DWORD dwMoveMethod) { KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle != NULL) { KU32 cbFile; KI64 offMove = pcbMoveHi ? ((KI64)*pcbMoveHi << 32) | cbMove : cbMove; switch (pHandle->enmType) { case KWHANDLETYPE_FSOBJ_READ_CACHE: cbFile = pHandle->u.pCachedFile->cbCached; break; #ifdef WITH_TEMP_MEMORY_FILES case KWHANDLETYPE_TEMP_FILE: cbFile = pHandle->u.pTempFile->cbFile; break; #endif case KWHANDLETYPE_TEMP_FILE_MAPPING: case KWHANDLETYPE_OUTPUT_BUF: default: kHlpAssertFailed(); SetLastError(ERROR_INVALID_FUNCTION); return INVALID_SET_FILE_POINTER; } switch (dwMoveMethod) { case FILE_BEGIN: break; case FILE_CURRENT: offMove += pHandle->offFile; break; case FILE_END: offMove += cbFile; break; default: KWFS_LOG(("SetFilePointer(%p) - invalid seek method %u! [cached]\n", hFile)); SetLastError(ERROR_INVALID_PARAMETER); return INVALID_SET_FILE_POINTER; } if (offMove >= 0) { if (offMove >= (KSSIZE)cbFile) { /* For read-only files, seeking beyond the end isn't useful to us, so clamp it. */ if (pHandle->enmType != KWHANDLETYPE_TEMP_FILE) offMove = (KSSIZE)cbFile; /* For writable files, seeking beyond the end is fine, but check that we've got the type range for the request. */ else if (((KU64)offMove & KU32_MAX) != (KU64)offMove) { kHlpAssertMsgFailed(("%#llx\n", offMove)); SetLastError(ERROR_SEEK); return INVALID_SET_FILE_POINTER; } } pHandle->offFile = (KU32)offMove; } else { KWFS_LOG(("SetFilePointer(%p) - negative seek! [cached]\n", hFile)); SetLastError(ERROR_NEGATIVE_SEEK); return INVALID_SET_FILE_POINTER; } if (pcbMoveHi) *pcbMoveHi = (KU64)offMove >> 32; KWFS_LOG(("SetFilePointer(%p,%#x,?,%u) -> %#llx [%s]\n", hFile, cbMove, dwMoveMethod, offMove, pHandle->enmType == KWHANDLETYPE_FSOBJ_READ_CACHE ? "cached" : "temp")); SetLastError(NO_ERROR); return (KU32)offMove; } } KWFS_LOG(("SetFilePointer(%p, %d, %p=%d, %d)\n", hFile, cbMove, pcbMoveHi ? *pcbMoveHi : 0, dwMoveMethod)); return SetFilePointer(hFile, cbMove, pcbMoveHi, dwMoveMethod); } /** Kernel32 - SetFilePointerEx */ static BOOL WINAPI kwSandbox_Kernel32_SetFilePointerEx(HANDLE hFile, LARGE_INTEGER offMove, PLARGE_INTEGER poffNew, DWORD dwMoveMethod) { KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle != NULL) { KI64 offMyMove = offMove.QuadPart; KU32 cbFile; switch (pHandle->enmType) { case KWHANDLETYPE_FSOBJ_READ_CACHE: cbFile = pHandle->u.pCachedFile->cbCached; break; #ifdef WITH_TEMP_MEMORY_FILES case KWHANDLETYPE_TEMP_FILE: cbFile = pHandle->u.pTempFile->cbFile; break; #endif case KWHANDLETYPE_TEMP_FILE_MAPPING: case KWHANDLETYPE_OUTPUT_BUF: default: kHlpAssertFailed(); SetLastError(ERROR_INVALID_FUNCTION); return INVALID_SET_FILE_POINTER; } switch (dwMoveMethod) { case FILE_BEGIN: break; case FILE_CURRENT: offMyMove += pHandle->offFile; break; case FILE_END: offMyMove += cbFile; break; default: KWFS_LOG(("SetFilePointer(%p) - invalid seek method %u! [cached]\n", hFile)); SetLastError(ERROR_INVALID_PARAMETER); return INVALID_SET_FILE_POINTER; } if (offMyMove >= 0) { if (offMyMove >= (KSSIZE)cbFile) { /* For read-only files, seeking beyond the end isn't useful to us, so clamp it. */ if (pHandle->enmType != KWHANDLETYPE_TEMP_FILE) offMyMove = (KSSIZE)cbFile; /* For writable files, seeking beyond the end is fine, but check that we've got the type range for the request. */ else if (((KU64)offMyMove & KU32_MAX) != (KU64)offMyMove) { kHlpAssertMsgFailed(("%#llx\n", offMyMove)); SetLastError(ERROR_SEEK); return INVALID_SET_FILE_POINTER; } } pHandle->offFile = (KU32)offMyMove; } else { KWFS_LOG(("SetFilePointerEx(%p) - negative seek! [cached]\n", hFile)); SetLastError(ERROR_NEGATIVE_SEEK); return INVALID_SET_FILE_POINTER; } if (poffNew) poffNew->QuadPart = offMyMove; KWFS_LOG(("SetFilePointerEx(%p,%#llx,,%u) -> TRUE, %#llx [%s]\n", hFile, offMove.QuadPart, dwMoveMethod, offMyMove, pHandle->enmType == KWHANDLETYPE_FSOBJ_READ_CACHE ? "cached" : "temp")); return TRUE; } } KWFS_LOG(("SetFilePointerEx(%p)\n", hFile)); return SetFilePointerEx(hFile, offMove, poffNew, dwMoveMethod); } /** Kernel32 - ReadFile */ static BOOL WINAPI kwSandbox_Kernel32_ReadFile(HANDLE hFile, LPVOID pvBuffer, DWORD cbToRead, LPDWORD pcbActuallyRead, LPOVERLAPPED pOverlapped) { BOOL fRet; KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile); g_cReadFileCalls++; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle != NULL) { switch (pHandle->enmType) { case KWHANDLETYPE_FSOBJ_READ_CACHE: { PKFSWCACHEDFILE pCachedFile = pHandle->u.pCachedFile; KU32 cbActually = pCachedFile->cbCached - pHandle->offFile; if (cbActually > cbToRead) cbActually = cbToRead; #ifdef WITH_HASH_MD5_CACHE if (g_Sandbox.pHashHead) { g_Sandbox.LastHashRead.pCachedFile = pCachedFile; g_Sandbox.LastHashRead.offRead = pHandle->offFile; g_Sandbox.LastHashRead.cbRead = cbActually; g_Sandbox.LastHashRead.pvRead = pvBuffer; } #endif kHlpMemCopy(pvBuffer, &pCachedFile->pbCached[pHandle->offFile], cbActually); pHandle->offFile += cbActually; kHlpAssert(!pOverlapped); kHlpAssert(pcbActuallyRead); *pcbActuallyRead = cbActually; g_cbReadFileFromReadCached += cbActually; g_cbReadFileTotal += cbActually; g_cReadFileFromReadCached++; KWFS_LOG(("ReadFile(%p,,%#x) -> TRUE, %#x bytes [cached]\n", hFile, cbToRead, cbActually)); return TRUE; } #ifdef WITH_TEMP_MEMORY_FILES case KWHANDLETYPE_TEMP_FILE: { PKWFSTEMPFILE pTempFile = pHandle->u.pTempFile; KU32 cbActually; if (pHandle->offFile < pTempFile->cbFile) { cbActually = pTempFile->cbFile - pHandle->offFile; if (cbActually > cbToRead) cbActually = cbToRead; /* Copy the data. */ if (cbActually > 0) { KU32 cbLeft; KU32 offSeg; KWFSTEMPFILESEG const *paSegs = pTempFile->paSegs; /* Locate the segment containing the byte at offFile. */ KU32 iSeg = pTempFile->cSegs - 1; kHlpAssert(pTempFile->cSegs > 0); while (paSegs[iSeg].offData > pHandle->offFile) iSeg--; /* Copy out the data. */ cbLeft = cbActually; offSeg = (pHandle->offFile - paSegs[iSeg].offData); for (;;) { KU32 cbAvail = paSegs[iSeg].cbDataAlloc - offSeg; if (cbAvail >= cbLeft) { kHlpMemCopy(pvBuffer, &paSegs[iSeg].pbData[offSeg], cbLeft); break; } pvBuffer = kHlpMemPCopy(pvBuffer, &paSegs[iSeg].pbData[offSeg], cbAvail); cbLeft -= cbAvail; offSeg = 0; iSeg++; kHlpAssert(iSeg < pTempFile->cSegs); } /* Update the file offset. */ pHandle->offFile += cbActually; } } /* Read does not commit file space, so return zero bytes. */ else cbActually = 0; kHlpAssert(!pOverlapped); kHlpAssert(pcbActuallyRead); *pcbActuallyRead = cbActually; g_cbReadFileTotal += cbActually; g_cbReadFileFromInMemTemp += cbActually; g_cReadFileFromInMemTemp++; KWFS_LOG(("ReadFile(%p,,%#x) -> TRUE, %#x bytes [temp]\n", hFile, cbToRead, (KU32)cbActually)); return TRUE; } #endif /* WITH_TEMP_MEMORY_FILES */ case KWHANDLETYPE_TEMP_FILE_MAPPING: case KWHANDLETYPE_OUTPUT_BUF: default: kHlpAssertFailed(); SetLastError(ERROR_INVALID_FUNCTION); *pcbActuallyRead = 0; return FALSE; } } } fRet = ReadFile(hFile, pvBuffer, cbToRead, pcbActuallyRead, pOverlapped); if (fRet && pcbActuallyRead) g_cbReadFileTotal += *pcbActuallyRead; KWFS_LOG(("ReadFile(%p,%p,%#x,,) -> %d, %#x\n", hFile, pvBuffer, cbToRead, fRet, pcbActuallyRead ? *pcbActuallyRead : 0)); return fRet; } /** Kernel32 - ReadFileEx */ static BOOL WINAPI kwSandbox_Kernel32_ReadFileEx(HANDLE hFile, LPVOID pvBuffer, DWORD cbToRead, LPOVERLAPPED pOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE pfnCompletionRoutine) { KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle != NULL) { kHlpAssertFailed(); } } KWFS_LOG(("ReadFile(%p)\n", hFile)); return ReadFileEx(hFile, pvBuffer, cbToRead, pOverlapped, pfnCompletionRoutine); } #ifdef WITH_STD_OUT_ERR_BUFFERING /** * Write something to a handle, making sure everything is actually written. * * @param hHandle Where to write it to. * @param pchBuf What to write * @param cchToWrite How much to write. */ static void kwSandboxOutBufWriteIt(HANDLE hFile, char const *pchBuf, KU32 cchToWrite) { if (cchToWrite > 0) { DWORD cchWritten = 0; if (WriteFile(hFile, pchBuf, cchToWrite, &cchWritten, NULL)) { if (cchWritten == cchToWrite) { /* likely */ } else { do { pchBuf += cchWritten; cchToWrite -= cchWritten; cchWritten = 0; } while ( cchToWrite > 0 && WriteFile(hFile, pchBuf, cchToWrite, &cchWritten, NULL)); } } else kHlpAssertFailed(); } } /** * Worker for WriteFile when the output isn't going to the console. * * @param pSandbox The sandbox. * @param pOutBuf The output buffer. * @param pchBuffer What to write. * @param cchToWrite How much to write. */ static void kwSandboxOutBufWrite(PKWSANDBOX pSandbox, PKWOUTPUTSTREAMBUF pOutBuf, const char *pchBuffer, KU32 cchToWrite) { if (pOutBuf->u.Fully.cchBufAlloc > 0) { /* likely */ } else { /* No realloc, max size is 64KB. */ pOutBuf->u.Fully.cchBufAlloc = 0x10000; pOutBuf->u.Fully.pchBuf = (char *)kHlpAlloc(pOutBuf->u.Fully.cchBufAlloc); if (!pOutBuf->u.Fully.pchBuf) { while ( !pOutBuf->u.Fully.pchBuf && pOutBuf->u.Fully.cchBufAlloc > 64) { pOutBuf->u.Fully.cchBufAlloc /= 2; pOutBuf->u.Fully.pchBuf = (char *)kHlpAlloc(pOutBuf->u.Fully.cchBufAlloc); } if (!pOutBuf->u.Fully.pchBuf) { pOutBuf->u.Fully.cchBufAlloc = sizeof(pOutBuf->abPadding); pOutBuf->u.Fully.pchBuf = pOutBuf->abPadding; } } } /* * Special case: Output ends with newline and fits in the buffer. */ if ( cchToWrite > 1 && pchBuffer[cchToWrite - 1] == '\n' && cchToWrite <= pOutBuf->u.Fully.cchBufAlloc - pOutBuf->u.Fully.cchBuf) { kHlpMemCopy(&pOutBuf->u.Fully.pchBuf[pOutBuf->u.Fully.cchBuf], pchBuffer, cchToWrite); pOutBuf->u.Fully.cchBuf += cchToWrite; } else { /* * Work thru the text line by line, flushing the buffer when * appropriate. The buffer is not a line buffer here, it's a * full buffer. */ while (cchToWrite > 0) { char const *pchNewLine = (const char *)memchr(pchBuffer, '\n', cchToWrite); KU32 cchLine = pchNewLine ? (KU32)(pchNewLine - pchBuffer) + 1 : cchToWrite; if (cchLine <= pOutBuf->u.Fully.cchBufAlloc - pOutBuf->u.Fully.cchBuf) { kHlpMemCopy(&pOutBuf->u.Fully.pchBuf[pOutBuf->u.Fully.cchBuf], pchBuffer, cchLine); pOutBuf->u.Fully.cchBuf += cchLine; } /* * Option one: Flush the buffer and the current line. * * We choose this one when the line won't ever fit, or when we have * an incomplete line in the buffer. */ else if ( cchLine >= pOutBuf->u.Fully.cchBufAlloc || pOutBuf->u.Fully.cchBuf == 0 || pOutBuf->u.Fully.pchBuf[pOutBuf->u.Fully.cchBuf - 1] != '\n') { KWOUT_LOG(("kwSandboxOutBufWrite: flushing %u bytes, writing %u bytes\n", pOutBuf->u.Fully.cchBuf, cchLine)); if (pOutBuf->u.Fully.cchBuf > 0) { kwSandboxOutBufWriteIt(pOutBuf->hBackup, pOutBuf->u.Fully.pchBuf, pOutBuf->u.Fully.cchBuf); pOutBuf->u.Fully.cchBuf = 0; } kwSandboxOutBufWriteIt(pOutBuf->hBackup, pchBuffer, cchLine); } /* * Option two: Only flush the lines in the buffer. */ else { KWOUT_LOG(("kwSandboxOutBufWrite: flushing %u bytes\n", pOutBuf->u.Fully.cchBuf)); kwSandboxOutBufWriteIt(pOutBuf->hBackup, pOutBuf->u.Fully.pchBuf, pOutBuf->u.Fully.cchBuf); kHlpMemCopy(&pOutBuf->u.Fully.pchBuf[0], pchBuffer, cchLine); pOutBuf->u.Fully.cchBuf = cchLine; } /* advance */ pchBuffer += cchLine; cchToWrite -= cchLine; } } } #endif /* WITH_STD_OUT_ERR_BUFFERING */ #ifdef WITH_TEMP_MEMORY_FILES static KBOOL kwFsTempFileEnsureSpace(PKWFSTEMPFILE pTempFile, KU32 offFile, KU32 cbNeeded) { KU32 cbMinFile = offFile + cbNeeded; if (cbMinFile >= offFile) { /* Calc how much space we've already allocated and */ if (cbMinFile <= pTempFile->cbFileAllocated) return K_TRUE; /* Grow the file. */ if (cbMinFile <= KWFS_TEMP_FILE_MAX) { int rc; KU32 cSegs = pTempFile->cSegs; KU32 cbNewSeg = cbMinFile > 4*1024*1024 ? 256*1024 : 4*1024*1024; do { /* grow the segment array? */ if ((cSegs % 16) == 0) { void *pvNew = kHlpRealloc(pTempFile->paSegs, (cSegs + 16) * sizeof(pTempFile->paSegs[0])); if (!pvNew) return K_FALSE; pTempFile->paSegs = (PKWFSTEMPFILESEG)pvNew; } /* Use page alloc here to simplify mapping later. */ rc = kHlpPageAlloc((void **)&pTempFile->paSegs[cSegs].pbData, cbNewSeg, KPROT_READWRITE, K_FALSE); if (rc == 0) { /* likely */ } else { cbNewSeg = 64*1024; rc = kHlpPageAlloc((void **)&pTempFile->paSegs[cSegs].pbData, cbNewSeg, KPROT_READWRITE, K_FALSE); if (rc != 0) { kHlpAssertFailed(); return K_FALSE; } } pTempFile->paSegs[cSegs].offData = pTempFile->cbFileAllocated; pTempFile->paSegs[cSegs].cbDataAlloc = cbNewSeg; pTempFile->cbFileAllocated += cbNewSeg; pTempFile->cSegs = ++cSegs; } while (pTempFile->cbFileAllocated < cbMinFile); return K_TRUE; } } kHlpAssertMsgFailed(("Out of bounds offFile=%#x + cbNeeded=%#x = %#x\n", offFile, cbNeeded, offFile + cbNeeded)); return K_FALSE; } #endif /* WITH_TEMP_MEMORY_FILES */ #if defined(WITH_TEMP_MEMORY_FILES) || defined(WITH_STD_OUT_ERR_BUFFERING) /** Kernel32 - WriteFile */ static BOOL WINAPI kwSandbox_Kernel32_WriteFile(HANDLE hFile, LPCVOID pvBuffer, DWORD cbToWrite, LPDWORD pcbActuallyWritten, LPOVERLAPPED pOverlapped) { BOOL fRet; KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile); g_cWriteFileCalls++; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread || g_fCtrlC); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle != NULL) { switch (pHandle->enmType) { # ifdef WITH_TEMP_MEMORY_FILES case KWHANDLETYPE_TEMP_FILE: { PKWFSTEMPFILE pTempFile = pHandle->u.pTempFile; kHlpAssert(!pOverlapped); kHlpAssert(pcbActuallyWritten); if (kwFsTempFileEnsureSpace(pTempFile, pHandle->offFile, cbToWrite)) { KU32 cbLeft; KU32 offSeg; /* Locate the segment containing the byte at offFile. */ KWFSTEMPFILESEG const *paSegs = pTempFile->paSegs; KU32 iSeg = pTempFile->cSegs - 1; kHlpAssert(pTempFile->cSegs > 0); while (paSegs[iSeg].offData > pHandle->offFile) iSeg--; /* Copy in the data. */ cbLeft = cbToWrite; offSeg = (pHandle->offFile - paSegs[iSeg].offData); for (;;) { KU32 cbAvail = paSegs[iSeg].cbDataAlloc - offSeg; if (cbAvail >= cbLeft) { kHlpMemCopy(&paSegs[iSeg].pbData[offSeg], pvBuffer, cbLeft); break; } kHlpMemCopy(&paSegs[iSeg].pbData[offSeg], pvBuffer, cbAvail); pvBuffer = (KU8 const *)pvBuffer + cbAvail; cbLeft -= cbAvail; offSeg = 0; iSeg++; kHlpAssert(iSeg < pTempFile->cSegs); } /* Update the file offset. */ pHandle->offFile += cbToWrite; if (pHandle->offFile > pTempFile->cbFile) pTempFile->cbFile = pHandle->offFile; *pcbActuallyWritten = cbToWrite; g_cbWriteFileTotal += cbToWrite; g_cbWriteFileToInMemTemp += cbToWrite; g_cWriteFileToInMemTemp++; KWFS_LOG(("WriteFile(%p,,%#x) -> TRUE [temp]\n", hFile, cbToWrite)); return TRUE; } kHlpAssertFailed(); *pcbActuallyWritten = 0; SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } # endif case KWHANDLETYPE_FSOBJ_READ_CACHE: kHlpAssertFailed(); SetLastError(ERROR_ACCESS_DENIED); *pcbActuallyWritten = 0; return FALSE; # if defined(WITH_STD_OUT_ERR_BUFFERING) || defined(WITH_CONSOLE_OUTPUT_BUFFERING) /* * Standard output & error. */ case KWHANDLETYPE_OUTPUT_BUF: { PKWOUTPUTSTREAMBUF pOutBuf = pHandle->u.pOutBuf; if (pOutBuf->fIsConsole) { kwSandboxConsoleWriteA(&g_Sandbox, pOutBuf, (const char *)pvBuffer, cbToWrite); KWOUT_LOG(("WriteFile(%p [console]) -> TRUE\n", hFile)); } else { # ifdef WITH_STD_OUT_ERR_BUFFERING kwSandboxOutBufWrite(&g_Sandbox, pOutBuf, (const char *)pvBuffer, cbToWrite); KWOUT_LOG(("WriteFile(%p [std%s], 's*.*', %#x) -> TRUE\n", hFile, pOutBuf == &g_Sandbox.StdErr ? "err" : "out", cbToWrite, cbToWrite, pvBuffer, cbToWrite)); # else kHlpAssertFailed(); # endif } if (pcbActuallyWritten) *pcbActuallyWritten = cbToWrite; g_cbWriteFileTotal += cbToWrite; return TRUE; } # endif default: case KWHANDLETYPE_TEMP_FILE_MAPPING: kHlpAssertFailed(); SetLastError(ERROR_INVALID_FUNCTION); *pcbActuallyWritten = 0; return FALSE; } } } fRet = WriteFile(hFile, pvBuffer, cbToWrite, pcbActuallyWritten, pOverlapped); if (fRet && pcbActuallyWritten) g_cbWriteFileTotal += *pcbActuallyWritten; KWFS_LOG(("WriteFile(%p,,%#x) -> %d, %#x\n", hFile, cbToWrite, fRet, pcbActuallyWritten ? *pcbActuallyWritten : 0)); return fRet; } /** Kernel32 - WriteFileEx */ static BOOL WINAPI kwSandbox_Kernel32_WriteFileEx(HANDLE hFile, LPCVOID pvBuffer, DWORD cbToWrite, LPOVERLAPPED pOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE pfnCompletionRoutine) { KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle != NULL) { kHlpAssertFailed(); } } KWFS_LOG(("WriteFileEx(%p)\n", hFile)); return WriteFileEx(hFile, pvBuffer, cbToWrite, pOverlapped, pfnCompletionRoutine); } #endif /* WITH_TEMP_MEMORY_FILES || WITH_STD_OUT_ERR_BUFFERING */ #ifdef WITH_TEMP_MEMORY_FILES /** Kernel32 - SetEndOfFile; */ static BOOL WINAPI kwSandbox_Kernel32_SetEndOfFile(HANDLE hFile) { KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle != NULL) { switch (pHandle->enmType) { case KWHANDLETYPE_TEMP_FILE: { PKWFSTEMPFILE pTempFile = pHandle->u.pTempFile; if ( pHandle->offFile > pTempFile->cbFile && !kwFsTempFileEnsureSpace(pTempFile, pHandle->offFile, 0)) { kHlpAssertFailed(); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } pTempFile->cbFile = pHandle->offFile; KWFS_LOG(("SetEndOfFile(%p) -> TRUE (cbFile=%#x)\n", hFile, pTempFile->cbFile)); return TRUE; } case KWHANDLETYPE_FSOBJ_READ_CACHE: kHlpAssertFailed(); SetLastError(ERROR_ACCESS_DENIED); return FALSE; case KWHANDLETYPE_OUTPUT_BUF: kHlpAssertFailed(); SetLastError(pHandle->u.pOutBuf->fIsConsole ? ERROR_INVALID_OPERATION : ERROR_ACCESS_DENIED); return FALSE; default: case KWHANDLETYPE_TEMP_FILE_MAPPING: kHlpAssertFailed(); SetLastError(ERROR_INVALID_FUNCTION); return FALSE; } } } KWFS_LOG(("SetEndOfFile(%p)\n", hFile)); return SetEndOfFile(hFile); } /** Kernel32 - GetFileType */ static BOOL WINAPI kwSandbox_Kernel32_GetFileType(HANDLE hFile) { KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle != NULL) { switch (pHandle->enmType) { case KWHANDLETYPE_FSOBJ_READ_CACHE: KWFS_LOG(("GetFileType(%p) -> FILE_TYPE_DISK [cached]\n", hFile)); return FILE_TYPE_DISK; case KWHANDLETYPE_TEMP_FILE: KWFS_LOG(("GetFileType(%p) -> FILE_TYPE_DISK [temp]\n", hFile)); return FILE_TYPE_DISK; case KWHANDLETYPE_OUTPUT_BUF: { PKWOUTPUTSTREAMBUF pOutBuf = pHandle->u.pOutBuf; DWORD fRet; if (pOutBuf->fFileType != KU8_MAX) { fRet = (pOutBuf->fFileType & 0xf) | ((pOutBuf->fFileType & (FILE_TYPE_REMOTE >> 8)) << 8); KWFS_LOG(("GetFileType(%p) -> %#x [outbuf]\n", hFile, fRet)); } else { fRet = GetFileType(hFile); KWFS_LOG(("GetFileType(%p) -> %#x [outbuf, fallback]\n", hFile, fRet)); } return fRet; } } } } KWFS_LOG(("GetFileType(%p)\n", hFile)); return GetFileType(hFile); } /** Kernel32 - GetFileSize */ static DWORD WINAPI kwSandbox_Kernel32_GetFileSize(HANDLE hFile, LPDWORD pcbHighDword) { KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle != NULL) { if (pcbHighDword) *pcbHighDword = 0; SetLastError(NO_ERROR); switch (pHandle->enmType) { case KWHANDLETYPE_FSOBJ_READ_CACHE: KWFS_LOG(("GetFileSize(%p) -> %#x [cached]\n", hFile, pHandle->u.pCachedFile->cbCached)); return pHandle->u.pCachedFile->cbCached; case KWHANDLETYPE_TEMP_FILE: KWFS_LOG(("GetFileSize(%p) -> %#x [temp]\n", hFile, pHandle->u.pTempFile->cbFile)); return pHandle->u.pTempFile->cbFile; case KWHANDLETYPE_OUTPUT_BUF: /* do default */ break; default: kHlpAssertFailed(); SetLastError(ERROR_INVALID_FUNCTION); return INVALID_FILE_SIZE; } } } KWFS_LOG(("GetFileSize(%p,)\n", hFile)); return GetFileSize(hFile, pcbHighDword); } /** Kernel32 - GetFileSizeEx */ static BOOL WINAPI kwSandbox_Kernel32_GetFileSizeEx(HANDLE hFile, PLARGE_INTEGER pcbFile) { KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle != NULL) { switch (pHandle->enmType) { case KWHANDLETYPE_FSOBJ_READ_CACHE: KWFS_LOG(("GetFileSizeEx(%p) -> TRUE, %#x [cached]\n", hFile, pHandle->u.pCachedFile->cbCached)); pcbFile->QuadPart = pHandle->u.pCachedFile->cbCached; return TRUE; case KWHANDLETYPE_TEMP_FILE: KWFS_LOG(("GetFileSizeEx(%p) -> TRUE, %#x [temp]\n", hFile, pHandle->u.pTempFile->cbFile)); pcbFile->QuadPart = pHandle->u.pTempFile->cbFile; return TRUE; case KWHANDLETYPE_OUTPUT_BUF: /* do default */ break; default: kHlpAssertFailed(); SetLastError(ERROR_INVALID_FUNCTION); return INVALID_FILE_SIZE; } } } KWFS_LOG(("GetFileSizeEx(%p,)\n", hFile)); return GetFileSizeEx(hFile, pcbFile); } /** Kernel32 - CreateFileMappingW */ static HANDLE WINAPI kwSandbox_Kernel32_CreateFileMappingW(HANDLE hFile, LPSECURITY_ATTRIBUTES pSecAttrs, DWORD fProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCWSTR pwszName) { HANDLE hMapping; KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle != NULL) { switch (pHandle->enmType) { case KWHANDLETYPE_TEMP_FILE: { PKWFSTEMPFILE pTempFile = pHandle->u.pTempFile; if ( ( fProtect == PAGE_READONLY || fProtect == PAGE_EXECUTE_READ) && dwMaximumSizeHigh == 0 && ( dwMaximumSizeLow == 0 || dwMaximumSizeLow == pTempFile->cbFile) && pwszName == NULL) { hMapping = kwFsTempFileCreateHandle(pHandle->u.pTempFile, GENERIC_READ, K_TRUE /*fMapping*/); KWFS_LOG(("CreateFileMappingW(%p, %u) -> %p [temp]\n", hFile, fProtect, hMapping)); return hMapping; } kHlpAssertMsgFailed(("fProtect=%#x cb=%#x'%08x name=%p\n", fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName)); SetLastError(ERROR_ACCESS_DENIED); return INVALID_HANDLE_VALUE; } /* moc.exe benefits from this. */ case KWHANDLETYPE_FSOBJ_READ_CACHE: { PKFSWCACHEDFILE pCachedFile = pHandle->u.pCachedFile; if ( ( fProtect == PAGE_READONLY || fProtect == PAGE_EXECUTE_READ) && dwMaximumSizeHigh == 0 && ( dwMaximumSizeLow == 0 || dwMaximumSizeLow == pCachedFile->cbCached) && pwszName == NULL) { if (kwFsObjCacheCreateFileHandle(pCachedFile, GENERIC_READ, FALSE /*fInheritHandle*/, K_FALSE /*fIsFileHandle*/, &hMapping)) { /* likely */ } else hMapping = NULL; KWFS_LOG(("CreateFileMappingW(%p, %u) -> %p [cached]\n", hFile, fProtect, hMapping)); return hMapping; } /* Do fallback (for .pch). */ kHlpAssertMsg(fProtect == PAGE_WRITECOPY, ("fProtect=%#x cb=%#x'%08x name=%p\n", fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName)); hMapping = CreateFileMappingW(hFile, pSecAttrs, fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName); KWFS_LOG(("CreateFileMappingW(%p, %p, %#x, %#x, %#x, %p) -> %p [cached-fallback]\n", hFile, pSecAttrs, fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName, hMapping)); return hMapping; } /** @todo read cached memory mapped files too for moc. */ } } } hMapping = CreateFileMappingW(hFile, pSecAttrs, fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName); KWFS_LOG(("CreateFileMappingW(%p, %p, %#x, %#x, %#x, %p) -> %p\n", hFile, pSecAttrs, fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName, hMapping)); return hMapping; } /** Kernel32 - MapViewOfFile */ static PVOID WINAPI kwSandbox_Kernel32_MapViewOfFile(HANDLE hSection, DWORD dwDesiredAccess, DWORD offFileHigh, DWORD offFileLow, SIZE_T cbToMap) { PVOID pvRet; KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hSection); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle != NULL) { KU32 idxMapping; /* * Ensure one free entry in the mapping tracking table first, * since this is common to both temporary and cached files. */ if (g_Sandbox.cMemMappings + 1 <= g_Sandbox.cMemMappingsAlloc) { /* likely */ } else { void *pvNew; KU32 cNew = g_Sandbox.cMemMappingsAlloc; if (cNew) cNew *= 2; else cNew = 32; pvNew = kHlpRealloc(g_Sandbox.paMemMappings, cNew * sizeof(g_Sandbox.paMemMappings)); if (pvNew) g_Sandbox.paMemMappings = (PKWMEMMAPPING)pvNew; else { kwErrPrintf("Failed to grow paMemMappings from %#x to %#x!\n", g_Sandbox.cMemMappingsAlloc, cNew); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return NULL; } g_Sandbox.cMemMappingsAlloc = cNew; } /* * Type specific work. */ switch (pHandle->enmType) { case KWHANDLETYPE_FSOBJ_READ_CACHE: case KWHANDLETYPE_TEMP_FILE: case KWHANDLETYPE_OUTPUT_BUF: default: kHlpAssertFailed(); SetLastError(ERROR_INVALID_OPERATION); return NULL; case KWHANDLETYPE_TEMP_FILE_MAPPING: { PKWFSTEMPFILE pTempFile = pHandle->u.pTempFile; if ( dwDesiredAccess == FILE_MAP_READ && offFileHigh == 0 && offFileLow == 0 && (cbToMap == 0 || cbToMap == pTempFile->cbFile) ) { kHlpAssert(pTempFile->cMappings == 0 || pTempFile->cSegs == 1); if (pTempFile->cSegs != 1) { KU32 iSeg; KU32 cbLeft; KU32 cbAll = pTempFile->cbFile ? (KU32)K_ALIGN_Z(pTempFile->cbFile, 0x2000) : 0x1000; KU8 *pbAll = NULL; int rc = kHlpPageAlloc((void **)&pbAll, cbAll, KPROT_READWRITE, K_FALSE); if (rc != 0) { kHlpAssertFailed(); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return NULL; } cbLeft = pTempFile->cbFile; for (iSeg = 0; iSeg < pTempFile->cSegs && cbLeft > 0; iSeg++) { KU32 cbToCopy = K_MIN(cbLeft, pTempFile->paSegs[iSeg].cbDataAlloc); kHlpMemCopy(&pbAll[pTempFile->paSegs[iSeg].offData], pTempFile->paSegs[iSeg].pbData, cbToCopy); cbLeft -= cbToCopy; } for (iSeg = 0; iSeg < pTempFile->cSegs; iSeg++) { kHlpPageFree(pTempFile->paSegs[iSeg].pbData, pTempFile->paSegs[iSeg].cbDataAlloc); pTempFile->paSegs[iSeg].pbData = NULL; pTempFile->paSegs[iSeg].cbDataAlloc = 0; } pTempFile->cSegs = 1; pTempFile->cbFileAllocated = cbAll; pTempFile->paSegs[0].cbDataAlloc = cbAll; pTempFile->paSegs[0].pbData = pbAll; pTempFile->paSegs[0].offData = 0; } pTempFile->cMappings++; kHlpAssert(pTempFile->cMappings == 1); pvRet = pTempFile->paSegs[0].pbData; KWFS_LOG(("CreateFileMappingW(%p) -> %p [temp]\n", hSection, pvRet)); break; } kHlpAssertMsgFailed(("dwDesiredAccess=%#x offFile=%#x'%08x cbToMap=%#x (cbFile=%#x)\n", dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pTempFile->cbFile)); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return NULL; } /* * This is simple in comparison to the above temporary file code. */ case KWHANDLETYPE_FSOBJ_READ_CACHE_MAPPING: { PKFSWCACHEDFILE pCachedFile = pHandle->u.pCachedFile; if ( dwDesiredAccess == FILE_MAP_READ && offFileHigh == 0 && offFileLow == 0 && (cbToMap == 0 || cbToMap == pCachedFile->cbCached) ) { pvRet = pCachedFile->pbCached; KWFS_LOG(("CreateFileMappingW(%p) -> %p [cached]\n", hSection, pvRet)); break; } kHlpAssertMsgFailed(("dwDesiredAccess=%#x offFile=%#x'%08x cbToMap=%#x (cbFile=%#x)\n", dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pCachedFile->cbCached)); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return NULL; } } /* * Insert into the mapping tracking table. This is common * and we should only get here with a non-NULL pvRet. * * Note! We could look for duplicates and do ref counting, but it's * easier to just append for now. */ kHlpAssert(pvRet != NULL); idxMapping = g_Sandbox.cMemMappings; kHlpAssert(idxMapping < g_Sandbox.cMemMappingsAlloc); g_Sandbox.paMemMappings[idxMapping].cRefs = 1; g_Sandbox.paMemMappings[idxMapping].pvMapping = pvRet; g_Sandbox.paMemMappings[idxMapping].enmType = pHandle->enmType; g_Sandbox.paMemMappings[idxMapping].u.pCachedFile = pHandle->u.pCachedFile; g_Sandbox.cMemMappings++; return pvRet; } } pvRet = MapViewOfFile(hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap); KWFS_LOG(("MapViewOfFile(%p, %#x, %#x, %#x, %#x) -> %p\n", hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pvRet)); return pvRet; } /** Kernel32 - MapViewOfFileEx */ static PVOID WINAPI kwSandbox_Kernel32_MapViewOfFileEx(HANDLE hSection, DWORD dwDesiredAccess, DWORD offFileHigh, DWORD offFileLow, SIZE_T cbToMap, PVOID pvMapAddr) { PVOID pvRet; KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hSection); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle != NULL) { switch (pHandle->enmType) { case KWHANDLETYPE_TEMP_FILE_MAPPING: KWFS_LOG(("MapViewOfFileEx(%p, %#x, %#x, %#x, %#x, %p) - temporary file!\n", hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pvMapAddr)); if (!pvMapAddr) return kwSandbox_Kernel32_MapViewOfFile(hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap); kHlpAssertFailed(); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return NULL; case KWHANDLETYPE_FSOBJ_READ_CACHE_MAPPING: KWFS_LOG(("MapViewOfFileEx(%p, %#x, %#x, %#x, %#x, %p) - read cached file!\n", hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pvMapAddr)); if (!pvMapAddr) return kwSandbox_Kernel32_MapViewOfFile(hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap); /* We can use fallback here as the handle is an actual section handle. */ break; case KWHANDLETYPE_FSOBJ_READ_CACHE: case KWHANDLETYPE_TEMP_FILE: case KWHANDLETYPE_OUTPUT_BUF: default: kHlpAssertFailed(); SetLastError(ERROR_INVALID_OPERATION); return NULL; } } } pvRet = MapViewOfFileEx(hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pvMapAddr); KWFS_LOG(("MapViewOfFileEx(%p, %#x, %#x, %#x, %#x, %p) -> %p\n", hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pvMapAddr, pvRet)); return pvRet; } /** Kernel32 - UnmapViewOfFile */ static BOOL WINAPI kwSandbox_Kernel32_UnmapViewOfFile(LPCVOID pvBase) { /* * Consult the memory mapping tracker. */ PKWMEMMAPPING paMemMappings = g_Sandbox.paMemMappings; KU32 idxMapping = g_Sandbox.cMemMappings; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); while (idxMapping-- > 0) if (paMemMappings[idxMapping].pvMapping == pvBase) { /* Type specific stuff. */ if (paMemMappings[idxMapping].enmType == KWHANDLETYPE_TEMP_FILE_MAPPING) { KWFS_LOG(("UnmapViewOfFile(%p) -> TRUE [temp]\n", pvBase)); paMemMappings[idxMapping].u.pTempFile->cMappings--; } else KWFS_LOG(("UnmapViewOfFile(%p) -> TRUE [cached]\n", pvBase)); /* Deref and probably free it. */ if (--paMemMappings[idxMapping].cRefs == 0) { g_Sandbox.cMemMappings--; if (idxMapping != g_Sandbox.cMemMappings) paMemMappings[idxMapping] = paMemMappings[g_Sandbox.cMemMappings]; } return TRUE; } KWFS_LOG(("UnmapViewOfFile(%p)\n", pvBase)); return UnmapViewOfFile(pvBase); } /** @todo UnmapViewOfFileEx */ #endif /* WITH_TEMP_MEMORY_FILES */ /** Kernel32 - DuplicateHandle */ static BOOL WINAPI kwSandbox_Kernel32_DuplicateHandle(HANDLE hSrcProc, HANDLE hSrc, HANDLE hDstProc, PHANDLE phNew, DWORD dwDesiredAccess, BOOL fInheritHandle, DWORD dwOptions) { BOOL fRet; /* * We must catch our handles being duplicated. */ if (hSrcProc == GetCurrentProcess()) { KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hSrc); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle) { fRet = DuplicateHandle(hSrcProc, hSrc, hDstProc, phNew, dwDesiredAccess, fInheritHandle, dwOptions); if (fRet) { if (kwSandboxHandleTableEnter(&g_Sandbox, pHandle, *phNew)) { pHandle->cRefs++; KWFS_LOG(("DuplicateHandle(%p, %p, %p, , %#x, %d, %#x) -> TRUE, %p [intercepted handle] enmType=%d cRef=%d\n", hSrcProc, hSrc, hDstProc, dwDesiredAccess, fInheritHandle, dwOptions, *phNew, pHandle->enmType, pHandle->cRefs)); } else { fRet = FALSE; SetLastError(ERROR_NOT_ENOUGH_MEMORY); KWFS_LOG(("DuplicateHandle(%p, %p, %p, , %#x, %d, %#x) -> !FALSE!, %p [intercepted handle] enmType=%d\n", hSrcProc, hSrc, hDstProc, dwDesiredAccess, fInheritHandle, dwOptions, *phNew, pHandle->enmType)); } } else KWFS_LOG(("DuplicateHandle(%p, %p, %p, , %#x, %d, %#x) -> FALSE [intercepted handle] enmType=%d\n", hSrcProc, hSrc, hDstProc, dwDesiredAccess, fInheritHandle, dwOptions, pHandle->enmType)); return fRet; } } } /* * Not one of ours, just do what the caller asks and log it. */ fRet = DuplicateHandle(hSrcProc, hSrc, hDstProc, phNew, dwDesiredAccess, fInheritHandle, dwOptions); KWFS_LOG(("DuplicateHandle(%p, %p, %p, , %#x, %d, %#x) -> %d, %p\n", hSrcProc, hSrc, hDstProc, dwDesiredAccess, fInheritHandle, dwOptions, fRet, *phNew)); return fRet; } /** Kernel32 - CloseHandle */ static BOOL WINAPI kwSandbox_Kernel32_CloseHandle(HANDLE hObject) { BOOL fRet; KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hObject); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread || g_fCtrlC); if (idxHandle < g_Sandbox.cHandles) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; if (pHandle) { /* Prevent the closing of the standard output and error handles. */ if ( pHandle->enmType != KWHANDLETYPE_OUTPUT_BUF || idxHandle != KW_HANDLE_TO_INDEX(pHandle->hHandle)) { fRet = CloseHandle(hObject); if (fRet) { PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle]; g_Sandbox.papHandles[idxHandle] = NULL; g_Sandbox.cActiveHandles--; kHlpAssert(g_Sandbox.cActiveHandles >= g_Sandbox.cFixedHandles); if (--pHandle->cRefs == 0) { #ifdef WITH_TEMP_MEMORY_FILES if (pHandle->enmType == KWHANDLETYPE_TEMP_FILE) { kHlpAssert(pHandle->u.pTempFile->cActiveHandles > 0); pHandle->u.pTempFile->cActiveHandles--; } #endif kHlpFree(pHandle); KWFS_LOG(("CloseHandle(%p) -> TRUE [intercepted handle, freed]\n", hObject)); } else KWFS_LOG(("CloseHandle(%p) -> TRUE [intercepted handle, not freed]\n", hObject)); } else KWFS_LOG(("CloseHandle(%p) -> FALSE [intercepted handle] err=%u!\n", hObject, GetLastError())); } else { KWFS_LOG(("CloseHandle(%p) -> TRUE [intercepted handle] Ignored closing of std%s!\n", hObject, hObject == g_Sandbox.StdErr.hOutput ? "err" : "out")); fRet = TRUE; } return fRet; } } fRet = CloseHandle(hObject); KWFS_LOG(("CloseHandle(%p) -> %d\n", hObject, fRet)); return fRet; } /** Kernel32 - GetFileAttributesA. */ static DWORD WINAPI kwSandbox_Kernel32_GetFileAttributesA(LPCSTR pszFilename) { DWORD fRet; const char *pszExt = kHlpGetExt(pszFilename); if (kwFsIsCacheableExtensionA(pszExt, K_TRUE /*fAttrQuery*/)) { KFSLOOKUPERROR enmError; PKFSOBJ pFsObj; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pFsObj = kFsCacheLookupNoMissingA(g_pFsCache, pszFilename, &enmError); if (pFsObj) { kHlpAssert(pFsObj->fHaveStats); fRet = pFsObj->Stats.st_attribs; kFsCacheObjRelease(g_pFsCache, pFsObj); } else { SetLastError(kwFsLookupErrorToWindowsError(enmError)); fRet = INVALID_FILE_ATTRIBUTES; } KWFS_LOG(("GetFileAttributesA(%s) -> %#x [cached]\n", pszFilename, fRet)); return fRet; } fRet = GetFileAttributesA(pszFilename); KWFS_LOG(("GetFileAttributesA(%s) -> %#x\n", pszFilename, fRet)); return fRet; } /** Kernel32 - GetFileAttributesW. */ static DWORD WINAPI kwSandbox_Kernel32_GetFileAttributesW(LPCWSTR pwszFilename) { DWORD fRet; if (kwFsIsCacheablePathExtensionW(pwszFilename, K_TRUE /*fAttrQuery*/)) { KFSLOOKUPERROR enmError; PKFSOBJ pFsObj; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pFsObj = kFsCacheLookupNoMissingW(g_pFsCache, pwszFilename, &enmError); if (pFsObj) { kHlpAssert(pFsObj->fHaveStats); fRet = pFsObj->Stats.st_attribs; kFsCacheObjRelease(g_pFsCache, pFsObj); } else { SetLastError(kwFsLookupErrorToWindowsError(enmError)); fRet = INVALID_FILE_ATTRIBUTES; } KWFS_LOG(("GetFileAttributesW(%ls) -> %#x [cached]\n", pwszFilename, fRet)); return fRet; } fRet = GetFileAttributesW(pwszFilename); KWFS_LOG(("GetFileAttributesW(%ls) -> %#x\n", pwszFilename, fRet)); return fRet; } /** Kernel32 - GetShortPathNameW - c1[xx].dll of VS2010 does this to the * directory containing each include file. We cache the result to speed * things up a little. */ static DWORD WINAPI kwSandbox_Kernel32_GetShortPathNameW(LPCWSTR pwszLongPath, LPWSTR pwszShortPath, DWORD cwcShortPath) { DWORD cwcRet; if (kwFsIsCacheablePathExtensionW(pwszLongPath, K_TRUE /*fAttrQuery*/)) { KFSLOOKUPERROR enmError; PKFSOBJ pObj; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pObj = kFsCacheLookupW(g_pFsCache, pwszLongPath, &enmError); if (pObj) { if (pObj->bObjType != KFSOBJ_TYPE_MISSING) { if (kFsCacheObjGetFullShortPathW(pObj, pwszShortPath, cwcShortPath, '\\')) { cwcRet = (DWORD)kwUtf16Len(pwszShortPath); /* Should preserve trailing slash on directory paths. */ if (pObj->bObjType == KFSOBJ_TYPE_DIR) { if ( cwcRet + 1 < cwcShortPath && pwszShortPath[cwcRet - 1] != '\\') { KSIZE cwcIn = kwUtf16Len(pwszLongPath); if ( cwcIn > 0 && (pwszLongPath[cwcIn - 1] == '\\' || pwszLongPath[cwcIn - 1] == '/') ) { pwszShortPath[cwcRet++] = '\\'; pwszShortPath[cwcRet] = '\0'; } } } KWFS_LOG(("GetShortPathNameW(%ls) -> '%*.*ls' & %#x [cached]\n", pwszLongPath, K_MIN(cwcShortPath, cwcRet), K_MIN(cwcShortPath, cwcRet), pwszShortPath, cwcRet)); kFsCacheObjRelease(g_pFsCache, pObj); return cwcRet; } /* fall back for complicated cases. */ } kFsCacheObjRelease(g_pFsCache, pObj); } } cwcRet = GetShortPathNameW(pwszLongPath, pwszShortPath, cwcShortPath); KWFS_LOG(("GetShortPathNameW(%ls) -> '%*.*ls' & %#x\n", pwszLongPath, K_MIN(cwcShortPath, cwcRet), K_MIN(cwcShortPath, cwcRet), pwszShortPath, cwcRet)); return cwcRet; } #ifdef WITH_TEMP_MEMORY_FILES /** Kernel32 - DeleteFileW * Skip deleting the in-memory files. */ static BOOL WINAPI kwSandbox_Kernel32_DeleteFileW(LPCWSTR pwszFilename) { BOOL fRc; if ( g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL && kwFsIsClTempFileW(pwszFilename)) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); KWFS_LOG(("DeleteFileW(%s) -> TRUE [temp]\n", pwszFilename)); fRc = TRUE; } else { fRc = DeleteFileW(pwszFilename); KWFS_LOG(("DeleteFileW(%s) -> %d (%d)\n", pwszFilename, fRc, GetLastError())); } return fRc; } #endif /* WITH_TEMP_MEMORY_FILES */ #ifdef WITH_CONSOLE_OUTPUT_BUFFERING /* * * Console output buffering. * Console output buffering. * Console output buffering. * */ /** * Write a wide char string to the console. * * @param pSandbox The sandbox which output buffer to flush. */ static void kwSandboxConsoleWriteIt(PKWSANDBOX pSandbox, wchar_t const *pwcBuf, KU32 cwcToWrite) { if (cwcToWrite > 0) { DWORD cwcWritten = 0; if (WriteConsoleW(pSandbox->Combined.hOutput, pwcBuf, cwcToWrite, &cwcWritten, NULL)) { if (cwcWritten == cwcToWrite) { /* likely */ } else { DWORD off = 0; do { off += cwcWritten; cwcWritten = 0; } while ( off < cwcToWrite && WriteConsoleW(pSandbox->Combined.hOutput, &pwcBuf[off], cwcToWrite - off, &cwcWritten, NULL)); kHlpAssert(off == cwcWritten); } } else kHlpAssertFailed(); pSandbox->Combined.cFlushes++; } } /** * Flushes the combined console output buffer. * * @param pSandbox The sandbox which output buffer to flush. */ static void kwSandboxConsoleFlushCombined(PKWSANDBOX pSandbox) { if (pSandbox->Combined.cwcBuf > 0) { KWOUT_LOG(("kwSandboxConsoleFlushCombined: %u wchars\n", pSandbox->Combined.cwcBuf)); kwSandboxConsoleWriteIt(pSandbox, pSandbox->Combined.wszBuf, pSandbox->Combined.cwcBuf); pSandbox->Combined.cwcBuf = 0; } } /** * For handling combined buffer overflow cases line by line. * * @param pSandbox The sandbox. * @param pwcBuf What to add to the combined buffer. Usually a * line, unless we're really low on buffer space. * @param cwcBuf The length of what to add. * @param fBrokenLine Whether this is a broken line. */ static void kwSandboxConsoleAddToCombined(PKWSANDBOX pSandbox, wchar_t const *pwcBuf, KU32 cwcBuf, KBOOL fBrokenLine) { if (fBrokenLine) kwSandboxConsoleFlushCombined(pSandbox); if (pSandbox->Combined.cwcBuf + cwcBuf > K_ELEMENTS(pSandbox->Combined.wszBuf)) { kwSandboxConsoleFlushCombined(pSandbox); kwSandboxConsoleWriteIt(pSandbox, pwcBuf, cwcBuf); } else { kHlpMemCopy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf], pwcBuf, cwcBuf * sizeof(wchar_t)); pSandbox->Combined.cwcBuf += cwcBuf; } } /** * Called to final flush a line buffer via the combined buffer (if applicable). * * @param pSandbox The sandbox. * @param pLineBuf The line buffer. * @param pszName The line buffer name (for logging) */ static void kwSandboxConsoleFinalFlushLineBuf(PKWSANDBOX pSandbox, PKWOUTPUTSTREAMBUF pLineBuf, const char *pszName) { if (pLineBuf->fIsConsole) { if (pLineBuf->u.Con.cwcBuf > 0) { KWOUT_LOG(("kwSandboxConsoleFinalFlushLineBuf: %s: %u wchars\n", pszName, pLineBuf->u.Con.cwcBuf)); if (pLineBuf->u.Con.cwcBuf < pLineBuf->u.Con.cwcBufAlloc) { pLineBuf->u.Con.pwcBuf[pLineBuf->u.Con.cwcBuf++] = '\n'; kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->u.Con.pwcBuf, pLineBuf->u.Con.cwcBuf, K_FALSE /*fBrokenLine*/); } else { kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->u.Con.pwcBuf, pLineBuf->u.Con.cwcBuf, K_TRUE /*fBrokenLine*/); kwSandboxConsoleAddToCombined(pSandbox, L"\n", 1, K_TRUE /*fBrokenLine*/); } pLineBuf->u.Con.cwcBuf = 0; } } #ifdef WITH_STD_OUT_ERR_BUFFERING else if (pLineBuf->u.Fully.cchBuf > 0) { KWOUT_LOG(("kwSandboxConsoleFinalFlushLineBuf: %s: %u bytes\n", pszName, pLineBuf->u.Fully.cchBuf)); kwSandboxOutBufWriteIt(pLineBuf->hBackup, pLineBuf->u.Fully.pchBuf, pLineBuf->u.Fully.cchBuf); pLineBuf->u.Fully.cchBuf = 0; } #endif } /** * Called at the end of sandboxed execution to flush both stream buffers. * * @param pSandbox The sandbox. */ static void kwSandboxConsoleFlushAll(PKWSANDBOX pSandbox) { /* * First do the cl.exe source file supression trick, if applicable. * The output ends up on CONOUT$ if either StdOut or StdErr is a console * handle. */ if ( pSandbox->pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL && pSandbox->Combined.cFlushes == 0) { if ( pSandbox->StdOut.fIsConsole || pSandbox->StdErr.fIsConsole) { if ( pSandbox->Combined.cwcBuf >= 3 && (pSandbox->StdOut.fIsConsole ? pSandbox->StdOut.u.Con.cwcBuf : pSandbox->StdOut.u.Fully.cchBuf) == 0 && (pSandbox->StdErr.fIsConsole ? pSandbox->StdErr.u.Con.cwcBuf : pSandbox->StdErr.u.Fully.cchBuf) == 0 ) { KI32 off = pSandbox->Combined.cwcBuf - 1; if (pSandbox->Combined.wszBuf[off] == '\n') { KBOOL fOk = K_TRUE; while (off-- > 0) { wchar_t const wc = pSandbox->Combined.wszBuf[off]; if (iswalnum(wc) || wc == '.' || wc == ' ' || wc == '_' || wc == '-') { /* likely */ } else { fOk = K_FALSE; break; } } if (fOk) { KWOUT_LOG(("kwSandboxConsoleFlushAll: Dropping '%*.*ls in combined console buffer\n", pSandbox->Combined.cwcBuf, pSandbox->Combined.cwcBuf, pSandbox->Combined.wszBuf)); pSandbox->Combined.cwcBuf = 0; return; } } KWOUT_LOG(("kwSandboxConsoleFlushAll: Unable to drop '%*.*ls in combined console buffer\n", pSandbox->Combined.cwcBuf, pSandbox->Combined.cwcBuf, pSandbox->Combined.wszBuf)); } } #ifdef WITH_STD_OUT_ERR_BUFFERING /* * Otherwise, it goes to standard output (redirected). */ else if ( pSandbox->StdErr.u.Fully.cchBuf == 0 && pSandbox->StdOut.u.Fully.cchBuf >= 3) { char const *pchBuf = pSandbox->StdOut.u.Fully.pchBuf; KI32 off = pSandbox->StdOut.u.Fully.cchBuf - 1; kHlpAssert(pSandbox->Combined.cFlushes == 0 && pSandbox->Combined.cwcBuf == 0); /* unused! */ if (pchBuf[off] == '\n') { KBOOL fOk = K_TRUE; if (pchBuf[off - 1] == '\r') off--; while (off-- > 0) { char const ch = pchBuf[off]; if (isalnum(ch) || ch == '.' || ch == ' ' || ch == '_' || ch == '-') { /* likely */ } else { fOk = K_FALSE; break; } } if (fOk) { KWOUT_LOG(("kwSandboxConsoleFlushAll: Dropping '%*.*s in stdout buffer\n", pSandbox->StdOut.u.Fully.cchBuf, pSandbox->StdOut.u.Fully.cchBuf, pchBuf)); pSandbox->StdOut.u.Fully.cchBuf = 0; return; } } KWOUT_LOG(("kwSandboxConsoleFlushAll: Unable to drop '%*.*s in stdout buffer\n", pSandbox->StdOut.u.Fully.cchBuf, pSandbox->StdOut.u.Fully.cchBuf, pchBuf)); } #endif } /* * Flush the two line buffer, the the combined buffer. */ kwSandboxConsoleFinalFlushLineBuf(pSandbox, &pSandbox->StdErr, "StdErr"); kwSandboxConsoleFinalFlushLineBuf(pSandbox, &pSandbox->StdOut, "StdOut"); kwSandboxConsoleFlushCombined(pSandbox); } /** * Writes a string to the given output stream. * * @param pSandbox The sandbox. * @param pLineBuf The line buffer for the output stream. * @param pwcBuffer The buffer to write. * @param cwcToWrite The number of wchar_t's in the buffer. */ static void kwSandboxConsoleWriteW(PKWSANDBOX pSandbox, PKWOUTPUTSTREAMBUF pLineBuf, wchar_t const *pwcBuffer, KU32 cwcToWrite) { kHlpAssert(pLineBuf->fIsConsole); if (cwcToWrite > 0) { /* * First, find the start of the last incomplete line so we can figure * out how much line buffering we need to do. */ KU32 cchLastIncompleteLine; KU32 offLastIncompleteLine = cwcToWrite; while ( offLastIncompleteLine > 0 && pwcBuffer[offLastIncompleteLine - 1] != '\n') offLastIncompleteLine--; cchLastIncompleteLine = cwcToWrite - offLastIncompleteLine; /* Was there anything to line buffer? */ if (offLastIncompleteLine < cwcToWrite) { /* Need to grow the line buffer? */ KU32 cwcNeeded = offLastIncompleteLine == 0 ? pLineBuf->u.Con.cwcBuf + cchLastIncompleteLine /* incomplete line, append to line buffer */ : cchLastIncompleteLine; /* Only the final incomplete line (if any) goes to the line buffer. */ if (cwcNeeded > pLineBuf->u.Con.cwcBufAlloc) { void *pvNew; KU32 cwcNew = !pLineBuf->u.Con.cwcBufAlloc ? 1024 : pLineBuf->u.Con.cwcBufAlloc * 2; while (cwcNew < cwcNeeded) cwcNew *= 2; pvNew = kHlpRealloc(pLineBuf->u.Con.pwcBuf, cwcNew * sizeof(wchar_t)); if (pvNew) { pLineBuf->u.Con.pwcBuf = (wchar_t *)pvNew; pLineBuf->u.Con.cwcBufAlloc = cwcNew; } else { pvNew = kHlpRealloc(pLineBuf->u.Con.pwcBuf, cwcNeeded * sizeof(wchar_t)); if (pvNew) { pLineBuf->u.Con.pwcBuf = (wchar_t *)pvNew; pLineBuf->u.Con.cwcBufAlloc = cwcNeeded; } else { /* This isn't perfect, but it will have to do for now. */ if (pLineBuf->u.Con.cwcBuf > 0) { kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->u.Con.pwcBuf, pLineBuf->u.Con.cwcBuf, K_TRUE /*fBrokenLine*/); pLineBuf->u.Con.cwcBuf = 0; } kwSandboxConsoleAddToCombined(pSandbox, pwcBuffer, cwcToWrite, K_TRUE /*fBrokenLine*/); return; } } } /* * Handle the case where we only add to the line buffer. */ if (offLastIncompleteLine == 0) { kHlpMemCopy(&pLineBuf->u.Con.pwcBuf[pLineBuf->u.Con.cwcBuf], pwcBuffer, cwcToWrite * sizeof(wchar_t)); pLineBuf->u.Con.cwcBuf += cwcToWrite; return; } } /* * If there is sufficient combined buffer to handle this request, this is rather simple. */ kHlpAssert(pSandbox->Combined.cwcBuf <= K_ELEMENTS(pSandbox->Combined.wszBuf)); if (pSandbox->Combined.cwcBuf + pLineBuf->u.Con.cwcBuf + offLastIncompleteLine <= K_ELEMENTS(pSandbox->Combined.wszBuf)) { if (pLineBuf->u.Con.cwcBuf > 0) { kHlpMemCopy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf], pLineBuf->u.Con.pwcBuf, pLineBuf->u.Con.cwcBuf * sizeof(wchar_t)); pSandbox->Combined.cwcBuf += pLineBuf->u.Con.cwcBuf; pLineBuf->u.Con.cwcBuf = 0; } kHlpMemCopy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf], pwcBuffer, offLastIncompleteLine * sizeof(wchar_t)); pSandbox->Combined.cwcBuf += offLastIncompleteLine; } else { /* * Do line-by-line processing of the input, flusing the combined buffer * when it becomes necessary. We may have to write lines */ KU32 off = 0; KU32 offNextLine = 0; /* If there are buffered chars, we handle the first line outside the main loop. We must try our best outputting it as a complete line. */ if (pLineBuf->u.Con.cwcBuf > 0) { while (offNextLine < cwcToWrite && pwcBuffer[offNextLine] != '\n') offNextLine++; offNextLine++; kHlpAssert(offNextLine <= offLastIncompleteLine); if (pSandbox->Combined.cwcBuf + pLineBuf->u.Con.cwcBuf + offNextLine <= K_ELEMENTS(pSandbox->Combined.wszBuf)) { kHlpMemCopy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf], pLineBuf->u.Con.pwcBuf, pLineBuf->u.Con.cwcBuf * sizeof(wchar_t)); pSandbox->Combined.cwcBuf += pLineBuf->u.Con.cwcBuf; pLineBuf->u.Con.cwcBuf = 0; kHlpMemCopy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf], pwcBuffer, offNextLine * sizeof(wchar_t)); pSandbox->Combined.cwcBuf += offNextLine; } else { KU32 cwcLeft = pLineBuf->u.Con.cwcBufAlloc - pLineBuf->u.Con.cwcBuf; if (cwcLeft > 0) { KU32 cwcCopy = K_MIN(cwcLeft, offNextLine); kHlpMemCopy(&pLineBuf->u.Con.pwcBuf[pLineBuf->u.Con.cwcBuf], pwcBuffer, cwcCopy * sizeof(wchar_t)); pLineBuf->u.Con.cwcBuf += cwcCopy; off += cwcCopy; } if (pLineBuf->u.Con.cwcBuf > 0) { kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->u.Con.pwcBuf, pLineBuf->u.Con.cwcBuf, K_TRUE /*fBrokenLine*/); pLineBuf->u.Con.cwcBuf = 0; } if (off < offNextLine) kwSandboxConsoleAddToCombined(pSandbox, &pwcBuffer[off], offNextLine - off, K_TRUE /*fBrokenLine*/); } off = offNextLine; } /* Deal with the remaining lines */ while (off < offLastIncompleteLine) { while (offNextLine < offLastIncompleteLine && pwcBuffer[offNextLine] != '\n') offNextLine++; offNextLine++; kHlpAssert(offNextLine <= offLastIncompleteLine); kwSandboxConsoleAddToCombined(pSandbox, &pwcBuffer[off], offNextLine - off, K_FALSE /*fBrokenLine*/); off = offNextLine; } } /* * Buffer any remaining incomplete line chars. */ if (cchLastIncompleteLine) { kHlpMemCopy(&pLineBuf->u.Con.pwcBuf[0], &pwcBuffer[offLastIncompleteLine], cchLastIncompleteLine * sizeof(wchar_t)); pLineBuf->u.Con.cwcBuf = cchLastIncompleteLine; } } } /** * Worker for WriteConsoleA and WriteFile. * * @param pSandbox The sandbox. * @param pLineBuf The line buffer. * @param pchBuffer What to write. * @param cchToWrite How much to write. */ static void kwSandboxConsoleWriteA(PKWSANDBOX pSandbox, PKWOUTPUTSTREAMBUF pLineBuf, const char *pchBuffer, KU32 cchToWrite) { /* * Convert it to wide char and use the 'W' to do the work. */ int cwcRet; KU32 cwcBuf = cchToWrite * 2 + 1; wchar_t *pwcBufFree = NULL; wchar_t *pwcBuf; kHlpAssert(pLineBuf->fIsConsole); if (cwcBuf <= 4096) pwcBuf = alloca(cwcBuf * sizeof(wchar_t)); else pwcBuf = pwcBufFree = kHlpAlloc(cwcBuf * sizeof(wchar_t)); cwcRet = MultiByteToWideChar(pSandbox->Combined.uCodepage, 0/*dwFlags*/, pchBuffer, cchToWrite, pwcBuf, cwcBuf); if (cwcRet > 0) kwSandboxConsoleWriteW(pSandbox, pLineBuf, pwcBuf, cwcRet); else { DWORD cchWritten; kHlpAssertFailed(); /* Flush the line buffer and combined buffer before calling WriteConsoleA. */ if (pLineBuf->u.Con.cwcBuf > 0) { kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->u.Con.pwcBuf, pLineBuf->u.Con.cwcBuf, K_TRUE /*fBroken*/); pLineBuf->u.Con.cwcBuf = 0; } kwSandboxConsoleFlushCombined(pSandbox); if (WriteConsoleA(pLineBuf->hBackup, pchBuffer, cchToWrite, &cchWritten, NULL /*pvReserved*/)) { if (cchWritten >= cchToWrite) { /* likely */ } else { KU32 off = 0; do { off += cchWritten; cchWritten = 0; } while ( off < cchToWrite && WriteConsoleA(pLineBuf->hBackup, &pchBuffer[off], cchToWrite - off, &cchWritten, NULL)); } } } if (pwcBufFree) kHlpFree(pwcBufFree); } /** Kernel32 - WriteConsoleA */ BOOL WINAPI kwSandbox_Kernel32_WriteConsoleA(HANDLE hConOutput, CONST VOID *pvBuffer, DWORD cbToWrite, PDWORD pcbWritten, PVOID pvReserved) { BOOL fRc; PKWOUTPUTSTREAMBUF pLineBuf; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (hConOutput == g_Sandbox.StdErr.hOutput) pLineBuf = &g_Sandbox.StdErr; else pLineBuf = &g_Sandbox.StdOut; if (pLineBuf->fIsConsole) { kwSandboxConsoleWriteA(&g_Sandbox, pLineBuf, (char const *)pvBuffer, cbToWrite); KWOUT_LOG(("WriteConsoleA: %p, %p LB %#x (%*.*s), %p, %p -> TRUE [cached]\n", hConOutput, pvBuffer, cbToWrite, cbToWrite, cbToWrite, pvBuffer, pcbWritten, pvReserved)); if (pcbWritten) *pcbWritten = cbToWrite; fRc = TRUE; } else { fRc = WriteConsoleA(hConOutput, pvBuffer, cbToWrite, pcbWritten, pvReserved); KWOUT_LOG(("WriteConsoleA: %p, %p LB %#x (%*.*s), %p, %p -> %d !fallback!\n", hConOutput, pvBuffer, cbToWrite, cbToWrite, cbToWrite, pvBuffer, pcbWritten, pvReserved, fRc)); } return fRc; } /** Kernel32 - WriteConsoleW */ BOOL WINAPI kwSandbox_Kernel32_WriteConsoleW(HANDLE hConOutput, CONST VOID *pvBuffer, DWORD cwcToWrite, PDWORD pcwcWritten, PVOID pvReserved) { BOOL fRc; PKWOUTPUTSTREAMBUF pLineBuf; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (hConOutput == g_Sandbox.StdErr.hOutput) pLineBuf = &g_Sandbox.StdErr; else if (hConOutput == g_Sandbox.StdOut.hOutput) pLineBuf = &g_Sandbox.StdOut; else pLineBuf = g_Sandbox.StdErr.fIsConsole ? &g_Sandbox.StdErr : &g_Sandbox.StdOut; if (pLineBuf->fIsConsole) { kwSandboxConsoleWriteW(&g_Sandbox, pLineBuf, (wchar_t const *)pvBuffer, cwcToWrite); KWOUT_LOG(("WriteConsoleW: %p, %p LB %#x (%*.*ls), %p, %p -> TRUE [cached]\n", hConOutput, pvBuffer, cwcToWrite, cwcToWrite, cwcToWrite, pvBuffer, pcwcWritten, pvReserved)); if (pcwcWritten) *pcwcWritten = cwcToWrite; fRc = TRUE; } else { fRc = WriteConsoleW(hConOutput, pvBuffer, cwcToWrite, pcwcWritten, pvReserved); KWOUT_LOG(("WriteConsoleW: %p, %p LB %#x (%*.*ls), %p, %p -> %d !fallback!\n", hConOutput, pvBuffer, cwcToWrite, cwcToWrite, cwcToWrite, pvBuffer, pcwcWritten, pvReserved, fRc)); } return fRc; } #endif /* WITH_CONSOLE_OUTPUT_BUFFERING */ /* * * Virtual memory leak prevension. * Virtual memory leak prevension. * Virtual memory leak prevension. * */ #ifdef WITH_FIXED_VIRTUAL_ALLOCS /** For debug logging. */ # ifndef NDEBUG static void kwSandboxLogFixedAllocation(KU32 idxFixed, const char *pszWhere) { MEMORY_BASIC_INFORMATION MemInfo = { NULL, NULL, 0, 0, 0, 0, 0}; SIZE_T cbMemInfo = VirtualQuery(g_aFixedVirtualAllocs[idxFixed].pvReserved, &MemInfo, sizeof(MemInfo)); kHlpAssert(cbMemInfo == sizeof(MemInfo)); if (cbMemInfo != 0) KW_LOG(("%s: #%u %p LB %#x: base=%p alloc=%p region=%#x state=%#x prot=%#x type=%#x\n", pszWhere, idxFixed, g_aFixedVirtualAllocs[idxFixed].pvReserved, g_aFixedVirtualAllocs[idxFixed].cbFixed, MemInfo.BaseAddress, MemInfo.AllocationBase, MemInfo.RegionSize, MemInfo.State, MemInfo.Protect, MemInfo.Type)); } # else # define kwSandboxLogFixedAllocation(idxFixed, pszWhere) do { } while (0) # endif /** * Used by both kwSandbox_Kernel32_VirtualFree and kwSandboxCleanupLate * * @param idxFixed The fixed allocation index to "free". */ static void kwSandboxResetFixedAllocation(KU32 idxFixed) { BOOL fRc; kwSandboxLogFixedAllocation(idxFixed, "kwSandboxResetFixedAllocation[pre]"); fRc = VirtualFree(g_aFixedVirtualAllocs[idxFixed].pvReserved, g_aFixedVirtualAllocs[idxFixed].cbFixed, MEM_DECOMMIT); kHlpAssert(fRc); K_NOREF(fRc); kwSandboxLogFixedAllocation(idxFixed, "kwSandboxResetFixedAllocation[pst]"); g_aFixedVirtualAllocs[idxFixed].fInUse = K_FALSE; } #endif /* WITH_FIXED_VIRTUAL_ALLOCS */ /** Kernel32 - VirtualAlloc - for managing cl.exe / c1[xx].dll heap with fixed * location (~78MB in 32-bit 2010 compiler). */ static PVOID WINAPI kwSandbox_Kernel32_VirtualAlloc(PVOID pvAddr, SIZE_T cb, DWORD fAllocType, DWORD fProt) { PVOID pvMem; if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL) { KU32 idxPreAllocated = KU32_MAX; #ifdef WITH_FIXED_VIRTUAL_ALLOCS /* * Look for a pre-reserved CL.exe heap allocation. */ pvMem = NULL; if ( pvAddr != 0 && (fAllocType & MEM_RESERVE)) { KU32 idxFixed = K_ELEMENTS(g_aFixedVirtualAllocs); kHlpAssert(!(fAllocType & ~(MEM_RESERVE | MEM_TOP_DOWN))); while (idxFixed-- > 0) if ( g_aFixedVirtualAllocs[idxFixed].uFixed == (KUPTR)pvAddr && g_aFixedVirtualAllocs[idxFixed].pvReserved) { if (g_aFixedVirtualAllocs[idxFixed].cbFixed >= cb) { if (!g_aFixedVirtualAllocs[idxFixed].fInUse) { g_aFixedVirtualAllocs[idxFixed].fInUse = K_TRUE; pvMem = pvAddr; idxPreAllocated = idxFixed; KW_LOG(("VirtualAlloc: pvAddr=%p cb=%p type=%#x prot=%#x -> %p [pre allocated]\n", pvAddr, cb, fAllocType, fProt, pvMem)); kwSandboxLogFixedAllocation(idxFixed, "kwSandbox_Kernel32_VirtualAlloc"); SetLastError(NO_ERROR); break; } kwErrPrintf("VirtualAlloc: Fixed allocation at %p is already in use!\n", pvAddr); } else kwErrPrintf("VirtualAlloc: Fixed allocation at %p LB %#x not large enough: %#x\n", pvAddr, g_aFixedVirtualAllocs[idxFixed].cbFixed, cb); } } if (!pvMem) #endif { pvMem = VirtualAlloc(pvAddr, cb, fAllocType, fProt); KW_LOG(("VirtualAlloc: pvAddr=%p cb=%p type=%#x prot=%#x -> %p (last=%d)\n", pvAddr, cb, fAllocType, fProt, pvMem, GetLastError())); if (pvAddr && pvAddr != pvMem) kwErrPrintf("VirtualAlloc %p LB %#x (%#x,%#x) failed: %p / %u\n", pvAddr, cb, fAllocType, fProt, pvMem, GetLastError()); } if (pvMem) { /* * Track it. */ PKWVIRTALLOC pTracker; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pTracker = g_Sandbox.pVirtualAllocHead; while ( pTracker && (KUPTR)pvMem - (KUPTR)pTracker->pvAlloc >= pTracker->cbAlloc) pTracker = pTracker->pNext; if (!pTracker) { DWORD dwErr = GetLastError(); PKWVIRTALLOC pTracker = (PKWVIRTALLOC)kHlpAlloc(sizeof(*pTracker)); if (pTracker) { pTracker->pvAlloc = pvMem; pTracker->cbAlloc = cb; pTracker->idxPreAllocated = idxPreAllocated; pTracker->pNext = g_Sandbox.pVirtualAllocHead; g_Sandbox.pVirtualAllocHead = pTracker; } SetLastError(dwErr); } } } else pvMem = VirtualAlloc(pvAddr, cb, fAllocType, fProt); KW_LOG(("VirtualAlloc: pvAddr=%p cb=%p type=%#x prot=%#x -> %p (last=%d)\n", pvAddr, cb, fAllocType, fProt, pvMem, GetLastError())); return pvMem; } /** Kernel32 - VirtualFree. */ static BOOL WINAPI kwSandbox_Kernel32_VirtualFree(PVOID pvAddr, SIZE_T cb, DWORD dwFreeType) { BOOL fRc; if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (dwFreeType & MEM_RELEASE) { PKWVIRTALLOC pTracker = g_Sandbox.pVirtualAllocHead; if (pTracker) { if (pTracker->pvAlloc == pvAddr) g_Sandbox.pVirtualAllocHead = pTracker->pNext; else { PKWVIRTALLOC pPrev; do { pPrev = pTracker; pTracker = pTracker->pNext; } while (pTracker && pTracker->pvAlloc != pvAddr); if (pTracker) pPrev->pNext = pTracker->pNext; } if (pTracker) { #ifdef WITH_FIXED_VIRTUAL_ALLOCS if (pTracker->idxPreAllocated != KU32_MAX) { kwSandboxResetFixedAllocation(pTracker->idxPreAllocated); KW_LOG(("VirtualFree: pvAddr=%p cb=%p type=%#x -> TRUE [pre allocated #%u]\n", pvAddr, cb, dwFreeType, pTracker->idxPreAllocated)); kHlpFree(pTracker); return TRUE; } #endif fRc = VirtualFree(pvAddr, cb, dwFreeType); if (fRc) kHlpFree(pTracker); else { pTracker->pNext = g_Sandbox.pVirtualAllocHead; g_Sandbox.pVirtualAllocHead = pTracker; } KW_LOG(("VirtualFree: pvAddr=%p cb=%p type=%#x -> %d\n", pvAddr, cb, dwFreeType, fRc)); return fRc; } KW_LOG(("VirtualFree: pvAddr=%p not found!\n", pvAddr)); } } } #ifdef WITH_FIXED_VIRTUAL_ALLOCS /* * Protect our fixed allocations (this isn't just paranoia, btw.). */ if (dwFreeType & MEM_RELEASE) { KU32 idxFixed = K_ELEMENTS(g_aFixedVirtualAllocs); while (idxFixed-- > 0) if (g_aFixedVirtualAllocs[idxFixed].pvReserved == pvAddr) { KW_LOG(("VirtualFree: Damn it! Don't free g_aFixedVirtualAllocs[#%u]: %p LB %#x\n", idxFixed, g_aFixedVirtualAllocs[idxFixed].pvReserved, g_aFixedVirtualAllocs[idxFixed].cbFixed)); return TRUE; } } #endif /* * Not tracker or not actually free the virtual range. */ fRc = VirtualFree(pvAddr, cb, dwFreeType); KW_LOG(("VirtualFree: pvAddr=%p cb=%p type=%#x -> %d\n", pvAddr, cb, dwFreeType, fRc)); return fRc; } /** Kernel32 - HeapCreate / NtDll - RTlCreateHeap */ HANDLE WINAPI kwSandbox_Kernel32_HeapCreate(DWORD fOptions, SIZE_T cbInitial, SIZE_T cbMax) { HANDLE hHeap; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); hHeap = HeapCreate(fOptions, cbInitial, cbMax); if (hHeap != NULL) { DWORD dwErr = GetLastError(); PKWHEAP pTracker = (PKWHEAP)kHlpAlloc(sizeof(*pTracker)); if (pTracker) { pTracker->hHeap = hHeap; pTracker->pNext = g_Sandbox.pHeapHead; g_Sandbox.pHeapHead = pTracker; } SetLastError(dwErr); } return hHeap; } /** Kernel32 - HeapDestroy / NtDll - RTlDestroyHeap */ BOOL WINAPI kwSandbox_Kernel32_HeapDestroy(HANDLE hHeap) { BOOL fRc = HeapDestroy(hHeap); KW_LOG(("HeapDestroy: hHeap=%p -> %d\n", hHeap, fRc)); kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); if (fRc) { PKWHEAP pTracker = g_Sandbox.pHeapHead; if (pTracker) { if (pTracker->hHeap == hHeap) g_Sandbox.pHeapHead = pTracker->pNext; else { PKWHEAP pPrev; do { pPrev = pTracker; pTracker = pTracker->pNext; } while (pTracker && pTracker->hHeap == hHeap); if (pTracker) pPrev->pNext = pTracker->pNext; } if (pTracker) kHlpFree(pTracker); else KW_LOG(("HeapDestroy: pvAddr=%p not found!\n", hHeap)); } } return fRc; } /* * * Thread/Fiber local storage leak prevention. * Thread/Fiber local storage leak prevention. * Thread/Fiber local storage leak prevention. * * Note! The FlsAlloc/Free & TlsAlloc/Free causes problems for statically * linked VS2010 code like VBoxBs3ObjConverter.exe. One thing is that * we're leaking these indexes, but more importantely we crash during * worker exit since the callback is triggered multiple times. */ /** Kernel32 - FlsAlloc */ DWORD WINAPI kwSandbox_Kernel32_FlsAlloc(PFLS_CALLBACK_FUNCTION pfnCallback) { DWORD idxFls = FlsAlloc(pfnCallback); KW_LOG(("FlsAlloc(%p) -> %#x\n", pfnCallback, idxFls)); if (idxFls != FLS_OUT_OF_INDEXES) { PKWLOCALSTORAGE pTracker = (PKWLOCALSTORAGE)kHlpAlloc(sizeof(*pTracker)); if (pTracker) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pTracker->idx = idxFls; pTracker->pNext = g_Sandbox.pFlsAllocHead; g_Sandbox.pFlsAllocHead = pTracker; } } return idxFls; } /** Kernel32 - FlsFree */ BOOL WINAPI kwSandbox_Kernel32_FlsFree(DWORD idxFls) { BOOL fRc = FlsFree(idxFls); KW_LOG(("FlsFree(%#x) -> %d\n", idxFls, fRc)); if (fRc) { PKWLOCALSTORAGE pTracker; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pTracker = g_Sandbox.pFlsAllocHead; if (pTracker) { if (pTracker->idx == idxFls) g_Sandbox.pFlsAllocHead = pTracker->pNext; else { PKWLOCALSTORAGE pPrev; do { pPrev = pTracker; pTracker = pTracker->pNext; } while (pTracker && pTracker->idx != idxFls); if (pTracker) pPrev->pNext = pTracker->pNext; } if (pTracker) { pTracker->idx = FLS_OUT_OF_INDEXES; pTracker->pNext = NULL; kHlpFree(pTracker); } } } return fRc; } /** Kernel32 - TlsAlloc */ DWORD WINAPI kwSandbox_Kernel32_TlsAlloc(VOID) { DWORD idxTls = TlsAlloc(); KW_LOG(("TlsAlloc() -> %#x\n", idxTls)); if (idxTls != TLS_OUT_OF_INDEXES) { PKWLOCALSTORAGE pTracker = (PKWLOCALSTORAGE)kHlpAlloc(sizeof(*pTracker)); if (pTracker) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pTracker->idx = idxTls; pTracker->pNext = g_Sandbox.pTlsAllocHead; g_Sandbox.pTlsAllocHead = pTracker; } } return idxTls; } /** Kernel32 - TlsFree */ BOOL WINAPI kwSandbox_Kernel32_TlsFree(DWORD idxTls) { BOOL fRc = TlsFree(idxTls); KW_LOG(("TlsFree(%#x) -> %d\n", idxTls, fRc)); if (fRc) { PKWLOCALSTORAGE pTracker; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pTracker = g_Sandbox.pTlsAllocHead; if (pTracker) { if (pTracker->idx == idxTls) g_Sandbox.pTlsAllocHead = pTracker->pNext; else { PKWLOCALSTORAGE pPrev; do { pPrev = pTracker; pTracker = pTracker->pNext; } while (pTracker && pTracker->idx != idxTls); if (pTracker) pPrev->pNext = pTracker->pNext; } if (pTracker) { pTracker->idx = TLS_OUT_OF_INDEXES; pTracker->pNext = NULL; kHlpFree(pTracker); } } } return fRc; } /* * * Header file hashing. * Header file hashing. * Header file hashing. * * c1.dll / c1XX.dll hashes the input files. The Visual C++ 2010 profiler * indicated that ~12% of the time was spent doing MD5 caluclation when * rebuiling openssl. The hashing it done right after reading the source * via ReadFile, same buffers and sizes. */ #ifdef WITH_HASH_MD5_CACHE /** AdvApi32 - CryptCreateHash */ static BOOL WINAPI kwSandbox_Advapi32_CryptCreateHash(HCRYPTPROV hProv, ALG_ID idAlg, HCRYPTKEY hKey, DWORD dwFlags, HCRYPTHASH *phHash) { BOOL fRc; /* * Only do this for cl.exe when it request normal MD5. */ if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL) { if (idAlg == CALG_MD5) { if (hKey == 0) { if (dwFlags == 0) { PKWHASHMD5 pHash = (PKWHASHMD5)kHlpAllocZ(sizeof(*pHash)); if (pHash) { kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); pHash->uMagic = KWHASHMD5_MAGIC; pHash->cbHashed = 0; pHash->fGoneBad = K_FALSE; pHash->fFallbackMode = K_FALSE; pHash->fFinal = K_FALSE; /* link it. */ pHash->pNext = g_Sandbox.pHashHead; g_Sandbox.pHashHead = pHash; *phHash = (KUPTR)pHash; KWCRYPT_LOG(("CryptCreateHash(hProv=%p, idAlg=CALG_MD5, 0, 0, *phHash=%p) -> %d [cached]\n", hProv, *phHash, TRUE)); return TRUE; } kwErrPrintf("CryptCreateHash: out of memory!\n"); } else kwErrPrintf("CryptCreateHash: dwFlags=%p is not supported with CALG_MD5\n", hKey); } else kwErrPrintf("CryptCreateHash: hKey=%p is not supported with CALG_MD5\n", hKey); } else kwErrPrintf("CryptCreateHash: idAlg=%#x is not supported\n", idAlg); } /* * Fallback. */ fRc = CryptCreateHash(hProv, idAlg, hKey, dwFlags, phHash); KWCRYPT_LOG(("CryptCreateHash(hProv=%p, idAlg=%#x (%d), hKey=%p, dwFlags=%#x, *phHash=%p) -> %d\n", hProv, idAlg, idAlg, hKey, dwFlags, *phHash, fRc)); return fRc; } /** AdvApi32 - CryptHashData */ static BOOL WINAPI kwSandbox_Advapi32_CryptHashData(HCRYPTHASH hHash, CONST BYTE *pbData, DWORD cbData, DWORD dwFlags) { BOOL fRc; PKWHASHMD5 pHash = g_Sandbox.pHashHead; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); while (pHash && (KUPTR)pHash != hHash) pHash = pHash->pNext; KWCRYPT_LOG(("CryptHashData(hHash=%p/%p, pbData=%p, cbData=%#x, dwFlags=%#x)\n", hHash, pHash, pbData, cbData, dwFlags)); if (pHash) { /* * Validate the state. */ if ( pHash->uMagic == KWHASHMD5_MAGIC && !pHash->fFinal) { if (!pHash->fFallbackMode) { /* * Does this match the previous ReadFile call to a cached file? * If it doesn't, try falling back. */ if ( g_Sandbox.LastHashRead.cbRead == cbData && g_Sandbox.LastHashRead.pvRead == (void *)pbData) { PKFSWCACHEDFILE pCachedFile = g_Sandbox.LastHashRead.pCachedFile; if ( pCachedFile && kHlpMemComp(pbData, &pCachedFile->pbCached[g_Sandbox.LastHashRead.offRead], K_MIN(cbData, 64)) == 0) { if (g_Sandbox.LastHashRead.offRead == pHash->cbHashed) { if ( pHash->pCachedFile == NULL && pHash->cbHashed == 0) pHash->pCachedFile = pCachedFile; if (pHash->pCachedFile == pCachedFile) { pHash->cbHashed += cbData; g_Sandbox.LastHashRead.pCachedFile = NULL; g_Sandbox.LastHashRead.pvRead = NULL; g_Sandbox.LastHashRead.cbRead = 0; g_Sandbox.LastHashRead.offRead = 0; KWCRYPT_LOG(("CryptHashData(hHash=%p/%p/%s, pbData=%p, cbData=%#x, dwFlags=%#x) -> 1 [cached]\n", hHash, pCachedFile, pCachedFile->szPath, pbData, cbData, dwFlags)); return TRUE; } /* Note! it's possible to fall back here too, if necessary. */ kwErrPrintf("CryptHashData: Expected pCachedFile=%p, last read was made to %p!!\n", pHash->pCachedFile, g_Sandbox.LastHashRead.pCachedFile); } else kwErrPrintf("CryptHashData: Expected last read at %#x, instead it was made at %#x\n", pHash->cbHashed, g_Sandbox.LastHashRead.offRead); } else if (!pCachedFile) kwErrPrintf("CryptHashData: Last pCachedFile is NULL when buffer address and size matches!\n"); else kwErrPrintf("CryptHashData: First 64 bytes of the buffer doesn't match the cache.\n"); } else if (g_Sandbox.LastHashRead.cbRead != 0 && pHash->cbHashed != 0) kwErrPrintf("CryptHashData: Expected cbRead=%#x and pbData=%p, got %#x and %p instead\n", g_Sandbox.LastHashRead.cbRead, g_Sandbox.LastHashRead.pvRead, cbData, pbData); if (pHash->cbHashed == 0) pHash->fFallbackMode = K_TRUE; if (pHash->fFallbackMode) { /* Initiate fallback mode (file that we don't normally cache, like .c/.cpp). */ pHash->fFallbackMode = K_TRUE; MD5Init(&pHash->Md5Ctx); MD5Update(&pHash->Md5Ctx, pbData, cbData); pHash->cbHashed = cbData; KWCRYPT_LOG(("CryptHashData(hHash=%p/fallback, pbData=%p, cbData=%#x, dwFlags=%#x) -> 1 [fallback!]\n", hHash, pbData, cbData, dwFlags)); return TRUE; } pHash->fGoneBad = K_TRUE; SetLastError(ERROR_INVALID_PARAMETER); fRc = FALSE; } else { /* fallback. */ MD5Update(&pHash->Md5Ctx, pbData, cbData); pHash->cbHashed += cbData; fRc = TRUE; KWCRYPT_LOG(("CryptHashData(hHash=%p/fallback, pbData=%p, cbData=%#x, dwFlags=%#x) -> 1 [fallback]\n", hHash, pbData, cbData, dwFlags)); } } /* * Bad handle state. */ else { if (pHash->uMagic != KWHASHMD5_MAGIC) kwErrPrintf("CryptHashData: Invalid cached hash handle!!\n"); else kwErrPrintf("CryptHashData: Hash is already finalized!!\n"); SetLastError(NTE_BAD_HASH); fRc = FALSE; } } else { fRc = CryptHashData(hHash, pbData, cbData, dwFlags); KWCRYPT_LOG(("CryptHashData(hHash=%p, pbData=%p, cbData=%#x, dwFlags=%#x) -> %d\n", hHash, pbData, cbData, dwFlags, fRc)); } return fRc; } /** AdvApi32 - CryptGetHashParam */ static BOOL WINAPI kwSandbox_Advapi32_CryptGetHashParam(HCRYPTHASH hHash, DWORD dwParam, BYTE *pbData, DWORD *pcbData, DWORD dwFlags) { BOOL fRc; PKWHASHMD5 pHash = g_Sandbox.pHashHead; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); while (pHash && (KUPTR)pHash != hHash) pHash = pHash->pNext; if (pHash) { if (pHash->uMagic == KWHASHMD5_MAGIC) { if (dwFlags == 0) { DWORD cbRet; void *pvRet; union { DWORD dw; } uBuf; switch (dwParam) { case HP_HASHVAL: { /* Check the hash progress. */ PKFSWCACHEDFILE pCachedFile = pHash->pCachedFile; if (pCachedFile) { if ( pCachedFile->cbCached == pHash->cbHashed && !pHash->fGoneBad) { if (pCachedFile->fValidMd5) KWCRYPT_LOG(("Already calculated hash for %p/%s! [hit]\n", pCachedFile, pCachedFile->szPath)); else { MD5Init(&pHash->Md5Ctx); MD5Update(&pHash->Md5Ctx, pCachedFile->pbCached, pCachedFile->cbCached); MD5Final(pCachedFile->abMd5Digest, &pHash->Md5Ctx); pCachedFile->fValidMd5 = K_TRUE; KWCRYPT_LOG(("Calculated hash for %p/%s.\n", pCachedFile, pCachedFile->szPath)); } pvRet = pCachedFile->abMd5Digest; } else { /* This actually happens (iprt/string.h + common/alloc/alloc.cpp), at least from what I can tell, so just deal with it. */ KWCRYPT_LOG(("CryptGetHashParam/HP_HASHVAL: Not at end of cached file! cbCached=%#x cbHashed=%#x fGoneBad=%d (%p/%p/%s)\n", pHash->pCachedFile->cbCached, pHash->cbHashed, pHash->fGoneBad, pHash, pCachedFile, pCachedFile->szPath)); pHash->fFallbackMode = K_TRUE; pHash->pCachedFile = NULL; MD5Init(&pHash->Md5Ctx); MD5Update(&pHash->Md5Ctx, pCachedFile->pbCached, pHash->cbHashed); MD5Final(pHash->abDigest, &pHash->Md5Ctx); pvRet = pHash->abDigest; } pHash->fFinal = K_TRUE; cbRet = 16; break; } else if (pHash->fFallbackMode) { if (!pHash->fFinal) { pHash->fFinal = K_TRUE; MD5Final(pHash->abDigest, &pHash->Md5Ctx); } pvRet = pHash->abDigest; cbRet = 16; break; } else { kwErrPrintf("CryptGetHashParam/HP_HASHVAL: pCachedFile is NULL!!\n"); SetLastError(ERROR_INVALID_SERVER_STATE); } return FALSE; } case HP_HASHSIZE: uBuf.dw = 16; pvRet = &uBuf; cbRet = sizeof(DWORD); break; case HP_ALGID: uBuf.dw = CALG_MD5; pvRet = &uBuf; cbRet = sizeof(DWORD); break; default: kwErrPrintf("CryptGetHashParam: Unknown dwParam=%#x\n", dwParam); SetLastError(NTE_BAD_TYPE); return FALSE; } /* * Copy out cbRet from pvRet. */ if (pbData) { if (*pcbData >= cbRet) { *pcbData = cbRet; kHlpMemCopy(pbData, pvRet, cbRet); if (cbRet == 4) KWCRYPT_LOG(("CryptGetHashParam/%#x/%p/%p: TRUE, cbRet=%#x data=%#x [cached]\n", dwParam, pHash, pHash->pCachedFile, cbRet, (DWORD *)pbData)); else if (cbRet == 16) KWCRYPT_LOG(("CryptGetHashParam/%#x/%p/%p: TRUE, cbRet=%#x data=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x [cached]\n", dwParam, pHash, pHash->pCachedFile, cbRet, pbData[0], pbData[1], pbData[2], pbData[3], pbData[4], pbData[5], pbData[6], pbData[7], pbData[8], pbData[9], pbData[10], pbData[11], pbData[12], pbData[13], pbData[14], pbData[15])); else KWCRYPT_LOG(("CryptGetHashParam/%#x%/p%/%p: TRUE, cbRet=%#x [cached]\n", dwParam, pHash, pHash->pCachedFile, cbRet)); return TRUE; } kHlpMemCopy(pbData, pvRet, *pcbData); } SetLastError(ERROR_MORE_DATA); *pcbData = cbRet; KWCRYPT_LOG(("CryptGetHashParam/%#x: ERROR_MORE_DATA\n")); } else { kwErrPrintf("CryptGetHashParam: dwFlags is not zero: %#x!\n", dwFlags); SetLastError(NTE_BAD_FLAGS); } } else { kwErrPrintf("CryptGetHashParam: Invalid cached hash handle!!\n"); SetLastError(NTE_BAD_HASH); } fRc = FALSE; } /* * Regular handle. */ else { fRc = CryptGetHashParam(hHash, dwParam, pbData, pcbData, dwFlags); KWCRYPT_LOG(("CryptGetHashParam(hHash=%p, dwParam=%#x (%d), pbData=%p, *pcbData=%#x, dwFlags=%#x) -> %d\n", hHash, dwParam, pbData, *pcbData, dwFlags, fRc)); } return fRc; } /** AdvApi32 - CryptDestroyHash */ static BOOL WINAPI kwSandbox_Advapi32_CryptDestroyHash(HCRYPTHASH hHash) { BOOL fRc; PKWHASHMD5 pPrev = NULL; PKWHASHMD5 pHash = g_Sandbox.pHashHead; kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread); while (pHash && (KUPTR)pHash != hHash) { pPrev = pHash; pHash = pHash->pNext; } if (pHash) { if (pHash->uMagic == KWHASHMD5_MAGIC) { pHash->uMagic = 0; if (!pPrev) g_Sandbox.pHashHead = pHash->pNext; else pPrev->pNext = pHash->pNext; kHlpFree(pHash); KWCRYPT_LOG(("CryptDestroyHash(hHash=%p) -> 1 [cached]\n", hHash)); fRc = TRUE; } else { kwErrPrintf("CryptDestroyHash: Invalid cached hash handle!!\n"); KWCRYPT_LOG(("CryptDestroyHash(hHash=%p) -> FALSE! [cached]\n", hHash)); SetLastError(ERROR_INVALID_HANDLE); fRc = FALSE; } } /* * Regular handle. */ else { fRc = CryptDestroyHash(hHash); KWCRYPT_LOG(("CryptDestroyHash(hHash=%p) -> %d\n", hHash, fRc)); } return fRc; } #endif /* WITH_HASH_MD5_CACHE */ /* * * Reuse crypt context. * Reuse crypt context. * Reuse crypt context. * * * This saves a little bit of time and registry accesses each time CL, C1 or C1XX runs. * */ #ifdef WITH_CRYPT_CTX_REUSE /** AdvApi32 - CryptAcquireContextW. */ static BOOL WINAPI kwSandbox_Advapi32_CryptAcquireContextW(HCRYPTPROV *phProv, LPCWSTR pwszContainer, LPCWSTR pwszProvider, DWORD dwProvType, DWORD dwFlags) { BOOL fRet; /* * Lookup reusable context based on the input. */ KSIZE const cwcContainer = pwszContainer ? kwUtf16Len(pwszContainer) : 0; KSIZE const cwcProvider = pwszProvider ? kwUtf16Len(pwszProvider) : 0; KU32 iCtx = g_Sandbox.cCryptCtxs; while (iCtx-- > 0) { if ( g_Sandbox.aCryptCtxs[iCtx].cwcContainer == cwcContainer && g_Sandbox.aCryptCtxs[iCtx].cwcProvider == cwcProvider && g_Sandbox.aCryptCtxs[iCtx].dwProvType == dwProvType && g_Sandbox.aCryptCtxs[iCtx].dwFlags == dwFlags && kHlpMemComp(g_Sandbox.aCryptCtxs[iCtx].pwszContainer, pwszContainer, cwcContainer * sizeof(wchar_t)) == 0 && kHlpMemComp(g_Sandbox.aCryptCtxs[iCtx].pwszProvider, pwszProvider, cwcProvider * sizeof(wchar_t)) == 0) { if (CryptContextAddRef(g_Sandbox.aCryptCtxs[iCtx].hProv, NULL, 0)) { *phProv = g_Sandbox.aCryptCtxs[iCtx].hProv; KWCRYPT_LOG(("CryptAcquireContextW(,%ls, %ls, %#x, %#x) -> TRUE, %p [reused]\n", pwszContainer, pwszProvider, dwProvType, dwFlags, *phProv)); return TRUE; } } } /* * Create it and enter it into the reused array if possible. */ fRet = CryptAcquireContextW(phProv, pwszContainer, pwszProvider, dwProvType, dwFlags); if (fRet) { iCtx = g_Sandbox.cCryptCtxs; if (iCtx < K_ELEMENTS(g_Sandbox.aCryptCtxs)) { /* Try duplicate the input strings. */ g_Sandbox.aCryptCtxs[iCtx].pwszContainer = kHlpDup(pwszContainer ? pwszContainer : L"", (cwcContainer + 1) * sizeof(wchar_t)); if (g_Sandbox.aCryptCtxs[iCtx].pwszContainer) { g_Sandbox.aCryptCtxs[iCtx].pwszProvider = kHlpDup(pwszProvider ? pwszProvider : L"", (cwcProvider + 1) * sizeof(wchar_t)); if (g_Sandbox.aCryptCtxs[iCtx].pwszProvider) { /* Add a couple of references just to be on the safe side and all that. */ HCRYPTPROV hProv = *phProv; if (CryptContextAddRef(hProv, NULL, 0)) { if (CryptContextAddRef(hProv, NULL, 0)) { /* Okay, finish the entry and return success */ g_Sandbox.aCryptCtxs[iCtx].hProv = hProv; g_Sandbox.aCryptCtxs[iCtx].dwProvType = dwProvType; g_Sandbox.aCryptCtxs[iCtx].dwFlags = dwFlags; g_Sandbox.cCryptCtxs = iCtx + 1; KWCRYPT_LOG(("CryptAcquireContextW(,%ls, %ls, %#x, %#x) -> TRUE, %p [new]\n", pwszContainer, pwszProvider, dwProvType, dwFlags, *phProv)); return TRUE; } CryptReleaseContext(hProv, 0); } KWCRYPT_LOG(("CryptAcquireContextW: CryptContextAddRef failed!\n")); kHlpFree(g_Sandbox.aCryptCtxs[iCtx].pwszProvider); g_Sandbox.aCryptCtxs[iCtx].pwszProvider = NULL; } kHlpFree(g_Sandbox.aCryptCtxs[iCtx].pwszContainer); g_Sandbox.aCryptCtxs[iCtx].pwszContainer = NULL; } } else KWCRYPT_LOG(("CryptAcquireContextW: Too many crypt contexts to keep and reuse!\n")); } KWCRYPT_LOG(("CryptAcquireContextW(,%ls, %ls, %#x, %#x) -> %d, %p\n", pwszContainer, pwszProvider, dwProvType, dwFlags, *phProv)); return fRet; } /** AdvApi32 - CryptReleaseContext */ static BOOL WINAPI kwSandbox_Advapi32_CryptReleaseContext(HCRYPTPROV hProv, DWORD dwFlags) { BOOL fRet = CryptReleaseContext(hProv, dwFlags); KWCRYPT_LOG(("CryptReleaseContext(%p,%#x) -> %d\n", hProv, dwFlags, fRet)); return fRet; } /** AdvApi32 - CryptContextAddRef */ static BOOL WINAPI kwSandbox_Advapi32_CryptContextAddRef(HCRYPTPROV hProv, DWORD *pdwReserved, DWORD dwFlags) { BOOL fRet = CryptContextAddRef(hProv, pdwReserved, dwFlags); KWCRYPT_LOG(("CryptContextAddRef(%p,%p,%#x) -> %d\n", hProv, pdwReserved, dwFlags, fRet)); return fRet; } #endif /* WITH_CRYPT_CTX_REUSE */ /* * * Structured exception handling. * Structured exception handling. * Structured exception handling. * */ #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_X86) # define EH_NONCONTINUABLE KU32_C(0x00000001) # define EH_UNWINDING KU32_C(0x00000002) # define EH_EXIT_UNWIND KU32_C(0x00000004) # define EH_STACK_INVALID KU32_C(0x00000008) # define EH_NESTED_CALL KU32_C(0x00000010) typedef KU32 (__cdecl * volatile PFNXCPTHANDLER)(PEXCEPTION_RECORD, struct _EXCEPTION_REGISTRATION_RECORD*, PCONTEXT, struct _EXCEPTION_REGISTRATION_RECORD * volatile *); typedef struct _EXCEPTION_REGISTRATION_RECORD { struct _EXCEPTION_REGISTRATION_RECORD * volatile pPrevRegRec; PFNXCPTHANDLER pfnXcptHandler; }; /** * Calls @a pfnHandler. */ static KU32 kwSandboxXcptCallHandler(PEXCEPTION_RECORD pXcptRec, struct _EXCEPTION_REGISTRATION_RECORD *pRegRec, PCONTEXT pXcptCtx, struct _EXCEPTION_REGISTRATION_RECORD * volatile * ppRegRec, PFNXCPTHANDLER pfnHandler) { # if 1 /* This is a more robust version that isn't subject to calling convension cleanup disputes and such. */ KU32 uSavedEdi; KU32 uSavedEsi; KU32 uSavedEbx; KU32 rcHandler; __asm { mov [uSavedEdi], edi mov [uSavedEsi], esi mov [uSavedEbx], ebx mov esi, esp mov edi, esp mov edi, [pXcptRec] mov edx, [pRegRec] mov eax, [pXcptCtx] mov ebx, [ppRegRec] mov ecx, [pfnHandler] sub esp, 16 and esp, 0fffffff0h mov [esp ], edi mov [esp + 4], edx mov [esp + 8], eax mov [esp + 12], ebx mov edi, esi call ecx mov esp, esi cmp esp, edi je stack_ok int 3 stack_ok: mov edi, [uSavedEdi] mov esi, [uSavedEsi] mov ebx, [uSavedEbx] mov [rcHandler], eax } return rcHandler; # else return pfnHandler(pXcptRec, pRegRec, pXctpCtx, ppRegRec); # endif } /** * Vectored exception handler that emulates x86 chained exception handler. * * This is necessary because the RtlIsValidHandler check fails for self loaded * code and prevents cl.exe from working. (On AMD64 we can register function * tables, but on X86 cooking your own handling seems to be the only viabke * alternative.) * * @returns EXCEPTION_CONTINUE_SEARCH or EXCEPTION_CONTINUE_EXECUTION. * @param pXcptPtrs The exception details. */ static LONG CALLBACK kwSandboxVecXcptEmulateChained(PEXCEPTION_POINTERS pXcptPtrs) { PNT_TIB pTib = (PNT_TIB)NtCurrentTeb(); KW_LOG(("kwSandboxVecXcptEmulateChained: %#x\n", pXcptPtrs->ExceptionRecord->ExceptionCode)); if (g_Sandbox.fRunning) { HANDLE const hCurProc = GetCurrentProcess(); PEXCEPTION_RECORD pXcptRec = pXcptPtrs->ExceptionRecord; PCONTEXT pXcptCtx = pXcptPtrs->ContextRecord; struct _EXCEPTION_REGISTRATION_RECORD * pRegRec = pTib->ExceptionList; while (((KUPTR)pRegRec & (sizeof(void *) - 3)) == 0 && pRegRec != NULL) { /* Read the exception record in a safe manner. */ struct _EXCEPTION_REGISTRATION_RECORD RegRec; DWORD cbActuallyRead = 0; if ( ReadProcessMemory(hCurProc, pRegRec, &RegRec, sizeof(RegRec), &cbActuallyRead) && cbActuallyRead == sizeof(RegRec)) { struct _EXCEPTION_REGISTRATION_RECORD * volatile pDispRegRec = NULL; KU32 rcHandler; KW_LOG(("kwSandboxVecXcptEmulateChained: calling %p, pRegRec=%p, pPrevRegRec=%p\n", RegRec.pfnXcptHandler, pRegRec, RegRec.pPrevRegRec)); rcHandler = kwSandboxXcptCallHandler(pXcptRec, pRegRec, pXcptCtx, &pDispRegRec, RegRec.pfnXcptHandler); KW_LOG(("kwSandboxVecXcptEmulateChained: rcHandler=%#x pDispRegRec=%p\n", rcHandler, pDispRegRec)); if (rcHandler == ExceptionContinueExecution) { kHlpAssert(!(pXcptPtrs->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)); KW_LOG(("kwSandboxVecXcptEmulateChained: returning EXCEPTION_CONTINUE_EXECUTION!\n")); return EXCEPTION_CONTINUE_EXECUTION; } if (rcHandler == ExceptionContinueSearch) kHlpAssert(!(pXcptPtrs->ExceptionRecord->ExceptionFlags & 8 /*EXCEPTION_STACK_INVALID*/)); else if (rcHandler == ExceptionNestedException) kHlpAssertMsgFailed(("Nested exceptions.\n")); else kHlpAssertMsgFailed(("Invalid return %#x (%d).\n", rcHandler, rcHandler)); } else { KW_LOG(("kwSandboxVecXcptEmulateChained: Bad xcpt chain entry at %p! Stopping search.\n", pRegRec)); break; } /* * Next. */ pRegRec = RegRec.pPrevRegRec; } } return EXCEPTION_CONTINUE_SEARCH; } /** NtDll,Kernel32 - RtlUnwind */ static VOID WINAPI kwSandbox_ntdll_RtlUnwind(struct _EXCEPTION_REGISTRATION_RECORD *pStopXcptRec, PVOID pvTargetIp, PEXCEPTION_RECORD pXcptRec, PVOID pvReturnValue) { PNT_TIB pTib = (PNT_TIB)NtCurrentTeb(); KW_LOG(("kwSandbox_ntdll_RtlUnwind: pStopXcptRec=%p pvTargetIp=%p pXctpRec=%p pvReturnValue=%p%s\n", pStopXcptRec, pvTargetIp, pXcptRec, pvReturnValue, g_Sandbox.fRunning ? "" : " [sandbox not running]")); if (g_Sandbox.fRunning) { HANDLE const hCurProc = GetCurrentProcess(); PCONTEXT pXcptCtx = NULL; struct _EXCEPTION_REGISTRATION_RECORD * pRegRec = pTib->ExceptionList; /* * Update / create an exception record. */ if (pXcptRec) pXcptRec->ExceptionFlags |= EH_UNWINDING; else { pXcptRec = (PEXCEPTION_RECORD)alloca(sizeof(*pXcptRec)); kHlpMemSet(pXcptRec, 0, sizeof(*pXcptRec)); pXcptRec->ExceptionCode = STATUS_UNWIND; pXcptRec->ExceptionFlags = EH_UNWINDING; } if (!pStopXcptRec) pXcptRec->ExceptionFlags |= EH_EXIT_UNWIND; /* * Walk the chain till we find pStopXctpRec. */ while ( ((KUPTR)pRegRec & (sizeof(void *) - 3)) == 0 && pRegRec != NULL && pRegRec != pStopXcptRec) { /* Read the exception record in a safe manner. */ struct _EXCEPTION_REGISTRATION_RECORD RegRec; DWORD cbActuallyRead = 0; if ( ReadProcessMemory(hCurProc, pRegRec, &RegRec, sizeof(RegRec), &cbActuallyRead) && cbActuallyRead == sizeof(RegRec)) { struct _EXCEPTION_REGISTRATION_RECORD * volatile pDispRegRec = NULL; KU32 rcHandler; KW_LOG(("kwSandbox_ntdll_RtlUnwind: calling %p, pRegRec=%p, pPrevRegRec=%p\n", RegRec.pfnXcptHandler, pRegRec, RegRec.pPrevRegRec)); rcHandler = kwSandboxXcptCallHandler(pXcptRec, pRegRec, pXcptCtx, &pDispRegRec, RegRec.pfnXcptHandler); KW_LOG(("kwSandbox_ntdll_RtlUnwind: rcHandler=%#x pDispRegRec=%p\n", rcHandler, pDispRegRec)); if (rcHandler == ExceptionContinueSearch) kHlpAssert(!(pXcptRec->ExceptionFlags & 8 /*EXCEPTION_STACK_INVALID*/)); else if (rcHandler == ExceptionCollidedUnwind) kHlpAssertMsgFailed(("Implement collided unwind!\n")); else kHlpAssertMsgFailed(("Invalid return %#x (%d).\n", rcHandler, rcHandler)); } else { KW_LOG(("kwSandbox_ntdll_RtlUnwind: Bad xcpt chain entry at %p! Stopping search.\n", pRegRec)); break; } /* * Pop next. */ pTib->ExceptionList = RegRec.pPrevRegRec; pRegRec = RegRec.pPrevRegRec; } return; } RtlUnwind(pStopXcptRec, pvTargetIp, pXcptRec, pvReturnValue); } #endif /* WINDOWS + X86 */ /* * * Misc function only intercepted while debugging. * Misc function only intercepted while debugging. * Misc function only intercepted while debugging. * */ #ifndef NDEBUG /** CRT - memcpy */ static void * __cdecl kwSandbox_msvcrt_memcpy(void *pvDst, void const *pvSrc, size_t cb) { KU8 const *pbSrc = (KU8 const *)pvSrc; KU8 *pbDst = (KU8 *)pvDst; KSIZE cbLeft = cb; while (cbLeft-- > 0) *pbDst++ = *pbSrc++; return pvDst; } /** CRT - memset */ static void * __cdecl kwSandbox_msvcrt_memset(void *pvDst, int bFiller, size_t cb) { KU8 *pbDst = (KU8 *)pvDst; KSIZE cbLeft = cb; while (cbLeft-- > 0) *pbDst++ = bFiller; return pvDst; } #endif /* NDEBUG */ /** * Functions that needs replacing for sandboxed execution. */ KWREPLACEMENTFUNCTION const g_aSandboxReplacements[] = { /* * Kernel32.dll and friends. */ { TUPLE("ExitProcess"), NULL, (KUPTR)kwSandbox_Kernel32_ExitProcess }, { TUPLE("TerminateProcess"), NULL, (KUPTR)kwSandbox_Kernel32_TerminateProcess }, { TUPLE("LoadLibraryA"), NULL, (KUPTR)kwSandbox_Kernel32_LoadLibraryA }, { TUPLE("LoadLibraryW"), NULL, (KUPTR)kwSandbox_Kernel32_LoadLibraryW }, { TUPLE("LoadLibraryExA"), NULL, (KUPTR)kwSandbox_Kernel32_LoadLibraryExA }, { TUPLE("LoadLibraryExW"), NULL, (KUPTR)kwSandbox_Kernel32_LoadLibraryExW }, { TUPLE("FreeLibrary"), NULL, (KUPTR)kwSandbox_Kernel32_FreeLibrary }, { TUPLE("GetModuleHandleA"), NULL, (KUPTR)kwSandbox_Kernel32_GetModuleHandleA }, { TUPLE("GetModuleHandleW"), NULL, (KUPTR)kwSandbox_Kernel32_GetModuleHandleW }, { TUPLE("GetProcAddress"), NULL, (KUPTR)kwSandbox_Kernel32_GetProcAddress }, { TUPLE("GetModuleFileNameA"), NULL, (KUPTR)kwSandbox_Kernel32_GetModuleFileNameA }, { TUPLE("GetModuleFileNameW"), NULL, (KUPTR)kwSandbox_Kernel32_GetModuleFileNameW }, { TUPLE("RtlPcToFileHeader"), NULL, (KUPTR)kwSandbox_ntdll_RtlPcToFileHeader }, { TUPLE("GetCommandLineA"), NULL, (KUPTR)kwSandbox_Kernel32_GetCommandLineA }, { TUPLE("GetCommandLineW"), NULL, (KUPTR)kwSandbox_Kernel32_GetCommandLineW }, { TUPLE("GetStartupInfoA"), NULL, (KUPTR)kwSandbox_Kernel32_GetStartupInfoA }, { TUPLE("GetStartupInfoW"), NULL, (KUPTR)kwSandbox_Kernel32_GetStartupInfoW }, { TUPLE("CreateThread"), NULL, (KUPTR)kwSandbox_Kernel32_CreateThread }, { TUPLE("GetEnvironmentStrings"), NULL, (KUPTR)kwSandbox_Kernel32_GetEnvironmentStrings }, { TUPLE("GetEnvironmentStringsA"), NULL, (KUPTR)kwSandbox_Kernel32_GetEnvironmentStringsA }, { TUPLE("GetEnvironmentStringsW"), NULL, (KUPTR)kwSandbox_Kernel32_GetEnvironmentStringsW }, { TUPLE("FreeEnvironmentStringsA"), NULL, (KUPTR)kwSandbox_Kernel32_FreeEnvironmentStringsA }, { TUPLE("FreeEnvironmentStringsW"), NULL, (KUPTR)kwSandbox_Kernel32_FreeEnvironmentStringsW }, { TUPLE("GetEnvironmentVariableA"), NULL, (KUPTR)kwSandbox_Kernel32_GetEnvironmentVariableA }, { TUPLE("GetEnvironmentVariableW"), NULL, (KUPTR)kwSandbox_Kernel32_GetEnvironmentVariableW }, { TUPLE("SetEnvironmentVariableA"), NULL, (KUPTR)kwSandbox_Kernel32_SetEnvironmentVariableA }, { TUPLE("SetEnvironmentVariableW"), NULL, (KUPTR)kwSandbox_Kernel32_SetEnvironmentVariableW }, { TUPLE("ExpandEnvironmentStringsA"), NULL, (KUPTR)kwSandbox_Kernel32_ExpandEnvironmentStringsA }, { TUPLE("ExpandEnvironmentStringsW"), NULL, (KUPTR)kwSandbox_Kernel32_ExpandEnvironmentStringsW }, { TUPLE("CreateFileA"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileA }, { TUPLE("CreateFileW"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileW }, { TUPLE("ReadFile"), NULL, (KUPTR)kwSandbox_Kernel32_ReadFile }, { TUPLE("ReadFileEx"), NULL, (KUPTR)kwSandbox_Kernel32_ReadFileEx }, #ifdef WITH_TEMP_MEMORY_FILES { TUPLE("WriteFile"), NULL, (KUPTR)kwSandbox_Kernel32_WriteFile }, { TUPLE("WriteFileEx"), NULL, (KUPTR)kwSandbox_Kernel32_WriteFileEx }, { TUPLE("SetEndOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_SetEndOfFile }, { TUPLE("GetFileType"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileType }, { TUPLE("GetFileSize"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileSize }, { TUPLE("GetFileSizeEx"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileSizeEx }, { TUPLE("CreateFileMappingW"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileMappingW }, { TUPLE("MapViewOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_MapViewOfFile }, { TUPLE("MapViewOfFileEx"), NULL, (KUPTR)kwSandbox_Kernel32_MapViewOfFileEx }, { TUPLE("UnmapViewOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_UnmapViewOfFile }, #endif { TUPLE("SetFilePointer"), NULL, (KUPTR)kwSandbox_Kernel32_SetFilePointer }, { TUPLE("SetFilePointerEx"), NULL, (KUPTR)kwSandbox_Kernel32_SetFilePointerEx }, { TUPLE("DuplicateHandle"), NULL, (KUPTR)kwSandbox_Kernel32_DuplicateHandle }, { TUPLE("CloseHandle"), NULL, (KUPTR)kwSandbox_Kernel32_CloseHandle }, { TUPLE("GetFileAttributesA"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileAttributesA }, { TUPLE("GetFileAttributesW"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileAttributesW }, { TUPLE("GetShortPathNameW"), NULL, (KUPTR)kwSandbox_Kernel32_GetShortPathNameW }, #ifdef WITH_TEMP_MEMORY_FILES { TUPLE("DeleteFileW"), NULL, (KUPTR)kwSandbox_Kernel32_DeleteFileW }, #endif { TUPLE("WriteConsoleA"), NULL, (KUPTR)kwSandbox_Kernel32_WriteConsoleA }, { TUPLE("WriteConsoleW"), NULL, (KUPTR)kwSandbox_Kernel32_WriteConsoleW }, { TUPLE("VirtualAlloc"), NULL, (KUPTR)kwSandbox_Kernel32_VirtualAlloc }, { TUPLE("VirtualFree"), NULL, (KUPTR)kwSandbox_Kernel32_VirtualFree }, { TUPLE("HeapCreate"), NULL, (KUPTR)kwSandbox_Kernel32_HeapCreate, K_TRUE /*fOnlyExe*/ }, { TUPLE("HeapDestroy"), NULL, (KUPTR)kwSandbox_Kernel32_HeapDestroy, K_TRUE /*fOnlyExe*/ }, { TUPLE("FlsAlloc"), NULL, (KUPTR)kwSandbox_Kernel32_FlsAlloc, K_TRUE /*fOnlyExe*/ }, { TUPLE("FlsFree"), NULL, (KUPTR)kwSandbox_Kernel32_FlsFree, K_TRUE /*fOnlyExe*/ }, { TUPLE("TlsAlloc"), NULL, (KUPTR)kwSandbox_Kernel32_TlsAlloc, K_TRUE /*fOnlyExe*/ }, { TUPLE("TlsFree"), NULL, (KUPTR)kwSandbox_Kernel32_TlsFree, K_TRUE /*fOnlyExe*/ }, { TUPLE("SetConsoleCtrlHandler"), NULL, (KUPTR)kwSandbox_Kernel32_SetConsoleCtrlHandler }, #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_X86) { TUPLE("RtlUnwind"), NULL, (KUPTR)kwSandbox_ntdll_RtlUnwind }, #endif #ifdef WITH_HASH_MD5_CACHE { TUPLE("CryptCreateHash"), NULL, (KUPTR)kwSandbox_Advapi32_CryptCreateHash }, { TUPLE("CryptHashData"), NULL, (KUPTR)kwSandbox_Advapi32_CryptHashData }, { TUPLE("CryptGetHashParam"), NULL, (KUPTR)kwSandbox_Advapi32_CryptGetHashParam }, { TUPLE("CryptDestroyHash"), NULL, (KUPTR)kwSandbox_Advapi32_CryptDestroyHash }, #endif #ifdef WITH_CRYPT_CTX_REUSE { TUPLE("CryptAcquireContextW"), NULL, (KUPTR)kwSandbox_Advapi32_CryptAcquireContextW }, { TUPLE("CryptReleaseContext"), NULL, (KUPTR)kwSandbox_Advapi32_CryptReleaseContext }, { TUPLE("CryptContextAddRef"), NULL, (KUPTR)kwSandbox_Advapi32_CryptContextAddRef }, #endif /* * MS Visual C++ CRTs. */ { TUPLE("exit"), NULL, (KUPTR)kwSandbox_msvcrt_exit }, { TUPLE("_exit"), NULL, (KUPTR)kwSandbox_msvcrt__exit }, { TUPLE("_cexit"), NULL, (KUPTR)kwSandbox_msvcrt__cexit }, { TUPLE("_c_exit"), NULL, (KUPTR)kwSandbox_msvcrt__c_exit }, { TUPLE("_amsg_exit"), NULL, (KUPTR)kwSandbox_msvcrt__amsg_exit }, { TUPLE("terminate"), NULL, (KUPTR)kwSandbox_msvcrt_terminate }, { TUPLE("onexit"), NULL, (KUPTR)kwSandbox_msvcrt__onexit, K_TRUE /*fOnlyExe*/ }, { TUPLE("_onexit"), NULL, (KUPTR)kwSandbox_msvcrt__onexit, K_TRUE /*fOnlyExe*/ }, { TUPLE("atexit"), NULL, (KUPTR)kwSandbox_msvcrt_atexit, K_TRUE /*fOnlyExe*/ }, { TUPLE("_beginthread"), NULL, (KUPTR)kwSandbox_msvcrt__beginthread }, { TUPLE("_beginthreadex"), NULL, (KUPTR)kwSandbox_msvcrt__beginthreadex }, { TUPLE("_beginthreadex"), "msvcr120.dll", (KUPTR)kwSandbox_msvcr120__beginthreadex }, /* higher priority last */ { TUPLE("__argc"), NULL, (KUPTR)&g_Sandbox.cArgs }, { TUPLE("__argv"), NULL, (KUPTR)&g_Sandbox.papszArgs }, { TUPLE("__wargv"), NULL, (KUPTR)&g_Sandbox.papwszArgs }, { TUPLE("__p___argc"), NULL, (KUPTR)kwSandbox_msvcrt___p___argc }, { TUPLE("__p___argv"), NULL, (KUPTR)kwSandbox_msvcrt___p___argv }, { TUPLE("__p___wargv"), NULL, (KUPTR)kwSandbox_msvcrt___p___wargv }, { TUPLE("_acmdln"), NULL, (KUPTR)&g_Sandbox.pszCmdLine }, { TUPLE("_wcmdln"), NULL, (KUPTR)&g_Sandbox.pwszCmdLine }, { TUPLE("__p__acmdln"), NULL, (KUPTR)kwSandbox_msvcrt___p__acmdln }, { TUPLE("__p__wcmdln"), NULL, (KUPTR)kwSandbox_msvcrt___p__wcmdln }, { TUPLE("_pgmptr"), NULL, (KUPTR)&g_Sandbox.pgmptr }, { TUPLE("_wpgmptr"), NULL, (KUPTR)&g_Sandbox.wpgmptr }, { TUPLE("_get_pgmptr"), NULL, (KUPTR)kwSandbox_msvcrt__get_pgmptr }, { TUPLE("_get_wpgmptr"), NULL, (KUPTR)kwSandbox_msvcrt__get_wpgmptr }, { TUPLE("__p__pgmptr"), NULL, (KUPTR)kwSandbox_msvcrt___p__pgmptr }, { TUPLE("__p__wpgmptr"), NULL, (KUPTR)kwSandbox_msvcrt___p__wpgmptr }, { TUPLE("_wincmdln"), NULL, (KUPTR)kwSandbox_msvcrt__wincmdln }, { TUPLE("_wwincmdln"), NULL, (KUPTR)kwSandbox_msvcrt__wwincmdln }, { TUPLE("__getmainargs"), NULL, (KUPTR)kwSandbox_msvcrt___getmainargs}, { TUPLE("__wgetmainargs"), NULL, (KUPTR)kwSandbox_msvcrt___wgetmainargs}, { TUPLE("_putenv"), NULL, (KUPTR)kwSandbox_msvcrt__putenv}, { TUPLE("_wputenv"), NULL, (KUPTR)kwSandbox_msvcrt__wputenv}, { TUPLE("_putenv_s"), NULL, (KUPTR)kwSandbox_msvcrt__putenv_s}, { TUPLE("_wputenv_s"), NULL, (KUPTR)kwSandbox_msvcrt__wputenv_s}, { TUPLE("__initenv"), NULL, (KUPTR)&g_Sandbox.initenv }, { TUPLE("__winitenv"), NULL, (KUPTR)&g_Sandbox.winitenv }, { TUPLE("__p___initenv"), NULL, (KUPTR)kwSandbox_msvcrt___p___initenv}, { TUPLE("__p___winitenv"), NULL, (KUPTR)kwSandbox_msvcrt___p___winitenv}, { TUPLE("_environ"), NULL, (KUPTR)&g_Sandbox.environ }, { TUPLE("_wenviron"), NULL, (KUPTR)&g_Sandbox.wenviron }, { TUPLE("_get_environ"), NULL, (KUPTR)kwSandbox_msvcrt__get_environ }, { TUPLE("_get_wenviron"), NULL, (KUPTR)kwSandbox_msvcrt__get_wenviron }, { TUPLE("__p__environ"), NULL, (KUPTR)kwSandbox_msvcrt___p__environ }, { TUPLE("__p__wenviron"), NULL, (KUPTR)kwSandbox_msvcrt___p__wenviron }, #ifndef NDEBUG { TUPLE("memcpy"), NULL, (KUPTR)kwSandbox_msvcrt_memcpy }, { TUPLE("memset"), NULL, (KUPTR)kwSandbox_msvcrt_memset }, #endif }; /** Number of entries in g_aReplacements. */ KU32 const g_cSandboxReplacements = K_ELEMENTS(g_aSandboxReplacements); /** * Functions that needs replacing in natively loaded DLLs when doing sandboxed * execution. */ KWREPLACEMENTFUNCTION const g_aSandboxNativeReplacements[] = { /* * Kernel32.dll and friends. */ { TUPLE("ExitProcess"), NULL, (KUPTR)kwSandbox_Kernel32_ExitProcess }, { TUPLE("TerminateProcess"), NULL, (KUPTR)kwSandbox_Kernel32_TerminateProcess }, #if 0 { TUPLE("CreateThread"), NULL, (KUPTR)kwSandbox_Kernel32_CreateThread }, #endif { TUPLE("CreateFileA"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileA }, { TUPLE("CreateFileW"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileW }, { TUPLE("ReadFile"), NULL, (KUPTR)kwSandbox_Kernel32_ReadFile }, { TUPLE("ReadFileEx"), NULL, (KUPTR)kwSandbox_Kernel32_ReadFileEx }, #ifdef WITH_TEMP_MEMORY_FILES { TUPLE("WriteFile"), NULL, (KUPTR)kwSandbox_Kernel32_WriteFile }, { TUPLE("WriteFileEx"), NULL, (KUPTR)kwSandbox_Kernel32_WriteFileEx }, { TUPLE("SetEndOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_SetEndOfFile }, { TUPLE("GetFileType"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileType }, { TUPLE("GetFileSize"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileSize }, { TUPLE("GetFileSizeEx"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileSizeEx }, { TUPLE("CreateFileMappingW"), NULL, (KUPTR)kwSandbox_Kernel32_CreateFileMappingW }, { TUPLE("MapViewOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_MapViewOfFile }, { TUPLE("MapViewOfFileEx"), NULL, (KUPTR)kwSandbox_Kernel32_MapViewOfFileEx }, { TUPLE("UnmapViewOfFile"), NULL, (KUPTR)kwSandbox_Kernel32_UnmapViewOfFile }, #endif { TUPLE("SetFilePointer"), NULL, (KUPTR)kwSandbox_Kernel32_SetFilePointer }, { TUPLE("SetFilePointerEx"), NULL, (KUPTR)kwSandbox_Kernel32_SetFilePointerEx }, { TUPLE("DuplicateHandle"), NULL, (KUPTR)kwSandbox_Kernel32_DuplicateHandle }, { TUPLE("CloseHandle"), NULL, (KUPTR)kwSandbox_Kernel32_CloseHandle }, { TUPLE("GetFileAttributesA"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileAttributesA }, { TUPLE("GetFileAttributesW"), NULL, (KUPTR)kwSandbox_Kernel32_GetFileAttributesW }, { TUPLE("GetShortPathNameW"), NULL, (KUPTR)kwSandbox_Kernel32_GetShortPathNameW }, #ifdef WITH_TEMP_MEMORY_FILES { TUPLE("DeleteFileW"), NULL, (KUPTR)kwSandbox_Kernel32_DeleteFileW }, #endif { TUPLE("SetConsoleCtrlHandler"), NULL, (KUPTR)kwSandbox_Kernel32_SetConsoleCtrlHandler }, { TUPLE("LoadLibraryExA"), NULL, (KUPTR)kwSandbox_Kernel32_Native_LoadLibraryExA }, { TUPLE("WriteConsoleA"), NULL, (KUPTR)kwSandbox_Kernel32_WriteConsoleA }, { TUPLE("WriteConsoleW"), NULL, (KUPTR)kwSandbox_Kernel32_WriteConsoleW }, #ifdef WITH_HASH_MD5_CACHE { TUPLE("CryptCreateHash"), NULL, (KUPTR)kwSandbox_Advapi32_CryptCreateHash }, { TUPLE("CryptHashData"), NULL, (KUPTR)kwSandbox_Advapi32_CryptHashData }, { TUPLE("CryptGetHashParam"), NULL, (KUPTR)kwSandbox_Advapi32_CryptGetHashParam }, { TUPLE("CryptDestroyHash"), NULL, (KUPTR)kwSandbox_Advapi32_CryptDestroyHash }, #endif { TUPLE("RtlPcToFileHeader"), NULL, (KUPTR)kwSandbox_ntdll_RtlPcToFileHeader }, #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_X86) { TUPLE("RtlUnwind"), NULL, (KUPTR)kwSandbox_ntdll_RtlUnwind }, #endif /* * MS Visual C++ CRTs. */ { TUPLE("exit"), NULL, (KUPTR)kwSandbox_msvcrt_exit }, { TUPLE("_exit"), NULL, (KUPTR)kwSandbox_msvcrt__exit }, { TUPLE("_cexit"), NULL, (KUPTR)kwSandbox_msvcrt__cexit }, { TUPLE("_c_exit"), NULL, (KUPTR)kwSandbox_msvcrt__c_exit }, { TUPLE("_amsg_exit"), NULL, (KUPTR)kwSandbox_msvcrt__amsg_exit }, { TUPLE("terminate"), NULL, (KUPTR)kwSandbox_msvcrt_terminate }, #if 0 /* used by mspdbXXX.dll */ { TUPLE("_beginthread"), NULL, (KUPTR)kwSandbox_msvcrt__beginthread }, { TUPLE("_beginthreadex"), NULL, (KUPTR)kwSandbox_msvcrt__beginthreadex }, #endif }; /** Number of entries in g_aSandboxNativeReplacements. */ KU32 const g_cSandboxNativeReplacements = K_ELEMENTS(g_aSandboxNativeReplacements); /** * Functions that needs replacing when queried by GetProcAddress. */ KWREPLACEMENTFUNCTION const g_aSandboxGetProcReplacements[] = { /* * Kernel32.dll and friends. */ { TUPLE("FlsAlloc"), NULL, (KUPTR)kwSandbox_Kernel32_FlsAlloc, K_TRUE /*fOnlyExe*/ }, { TUPLE("FlsFree"), NULL, (KUPTR)kwSandbox_Kernel32_FlsFree, K_TRUE /*fOnlyExe*/ }, { TUPLE("TlsAlloc"), NULL, (KUPTR)kwSandbox_Kernel32_TlsAlloc, K_TRUE /*fOnlyExe*/ }, { TUPLE("TlsFree"), NULL, (KUPTR)kwSandbox_Kernel32_TlsFree, K_TRUE /*fOnlyExe*/ }, }; /** Number of entries in g_aSandboxGetProcReplacements. */ KU32 const g_cSandboxGetProcReplacements = K_ELEMENTS(g_aSandboxGetProcReplacements); /** * Control handler. * * @returns TRUE if handled, FALSE if not. * @param dwCtrlType The signal. */ static BOOL WINAPI kwSandboxCtrlHandler(DWORD dwCtrlType) { switch (dwCtrlType) { case CTRL_C_EVENT: fprintf(stderr, "kWorker: Ctrl-C\n"); g_fCtrlC = K_TRUE; exit(9); break; case CTRL_BREAK_EVENT: fprintf(stderr, "kWorker: Ctrl-Break\n"); g_fCtrlC = K_TRUE; exit(10); break; case CTRL_CLOSE_EVENT: fprintf(stderr, "kWorker: console closed\n"); g_fCtrlC = K_TRUE; exit(11); break; case CTRL_LOGOFF_EVENT: fprintf(stderr, "kWorker: logoff event\n"); g_fCtrlC = K_TRUE; exit(11); break; case CTRL_SHUTDOWN_EVENT: fprintf(stderr, "kWorker: shutdown event\n"); g_fCtrlC = K_TRUE; exit(11); break; default: fprintf(stderr, "kwSandboxCtrlHandler: %#x\n", dwCtrlType); break; } return TRUE; } /** * Used by kwSandboxExec to reset the state of the module tree. * * This is done recursively. * * @param pMod The root of the tree to consider. */ static void kwSandboxResetModuleState(PKWMODULE pMod) { if ( !pMod->fNative && pMod->u.Manual.enmState != KWMODSTATE_NEEDS_BITS) { KSIZE iImp; pMod->u.Manual.enmState = KWMODSTATE_NEEDS_BITS; iImp = pMod->u.Manual.cImpMods; while (iImp-- > 0) kwSandboxResetModuleState(pMod->u.Manual.apImpMods[iImp]); } } static PPEB kwSandboxGetProcessEnvironmentBlock(void) { #if K_ARCH == K_ARCH_X86_32 return (PPEB)__readfsdword(0x030 /* offset of ProcessEnvironmentBlock in TEB */); #elif K_ARCH == K_ARCH_AMD64 return (PPEB)__readgsqword(0x060 /* offset of ProcessEnvironmentBlock in TEB */); #else # error "Port me!" #endif } /** * Enters the given handle into the handle table. * * @returns K_TRUE on success, K_FALSE on failure. * @param pSandbox The sandbox. * @param pHandle The handle. * @param hHandle The handle value to enter it under (for the * duplicate handle API). */ static KBOOL kwSandboxHandleTableEnter(PKWSANDBOX pSandbox, PKWHANDLE pHandle, HANDLE hHandle) { KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hHandle); kHlpAssertReturn(idxHandle < KW_HANDLE_MAX, K_FALSE); /* * Grow handle table. */ if (idxHandle >= pSandbox->cHandles) { void *pvNew; KU32 cHandles = pSandbox->cHandles ? pSandbox->cHandles * 2 : 32; while (cHandles <= idxHandle) cHandles *= 2; pvNew = kHlpRealloc(pSandbox->papHandles, cHandles * sizeof(pSandbox->papHandles[0])); if (!pvNew) { KW_LOG(("Out of memory growing handle table to %u handles\n", cHandles)); return K_FALSE; } pSandbox->papHandles = (PKWHANDLE *)pvNew; kHlpMemSet(&pSandbox->papHandles[pSandbox->cHandles], 0, (cHandles - pSandbox->cHandles) * sizeof(pSandbox->papHandles[0])); pSandbox->cHandles = cHandles; } /* * Check that the entry is unused then insert it. */ kHlpAssertReturn(pSandbox->papHandles[idxHandle] == NULL, K_FALSE); pSandbox->papHandles[idxHandle] = pHandle; pSandbox->cActiveHandles++; return K_TRUE; } /** * Creates a correctly quoted ANSI command line string from the given argv. * * @returns Pointer to the command line. * @param cArgs Number of arguments. * @param papszArgs The argument vector. * @param fWatcomBrainDamange Whether to apply watcom rules while quoting. * @param pcbCmdLine Where to return the command line length, * including one terminator. */ static char *kwSandboxInitCmdLineFromArgv(KU32 cArgs, const char **papszArgs, KBOOL fWatcomBrainDamange, KSIZE *pcbCmdLine) { KU32 i; KSIZE cbCmdLine; char *pszCmdLine; /* Make a copy of the argument vector that we'll be quoting. */ char **papszQuotedArgs = alloca(sizeof(papszArgs[0]) * (cArgs + 1)); kHlpMemCopy(papszQuotedArgs, papszArgs, sizeof(papszArgs[0]) * (cArgs + 1)); /* Quote the arguments that need it. */ quote_argv(cArgs, papszQuotedArgs, fWatcomBrainDamange, 0 /*leak*/); /* figure out cmd line length. */ cbCmdLine = 0; for (i = 0; i < cArgs; i++) cbCmdLine += kHlpStrLen(papszQuotedArgs[i]) + 1; *pcbCmdLine = cbCmdLine; pszCmdLine = (char *)kHlpAlloc(cbCmdLine + 1); if (pszCmdLine) { char *psz = kHlpStrPCopy(pszCmdLine, papszQuotedArgs[0]); if (papszQuotedArgs[0] != papszArgs[0]) free(papszQuotedArgs[0]); for (i = 1; i < cArgs; i++) { *psz++ = ' '; psz = kHlpStrPCopy(psz, papszQuotedArgs[i]); if (papszQuotedArgs[i] != papszArgs[i]) free(papszQuotedArgs[i]); } kHlpAssert((KSIZE)(&psz[1] - pszCmdLine) == cbCmdLine); *psz++ = '\0'; *psz++ = '\0'; } return pszCmdLine; } static int kwSandboxInit(PKWSANDBOX pSandbox, PKWTOOL pTool, KU32 cArgs, const char **papszArgs, KBOOL fWatcomBrainDamange, KU32 cEnvVars, const char **papszEnvVars, KBOOL fNoPchCaching) { PPEB pPeb = kwSandboxGetProcessEnvironmentBlock(); PMY_RTL_USER_PROCESS_PARAMETERS pProcParams = (PMY_RTL_USER_PROCESS_PARAMETERS)pPeb->ProcessParameters; wchar_t *pwcPool; KSIZE cbStrings; KSIZE cwc; KSIZE cbCmdLine; KU32 i; /* Simple stuff. */ pSandbox->rcExitCode = 256; pSandbox->pTool = pTool; pSandbox->idMainThread = GetCurrentThreadId(); pSandbox->pgmptr = (char *)pTool->pszPath; pSandbox->wpgmptr = (wchar_t *)pTool->pwszPath; #ifdef WITH_CONSOLE_OUTPUT_BUFFERING if (pSandbox->StdOut.fIsConsole) pSandbox->StdOut.u.Con.cwcBuf = 0; else pSandbox->StdOut.u.Fully.cchBuf = 0; if (pSandbox->StdErr.fIsConsole) pSandbox->StdErr.u.Con.cwcBuf = 0; else pSandbox->StdErr.u.Fully.cchBuf = 0; pSandbox->Combined.cwcBuf = 0; pSandbox->Combined.cFlushes = 0; #endif pSandbox->fNoPchCaching = fNoPchCaching; pSandbox->cArgs = cArgs; pSandbox->papszArgs = (char **)papszArgs; pSandbox->pszCmdLine = kwSandboxInitCmdLineFromArgv(cArgs, papszArgs, fWatcomBrainDamange, &cbCmdLine); if (!pSandbox->pszCmdLine) return KERR_NO_MEMORY; /* * Convert command line and argv to UTF-16. * We assume each ANSI char requires a surrogate pair in the UTF-16 variant. */ pSandbox->papwszArgs = (wchar_t **)kHlpAlloc(sizeof(wchar_t *) * (pSandbox->cArgs + 2) + cbCmdLine * 2 * sizeof(wchar_t)); if (!pSandbox->papwszArgs) return KERR_NO_MEMORY; pwcPool = (wchar_t *)&pSandbox->papwszArgs[pSandbox->cArgs + 2]; for (i = 0; i < cArgs; i++) { *pwcPool++ = pSandbox->papszArgs[i][-1]; /* flags */ pSandbox->papwszArgs[i] = pwcPool; pwcPool += kwStrToUtf16(pSandbox->papszArgs[i], pwcPool, (kHlpStrLen(pSandbox->papszArgs[i]) + 1) * 2); pwcPool++; } pSandbox->papwszArgs[pSandbox->cArgs + 0] = NULL; pSandbox->papwszArgs[pSandbox->cArgs + 1] = NULL; /* * Convert the commandline string to UTF-16, same pessimistic approach as above. */ cbStrings = (cbCmdLine + 1) * 2 * sizeof(wchar_t); pSandbox->pwszCmdLine = kHlpAlloc(cbStrings); if (!pSandbox->pwszCmdLine) return KERR_NO_MEMORY; cwc = kwStrToUtf16(pSandbox->pszCmdLine, pSandbox->pwszCmdLine, cbStrings / sizeof(wchar_t)); pSandbox->SavedCommandLine = pProcParams->CommandLine; pProcParams->CommandLine.Buffer = pSandbox->pwszCmdLine; pProcParams->CommandLine.Length = (USHORT)cwc * sizeof(wchar_t); /* * Setup the environment. */ if ( cEnvVars + 2 <= pSandbox->cEnvVarsAllocated || kwSandboxGrowEnv(pSandbox, cEnvVars + 2) == 0) { KU32 iDst = 0; for (i = 0; i < cEnvVars; i++) { const char *pszVar = papszEnvVars[i]; KSIZE cchVar = kHlpStrLen(pszVar); const char *pszEqual; if ( cchVar > 0 && (pszEqual = kHlpMemChr(pszVar, '=', cchVar)) != NULL) { char *pszCopy = kHlpDup(pszVar, cchVar + 1); wchar_t *pwszCopy = kwStrToUtf16AllocN(pszVar, cchVar + 1); if (pszCopy && pwszCopy) { pSandbox->papszEnvVars[iDst] = pszCopy; pSandbox->environ[iDst] = pszCopy; pSandbox->papwszEnvVars[iDst] = pwszCopy; pSandbox->wenviron[iDst] = pwszCopy; /* When we see the path, we must tell the system or native exec and module loading won't work . */ if ( (pszEqual - pszVar) == 4 && ( pszCopy[0] == 'P' || pszCopy[0] == 'p') && ( pszCopy[1] == 'A' || pszCopy[1] == 'a') && ( pszCopy[2] == 'T' || pszCopy[2] == 't') && ( pszCopy[3] == 'H' || pszCopy[3] == 'h')) if (!SetEnvironmentVariableW(L"Path", &pwszCopy[5])) kwErrPrintf("kwSandboxInit: SetEnvironmentVariableW(Path,) failed: %u\n", GetLastError()); iDst++; } else { kHlpFree(pszCopy); kHlpFree(pwszCopy); return kwErrPrintfRc(KERR_NO_MEMORY, "Out of memory setting up env vars!\n"); } } else kwErrPrintf("kwSandboxInit: Skipping bad env var '%s'\n", pszVar); } pSandbox->papszEnvVars[iDst] = NULL; pSandbox->environ[iDst] = NULL; pSandbox->papwszEnvVars[iDst] = NULL; pSandbox->wenviron[iDst] = NULL; } else return kwErrPrintfRc(KERR_NO_MEMORY, "Error setting up environment variables: kwSandboxGrowEnv failed\n"); /* * Invalidate the volatile parts of cache (kBuild output directory, * temporary directory, whatever). */ kFsCacheInvalidateCustomBoth(g_pFsCache); #ifdef WITH_HISTORY /* * Record command line in debug history. */ kHlpFree(g_apszHistory[g_iHistoryNext]); g_apszHistory[g_iHistoryNext] = kHlpStrDup(pSandbox->pszCmdLine); g_iHistoryNext = (g_iHistoryNext + 1) % K_ELEMENTS(g_apszHistory); #endif return 0; } /** * Does sandbox cleanup between jobs. * * We postpone whatever isn't externally visible (i.e. files) and doesn't * influence the result, so that kmk can get on with things ASAP. * * @param pSandbox The sandbox. */ static void kwSandboxCleanupLate(PKWSANDBOX pSandbox) { PROCESS_MEMORY_COUNTERS MemInfo; PKWVIRTALLOC pTracker; PKWHEAP pHeap; PKWLOCALSTORAGE pLocalStorage; #ifdef WITH_HASH_MD5_CACHE PKWHASHMD5 pHash; #endif #ifdef WITH_TEMP_MEMORY_FILES PKWFSTEMPFILE pTempFile; #endif PKWEXITCALLACK pExitCallback; /* * First stuff that may cause code to run. */ /* Do exit callback first. */ pExitCallback = g_Sandbox.pExitCallbackHead; g_Sandbox.pExitCallbackHead = NULL; while (pExitCallback) { PKWEXITCALLACK pNext = pExitCallback->pNext; KW_LOG(("kwSandboxCleanupLate: calling %p %sexit handler\n", pExitCallback->pfnCallback, pExitCallback->fAtExit ? "at" : "_on")); __try { pExitCallback->pfnCallback(); } __except (EXCEPTION_EXECUTE_HANDLER) { KW_LOG(("kwSandboxCleanupLate: %sexit handler %p threw an exception!\n", pExitCallback->fAtExit ? "at" : "_on", pExitCallback->pfnCallback)); kHlpAssertFailed(); } kHlpFree(pExitCallback); pExitCallback = pNext; } /* Free left behind FlsAlloc leaks. */ pLocalStorage = g_Sandbox.pFlsAllocHead; g_Sandbox.pFlsAllocHead = NULL; while (pLocalStorage) { PKWLOCALSTORAGE pNext = pLocalStorage->pNext; KW_LOG(("Freeing leaked FlsAlloc index %#x\n", pLocalStorage->idx)); FlsFree(pLocalStorage->idx); kHlpFree(pLocalStorage); pLocalStorage = pNext; } /* Free left behind TlsAlloc leaks. */ pLocalStorage = g_Sandbox.pTlsAllocHead; g_Sandbox.pTlsAllocHead = NULL; while (pLocalStorage) { PKWLOCALSTORAGE pNext = pLocalStorage->pNext; KW_LOG(("Freeing leaked TlsAlloc index %#x\n", pLocalStorage->idx)); TlsFree(pLocalStorage->idx); kHlpFree(pLocalStorage); pLocalStorage = pNext; } /* * Then free resources associated with the sandbox run. */ /* Open handles, except fixed handles (stdout and stderr). */ if (pSandbox->cActiveHandles > pSandbox->cFixedHandles) { KU32 idxHandle = pSandbox->cHandles; while (idxHandle-- > 0) if (pSandbox->papHandles[idxHandle] == NULL) { /* likely */ } else { PKWHANDLE pHandle = pSandbox->papHandles[idxHandle]; if ( pHandle->enmType != KWHANDLETYPE_OUTPUT_BUF || idxHandle != KW_HANDLE_TO_INDEX(pHandle->hHandle) ) { pSandbox->papHandles[idxHandle] = NULL; pSandbox->cLeakedHandles++; switch (pHandle->enmType) { case KWHANDLETYPE_FSOBJ_READ_CACHE: KWFS_LOG(("Closing leaked read cache handle: %#x/%p cRefs=%d\n", idxHandle, pHandle->hHandle, pHandle->cRefs)); break; case KWHANDLETYPE_FSOBJ_READ_CACHE_MAPPING: KWFS_LOG(("Closing leaked read mapping handle: %#x/%p cRefs=%d\n", idxHandle, pHandle->hHandle, pHandle->cRefs)); break; case KWHANDLETYPE_OUTPUT_BUF: KWFS_LOG(("Closing leaked output buf handle: %#x/%p cRefs=%d\n", idxHandle, pHandle->hHandle, pHandle->cRefs)); break; case KWHANDLETYPE_TEMP_FILE: KWFS_LOG(("Closing leaked temp file handle: %#x/%p cRefs=%d\n", idxHandle, pHandle->hHandle, pHandle->cRefs)); pHandle->u.pTempFile->cActiveHandles--; break; case KWHANDLETYPE_TEMP_FILE_MAPPING: KWFS_LOG(("Closing leaked temp mapping handle: %#x/%p cRefs=%d\n", idxHandle, pHandle->hHandle, pHandle->cRefs)); pHandle->u.pTempFile->cActiveHandles--; break; default: kHlpAssertFailed(); } if (--pHandle->cRefs == 0) kHlpFree(pHandle); if (--pSandbox->cActiveHandles == pSandbox->cFixedHandles) break; } } kHlpAssert(pSandbox->cActiveHandles == pSandbox->cFixedHandles); } /* Reset memory mappings - This assumes none of the DLLs keeps any of our mappings open! */ g_Sandbox.cMemMappings = 0; #ifdef WITH_TEMP_MEMORY_FILES /* The temporary files aren't externally visible, they're all in memory. */ pTempFile = pSandbox->pTempFileHead; pSandbox->pTempFileHead = NULL; while (pTempFile) { PKWFSTEMPFILE pNext = pTempFile->pNext; KU32 iSeg = pTempFile->cSegs; while (iSeg-- > 0) kHlpPageFree(pTempFile->paSegs[iSeg].pbData, pTempFile->paSegs[iSeg].cbDataAlloc); kHlpFree(pTempFile->paSegs); pTempFile->pNext = NULL; kHlpFree(pTempFile); pTempFile = pNext; } #endif /* Free left behind HeapCreate leaks. */ pHeap = g_Sandbox.pHeapHead; g_Sandbox.pHeapHead = NULL; while (pHeap != NULL) { PKWHEAP pNext = pHeap->pNext; KW_LOG(("Freeing HeapCreate leak %p\n", pHeap->hHeap)); HeapDestroy(pHeap->hHeap); pHeap = pNext; } /* Free left behind VirtualAlloc leaks. */ pTracker = g_Sandbox.pVirtualAllocHead; g_Sandbox.pVirtualAllocHead = NULL; while (pTracker) { PKWVIRTALLOC pNext = pTracker->pNext; KW_LOG(("Freeing VirtualFree leak %p LB %#x\n", pTracker->pvAlloc, pTracker->cbAlloc)); #ifdef WITH_FIXED_VIRTUAL_ALLOCS if (pTracker->idxPreAllocated != KU32_MAX) kwSandboxResetFixedAllocation(pTracker->idxPreAllocated); else #endif VirtualFree(pTracker->pvAlloc, 0, MEM_RELEASE); kHlpFree(pTracker); pTracker = pNext; } /* Free the environment. */ if (pSandbox->papszEnvVars) { KU32 i; for (i = 0; pSandbox->papszEnvVars[i]; i++) kHlpFree(pSandbox->papszEnvVars[i]); pSandbox->environ[0] = NULL; pSandbox->papszEnvVars[0] = NULL; for (i = 0; pSandbox->papwszEnvVars[i]; i++) kHlpFree(pSandbox->papwszEnvVars[i]); pSandbox->wenviron[0] = NULL; pSandbox->papwszEnvVars[0] = NULL; } #ifdef WITH_HASH_MD5_CACHE /* * Hash handles. */ pHash = pSandbox->pHashHead; pSandbox->pHashHead = NULL; while (pHash) { PKWHASHMD5 pNext = pHash->pNext; KWCRYPT_LOG(("Freeing leaked hash instance %#p\n", pHash)); kHlpFree(pHash); pHash = pNext; } #endif /* * Check the memory usage. If it's getting high, trigger a respawn * after the next job. */ MemInfo.WorkingSetSize = 0; if (GetProcessMemoryInfo(GetCurrentProcess(), &MemInfo, sizeof(MemInfo))) { /* The first time thru, we figure out approximately when to restart based on installed RAM and CPU threads. */ static KU64 s_cbMaxWorkingSet = 0; if (s_cbMaxWorkingSet != 0) { /* likely */ } else { SYSTEM_INFO SysInfo; MEMORYSTATUSEX GlobalMemInfo; const char *pszValue; /* Calculate a reasonable estimate. */ kHlpMemSet(&SysInfo, 0, sizeof(SysInfo)); GetNativeSystemInfo(&SysInfo); kHlpMemSet(&GlobalMemInfo, 0, sizeof(GlobalMemInfo)); GlobalMemInfo.dwLength = sizeof(GlobalMemInfo); if (!GlobalMemoryStatusEx(&GlobalMemInfo)) #if K_ARCH_BITS >= 64 GlobalMemInfo.ullTotalPhys = KU64_C(0x000200000000); /* 8GB */ #else GlobalMemInfo.ullTotalPhys = KU64_C(0x000080000000); /* 2GB */ #endif s_cbMaxWorkingSet = GlobalMemInfo.ullTotalPhys / (K_MAX(SysInfo.dwNumberOfProcessors, 1) * 4); KW_LOG(("Raw estimate of s_cbMaxWorkingSet=%" KU64_PRI "\n", s_cbMaxWorkingSet)); /* User limit. */ pszValue = getenv("KWORKER_MEMORY_LIMIT"); if (pszValue != NULL) { char *pszNext; unsigned long ulValue = strtol(pszValue, &pszNext, 0); if (*pszNext == '\0' || *pszNext == 'M') s_cbMaxWorkingSet = ulValue * (KU64)1048576; else if (*pszNext == 'K') s_cbMaxWorkingSet = ulValue * (KU64)1024; else if (*pszNext == 'G') s_cbMaxWorkingSet = ulValue * (KU64)1073741824; else kwErrPrintf("Unable to grok KWORKER_MEMORY_LIMIT: %s\n", pszValue); KW_LOG(("User s_cbMaxWorkingSet=%" KU64_PRI "\n", s_cbMaxWorkingSet)); } /* Clamp it a little. */ if (s_cbMaxWorkingSet < 168*1024*1024) s_cbMaxWorkingSet = 168*1024*1024; #if K_ARCH_BITS < 64 else s_cbMaxWorkingSet = K_MIN(s_cbMaxWorkingSet, SysInfo.dwProcessorType != PROCESSOR_ARCHITECTURE_AMD64 ? 512*1024*1024 /* Only got 2 or 3 GB VA */ : 1536*1024*1024 /* got 4GB VA */); #endif if (s_cbMaxWorkingSet > GlobalMemInfo.ullTotalPhys) s_cbMaxWorkingSet = GlobalMemInfo.ullTotalPhys; KW_LOG(("Final s_cbMaxWorkingSet=%" KU64_PRI "\n", s_cbMaxWorkingSet)); } /* Finally the check. */ if (MemInfo.WorkingSetSize >= s_cbMaxWorkingSet) { KW_LOG(("WorkingSetSize = %#x - > restart next time.\n", MemInfo.WorkingSetSize)); g_fRestart = K_TRUE; } } /* * The CRT has a max of 8192 handles, so we better restart after a while if * someone is leaking handles or we risk running out of descriptors. * * Note! We only detect leaks for handles we intercept. In the case of CL.EXE * doing _dup2(1, 2) (stderr ==> stdout), there isn't actually a leak. */ if (pSandbox->cLeakedHandles > 6000) { KW_LOG(("LeakedHandles = %#x - > restart next time.\n", pSandbox->cLeakedHandles)); g_fRestart = K_TRUE; } } /** * Does essential cleanups and restoring, anything externally visible. * * All cleanups that aren't externally visible are postponed till after we've * informed kmk of the result, so it can be done in the dead time between jobs. * * @param pSandbox The sandbox. */ static void kwSandboxCleanup(PKWSANDBOX pSandbox) { /* * Restore the parent command line string. */ PPEB pPeb = kwSandboxGetProcessEnvironmentBlock(); PMY_RTL_USER_PROCESS_PARAMETERS pProcParams = (PMY_RTL_USER_PROCESS_PARAMETERS)pPeb->ProcessParameters; pProcParams->CommandLine = pSandbox->SavedCommandLine; pProcParams->StandardOutput = pSandbox->StdOut.hOutput; pProcParams->StandardError = pSandbox->StdErr.hOutput; /* CL.EXE messes with this one. */ } static int kwSandboxExec(PKWSANDBOX pSandbox, PKWTOOL pTool, KU32 cArgs, const char **papszArgs, KBOOL fWatcomBrainDamange, KU32 cEnvVars, const char **papszEnvVars, KBOOL fNoPchCaching) { int rcExit = 42; int rc; /* * Initialize the sandbox environment. */ rc = kwSandboxInit(&g_Sandbox, pTool, cArgs, papszArgs, fWatcomBrainDamange, cEnvVars, papszEnvVars, fNoPchCaching); if (rc == 0) { /* * Do module initialization. */ kwSandboxResetModuleState(pTool->u.Sandboxed.pExe); rc = kwLdrModuleInitTree(pTool->u.Sandboxed.pExe); if (rc == 0) { /* * Call the main function. */ #if K_ARCH == K_ARCH_AMD64 int (*pfnWin64Entrypoint)(void *pvPeb, void *, void *, void *); #elif K_ARCH == K_ARCH_X86_32 int (__cdecl *pfnWin32Entrypoint)(void *pvPeb); #else # error "Port me!" #endif /* Save the NT TIB first (should do that here, not in some other function). */ PNT_TIB pTib = (PNT_TIB)NtCurrentTeb(); pSandbox->TibMainThread = *pTib; /* Make the call in a guarded fashion. */ #if K_ARCH == K_ARCH_AMD64 /* AMD64 */ *(KUPTR *)&pfnWin64Entrypoint = pTool->u.Sandboxed.uMainAddr; __try { pSandbox->pOutXcptListHead = pTib->ExceptionList; if (setjmp(pSandbox->JmpBuf) == 0) { *(KU64*)(pSandbox->JmpBuf) = 0; /** @todo find other way to prevent longjmp from doing unwind! */ pSandbox->fRunning = K_TRUE; rcExit = pfnWin64Entrypoint(kwSandboxGetProcessEnvironmentBlock(), NULL, NULL, NULL); pSandbox->fRunning = K_FALSE; } else rcExit = pSandbox->rcExitCode; } #elif K_ARCH == K_ARCH_X86_32 /* x86 (see _tmainCRTStartup) */ *(KUPTR *)&pfnWin32Entrypoint = pTool->u.Sandboxed.uMainAddr; __try { pSandbox->pOutXcptListHead = pTib->ExceptionList; if (setjmp(pSandbox->JmpBuf) == 0) { //*(KU64*)(pSandbox->JmpBuf) = 0; /** @todo find other way to prevent longjmp from doing unwind! */ pSandbox->fRunning = K_TRUE; rcExit = pfnWin32Entrypoint(kwSandboxGetProcessEnvironmentBlock()); pSandbox->fRunning = K_FALSE; } else rcExit = pSandbox->rcExitCode; } #endif __except (EXCEPTION_EXECUTE_HANDLER) { kwErrPrintf("Caught exception %#x!\n", GetExceptionCode()); #ifdef WITH_HISTORY { KU32 cPrinted = 0; while (cPrinted++ < 5) { KU32 idx = (g_iHistoryNext + K_ELEMENTS(g_apszHistory) - cPrinted) % K_ELEMENTS(g_apszHistory); if (g_apszHistory[idx]) kwErrPrintf("cmd[%d]: %s\n", 1 - cPrinted, g_apszHistory[idx]); } } #endif rcExit = 512; } pSandbox->fRunning = K_FALSE; /* Now, restore the NT TIB. */ *pTib = pSandbox->TibMainThread; } else rcExit = 42 + 4; /* * Flush and clean up the essential bits only, postpone whatever we * can till after we've replied to kmk. */ #ifdef WITH_CONSOLE_OUTPUT_BUFFERING kwSandboxConsoleFlushAll(&g_Sandbox); #endif kwSandboxCleanup(&g_Sandbox); } else rcExit = 42 + 3; return rcExit; } /** * Does the post command part of a job (optional). * * @returns The exit code of the job. * @param cPostCmdArgs Number of post command arguments (includes cmd). * @param papszPostCmdArgs The post command and its argument. */ static int kSubmitHandleJobPostCmd(KU32 cPostCmdArgs, const char **papszPostCmdArgs) { const char *pszCmd = papszPostCmdArgs[0]; /* Allow the kmk builtin prefix. */ static const char s_szKmkBuiltinPrefix[] = "kmk_builtin_"; if (kHlpStrNComp(pszCmd, s_szKmkBuiltinPrefix, sizeof(s_szKmkBuiltinPrefix) - 1) == 0) pszCmd += sizeof(s_szKmkBuiltinPrefix) - 1; /* Command switch. */ if (kHlpStrComp(pszCmd, "kDepObj") == 0) return kmk_builtin_kDepObj(cPostCmdArgs, (char **)papszPostCmdArgs, NULL); return kwErrPrintfRc(42 + 5 , "Unknown post command: '%s'\n", pszCmd); } /** * Part 2 of the "JOB" command handler. * * @returns The exit code of the job. * @param pszExecutable The executable to execute. * @param pszCwd The current working directory of the job. * @param cArgs The number of arguments. * @param papszArgs The argument vector. * @param fWatcomBrainDamange Whether to apply watcom rules while quoting. * @param cEnvVars The number of environment variables. * @param papszEnvVars The environment vector. * @param fNoPchCaching Whether to disable precompiled header file * caching. Avoid trouble when creating them. * @param cPostCmdArgs Number of post command arguments (includes cmd). * @param papszPostCmdArgs The post command and its argument. */ static int kSubmitHandleJobUnpacked(const char *pszExecutable, const char *pszCwd, KU32 cArgs, const char **papszArgs, KBOOL fWatcomBrainDamange, KU32 cEnvVars, const char **papszEnvVars, KBOOL fNoPchCaching, KU32 cPostCmdArgs, const char **papszPostCmdArgs) { int rcExit; PKWTOOL pTool; KW_LOG(("\n\nkSubmitHandleJobUnpacked: '%s' in '%s' cArgs=%u cEnvVars=%u cPostCmdArgs=%u\n", pszExecutable, pszCwd, cArgs, cEnvVars, cPostCmdArgs)); #ifdef KW_LOG_ENABLED { KU32 i; for (i = 0; i < cArgs; i++) KW_LOG((" papszArgs[%u]=%s\n", i, papszArgs[i])); for (i = 0; i < cPostCmdArgs; i++) KW_LOG((" papszPostCmdArgs[%u]=%s\n", i, papszPostCmdArgs[i])); } #endif g_cJobs++; /* * Lookup the tool. */ pTool = kwToolLookup(pszExecutable, cEnvVars, papszEnvVars); if (pTool) { /* * Change the directory if we're going to execute the job inside * this process. Then invoke the tool type specific handler. */ switch (pTool->enmType) { case KWTOOLTYPE_SANDBOXED: case KWTOOLTYPE_WATCOM: { /* Change dir. */ KFSLOOKUPERROR enmError; PKFSOBJ pNewCurDir = kFsCacheLookupA(g_pFsCache, pszCwd, &enmError); if ( pNewCurDir == g_pCurDirObj && pNewCurDir->bObjType == KFSOBJ_TYPE_DIR) kFsCacheObjRelease(g_pFsCache, pNewCurDir); else if (SetCurrentDirectoryA(pszCwd)) { kFsCacheObjRelease(g_pFsCache, g_pCurDirObj); g_pCurDirObj = pNewCurDir; } else { kwErrPrintf("SetCurrentDirectory failed with %u on '%s'\n", GetLastError(), pszCwd); kFsCacheObjRelease(g_pFsCache, pNewCurDir); rcExit = 42 + 1; break; } /* Call specific handler. */ if (pTool->enmType == KWTOOLTYPE_SANDBOXED) { KW_LOG(("Sandboxing tool %s\n", pTool->pszPath)); rcExit = kwSandboxExec(&g_Sandbox, pTool, cArgs, papszArgs, fWatcomBrainDamange, cEnvVars, papszEnvVars, fNoPchCaching); } else { kwErrPrintf("TODO: Watcom style tool %s\n", pTool->pszPath); rcExit = 42 + 2; } break; } case KWTOOLTYPE_EXEC: kwErrPrintf("TODO: Direct exec tool %s\n", pTool->pszPath); rcExit = 42 + 2; break; default: kHlpAssertFailed(); kwErrPrintf("Internal tool type corruption!!\n"); rcExit = 42 + 2; g_fRestart = K_TRUE; break; } /* * Do the post command, if present. */ if (cPostCmdArgs && rcExit == 0) rcExit = kSubmitHandleJobPostCmd(cPostCmdArgs, papszPostCmdArgs); } else rcExit = 42 + 1; return rcExit; } /** * Handles a "JOB" command. * * @returns The exit code of the job. * @param pszMsg Points to the "JOB" command part of the message. * @param cbMsg Number of message bytes at @a pszMsg. There are * 4 more zero bytes after the message body to * simplify parsing. */ static int kSubmitHandleJob(const char *pszMsg, KSIZE cbMsg) { int rcExit = 42; /* * Unpack the message. */ const char *pszExecutable; KSIZE cbTmp; pszMsg += sizeof("JOB"); cbMsg -= sizeof("JOB"); /* Executable name. */ pszExecutable = pszMsg; cbTmp = kHlpStrLen(pszMsg) + 1; pszMsg += cbTmp; if ( cbTmp < cbMsg && cbTmp > 2) { const char *pszCwd; cbMsg -= cbTmp; /* Current working directory. */ pszCwd = pszMsg; cbTmp = kHlpStrLen(pszMsg) + 1; pszMsg += cbTmp; if ( cbTmp + sizeof(KU32) < cbMsg && cbTmp >= 2) { KU32 cArgs; cbMsg -= cbTmp; /* Argument count. */ kHlpMemCopy(&cArgs, pszMsg, sizeof(cArgs)); pszMsg += sizeof(cArgs); cbMsg -= sizeof(cArgs); if (cArgs > 0 && cArgs < 4096) { /* The argument vector. */ char const **papszArgs = kHlpAlloc((cArgs + 1) * sizeof(papszArgs[0])); if (papszArgs) { KU32 i; for (i = 0; i < cArgs; i++) { papszArgs[i] = pszMsg + 1; /* First byte is expansion flags for MSC & EMX. */ cbTmp = 1 + kHlpStrLen(pszMsg + 1) + 1; pszMsg += cbTmp; if (cbTmp < cbMsg) cbMsg -= cbTmp; else { cbMsg = 0; break; } } papszArgs[cArgs] = 0; /* Environment variable count. */ if (cbMsg > sizeof(KU32)) { KU32 cEnvVars; kHlpMemCopy(&cEnvVars, pszMsg, sizeof(cEnvVars)); pszMsg += sizeof(cEnvVars); cbMsg -= sizeof(cEnvVars); if (cEnvVars >= 0 && cEnvVars < 4096) { /* The argument vector. */ char const **papszEnvVars = kHlpAlloc((cEnvVars + 1) * sizeof(papszEnvVars[0])); if (papszEnvVars) { for (i = 0; i < cEnvVars; i++) { papszEnvVars[i] = pszMsg; cbTmp = kHlpStrLen(pszMsg) + 1; pszMsg += cbTmp; if (cbTmp < cbMsg) cbMsg -= cbTmp; else { cbMsg = 0; break; } } papszEnvVars[cEnvVars] = 0; /* Flags (currently just watcom argument brain damage and no precompiled header caching). */ if (cbMsg >= sizeof(KU8) * 2) { KBOOL fWatcomBrainDamange = *pszMsg++; KBOOL fNoPchCaching = *pszMsg++; cbMsg -= 2; /* Post command argument count (can be zero). */ if (cbMsg >= sizeof(KU32)) { KU32 cPostCmdArgs; kHlpMemCopy(&cPostCmdArgs, pszMsg, sizeof(cPostCmdArgs)); pszMsg += sizeof(cPostCmdArgs); cbMsg -= sizeof(cPostCmdArgs); if (cPostCmdArgs >= 0 && cPostCmdArgs < 32) { char const *apszPostCmdArgs[32+1]; for (i = 0; i < cPostCmdArgs; i++) { apszPostCmdArgs[i] = pszMsg; cbTmp = kHlpStrLen(pszMsg) + 1; pszMsg += cbTmp; if ( cbTmp < cbMsg || (cbTmp == cbMsg && i + 1 == cPostCmdArgs)) cbMsg -= cbTmp; else { cbMsg = KSIZE_MAX; break; } } if (cbMsg == 0) { apszPostCmdArgs[cPostCmdArgs] = NULL; /* * The next step. */ rcExit = kSubmitHandleJobUnpacked(pszExecutable, pszCwd, cArgs, papszArgs, fWatcomBrainDamange, cEnvVars, papszEnvVars, fNoPchCaching, cPostCmdArgs, apszPostCmdArgs); } else if (cbMsg == KSIZE_MAX) kwErrPrintf("Detected bogus message unpacking post command and its arguments!\n"); else kwErrPrintf("Message has %u bytes unknown trailing bytes\n", cbMsg); } else kwErrPrintf("Bogus post command argument count: %u %#x\n", cPostCmdArgs, cPostCmdArgs); } else kwErrPrintf("Detected bogus message looking for the post command argument count!\n"); } else kwErrPrintf("Detected bogus message unpacking environment variables!\n"); kHlpFree((void *)papszEnvVars); } else kwErrPrintf("Error allocating papszEnvVars for %u variables\n", cEnvVars); } else kwErrPrintf("Bogus environment variable count: %u (%#x)\n", cEnvVars, cEnvVars); } else kwErrPrintf("Detected bogus message unpacking arguments and environment variable count!\n"); kHlpFree((void *)papszArgs); } else kwErrPrintf("Error allocating argv for %u arguments\n", cArgs); } else kwErrPrintf("Bogus argument count: %u (%#x)\n", cArgs, cArgs); } else kwErrPrintf("Detected bogus message unpacking CWD path and argument count!\n"); } else kwErrPrintf("Detected bogus message unpacking executable path!\n"); return rcExit; } /** * Wrapper around WriteFile / write that writes the whole @a cbToWrite. * * @retval 0 on success. * @retval -1 on error (fully bitched). * * @param hPipe The pipe handle. * @param pvBuf The buffer to write out out. * @param cbToWrite The number of bytes to write. */ static int kSubmitWriteIt(HANDLE hPipe, const void *pvBuf, KU32 cbToWrite) { KU8 const *pbBuf = (KU8 const *)pvBuf; KU32 cbLeft = cbToWrite; for (;;) { DWORD cbActuallyWritten = 0; if (WriteFile(hPipe, pbBuf, cbLeft, &cbActuallyWritten, NULL /*pOverlapped*/)) { cbLeft -= cbActuallyWritten; if (!cbLeft) return 0; pbBuf += cbActuallyWritten; } else { DWORD dwErr = GetLastError(); if (cbLeft == cbToWrite) kwErrPrintf("WriteFile failed: %u\n", dwErr); else kwErrPrintf("WriteFile failed %u byte(s) in: %u\n", cbToWrite - cbLeft, dwErr); return -1; } } } /** * Wrapper around ReadFile / read that reads the whole @a cbToRead. * * @retval 0 on success. * @retval 1 on shut down (fShutdownOkay must be K_TRUE). * @retval -1 on error (fully bitched). * @param hPipe The pipe handle. * @param pvBuf The buffer to read into. * @param cbToRead The number of bytes to read. * @param fShutdownOkay Whether connection shutdown while reading the * first byte is okay or not. */ static int kSubmitReadIt(HANDLE hPipe, void *pvBuf, KU32 cbToRead, KBOOL fMayShutdown) { KU8 *pbBuf = (KU8 *)pvBuf; KU32 cbLeft = cbToRead; for (;;) { DWORD cbActuallyRead = 0; if (ReadFile(hPipe, pbBuf, cbLeft, &cbActuallyRead, NULL /*pOverlapped*/)) { cbLeft -= cbActuallyRead; if (!cbLeft) return 0; pbBuf += cbActuallyRead; } else { DWORD dwErr = GetLastError(); if (cbLeft == cbToRead) { if ( fMayShutdown && dwErr == ERROR_BROKEN_PIPE) return 1; kwErrPrintf("ReadFile failed: %u\n", dwErr); } else kwErrPrintf("ReadFile failed %u byte(s) in: %u\n", cbToRead - cbLeft, dwErr); return -1; } } } /** * Decimal formatting of a 64-bit unsigned value into a large enough buffer. * * @returns pszBuf * @param pszBuf The buffer (sufficiently large). * @param uValue The value. */ static const char *kwFmtU64(char *pszBuf, KU64 uValue) { char szTmp[64]; char *psz = &szTmp[63]; int cch = 4; *psz-- = '\0'; do { if (--cch == 0) { *psz-- = ' '; cch = 3; } *psz-- = (uValue % 10) + '0'; uValue /= 10; } while (uValue != 0); return strcpy(pszBuf, psz + 1); } /** * Prints statistics. */ static void kwPrintStats(void) { PROCESS_MEMORY_COUNTERS_EX MemInfo; MEMORYSTATUSEX MemStatus; IO_COUNTERS IoCounters; DWORD cHandles; KSIZE cMisses; char szBuf[16*1024]; int off = 0; char szPrf[24]; char sz1[64]; char sz2[64]; char sz3[64]; char sz4[64]; extern size_t maybe_con_fwrite(void const *pvBuf, size_t cbUnit, size_t cUnits, FILE *pFile); sprintf(szPrf, "%5d/%u:", getpid(), K_ARCH_BITS); szBuf[off++] = '\n'; off += sprintf(&szBuf[off], "%s %14s jobs, %s tools, %s modules, %s non-native ones\n", szPrf, kwFmtU64(sz1, g_cJobs), kwFmtU64(sz2, g_cTools), kwFmtU64(sz3, g_cModules), kwFmtU64(sz4, g_cNonNativeModules)); off += sprintf(&szBuf[off], "%s %14s bytes in %s read-cached files, avg %s bytes\n", szPrf, kwFmtU64(sz1, g_cbReadCachedFiles), kwFmtU64(sz2, g_cReadCachedFiles), kwFmtU64(sz3, g_cbReadCachedFiles / K_MAX(g_cReadCachedFiles, 1))); off += sprintf(&szBuf[off], "%s %14s bytes read in %s calls\n", szPrf, kwFmtU64(sz1, g_cbReadFileTotal), kwFmtU64(sz2, g_cReadFileCalls)); off += sprintf(&szBuf[off], "%s %14s bytes read (%u%%) in %s calls (%u%%) from read cached files\n", szPrf, kwFmtU64(sz1, g_cbReadFileFromReadCached), (unsigned)(g_cbReadFileFromReadCached * (KU64)100 / g_cbReadFileTotal), kwFmtU64(sz2, g_cReadFileFromReadCached), (unsigned)(g_cReadFileFromReadCached * (KU64)100 / g_cReadFileCalls)); off += sprintf(&szBuf[off], "%s %14s bytes read (%u%%) in %s calls (%u%%) from in-memory temporary files\n", szPrf, kwFmtU64(sz1, g_cbReadFileFromInMemTemp), (unsigned)(g_cbReadFileFromInMemTemp * (KU64)100 / K_MAX(g_cbReadFileTotal, 1)), kwFmtU64(sz2, g_cReadFileFromInMemTemp), (unsigned)(g_cReadFileFromInMemTemp * (KU64)100 / K_MAX(g_cReadFileCalls, 1))); off += sprintf(&szBuf[off], "%s %14s bytes written in %s calls\n", szPrf, kwFmtU64(sz1, g_cbWriteFileTotal), kwFmtU64(sz2, g_cWriteFileCalls)); off += sprintf(&szBuf[off], "%s %14s bytes written (%u%%) in %s calls (%u%%) to in-memory temporary files\n", szPrf, kwFmtU64(sz1, g_cbWriteFileToInMemTemp), (unsigned)(g_cbWriteFileToInMemTemp * (KU64)100 / K_MAX(g_cbWriteFileTotal, 1)), kwFmtU64(sz2, g_cWriteFileToInMemTemp), (unsigned)(g_cWriteFileToInMemTemp * (KU64)100 / K_MAX(g_cWriteFileCalls, 1))); off += sprintf(&szBuf[off], "%s %14s bytes for the cache\n", szPrf, kwFmtU64(sz1, g_pFsCache->cbObjects + g_pFsCache->cbAnsiPaths + g_pFsCache->cbUtf16Paths + sizeof(*g_pFsCache))); off += sprintf(&szBuf[off], "%s %14s objects, taking up %s bytes, avg %s bytes\n", szPrf, kwFmtU64(sz1, g_pFsCache->cObjects), kwFmtU64(sz2, g_pFsCache->cbObjects), kwFmtU64(sz3, g_pFsCache->cbObjects / g_pFsCache->cObjects)); off += sprintf(&szBuf[off], "%s %14s A path hashes, taking up %s bytes, avg %s bytes, %s collision\n", szPrf, kwFmtU64(sz1, g_pFsCache->cAnsiPaths), kwFmtU64(sz2, g_pFsCache->cbAnsiPaths), kwFmtU64(sz3, g_pFsCache->cbAnsiPaths / K_MAX(g_pFsCache->cAnsiPaths, 1)), kwFmtU64(sz4, g_pFsCache->cAnsiPathCollisions)); #ifdef KFSCACHE_CFG_UTF16 off += sprintf(&szBuf[off], "%s %14s W path hashes, taking up %s bytes, avg %s bytes, %s collisions\n", szPrf, kwFmtU64(sz1, g_pFsCache->cUtf16Paths), kwFmtU64(sz2, g_pFsCache->cbUtf16Paths), kwFmtU64(sz3, g_pFsCache->cbUtf16Paths / K_MAX(g_pFsCache->cUtf16Paths, 1)), kwFmtU64(sz4, g_pFsCache->cUtf16PathCollisions)); #endif off += sprintf(&szBuf[off], "%s %14s child hash tables, total of %s entries, %s children inserted, %s collisions\n", szPrf, kwFmtU64(sz1, g_pFsCache->cChildHashTabs), kwFmtU64(sz2, g_pFsCache->cChildHashEntriesTotal), kwFmtU64(sz3, g_pFsCache->cChildHashed), kwFmtU64(sz4, g_pFsCache->cChildHashCollisions)); cMisses = g_pFsCache->cLookups - g_pFsCache->cPathHashHits - g_pFsCache->cWalkHits; off += sprintf(&szBuf[off], "%s %14s lookups: %s (%u%%) path hash hits, %s (%u%%) walks hits, %s (%u%%) misses\n", szPrf, kwFmtU64(sz1, g_pFsCache->cLookups), kwFmtU64(sz2, g_pFsCache->cPathHashHits), (unsigned)(g_pFsCache->cPathHashHits * (KU64)100 / K_MAX(g_pFsCache->cLookups, 1)), kwFmtU64(sz3, g_pFsCache->cWalkHits), (unsigned)(g_pFsCache->cWalkHits * (KU64)100 / K_MAX(g_pFsCache->cLookups, 1)), kwFmtU64(sz4, cMisses), (unsigned)(cMisses * (KU64)100 / K_MAX(g_pFsCache->cLookups, 1))); off += sprintf(&szBuf[off], "%s %14s child searches, %s (%u%%) hash hits\n", szPrf, kwFmtU64(sz1, g_pFsCache->cChildSearches), kwFmtU64(sz2, g_pFsCache->cChildHashHits), (unsigned)(g_pFsCache->cChildHashHits * (KU64)100 / K_MAX(g_pFsCache->cChildSearches, 1))); off += sprintf(&szBuf[off], "%s %14s name changes, growing %s times (%u%%)\n", szPrf, kwFmtU64(sz1, g_pFsCache->cNameChanges), kwFmtU64(sz2, g_pFsCache->cNameGrowths), (unsigned)(g_pFsCache->cNameGrowths * 100 / K_MAX(g_pFsCache->cNameChanges, 1)) ); /* * Process & Memory details. */ if (!GetProcessHandleCount(GetCurrentProcess(), &cHandles)) cHandles = 0; MemInfo.cb = sizeof(MemInfo); if (!GetProcessMemoryInfo(GetCurrentProcess(), (PPROCESS_MEMORY_COUNTERS)&MemInfo, sizeof(MemInfo))) memset(&MemInfo, 0, sizeof(MemInfo)); off += sprintf(&szBuf[off], "%s %14s handles; %s page faults; %s bytes page file, peaking at %s bytes\n", szPrf, kwFmtU64(sz1, cHandles), kwFmtU64(sz2, MemInfo.PageFaultCount), kwFmtU64(sz3, MemInfo.PagefileUsage), kwFmtU64(sz4, MemInfo.PeakPagefileUsage)); off += sprintf(&szBuf[off], "%s %14s bytes working set, peaking at %s bytes; %s byte private\n", szPrf, kwFmtU64(sz1, MemInfo.WorkingSetSize), kwFmtU64(sz2, MemInfo.PeakWorkingSetSize), kwFmtU64(sz3, MemInfo.PrivateUsage)); off += sprintf(&szBuf[off], "%s %14s bytes non-paged pool, peaking at %s bytes; %s bytes paged pool, peaking at %s bytes\n", szPrf, kwFmtU64(sz1, MemInfo.QuotaNonPagedPoolUsage), kwFmtU64(sz2, MemInfo.QuotaPeakNonPagedPoolUsage), kwFmtU64(sz3, MemInfo.QuotaPagedPoolUsage), kwFmtU64(sz4, MemInfo.QuotaPeakPagedPoolUsage)); if (!GetProcessIoCounters(GetCurrentProcess(), &IoCounters)) memset(&IoCounters, 0, sizeof(IoCounters)); off += sprintf(&szBuf[off], "%s %14s bytes in %s reads [src: OS]\n", szPrf, kwFmtU64(sz1, IoCounters.ReadTransferCount), kwFmtU64(sz2, IoCounters.ReadOperationCount)); off += sprintf(&szBuf[off], "%s %14s bytes in %s writes [src: OS]\n", szPrf, kwFmtU64(sz1, IoCounters.WriteTransferCount), kwFmtU64(sz2, IoCounters.WriteOperationCount)); off += sprintf(&szBuf[off], "%s %14s bytes in %s other I/O operations [src: OS]\n", szPrf, kwFmtU64(sz1, IoCounters.OtherTransferCount), kwFmtU64(sz2, IoCounters.OtherOperationCount)); MemStatus.dwLength = sizeof(MemStatus); if (!GlobalMemoryStatusEx(&MemStatus)) memset(&MemStatus, 0, sizeof(MemStatus)); off += sprintf(&szBuf[off], "%s %14s bytes used VA, %#" KX64_PRI " bytes available\n", szPrf, kwFmtU64(sz1, MemStatus.ullTotalVirtual - MemStatus.ullAvailVirtual), MemStatus.ullAvailVirtual); off += sprintf(&szBuf[off], "%s %14u %% system memory load\n", szPrf, MemStatus.dwMemoryLoad); maybe_con_fwrite(szBuf, off, 1, stdout); fflush(stdout); } /** * Handles what comes after --test. * * @returns Exit code. * @param argc Number of arguments after --test. * @param argv Arguments after --test. */ static int kwTestRun(int argc, char **argv) { int i; int j; int rcExit; int cRepeats; char szCwd[MAX_PATH]; const char *pszCwd = getcwd(szCwd, sizeof(szCwd)); KU32 cEnvVars; KBOOL fWatcomBrainDamange = K_FALSE; KBOOL fNoPchCaching = K_FALSE; /* * Parse arguments. */ /* Repeat count. */ i = 0; if (i >= argc) return kwErrPrintfRc(2, "--test takes an repeat count argument or '--'!\n"); if (strcmp(argv[i], "--") != 0) { cRepeats = atoi(argv[i]); if (cRepeats <= 0) return kwErrPrintfRc(2, "The repeat count '%s' is zero, negative or invalid!\n", argv[i]); i++; /* Optional directory change. */ if ( i < argc && ( strcmp(argv[i], "--chdir") == 0 || strcmp(argv[i], "-C") == 0 ) ) { i++; if (i >= argc) return kwErrPrintfRc(2, "--chdir takes an argument!\n"); pszCwd = argv[i++]; } /* Optional watcom flag directory change. */ if ( i < argc && ( strcmp(argv[i], "--wcc-brain-damage") == 0 || strcmp(argv[i], "--watcom-brain-damage") == 0) ) { fWatcomBrainDamange = K_TRUE; i++; } /* Optional watcom flag directory change. */ if ( i < argc && strcmp(argv[i], "--no-pch-caching") == 0) { fNoPchCaching = K_TRUE; i++; } /* Trigger breakpoint */ if ( i < argc && strcmp(argv[i], "--breakpoint") == 0) { __debugbreak(); i++; } /* Check for '--'. */ if (i >= argc) return kwErrPrintfRc(2, "Missing '--'\n"); if (strcmp(argv[i], "--") != 0) return kwErrPrintfRc(2, "Expected '--' found '%s'\n", argv[i]); i++; } else { cRepeats = 1; i++; } if (i >= argc) return kwErrPrintfRc(2, "Nothing to execute after '--'!\n"); /* * Do the job. */ cEnvVars = 0; while (environ[cEnvVars] != NULL) cEnvVars++; for (j = 0; j < cRepeats; j++) { rcExit = kSubmitHandleJobUnpacked(argv[i], pszCwd, argc - i, &argv[i], fWatcomBrainDamange, cEnvVars, environ, fNoPchCaching, 0, NULL); KW_LOG(("rcExit=%d\n", rcExit)); kwSandboxCleanupLate(&g_Sandbox); } if (getenv("KWORKER_STATS") != NULL) kwPrintStats(); # ifdef WITH_LOG_FILE if (g_hLogFile != INVALID_HANDLE_VALUE && g_hLogFile != NULL) CloseHandle(g_hLogFile); # endif return rcExit; } int main(int argc, char **argv) { KSIZE cbMsgBuf = 0; KU8 *pbMsgBuf = NULL; int i; HANDLE hPipe = INVALID_HANDLE_VALUE; const char *pszTmp; KFSLOOKUPERROR enmIgnored; #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_X86) PVOID pvVecXcptHandler = AddVectoredExceptionHandler(0 /*called last*/, kwSandboxVecXcptEmulateChained); #endif #ifdef WITH_CONSOLE_OUTPUT_BUFFERING HANDLE hCurProc = GetCurrentProcess(); PPEB pPeb = kwSandboxGetProcessEnvironmentBlock(); PMY_RTL_USER_PROCESS_PARAMETERS pProcessParams = (PMY_RTL_USER_PROCESS_PARAMETERS)pPeb->ProcessParameters; DWORD dwType; #endif #ifdef WITH_FIXED_VIRTUAL_ALLOCS /* * Reserve memory for cl.exe */ for (i = 0; i < K_ELEMENTS(g_aFixedVirtualAllocs); i++) { g_aFixedVirtualAllocs[i].fInUse = K_FALSE; g_aFixedVirtualAllocs[i].pvReserved = VirtualAlloc((void *)g_aFixedVirtualAllocs[i].uFixed, g_aFixedVirtualAllocs[i].cbFixed, MEM_RESERVE, PAGE_READWRITE); if ( !g_aFixedVirtualAllocs[i].pvReserved || g_aFixedVirtualAllocs[i].pvReserved != (void *)g_aFixedVirtualAllocs[i].uFixed) { kwErrPrintf("Failed to reserve %p LB %#x: %u\n", g_aFixedVirtualAllocs[i].uFixed, g_aFixedVirtualAllocs[i].cbFixed, GetLastError()); if (g_aFixedVirtualAllocs[i].pvReserved) { VirtualFree(g_aFixedVirtualAllocs[i].pvReserved, g_aFixedVirtualAllocs[i].cbFixed, MEM_RELEASE); g_aFixedVirtualAllocs[i].pvReserved = NULL; } } } #endif /* * Register our Control-C and Control-Break handlers. */ if (!SetConsoleCtrlHandler(kwSandboxCtrlHandler, TRUE /*fAdd*/)) return kwErrPrintfRc(3, "SetConsoleCtrlHandler failed: %u\n", GetLastError()); /* * Create the cache and mark the temporary directory as using the custom revision. */ g_pFsCache = kFsCacheCreate(KFSCACHE_F_MISSING_OBJECTS | KFSCACHE_F_MISSING_PATHS); if (!g_pFsCache) return kwErrPrintfRc(3, "kFsCacheCreate failed!\n"); pszTmp = getenv("TEMP"); if (pszTmp && *pszTmp != '\0') kFsCacheSetupCustomRevisionForTree(g_pFsCache, kFsCacheLookupA(g_pFsCache, pszTmp, &enmIgnored)); pszTmp = getenv("TMP"); if (pszTmp && *pszTmp != '\0') kFsCacheSetupCustomRevisionForTree(g_pFsCache, kFsCacheLookupA(g_pFsCache, pszTmp, &enmIgnored)); pszTmp = getenv("TMPDIR"); if (pszTmp && *pszTmp != '\0') kFsCacheSetupCustomRevisionForTree(g_pFsCache, kFsCacheLookupA(g_pFsCache, pszTmp, &enmIgnored)); /* * Make g_abDefLdBuf executable. */ if (!VirtualProtect(g_abDefLdBuf, sizeof(g_abDefLdBuf), PAGE_EXECUTE_READWRITE, &dwType)) return kwErrPrintfRc(3, "VirtualProtect(%p, %#x, PAGE_EXECUTE_READWRITE,NULL) failed: %u\n", g_abDefLdBuf, sizeof(g_abDefLdBuf), GetLastError()); #ifdef WITH_CONSOLE_OUTPUT_BUFFERING /* * Get and duplicate the console handles. */ /* Standard output. */ g_Sandbox.StdOut.hOutput = pProcessParams->StandardOutput; if (!DuplicateHandle(hCurProc, pProcessParams->StandardOutput, hCurProc, &g_Sandbox.StdOut.hBackup, GENERIC_WRITE, FALSE /*fInherit*/, DUPLICATE_SAME_ACCESS)) kHlpAssertFailedStmt(g_Sandbox.StdOut.hBackup = pProcessParams->StandardOutput); dwType = GetFileType(g_Sandbox.StdOut.hOutput); g_Sandbox.StdOut.fIsConsole = dwType == FILE_TYPE_CHAR; g_Sandbox.StdOut.fFileType = (dwType & ~FILE_TYPE_REMOTE) < 0xf ? (KU8)((dwType & ~FILE_TYPE_REMOTE) | (dwType >> 8)) : KU8_MAX; g_Sandbox.HandleStdOut.enmType = KWHANDLETYPE_OUTPUT_BUF; g_Sandbox.HandleStdOut.cRefs = 0x10001; g_Sandbox.HandleStdOut.dwDesiredAccess = GENERIC_WRITE; g_Sandbox.HandleStdOut.u.pOutBuf = &g_Sandbox.StdOut; g_Sandbox.HandleStdOut.hHandle = g_Sandbox.StdOut.hOutput; if (g_Sandbox.StdOut.hOutput != INVALID_HANDLE_VALUE) { if (kwSandboxHandleTableEnter(&g_Sandbox, &g_Sandbox.HandleStdOut, g_Sandbox.StdOut.hOutput)) g_Sandbox.cFixedHandles++; else return kwErrPrintfRc(3, "kwSandboxHandleTableEnter failed for StdOut (%p)!\n", g_Sandbox.StdOut.hOutput); } KWOUT_LOG(("StdOut: hOutput=%p (%p) fIsConsole=%d dwType=%#x\n", g_Sandbox.StdOut.hOutput, g_Sandbox.StdOut.hBackup, g_Sandbox.StdOut.fIsConsole, dwType)); /* Standard error. */ g_Sandbox.StdErr.hOutput = pProcessParams->StandardError; if (!DuplicateHandle(hCurProc, pProcessParams->StandardError, hCurProc, &g_Sandbox.StdErr.hBackup, GENERIC_WRITE, FALSE /*fInherit*/, DUPLICATE_SAME_ACCESS)) kHlpAssertFailedStmt(g_Sandbox.StdErr.hBackup = pProcessParams->StandardError); dwType = GetFileType(g_Sandbox.StdErr.hOutput); g_Sandbox.StdErr.fIsConsole = dwType == FILE_TYPE_CHAR; g_Sandbox.StdErr.fFileType = (dwType & ~FILE_TYPE_REMOTE) < 0xf ? (KU8)((dwType & ~FILE_TYPE_REMOTE) | (dwType >> 8)) : KU8_MAX; g_Sandbox.HandleStdErr.enmType = KWHANDLETYPE_OUTPUT_BUF; g_Sandbox.HandleStdErr.cRefs = 0x10001; g_Sandbox.HandleStdErr.dwDesiredAccess = GENERIC_WRITE; g_Sandbox.HandleStdErr.u.pOutBuf = &g_Sandbox.StdErr; g_Sandbox.HandleStdErr.hHandle = g_Sandbox.StdErr.hOutput; if ( g_Sandbox.StdErr.hOutput != INVALID_HANDLE_VALUE && g_Sandbox.StdErr.hOutput != g_Sandbox.StdOut.hOutput) { if (kwSandboxHandleTableEnter(&g_Sandbox, &g_Sandbox.HandleStdErr, g_Sandbox.StdErr.hOutput)) g_Sandbox.cFixedHandles++; else return kwErrPrintfRc(3, "kwSandboxHandleTableEnter failed for StdErr (%p)!\n", g_Sandbox.StdErr.hOutput); } KWOUT_LOG(("StdErr: hOutput=%p (%p) fIsConsole=%d dwType=%#x\n", g_Sandbox.StdErr.hOutput, g_Sandbox.StdErr.hBackup, g_Sandbox.StdErr.fIsConsole, dwType)); /* Combined console buffer. */ if (g_Sandbox.StdErr.fIsConsole) { g_Sandbox.Combined.hOutput = g_Sandbox.StdErr.hBackup; g_Sandbox.Combined.uCodepage = GetConsoleCP(); } else if (g_Sandbox.StdOut.fIsConsole) { g_Sandbox.Combined.hOutput = g_Sandbox.StdOut.hBackup; g_Sandbox.Combined.uCodepage = GetConsoleCP(); } else { g_Sandbox.Combined.hOutput = INVALID_HANDLE_VALUE; g_Sandbox.Combined.uCodepage = CP_ACP; } KWOUT_LOG(("Combined: hOutput=%p uCodepage=%d\n", g_Sandbox.Combined.hOutput, g_Sandbox.Combined.uCodepage)); #endif /* WITH_CONSOLE_OUTPUT_BUFFERING */ /* * Parse arguments. */ for (i = 1; i < argc; i++) { if (strcmp(argv[i], "--pipe") == 0) { i++; if (i < argc) { char *pszEnd = NULL; unsigned __int64 u64Value = _strtoui64(argv[i], &pszEnd, 16); if ( *argv[i] && pszEnd != NULL && *pszEnd == '\0' && u64Value != 0 && u64Value != (uintptr_t)INVALID_HANDLE_VALUE && (uintptr_t)u64Value == u64Value) hPipe = (HANDLE)(uintptr_t)u64Value; else return kwErrPrintfRc(2, "Invalid --pipe argument: %s\n", argv[i]); } else return kwErrPrintfRc(2, "--pipe takes an argument!\n"); } else if (strcmp(argv[i], "--volatile") == 0) { i++; if (i < argc) kFsCacheSetupCustomRevisionForTree(g_pFsCache, kFsCacheLookupA(g_pFsCache, argv[i], &enmIgnored)); else return kwErrPrintfRc(2, "--volatile takes an argument!\n"); } else if (strcmp(argv[i], "--test") == 0) return kwTestRun(argc - i - 1, &argv[i + 1]); else if (strcmp(argv[i], "--priority") == 0) { i++; if (i < argc) { char *pszEnd = NULL; unsigned long uValue = strtoul(argv[i], &pszEnd, 16); if ( *argv[i] && pszEnd != NULL && *pszEnd == '\0' && uValue >= 1 && uValue <= 5) { DWORD dwClass, dwPriority; switch (uValue) { case 1: dwClass = IDLE_PRIORITY_CLASS; dwPriority = THREAD_PRIORITY_IDLE; break; case 2: dwClass = BELOW_NORMAL_PRIORITY_CLASS; dwPriority = THREAD_PRIORITY_BELOW_NORMAL; break; case 3: dwClass = NORMAL_PRIORITY_CLASS; dwPriority = THREAD_PRIORITY_NORMAL; break; case 4: dwClass = HIGH_PRIORITY_CLASS; dwPriority = 0xffffffff; break; case 5: dwClass = REALTIME_PRIORITY_CLASS; dwPriority = 0xffffffff; break; } SetPriorityClass(GetCurrentProcess(), dwClass); if (dwPriority != 0xffffffff) SetThreadPriority(GetCurrentThread(), dwPriority); } else return kwErrPrintfRc(2, "Invalid --priority argument: %s\n", argv[i]); } else return kwErrPrintfRc(2, "--priority takes an argument!\n"); } else if ( strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-?") == 0) { printf("usage: kWorker [--volatile dir] [--priority <1-5>] --pipe \n" "usage: kWorker <--help|-h>\n" "usage: kWorker <--version|-V>\n" "usage: kWorker [--volatile dir] --test [ [--chdir ] [--breakpoint] -- args\n" "\n" "This is an internal kmk program that is used via the builtin_kSubmit.\n"); return 0; } else if ( strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-V") == 0) return kbuild_version(argv[0]); else return kwErrPrintfRc(2, "Unknown argument '%s'\n", argv[i]); } if (hPipe == INVALID_HANDLE_VALUE) return kwErrPrintfRc(2, "Missing --pipe argument!\n"); /* * Serve the pipe. */ for (;;) { KU32 cbMsg = 0; int rc = kSubmitReadIt(hPipe, &cbMsg, sizeof(cbMsg), K_TRUE /*fShutdownOkay*/); if (rc == 0) { /* Make sure the message length is within sane bounds. */ if ( cbMsg > 4 && cbMsg <= 256*1024*1024) { /* Reallocate the message buffer if necessary. We add 4 zero bytes. */ if (cbMsg + 4 <= cbMsgBuf) { /* likely */ } else { cbMsgBuf = K_ALIGN_Z(cbMsg + 4, 2048); pbMsgBuf = kHlpRealloc(pbMsgBuf, cbMsgBuf); if (!pbMsgBuf) return kwErrPrintfRc(1, "Failed to allocate %u bytes for a message buffer!\n", cbMsgBuf); } /* Read the whole message into the buffer, making sure there is are a 4 zero bytes following it. */ *(KU32 *)pbMsgBuf = cbMsg; rc = kSubmitReadIt(hPipe, &pbMsgBuf[sizeof(cbMsg)], cbMsg - sizeof(cbMsg), K_FALSE /*fShutdownOkay*/); if (rc == 0) { const char *psz; pbMsgBuf[cbMsg] = '\0'; pbMsgBuf[cbMsg + 1] = '\0'; pbMsgBuf[cbMsg + 2] = '\0'; pbMsgBuf[cbMsg + 3] = '\0'; /* The first string after the header is the command. */ psz = (const char *)&pbMsgBuf[sizeof(cbMsg)]; if (strcmp(psz, "JOB") == 0) { struct { KI32 rcExitCode; KU8 bExiting; KU8 abZero[3]; } Reply; Reply.rcExitCode = kSubmitHandleJob(psz, cbMsg - sizeof(cbMsg)); Reply.bExiting = g_fRestart; Reply.abZero[0] = 0; Reply.abZero[1] = 0; Reply.abZero[2] = 0; rc = kSubmitWriteIt(hPipe, &Reply, sizeof(Reply)); if ( rc == 0 && !g_fRestart) { kwSandboxCleanupLate(&g_Sandbox); continue; } } else rc = kwErrPrintfRc(-1, "Unknown command: '%s'\n", psz); } } else rc = kwErrPrintfRc(-1, "Bogus message length: %u (%#x)\n", cbMsg, cbMsg); } /* * If we're exitting because we're restarting, we need to delay till * kmk/kSubmit has read the result. Windows documentation says it * immediately discards pipe buffers once the pipe is broken by the * server (us). So, We flush the buffer and queues a 1 byte read * waiting for kSubmit to close the pipe when it receives the * bExiting = K_TRUE result. */ if (g_fRestart) { KU8 b; FlushFileBuffers(hPipe); ReadFile(hPipe, &b, 1, &cbMsg, NULL); } CloseHandle(hPipe); #ifdef WITH_LOG_FILE if (g_hLogFile != INVALID_HANDLE_VALUE && g_hLogFile != NULL) CloseHandle(g_hLogFile); #endif if (getenv("KWORKER_STATS") != NULL) kwPrintStats(); return rc > 0 ? 0 : 1; } } /** @page pg_kWorker kSubmit / kWorker * * @section sec_kWorker_Motivation Motivation / Inspiration * * The kSubmit / kWorker combo was conceived as a way to speed up VirtualBox * builds on machines "infested" by Anti Virus protection and disk encryption * software. Build times jumping from 35-40 min to 77-82 min after the machine * got "infected". * * Speeing up builting of Boot Sector Kit \#3 was also hightly desirable. It is * mainly a bunch of tiny assembly and C files being compiler a million times. * As some of us OS/2 users maybe recalls, the Watcom make program can run its * own toolchain from within the same process, saving a lot of process creation * and teardown overhead. * * * @section sec_kWorker_kSubmit About kSubmit * * When wanting to execute a job in a kWorker instance, it must be submitted * using the kmk_builtin_kSubmit command in kmk. As the name suggest, this is * built into kmk and does not exist as an external program. The reason for * this is that it keep track of the kWorker instances. * * The kSubmit command has the --32-bit and --64-bit options for selecting * between 32-bit and 64-bit worker instance. We generally assume the user of * the command knows which bit count the executable has, so kSubmit is spared * the extra work of finding out. * * The kSubmit command shares a environment and current directory manipulation * with the kRedirect command, but not the file redirection. So long no file * operation is involed, kSubmit is a drop in kRedirect replacement. This is * hand for tools like OpenWatcom, NASM and YASM which all require environment * and/or current directory changes to work. * * Unlike the kRedirect command, the kSubmit command can also specify an * internall post command to be executed after the main command succeeds. * Currently only kmk_builtin_kDepObj is supported. kDepObj gathers dependency * information from Microsoft COFF object files and Watcom OMF object files and * is scheduled to replace kDepIDB. * * * @section sec_kWorker_Interaction kSubmit / kWorker interaction * * The kmk_builtin_kSubmit communicates with the kWorker instances over pipes. * A job request is written by kSubmit and kWorker read, unpacks it and executes * it. When the job is completed, kWorker writes a short reply with the exit * code and an internal status indicating whether it is going to restart. * * The kWorker intance will reply to kSubmit before completing all the internal * cleanup work, so as not to delay the next job execution unnecessarily. This * includes checking its own memory consumption and checking whether it needs * restarting. So, a decision to restart unfortunately have to wait till after * the next job has completed. This is a little bit unfortunate if the next job * requires a lot of memory and kWorker has already leaked/used a lot. * * * @section sec_kWorker_How_Works How kWorker Works * * kWorker will load the executable specified by kSubmit into memory and call * it's entrypoint in a lightly sandbox'ed environment. * * * @subsection ssec_kWorker_Loaing Image loading * * kWorker will manually load all the executable images into memory, fix them * up, and make a copy of the virgin image so it can be restored using memcpy * the next time it is used. * * Imported functions are monitored and replacements used for a few of them. * These replacements are serve the following purposes: * - Provide a different command line. * - Provide a different environment. * - Intercept process termination. * - Intercept thread creation (only linker is allowed to create threads). * - Intercept file reading for caching (header files, ++) as file system * access is made even slower by anti-virus software. * - Intercept crypto hash APIs to cache MD5 digests of header files * (c1.dll / c1xx.dll spends a noticable bit of time doing MD5). * - Intercept temporary files (%TEMP%/_CL_XXXXXXyy) to keep the entirely * in memory as writing files grows expensive with encryption and * anti-virus software active. * - Intercept some file system queries to use the kFsCache instead of * going to the kernel and slowly worm thru the AV filter driver. * - Intercept standard output/error and console writes to aggressivly * buffer the output. The MS CRT does not buffer either when it goes to * the console, resulting in terrible performance and mixing up output * with other compile jobs. * This also allows us to filter out the annoying source file announcements * by cl.exe. * - Intercept VirtualAlloc and VirtualFree to prevent * CL.EXE/C1.DLL/C1XX.DLL from leaking some 72MB internal allocat area. * - Intercept FlsAlloc/FlsFree to make sure the allocations are freed and * the callbacks run after each job. * - Intercept HeapCreate/HeapFree to reduce leaks from statically linked * executables and tools using custom heaps (like the microsoft linker). * [exectuable images only] * - Intercept atexit and _onexit registration to be able run them after * each job instead of crashing as kWorker exits. This also helps avoid * some leaks. [executable image only] * * DLLs falls into two categories, system DLLs which we always load using the * native loader, and tool DLLs which can be handled like the executable or * optionally using the native loader. We maintain a hardcoded white listing of * tool DLLs we trust to load using the native loader. * * Imports of natively loaded DLLs are processed too, but we only replace a * subset of the functions compared to natively loaded excutable and DLL images. * * DLLs are never unloaded and we cache LoadLibrary requests (hash the input). * This is to speed up job execution. * * It was thought that we needed to restore (memcpy) natively loaded tool DLLs * for each job run, but so far this hasn't been necessary. * * * @subsection ssec_kWorker_Optimizing Optimizing the Compiler * * The Visual Studio 2010 C/C++ compiler does a poor job at processing header * files and uses a whole bunch of temporary files (in %TEMP%) for passing * intermediate representation between the first (c1/c1xx.dll) and second pass * (c2.dll). * * kWorker helps the compiler as best as it can. Given a little knowledge about * stable and volatile file system areas, it can do a lot of caching that a * normal compiler driver cannot easily do when given a single file. * * * @subsubsection sssec_kWorker_Headers Cache Headers Files and Searches * * The preprocessor part will open and process header files exactly as they are * encountered in the source files. If string.h is included by the main source * and five other header files, it will be searched for (include path), opened, * read, MD5-summed, and pre-processed six times. The last five times is just a * waste of time because of the guards or \#pragma once. A smart compiler would * make a little extra effort and realize this. * * kWorker will cache help the preprocessor by remembering places where the * header was not found with help of kFsCache, and cache the file in memory when * found. The first part is taken care of by intercepting GetFileAttributesW, * and the latter by intercepting CreateFileW, ReadFile and CloseFile. Once * cached, the file is kept open and the CreateFileW call returns a duplicate of * that handle. An internal handle table is used by ReadFile and CloseFile to * keep track of intercepted handles (also used for temporary file, temporary * file mappings, console buffering, and standard out/err buffering). * * PS. The header search optimization also comes in handy when cl.exe goes on * thru the whole PATH looking for c1/c1xx.exe and c2.exe after finding * c1/c1xx.dll and c2.dll. My guess is that the compiler team can * optionally compile the three pass DLLs as executables during development * and problem analysis. * * * @subsubsection sssec_kWorker_Temp_Files Temporary Files In Memory * * The issues of the temporary files is pretty severe on the Dell machine used * for benchmarking with full AV and encryption. The synthetic benchmark * improved by 30% when kWorker implemented measures to keep them entirely in * memory. * * kWorker implement these by recognizing the filename pattern in CreateFileW * and creating/opening the given file as needed. The handle returned is a * duplicate of the current process, thus giving us a good chance of catching * API calls we're not intercepting. * * In addition to CreateFileW, we also need to intercept GetFileType, ReadFile, * WriteFile, SetFilePointer+Ex, SetEndOfFile, and CloseFile. The 2nd pass * additionally requires GetFileSize+Ex, CreateFileMappingW, MapViewOfFile and * UnmapViewOfFile. * * * @section sec_kWorker_Numbers Some measurements. * * - r2881 building src/VBox/Runtime: * - without: 2m01.016388s = 120.016388 s * - with: 1m15.165069s = 75.165069 s => 120.016388s - 75.165069s = 44.851319s => 44.85/120.02 = 37% speed up. * - r2884 building vbox/debug (r110512): * - without: 11m14.446609s = 674.446609 s * - with: 9m01.017344s = 541.017344 s => 674.446609s - 541.017344s = 133.429265 => 133.43/674.45 = 19% speed up * - r2896 building vbox/debug (r110577): * - with: 8m31.182384s = 511.182384 s => 674.446609s - 511.182384s = 163.264225 = 163.26/674.45 = 24% speed up * - r2920 building vbox/debug (r110702) on Skylake (W10/amd64, only standard * MS Defender as AV): * - without: 10m24.990389s = 624.990389s * - with: 08m04.738184s = 484.738184s * - delta: 624.99s - 484.74s = 140.25s * - saved: 140.25/624.99 = 22% faster * * * @subsection subsec_kWorker_Early_Numbers Early Experiments * * These are some early experiments doing 1024 compilations of * VBoxBS2Linker.cpp using a hard coded command line and looping in kWorker's * main function: * * Skylake (W10/amd64, only stdandard MS defender): * - cmd 1: 48 /1024 = 0x0 (0.046875) [for /l %i in (1,1,1024) do ...] * - kmk 1: 44 /1024 = 0x0 (0.04296875) [all: ; 1024 x cl.exe] * - run 1: 37 /1024 = 0x0 (0.0361328125) [just process creation gain] * - run 2: 34 /1024 = 0x0 (0.033203125) [get file attribs] * - run 3: 32.77 /1024 = 0x0 (0.032001953125) [read caching of headers] * - run 4: 32.67 /1024 = 0x0 (0.031904296875) [loader tweaking] * - run 5: 29.144/1024 = 0x0 (0.0284609375) [with temp files in memory] * * Dell (W7/amd64, infected by mcafee): * - kmk 1: 285.278/1024 = 0x0 (0.278591796875) * - run 1: 134.503/1024 = 0x0 (0.1313505859375) [w/o temp files in memory] * - run 2: 78.161/1024 = 0x0 (0.0763291015625) [with temp files in memory] * * The command line: * @code{.cpp} "\"E:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/bin/amd64/cl.exe\" -c -c -TP -nologo -Zi -Zi -Zl -GR- -EHsc -GF -Zc:wchar_t- -Oy- -MT -W4 -Wall -wd4065 -wd4996 -wd4127 -wd4706 -wd4201 -wd4214 -wd4510 -wd4512 -wd4610 -wd4514 -wd4820 -wd4365 -wd4987 -wd4710 -wd4061 -wd4986 -wd4191 -wd4574 -wd4917 -wd4711 -wd4611 -wd4571 -wd4324 -wd4505 -wd4263 -wd4264 -wd4738 -wd4242 -wd4244 -WX -RTCsu -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/include -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/atlmfc/include -IE:/vbox/svn/trunk/tools/win.x86/sdk/v7.1/Include -IE:/vbox/svn/trunk/include -IE:/vbox/svn/trunk/out/win.amd64/debug -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/include -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/atlmfc/include -DVBOX -DVBOX_WITH_64_BITS_GUESTS -DVBOX_WITH_REM -DVBOX_WITH_RAW_MODE -DDEBUG -DDEBUG_bird -DDEBUG_USERNAME=bird -DRT_OS_WINDOWS -D__WIN__ -DRT_ARCH_AMD64 -D__AMD64__ -D__WIN64__ -DVBOX_WITH_DEBUGGER -DRT_LOCK_STRICT -DRT_LOCK_STRICT_ORDER -DIN_RING3 -DLOG_DISABLED -DIN_BLD_PROG -D_CRT_SECURE_NO_DEPRECATE -FdE:/vbox/svn/trunk/out/win.amd64/debug/obj/VBoxBs2Linker/VBoxBs2Linker-obj.pdb -FD -FoE:/vbox/svn/trunk/out/win.amd64/debug/obj/VBoxBs2Linker/VBoxBs2Linker.obj E:\\vbox\\svn\\trunk\\src\\VBox\\ValidationKit\\bootsectors\\VBoxBs2Linker.cpp" * @endcode */ kbuild-3149/src/kLibTweaker/0000755000175000017500000000000013252530215015675 5ustar locutuslocutuskbuild-3149/src/kLibTweaker/kLibTweaker.c0000644000175000017500000006005513252530215020253 0ustar locutuslocutus/* $Id: kLibTweaker.c 2791 2015-09-15 22:57:44Z bird $ */ /** @file * kLibTweaker - Import library tweaker for windows. */ /* * Copyright (c) 2007-2015 knut st. osmundsen * * This file is part of kBuild. * * kBuild 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. * * kBuild 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 kBuild. If not, see * */ /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ #if 0 # define ELECTRIC_HEAP # include "../kmk/electric.h" # include "../kmk/electric.c" #endif #include #include #include #include #include #include #include #include "k/kLdrFmts/pe.h" /********************************************************************************************************************************* * Structures and Typedefs * *********************************************************************************************************************************/ /** * Microsoft import library archive header. * * This has the same size as a COFF header, which is probably not a coincidence. */ typedef struct COFFIMPLIBHDR { KU16 uSig1; /* 0 */ KU16 uSig2; /* 0xffff */ KU16 uVersion; /* 0 */ KU16 uMachine; /* IMAGE_FILE_MACHINE_I386, ... */ KU32 uTimeDateStamp; KU32 cbData; KU16 uOrdinalOrHint; KU16 uFlags; } COFFIMPLIBHDR; /** * COFF symbol. * * This one has an odd size and will cause misaligned accesses on platforms * which cares about such. */ #pragma pack(1) typedef struct COFFSYMBOL { union { char e_name[8]; struct { KU32 e_zeros; /**< Zero to distinguish it from ascii name. */ KU32 e_offset; /**< String table offset. */ } e; } e; KU32 e_value; KI16 e_scnum; KU16 e_type; KU8 e_sclass; KU8 e_numaux; } COFFSYMBOL; #pragma pack() /** * Archive file header. */ typedef struct ARCHFILEHDR { char achName[16]; char achModtime[12]; char achOwnerId[6]; char achGroupId[6]; char achMode[8]; char achSize[10]; char achMagic[2]; } ARCHFILEHDR; /********************************************************************************************************************************* * Global Variables * *********************************************************************************************************************************/ /** Whether verbose output is enabled. */ static unsigned g_cVerbosityLevel = 0; /** What to prefix the errors with. */ static char g_szErrorPrefix[128]; void FatalMsg(const char *pszFormat, ...) { va_list va; if (g_szErrorPrefix[0]) fprintf(stderr, "%s - fatal error: ", g_szErrorPrefix); else fprintf(stderr, "fatal error: "); va_start(va, pszFormat); vfprintf(stderr, pszFormat, va); va_end(va); } void FatalDie(const char *pszFormat, ...) { va_list va; if (g_szErrorPrefix[0]) fprintf(stderr, "%s - fatal error: ", g_szErrorPrefix); else fprintf(stderr, "fatal error: "); va_start(va, pszFormat); vfprintf(stderr, pszFormat, va); va_end(va); exit(1); } static int ErrorMsg(const char *pszFormat, ...) { va_list va; if (g_szErrorPrefix[0]) fprintf(stderr, "%s - error: ", g_szErrorPrefix); else fprintf(stderr, "error: "); va_start(va, pszFormat); vfprintf(stderr, pszFormat, va); va_end(va); return 1; } static void InfoMsg(unsigned uLevel, const char *pszFormat, ...) { if (uLevel <= g_cVerbosityLevel) { va_list va; if (g_szErrorPrefix[0]) fprintf(stderr, "%s - info: ", g_szErrorPrefix); else fprintf(stderr, "info: "); va_start(va, pszFormat); vfprintf(stderr, pszFormat, va); va_end(va); } } static void SetErrorPrefix(const char *pszPrefix, ...) { int cch; va_list va; va_start(va, pszPrefix); #if defined(_MSC_VER) || defined(__sun__) cch = vsprintf(g_szErrorPrefix, pszPrefix, va); if (cch >= sizeof(g_szErrorPrefix)) FatalDie("Buffer overflow setting error prefix!\n"); #else vsnprintf(g_szErrorPrefix, sizeof(g_szErrorPrefix), pszPrefix, va); #endif va_end(va); (void)cch; } #ifndef ELECTRIC_HEAP void *xmalloc(size_t cb) { void *pv = malloc(cb); if (!pv) FatalDie("out of memory (%d)\n", (int)cb); return pv; } void *xrealloc(void *pvOld, size_t cb) { void *pv = realloc(pvOld, cb); if (!pv) FatalDie("out of memory (%d)\n", (int)cb); return pv; } char *xstrdup(const char *pszIn) { char *psz; if (pszIn) { psz = strdup(pszIn); if (!psz) FatalDie("out of memory (%d)\n", (int)strlen(pszIn)); } else psz = NULL; return psz; } #endif void *xmallocz(size_t cb) { void *pv = xmalloc(cb); memset(pv, 0, cb); return pv; } /** * Adds the arguments found in the pszCmdLine string to argument vector. * * The parsing of the pszCmdLine string isn't very sophisticated, no * escaping or quotes. * * @param pcArgs Pointer to the argument counter. * @param ppapszArgs Pointer to the argument vector pointer. * @param pszCmdLine The command line to parse and append. * @param pszWedgeArg Argument to put infront of anything found in pszCmdLine. */ static void AppendArgs(int *pcArgs, char ***ppapszArgs, const char *pszCmdLine, const char *pszWedgeArg) { int i; int cExtraArgs; const char *psz; char **papszArgs; /* * Count the new arguments. */ cExtraArgs = 0; psz = pszCmdLine; while (*psz) { while (isspace(*psz)) psz++; if (!psz) break; cExtraArgs++; while (!isspace(*psz) && *psz) psz++; } if (!cExtraArgs) return; /* * Allocate a new vector that can hold the arguments. * (Reallocating might not work since the argv might not be allocated * from the heap but off the stack or somewhere... ) */ i = *pcArgs; *pcArgs = i + cExtraArgs + !!pszWedgeArg; papszArgs = xmalloc((*pcArgs + 1) * sizeof(char *)); *ppapszArgs = memcpy(papszArgs, *ppapszArgs, i * sizeof(char *)); if (pszWedgeArg) papszArgs[i++] = xstrdup(pszWedgeArg); psz = pszCmdLine; while (*psz) { size_t cch; const char *pszEnd; while (isspace(*psz)) psz++; if (!psz) break; pszEnd = psz; while (!isspace(*pszEnd) && *pszEnd) pszEnd++; cch = pszEnd - psz; papszArgs[i] = xmalloc(cch + 1); memcpy(papszArgs[i], psz, cch); papszArgs[i][cch] = '\0'; i++; psz = pszEnd; } papszArgs[i] = NULL; } static fpos_t kLibTweakerAsciiToSize(const char *pch, size_t cch) { fpos_t cb = 0; /* strip leading spaces. */ while (cch > 0 && (*pch == ' ' || *pch == '\t')) cch--, pch++; /* Convert decimal to binary. */ while (cch-- > 0) { char ch = *pch++; if (ch >= '0' && ch <= '9') { cb *= 10; cb += ch - '0'; } else break; } return cb; } static int kLibMyReadAt(FILE *pFile, void *pv, size_t cb, fpos_t off, int fEofOk) { if (fsetpos(pFile, &off) == 0) { size_t cbActual = fread(pv, 1, cb, pFile); if (cbActual == cb) return 0; if (!fEofOk || !feof(pFile)) ErrorMsg("fread returned %#lx, expected %#lx!\n", (unsigned long)cbActual, (unsigned long)cb); } else ErrorMsg("seek error!\n"); return 1; } static int kLibMyWriteAt(FILE *pFile, const void *pv, size_t cb, fpos_t off) { if (fsetpos(pFile, &off) == 0) { size_t cbActual = fwrite(pv, 1, cb, pFile); if (cbActual == cb) return 0; ErrorMsg("fwrite returned %#lx, expected %#lx!\n", (unsigned long)cbActual, (unsigned long)cb); } else ErrorMsg("seek error!\n"); return 1; } static int kLibFillNullThunkData(FILE *pFile, fpos_t cbFile, fpos_t offFileBytes) { size_t off; IMAGE_FILE_HEADER CoffHdr; IMAGE_SECTION_HEADER SecHdr; unsigned iSecHdr; fpos_t offCur; unsigned cbMachineWord; KU32 cbStrTab; COFFSYMBOL *paSymbols; int rcRet = 0; /* * Read the COFF file header and filter out unlikly files based on * section and symbol counts. */ if (cbFile <= sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_SECTION_HEADER) * 2 + 4) return 0; if (kLibMyReadAt(pFile, &CoffHdr, sizeof(CoffHdr), offFileBytes, 0) != 0) return 1; if ( CoffHdr.Machine != IMAGE_FILE_MACHINE_I386 && CoffHdr.Machine != IMAGE_FILE_MACHINE_AMD64) return 0; cbMachineWord = CoffHdr.Machine == IMAGE_FILE_MACHINE_I386 ? 4 : 8; if ( CoffHdr.NumberOfSections == 0 || CoffHdr.NumberOfSymbols == 0) return 0; off = sizeof(IMAGE_FILE_HEADER) + CoffHdr.NumberOfSections * sizeof(IMAGE_SECTION_HEADER); if ((fpos_t)off >= cbFile) return 0; if ( CoffHdr.PointerToSymbolTable >= (KU64)cbFile || CoffHdr.PointerToSymbolTable < off) return 0; /* * Search for the .idata$5 section which the thunk data is usually found in. */ offCur = offFileBytes + sizeof(CoffHdr); for (iSecHdr = 0; iSecHdr < CoffHdr.NumberOfSections; iSecHdr++) { if (kLibMyReadAt(pFile, &SecHdr, sizeof(SecHdr), offCur, 0) != 0) return 1; InfoMsg(2, "#2: %.8s VirtualSize=%#lx\n", SecHdr.Name, SecHdr.SizeOfRawData); if ( !memcmp(SecHdr.Name, ".idata$5", 8) && SecHdr.SizeOfRawData == cbMachineWord) break; offCur += sizeof(SecHdr); } if (iSecHdr == CoffHdr.NumberOfSections) return 0; /* * Read in the symbo and string tables. */ off = CoffHdr.PointerToSymbolTable + CoffHdr.NumberOfSymbols * sizeof(COFFSYMBOL); if (kLibMyReadAt(pFile, &cbStrTab, sizeof(cbStrTab), offFileBytes + off, 0) != 0) return 1; InfoMsg(2, "#2: Found COFF file header, cbStrTab=%#x; off=%#lx NumberOfSymbols=%#x PointerToSymbolTable=%#x\n", cbStrTab, (long)off, CoffHdr.NumberOfSymbols, CoffHdr.PointerToSymbolTable); if ( cbStrTab <= 4U || cbStrTab >= 16*1024*1024U /* 16MB */ || (fpos_t)off + cbStrTab > cbFile) return 0; paSymbols = xmalloc(CoffHdr.NumberOfSymbols * sizeof(COFFSYMBOL) + cbStrTab + 1); if (kLibMyReadAt(pFile, paSymbols, CoffHdr.NumberOfSymbols * sizeof(COFFSYMBOL) + cbStrTab, offFileBytes + CoffHdr.PointerToSymbolTable, 0) == 0) { char *pchStrTab = (char *)&paSymbols[CoffHdr.NumberOfSymbols]; unsigned iSym; pchStrTab[cbStrTab] = '\0'; pchStrTab[0] = '\0'; pchStrTab[1] = '\0'; pchStrTab[2] = '\0'; pchStrTab[3] = '\0'; for (iSym = 0; iSym < CoffHdr.NumberOfSymbols; iSym++) { static char const s_szSuffix[] = "NULL_THUNK_DATA"; const char *pchName; size_t cchName; if (paSymbols[iSym].e.e.e_zeros != 0) { pchName = &paSymbols[iSym].e.e_name[0]; cchName = (char *)memchr(pchName, '\0', sizeof(paSymbols[iSym].e.e_name)) - pchName; if (cchName > sizeof(paSymbols[iSym].e.e_name)) cchName = sizeof(paSymbols[iSym].e.e_name); } else if ( paSymbols[iSym].e.e.e_offset == 0 || paSymbols[iSym].e.e.e_offset >= cbStrTab) continue; else { pchName = &pchStrTab[paSymbols[iSym].e.e.e_offset]; cchName = strlen(pchName); } if ( *pchName == 0x7f && cchName >= sizeof(s_szSuffix) && memcmp(&pchName[cchName - sizeof(s_szSuffix) + 1], s_szSuffix, sizeof(s_szSuffix) - 1) == 0) { if (pchName[cchName] == '\0') InfoMsg(1, "#2: Found '%s': value=%#lx\n", pchName, paSymbols[iSym].e_value); else InfoMsg(1, "#2: Found '%.8s': value=%#lx\n", pchName, paSymbols[iSym].e_value); if ( paSymbols[iSym].e_scnum > 0 && paSymbols[iSym].e_scnum <= CoffHdr.NumberOfSections) { if (paSymbols[iSym].e_scnum != iSecHdr + 1) InfoMsg(0, "#2: '%s' in section %u, expected %u\n", pchName, paSymbols[iSym].e_scnum, iSecHdr); else if (paSymbols[iSym].e_value != 0) InfoMsg(0, "#2: '%s' in value %#xu, expected 0x0\n", pchName, paSymbols[iSym].e_value); else if ( SecHdr.PointerToRawData < sizeof(CoffHdr) + CoffHdr.NumberOfSections * sizeof(IMAGE_SECTION_HEADER) || (fpos_t)SecHdr.PointerToRawData + cbMachineWord > cbFile) InfoMsg(0, "#2: Unexpected PointerToRawData value: %#x\n", SecHdr.PointerToRawData); else { union { KU8 ab[8]; KU32 u32; KU64 u64; } uBuf; uBuf.u64 = 0; off = offFileBytes + SecHdr.PointerToRawData; if (kLibMyReadAt(pFile, &uBuf, cbMachineWord, off, 0) == 0) { static const KU8 s_abGarbage[8] = { 0xaa, 0x99, 0x88, 0xbb, 0xbb, 0xaa, 0x88, 0x99 }; static const KU8 s_abZero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; if (memcmp(&uBuf, s_abZero,cbMachineWord) == 0) { rcRet = kLibMyWriteAt(pFile, s_abGarbage, cbMachineWord, off); if (!rcRet) InfoMsg(1, "#2: Updated '%s'\n", pchName); } else if (memcmp(&uBuf, s_abGarbage, cbMachineWord) == 0) { InfoMsg(1, "#2: Already modified '%s'\n", pchName); rcRet = 0; } else rcRet = ErrorMsg(0, "#2: Unexpected '%s' data: %02x %02x %02x %02x %02x %02x %02x %02x\n", pchName, uBuf.ab[0], uBuf.ab[1], uBuf.ab[2], uBuf.ab[3], uBuf.ab[4], uBuf.ab[5], uBuf.ab[6], uBuf.ab[7]); } break; } } } } } else rcRet = 1; free(paSymbols); return rcRet; } /** * Clears timestamps to avoid rebuilding stuff just because the internal * timestamps changed in an import library. */ static int kLibClearTimestamps(FILE *pFile, fpos_t offFileHdr, ARCHFILEHDR *pFileHdr, fpos_t cbFile, fpos_t offFileBytes) { union { IMAGE_FILE_HEADER CoffHdr; COFFIMPLIBHDR ImpLibHdr; } u; if (sizeof(u.CoffHdr) != sizeof(u.ImpLibHdr)) FatalDie("Oops!"); /* * Clear the timestamp in the library file header. */ memset(pFileHdr->achModtime, '0', sizeof(pFileHdr->achModtime)); if (kLibMyWriteAt(pFile, pFileHdr, sizeof(*pFileHdr), offFileHdr) != 0) return 1; /* * Clear the timestamp in the COFF header, if we find one. */ if (cbFile <= sizeof(IMAGE_FILE_HEADER)) return 0; if (kLibMyReadAt(pFile, &u.CoffHdr, sizeof(u.CoffHdr), offFileBytes, 0) != 0) return 1; if ( ( u.CoffHdr.Machine == IMAGE_FILE_MACHINE_I386 || u.CoffHdr.Machine == IMAGE_FILE_MACHINE_AMD64) && sizeof(IMAGE_FILE_HEADER) + u.CoffHdr.NumberOfSections * sizeof(IMAGE_SECTION_HEADER) <= (KU64)cbFile && u.CoffHdr.PointerToSymbolTable <= (KU64)cbFile) { InfoMsg(1, "Found COFF file header\n"); if (u.CoffHdr.TimeDateStamp != 0) { u.CoffHdr.TimeDateStamp = 0; return kLibMyWriteAt(pFile, &u.CoffHdr, sizeof(u.CoffHdr), offFileBytes); } } else if ( u.ImpLibHdr.uSig1 == 0 && u.ImpLibHdr.uSig2 == 0xffff && u.ImpLibHdr.uVersion == 0 && ( u.ImpLibHdr.uMachine == IMAGE_FILE_MACHINE_I386 || u.ImpLibHdr.uMachine == IMAGE_FILE_MACHINE_AMD64) && u.ImpLibHdr.cbData <= cbFile) { InfoMsg(1, "Found COFF import library header\n"); if (u.ImpLibHdr.uTimeDateStamp) { u.ImpLibHdr.uTimeDateStamp = 0; return kLibMyWriteAt(pFile, &u.ImpLibHdr, sizeof(u.ImpLibHdr), offFileBytes); } } else InfoMsg(1, "CoffHdr.Machine=%#x ImpLibHdr.Machine=%#x\n", u.CoffHdr.Machine, u.ImpLibHdr.uMachine); return 0; } static int kLibTweakerDoIt(const char *pszLib, int fClearTimestamps, int fFillNullThunkData) { int rcRet = 0; FILE *pFile = fopen(pszLib, "r+b"); if (pFile) { /* * Read the header. */ static char s_szMagic[] = "!\n"; union { char ab[1024]; IMAGE_FILE_HEADER CoffHdr; } uBuf; if ( fread(uBuf.ab, 1, sizeof(s_szMagic) - 1, pFile) == sizeof(s_szMagic) - 1 && memcmp(uBuf.ab, s_szMagic, sizeof(s_szMagic) - 1) == 0) { fpos_t offFileHdr = sizeof(s_szMagic) - 1; while (!feof(pFile)) { ARCHFILEHDR FileHdr; if (kLibMyReadAt(pFile, &FileHdr, sizeof(FileHdr), offFileHdr, 1) != 0) { if (feof(pFile)) break; rcRet = ErrorMsg("failed reading the file header (offset %ld)\n", (long)offFileHdr); break; } if ( FileHdr.achMagic[0] == 0x60 && FileHdr.achMagic[1] == 0x0a) { fpos_t const offFileBytes = offFileHdr + sizeof(FileHdr); /* * Convert the size from decimal to binary as we need it to skip to * the next file header. */ fpos_t const cb = kLibTweakerAsciiToSize(FileHdr.achSize, sizeof(FileHdr.achSize)); InfoMsg(1, "Found header at %#lx: cbFile=%#lx, bytes at %#lx\n", (unsigned long)offFileHdr, (unsigned long)cb, (unsigned long)offFileBytes); /* * Make the requested changes. */ if (fClearTimestamps) rcRet |= kLibClearTimestamps(pFile, offFileHdr, &FileHdr, cb, offFileBytes); if (fFillNullThunkData) rcRet |= kLibFillNullThunkData(pFile, cb, offFileBytes); /* * Skip to the next header. */ offFileHdr = offFileBytes + ((cb + 1) & ~(fpos_t)1); } else rcRet = ErrorMsg("invalid file header magic (offset %ld)\n", (long)offFileHdr); } } else rcRet = ErrorMsg("Didn't find '!\\n' magic in '%s' (or read error)\n", pszLib); if (fclose(pFile) != 0) rcRet = ErrorMsg("Error closing '%s'\n"); } else rcRet = ErrorMsg("Failed to open '%s' for read+write\n", pszLib); return rcRet; } /** * Prints a syntax error and returns the appropriate exit code * * @returns approriate exit code. * @param pszFormat The syntax error message. * @param ... Message args. */ static int SyntaxError(const char *pszFormat, ...) { va_list va; fprintf(stderr, "kObjCache: syntax error: "); va_start(va, pszFormat); vfprintf(stderr, pszFormat, va); va_end(va); return 1; } /** * Prints the usage. * @returns 0. */ static int usage(FILE *pOut) { fprintf(pOut, "syntax: kLibTweaker [-v|--verbose] [--clear-timestamps] \n" "\n"); return 0; } int main(int argc, char **argv) { char *psz; int i; int fClearTimestamps = 0; int fFillNullThunkData = 0; const char *pszLib = NULL; SetErrorPrefix("kLibTweaker"); /* * Arguments passed in the environmnet? */ psz = getenv("KLIBTWEAKER_OPTS"); if (psz) AppendArgs(&argc, &argv, psz, NULL); /** @todo Add the capability to produce import/stub libraries from ELF shared * objects that we can use while linking and break up linking dependencies * (i.e. not relink everything just because something in VBoxRT change that * didn't make any difference to the symbols it exports). */ /* * Parse the arguments. */ if (argc <= 1) return usage(stderr) + 1; for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "--clear-timestamps")) fClearTimestamps = 1; else if (!strcmp(argv[i], "--fill-null_thunk_data")) fFillNullThunkData = 1; /* Standard stuff: */ else if (!strcmp(argv[i], "--help")) return usage(stderr); else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose")) g_cVerbosityLevel++; else if (!strcmp(argv[i], "-q") || !strcmp(argv[i], "--quiet")) g_cVerbosityLevel = 0; else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-?") || !strcmp(argv[i], "/h") || !strcmp(argv[i], "/?") || !strcmp(argv[i], "/help")) return usage(stdout); else if (!strcmp(argv[i], "-V") || !strcmp(argv[i], "--version")) { printf("kLibTweaker - kBuild version %d.%d.%d ($Revision: 2791 $)\n" "Copyright (c) 2007-2015 knut st. osmundsen\n", KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH); return 0; } else if (!strcmp(argv[i], "--")) { i++; if (i == argc) return SyntaxError("No library given!\n"); if (i + 1 != argc || pszLib) return SyntaxError("Only one library can be tweaked at a time!\n"); pszLib = argv[i]; break; } else if (argv[i][0] == '-') return SyntaxError("Doesn't grok '%s'!\n", argv[i]); else if (!pszLib) pszLib = argv[i]; else return SyntaxError("Only one library can be tweaked at a time!\n"); } if (!pszLib) return SyntaxError("No library given!\n"); return kLibTweakerDoIt(pszLib, fClearTimestamps, fFillNullThunkData); } kbuild-3149/src/kLibTweaker/Makefile.kmk0000644000175000017500000000214313252530215020116 0ustar locutuslocutus# $Id: Makefile.kmk 2791 2015-09-15 22:57:44Z bird $ ## @file # Sub-makefile for kLibTweaker. # # # Copyright (c) 2007-2015 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # SUB_DEPTH = ../.. include $(PATH_KBUILD)/subheader.kmk PROGRAMS += kLibTweaker kLibTweaker_TEMPLATE = BIN kLibTweaker_DEFS.release = NASSERT kLibTweaker_SOURCES = kLibTweaker.c kLibTweaker_INCS = ../lib kLibTweaker_LIBS = \ $(LIB_KDEP) \ $(LIB_KUTIL) include $(KBUILD_PATH)/subfooter.kmk kbuild-3149/src/kmk/0000755000175000017500000000000013252530204014251 5ustar locutuslocutuskbuild-3149/src/kmk/NEWS0000644000175000017500000020503013252530176014760 0ustar locutuslocutusGNU make NEWS -*-indented-text-*- History of user-visible changes. 10 June 2016 See the end of this file for copyrights and conditions. All changes mentioned here are more fully described in the GNU make manual, which is contained in this distribution as the file doc/make.texi. See the README file and the GNU make manual for instructions for reporting bugs. Version 4.2.1 (10 Jun 2016) A complete list of bugs fixed in this version is available here: h ttp://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=107&set=custom This release is a bug-fix release. Version 4.2 (22 May 2016) A complete list of bugs fixed in this version is available here: http://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=106&set=custom * New variable: $(.SHELLSTATUS) is set to the exit status of the last != or $(shell ...) function invoked in this instance of make. This will be "0" if successful or not "0" if not successful. The variable value is unset if no != or $(shell ...) function has been invoked. * The $(file ...) function can now read from a file with $(file * The interface to GNU make's "jobserver" is stable as documented in the manual, for tools which may want to access it. WARNING: Backward-incompatibility! The internal-only command line option --jobserver-fds has been renamed for publishing, to --jobserver-auth. * The amount of parallelism can be determined by querying MAKEFLAGS, even when the job server is enabled (previously MAKEFLAGS would always contain only "-j", with no number, when job server was enabled). * VMS-specific changes: * Perl test harness now works. * Full support for converting Unix exit status codes to VMS exit status codes. BACKWARD INCOMPATIBILITY Notice: On a child failure the VMS exit code is now the encoded Unix exit status that Make usually generates, not the VMS exit status of the child. Version 4.1 (05 Oct 2014) A complete list of bugs fixed in this version is available here: http://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=105&set=custom * New variables: $(MAKE_TERMOUT) and $(MAKE_TERMERR) are set to non-empty values if stdout or stderr, respectively, are believed to be writing to a terminal. These variables are exported by default. * Allow a no-text-argument form of the $(file ...) function. Without a text argument nothing is written to the file: it is simply opened in the requested mode, then closed again. * Change the fatal error for mixed explicit and implicit rules, that was introduced in GNU make 3.82, to a non-fatal error. However, this syntax is still deprecated and may return to being illegal in a future version of GNU make. Makefiles that rely on this syntax should be fixed. See https://savannah.gnu.org/bugs/?33034 * VMS-specific changes: * Support for library files added, including support for using the GNV ar utility. * Partial support for properly encoding Unix exit status codes into VMS exit status codes. WARNING: Backward-incompatibility! These are different exit status codes than Make exited with in the past. * Macros to hold the current make command are set up to translate the argv[0] string to a VMS format path name and prefix it with "MCR " so that the macro has a space in it. WARNING: Backward-incompatibility! This may break complex makefiles that do processing on those macros. This is unlikely because so much in that area was not and is still not currently working on VMS, it is unlikely to find such a complex makefile, so this is more likely to impact construction of a future makefile. * A command file is always used to run the commands for a recipe. WARNING: Backward-incompatibility! Running the make self tests has exposed that there are significant differences in behavior when running with the command file mode. It is unknown if this will be noticed by most existing VMS makefiles. Version 4.0 (09 Oct 2013) A complete list of bugs fixed in this version is available here: http://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=101&set=custom * WARNING: Backward-incompatibility! If .POSIX is specified, then make adheres to the POSIX backslash/newline handling requirements, which introduces the following changes to the standard backslash/newline handling in non-recipe lines: * Any trailing space before the backslash is preserved * Each backslash/newline (plus subsequent whitespace) is converted to a single space * New feature: GNU Guile integration This version of GNU make can be compiled with GNU Guile integration. GNU Guile serves as an embedded extension language for make. See the "Guile Function" section in the GNU Make manual for details. Currently GNU Guile 1.8 and 2.0+ are supported. In Guile 1.8 there is no support for internationalized character sets. In Guile 2.0+, scripts can be encoded in UTF-8. * New command line option: --output-sync (-O) enables grouping of output by target or by recursive make. This is useful during parallel builds to avoid mixing output from different jobs together giving hard-to-understand results. Original implementation by David Boyce . Reworked and enhanced by Frank Heckenbach . Windows support by Eli Zaretskii . * New command line option: --trace enables tracing of targets. When enabled the recipe to be invoked is printed even if it would otherwise be suppressed by .SILENT or a "@" prefix character. Also before each recipe is run the makefile name and linenumber where it was defined are shown as well as the prerequisites that caused the target to be considered out of date. * New command line option argument: --debug now accepts a "n" (none) flag which disables all debugging settings that are currently enabled. * New feature: The "job server" capability is now supported on Windows. Implementation contributed by Troy Runkel * New feature: The .ONESHELL capability is now supported on Windows. Support added by Eli Zaretskii . * New feature: "!=" shell assignment operator as an alternative to the $(shell ...) function. Implemented for compatibility with BSD makefiles. Note there are subtle differences between "!=" and $(shell ...). See the description in the GNU make manual. WARNING: Backward-incompatibility! Variables ending in "!" previously defined as "variable!= value" will now be interpreted as shell assignment. Change your assignment to add whitespace between the "!" and "=": "variable! = value" * New feature: "::=" simple assignment operator as defined by POSIX in 2012. This operator has identical functionality to ":=" in GNU make, but will be portable to any implementation of make conforming to a sufficiently new version of POSIX (see http://austingroupbugs.net/view.php?id=330). It is not necessary to define the .POSIX target to access this operator. * New feature: Loadable objects This version of GNU make contains a "technology preview": the ability to load dynamic objects into the make runtime. These objects can be created by the user and can add extended functionality, usable by makefiles. * New function: $(file ...) writes to a file. * New variable: $(GNUMAKEFLAGS) will be parsed for make flags, just like MAKEFLAGS is. It can be set in the environment or the makefile, containing GNU make-specific flags to allow your makefile to be portable to other versions of make. Once this variable is parsed, GNU make will set it to the empty string so that flags will not be duplicated on recursion. * New variable: `MAKE_HOST' gives the name of the host architecture make was compiled for. This is the same value you see after 'Built for' when running 'make --version'. * Behavior of MAKEFLAGS and MFLAGS is more rigorously defined. All simple flags are grouped together in the first word of MAKEFLAGS. No options that accept arguments appear in the first word. If no simple flags are present MAKEFLAGS begins with a space. Flags with both short and long versions always use the short versions in MAKEFLAGS. Flags are listed in alphabetical order using ASCII ordering. MFLAGS never begins with "- ". * Setting the -r and -R options in MAKEFLAGS inside a makefile now works as expected, removing all built-in rules and variables, respectively. * If a recipe fails, the makefile name and linenumber of the recipe are shown. * A .RECIPEPREFIX setting is remembered per-recipe and variables expanded in that recipe also use that recipe prefix setting. * In -p output, .RECIPEPREFIX settings are shown and all target-specific variables are output as if in a makefile, instead of as comments. * On MS-Windows, recipes that use ".." quoting will no longer force invocation of commands via temporary batch files and stock Windows shells, they will be short-circuited and invoked directly. (In other words, " is no longer a special character for stock Windows shells.) This avoids hitting shell limits for command length when quotes are used, but nothing else in the command requires the shell. This change could potentially mean some minor incompatibilities in behavior when the recipe uses quoted string on shell command lines. Version 3.82 (28 Jul 2010) A complete list of bugs fixed in this version is available here: http://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=104&set=custom * Compiling GNU make now requires a conforming ISO C 1989 compiler and standard runtime library. * WARNING: Backward-incompatibility! The POSIX standard for make was changed in the 2008 version in a fundamentally incompatible way: make is required to invoke the shell as if the '-e' flag were provided. Because this would break many makefiles that have been written to conform to the original text of the standard, the default behavior of GNU make remains to invoke the shell with simply '-c'. However, any makefile specifying the .POSIX special target will follow the new POSIX standard and pass '-e' to the shell. See also .SHELLFLAGS below. * WARNING: Backward-incompatibility! The '$?' variable now contains all prerequisites that caused the target to be considered out of date, even if they do not exist (previously only existing targets were provided in $?). * WARNING: Backward-incompatibility! Wildcards were not documented as returning sorted values, but the results have been sorted up until this release.. If your makefiles require sorted results from wildcard expansions, use the $(sort ...) function to request it explicitly. * WARNING: Backward-incompatibility! As a result of parser enhancements, three backward-compatibility issues exist: first, a prerequisite containing an "=" cannot be escaped with a backslash any longer. You must create a variable containing an "=" and use that variable in the prerequisite. Second, variable names can no longer contain whitespace, unless you put the whitespace in a variable and use the variable. Third, in previous versions of make it was sometimes not flagged as an error for explicit and pattern targets to appear in the same rule. Now this is always reported as an error. * WARNING: Backward-incompatibility! The pattern-specific variables and pattern rules are now applied in the shortest stem first order instead of the definition order (variables and rules with the same stem length are still applied in the definition order). This produces the usually-desired behavior where more specific patterns are preferred. To detect this feature search for 'shortest-stem' in the .FEATURES special variable. * WARNING: Backward-incompatibility! The library search behavior has changed to be compatible with the standard linker behavior. Prior to this version for prerequisites specified using the -lfoo syntax make first searched for libfoo.so in the current directory, vpath directories, and system directories. If that didn't yield a match, make then searched for libfoo.a in these directories. Starting with this version make searches first for libfoo.so and then for libfoo.a in each of these directories in order. * New command line option: --eval=STRING causes STRING to be evaluated as makefile syntax (akin to using the $(eval ...) function). The evaluation is performed after all default rules and variables are defined, but before any makefiles are read. * New special variable: .RECIPEPREFIX allows you to reset the recipe introduction character from the default (TAB) to something else. The first character of this variable value is the new recipe introduction character. If the variable is set to the empty string, TAB is used again. It can be set and reset at will; recipes will use the value active when they were first parsed. To detect this feature check the value of $(.RECIPEPREFIX). * New special variable: .SHELLFLAGS allows you to change the options passed to the shell when it invokes recipes. By default the value will be "-c" (or "-ec" if .POSIX is set). * New special target: .ONESHELL instructs make to invoke a single instance of the shell and provide it with the entire recipe, regardless of how many lines it contains. As a special feature to allow more straightforward conversion of makefiles to use .ONESHELL, any recipe line control characters ('@', '+', or '-') will be removed from the second and subsequent recipe lines. This happens _only_ if the SHELL value is deemed to be a standard POSIX-style shell. If not, then no interior line control characters are removed (as they may be part of the scripting language used with the alternate SHELL). * New variable modifier 'private': prefixing a variable assignment with the modifier 'private' suppresses inheritance of that variable by prerequisites. This is most useful for target- and pattern-specific variables. * New make directive: 'undefine' allows you to undefine a variable so that it appears as if it was never set. Both $(flavor) and $(origin) functions will return 'undefined' for such a variable. To detect this feature search for 'undefine' in the .FEATURES special variable. * The parser for variable assignments has been enhanced to allow multiple modifiers ('export', 'override', 'private') on the same line as variables, including define/endef variables, and in any order. Also, it is possible to create variables and targets named as these modifiers. * The 'define' make directive now allows a variable assignment operator after the variable name, to allow for simple, conditional, or appending multi-line variable assignment. * VMS-specific changes: * Michael Gehre (at VISTEC-SEMI dot COM) supplied a fix for a problem with timestamps of object modules in OLBs. The timestamps were not correctly adjusted to GMT based time, if the local VMS time was using a daylight saving algorithm and if daylight saving was switched off. * John Eisenbraun (at HP dot COM) supplied fixes and and an enhancement to append output redirection in action lines. * Rework of ctrl+c and ctrl+y handling. * Fix a problem with cached strings, which showed on case-insensitive file systems. * Build fixes for const-ified code in VMS specific sources. * A note on appending the redirected output. With this change, a simple mechanism is implemented to make ">>" work in action lines. In VMS there is no simple feature like ">>" to have DCL command or program output redirected and appended to a file. GNU make for VMS already implements the redirection of output. If such a redirection is detected, an ">" on the action line, GNU make creates a DCL command procedure to execute the action and to redirect its output. Based on that, now ">>" is also recognized and a similar but different command procedure is created to implement the append. The main idea here is to create a temporary file which collects the output and which is appended to the wanted output file. Then the temporary file is deleted. This is all done in the command procedure to keep changes in make small and simple. This obviously has some limitations but it seems good enough compared with the current ">" implementation. (And in my opinion, redirection is not really what GNU make has to do.) With this approach, it may happen that the temporary file is not yet appended and is left in SYS$SCRATCH. The temporary file names look like "CMDxxxxx.". Any time the created command procedure can not complete, this happens. Pressing Ctrl+Y to abort make is one case. In case of Ctrl+Y the associated command procedure is left in SYS$SCRATCH as well. Its name is CMDxxxxx.COM. * Change in the Ctrl+Y handling. The CtrlY handler now uses $delprc to delete all children. This way also actions with DCL commands will be stopped. As before the CtrlY handler then sends SIGQUIT to itself, which is handled in common code. * Change in deleteing temporary command files. Temporary command files are now deleted in the vms child termination handler. That deletes them even if a Ctrl+C was pressed. * The behavior of pressing Ctrl+C is not changed. It still has only an effect, after the current action is terminated. If that doesn't happen or takes too long, Ctrl+Y should be used instead. Version 3.81 (01 Apr 2006) * GNU make is ported to OS/2. * GNU make is ported to MinGW. The MinGW build is only supported by the build_w32.bat batch file; see the file README.W32 for more details. * WARNING: Future backward-incompatibility! Up to and including this release, the '$?' variable does not contain any prerequisite that does not exist, even though that prerequisite might have caused the target to rebuild. Starting with the _next_ release of GNU make, '$?' will contain all prerequisites that caused the target to be considered out of date. See http://savannah.gnu.org/bugs/?16051 * WARNING: Backward-incompatibility! GNU make now implements a generic "second expansion" feature on the prerequisites of both explicit and implicit (pattern) rules. In order to enable this feature, the special target '.SECONDEXPANSION' must be defined before the first target which takes advantage of it. If this feature is enabled then after all rules have been parsed the prerequisites are expanded again, this time with all the automatic variables in scope. This means that in addition to using standard SysV $$@ in prerequisites lists, you can also use complex functions such as $$(notdir $$@) etc. This behavior applies to implicit rules, as well, where the second expansion occurs when the rule is matched. However, this means that when '.SECONDEXPANSION' is enabled you must double-quote any "$" in your filenames; instead of "foo: boo$$bar" you now must write "foo: foo$$$$bar". Note that the SysV $$@ etc. feature, which used to be available by default, is now ONLY available when the .SECONDEXPANSION target is defined. If your makefiles take advantage of this SysV feature you will need to update them. * WARNING: Backward-incompatibility! In order to comply with POSIX, the way in which GNU make processes backslash-newline sequences in recipes has changed. If your makefiles use backslash-newline sequences inside of single-quoted strings in recipes you will be impacted by this change. See the GNU make manual subsection "Splitting Recipe Lines" (node "Splitting Lines"), in section "Recipe Syntax", chapter "Writing Recipe in Rules", for details. * WARNING: Backward-incompatibility! Some previous versions of GNU make had a bug where "#" in a function invocation such as $(shell ...) was treated as a make comment. A workaround was to escape these with backslashes. This bug has been fixed: if your makefile uses "\#" in a function invocation the backslash is now preserved, so you'll need to remove it. * New command line option: -L (--check-symlink-times). On systems that support symbolic links, if this option is given then GNU make will use the most recent modification time of any symbolic links that are used to resolve target files. The default behavior remains as it always has: use the modification time of the actual target file only. * The "else" conditional line can now be followed by any other valid conditional on the same line: this does not increase the depth of the conditional nesting, so only one "endif" is required to close the conditional. * All pattern-specific variables that match a given target are now used (previously only the first match was used). * Target-specific variables can be marked as exportable using the "export" keyword. * In a recursive $(call ...) context, any extra arguments from the outer call are now masked in the context of the inner call. * Implemented a solution for the "thundering herd" problem with "-j -l". This version of GNU make uses an algorithm suggested by Thomas Riedl to track the number of jobs started in the last second and artificially adjust GNU make's view of the system's load average accordingly. * New special variables available in this release: - .INCLUDE_DIRS: Expands to a list of directories that make searches for included makefiles. - .FEATURES: Contains a list of special features available in this version of GNU make. - .DEFAULT_GOAL: Set the name of the default goal make will use if no goals are provided on the command line. - MAKE_RESTARTS: If set, then this is the number of times this instance of make has been restarted (see "How Makefiles Are Remade" in the manual). - New automatic variable: $| (added in 3.80, actually): contains all the order-only prerequisites defined for the target. * New functions available in this release: - $(lastword ...) returns the last word in the list. This gives identical results as $(word $(words ...) ...), but is much faster. - $(abspath ...) returns the absolute path (all "." and ".." directories resolved, and any duplicate "/" characters removed) for each path provided. - $(realpath ...) returns the canonical pathname for each path provided. The canonical pathname is the absolute pathname, with all symbolic links resolved as well. - $(info ...) prints its arguments to stdout. No makefile name or line number info, etc. is printed. - $(flavor ...) returns the flavor of a variable. - $(or ...) provides a short-circuiting OR conditional: each argument is expanded. The first true (non-empty) argument is returned; no further arguments are expanded. Expands to empty if there are no true arguments. - $(and ...) provides a short-circuiting AND conditional: each argument is expanded. The first false (empty) argument is returned; no further arguments are expanded. Expands to the last argument if all arguments are true. * Changes made for POSIX compatibility: - Only touch targets (under -t) if they have a recipe. - Setting the SHELL make variable does NOT change the value of the SHELL environment variable given to programs invoked by make. As an enhancement to POSIX, if you export the make variable SHELL then it will be set in the environment, just as before. * On MS Windows systems, explicitly setting SHELL to a pathname ending in "cmd" or "cmd.exe" (case-insensitive) will force GNU make to use the DOS command interpreter in batch mode even if a UNIX-like shell could be found on the system. * On VMS there is now support for case-sensitive filesystems such as ODS5. See the README.VMS file for information. * Parallel builds (-jN) no longer require a working Bourne shell on Windows platforms. They work even with the stock Windows shells, such as cmd.exe and command.com. * Updated to autoconf 2.59, automake 1.9.5, and gettext 0.14.1. Users should not be impacted. * New translations for Swedish, Chinese (simplified), Ukrainian, Belarusian, Finnish, Kinyarwandan, and Irish. Many updated translations. A complete list of bugs fixed in this version is available here: http://savannah.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=103 Version 3.80 (03 Oct 2002) * A new feature exists: order-only prerequisites. These prerequisites affect the order in which targets are built, but they do not impact the rebuild/no-rebuild decision of their dependents. That is to say, they allow you to require target B be built before target A, without requiring that target A will always be rebuilt if target B is updated. Patch for this feature provided by Greg McGary . * For compatibility with SysV make, GNU make now supports the peculiar syntax $$@, $$(@D), and $$(@F) in the prerequisites list of a rule. This syntax is only valid within explicit and static pattern rules: it cannot be used in implicit (suffix or pattern) rules. Edouard G. Parmelan provided a patch implementing this feature; however, I decided to implement it in a different way. * The argument to the "ifdef" conditional is now expanded before it's tested, so it can be a constructed variable name. Similarly, the arguments to "export" (when not used in a variable definition context) and "unexport" are also now expanded. * A new function is defined: $(value ...). The argument to this function is the _name_ of a variable. The result of the function is the value of the variable, without having been expanded. * A new function is defined: $(eval ...). The arguments to this function should expand to makefile commands, which will then be evaluated as if they had appeared in the makefile. In combination with define/endef multiline variable definitions this is an extremely powerful capability. The $(value ...) function is also sometimes useful here. * A new built-in variable is defined, $(MAKEFILE_LIST). It contains a list of each makefile GNU make has read, or started to read, in the order in which they were encountered. So, the last filename in the list when a makefile is just being read (before any includes) is the name of the current makefile. * A new built-in variable is defined: $(.VARIABLES). When it is expanded it returns a complete list of variable names defined by all makefiles at that moment. * A new command line option is defined, -B or --always-make. If specified GNU make will consider all targets out-of-date even if they would otherwise not be. * The arguments to $(call ...) functions were being stored in $1, $2, etc. as recursive variables, even though they are fully expanded before assignment. This means that escaped dollar signs ($$ etc.) were not behaving properly. Now the arguments are stored as simple variables. This may mean that if you added extra escaping to your $(call ...) function arguments you will need to undo it now. * The variable invoked by $(call ...) can now be recursive: unlike other variables it can reference itself and this will not produce an error when it is used as the first argument to $(call ...) (but only then). * New pseudo-target .LOW_RESOLUTION_TIME, superseding the configure option --disable-nsec-timestamps. You might need this if your build process depends on tools like "cp -p" preserving time stamps, since "cp -p" (right now) doesn't preserve the subsecond portion of a time stamp. * Updated translations for French, Galician, German, Japanese, Korean, and Russian. New translations for Croatian, Danish, Hebrew, and Turkish. * Updated internationalization support to Gettext 0.11.5. GNU make now uses Gettext's "external" feature, and does not include any internationalization code itself. Configure will search your system for an existing implementation of GNU Gettext (only GNU Gettext is acceptable) and use it if it exists. If not, NLS will be disabled. See ABOUT-NLS for more information. * Updated to autoconf 2.54 and automake 1.7. Users should not be impacted. * VMS-specific changes: * In default.c define variable ARCH as IA64 for VMS on Itanium systems. * In makefile.vms avoid name collision for glob and globfree. * This is the VMS port of GNU Make done by Hartmut.Becker@compaq.com. It is based on the specific version 3.77k and on 3.78.1. 3.77k was done by Klaus Kämpf , the code was based on the VMS port of GNU Make 3.60 by Mike Moretti. It was ported on OpenVMS/Alpha V7.1, DECC V5.7-006. It was re-build and tested on OpenVMS/Alpha V7.2, OpenVMS/VAX 7.1 and 5.5-2. Different versions of DECC were used. VAXC was tried: it fails; but it doesn't seem worth to get it working. There are still some PTRMISMATCH warnings during the compile. Although perl is working on VMS the test scripts don't work. The function $shell is still missing. There is a known bug in some of the VMS CRTLs. It is in the shipped versions of VMS V7.2 and V7.2-1 and in the currently (October 1999) available ECOs for VMS V7.1 and newer versions. It is fixed in versions shipped with newer VMS versions and all ECO kits after October 1999. It only shows up during the daylight saving time period (DST): stat() returns a modification time 1 hour ahead. This results in GNU make warning messages. For a just created source you will see: $ gmake x.exe gmake.exe;1: *** Warning: File 'x.c' has modification time in the future (940582863 > 940579269) cc /obj=x.obj x.c link x.obj /exe=x.exe gmake.exe;1: *** Warning: Clock skew detected. Your build may be incomplete. A complete list of bugs fixed in this version is available here: http://savannah.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=102 Version 3.79.1 (23 Jun 2000) * .SECONDARY with no prerequisites now prevents any target from being removed because make thinks it's an intermediate file, not just those listed in the makefile. * New configure option --disable-nsec-timestamps, but this was superseded in later versions by the .LOW_RESOLUTION_TIME pseudo-target. Version 3.79 (04 Apr 2000) * GNU make optionally supports internationalization and locales via the GNU gettext (or local gettext if suitable) package. See the ABOUT-NLS file for more information on configuring GNU make for NLS. * Previously, GNU make quoted variables such as MAKEFLAGS and MAKEOVERRIDES for proper parsing by the shell. This allowed them to be used within make build scripts. However, using them there is not proper behavior: they are meant to be passed to subshells via the environment. Unfortunately the values were not quoted properly to be passed through the environment. This meant that make didn't properly pass some types of command line values to submakes. With this version we change that behavior: now these variables are quoted properly for passing through the environment, which is the correct way to do it. If you previously used these variables explicitly within a make rule you may need to re-examine your use for correctness given this change. * A new pseudo-target .NOTPARALLEL is available. If defined, the current makefile is run serially regardless of the value of -j. However, submakes are still eligible for parallel execution. * The --debug option has changed: it now allows optional flags controlling the amount and type of debugging output. By default only a minimal amount information is generated, displaying the names of "normal" targets (not makefiles) that were deemed out of date and in need of being rebuilt. Note that the -d option behaves as before: it takes no arguments and all debugging information is generated. * The `-p' (print database) output now includes filename and linenumber information for variable definitions, to aid debugging. * The wordlist function no longer reverses its arguments if the "start" value is greater than the "end" value. If that's true, nothing is returned. * Hartmut Becker provided many updates for the VMS port of GNU make. See the README.VMS file for more details. * VMS-specific changes: * Fix a problem with automatically remaking makefiles. GNU make uses an execve to restart itself after a successful remake of the makefile. On UNIX systems execve replaces the running program with a new one and resets all signal handling to the default. On VMS execve creates a child process, signal and exit handlers of the parent are still active, and, unfortunately, corrupt the exit code from the child. Fix in job.c: ignore SIGCHLD. * Added some switches to reflect latest features of DECC. Modifications in makefile.vms. * Set some definitions to reflect latest features of DECC. Modifications in config.h-vms (which is copied to config.h). * Added extern strcmpi declaration to avoid 'implicitly declared' messages. Modification in make.h. * Default rule for C++, conditionals for gcc (GCC_IS_NATIVE) or DEC/Digital/ Compaq c/c++ compilers. Modifications in default.c. * Usage of opendir() and friends, suppress file version. Modifications in dir.c. * Added VMS specific code to handle ctrl+c and ctrl+y to abort make. Modifications in job.c. * Added support to have case sensitive targets and dependencies but to still use case blind file names. This is especially useful for Java makefiles on VMS: .SUFFIXES : .SUFFIXES : .class .java .java.class : javac "$< HelloWorld.class : HelloWorld.java * A new macro WANT_CASE_SENSITIVE_TARGETS in config.h-vms was introduced. It needs to be enabled to get this feature; default is disabled. The macro HAVE_CASE_INSENSITIVE_FS must not be touched: it is still enabled. Modifications in file.c and config.h-vms. * Bootstrap make to start building make is still makefile.com, but make needs to be re-made with a make to make a correct version: ignore all possible warnings, delete all objects, rename make.exe to a different name and run it. * Made some minor modifications to the bootstrap build makefile.com. Version 3.78 (22 Sep 1999) * Two new functions, $(error ...) and $(warning ...) are available. The former will cause make to fail and exit immediately upon expansion of the function, with the text provided as the error message. The latter causes the text provided to be printed as a warning message, but make proceeds normally. * A new function $(call ...) is available. This allows users to create their own parameterized macros and invoke them later. Original implementation of this function was provided by Han-Wen Nienhuys . * A new function $(if ...) is available. It provides if-then-else capabilities in a builtin function. Original implementation of this function was provided by Han-Wen Nienhuys . * Make defines a new variable, .LIBPATTERNS. This variable controls how library dependency expansion (dependencies like ``-lfoo'') is performed. * Make accepts CRLF sequences as well as traditional LF, for compatibility with makefiles created on other operating systems. * Make accepts a new option: -R, or --no-builtin-variables. This option disables the definition of the rule-specific builtin variables (CC, LD, AR, etc.). Specifying this option forces -r (--no-builtin-rules) as well. * A "job server" feature, suggested by Howard Chu . On systems that support POSIX pipe(2) semantics, GNU make can now pass -jN options to submakes rather than forcing them all to use -j1. The top make and all its sub-make processes use a pipe to communicate with each other to ensure that no more than N jobs are started across all makes. To get the old behavior of -j back, you can configure make with the --disable-job-server option. * The confusing term "dependency" has been replaced by the more accurate and standard term "prerequisite", both in the manual and in all GNU make output. * GNU make supports the "big archive" library format introduced in AIX 4.3. * GNU make supports large files on AIX, HP-UX, and IRIX. These changes were provided by Paul Eggert . (Large file support for Solaris and Linux was introduced in 3.77, but the configuration had issues: these have also been resolved). * The Windows 95/98/NT (W32) version of GNU make now has native support for the Cygnus Cygwin release B20.1 shell (bash). * The GNU make regression test suite, long available separately "under the table", has been integrated into the release. You can invoke it by running "make check" in the distribution. Note that it requires Perl (either Perl 4 or Perl 5) to run. Version 3.77 (28 Jul 1998) * Implement BSD make's "?=" variable assignment operator. The variable is assigned the specified value only if that variable is not already defined. * Make defines a new variable, "CURDIR", to contain the current working directory (after the -C option, if any, has been processed). Modifying this variable has no effect on the operation of make. * Make defines a new default RCS rule, for new-style master file storage: ``% :: RCS/%'' (note no ``,v'' suffix). Make defines new default rules for DOS-style C++ file naming conventions, with ``.cpp'' suffixes. All the same rules as for ``.cc'' and ``.C'' suffixes are provided, along with LINK.cpp and COMPILE.cpp macros (which default to the same value as LINK.cc and COMPILE.cc). Note CPPFLAGS is still C preprocessor flags! You should use CXXFLAGS to change C++ compiler flags. * A new feature, "target-specific variable values", has been added. This is a large change so please see the appropriate sections of the manual for full details. Briefly, syntax like this: TARGET: VARIABLE = VALUE defines VARIABLE as VALUE within the context of TARGET. This is similar to SunOS make's "TARGET := VARIABLE = VALUE" feature. Note that the assignment may be of any type, not just recursive, and that the override keyword is available. COMPATIBILITY: This new syntax means that if you have any rules where the first or second dependency has an equal sign (=) in its name, you'll have to escape them with a backslash: "foo : bar\=baz". Further, if you have any dependencies which already contain "\=", you'll have to escape both of them: "foo : bar\\\=baz". * A new appendix listing the most common error and warning messages generated by GNU make, with some explanation, has been added to the GNU make User's Manual. * Updates to the GNU make Customs library support (see README.customs). * Updates to the Windows 95/NT port from Rob Tulloh (see README.W32), and to the DOS port from Eli Zaretski (see README.DOS). * VMS-specific changes: * This is the VMS port of GNU Make. It is based on the VMS port of GNU Make 3.60 by Mike Moretti. This port was done by Klaus Kämpf * There is first-level support available from proGIS Software, Germany. Visit their web-site at http://www.progis.de to get information about other vms software and forthcoming updates to gnu make. * /bin/sh style I/O redirection is supported. You can now write lines like mcr sys$disk:[]program.exe < input.txt > output.txt &> error.txt * Makefile variables are looked up in the current environment. You can set symbols or logicals in DCL and evaluate them in the Makefile via $(). Variables defined in the Makefile override VMS symbols/logicals ! * Functions for file names are working now. See the GNU Make manual for $(dir ...) and $(wildcard ...). Unix-style and VMS-style names are supported as arguments. * The default rules are set up for GNU C. Building an executable from a single source file is as easy as 'make file.exe'. * The variable $(ARCH) is predefined as ALPHA or VAX resp. Makefiles for different VMS systems can now be written by checking $(ARCH) as in ifeq ($(ARCH),ALPHA) $(ECHO) "On the Alpha" else $(ECHO) "On the VAX" endif * Command lines of excessive length are correctly broken and written to a batch file in sys$scratch for later execution. There's no limit to the lengths of commands (and no need for .opt files :-) any more. * Empty commands are handled correctly and don't end in a new DCL process. Version 3.76.1 (19 Sep 1997) * Small (but serious) bug fix. Quick rollout to get into the GNU source CD. Version 3.76 (16 Sep 1997) * GNU make now uses automake to control Makefile.in generation. This should make it more consistent with the GNU standards. * VPATH functionality has been changed to incorporate the VPATH+ patch, previously maintained by Paul Smith . See the manual. * Make defines a new variable, `MAKECMDGOALS', to contain the goals that were specified on the command line, if any. Modifying this variable has no effect on the operation of make. * A new function, `$(wordlist S,E,TEXT)', is available: it returns a list of words from number S to number E (inclusive) of TEXT. * Instead of an error, detection of future modification times gives a warning and continues. The warning is repeated just before GNU make exits, so it is less likely to be lost. * Fix the $(basename) and $(suffix) functions so they only operate on the last filename, not the entire string: Command Old Result New Result ------- ---------- ---------- $(basename a.b) a a $(basename a.b/c) a a.b/c $(suffix a.b) b b $(suffix a.b/c) b/c * The $(strip) function now removes newlines as well as TABs and spaces. * The $(shell) function now changes CRLF (\r\n) pairs to a space as well as newlines (\n). * Updates to the Windows 95/NT port from Rob Tulloh (see README.W32). * Eli Zaretskii has updated the port to 32-bit protected mode on MSDOS and MS-Windows, building with the DJGPP v2 port of GNU C/C++ compiler and utilities. See README.DOS for details, and direct all questions concerning this port to Eli Zaretskii or DJ Delorie . * VMS-specific changes: * John W. Eaton has updated the VMS port to support libraries and VPATH. * The cd command is supported if it's called as $(CD). This invokes the 'builtin_cd' command which changes the directory. Calling 'set def' doesn't do the trick, since a sub-shell is spawned for this command, the directory is changed *in this sub-shell* and the sub-shell ends. * Libraries are not supported. They were in GNU Make 3.60 but somehow I didn't care porting the code. If there is enough interest, I'll do it at some later time. * The variable $^ separates files with commas instead of spaces (It's the natural thing to do for VMS). * See defaults.c for VMS default suffixes and my definitions for default rules and variables. * The shell function is not implemented yet. * Load average routines haven't been implemented for VMS yet. * The default include directory for including other makefiles is SYS$SYSROOT:[SYSLIB] (I don't remember why I didn't just use SYS$LIBRARY: instead; maybe it wouldn't work that way). * The default makefiles make looks for are: makefile.vms, gnumakefile, makefile., and gnumakefile. . * The stat() function and handling of time stamps in VMS is broken, so I replaced it with a hack in vmsfunctions.c. I will provide a full rewrite somewhere in the future. Be warned, the time resolution inside make is less than what vms provides. This might be a problem on the faster Alphas. * You can use a : in a filename only if you precede it with a backslash ('\'). E.g.- hobbes\:[bogas.files] * Make ignores success, informational, or warning errors (-S-, -I-, or -W-). But it will stop on -E- and -F- errors. (unless you do something to override this in your makefile, or whatever). * Remote stuff isn't implemented yet. * Multiple line DCL commands, such as "if" statements, must be put inside command files. You can run a command file by using \@. Version 3.75 (27 Aug 1996) * The directory messages printed by `-w' and implicitly in sub-makes, are now omitted if Make runs no commands and has no other messages to print. * Make now detects files that for whatever reason have modification times in the future and gives an error. Files with such impossible timestamps can result from unsynchronized clocks, or archived distributions containing bogus timestamps; they confuse Make's dependency engine thoroughly. * The new directive `sinclude' is now recognized as another name for `-include', for compatibility with some other Makes. * Aaron Digulla has contributed a port to AmigaDOS. See README.Amiga for details, and direct all Amiga-related questions to . * Rob Tulloh of Tivoli Systems has contributed a port to Windows NT or 95. See README.W32 for details, and direct all Windows-related questions to . * VMS-specific changes: * Lots of default settings are adapted for VMS. See default.c. * Long command lines are now converted to command files. * Comma (',') as a separator is now allowed. See makefile.vms for an example. Version 3.73 (05 Apr 1995) * Converted to use Autoconf version 2, so `configure' has some new options. See INSTALL for details. * You can now send a SIGUSR1 signal to Make to toggle printing of debugging output enabled by -d, at any time during the run. Version 3.72 (04 Nov 1994) * DJ Delorie has ported Make to MS-DOS using the GO32 extender. He is maintaining the DOS port, not the GNU Make maintainer; please direct bugs and questions for DOS to . MS-DOS binaries are available for FTP from ftp.simtel.net in /pub/simtelnet/gnu/djgpp/. * The `MAKEFLAGS' variable (in the environment or in a makefile) can now contain variable definitions itself; these are treated just like command line variable definitions. Make will automatically insert any variable definitions from the environment value of `MAKEFLAGS' or from the command line, into the `MAKEFLAGS' value exported to children. The `MAKEOVERRIDES' variable previously included in the value of `$(MAKE)' for sub-makes is now included in `MAKEFLAGS' instead. As before, you can reset `MAKEOVERRIDES' in your makefile to avoid putting all the variables in the environment when its size is limited. * If `.DELETE_ON_ERROR' appears as a target, Make will delete the target of a rule if it has changed when its recipe exits with a nonzero status, just as when the recipe gets a signal. * The automatic variable `$+' is new. It lists all the dependencies like `$^', but preserves duplicates listed in the makefile. This is useful for linking rules, where library files sometimes need to be listed twice in the link order. * You can now specify the `.IGNORE' and `.SILENT' special targets with dependencies to limit their effects to those files. If a file appears as a dependency of `.IGNORE', then errors will be ignored while running the recipe to update that file. Likewise if a file appears as a dependency of `.SILENT', then the recipe to update that file will not be printed before it is run. (This change was made to conform to POSIX.2.) Version 3.71 (21 May 1994) * The automatic variables `$(@D)', `$(%D)', `$(*D)', `$(. kbuild-3149/src/kmk/vmsjobs.c0000644000175000017500000012376313252530203016113 0ustar locutuslocutus/* --------------- Moved here from job.c --------------- This file must be #included in job.c, as it accesses static functions. Copyright (C) 1996-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include /* TODO - VMS specific header file conditionally included in makeint.h */ #include #include void decc$exit (int status); /* Lowest legal non-success VMS exit code is 8 */ /* GNU make only defines codes 0, 1, 2 */ /* So assume any exit code > 8 is a VMS exit code */ #ifndef MAX_EXPECTED_EXIT_CODE # define MAX_EXPECTED_EXIT_CODE 7 #endif #if __CRTL_VER >= 70302000 && !defined(__VAX) # define MAX_DCL_LINE_LENGTH 4095 # define MAX_DCL_CMD_LINE_LENGTH 8192 #else # define MAX_DCL_LINE_LENGTH 255 # define MAX_DCL_CMD_LINE_LENGTH 1024 #endif #define MAX_DCL_TOKEN_LENGTH 255 #define MAX_DCL_TOKENS 127 enum auto_pipe { nopipe, add_pipe, dcl_pipe }; char *vmsify (char *name, int type); static int vms_jobsefnmask = 0; /* returns whether path is assumed to be a unix like shell. */ int _is_unixy_shell (const char *path) { return vms_gnv_shell; } #define VMS_GETMSG_MAX 256 static char vms_strsignal_text[VMS_GETMSG_MAX + 2]; char * vms_strsignal (int status) { if (status <= MAX_EXPECTED_EXIT_CODE) sprintf (vms_strsignal_text, "lib$spawn returned %x", status); else { int vms_status; unsigned short * msg_len; unsigned char out[4]; vms_status = SYS$GETMSG (status, &msg_len, vms_strsignal_text, 7, *out); } return vms_strsignal_text; } /* Wait for nchildren children to terminate */ static void vmsWaitForChildren (int *status) { while (1) { if (!vms_jobsefnmask) { *status = 0; return; } *status = sys$wflor (32, vms_jobsefnmask); } return; } static int ctrlYPressed= 0; /* This is called at main or AST level. It is at AST level for DONTWAITFORCHILD and at main level otherwise. In any case it is called when a child process terminated. At AST level it won't get interrupted by anything except a inner mode level AST. */ static int vmsHandleChildTerm (struct child *child) { int exit_code; register struct child *lastc, *c; int child_failed; /* The child efn is 0 when a built-in or null command is executed successfully with out actually creating a child. */ if (child->efn > 0) { vms_jobsefnmask &= ~(1 << (child->efn - 32)); lib$free_ef (&child->efn); } if (child->comname) { if (!ISDB (DB_JOBS) && !ctrlYPressed) unlink (child->comname); free (child->comname); } (void) sigblock (fatal_signal_mask); /* First check to see if this is a POSIX exit status and handle */ if ((child->cstatus & VMS_POSIX_EXIT_MASK) == VMS_POSIX_EXIT_MASK) { exit_code = (child->cstatus >> 3) & 255; if (exit_code != MAKE_SUCCESS) child_failed = 1; } else { child_failed = !$VMS_STATUS_SUCCESS (child->cstatus); if (child_failed) exit_code = child->cstatus; } /* Search for a child matching the deceased one. */ lastc = 0; #if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */ for (c = children; c != 0 && c != child; lastc = c, c = c->next) ; #else c = child; #endif if ($VMS_STATUS_SUCCESS (child->vms_launch_status)) { /* Convert VMS success status to 0 for UNIX code to be happy */ child->vms_launch_status = 0; } /* Set the state flag to say the commands have finished. */ c->file->command_state = cs_finished; notice_finished_file (c->file); (void) sigsetmask (sigblock (0) & ~(fatal_signal_mask)); return 1; } /* VMS: Spawn a process executing the command in ARGV and return its pid. */ /* local helpers to make ctrl+c and ctrl+y working, see below */ #include #include #include static int ctrlMask= LIB$M_CLI_CTRLY; static int oldCtrlMask; static int setupYAstTried= 0; static unsigned short int chan= 0; static void reEnableAst(void) { lib$enable_ctrl (&oldCtrlMask,0); } static int astYHandler (void) { struct child *c; for (c = children; c != 0; c = c->next) sys$delprc (&c->pid, 0, 0); ctrlYPressed= 1; kill (getpid(),SIGQUIT); return SS$_NORMAL; } static void tryToSetupYAst(void) { $DESCRIPTOR(inputDsc,"SYS$COMMAND"); int status; struct { short int status, count; int dvi; } iosb; unsigned short int loc_chan; setupYAstTried++; if (chan) loc_chan= chan; else { status= sys$assign(&inputDsc,&loc_chan,0,0); if (!(status&SS$_NORMAL)) { lib$signal(status); return; } } status= sys$qiow (0, loc_chan, IO$_SETMODE|IO$M_CTRLYAST,&iosb,0,0, astYHandler,0,0,0,0,0); if (status==SS$_NORMAL) status= iosb.status; if (status!=SS$_NORMAL) { if (!chan) sys$dassgn(loc_chan); if (status!=SS$_ILLIOFUNC && status!=SS$_NOPRIV) lib$signal(status); return; } /* called from AST handler ? */ if (setupYAstTried>1) return; if (atexit(reEnableAst)) fprintf (stderr, _("-warning, you may have to re-enable CTRL-Y handling from DCL.\n")); status= lib$disable_ctrl (&ctrlMask, &oldCtrlMask); if (!(status&SS$_NORMAL)) { lib$signal(status); return; } if (!chan) chan = loc_chan; } /* Check if a token is too long */ #define INC_TOKEN_LEN_OR_RETURN(x) {token->length++; \ if (token->length >= MAX_DCL_TOKEN_LENGTH) \ { token->cmd_errno = ERANGE; return x; }} #define INC_TOKEN_LEN_OR_BREAK {token->length++; \ if (token->length >= MAX_DCL_TOKEN_LENGTH) \ { token->cmd_errno = ERANGE; break; }} #define ADD_TOKEN_LEN_OR_RETURN(add_len, x) {token->length += add_len; \ if (token->length >= MAX_DCL_TOKEN_LENGTH) \ { token->cmd_errno = ERANGE; return x; }} /* Check if we are out of space for more tokens */ #define V_NEXT_TOKEN { if (cmd_tkn_index < MAX_DCL_TOKENS) \ cmd_tokens[++cmd_tkn_index] = NULL; \ else { token.cmd_errno = E2BIG; break; } \ token.length = 0;} #define UPDATE_TOKEN {cmd_tokens[cmd_tkn_index] = strdup(token.text); \ V_NEXT_TOKEN;} #define EOS_ERROR(x) { if (*x == 0) { token->cmd_errno = ERANGE; break; }} struct token_info { char *text; /* Parsed text */ int length; /* Length of parsed text */ char *src; /* Pointer to source text */ int cmd_errno; /* Error status of parse */ int use_cmd_file; /* Force use of a command file */ }; /* Extract a Posix single quoted string from input line */ static char * posix_parse_sq (struct token_info *token) { /* A Posix quoted string with no expansion unless in a string Unix simulation means no lexical functions present. */ char * q; char * p; q = token->text; p = token->src; *q++ = '"'; p++; INC_TOKEN_LEN_OR_RETURN (p); while (*p != '\'' && (token->length < MAX_DCL_TOKEN_LENGTH)) { EOS_ERROR (p); if (*p == '"') { /* Embedded double quotes need to be doubled */ *q++ = '"'; INC_TOKEN_LEN_OR_BREAK; *q = '"'; } else *q = *p; q++; p++; INC_TOKEN_LEN_OR_BREAK; } *q++ = '"'; p++; INC_TOKEN_LEN_OR_RETURN (p); *q = 0; return p; } /* Extract a Posix double quoted string from input line */ static char * posix_parse_dq (struct token_info *token) { /* Unix mode: Any imbedded \" becomes doubled. \t is tab, \\, \$ leading character stripped. $ character replaced with \' unless escaped. */ char * q; char * p; q = token->text; p = token->src; *q++ = *p++; INC_TOKEN_LEN_OR_RETURN (p); while (*p != 0) { if (*p == '\\') { switch(p[1]) { case 't': /* Convert tabs */ *q = '\t'; p++; break; case '\\': /* Just remove leading backslash */ case '$': p++; *q = *p; break; case '"': p++; *q = *p; *q++ = '"'; INC_TOKEN_LEN_OR_BREAK; default: /* Pass through unchanged */ *q++ = *p++; INC_TOKEN_LEN_OR_BREAK; } INC_TOKEN_LEN_OR_BREAK; } else if (*p == '$' && isalpha (p[1])) { /* A symbol we should be able to substitute */ *q++ = '\''; INC_TOKEN_LEN_OR_BREAK; *q = '\''; INC_TOKEN_LEN_OR_BREAK; token->use_cmd_file = 1; } else { *q = *p; INC_TOKEN_LEN_OR_BREAK; if (*p == '"') { p++; q++; break; } } p++; q++; } *q = 0; return p; } /* Extract a VMS quoted string or substitution string from input line */ static char * vms_parse_quotes (struct token_info *token) { /* VMS mode, the \' means that a symbol substitution is starting so while you might think you can just copy until the next \'. Unfortunately the substitution can be a lexical function which can contain embedded strings and lexical functions. Messy, so both types need to be handled together. */ char * q; char * p; q = token->text; p = token->src; int parse_level[MAX_DCL_TOKENS + 1]; int nest = 0; parse_level[0] = *p; if (parse_level[0] == '\'') token->use_cmd_file = 1; *q++ = *p++; INC_TOKEN_LEN_OR_RETURN (p); /* Copy everything until after the next single quote at nest == 0 */ while (token->length < MAX_DCL_TOKEN_LENGTH) { EOS_ERROR (p); *q = *p; INC_TOKEN_LEN_OR_BREAK; if ((*p == parse_level[nest]) && (p[1] != '"')) { if (nest == 0) { *q++ = *p++; break; } nest--; } else { switch(*p) { case '\\': /* Handle continuation on to next line */ if (p[1] != '\n') break; p++; p++; *q = *p; break; case '(': /* Parenthesis only in single quote level */ if (parse_level[nest] == '\'') { nest++; parse_level[nest] == ')'; } break; case '"': /* Double quotes only in parenthesis */ if (parse_level[nest] == ')') { nest++; parse_level[nest] == '"'; } break; case '\'': /* Symbol substitution ony in double quotes */ if ((p[1] == '\'') && (parse_level[nest] == '"')) { nest++; parse_level[nest] == '\''; *p++ = *q++; token->use_cmd_file = 1; INC_TOKEN_LEN_OR_BREAK; break; } *q = *p; } } p++; q++; /* Pass through doubled double quotes */ if ((*p == '"') && (p[1] == '"') && (parse_level[nest] == '"')) { *p++ = *q++; INC_TOKEN_LEN_OR_BREAK; *p++ = *q++; INC_TOKEN_LEN_OR_BREAK; } } *q = 0; return p; } /* Extract a $ string from the input line */ static char * posix_parse_dollar (struct token_info *token) { /* $foo becomes 'foo' */ char * q; char * p; q = token->text; p = token->src; token->use_cmd_file = 1; p++; *q++ = '\''; INC_TOKEN_LEN_OR_RETURN (p); while ((isalnum (*p)) || (*p == '_')) { *q++ = *p++; INC_TOKEN_LEN_OR_BREAK; } *q++ = '\''; while (1) { INC_TOKEN_LEN_OR_BREAK; break; } *q = 0; return p; } const char *vms_filechars = "0123456789abcdefghijklmnopqrstuvwxyz" \ "ABCDEFGHIJKLMNOPQRSTUVWXYZ[]<>:/_-.$"; /* Simple text copy */ static char * parse_text (struct token_info *token, int assignment_hack) { char * q; char * p; int str_len; q = token->text; p = token->src; /* If assignment hack, then this text needs to be double quoted. */ if (vms_unix_simulation && (assignment_hack == 2)) { *q++ = '"'; INC_TOKEN_LEN_OR_RETURN (p); } *q++ = *p++; INC_TOKEN_LEN_OR_RETURN (p); while (*p != 0) { str_len = strspn (p, vms_filechars); if (str_len == 0) { /* Pass through backslash escapes in Unix simulation probably will not work anyway. All any character after a ^ otherwise to support EFS. */ if (vms_unix_simulation && (p[0] == '\\') && (p[1] != 0)) str_len = 2; else if ((p[0] == '^') && (p[1] != 0)) str_len = 2; else if (!vms_unix_simulation && (p[0] == ';')) str_len = 1; if (str_len == 0) { /* If assignment hack, then this needs to be double quoted. */ if (vms_unix_simulation && (assignment_hack == 2)) { *q++ = '"'; INC_TOKEN_LEN_OR_RETURN (p); } *q = 0; return p; } } if (str_len > 0) { ADD_TOKEN_LEN_OR_RETURN (str_len, p); strncpy (q, p, str_len); p += str_len; q += str_len; *q = 0; } } /* If assignment hack, then this text needs to be double quoted. */ if (vms_unix_simulation && (assignment_hack == 2)) { *q++ = '"'; INC_TOKEN_LEN_OR_RETURN (p); } return p; } /* single character copy */ static char * parse_char (struct token_info *token, int count) { char * q; char * p; q = token->text; p = token->src; while (count > 0) { *q++ = *p++; INC_TOKEN_LEN_OR_RETURN (p); count--; } *q = 0; return p; } /* Build a command string from the collected tokens and process built-ins now */ static struct dsc$descriptor_s * build_vms_cmd (char **cmd_tokens, enum auto_pipe use_pipe_cmd, int append_token) { struct dsc$descriptor_s *cmd_dsc; int cmd_tkn_index; char * cmd; int cmd_len; int semicolon_seen; cmd_tkn_index = 0; cmd_dsc = xmalloc (sizeof (struct dsc$descriptor_s)); /* Empty command? */ if (cmd_tokens[0] == NULL) { cmd_dsc->dsc$a_pointer = NULL; cmd_dsc->dsc$w_length = 0; return cmd_dsc; } /* Max DCL command + 1 extra token and trailing space */ cmd = xmalloc (MAX_DCL_CMD_LINE_LENGTH + 256); cmd[0] = '$'; cmd[1] = 0; cmd_len = 1; /* Handle real or auto-pipe */ if (use_pipe_cmd == add_pipe) { /* We need to auto convert to a pipe command */ strcat (cmd, "pipe "); cmd_len += 5; } semicolon_seen = 0; while (cmd_tokens[cmd_tkn_index] != NULL) { /* Check for buffer overflow */ if (cmd_len > MAX_DCL_CMD_LINE_LENGTH) { errno = E2BIG; break; } /* Eliminate double ';' */ if (semicolon_seen && (cmd_tokens[cmd_tkn_index][0] == ';')) { semicolon_seen = 0; free (cmd_tokens[cmd_tkn_index++]); if (cmd_tokens[cmd_tkn_index] == NULL) break; } /* Special handling for CD built-in */ if (strncmp (cmd_tokens[cmd_tkn_index], "builtin_cd", 11) == 0) { int result; semicolon_seen = 0; free (cmd_tokens[cmd_tkn_index]); cmd_tkn_index++; if (cmd_tokens[cmd_tkn_index] == NULL) break; DB(DB_JOBS, (_("BUILTIN CD %s\n"), cmd_tokens[cmd_tkn_index])); /* TODO: chdir fails with some valid syntaxes */ result = chdir (cmd_tokens[cmd_tkn_index]); if (result != 0) { /* TODO: Handle failure better */ free (cmd); while (cmd_tokens[cmd_tkn_index] == NULL) free (cmd_tokens[cmd_tkn_index++]); cmd_dsc->dsc$w_length = -1; cmd_dsc->dsc$a_pointer = NULL; return cmd_dsc; } } else if (strncmp (cmd_tokens[cmd_tkn_index], "exit", 5) == 0) { /* Copy the exit command */ semicolon_seen = 0; strcpy (&cmd[cmd_len], cmd_tokens[cmd_tkn_index]); cmd_len += strlen (cmd_tokens[cmd_tkn_index]); free (cmd_tokens[cmd_tkn_index++]); if (cmd_len > MAX_DCL_CMD_LINE_LENGTH) { errno = E2BIG; break; } /* Optional whitespace */ if (isspace (cmd_tokens[cmd_tkn_index][0])) { strcpy (&cmd[cmd_len], cmd_tokens[cmd_tkn_index]); cmd_len += strlen (cmd_tokens[cmd_tkn_index]); free (cmd_tokens[cmd_tkn_index++]); if (cmd_len > MAX_DCL_CMD_LINE_LENGTH) { errno = E2BIG; break; } } /* There should be a status, but it is optional */ if (cmd_tokens[cmd_tkn_index][0] == ';') continue; /* If Unix simulation, add '((' */ if (vms_unix_simulation) { strcpy (&cmd[cmd_len], "(("); cmd_len += 2; if (cmd_len > MAX_DCL_CMD_LINE_LENGTH) { errno = E2BIG; break; } } /* Add the parameter */ strcpy (&cmd[cmd_len], cmd_tokens[cmd_tkn_index]); cmd_len += strlen (cmd_tokens[cmd_tkn_index]); free (cmd_tokens[cmd_tkn_index++]); if (cmd_len > MAX_DCL_CMD_LINE_LENGTH) { errno = E2BIG; break; } /* Add " * 8) .and. %x7f8) .or. %x1035a002" */ if (vms_unix_simulation) { const char *end_str = " * 8) .and. %x7f8) .or. %x1035a002"; strcpy (&cmd[cmd_len], end_str); cmd_len += strlen (end_str); if (cmd_len > MAX_DCL_CMD_LINE_LENGTH) { errno = E2BIG; break; } } continue; } /* auto pipe needs spaces before semicolon */ if (use_pipe_cmd == add_pipe) if (cmd_tokens[cmd_tkn_index][0] == ';') { cmd[cmd_len++] = ' '; semicolon_seen = 1; if (cmd_len > MAX_DCL_CMD_LINE_LENGTH) { errno = E2BIG; break; } } else { char ch; ch = cmd_tokens[cmd_tkn_index][0]; if (!(ch == ' ' || ch == '\t')) semicolon_seen = 0; } strcpy (&cmd[cmd_len], cmd_tokens[cmd_tkn_index]); cmd_len += strlen (cmd_tokens[cmd_tkn_index]); free (cmd_tokens[cmd_tkn_index++]); /* Skip the append tokens if they exist */ if (cmd_tkn_index == append_token) { free (cmd_tokens[cmd_tkn_index++]); if (isspace (cmd_tokens[cmd_tkn_index][0])) free (cmd_tokens[cmd_tkn_index++]); free (cmd_tokens[cmd_tkn_index++]); } } cmd[cmd_len] = 0; cmd_dsc->dsc$w_length = cmd_len; cmd_dsc->dsc$a_pointer = cmd; cmd_dsc->dsc$b_dtype = DSC$K_DTYPE_T; cmd_dsc->dsc$b_class = DSC$K_CLASS_S; return cmd_dsc; } int child_execute_job (struct child *child, char *argv) { int i; static struct dsc$descriptor_s *cmd_dsc; static struct dsc$descriptor_s pnamedsc; int spflags = CLI$M_NOWAIT; int status; int comnamelen; char procname[100]; char *p; char *cmd_tokens[(MAX_DCL_TOKENS * 2) + 1]; /* whitespace does not count */ char token_str[MAX_DCL_TOKEN_LENGTH + 1]; struct token_info token; int cmd_tkn_index; int paren_level = 0; enum auto_pipe use_pipe_cmd = nopipe; int append_token = -1; char *append_file = NULL; int unix_echo_cmd = 0; /* Special handle Unix echo command */ int assignment_hack = 0; /* Handle x=y command as piped command */ /* Parse IO redirection. */ child->comname = NULL; DB (DB_JOBS, ("child_execute_job (%s)\n", argv)); while (isspace ((unsigned char)*argv)) argv++; if (*argv == 0) { /* Only a built-in or a null command - Still need to run term AST */ child->cstatus = VMS_POSIX_EXIT_MASK; child->vms_launch_status = SS$_NORMAL; /* TODO what is this "magic number" */ child->pid = 270163; /* Special built-in */ child->efn = 0; vmsHandleChildTerm (child); return 1; } sprintf (procname, "GMAKE_%05x", getpid () & 0xfffff); pnamedsc.dsc$w_length = strlen (procname); pnamedsc.dsc$a_pointer = procname; pnamedsc.dsc$b_dtype = DSC$K_DTYPE_T; pnamedsc.dsc$b_class = DSC$K_CLASS_S; /* Old */ /* Handle comments and redirection. For ONESHELL, the redirection must be on the first line. Any other redirection token is handled by DCL, that is, the pipe command with redirection can be used, but it should not be used on the first line for ONESHELL. */ /* VMS parser notes: 1. A token is any of DCL verbs, qualifiers, parameters, or punctuation. 2. Only MAX_DCL_TOKENS per line in both one line or command file mode. 3. Each token limited to MAC_DCL_TOKEN_LENGTH 4. If the line to DCL is greater than MAX_DCL_LINE_LENGTH then a command file must be used. 5. Currently a command file must be used symbol substitution is to be performed. 6. Currently limiting command files to 2 * MAX_DCL_TOKENS. Build both a command file token list and command line token list until it is determined that the command line limits are exceeded. */ cmd_tkn_index = 0; cmd_tokens[cmd_tkn_index] = NULL; p = argv; token.text = token_str; token.length = 0; token.cmd_errno = 0; token.use_cmd_file = 0; while (*p != 0) { /* We can not build this command so give up */ if (token.cmd_errno != 0) break; token.src = p; switch (*p) { case '\'': if (vms_unix_simulation || unix_echo_cmd) { p = posix_parse_sq (&token); UPDATE_TOKEN; break; } /* VMS mode, the \' means that a symbol substitution is starting so while you might think you can just copy until the next \'. Unfortunately the substitution can be a lexical function which can contain embedded strings and lexical functions. Messy. */ p = vms_parse_quotes (&token); UPDATE_TOKEN; break; case '"': if (vms_unix_simulation) { p = posix_parse_dq (&token); UPDATE_TOKEN; break; } /* VMS quoted string, can contain lexical functions with quoted strings and nested lexical functions. */ p = vms_parse_quotes (&token); UPDATE_TOKEN; break; case '$': if (vms_unix_simulation) { p = posix_parse_dollar (&token); UPDATE_TOKEN; break; } /* Otherwise nothing special */ p = parse_text (&token, 0); UPDATE_TOKEN; break; case '\\': if (p[1] == '\n') { /* Line continuation, remove it */ p += 2; break; } /* Ordinary character otherwise */ if (assignment_hack != 0) assignment_hack++; if (assignment_hack > 2) { assignment_hack = 0; /* Reset */ if (use_pipe_cmd == nopipe) /* force pipe use */ use_pipe_cmd = add_pipe; token_str[0] = ';'; /* add ; token */ token_str[1] = 0; UPDATE_TOKEN; } p = parse_text (&token, assignment_hack); UPDATE_TOKEN; break; case '!': case '#': /* Unix '#' is VMS '!' which comments out the rest of the line. Historically the rest of the line has been skipped. Not quite the right thing to do, as the f$verify lexical function works in comments. But this helps keep the line lengths short. */ unix_echo_cmd = 0; while (*p != '\n' && *p != 0) p++; break; case '(': /* Subshell, equation, or lexical function argument start */ p = parse_char (&token, 1); UPDATE_TOKEN; paren_level++; break; case ')': /* Close out a paren level */ p = parse_char (&token, 1); UPDATE_TOKEN; paren_level--; /* TODO: Should we diagnose if paren_level goes negative? */ break; case '&': if (isalpha (p[1]) && !vms_unix_simulation) { /* VMS symbol substitution */ p = parse_text (&token, 0); token.use_cmd_file = 1; UPDATE_TOKEN; break; } if (use_pipe_cmd == nopipe) use_pipe_cmd = add_pipe; if (p[1] != '&') p = parse_char (&token, 1); else p = parse_char (&token, 2); UPDATE_TOKEN; break; case '|': if (use_pipe_cmd == nopipe) use_pipe_cmd = add_pipe; if (p[1] != '|') p = parse_char (&token, 1); else p = parse_char (&token, 2); UPDATE_TOKEN; break; case ';': /* Separator - convert to a pipe command. */ unix_echo_cmd = 0; case '<': if (use_pipe_cmd == nopipe) use_pipe_cmd = add_pipe; p = parse_char (&token, 1); UPDATE_TOKEN; break; case '>': if (use_pipe_cmd == nopipe) use_pipe_cmd = add_pipe; if (p[1] == '>') { /* Parsing would have been simple until support for the >> append redirect was added. Implementation needs: * if not exist output file create empty * open/append gnv$make_temp??? output_file * define/user sys$output gnv$make_temp??? ** And all this done before the command previously tokenized. * command previously tokenized * close gnv$make_temp??? */ p = parse_char (&token, 2); append_token = cmd_tkn_index; token.use_cmd_file = 1; } else p = parse_char (&token, 1); UPDATE_TOKEN; break; case '/': /* Unix path or VMS option start, read until non-path symbol */ if (assignment_hack != 0) assignment_hack++; if (assignment_hack > 2) { assignment_hack = 0; /* Reset */ if (use_pipe_cmd == nopipe) /* force pipe use */ use_pipe_cmd = add_pipe; token_str[0] = ';'; /* add ; token */ token_str[1] = 0; UPDATE_TOKEN; } p = parse_text (&token, assignment_hack); UPDATE_TOKEN; break; case ':': if ((p[1] == 0) || isspace (p[1])) { /* Unix Null command - treat as comment until next command */ unix_echo_cmd = 0; p++; while (*p != 0) { if (*p == ';') { /* Remove Null command from pipeline */ p++; break; } p++; } break; } /* String assignment */ /* := :== or : */ if (p[1] != '=') p = parse_char (&token, 1); else if (p[2] != '=') p = parse_char (&token, 2); else p = parse_char (&token, 3); UPDATE_TOKEN; break; case '=': /* = or == */ /* If this is not an echo statement, this could be a shell assignment. VMS requires the target to be quoted if it is not a macro substitution */ if (!unix_echo_cmd && vms_unix_simulation && (assignment_hack == 0)) assignment_hack = 1; if (p[1] != '=') p = parse_char (&token, 1); else p = parse_char (&token, 2); UPDATE_TOKEN; break; case '+': case '-': case '*': p = parse_char (&token, 1); UPDATE_TOKEN; break; case '.': /* .xxx. operation, VMS does not require the trailing . */ p = parse_text (&token, 0); UPDATE_TOKEN; break; default: /* Skip repetitive whitespace */ if (isspace (*p)) { p = parse_char (&token, 1); /* Force to a space or a tab */ if ((token_str[0] != ' ') || (token_str[0] != '\t')) token_str[0] = ' '; UPDATE_TOKEN; while (isspace (*p)) p++; if (assignment_hack != 0) assignment_hack++; break; } if (assignment_hack != 0) assignment_hack++; if (assignment_hack > 2) { assignment_hack = 0; /* Reset */ if (use_pipe_cmd == nopipe) /* force pipe use */ use_pipe_cmd = add_pipe; token_str[0] = ';'; /* add ; token */ token_str[1] = 0; UPDATE_TOKEN; } p = parse_text (&token, assignment_hack); if (strncasecmp (token.text, "echo", 4) == 0) unix_echo_cmd = 1; else if (strncasecmp (token.text, "pipe", 4) == 0) use_pipe_cmd = dcl_pipe; UPDATE_TOKEN; break; } } /* End up here with a list of tokens to build a command line. Deal with errors detected during parsing. */ if (token.cmd_errno != 0) { while (cmd_tokens[cmd_tkn_index] == NULL) free (cmd_tokens[cmd_tkn_index++]); child->cstatus = VMS_POSIX_EXIT_MASK | (MAKE_TROUBLE << 3); child->vms_launch_status = SS$_ABORT; /* TODO what is this "magic number" */ child->pid = 270163; /* Special built-in */ child->efn = 0; errno = token.cmd_errno; return 0; } /* Save any redirection to append file */ if (append_token != -1) { int file_token; char * lastdot; char * lastdir; char * raw_append_file; file_token = append_token; file_token++; if (isspace (cmd_tokens[file_token][0])) file_token++; raw_append_file = vmsify (cmd_tokens[file_token], 0); /* VMS DCL needs a trailing dot if null file extension */ lastdot = strrchr(raw_append_file, '.'); lastdir = strrchr(raw_append_file, ']'); if (lastdir == NULL) lastdir = strrchr(raw_append_file, '>'); if (lastdir == NULL) lastdir = strrchr(raw_append_file, ':'); if ((lastdot == NULL) || (lastdot > lastdir)) { append_file = xmalloc (strlen (raw_append_file) + 1); strcpy (append_file, raw_append_file); strcat (append_file, "."); } else append_file = strdup(raw_append_file); } cmd_dsc = build_vms_cmd (cmd_tokens, use_pipe_cmd, append_token); if (cmd_dsc->dsc$a_pointer == NULL) { if (cmd_dsc->dsc$w_length < 0) { free (cmd_dsc); child->cstatus = VMS_POSIX_EXIT_MASK | (MAKE_TROUBLE << 3); child->vms_launch_status = SS$_ABORT; /* TODO what is this "magic number" */ child->pid = 270163; /* Special built-in */ child->efn = 0; return 0; } /* Only a built-in or a null command - Still need to run term AST */ free (cmd_dsc); child->cstatus = VMS_POSIX_EXIT_MASK; child->vms_launch_status = SS$_NORMAL; /* TODO what is this "magic number" */ child->pid = 270163; /* Special built-in */ child->efn = 0; vmsHandleChildTerm (child); return 1; } if (cmd_dsc->dsc$w_length > MAX_DCL_LINE_LENGTH) token.use_cmd_file = 1; DB(DB_JOBS, (_("DCL: %s\n"), cmd_dsc->dsc$a_pointer)); /* Enforce the creation of a command file if "vms_always_use_cmd_file" is non-zero. Further, this way DCL reads the input stream and therefore does 'forced' symbol substitution, which it doesn't do for one-liners when they are 'lib$spawn'ed. Otherwise the behavior is: Create a *.com file if either the command is too long for lib$spawn, or if a redirect appending to a file is desired, or symbol substitition. */ if (vms_always_use_cmd_file || token.use_cmd_file) { FILE *outfile; int cmd_len; outfile = output_tmpfile (&child->comname, "sys$scratch:gnv$make_cmdXXXXXX.com"); /* 012345678901234567890 */ if (outfile == 0) pfatal_with_name (_("fopen (temporary file)")); comnamelen = strlen (child->comname); /* The whole DCL "script" is executed as one action, and it behaves as any DCL "script", that is errors stop it but warnings do not. Usually the command on the last line, defines the exit code. However, with redirections there is a prolog and possibly an epilog to implement the redirection. Both are part of the script which is actually executed. So if the redirection encounters an error in the prolog, the user actions will not run; if in the epilog, the user actions ran, but output is not captured. In both error cases, the error of redirection is passed back and not the exit code of the actions. The user should be able to enable DCL "script" verification with "set verify". However, the prolog and epilog commands are not shown. Also, if output redirection is used, the verification output is redirected into that file as well. */ fprintf (outfile, "$ gnv$$make_verify = \"''f$verify(0)'\"\n"); fprintf (outfile, "$ gnv$$make_pid = f$getjpi(\"\",\"pid\")\n"); fprintf (outfile, "$ on error then $ goto gnv$$make_error\n"); /* Handle append redirection */ if (append_file != NULL) { /* If file does not exist, create it */ fprintf (outfile, "$ gnv$$make_al = \"gnv$$make_append''gnv$$make_pid'\"\n"); fprintf (outfile, "$ if f$search(\"%s\") .eqs. \"\" then create %s\n", append_file, append_file); fprintf (outfile, "$ open/append 'gnv$$make_al' %s\n", append_file); /* define sys$output to that file */ fprintf (outfile, "$ define/user sys$output 'gnv$$make_al'\n"); DB (DB_JOBS, (_("Append output to %s\n"), append_file)); free(append_file); } fprintf (outfile, "$ gnv$$make_verify = f$verify(gnv$$make_verify)\n"); /* TODO: Only for ONESHELL there will be several commands separated by '\n'. But there can always be multiple continuation lines. */ fprintf (outfile, "%s\n", cmd_dsc->dsc$a_pointer); fprintf (outfile, "$ gnv$$make_status_2 = $status\n"); fprintf (outfile, "$ goto gnv$$make_exit\n"); /* Exit and clean up */ fprintf (outfile, "$ gnv$$make_error: ! 'f$verify(0)\n"); fprintf (outfile, "$ gnv$$make_status_2 = $status\n"); if (append_token != -1) { fprintf (outfile, "$ deassign sys$output\n"); fprintf (outfile, "$ close 'gnv$$make_al'\n"); DB (DB_JOBS, (_("Append %.*s and cleanup\n"), comnamelen-3, child->comname)); } fprintf (outfile, "$ gnv$$make_exit: ! 'f$verify(0)\n"); fprintf (outfile, "$ exit 'gnv$$make_status_2' + (0*f$verify(gnv$$make_verify))\n"); fclose (outfile); free (cmd_dsc->dsc$a_pointer); cmd_dsc->dsc$a_pointer = xmalloc (256 + 4); sprintf (cmd_dsc->dsc$a_pointer, "$ @%s", child->comname); cmd_dsc->dsc$w_length = strlen (cmd_dsc->dsc$a_pointer); DB (DB_JOBS, (_("Executing %s instead\n"), child->comname)); } child->efn = 0; while (child->efn < 32 || child->efn > 63) { status = LIB$GET_EF ((unsigned long *)&child->efn); if (!$VMS_STATUS_SUCCESS (status)) { if (child->comname) { if (!ISDB (DB_JOBS)) unlink (child->comname); free (child->comname); } return 0; } } SYS$CLREF (child->efn); vms_jobsefnmask |= (1 << (child->efn - 32)); /* Export the child environment into DCL symbols */ if (child->environment != 0) { char **ep = child->environment; while (*ep != 0) { vms_putenv_symbol (*ep); *ep++; } } /* LIB$SPAWN [command-string] [,input-file] [,output-file] [,flags] [,process-name] [,process-id] [,completion-status-address] [,byte-integer-event-flag-num] [,AST-address] [,varying-AST-argument] [,prompt-string] [,cli] [,table] */ #ifndef DONTWAITFORCHILD /* * Code to make ctrl+c and ctrl+y working. * The problem starts with the synchronous case where after lib$spawn is * called any input will go to the child. But with input re-directed, * both control characters won't make it to any of the programs, neither * the spawning nor to the spawned one. Hence the caller needs to spawn * with CLI$M_NOWAIT to NOT give up the input focus. A sys$waitfr * has to follow to simulate the wanted synchronous behaviour. * The next problem is ctrl+y which isn't caught by the crtl and * therefore isn't converted to SIGQUIT (for a signal handler which is * already established). The only way to catch ctrl+y, is an AST * assigned to the input channel. But ctrl+y handling of DCL needs to be * disabled, otherwise it will handle it. Not to mention the previous * ctrl+y handling of DCL needs to be re-established before make exits. * One more: At the time of LIB$SPAWN signals are blocked. SIGQUIT will * make it to the signal handler after the child "normally" terminates. * This isn't enough. It seems reasonable for simple command lines like * a 'cc foobar.c' spawned in a subprocess but it is unacceptable for * spawning make. Therefore we need to abort the process in the AST. * * Prior to the spawn it is checked if an AST is already set up for * ctrl+y, if not one is set up for a channel to SYS$COMMAND. In general * this will work except if make is run in a batch environment, but there * nobody can press ctrl+y. During the setup the DCL handling of ctrl+y * is disabled and an exit handler is established to re-enable it. * If the user interrupts with ctrl+y, the assigned AST will fire, force * an abort to the subprocess and signal SIGQUIT, which will be caught by * the already established handler and will bring us back to common code. * After the spawn (now /nowait) a sys$waitfr simulates the /wait and * enables the ctrl+y be delivered to this code. And the ctrl+c too, * which the crtl converts to SIGINT and which is caught by the common * signal handler. Because signals were blocked before entering this code * sys$waitfr will always complete and the SIGQUIT will be processed after * it (after termination of the current block, somewhere in common code). * And SIGINT too will be delayed. That is ctrl+c can only abort when the * current command completes. Anyway it's better than nothing :-) */ if (!setupYAstTried) tryToSetupYAst(); child->vms_launch_status = lib$spawn (cmd_dsc, /* cmd-string */ NULL, /* input-file */ NULL, /* output-file */ &spflags, /* flags */ &pnamedsc, /* proc name */ &child->pid, &child->cstatus, &child->efn, 0, 0, 0, 0, 0); status = child->vms_launch_status; if ($VMS_STATUS_SUCCESS (status)) { status = sys$waitfr (child->efn); vmsHandleChildTerm (child); } #else child->vms_launch_status = lib$spawn (cmd_dsc, NULL, NULL, &spflags, &pnamedsc, &child->pid, &child->cstatus, &child->efn, vmsHandleChildTerm, child, 0, 0, 0); status = child->vms_launch_status; #endif /* Free the pointer if not a command file */ if (!vms_always_use_cmd_file && !token.use_cmd_file) free (cmd_dsc->dsc$a_pointer); free (cmd_dsc); if (!$VMS_STATUS_SUCCESS (status)) { switch (status) { case SS$_EXQUOTA: errno = EPROCLIM; break; default: errno = EFAIL; } } /* Restore the VMS symbols that were changed */ if (child->environment != 0) { char **ep = child->environment; while (*ep != 0) { vms_restore_symbol (*ep); *ep++; } } return (status & 1); } kbuild-3149/src/kmk/kmk_cc_exec.h0000644000175000017500000000321513252530204016656 0ustar locutuslocutus/* $Id: kmk_cc_exec.h 2788 2015-09-06 15:43:10Z bird $ */ /** @file * kmk_cc - Make "Compiler". */ /* * Copyright (c) 2015 knut st. osmundsen * * This file is part of kBuild. * * kBuild 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. * * kBuild 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 kBuild. If not, see * */ #ifndef ___kmk_cc_and_exech #define ___kmk_cc_and_exech #ifdef CONFIG_WITH_COMPILER #include void kmk_cc_init(void); void kmk_cc_print_stats(void); struct variable; extern struct kmk_cc_expandprog *kmk_cc_compile_variable_for_expand(struct variable *pVar); extern struct kmk_cc_evalprog *kmk_cc_compile_variable_for_eval(struct variable *pVar); extern struct kmk_cc_evalprog *kmk_cc_compile_file_for_eval(FILE *pFile, const char *pszFilename); extern char *kmk_exec_expand_to_var_buf(struct variable *pVar, char *pchDst); extern void kmk_exec_eval_file(struct kmk_cc_evalprog *pProg); extern void kmk_exec_eval_variable(struct variable *pVar); extern void kmk_cc_variable_changed(struct variable *pVar); extern void kmk_cc_variable_deleted(struct variable *pVar); #endif /* CONFIG_WITH_COMPILER */ #endif kbuild-3149/src/kmk/kmk_cc_exec.c0000644000175000017500000076244213252530201016664 0ustar locutuslocutus#ifdef CONFIG_WITH_COMPILER /* $Id: kmk_cc_exec.c 3140 2018-03-14 21:28:10Z bird $ */ /** @file * kmk_cc - Make "Compiler". */ /* * Copyright (c) 2015 knut st. osmundsen * * This file is part of kBuild. * * kBuild 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. * * kBuild 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 kBuild. If not, see * */ /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ #include "makeint.h" #include "dep.h" #include "variable.h" #include "rule.h" #include "debug.h" #include "hash.h" #include #ifdef HAVE_STDINT_H # include #endif #include #include #include "k/kDefs.h" #include "k/kTypes.h" /********************************************************************************************************************************* * Defined Constants And Macros * *********************************************************************************************************************************/ /** @def KMK_CC_WITH_STATS * Enables the collection of extra statistics. */ #ifndef KMK_CC_WITH_STATS # ifdef CONFIG_WITH_MAKE_STATS # define KMK_CC_WITH_STATS # endif #endif /** @def KMK_CC_STRICT * Indicates whether assertions and other checks are enabled. */ #ifndef KMK_CC_STRICT # ifndef NDEBUG # define KMK_CC_STRICT # endif #endif #ifdef KMK_CC_STRICT # ifdef _MSC_VER # define KMK_CC_ASSERT(a_TrueExpr) do { if (!(a_TrueExpr)) __debugbreak(); } while (0) # elif defined(__GNUC__) && (defined(KBUILD_ARCH_X86) || defined(KBUILD_ARCH_AMD64)) # define KMK_CC_ASSERT(a_TrueExpr) do { if (!(a_TrueExpr)) __asm__ __volatile__("int3;nop"); } while (0) # else # define KMK_CC_ASSERT(a_TrueExpr) assert(a_TrueExpr) # endif #else # define KMK_CC_ASSERT(a_TrueExpr) do {} while (0) #endif #define KMK_CC_ASSERT_ALIGNED(a_uValue, a_uAlignment) \ KMK_CC_ASSERT( ((a_uValue) & ((a_uAlignment) - 1)) == 0 ) /** @def KMK_CC_OFFSETOF * Offsetof for simple stuff. */ #if defined(__GNUC__) # define KMK_CC_OFFSETOF(a_Struct, a_Member) __builtin_offsetof(a_Struct, a_Member) #else # define KMK_CC_OFFSETOF(a_Struct, a_Member) ( (uintptr_t)&( ((a_Struct *)(void *)0)->a_Member) ) #endif /** def KMK_CC_SIZEOF_MEMBER */ #define KMK_CC_SIZEOF_MEMBER(a_Struct, a_Member) ( sizeof( ((a_Struct *)(void *)0x1000)->a_Member) ) /** @def KMK_CC_SIZEOF_VAR_STRUCT * Size of a struct with a variable sized array as the final member. */ #define KMK_CC_SIZEOF_VAR_STRUCT(a_Struct, a_FinalArrayMember, a_cArray) \ ( KMK_CC_OFFSETOF(a_Struct, a_FinalArrayMember) + KMK_CC_SIZEOF_MEMBER(a_Struct, a_FinalArrayMember) * (a_cArray) ) /** @def KMK_CC_STATIC_ASSERT_EX * Compile time assertion with text. */ #ifdef _MSC_VER_ # if _MSC_VER >= 1600 # define KMK_CC_STATIC_ASSERT_EX(a_Expr, a_szExpl) static_assert(a_Expr, a_szExpl) # else # define KMK_CC_STATIC_ASSERT_EX(a_Expr, a_szExpl) typedef int RTASSERTVAR[(a_Expr) ? 1 : 0] # endif #elif defined(__GNUC__) && defined(__GXX_EXPERIMENTAL_CXX0X__) # define KMK_CC_STATIC_ASSERT_EX(a_Expr, a_szExpl) static_assert(a_Expr, a_szExpl) #elif !defined(__GNUC__) && !defined(__IBMC__) && !defined(__IBMCPP__) # define KMK_CC_STATIC_ASSERT_EX(a_Expr, a_szExpl) typedef int KMK_CC_STATIC_ASSERT_EX_TYPE[(a_Expr) ? 1 : 0] #else # define KMK_CC_STATIC_ASSERT_EX(a_Expr, a_szExpl) extern int KMK_CC_STATIC_ASSERT_EX_VAR[(a_Expr) ? 1 : 0] extern int KMK_CC_STATIC_ASSERT_EX_VAR[1]; #endif /** @def KMK_CC_STATIC_ASSERT * Compile time assertion, simple variant. */ #define KMK_CC_STATIC_ASSERT(a_Expr) KMK_CC_STATIC_ASSERT_EX(a_Expr, #a_Expr) /** Aligns a size for the block allocator. */ #define KMK_CC_BLOCK_ALIGN_SIZE(a_cb) ( ((a_cb) + (sizeof(void *) - 1U)) & ~(uint32_t)(sizeof(void *) - 1U) ) /** How to declare a no-return function. * Place between scope (if any) and return type. */ #ifdef _MSC_VER # define KMK_CC_FN_NO_RETURN __declspec(noreturn) #elif defined(__GNUC__) # define KMK_CC_FN_NO_RETURN __attribute__((__noreturn__)) #endif /** @defgroup grp_kmk_cc_evalprog Makefile Evaluation * @{ */ #if 1 # define KMK_CC_EVAL_DPRINTF_UNPACK(...) __VA_ARGS__ # define KMK_CC_EVAL_DPRINTF(a) fprintf(stderr, KMK_CC_EVAL_DPRINTF_UNPACK a) #else # define KMK_CC_EVAL_DPRINTF(a) do { } while (0) #endif /** @name KMK_CC_EVAL_QUALIFIER_XXX - Variable qualifiers. * @{ */ #define KMK_CC_EVAL_QUALIFIER_LOCAL 1 #define KMK_CC_EVAL_QUALIFIER_EXPORT 2 #define KMK_CC_EVAL_QUALIFIER_OVERRIDE 4 #define KMK_CC_EVAL_QUALIFIER_PRIVATE 8 /** @} */ /** Eval: Max nesting depth of makefile conditionals. * Affects stack usage in kmk_cc_eval_compile_worker. */ #define KMK_CC_EVAL_MAX_IF_DEPTH 32 /** Eval: Maximum number of escaped end of line sequences to track. * Affects stack usage in kmk_cc_eval_compile_worker, but not the actual * number of consequtive escaped newlines in the input file/variable. */ #define KMK_CC_EVAL_MAX_ESC_EOLS 2 /** Minimum keyword length. */ #define KMK_CC_EVAL_KEYWORD_MIN 2 /** Maximum keyword length. */ #define KMK_CC_EVAL_KEYWORD_MAX 16 /** @name KMK_CC_EVAL_CH_XXX - flags found in g_abEvalCcChars. * @{ */ /** Normal character, nothing special. */ #define KMK_CC_EVAL_CH_NORMAL UINT16_C(0) /** Blank character. */ #define KMK_CC_EVAL_CH_BLANK UINT16_C(1) #define KMK_CC_EVAL_IS_BLANK(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_BLANK) /** Space character. */ #define KMK_CC_EVAL_CH_SPACE UINT16_C(2) #define KMK_CC_EVAL_IS_SPACE(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_SPACE) /** Space character or potential EOL escape backslash. */ #define KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH UINT16_C(4) #define KMK_CC_EVAL_IS_SPACE_OR_BACKSLASH(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH) /** Anything we need to take notice of when parsing something could be a * variable name or a recipe. * All space characters, backslash (EOL escape), variable expansion dollar, * variable assignment operator chars, recipe colon and recipe percent. */ #define KMK_CC_EVAL_CH_SPACE_VAR_OR_RECIPE UINT16_C(8) #define KMK_CC_EVAL_IS_SPACE_VAR_OR_RECIPE(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_SPACE_VAR_OR_RECIPE) /** Dollar character (possible variable expansion). */ #define KMK_CC_EVAL_CH_DOLLAR UINT16_C(16) #define KMK_CC_EVAL_IS_DOLLAR(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_DOLLAR) /** Dollar character (possible variable expansion). */ #define KMK_CC_EVAL_CH_BACKSLASH UINT16_C(32) #define KMK_CC_EVAL_IS_BACKSLASH(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_BACKSLASH) /** Possible EOL character. */ #define KMK_CC_EVAL_CH_EOL_CANDIDATE UINT16_C(64) #define KMK_CC_EVAL_IS_EOL_CANDIDATE(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_EOL_CANDIDATE) /** First character in a keyword. */ #define KMK_CC_EVAL_CH_1ST_IN_KEYWORD UINT16_C(128) #define KMK_CC_EVAL_IS_1ST_IN_KEYWORD(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_1ST_IN_KEYWORD) /** Second character in a keyword. */ #define KMK_CC_EVAL_CH_2ND_IN_KEYWORD UINT16_C(256) #define KMK_CC_EVAL_IS_2ND_IN_KEYWORD(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_2ND_IN_KEYWORD) /** First character in a variable qualifier keyword or 'define'. */ #define KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD UINT16_C(512) #define KMK_CC_EVAL_IS_1ST_IN_VARIABLE_KEYWORD(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD) /** Used when parsing variable names, looking for the end of a nested * variable reference. Matches parentheses and backslash (escaped eol). */ #define KMK_CC_EVAL_CH_PAREN_OR_SLASH UINT16_C(1024) #define KMK_CC_EVAL_IS_PAREN_OR_SLASH(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_PAREN_OR_SLASH) /** Used when parsing ifeq/ifneq (,) sequences. * Matches parentheses, comma and dollar (for non-plain string detection). */ #define KMK_CC_EVAL_CH_PAREN_COMMA_OR_DOLLAR UINT16_C(2048) #define KMK_CC_EVAL_IS_PAREN_COMMA_OR_DOLLAR(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_PAREN_COMMA_OR_DOLLAR) /** Test of space or dollar characters. */ #define KMK_CC_EVAL_IS_SPACE_OR_DOLLAR(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & (KMK_CC_EVAL_CH_SPACE | KMK_CC_EVAL_CH_DOLLAR)) /** Test of space, dollar or backslash (possible EOL escape) characters. */ #define KMK_CC_EVAL_IS_SPACE_DOLLAR_OR_SLASH(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & (KMK_CC_EVAL_CH_SPACE | KMK_CC_EVAL_CH_DOLLAR | KMK_CC_EVAL_CH_BACKSLASH)) /** Test of space, dollar, backslash (possible EOL escape) or variable * assingment characters. */ #define KMK_CC_EVAL_IS_SPACE_DOLLAR_SLASH_OR_ASSIGN(a_ch) \ (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & (KMK_CC_EVAL_CH_SPACE | KMK_CC_EVAL_CH_SPACE_VAR_OR_RECIPE | KMK_CC_EVAL_CH_DOLLAR)) /** @} */ /** Sets a bitmap entry. * @param a_abBitmap Typically g_abEvalCcChars. * @param a_ch The character to set. * @param a_uVal The value to OR in. */ #define KMK_CC_EVAL_BM_OR(g_abBitmap, a_ch, a_uVal) do { (g_abBitmap)[(unsigned char)(a_ch)] |= (a_uVal); } while (0) /** Gets a bitmap entry. * @returns The value corresponding to @a a_ch. * @param a_abBitmap Typically g_abEvalCcChars. * @param a_ch The character to set. */ #define KMK_CC_EVAL_BM_GET(g_abBitmap, a_ch) ( (g_abBitmap)[(unsigned char)(a_ch)] ) /** @} */ /********************************************************************************************************************************* * Structures and Typedefs * *********************************************************************************************************************************/ /** * Block of expand instructions. * * To avoid wasting space on "next" pointers, as well as a lot of time walking * these chains when destroying programs, we work with blocks of instructions. */ typedef struct kmk_cc_block { /** The pointer to the next block (LIFO). */ struct kmk_cc_block *pNext; /** The size of this block. */ uint32_t cbBlock; /** The offset of the next free byte in the block. When set to cbBlock the * block is 100% full. */ uint32_t offNext; } KMKCCBLOCK; typedef KMKCCBLOCK *PKMKCCBLOCK; /** @defgroup grp_kmk_cc_exp String Expansion * @{*/ /** * String expansion statistics. */ typedef struct KMKCCEXPSTATS { /** Recent average size. */ uint32_t cchAvg; } KMKCCEXPSTATS; typedef KMKCCEXPSTATS *PKMKCCEXPSTATS; /** * Expansion instructions. */ typedef enum KMKCCEXPINSTR { /** Copy a plain string. */ kKmkCcExpInstr_CopyString = 0, /** Insert an expanded variable value, which name we already know. */ kKmkCcExpInstr_PlainVariable, /** Insert an expanded variable value, the name is dynamic (sub prog). */ kKmkCcExpInstr_DynamicVariable, /** Insert an expanded variable value, which name we already know, doing * search an replace on a string. */ kKmkCcExpInstr_SearchAndReplacePlainVariable, /** Insert the output of function that requires no argument expansion. */ kKmkCcExpInstr_PlainFunction, /** Insert the output of function that requires dynamic expansion of one ore * more arguments. (Dynamic is perhaps not such a great name, but whatever.) */ kKmkCcExpInstr_DynamicFunction, /** Jump to a new instruction block. */ kKmkCcExpInstr_Jump, /** We're done, return. Has no specific structure. */ kKmkCcExpInstr_Return, /** The end of valid instructions (exclusive). */ kKmkCcExpInstr_End } KMKCCEXPINSTR; /** Instruction core. */ typedef struct kmk_cc_exp_core { /** The instruction opcode number (KMKCCEXPINSTR). */ KMKCCEXPINSTR enmOpcode; } KMKCCEXPCORE; typedef KMKCCEXPCORE *PKMKCCEXPCORE; /** * String expansion subprogram. */ #pragma pack(1) /* save some precious bytes */ typedef struct kmk_cc_exp_subprog { /** Pointer to the first instruction. */ PKMKCCEXPCORE pFirstInstr; /** Statistics. */ KMKCCEXPSTATS Stats; } KMKCCEXPSUBPROG; #pragma pack() typedef KMKCCEXPSUBPROG *PKMKCCEXPSUBPROG; KMK_CC_STATIC_ASSERT(sizeof(KMKCCEXPSUBPROG) == 12 || sizeof(void *) != 8); /** * String expansion subprogram or plain string. */ #pragma pack(1) /* save some precious bytes */ typedef struct kmk_cc_exp_subprog_or_string { /** Either a plain string pointer or a subprogram. */ union { /** Subprogram for expanding this argument. */ KMKCCEXPSUBPROG Subprog; /** Pointer to the plain string. */ struct { /** Pointer to the string. */ const char *psz; /** String length. */ uint32_t cch; } Plain; } u; /** Set if subprogram (u.Subprog), clear if plain string (u.Plain). */ uint8_t fSubprog; /** Set if the plain string is kept in the variable_strcache. * @remarks Here rather than in u.Plain to make use of alignment padding. */ uint8_t fPlainIsInVarStrCache; /** Context/user specific. */ uint8_t bUser; /** Context/user specific #2. */ uint8_t bUser2; } KMKCCEXPSUBPROGORPLAIN; #pragma pack() typedef KMKCCEXPSUBPROGORPLAIN *PKMKCCEXPSUBPROGORPLAIN; KMK_CC_STATIC_ASSERT( sizeof(void *) == 8 ? sizeof(KMKCCEXPSUBPROGORPLAIN) == 16 : sizeof(void *) == 4 ? sizeof(KMKCCEXPSUBPROGORPLAIN) == 12 : 1); /** * kKmkCcExpInstr_CopyString instruction format. */ typedef struct kmk_cc_exp_copy_string { /** The core instruction. */ KMKCCEXPCORE Core; /** The number of bytes to copy. */ uint32_t cchCopy; /** Pointer to the source string (not terminated at cchCopy). */ const char *pachSrc; } KMKCCEXPCOPYSTRING; typedef KMKCCEXPCOPYSTRING *PKMKCCEXPCOPYSTRING; /** * kKmkCcExpInstr_PlainVariable instruction format. */ typedef struct kmk_cc_exp_plain_variable { /** The core instruction. */ KMKCCEXPCORE Core; /** The name of the variable (points into variable_strcache). */ const char *pszName; } KMKCCEXPPLAINVAR; typedef KMKCCEXPPLAINVAR *PKMKCCEXPPLAINVAR; /** * kKmkCcExpInstr_DynamicVariable instruction format. */ typedef struct kmk_cc_exp_dynamic_variable { /** The core instruction. */ KMKCCEXPCORE Core; /** The subprogram that will give us the variable name. */ KMKCCEXPSUBPROG Subprog; /** Where to continue after this instruction. (This is necessary since the * instructions of the subprogram are emitted after this instruction.) */ PKMKCCEXPCORE pNext; } KMKCCEXPDYNVAR; typedef KMKCCEXPDYNVAR *PKMKCCEXPDYNVAR; /** * kKmkCcExpInstr_SearchAndReplacePlainVariable instruction format. */ typedef struct kmk_cc_exp_sr_plain_variable { /** The core instruction. */ KMKCCEXPCORE Core; /** Where to continue after this instruction. (This is necessary since the * instruction contains string data of variable size.) */ PKMKCCEXPCORE pNext; /** The name of the variable (points into variable_strcache). */ const char *pszName; /** Search pattern. */ const char *pszSearchPattern; /** Replacement pattern. */ const char *pszReplacePattern; /** Offset into pszSearchPattern of the significant '%' char. */ uint32_t offPctSearchPattern; /** Offset into pszReplacePattern of the significant '%' char. */ uint32_t offPctReplacePattern; } KMKCCEXPSRPLAINVAR; typedef KMKCCEXPSRPLAINVAR *PKMKCCEXPSRPLAINVAR; /** * Instruction format parts common to both kKmkCcExpInstr_PlainFunction and * kKmkCcExpInstr_DynamicFunction. */ typedef struct kmk_cc_exp_function_core { /** The core instruction. */ KMKCCEXPCORE Core; /** Number of arguments. */ uint32_t cArgs; /**< @todo uint16_t to save 7 bytes of unecessary alignment padding on 64-bit systems, or merge fDirty into this member. */ /** Set if the function could be modifying the input arguments. */ uint8_t fDirty; /** Where to continue after this instruction. (This is necessary since the * instructions are of variable size and may be followed by string data.) */ PKMKCCEXPCORE pNext; /** * Pointer to the function table entry. * * @returns New variable buffer position. * @param pchDst Current variable buffer position. * @param papszArgs Pointer to a NULL terminated array of argument strings. * @param pszFuncName The name of the function being called. */ char * (*pfnFunction)(char *pchDst, char **papszArgs, const char *pszFuncName); /** Pointer to the function name in the variable string cache. */ const char *pszFuncName; } KMKCCEXPFUNCCORE; typedef KMKCCEXPFUNCCORE *PKMKCCEXPFUNCCORE; /** * Instruction format for kKmkCcExpInstr_PlainFunction. */ typedef struct kmk_cc_exp_plain_function { /** The bits comment to both plain and dynamic functions. */ KMKCCEXPFUNCCORE FnCore; /** Variable sized argument list (cArgs + 1 in length, last entry is NULL). * The string pointers are to memory following this instruction, to memory in * the next block or to memory in the variable / makefile we're working on * (if zero terminated appropriately). */ const char *apszArgs[1]; } KMKCCEXPPLAINFUNC; typedef KMKCCEXPPLAINFUNC *PKMKCCEXPPLAINFUNC; /** Calculates the size of an KMKCCEXPPLAINFUNC structure with the apszArgs * member holding a_cArgs entries plus a NULL terminator. */ #define KMKCCEXPPLAINFUNC_SIZE(a_cArgs) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEXPDYNFUNC, aArgs, (a_cArgs) + 1) /** * Instruction format for kKmkCcExpInstr_DynamicFunction. */ typedef struct kmk_cc_exp_dyn_function { /** The bits comment to both plain and dynamic functions. */ KMKCCEXPFUNCCORE FnCore; /** Variable sized argument list (FnCore.cArgs in length). * The subprograms / strings are allocated after this array (or in the next * block). */ KMKCCEXPSUBPROGORPLAIN aArgs[1]; } KMKCCEXPDYNFUNC; typedef KMKCCEXPDYNFUNC *PKMKCCEXPDYNFUNC; /** Calculates the size of an KMKCCEXPDYNFUNC structure with the apszArgs * member holding a_cArgs entries (no zero terminator). */ #define KMKCCEXPDYNFUNC_SIZE(a_cArgs) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEXPDYNFUNC, aArgs, a_cArgs) /** * Instruction format for kKmkCcExpInstr_Jump. */ typedef struct kmk_cc_exp_jump { /** The core instruction. */ KMKCCEXPCORE Core; /** Where to jump to (new instruction block, typically). */ PKMKCCEXPCORE pNext; } KMKCCEXPJUMP; typedef KMKCCEXPJUMP *PKMKCCEXPJUMP; /** * String expansion program. */ typedef struct kmk_cc_expandprog { /** Pointer to the first instruction for this program. */ PKMKCCEXPCORE pFirstInstr; /** List of blocks for this program (LIFO). */ PKMKCCBLOCK pBlockTail; /** Statistics. */ KMKCCEXPSTATS Stats; #ifdef KMK_CC_STRICT /** The hash of the input string. Used to check that we get all the change * notifications we require. */ uint32_t uInputHash; #endif /** Reference count. */ uint32_t volatile cRefs; } KMKCCEXPPROG; /** Pointer to a string expansion program. */ typedef KMKCCEXPPROG *PKMKCCEXPPROG; /** @} */ /** @addtogroup grp_kmk_cc_evalprog * @{ */ /** Pointer to a makefile evaluation program. */ typedef struct kmk_cc_evalprog *PKMKCCEVALPROG; /** * Makefile evaluation instructions. */ typedef enum KMKCCEVALINSTR { /** Jump instruction - KMKCCEVALJUMP. */ kKmkCcEvalInstr_jump = 0, /** [local|override|export] variable = value - KMKCCEVALASSIGN. * @note Can be used for target-specific variables. */ kKmkCcEvalInstr_assign_recursive, /** [local|override|export] variable := value - KMKCCEVALASSIGN. * @note Can be used for target-specific variables. */ kKmkCcEvalInstr_assign_simple, /** [local|override|export] variable += value - KMKCCEVALASSIGN. * @note Can be used for target-specific variables. */ kKmkCcEvalInstr_assign_append, /** [local|override|export] variable -= value - KMKCCEVALASSIGN. * @note Can be used for target-specific variables. */ kKmkCcEvalInstr_assign_prepend, /** [local|override|export] variable ?= value - KMKCCEVALASSIGN. * @note Can be used for target-specific variables. */ kKmkCcEvalInstr_assign_if_new, /** [local|override|export] define variable ... endef - KMKCCEVALASSIGNDEF. */ kKmkCcEvalInstr_assign_define, /** export variable1 [variable2...] - KMKCCEVALVARIABLES. */ kKmkCcEvalInstr_export, /** unexport variable1 [variable2...] - KMKCCEVALVARIABLES. */ kKmkCcEvalInstr_unexport, /** export - KMKCCEVALCORE. */ kKmkCcEvalInstr_export_all, /** unexport - KMKCCEVALCORE. */ kKmkCcEvalInstr_unexport_all, /** [local|override] undefine - KMKCCEVALVARIABLES. */ kKmkCcEvalInstr_undefine, /** [else] ifdef variable - KMKCCEVALIFDEFPLAIN. */ kKmkCcEvalInstr_ifdef_plain, /** [else] ifndef variable - KMKCCEVALIFDEFPLAIN. */ kKmkCcEvalInstr_ifndef_plain, /** [else] ifdef variable - KMKCCEVALIFDEFDYNAMIC. */ kKmkCcEvalInstr_ifdef_dynamic, /** [else] ifndef variable - KMKCCEVALIFDEFDYNAMIC. */ kKmkCcEvalInstr_ifndef_dynamic, /** [else] ifeq (a,b) - KMKCCEVALIFEQ. */ kKmkCcEvalInstr_ifeq, /** [else] ifeq (a,b) - KMKCCEVALIFEQ. */ kKmkCcEvalInstr_ifneq, /** [else] if1of (set-a,set-b) - KMKCCEVALIF1OF. */ kKmkCcEvalInstr_if1of, /** [else] ifn1of (set-a,set-b) - KMKCCEVALIF1OF. */ kKmkCcEvalInstr_ifn1of, /** [else] if expr - KMKCCEVALIFEXPR. */ kKmkCcEvalInstr_if, /** include file1 [file2...] - KMKCCEVALINCLUDE. */ kKmkCcEvalInstr_include, /** [sinclude|-include] file1 [file2...] - KMKCCEVALINCLUDE. */ kKmkCcEvalInstr_include_silent, /** includedep file1 [file2...] - KMKCCEVALINCLUDE. */ kKmkCcEvalInstr_includedep, /** includedep-queue file1 [file2...] - KMKCCEVALINCLUDE. */ kKmkCcEvalInstr_includedep_queue, /** includedep-flush file1 [file2...] - KMKCCEVALINCLUDE. */ kKmkCcEvalInstr_includedep_flush, /** Recipe without commands (defines dependencies) - KMKCCEVALRECIPE. */ kKmkCcEvalInstr_recipe_no_commands, /** Recipe with commands (defines dependencies) - KMKCCEVALRECIPE. */ kKmkCcEvalInstr_recipe_start_normal, /** Recipe with commands (defines dependencies) - KMKCCEVALRECIPE. */ kKmkCcEvalInstr_recipe_start_double_colon, /** Recipe with commands (defines dependencies) - KMKCCEVALRECIPE. */ kKmkCcEvalInstr_recipe_start_pattern, /** Adds more commands to the current recipe - KMKCCEVALRECIPECOMMANDS. */ kKmkCcEvalInstr_recipe_commands, /** Special instruction for indicating the end of the recipe commands - KMKCCEVALCORE. */ kKmkCcEvalInstr_recipe_end, /** Cancel previously defined pattern rule - KMKCCEVALRECIPE. */ kKmkCcEvalInstr_recipe_cancel_pattern, /** vpath pattern directories - KMKCCEVALVPATH. */ kKmkCcEvalInstr_vpath, /** vpath pattern directories - KMKCCEVALVPATH. */ kKmkCcEvalInstr_vpath_clear_pattern, /** vpath - KMKCCEVALCORE. */ kKmkCcEvalInstr_vpath_clear_all, /** The end of valid instructions (exclusive). */ kKmkCcEvalInstr_End } KMKCCEVALINSTR; /** * Instruction core common to all instructions. */ typedef struct kmk_cc_eval_core { /** The instruction opcode number (KMKCCEVALINSTR). */ KMKCCEVALINSTR enmOpcode; /** The line number in the source this statement is associated with. */ unsigned iLine; } KMKCCEVALCORE; /** Pointer to an instruction core structure. */ typedef KMKCCEVALCORE *PKMKCCEVALCORE; /** * Instruction format for kKmkCcEvalInstr_jump. */ typedef struct kmk_cc_eval_jump { /** The core instruction. */ KMKCCEVALCORE Core; /** Where to jump to (new instruction block or endif, typically). */ PKMKCCEVALCORE pNext; } KMKCCEVALJUMP; typedef KMKCCEVALJUMP *PKMKCCEVALJUMP; /** * Instruction format for kKmkCcEvalInstr_assign_recursive, * kKmkCcEvalInstr_assign_simple, kKmkCcEvalInstr_assign_append, * kKmkCcEvalInstr_assign_prepend and kKmkCcEvalInstr_assign_if_new. */ typedef struct kmk_cc_eval_assign { /** The core instruction. */ KMKCCEVALCORE Core; /** Whether the 'export' qualifier was used. */ uint8_t fExport; /** Whether the 'override' qualifier was used. */ uint8_t fOverride; /** Whether the 'local' qualifier was used. */ uint8_t fLocal; /** Whether the 'private' qualifier was used. */ uint8_t fPrivate; /** The variable name. * @remarks Plain text names are in variable_strcache. */ KMKCCEXPSUBPROGORPLAIN Variable; /** The value or value expression. */ KMKCCEXPSUBPROGORPLAIN Value; /** Pointer to the next instruction. */ PKMKCCEVALCORE pNext; } KMKCCEVALASSIGN; typedef KMKCCEVALASSIGN *PKMKCCEVALASSIGN; /** * Instruction format for kKmkCcEvalInstr_assign_define. */ typedef struct kmk_cc_eval_assign_define { /** The assignment core structure. */ KMKCCEVALASSIGN AssignCore; /** Makefile evaluation program compiled from the define. * NULL if it does not compile. * @todo Let's see if this is actually doable... */ PKMKCCEVALPROG pEvalProg; } KMKCCEVALASSIGNDEF; typedef KMKCCEVALASSIGNDEF *PKMKCCEVALASSIGNDEF; /** * Instruction format for kKmkCcEvalInstr_export, kKmkCcEvalInstr_unexport and * kKmkCcEvalInstr_undefine. */ typedef struct kmk_cc_eval_variables { /** The core instruction. */ KMKCCEVALCORE Core; /** The number of variables named in aVars. */ uint32_t cVars; /** Whether the 'local' qualifier was used (undefine only). */ uint8_t fLocal; /** Pointer to the next instruction. */ PKMKCCEVALCORE pNext; /** The variable names. * Expressions will be expanded and split on space. * @remarks Plain text names are in variable_strcache. */ KMKCCEXPSUBPROGORPLAIN aVars[1]; } KMKCCEVALVARIABLES; typedef KMKCCEVALVARIABLES *PKMKCCEVALVARIABLES; /** Calculates the size of an KMKCCEVALVARIABLES structure for @a a_cVars. */ #define KMKCCEVALVARIABLES_SIZE(a_cVars) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEVALVARIABLES, aVars, a_cVars) /** * Core structure for all conditionals (kKmkCcEvalInstr_if*). */ typedef struct kmk_cc_eval_if_core { /** The core instruction. */ KMKCCEVALCORE Core; /** Condition true: Pointer to the next instruction. */ PKMKCCEVALCORE pNextTrue; /** Condition false: Pointer to the next instruction (i.e. 'else if*' * or whatever follows 'else' / 'endif'. */ PKMKCCEVALCORE pNextFalse; /** Pointer to the previous conditional for 'else if*' directives. * This is only to assist the compilation process. */ struct kmk_cc_eval_if_core *pPrevCond; /** Pointer to the jump out of the true block, if followed by 'else'. * This is only to assist the compilation process. */ PKMKCCEVALJUMP pTrueEndJump; } KMKCCEVALIFCORE; typedef KMKCCEVALIFCORE *PKMKCCEVALIFCORE; /** * Instruction format for kKmkCcEvalInstr_ifdef_plain and * kKmkCcEvalInstr_ifndef_plain. * The variable name is known at compilation time. */ typedef struct kmk_cc_eval_ifdef_plain { /** The 'if' core structure. */ KMKCCEVALIFCORE IfCore; /** The name of the variable (points into variable_strcache). */ const char *pszName; } KMKCCEVALIFDEFPLAIN; typedef KMKCCEVALIFDEFPLAIN *PKMKCCEVALIFDEFPLAIN; /** * Instruction format for kKmkCcEvalInstr_ifdef_dynamic and * kKmkCcEvalInstr_ifndef_dynamic. * The variable name is dynamically expanded at run time. */ typedef struct kmk_cc_eval_ifdef_dynamic { /** The 'if' core structure. */ KMKCCEVALIFCORE IfCore; /** The subprogram that will give us the variable name. */ KMKCCEXPSUBPROG NameSubprog; } KMKCCEVALIFDEFDYNAMIC; typedef KMKCCEVALIFDEFDYNAMIC *PKMKCCEVALIFDEFDYNAMIC; /** * Instruction format for kKmkCcEvalInstr_ifeq and kKmkCcEvalInstr_ifneq. */ typedef struct kmk_cc_eval_ifeq { /** The 'if' core structure. */ KMKCCEVALIFCORE IfCore; /** The left hand side string expression (dynamic or plain). */ KMKCCEXPSUBPROGORPLAIN Left; /** The rigth hand side string expression (dynamic or plain). */ KMKCCEXPSUBPROGORPLAIN Right; } KMKCCEVALIFEQ; typedef KMKCCEVALIFEQ *PKMKCCEVALIFEQ; /** * Instruction format for kKmkCcEvalInstr_if1of and kKmkCcEvalInstr_ifn1of. * * @todo This can be optimized further by pre-hashing plain text items. One of * the sides are usually plain text. */ typedef struct kmk_cc_eval_if1of { /** The 'if' core structure. */ KMKCCEVALIFCORE IfCore; /** The left hand side string expression (dynamic or plain). */ KMKCCEXPSUBPROGORPLAIN Left; /** The rigth hand side string expression (dynamic or plain). */ KMKCCEXPSUBPROGORPLAIN Right; } KMKCCEVALIF1OF; typedef KMKCCEVALIF1OF *PKMKCCEVALIF1OF; /** * Instruction format for kKmkCcEvalInstr_if. * * @todo Parse and compile the expression. At least strip whitespace in it. */ typedef struct kmk_cc_eval_if_expr { /** The 'if' core structure. */ KMKCCEVALIFCORE IfCore; /** The expression string length. */ uint16_t cchExpr; /** The expression string. */ char szExpr[1]; } KMKCCEVALIFEXPR; typedef KMKCCEVALIFEXPR *PKMKCCEVALIFEXPR; /** Calculates the size of an KMKCCEVALIFEXPR structure for @a a_cchExpr long * expression string (terminator is automatically added). */ #define KMKCCEVALIFEXPR_SIZE(a_cchExpr) KMK_CC_BLOCK_ALIGN_SIZE(KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEVALIFEXPR, szExpr, (a_cchExpr) + 1)) /** * Instruction format for kKmkCcEvalInstr_include, * kKmkCcEvalInstr_include_silent, kKmkCcEvalInstr_includedep, * kKmkCcEvalInstr_includedep_queue, kKmkCcEvalInstr_includedep_flush. */ typedef struct kmk_cc_eval_include { /** The core instruction. */ KMKCCEVALCORE Core; /** The number of files. */ uint32_t cFiles; /** Pointer to the next instruction (subprogs and strings after this one). */ PKMKCCEVALCORE pNext; /** The files to be included. * Expressions will be expanded and split on space. * @todo Plain text file name could be replaced by file string cache entries. */ KMKCCEXPSUBPROGORPLAIN aFiles[1]; } KMKCCEVALINCLUDE; typedef KMKCCEVALINCLUDE *PKMKCCEVALINCLUDE; /** Calculates the size of an KMKCCEVALINCLUDE structure for @a a_cFiles files. */ #define KMKCCEVALINCLUDE_SIZE(a_cFiles) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEVALINCLUDE, aFiles, a_cFiles) /** * Instruction format for kKmkCcEvalInstr_recipe_no_commands, * kKmkCcEvalInstr_recipe_start_normal, * kKmkCcEvalInstr_recipe_start_double_colon, kKmkCcEvalInstr_includedep_queue, * kKmkCcEvalInstr_recipe_start_pattern. */ typedef struct kmk_cc_eval_recipe { /** The core instruction. */ KMKCCEVALCORE Core; /** The total number of files and dependencies in aFilesAndDeps. */ uint16_t cFilesAndDeps; /** Number of targets (from index 0). * This is always 1 if this is an explicit multitarget or pattern recipe, * indicating the main target. */ uint16_t cTargets; /** Explicit multitarget & patterns: First always made target. */ uint16_t iFirstAlwaysMadeTargets; /** Explicit multitarget & patterns: Number of always targets. */ uint16_t cAlwaysMadeTargets; /** Explicit multitarget: First maybe made target. */ uint16_t iFirstMaybeTarget; /** Explicit multitarget: Number of maybe made targets. */ uint16_t cMaybeTargets; /** First dependency. */ uint16_t iFirstDep; /** Number of ordinary dependnecies. */ uint16_t cDeps; /** First order only dependency. */ uint16_t iFirstOrderOnlyDep; /** Number of ordinary dependnecies. */ uint16_t cOrderOnlyDeps; /** Pointer to the next instruction (subprogs and strings after this one). */ PKMKCCEVALCORE pNext; /** The .MUST_MAKE variable value, if present. * If not present, this is a zero length plain string. */ KMKCCEXPSUBPROGORPLAIN MustMake; /** The target files and dependencies. * This is sorted into several sections, as defined by the above indexes and * counts. Expressions will be expanded and split on space. * * The KMKCCEXPSUBPROGORPLAIN::bUser member one of KMKCCEVALRECIPE_FD_XXX. * * @todo Plain text file name could be replaced by file string cache entries. */ KMKCCEXPSUBPROGORPLAIN aFilesAndDeps[1]; } KMKCCEVALRECIPE; typedef KMKCCEVALRECIPE *PKMKCCEVALRECIPE; /** Calculates the size of an KMKCCEVALRECIPE structure for @a a_cFiles * files. */ #define KMKCCEVALRECIPE_SIZE(a_cFilesAndDeps) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEVALRECIPE, aFilesAndDeps, a_cFilesAndDeps) /** @name KMKCCEVALRECIPE_FD_XXX - Values for KMKCCEVALRECIPE::aFilesAndDeps[x].bUser * @{ */ #define KMKCCEVALRECIPE_FD_NORMAL 0 #define KMKCCEVALRECIPE_FD_SEC_EXP 1 #define KMKCCEVALRECIPE_FD_SPECIAL_POSIX 2 #define KMKCCEVALRECIPE_FD_SPECIAL_SECONDEXPANSION 3 #define KMKCCEVALRECIPE_FD_SPECIAL_ONESHELL 4 /** @} */ /** * Instruction format for kKmkCcEvalInstr_recipe_commands. */ typedef struct kmk_cc_eval_recipe_commands { /** The core instruction. */ KMKCCEVALCORE Core; /** The number of search directories. */ uint32_t cCommands; /** Pointer to the next instruction (subprogs and strings after this one). */ PKMKCCEVALCORE pNext; /** Commands to add to the current recipe. * Expressions will be expanded and split on space. */ KMKCCEXPSUBPROGORPLAIN aCommands[1]; } KMKCCEVALRECIPECOMMANDS; typedef KMKCCEVALRECIPECOMMANDS *PKMKCCEVALRECIPECOMMANDS; /** Calculates the size of an KMKCCEVALRECIPECOMMANDS structure for * @a a_cCommands commands. */ #define KMKCCEVALRECIPECOMMANDS_SIZE(a_cCommands) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEVALRECIPECOMMANDS, aCommands, a_cCommands) /** * Instruction format for kKmkCcEvalInstr_vpath and * kKmkCcEvalInstr_vpath_clear_pattern. */ typedef struct kmk_cc_eval_vpath { /** The core instruction. */ KMKCCEVALCORE Core; /** The number of search directories. * This will be zero for kKmkCcEvalInstr_vpath_clear_pattern. */ uint32_t cDirs; /** Pointer to the next instruction (subprogs and strings after this one). */ PKMKCCEVALCORE pNext; /** The pattern. */ KMKCCEXPSUBPROGORPLAIN Pattern; /** The directory. Expressions will be expanded and split on space. */ KMKCCEXPSUBPROGORPLAIN aDirs[1]; } KMKCCEVALVPATH; typedef KMKCCEVALVPATH *PKMKCCEVALVPATH; /** Calculates the size of an KMKCCEVALVPATH structure for @a a_cFiles files. */ #define KMKCCEVALVPATH_SIZE(a_cFiles) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEVALVPATH, aDirs, a_cDirs) /** * Makefile evaluation program. */ typedef struct kmk_cc_evalprog { /** Pointer to the first instruction for this program. */ PKMKCCEVALCORE pFirstInstr; /** List of blocks for this program (LIFO). */ PKMKCCBLOCK pBlockTail; /** The name of the file containing this program. */ const char *pszFilename; /** The name of the variable containing this program, if applicable. */ const char *pszVarName; #ifdef KMK_CC_STRICT /** The hash of the input string. Used to check that we get all the change * notifications we require. */ uint32_t uInputHash; #endif /** Reference count. */ uint32_t volatile cRefs; } KMKCCEVALPROG; typedef KMKCCEVALPROG *PKMKCCEVALPROG; /** @} */ /********************************************************************************************************************************* * Global Variables * *********************************************************************************************************************************/ static uint32_t g_cVarForExpandCompilations = 0; static uint32_t g_cVarForExpandExecs = 0; static uint32_t g_cVarForEvalCompilations = 0; static uint32_t g_cVarForEvalExecs = 0; static uint32_t g_cFileForEvalCompilations = 0; static uint32_t g_cFileForEvalExecs = 0; #ifdef KMK_CC_WITH_STATS static uint32_t g_cBlockAllocated = 0; static uint32_t g_cbAllocated = 0; static uint32_t g_cBlocksAllocatedExpProgs = 0; static uint32_t g_cbAllocatedExpProgs = 0; static uint32_t g_cSingleBlockExpProgs = 0; static uint32_t g_cTwoBlockExpProgs = 0; static uint32_t g_cMultiBlockExpProgs = 0; static uint32_t g_cbUnusedMemExpProgs = 0; static uint32_t g_cBlocksAllocatedEvalProgs = 0; static uint32_t g_cbAllocatedEvalProgs = 0; static uint32_t g_cSingleBlockEvalProgs = 0; static uint32_t g_cTwoBlockEvalProgs = 0; static uint32_t g_cMultiBlockEvalProgs = 0; static uint32_t g_cbUnusedMemEvalProgs = 0; #endif /** Generic character classification, taking an 'unsigned char' index. * ASSUMES unsigned char is 8-bits. */ static uint16_t g_abEvalCcChars[256]; /** * Makefile evaluation keywords. */ static const char * const g_apszEvalKeywords[] = { "define", "export", "else", "endef", "endif", "ifdef", "ifndef", "ifeq", "ifneq", "if1of", "ifn1of", "if", "include", "includedep", "includedep-queue", "includedep-flush", "local", "override", "private", "sinclude", "unexport", "undefine", "vpath", "-include", }; /** This is parallel to KMKCCEVALINSTR. */ static const char * const g_apszEvalInstrNms[] = { "jump", "assign_recursive", "assign_simple", "assign_append", "assign_prepend", "assign_if_new", "assign_define", "export", "unexport", "export_all", "unexport_all", "undefine", "ifdef_plain", "ifndef_plain", "ifdef_dynamic", "ifndef_dynamic", "ifeq", "ifneq", "if1of", "ifn1of", "if", "include", "include_silent", "includedep", "includedep_queue", "includedep_flush", "recipe_no_commands", "recipe_start_normal", "recipe_start_double_colon", "recipe_start_pattern", "recipe_commands", "recipe_end", "recipe_cancel_pattern", "vpath", "vpath_clear_pattern", "vpath_clear_all", }; /********************************************************************************************************************************* * Internal Functions * *********************************************************************************************************************************/ static int kmk_cc_exp_compile_subprog(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr, PKMKCCEXPSUBPROG pSubprog); static char *kmk_exec_expand_subprog_to_tmp(PKMKCCEXPSUBPROG pSubprog, uint32_t *pcch); /** * Initializes global variables for the 'compiler'. */ void kmk_cc_init(void) { unsigned i; /* * Initialize the bitmap. */ memset(g_abEvalCcChars, 0, sizeof(g_abEvalCcChars)); /* blank chars */ KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ' ', KMK_CC_EVAL_CH_BLANK); KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\t', KMK_CC_EVAL_CH_BLANK); /* space chars and zero terminator. */ #define MY_SPACE_BITS KMK_CC_EVAL_CH_SPACE | KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH | KMK_CC_EVAL_CH_SPACE_VAR_OR_RECIPE KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ' ', MY_SPACE_BITS); KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\t', MY_SPACE_BITS); KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\n', MY_SPACE_BITS | KMK_CC_EVAL_CH_EOL_CANDIDATE); KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\v', MY_SPACE_BITS); KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\f', MY_SPACE_BITS); KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\r', MY_SPACE_BITS | KMK_CC_EVAL_CH_EOL_CANDIDATE); KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\\', KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH | KMK_CC_EVAL_CH_SPACE_VAR_OR_RECIPE); #undef MY_SPACE_BITS /* keywords */ for (i = 0; i < K_ELEMENTS(g_apszEvalKeywords); i++) { size_t cch = strlen(g_apszEvalKeywords[i]); KMK_CC_ASSERT(cch >= KMK_CC_EVAL_KEYWORD_MIN); KMK_CC_ASSERT(cch <= KMK_CC_EVAL_KEYWORD_MAX); KMK_CC_EVAL_BM_OR(g_abEvalCcChars, g_apszEvalKeywords[i][0], KMK_CC_EVAL_CH_1ST_IN_KEYWORD); KMK_CC_EVAL_BM_OR(g_abEvalCcChars, g_apszEvalKeywords[i][1], KMK_CC_EVAL_CH_2ND_IN_KEYWORD); } KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'd', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* define */ KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'e', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* export (, endef) */ KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'l', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* local */ KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'o', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* override */ KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'p', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* private */ KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'u', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* undefine, unexport */ /* Assignment punctuation and recipe stuff. */ KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '=', KMK_CC_EVAL_CH_SPACE_VAR_OR_RECIPE); KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ':', KMK_CC_EVAL_CH_SPACE_VAR_OR_RECIPE); /* For locating the end of variable expansion. */ KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '(', KMK_CC_EVAL_CH_PAREN_OR_SLASH); KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ')', KMK_CC_EVAL_CH_PAREN_OR_SLASH); KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '{', KMK_CC_EVAL_CH_PAREN_OR_SLASH); KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '}', KMK_CC_EVAL_CH_PAREN_OR_SLASH); KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\\', KMK_CC_EVAL_CH_PAREN_OR_SLASH); /* For parsing ifeq and if1of expressions. (GNU weirdly does not respect {} style function references.) */ KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '(', KMK_CC_EVAL_CH_PAREN_COMMA_OR_DOLLAR); KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ')', KMK_CC_EVAL_CH_PAREN_COMMA_OR_DOLLAR); KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ',', KMK_CC_EVAL_CH_PAREN_COMMA_OR_DOLLAR); KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '$', KMK_CC_EVAL_CH_PAREN_COMMA_OR_DOLLAR); /* Misc. */ KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '$', KMK_CC_EVAL_CH_DOLLAR); KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\\', KMK_CC_EVAL_CH_BACKSLASH); /* * Check that the eval instruction names match up. */ KMK_CC_ASSERT(strcmp(g_apszEvalInstrNms[kKmkCcEvalInstr_ifneq], "ifneq") == 0); KMK_CC_ASSERT(strcmp(g_apszEvalInstrNms[kKmkCcEvalInstr_vpath_clear_all], "vpath_clear_all") == 0); } /** * Prints stats (for kmk -p). */ void kmk_cc_print_stats(void) { #ifdef KMK_CC_WITH_STATS uint32_t const cEvalCompilations = g_cFileForEvalCompilations + g_cVarForEvalCompilations; #endif puts(_("\n# The kmk 'compiler' and kmk 'program executor':\n")); printf(_("# Variables compiled for string expansion: %6u\n"), g_cVarForExpandCompilations); printf(_("# Variables string expansion runs: %6u\n"), g_cVarForExpandExecs); printf(_("# String expansion runs per compile: %6u\n"), g_cVarForExpandExecs / g_cVarForExpandCompilations); #ifdef KMK_CC_WITH_STATS printf(_("# Single alloc block exp progs: %6u (%u%%)\n" "# Two alloc block exp progs: %6u (%u%%)\n" "# Three or more alloc block exp progs: %6u (%u%%)\n" ), g_cSingleBlockExpProgs, (uint32_t)((uint64_t)g_cSingleBlockExpProgs * 100 / g_cVarForExpandCompilations), g_cTwoBlockExpProgs, (uint32_t)((uint64_t)g_cTwoBlockExpProgs * 100 / g_cVarForExpandCompilations), g_cMultiBlockExpProgs, (uint32_t)((uint64_t)g_cMultiBlockExpProgs * 100 / g_cVarForExpandCompilations)); printf(_("# Total amount of memory for exp progs: %8u bytes\n" "# in: %6u blocks\n" "# avg block size: %6u bytes\n" "# unused memory: %8u bytes (%u%%)\n" "# avg unused memory per block: %6u bytes\n" "\n"), g_cbAllocatedExpProgs, g_cBlocksAllocatedExpProgs, g_cbAllocatedExpProgs / g_cBlocksAllocatedExpProgs, g_cbUnusedMemExpProgs, (uint32_t)((uint64_t)g_cbUnusedMemExpProgs * 100 / g_cbAllocatedExpProgs), g_cbUnusedMemExpProgs / g_cBlocksAllocatedExpProgs); puts(""); #endif printf(_("# Variables compiled for string eval: %6u\n"), g_cVarForEvalCompilations); printf(_("# Variables string eval runs: %6u\n"), g_cVarForEvalExecs); printf(_("# String evals runs per compile: %6u\n"), g_cVarForEvalExecs / g_cVarForEvalCompilations); printf(_("# Files compiled: %6u\n"), g_cFileForEvalCompilations); printf(_("# Files runs: %6u\n"), g_cFileForEvalExecs); printf(_("# Files eval runs per compile: %6u\n"), g_cFileForEvalExecs / g_cFileForEvalCompilations); #ifdef KMK_CC_WITH_STATS printf(_("# Single alloc block eval progs: %6u (%u%%)\n" "# Two alloc block eval progs: %6u (%u%%)\n" "# Three or more alloc block eval progs: %6u (%u%%)\n" ), g_cSingleBlockEvalProgs, (uint32_t)((uint64_t)g_cSingleBlockEvalProgs * 100 / cEvalCompilations), g_cTwoBlockEvalProgs, (uint32_t)((uint64_t)g_cTwoBlockEvalProgs * 100 / cEvalCompilations), g_cMultiBlockEvalProgs, (uint32_t)((uint64_t)g_cMultiBlockEvalProgs * 100 / cEvalCompilations)); printf(_("# Total amount of memory for eval progs: %8u bytes\n" "# in: %6u blocks\n" "# avg block size: %6u bytes\n" "# unused memory: %8u bytes (%u%%)\n" "# avg unused memory per block: %6u bytes\n" "\n"), g_cbAllocatedEvalProgs, g_cBlocksAllocatedEvalProgs, g_cbAllocatedEvalProgs / g_cBlocksAllocatedEvalProgs, g_cbUnusedMemEvalProgs, (uint32_t)((uint64_t)g_cbUnusedMemEvalProgs * 100 / g_cbAllocatedEvalProgs), g_cbUnusedMemEvalProgs / g_cBlocksAllocatedEvalProgs); puts(""); printf(_("# Total amount of block mem allocated: %8u bytes\n"), g_cbAllocated); printf(_("# Total number of block allocated: %8u\n"), g_cBlockAllocated); printf(_("# Average block size: %8u byte\n"), g_cbAllocated / g_cBlockAllocated); #endif puts(""); } /* * * Various utility functions. * Various utility functions. * Various utility functions. * */ /** * Counts the number of dollar chars in the string. * * @returns Number of dollar chars. * @param pchStr The string to search (does not need to be zero * terminated). * @param cchStr The length of the string. */ static uint32_t kmk_cc_count_dollars(const char *pchStr, uint32_t cchStr) { uint32_t cDollars = 0; const char *pch; while ((pch = memchr(pchStr, '$', cchStr)) != NULL) { cDollars++; cchStr -= pch - pchStr + 1; pchStr = pch + 1; } return cDollars; } #ifdef KMK_CC_STRICT /** * Used to check that function arguments are left alone. * @returns Updated hash. * @param uHash The current hash value. * @param psz The string to hash. */ static uint32_t kmk_cc_debug_string_hash(uint32_t uHash, const char *psz) { unsigned char ch; while ((ch = *(unsigned char const *)psz++) != '\0') uHash = (uHash << 6) + (uHash << 16) - uHash + (unsigned char)ch; return uHash; } /** * Used to check that function arguments are left alone. * @returns Updated hash. * @param uHash The current hash value. * @param pch The string to hash, not terminated. * @param cch The number of chars to hash. */ static uint32_t kmk_cc_debug_string_hash_n(uint32_t uHash, const char *pch, uint32_t cch) { while (cch-- > 0) { unsigned char ch = *(unsigned char const *)pch++; uHash = (uHash << 6) + (uHash << 16) - uHash + (unsigned char)ch; } return uHash; } #endif /* * * The allocator. * The allocator. * The allocator. * */ /** * For the first allocation using the block allocator. * * @returns Pointer to the first allocation (@a cbFirst in size). * @param ppBlockTail Where to return the pointer to the first block. * @param cbFirst The size of the first allocation. * @param cbHint Hint about how much memory we might be needing. */ static void *kmk_cc_block_alloc_first(PKMKCCBLOCK *ppBlockTail, size_t cbFirst, size_t cbHint) { uint32_t cbBlock; PKMKCCBLOCK pNewBlock; KMK_CC_ASSERT_ALIGNED(cbFirst, sizeof(void *)); KMK_CC_ASSERT(cbFirst <= 128); /* * Turn the hint into a block size. */ cbHint += cbFirst; if (cbHint <= 512) { if (cbHint <= 256) { if (cbFirst <= 64) cbBlock = 128; else cbBlock = 256; } else cbBlock = 256; } else if (cbHint < 2048) cbBlock = 1024; else if (cbHint < 3072) cbBlock = 2048; else cbBlock = 4096; /* * Allocate and initialize the first block. */ pNewBlock = (PKMKCCBLOCK)xmalloc(cbBlock); pNewBlock->cbBlock = cbBlock; pNewBlock->offNext = sizeof(*pNewBlock) + cbFirst; pNewBlock->pNext = NULL; *ppBlockTail = pNewBlock; #ifdef KMK_CC_WITH_STATS g_cBlockAllocated++; g_cbAllocated += cbBlock; #endif return pNewBlock + 1; } /** * Used for getting the address of the next instruction. * * @returns Pointer to the next allocation. * @param pBlockTail The allocator tail pointer. */ static void *kmk_cc_block_get_next_ptr(PKMKCCBLOCK pBlockTail) { return (char *)pBlockTail + pBlockTail->offNext; } /** * Realigns the allocator after doing byte or string allocations. * * @param ppBlockTail Pointer to the allocator tail pointer. */ static void kmk_cc_block_realign(PKMKCCBLOCK *ppBlockTail) { PKMKCCBLOCK pBlockTail = *ppBlockTail; if (pBlockTail->offNext & (sizeof(void *) - 1U)) { pBlockTail->offNext = KMK_CC_BLOCK_ALIGN_SIZE(pBlockTail->offNext); KMK_CC_ASSERT(pBlockTail->cbBlock - pBlockTail->offNext >= sizeof(KMKCCEXPJUMP)); } } /** * Grows the allocation with another block, byte allocator case. * * @returns Pointer to the byte allocation. * @param ppBlockTail Pointer to the allocator tail pointer. * @param cb The number of bytes to allocate. */ static void *kmk_cc_block_byte_alloc_grow(PKMKCCBLOCK *ppBlockTail, uint32_t cb) { PKMKCCBLOCK pOldBlock = *ppBlockTail; PKMKCCBLOCK pPrevBlock = pOldBlock->pNext; PKMKCCBLOCK pNewBlock; uint32_t cbBlock; /* * Check if there accidentally is some space left in the previous block first. */ if ( pPrevBlock && pPrevBlock->cbBlock - pPrevBlock->offNext >= cb) { void *pvRet = (char *)pPrevBlock + pPrevBlock->offNext; pPrevBlock->offNext += cb; return pvRet; } /* * Allocate a new block. */ /* Figure the block size. */ cbBlock = pOldBlock->cbBlock; while (cbBlock - sizeof(KMKCCEXPJUMP) - sizeof(*pNewBlock) < cb) cbBlock *= 2; /* Allocate and initialize the block it with the new instruction already accounted for. */ pNewBlock = (PKMKCCBLOCK)xmalloc(cbBlock); pNewBlock->cbBlock = cbBlock; pNewBlock->offNext = sizeof(*pNewBlock) + cb; pNewBlock->pNext = pOldBlock; *ppBlockTail = pNewBlock; #ifdef KMK_CC_WITH_STATS g_cBlockAllocated++; g_cbAllocated += cbBlock; #endif return pNewBlock + 1; } /** * Make a byte allocation. * * Must call kmk_cc_block_realign() when done doing byte and string allocations. * * @returns Pointer to the byte allocation (byte aligned). * @param ppBlockTail Pointer to the allocator tail pointer. * @param cb The number of bytes to allocate. */ static void *kmk_cc_block_byte_alloc(PKMKCCBLOCK *ppBlockTail, uint32_t cb) { PKMKCCBLOCK pBlockTail = *ppBlockTail; uint32_t cbLeft = pBlockTail->cbBlock - pBlockTail->offNext; KMK_CC_ASSERT(cbLeft >= sizeof(KMKCCEXPJUMP)); if (cbLeft >= cb + sizeof(KMKCCEXPJUMP)) { void *pvRet = (char *)pBlockTail + pBlockTail->offNext; pBlockTail->offNext += cb; return pvRet; } return kmk_cc_block_byte_alloc_grow(ppBlockTail, cb); } /** * Duplicates the given string in a byte allocation. * * Must call kmk_cc_block_realign() when done doing byte and string allocations. * * @returns Pointer to the byte allocation (byte aligned). * @param ppBlockTail Pointer to the allocator tail pointer. * @param cb The number of bytes to allocate. */ static const char *kmk_cc_block_strdup(PKMKCCBLOCK *ppBlockTail, const char *pachStr, uint32_t cchStr) { char *pszCopy; if (cchStr) { pszCopy = kmk_cc_block_byte_alloc(ppBlockTail, cchStr + 1); memcpy(pszCopy, pachStr, cchStr); pszCopy[cchStr] = '\0'; return pszCopy; } return ""; } /** * Grows the allocation with another block, string expansion program case. * * @returns Pointer to a string expansion instruction core. * @param ppBlockTail Pointer to the allocator tail pointer. * @param cb The number of bytes to allocate. */ static PKMKCCEXPCORE kmk_cc_block_alloc_exp_grow(PKMKCCBLOCK *ppBlockTail, uint32_t cb) { PKMKCCBLOCK pOldBlock = *ppBlockTail; PKMKCCBLOCK pNewBlock; PKMKCCEXPCORE pRet; PKMKCCEXPJUMP pJump; /* Figure the block size. */ uint32_t cbBlock = !pOldBlock->pNext ? 128 : pOldBlock->cbBlock; while (cbBlock - sizeof(KMKCCEXPJUMP) - sizeof(*pNewBlock) < cb) cbBlock *= 2; /* Allocate and initialize the block it with the new instruction already accounted for. */ pNewBlock = (PKMKCCBLOCK)xmalloc(cbBlock); pNewBlock->cbBlock = cbBlock; pNewBlock->offNext = sizeof(*pNewBlock) + cb; pNewBlock->pNext = pOldBlock; *ppBlockTail = pNewBlock; #ifdef KMK_CC_WITH_STATS g_cBlockAllocated++; g_cbAllocated += cbBlock; #endif pRet = (PKMKCCEXPCORE)(pNewBlock + 1); KMK_CC_ASSERT(((size_t)pRet & (sizeof(void *) - 1)) == 0); /* Emit jump. */ pJump = (PKMKCCEXPJUMP)((char *)pOldBlock + pOldBlock->offNext); pJump->Core.enmOpcode = kKmkCcExpInstr_Jump; pJump->pNext = pRet; pOldBlock->offNext += sizeof(*pJump); KMK_CC_ASSERT(pOldBlock->offNext <= pOldBlock->cbBlock); return pRet; } /** * Allocates a string expansion instruction of size @a cb. * * @returns Pointer to a string expansion instruction core. * @param ppBlockTail Pointer to the allocator tail pointer. * @param cb The number of bytes to allocate. */ static PKMKCCEXPCORE kmk_cc_block_alloc_exp(PKMKCCBLOCK *ppBlockTail, uint32_t cb) { PKMKCCBLOCK pBlockTail = *ppBlockTail; uint32_t cbLeft = pBlockTail->cbBlock - pBlockTail->offNext; KMK_CC_ASSERT(cbLeft >= sizeof(KMKCCEXPJUMP)); KMK_CC_ASSERT( (cb & (sizeof(void *) - 1)) == 0 || cb == sizeof(KMKCCEXPCORE) /* final */ ); if (cbLeft >= cb + sizeof(KMKCCEXPJUMP)) { PKMKCCEXPCORE pRet = (PKMKCCEXPCORE)((char *)pBlockTail + pBlockTail->offNext); pBlockTail->offNext += cb; KMK_CC_ASSERT(((size_t)pRet & (sizeof(void *) - 1)) == 0); return pRet; } return kmk_cc_block_alloc_exp_grow(ppBlockTail, cb); } /** * Grows the allocation with another block, makefile evaluation program case. * * @returns Pointer to a makefile evaluation instruction core. * @param ppBlockTail Pointer to the allocator tail pointer. * @param cb The number of bytes to allocate. */ static PKMKCCEVALCORE kmk_cc_block_alloc_eval_grow(PKMKCCBLOCK *ppBlockTail, uint32_t cb) { PKMKCCBLOCK pOldBlock = *ppBlockTail; PKMKCCBLOCK pNewBlock; PKMKCCEVALCORE pRet; PKMKCCEVALJUMP pJump; /* Figure the block size. */ uint32_t cbBlock = !pOldBlock->pNext ? 128 : pOldBlock->cbBlock; while (cbBlock - sizeof(KMKCCEVALJUMP) - sizeof(*pNewBlock) < cb) cbBlock *= 2; /* Allocate and initialize the block it with the new instruction already accounted for. */ pNewBlock = (PKMKCCBLOCK)xmalloc(cbBlock); pNewBlock->cbBlock = cbBlock; pNewBlock->offNext = sizeof(*pNewBlock) + cb; pNewBlock->pNext = pOldBlock; *ppBlockTail = pNewBlock; #ifdef KMK_CC_WITH_STATS g_cBlockAllocated++; g_cbAllocated += cbBlock; #endif pRet = (PKMKCCEVALCORE)(pNewBlock + 1); /* Emit jump. */ pJump = (PKMKCCEVALJUMP)((char *)pOldBlock + pOldBlock->offNext); pJump->Core.enmOpcode = kKmkCcEvalInstr_jump; pJump->pNext = pRet; pOldBlock->offNext += sizeof(*pJump); KMK_CC_ASSERT(pOldBlock->offNext <= pOldBlock->cbBlock); return pRet; } /** * Allocates a makefile evaluation instruction of size @a cb. * * @returns Pointer to a makefile evaluation instruction core. * @param ppBlockTail Pointer to the allocator tail pointer. * @param cb The number of bytes to allocate. */ static PKMKCCEVALCORE kmk_cc_block_alloc_eval(PKMKCCBLOCK *ppBlockTail, uint32_t cb) { PKMKCCBLOCK pBlockTail = *ppBlockTail; uint32_t cbLeft = pBlockTail->cbBlock - pBlockTail->offNext; KMK_CC_ASSERT(cbLeft >= sizeof(KMKCCEVALJUMP)); KMK_CC_ASSERT( (cb & (sizeof(void *) - 1)) == 0 ); if (cbLeft >= cb + sizeof(KMKCCEVALJUMP)) { PKMKCCEVALCORE pRet = (PKMKCCEVALCORE)((char *)pBlockTail + pBlockTail->offNext); pBlockTail->offNext += cb; return pRet; } return kmk_cc_block_alloc_eval_grow(ppBlockTail, cb); } /** * Frees all memory used by an allocator. * * @param ppBlockTail The allocator tail pointer. */ static void kmk_cc_block_free_list(PKMKCCBLOCK pBlockTail) { while (pBlockTail) { PKMKCCBLOCK pThis = pBlockTail; pBlockTail = pBlockTail->pNext; free(pThis); } } /* * * The string expansion compiler. * The string expansion compiler. * The string expansion compiler. * */ /** * Emits a kKmkCcExpInstr_Return. * * @param ppBlockTail Pointer to the allocator tail pointer. */ static void kmk_cc_exp_emit_return(PKMKCCBLOCK *ppBlockTail) { PKMKCCEXPCORE pCore = kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pCore)); pCore->enmOpcode = kKmkCcExpInstr_Return; kmk_cc_block_realign(ppBlockTail); } /** * Checks if a function is known to mess up the arguments its given. * * When executing calls to "dirty" functions, all arguments must be duplicated * on the heap. * * @returns 1 if dirty, 0 if clean. * @param pszFunction The function name. */ static uint8_t kmk_cc_is_dirty_function(const char *pszFunction) { switch (pszFunction[0]) { default: return 0; case 'e': if (!strcmp(pszFunction, "eval")) return 1; if (!strcmp(pszFunction, "evalctx")) return 1; return 0; case 'f': if (!strcmp(pszFunction, "filter")) return 1; if (!strcmp(pszFunction, "filter-out")) return 1; if (!strcmp(pszFunction, "for")) return 1; return 0; case 's': if (!strcmp(pszFunction, "sort")) return 1; return 0; } } /** * Emits a function call instruction taking arguments that needs expanding. * * @returns 0 on success, non-zero on failure. * @param ppBlockTail Pointer to the allocator tail pointer. * @param pszFunction The function name (const string from function.c). * @param pchArgs Pointer to the arguments expression string, leading * any blanks has been stripped. * @param cchArgs The length of the arguments expression string. * @param cArgs Number of arguments found. * @param chOpen The char used to open the function call. * @param chClose The char used to close the function call. * @param pfnFunction The function implementation. * @param cMaxArgs Maximum number of arguments the function takes. */ static int kmk_cc_exp_emit_dyn_function(PKMKCCBLOCK *ppBlockTail, const char *pszFunction, const char *pchArgs, uint32_t cchArgs, uint32_t cArgs, char chOpen, char chClose, make_function_ptr_t pfnFunction, unsigned char cMaxArgs) { uint32_t iArg; /* * The function instruction has variable size. The maximum argument count * isn't quite like the minium one. Zero means no limit. While a non-zero * value means that any commas beyond the max will be taken to be part of * the final argument. */ uint32_t cActualArgs = cArgs <= cMaxArgs || !cMaxArgs ? cArgs : cMaxArgs; PKMKCCEXPDYNFUNC pInstr = (PKMKCCEXPDYNFUNC)kmk_cc_block_alloc_exp(ppBlockTail, KMKCCEXPDYNFUNC_SIZE(cActualArgs)); pInstr->FnCore.Core.enmOpcode = kKmkCcExpInstr_DynamicFunction; pInstr->FnCore.cArgs = cActualArgs; pInstr->FnCore.pfnFunction = pfnFunction; pInstr->FnCore.pszFuncName = pszFunction; pInstr->FnCore.fDirty = kmk_cc_is_dirty_function(pszFunction); /* * Parse the arguments. Plain arguments gets duplicated in the program * memory so that they are terminated and no extra processing is necessary * later on. ASSUMES that the function implementations do NOT change * argument memory. Other arguments the compiled into their own expansion * sub programs. */ iArg = 0; for (;;) { /* Find the end of the argument. Check for $. */ char ch = '\0'; uint8_t fDollar = 0; int32_t cDepth = 0; uint32_t cchThisArg = 0; while (cchThisArg < cchArgs) { ch = pchArgs[cchThisArg]; if (ch == chClose) { KMK_CC_ASSERT(cDepth > 0); if (cDepth > 0) cDepth--; } else if (ch == chOpen) cDepth++; else if (ch == ',' && cDepth == 0 && iArg + 1 < cActualArgs) break; else if (ch == '$') fDollar = 1; cchThisArg++; } pInstr->aArgs[iArg].fSubprog = fDollar; if (fDollar) { /* Compile it. */ int rc; kmk_cc_block_realign(ppBlockTail); rc = kmk_cc_exp_compile_subprog(ppBlockTail, pchArgs, cchThisArg, &pInstr->aArgs[iArg].u.Subprog); if (rc != 0) return rc; } else { /* Duplicate it. */ pInstr->aArgs[iArg].u.Plain.psz = kmk_cc_block_strdup(ppBlockTail, pchArgs, cchThisArg); pInstr->aArgs[iArg].u.Plain.cch = cchThisArg; } iArg++; if (ch != ',') break; pchArgs += cchThisArg + 1; cchArgs -= cchThisArg + 1; } KMK_CC_ASSERT(iArg == cActualArgs); /* * Realign the allocator and take down the address of the next instruction. */ kmk_cc_block_realign(ppBlockTail); pInstr->FnCore.pNext = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail); return 0; } /** * Emits a function call instruction taking plain arguments. * * @returns 0 on success, non-zero on failure. * @param ppBlockTail Pointer to the allocator tail pointer. * @param pszFunction The function name (const string from function.c). * @param pchArgs Pointer to the arguments string, leading any blanks * has been stripped. * @param cchArgs The length of the arguments string. * @param cArgs Number of arguments found. * @param chOpen The char used to open the function call. * @param chClose The char used to close the function call. * @param pfnFunction The function implementation. * @param cMaxArgs Maximum number of arguments the function takes. */ static void kmk_cc_exp_emit_plain_function(PKMKCCBLOCK *ppBlockTail, const char *pszFunction, const char *pchArgs, uint32_t cchArgs, uint32_t cArgs, char chOpen, char chClose, make_function_ptr_t pfnFunction, unsigned char cMaxArgs) { uint32_t iArg; /* * The function instruction has variable size. The maximum argument count * isn't quite like the minium one. Zero means no limit. While a non-zero * value means that any commas beyond the max will be taken to be part of * the final argument. */ uint32_t cActualArgs = cArgs <= cMaxArgs || !cMaxArgs ? cArgs : cMaxArgs; PKMKCCEXPPLAINFUNC pInstr = (PKMKCCEXPPLAINFUNC)kmk_cc_block_alloc_exp(ppBlockTail, KMKCCEXPPLAINFUNC_SIZE(cActualArgs)); pInstr->FnCore.Core.enmOpcode = kKmkCcExpInstr_PlainFunction; pInstr->FnCore.cArgs = cActualArgs; pInstr->FnCore.pfnFunction = pfnFunction; pInstr->FnCore.pszFuncName = pszFunction; pInstr->FnCore.fDirty = kmk_cc_is_dirty_function(pszFunction); /* * Parse the arguments. Plain arguments gets duplicated in the program * memory so that they are terminated and no extra processing is necessary * later on. ASSUMES that the function implementations do NOT change * argument memory. */ iArg = 0; for (;;) { /* Find the end of the argument. */ char ch = '\0'; int32_t cDepth = 0; uint32_t cchThisArg = 0; while (cchThisArg < cchArgs) { ch = pchArgs[cchThisArg]; if (ch == chClose) { KMK_CC_ASSERT(cDepth > 0); if (cDepth > 0) cDepth--; } else if (ch == chOpen) cDepth++; else if (ch == ',' && cDepth == 0 && iArg + 1 < cActualArgs) break; cchThisArg++; } /* Duplicate it. */ pInstr->apszArgs[iArg++] = kmk_cc_block_strdup(ppBlockTail, pchArgs, cchThisArg); if (ch != ',') break; pchArgs += cchThisArg + 1; cchArgs -= cchThisArg + 1; } KMK_CC_ASSERT(iArg == cActualArgs); pInstr->apszArgs[iArg] = NULL; /* * Realign the allocator and take down the address of the next instruction. */ kmk_cc_block_realign(ppBlockTail); pInstr->FnCore.pNext = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail); } /** * Emits a kKmkCcExpInstr_DynamicVariable. * * @returns 0 on success, non-zero on failure. * @param ppBlockTail Pointer to the allocator tail pointer. * @param pchNameExpr The name of the variable (ASSUMED presistent * thru-out the program life time). * @param cchNameExpr The length of the variable name. If zero, * nothing will be emitted. */ static int kmk_cc_exp_emit_dyn_variable(PKMKCCBLOCK *ppBlockTail, const char *pchNameExpr, uint32_t cchNameExpr) { PKMKCCEXPDYNVAR pInstr; int rc; KMK_CC_ASSERT(cchNameExpr > 0); pInstr = (PKMKCCEXPDYNVAR)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr)); pInstr->Core.enmOpcode = kKmkCcExpInstr_DynamicVariable; rc = kmk_cc_exp_compile_subprog(ppBlockTail, pchNameExpr, cchNameExpr, &pInstr->Subprog); pInstr->pNext = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail); return rc; } /** * Emits either a kKmkCcExpInstr_PlainVariable or * kKmkCcExpInstr_SearchAndReplacePlainVariable instruction. * * @param ppBlockTail Pointer to the allocator tail pointer. * @param pchName The name of the variable. (Does not need to be * valid beyond the call.) * @param cchName The length of the variable name. If zero, * nothing will be emitted. */ static void kmk_cc_exp_emit_plain_variable_maybe_sr(PKMKCCBLOCK *ppBlockTail, const char *pchName, uint32_t cchName) { if (cchName > 0) { /* * Hopefully, we're not expected to do any search and replace on the * expanded variable string later... Requires both ':' and '='. */ const char *pchEqual; const char *pchColon = (const char *)memchr(pchName, ':', cchName); if ( pchColon == NULL || (pchEqual = (const char *)memchr(pchColon + 1, ':', cchName - (pchColon - pchName - 1))) == NULL || pchEqual == pchEqual + 1) { PKMKCCEXPPLAINVAR pInstr = (PKMKCCEXPPLAINVAR)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr)); pInstr->Core.enmOpcode = kKmkCcExpInstr_PlainVariable; pInstr->pszName = strcache2_add(&variable_strcache, pchName, cchName); } else if (pchColon != pchName) { /* * Okay, we need to do search and replace the variable value. * This is performed by patsubst_expand_pat using '%' patterns. */ uint32_t cchName2 = (uint32_t)(pchColon - pchName); uint32_t cchSearch = (uint32_t)(pchEqual - pchColon - 1); uint32_t cchReplace = cchName - cchName2 - cchSearch - 2; const char *pchPct; char *psz; PKMKCCEXPSRPLAINVAR pInstr; pInstr = (PKMKCCEXPSRPLAINVAR)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr)); pInstr->Core.enmOpcode = kKmkCcExpInstr_SearchAndReplacePlainVariable; pInstr->pszName = strcache2_add(&variable_strcache, pchName, cchName2); /* Figure out the search pattern, unquoting percent chars.. */ psz = (char *)kmk_cc_block_byte_alloc(ppBlockTail, cchSearch + 2); psz[0] = '%'; memcpy(psz + 1, pchColon + 1, cchSearch); psz[1 + cchSearch] = '\0'; pchPct = find_percent(psz + 1); /* also performs unquoting */ if (pchPct) { pInstr->pszSearchPattern = psz + 1; pInstr->offPctSearchPattern = (uint32_t)(pchPct - psz - 1); } else { pInstr->pszSearchPattern = psz; pInstr->offPctSearchPattern = 0; } /* Figure out the replacement pattern, unquoting percent chars.. */ if (cchReplace == 0) { pInstr->pszReplacePattern = "%"; pInstr->offPctReplacePattern = 0; } else { psz = (char *)kmk_cc_block_byte_alloc(ppBlockTail, cchReplace + 2); psz[0] = '%'; memcpy(psz + 1, pchEqual + 1, cchReplace); psz[1 + cchReplace] = '\0'; pchPct = find_percent(psz + 1); /* also performs unquoting */ if (pchPct) { pInstr->pszReplacePattern = psz + 1; pInstr->offPctReplacePattern = (uint32_t)(pchPct - psz - 1); } else { pInstr->pszReplacePattern = psz; pInstr->offPctReplacePattern = 0; } } /* Note down where the next instruction is after realigning the allocator. */ kmk_cc_block_realign(ppBlockTail); pInstr->pNext = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail); } } } /** * Emits a kKmkCcExpInstr_CopyString. * * @param ppBlockTail Pointer to the allocator tail pointer. * @param pchStr The string to emit (ASSUMED presistent thru-out * the program life time). * @param cchStr The number of chars to copy. If zero, nothing * will be emitted. */ static void kmk_cc_exp_emit_copy_string(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr) { if (cchStr > 0) { PKMKCCEXPCOPYSTRING pInstr = (PKMKCCEXPCOPYSTRING)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr)); pInstr->Core.enmOpcode = kKmkCcExpInstr_CopyString; pInstr->cchCopy = cchStr; pInstr->pachSrc = pchStr; } } /** * String expansion compilation function common to both normal and sub programs. * * @returns 0 on success, non-zero on failure. * @param ppBlockTail Pointer to the allocator tail pointer. * @param pchStr The expression to compile. * @param cchStr The length of the expression to compile. */ static int kmk_cc_exp_compile_common(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr) { /* * Process the string. */ while (cchStr > 0) { /* Look for dollar sign, marks variable expansion or dollar-escape. */ int rc; const char *pchDollar = memchr(pchStr, '$', cchStr); if (pchDollar) { /* * Check for multiple dollar chars. */ uint32_t offDollar = (uint32_t)(pchDollar - pchStr); uint32_t cDollars = 1; while ( offDollar + cDollars < cchStr && pchStr[offDollar + cDollars] == '$') cDollars++; /* * Emit a string copy for any preceeding stuff, including half of * the dollars we found (dollar escape: $$ -> $). * (kmk_cc_exp_emit_copy_string ignore zero length strings). */ kmk_cc_exp_emit_copy_string(ppBlockTail, pchStr, offDollar + cDollars / 2); pchStr += offDollar + cDollars; cchStr -= offDollar + cDollars; /* * Odd number of dollar chars means there is a variable to expand * or function to call. */ if (cDollars & 1) { if (cchStr > 0) { char const chOpen = *pchStr; if (chOpen == '(' || chOpen == '{') { /* There are several alternative ways of finding the ending parenthesis / braces. GNU make does one thing for functions and variable containing any '$' chars before the first closing char. While for variables where a closing char comes before any '$' char, a simplified approach is taken. This means that for example: Given VAR=var, the expressions "$(var())" and "$($(VAR)())" would be expanded differently. In the first case the variable "var(" would be used and in the second "var()". This code will not duplicate this weird behavior, but work the same regardless of whether there is a '$' char before the first closing char. */ make_function_ptr_t pfnFunction; const char *pszFunction; unsigned char cMaxArgs; unsigned char cMinArgs; char fExpandArgs; char const chClose = chOpen == '(' ? ')' : '}'; char ch = 0; uint32_t cchName = 0; uint32_t cDepth = 1; uint32_t cMaxDepth = 1; cDollars = 0; pchStr++; cchStr--; /* First loop: Identify potential function calls and dynamic expansion. */ KMK_CC_ASSERT(!func_char_map[(unsigned char)chOpen]); KMK_CC_ASSERT(!func_char_map[(unsigned char)chClose]); KMK_CC_ASSERT(!func_char_map[(unsigned char)'$']); while (cchName < cchStr) { ch = pchStr[cchName]; if (!func_char_map[(unsigned char)ch]) break; cchName++; } if ( cchName >= MIN_FUNCTION_LENGTH && cchName <= MAX_FUNCTION_LENGTH && (ISBLANK(ch) || ch == chClose || cchName == cchStr) && (pfnFunction = lookup_function_for_compiler(pchStr, cchName, &cMinArgs, &cMaxArgs, &fExpandArgs, &pszFunction)) != NULL) { /* * It's a function invocation, we should count parameters while * looking for the end. * Note! We use cchName for the length of the argument list. */ uint32_t cArgs = 1; if (ch != chClose) { /* Skip leading spaces before the first arg. */ cchName++; while (cchName < cchStr && ISBLANK(pchStr[cchName])) cchName++; pchStr += cchName; cchStr -= cchName; cchName = 0; while (cchName < cchStr) { ch = pchStr[cchName]; if (ch == ',') { if (cDepth == 1) cArgs++; } else if (ch == chClose) { if (!--cDepth) break; } else if (ch == chOpen) { if (++cDepth > cMaxDepth) cMaxDepth = cDepth; } else if (ch == '$') cDollars++; cchName++; } } else { pchStr += cchName; cchStr -= cchName; cchName = 0; } if (cArgs < cMinArgs) { fatal(NULL, _("Function '%s' takes a minimum of %d arguments: %d given"), pszFunction, (int)cMinArgs, (int)cArgs); return -1; /* not reached */ } if (cDepth != 0) { fatal(NULL, chOpen == '(' ? _("Missing closing parenthesis calling '%s'") : _("Missing closing braces calling '%s'"), pszFunction); return -1; /* not reached */ } if (cMaxDepth > 16 && fExpandArgs) { fatal(NULL, _("Too many levels of nested function arguments expansions: %s"), pszFunction); return -1; /* not reached */ } if (!fExpandArgs || cDollars == 0) kmk_cc_exp_emit_plain_function(ppBlockTail, pszFunction, pchStr, cchName, cArgs, chOpen, chClose, pfnFunction, cMaxArgs); else { rc = kmk_cc_exp_emit_dyn_function(ppBlockTail, pszFunction, pchStr, cchName, cArgs, chOpen, chClose, pfnFunction, cMaxArgs); if (rc != 0) return rc; } } else { /* * Variable, find the end while checking whether anything needs expanding. */ if (ch == chClose) cDepth = 0; else if (cchName < cchStr) { if (ch != '$') { /* Second loop: Look for things that needs expanding. */ while (cchName < cchStr) { ch = pchStr[cchName]; if (ch == chClose) { if (!--cDepth) break; } else if (ch == chOpen) { if (++cDepth > cMaxDepth) cMaxDepth = cDepth; } else if (ch == '$') break; cchName++; } } if (ch == '$') { /* Third loop: Something needs expanding, just find the end. */ cDollars = 1; cchName++; while (cchName < cchStr) { ch = pchStr[cchName]; if (ch == chClose) { if (!--cDepth) break; } else if (ch == chOpen) { if (++cDepth > cMaxDepth) cMaxDepth = cDepth; } cchName++; } } } if (cDepth > 0) /* After warning, we just assume they're all there. */ error(NULL, chOpen == '(' ? _("Missing closing parenthesis ") : _("Missing closing braces")); if (cMaxDepth >= 16) { fatal(NULL, _("Too many levels of nested variable expansions: '%.*s'"), (int)cchName + 2, pchStr - 1); return -1; /* not reached */ } if (cDollars == 0) kmk_cc_exp_emit_plain_variable_maybe_sr(ppBlockTail, pchStr, cchName); else { rc = kmk_cc_exp_emit_dyn_variable(ppBlockTail, pchStr, cchName); if (rc != 0) return rc; } } pchStr += cchName + 1; cchStr -= cchName + (cDepth == 0); } else { /* Single character variable name. */ kmk_cc_exp_emit_plain_variable_maybe_sr(ppBlockTail, pchStr, 1); pchStr++; cchStr--; } } else { error(NULL, _("Unexpected end of string after $")); break; } } } else { /* * Nothing more to expand, the remainder is a simple string copy. */ kmk_cc_exp_emit_copy_string(ppBlockTail, pchStr, cchStr); break; } } /* * Emit final instruction. */ kmk_cc_exp_emit_return(ppBlockTail); return 0; } /** * Initializes string expansion program statistics. * @param pStats Pointer to the statistics structure to init. */ static void kmk_cc_exp_stats_init(PKMKCCEXPSTATS pStats) { pStats->cchAvg = 0; } /** * Compiles a string expansion subprogram. * * The caller typically make a call to kmk_cc_block_get_next_ptr after this * function returns to figure out where to continue executing. * * @returns 0 on success, non-zero on failure. * @param ppBlockTail Pointer to the allocator tail pointer. * @param pchStr Pointer to the string to compile an expansion * program for (ASSUMED to be valid for the * lifetime of the program). * @param cchStr The length of the string to compile. Expected to * be at least on char long. * @param pSubprog The subprogram structure to initialize. */ static int kmk_cc_exp_compile_subprog(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr, PKMKCCEXPSUBPROG pSubprog) { KMK_CC_ASSERT(cchStr > 0); pSubprog->pFirstInstr = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail); kmk_cc_exp_stats_init(&pSubprog->Stats); return kmk_cc_exp_compile_common(ppBlockTail, pchStr, cchStr); } /** * Compiles a string expansion program. * * @returns Pointer to the program on success, NULL on failure. * @param pchStr Pointer to the string to compile an expansion * program for (ASSUMED to be valid for the * lifetime of the program). * @param cchStr The length of the string to compile. Expected to * be at least on char long. */ static PKMKCCEXPPROG kmk_cc_exp_compile(const char *pchStr, uint32_t cchStr) { /* * Estimate block size, allocate one and initialize it. */ PKMKCCEXPPROG pProg; PKMKCCBLOCK pBlock; pProg = kmk_cc_block_alloc_first(&pBlock, sizeof(*pProg), (kmk_cc_count_dollars(pchStr, cchStr) + 4) * 8); if (pProg) { pProg->pBlockTail = pBlock; pProg->pFirstInstr = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(pBlock); kmk_cc_exp_stats_init(&pProg->Stats); pProg->cRefs = 1; #ifdef KMK_CC_STRICT pProg->uInputHash = kmk_cc_debug_string_hash_n(0, pchStr, cchStr); #endif /* * Join forces with the subprogram compilation code. */ if (kmk_cc_exp_compile_common(&pProg->pBlockTail, pchStr, cchStr) == 0) { #ifdef KMK_CC_WITH_STATS pBlock = pProg->pBlockTail; if (!pBlock->pNext) g_cSingleBlockExpProgs++; else if (!pBlock->pNext->pNext) g_cTwoBlockExpProgs++; else g_cMultiBlockExpProgs++; for (; pBlock; pBlock = pBlock->pNext) { g_cBlocksAllocatedExpProgs++; g_cbAllocatedExpProgs += pBlock->cbBlock; g_cbUnusedMemExpProgs += pBlock->cbBlock - pBlock->offNext; } #endif return pProg; } kmk_cc_block_free_list(pProg->pBlockTail); } return NULL; } /** * Updates the recursive_without_dollar member of a variable structure. * * This avoid compiling string expansion programs with only a CopyString * instruction. By setting recursive_without_dollar to 1, code calling * kmk_cc_compile_variable_for_expand and kmk_exec_expand_to_var_buf will * instead treat start treating it as a simple variable, which is faster. * * @returns The updated recursive_without_dollar value. * @param pVar Pointer to the variable. */ static int kmk_cc_update_variable_recursive_without_dollar(struct variable *pVar) { int fValue; KMK_CC_ASSERT(pVar->recursive_without_dollar == 0); if (memchr(pVar->value, '$', pVar->value_length)) fValue = -1; else fValue = 1; pVar->recursive_without_dollar = fValue; return fValue; } /** * Compiles a variable for string expansion. * * @returns Pointer to the string expansion program on success, NULL if no * program was created. * @param pVar Pointer to the variable. */ struct kmk_cc_expandprog *kmk_cc_compile_variable_for_expand(struct variable *pVar) { KMK_CC_ASSERT(strlen(pVar->value) == pVar->value_length); KMK_CC_ASSERT(!pVar->expandprog); KMK_CC_ASSERT(pVar->recursive_without_dollar <= 0); if ( !pVar->expandprog && pVar->recursive) { if ( pVar->recursive_without_dollar < 0 || ( pVar->recursive_without_dollar == 0 && kmk_cc_update_variable_recursive_without_dollar(pVar) < 0) ) { pVar->expandprog = kmk_cc_exp_compile(pVar->value, pVar->value_length); g_cVarForExpandCompilations++; } } return pVar->expandprog; } /** * String expansion execution worker for outputting a variable. * * @returns The new variable buffer position. * @param pVar The variable to reference. * @param pchDst The current variable buffer position. */ static char *kmk_exec_expand_worker_reference_variable(struct variable *pVar, char *pchDst) { if (pVar->value_length > 0) { if (!pVar->recursive || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR(pVar)) pchDst = variable_buffer_output(pchDst, pVar->value, pVar->value_length); else pchDst = reference_recursive_variable(pchDst, pVar); } else if (pVar->append) pchDst = reference_recursive_variable(pchDst, pVar); return pchDst; } /** * Executes a stream string expansion instructions, outputting to the current * varaible buffer. * * @returns The new variable buffer position. * @param pInstrCore The instruction to start executing at. * @param pchDst The current variable buffer position. */ static char *kmk_exec_expand_instruction_stream_to_var_buf(PKMKCCEXPCORE pInstrCore, char *pchDst) { for (;;) { switch (pInstrCore->enmOpcode) { case kKmkCcExpInstr_CopyString: { PKMKCCEXPCOPYSTRING pInstr = (PKMKCCEXPCOPYSTRING)pInstrCore; pchDst = variable_buffer_output(pchDst, pInstr->pachSrc, pInstr->cchCopy); pInstrCore = &(pInstr + 1)->Core; break; } case kKmkCcExpInstr_PlainVariable: { PKMKCCEXPPLAINVAR pInstr = (PKMKCCEXPPLAINVAR)pInstrCore; struct variable *pVar = lookup_variable_strcached(pInstr->pszName); if (pVar) pchDst = kmk_exec_expand_worker_reference_variable(pVar, pchDst); else warn_undefined(pInstr->pszName, strcache2_get_len(&variable_strcache, pInstr->pszName)); pInstrCore = &(pInstr + 1)->Core; break; } case kKmkCcExpInstr_DynamicVariable: { PKMKCCEXPDYNVAR pInstr = (PKMKCCEXPDYNVAR)pInstrCore; struct variable *pVar; uint32_t cchName; char *pszName = kmk_exec_expand_subprog_to_tmp(&pInstr->Subprog, &cchName); char *pszColon = (char *)memchr(pszName, ':', cchName); char *pszEqual; if ( pszColon == NULL || (pszEqual = (char *)memchr(pszColon + 1, '=', &pszName[cchName] - pszColon - 1)) == NULL || pszEqual == pszColon + 1) { pVar = lookup_variable(pszName, cchName); if (pVar) pchDst = kmk_exec_expand_worker_reference_variable(pVar, pchDst); else warn_undefined(pszName, cchName); } else if (pszColon != pszName) { /* * Oh, we have to do search and replace. How tedious. * Since the variable name is a temporary buffer, we can transform * the strings into proper search and replacement patterns directly. */ pVar = lookup_variable(pszName, pszColon - pszName); if (pVar) { char const *pszExpandedVarValue = pVar->recursive ? recursively_expand(pVar) : pVar->value; char *pszSearchPat = pszColon + 1; char *pszReplacePat = pszEqual + 1; const char *pchPctSearchPat; const char *pchPctReplacePat; *pszEqual = '\0'; pchPctSearchPat = find_percent(pszSearchPat); pchPctReplacePat = find_percent(pszReplacePat); if (!pchPctReplacePat) { if (pszReplacePat[-2] != '\0') /* On the offchance that a pct was unquoted by find_percent. */ { memmove(pszName + 1, pszSearchPat, pszReplacePat - pszSearchPat); if (pchPctSearchPat) pchPctSearchPat -= pszSearchPat - &pszName[1]; pszSearchPat = &pszName[1]; } pchPctReplacePat = --pszReplacePat; *pszReplacePat = '%'; } if (!pchPctSearchPat) { pchPctSearchPat = --pszSearchPat; *pszSearchPat = '%'; } pchDst = patsubst_expand_pat(pchDst, pszExpandedVarValue, pszSearchPat, pszReplacePat, pchPctSearchPat, pchPctReplacePat); if (pVar->recursive) free((void *)pszExpandedVarValue); } else warn_undefined(pszName, pszColon - pszName); } free(pszName); pInstrCore = pInstr->pNext; break; } case kKmkCcExpInstr_SearchAndReplacePlainVariable: { PKMKCCEXPSRPLAINVAR pInstr = (PKMKCCEXPSRPLAINVAR)pInstrCore; struct variable *pVar = lookup_variable_strcached(pInstr->pszName); if (pVar) { char const *pszExpandedVarValue = pVar->recursive ? recursively_expand(pVar) : pVar->value; pchDst = patsubst_expand_pat(pchDst, pszExpandedVarValue, pInstr->pszSearchPattern, pInstr->pszReplacePattern, &pInstr->pszSearchPattern[pInstr->offPctSearchPattern], &pInstr->pszReplacePattern[pInstr->offPctReplacePattern]); if (pVar->recursive) free((void *)pszExpandedVarValue); } else warn_undefined(pInstr->pszName, strcache2_get_len(&variable_strcache, pInstr->pszName)); pInstrCore = pInstr->pNext; break; } case kKmkCcExpInstr_PlainFunction: { PKMKCCEXPPLAINFUNC pInstr = (PKMKCCEXPPLAINFUNC)pInstrCore; uint32_t iArg; if (!pInstr->FnCore.fDirty) { #ifdef KMK_CC_STRICT uint32_t uCrcBefore = 0; uint32_t uCrcAfter = 0; iArg = pInstr->FnCore.cArgs; while (iArg-- > 0) uCrcBefore = kmk_cc_debug_string_hash(uCrcBefore, pInstr->apszArgs[iArg]); #endif pchDst = pInstr->FnCore.pfnFunction(pchDst, (char **)&pInstr->apszArgs[0], pInstr->FnCore.pszFuncName); #ifdef KMK_CC_STRICT iArg = pInstr->FnCore.cArgs; while (iArg-- > 0) uCrcAfter = kmk_cc_debug_string_hash(uCrcAfter, pInstr->apszArgs[iArg]); KMK_CC_ASSERT(uCrcBefore == uCrcAfter); #endif } else { char **papszShadowArgs = xmalloc((pInstr->FnCore.cArgs * 2 + 1) * sizeof(papszShadowArgs[0])); char **papszArgs = &papszShadowArgs[pInstr->FnCore.cArgs]; iArg = pInstr->FnCore.cArgs; papszArgs[iArg] = NULL; while (iArg-- > 0) papszArgs[iArg] = papszShadowArgs[iArg] = xstrdup(pInstr->apszArgs[iArg]); pchDst = pInstr->FnCore.pfnFunction(pchDst, (char **)&pInstr->apszArgs[0], pInstr->FnCore.pszFuncName); iArg = pInstr->FnCore.cArgs; while (iArg-- > 0) free(papszShadowArgs[iArg]); free(papszShadowArgs); } pInstrCore = pInstr->FnCore.pNext; break; } case kKmkCcExpInstr_DynamicFunction: { PKMKCCEXPDYNFUNC pInstr = (PKMKCCEXPDYNFUNC)pInstrCore; char **papszArgsShadow = xmalloc( (pInstr->FnCore.cArgs * 2 + 1) * sizeof(char *)); char **papszArgs = &papszArgsShadow[pInstr->FnCore.cArgs]; uint32_t iArg; if (!pInstr->FnCore.fDirty) { #ifdef KMK_CC_STRICT uint32_t uCrcBefore = 0; uint32_t uCrcAfter = 0; #endif iArg = pInstr->FnCore.cArgs; papszArgs[iArg] = NULL; while (iArg-- > 0) { char *pszArg; if (pInstr->aArgs[iArg].fSubprog) pszArg = kmk_exec_expand_subprog_to_tmp(&pInstr->aArgs[iArg].u.Subprog, NULL); else pszArg = (char *)pInstr->aArgs[iArg].u.Plain.psz; papszArgsShadow[iArg] = pszArg; papszArgs[iArg] = pszArg; #ifdef KMK_CC_STRICT uCrcBefore = kmk_cc_debug_string_hash(uCrcBefore, pszArg); #endif } pchDst = pInstr->FnCore.pfnFunction(pchDst, papszArgs, pInstr->FnCore.pszFuncName); iArg = pInstr->FnCore.cArgs; while (iArg-- > 0) { #ifdef KMK_CC_STRICT KMK_CC_ASSERT(papszArgsShadow[iArg] == papszArgs[iArg]); uCrcAfter = kmk_cc_debug_string_hash(uCrcAfter, papszArgsShadow[iArg]); #endif if (pInstr->aArgs[iArg].fSubprog) free(papszArgsShadow[iArg]); } KMK_CC_ASSERT(uCrcBefore == uCrcAfter); } else { iArg = pInstr->FnCore.cArgs; papszArgs[iArg] = NULL; while (iArg-- > 0) { char *pszArg; if (pInstr->aArgs[iArg].fSubprog) pszArg = kmk_exec_expand_subprog_to_tmp(&pInstr->aArgs[iArg].u.Subprog, NULL); else pszArg = xstrdup(pInstr->aArgs[iArg].u.Plain.psz); papszArgsShadow[iArg] = pszArg; papszArgs[iArg] = pszArg; } pchDst = pInstr->FnCore.pfnFunction(pchDst, papszArgs, pInstr->FnCore.pszFuncName); iArg = pInstr->FnCore.cArgs; while (iArg-- > 0) free(papszArgsShadow[iArg]); } free(papszArgsShadow); pInstrCore = pInstr->FnCore.pNext; break; } case kKmkCcExpInstr_Jump: { PKMKCCEXPJUMP pInstr = (PKMKCCEXPJUMP)pInstrCore; pInstrCore = pInstr->pNext; break; } case kKmkCcExpInstr_Return: return pchDst; default: fatal(NULL, _("Unknown string expansion opcode: %d (%#x)"), (int)pInstrCore->enmOpcode, (int)pInstrCore->enmOpcode); return NULL; } } } /** * Updates the string expansion statistics. * * @param pStats The statistics structure to update. * @param cchResult The result lenght. */ void kmk_cc_exp_stats_update(PKMKCCEXPSTATS pStats, uint32_t cchResult) { /* * The average is simplified and not an exact average for every * expansion that has taken place. */ pStats->cchAvg = (pStats->cchAvg * 7 + cchResult) / 8; } /** * Execute a string expansion subprogram, outputting to a new heap buffer. * * @returns Pointer to the output buffer (hand to free when done). * @param pSubprog The subprogram to execute. * @param pcchResult Where to return the size of the result. Optional. */ static char *kmk_exec_expand_subprog_to_tmp(PKMKCCEXPSUBPROG pSubprog, uint32_t *pcchResult) { char *pchOldVarBuf; unsigned int cbOldVarBuf; char *pchDst; char *pszResult; uint32_t cchResult; /* * Temporarily replace the variable buffer while executing the instruction * stream for this subprogram. */ pchDst = install_variable_buffer_with_hint(&pchOldVarBuf, &cbOldVarBuf, pSubprog->Stats.cchAvg ? pSubprog->Stats.cchAvg + 32 : 256); pchDst = kmk_exec_expand_instruction_stream_to_var_buf(pSubprog->pFirstInstr, pchDst); /* Ensure that it's terminated. */ pchDst = variable_buffer_output(pchDst, "\0", 1) - 1; /* Grab the result buffer before restoring the previous one. */ pszResult = variable_buffer; cchResult = (uint32_t)(pchDst - pszResult); if (pcchResult) *pcchResult = cchResult; kmk_cc_exp_stats_update(&pSubprog->Stats, cchResult); variable_buffer = pchOldVarBuf; variable_buffer_length = cbOldVarBuf; return pszResult; } /** * Execute a string expansion program, outputting to the current variable * buffer. * * @returns New variable buffer position. * @param pProg The program to execute. * @param pchDst The current varaible buffer position. */ static char *kmk_exec_expand_prog_to_var_buf(PKMKCCEXPPROG pProg, char *pchDst) { uint32_t cchResult; uint32_t offStart = (uint32_t)(pchDst - variable_buffer); if (pProg->Stats.cchAvg >= variable_buffer_length - offStart) pchDst = ensure_variable_buffer_space(pchDst, offStart + pProg->Stats.cchAvg + 32); KMK_CC_ASSERT(pProg->cRefs > 0); pProg->cRefs++; pchDst = kmk_exec_expand_instruction_stream_to_var_buf(pProg->pFirstInstr, pchDst); pProg->cRefs--; KMK_CC_ASSERT(pProg->cRefs > 0); cchResult = (uint32_t)(pchDst - variable_buffer); KMK_CC_ASSERT(cchResult >= offStart); cchResult -= offStart; kmk_cc_exp_stats_update(&pProg->Stats, cchResult); g_cVarForExpandExecs++; return pchDst; } /** * Expands a variable into a variable buffer using its expandprog. * * @returns The new variable buffer position. * @param pVar Pointer to the variable. Must have a program. * @param pchDst Pointer to the current variable buffer position. */ char *kmk_exec_expand_to_var_buf(struct variable *pVar, char *pchDst) { KMK_CC_ASSERT(pVar->expandprog); KMK_CC_ASSERT(pVar->expandprog->uInputHash == kmk_cc_debug_string_hash(0, pVar->value)); return kmk_exec_expand_prog_to_var_buf(pVar->expandprog, pchDst); } /* * * Makefile evaluation programs. * Makefile evaluation programs. * Makefile evaluation programs. * */ static size_t kmk_cc_eval_detect_eol_style(char *pchFirst, char *pchSecond, const char *pszContent, size_t cchContent) { /* Look for LF first. */ const char *pszTmp = (const char *)memchr(pszContent, '\n', cchContent); if (pszTmp) { /* CRLF? */ if (pszTmp != pszContent && pszTmp[-1] == '\r') { *pchFirst = '\r'; *pchSecond = '\n'; return 2; } /* No, LF or LFCR. (pszContent is zero terminated, so no bounds checking necessary.) */ *pchFirst = '\n'; if (pszTmp[1] != '\r') { *pchSecond = 0; return 1; } *pchSecond = '\r'; return 2; } /* Probably no EOLs here. */ if (memchr(pszContent, '\r', cchContent) == NULL) { *pchSecond = *pchFirst = 0; return 0; } /* kind of unlikely */ *pchFirst = '\r'; *pchSecond = 0; return 1; } #if 0 /** * Checks whether we've got an EOL escape sequence or not. * * @returns non-zero if escaped EOL, 0 if not (i.e. actual EOL). * @param pszContent The string pointer @a offEol is relative to. * @param offEol The offset of the first EOL char. */ static unsigned kmk_cc_eval_is_eol_escape_seq(const char *pszContent, size_t offEol) { /* The caller has already checked out two backslashes. */ size_t offFirstBackslash = offEol; KMK_CC_ASSERT(offFirstBackslash >= 2); offFirstBackslash -= 2; /* Find the first backslash. */ while (offFirstBackslash > 0 && pszContent[offFirstBackslash - 1] == '\\') offFirstBackslash--; /* Odd number -> escaped EOL; Even number -> real EOL; */ return (offEol - offFirstBackslash) & 1; } #endif typedef enum kmk_cc_eval_token { /** Invalid token . */ kKmkCcEvalToken_Invalid = 0, /** Assignment: '=' */ kKmkCcEvalToken_AssignRecursive, /** Assignment: ':=' */ kKmkCcEvalToken_AssignSimple, /** Assignment: '+=' */ kKmkCcEvalToken_AssignAppend, /** Assignment: '<=' */ kKmkCcEvalToken_AssignPrepend, /** Assignment: '?=' */ kKmkCcEvalToken_AssignIfNew, /** Assignment: 'define' */ kKmkCcEvalToken_define, /** Unassignment: 'undefine' */ kKmkCcEvalToken_undefine, /* Assignment modifier: 'local' */ kKmkCcEvalToken_local, /* Assignment modifier: 'override' */ kKmkCcEvalToken_override, /* Assignment modifier: 'private' (target variable not inh by deps) */ kKmkCcEvalToken_private, /* Assignment modifier / other variable thing: 'export' */ kKmkCcEvalToken_export, /* Other variable thing: 'unexport' */ kKmkCcEvalToken_unexport, kKmkCcEvalToken_ifdef, kKmkCcEvalToken_ifndef, kKmkCcEvalToken_ifeq, kKmkCcEvalToken_ifneq, kKmkCcEvalToken_if1of, kKmkCcEvalToken_ifn1of, kKmkCcEvalToken_if, kKmkCcEvalToken_else, kKmkCcEvalToken_endif, kKmkCcEvalToken_include, kKmkCcEvalToken_include_silent, kKmkCcEvalToken_includedep, kKmkCcEvalToken_includedep_queue, kKmkCcEvalToken_includedep_flush, kKmkCcEvalToken_colon, kKmkCcEvalToken_double_colon, kKmkCcEvalToken_plus, kKmkCcEvalToken_plus_maybe, kKmkCcEvalToken_vpath, /** Plain word. */ kKmkCcEvalToken_WordPlain, /** Word that maybe in need of expanding. */ kKmkCcEvalToken_WordWithDollar, kKmkCcEvalToken_End } KMKCCEVALTOKEN; /** * A tokenized word. */ typedef struct kmk_cc_eval_word { /** The token word (lexeme). */ const char *pchWord; /** The length of the word (lexeme). */ uint32_t cchWord; /** The token classification. */ KMKCCEVALTOKEN enmToken; } KMKCCEVALWORD; typedef KMKCCEVALWORD *PKMKCCEVALWORD; typedef KMKCCEVALWORD const *PCKMKCCEVALWORD; /** * Escaped end-of-line sequence in the current line. */ typedef struct KMKCCEVALESCEOL { /** Offset at which the EOL escape sequence starts for a non-command line. */ size_t offEsc; /** Offset of the newline sequence. */ size_t offEol; } KMKCCEVALESCEOL; typedef KMKCCEVALESCEOL *PKMKCCEVALESCEOL; /** * String copy segment. */ typedef struct KMKCCEVALSTRCPYSEG { /** The start. */ const char *pchSrc; /** The number of chars to copy and whether to prepend space. * Negative values indicates that we should prepend a space. */ ssize_t cchSrcAndPrependSpace; } KMKCCEVALSTRCPYSEG; typedef KMKCCEVALSTRCPYSEG *PKMKCCEVALSTRCPYSEG; typedef KMKCCEVALSTRCPYSEG const *PCKMKCCEVALSTRCPYSEG; typedef struct KMKCCEVALCOMPILER { /** Pointer to the KMKCCEVALPROG::pBlockTail member. */ PKMKCCBLOCK *ppBlockTail; /** @name Line parsing state. * @{ */ /** Offset of newline escape sequences in the current line. * This is only applicable if cEscEols is not zero. */ PKMKCCEVALESCEOL paEscEols; /** The number of number of paEscEols entries we've allocated. */ unsigned cEscEolsAllocated; /** Number of escaped EOLs (line count - 1). */ unsigned cEscEols; /** The paEscEols entry corresponding to the current parsing location. * Still to be seen how accurate this can be made to be. */ unsigned iEscEol; /** The current line number (for error handling / debugging). */ unsigned iLine; /** The start offset of the current line. */ size_t offLine; /** Length of the current line, sans the final EOL and comments. */ size_t cchLine; /** Length of the current line, sans the final EOL but with comments. */ size_t cchLineWithComments; /** The first char in an EOL sequence. * We ASSUMES that this char won't appear in any other sequence in the file, * thus skipping matching any subsequent chars. */ char chFirstEol; /** The second char in an EOL sequence, if applicable. */ char chSecondEol; /** The length of the EOL sequence. */ size_t cchEolSeq; /** The minimum length of an esacped EOL sequence (cchEolSeq + 1). */ size_t cchEscEolSeq; /** String copy segments. */ PKMKCCEVALSTRCPYSEG paStrCopySegs; /** The number of segments that has been prepared. */ unsigned cStrCopySegs; /** The number of segments we've allocated. */ unsigned cStrCopySegsAllocated; /** @} */ /** @name Recipe state. * @{ */ /** Set if we're working on a recipe. */ PKMKCCEVALRECIPE pRecipe; /** Set for ignoring recipes without targets (Sun OS 4 Make). */ uint8_t fNoTargetRecipe; /** The command prefix character. */ char chCmdPrefix; /** @} */ /** @name Tokenzied words. * @{ */ uint32_t cWords; uint32_t cWordsAllocated; PKMKCCEVALWORD paWords; /** @} */ /** @name Conditionals. * @{ */ /** Current conditional stack depth. */ unsigned cIfs; /** The conditional directive stack. */ PKMKCCEVALIFCORE apIfs[KMK_CC_EVAL_MAX_IF_DEPTH]; /** @} */ /** The program being compiled. */ PKMKCCEVALPROG pEvalProg; /** Pointer to the content. */ const char *pszContent; /** The amount of input to parse. */ size_t cchContent; } KMKCCEVALCOMPILER; typedef KMKCCEVALCOMPILER *PKMKCCEVALCOMPILER; static void kmk_cc_eval_init_compiler(PKMKCCEVALCOMPILER pCompiler, PKMKCCEVALPROG pEvalProg, unsigned iLine, const char *pszContent, size_t cchContent) { pCompiler->ppBlockTail = &pEvalProg->pBlockTail; pCompiler->pRecipe = NULL; pCompiler->fNoTargetRecipe = 0; pCompiler->chCmdPrefix = cmd_prefix; pCompiler->cWordsAllocated = 0; pCompiler->paWords = NULL; pCompiler->cEscEolsAllocated = 0; pCompiler->paEscEols = NULL; pCompiler->iLine = iLine; pCompiler->cStrCopySegsAllocated = 0; pCompiler->paStrCopySegs = NULL; pCompiler->cIfs = 0; pCompiler->pEvalProg = pEvalProg; pCompiler->pszContent = pszContent; pCompiler->cchContent = cchContent; /* Detect EOL style. */ pCompiler->cchEolSeq = kmk_cc_eval_detect_eol_style(&pCompiler->chFirstEol, &pCompiler->chSecondEol, pszContent, cchContent); pCompiler->cchEscEolSeq = 1 + pCompiler->cchEolSeq; } static void kmk_cc_eval_delete_compiler(PKMKCCEVALCOMPILER pCompiler) { if (pCompiler->paWords) free(pCompiler->paWords); if (pCompiler->paEscEols) free(pCompiler->paEscEols); } static void KMK_CC_FN_NO_RETURN kmk_cc_eval_fatal(PKMKCCEVALCOMPILER pCompiler, const char *pchWhere, const char *pszMsg, ...) { va_list va; unsigned iLine = pCompiler->iLine; log_working_directory(1); /* * If we have a pointer location, use it to figure out the exact line and column. */ if (pchWhere) { size_t offLine = pCompiler->offLine; size_t off = pchWhere - pCompiler->pszContent; unsigned i = 0; while ( i < pCompiler->cEscEols && off > pCompiler->paEscEols[i].offEol) { offLine = pCompiler->paEscEols[i].offEol + 1 + pCompiler->cchEolSeq; iLine++; i++; } KMK_CC_ASSERT(off <= pCompiler->cchContent); if (pCompiler->pEvalProg->pszVarName) fprintf(stderr, "%s:%u:%u: *** fatal parsing error in %s: ", pCompiler->pEvalProg->pszFilename, iLine, (unsigned)(off - offLine), pCompiler->pEvalProg->pszVarName); else fprintf(stderr, "%s:%u:%u: *** fatal parsing error: ", pCompiler->pEvalProg->pszFilename, iLine, (unsigned)(off - offLine)); } else if (pCompiler->pEvalProg->pszVarName) fprintf(stderr, "%s:%u: *** fatal parsing error in %s: ", pCompiler->pEvalProg->pszFilename, iLine, pCompiler->pEvalProg->pszVarName); else fprintf(stderr, "%s:%u: *** fatal parsing error: ", pCompiler->pEvalProg->pszFilename, iLine); /* * Print the message and die. */ va_start(va, pszMsg); vfprintf(stderr, pszMsg, va); va_end(va); fputs(". Stop.\n", stderr); for (;;) die(2); } static KMK_CC_FN_NO_RETURN void kmk_cc_eval_fatal_eol(PKMKCCEVALCOMPILER pCompiler, const char *pchEol, unsigned iLine, size_t offLine) { pCompiler->iLine = iLine; pCompiler->offLine = offLine; for (;;) kmk_cc_eval_fatal(pCompiler, pchEol, "Missing 2nd EOL character: found %#x instead of %#x\n", pchEol, pCompiler->chSecondEol); } static void kmk_cc_eval_warn(PKMKCCEVALCOMPILER pCompiler, const char *pchWhere, const char *pszMsg, ...) { /** @todo warnings. */ (void)pchWhere; (void)pCompiler; (void)pszMsg; } /** * Compiles a string expansion subprogram. * * @param pCompiler The compiler state. * @param pszExpr The expression to compile. * @param cchExpr The length of the expression. * @param pSubprog The subprogram to compile. */ static void kmk_cc_eval_compile_string_exp_subprog(PKMKCCEVALCOMPILER pCompiler, const char *pszExpr, size_t cchExpr, PKMKCCEXPSUBPROG pSubprog) { int rc = kmk_cc_exp_compile_subprog(pCompiler->ppBlockTail, pszExpr, cchExpr, pSubprog); if (rc == 0) return; kmk_cc_eval_fatal(pCompiler, NULL, "String expansion compile error"); } /** * Initializes a subprogam or plain operand structure. * * @param pCompiler The compiler state. * @param pOperand The subprogram or plain structure to init. * @param pszString The string. * @param cchString The length of the string. * @param fPlain Whether it's plain or not. If not, we'll compile it. */ static void kmk_cc_eval_init_subprogram_or_plain(PKMKCCEVALCOMPILER pCompiler, PKMKCCEXPSUBPROGORPLAIN pOperand, const char *pszString, size_t cchString, int fPlain) { pOperand->fPlainIsInVarStrCache = 0; pOperand->bUser = 0; pOperand->bUser2 = 0; pOperand->fSubprog = fPlain; if (fPlain) { pOperand->u.Plain.cch = cchString; pOperand->u.Plain.psz = pszString; } else kmk_cc_eval_compile_string_exp_subprog(pCompiler, pszString, cchString, &pOperand->u.Subprog); } /** * Initializes an array of subprogram-or-plain (spp) operands from a word array. * * The words will be duplicated and the caller must therefore call * kmk_cc_block_realign() when done (it's not done here as the caller may * initialize several string operands and we don't want any unnecessary * fragmentation). * * @param pCompiler The compiler state. * @param cWords The number of words to copy. * @param paSrc The source words. * @param paDst The destination subprogram-or-plain array. */ static void kmk_cc_eval_init_spp_array_from_duplicated_words(PKMKCCEVALCOMPILER pCompiler, unsigned cWords, PKMKCCEVALWORD paSrc, PKMKCCEXPSUBPROGORPLAIN paDst) { unsigned i; for (i = 0; i < cWords; i++) { const char *pszCopy = kmk_cc_block_strdup(pCompiler->ppBlockTail, paSrc[i].pchWord, paSrc[i].cchWord); paDst[i].fPlainIsInVarStrCache = 0; paDst[i].bUser = 0; paDst[i].bUser2 = 0; if (paSrc[i].enmToken == kKmkCcEvalToken_WordWithDollar) { paDst[i].fSubprog = 1; kmk_cc_eval_compile_string_exp_subprog(pCompiler, pszCopy, paSrc[i].cchWord, &paDst[i].u.Subprog); } else { paDst[i].fSubprog = 0; paDst[i].u.Plain.cch = paSrc[i].cchWord; paDst[i].u.Plain.psz = pszCopy; } KMK_CC_EVAL_DPRINTF((" %s\n", pszCopy)); } } /** @name KMK_CC_WORD_COMP_CONST_XXX - Optimal(/insane) constant work matching. * @{ */ #if (defined(KBUILD_ARCH_X86) || defined(KBUILD_ARCH_AMD64)) /* Unaligned access is reasonably cheap. */ \ && !defined(GCC_ADDRESS_SANITIZER) # define KMK_CC_WORD_COMP_CONST_2(a_pchLine, a_pszWord) \ ( *(uint16_t const *)(a_pchLine) == *(uint16_t const *)(a_pszWord) ) # define KMK_CC_WORD_COMP_CONST_3(a_pchLine, a_pszWord) \ ( *(uint16_t const *)(a_pchLine) == *(uint16_t const *)(a_pszWord) \ && (a_pchLine)[2] == (a_pszWord)[2] ) # define KMK_CC_WORD_COMP_CONST_4(a_pchLine, a_pszWord) \ ( *(uint32_t const *)(a_pchLine) == *(uint32_t const *)(a_pszWord) ) # define KMK_CC_WORD_COMP_CONST_5(a_pchLine, a_pszWord) \ ( *(uint32_t const *)(a_pchLine) == *(uint32_t const *)(a_pszWord) \ && (a_pchLine)[4] == (a_pszWord)[4] ) # define KMK_CC_WORD_COMP_CONST_6(a_pchLine, a_pszWord) \ ( *(uint32_t const *)(a_pchLine) == *(uint32_t const *)(a_pszWord) \ && ((uint16_t const *)(a_pchLine))[2] == ((uint32_t const *)(a_pszWord))[2] ) # define KMK_CC_WORD_COMP_CONST_7(a_pchLine, a_pszWord) \ ( *(uint32_t const *)(a_pchLine) == *(uint32_t const *)(a_pszWord) \ && ((uint16_t const *)(a_pchLine))[2] == ((uint32_t const *)(a_pszWord))[2] \ && (a_pchLine)[6] == (a_pszWord)[6] ) # define KMK_CC_WORD_COMP_CONST_8(a_pchLine, a_pszWord) \ ( *(uint64_t const *)(a_pchLine) == *(uint64_t const *)(a_pszWord) ) # define KMK_CC_WORD_COMP_CONST_10(a_pchLine, a_pszWord) \ ( *(uint64_t const *)(a_pchLine) == *(uint64_t const *)(a_pszWord) \ && ((uint16_t const *)(a_pchLine))[4] == ((uint16_t const *)(a_pszWord))[4] ) # define KMK_CC_WORD_COMP_CONST_16(a_pchLine, a_pszWord) \ ( *(uint64_t const *)(a_pchLine) == *(uint64_t const *)(a_pszWord) \ && ((uint64_t const *)(a_pchLine))[1] == ((uint64_t const *)(a_pszWord))[1] ) #else # define KMK_CC_WORD_COMP_CONST_2(a_pchLine, a_pszWord) \ ( (a_pchLine)[0] == (a_pszWord)[0] \ && (a_pchLine)[1] == (a_pszWord)[1] ) # define KMK_CC_WORD_COMP_CONST_3(a_pchLine, a_pszWord) \ ( (a_pchLine)[0] == (a_pszWord)[0] \ && (a_pchLine)[1] == (a_pszWord)[1] \ && (a_pchLine)[2] == (a_pszWord)[2] ) # define KMK_CC_WORD_COMP_CONST_4(a_pchLine, a_pszWord) \ ( (a_pchLine)[0] == (a_pszWord)[0] \ && (a_pchLine)[1] == (a_pszWord)[1] \ && (a_pchLine)[2] == (a_pszWord)[2] \ && (a_pchLine)[3] == (a_pszWord)[3] ) # define KMK_CC_WORD_COMP_CONST_5(a_pchLine, a_pszWord) \ ( (a_pchLine)[0] == (a_pszWord)[0] \ && (a_pchLine)[1] == (a_pszWord)[1] \ && (a_pchLine)[2] == (a_pszWord)[2] \ && (a_pchLine)[3] == (a_pszWord)[3] \ && (a_pchLine)[4] == (a_pszWord)[4] ) # define KMK_CC_WORD_COMP_CONST_6(a_pchLine, a_pszWord) \ ( (a_pchLine)[0] == (a_pszWord)[0] \ && (a_pchLine)[1] == (a_pszWord)[1] \ && (a_pchLine)[2] == (a_pszWord)[2] \ && (a_pchLine)[3] == (a_pszWord)[3] \ && (a_pchLine)[4] == (a_pszWord)[4] \ && (a_pchLine)[5] == (a_pszWord)[5] ) # define KMK_CC_WORD_COMP_CONST_7(a_pchLine, a_pszWord) \ ( (a_pchLine)[0] == (a_pszWord)[0] \ && (a_pchLine)[1] == (a_pszWord)[1] \ && (a_pchLine)[2] == (a_pszWord)[2] \ && (a_pchLine)[3] == (a_pszWord)[3] \ && (a_pchLine)[4] == (a_pszWord)[4] \ && (a_pchLine)[5] == (a_pszWord)[5] \ && (a_pchLine)[6] == (a_pszWord)[6] ) # define KMK_CC_WORD_COMP_CONST_8(a_pchLine, a_pszWord) \ ( (a_pchLine)[0] == (a_pszWord)[0] \ && (a_pchLine)[1] == (a_pszWord)[1] \ && (a_pchLine)[2] == (a_pszWord)[2] \ && (a_pchLine)[3] == (a_pszWord)[3] \ && (a_pchLine)[4] == (a_pszWord)[4] \ && (a_pchLine)[5] == (a_pszWord)[5] \ && (a_pchLine)[6] == (a_pszWord)[6] \ && (a_pchLine)[7] == (a_pszWord)[7] ) # define KMK_CC_WORD_COMP_CONST_10(a_pchLine, a_pszWord) \ ( (a_pchLine)[0] == (a_pszWord)[0] \ && (a_pchLine)[1] == (a_pszWord)[1] \ && (a_pchLine)[2] == (a_pszWord)[2] \ && (a_pchLine)[3] == (a_pszWord)[3] \ && (a_pchLine)[4] == (a_pszWord)[4] \ && (a_pchLine)[5] == (a_pszWord)[5] \ && (a_pchLine)[6] == (a_pszWord)[6] \ && (a_pchLine)[7] == (a_pszWord)[7] \ && (a_pchLine)[8] == (a_pszWord)[8] \ && (a_pchLine)[9] == (a_pszWord)[9] ) # define KMK_CC_WORD_COMP_CONST_16(a_pchLine, a_pszWord) \ ( (a_pchLine)[0] == (a_pszWord)[0] \ && (a_pchLine)[1] == (a_pszWord)[1] \ && (a_pchLine)[2] == (a_pszWord)[2] \ && (a_pchLine)[3] == (a_pszWord)[3] \ && (a_pchLine)[4] == (a_pszWord)[4] \ && (a_pchLine)[5] == (a_pszWord)[5] \ && (a_pchLine)[6] == (a_pszWord)[6] \ && (a_pchLine)[7] == (a_pszWord)[7] \ && (a_pchLine)[8] == (a_pszWord)[8] \ && (a_pchLine)[9] == (a_pszWord)[9] \ && (a_pchLine)[10] == (a_pszWord)[10] \ && (a_pchLine)[11] == (a_pszWord)[11] \ && (a_pchLine)[12] == (a_pszWord)[12] \ && (a_pchLine)[13] == (a_pszWord)[13] \ && (a_pchLine)[14] == (a_pszWord)[14] \ && (a_pchLine)[15] == (a_pszWord)[15]) #endif /** See if the given string match a constant string. */ #define KMK_CC_STRCMP_CONST(a_pchLeft, a_cchLeft, a_pszConst, a_cchConst) \ ( (a_cchLeft) == (a_cchConst) \ && KMK_CC_WORD_COMP_CONST_##a_cchConst(a_pchLeft, a_pszConst) ) /** See if a starting of a given length starts with a constant word. */ #define KMK_CC_EVAL_WORD_COMP_IS_EOL(a_pCompiler, a_pchLine, a_cchLine) \ ( (a_cchLine) == 0 \ || KMK_CC_EVAL_IS_SPACE((a_pchLine)[0]) \ || ((a_pchLine)[0] == '\\' && (a_pchLine)[1] == (a_pCompiler)->chFirstEol) ) \ /** See if a starting of a given length starts with a constant word. */ #define KMK_CC_EVAL_WORD_COMP_CONST(a_pCompiler, a_pchLine, a_cchLine, a_pszWord, a_cchWord) \ ( (a_cchLine) >= (a_cchWord) \ && ( (a_cchLine) == (a_cchWord) \ || KMK_CC_EVAL_IS_SPACE((a_pchLine)[a_cchWord]) \ || ((a_pchLine)[a_cchWord] == '\\' && (a_pchLine)[(a_cchWord) + 1] == (a_pCompiler)->chFirstEol) ) \ && KMK_CC_WORD_COMP_CONST_##a_cchWord(a_pchLine, a_pszWord) ) /** @} */ /** * Checks if a_ch is a space after a word. * * Since there is always a terminating zero, the user can safely access a char * beyond @a a_cchLeft. However, that byte isn't necessarily a zero terminator * character, so we have to check @a a_cchLeft whether we're at the end of the * parsing input string. * * @returns true / false. * @param a_pCompiler The compiler instance data. * @param a_ch The character to inspect. * @param a_ch2 The character following it, in case of escaped EOL. * @param a_cchLeft The number of chars left to parse (from @a a_ch). */ #define KMK_CC_EVAL_IS_SPACE_AFTER_WORD(a_pCompiler, a_ch, a_ch2, a_cchLeft) \ ( a_cchLeft == 0 \ || KMK_CC_EVAL_IS_SPACE(a_ch) \ || ((a_ch) == '\\' && (a_ch2) == (a_pCompiler)->chFirstEol) ) /** * Common path for space skipping worker functions when escaped EOLs may be * involed. * * @returns Points to the first non-space character or end of input. * @param pchWord The current position. There is some kind of char * @param cchLeft The current number of chars left to parse in the * current line. * @param pcchLeft Where to store the updated @a cchLeft value. * @param pCompiler The compiler instance data. */ static const char *kmk_cc_eval_skip_spaces_with_esc_eol(const char *pchWord, size_t cchLeft, size_t *pcchLeft, PKMKCCEVALCOMPILER pCompiler) { /* * Skip further spaces. We unrolls 4 loops here. * ASSUMES cchEscEolSeq is either 2 or 3! */ KMK_CC_ASSERT(pCompiler->cchEscEolSeq == 2 || pCompiler->cchEscEolSeq == 3); KMK_CC_ASSERT(pCompiler->iEscEol < pCompiler->cEscEols); while (cchLeft >= 4) { /* First char. */ char ch = pchWord[0]; if (KMK_CC_EVAL_IS_SPACE(ch)) { /* maybe likely */ } else if ( ch == '\\' && pchWord[1] == pCompiler->chFirstEol) { pchWord += pCompiler->cchEscEolSeq; cchLeft -= pCompiler->cchEscEolSeq; pCompiler->iEscEol++; continue; } else { *pcchLeft = cchLeft; return pchWord; } /* Second char. */ ch = pchWord[1]; if (KMK_CC_EVAL_IS_SPACE(ch)) { /* maybe likely */ } else if ( ch == '\\' && pchWord[2] == pCompiler->chFirstEol) { pchWord += 1 + pCompiler->cchEscEolSeq; cchLeft -= 1 + pCompiler->cchEscEolSeq; pCompiler->iEscEol++; continue; } else { *pcchLeft = cchLeft - 1; return pchWord + 1; } /* Third char. */ ch = pchWord[2]; if (KMK_CC_EVAL_IS_SPACE(ch)) { /* maybe likely */ } else if ( ch == '\\' && pchWord[3] == pCompiler->chFirstEol && cchLeft >= 2 + pCompiler->cchEscEolSeq) { pchWord += 2 + pCompiler->cchEscEolSeq; cchLeft -= 2 + pCompiler->cchEscEolSeq; pCompiler->iEscEol++; continue; } else { *pcchLeft = cchLeft - 2; return pchWord + 2; } /* Third char. */ ch = pchWord[3]; if (KMK_CC_EVAL_IS_SPACE(ch)) { pchWord += 4; cchLeft -= 4; } else if ( ch == '\\' && cchLeft >= 3 + pCompiler->cchEscEolSeq && pchWord[4] == pCompiler->chFirstEol) { pchWord += 3 + pCompiler->cchEscEolSeq; cchLeft -= 3 + pCompiler->cchEscEolSeq; pCompiler->iEscEol++; } else { *pcchLeft = cchLeft - 3; return pchWord + 3; } } /* * Simple loop for the final three chars. */ while (cchLeft > 0) { /* First char. */ char ch = *pchWord; if (KMK_CC_EVAL_IS_SPACE(ch)) { pchWord += 1; cchLeft -= 1; } else if ( ch == '\\' && cchLeft > pCompiler->cchEolSeq && pchWord[1] == pCompiler->chFirstEol) { pchWord += pCompiler->cchEscEolSeq; cchLeft -= pCompiler->cchEscEolSeq; pCompiler->iEscEol++; } else break; } *pcchLeft = cchLeft; return pchWord; } /** * Common path for space skipping worker functions when no escaped EOLs need * considering. * * @returns Points to the first non-space character or end of input. * @param pchWord The current position. There is some kind of char * @param cchLeft The current number of chars left to parse in the * current line. * @param pcchLeft Where to store the updated @a cchLeft value. * @param pCompiler The compiler instance data. */ static const char *kmk_cc_eval_skip_spaces_without_esc_eol(const char *pchWord, size_t cchLeft, size_t *pcchLeft, PKMKCCEVALCOMPILER pCompiler) { /* * 4x loop unroll. */ while (cchLeft >= 4) { if (KMK_CC_EVAL_IS_SPACE(pchWord[0])) { if (KMK_CC_EVAL_IS_SPACE(pchWord[1])) { if (KMK_CC_EVAL_IS_SPACE(pchWord[2])) { if (KMK_CC_EVAL_IS_SPACE(pchWord[3])) { pchWord += 4; cchLeft -= 4; } else { *pcchLeft = cchLeft - 3; return pchWord + 3; } } else { *pcchLeft = cchLeft - 2; return pchWord + 2; } } else { *pcchLeft = cchLeft - 1; return pchWord + 1; } } else { *pcchLeft = cchLeft; return pchWord; } } /* * The last 3. Not entirely sure if this yield good code. */ switch (cchLeft & 3) { case 3: if (!KMK_CC_EVAL_IS_SPACE(*pchWord)) break; pchWord++; cchLeft--; case 2: if (!KMK_CC_EVAL_IS_SPACE(*pchWord)) break; pchWord++; cchLeft--; case 1: if (!KMK_CC_EVAL_IS_SPACE(*pchWord)) break; pchWord++; cchLeft--; case 0: break; } *pcchLeft = cchLeft; return pchWord; } /** * Used to skip spaces after a word. * * We ASSUME that the first char is a space or that we've reached the end of the * string (a_cchLeft == 0). * * @param a_pCompiler The compiler instance data. * @param a_pchWord The current input position, this will be moved to * the start of the next word or end of the input. * @param a_cchLeft The number of chars left to parse. This will be * updated. */ #define KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(a_pCompiler, a_pchWord, a_cchLeft) \ do { \ /* Skip the first char which is known to be a space, end of line or end of input. */ \ if ((a_cchLeft) > 0) \ { \ char const chSkipBlanksFirst = *(a_pchWord); \ KMK_CC_ASSERT(KMK_CC_EVAL_IS_SPACE_AFTER_WORD(a_pCompiler, chSkipBlanksFirst, (a_pchWord)[1], a_cchLeft)); \ if (chSkipBlanksFirst != '\\') \ { \ (a_pchWord) += 1; \ (a_cchLeft) -= 1; \ \ /* Another space or escaped EOL? Then there are probably more then, so call worker function. */ \ if ((a_cchLeft) > 0) \ { \ char const chSkipBlanksSecond = *(a_pchWord); \ if (KMK_CC_EVAL_IS_SPACE_OR_BACKSLASH(chSkipBlanksSecond)) \ (a_pchWord) = kmk_cc_eval_skip_spaces_after_word_slow(a_pchWord, &(a_cchLeft), \ chSkipBlanksSecond, a_pCompiler); \ } \ } \ else /* escape sequences can be complicated. */ \ (a_pchWord) = kmk_cc_eval_skip_spaces_after_word_slow(a_pchWord, &(a_cchLeft), \ chSkipBlanksFirst, a_pCompiler); \ } \ } while (0) /** * The slow path of KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD. * * This is called to handles escaped EOL sequences, as these can involve * multiple backslashes and therefore doesn't led themselves well to inlined * code. * * The other case this is used for is to handle more than once space, since it's * likely that when there are two there might be more. No point in inlining * that, better do some loop unrolling instead. * * @returns Points to the first non-space character or end of input. * @param pchWord The current position. There is some kind of char * @param pcchLeft Pointer to the cchLeft variable, this is both * input and output. * @param ch The current character. * @param pCompiler The compiler instance data. */ static const char *kmk_cc_eval_skip_spaces_after_word_slow(const char *pchWord, size_t *pcchLeft, char ch, PKMKCCEVALCOMPILER pCompiler) { size_t cchLeft = *pcchLeft; /* * It's all very simple when we don't have to consider escaped EOLs. */ if (pCompiler->iEscEol >= pCompiler->cEscEols) { if (ch != '\\') { pchWord += 1; cchLeft -= 1; } else return pchWord; return kmk_cc_eval_skip_spaces_without_esc_eol(pchWord, cchLeft, pcchLeft, pCompiler); } /* * Skip the pending space or EOL found by the caller. We need to * confirm the EOL. * * Note! We only need to care about simple backslash+EOL sequences here * since we're either at the end of a validated word, or we've already * skipped one space. In the former case, someone else has already * validated the escape esequence, in the latter case multiple * backslashes would indicate a new word that that we should return. */ if (ch != '\\') { pchWord += 1; cchLeft -= 1; } else if ( cchLeft >= pCompiler->cchEscEolSeq && pchWord[1] == pCompiler->chFirstEol) { KMK_CC_ASSERT(pCompiler->cchEolSeq == 1 || pchWord[2] == pCompiler->chSecondEol); pchWord += pCompiler->cchEscEolSeq; cchLeft -= pCompiler->cchEscEolSeq; pCompiler->iEscEol++; if (pCompiler->iEscEol < pCompiler->cEscEols) { /* likely */ } else return kmk_cc_eval_skip_spaces_without_esc_eol(pchWord, cchLeft, pcchLeft, pCompiler); } else return pchWord; return kmk_cc_eval_skip_spaces_with_esc_eol(pchWord, cchLeft, pcchLeft, pCompiler); } /** * Skip zero or more spaces. * * This macro deals with a single space, if there are more or we're hittin some * possible escaped EOL sequence, work is deferred to a worker function. * * @param a_pCompiler The compiler state. * @param a_pchWord The current input position. Advanced past spaces. * @param a_cchLeft The amount of input left to parse. Will be updated. */ #define KMK_CC_EVAL_SKIP_SPACES(a_pCompiler, a_pchWord, a_cchLeft) \ do { \ if ((a_cchLeft) > 0) \ { \ char chSkipSpaces = *(a_pchWord); \ if (KMK_CC_EVAL_IS_SPACE_OR_BACKSLASH(chSkipSpaces)) \ { \ if (chSkipSpaces != '\\') \ { \ (a_pchWord) += 1; \ (a_cchLeft) -= 1; \ chSkipSpaces = *(a_pchWord); \ if (KMK_CC_EVAL_IS_SPACE_OR_BACKSLASH(chSkipSpaces)) \ (a_pchWord) = kmk_cc_eval_skip_spaces_slow(a_pchWord, &(a_cchLeft), chSkipSpaces, a_pCompiler); \ } \ else \ (a_pchWord) = kmk_cc_eval_skip_spaces_slow(a_pchWord, &(a_cchLeft), chSkipSpaces, a_pCompiler); \ } \ } \ } while (0) /** * Worker for KMK_CC_EVAL_SKIP_SPACES. * * @returns Points to the first non-space character or end of input. * @param pchWord The current position. There is some kind of char * @param pcchLeft Pointer to the cchLeft variable, this is both * input and output. * @param ch The current character. * @param pCompiler The compiler instance data. */ static const char *kmk_cc_eval_skip_spaces_slow(const char *pchWord, size_t *pcchLeft, char ch, PKMKCCEVALCOMPILER pCompiler) { size_t cchLeft = *pcchLeft; #ifdef KMK_CC_STRICT size_t offWordCcStrict = pchWord - pCompiler->pszContent; #endif KMK_CC_ASSERT(cchLeft > 0); KMK_CC_ASSERT(cchLeft <= pCompiler->cchLine); KMK_CC_ASSERT(*pchWord == ch); KMK_CC_ASSERT(KMK_CC_EVAL_IS_SPACE_OR_BACKSLASH(ch)); KMK_CC_ASSERT(offWordCcStrict >= pCompiler->offLine); KMK_CC_ASSERT(offWordCcStrict < pCompiler->offLine + pCompiler->cchLine); KMK_CC_ASSERT( pCompiler->iEscEol >= pCompiler->cEscEols || offWordCcStrict <= pCompiler->paEscEols[pCompiler->iEscEol].offEsc); KMK_CC_ASSERT( pCompiler->iEscEol >= pCompiler->cEscEols || pCompiler->iEscEol == 0 || offWordCcStrict >= pCompiler->paEscEols[pCompiler->iEscEol - 1].offEol + pCompiler->cchEolSeq); /* * If we don't need to consider escaped EOLs, things are much much simpler. */ if (pCompiler->iEscEol >= pCompiler->cEscEols) { if (ch != '\\') { pchWord++; cchLeft--; } else return pchWord; return kmk_cc_eval_skip_spaces_without_esc_eol(pchWord, cchLeft, pcchLeft, pCompiler); } /* * Possible escaped EOL complications. */ if (ch != '\\') { pchWord++; cchLeft--; } else { size_t cchSkip; size_t offWord; unsigned iEscEol = pCompiler->iEscEol; if (iEscEol >= pCompiler->cEscEols) return pchWord; offWord = pchWord - pCompiler->pszContent; if (offWord < pCompiler->paEscEols[iEscEol].offEsc) return pchWord; KMK_CC_ASSERT(offWord == pCompiler->paEscEols[iEscEol].offEsc); cchSkip = pCompiler->paEscEols[iEscEol].offEol + pCompiler->cchEolSeq - offWord; pchWord += cchSkip; cchLeft -= cchSkip; pCompiler->iEscEol = ++iEscEol; if (iEscEol < pCompiler->cEscEols) { /* likely */ } else return kmk_cc_eval_skip_spaces_without_esc_eol(pchWord, cchLeft, pcchLeft, pCompiler); } return kmk_cc_eval_skip_spaces_with_esc_eol(pchWord, cchLeft, pcchLeft, pCompiler); } /** * Skips to the end of a variable name. * * This may advance pCompiler->iEscEol. * * @returns Pointer to the first char after the variable name. * @param pCompiler The compiler state. * @param pchWord The current position. Must be at the start of the * variable name. * @param cchLeft The number of chars left to parse in the current line. * @param pcchLeft The to store the updated count of characters left to * parse. * @param pfPlain Where to store the plain variable name indicator. * Returns 0 if plain, and 1 if there are variable * references in it. */ static const char *kmk_cc_eval_skip_var_name(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, size_t *pcchLeft, int *pfPlain) { const char * const pszContent = pCompiler->pszContent; size_t off = pchWord - pszContent; size_t const offLineEnd = off + cchLeft; int fPlain = 1; unsigned iEscEol = pCompiler->iEscEol; /* Check our expectations. */ KMK_CC_ASSERT(cchLeft); KMK_CC_ASSERT(!KMK_CC_EVAL_IS_SPACE(*pchWord)); KMK_CC_ASSERT(iEscEol <= pCompiler->cEscEols); KMK_CC_ASSERT( iEscEol >= pCompiler->cEscEols || off < pCompiler->paEscEols[iEscEol].offEol); KMK_CC_ASSERT(off >= (iEscEol == 0 ? pCompiler->offLine : pCompiler->paEscEols[iEscEol - 1].offEol + pCompiler->cchEolSeq)); /* * The outer loop parses plain text. Variable expansion ($) is handled * by an inner loop. */ while (off < offLineEnd) { char ch = pszContent[off]; if (!KMK_CC_EVAL_IS_SPACE_DOLLAR_OR_SLASH(ch)) off++; else if (KMK_CC_EVAL_IS_SPACE(ch)) break; else if (ch == '$') { off++; if (off < offLineEnd) { char const chOpen = pszContent[off]; if (chOpen == '(' || chOpen == '{') { /* * Got a $(VAR) or ${VAR} to deal with here. This may * include nested variable references and span multiple * lines (at least for function calls). * * We scan forward till we've found the corresponding * closing parenthesis, considering any open parentheses * of the same kind as worth counting, even if there are * no dollar preceeding them, just like GNU make does. */ size_t const offStart = off - 1; char const chClose = chOpen == '(' ? ')' : '}'; unsigned cOpen = 1; off++; for (;;) { if (off < offLineEnd) { ch = pszContent[off]; if (!(KMK_CC_EVAL_IS_PAREN_OR_SLASH(ch))) off++; else { off++; if (ch == chClose) { if (--cOpen == 0) break; } else if (ch == chOpen) cOpen++; else if ( ch == '\\' && iEscEol < pCompiler->cEscEols && off == pCompiler->paEscEols[iEscEol].offEsc) { off = pCompiler->paEscEols[iEscEol].offEol + pCompiler->cchEolSeq; pCompiler->iEscEol = ++iEscEol; } } } else if (cOpen == 1) kmk_cc_eval_fatal(pCompiler, &pszContent[offStart], "Variable reference is missing '%c'", chClose); else kmk_cc_eval_fatal(pCompiler, &pszContent[offStart], "%u variable references are missing '%c'", cOpen, chClose); } } /* Single char variable name. */ else if (!KMK_CC_EVAL_IS_SPACE(chOpen)) { /* likely */ } else kmk_cc_eval_fatal(pCompiler, &pszContent[off], "Expected variable name after '$', not end of line"); } else kmk_cc_eval_fatal(pCompiler, &pszContent[off], "Expected variable name after '$', not end of line"); fPlain = 0; } /* Deal with potential escaped EOL. */ else if ( ch != '\\' || iEscEol >= pCompiler->cEscEols || off != pCompiler->paEscEols[iEscEol].offEsc ) off++; else break; } *pcchLeft = offLineEnd - off; *pfPlain = fPlain; return &pszContent[off]; } #if 0 /* unused atm */ /** * Prepares for copying a command line. * * The current version of this code will not modify any of the paEscEols * entries, unlike our kmk_cc_eval_prep_normal_line sibling function. * * @returns The number of chars that will be copied by * kmk_cc_eval_copy_prepped_command_line(). * @param pCompiler The compiler instance data. * @param pchLeft Pointer to the first char to copy from the current line. * This does not have to the start of a word. * @param cchLeft The number of chars left on the current line starting at * @a pchLeft. */ static size_t kmk_cc_eval_prep_command_line(PKMKCCEVALCOMPILER pCompiler, const char * const pchLeft, size_t cchLeft) { size_t cchRet; unsigned iEscEol = pCompiler->iEscEol; unsigned const cEscEols = pCompiler->cEscEols; KMK_CC_ASSERT(cchLeft > 0); KMK_CC_ASSERT(iEscEol <= cEscEols); if (iEscEol >= cEscEols) { /* * No escaped EOLs left, dead simple. */ cchRet = cchLeft; } else { /* * Compared to the normal prepping of a line, this is actually * really simple. We need to account for two kind of conversions: * - One leading tab is skipped after escaped EOL. * - Convert EOL to LF. */ const char * const pszContent = pCompiler->pszContent; size_t const cchEolSeq = pCompiler->cchEolSeq; #ifdef KMK_CC_STRICT size_t const offLeft = pchLeft - pszContent; KMK_CC_ASSERT(offLeft + cchLeft <= pCompiler->offLine + pCompiler->cchLine); KMK_CC_ASSERT(offLeft + cchLeft <= pCompiler->cchContent); KMK_CC_ASSERT(offLeft < pCompiler->paEscEols[iEscEol].offEsc); KMK_CC_ASSERT(offLeft >= (iEscEol ? pCompiler->paEscEols[cEscEols - 1].offEol + pCompiler->cchEolSeq : pCompiler->offLine)); #endif cchRet = cchLeft; if (cchEolSeq > 1) cchRet -= (cchEolSeq - 1) * cEscEols; do { if (pszContent[pCompiler->paEscEols[cchEolSeq].offEol]) cchRet--; iEscEol++; } while (iEscEol < cEscEols); } return cchRet; } /** * Copies a command line to the buffer @a pszDst points to. * * Must only be used immediately after kmk_cc_eval_prep_command_line(). * * @returns * @param pCompiler The compiler instance data. * @param pchLeft Pointer to the first char to copy from the current line. * This does not have to the start of a word. * @param cchPrepped The return value of kmk_cc_eval_prep_command_line(). * @param pszDst The destination buffer, must be at least @a cchPrepped * plus one (terminator) char big. */ static void kmk_cc_eval_copy_prepped_command_line(PKMKCCEVALCOMPILER pCompiler, const char *pchLeft, size_t cchPrepped, char *pszDst) { unsigned iEscEol = pCompiler->iEscEol; unsigned const cEscEols = pCompiler->cEscEols; if (iEscEol >= cEscEols) { /* Single line. */ memcpy(pszDst, pchLeft, cchPrepped); pszDst[cchPrepped] = '\0'; } else { /* Multiple lines with normalized EOL and maybe one stripped leading TAB. */ char * const pszDstStart = pszDst; const char * const pszContent = pCompiler->pszContent; size_t const cchEolSeq = pCompiler->cchEolSeq; size_t offLeft = pchLeft - pCompiler->pszContent; size_t cchCopy; do { size_t offEol = pCompiler->paEscEols[iEscEol].offEsc; cchCopy = offEol - offLeft; KMK_CC_ASSERT(offEol >= offLeft); memcpy(pszDst, &pszContent[offLeft], cchCopy); pszDst += cchCopy; *pszDst += '\n'; offLeft = offEol + cchEolSeq; if (pszContent[offLeft] == '\t') offLeft++; } while (iEscEol < cEscEols); cchCopy = cchPrepped - (pszDst - pszDstStart); KMK_CC_ASSERT(cchCopy <= cchPrepped); memcpy(pszDst, &pszContent[offLeft], cchCopy); pszDst += cchCopy; *pszDst = '\0'; KMK_CC_ASSERT(pszDst == &pszDstStart[cchPrepped]); } } #endif /* unused atm */ /** * Helper for ensuring that we've got sufficient number of words allocated. */ #define KMK_CC_EVAL_ENSURE_WORDS(a_pCompiler, a_cRequiredWords) \ do { \ if ((a_cRequiredWords) < (a_pCompiler)->cWordsAllocated) \ { /* likely */ } \ else \ { \ unsigned cEnsureWords = ((a_cRequiredWords) + 3 /*15*/) & ~(unsigned)3/*15*/; \ KMK_CC_ASSERT((a_cRequiredWords) < 0x8000); \ (a_pCompiler)->paWords = (PKMKCCEVALWORD)xmalloc(cEnsureWords * sizeof((a_pCompiler)->paWords)[0]); \ } \ } while (0) /** * Parses the remainder of the line into simple words. * * The resulting words are classified as either kKmkCcEvalToken_WordPlain or * kKmkCcEvalToken_WordWithDollar. * * @returns Number of words. * @param pCompiler The compiler state. * @param pchWord Where to start, we expect this to be at a word. * @param cchLeft The number of chars left to parse on this line. * This is expected to be non-zero. */ static unsigned kmk_cc_eval_parse_words(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft) { unsigned iEscEol = pCompiler->iEscEol; unsigned cEscEols = pCompiler->cEscEols; unsigned cWords = 0; /* Precoditions. */ KMK_CC_ASSERT(cchLeft > 0); KMK_CC_ASSERT(!KMK_CC_EVAL_IS_SPACE(*pchWord)); /* * If we don't have to deal with escaped EOLs, the find-end-of word search * becomes a little bit simpler. Since this function will be used a lot * for simple lines with single words, this could maybe save a nano second * or two. */ if (iEscEol >= cEscEols) { do { size_t cchSkipAfter = 0; size_t cchWord = 1; KMKCCEVALTOKEN enmToken = kKmkCcEvalToken_WordPlain; /* Find the end of the current word. */ while (cchWord < cchLeft) { char ch = pchWord[cchWord]; if (!KMK_CC_EVAL_IS_SPACE_OR_DOLLAR(ch)) { /* likely */ } else if (ch == '$') enmToken = kKmkCcEvalToken_WordWithDollar; else break; cchWord++; } /* Add the word. */ KMK_CC_EVAL_ENSURE_WORDS(pCompiler, cWords + 1); pCompiler->paWords[cWords].pchWord = pchWord; pCompiler->paWords[cWords].cchWord = cchWord; pCompiler->paWords[cWords].enmToken = enmToken; cWords++; /* Skip the work and any trailing blanks. */ cchWord += cchSkipAfter; pchWord += cchWord; cchLeft -= cchWord; KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); } while (cchLeft > 0); } /* * Have to deal with escaped EOLs. */ else { const char *pszContent = pCompiler->pszContent; do { size_t cchSkipAfter = 0; size_t cchWord = 1; KMKCCEVALTOKEN enmToken = kKmkCcEvalToken_WordPlain; /* Find the end of the current word. */ while (cchWord < cchLeft) { char ch = pchWord[cchWord]; if (!KMK_CC_EVAL_IS_SPACE_DOLLAR_OR_SLASH(ch)) { /* likely */ } else if (ch == '$') enmToken = kKmkCcEvalToken_WordWithDollar; else if (ch != '\\') break; else if ((size_t)(&pchWord[cchWord] - pszContent) == pCompiler->paEscEols[iEscEol].offEsc) { cchSkipAfter = pCompiler->paEscEols[iEscEol].offEol - pCompiler->paEscEols[iEscEol].offEsc + pCompiler->cchEolSeq; iEscEol++; break; } cchWord++; } /* Add the word. */ KMK_CC_EVAL_ENSURE_WORDS(pCompiler, cWords + 1); pCompiler->paWords[cWords].pchWord = pchWord; pCompiler->paWords[cWords].cchWord = cchWord; pCompiler->paWords[cWords].enmToken = enmToken; cWords++; /* Skip the work and any trailing blanks. */ cchWord += cchSkipAfter; pchWord += cchWord; cchLeft -= cchWord; KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); } while (cchLeft > 0); } pCompiler->cWords = cWords; return cWords; } /** * Gather string from segments and optional space insertion trick. * * @param pszDst The destination buffer. * @param paSegs The source segments. * @param cSegs The number of segments. * @param cchDstPrepped The size of pszDst, excluding the terminator. */ static void kmk_cc_eval_strcpyv(char *pszDst, PCKMKCCEVALSTRCPYSEG paSegs, unsigned cSegs, size_t cchDstPrepped) { const char *pszDstStart = pszDst; unsigned iSeg = 0; while (iSeg < cSegs) { size_t cchToCopy; if (paSegs[iSeg].cchSrcAndPrependSpace >= 0) cchToCopy = paSegs[iSeg].cchSrcAndPrependSpace; else { cchToCopy = -paSegs[iSeg].cchSrcAndPrependSpace; *pszDst++ = ' '; } memcpy(pszDst, paSegs[iSeg].pchSrc, cchToCopy); pszDst += cchToCopy; iSeg++; } *pszDst = '\0'; KMK_CC_ASSERT(pszDst == &pszDstStart[cchDstPrepped]); K_NOREF(pszDstStart); K_NOREF(cchDstPrepped); } /** * Allocate a byte buffer and ocpy the prepared string segments into it. * * The caller must call kmk_cc_block_realign! * * @returns Pointer to the duplicated string. * @param pCompiler The compiler instance data. * @param cchPrepped The length of the prepped string segments. */ static char *kmk_cc_eval_strdup_prepped(PKMKCCEVALCOMPILER pCompiler, size_t cchPrepped) { char *pszCopy = kmk_cc_block_byte_alloc(pCompiler->ppBlockTail, cchPrepped + 1); kmk_cc_eval_strcpyv(pszCopy, pCompiler->paStrCopySegs, pCompiler->cStrCopySegs, cchPrepped); return pszCopy; } /** * Strip trailing spaces from prepped copy * * @param paSegs The segments to strip trailing chars from. * @param pcSegs The number of segments (in/out). * @param pcchDstPrepped The total number of chars prepped (in/out). */ static void kmk_cc_eval_strip_right_v(PKMKCCEVALSTRCPYSEG paSegs, unsigned *pcSegs, size_t *pcchDstPrepped) { /* * Work our way thru the segments, from the end obviously. */ size_t cchDstPrepped = *pcchDstPrepped; unsigned cSegs = *pcSegs; while (cSegs > 0) { unsigned iSeg = cSegs - 1; const char *pszSrc = paSegs[iSeg].pchSrc; size_t cchSrc = paSegs[iSeg].cchSrcAndPrependSpace >= 0 ? paSegs[iSeg].cchSrcAndPrependSpace : -paSegs[iSeg].cchSrcAndPrependSpace; if (cchSrc) { /* * Check for trailing spaces. */ size_t cchSrcOrg; if (!KMK_CC_EVAL_IS_SPACE(pszSrc[cchSrc - 1])) { /* Special case: No trailing spaces at all. No need to update input/output variables. */ if (cSegs == *pcSegs) return; break; } /* Skip the rest of the trailing spaces. */ cchSrcOrg = cchSrc; do cchSrc--; while (cchSrc > 0 && KMK_CC_EVAL_IS_SPACE(pszSrc[cchSrc - 1])); if (cchSrc > 0) { /* * There are non-space chars in this segment. So, update the * segment and total char count and we're done. */ cchDstPrepped -= cchSrcOrg - cchSrc; if (paSegs[iSeg].cchSrcAndPrependSpace < 0) paSegs[iSeg].cchSrcAndPrependSpace = -(ssize_t)cchSrc; else paSegs[iSeg].cchSrcAndPrependSpace = cchSrc; break; } /* * Skip the whole segment. */ cchDstPrepped -= cchSrcOrg + (paSegs[iSeg].cchSrcAndPrependSpace < 0); } cSegs--; } *pcchDstPrepped = cchDstPrepped; *pcSegs = cSegs; } /** * Helper for ensuring that we've got sufficient number of string copy segments. */ #define KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(a_pCompiler, a_cRequiredSegs) \ do { \ if ((a_cRequiredSegs) < (a_pCompiler)->cStrCopySegsAllocated) \ { /* likely */ } \ else \ { \ unsigned cEnsureSegs = ((a_cRequiredSegs) + 3 /*15*/) & ~(unsigned)3/*15*/; \ KMK_CC_ASSERT((a_cRequiredSegs) < 0x8000); \ (a_pCompiler)->paStrCopySegs = (PKMKCCEVALSTRCPYSEG)xmalloc(cEnsureSegs * sizeof((a_pCompiler)->paStrCopySegs)[0]); \ } \ } while (0) /** * Prepares for copying a normal line, extended version. * * This does not assume that we start on a word, it can handle any starting * character. It can also prepare partial copies. * * In addition to the returned information, this will store instruction in * paEscEols for the following kmk_cc_eval_strcpyv() call. * * This will advance pCompiler->iEscEol, so that it's possible to use the common * macros and helpers for parsing what comes afterwards. * * @returns The number of chars that will be copied by kmk_cc_eval_strcpyv(). * @param pCompiler The compiler instance data. * @param pchWord Pointer to the first char to copy from the * current line. This must be the start of a * word. * @param cchLeft The number of chars left on the current line * starting at @a pchWord. */ static size_t kmk_cc_eval_prep_normal_line_ex(PKMKCCEVALCOMPILER pCompiler, const char * const pchWord, size_t cchLeft) { size_t cchRet; unsigned iEscEol = pCompiler->iEscEol; unsigned const cEscEols = pCompiler->cEscEols; KMK_CC_ASSERT(iEscEol <= cEscEols); if (cchLeft > 0) { /* * If there are no escaped EOLs left, just copy exactly * what was passed in. */ if (iEscEol >= cEscEols) { KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(pCompiler, 1); pCompiler->cStrCopySegs = 1; pCompiler->paStrCopySegs[0].pchSrc = pchWord; pCompiler->paStrCopySegs[0].cchSrcAndPrependSpace = cchRet = cchLeft; } /* * Ok, we have to deal with escaped EOLs and do the proper * replacement of escaped newlines with space. The deal is that we * collaps all whitespace before and after one or more newlines into a * single space. (FreeBSD make does this differently, by the by.) */ else { const char * const pszContent = pCompiler->pszContent; size_t offWord = pchWord - pCompiler->pszContent; size_t const offLineEnd = offWord + cchLeft; /* Note! Not necessarily end of line.*/ size_t offEsc; size_t fPendingSpace = 0; unsigned cSegs = 0; size_t cchSeg; /* Go nuts checking our preconditions here. */ KMK_CC_ASSERT(offWord >= pCompiler->offLine); KMK_CC_ASSERT(offWord + cchLeft <= pCompiler->offLine + pCompiler->cchLine); KMK_CC_ASSERT(offWord + cchLeft <= pCompiler->cchContent); KMK_CC_ASSERT(offWord <= pCompiler->paEscEols[iEscEol].offEsc); KMK_CC_ASSERT(offWord >= (iEscEol ? pCompiler->paEscEols[cEscEols - 1].offEol + pCompiler->cchEolSeq : pCompiler->offLine)); KMK_CC_ASSERT(offWord < offLineEnd); /* Make sure we've got more than enough segments to fill in. */ KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(pCompiler, cEscEols - iEscEol + 2); /* * All but the last line. */ cchRet = 0; do { KMK_CC_ASSERT(offWord < offLineEnd); offEsc = pCompiler->paEscEols[iEscEol].offEsc; if (offWord < offEsc) { /* Strip trailing spaces. */ while (offEsc > offWord && KMK_CC_EVAL_IS_SPACE(pszContent[offEsc - 1])) offEsc--; cchSeg = offEsc - offWord; if (cchSeg) { /* Add segment. */ pCompiler->paStrCopySegs[cSegs].pchSrc = &pszContent[offWord]; if (offEsc < offLineEnd) { pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = fPendingSpace ? -(ssize_t)cchSeg : (ssize_t)cchSeg; cchRet += cchSeg + fPendingSpace; cSegs += 1; fPendingSpace = 1; } else { cchSeg = offLineEnd - offWord; pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = fPendingSpace ? -(ssize_t)cchSeg : (ssize_t)cchSeg; pCompiler->cStrCopySegs = cSegs + 1; pCompiler->iEscEol = iEscEol; return cchRet + cchSeg + fPendingSpace; } } } else KMK_CC_ASSERT(offWord == offEsc); /* Next line. */ offWord = pCompiler->paEscEols[iEscEol].offEol + pCompiler->cchEolSeq; iEscEol++; /* Strip leading spaces. */ while (offWord < offLineEnd && KMK_CC_EVAL_IS_SPACE(pszContent[offWord])) offWord++; if (offWord >= offLineEnd) { pCompiler->cStrCopySegs = cSegs; pCompiler->iEscEol = iEscEol; return cchRet; } } while (iEscEol < cEscEols); /* * The last line. */ cchSeg = offLineEnd - offWord; cchRet += cchSeg; pCompiler->paStrCopySegs[cSegs].pchSrc = &pszContent[offWord]; pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = fPendingSpace ? -(ssize_t)cchSeg : (ssize_t)cchSeg; pCompiler->cStrCopySegs = cSegs + 1; pCompiler->iEscEol = iEscEol; } } /* * Odd case: Nothing to copy. */ else { cchRet = 0; pCompiler->cStrCopySegs = 0; } return cchRet; } /** * Prepares for copying a normal line, from the given position all the way to * the end. * * In addition to the returned information, this will store instruction in * paStrCopySegs and cSTrCopySeg for the following kmk_cc_eval_strcpyv() call. * * @returns The number of chars that will be copied by kmk_cc_eval_strcpyv(). * @param pCompiler The compiler instance data. * @param pchWord Pointer to the first char to copy from the * current line. This must be the start of a * word. * @param cchLeft The number of chars left on the current line * starting at @a pchWord. */ static size_t kmk_cc_eval_prep_normal_line(PKMKCCEVALCOMPILER pCompiler, const char * const pchWord, size_t cchLeft) { size_t cchRet; unsigned iEscEol = pCompiler->iEscEol; unsigned const cEscEols = pCompiler->cEscEols; KMK_CC_ASSERT(cchLeft > 0); KMK_CC_ASSERT(!KMK_CC_EVAL_IS_SPACE(*pchWord)); /* The fact that we're standing at a word, is exploited below. */ KMK_CC_ASSERT(iEscEol <= cEscEols); /* * If there are no escaped EOLs left, just copy what was specified, * optionally sans any trailing spaces. */ if (iEscEol >= cEscEols) { cchRet = cchLeft; KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(pCompiler, 1); pCompiler->cStrCopySegs = 1; pCompiler->paStrCopySegs[0].pchSrc = pchWord; pCompiler->paStrCopySegs[0].cchSrcAndPrependSpace = cchRet; } /* * Ok, we have to deal with escaped EOLs and do the proper * replacement of escaped newlines with space. The deal is that we * collaps all whitespace before and after one or more newlines into a * single space. (FreeBSD make does this differently, by the by.) */ else { const char *pszContent = pCompiler->pszContent; size_t offWord = pchWord - pCompiler->pszContent; size_t offEsc; size_t fPendingSpace; size_t cchSeg; unsigned cSegs = 0; /* Go nuts checking our preconditions here. */ KMK_CC_ASSERT(offWord >= pCompiler->offLine); KMK_CC_ASSERT(offWord + cchLeft <= pCompiler->offLine + pCompiler->cchLine); KMK_CC_ASSERT(offWord + cchLeft <= pCompiler->cchContent); KMK_CC_ASSERT(offWord < pCompiler->paEscEols[iEscEol].offEsc); KMK_CC_ASSERT(offWord >= (iEscEol ? pCompiler->paEscEols[iEscEol - 1].offEol + pCompiler->cchEolSeq : pCompiler->offLine)); /* Make sure we've got more than enough segments to fill in. */ KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(pCompiler, cEscEols - iEscEol + 2); /* * First line - We're at the start of a word, so no left stripping needed. */ offEsc = pCompiler->paEscEols[iEscEol].offEsc; KMK_CC_ASSERT(offEsc > offWord); while (KMK_CC_EVAL_IS_SPACE(pszContent[offEsc - 1])) offEsc--; KMK_CC_ASSERT(offEsc > offWord); fPendingSpace = 1; cchRet = offEsc - offWord; pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = cchRet; pCompiler->paStrCopySegs[cSegs].pchSrc = pchWord; cSegs++; offWord = pCompiler->paEscEols[iEscEol].offEol + pCompiler->cchEolSeq; iEscEol++; /* * All but the last line. */ while (iEscEol < cEscEols) { offEsc = pCompiler->paEscEols[iEscEol].offEsc; /* Strip leading spaces. */ while (offWord < offEsc && KMK_CC_EVAL_IS_SPACE(pszContent[offWord])) offWord++; if (offWord < offEsc) { /* Strip trailing spaces. */ while (KMK_CC_EVAL_IS_SPACE(pszContent[offEsc - 1])) offEsc--; cchSeg = offEsc - offWord; pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = fPendingSpace ? -(ssize_t)cchSeg : (ssize_t)cchSeg; cchRet += cchSeg + fPendingSpace; pCompiler->paStrCopySegs[cSegs].pchSrc = &pszContent[offWord]; cSegs += 1; fPendingSpace = 1; } /* Next. */ offWord = pCompiler->paEscEols[iEscEol].offEol + pCompiler->cchEolSeq; iEscEol++; } /* * Final line. We must calculate the end of line offset our selves here. */ offEsc = &pchWord[cchLeft] - pszContent; while (offWord < offEsc && KMK_CC_EVAL_IS_SPACE(pszContent[offWord])) offWord++; if (offWord < offEsc) { cchSeg = offEsc - offWord; pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = fPendingSpace ? -(ssize_t)cchSeg : (ssize_t)cchSeg; cchRet += cchSeg + fPendingSpace; pCompiler->paStrCopySegs[cSegs].pchSrc = &pszContent[offWord]; cSegs += 1; } pCompiler->cStrCopySegs = cSegs; } return cchRet; } /** * Common worker for all kmk_cc_eval_do_if*() functions. * * @param pCompiler The compiler state. * @param pIfCore The new IF statement. * @param fInElse Set if this is an 'else if' (rather than just 'if'). */ static void kmk_cc_eval_do_if_core(PKMKCCEVALCOMPILER pCompiler, PKMKCCEVALIFCORE pIfCore, int fInElse) { unsigned iIf = pCompiler->cIfs; if (!fInElse) { /* Push an IF statement. */ if (iIf < KMK_CC_EVAL_MAX_IF_DEPTH) { pCompiler->cIfs = iIf + 1; pCompiler->apIfs[iIf] = pIfCore; pIfCore->pPrevCond = NULL; } else kmk_cc_eval_fatal(pCompiler, NULL, "Too deep IF nesting"); } else if (iIf > 0) { /* Link an IF statement. */ iIf--; pIfCore->pPrevCond = pCompiler->apIfs[iIf]; pCompiler->apIfs[iIf] = pIfCore; } else kmk_cc_eval_fatal(pCompiler, NULL, "'else if' without 'if'"); pIfCore->pNextTrue = (PKMKCCEVALCORE)kmk_cc_block_get_next_ptr(*pCompiler->ppBlockTail); pIfCore->pNextFalse = NULL; /* This is set by else or endif. */ pIfCore->pTrueEndJump = NULL; /* This is set by else or endif. */ } /** * Deals with 'if expr' and 'else if expr' statements. * * @returns 1 to indicate we've handled a keyword (see * kmk_cc_eval_try_handle_keyword). * @param pCompiler The compiler state. * @param pchWord First char after 'if'. * @param cchLeft The number of chars left to parse on this line. * @param fInElse Set if this is an 'else if' (rather than just 'if'). */ static int kmk_cc_eval_do_if(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, int fInElse) { KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); if (cchLeft) { PKMKCCEVALIFEXPR pInstr; size_t cchExpr = kmk_cc_eval_prep_normal_line(pCompiler, pchWord, cchLeft); kmk_cc_eval_strip_right_v(pCompiler->paStrCopySegs, &pCompiler->cStrCopySegs, &cchExpr); pInstr = (PKMKCCEVALIFEXPR)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, KMKCCEVALIFEXPR_SIZE(cchExpr)); kmk_cc_eval_strcpyv(pInstr->szExpr, pCompiler->paStrCopySegs, pCompiler->cStrCopySegs, cchExpr); pInstr->cchExpr = cchExpr; pInstr->IfCore.Core.enmOpcode = kKmkCcEvalInstr_if; pInstr->IfCore.Core.iLine = pCompiler->iLine; kmk_cc_eval_do_if_core(pCompiler, &pInstr->IfCore, fInElse); } else kmk_cc_eval_fatal(pCompiler, pchWord, "Expected expression after 'if' directive"); return 1; } /** * Deals with 'ifdef var', 'ifndef var', 'else ifdef var' and 'else ifndef var' * statements. * * @returns 1 to indicate we've handled a keyword (see * kmk_cc_eval_try_handle_keyword). * @param pCompiler The compiler state. * @param pchWord First char after 'if[n]def'. * @param cchLeft The number of chars left to parse on this line. * @param fInElse Set if this is an 'else if' (rather than just 'if'). * @param fPositiveStmt Set if 'ifdef', clear if 'ifndef'. */ static int kmk_cc_eval_do_ifdef(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, int fInElse, int fPositiveStmt) { KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); if (cchLeft) { /* * Skip to the end of the variable name. */ unsigned const iSavedEscEol = pCompiler->iEscEol; const char * const pchVarNm = pchWord; int fPlain; /** @todo this isn't quite right. It is a variable name, correct. However, it * doesn't need to subscribe entirely to the rules of a variable name. * Just find the end of the word, taking variable refs into account, * and consider it what we need. */ pchWord = kmk_cc_eval_skip_var_name(pCompiler, pchWord, cchLeft, &cchLeft, &fPlain); KMK_CC_ASSERT(pCompiler->iEscEol == iSavedEscEol || !fPlain); if (fPlain) { size_t const cchVarNm = pchWord - pchVarNm; PKMKCCEVALIFDEFPLAIN pInstr; pInstr = (PKMKCCEVALIFDEFPLAIN)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr)); pInstr->IfCore.Core.enmOpcode = fPositiveStmt ? kKmkCcEvalInstr_ifdef_plain : kKmkCcEvalInstr_ifndef_plain; pInstr->IfCore.Core.iLine = pCompiler->iLine; pInstr->pszName = strcache2_add(&variable_strcache, pchVarNm, cchVarNm); kmk_cc_eval_do_if_core(pCompiler, &pInstr->IfCore, fInElse); } else { PKMKCCEVALIFDEFDYNAMIC pInstr; size_t const cchVarNm = pchWord - pchVarNm; size_t cchCopy; char *pszCopy; pCompiler->iEscEol = iSavedEscEol; cchCopy = kmk_cc_eval_prep_normal_line(pCompiler, pchVarNm, cchVarNm); pInstr = (PKMKCCEVALIFDEFDYNAMIC)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr)); /** @todo Make the subprogram embed necessary strings. */ pszCopy = kmk_cc_eval_strdup_prepped(pCompiler, cchCopy); kmk_cc_block_realign(pCompiler->ppBlockTail); pInstr->IfCore.Core.enmOpcode = fPositiveStmt ? kKmkCcEvalInstr_ifdef_dynamic : kKmkCcEvalInstr_ifndef_dynamic; pInstr->IfCore.Core.iLine = pCompiler->iLine; kmk_cc_eval_compile_string_exp_subprog(pCompiler, pszCopy, cchCopy, &pInstr->NameSubprog); kmk_cc_eval_do_if_core(pCompiler, &pInstr->IfCore, fInElse); } /* * Make sure there is nothing following the variable name. */ KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); if (cchLeft) kmk_cc_eval_fatal(pCompiler, pchWord, "Bogus stuff after 'if%sdef' variable name", fPositiveStmt ? "" : "n"); } else kmk_cc_eval_fatal(pCompiler, pchWord, "Expected expression after 'if' directive"); return 1; } /** * Deals with 'ifeq (a,b)', 'ifeq "a" "b"', 'ifneq (a,b)', 'ifneq "a" "b"', * 'else ifeq (a,b)', 'else ifeq "a" "b"', 'else ifneq (a,b)' and * 'else ifneq "a" "b"' statements. * * @returns 1 to indicate we've handled a keyword (see * kmk_cc_eval_try_handle_keyword). * @param pCompiler The compiler state. * @param pchWord First char after 'if[n]eq'. * @param cchLeft The number of chars left to parse on this line. * @param fInElse Set if this is an 'else if' (rather than just 'if'). * @param fPositiveStmt Set if 'ifeq', clear if 'ifneq'. */ static int kmk_cc_eval_do_ifeq(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, int fInElse, int fPositiveStmt) { KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); if (cchLeft) { /* * There are two forms: * * ifeq (string1, string2) * ifeq "string1" 'string2' * */ const char * const pchEnd = &pchWord[cchLeft]; PKMKCCEVALIFEQ pInstr = (PKMKCCEVALIFEQ)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr)); struct { char *pszCopy; size_t cchCopy; int fPlain; } Left, Right; char ch = *pchWord; if (ch == '(') { int cCounts; size_t off; /* * The left side ends with a comma. We respect parentheses, but * not curly brackets. */ /* Skip the parenthesis. */ pchWord++; cchLeft--; /* Find the comma, checking for non-plainness. */ cCounts = 0; Left.fPlain = 1; for (off = 0; off < cchLeft; off++) { ch = pchWord[off]; if (!KMK_CC_EVAL_IS_PAREN_COMMA_OR_DOLLAR(ch)) { /* likely */ } else if (ch == '$') Left.fPlain = 0; else if (ch == '(') cCounts++; else if (ch == ')') cCounts--; /** @todo warn if it goes negative. */ else if (ch == ',' && cCounts == 0) break; else KMK_CC_ASSERT(cCounts > 0); } if (ch == ',' && cCounts == 0) { /* likely */ } else kmk_cc_eval_fatal(pCompiler, &pchWord[off], "Expected ',' before end of line"); /* Copy out the string. */ Left.cchCopy = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchWord, off); kmk_cc_eval_strip_right_v(pCompiler->paStrCopySegs, &pCompiler->cStrCopySegs, &Left.cchCopy); Left.pszCopy = kmk_cc_eval_strdup_prepped(pCompiler, Left.cchCopy); /* Skip past the comma and any following spaces. */ pchWord += off + 1; cchLeft -= off + 1; if ( cchLeft /** @todo replace with straight 'isspace' that takes escaped EOLs into account. */ && KMK_CC_EVAL_IS_SPACE_AFTER_WORD(pCompiler, pchWord[0], pchWord[1], cchLeft)) KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); /* * Ditto for the right side, only it ends with a closing parenthesis. */ cCounts = 1; Right.fPlain = 1; for (off = 0; off < cchLeft; off++) { ch = pchWord[off]; if (!KMK_CC_EVAL_IS_PAREN_COMMA_OR_DOLLAR(ch)) { /* likely */ } else if (ch == '$') Right.fPlain = 0; else if (ch == '(') cCounts++; else if (ch == ')') { if (--cCounts == 0) break; } else KMK_CC_ASSERT(cCounts > 0 || ch == ','); } if (ch == ')' && cCounts == 0) { /* likely */ } else kmk_cc_eval_fatal(pCompiler, &pchWord[off], "Expected ')' before end of line"); /* Copy out the string. */ Right.cchCopy = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchWord, off); kmk_cc_eval_strip_right_v(pCompiler->paStrCopySegs, &pCompiler->cStrCopySegs, &Right.cchCopy); Right.pszCopy = kmk_cc_eval_strdup_prepped(pCompiler, Right.cchCopy); /* Skip past the parenthesis. */ pchWord += off + 1; cchLeft -= off + 1; } else if (ch == '"' || ch == '\'') { const char *pchTmp; /* * Quoted left side. */ /* Skip leading quote. */ pchWord++; cchLeft--; /* Locate the end quote. */ pchTmp = (const char *)memchr(pchWord, ch, cchLeft); if (pchTmp) { /* likely */ } else kmk_cc_eval_fatal(pCompiler, pchWord - 1, "Unbalanced quote in first if%seq string", fPositiveStmt ? "" : "n"); Left.cchCopy = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchWord, pchTmp - pchWord); Left.pszCopy = kmk_cc_eval_strdup_prepped(pCompiler, Left.cchCopy); Left.fPlain = memchr(Left.pszCopy, '$', Left.cchCopy) == NULL; /* skip end quote */ pchWord = pchTmp + 1; cchLeft = pchEnd - pchWord; /* Skip anything inbetween the left and right hand side (not mandatory). */ if ( cchLeft /** @todo replace with straight 'isspace' that takes escaped EOLs into account. */ && KMK_CC_EVAL_IS_SPACE_AFTER_WORD(pCompiler, pchWord[0], pchWord[1], cchLeft)) KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); /* * Quoted right side. */ if ( cchLeft > 0 && ( (ch = *pchWord) != '"' || ch == '\'') ) { /* Skip leading quote. */ pchWord++; cchLeft--; /* Locate the end quote. */ pchTmp = (const char *)memchr(pchWord, ch, cchLeft); if (pchTmp) { /* likely */ } else kmk_cc_eval_fatal(pCompiler, pchWord - 1, "Unbalanced quote in second if%seq string", fPositiveStmt ? "" : "n"); Right.cchCopy = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchWord, pchTmp - pchWord); Right.pszCopy = kmk_cc_eval_strdup_prepped(pCompiler, Right.cchCopy); Right.fPlain = memchr(Right.pszCopy, '$', Right.cchCopy) == NULL; /* skip end quote */ pchWord = pchTmp + 1; cchLeft = pchEnd - pchWord; } else kmk_cc_eval_fatal(pCompiler, pchWord, "Expected a second quoted string for 'if%seq'", fPositiveStmt ? "" : "n"); } else kmk_cc_eval_fatal(pCompiler, pchWord, "Expected parentheses or quoted string after 'if%seq'", fPositiveStmt ? "" : "n"); kmk_cc_block_realign(pCompiler->ppBlockTail); /* * Initialize the instruction. */ pInstr->IfCore.Core.enmOpcode = fPositiveStmt ? kKmkCcEvalInstr_ifeq : kKmkCcEvalInstr_ifneq; pInstr->IfCore.Core.iLine = pCompiler->iLine; kmk_cc_eval_init_subprogram_or_plain(pCompiler, &pInstr->Left, Left.pszCopy, Left.cchCopy, Left.fPlain); kmk_cc_eval_init_subprogram_or_plain(pCompiler, &pInstr->Right, Right.pszCopy, Right.cchCopy, Right.fPlain); kmk_cc_eval_do_if_core(pCompiler, &pInstr->IfCore, fInElse); /* * Make sure there is nothing following the variable name. */ KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); if (cchLeft) kmk_cc_eval_fatal(pCompiler, pchWord, "Bogus stuff after 'if%sdef' variable name", fPositiveStmt ? "" : "n"); } else kmk_cc_eval_fatal(pCompiler, pchWord, "Expected expression after 'if' directive"); return 1; } /** * Deals with 'if1of (set-a,set-b)', 'ifn1of (set-a,set-b)', * 'else if1of (set-a,set-b)' and 'else ifn1of (set-a,set-b)' statements. * * @returns 1 to indicate we've handled a keyword (see * kmk_cc_eval_try_handle_keyword). * @param pCompiler The compiler state. * @param pchWord First char after 'if[n]1of'. * @param cchLeft The number of chars left to parse on this line. * @param fInElse Set if this is an 'else if' (rather than just 'if'). * @param fPositiveStmt Set if 'if1of', clear if 'ifn1of'. */ static int kmk_cc_eval_do_if1of(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, int fInElse, int fPositiveStmt) { KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); if (cchLeft) { /* * This code is (currently) very similar to kmk_cc_eval_do_ifeq. * However, we may want to add hashing optimizations of plain text, * and we don't want to support the quoted form as it is not necessary * and may interfere with support for quoted words later on. */ PKMKCCEVALIF1OF pInstr = (PKMKCCEVALIF1OF)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr)); struct { char *pszCopy; size_t cchCopy; int fPlain; } Left, Right; char ch = *pchWord; if (ch == '(') { int cCounts; size_t off; /* * The left side ends with a comma. We respect parentheses, but * not curly brackets. */ /* Skip the parenthesis. */ pchWord++; cchLeft--; /* Find the comma, checking for non-plainness. */ cCounts = 0; Left.fPlain = 1; for (off = 0; off < cchLeft; off++) { ch = pchWord[off]; if (!KMK_CC_EVAL_IS_PAREN_COMMA_OR_DOLLAR(ch)) { /* likely */ } else if (ch == '$') Left.fPlain = 0; else if (ch == '(') cCounts++; else if (ch == ')') cCounts--; /** @todo warn if it goes negative. */ else if (ch == ',' && cCounts == 0) break; else KMK_CC_ASSERT(cCounts > 0); } if (ch == ',' && cCounts == 0) { /* likely */ } else kmk_cc_eval_fatal(pCompiler, &pchWord[off], "Expected ',' before end of line"); /* Copy out the string. */ Left.cchCopy = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchWord, off); kmk_cc_eval_strip_right_v(pCompiler->paStrCopySegs, &pCompiler->cStrCopySegs, &Left.cchCopy); Left.pszCopy = kmk_cc_eval_strdup_prepped(pCompiler, Left.cchCopy); /* Skip past the comma and any following spaces. */ pchWord += off + 1; cchLeft -= off + 1; if ( cchLeft /** @todo replace with straight 'isspace' that takes escaped EOLs into account. */ && KMK_CC_EVAL_IS_SPACE_AFTER_WORD(pCompiler, pchWord[0], pchWord[1], cchLeft)) KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); /* * Ditto for the right side, only it ends with a closing parenthesis. */ cCounts = 1; Right.fPlain = 1; for (off = 0; off < cchLeft; off++) { ch = pchWord[off]; if (!KMK_CC_EVAL_IS_PAREN_COMMA_OR_DOLLAR(ch)) { /* likely */ } else if (ch == '$') Right.fPlain = 0; else if (ch == '(') cCounts++; else if (ch == ')') { if (--cCounts == 0) break; } else KMK_CC_ASSERT(cCounts > 0 || ch == ','); } if (ch == ')' && cCounts == 0) { /* likely */ } else kmk_cc_eval_fatal(pCompiler, &pchWord[off], "Expected ')' before end of line"); /* Copy out the string. */ Right.cchCopy = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchWord, off); kmk_cc_eval_strip_right_v(pCompiler->paStrCopySegs, &pCompiler->cStrCopySegs, &Right.cchCopy); Right.pszCopy = kmk_cc_eval_strdup_prepped(pCompiler, Right.cchCopy); /* Skip past the parenthesis. */ pchWord += off + 1; cchLeft -= off + 1; } else kmk_cc_eval_fatal(pCompiler, pchWord, "Expected parentheses after 'if%s1of'", fPositiveStmt ? "" : "n"); kmk_cc_block_realign(pCompiler->ppBlockTail); /* * Initialize the instruction. */ pInstr->IfCore.Core.enmOpcode = fPositiveStmt ? kKmkCcEvalInstr_if1of : kKmkCcEvalInstr_ifn1of; pInstr->IfCore.Core.iLine = pCompiler->iLine; kmk_cc_eval_init_subprogram_or_plain(pCompiler, &pInstr->Left, Left.pszCopy, Left.cchCopy, Left.fPlain); kmk_cc_eval_init_subprogram_or_plain(pCompiler, &pInstr->Right, Right.pszCopy, Right.cchCopy, Right.fPlain); kmk_cc_eval_do_if_core(pCompiler, &pInstr->IfCore, fInElse); /* * Make sure there is nothing following the variable name. */ KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); if (cchLeft) kmk_cc_eval_fatal(pCompiler, pchWord, "Bogus stuff after 'if%s1of' variable name", fPositiveStmt ? "" : "n"); } else kmk_cc_eval_fatal(pCompiler, pchWord, "Expected expression after 'if' directive"); return 1; } /** * Deals with 'else' and 'else ifxxx' statements. * * @returns 1 to indicate we've handled a keyword (see * kmk_cc_eval_try_handle_keyword). * @param pCompiler The compiler state. * @param pchWord First char after 'define'. * @param cchLeft The number of chars left to parse on this line. */ static int kmk_cc_eval_do_else(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft) { /* * There must be an 'if' on the stack. */ unsigned iIf = pCompiler->cIfs; if (iIf > 0) { PKMKCCEVALIFCORE pIfCore = pCompiler->apIfs[--iIf]; if (!pIfCore->pTrueEndJump) { /* Emit a jump instruction that will take us from the 'True' block to the 'endif'. */ PKMKCCEVALJUMP pInstr = (PKMKCCEVALJUMP)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr)); pInstr->Core.enmOpcode = kKmkCcEvalInstr_jump; pInstr->Core.iLine = pCompiler->iLine; pInstr->pNext = NULL; pIfCore->pTrueEndJump = pInstr; /* The next instruction is the first in the 'False' block of the current 'if'. Should this be an 'else if', this will be the 'if' instruction emitted below. */ pIfCore->pNextFalse = (PKMKCCEVALCORE)kmk_cc_block_get_next_ptr(*pCompiler->ppBlockTail); } else if (iIf == 0) kmk_cc_eval_fatal(pCompiler, pchWord, "2nd 'else' for 'if' at line %u", pIfCore->Core.iLine); else kmk_cc_eval_fatal(pCompiler, pchWord, "2nd 'else' in a row - missing 'endif' for 'if' at line %u?", pIfCore->Core.iLine); } else kmk_cc_eval_fatal(pCompiler, pchWord, "'else' without 'if'"); /* * Check for 'else ifxxx'. There can be nothing else following an else. */ KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); if (cchLeft) { if ( cchLeft > 2 && KMK_CC_WORD_COMP_CONST_2(pchWord, "if")) { pchWord += 2; cchLeft -= 2; if (KMK_CC_EVAL_WORD_COMP_IS_EOL(pCompiler, pchWord, cchLeft)) return kmk_cc_eval_do_if(pCompiler, pchWord, cchLeft, 1 /* in else */); if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "eq", 2)) return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 2, cchLeft - 2, 1 /* in else */, 1 /* positive */); if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "def", 3)) return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 3, cchLeft - 3, 1 /* in else */, 1 /* positive */); if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "neq", 3)) return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 3, cchLeft - 3, 1 /* in else */, 0 /* positive */); if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "1of", 3)) return kmk_cc_eval_do_if1of(pCompiler, pchWord + 3, cchLeft - 3, 1 /* in else */, 1 /* positive */); if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "ndef", 4)) return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 4, cchLeft - 4, 1 /* in else */, 0 /* positive */); if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "n1of", 4)) return kmk_cc_eval_do_if1of(pCompiler, pchWord + 4, cchLeft - 4, 1 /* in else */, 0 /* positive */); pchWord -= 2; cchLeft += 2; } kmk_cc_eval_fatal(pCompiler, pchWord, "Bogus stuff after 'else'"); } return 1; } /** * Deals with the 'endif' statement. * * @returns 1 to indicate we've handled a keyword (see * kmk_cc_eval_try_handle_keyword). * @param pCompiler The compiler state. * @param pchWord First char after 'define'. * @param cchLeft The number of chars left to parse on this line. */ static int kmk_cc_eval_do_endif(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft) { /* * There must be an 'if' on the stack. We'll POP it. */ unsigned iIf = pCompiler->cIfs; if (iIf > 0) { PKMKCCEVALCORE pNextInstr; PKMKCCEVALIFCORE pIfCore = pCompiler->apIfs[--iIf]; pCompiler->cIfs = iIf; /* POP! */ /* Update the jump targets for all IFs at this level. */ pNextInstr = (PKMKCCEVALCORE)kmk_cc_block_get_next_ptr(*pCompiler->ppBlockTail); do { if (pIfCore->pTrueEndJump) { /* Make the true block jump here, to the 'endif'. The false block is already here. */ pIfCore->pTrueEndJump->pNext = pNextInstr; KMK_CC_ASSERT(pIfCore->pNextFalse); } else { /* No 'else'. The false-case jump here, to the 'endif'. */ KMK_CC_ASSERT(!pIfCore->pNextFalse); pIfCore->pNextFalse = pNextInstr; } pIfCore = pIfCore->pPrevCond; } while (pIfCore); } else kmk_cc_eval_fatal(pCompiler, pchWord, "'endif' without 'if'"); /* * There shouldn't be anything trailing an 'endif'. */ KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); if (!cchLeft) { /* likely */ } else kmk_cc_eval_fatal(pCompiler, pchWord, "Bogus stuff after 'else'"); return 1; } /** * Parses a 'include file...', 'sinclude file...', '-include file...', * 'includedep file...', 'includedep-queue file...' and * 'includedep-flush file...' * * @returns 1 to indicate we've handled a keyword (see * kmk_cc_eval_try_handle_keyword). * @param pCompiler The compiler state. * @param pchWord First char after the include directive. * @param cchLeft The number of chars left to parse on this line. * @param enmOpcode The opcode for the include directive we're parsing. */ static int kmk_cc_eval_do_include(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, KMKCCEVALINSTR enmOpcode) { KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); if (cchLeft) { /* * Split what's left up into words. */ unsigned cWords = kmk_cc_eval_parse_words(pCompiler, pchWord, cchLeft); KMK_CC_EVAL_DPRINTF(("%s: cWords=%d\n", g_apszEvalInstrNms[enmOpcode], cWords)); if (cWords) { PKMKCCEVALINCLUDE pInstr = (PKMKCCEVALINCLUDE)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, KMKCCEVALINCLUDE_SIZE(cWords)); pInstr->Core.enmOpcode = enmOpcode; pInstr->Core.iLine = pCompiler->iLine; pInstr->cFiles = cWords; kmk_cc_eval_init_spp_array_from_duplicated_words(pCompiler, cWords, pCompiler->paWords, pInstr->aFiles); kmk_cc_block_realign(pCompiler->ppBlockTail); } else KMK_CC_ASSERT(0); } else KMK_CC_EVAL_DPRINTF(("%s: include without args\n", g_apszEvalInstrNms[enmOpcode])); return 1; } static int kmk_cc_eval_do_vpath(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft) { kmk_cc_eval_fatal(pCompiler, NULL, "vpath directive is not implemented\n"); return 1; } static void kmk_cc_eval_handle_command(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft) { kmk_cc_eval_fatal(pCompiler, pchWord, "command handling not implemented yet"); } static int kmk_cc_eval_handle_recipe_cont_colon(PKMKCCEVALCOMPILER pCompiler, const char *pchWord0, size_t cchWord0, const char *pchColon, size_t cchLeft, unsigned fQualifiers) { kmk_cc_eval_fatal(pCompiler, pchWord0, "recipe handling not implemented yet (#1)"); return 1; } static int kmk_cc_eval_handle_recipe_cont_2nd_word(PKMKCCEVALCOMPILER pCompiler, const char *pchWord0, size_t cchWord0, const char *pchWord, size_t cchLeft, unsigned fQualifiers) { kmk_cc_eval_fatal(pCompiler, pchWord, "recipe handling not implemented yet (#2)"); return 1; } static void kmk_cc_eval_handle_recipe(PKMKCCEVALCOMPILER pCompiler, const char *pszEqual, const char *pchWord, size_t cchLeft) { kmk_cc_eval_fatal(pCompiler, pchWord, "recipe handling not implemented yet (#3)"); } static void kmk_cc_eval_end_of_recipe(PKMKCCEVALCOMPILER pCompiler) { if (pCompiler->pRecipe) { /** @todo do stuff here. */ } } /** * Common worker for handling export (non-assign), undefine and unexport. * * For instructions using the KMKCCEVALVARIABLES structure. * * @returns 1 to indicate we've handled a keyword (see * kmk_cc_eval_try_handle_keyword). * @param pCompiler The compiler state. * @param pchWord First non-space chare after the keyword. * @param cchLeft The number of chars left to parse on this line. * @param fQualifiers The qualifiers. */ static int kmk_cc_eval_do_with_variable_list(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, KMKCCEVALINSTR enmOpcode, unsigned fQualifiers) { if (cchLeft) { /* * Parse the variable name list. GNU make is using normal word * handling here, so we can share code with the include directives. */ unsigned cWords = kmk_cc_eval_parse_words(pCompiler, pchWord, cchLeft); KMK_CC_EVAL_DPRINTF(("%s: cWords=%d\n", g_apszEvalInstrNms[enmOpcode], cWords)); if (cWords) { PKMKCCEVALVARIABLES pInstr = (PKMKCCEVALVARIABLES)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, KMKCCEVALVARIABLES_SIZE(cWords)); pInstr->Core.enmOpcode = enmOpcode; pInstr->Core.iLine = pCompiler->iLine; pInstr->cVars = cWords; kmk_cc_eval_init_spp_array_from_duplicated_words(pCompiler, cWords, pCompiler->paWords, pInstr->aVars); kmk_cc_block_realign(pCompiler->ppBlockTail); } else KMK_CC_ASSERT(0); } /* else: NOP */ return 1; } /** * Parses a '[qualifiers] undefine variable [..]' expression. * * A 'undefine' directive is final, any qualifiers must preceed it. So, we just * have to extract the variable names now. * * @returns 1 to indicate we've handled a keyword (see * kmk_cc_eval_try_handle_keyword). * @param pCompiler The compiler state. * @param pchWord First char after 'define'. * @param cchLeft The number of chars left to parse on this line. * @param fQualifiers The qualifiers. */ static int kmk_cc_eval_do_var_undefine(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, unsigned fQualifiers) { KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); if (!cchLeft) kmk_cc_eval_fatal(pCompiler, pchWord, "undefine requires a variable name"); /** @todo GNU make doesn't actually do the list thing for undefine, it seems * to assume everything after it is a single variable... Going with * simple common code for now. */ return kmk_cc_eval_do_with_variable_list(pCompiler, pchWord, cchLeft, kKmkCcEvalInstr_undefine, fQualifiers); } /** * Parses a '[qualifiers] unexport variable [..]' expression. * * A 'unexport' directive is final, any qualifiers must preceed it. So, we just * have to extract the variable names now. * * @returns 1 to indicate we've handled a keyword (see * kmk_cc_eval_try_handle_keyword). * @param pCompiler The compiler state. * @param pchWord First char after 'define'. * @param cchLeft The number of chars left to parse on this line. * @param fQualifiers The qualifiers. */ static int kmk_cc_eval_do_var_unexport(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, unsigned fQualifiers) { PKMKCCEVALCORE pInstr; /* * Join paths with undefine and export, unless it's an unexport all directive. */ KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); if (cchLeft) return kmk_cc_eval_do_with_variable_list(pCompiler, pchWord, cchLeft, kKmkCcEvalInstr_unexport, fQualifiers); /* * We're unexporting all variables. */ pInstr = kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr)); pInstr->enmOpcode = kKmkCcEvalInstr_unexport_all; pInstr->iLine = pCompiler->iLine; return 1; } /** * Parses a 'define variable' expression. * * A 'define' directive is final, any qualifiers must preceed it. So, we just * have to extract the variable name now, well and find the corresponding * 'endef'. * * @returns 1 to indicate we've handled a keyword (see * kmk_cc_eval_try_handle_keyword). * @param pCompiler The compiler state. * @param pchWord First char after 'define'. * @param cchLeft The number of chars left to parse on this line. * @param fQualifiers The qualifiers. */ static int kmk_cc_eval_do_var_define(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, unsigned fQualifiers) { KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); kmk_cc_eval_fatal(pCompiler, pchWord, "define handling not implemented yet"); return 1; } static int kmk_cc_eval_handle_assignment_or_recipe(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, unsigned fQualifiers) { /* * We're currently at a word which may or may not be a variable name * followed by an assignment operator, alternatively it must be a recipe. * We need to figure this out and deal with it in the most efficient * manner as this is a very common occurence. */ unsigned const iEscEolVarNm = pCompiler->iEscEol; int fPlainVarNm = 1; const char *pchVarNm = pchWord; size_t cchVarNm; size_t cch = 0; char ch; /* * The variable name. Complicate by there being no requirement of a space * preceeding the assignment operator, as well as that the variable name * may include variable references with spaces (function++) in them. */ for (;;) { if (cch < cchLeft) { /*likely*/ } else kmk_cc_eval_fatal(pCompiler, &pchWord[cch], "Neither recipe nor variable assignment"); ch = pchWord[cch]; if (!KMK_CC_EVAL_IS_SPACE_DOLLAR_SLASH_OR_ASSIGN(ch)) cch++; /* Space? */ else if (KMK_CC_EVAL_IS_SPACE(ch)) { cchVarNm = cch; pchWord += cch; cchLeft -= cch; KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); break; } /* Variable expansion may contain spaces, so handle specially. */ else if (ch == '$') { cch++; if (cch < cchLeft) { char const chOpen = pchWord[cch]; if (chOpen == '(' || chOpen == '{') { /* * Got a $(VAR) or ${VAR} to deal with here. This may * include nested variable references and span multiple * lines (at least for function calls). * * We scan forward till we've found the corresponding * closing parenthesis, considering any open parentheses * of the same kind as worth counting, even if there are * no dollar preceeding them, just like GNU make does. */ size_t const cchStart = cch - 1; char const chClose = chOpen == '(' ? ')' : '}'; unsigned cOpen = 1; cch++; for (;;) { if (cch < cchLeft) { ch = pchWord[cch]; if (!(KMK_CC_EVAL_IS_PAREN_OR_SLASH(ch))) cch++; else { cch++; if (ch == chClose) { if (--cOpen == 0) break; } else if (ch == chOpen) cOpen++; else if ( ch == '\\' && pCompiler->iEscEol < pCompiler->cEscEols && (size_t)(&pchWord[cch] - pCompiler->pszContent) == pCompiler->paEscEols[pCompiler->iEscEol].offEsc) { cch += pCompiler->paEscEols[pCompiler->iEscEol].offEol - pCompiler->paEscEols[pCompiler->iEscEol].offEsc + pCompiler->cchEolSeq; pCompiler->iEscEol++; } } } else if (cOpen == 1) kmk_cc_eval_fatal(pCompiler, &pchWord[cchStart], "Variable reference is missing '%c'", chClose); else kmk_cc_eval_fatal(pCompiler, &pchWord[cchStart], "%u variable references are missing '%c'", cOpen, chClose); } } /* Single char variable name. */ else if (!KMK_CC_EVAL_IS_SPACE(chOpen)) { /* likely */ } else kmk_cc_eval_fatal(pCompiler, &pchWord[cch], "Expected variable name after '$', not end of line"); } else kmk_cc_eval_fatal(pCompiler, &pchWord[cch], "Neither recipe nor variable assignment"); fPlainVarNm = 0; } /* Check out potential recipe. */ else if (ch == ':') { if ( cch + 1 < cchLeft && pchWord[cch + 1] != '=') { cchVarNm = cch; pchWord += cch; cchLeft -= cch; break; } #ifdef HAVE_DOS_PATHS /* Don't confuse the first colon in: C:/Windows/System32/Kernel32.dll: C:/Windows/System32/NtDll.dll for a recipe, it is only the second one which counts. */ else if ( cch == 1 && isalpha((unsigned char)pchWord[0])) cch++; #endif else return kmk_cc_eval_handle_recipe_cont_colon(pCompiler, pchWord, cch, pchWord + cch, cchLeft - cch, fQualifiers); } /* Check out assignment operator. */ else if (ch == '=') { if (cch) { char chPrev = pchWord[cch - 1]; if (chPrev == ':' || chPrev == '+' || chPrev == '?' || chPrev == '<') cch--; cchVarNm = cch; pchWord += cch; cchLeft -= cch; break; } else kmk_cc_eval_fatal(pCompiler, pchWord, "Empty variable name."); } /* Check out potential escaped EOL sequence. */ else if (ch == '\\') { unsigned const iEscEol = pCompiler->iEscEol; if (iEscEol >= pCompiler->cEscEols) cch++; else { size_t offCur = &pchWord[cch] - pCompiler->pszContent; if (offCur < pCompiler->paEscEols[iEscEol].offEol) cch++; else { cchVarNm = cch; KMK_CC_ASSERT(offCur == pCompiler->paEscEols[iEscEol].offEol); cch = pCompiler->paEscEols[iEscEol].offEol + pCompiler->cchEolSeq - offCur; pCompiler->iEscEol = iEscEol + 1; pchWord += cch; cchLeft -= cch; KMK_CC_EVAL_SKIP_SPACES(pCompiler, pchWord, cchLeft); break; } } } else KMK_CC_ASSERT(0); } /* * Check for assignment operator. */ if (cchLeft) { size_t cchValue; PKMKCCEVALASSIGN pInstr; KMKCCEVALINSTR enmOpCode; int fPlainValue; char *pszValue; ch = *pchWord; if (ch == '=') { enmOpCode = kKmkCcEvalInstr_assign_recursive; pchWord++; cchLeft--; } else if (cchLeft >= 2 && pchWord[1] == '=') { if (ch == ':') enmOpCode = kKmkCcEvalInstr_assign_simple; else if (ch == '+') enmOpCode = kKmkCcEvalInstr_assign_append; else if (ch == '<') enmOpCode = kKmkCcEvalInstr_assign_prepend; else if (ch == '?') enmOpCode = kKmkCcEvalInstr_assign_if_new; else return kmk_cc_eval_handle_recipe_cont_2nd_word(pCompiler, pchVarNm, cchVarNm, pchWord, cchLeft, fQualifiers); pchWord += 2; cchLeft -= 2; } else return kmk_cc_eval_handle_recipe_cont_2nd_word(pCompiler, pchVarNm, cchVarNm, pchWord, cchLeft, fQualifiers); /* * Skip leading spaces, if any and prep the value for copying. */ KMK_CC_EVAL_SKIP_SPACES(pCompiler, pchWord, cchLeft); cchValue = kmk_cc_eval_prep_normal_line(pCompiler, pchWord, cchLeft); fPlainValue = memchr(pchWord, '$', cchLeft) == NULL; /* * Emit the instruction. */ kmk_cc_eval_end_of_recipe(pCompiler); pInstr = (PKMKCCEVALASSIGN)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr)); pInstr->Core.enmOpcode = enmOpCode; pInstr->Core.iLine = pCompiler->iLine; pInstr->fExport = (fQualifiers & KMK_CC_EVAL_QUALIFIER_EXPORT) != 0; pInstr->fOverride = (fQualifiers & KMK_CC_EVAL_QUALIFIER_OVERRIDE) != 0; pInstr->fPrivate = (fQualifiers & KMK_CC_EVAL_QUALIFIER_PRIVATE) != 0; pInstr->fLocal = (fQualifiers & KMK_CC_EVAL_QUALIFIER_LOCAL) != 0; /* We copy the value before messing around with the variable name since we have to do more iEolEsc saves & restores the other way around. */ pszValue = kmk_cc_eval_strdup_prepped(pCompiler, cchValue); if (fPlainVarNm) pchVarNm = strcache2_add(&variable_strcache, pchVarNm, cchVarNm); else { pCompiler->iEscEol = iEscEolVarNm; cchVarNm = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchVarNm, cchVarNm); pchVarNm = kmk_cc_eval_strdup_prepped(pCompiler, cchVarNm); } kmk_cc_block_realign(pCompiler->ppBlockTail); KMK_CC_EVAL_DPRINTF(("%s: '%s' '%s'\n", g_apszEvalInstrNms[enmOpCode], pchVarNm, pszValue)); kmk_cc_eval_init_subprogram_or_plain(pCompiler, &pInstr->Variable, pchVarNm, cchVarNm, fPlainVarNm); kmk_cc_eval_init_subprogram_or_plain(pCompiler, &pInstr->Value, pszValue, cchValue, fPlainValue); pInstr->pNext = (PKMKCCEVALCORE)kmk_cc_block_get_next_ptr(*pCompiler->ppBlockTail); } else kmk_cc_eval_fatal(pCompiler, pchWord, "Neither recipe nor variable assignment"); return 1; } /** * Parses a 'local [override] variable = value', 'local define variable', and * 'local undefine variable [...]' expressions. * * The 'local' directive must be first and it does not permit any qualifiers at * the moment. Should any be added later, they will have to come after 'local'. * * @returns 1 to indicate we've handled a keyword (see * kmk_cc_eval_try_handle_keyword). * @param pCompiler The compiler state. * @param pchWord First char after 'local'. * @param cchLeft The number of chars left to parse on this line. * @param fQualifiers The qualifiers. */ static int kmk_cc_eval_do_var_local(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft) { KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); if (cchLeft) { /* * Check for 'local define' and 'local undefine' */ if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "define", 6)) /* final */ return kmk_cc_eval_do_var_define(pCompiler, pchWord + 6, cchLeft + 6, KMK_CC_EVAL_QUALIFIER_LOCAL); if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "undefine", 8)) /* final */ return kmk_cc_eval_do_var_undefine(pCompiler, pchWord + 8, cchLeft + 8, KMK_CC_EVAL_QUALIFIER_LOCAL); /* * Simpler to just join paths with the rest here, even if we could * probably optimize the parsing a little if we liked. */ return kmk_cc_eval_handle_assignment_or_recipe(pCompiler, pchWord, cchLeft, KMK_CC_EVAL_QUALIFIER_LOCAL); } kmk_cc_eval_fatal(pCompiler, pchWord, "Expected variable name, assignment operator and value after 'local'"); return 1; } /** * We've found one variable qualification keyword, now continue parsing and see * if this is some kind of variable assignment expression or not. * * @returns 1 if variable assignment, 0 if not. * @param pCompiler The compiler state. * @param pchWord First char after the first qualifier. * @param cchLeft The number of chars left to parse on this line. * @param fQualifiers The qualifier. */ static int kmk_cc_eval_try_handle_var_with_keywords(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, unsigned fQualifiers) { for (;;) { KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); if (cchLeft) { char ch = *pchWord; if (KMK_CC_EVAL_IS_1ST_IN_VARIABLE_KEYWORD(ch)) { if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "define", 6)) /* final */ return kmk_cc_eval_do_var_define(pCompiler, pchWord + 6, cchLeft - 6, fQualifiers); if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "undefine", 8)) /* final */ return kmk_cc_eval_do_var_undefine(pCompiler, pchWord + 8, cchLeft -86, fQualifiers); if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "unexport", 8)) /* final */ return kmk_cc_eval_do_var_unexport(pCompiler, pchWord + 8, cchLeft - 8, fQualifiers); if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "export", 6)) { if (!(fQualifiers & KMK_CC_EVAL_QUALIFIER_EXPORT)) fQualifiers |= KMK_CC_EVAL_QUALIFIER_EXPORT; else kmk_cc_eval_warn(pCompiler, pchWord, "'export' qualifier repeated"); pchWord += 6; cchLeft -= 6; continue; } if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "override", 8)) { if (!(fQualifiers & KMK_CC_EVAL_QUALIFIER_OVERRIDE)) fQualifiers |= KMK_CC_EVAL_QUALIFIER_OVERRIDE; else kmk_cc_eval_warn(pCompiler, pchWord, "'override' qualifier repeated"); pchWord += 8; cchLeft -= 8; continue; } if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "private", 7)) { if (!(fQualifiers & KMK_CC_EVAL_QUALIFIER_PRIVATE)) fQualifiers |= KMK_CC_EVAL_QUALIFIER_PRIVATE; else kmk_cc_eval_warn(pCompiler, pchWord, "'private' qualifier repeated"); pchWord += 7; cchLeft -= 7; continue; } } /* * Not a keyword, likely variable name followed by an assignment * operator and a value. Do a rough check for the assignment operator * and join paths with the unqualified assignment handling code. */ { const char *pchEqual = (const char *)memchr(pchWord, '=', cchLeft); if (pchEqual) return kmk_cc_eval_handle_assignment_or_recipe(pCompiler, pchWord, cchLeft, fQualifiers); } return 0; } else kmk_cc_eval_fatal(pCompiler, NULL, "Expected assignment operator or variable directive after variable qualifier(s)\n"); } } /** * Parses 'export [variable]' and 'export [qualifiers] variable = value' * expressions. * * When we find the 'export' directive at the start of a line, we need to * continue parsing with till we can tell the difference between the two forms. * * @returns 1 to indicate we've handled a keyword (see * kmk_cc_eval_try_handle_keyword). * @param pCompiler The compiler state. * @param pchWord First char after 'define'. * @param cchLeft The number of chars left to parse on this line. */ static int kmk_cc_eval_handle_var_export(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft) { KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); if (cchLeft) { unsigned iSavedEscEol; unsigned cWords; /* * We need to figure out whether this is an assignment or a export statement, * in the latter case join paths with 'export' and 'undefine'. */ const char *pchEqual = (const char *)memchr(pchWord, '=', cchLeft); if (!pchEqual) return kmk_cc_eval_do_with_variable_list(pCompiler, pchWord, cchLeft, kKmkCcEvalInstr_export, 0 /*fQualifiers*/); /* * Found an '=', could be an assignment. Let's take the easy way out * and just parse the whole statement into words like we would do if * it wasn't an assignment, and then check the words out for * assignment keywords and operators. */ iSavedEscEol = pCompiler->iEscEol; cWords = kmk_cc_eval_parse_words(pCompiler, pchWord, cchLeft); if (cWords) { PKMKCCEVALVARIABLES pInstr; PKMKCCEVALWORD pWord = pCompiler->paWords; unsigned iWord = 0; while (iWord < cWords) { /* Trailing assignment operator or terminal assignment directive ('undefine' and 'unexport' makes no sense here but GNU make ignores that). */ if ( ( pWord->cchWord > 1 && pWord->pchWord[pWord->cchWord - 1] == '=') || KMK_CC_STRCMP_CONST(pWord->pchWord, pWord->cchWord, "define", 6) || KMK_CC_STRCMP_CONST(pWord->pchWord, pWord->cchWord, "undefine", 8) || KMK_CC_STRCMP_CONST(pWord->pchWord, pWord->cchWord, "unexport", 8) ) { pCompiler->iEscEol = iSavedEscEol; return kmk_cc_eval_try_handle_var_with_keywords(pCompiler, pchWord, cchLeft, KMK_CC_EVAL_QUALIFIER_EXPORT); } /* If not a variable assignment qualifier, it must be a variable name followed by an assignment operator. */ if (iWord + 1 < cWords) { if ( !KMK_CC_STRCMP_CONST(pWord->pchWord, pWord->cchWord, "export", 6) && !KMK_CC_STRCMP_CONST(pWord->pchWord, pWord->cchWord, "private", 7) && !KMK_CC_STRCMP_CONST(pWord->pchWord, pWord->cchWord, "override", 8)) { pWord++; if ( pWord->cchWord > 0 && ( pWord->pchWord[0] == '=' || ( pWord->cchWord > 1 && pWord->pchWord[1] == '=' && ( pWord->pchWord[0] == ':' || pWord->pchWord[0] == '+' || pWord->pchWord[0] == '?' || pWord->pchWord[0] == '<') ) ) ) { pCompiler->iEscEol = iSavedEscEol; return kmk_cc_eval_try_handle_var_with_keywords(pCompiler, pchWord, cchLeft, KMK_CC_EVAL_QUALIFIER_EXPORT); } break; } } else break; /* next */ pWord++; iWord++; } /* * It's not an assignment. * (This is the same as kmk_cc_eval_do_with_variable_list does.) */ pInstr = (PKMKCCEVALVARIABLES)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, KMKCCEVALVARIABLES_SIZE(cWords)); pInstr->Core.enmOpcode = kKmkCcEvalInstr_export; pInstr->Core.iLine = pCompiler->iLine; pInstr->cVars = cWords; kmk_cc_eval_init_spp_array_from_duplicated_words(pCompiler, cWords, pCompiler->paWords, pInstr->aVars); kmk_cc_block_realign(pCompiler->ppBlockTail); } else KMK_CC_ASSERT(0); } else { /* * We're exporting all variables. */ PKMKCCEVALCORE pInstr = kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr)); pInstr->enmOpcode = kKmkCcEvalInstr_export_all; pInstr->iLine = pCompiler->iLine; } return 1; } /** * When entering this function we know that the first two character in the first * word both independently occurs in keywords. * * @returns 1 if make directive or qualified variable assignment, 0 if neither. * @param pCompiler The compiler state. * @param ch The first char. * @param pchWord Pointer to the first word. * @param cchLeft Number of characters left to parse starting at * @a cchLeft. */ int kmk_cc_eval_try_handle_keyword(PKMKCCEVALCOMPILER pCompiler, char ch, const char *pchWord, size_t cchLeft) { unsigned iSavedEscEol = pCompiler->iEscEol; KMK_CC_ASSERT(cchLeft >= 2); KMK_CC_ASSERT(ch == pchWord[0]); KMK_CC_ASSERT(KMK_CC_EVAL_IS_1ST_IN_KEYWORD(pchWord[0])); KMK_CC_ASSERT(KMK_CC_EVAL_IS_2ND_IN_KEYWORD(pchWord[1])); /* * If it's potentially a variable related keyword, check that out first. */ if (KMK_CC_EVAL_IS_1ST_IN_VARIABLE_KEYWORD(ch)) { if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "local", 5)) return kmk_cc_eval_do_var_local(pCompiler, pchWord + 5, cchLeft - 5); if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "define", 6)) return kmk_cc_eval_do_var_define(pCompiler, pchWord + 6, cchLeft - 6, 0); if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "export", 6)) return kmk_cc_eval_handle_var_export(pCompiler, pchWord + 6, cchLeft - 6); if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "undefine", 8)) return kmk_cc_eval_do_var_undefine(pCompiler, pchWord + 8, cchLeft - 8, 0); if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "unexport", 8)) return kmk_cc_eval_do_var_unexport(pCompiler, pchWord + 8, cchLeft - 8, 0); if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "override", 8)) { if (kmk_cc_eval_try_handle_var_with_keywords(pCompiler, pchWord + 8, cchLeft - 8, KMK_CC_EVAL_QUALIFIER_OVERRIDE)) return 1; pCompiler->iEscEol = iSavedEscEol; } else if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "private", 7)) { if (kmk_cc_eval_try_handle_var_with_keywords(pCompiler, pchWord + 7, cchLeft - 7, KMK_CC_EVAL_QUALIFIER_PRIVATE)) return 1; pCompiler->iEscEol = iSavedEscEol; } } /* * Check out the other keywords. */ if (ch == 'i') /* Lots of directives starting with 'i'. */ { char ch2 = pchWord[1]; pchWord += 2; cchLeft -= 2; /* 'if...' */ if (ch2 == 'f') { if (KMK_CC_EVAL_WORD_COMP_IS_EOL(pCompiler, pchWord, cchLeft)) return kmk_cc_eval_do_if(pCompiler, pchWord, cchLeft, 0 /* in else */); if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "eq", 2)) return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 2, cchLeft - 2, 0 /* in else */, 1 /* positive */); if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "def", 3)) return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 3, cchLeft - 3, 0 /* in else */, 1 /* positive */); if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "neq", 3)) return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 3, cchLeft - 3, 0 /* in else */, 0 /* positive */); if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "1of", 3)) return kmk_cc_eval_do_if1of(pCompiler, pchWord + 3, cchLeft - 3, 0 /* in else */, 1 /* positive */); if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "ndef", 4)) return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 4, cchLeft - 4, 0 /* in else */, 0 /* positive */); if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "n1of", 4)) return kmk_cc_eval_do_if1of(pCompiler, pchWord + 4, cchLeft - 4, 0 /* in else */, 0 /* positive */); } /* include... */ else if (ch2 == 'n' && cchLeft >= 5 && KMK_CC_WORD_COMP_CONST_5(pchWord, "clude") ) /* 'in...' */ { pchWord += 5; cchLeft -= 5; if (KMK_CC_EVAL_WORD_COMP_IS_EOL(pCompiler, pchWord, cchLeft)) return kmk_cc_eval_do_include(pCompiler, pchWord, cchLeft, kKmkCcEvalInstr_include); if (cchLeft >= 3 && KMK_CC_WORD_COMP_CONST_3(pchWord, "dep")) { pchWord += 3; cchLeft -= 3; if (KMK_CC_EVAL_WORD_COMP_IS_EOL(pCompiler, pchWord, cchLeft)) return kmk_cc_eval_do_include(pCompiler, pchWord, cchLeft, kKmkCcEvalInstr_includedep); if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "-queue", 6)) return kmk_cc_eval_do_include(pCompiler, pchWord + 6, cchLeft - 6, kKmkCcEvalInstr_includedep_queue); if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "-flush", 6)) return kmk_cc_eval_do_include(pCompiler, pchWord + 6, cchLeft - 6, kKmkCcEvalInstr_includedep_flush); } } } else if (ch == 'e') /* A few directives starts with 'e'. */ { if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "else", 4)) return kmk_cc_eval_do_else(pCompiler, pchWord + 4, cchLeft - 4); if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "endif", 5)) return kmk_cc_eval_do_endif(pCompiler, pchWord + 5, cchLeft - 5); /* export and endef are handled elsewhere, though stray endef's may end up here... */ KMK_CC_ASSERT(!KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "export", 6)); } else /* the rest. */ { if ( KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "sinclude", 8) || KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "-include", 8)) return kmk_cc_eval_do_include(pCompiler, pchWord + 8, cchLeft - 8, kKmkCcEvalInstr_include_silent); if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "vpath", 5)) return kmk_cc_eval_do_vpath(pCompiler, pchWord + 5, cchLeft - 5); KMK_CC_ASSERT(!KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "local", 5)); KMK_CC_ASSERT(!KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "define", 6)); KMK_CC_ASSERT(!KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "private", 7)); KMK_CC_ASSERT(!KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "override", 8)); KMK_CC_ASSERT(!KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "unexport", 8)); KMK_CC_ASSERT(!KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "undefine", 8)); } pCompiler->iEscEol = iSavedEscEol; return 0; } static int kmk_cc_eval_compile_worker(PKMKCCEVALPROG pEvalProg, const char *pszContent, size_t cchContent, unsigned iLine) { const char *pchTmp; /* * Compiler state. */ KMKCCEVALCOMPILER Compiler; kmk_cc_eval_init_compiler(&Compiler, pEvalProg, iLine, pszContent, cchContent); KMK_CC_EVAL_DPRINTF(("\nkmk_cc_eval_compile_worker - begin (%s/%s/%d)\n", pEvalProg->pszFilename, pEvalProg->pszVarName, iLine)); { /* * Line state. */ size_t cchLine; /* The length of the current line (w/o comments). */ size_t offNext = 0; /* The offset of the next line. */ size_t off = 0; /* The offset into pszContent of the current line. */ /* Try for some register/whatever optimzations. */ int const chFirstEol = Compiler.chFirstEol; size_t const cchEolSeq = Compiler.cchEolSeq; /* * Process input lines. * * The code here concerns itself with getting the next line in an efficient * manner, very basic classification and trying out corresponding handlers. * The real work is done in the handlers. */ while (offNext < cchContent) { size_t offFirstWord; /* * Find the end of the next line. */ KMK_CC_ASSERT(off == offNext); /* Simple case: No escaped EOL, nor the end of the input. */ pchTmp = (const char *)memchr(&pszContent[offNext], chFirstEol, cchContent - offNext); if ( pchTmp && ( &pszContent[offNext] == pchTmp || pchTmp[-1] != '\\') ) { if ( cchEolSeq == 1 || pchTmp[1] == Compiler.chSecondEol) { /* Frequent: Blank line. */ if (&pszContent[offNext] == pchTmp) { KMK_CC_EVAL_DPRINTF(("#%03u: \n", Compiler.iLine)); Compiler.iLine++; off = offNext += cchEolSeq; continue; } if (pszContent[offNext] == '#') { KMK_CC_EVAL_DPRINTF(("#%03u: \n", Compiler.iLine)); Compiler.iLine++; offNext = pchTmp - pszContent; off = offNext += cchEolSeq; continue; } offNext = pchTmp - pszContent; cchLine = offNext - off; offFirstWord = off; while (offFirstWord < offNext && KMK_CC_EVAL_IS_SPACE(pszContent[offFirstWord])) offFirstWord++; offNext += cchEolSeq; Compiler.cEscEols = 0; Compiler.iEscEol = 0; } else kmk_cc_eval_fatal_eol(&Compiler, pchTmp, Compiler.iLine, off); } /* The complicated, less common cases. */ else { Compiler.cEscEols = 0; Compiler.iEscEol = 0; offFirstWord = offNext; for (;;) { if (offFirstWord == offNext) { size_t offEol = off + cchLine; while (offFirstWord < offEol && KMK_CC_EVAL_IS_SPACE(pszContent[offFirstWord])) offFirstWord++; } if (pchTmp) { if ( cchEolSeq == 1 || pchTmp[1] == Compiler.chSecondEol) { size_t offEsc; if (offFirstWord != offNext) offNext = pchTmp - pszContent; else { offNext = pchTmp - pszContent; while (offFirstWord < offNext && KMK_CC_EVAL_IS_SPACE(pszContent[offFirstWord])) offFirstWord++; } /* Is it an escape sequence? */ if ( !offNext || pchTmp[-1] != '\\') { cchLine = offNext - off; offNext += cchEolSeq; break; } if (offNext < 2 || pchTmp[-2] != '\\') offEsc = offNext - 1; else { /* Count how many backslashes there are. Must be odd number to be an escape sequence. Normally we keep half of them, except for command lines. */ size_t cSlashes = 2; while (offNext >= cSlashes && pchTmp[0 - cSlashes] == '\\') cSlashes--; if (!(cSlashes & 1)) { cchLine = offNext - off; offNext += cchEolSeq; break; } offEsc = offNext - (cSlashes >> 1); } /* Record it. */ if (Compiler.cEscEols < Compiler.cEscEolsAllocated) { /* likely */ } else { KMK_CC_ASSERT(Compiler.cEscEols == Compiler.cEscEolsAllocated); Compiler.cEscEolsAllocated = Compiler.cEscEolsAllocated ? Compiler.cEscEolsAllocated * 2 : 2; Compiler.paEscEols = (PKMKCCEVALESCEOL)xrealloc(Compiler.paEscEols, Compiler.cEscEolsAllocated * sizeof(Compiler.paEscEols[0])); } Compiler.paEscEols[Compiler.cEscEols].offEsc = offEsc; Compiler.paEscEols[Compiler.cEscEols].offEol = offNext; Compiler.cEscEols++; /* Advance. */ offNext += cchEolSeq; if (offFirstWord == offEsc) { offFirstWord = offNext; Compiler.iEscEol++; } } else kmk_cc_eval_fatal_eol(&Compiler, pchTmp, Compiler.iLine, off); } else { /* End of input. Happens only once per compilation, nothing to optimize for. */ if (offFirstWord == offNext) while (offFirstWord < cchContent && KMK_CC_EVAL_IS_SPACE(pszContent[offFirstWord])) offFirstWord++; offNext = cchContent; cchLine = cchContent - off; break; } pchTmp = (const char *)memchr(&pszContent[offNext], chFirstEol, cchContent - offNext); } } KMK_CC_ASSERT(offNext <= cchContent); KMK_CC_ASSERT(offNext >= off + cchLine); KMK_CC_ASSERT(off + cchLine <= cchContent && cchLine <= cchContent); KMK_CC_ASSERT(offFirstWord <= off + cchLine); KMK_CC_ASSERT(offFirstWord >= off); KMK_CC_ASSERT(pszContent[offFirstWord] != ' ' && pszContent[offFirstWord] != '\t'); KMK_CC_EVAL_DPRINTF(("#%03u: %*.*s\n", Compiler.iLine, (int)cchLine, (int)cchLine, &pszContent[off])); /* * Skip blank lines. */ if (offFirstWord < off + cchLine) { /* * Command? Ignore command prefix if no open recipe (SunOS 4 behavior). */ if ( pszContent[off] == Compiler.chCmdPrefix && (Compiler.pRecipe || Compiler.fNoTargetRecipe)) { if (!Compiler.fNoTargetRecipe) kmk_cc_eval_handle_command(&Compiler, &pszContent[off], cchLine); } /* * Since it's not a command line, we can now skip comment lines * even with a tab indentation. If it's not a comment line, we * tentatively strip any trailing comment. */ else if (pszContent[offFirstWord] != '#') { const char *pchWord = &pszContent[offFirstWord]; size_t cchLeft = off + cchLine - offFirstWord; char ch; Compiler.cchLineWithComments = cchLine; pchTmp = (const char *)memchr(pchWord, '#', cchLeft); if (pchTmp) { cchLeft = pchTmp - pchWord; cchLine = pchTmp - &pszContent[off]; } Compiler.cchLine = cchLine; Compiler.offLine = off; /* * If not a directive or variable qualifier, it's either a variable * assignment or a recipe. */ ch = *pchWord; if ( !KMK_CC_EVAL_IS_1ST_IN_KEYWORD(ch) || !KMK_CC_EVAL_IS_2ND_IN_KEYWORD(pchWord[1]) || !kmk_cc_eval_try_handle_keyword(&Compiler, ch, pchWord, cchLeft) ) { pchTmp = (const char *)memchr(pchWord, '=', cchLeft); if (pchTmp) kmk_cc_eval_handle_assignment_or_recipe(&Compiler, pchWord, cchLeft, 0 /*fQualifiers*/); else kmk_cc_eval_handle_recipe(&Compiler, pchTmp, pchWord, cchLeft); } /* else: handled a keyword expression */ } } /* * Advance to the next line. */ off = offNext; Compiler.iLine += Compiler.cEscEols + 1; } } /* * Check whether */ kmk_cc_eval_delete_compiler(&Compiler); KMK_CC_EVAL_DPRINTF(("kmk_cc_eval_compile_worker - done (%s/%s)\n\n", pEvalProg->pszFilename, pEvalProg->pszVarName)); return 0; } static PKMKCCEVALPROG kmk_cc_eval_compile(const char *pszContent, size_t cchContent, const char *pszFilename, unsigned iLine, const char *pszVarName) { /* * Estimate block size, allocate one and initialize it. */ PKMKCCEVALPROG pEvalProg; PKMKCCBLOCK pBlock; pEvalProg = kmk_cc_block_alloc_first(&pBlock, sizeof(*pEvalProg), cchContent / 32); /** @todo adjust */ if (pEvalProg) { pEvalProg->pBlockTail = pBlock; pEvalProg->pFirstInstr = (PKMKCCEVALCORE)kmk_cc_block_get_next_ptr(pBlock); pEvalProg->pszFilename = pszFilename ? pszFilename : ""; pEvalProg->pszVarName = pszVarName; pEvalProg->cRefs = 1; #ifdef KMK_CC_STRICT pEvalProg->uInputHash = kmk_cc_debug_string_hash_n(0, pszContent, cchContent); #endif /* * Do the actual compiling. */ #ifdef CONFIG_WITH_EVAL_COMPILER if (kmk_cc_eval_compile_worker(pEvalProg, pszContent, cchContent, iLine) == 0) #else if (0) #endif { #ifdef KMK_CC_WITH_STATS pBlock = pEvalProg->pBlockTail; if (!pBlock->pNext) g_cSingleBlockEvalProgs++; else if (!pBlock->pNext->pNext) g_cTwoBlockEvalProgs++; else g_cMultiBlockEvalProgs++; for (; pBlock; pBlock = pBlock->pNext) { g_cBlocksAllocatedEvalProgs++; g_cbAllocatedEvalProgs += pBlock->cbBlock; g_cbUnusedMemEvalProgs += pBlock->cbBlock - pBlock->offNext; } #endif return pEvalProg; } kmk_cc_block_free_list(pEvalProg->pBlockTail); } return NULL; } /** * Compiles a variable direct evaluation as is, setting v->evalprog on success. * * @returns Pointer to the program on success, NULL if no program was created. * @param pVar Pointer to the variable. */ struct kmk_cc_evalprog *kmk_cc_compile_variable_for_eval(struct variable *pVar) { PKMKCCEVALPROG pEvalProg = pVar->evalprog; if (!pEvalProg) { #ifdef CONFIG_WITH_EVAL_COMPILER pEvalProg = kmk_cc_eval_compile(pVar->value, pVar->value_length, pVar->fileinfo.filenm, pVar->fileinfo.lineno, pVar->name); pVar->evalprog = pEvalProg; #endif g_cVarForEvalCompilations++; } return pEvalProg; } /** * Compiles a makefile for * * @returns Pointer to the program on success, NULL if no program was created. * @param pVar Pointer to the variable. */ struct kmk_cc_evalprog *kmk_cc_compile_file_for_eval(FILE *pFile, const char *pszFilename) { PKMKCCEVALPROG pEvalProg; /* * Read the entire file into a zero terminate memory buffer. */ size_t cchContent = 0; char *pszContent = NULL; struct stat st; if (!fstat(fileno(pFile), &st)) { if ( st.st_size > (off_t)16*1024*1024 && st.st_size < 0) fatal(NULL, _("Makefile too large to compile: %ld bytes (%#lx) - max 16MB"), (long)st.st_size, (long)st.st_size); cchContent = (size_t)st.st_size; pszContent = (char *)xmalloc(cchContent + 1); cchContent = fread(pszContent, 1, cchContent, pFile); if (ferror(pFile)) fatal(NULL, _("Read error: %s"), strerror(errno)); } else { size_t cbAllocated = 2048; do { cbAllocated *= 2; if (cbAllocated > 16*1024*1024) fatal(NULL, _("Makefile too large to compile: max 16MB")); pszContent = (char *)xrealloc(pszContent, cbAllocated); cchContent += fread(&pszContent[cchContent], 1, cbAllocated - 1 - cchContent, pFile); if (ferror(pFile)) fatal(NULL, _("Read error: %s"), strerror(errno)); } while (!feof(pFile)); } pszContent[cchContent] = '\0'; /* * Call common function to do the compilation. */ pEvalProg = kmk_cc_eval_compile(pszContent, cchContent, pszFilename, 1, NULL /*pszVarName*/); g_cFileForEvalCompilations++; free(pszContent); if (!pEvalProg) fseek(pFile, 0, SEEK_SET); return pEvalProg; } /** * Equivalent of eval_buffer, only it's using the evalprog of the variable. * * @param pVar Pointer to the variable. Must have a program. */ void kmk_exec_eval_variable(struct variable *pVar) { KMK_CC_ASSERT(pVar->evalprog); assert(0); } /** * Worker for eval_makefile. * * @param pEvalProg The program pointer. */ void kmk_exec_eval_file(struct kmk_cc_evalprog *pEvalProg) { KMK_CC_ASSERT(pEvalProg); assert(0); } /* * * Program destruction hooks. * Program destruction hooks. * Program destruction hooks. * */ /** * Called when a variable with expandprog or/and evalprog changes. * * @param pVar Pointer to the variable. */ void kmk_cc_variable_changed(struct variable *pVar) { PKMKCCEXPPROG pProg = pVar->expandprog; KMK_CC_ASSERT(pVar->evalprog || pProg); if (pVar->evalprog) { kmk_cc_block_free_list(pVar->evalprog->pBlockTail); pVar->evalprog = NULL; } if (pProg) { if (pProg->cRefs == 1) kmk_cc_block_free_list(pProg->pBlockTail); else fatal(NULL, _("Modifying a variable (%s) while its expansion program is running is not supported"), pVar->name); pVar->expandprog = NULL; } } /** * Called when a variable with expandprog or/and evalprog is deleted. * * @param pVar Pointer to the variable. */ void kmk_cc_variable_deleted(struct variable *pVar) { PKMKCCEXPPROG pProg = pVar->expandprog; KMK_CC_ASSERT(pVar->evalprog || pProg); if (pVar->evalprog) { kmk_cc_block_free_list(pVar->evalprog->pBlockTail); pVar->evalprog = NULL; } if (pProg) { if (pProg->cRefs == 1) kmk_cc_block_free_list(pProg->pBlockTail); else fatal(NULL, _("Deleting a variable (%s) while its expansion program is running is not supported"), pVar->name); pVar->expandprog = NULL; } } #endif /* CONFIG_WITH_COMPILER */ kbuild-3149/src/kmk/main.c0000644000175000017500000040263113252530176015357 0ustar locutuslocutus/* Argument parsing and main program of GNU Make. Copyright (C) 1988-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" #include "os.h" #include "filedef.h" #include "dep.h" #include "variable.h" #include "job.h" #include "commands.h" #include "rule.h" #include "debug.h" #include "getopt.h" #ifdef KMK # include "kbuild.h" #endif #include #ifdef _AMIGA # include # include #endif #ifdef WINDOWS32 # include # include # include "pathstuff.h" # include "sub_proc.h" # include "w32err.h" #endif #ifdef __EMX__ # include # include #endif #ifdef HAVE_FCNTL_H # include #endif #ifdef CONFIG_WITH_COMPILER # include "kmk_cc_exec.h" #endif #ifdef KMK /* for get_online_cpu_count */ # if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) # include # endif # ifdef __OS2__ # define INCL_BASE # include # endif # ifdef __HAIKU__ # include # endif #endif /* KMK*/ #if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) # define SET_STACK_SIZE #endif #ifdef SET_STACK_SIZE # include #endif #ifdef _AMIGA int __stack = 20000; /* Make sure we have 20K of stack space */ #endif #ifdef VMS int vms_use_mcr_command = 0; int vms_always_use_cmd_file = 0; int vms_gnv_shell = 0; int vms_legacy_behavior = 0; int vms_comma_separator = 0; int vms_unix_simulation = 0; int vms_report_unix_paths = 0; /* Evaluates if a VMS environment option is set, only look at first character */ static int get_vms_env_flag (const char *name, int default_value) { char * value; char x; value = getenv (name); if (value == NULL) return default_value; x = toupper (value[0]); switch (x) { case '1': case 'T': case 'E': return 1; break; case '0': case 'F': case 'D': return 0; } } #endif #ifdef CONFIG_WITH_PRINT_STATS_SWITCH void print_variable_stats (void); void print_dir_stats (void); void print_file_stats (void); #endif #if defined HAVE_WAITPID || defined HAVE_WAIT3 # define HAVE_WAIT_NOHANG #endif #if !defined(HAVE_UNISTD_H) && !defined(_MSC_VER) /* bird */ int chdir (); #endif #ifndef STDC_HEADERS # ifndef sun /* Sun has an incorrect decl in a header. */ void exit (int) __attribute__ ((noreturn)); # endif double atof (); #endif static void clean_jobserver (int status); static void print_data_base (void); static void print_version (void); static void decode_switches (int argc, const char **argv, int env); static void decode_env_switches (const char *envar, unsigned int len); static struct variable *define_makeflags (int all, int makefile); static char *quote_for_env (char *out, const char *in); static void initialize_global_hash_tables (void); /* The structure that describes an accepted command switch. */ struct command_switch { int c; /* The switch character. */ enum /* Type of the value. */ { flag, /* Turn int flag on. */ flag_off, /* Turn int flag off. */ string, /* One string per invocation. */ strlist, /* One string per switch. */ filename, /* A string containing a file name. */ positive_int, /* A positive integer. */ floating, /* A floating-point number (double). */ ignore /* Ignored. */ } type; void *value_ptr; /* Pointer to the value-holding variable. */ unsigned int env:1; /* Can come from MAKEFLAGS. */ unsigned int toenv:1; /* Should be put in MAKEFLAGS. */ unsigned int no_makefile:1; /* Don't propagate when remaking makefiles. */ const void *noarg_value; /* Pointer to value used if no arg given. */ const void *default_value; /* Pointer to default value. */ const char *long_name; /* Long option name. */ }; /* True if C is a switch value that corresponds to a short option. */ #define short_option(c) ((c) <= CHAR_MAX) /* The structure used to hold the list of strings given in command switches of a type that takes strlist arguments. */ struct stringlist { const char **list; /* Nil-terminated list of strings. */ unsigned int idx; /* Index into above. */ unsigned int max; /* Number of pointers allocated. */ }; /* The recognized command switches. */ /* Nonzero means do extra verification (that may slow things down). */ int verify_flag; /* Nonzero means do not print commands to be executed (-s). */ int silent_flag; /* Nonzero means just touch the files that would appear to need remaking (-t) */ int touch_flag; /* Nonzero means just print what commands would need to be executed, don't actually execute them (-n). */ int just_print_flag; #ifdef CONFIG_PRETTY_COMMAND_PRINTING /* Nonzero means to print commands argument for argument skipping blanks. */ int pretty_command_printing; #endif #ifdef CONFIG_WITH_PRINT_STATS_SWITCH /* Nonzero means to print internal statistics before exiting. */ int print_stats_flag; #endif #ifdef CONFIG_WITH_PRINT_TIME_SWITCH /* Minimum number of seconds to report, -1 if disabled. */ int print_time_min = -1; static int default_print_time_min = -1; static int no_val_print_time_min = 0; static big_int make_start_ts = -1; int print_time_width = 5; #endif /* Print debugging info (--debug). */ static struct stringlist *db_flags = 0; static int debug_flag = 0; int db_level = 0; /* Synchronize output (--output-sync). */ char *output_sync_option = 0; #ifdef WINDOWS32 /* Suspend make in main for a short time to allow debugger to attach */ int suspend_flag = 0; #endif /* Environment variables override makefile definitions. */ int env_overrides = 0; /* Nonzero means ignore status codes returned by commands executed to remake files. Just treat them all as successful (-i). */ int ignore_errors_flag = 0; /* Nonzero means don't remake anything, just print the data base that results from reading the makefile (-p). */ int print_data_base_flag = 0; /* Nonzero means don't remake anything; just return a nonzero status if the specified targets are not up to date (-q). */ int question_flag = 0; /* Nonzero means do not use any of the builtin rules (-r) / variables (-R). */ int no_builtin_rules_flag = 0; int no_builtin_variables_flag = 0; /* Nonzero means keep going even if remaking some file fails (-k). */ int keep_going_flag; int default_keep_going_flag = 0; /* Nonzero means check symlink mtimes. */ int check_symlink_flag = 0; /* Nonzero means print directory before starting and when done (-w). */ int print_directory_flag = 0; /* Nonzero means ignore print_directory_flag and never print the directory. This is necessary because print_directory_flag is set implicitly. */ int inhibit_print_directory_flag = 0; /* Nonzero means print version information. */ int print_version_flag = 0; /* List of makefiles given with -f switches. */ static struct stringlist *makefiles = 0; /* Size of the stack when we started. */ #ifdef SET_STACK_SIZE struct rlimit stack_limit; #endif /* Number of job slots for parallelism. */ unsigned int job_slots; #define INVALID_JOB_SLOTS (-1) static unsigned int master_job_slots = 0; static int arg_job_slots = INVALID_JOB_SLOTS; #ifdef KMK static int default_job_slots = INVALID_JOB_SLOTS; #else static const int default_job_slots = INVALID_JOB_SLOTS; #endif /* Value of job_slots that means no limit. */ static const int inf_jobs = 0; /* Authorization for the jobserver. */ static char *jobserver_auth = NULL; /* Handle for the mutex used on Windows to synchronize output of our children under -O. */ char *sync_mutex = NULL; /* Maximum load average at which multiple jobs will be run. Negative values mean unlimited, while zero means limit to zero load (which could be useful to start infinite jobs remotely but one at a time locally). */ #ifndef NO_FLOAT double max_load_average = -1.0; double default_load_average = -1.0; #else int max_load_average = -1; int default_load_average = -1; #endif /* List of directories given with -C switches. */ static struct stringlist *directories = 0; /* List of include directories given with -I switches. */ static struct stringlist *include_directories = 0; /* List of files given with -o switches. */ static struct stringlist *old_files = 0; /* List of files given with -W switches. */ static struct stringlist *new_files = 0; /* List of strings to be eval'd. */ static struct stringlist *eval_strings = 0; /* If nonzero, we should just print usage and exit. */ static int print_usage_flag = 0; /* If nonzero, we should print a warning message for each reference to an undefined variable. */ int warn_undefined_variables_flag; /* If nonzero, always build all targets, regardless of whether they appear out of date or not. */ static int always_make_set = 0; int always_make_flag = 0; /* If nonzero, we're in the "try to rebuild makefiles" phase. */ int rebuilding_makefiles = 0; /* Remember the original value of the SHELL variable, from the environment. */ struct variable shell_var; /* This character introduces a command: it's the first char on the line. */ char cmd_prefix = '\t'; #ifdef KMK /* Process priority. 0 = no change; 1 = idle / max nice; 2 = below normal / nice 10; 3 = normal / nice 0; 4 = high / nice -10; 5 = realtime / nice -19; */ int process_priority = 0; /* Process affinity mask; 0 means any CPU. */ int process_affinity = 0; #endif /* KMK */ #if defined (CONFIG_WITH_MAKE_STATS) || defined (CONFIG_WITH_MINIMAL_STATS) /* When set, we'll gather expensive statistics like for the heap. */ int make_expensive_statistics = 0; #endif /* The usage output. We write it this way to make life easier for the translators, especially those trying to translate to right-to-left languages like Hebrew. */ static const char *const usage[] = { N_("Options:\n"), N_("\ -b, -m Ignored for compatibility.\n"), N_("\ -B, --always-make Unconditionally make all targets.\n"), N_("\ -C DIRECTORY, --directory=DIRECTORY\n\ Change to DIRECTORY before doing anything.\n"), N_("\ -d Print lots of debugging information.\n"), N_("\ --debug[=FLAGS] Print various types of debugging information.\n"), N_("\ -e, --environment-overrides\n\ Environment variables override makefiles.\n"), N_("\ --eval=STRING Evaluate STRING as a makefile statement.\n"), N_("\ -f FILE, --file=FILE, --makefile=FILE\n\ Read FILE as a makefile.\n"), N_("\ -h, --help Print this message and exit.\n"), N_("\ -i, --ignore-errors Ignore errors from recipes.\n"), N_("\ -I DIRECTORY, --include-dir=DIRECTORY\n\ Search DIRECTORY for included makefiles.\n"), #ifdef KMK N_("\ -j [N], --jobs[=N] Allow N jobs at once; infinite jobs with no arg.\n\ The default is the number of active CPUs.\n"), #else N_("\ -j [N], --jobs[=N] Allow N jobs at once; infinite jobs with no arg.\n"), #endif N_("\ -k, --keep-going Keep going when some targets can't be made.\n"), N_("\ -l [N], --load-average[=N], --max-load[=N]\n\ Don't start multiple jobs unless load is below N.\n"), N_("\ -L, --check-symlink-times Use the latest mtime between symlinks and target.\n"), N_("\ -n, --just-print, --dry-run, --recon\n\ Don't actually run any recipe; just print them.\n"), N_("\ -o FILE, --old-file=FILE, --assume-old=FILE\n\ Consider FILE to be very old and don't remake it.\n"), N_("\ -O[TYPE], --output-sync[=TYPE]\n\ Synchronize output of parallel jobs by TYPE.\n"), N_("\ -p, --print-data-base Print make's internal database.\n"), N_("\ -q, --question Run no recipe; exit status says if up to date.\n"), N_("\ -r, --no-builtin-rules Disable the built-in implicit rules.\n"), N_("\ -R, --no-builtin-variables Disable the built-in variable settings.\n"), N_("\ -s, --silent, --quiet Don't echo recipes.\n"), N_("\ -S, --no-keep-going, --stop\n\ Turns off -k.\n"), N_("\ -t, --touch Touch targets instead of remaking them.\n"), N_("\ --trace Print tracing information.\n"), N_("\ -v, --version Print the version number of make and exit.\n"), N_("\ -w, --print-directory Print the current directory.\n"), N_("\ --no-print-directory Turn off -w, even if it was turned on implicitly.\n"), N_("\ -W FILE, --what-if=FILE, --new-file=FILE, --assume-new=FILE\n\ Consider FILE to be infinitely new.\n"), N_("\ --warn-undefined-variables Warn when an undefined variable is referenced.\n"), #ifdef KMK N_("\ --affinity=mask Sets the CPU affinity on some hosts.\n"), N_("\ --priority=1-5 Sets the process priority / nice level:\n\ 1 = idle / max nice;\n\ 2 = below normal / nice 10;\n\ 3 = normal / nice 0;\n\ 4 = high / nice -10;\n\ 5 = realtime / nice -19;\n"), N_("\ --nice Alias for --priority=1\n"), #endif /* KMK */ #ifdef CONFIG_PRETTY_COMMAND_PRINTING N_("\ --pretty-command-printing Makes the command echo easier to read.\n"), #endif #ifdef CONFIG_WITH_PRINT_STATS_SWITCH N_("\ --print-stats Print make statistics.\n"), #endif #ifdef CONFIG_WITH_PRINT_TIME_SWITCH N_("\ --print-time[=MIN-SEC] Print file build times starting at arg.\n"), #endif #ifdef CONFIG_WITH_MAKE_STATS N_("\ --statistics Gather extra statistics for $(make-stats ).\n"), #endif NULL }; /* The table of command switches. Order matters here: this is the order MAKEFLAGS will be constructed. So be sure all simple flags (single char, no argument) come first. */ static const struct command_switch switches[] = { { 'b', ignore, 0, 0, 0, 0, 0, 0, 0 }, { 'B', flag, &always_make_set, 1, 1, 0, 0, 0, "always-make" }, { 'd', flag, &debug_flag, 1, 1, 0, 0, 0, 0 }, #ifdef WINDOWS32 { 'D', flag, &suspend_flag, 1, 1, 0, 0, 0, "suspend-for-debug" }, #endif { 'e', flag, &env_overrides, 1, 1, 0, 0, 0, "environment-overrides", }, { 'h', flag, &print_usage_flag, 0, 0, 0, 0, 0, "help" }, { 'i', flag, &ignore_errors_flag, 1, 1, 0, 0, 0, "ignore-errors" }, { 'k', flag, &keep_going_flag, 1, 1, 0, 0, &default_keep_going_flag, "keep-going" }, { 'L', flag, &check_symlink_flag, 1, 1, 0, 0, 0, "check-symlink-times" }, { 'm', ignore, 0, 0, 0, 0, 0, 0, 0 }, { 'n', flag, &just_print_flag, 1, 1, 1, 0, 0, "just-print" }, { 'p', flag, &print_data_base_flag, 1, 1, 0, 0, 0, "print-data-base" }, #ifdef CONFIG_PRETTY_COMMAND_PRINTING { CHAR_MAX+10, flag, (char *) &pretty_command_printing, 1, 1, 1, 0, 0, "pretty-command-printing" }, #endif #ifdef CONFIG_WITH_PRINT_STATS_SWITCH { CHAR_MAX+11, flag, (char *) &print_stats_flag, 1, 1, 1, 0, 0, "print-stats" }, #endif #ifdef CONFIG_WITH_PRINT_TIME_SWITCH { CHAR_MAX+12, positive_int, (char *) &print_time_min, 1, 1, 0, (char *) &no_val_print_time_min, (char *) &default_print_time_min, "print-time" }, #endif #ifdef KMK { CHAR_MAX+14, positive_int, (char *) &process_priority, 1, 1, 0, (char *) &process_priority, (char *) &process_priority, "priority" }, { CHAR_MAX+15, positive_int, (char *) &process_affinity, 1, 1, 0, (char *) &process_affinity, (char *) &process_affinity, "affinity" }, { CHAR_MAX+17, flag, (char *) &process_priority, 1, 1, 0, 0, 0, "nice" }, #endif { 'q', flag, &question_flag, 1, 1, 1, 0, 0, "question" }, { 'r', flag, &no_builtin_rules_flag, 1, 1, 0, 0, 0, "no-builtin-rules" }, { 'R', flag, &no_builtin_variables_flag, 1, 1, 0, 0, 0, "no-builtin-variables" }, { 's', flag, &silent_flag, 1, 1, 0, 0, 0, "silent" }, { 'S', flag_off, &keep_going_flag, 1, 1, 0, 0, &default_keep_going_flag, "no-keep-going" }, #if defined (CONFIG_WITH_MAKE_STATS) || defined (CONFIG_WITH_MINIMAL_STATS) { CHAR_MAX+16, flag, (char *) &make_expensive_statistics, 1, 1, 1, 0, 0, "statistics" }, #endif { 't', flag, &touch_flag, 1, 1, 1, 0, 0, "touch" }, { 'v', flag, &print_version_flag, 1, 1, 0, 0, 0, "version" }, { 'w', flag, &print_directory_flag, 1, 1, 0, 0, 0, "print-directory" }, /* These options take arguments. */ { 'C', filename, &directories, 0, 0, 0, 0, 0, "directory" }, { 'f', filename, &makefiles, 0, 0, 0, 0, 0, "file" }, { 'I', filename, &include_directories, 1, 1, 0, 0, 0, "include-dir" }, { 'j', positive_int, &arg_job_slots, 1, 1, 0, &inf_jobs, &default_job_slots, "jobs" }, #ifndef NO_FLOAT { 'l', floating, &max_load_average, 1, 1, 0, &default_load_average, &default_load_average, "load-average" }, #else { 'l', positive_int, &max_load_average, 1, 1, 0, &default_load_average, &default_load_average, "load-average" }, #endif { 'o', filename, &old_files, 0, 0, 0, 0, 0, "old-file" }, { 'O', string, &output_sync_option, 1, 1, 0, "target", 0, "output-sync" }, { 'W', filename, &new_files, 0, 0, 0, 0, 0, "what-if" }, /* These are long-style options. */ { CHAR_MAX+1, strlist, &db_flags, 1, 1, 0, "basic", 0, "debug" }, { CHAR_MAX+2, string, &jobserver_auth, 1, 1, 0, 0, 0, "jobserver-auth" }, { CHAR_MAX+3, flag, &trace_flag, 1, 1, 0, 0, 0, "trace" }, { CHAR_MAX+4, flag, &inhibit_print_directory_flag, 1, 1, 0, 0, 0, "no-print-directory" }, { CHAR_MAX+5, flag, &warn_undefined_variables_flag, 1, 1, 0, 0, 0, "warn-undefined-variables" }, { CHAR_MAX+6, strlist, &eval_strings, 1, 0, 0, 0, 0, "eval" }, { CHAR_MAX+7, string, &sync_mutex, 1, 1, 0, 0, 0, "sync-mutex" }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; /* Secondary long names for options. */ static struct option long_option_aliases[] = { { "quiet", no_argument, 0, 's' }, { "stop", no_argument, 0, 'S' }, { "new-file", required_argument, 0, 'W' }, { "assume-new", required_argument, 0, 'W' }, { "assume-old", required_argument, 0, 'o' }, { "max-load", optional_argument, 0, 'l' }, { "dry-run", no_argument, 0, 'n' }, { "recon", no_argument, 0, 'n' }, { "makefile", required_argument, 0, 'f' }, }; /* List of goal targets. */ #ifndef KMK static #endif struct goaldep *goals, *lastgoal; /* List of variables which were defined on the command line (or, equivalently, in MAKEFLAGS). */ struct command_variable { struct command_variable *next; struct variable *variable; }; static struct command_variable *command_variables; /* The name we were invoked with. */ #ifdef WINDOWS32 /* On MS-Windows, we chop off the .exe suffix in 'main', so this cannot be 'const'. */ char *program; #else const char *program; #endif /* Our current directory before processing any -C options. */ char *directory_before_chdir; /* Our current directory after processing all -C options. */ char *starting_directory; /* Value of the MAKELEVEL variable at startup (or 0). */ unsigned int makelevel; /* Pointer to the value of the .DEFAULT_GOAL special variable. The value will be the name of the goal to remake if the command line does not override it. It can be set by the makefile, or else it's the first target defined in the makefile whose name does not start with '.'. */ struct variable * default_goal_var; /* Pointer to structure for the file .DEFAULT whose commands are used for any file that has none of its own. This is zero if the makefiles do not define .DEFAULT. */ struct file *default_file; /* Nonzero if we have seen the magic '.POSIX' target. This turns on pedantic compliance with POSIX.2. */ int posix_pedantic; /* Nonzero if we have seen the '.SECONDEXPANSION' target. This turns on secondary expansion of prerequisites. */ int second_expansion; #ifdef CONFIG_WITH_2ND_TARGET_EXPANSION /* Nonzero if we have seen the '.SECONDTARGETEXPANSION' target. This turns on secondary expansion of targets. */ int second_target_expansion; #endif /* Nonzero if we have seen the '.ONESHELL' target. This causes the entire recipe to be handed to SHELL as a single string, potentially containing newlines. */ int one_shell; /* One of OUTPUT_SYNC_* if the "--output-sync" option was given. This attempts to synchronize the output of parallel jobs such that the results of each job stay together. */ int output_sync = OUTPUT_SYNC_NONE; /* Nonzero if the "--trace" option was given. */ int trace_flag = 0; #ifndef CONFIG_WITH_EXTENDED_NOTPARALLEL /* Nonzero if we have seen the '.NOTPARALLEL' target. This turns off parallel builds for this invocation of make. */ #else /* CONFIG_WITH_EXTENDED_NOTPARALLEL */ /* Negative if we have seen the '.NOTPARALLEL' target with an empty dependency list. Zero if no '.NOTPARALLEL' or no file in the dependency list is being executed. Positive when a file in the '.NOTPARALLEL' dependency list is in progress, the value is the number of notparallel files in progress (running or queued for running). In short, any nonzero value means no more parallel builing. */ #endif /* CONFIG_WITH_EXTENDED_NOTPARALLEL */ int not_parallel; /* Nonzero if some rule detected clock skew; we keep track so (a) we only print one warning about it during the run, and (b) we can print a final warning at the end of the run. */ int clock_skew_detected; /* Map of possible stop characters for searching strings. */ #ifndef UCHAR_MAX # define UCHAR_MAX 255 #endif #ifdef _MSC_VER __declspec(align(512)) /* bird: improve cacheline & tlb mojo */ #endif unsigned short stopchar_map[UCHAR_MAX + 1] = {0}; /* If output-sync is enabled we'll collect all the output generated due to options, while reading makefiles, etc. */ struct output make_sync; /* Mask of signals that are being caught with fatal_error_signal. */ #ifdef POSIX sigset_t fatal_signal_set; #else # ifdef HAVE_SIGSETMASK int fatal_signal_mask; # endif #endif #if !HAVE_DECL_BSD_SIGNAL && !defined bsd_signal # if !defined HAVE_SIGACTION # define bsd_signal signal # else typedef RETSIGTYPE (*bsd_signal_ret_t) (int); static bsd_signal_ret_t bsd_signal (int sig, bsd_signal_ret_t func) { struct sigaction act, oact; act.sa_handler = func; act.sa_flags = SA_RESTART; sigemptyset (&act.sa_mask); sigaddset (&act.sa_mask, sig); if (sigaction (sig, &act, &oact) != 0) return SIG_ERR; return oact.sa_handler; } # endif #endif #ifdef CONFIG_WITH_ALLOC_CACHES struct alloccache dep_cache; struct alloccache goaldep_cache; struct alloccache nameseq_cache; struct alloccache file_cache; struct alloccache commands_cache; struct alloccache variable_cache; struct alloccache variable_set_cache; struct alloccache variable_set_list_cache; static void initialize_global_alloc_caches (void) { alloccache_init (&dep_cache, sizeof (struct dep), "dep", NULL, NULL); alloccache_init (&goaldep_cache, sizeof (struct goaldep), "goaldep", NULL, NULL); alloccache_init (&nameseq_cache, sizeof (struct nameseq), "nameseq", NULL, NULL); alloccache_init (&file_cache, sizeof (struct file), "file", NULL, NULL); alloccache_init (&commands_cache, sizeof (struct commands), "commands", NULL, NULL); alloccache_init (&variable_cache, sizeof (struct variable), "variable", NULL, NULL); alloccache_init (&variable_set_cache, sizeof (struct variable_set), "variable_set", NULL, NULL); alloccache_init (&variable_set_list_cache, sizeof (struct variable_set_list), "variable_set_list", NULL, NULL); } #endif /* CONFIG_WITH_ALLOC_CACHES */ static void initialize_global_hash_tables (void) { init_hash_global_variable_set (); strcache_init (); init_hash_files (); hash_init_directories (); hash_init_function_table (); } /* This character map locate stop chars when parsing GNU makefiles. Each element is true if we should stop parsing on that character. */ static void initialize_stopchar_map (void) { int i; stopchar_map[(int)'\0'] = MAP_NUL; stopchar_map[(int)'#'] = MAP_COMMENT; stopchar_map[(int)';'] = MAP_SEMI; stopchar_map[(int)'='] = MAP_EQUALS; stopchar_map[(int)':'] = MAP_COLON; stopchar_map[(int)'%'] = MAP_PERCENT; stopchar_map[(int)'|'] = MAP_PIPE; stopchar_map[(int)'.'] = MAP_DOT | MAP_USERFUNC; stopchar_map[(int)','] = MAP_COMMA; stopchar_map[(int)'$'] = MAP_VARIABLE; stopchar_map[(int)'-'] = MAP_USERFUNC; stopchar_map[(int)'_'] = MAP_USERFUNC; stopchar_map[(int)' '] = MAP_BLANK; stopchar_map[(int)'\t'] = MAP_BLANK; stopchar_map[(int)'/'] = MAP_DIRSEP; #if defined(VMS) stopchar_map[(int)':'] |= MAP_DIRSEP; stopchar_map[(int)']'] |= MAP_DIRSEP; stopchar_map[(int)'>'] |= MAP_DIRSEP; #elif defined(HAVE_DOS_PATHS) stopchar_map[(int)'\\'] |= MAP_DIRSEP; #endif for (i = 1; i <= UCHAR_MAX; ++i) { if (isspace (i) && NONE_SET (stopchar_map[i], MAP_BLANK)) /* Don't mark blank characters as newline characters. */ stopchar_map[i] |= MAP_NEWLINE; else if (isalnum (i)) stopchar_map[i] |= MAP_USERFUNC; } } static const char * expand_command_line_file (const char *name) { const char *cp; char *expanded = 0; if (name[0] == '\0') O (fatal, NILF, _("empty string invalid as file name")); if (name[0] == '~') { expanded = tilde_expand (name); if (expanded && expanded[0] != '\0') name = expanded; } /* This is also done in parse_file_seq, so this is redundant for names read from makefiles. It is here for names passed on the command line. */ while (name[0] == '.' && name[1] == '/') { name += 2; while (name[0] == '/') /* Skip following slashes: ".//foo" is "foo", not "/foo". */ ++name; } if (name[0] == '\0') { /* Nothing else but one or more "./", maybe plus slashes! */ name = "./"; } cp = strcache_add (name); free (expanded); return cp; } /* Toggle -d on receipt of SIGUSR1. */ #ifdef SIGUSR1 static RETSIGTYPE debug_signal_handler (int sig UNUSED) { db_level = db_level ? DB_NONE : DB_BASIC; } #endif static void decode_debug_flags (void) { const char **pp; if (debug_flag) db_level = DB_ALL; if (db_flags) for (pp=db_flags->list; *pp; ++pp) { const char *p = *pp; while (1) { switch (tolower (p[0])) { case 'a': db_level |= DB_ALL; break; case 'b': db_level |= DB_BASIC; break; case 'i': db_level |= DB_BASIC | DB_IMPLICIT; break; case 'j': db_level |= DB_JOBS; break; case 'm': db_level |= DB_BASIC | DB_MAKEFILES; break; case 'n': db_level = 0; break; case 'v': db_level |= DB_BASIC | DB_VERBOSE; break; #ifdef DB_KMK case 'k': db_level |= DB_KMK; break; #endif /* DB_KMK */ default: OS (fatal, NILF, _("unknown debug level specification '%s'"), p); } while (*(++p) != '\0') if (*p == ',' || *p == ' ') { ++p; break; } if (*p == '\0') break; } } if (db_level) verify_flag = 1; if (! db_level) debug_flag = 0; } static void decode_output_sync_flags (void) { #ifdef NO_OUTPUT_SYNC output_sync = OUTPUT_SYNC_NONE; #else if (output_sync_option) { if (streq (output_sync_option, "none")) output_sync = OUTPUT_SYNC_NONE; else if (streq (output_sync_option, "line")) output_sync = OUTPUT_SYNC_LINE; else if (streq (output_sync_option, "target")) output_sync = OUTPUT_SYNC_TARGET; else if (streq (output_sync_option, "recurse")) output_sync = OUTPUT_SYNC_RECURSE; else OS (fatal, NILF, _("unknown output-sync type '%s'"), output_sync_option); } if (sync_mutex) RECORD_SYNC_MUTEX (sync_mutex); #endif } #ifdef KMK static void set_make_priority_and_affinity (void) { # ifdef WINDOWS32 DWORD dwClass, dwPriority; if (process_affinity) if (!SetProcessAffinityMask (GetCurrentProcess (), process_affinity)) fprintf (stderr, "warning: SetProcessAffinityMask (,%#x) failed with last error %d\n", process_affinity, GetLastError ()); switch (process_priority) { case 0: return; case 1: dwClass = IDLE_PRIORITY_CLASS; dwPriority = THREAD_PRIORITY_IDLE; break; case 2: dwClass = BELOW_NORMAL_PRIORITY_CLASS; dwPriority = THREAD_PRIORITY_BELOW_NORMAL; break; case 3: dwClass = NORMAL_PRIORITY_CLASS; dwPriority = THREAD_PRIORITY_NORMAL; break; case 4: dwClass = HIGH_PRIORITY_CLASS; dwPriority = 0xffffffff; break; case 5: dwClass = REALTIME_PRIORITY_CLASS; dwPriority = 0xffffffff; break; default: ON (fatal, NILF, _("invalid priority %d\n"), process_priority); } if (!SetPriorityClass (GetCurrentProcess (), dwClass)) fprintf (stderr, "warning: SetPriorityClass (,%#x) failed with last error %d\n", dwClass, GetLastError ()); if (dwPriority != 0xffffffff && !SetThreadPriority (GetCurrentThread (), dwPriority)) fprintf (stderr, "warning: SetThreadPriority (,%#x) failed with last error %d\n", dwPriority, GetLastError ()); #elif defined(__HAIKU__) int32 iNewPriority; status_t error; switch (process_priority) { case 0: return; case 1: iNewPriority = B_LOWEST_ACTIVE_PRIORITY; break; case 2: iNewPriority = B_LOW_PRIORITY; break; case 3: iNewPriority = B_NORMAL_PRIORITY; break; case 4: iNewPriority = B_URGENT_DISPLAY_PRIORITY; break; case 5: iNewPriority = B_REAL_TIME_DISPLAY_PRIORITY; break; default: ON (fatal, NILF, _("invalid priority %d\n"), process_priority); } error = set_thread_priority (find_thread (NULL), iNewPriority); if (error != B_OK) fprintf (stderr, "warning: set_thread_priority (,%d) failed: %s\n", iNewPriority, strerror (error)); # else /*#elif HAVE_NICE */ int nice_level = 0; switch (process_priority) { case 0: return; case 1: nice_level = 19; break; case 2: nice_level = 10; break; case 3: nice_level = 0; break; case 4: nice_level = -10; break; case 5: nice_level = -19; break; default: ON (fatal, NILF, _("invalid priority %d\n"), process_priority); } errno = 0; if (nice (nice_level) == -1 && errno != 0) fprintf (stderr, "warning: nice (%d) failed: %s\n", nice_level, strerror (errno)); # endif } #endif /* KMK */ #ifdef WINDOWS32 #ifndef NO_OUTPUT_SYNC /* This is called from start_job_command when it detects that output_sync option is in effect. The handle to the synchronization mutex is passed, as a string, to sub-makes via the --sync-mutex command-line argument. */ void prepare_mutex_handle_string (sync_handle_t handle) { if (!sync_mutex) { /* Prepare the mutex handle string for our children. */ /* 2 hex digits per byte + 2 characters for "0x" + null. */ sync_mutex = xmalloc ((2 * sizeof (sync_handle_t)) + 2 + 1); sprintf (sync_mutex, "0x%Ix", handle); define_makeflags (1, 0); } } #endif /* NO_OUTPUT_SYNC */ # ifndef KMK /* I'd rather have WER collect dumps. */ /* * HANDLE runtime exceptions by avoiding a requestor on the GUI. Capture * exception and print it to stderr instead. * * If ! DB_VERBOSE, just print a simple message and exit. * If DB_VERBOSE, print a more verbose message. * If compiled for DEBUG, let exception pass through to GUI so that * debuggers can attach. */ LONG WINAPI handle_runtime_exceptions (struct _EXCEPTION_POINTERS *exinfo) { PEXCEPTION_RECORD exrec = exinfo->ExceptionRecord; LPSTR cmdline = GetCommandLine (); LPSTR prg = strtok (cmdline, " "); CHAR errmsg[1024]; #ifdef USE_EVENT_LOG HANDLE hEventSource; LPTSTR lpszStrings[1]; #endif if (! ISDB (DB_VERBOSE)) { sprintf (errmsg, _("%s: Interrupt/Exception caught (code = 0x%lx, addr = 0x%p)\n"), prg, exrec->ExceptionCode, exrec->ExceptionAddress); fprintf (stderr, errmsg); exit (255); } sprintf (errmsg, _("\nUnhandled exception filter called from program %s\nExceptionCode = %lx\nExceptionFlags = %lx\nExceptionAddress = 0x%p\n"), prg, exrec->ExceptionCode, exrec->ExceptionFlags, exrec->ExceptionAddress); if (exrec->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && exrec->NumberParameters >= 2) sprintf (&errmsg[strlen(errmsg)], (exrec->ExceptionInformation[0] ? _("Access violation: write operation at address 0x%p\n") : _("Access violation: read operation at address 0x%p\n")), (PVOID)exrec->ExceptionInformation[1]); /* turn this on if we want to put stuff in the event log too */ #ifdef USE_EVENT_LOG hEventSource = RegisterEventSource (NULL, "GNU Make"); lpszStrings[0] = errmsg; if (hEventSource != NULL) { ReportEvent (hEventSource, /* handle of event source */ EVENTLOG_ERROR_TYPE, /* event type */ 0, /* event category */ 0, /* event ID */ NULL, /* current user's SID */ 1, /* strings in lpszStrings */ 0, /* no bytes of raw data */ lpszStrings, /* array of error strings */ NULL); /* no raw data */ (VOID) DeregisterEventSource (hEventSource); } #endif /* Write the error to stderr too */ fprintf (stderr, errmsg); #ifdef DEBUG return EXCEPTION_CONTINUE_SEARCH; #else exit (255); return (255); /* not reached */ #endif } # endif /* !KMK */ /* * On WIN32 systems we don't have the luxury of a /bin directory that * is mapped globally to every drive mounted to the system. Since make could * be invoked from any drive, and we don't want to propagate /bin/sh * to every single drive. Allow ourselves a chance to search for * a value for default shell here (if the default path does not exist). */ int find_and_set_default_shell (const char *token) { int sh_found = 0; char *atoken = 0; const char *search_token; const char *tokend; PATH_VAR(sh_path); extern const char *default_shell; if (!token) search_token = default_shell; else search_token = atoken = xstrdup (token); /* If the user explicitly requests the DOS cmd shell, obey that request. However, make sure that's what they really want by requiring the value of SHELL either equal, or have a final path element of, "cmd" or "cmd.exe" case-insensitive. */ tokend = search_token + strlen (search_token) - 3; if (((tokend == search_token || (tokend > search_token && (tokend[-1] == '/' || tokend[-1] == '\\'))) && !strcasecmp (tokend, "cmd")) || ((tokend - 4 == search_token || (tokend - 4 > search_token && (tokend[-5] == '/' || tokend[-5] == '\\'))) && !strcasecmp (tokend - 4, "cmd.exe"))) { batch_mode_shell = 1; unixy_shell = 0; sprintf (sh_path, "%s", search_token); default_shell = xstrdup (w32ify (sh_path, 0)); DB (DB_VERBOSE, (_("find_and_set_shell() setting default_shell = %s\n"), default_shell)); sh_found = 1; } else if (!no_default_sh_exe && (token == NULL || !strcmp (search_token, default_shell))) { /* no new information, path already set or known */ sh_found = 1; } else if (_access (search_token, 0) == 0) { /* search token path was found */ sprintf (sh_path, "%s", search_token); default_shell = xstrdup (w32ify (sh_path, 0)); DB (DB_VERBOSE, (_("find_and_set_shell() setting default_shell = %s\n"), default_shell)); sh_found = 1; } else { char *p; struct variable *v = lookup_variable (STRING_SIZE_TUPLE ("PATH")); /* Search Path for shell */ if (v && v->value) { char *ep; p = v->value; ep = strchr (p, PATH_SEPARATOR_CHAR); while (ep && *ep) { *ep = '\0'; sprintf (sh_path, "%s/%s", p, search_token); if (_access (sh_path, 0) == 0) { default_shell = xstrdup (w32ify (sh_path, 0)); sh_found = 1; *ep = PATH_SEPARATOR_CHAR; /* terminate loop */ p += strlen (p); } else { *ep = PATH_SEPARATOR_CHAR; p = ++ep; } ep = strchr (p, PATH_SEPARATOR_CHAR); } /* be sure to check last element of Path */ if (p && *p) { sprintf (sh_path, "%s/%s", p, search_token); if (_access (sh_path, 0) == 0) { default_shell = xstrdup (w32ify (sh_path, 0)); sh_found = 1; } } if (sh_found) DB (DB_VERBOSE, (_("find_and_set_shell() path search set default_shell = %s\n"), default_shell)); } } /* naive test */ if (!unixy_shell && sh_found && (strstr (default_shell, "sh") || strstr (default_shell, "SH"))) { unixy_shell = 1; batch_mode_shell = 0; } #ifdef BATCH_MODE_ONLY_SHELL batch_mode_shell = 1; #endif free (atoken); return (sh_found); } /* bird: */ #ifdef CONFIG_NEW_WIN32_CTRL_EVENT #include static UINT g_tidMainThread = 0; static int volatile g_sigPending = 0; /* lazy bird */ # ifndef _M_IX86 static LONG volatile g_lTriggered = 0; static CONTEXT g_Ctx; # endif # ifdef _M_IX86 static __declspec(naked) void dispatch_stub(void) { __asm { pushfd pushad cld } fflush(stdout); /*fprintf(stderr, "dbg: raising %s on the main thread (%d)\n", g_sigPending == SIGINT ? "SIGINT" : "SIGBREAK", _getpid());*/ raise(g_sigPending); __asm { popad popfd ret } } # else /* !_M_IX86 */ static void dispatch_stub(void) { fflush(stdout); /*fprintf(stderr, "dbg: raising %s on the main thread (%d)\n", g_sigPending == SIGINT ? "SIGINT" : "SIGBREAK", _getpid());*/ raise(g_sigPending); SetThreadContext(GetCurrentThread(), &g_Ctx); fprintf(stderr, "fatal error: SetThreadContext failed with last error %d\n", GetLastError()); for (;;) exit(131); } # endif /* !_M_IX86 */ static BOOL WINAPI ctrl_event(DWORD CtrlType) { int sig = (CtrlType == CTRL_C_EVENT) ? SIGINT : SIGBREAK; HANDLE hThread; CONTEXT Ctx; /*fprintf(stderr, "dbg: ctrl_event sig=%d\n", sig);*/ #ifndef _M_IX86 /* only once. */ if (InterlockedExchange(&g_lTriggered, 1)) { Sleep(1); return TRUE; } #endif /* open the main thread and suspend it. */ hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, g_tidMainThread); SuspendThread(hThread); /* Get the thread context and if we've get a valid Esp, dispatch it on the main thread otherwise raise the signal in the ctrl-event thread (this). */ memset(&Ctx, 0, sizeof(Ctx)); Ctx.ContextFlags = CONTEXT_FULL; if (GetThreadContext(hThread, &Ctx) #ifdef _M_IX86 && Ctx.Esp >= 0x1000 #else && Ctx.Rsp >= 0x1000 #endif ) { #ifdef _M_IX86 ((uintptr_t *)Ctx.Esp)[-1] = Ctx.Eip; Ctx.Esp -= sizeof(uintptr_t); Ctx.Eip = (uintptr_t)&dispatch_stub; #else g_Ctx = Ctx; Ctx.Rsp -= 0x80; Ctx.Rsp &= ~(uintptr_t)0xf; Ctx.Rsp += 8; /* (Stack aligned before call instruction, not after.) */ Ctx.Rip = (uintptr_t)&dispatch_stub; #endif SetThreadContext(hThread, &Ctx); g_sigPending = sig; ResumeThread(hThread); CloseHandle(hThread); } else { fprintf(stderr, "dbg: raising %s on the ctrl-event thread (%d)\n", sig == SIGINT ? "SIGINT" : "SIGBREAK", _getpid()); raise(sig); ResumeThread(hThread); CloseHandle(hThread); exit(130); } Sleep(1); return TRUE; } #endif /* CONFIG_NEW_WIN32_CTRL_EVENT */ #endif /* WINDOWS32 */ #ifdef KMK /* Determins the number of CPUs that are currently online. This is used to setup the default number of job slots. */ static int get_online_cpu_count(void) { # ifdef WINDOWS32 /* Windows: Count the active CPUs. */ int cpus; /* Process groups (W7+). */ typedef DWORD (WINAPI *PFNGETACTIVEPROCESSORCOUNT)(DWORD); PFNGETACTIVEPROCESSORCOUNT pfnGetActiveProcessorCount; pfnGetActiveProcessorCount = (PFNGETACTIVEPROCESSORCOUNT)GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "GetActiveProcessorCount"); if (pfnGetActiveProcessorCount) cpus = pfnGetActiveProcessorCount(ALL_PROCESSOR_GROUPS); /* Legacy (<= Vista). */ else { int i; SYSTEM_INFO si; GetSystemInfo(&si); for (i = cpus = 0; i < sizeof(si.dwActiveProcessorMask) * 8; i++) { if (si.dwActiveProcessorMask & 1) cpus++; si.dwActiveProcessorMask >>= 1; } } if (!cpus) cpus = 1; if (cpus > 64) cpus = 64; /* (wait for multiple objects limit) */ return cpus; # elif defined(__OS2__) /* OS/2: Count the active CPUs. */ int cpus, i, j; MPAFFINITY mp; if (DosQueryThreadAffinity(AFNTY_SYSTEM, &mp)) return 1; for (j = cpus = 0; j < sizeof(mp.mask) / sizeof(mp.mask[0]); j++) for (i = 0; i < 32; i++) if (mp.mask[j] & (1UL << i)) cpus++; return cpus ? cpus : 1; # else /* UNIX like systems, try sysconf and sysctl. */ int cpus = -1; # if defined(CTL_HW) int mib[2]; size_t sz; # endif # ifdef _SC_NPROCESSORS_ONLN cpus = sysconf(_SC_NPROCESSORS_ONLN); if (cpus >= 1) return cpus; cpus = -1; # endif # if defined(CTL_HW) # ifdef HW_AVAILCPU sz = sizeof(cpus); mib[0] = CTL_HW; mib[1] = HW_AVAILCPU; if (!sysctl(mib, 2, &cpus, &sz, NULL, 0) && cpus >= 1) return cpus; cpus = -1; # endif /* HW_AVAILCPU */ sz = sizeof(cpus); mib[0] = CTL_HW; mib[1] = HW_NCPU; if (!sysctl(mib, 2, &cpus, &sz, NULL, 0) && cpus >= 1) return cpus; cpus = -1; # endif /* CTL_HW */ /* no idea / failure, just return 1. */ return 1; # endif } #endif /* KMK */ #ifdef __MSDOS__ static void msdos_return_to_initial_directory (void) { if (directory_before_chdir) chdir (directory_before_chdir); } #endif /* __MSDOS__ */ static void reset_jobserver (void) { jobserver_clear (); free (jobserver_auth); jobserver_auth = NULL; } #ifdef _AMIGA int main (int argc, char **argv) #else int main (int argc, char **argv, char **envp) #endif { static char *stdin_nm = 0; #ifdef CONFIG_WITH_MAKE_STATS unsigned long long uStartTick = CURRENT_CLOCK_TICK(); #endif int makefile_status = MAKE_SUCCESS; struct goaldep *read_files; PATH_VAR (current_directory); unsigned int restarts = 0; unsigned int syncing = 0; int argv_slots; #ifdef WINDOWS32 const char *unix_path = NULL; const char *windows32_path = NULL; # ifndef ELECTRIC_HEAP /* Drop this because it prevents JIT debugging. */ # ifndef KMK /* Don't want none of this crap. */ SetUnhandledExceptionFilter (handle_runtime_exceptions); # endif # endif /* !ELECTRIC_HEAP */ # ifdef KMK /* Clear the SEM_NOGPFAULTERRORBOX flag so WER will generate dumps when we run under cygwin. To void popups, set WER registry value DontShowUI to 1. */ if (getenv("KMK_NO_SET_ERROR_MODE") == NULL) SetErrorMode(SetErrorMode(0) & ~SEM_NOGPFAULTERRORBOX); # endif /* start off assuming we have no shell */ unixy_shell = 0; no_default_sh_exe = 1; #endif #ifdef CONFIG_WITH_PRINT_TIME_SWITCH make_start_ts = nano_timestamp (); #endif output_init (&make_sync); initialize_stopchar_map(); #ifdef SET_STACK_SIZE /* Get rid of any avoidable limit on stack size. */ { struct rlimit rlim; /* Set the stack limit huge so that alloca does not fail. */ if (getrlimit (RLIMIT_STACK, &rlim) == 0 && rlim.rlim_cur > 0 && rlim.rlim_cur < rlim.rlim_max) { stack_limit = rlim; rlim.rlim_cur = rlim.rlim_max; setrlimit (RLIMIT_STACK, &rlim); } else stack_limit.rlim_cur = 0; } #endif /* Needed for OS/2 */ initialize_main (&argc, &argv); #ifdef KMK init_kbuild (argc, argv); #endif #ifdef MAKE_MAINTAINER_MODE /* In maintainer mode we always enable verification. */ verify_flag = 1; #endif #if defined (__MSDOS__) && !defined (_POSIX_SOURCE) /* Request the most powerful version of 'system', to make up for the dumb default shell. */ __system_flags = (__system_redirect | __system_use_shell | __system_allow_multiple_cmds | __system_allow_long_cmds | __system_handle_null_commands | __system_emulate_chdir); #endif /* Set up gettext/internationalization support. */ setlocale (LC_ALL, ""); /* The cast to void shuts up compiler warnings on systems that disable NLS. */ #ifdef LOCALEDIR /* bird */ (void)bindtextdomain (PACKAGE, LOCALEDIR); (void)textdomain (PACKAGE); #endif #ifdef POSIX sigemptyset (&fatal_signal_set); #define ADD_SIG(sig) sigaddset (&fatal_signal_set, sig) #else #ifdef HAVE_SIGSETMASK fatal_signal_mask = 0; #define ADD_SIG(sig) fatal_signal_mask |= sigmask (sig) #else #define ADD_SIG(sig) (void)sig #endif #endif #define FATAL_SIG(sig) \ if (bsd_signal (sig, fatal_error_signal) == SIG_IGN) \ bsd_signal (sig, SIG_IGN); \ else \ ADD_SIG (sig); #ifdef SIGHUP FATAL_SIG (SIGHUP); #endif #ifdef SIGQUIT FATAL_SIG (SIGQUIT); #endif FATAL_SIG (SIGINT); FATAL_SIG (SIGTERM); #ifdef __MSDOS__ /* Windows 9X delivers FP exceptions in child programs to their parent! We don't want Make to die when a child divides by zero, so we work around that lossage by catching SIGFPE. */ FATAL_SIG (SIGFPE); #endif #ifdef SIGDANGER FATAL_SIG (SIGDANGER); #endif #ifdef SIGXCPU FATAL_SIG (SIGXCPU); #endif #ifdef SIGXFSZ FATAL_SIG (SIGXFSZ); #endif #ifdef CONFIG_NEW_WIN32_CTRL_EVENT /* bird: dispatch signals in our own way to try avoid deadlocks. */ g_tidMainThread = GetCurrentThreadId (); SetConsoleCtrlHandler (ctrl_event, TRUE); #endif /* CONFIG_NEW_WIN32_CTRL_EVENT */ #undef FATAL_SIG /* Do not ignore the child-death signal. This must be done before any children could possibly be created; otherwise, the wait functions won't work on systems with the SVR4 ECHILD brain damage, if our invoker is ignoring this signal. */ #ifdef HAVE_WAIT_NOHANG # if defined SIGCHLD (void) bsd_signal (SIGCHLD, SIG_DFL); # endif # if defined SIGCLD && SIGCLD != SIGCHLD (void) bsd_signal (SIGCLD, SIG_DFL); # endif #endif output_init (NULL); /* Figure out where this program lives. */ if (argv[0] == 0) argv[0] = (char *)""; if (argv[0][0] == '\0') #ifdef KMK program = "kmk"; #else program = "make"; #endif else { program = strrchr (argv[0], '/'); #if defined(__MSDOS__) || defined(__EMX__) if (program == 0) program = strrchr (argv[0], '\\'); else { /* Some weird environments might pass us argv[0] with both kinds of slashes; we must find the rightmost. */ char *p = strrchr (argv[0], '\\'); if (p && p > program) program = p; } if (program == 0 && argv[0][1] == ':') program = argv[0] + 1; #endif #ifdef WINDOWS32 if (program == 0) { /* Extract program from full path */ program = strrchr (argv[0], '\\'); if (program) { int argv0_len = strlen (program); if (argv0_len > 4 && streq (&program[argv0_len - 4], ".exe")) /* Remove .exe extension */ program[argv0_len - 4] = '\0'; } } #endif #ifdef VMS set_program_name (argv[0]); program = program_name; { const char *shell; char pwdbuf[256]; char *pwd; shell = getenv ("SHELL"); if (shell != NULL) vms_gnv_shell = 1; /* Need to know if CRTL set to report UNIX paths. Use getcwd as it works on all versions of VMS. */ pwd = getcwd(pwdbuf, 256); if (pwd[0] == '/') vms_report_unix_paths = 1; vms_use_mcr_command = get_vms_env_flag ("GNV$MAKE_USE_MCR", 0); vms_always_use_cmd_file = get_vms_env_flag ("GNV$MAKE_USE_CMD_FILE", 0); /* Legacy behavior is on VMS is older behavior that needed to be changed to be compatible with standard make behavior. For now only completely disable when running under a Bash shell. TODO: Update VMS built in recipes and macros to not need this behavior, at which time the default may change. */ vms_legacy_behavior = get_vms_env_flag ("GNV$MAKE_OLD_VMS", !vms_gnv_shell); /* VMS was changed to use a comma separator in the past, but that is incompatible with built in functions that expect space separated lists. Allow this to be selectively turned off. */ vms_comma_separator = get_vms_env_flag ("GNV$MAKE_COMMA", vms_legacy_behavior); /* Some Posix shell syntax options are incompatible with VMS syntax. VMS requires double quotes for strings and escapes quotes differently. When this option is active, VMS will try to simulate Posix shell simulations instead of using VMS DCL behavior. */ vms_unix_simulation = get_vms_env_flag ("GNV$MAKE_SHELL_SIM", !vms_legacy_behavior); } if (need_vms_symbol () && !vms_use_mcr_command) create_foreign_command (program_name, argv[0]); #else if (program == 0) program = argv[0]; else ++program; #endif } /* Set up to access user data (files). */ user_access (); # ifdef CONFIG_WITH_COMPILER kmk_cc_init (); # endif #ifdef CONFIG_WITH_ALLOC_CACHES initialize_global_alloc_caches (); #endif initialize_global_hash_tables (); #ifdef KMK init_kbuild_object (); #endif /* Figure out where we are. */ #ifdef WINDOWS32 if (getcwd_fs (current_directory, GET_PATH_MAX) == 0) #else if (getcwd (current_directory, GET_PATH_MAX) == 0) #endif { #ifdef HAVE_GETCWD perror_with_name ("getcwd", ""); #else OS (error, NILF, "getwd: %s", current_directory); #endif current_directory[0] = '\0'; directory_before_chdir = 0; } else directory_before_chdir = xstrdup (current_directory); #ifdef __MSDOS__ /* Make sure we will return to the initial directory, come what may. */ atexit (msdos_return_to_initial_directory); #endif /* Initialize the special variables. */ define_variable_cname (".VARIABLES", "", o_default, 0)->special = 1; /* define_variable_cname (".TARGETS", "", o_default, 0)->special = 1; */ define_variable_cname (".RECIPEPREFIX", "", o_default, 0)->special = 1; define_variable_cname (".SHELLFLAGS", "-c", o_default, 0); define_variable_cname (".LOADED", "", o_default, 0); /* Set up .FEATURES Use a separate variable because define_variable_cname() is a macro and some compilers (MSVC) don't like conditionals in macros. */ { const char *features = "target-specific order-only second-expansion" " else-if shortest-stem undefine oneshell" #ifndef NO_ARCHIVES " archives" #endif #ifdef MAKE_JOBSERVER " jobserver" #endif #ifndef NO_OUTPUT_SYNC " output-sync" #endif #ifdef MAKE_SYMLINKS " check-symlink" #endif #ifdef HAVE_GUILE " guile" #endif #ifdef MAKE_LOAD " load" #endif #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET " explicit-multitarget" #endif #ifdef CONFIG_WITH_PREPEND_ASSIGNMENT " prepend-assignment" #endif ; define_variable_cname (".FEATURES", features, o_default, 0); } #ifdef KMK /* Initialize the default number of jobs to the cpu/core/smt count. */ default_job_slots = arg_job_slots = job_slots = get_online_cpu_count (); #endif /* KMK */ /* Configure GNU Guile support */ guile_gmake_setup (NILF); /* Read in variables from the environment. It is important that this be done before $(MAKE) is figured out so its definitions will not be from the environment. */ #ifndef _AMIGA { unsigned int i; for (i = 0; envp[i] != 0; ++i) { struct variable *v; const char *ep = envp[i]; /* By default, export all variables culled from the environment. */ enum variable_export export = v_export; unsigned int len; while (! STOP_SET (*ep, MAP_EQUALS)) ++ep; /* If there's no equals sign it's a malformed environment. Ignore. */ if (*ep == '\0') continue; #ifdef WINDOWS32 if (!unix_path && strneq (envp[i], "PATH=", 5)) unix_path = ep+1; else if (!strnicmp (envp[i], "Path=", 5)) { if (!windows32_path) windows32_path = ep+1; /* PATH gets defined after the loop exits. */ continue; } #endif /* Length of the variable name, and skip the '='. */ len = ep++ - envp[i]; /* If this is MAKE_RESTARTS, check to see if the "already printed the enter statement" flag is set. */ if (len == 13 && strneq (envp[i], "MAKE_RESTARTS", 13)) { if (*ep == '-') { OUTPUT_TRACED (); ++ep; } restarts = (unsigned int) atoi (ep); export = v_noexport; } v = define_variable (envp[i], len, ep, o_env, 1); /* POSIX says the value of SHELL set in the makefile won't change the value of SHELL given to subprocesses. */ if (streq (v->name, "SHELL")) { #ifndef __MSDOS__ export = v_noexport; #endif #ifndef CONFIG_WITH_STRCACHE2 shell_var.name = xstrdup ("SHELL"); #else shell_var.name = v->name; #endif shell_var.length = 5; #ifndef CONFIG_WITH_VALUE_LENGTH shell_var.value = xstrdup (ep); #else shell_var.value = xstrndup (v->value, v->value_length); shell_var.value_length = v->value_length; #endif } v->export = export; } } #ifdef WINDOWS32 /* If we didn't find a correctly spelled PATH we define PATH as * either the first misspelled value or an empty string */ if (!unix_path) define_variable_cname ("PATH", windows32_path ? windows32_path : "", o_env, 1)->export = v_export; #endif #else /* For Amiga, read the ENV: device, ignoring all dirs */ { BPTR env, file, old; char buffer[1024]; int len; __aligned struct FileInfoBlock fib; env = Lock ("ENV:", ACCESS_READ); if (env) { old = CurrentDir (DupLock (env)); Examine (env, &fib); while (ExNext (env, &fib)) { if (fib.fib_DirEntryType < 0) /* File */ { /* Define an empty variable. It will be filled in variable_lookup(). Makes startup quite a bit faster. */ define_variable (fib.fib_FileName, strlen (fib.fib_FileName), "", o_env, 1)->export = v_export; } } UnLock (env); UnLock (CurrentDir (old)); } } #endif /* Decode the switches. */ decode_env_switches (STRING_SIZE_TUPLE ("GNUMAKEFLAGS")); /* Clear GNUMAKEFLAGS to avoid duplication. */ define_variable_cname ("GNUMAKEFLAGS", "", o_env, 0); #ifdef KMK decode_env_switches (STRING_SIZE_TUPLE ("KMK_FLAGS")); #else /* !KMK */ decode_env_switches (STRING_SIZE_TUPLE ("MAKEFLAGS")); #if 0 /* People write things like: MFLAGS="CC=gcc -pipe" "CFLAGS=-g" and we set the -p, -i and -e switches. Doesn't seem quite right. */ decode_env_switches (STRING_SIZE_TUPLE ("MFLAGS")); #endif #endif /* !KMK */ /* In output sync mode we need to sync any output generated by reading the makefiles, such as in $(info ...) or stderr from $(shell ...) etc. */ syncing = make_sync.syncout = (output_sync == OUTPUT_SYNC_LINE || output_sync == OUTPUT_SYNC_TARGET); OUTPUT_SET (&make_sync); /* Remember the job slots set through the environment vs. command line. */ { int env_slots = arg_job_slots; arg_job_slots = INVALID_JOB_SLOTS; decode_switches (argc, (const char **)argv, 0); argv_slots = arg_job_slots; if (arg_job_slots == INVALID_JOB_SLOTS) arg_job_slots = env_slots; } /* Set a variable specifying whether stdout/stdin is hooked to a TTY. */ #ifdef HAVE_ISATTY if (isatty (fileno (stdout))) if (! lookup_variable (STRING_SIZE_TUPLE ("MAKE_TERMOUT"))) { const char *tty = TTYNAME (fileno (stdout)); define_variable_cname ("MAKE_TERMOUT", tty ? tty : DEFAULT_TTYNAME, o_default, 0)->export = v_export; } if (isatty (fileno (stderr))) if (! lookup_variable (STRING_SIZE_TUPLE ("MAKE_TERMERR"))) { const char *tty = TTYNAME (fileno (stderr)); define_variable_cname ("MAKE_TERMERR", tty ? tty : DEFAULT_TTYNAME, o_default, 0)->export = v_export; } #endif /* Reset in case the switches changed our minds. */ syncing = (output_sync == OUTPUT_SYNC_LINE || output_sync == OUTPUT_SYNC_TARGET); #ifdef KMK set_make_priority_and_affinity (); #endif if (make_sync.syncout && ! syncing) output_close (&make_sync); make_sync.syncout = syncing; OUTPUT_SET (&make_sync); /* Figure out the level of recursion. */ { struct variable *v = lookup_variable (STRING_SIZE_TUPLE (MAKELEVEL_NAME)); if (v && v->value[0] != '\0' && v->value[0] != '-') makelevel = (unsigned int) atoi (v->value); else makelevel = 0; } #ifdef WINDOWS32 if (suspend_flag) { fprintf (stderr, "%s (pid = %ld)\n", argv[0], GetCurrentProcessId ()); fprintf (stderr, _("%s is suspending for 30 seconds..."), argv[0]); Sleep (30 * 1000); fprintf (stderr, _("done sleep(30). Continuing.\n")); } #endif /* Set always_make_flag if -B was given and we've not restarted already. */ always_make_flag = always_make_set && (restarts == 0); /* Print version information, and exit. */ if (print_version_flag) { print_version (); die (MAKE_SUCCESS); } if (ISDB (DB_BASIC)) print_version (); #ifndef VMS /* Set the "MAKE_COMMAND" variable to the name we were invoked with. (If it is a relative pathname with a slash, prepend our directory name so the result will run the same program regardless of the current dir. If it is a name with no slash, we can only hope that PATH did not find it in the current directory.) */ #ifdef WINDOWS32 /* * Convert from backslashes to forward slashes for * programs like sh which don't like them. Shouldn't * matter if the path is one way or the other for * CreateProcess(). */ if (strpbrk (argv[0], "/:\\") || strstr (argv[0], "..") || strneq (argv[0], "//", 2)) argv[0] = xstrdup (w32ify (argv[0], 1)); #else /* WINDOWS32 */ #if defined (__MSDOS__) || defined (__EMX__) if (strchr (argv[0], '\\')) { char *p; argv[0] = xstrdup (argv[0]); for (p = argv[0]; *p; p++) if (*p == '\\') *p = '/'; } /* If argv[0] is not in absolute form, prepend the current directory. This can happen when Make is invoked by another DJGPP program that uses a non-absolute name. */ if (current_directory[0] != '\0' && argv[0] != 0 && (argv[0][0] != '/' && (argv[0][0] == '\0' || argv[0][1] != ':')) # ifdef __EMX__ /* do not prepend cwd if argv[0] contains no '/', e.g. "make" */ && (strchr (argv[0], '/') != 0 || strchr (argv[0], '\\') != 0) # endif ) argv[0] = xstrdup (concat (3, current_directory, "/", argv[0])); #else /* !__MSDOS__ */ if (current_directory[0] != '\0' && argv[0] != 0 && argv[0][0] != '/' && strchr (argv[0], '/') != 0 #ifdef HAVE_DOS_PATHS && (argv[0][0] != '\\' && (!argv[0][0] || argv[0][1] != ':')) && strchr (argv[0], '\\') != 0 #endif ) argv[0] = xstrdup (concat (3, current_directory, "/", argv[0])); #endif /* !__MSDOS__ */ #endif /* WINDOWS32 */ #endif /* We may move, but until we do, here we are. */ starting_directory = current_directory; /* Set up the job_slots value and the jobserver. This can't be usefully set in the makefile, and we want to verify the authorization is valid before make has a chance to start using it for something else. */ if (jobserver_auth) { if (argv_slots == INVALID_JOB_SLOTS) { if (jobserver_parse_auth (jobserver_auth)) { /* Success! Use the jobserver. */ job_slots = 0; goto job_setup_complete; } O (error, NILF, _("warning: jobserver unavailable: using -j1. Add '+' to parent make rule.")); arg_job_slots = 1; } /* The user provided a -j setting on the command line: use it. */ else if (!restarts) /* If restarts is >0 we already printed this message. */ O (error, NILF, _("warning: -jN forced in submake: disabling jobserver mode.")); /* We failed to use our parent's jobserver. */ reset_jobserver (); job_slots = (unsigned int)arg_job_slots; } else if (arg_job_slots == INVALID_JOB_SLOTS) #ifdef KMK job_slots = default_job_slots; /* The default is set to CPU count early in main. */ #else /* The default is one job at a time. */ job_slots = 1; #endif else /* Use whatever was provided. */ job_slots = (unsigned int)arg_job_slots; job_setup_complete: /* The extra indirection through $(MAKE_COMMAND) is done for hysterical raisins. */ #ifdef VMS if (vms_use_mcr_command) define_variable_cname ("MAKE_COMMAND", vms_command (argv[0]), o_default, 0); else define_variable_cname ("MAKE_COMMAND", program, o_default, 0); #else define_variable_cname ("MAKE_COMMAND", argv[0], o_default, 0); #endif define_variable_cname ("MAKE", "$(MAKE_COMMAND)", o_default, 1); #ifdef KMK (void) define_variable ("KMK", 3, argv[0], o_default, 1); #endif if (command_variables != 0) { struct command_variable *cv; struct variable *v; unsigned int len = 0; char *value, *p; /* Figure out how much space will be taken up by the command-line variable definitions. */ for (cv = command_variables; cv != 0; cv = cv->next) { v = cv->variable; len += 2 * strlen (v->name); if (! v->recursive) ++len; ++len; len += 2 * strlen (v->value); ++len; } /* Now allocate a buffer big enough and fill it. */ p = value = alloca (len); for (cv = command_variables; cv != 0; cv = cv->next) { v = cv->variable; p = quote_for_env (p, v->name); if (! v->recursive) *p++ = ':'; *p++ = '='; p = quote_for_env (p, v->value); *p++ = ' '; } p[-1] = '\0'; /* Kill the final space and terminate. */ /* Define an unchangeable variable with a name that no POSIX.2 makefile could validly use for its own variable. */ define_variable_cname ("-*-command-variables-*-", value, o_automatic, 0); /* Define the variable; this will not override any user definition. Normally a reference to this variable is written into the value of MAKEFLAGS, allowing the user to override this value to affect the exported value of MAKEFLAGS. In POSIX-pedantic mode, we cannot allow the user's setting of MAKEOVERRIDES to affect MAKEFLAGS, so a reference to this hidden variable is written instead. */ #ifdef KMK define_variable_cname ("KMK_OVERRIDES", "${-*-command-variables-*-}", o_env, 1); #else define_variable_cname ("MAKEOVERRIDES", "${-*-command-variables-*-}", o_env, 1); #endif #ifdef VMS vms_export_dcl_symbol ("MAKEOVERRIDES", "${-*-command-variables-*-}"); #endif } /* If there were -C flags, move ourselves about. */ if (directories != 0) { unsigned int i; for (i = 0; directories->list[i] != 0; ++i) { const char *dir = directories->list[i]; #ifdef WINDOWS32 /* WINDOWS32 chdir() doesn't work if the directory has a trailing '/' But allow -C/ just in case someone wants that. */ { char *p = (char *)dir + strlen (dir) - 1; while (p > dir && (p[0] == '/' || p[0] == '\\')) --p; p[1] = '\0'; } #endif if (chdir (dir) < 0) pfatal_with_name (dir); } } #ifdef KMK /* Check for [Mm]akefile.kup and change directory when found. Makefile.kmk overrides Makefile.kup but not plain Makefile. If no -C arguments were given, fake one to indicate chdir. */ if (makefiles == 0) { struct stat st; if (( ( stat ("Makefile.kup", &st) == 0 && S_ISREG (st.st_mode) ) || ( stat ("makefile.kup", &st) == 0 && S_ISREG (st.st_mode) ) ) && stat ("Makefile.kmk", &st) < 0 && stat ("makefile.kmk", &st) < 0) { static char fake_path[3*16 + 32] = ".."; char *cur = &fake_path[2]; int up_levels = 1; while (up_levels < 16) { /* File with higher precedence.s */ strcpy (cur, "/Makefile.kmk"); if (stat (fake_path, &st) == 0) break; strcpy (cur, "/makefile.kmk"); if (stat (fake_path, &st) == 0) break; /* the .kup files */ strcpy (cur, "/Makefile.kup"); if ( stat (fake_path, &st) != 0 || !S_ISREG (st.st_mode)) { strcpy (cur, "/makefile.kup"); if ( stat (fake_path, &st) != 0 || !S_ISREG (st.st_mode)) break; } /* ok */ strcpy (cur, "/.."); cur += 3; up_levels++; } if (up_levels >= 16) O (fatal, NILF, _("Makefile.kup recursion is too deep.")); /* attempt to change to the directory. */ *cur = '\0'; if (chdir (fake_path) < 0) pfatal_with_name (fake_path); /* add the string to the directories. */ if (!directories) { directories = xmalloc (sizeof(*directories)); directories->list = xmalloc (5 * sizeof (char *)); directories->max = 5; directories->idx = 0; } else if (directories->idx == directories->max - 1) { directories->max += 5; directories->list = xrealloc ((void *)directories->list, directories->max * sizeof (char *)); } directories->list[directories->idx++] = fake_path; } } #endif /* KMK */ #ifdef WINDOWS32 /* * THIS BLOCK OF CODE MUST COME AFTER chdir() CALL ABOVE IN ORDER * TO NOT CONFUSE THE DEPENDENCY CHECKING CODE IN implicit.c. * * The functions in dir.c can incorrectly cache information for "." * before we have changed directory and this can cause file * lookups to fail because the current directory (.) was pointing * at the wrong place when it was first evaluated. */ #ifdef KMK /* this is really a candidate for all platforms... */ { extern const char *default_shell; const char *bin = get_kbuild_bin_path(); char *newshell; size_t len = strlen (bin); default_shell = newshell = xmalloc (len + sizeof("/kmk_ash.exe")); memcpy (newshell, bin, len); strcpy (newshell + len, "/kmk_ash.exe"); no_default_sh_exe = 0; batch_mode_shell = 1; unixy_shell = 1; } #else /* !KMK */ no_default_sh_exe = !find_and_set_default_shell (NULL); #endif /* !KMK */ #endif /* WINDOWS32 */ /* Except under -s, always do -w in sub-makes and under -C. */ if (!silent_flag && (directories != 0 || makelevel > 0)) print_directory_flag = 1; /* Let the user disable that with --no-print-directory. */ if (inhibit_print_directory_flag) print_directory_flag = 0; /* If -R was given, set -r too (doesn't make sense otherwise!) */ if (no_builtin_variables_flag) no_builtin_rules_flag = 1; /* Construct the list of include directories to search. */ construct_include_path (include_directories == 0 ? 0 : include_directories->list); /* If we chdir'ed, figure out where we are now. */ if (directories) { #ifdef WINDOWS32 if (getcwd_fs (current_directory, GET_PATH_MAX) == 0) #else if (getcwd (current_directory, GET_PATH_MAX) == 0) #endif { #ifdef HAVE_GETCWD perror_with_name ("getcwd", ""); #else OS (error, NILF, "getwd: %s", current_directory); #endif starting_directory = 0; } else starting_directory = current_directory; } define_variable_cname ("CURDIR", current_directory, o_file, 0); /* Read any stdin makefiles into temporary files. */ if (makefiles != 0) { unsigned int i; for (i = 0; i < makefiles->idx; ++i) if (makefiles->list[i][0] == '-' && makefiles->list[i][1] == '\0') { /* This makefile is standard input. Since we may re-exec and thus re-read the makefiles, we read standard input into a temporary file and read from that. */ FILE *outfile; char *template; const char *tmpdir; if (stdin_nm) O (fatal, NILF, _("Makefile from standard input specified twice.")); #ifdef VMS # define DEFAULT_TMPDIR "/sys$scratch/" #else # ifdef P_tmpdir # define DEFAULT_TMPDIR P_tmpdir # else # define DEFAULT_TMPDIR "/tmp" # endif #endif #define DEFAULT_TMPFILE "GmXXXXXX" if (((tmpdir = getenv ("TMPDIR")) == NULL || *tmpdir == '\0') #if defined (__MSDOS__) || defined (WINDOWS32) || defined (__EMX__) /* These are also used commonly on these platforms. */ && ((tmpdir = getenv ("TEMP")) == NULL || *tmpdir == '\0') && ((tmpdir = getenv ("TMP")) == NULL || *tmpdir == '\0') #endif ) tmpdir = DEFAULT_TMPDIR; template = alloca (strlen (tmpdir) + CSTRLEN (DEFAULT_TMPFILE) + 2); strcpy (template, tmpdir); #ifdef HAVE_DOS_PATHS if (strchr ("/\\", template[strlen (template) - 1]) == NULL) strcat (template, "/"); #else # ifndef VMS if (template[strlen (template) - 1] != '/') strcat (template, "/"); # endif /* !VMS */ #endif /* !HAVE_DOS_PATHS */ strcat (template, DEFAULT_TMPFILE); outfile = output_tmpfile (&stdin_nm, template); if (outfile == 0) pfatal_with_name (_("fopen (temporary file)")); while (!feof (stdin) && ! ferror (stdin)) { char buf[2048]; unsigned int n = fread (buf, 1, sizeof (buf), stdin); if (n > 0 && fwrite (buf, 1, n, outfile) != n) pfatal_with_name (_("fwrite (temporary file)")); } fclose (outfile); /* Replace the name that read_all_makefiles will see with the name of the temporary file. */ makefiles->list[i] = strcache_add (stdin_nm); /* Make sure the temporary file will not be remade. */ { struct file *f = enter_file (strcache_add (stdin_nm)); f->updated = 1; f->update_status = us_success; f->command_state = cs_finished; /* Can't be intermediate, or it'll be removed too early for make re-exec. */ f->intermediate = 0; f->dontcare = 0; } } } #if !defined(__EMX__) || defined(__KLIBC__) /* Don't use a SIGCHLD handler for good old EMX (bird) */ #if !defined(HAVE_WAIT_NOHANG) || defined(MAKE_JOBSERVER) /* Set up to handle children dying. This must be done before reading in the makefiles so that 'shell' function calls will work. If we don't have a hanging wait we have to fall back to old, broken functionality here and rely on the signal handler and counting children. If we're using the jobs pipe we need a signal handler so that SIGCHLD is not ignored; we need it to interrupt the read(2) of the jobserver pipe if we're waiting for a token. If none of these are true, we don't need a signal handler at all. */ { # if defined SIGCHLD bsd_signal (SIGCHLD, child_handler); # endif # if defined SIGCLD && SIGCLD != SIGCHLD bsd_signal (SIGCLD, child_handler); # endif } #ifdef HAVE_PSELECT /* If we have pselect() then we need to block SIGCHLD so it's deferred. */ { sigset_t block; sigemptyset (&block); sigaddset (&block, SIGCHLD); if (sigprocmask (SIG_SETMASK, &block, NULL) < 0) pfatal_with_name ("sigprocmask(SIG_SETMASK, SIGCHLD)"); } #endif #endif #endif /* Let the user send us SIGUSR1 to toggle the -d flag during the run. */ #ifdef SIGUSR1 bsd_signal (SIGUSR1, debug_signal_handler); #endif /* Define the initial list of suffixes for old-style rules. */ set_default_suffixes (); /* Define the file rules for the built-in suffix rules. These will later be converted into pattern rules. We used to do this in install_default_implicit_rules, but since that happens after reading makefiles, it results in the built-in pattern rules taking precedence over makefile-specified suffix rules, which is wrong. */ install_default_suffix_rules (); /* Define some internal and special variables. */ define_automatic_variables (); /* Set up the MAKEFLAGS and MFLAGS variables for makefiles to see. Initialize it to be exported but allow the makefile to reset it. */ define_makeflags (0, 0)->export = v_export; /* Define the default variables. */ define_default_variables (); default_file = enter_file (strcache_add (".DEFAULT")); default_goal_var = define_variable_cname (".DEFAULT_GOAL", "", o_file, 0); /* Evaluate all strings provided with --eval. Also set up the $(-*-eval-flags-*-) variable. */ if (eval_strings) { char *p, *value; unsigned int i; unsigned int len = (CSTRLEN ("--eval=") + 1) * eval_strings->idx; for (i = 0; i < eval_strings->idx; ++i) { #ifndef CONFIG_WITH_VALUE_LENGTH p = xstrdup (eval_strings->list[i]); len += 2 * strlen (p); eval_buffer (p, NULL); #else unsigned int sub_len = strlen(eval_strings->list[i]); p = xstrndup (eval_strings->list[i], sub_len); len += 2 * sub_len; eval_buffer (p, NULL, p + sub_len); #endif free (p); } p = value = alloca (len); for (i = 0; i < eval_strings->idx; ++i) { strcpy (p, "--eval="); p += CSTRLEN ("--eval="); p = quote_for_env (p, eval_strings->list[i]); *(p++) = ' '; } p[-1] = '\0'; define_variable_cname ("-*-eval-flags-*-", value, o_automatic, 0); } /* Read all the makefiles. */ read_files = read_all_makefiles (makefiles == 0 ? 0 : makefiles->list); #ifdef WINDOWS32 /* look one last time after reading all Makefiles */ if (no_default_sh_exe) no_default_sh_exe = !find_and_set_default_shell (NULL); #endif /* WINDOWS32 */ #if defined (__MSDOS__) || defined (__EMX__) || defined (VMS) /* We need to know what kind of shell we will be using. */ { extern int _is_unixy_shell (const char *_path); struct variable *shv = lookup_variable (STRING_SIZE_TUPLE ("SHELL")); extern int unixy_shell; extern const char *default_shell; if (shv && *shv->value) { char *shell_path = recursively_expand (shv); if (shell_path && _is_unixy_shell (shell_path)) unixy_shell = 1; else unixy_shell = 0; if (shell_path) default_shell = shell_path; } } #endif /* __MSDOS__ || __EMX__ */ { int old_builtin_rules_flag = no_builtin_rules_flag; int old_builtin_variables_flag = no_builtin_variables_flag; /* Decode switches again, for variables set by the makefile. */ decode_env_switches (STRING_SIZE_TUPLE ("GNUMAKEFLAGS")); /* Clear GNUMAKEFLAGS to avoid duplication. */ define_variable_cname ("GNUMAKEFLAGS", "", o_override, 0); #ifdef KMK decode_env_switches (STRING_SIZE_TUPLE ("KMK_FLAGS")); #else /* !KMK */ decode_env_switches (STRING_SIZE_TUPLE ("MAKEFLAGS")); #if 0 decode_env_switches (STRING_SIZE_TUPLE ("MFLAGS")); #endif #endif /* !KMK */ /* Reset in case the switches changed our mind. */ syncing = (output_sync == OUTPUT_SYNC_LINE || output_sync == OUTPUT_SYNC_TARGET); if (make_sync.syncout && ! syncing) output_close (&make_sync); make_sync.syncout = syncing; OUTPUT_SET (&make_sync); /* If we've disabled builtin rules, get rid of them. */ if (no_builtin_rules_flag && ! old_builtin_rules_flag) { if (suffix_file->builtin) { free_dep_chain (suffix_file->deps); suffix_file->deps = 0; } define_variable_cname ("SUFFIXES", "", o_default, 0); } /* If we've disabled builtin variables, get rid of them. */ if (no_builtin_variables_flag && ! old_builtin_variables_flag) undefine_default_variables (); } #if defined (__MSDOS__) || defined (__EMX__) || defined (VMS) if (arg_job_slots != 1 # ifdef __EMX__ && _osmode != OS2_MODE /* turn off -j if we are in DOS mode */ # endif ) { O (error, NILF, _("Parallel jobs (-j) are not supported on this platform.")); O (error, NILF, _("Resetting to single job (-j1) mode.")); arg_job_slots = job_slots = 1; } #endif /* If we have >1 slot at this point, then we're a top-level make. Set up the jobserver. Every make assumes that it always has one job it can run. For the submakes it's the token they were given by their parent. For the top make, we just subtract one from the number the user wants. */ if (job_slots > 1 && jobserver_setup (job_slots - 1)) { /* Fill in the jobserver_auth for our children. */ jobserver_auth = jobserver_get_auth (); if (jobserver_auth) { /* We're using the jobserver so set job_slots to 0. */ master_job_slots = job_slots; job_slots = 0; } } /* If we're not using parallel jobs, then we don't need output sync. This is so people can enable output sync in GNUMAKEFLAGS or similar, but not have it take effect unless parallel builds are enabled. */ if (syncing && job_slots == 1) { OUTPUT_UNSET (); output_close (&make_sync); syncing = 0; output_sync = OUTPUT_SYNC_NONE; } #ifndef MAKE_SYMLINKS if (check_symlink_flag) { O (error, NILF, _("Symbolic links not supported: disabling -L.")); check_symlink_flag = 0; } #endif /* Set up MAKEFLAGS and MFLAGS again, so they will be right. */ define_makeflags (1, 0); /* Make each 'struct goaldep' point at the 'struct file' for the file depended on. Also do magic for special targets. */ snap_deps (); /* Convert old-style suffix rules to pattern rules. It is important to do this before installing the built-in pattern rules below, so that makefile-specified suffix rules take precedence over built-in pattern rules. */ convert_to_pattern (); /* Install the default implicit pattern rules. This used to be done before reading the makefiles. But in that case, built-in pattern rules were in the chain before user-defined ones, so they matched first. */ install_default_implicit_rules (); /* Compute implicit rule limits. */ count_implicit_rule_limits (); /* Construct the listings of directories in VPATH lists. */ build_vpath_lists (); /* Mark files given with -o flags as very old and as having been updated already, and files given with -W flags as brand new (time-stamp as far as possible into the future). If restarts is set we'll do -W later. */ if (old_files != 0) { const char **p; for (p = old_files->list; *p != 0; ++p) { struct file *f = enter_file (*p); f->last_mtime = f->mtime_before_update = OLD_MTIME; f->updated = 1; f->update_status = us_success; f->command_state = cs_finished; } } if (!restarts && new_files != 0) { const char **p; for (p = new_files->list; *p != 0; ++p) { struct file *f = enter_file (*p); f->last_mtime = f->mtime_before_update = NEW_MTIME; } } /* Initialize the remote job module. */ remote_setup (); /* Dump any output we've collected. */ OUTPUT_UNSET (); output_close (&make_sync); if (read_files != 0) { /* Update any makefiles if necessary. */ FILE_TIMESTAMP *makefile_mtimes = 0; unsigned int mm_idx = 0; char **aargv = NULL; const char **nargv; int nargc; enum update_status status; DB (DB_BASIC, (_("Updating makefiles....\n"))); /* Remove any makefiles we don't want to try to update. Also record the current modtimes so we can compare them later. */ { register struct goaldep *d, *last; last = 0; d = read_files; while (d != 0) { struct file *f = d->file; if (f->double_colon) for (f = f->double_colon; f != NULL; f = f->prev) { if (f->deps == 0 && f->cmds != 0) { /* This makefile is a :: target with commands, but no dependencies. So, it will always be remade. This might well cause an infinite loop, so don't try to remake it. (This will only happen if your makefiles are written exceptionally stupidly; but if you work for Athena, that's how you write your makefiles.) */ DB (DB_VERBOSE, (_("Makefile '%s' might loop; not remaking it.\n"), f->name)); if (last == 0) read_files = d->next; else last->next = d->next; /* Free the storage. */ free_goaldep (d); d = last == 0 ? read_files : last->next; break; } } if (f == NULL || !f->double_colon) { makefile_mtimes = xrealloc (makefile_mtimes, (mm_idx+1) * sizeof (FILE_TIMESTAMP)); makefile_mtimes[mm_idx++] = file_mtime_no_search (d->file); last = d; d = d->next; } } } /* Set up 'MAKEFLAGS' specially while remaking makefiles. */ define_makeflags (1, 1); { int orig_db_level = db_level; if (! ISDB (DB_MAKEFILES)) db_level = DB_NONE; rebuilding_makefiles = 1; status = update_goal_chain (read_files); rebuilding_makefiles = 0; db_level = orig_db_level; } switch (status) { case us_question: /* The only way this can happen is if the user specified -q and asked for one of the makefiles to be remade as a target on the command line. Since we're not actually updating anything with -q we can treat this as "did nothing". */ case us_none: /* Did nothing. */ break; case us_failed: /* Failed to update. Figure out if we care. */ { /* Nonzero if any makefile was successfully remade. */ int any_remade = 0; /* Nonzero if any makefile we care about failed in updating or could not be found at all. */ int any_failed = 0; unsigned int i; struct goaldep *d; for (i = 0, d = read_files; d != 0; ++i, d = d->next) { if (d->file->updated) { /* This makefile was updated. */ if (d->file->update_status == us_success) { /* It was successfully updated. */ any_remade |= (file_mtime_no_search (d->file) != makefile_mtimes[i]); } else if (! (d->flags & RM_DONTCARE)) { FILE_TIMESTAMP mtime; /* The update failed and this makefile was not from the MAKEFILES variable, so we care. */ OS (error, NILF, _("Failed to remake makefile '%s'."), d->file->name); mtime = file_mtime_no_search (d->file); any_remade |= (mtime != NONEXISTENT_MTIME && mtime != makefile_mtimes[i]); makefile_status = MAKE_FAILURE; } } else /* This makefile was not found at all. */ if (! (d->flags & RM_DONTCARE)) { const char *dnm = dep_name (d); size_t l = strlen (dnm); /* This is a makefile we care about. See how much. */ if (d->flags & RM_INCLUDED) /* An included makefile. We don't need to die, but we do want to complain. */ error (NILF, l, _("Included makefile '%s' was not found."), dnm); else { /* A normal makefile. We must die later. */ error (NILF, l, _("Makefile '%s' was not found"), dnm); any_failed = 1; } } } /* Reset this to empty so we get the right error message below. */ read_files = 0; if (any_remade) goto re_exec; if (any_failed) die (MAKE_FAILURE); break; } case us_success: re_exec: /* Updated successfully. Re-exec ourselves. */ remove_intermediates (0); if (print_data_base_flag) print_data_base (); clean_jobserver (0); if (makefiles != 0) { /* These names might have changed. */ int i, j = 0; for (i = 1; i < argc; ++i) if (strneq (argv[i], "-f", 2)) /* XXX */ { if (argv[i][2] == '\0') /* This cast is OK since we never modify argv. */ argv[++i] = (char *) makefiles->list[j]; else argv[i] = xstrdup (concat (2, "-f", makefiles->list[j])); ++j; } } /* Add -o option for the stdin temporary file, if necessary. */ nargc = argc; if (stdin_nm) { void *m = xmalloc ((nargc + 2) * sizeof (char *)); aargv = m; memcpy (aargv, argv, argc * sizeof (char *)); aargv[nargc++] = xstrdup (concat (2, "-o", stdin_nm)); aargv[nargc] = 0; nargv = m; } else nargv = (const char**)argv; if (directories != 0 && directories->idx > 0) { int bad = 1; if (directory_before_chdir != 0) { if (chdir (directory_before_chdir) < 0) perror_with_name ("chdir", ""); else bad = 0; } if (bad) O (fatal, NILF, _("Couldn't change back to original directory.")); } ++restarts; if (ISDB (DB_BASIC)) { const char **p; printf (_("Re-executing[%u]:"), restarts); for (p = nargv; *p != 0; ++p) printf (" %s", *p); putchar ('\n'); fflush (stdout); } #ifndef _AMIGA { char **p; for (p = environ; *p != 0; ++p) { if (strneq (*p, MAKELEVEL_NAME "=", MAKELEVEL_LENGTH+1)) { *p = alloca (40); sprintf (*p, "%s=%u", MAKELEVEL_NAME, makelevel); #ifdef VMS vms_putenv_symbol (*p); #endif } else if (strneq (*p, "MAKE_RESTARTS=", CSTRLEN ("MAKE_RESTARTS="))) { *p = alloca (40); sprintf (*p, "MAKE_RESTARTS=%s%u", OUTPUT_IS_TRACED () ? "-" : "", restarts); restarts = 0; } } } #else /* AMIGA */ { char buffer[256]; sprintf (buffer, "%u", makelevel); SetVar (MAKELEVEL_NAME, buffer, -1, GVF_GLOBAL_ONLY); sprintf (buffer, "%s%u", OUTPUT_IS_TRACED () ? "-" : "", restarts); SetVar ("MAKE_RESTARTS", buffer, -1, GVF_GLOBAL_ONLY); restarts = 0; } #endif /* If we didn't set the restarts variable yet, add it. */ if (restarts) { char *b = alloca (40); sprintf (b, "MAKE_RESTARTS=%s%u", OUTPUT_IS_TRACED () ? "-" : "", restarts); putenv (b); } fflush (stdout); fflush (stderr); #ifdef _AMIGA exec_command (nargv); exit (0); #elif defined (__EMX__) { /* It is not possible to use execve() here because this would cause the parent process to be terminated with exit code 0 before the child process has been terminated. Therefore it may be the best solution simply to spawn the child process including all file handles and to wait for its termination. */ int pid; int r; pid = child_execute_job (NULL, 1, nargv, environ); /* is this loop really necessary? */ do { pid = wait (&r); } while (pid <= 0); /* use the exit code of the child process */ exit (WIFEXITED(r) ? WEXITSTATUS(r) : EXIT_FAILURE); } #else #ifdef SET_STACK_SIZE /* Reset limits, if necessary. */ if (stack_limit.rlim_cur) setrlimit (RLIMIT_STACK, &stack_limit); #endif exec_command ((char **)nargv, environ); #endif free (aargv); break; } /* Free the makefile mtimes. */ free (makefile_mtimes); } /* Set up 'MAKEFLAGS' again for the normal targets. */ define_makeflags (1, 0); /* Set always_make_flag if -B was given. */ always_make_flag = always_make_set; /* If restarts is set we haven't set up -W files yet, so do that now. */ if (restarts && new_files != 0) { const char **p; for (p = new_files->list; *p != 0; ++p) { struct file *f = enter_file (*p); f->last_mtime = f->mtime_before_update = NEW_MTIME; } } /* If there is a temp file from reading a makefile from stdin, get rid of it now. */ if (stdin_nm && unlink (stdin_nm) < 0 && errno != ENOENT) perror_with_name (_("unlink (temporary file): "), stdin_nm); /* If there were no command-line goals, use the default. */ if (goals == 0) { char *p; if (default_goal_var->recursive) p = variable_expand (default_goal_var->value); else { p = variable_buffer_output (variable_buffer, default_goal_var->value, strlen (default_goal_var->value)); *p = '\0'; p = variable_buffer; } if (*p != '\0') { struct file *f = lookup_file (p); /* If .DEFAULT_GOAL is a non-existent target, enter it into the table and let the standard logic sort it out. */ if (f == 0) { struct nameseq *ns; ns = PARSE_SIMPLE_SEQ (&p, struct nameseq); if (ns) { /* .DEFAULT_GOAL should contain one target. */ if (ns->next != 0) O (fatal, NILF, _(".DEFAULT_GOAL contains more than one target")); #ifndef CONFIG_WITH_VALUE_LENGTH f = enter_file (strcache_add (ns->name)); #else f = enter_file (ns->name); #endif ns->name = 0; /* It was reused by enter_file(). */ free_ns_chain (ns); } } if (f) { goals = alloc_goaldep (); goals->file = f; } } } else lastgoal->next = 0; if (!goals) { if (read_files == 0) O (fatal, NILF, _("No targets specified and no makefile found")); O (fatal, NILF, _("No targets")); } /* Update the goals. */ DB (DB_BASIC, (_("Updating goal targets....\n"))); { switch (update_goal_chain (goals)) { case us_none: /* Nothing happened. */ /* FALLTHROUGH */ case us_success: /* Keep the previous result. */ break; case us_question: /* We are under -q and would run some commands. */ makefile_status = MAKE_TROUBLE; break; case us_failed: /* Updating failed. POSIX.2 specifies exit status >1 for this; */ makefile_status = MAKE_FAILURE; break; } /* If we detected some clock skew, generate one last warning */ if (clock_skew_detected) O (error, NILF, _("warning: Clock skew detected. Your build may be incomplete.")); MAKE_STATS_2(if (uStartTick) printf("main ticks elapsed: %llu\n", (unsigned long long)(CURRENT_CLOCK_TICK() - uStartTick)) ); /* Exit. */ die (makefile_status); } /* NOTREACHED */ exit (MAKE_SUCCESS); } /* Parsing of arguments, decoding of switches. */ static char options[1 + sizeof (switches) / sizeof (switches[0]) * 3]; static struct option long_options[(sizeof (switches) / sizeof (switches[0])) + (sizeof (long_option_aliases) / sizeof (long_option_aliases[0]))]; /* Fill in the string and vector for getopt. */ static void init_switches (void) { char *p; unsigned int c; unsigned int i; if (options[0] != '\0') /* Already done. */ return; p = options; /* Return switch and non-switch args in order, regardless of POSIXLY_CORRECT. Non-switch args are returned as option 1. */ *p++ = '-'; for (i = 0; switches[i].c != '\0'; ++i) { long_options[i].name = (switches[i].long_name == 0 ? "" : switches[i].long_name); long_options[i].flag = 0; long_options[i].val = switches[i].c; if (short_option (switches[i].c)) *p++ = switches[i].c; switch (switches[i].type) { case flag: case flag_off: case ignore: long_options[i].has_arg = no_argument; break; case string: case strlist: case filename: case positive_int: case floating: if (short_option (switches[i].c)) *p++ = ':'; if (switches[i].noarg_value != 0) { if (short_option (switches[i].c)) *p++ = ':'; long_options[i].has_arg = optional_argument; } else long_options[i].has_arg = required_argument; break; } } *p = '\0'; for (c = 0; c < (sizeof (long_option_aliases) / sizeof (long_option_aliases[0])); ++c) long_options[i++] = long_option_aliases[c]; long_options[i].name = 0; } /* Non-option argument. It might be a variable definition. */ static void handle_non_switch_argument (const char *arg, int env) { struct variable *v; if (arg[0] == '-' && arg[1] == '\0') /* Ignore plain '-' for compatibility. */ return; #ifdef VMS { /* VMS DCL quoting can result in foo="bar baz" showing up here. Need to remove the double quotes from the value. */ char * eq_ptr; char * new_arg; eq_ptr = strchr (arg, '='); if ((eq_ptr != NULL) && (eq_ptr[1] == '"')) { int len; int seg1; int seg2; len = strlen(arg); new_arg = alloca(len); seg1 = eq_ptr - arg + 1; strncpy(new_arg, arg, (seg1)); seg2 = len - seg1 - 1; strncpy(&new_arg[seg1], &eq_ptr[2], seg2); new_arg[seg1 + seg2] = 0; if (new_arg[seg1 + seg2 - 1] == '"') new_arg[seg1 + seg2 - 1] = 0; arg = new_arg; } } #endif v = try_variable_definition (0, arg IF_WITH_VALUE_LENGTH_PARAM(NULL), o_command, 0); if (v != 0) { /* It is indeed a variable definition. If we don't already have this one, record a pointer to the variable for later use in define_makeflags. */ struct command_variable *cv; for (cv = command_variables; cv != 0; cv = cv->next) if (cv->variable == v) break; if (! cv) { cv = xmalloc (sizeof (*cv)); cv->variable = v; cv->next = command_variables; command_variables = cv; } } else if (! env) { /* Not an option or variable definition; it must be a goal target! Enter it as a file and add it to the dep chain of goals. */ struct file *f = enter_file (strcache_add (expand_command_line_file (arg))); f->cmd_target = 1; if (goals == 0) { goals = alloc_goaldep (); lastgoal = goals; } else { lastgoal->next = alloc_goaldep (); lastgoal = lastgoal->next; } lastgoal->file = f; { /* Add this target name to the MAKECMDGOALS variable. */ struct variable *gv; const char *value; gv = lookup_variable (STRING_SIZE_TUPLE ("MAKECMDGOALS")); if (gv == 0) value = f->name; else { /* Paste the old and new values together */ unsigned int oldlen, newlen; char *vp; oldlen = strlen (gv->value); newlen = strlen (f->name); vp = alloca (oldlen + 1 + newlen + 1); memcpy (vp, gv->value, oldlen); vp[oldlen] = ' '; memcpy (&vp[oldlen + 1], f->name, newlen + 1); value = vp; } define_variable_cname ("MAKECMDGOALS", value, o_default, 0); } } } /* Print a nice usage method. */ static void print_usage (int bad) { const char *const *cpp; FILE *usageto; if (print_version_flag) print_version (); usageto = bad ? stderr : stdout; fprintf (usageto, _("Usage: %s [options] [target] ...\n"), program); for (cpp = usage; *cpp; ++cpp) fputs (_(*cpp), usageto); #ifdef KMK if (!remote_description || *remote_description == '\0') fprintf (usageto, _("\nThis program is built for %s/%s/%s [" __DATE__ " " __TIME__ "]\n"), KBUILD_HOST, KBUILD_HOST_ARCH, KBUILD_HOST_CPU); else fprintf (usageto, _("\nThis program is built for %s/%s/%s (%s) [" __DATE__ " " __TIME__ "]\n"), KBUILD_HOST, KBUILD_HOST_ARCH, KBUILD_HOST_CPU, remote_description); #else /* !KMK */ if (!remote_description || *remote_description == '\0') fprintf (usageto, _("\nThis program built for %s\n"), make_host); else fprintf (usageto, _("\nThis program built for %s (%s)\n"), make_host, remote_description); #endif /* !KMK */ fprintf (usageto, _("Report bugs to \n")); } /* Decode switches from ARGC and ARGV. They came from the environment if ENV is nonzero. */ static void decode_switches (int argc, const char **argv, int env) { int bad = 0; register const struct command_switch *cs; register struct stringlist *sl; register int c; /* getopt does most of the parsing for us. First, get its vectors set up. */ init_switches (); /* Let getopt produce error messages for the command line, but not for options from the environment. */ opterr = !env; /* Reset getopt's state. */ optind = 0; while (optind < argc) { const char *coptarg; /* Parse the next argument. */ c = getopt_long (argc, (char*const*)argv, options, long_options, NULL); coptarg = optarg; if (c == EOF) /* End of arguments, or "--" marker seen. */ break; else if (c == 1) /* An argument not starting with a dash. */ handle_non_switch_argument (coptarg, env); else if (c == '?') /* Bad option. We will print a usage message and die later. But continue to parse the other options so the user can see all he did wrong. */ bad = 1; else for (cs = switches; cs->c != '\0'; ++cs) if (cs->c == c) { /* Whether or not we will actually do anything with this switch. We test this individually inside the switch below rather than just once outside it, so that options which are to be ignored still consume args. */ int doit = !env || cs->env; switch (cs->type) { default: abort (); case ignore: break; case flag: case flag_off: if (doit) *(int *) cs->value_ptr = cs->type == flag; break; case string: case strlist: case filename: if (!doit) break; if (! coptarg) coptarg = xstrdup (cs->noarg_value); else if (*coptarg == '\0') { char opt[2] = "c"; const char *op = opt; if (short_option (cs->c)) opt[0] = cs->c; else op = cs->long_name; error (NILF, strlen (op), _("the '%s%s' option requires a non-empty string argument"), short_option (cs->c) ? "-" : "--", op); bad = 1; break; } if (cs->type == string) { char **val = (char **)cs->value_ptr; free (*val); *val = xstrdup (coptarg); break; } sl = *(struct stringlist **) cs->value_ptr; if (sl == 0) { sl = xmalloc (sizeof (struct stringlist)); sl->max = 5; sl->idx = 0; sl->list = xmalloc (5 * sizeof (char *)); *(struct stringlist **) cs->value_ptr = sl; } else if (sl->idx == sl->max - 1) { sl->max += 5; /* MSVC erroneously warns without a cast here. */ sl->list = xrealloc ((void *)sl->list, sl->max * sizeof (char *)); } if (cs->type == filename) sl->list[sl->idx++] = expand_command_line_file (coptarg); else sl->list[sl->idx++] = xstrdup (coptarg); sl->list[sl->idx] = 0; break; case positive_int: /* See if we have an option argument; if we do require that it's all digits, not something like "10foo". */ if (coptarg == 0 && argc > optind) { const char *cp; for (cp=argv[optind]; ISDIGIT (cp[0]); ++cp) ; if (cp[0] == '\0') coptarg = argv[optind++]; } if (!doit) break; if (coptarg) { int i = atoi (coptarg); const char *cp; /* Yes, I realize we're repeating this in some cases. */ for (cp = coptarg; ISDIGIT (cp[0]); ++cp) ; if (i < 1 || cp[0] != '\0') { error (NILF, 0, _("the '-%c' option requires a positive integer argument"), cs->c); bad = 1; } else *(unsigned int *) cs->value_ptr = i; } else *(unsigned int *) cs->value_ptr = *(unsigned int *) cs->noarg_value; break; #ifndef NO_FLOAT case floating: if (coptarg == 0 && optind < argc && (ISDIGIT (argv[optind][0]) || argv[optind][0] == '.')) coptarg = argv[optind++]; if (doit) *(double *) cs->value_ptr = (coptarg != 0 ? atof (coptarg) : *(double *) cs->noarg_value); break; #endif } /* We've found the switch. Stop looking. */ break; } } /* There are no more options according to getting getopt, but there may be some arguments left. Since we have asked for non-option arguments to be returned in order, this only happens when there is a "--" argument to prevent later arguments from being options. */ while (optind < argc) handle_non_switch_argument (argv[optind++], env); if (!env && (bad || print_usage_flag)) { print_usage (bad); die (bad ? MAKE_FAILURE : MAKE_SUCCESS); } /* If there are any options that need to be decoded do it now. */ decode_debug_flags (); decode_output_sync_flags (); } /* Decode switches from environment variable ENVAR (which is LEN chars long). We do this by chopping the value into a vector of words, prepending a dash to the first word if it lacks one, and passing the vector to decode_switches. */ static void decode_env_switches (const char *envar, unsigned int len) { char *varref = alloca (2 + len + 2); char *value, *p, *buf; int argc; const char **argv; /* Get the variable's value. */ varref[0] = '$'; varref[1] = '('; memcpy (&varref[2], envar, len); varref[2 + len] = ')'; varref[2 + len + 1] = '\0'; value = variable_expand (varref); /* Skip whitespace, and check for an empty value. */ NEXT_TOKEN (value); len = strlen (value); if (len == 0) return; /* Allocate a vector that is definitely big enough. */ argv = alloca ((1 + len + 1) * sizeof (char *)); /* getopt will look at the arguments starting at ARGV[1]. Prepend a spacer word. */ argv[0] = 0; argc = 1; /* We need a buffer to copy the value into while we split it into words and unquote it. Set up in case we need to prepend a dash later. */ buf = alloca (1 + len + 1); buf[0] = '-'; p = buf+1; argv[argc] = p; while (*value != '\0') { if (*value == '\\' && value[1] != '\0') ++value; /* Skip the backslash. */ else if (ISBLANK (*value)) { /* End of the word. */ *p++ = '\0'; argv[++argc] = p; do ++value; while (ISBLANK (*value)); continue; } *p++ = *value++; } *p = '\0'; argv[++argc] = 0; assert (p < buf + len + 2); if (argv[1][0] != '-' && strchr (argv[1], '=') == 0) /* The first word doesn't start with a dash and isn't a variable definition, so add a dash. */ argv[1] = buf; /* Parse those words. */ decode_switches (argc, argv, 1); } /* Quote the string IN so that it will be interpreted as a single word with no magic by decode_env_switches; also double dollar signs to avoid variable expansion in make itself. Write the result into OUT, returning the address of the next character to be written. Allocating space for OUT twice the length of IN is always sufficient. */ static char * quote_for_env (char *out, const char *in) { while (*in != '\0') { if (*in == '$') *out++ = '$'; else if (ISBLANK (*in) || *in == '\\') *out++ = '\\'; *out++ = *in++; } return out; } /* Define the MAKEFLAGS and MFLAGS variables to reflect the settings of the command switches. Include options with args if ALL is nonzero. Don't include options with the 'no_makefile' flag set if MAKEFILE. */ static struct variable * define_makeflags (int all, int makefile) { #ifdef KMK static const char ref[] = "$(KMK_OVERRIDES)"; #else static /*<- bird*/ const char ref[] = "$(MAKEOVERRIDES)"; #endif static /*<- bird*/ const char posixref[] = "$(-*-command-variables-*-)"; static /*<- bird*/ const char evalref[] = "$(-*-eval-flags-*-)"; const struct command_switch *cs; char *flagstring; char *p; /* We will construct a linked list of 'struct flag's describing all the flags which need to go in MAKEFLAGS. Then, once we know how many there are and their lengths, we can put them all together in a string. */ struct flag { struct flag *next; const struct command_switch *cs; const char *arg; }; struct flag *flags = 0; struct flag *last = 0; unsigned int flagslen = 0; #define ADD_FLAG(ARG, LEN) \ do { \ struct flag *new = alloca (sizeof (struct flag)); \ new->cs = cs; \ new->arg = (ARG); \ new->next = 0; \ if (! flags) \ flags = new; \ else \ last->next = new; \ last = new; \ if (new->arg == 0) \ /* Just a single flag letter: " -x" */ \ flagslen += 3; \ else \ /* " -xfoo", plus space to escape "foo". */ \ flagslen += 1 + 1 + 1 + (3 * (LEN)); \ if (!short_option (cs->c)) \ /* This switch has no single-letter version, so we use the long. */ \ flagslen += 2 + strlen (cs->long_name); \ } while (0) for (cs = switches; cs->c != '\0'; ++cs) if (cs->toenv && (!makefile || !cs->no_makefile)) switch (cs->type) { case ignore: break; case flag: case flag_off: if ((!*(int *) cs->value_ptr) == (cs->type == flag_off) && (cs->default_value == 0 || *(int *) cs->value_ptr != *(int *) cs->default_value)) ADD_FLAG (0, 0); break; case positive_int: if (all) { if ((cs->default_value != 0 && (*(unsigned int *) cs->value_ptr == *(unsigned int *) cs->default_value))) break; else if (cs->noarg_value != 0 && (*(unsigned int *) cs->value_ptr == *(unsigned int *) cs->noarg_value)) ADD_FLAG ("", 0); /* Optional value omitted; see below. */ else { char *buf = alloca (30); sprintf (buf, "%u", *(unsigned int *) cs->value_ptr); ADD_FLAG (buf, strlen (buf)); } } break; #ifndef NO_FLOAT case floating: if (all) { if (cs->default_value != 0 && (*(double *) cs->value_ptr == *(double *) cs->default_value)) break; else if (cs->noarg_value != 0 && (*(double *) cs->value_ptr == *(double *) cs->noarg_value)) ADD_FLAG ("", 0); /* Optional value omitted; see below. */ else { char *buf = alloca (100); sprintf (buf, "%g", *(double *) cs->value_ptr); ADD_FLAG (buf, strlen (buf)); } } break; #endif case string: if (all) { p = *((char **)cs->value_ptr); if (p) ADD_FLAG (p, strlen (p)); } break; case filename: case strlist: if (all) { struct stringlist *sl = *(struct stringlist **) cs->value_ptr; if (sl != 0) { unsigned int i; for (i = 0; i < sl->idx; ++i) ADD_FLAG (sl->list[i], strlen (sl->list[i])); } } break; default: abort (); } #undef ADD_FLAG /* Four more for the possible " -- ", plus variable references. */ flagslen += 4 + CSTRLEN (posixref) + 1 + CSTRLEN (evalref) + 1; /* Construct the value in FLAGSTRING. We allocate enough space for a preceding dash and trailing null. */ flagstring = alloca (1 + flagslen + 1); memset (flagstring, '\0', 1 + flagslen + 1); p = flagstring; /* Start with a dash, for MFLAGS. */ *p++ = '-'; /* Add simple options as a group. */ while (flags != 0 && !flags->arg && short_option (flags->cs->c)) { *p++ = flags->cs->c; flags = flags->next; } /* Now add more complex flags: ones with options and/or long names. */ while (flags) { *p++ = ' '; *p++ = '-'; /* Add the flag letter or name to the string. */ if (short_option (flags->cs->c)) *p++ = flags->cs->c; else { /* Long options require a double-dash. */ *p++ = '-'; strcpy (p, flags->cs->long_name); p += strlen (p); } /* An omitted optional argument has an ARG of "". */ if (flags->arg && flags->arg[0] != '\0') { if (!short_option (flags->cs->c)) /* Long options require '='. */ *p++ = '='; p = quote_for_env (p, flags->arg); } flags = flags->next; } /* If no flags at all, get rid of the initial dash. */ if (p == &flagstring[1]) { flagstring[0] = '\0'; p = flagstring; } #ifdef KMK /* Define MFLAGS before appending variable definitions. Omit an initial empty dash. Since MFLAGS is not parsed for flags, there is no reason to override any makefile redefinition. */ define_variable_cname ("MFLAGS", flagstring + (flagstring[0] == '-' && flagstring[1] == ' ' ? 2 : 0), o_env, 1); #endif /* !KMK */ /* Write a reference to -*-eval-flags-*-, which contains all the --eval flag options. */ if (eval_strings) { *p++ = ' '; memcpy (p, evalref, CSTRLEN (evalref)); p += CSTRLEN (evalref); } if (all && command_variables) { /* Write a reference to $(MAKEOVERRIDES), which contains all the command-line variable definitions. Separate the variables from the switches with a "--" arg. */ strcpy (p, " -- "); p += 4; /* Copy in the string. */ if (posix_pedantic) { memcpy (p, posixref, CSTRLEN (posixref)); p += CSTRLEN (posixref); } else { memcpy (p, ref, CSTRLEN (ref)); p += CSTRLEN (ref); } } /* If there is a leading dash, omit it. */ if (flagstring[0] == '-') ++flagstring; #ifdef KMK /* Provide simple access to some of the options. */ { char val[32]; sprintf (val, "%u", job_slots); define_variable_cname ("KMK_OPTS_JOBS", val, o_default, 1); define_variable_cname ("KMK_OPTS_KEEP_GOING", keep_going_flag ? "1" : "0", o_default, 1); define_variable_cname ("KMK_OPTS_JUST_PRINT", just_print_flag ? "1" : "0", o_default, 1); define_variable_cname ("KMK_OPTS_PRETTY_COMMAND_PRINTING", pretty_command_printing ? "1" : "0", o_default, 1); sprintf (val, "%u", process_priority); define_variable_cname ("KMK_OPTS_PRORITY", val, o_default, 1); sprintf (val, "%u", process_affinity); define_variable_cname ("KMK_OPTS_AFFINITY", val, o_default, 1); # if defined (CONFIG_WITH_MAKE_STATS) || defined (CONFIG_WITH_MINIMAL_STATS) define_variable_cname ("KMK_OPTS_STATISTICS", make_expensive_statistics ? "1" : "0", o_default, 1); # endif # ifdef CONFIG_WITH_PRINT_TIME_SWITCH sprintf (val, "%u", print_time_min); define_variable_cname ("KMK_OPTS_PRINT_TIME", val, o_default, 1); # endif } #endif /* This used to use o_env, but that lost when a makefile defined MAKEFLAGS. Makefiles set MAKEFLAGS to add switches, but we still want to redefine its value with the full set of switches. Then we used o_file, but that lost when users added -e, causing a previous MAKEFLAGS env. var. to take precedence over the new one. Of course, an override or command definition will still take precedence. */ #ifdef KMK return define_variable_cname ("KMK_FLAGS", flagstring, env_overrides ? o_env_override : o_file, 1); #else return define_variable_cname ("MAKEFLAGS", flagstring, env_overrides ? o_env_override : o_file, 1); #endif } /* Print version information. */ static void print_version (void) { static int printed_version = 0; const char *precede = print_data_base_flag ? "# " : ""; if (printed_version) /* Do it only once. */ return; #ifdef KMK printf ("%skmk - kBuild version %d.%d.%d (r%u)\n\ \n", precede, KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH, KBUILD_SVN_REV); printf("%sBased on GNU Make %s:\n", precede, version_string); #else /* !KMK */ printf ("%sGNU Make %s\n", precede, version_string); if (!remote_description || *remote_description == '\0') printf (_("%sBuilt for %s\n"), precede, make_host); else printf (_("%sBuilt for %s (%s)\n"), precede, make_host, remote_description); #endif /* !KMK */ /* Print this untranslated. The coding standards recommend translating the (C) to the copyright symbol, but this string is going to change every year, and none of the rest of it should be translated (including the word "Copyright"), so it hardly seems worth it. */ printf ("%sCopyright (C) 1988-2016 Free Software Foundation, Inc.\n", precede); printf (_("%sLicense GPLv3+: GNU GPL version 3 or later \n\ %sThis is free software: you are free to change and redistribute it.\n\ %sThere is NO WARRANTY, to the extent permitted by law.\n"), precede, precede, precede); #ifdef KMK printf ("\n\ %skBuild modifications:\n\ %s Copyright (c) 2005-2018 knut st. osmundsen.\n\ \n\ %skmkbuiltin commands derived from *BSD sources:\n\ %s Copyright (c) 1983 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994\n\ %s The Regents of the University of California. All rights reserved.\n\ %s Copyright (c) 1998 Todd C. Miller \n", precede, precede, precede, precede, precede, precede); # ifdef KBUILD_PATH printf (_("\n\ %sKBUILD_PATH: '%s' (default '%s')\n\ %sKBUILD_BIN_PATH: '%s' (default '%s')\n\ \n"), precede, get_kbuild_path(), KBUILD_PATH, precede, get_kbuild_bin_path(), KBUILD_BIN_PATH); # else /* !KBUILD_PATH */ printf ("\n\ %sKBUILD_PATH: '%s'\n\ %sKBUILD_BIN_PATH: '%s'\n\ \n", precede, get_kbuild_path(), precede, get_kbuild_bin_path()); # endif /* !KBUILD_PATH */ if (!remote_description || *remote_description == '\0') printf (_("%sThis program is a %s build, built for %s/%s/%s [" __DATE__ " " __TIME__ "]\n\n"), precede, KBUILD_TYPE, KBUILD_HOST, KBUILD_HOST_ARCH, KBUILD_HOST_CPU); else printf (_("%sThis program is a %s build, built for %s/%s/%s (%s) [" __DATE__ " " __TIME__ "]\n\n"), precede, KBUILD_TYPE, KBUILD_HOST, KBUILD_HOST_ARCH, KBUILD_HOST_CPU, remote_description); #endif /* KMK */ printed_version = 1; /* Flush stdout so the user doesn't have to wait to see the version information while make thinks about things. */ fflush (stdout); } /* Print a bunch of information about this and that. */ static void print_data_base (void) { time_t when = time ((time_t *) 0); print_version (); printf (_("\n# Make data base, printed on %s"), ctime (&when)); print_variable_data_base (); print_dir_data_base (); print_rule_data_base (); print_file_data_base (); print_vpath_data_base (); #ifdef KMK print_kbuild_data_base (); #endif #ifndef CONFIG_WITH_STRCACHE2 strcache_print_stats ("#"); #else strcache2_print_stats_all ("#"); #endif #ifdef CONFIG_WITH_ALLOC_CACHES alloccache_print_all (); #endif #ifdef CONFIG_WITH_COMPILER kmk_cc_print_stats (); #endif when = time ((time_t *) 0); printf (_("\n# Finished Make data base on %s\n"), ctime (&when)); } #ifdef CONFIG_WITH_PRINT_STATS_SWITCH static void print_stats () { time_t when; when = time ((time_t *) 0); printf (_("\n# Make statistics, printed on %s"), ctime (&when)); /* Allocators: */ #ifdef CONFIG_WITH_COMPILER kmk_cc_print_stats (); #endif # ifndef CONFIG_WITH_STRCACHE2 strcache_print_stats ("#"); # else strcache2_print_stats_all ("#"); # endif # ifdef CONFIG_WITH_ALLOC_CACHES alloccache_print_all (); # endif print_heap_stats (); /* Make stuff: */ print_variable_stats (); print_file_stats (); print_dir_stats (); # ifdef KMK print_kbuild_define_stats (); # endif # ifdef CONFIG_WITH_COMPILER kmk_cc_print_stats (); # endif when = time ((time_t *) 0); printf (_("\n# Finished Make statistics on %s\n"), ctime (&when)); } #endif static void clean_jobserver (int status) { /* Sanity: have we written all our jobserver tokens back? If our exit status is 2 that means some kind of syntax error; we might not have written all our tokens so do that now. If tokens are left after any other error code, that's bad. */ if (jobserver_enabled() && jobserver_tokens) { if (status != 2) ON (error, NILF, "INTERNAL: Exiting with %u jobserver tokens (should be 0)!", jobserver_tokens); else /* Don't write back the "free" token */ while (--jobserver_tokens) jobserver_release (0); } /* Sanity: If we're the master, were all the tokens written back? */ if (master_job_slots) { /* We didn't write one for ourself, so start at 1. */ unsigned int tokens = 1 + jobserver_acquire_all (); if (tokens != master_job_slots) ONN (error, NILF, "INTERNAL: Exiting with %u jobserver tokens available; should be %u!", tokens, master_job_slots); reset_jobserver (); } } /* Exit with STATUS, cleaning up as necessary. */ void die (int status) { static char dying = 0; #ifdef KMK static char need_2nd_error = 0; #endif if (!dying) { int err; dying = 1; if (print_version_flag) print_version (); #ifdef KMK /* Flag 2nd error message. */ if (status != 0 && ( job_slots_used > 0 || print_data_base_flag || print_stats_flag)) need_2nd_error = 1; #endif /* KMK */ /* Wait for children to die. */ err = (status != 0); while (job_slots_used > 0) reap_children (1, err); /* Let the remote job module clean up its state. */ remote_cleanup (); /* Remove the intermediate files. */ remove_intermediates (0); if (print_data_base_flag) print_data_base (); #ifdef CONFIG_WITH_PRINT_STATS_SWITCH if (print_stats_flag) print_stats (); #endif if (verify_flag) verify_file_data_base (); #ifdef NDEBUG /* bird: Don't waste time on debug sanity checks. */ if (print_data_base_flag || db_level) #endif verify_file_data_base (); clean_jobserver (status); if (output_context) { /* die() might be called in a recipe output context due to an $(error ...) function. */ output_close (output_context); if (output_context != &make_sync) output_close (&make_sync); OUTPUT_UNSET (); } output_close (NULL); /* Try to move back to the original directory. This is essential on MS-DOS (where there is really only one process), and on Unix it puts core files in the original directory instead of the -C directory. Must wait until after remove_intermediates(), or unlinks of relative pathnames fail. */ if (directory_before_chdir != 0) { /* If it fails we don't care: shut up GCC. */ int _x UNUSED; _x = chdir (directory_before_chdir); } #ifdef CONFIG_WITH_PRINT_TIME_SWITCH if (print_time_min != -1) { big_int elapsed = nano_timestamp () - make_start_ts; if (elapsed >= print_time_min * BIG_INT_C(1000000000)) { char buf[64]; format_elapsed_nano (buf, sizeof (buf), elapsed); message (1, strlen (buf), _("%*s"), print_time_width, buf); } } #endif } #ifdef KMK /* The failure might be lost in a -j run, so mention the failure again before exiting. */ if (need_2nd_error != 0) ON (error, NILF, _("*** Exiting with status %d"), status); #endif exit (status); } kbuild-3149/src/kmk/configure.ac0000644000175000017500000004333313252530177016556 0ustar locutuslocutus# Process this file with autoconf to produce a configure script. # # Copyright (C) 1993-2016 Free Software Foundation, Inc. # This file is part of GNU Make. # # GNU Make 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. # # GNU Make 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 . AC_INIT([GNU make],[4.2.1],[bug-make@gnu.org]) AC_PREREQ([2.69]) # Autoconf setup AC_CONFIG_AUX_DIR([config]) AC_CONFIG_SRCDIR([vpath.c]) AC_CONFIG_HEADERS([config.h]) # Automake setup # We have to enable "foreign" because ChangeLog is auto-generated # We cannot enable -Werror because gettext 0.18.1 has invalid content # When we update gettext to 0.18.3 or better we can add it again. # bird: Added subdir-objects AM_INIT_AUTOMAKE([1.15 foreign -Werror -Wall subdir-objects]) # Checks for programs. AC_USE_SYSTEM_EXTENSIONS AC_PROG_CC AC_PROG_INSTALL AC_PROG_RANLIB AC_PROG_CPP AC_CHECK_PROG([AR], [ar], [ar], [ar]) # Perl is needed for the test suite (only) AC_CHECK_PROG([PERL], [perl], [perl], [perl]) # Needed for w32/Makefile.am AM_PROG_AR # Specialized system macros AC_CANONICAL_HOST AC_AIX AC_ISC_POSIX AC_MINIX # Enable gettext, in "external" mode. # bird: causes trouble when it doesn't find 'po' in SUBDIRS, so skip it. #AM_GNU_GETTEXT_VERSION([0.19.4]) #AM_GNU_GETTEXT([external]) # This test must come as early as possible after the compiler configuration # tests, because the choice of the file model can (in principle) affect # whether functions and headers are available, whether they work, etc. AC_SYS_LARGEFILE # Checks for libraries. AC_SEARCH_LIBS([getpwnam], [sun]) # Checks for header files. AC_HEADER_STDC AC_HEADER_DIRENT AC_HEADER_STAT AC_HEADER_TIME AC_CHECK_HEADERS([stdlib.h locale.h unistd.h limits.h fcntl.h string.h \ memory.h sys/param.h sys/resource.h sys/time.h sys/timeb.h \ sys/select.h]) AM_PROG_CC_C_O AC_C_CONST AC_TYPE_SIGNAL AC_TYPE_UID_T AC_TYPE_PID_T AC_TYPE_OFF_T AC_TYPE_SIZE_T AC_TYPE_SSIZE_T AC_TYPE_UINTMAX_T # Find out whether our struct stat returns nanosecond resolution timestamps. AC_STRUCT_ST_MTIM_NSEC AC_CACHE_CHECK([whether to use high resolution file timestamps], [make_cv_file_timestamp_hi_res], [ make_cv_file_timestamp_hi_res=no AS_IF([test "$ac_cv_struct_st_mtim_nsec" != no], [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #if HAVE_INTTYPES_H # include #endif]], [[char a[0x7fffffff < (uintmax_t)-1 >> 30 ? 1 : -1];]])], [make_cv_file_timestamp_hi_res=yes]) ])]) AS_IF([test "$make_cv_file_timestamp_hi_res" = yes], [val=1], [val=0]) AC_DEFINE_UNQUOTED([FILE_TIMESTAMP_HI_RES], [$val], [Use high resolution file timestamps if nonzero.]) AS_IF([test "$make_cv_file_timestamp_hi_res" = yes], [ # Solaris 2.5.1 needs -lposix4 to get the clock_gettime function. # Solaris 7 prefers the library name -lrt to the obsolescent name -lposix4. AC_SEARCH_LIBS([clock_gettime], [rt posix4]) AS_IF([test "$ac_cv_search_clock_gettime" != no], [ AC_DEFINE([HAVE_CLOCK_GETTIME], [1], [Define to 1 if you have the clock_gettime function.]) ]) ]) # Check for DOS-style pathnames. pds_AC_DOS_PATHS # See if we have a standard version of gettimeofday(). Since actual # implementations can differ, just make sure we have the most common # one. AC_CACHE_CHECK([for standard gettimeofday], [ac_cv_func_gettimeofday], [ac_cv_func_gettimeofday=no AC_RUN_IFELSE([AC_LANG_SOURCE([[#include int main () { struct timeval t; t.tv_sec = -1; t.tv_usec = -1; exit (gettimeofday (&t, 0) != 0 || t.tv_sec < 0 || t.tv_usec < 0); }]])], [ac_cv_func_gettimeofday=yes], [ac_cv_func_gettimeofday=no], [ac_cv_func_gettimeofday="no (cross-compiling)"])]) AS_IF([test "$ac_cv_func_gettimeofday" = yes], [ AC_DEFINE([HAVE_GETTIMEOFDAY], [1], [Define to 1 if you have a standard gettimeofday function]) ]) AC_CHECK_FUNCS([strdup strndup mkstemp mktemp fdopen fileno \ dup dup2 getcwd realpath sigsetmask sigaction \ getgroups seteuid setegid setlinebuf setreuid setregid \ getrlimit setrlimit setvbuf pipe strerror strsignal \ lstat readlink atexit isatty ttyname pselect]) # We need to check declarations, not just existence, because on Tru64 this # function is not declared without special flags, which themselves cause # other problems. We'll just use our own. AC_CHECK_DECLS([bsd_signal], [], [], [[#define _GNU_SOURCE 1 #include ]]) AC_FUNC_FORK AC_FUNC_SETVBUF_REVERSED # Rumor has it that strcasecmp lives in -lresolv on some odd systems. # It doesn't hurt much to use our own if we can't find it so I don't # make the effort here. AC_CHECK_FUNCS([strcasecmp strncasecmp strcmpi strncmpi stricmp strnicmp]) # strcoll() is used by the GNU glob library AC_FUNC_STRCOLL AC_FUNC_ALLOCA AC_FUNC_CLOSEDIR_VOID # See if the user wants to add (or not) GNU Guile support PKG_PROG_PKG_CONFIG AC_ARG_WITH([guile], [AS_HELP_STRING([--with-guile], [Support GNU Guile for embedded scripting])]) # For some strange reason, at least on Ubuntu, each version of Guile # comes with it's own PC file so we have to specify them as individual # packages. Ugh. AS_IF([test "x$with_guile" != xno], [ PKG_CHECK_MODULES([GUILE], [guile-2.0], [have_guile=yes], [PKG_CHECK_MODULES([GUILE], [guile-1.8], [have_guile=yes], [have_guile=no])]) ]) AS_IF([test "$have_guile" = yes], [AC_DEFINE([HAVE_GUILE], [1], [Embed GNU Guile support])]) AM_CONDITIONAL([HAVE_GUILE], [test "$have_guile" = yes]) AC_FUNC_GETLOADAVG # AC_FUNC_GETLOADAVG is documented to set the NLIST_STRUCT value, but it # doesn't. So, we will. AS_IF([test "$ac_cv_header_nlist_h" = yes], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[struct nlist nl; nl.n_name = "string"; return 0;]])], [make_cv_nlist_struct=yes], [make_cv_nlist_struct=no]) AS_IF([test "$make_cv_nlist_struct" = yes], [ AC_DEFINE([NLIST_STRUCT], [1], [Define to 1 if struct nlist.n_name is a pointer rather than an array.]) ]) ]) AC_CHECK_DECLS([sys_siglist, _sys_siglist, __sys_siglist], , , [AC_INCLUDES_DEFAULT #include /* NetBSD declares sys_siglist in unistd.h. */ #if HAVE_UNISTD_H # include #endif ]) # Check out the wait reality. AC_CHECK_HEADERS([sys/wait.h],[],[],[[#include ]]) AC_CHECK_FUNCS([waitpid wait3]) AC_CACHE_CHECK([for union wait], [make_cv_union_wait], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include #include ]], [[union wait status; int pid; pid = wait (&status); #ifdef WEXITSTATUS /* Some POSIXoid systems have both the new-style macros and the old union wait type, and they do not work together. If union wait conflicts with WEXITSTATUS et al, we don't want to use it at all. */ if (WEXITSTATUS (status) != 0) pid = -1; #ifdef WTERMSIG /* If we have WEXITSTATUS and WTERMSIG, just use them on ints. */ -- blow chunks here -- #endif #endif #ifdef HAVE_WAITPID /* Make sure union wait works with waitpid. */ pid = waitpid (-1, &status, 0); #endif ]])], [make_cv_union_wait=yes], [make_cv_union_wait=no]) ]) AS_IF([test "$make_cv_union_wait" = yes], [ AC_DEFINE([HAVE_UNION_WAIT], [1], [Define to 1 if you have the 'union wait' type in .]) ]) # If we're building on Windows/DOS/OS/2, add some support for DOS drive specs. AS_IF([test "$PATH_SEPARATOR" = ';'], [ AC_DEFINE([HAVE_DOS_PATHS], [1], [Define to 1 if your system requires backslashes or drive specs in pathnames.]) ]) # See if the user wants to use pmake's "customs" distributed build capability AC_SUBST([REMOTE]) REMOTE=stub use_customs=false AC_ARG_WITH([customs], [AC_HELP_STRING([--with-customs=DIR], [enable remote jobs via Customs--see README.customs])], [ AS_CASE([$withval], [n|no], [:], [make_cppflags="$CPPFLAGS" AS_CASE([$withval], [y|ye|yes], [:], [CPPFLAGS="$CPPFLAGS -I$with_customs/include/customs" make_ldflags="$LDFLAGS -L$with_customs/lib"]) CF_NETLIBS AC_CHECK_HEADER([customs.h], [use_customs=true REMOTE=cstms LIBS="$LIBS -lcustoms" LDFLAGS="$make_ldflags"], [with_customs=no CPPFLAGS="$make_cppflags" make_badcust=yes]) ]) ]) # Tell automake about this, so it can include the right .c files. AM_CONDITIONAL([USE_CUSTOMS], [test "$use_customs" = true]) # See if the user asked to handle case insensitive file systems. AH_TEMPLATE([HAVE_CASE_INSENSITIVE_FS], [Use case insensitive file names]) AC_ARG_ENABLE([case-insensitive-file-system], AC_HELP_STRING([--enable-case-insensitive-file-system], [assume file systems are case insensitive]), [AS_IF([test "$enableval" = yes], [AC_DEFINE([HAVE_CASE_INSENSITIVE_FS])])]) # See if we can handle the job server feature, and if the user wants it. AC_ARG_ENABLE([job-server], AC_HELP_STRING([--disable-job-server], [disallow recursive make communication during -jN]), [make_cv_job_server="$enableval" user_job_server="$enableval"], [make_cv_job_server="yes"]) AS_IF([test "$ac_cv_func_waitpid" = no && test "$ac_cv_func_wait3" = no], [has_wait_nohang=no], [has_wait_nohang=yes]) AC_CACHE_CHECK([for SA_RESTART], [make_cv_sa_restart], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[return SA_RESTART;]])], [make_cv_sa_restart=yes], [make_cv_sa_restart=no])]) AS_IF([test "$make_cv_sa_restart" != no], [ AC_DEFINE([HAVE_SA_RESTART], [1], [Define to 1 if defines the SA_RESTART constant.]) ]) # Only allow jobserver on systems that support it AS_CASE([/$ac_cv_func_pipe/$ac_cv_func_sigaction/$make_cv_sa_restart/$has_wait_nohang/], [*/no/*], [make_cv_job_server=no]) # Also supported on OS2 and MinGW AS_CASE([$host_os], [os2*|mingw*], [make_cv_job_server=yes]) # If we support it and the user didn't disable it, build with jobserver AS_CASE([/$make_cv_job_server/$user_job_server/], [*/no/*], [: no jobserver], [AC_DEFINE(MAKE_JOBSERVER, 1, [Define to 1 to enable job server support in GNU make.]) ]) # If dl*() functions are supported we can enable the load operation AC_CHECK_DECLS([dlopen, dlsym, dlerror], [], [], [[#include ]]) AC_ARG_ENABLE([load], AC_HELP_STRING([--disable-load], [disable support for the 'load' operation]), [make_cv_load="$enableval" user_load="$enableval"], [make_cv_load="yes"]) AS_CASE([/$ac_cv_have_decl_dlopen/$ac_cv_have_decl_dlsym/$ac_cv_have_decl_dlerror/], [*/no/*], [make_cv_load=no]) # We might need -ldl AS_IF([test "$make_cv_load" = yes], [ AC_SEARCH_LIBS([dlopen], [dl], [], [make_cv_load=]) ]) AS_CASE([/$make_cv_load/$user_load/], [*/no/*], [make_cv_load=no], [AC_DEFINE(MAKE_LOAD, 1, [Define to 1 to enable 'load' support in GNU make.]) ]) # If we want load support, we might need to link with export-dynamic. # See if we can figure it out. Unfortunately this is very difficult. # For example passing -rdynamic to the SunPRO linker gives a warning # but succeeds and creates a shared object, not an executable! AS_IF([test "$make_cv_load" = yes], [ AC_MSG_CHECKING([If the linker accepts -Wl,--export-dynamic]) old_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -Wl,--export-dynamic" AC_LINK_IFELSE([AC_LANG_SOURCE([int main(){}])], [AC_MSG_RESULT([yes]) AC_SUBST([AM_LDFLAGS], [-Wl,--export-dynamic])], [AC_MSG_RESULT([no]) AC_MSG_CHECKING([If the linker accepts -rdynamic]) LDFLAGS="$old_LDFLAGS -rdynamic" AC_LINK_IFELSE([AC_LANG_SOURCE([int main(){}])], [AC_MSG_RESULT([yes]) AC_SUBST([AM_LDFLAGS], [-rdynamic])], [AC_MSG_RESULT([no])]) ]) LDFLAGS="$old_LDFLAGS" ]) # if we have both lstat() and readlink() then we can support symlink # timechecks. AS_IF([test "$ac_cv_func_lstat" = yes && test "$ac_cv_func_readlink" = yes], [ AC_DEFINE([MAKE_SYMLINKS], [1], [Define to 1 to enable symbolic link timestamp checking.]) ]) # Find the SCCS commands, so we can include them in our default rules. AC_CACHE_CHECK([for location of SCCS get command], [make_cv_path_sccs_get], [ AS_IF([test -f /usr/sccs/get], [make_cv_path_sccs_get=/usr/sccs/get], [make_cv_path_sccs_get=get]) ]) AC_DEFINE_UNQUOTED([SCCS_GET], ["$make_cv_path_sccs_get"], [Define to the name of the SCCS 'get' command.]) ac_clean_files="$ac_clean_files s.conftest conftoast" # Remove these later. AS_IF([(/usr/sccs/admin -n s.conftest || admin -n s.conftest) >/dev/null 2>&1 && test -f s.conftest], [ # We successfully created an SCCS file. AC_CACHE_CHECK([if SCCS get command understands -G], [make_cv_sys_get_minus_G], [AS_IF([$make_cv_path_sccs_get -Gconftoast s.conftest >/dev/null 2>&1 && test -f conftoast], [make_cv_sys_get_minus_G=yes], [make_cv_sys_get_minus_G=no]) ]) AS_IF([test "$make_cv_sys_get_minus_G" = yes], [AC_DEFINE([SCCS_GET_MINUS_G], [1], [Define to 1 if the SCCS 'get' command understands the '-G' option.]) ]) ]) rm -f s.conftest conftoast ## bird: always use our glob impl. Avoids trouble with newish glibc. # Check the system to see if it provides GNU glob. If not, use our # local version. #x# AC_CACHE_CHECK([if system libc has GNU glob], [make_cv_sys_gnu_glob], #x# [ AC_EGREP_CPP([gnu glob],[ #x# #include #x# #include #x# #include #x# #x# #define GLOB_INTERFACE_VERSION 1 #x# #if !defined _LIBC && defined __GNU_LIBRARY__ && __GNU_LIBRARY__ > 1 #x# # include #x# # if _GNU_GLOB_INTERFACE_VERSION == GLOB_INTERFACE_VERSION #x# gnu glob #x# # endif #x# #endif], #x# [make_cv_sys_gnu_glob=yes], #x# [make_cv_sys_gnu_glob=no])]) #x# AS_IF([test "$make_cv_sys_gnu_glob" = no], AS_IF([test yes = yes], [ GLOBINC='-I$(srcdir)/glob' GLOBLIB=glob/libglob.a make_cv_sys_gnu_glob=no ]) AC_SUBST([GLOBINC]) AC_SUBST([GLOBLIB]) # Tell automake about this, so it can build the right .c files. AM_CONDITIONAL([USE_LOCAL_GLOB], [test "$make_cv_sys_gnu_glob" = no]) # Let the makefile know what our build host is AC_DEFINE_UNQUOTED([MAKE_HOST],["$host"],[Build host information.]) MAKE_HOST="$host" AC_SUBST([MAKE_HOST]) w32_target_env=no AM_CONDITIONAL([WINDOWSENV], [false]) AS_CASE([$host], [*-*-mingw32], [AM_CONDITIONAL([WINDOWSENV], [true]) w32_target_env=yes AC_DEFINE([WINDOWS32], [1], [Use platform specific coding]) AC_DEFINE([HAVE_DOS_PATHS], [1], [Use platform specific coding]) ]) AC_DEFINE_UNQUOTED([PATH_SEPARATOR_CHAR],['$PATH_SEPARATOR'], [Define to the character that separates directories in PATH.]) # Include the Maintainer's Makefile section, if it's here. MAINT_MAKEFILE=/dev/null AS_IF([test -r "$srcdir/maintMakefile"], [ MAINT_MAKEFILE="$srcdir/maintMakefile" ]) AC_SUBST_FILE([MAINT_MAKEFILE]) # Allow building with dmalloc AM_WITH_DMALLOC # Forcibly disable SET_MAKE. If it's set it breaks things like the test # scripts, etc. SET_MAKE= # Sanity check and inform the user of what we found AS_IF([test "x$make_badcust" = xyes], [ echo echo "WARNING: --with-customs specified but no customs.h could be found;" echo " disabling Customs support." echo ]) AS_CASE([$with_customs], [""|n|no|y|ye|yes], [:], [AS_IF([test -f "$with_customs/lib/libcustoms.a"], [:], [ echo echo "WARNING: '$with_customs/lib' does not appear to contain the" echo " Customs library. You must build and install Customs" echo " before compiling GNU make." echo ])]) AS_IF([test "x$has_wait_nohang" = xno], [ echo echo "WARNING: Your system has neither waitpid() nor wait3()." echo " Without one of these, signal handling is unreliable." echo " You should be aware that running GNU make with -j" echo " could result in erratic behavior." echo ]) AS_IF([test "x$make_cv_job_server" = xno && test "x$user_job_server" = xyes], [ echo echo "WARNING: Make job server requires a POSIX-ish system that" echo " supports the pipe(), sigaction(), and either" echo " waitpid() or wait3() functions. Your system doesn't" echo " appear to provide one or more of those." echo " Disabling job server support." echo ]) AS_IF([test "x$make_cv_load" = xno && test "x$user_load" = xyes], [ echo echo "WARNING: 'load' support requires a POSIX-ish system that" echo " supports the dlopen(), dlsym(), and dlerror() functions." echo " Your system doesn't appear to provide one or more of these." echo " Disabling 'load' support." echo ]) # Specify what files are to be created. AC_CONFIG_FILES([Makefile glob/Makefile po/Makefile.in config/Makefile \ doc/Makefile w32/Makefile tests/config-flags.pm]) # OK, do it! AC_OUTPUT # We only generate the build.sh if we have a build.sh.in; we won't have # one before we've created a distribution. AS_IF([test -f "$srcdir/build.sh.in"], [ ./config.status --file build.sh chmod +x build.sh ]) dnl Local Variables: dnl comment-start: "dnl " dnl comment-end: "" dnl comment-start-skip: "\\bdnl\\b\\s *" dnl compile-command: "make configure config.h.in" dnl End: kbuild-3149/src/kmk/vmsfunctions.c0000644000175000017500000001345213252530203017157 0ustar locutuslocutus/* VMS functions Copyright (C) 1996-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" #include "debug.h" #include "job.h" #include #include #ifdef __DECC #include #endif #include #include "vmsdir.h" #ifdef HAVE_VMSDIR_H DIR * opendir (char *dspec) { struct DIR *dir = xcalloc (sizeof (struct DIR)); struct NAM *dnam = xmalloc (sizeof (struct NAM)); struct FAB *dfab = &dir->fab; char *searchspec = xmalloc (MAXNAMLEN + 1); *dfab = cc$rms_fab; *dnam = cc$rms_nam; sprintf (searchspec, "%s*.*;", dspec); dfab->fab$l_fna = searchspec; dfab->fab$b_fns = strlen (searchspec); dfab->fab$l_nam = dnam; *dnam = cc$rms_nam; dnam->nam$l_esa = searchspec; dnam->nam$b_ess = MAXNAMLEN; if (! (sys$parse (dfab) & 1)) { free (dir); free (dnam); free (searchspec); return (NULL); } return dir; } #define uppercasify(str) \ do \ { \ char *tmp; \ for (tmp = (str); *tmp != '\0'; tmp++) \ if (islower ((unsigned char)*tmp)) \ *tmp = toupper ((unsigned char)*tmp); \ } \ while (0) struct direct * readdir (DIR *dir) { struct FAB *dfab = &dir->fab; struct NAM *dnam = (struct NAM *)(dfab->fab$l_nam); struct direct *dentry = &dir->dir; int i; memset (dentry, 0, sizeof *dentry); dnam->nam$l_rsa = dir->d_result; dnam->nam$b_rss = MAXNAMLEN; DB (DB_VERBOSE, (".")); if (!((i = sys$search (dfab)) & 1)) { DB (DB_VERBOSE, (_("sys$search() failed with %d\n"), i)); return (NULL); } dentry->d_off = 0; if (dnam->nam$w_fid == 0) dentry->d_fileno = 1; else dentry->d_fileno = dnam->nam$w_fid[0] + (dnam->nam$w_fid[1] << 16); dentry->d_reclen = sizeof (struct direct); dentry->d_namlen = dnam->nam$b_name + dnam->nam$b_type; strncpy (dentry->d_name, dnam->nam$l_name, dentry->d_namlen); dentry->d_name[dentry->d_namlen] = '\0'; #ifdef HAVE_CASE_INSENSITIVE_FS uppercasify (dentry->d_name); #endif return (dentry); } int closedir (DIR *dir) { if (dir != NULL) { struct FAB *dfab = &dir->fab; struct NAM *dnam = (struct NAM *)(dfab->fab$l_nam); if (dnam != NULL) free (dnam->nam$l_esa); free (dnam); free (dir); } return 0; } #endif /* compiled for OpenVMS prior to V7.x */ /* Argv0 will be a full vms file specification, like node$dka100:[utils.gnumake]make.exe;47 prefix it with "mcr " to make it a vms command, executable for DCL. */ const char * vms_command(const char* argv0) { size_t l = strlen(argv0) + 1; char* s = xmalloc(l + 4); memcpy(s, "mcr ", 4); memcpy(s+4, argv0, l); return s; } /* Argv0 aka argv[0] will be a full vms file specification, like node$dka100:[utils.gnumake]make.exe;47, set up by the CRTL. The vms progname should be ^^^^, the file name without file type .exe and ;version. Use sys$parse to get the name part of the file specification. That is in the above example, pick up "make" and return a copy of that string. If something goes wrong in sys$parse (unlikely, this is a VMS/CRTL supplied file specification) or if there is an empty name part (not easy to produce, but it is possible) just return "make". Somes notes ... NAM[L]$M_SYNCHK requests a syntax check, only. NAM is for ODS2 names (shorter parts, output usually converted to UPPERCASE). NAML is for ODS2/ODS5 names (longer parts, output unchanged). NAM$M_NO_SHORT_UPCASE may not be available for older versions of VMS. NAML is not available on older versions of VMS (NAML$C_BID not defined). argv[0] on older versions of VMS (no extended parse style and no CRTL feature DECC$ARGV_PARSE_STYLE) is always in lowercase. */ const char * vms_progname(const char* argv0) { int status; static struct FAB fab; char *progname; const char *fallback = "make"; #ifdef NAML$C_BID static char esa[NAML$C_MAXRSS]; static struct NAML naml; #else static char esa[NAM$C_MAXRSS]; static struct NAM nam; #endif fab = cc$rms_fab; fab.fab$l_fna = (char*)argv0; fab.fab$b_fns = strlen(argv0); #ifdef NAML$C_BID fab.fab$l_naml = &naml; naml = cc$rms_naml; naml.naml$l_long_expand = esa; naml.naml$l_long_expand_alloc = NAML$C_MAXRSS; naml.naml$b_nop = NAML$M_SYNCHK; naml.naml$l_input_flags = NAML$M_NO_SHORT_OUTPUT; #else fab.fab$l_nam = &nam; nam = cc$rms_nam; nam.nam$l_esa = esa; nam.nam$b_ess = NAM$C_MAXRSS; # ifdef NAM$M_NO_SHORT_UPCASE nam.nam$b_nop = NAM$M_SYNCHK | NAM$M_NO_SHORT_UPCASE; # else nam.nam$b_nop = NAM$M_SYNCHK; # endif #endif status = sys$parse(&fab); if (!(status & 1)) return fallback; #ifdef NAML$C_BID if (naml.naml$l_long_name_size == 0) return fallback; progname = xmalloc(naml.naml$l_long_name_size + 1); memcpy(progname, naml.naml$l_long_name, naml.naml$l_long_name_size); progname[naml.naml$l_long_name_size] = '\0'; #else if (nam.nam$b_name == 0) return fallback; progname = xmalloc(nam.nam$b_name + 1); # ifdef NAM$M_NO_SHORT_UPCASE memcpy(progname, nam.nam$l_name, nam.nam$b_name); # else { int i; for (i = 0; i < nam.nam$b_name; i++) progname[i] = tolower(nam.nam$l_name[i]); } # endif progname[nam.nam$b_name] = '\0'; #endif return progname; } kbuild-3149/src/kmk/Makefile.kmk0000644000175000017500000003727013252530176016513 0ustar locutuslocutus# $Id: Makefile.kmk 3147 2018-03-15 17:29:12Z bird $ ## @file # Sub-makefile for kmk / GNU Make. # # # Copyright (c) 2004-2011 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # SUB_DEPTH = ../.. include $(KBUILD_PATH)/subheader.kmk # # Template for kmk and the kmk_* binaries in this makefile. # TEMPLATE_BIN-KMK = Template for src/gmake binaries TEMPLATE_BIN-KMK_EXTENDS = BIN-THREADED TEMPLATE_BIN-KMK_DEFS = \ HAVE_CONFIG_H \ $(TEMPLATE_BIN_DEFS) \ KBUILD_SVN_REV=$(KBUILD_SVN_REV) \ KBUILD_TYPE=\"$(KBUILD_TYPE)\" TEMPLATE_BIN-KMK_DEPS = \ $(kmk_0_OUTDIR)/config.h \ $(kmk_0_OUTDIR)/fts.h TEMPLATE_BIN-KMK_CLEAN = $(TEMPLATE_BIN-KMK_DEPS) TEMPLATE_BIN-KMK_DEPS.solaris = \ $(kmk_0_OUTDIR)/paths.h TEMPLATE_BIN-KMK_CLEAN.solaris = $(TEMPLATE_BIN-KMK_DEPS.solaris) TEMPLATE_BIN-KMK_DEPS.win = \ $(kmk_0_OUTDIR)/sysexits.h \ $(kmk_0_OUTDIR)/unistd.h \ $(kmk_0_OUTDIR)/paths.h \ $(kmk_0_OUTDIR)/grp.h \ $(kmk_0_OUTDIR)/pwd.h \ $(kmk_0_OUTDIR)/inttypes.h TEMPLATE_BIN-KMK_CFLAGS.win.amd64 = $(TEMPLATE_BIN-THREADED_CFLAGS.win.amd64) -wd4244 -wd4267 TEMPLATE_BIN-KMK_CLEAN.win = $(TEMPLATE_BIN-KMK_DEPS.win) TEMPLATE_BIN-KMK_DEFS.debug = $(TEMPLATE_BIN-KMK_DEPS.debug) MAKE_MAINTAINER_MODE TEMPLATE_BIN-KMK_INCS = $(kmk_0_OUTDIR) . $(TEMPLATE_BIN-THREADED_INCS) ifneq ($(KBUILD_TARGET),os2) TEMPLATE_BIN-KMK_INCS += glob endif TEMPLATE_BIN-KMK_LIBS = $(LIB_KUTIL) $(TEMPLATE_BIN-THREADED_LIBS) $(kmkmissing_1_TARGET) $(LIB_KUTIL) ifdef ELECTRIC_HEAP # for electric heap (see electric.c) - windows only. ifeq ($(KBUILD_TARGET),win) TEMPLATE_BIN-KMK_CFLAGS = $(TEMPLATE_BIN-THREADED_CFLAGS) /FI$(kmk_DEFPATH)/electric.h -DELECTRIC_HEAP=1 else TEMPLATE_BIN-KMK_CFLAGS = $(TEMPLATE_BIN-THREADED_CFLAGS) -include $(kmk_DEFPATH)/electric.h -DELECTRIC_HEAP=1 endif endif # GCC sanitizers. ifdef GCC_SANITIZERS TEMPLATE_BIN-KMK_CFLAGS ?= $(TEMPLATE_BIN-THREADED_CFLAGS) TEMPLATE_BIN-KMK_CFLAGS += -fsanitize=address -fsanitize=undefined -static-libubsan -D GCC_ADDRESS_SANITIZER TEMPLATE_BIN-KMK_LDFLAGS ?= $(TEMPLATE_BIN-THREADED_LDFLAGS) TEMPLATE_BIN-KMK_LDFLAGS += -fsanitize=address -fsanitize=undefined endif # # A library containing the missing features needed by kmk and the # kmk_* binaries. Saves a bit of work later on. # LIBRARIES += kmkmissing kmkmissing_TEMPLATE = BIN-KMK kmkmissing_DEFS = KMK kmkmissing_NOINST = 1 kmkmissing_SOURCES = \ kmkbuiltin/err.c \ kmkbuiltin/fts.c \ kmkbuiltin/setmode.c \ kmkbuiltin/strmode.c \ kmkbuiltin/kbuild_protection.c \ kmkbuiltin/common-env-and-cwd-opt.c \ getopt.c \ getopt1.c \ electric.c ifneq ($(KBUILD_TARGET),os2) kmkmissing_SOURCES += \ glob/glob.c endif kmkmissing_SOURCES.darwin = \ kmkbuiltin/darwin.c \ glob/fnmatch.c kmkmissing_SOURCES.dragonfly = \ glob/fnmatch.c kmkmissing_SOURCES.freebsd = \ glob/fnmatch.c kmkmissing_SOURCES.gnuhurd += \ kmkbuiltin/strlcpy.c kmkmissing_SOURCES.gnukfbsd += \ kmkbuiltin/strlcpy.c kmkmissing_SOURCES.gnuknbsd += \ kmkbuiltin/strlcpy.c kmkmissing_SOURCES.haiku = \ kmkbuiltin/haikufakes.c \ glob/fnmatch.c kmkmissing_SOURCES.linux += \ kmkbuiltin/strlcpy.c kmkmissing_SOURCES.netbsd = \ glob/fnmatch.c kmkmissing_SOURCES.openbsd = \ kmkbuiltin/openbsd.c kmkmissing_SOURCES.solaris = \ kmkbuiltin/strlcpy.c \ kmkbuiltin/solfakes.c \ glob/fnmatch.c kmkmissing_SOURCES.win += \ kmkbuiltin/strlcpy.c \ kmkbuiltin/mscfakes.c \ glob/fnmatch.c \ getloadavg.c \ w32/subproc/misc.c \ w32/subproc/w32err.c \ w32/pathstuff.c \ w32/imagecache.c \ w32/compat/posixfcn.c # # kmk # PROGRAMS += kmk kmk_TEMPLATE = BIN-KMK kmk_DEFS = \ NO_ARCHIVES \ EXPERIMENTAL \ CONFIG_WITH_TOUPPER_TOLOWER \ CONFIG_WITH_DEFINED \ CONFIG_WITH_EXPLICIT_MULTITARGET \ CONFIG_WITH_DOT_MUST_MAKE \ CONFIG_WITH_PREPEND_ASSIGNMENT \ CONFIG_WITH_LOCAL_VARIABLES \ CONFIG_WITH_2ND_TARGET_EXPANSION \ CONFIG_WITH_ALLOC_CACHES \ CONFIG_WITH_STRCACHE2 \ \ KMK \ KMK_HELPERS \ CONFIG_NO_DEFAULT_SUFFIXES \ CONFIG_NO_DEFAULT_PATTERN_RULES \ CONFIG_NO_DEFAULT_TERMINAL_RULES \ CONFIG_NO_DEFAULT_SUFFIX_RULES \ CONFIG_NO_DEFAULT_VARIABLES \ \ CONFIG_WITH_ABSPATHEX \ CONFIG_WITH_COMMANDS_FUNC \ CONFIG_WITH_DATE \ CONFIG_WITH_DEFINED_FUNCTIONS \ CONFIG_WITH_EVALPLUS \ CONFIG_WITH_FILE_SIZE \ CONFIG_WITH_LOOP_FUNCTIONS \ CONFIG_WITH_MATH \ CONFIG_WITH_NANOTS \ CONFIG_WITH_ROOT_FUNC \ CONFIG_WITH_RSORT \ CONFIG_WITH_STACK \ CONFIG_WITH_STRING_FUNCTIONS \ CONFIG_WITH_WHERE_FUNCTION \ CONFIG_WITH_WHICH \ CONFIG_WITH_XARGS \ \ CONFIG_WITH_EXTENDED_NOTPARALLEL \ CONFIG_WITH_INCLUDEDEP \ CONFIG_WITH_VALUE_LENGTH \ CONFIG_WITH_COMPARE \ CONFIG_WITH_SET_CONDITIONALS \ CONFIG_WITH_IF_CONDITIONALS \ CONFIG_WITH_PRINTF \ CONFIG_WITH_MINIMAL_STATS \ \ CONFIG_PRETTY_COMMAND_PRINTING \ CONFIG_WITH_PRINT_STATS_SWITCH \ CONFIG_WITH_PRINT_TIME_SWITCH \ CONFIG_WITH_RDONLY_VARIABLE_VALUE \ CONFIG_WITH_LAZY_DEPS_VARS \ CONFIG_WITH_MEMORY_OPTIMIZATIONS \ \ KBUILD_HOST=\"$(KBUILD_TARGET)\" \ KBUILD_HOST_ARCH=\"$(KBUILD_TARGET_ARCH)\" \ KBUILD_HOST_CPU=\"$(KBUILD_TARGET_CPU)\" # kmk_DEFS += CONFIG_WITH_COMPILER # experimental, doesn't work 101% right it seems. kmk_DEFS.x86 = CONFIG_WITH_OPTIMIZATION_HACKS kmk_DEFS.amd64 = CONFIG_WITH_OPTIMIZATION_HACKS kmk_DEFS.win = CONFIG_NEW_WIN32_CTRL_EVENT kmk_DEFS.debug = CONFIG_WITH_MAKE_STATS ifdef CONFIG_WITH_MAKE_STATS kmk_DEFS += CONFIG_WITH_MAKE_STATS endif ifdef CONFIG_WITH_EVAL_COMPILER kmk_DEFS += CONFIG_WITH_EVAL_COMPILER endif ifdef CONFIG_WITH_COMPILE_EVERYTHING kmk_DEFS += CONFIG_WITH_COMPILE_EVERYTHING endif kmk_SOURCES = \ main.c \ read.c \ hash.c \ strcache.c \ variable.c \ ar.c \ arscan.c \ commands.c \ default.c \ expand.c \ file.c \ function.c \ implicit.c \ job.c \ misc.c \ output.c \ remake.c \ rule.c \ signame.c \ version.c \ vpath.c \ remote-stub.c \ guile.c \ load.c \ \ alloccache.c \ expreval.c \ incdep.c \ strcache2.c \ kmk_cc_exec.c \ kbuild.c \ kbuild-object.c ifeq ($(KBUILD_TARGET),win) kmk_SOURCES += \ dir-nt-bird.c \ w32/w32os.c else kmk_SOURCES += \ dir.c \ posixos.c endif kmk_SOURCES.win = \ w32/subproc/sub_proc.c kmk_DEFS.freebsd.x86 = CONFIG_WITHOUT_THREADS #kmk_LIBS.solaris = malloc #kmk_DEFS.solaris += HAVE_MALLINFO # # kmkbuiltin commands # kmk_DEFS += CONFIG_WITH_KMK_BUILTIN kmk_LIBS += $(LIB_KUTIL) #$(LIB_KDEP) kmk_SOURCES += \ kmkbuiltin.c \ kmkbuiltin/append.c \ kmkbuiltin/cat.c \ kmkbuiltin/chmod.c \ kmkbuiltin/cmp.c \ kmkbuiltin/cmp_util.c \ kmkbuiltin/cp.c \ kmkbuiltin/cp_utils.c \ kmkbuiltin/echo.c \ kmkbuiltin/expr.c \ kmkbuiltin/install.c \ kmkbuiltin/kDepIDB.c \ kmkbuiltin/kDepObj.c \ ../lib/kDep.c \ kmkbuiltin/md5sum.c \ kmkbuiltin/mkdir.c \ kmkbuiltin/mv.c \ kmkbuiltin/ln.c \ kmkbuiltin/printf.c \ kmkbuiltin/redirect.c \ kmkbuiltin/rm.c \ kmkbuiltin/rmdir.c \ $(if-expr $(KBUILD_TARGET) == win,kmkbuiltin/kSubmit.c) \ kmkbuiltin/sleep.c \ kmkbuiltin/test.c \ kmkbuiltin/touch.c ## @todo kmkbuiltin/redirect.c ## Some profiling #kmk_SOURCES += kbuildprf.c #kmk_DEFS += open=prf_open read=prf_read lseek=prf_lseek close=prf_close ##kmk_DEFS += KMK_PRF=1 ##kmkmissing_DEFS += KMK_PRF=1 # # Standalone kmkbuiltin commands. # PROGRAMS += \ kmk_append \ kmk_cat \ kmk_chmod \ kmk_cp \ kmk_cmp \ kmk_echo \ kmk_expr \ kmk_md5sum \ kmk_mkdir \ kmk_mv \ kmk_install \ kmk_ln \ kmk_printf \ kmk_redirect \ kmk_rm \ kmk_rmdir \ kmk_sleep \ kmk_test \ kmk_touch \ kDepIDB \ kDepObj \ kmk_append_TEMPLATE = BIN-KMK kmk_append_DEFS = kmk_builtin_append=main kmk_append_INCS = . kmk_append_SOURCES = \ kmkbuiltin/append.c kmk_cat_TEMPLATE = BIN-KMK kmk_cat_DEFS = kmk_builtin_cat=main kmk_cat_SOURCES = \ kmkbuiltin/cat.c kmk_chmod_TEMPLATE = BIN-KMK kmk_chmod_DEFS = kmk_builtin_chmod=main kmk_chmod_SOURCES = \ kmkbuiltin/chmod.c kmk_cmp_TEMPLATE = BIN-KMK kmk_cmp_DEFS = kmk_builtin_cmp=main kmk_cmp_SOURCES = \ kmkbuiltin/cmp.c \ kmkbuiltin/cmp_util.c kmk_cp_TEMPLATE = BIN-KMK kmk_cp_DEFS = kmk_builtin_cp=main kmk_cp_SOURCES = \ kmkbuiltin/cp.c \ kmkbuiltin/cp_utils.c \ kmkbuiltin/cmp_util.c kmk_echo_TEMPLATE = BIN-KMK kmk_echo_DEFS = kmk_builtin_echo=main kmk_echo_SOURCES = \ kmkbuiltin/echo.c kmk_expr_TEMPLATE = BIN-KMK kmk_expr_DEFS = kmk_builtin_expr=main kmk_expr_SOURCES = \ kmkbuiltin/expr.c kmk_install_TEMPLATE = BIN-KMK kmk_install_DEFS = kmk_builtin_install=main kmk_install_SOURCES = \ kmkbuiltin/install.c kmk_ln_TEMPLATE = BIN-KMK kmk_ln_DEFS = kmk_builtin_ln=main kmk_ln_SOURCES = \ kmkbuiltin/ln.c kmk_mkdir_TEMPLATE = BIN-KMK kmk_mkdir_DEFS = kmk_builtin_mkdir=main kmk_mkdir_SOURCES = \ kmkbuiltin/mkdir.c kmk_md5sum_TEMPLATE = BIN-KMK kmk_md5sum_DEFS = kmk_builtin_md5sum=main kmk_md5sum_SOURCES = \ kmkbuiltin/md5sum.c kmk_md5sum_LIBS = $(LIB_KUTIL) kmk_mv_TEMPLATE = BIN-KMK kmk_mv_DEFS = kmk_builtin_mv=main kmk_mv_SOURCES = \ kmkbuiltin/mv.c kmk_printf_TEMPLATE = BIN-KMK kmk_printf_DEFS = kmk_builtin_printf=main kmk_printf_SOURCES = \ kmkbuiltin/printf.c kmk_rm_TEMPLATE = BIN-KMK kmk_rm_DEFS = kmk_builtin_rm=main kmk_rm_SOURCES = \ kmkbuiltin/rm.c kmk_redirect_TEMPLATE = BIN-KMK kmk_redirect_SOURCES = \ kmkbuiltin/redirect.c kmk_redirect_SOURCES.win = \ ../lib/startuphacks-win.c kmk_rmdir_TEMPLATE = BIN-KMK kmk_rmdir_DEFS = kmk_builtin_rmdir=main kmk_rmdir_SOURCES = \ kmkbuiltin/rmdir.c kmk_sleep_TEMPLATE = BIN-KMK kmk_sleep_DEFS = kmk_builtin_sleep=main kmk_sleep_SOURCES = \ kmkbuiltin/sleep.c kmk_test_TEMPLATE = BIN-KMK kmk_test_DEFS = kmk_builtin_test=main kmk_test_SOURCES = \ kmkbuiltin/test.c kmk_touch_TEMPLATE = BIN-KMK kmk_touch_DEFS = kmk_builtin_touch=main kmk_touch_SOURCES = \ kmkbuiltin/touch.c kDepIDB_TEMPLATE = BIN-KMK kDepIDB_DEFS = kmk_builtin_kDepIDB=main kDepIDB_INCS = . kDepIDB_LIBS = $(LIB_KDEP) $(LIB_KUTIL) kDepIDB_SOURCES = \ kmkbuiltin/kDepIDB.c kDepObj_TEMPLATE = BIN-KMK kDepObj_DEFS = kmk_builtin_kDepObj=main kDepObj_INCS = . kDepObj_LIBS = $(LIB_KDEP) $(LIB_KUTIL) kDepObj_SOURCES = \ kmkbuiltin/kDepObj.c # # kmk_gmake - almost plain GNU Make. # PROGRAMS += kmk_gmake kmk_gmake_TEMPLATE = BIN-KMK kmk_gmake_DEFS = \ HAVE_CONFIG_H \ CONFIG_WITH_TOUPPER_TOLOWER \ EXPERIMENTAL # NO_ARCHIVES kmk_gmake_SOURCES = \ main.c \ read.c \ hash.c \ strcache.c \ variable.c \ ar.c \ arscan.c \ commands.c \ default.c \ dir.c \ expand.c \ file.c \ function.c \ implicit.c \ job.c \ misc.c \ output.c \ remake.c \ rule.c \ signame.c \ version.c \ vpath.c \ remote-stub.c \ guile.c \ load.c ifeq ($(KBUILD_TARGET),win) kmk_gmake_SOURCES += \ w32/w32os.c else kmk_gmake_SOURCES += \ posixos.c endif kmk_gmake_SOURCES.win = \ w32/subproc/sub_proc.c # # kmk_fmake - Faster GNU Make. # ifeq ($(USER),bird) # for experimental purposes only. PROGRAMS += kmk_fgmake endif kmk_fgmake_TEMPLATE = BIN-KMK kmk_fgmake_DEFS = \ HAVE_CONFIG_H \ NO_ARCHIVES \ CONFIG_WITH_TOUPPER_TOLOWER \ EXPERIMENTAL \ \ CONFIG_WITH_ALLOC_CACHES \ CONFIG_WITH_LAZY_DEPS_VARS \ CONFIG_WITH_STRCACHE2 \ CONFIG_WITH_VALUE_LENGTH \ CONFIG_WITH_RDONLY_VARIABLE_VALUE # TODO ? # CONFIG_WITH_PRINT_STATS_SWITCH \ # CONFIG_WITH_EXTENDED_NOTPARALLEL \ kmk_fgmake_SOURCES = \ main.c \ read.c \ hash.c \ strcache.c \ strcache2.c \ variable.c \ ar.c \ arscan.c \ commands.c \ default.c \ dir.c \ expand.c \ file.c \ function.c \ implicit.c \ job.c \ misc.c \ output.c \ alloccache.c \ remake.c \ rule.c \ signame.c \ version.c \ vpath.c \ remote-stub.c \ guile.c \ load.c ifeq ($(KBUILD_TARGET),win) kmk_fgmake_SOURCES += \ w32/w32os.c # @todo: dir-nt-bird.c for fgmake else kmk_fgmake_SOURCES += \ posixos.c endif kmk_fgmake_SOURCES.win = \ w32/subproc/sub_proc.c # # tstFileInfo # PROGRAMS.win += tstFileInfo tstFileInfo_TEMPLATE = BIN tstFileInfo_SOURCES = w32/tstFileInfo.c # # tstFileInfo # PROGRAMS.win += tstFtsFake tstFtsFake_TEMPLATE = BIN-KMK tstFtsFake_NOINST = 1 tstFtsFake_DEFS = USE_OLD_FTS tstFtsFake_SOURCES = ../lib/nt/tstNtFts.c include $(FILE_KBUILD_SUB_FOOTER) # # Use checked in config.h instead of running ./Configure for it. # kmk_config.h.$(KBUILD_TARGET) := $(kmk_DEFPATH)/config.h.$(KBUILD_TARGET) $(kmk_0_OUTDIR)/config.h: $(kmk_config.h.$(KBUILD_TARGET)) $(MKDIR) -p $(dir $@) $(CP) $^ $@ # # Some missing headers. # if1of ($(KBUILD_TARGET), win nt) $(kmk_0_OUTDIR)/fts.h: $(MAKEFILE) | $(call DIRDEP,$(kmk_0_OUTDIR)) $(APPEND) -t "$@" "#include " else $(kmk_0_OUTDIR)/fts.h: $(kmk_DEFPATH)/kmkbuiltin/ftsfake.h | $(call DIRDEP,$(kmk_0_OUTDIR)) $(CP) $^ $@ endif $(kmk_0_OUTDIR)/unistd.h: | $(call DIRDEP,$(kmk_0_OUTDIR)) $(ECHO_EXT) > $@ $(kmk_0_OUTDIR)/sysexits.h: | $(call DIRDEP,$(kmk_0_OUTDIR)) $(ECHO_EXT) > $@ $(kmk_0_OUTDIR)/inttypes.h: | $(call DIRDEP,$(kmk_0_OUTDIR)) $(ECHO_EXT) > $@ $(kmk_0_OUTDIR)/paths.h: | $(call DIRDEP,$(kmk_0_OUTDIR)) $(ECHO_EXT) > $@ $(kmk_0_OUTDIR)/pwd.h: | $(call DIRDEP,$(kmk_0_OUTDIR)) $(ECHO_EXT) > $@ $(kmk_0_OUTDIR)/grp.h: | $(call DIRDEP,$(kmk_0_OUTDIR)) $(ECHO_EXT) > $@ # # Some tests. # parallel: parallel_1 parallel_2 parallel_3 parallel_4 parallel_5 parallel_1 parallel_2 parallel_3 parallel_4 parallel_5: echo $@_start ; sleep 1; echo $@_done my_test: echo "1" echo "2" echo "3" echo "4" # # Shell execution tests. # test_shell: test_shell_quoting test_shell_double_quoting test_shell_newline # shell double and single quoting check (was busted on windows in 3.81). test_shell_quoting: $(ECHO_EXT) "double quoted sTrInG" $(ECHO_EXT) "double quoted sTrInG" | $(SED_EXT) -e "s/sTrInG/string/g" $(ECHO_EXT) 'single quoted sTrInG' | $(SED_EXT) -e 's/sTrInG/string/g' $(ECHO) "This string should not be printed with double quotes." $(ECHO) 'This string should not be printed with single quotes.' ( echo " #define PWD \"`pwd`\""; ) test_shell_double_quoting: $(ECHO_EXT) "foo foo foo" | $(SED_EXT) -e \ "s/foo/$@/" -e \ "s/foo/works/" \ -e "s/foo/\!/" test_shell_double_quoting2: $(ECHO_EXT) "foo foo foo" | $(SED_EXT) -e \ "s/foo/$@/" -e \ "s/foo/works/" \ -e\ "s/foo/\!/" # when using batch mode shell, the newline got escaped twice and spoiling everything. test_shell_newline: $(ECHO_EXT) "foo foo foo" | $(SED_EXT) -e \ 's/foo/$@/' -e \ 's/foo/works/' \ -e 's/foo/\!/' test_stack: $(MAKE) -f $(kmk_DEFPATH)/testcase-stack.kmk test_math: $(MAKE) -f $(kmk_DEFPATH)/testcase-math.kmk test_if1of: $(MAKE) -f $(kmk_DEFPATH)/testcase-if1of.kmk test_local: $(MAKE) -f $(kmk_DEFPATH)/testcase-local.kmk test_includedep: $(MAKE) -f $(kmk_DEFPATH)/testcase-includedep.kmk test_root: $(MAKE) -f $(kmk_DEFPATH)/testcase-root.kmk test_2ndtargetexp: $(MAKE) -f $(kmk_DEFPATH)/testcase-2ndtargetexp.kmk test_30_continued_on_failure_worker: this_executable_does_not_exist.exe echo "We shouldn't see this..." test_30_continued_on_failure: $(MAKE) -f $(MAKEFILE) test_30_continued_on_failure_worker; \ RC=$$?; \ if test $${RC} -ne 2; then \ echo "$@: FAILED - exit code $${RC} instead of 2."; \ exit 1; \ else \ echo "$@: SUCCESS"; \ fi test_lazy_deps_vars: $(MAKE) -C $(kmk_DEFPATH) -f testcase-lazy-deps-vars.kmk test_all: \ test_math \ test_stack \ test_shell \ test_if1of \ test_local \ test_root \ test_includedep \ test_2ndtargetexp \ test_30_continued_on_failure \ test_lazy_deps_vars kbuild-3149/src/kmk/incdep.c0000644000175000017500000015560413252530201015667 0ustar locutuslocutus#ifdef CONFIG_WITH_INCLUDEDEP /* $Id: incdep.c 3141 2018-03-14 21:58:32Z bird $ */ /** @file * incdep - Simple dependency files. */ /* * Copyright (c) 2007-2010 knut st. osmundsen * * This file is part of kBuild. * * kBuild 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. * * kBuild 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 kBuild. If not, see * */ /******************************************************************************* * Header Files * *******************************************************************************/ #ifdef __OS2__ # define INCL_BASE # define INCL_ERRORS #endif #ifdef KBUILD_OS_WINDOWS # ifdef KMK # define INCDEP_USE_KFSCACHE # endif #endif #include "makeint.h" #if !defined(WINDOWS32) && !defined(__OS2__) # define HAVE_PTHREAD #endif #include #include #include "filedef.h" #include "dep.h" #include "job.h" #include "commands.h" #include "variable.h" #include "rule.h" #include "debug.h" #include "strcache2.h" #ifdef HAVE_FCNTL_H # include #else # include #endif #ifdef WINDOWS32 # include # include # include # define PARSE_IN_WORKER #endif #ifdef INCDEP_USE_KFSCACHE # include "nt/kFsCache.h" extern PKFSCACHE g_pFsCache; /* dir-nt-bird.c for now */ #endif #ifdef __OS2__ # include # include #endif #ifdef HAVE_PTHREAD # include #endif #ifdef __APPLE__ # include # define PARSE_IN_WORKER #endif #if defined(__gnu_linux__) || defined(__linux__) # define PARSE_IN_WORKER #endif /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ struct incdep_variable_in_set { struct incdep_variable_in_set *next; /* the parameters */ struct strcache2_entry *name_entry; /* dep strcache - WRONG */ const char *value; /* xmalloc'ed */ unsigned int value_length; int duplicate_value; /* 0 */ enum variable_origin origin; int recursive; struct variable_set *set; const floc *flocp; /* NILF */ }; struct incdep_variable_def { struct incdep_variable_def *next; /* the parameters */ const floc *flocp; /* NILF */ struct strcache2_entry *name_entry; /* dep strcache - WRONG */ char *value; /* xmalloc'ed, free it */ unsigned int value_length; enum variable_origin origin; enum variable_flavor flavor; int target_var; }; struct incdep_recorded_file { struct incdep_recorded_file *next; /* the parameters */ struct strcache2_entry *filename_entry; /* dep strcache; converted to a nameseq record. */ struct dep *deps; /* All the names are dep strcache entries. */ const floc *flocp; /* NILF */ }; /* per dep file structure. */ struct incdep { struct incdep *next; char *file_base; char *file_end; int worker_tid; #ifdef PARSE_IN_WORKER unsigned int err_line_no; const char *err_msg; struct incdep_variable_in_set *recorded_variables_in_set_head; struct incdep_variable_in_set *recorded_variables_in_set_tail; struct incdep_variable_def *recorded_variable_defs_head; struct incdep_variable_def *recorded_variable_defs_tail; struct incdep_recorded_file *recorded_file_head; struct incdep_recorded_file *recorded_file_tail; #endif #ifdef INCDEP_USE_KFSCACHE /** Pointer to the fs cache object for this file (it exists and is a file). */ PKFSOBJ pFileObj; #else char name[1]; #endif }; /******************************************************************************* * Global Variables * *******************************************************************************/ /* mutex protecting the globals and an associated condition/event. */ #ifdef HAVE_PTHREAD static pthread_mutex_t incdep_mtx; static pthread_cond_t incdep_cond_todo; static pthread_cond_t incdep_cond_done; #elif defined (WINDOWS32) static CRITICAL_SECTION incdep_mtx; static HANDLE incdep_hev_todo; static HANDLE incdep_hev_done; static int volatile incdep_hev_todo_waiters; static int volatile incdep_hev_done_waiters; #elif defined (__OS2__) static _fmutex incdep_mtx; static HEV incdep_hev_todo; static HEV incdep_hev_done; static int volatile incdep_hev_todo_waiters; static int volatile incdep_hev_done_waiters; #endif /* flag indicating whether the threads, lock and event/condvars has been initialized or not. */ static int incdep_initialized; /* the list of files that needs reading. */ static struct incdep * volatile incdep_head_todo; static struct incdep * volatile incdep_tail_todo; /* the number of files that are currently being read. */ static int volatile incdep_num_reading; /* the list of files that have been read. */ static struct incdep * volatile incdep_head_done; static struct incdep * volatile incdep_tail_done; /* The handles to the worker threads. */ #ifdef HAVE_PTHREAD # define INCDEP_MAX_THREADS 1 static pthread_t incdep_threads[INCDEP_MAX_THREADS]; #elif defined (WINDOWS32) # define INCDEP_MAX_THREADS 2 static HANDLE incdep_threads[INCDEP_MAX_THREADS]; #elif defined (__OS2__) # define INCDEP_MAX_THREADS 2 static TID incdep_threads[INCDEP_MAX_THREADS]; #endif static struct alloccache incdep_rec_caches[INCDEP_MAX_THREADS]; static struct alloccache incdep_dep_caches[INCDEP_MAX_THREADS]; static struct strcache2 incdep_dep_strcaches[INCDEP_MAX_THREADS]; static struct strcache2 incdep_var_strcaches[INCDEP_MAX_THREADS]; static unsigned incdep_num_threads; /* flag indicating whether the worker threads should terminate or not. */ static int volatile incdep_terminate; #ifdef __APPLE__ /* malloc zone for the incdep threads. */ static malloc_zone_t *incdep_zone; #endif /******************************************************************************* * Internal Functions * *******************************************************************************/ static void incdep_flush_it (floc *); static void eval_include_dep_file (struct incdep *, floc *); static void incdep_commit_recorded_file (const char *filename, struct dep *deps, const floc *flocp); /* xmalloc wrapper. For working around multithreaded performance problems found on Darwin, Linux (glibc), and possibly other systems. */ static void * incdep_xmalloc (struct incdep *cur, size_t size) { void *ptr; #ifdef __APPLE__ if (cur && cur->worker_tid != -1) { ptr = malloc_zone_malloc (incdep_zone, size); if (!ptr) fatal (NILF, _("virtual memory exhausted")); } else ptr = xmalloc (size); #else ptr = xmalloc (size); #endif (void)cur; return ptr; } #if 0 /* cmalloc wrapper */ static void * incdep_xcalloc (struct incdep *cur, size_t size) { void *ptr; #ifdef __APPLE__ if (cur && cur->worker_tid != -1) ptr = malloc_zone_calloc (incdep_zone, size, 1); else ptr = calloc (size, 1); #else ptr = calloc (size, 1); #endif if (!ptr) fatal (NILF, _("virtual memory exhausted")); (void)cur; return ptr; } #endif /* unused */ /* free wrapper */ static void incdep_xfree (struct incdep *cur, void *ptr) { /* free() *must* work for the allocation hacks above because of free_dep_chain. */ free (ptr); (void)cur; } /* alloc a dep structure. These are allocated in bunches to save time. */ struct dep * incdep_alloc_dep (struct incdep *cur) { struct alloccache *cache; if (cur->worker_tid != -1) cache = &incdep_dep_caches[cur->worker_tid]; else cache = &dep_cache; return alloccache_calloc (cache); } /* duplicates the dependency list pointed to by srcdep. */ static struct dep * incdep_dup_dep_list (struct incdep *cur, struct dep const *srcdep) { struct alloccache *cache; struct dep *retdep; struct dep *dstdep; if (cur->worker_tid != -1) cache = &incdep_dep_caches[cur->worker_tid]; else cache = &dep_cache; if (srcdep) { retdep = dstdep = alloccache_alloc (cache); for (;;) { dstdep->name = srcdep->name; /* string cached */ dstdep->includedep = srcdep->includedep; srcdep = srcdep->next; if (!srcdep) { dstdep->next = NULL; break; } dstdep->next = alloccache_alloc (cache); dstdep = dstdep->next; } } else retdep = NULL; return retdep; } /* allocate a record. */ static void * incdep_alloc_rec (struct incdep *cur) { return alloccache_alloc (&incdep_rec_caches[cur->worker_tid]); } /* free a record. */ static void incdep_free_rec (struct incdep *cur, void *rec) { /*alloccache_free (&incdep_rec_caches[cur->worker_tid], rec); - doesn't work of course. */ } /* grow a cache. */ static void * incdep_cache_allocator (void *thrd, unsigned int size) { (void)thrd; #ifdef __APPLE__ return malloc_zone_malloc (incdep_zone, size); #else return xmalloc (size); #endif } /* term a cache. */ static void incdep_cache_deallocator (void *thrd, void *ptr, unsigned int size) { (void)thrd; (void)size; free (ptr); } /* acquires the lock */ void incdep_lock(void) { #if defined (HAVE_PTHREAD) && !defined (CONFIG_WITHOUT_THREADS) pthread_mutex_lock (&incdep_mtx); #elif defined (WINDOWS32) EnterCriticalSection (&incdep_mtx); #elif defined (__OS2__) _fmutex_request (&incdep_mtx, 0); #endif } /* releases the lock */ void incdep_unlock(void) { #if defined (HAVE_PTHREAD) && !defined (CONFIG_WITHOUT_THREADS) pthread_mutex_unlock (&incdep_mtx); #elif defined(WINDOWS32) LeaveCriticalSection (&incdep_mtx); #elif defined(__OS2__) _fmutex_release (&incdep_mtx); #endif } /* signals the main thread that there is stuff todo. caller owns the lock. */ static void incdep_signal_done (void) { #if defined (HAVE_PTHREAD) && !defined (CONFIG_WITHOUT_THREADS) pthread_cond_broadcast (&incdep_cond_done); #elif defined (WINDOWS32) if (incdep_hev_done_waiters) SetEvent (incdep_hev_done); #elif defined (__OS2__) if (incdep_hev_done_waiters) DosPostEventSem (incdep_hev_done); #endif } /* waits for a reader to finish reading. caller owns the lock. */ static void incdep_wait_done (void) { #if defined (HAVE_PTHREAD) && !defined (CONFIG_WITHOUT_THREADS) pthread_cond_wait (&incdep_cond_done, &incdep_mtx); #elif defined (WINDOWS32) ResetEvent (incdep_hev_done); incdep_hev_done_waiters++; incdep_unlock (); WaitForSingleObject (incdep_hev_done, INFINITE); incdep_lock (); incdep_hev_done_waiters--; #elif defined (__OS2__) ULONG ulIgnore; DosResetEventSem (incdep_hev_done, &ulIgnore); incdep_hev_done_waiters++; incdep_unlock (); DosWaitEventSem (incdep_hev_done, SEM_INDEFINITE_WAIT); incdep_lock (); incdep_hev_done_waiters--; #endif } /* signals the worker threads. caller owns the lock. */ static void incdep_signal_todo (void) { #if defined (HAVE_PTHREAD) && !defined (CONFIG_WITHOUT_THREADS) pthread_cond_broadcast (&incdep_cond_todo); #elif defined(WINDOWS32) if (incdep_hev_todo_waiters) SetEvent (incdep_hev_todo); #elif defined(__OS2__) if (incdep_hev_todo_waiters) DosPostEventSem (incdep_hev_todo); #endif } /* waits for stuff to arrive in the todo list. caller owns the lock. */ static void incdep_wait_todo (void) { #if defined (HAVE_PTHREAD) && !defined (CONFIG_WITHOUT_THREADS) pthread_cond_wait (&incdep_cond_todo, &incdep_mtx); #elif defined (WINDOWS32) ResetEvent (incdep_hev_todo); incdep_hev_todo_waiters++; incdep_unlock (); WaitForSingleObject (incdep_hev_todo, INFINITE); incdep_lock (); incdep_hev_todo_waiters--; #elif defined (__OS2__) ULONG ulIgnore; DosResetEventSem (incdep_hev_todo, &ulIgnore); incdep_hev_todo_waiters++; incdep_unlock (); DosWaitEventSem (incdep_hev_todo, SEM_INDEFINITE_WAIT); incdep_lock (); incdep_hev_todo_waiters--; #endif } /* Reads a dep file into memory. */ static int incdep_read_file (struct incdep *cur, floc *f) { #ifdef INCDEP_USE_KFSCACHE size_t const cbFile = (size_t)cur->pFileObj->Stats.st_size; assert(cur->pFileObj->fHaveStats); cur->file_base = incdep_xmalloc (cur, cbFile + 1); if (cur->file_base) { if (kFsCacheFileSimpleOpenReadClose (g_pFsCache, cur->pFileObj, 0, cur->file_base, cbFile)) { cur->file_end = cur->file_base + cbFile; cur->file_base[cbFile] = '\0'; return 0; } incdep_xfree (cur, cur->file_base); } OSS (error, f, "%s/%s: error reading file", cur->pFileObj->pParent->Obj.pszName, cur->pFileObj->pszName); #else /* !INCDEP_USE_KFSCACHE */ int fd; struct stat st; errno = 0; # ifdef O_BINARY fd = open (cur->name, O_RDONLY | O_BINARY, 0); # else fd = open (cur->name, O_RDONLY, 0); # endif if (fd < 0) { /* ignore non-existing dependency files. */ int err = errno; if (err == ENOENT || stat (cur->name, &st) != 0) return 1; OSS (error, f, "%s: %s", cur->name, strerror (err)); return -1; } # ifdef KBUILD_OS_WINDOWS /* fewer kernel calls */ if (!birdStatOnFdJustSize (fd, &st.st_size)) # else if (!fstat (fd, &st)) # endif { cur->file_base = incdep_xmalloc (cur, st.st_size + 1); if (read (fd, cur->file_base, st.st_size) == st.st_size) { close (fd); cur->file_end = cur->file_base + st.st_size; cur->file_base[st.st_size] = '\0'; return 0; } /* bail out */ OSS (error, f, "%s: read: %s", cur->name, strerror (errno)); incdep_xfree (cur, cur->file_base); } else OSS (error, f, "%s: fstat: %s", cur->name, strerror (errno)); close (fd); #endif /* !INCDEP_USE_KFSCACHE */ cur->file_base = cur->file_end = NULL; return -1; } /* Free the incdep structure. */ static void incdep_freeit (struct incdep *cur) { #ifdef PARSE_IN_WORKER assert (!cur->recorded_variables_in_set_head); assert (!cur->recorded_variable_defs_head); assert (!cur->recorded_file_head); #endif incdep_xfree (cur, cur->file_base); #ifdef INCDEP_USE_KFSCACHE /** @todo release object ref some day... */ #endif cur->next = NULL; free (cur); } /* A worker thread. */ void incdep_worker (int thrd) { incdep_lock (); while (!incdep_terminate) { /* get job from the todo list. */ struct incdep *cur = incdep_head_todo; if (!cur) { incdep_wait_todo (); continue; } if (cur->next) incdep_head_todo = cur->next; else incdep_head_todo = incdep_tail_todo = NULL; incdep_num_reading++; /* read the file. */ incdep_unlock (); cur->worker_tid = thrd; incdep_read_file (cur, NILF); #ifdef PARSE_IN_WORKER eval_include_dep_file (cur, NILF); #endif cur->worker_tid = -1; incdep_lock (); /* insert finished job into the done list. */ incdep_num_reading--; cur->next = NULL; if (incdep_tail_done) incdep_tail_done->next = cur; else incdep_head_done = cur; incdep_tail_done = cur; incdep_signal_done (); } incdep_unlock (); } /* Thread library specific thread functions wrapping incdep_wroker. */ #ifdef HAVE_PTHREAD static void * incdep_worker_pthread (void *thrd) { incdep_worker ((size_t)thrd); return NULL; } #elif defined (WINDOWS32) static unsigned __stdcall incdep_worker_windows (void *thrd) { incdep_worker ((size_t)thrd); return 0; } #elif defined (__OS2__) static void incdep_worker_os2 (void *thrd) { incdep_worker ((size_t)thrd); } #endif /* Checks if threads are enabled or not. This is a special hack so that is possible to disable the threads when in a debian fakeroot environment. Thus, in addition to the KMK_THREADS_DISABLED and KMK_THREADS_ENABLED environment variable check we also check for signs of fakeroot. */ static int incdep_are_threads_enabled (void) { #if defined (CONFIG_WITHOUT_THREADS) return 0; #endif /* Generic overrides. */ if (getenv ("KMK_THREADS_DISABLED")) { O (message, 1, "Threads disabled (environment)"); return 0; } if (getenv ("KMK_THREADS_ENABLED")) return 1; #if defined (__gnu_linux__) || defined (__linux__) || defined(__GLIBC__) /* Try detect fakeroot. */ if (getenv ("FAKEROOTKEY") || getenv ("FAKEROOTUID") || getenv ("FAKEROOTGID") || getenv ("FAKEROOTEUID") || getenv ("FAKEROOTEGID") || getenv ("FAKEROOTSUID") || getenv ("FAKEROOTSGID") || getenv ("FAKEROOTFUID") || getenv ("FAKEROOTFGID") || getenv ("FAKEROOTDONTTRYCHOWN") || getenv ("FAKEROOT_FD_BASE") || getenv ("FAKEROOT_DB_SEARCH_PATHS")) { O (message, 1, "Threads disabled (fakeroot)"); return 0; } /* LD_PRELOAD could indicate undetected debian fakeroot or some other ingenius library which cannot deal correctly with threads. */ if (getenv ("LD_PRELOAD")) { O (message, 1, "Threads disabled (LD_PRELOAD)"); return 0; } #elif defined(__APPLE__) \ || defined(__sun__) || defined(__SunOS__) || defined(__sun) || defined(__SunOS) \ || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) \ || defined(__HAIKU__) /* No broken preload libraries known to be in common use on these platforms... */ #elif defined(_MSC_VER) || defined(_WIN32) || defined(__OS2__) /* No preload mess to care about. */ #else # error "Add your self to the appropriate case above and send a patch to bird." #endif return 1; } /* Creates the the worker threads. */ static void incdep_init (floc *f) { unsigned i; #if defined (HAVE_PTHREAD) && !defined (CONFIG_WITHOUT_THREADS) int rc; pthread_attr_t attr; #elif defined (WINDOWS32) unsigned tid; uintptr_t hThread; #elif defined (__OS2__) int rc; int tid; #endif (void)f; /* heap hacks */ #ifdef __APPLE__ incdep_zone = malloc_create_zone (0, 0); if (!incdep_zone) incdep_zone = malloc_default_zone (); #endif /* create the mutex and two condition variables / event objects. */ #if defined (HAVE_PTHREAD) && !defined (CONFIG_WITHOUT_THREADS) rc = pthread_mutex_init (&incdep_mtx, NULL); if (rc) ON (fatal, f, _("pthread_mutex_init failed: err=%d"), rc); rc = pthread_cond_init (&incdep_cond_todo, NULL); if (rc) ON (fatal, f, _("pthread_cond_init failed: err=%d"), rc); rc = pthread_cond_init (&incdep_cond_done, NULL); if (rc) ON (fatal, f, _("pthread_cond_init failed: err=%d"), rc); #elif defined (WINDOWS32) InitializeCriticalSection (&incdep_mtx); incdep_hev_todo = CreateEvent (NULL, TRUE /*bManualReset*/, FALSE /*bInitialState*/, NULL); if (!incdep_hev_todo) ON (fatal, f, _("CreateEvent failed: err=%d"), GetLastError()); incdep_hev_done = CreateEvent (NULL, TRUE /*bManualReset*/, FALSE /*bInitialState*/, NULL); if (!incdep_hev_done) ON (fatal, f, _("CreateEvent failed: err=%d"), GetLastError()); incdep_hev_todo_waiters = 0; incdep_hev_done_waiters = 0; #elif defined (__OS2__) _fmutex_create (&incdep_mtx, 0); rc = DosCreateEventSem (NULL, &incdep_hev_todo, 0, FALSE); if (rc) ON (fatal, f, _("DosCreateEventSem failed: rc=%d"), rc); rc = DosCreateEventSem (NULL, &incdep_hev_done, 0, FALSE); if (rc) ON (fatal, f, _("DosCreateEventSem failed: rc=%d"), rc); incdep_hev_todo_waiters = 0; incdep_hev_done_waiters = 0; #endif /* create the worker threads and associated per thread data. */ incdep_terminate = 0; if (incdep_are_threads_enabled()) { incdep_num_threads = sizeof (incdep_threads) / sizeof (incdep_threads[0]); if (incdep_num_threads + 1 > job_slots) incdep_num_threads = job_slots <= 1 ? 1 : job_slots - 1; for (i = 0; i < incdep_num_threads; i++) { /* init caches */ unsigned rec_size = sizeof (struct incdep_variable_in_set); if (rec_size < sizeof (struct incdep_variable_def)) rec_size = sizeof (struct incdep_variable_def); if (rec_size < sizeof (struct incdep_recorded_file)) rec_size = sizeof (struct incdep_recorded_file); alloccache_init (&incdep_rec_caches[i], rec_size, "incdep rec", incdep_cache_allocator, (void *)(size_t)i); alloccache_init (&incdep_dep_caches[i], sizeof(struct dep), "incdep dep", incdep_cache_allocator, (void *)(size_t)i); strcache2_init (&incdep_dep_strcaches[i], "incdep dep", /* name */ 65536, /* hash size */ 0, /* default segment size*/ #ifdef HAVE_CASE_INSENSITIVE_FS 1, /* case insensitive */ #else 0, /* case insensitive */ #endif 0); /* thread safe */ strcache2_init (&incdep_var_strcaches[i], "incdep var", /* name */ 32768, /* hash size */ 0, /* default segment size*/ 0, /* case insensitive */ 0); /* thread safe */ /* create the thread. */ #if defined (HAVE_PTHREAD) && !defined (CONFIG_WITHOUT_THREADS) rc = pthread_attr_init (&attr); if (rc) ON (fatal, f, _("pthread_attr_init failed: err=%d"), rc); /*rc = pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE); */ rc = pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); if (rc) ON (fatal, f, _("pthread_attr_setdetachstate failed: err=%d"), rc); rc = pthread_create (&incdep_threads[i], &attr, incdep_worker_pthread, (void *)(size_t)i); if (rc) ON (fatal, f, _("pthread_mutex_init failed: err=%d"), rc); pthread_attr_destroy (&attr); #elif defined (WINDOWS32) tid = 0; hThread = _beginthreadex (NULL, 128*1024, incdep_worker_windows, (void *)i, 0, &tid); if (hThread == 0 || hThread == ~(uintptr_t)0) ON (fatal, f, _("_beginthreadex failed: err=%d"), errno); incdep_threads[i] = (HANDLE)hThread; #elif defined (__OS2__) tid = _beginthread (incdep_worker_os2, NULL, 128*1024, (void *)i); if (tid <= 0) ON (fatal, f, _("_beginthread failed: err=%d"), errno); incdep_threads[i] = tid; #endif } } else incdep_num_threads = 0; incdep_initialized = 1; } /* Flushes outstanding work and terminates the worker threads. This is called from snap_deps(). */ void incdep_flush_and_term (void) { unsigned i; if (!incdep_initialized) return; /* flush any out standing work */ incdep_flush_it (NILF); /* tell the threads to terminate */ incdep_lock (); incdep_terminate = 1; incdep_signal_todo (); incdep_unlock (); /* wait for the threads to quit */ for (i = 0; i < incdep_num_threads; i++) { /* more later? */ /* terminate or join up the allocation caches. */ alloccache_term (&incdep_rec_caches[i], incdep_cache_deallocator, (void *)(size_t)i); alloccache_join (&dep_cache, &incdep_dep_caches[i]); strcache2_term (&incdep_dep_strcaches[i]); strcache2_term (&incdep_var_strcaches[i]); } incdep_num_threads = 0; /* destroy the lock and condition variables / event objects. */ /* later */ incdep_initialized = 0; } #ifdef PARSE_IN_WORKER /* Flushes a strcache entry returning the actual string cache entry. The input is freed! */ static const char * incdep_flush_strcache_entry (struct strcache2_entry *entry) { if (!entry->user) entry->user = (void *) strcache2_add_hashed_file (&file_strcache, (const char *)(entry + 1), entry->length, entry->hash); return (const char *)entry->user; } /* Flushes the recorded instructions. */ static void incdep_flush_recorded_instructions (struct incdep *cur) { struct incdep_variable_in_set *rec_vis; struct incdep_variable_def *rec_vd; struct incdep_recorded_file *rec_f; /* Display saved error. */ if (cur->err_msg) #ifdef INCDEP_USE_KFSCACHE OSSNS (error, NILF, "%s/%s(%d): %s", cur->pFileObj->pParent->Obj.pszName, cur->pFileObj->pszName, cur->err_line_no, cur->err_msg); #else OSNS (error,NILF, "%s(%d): %s", cur->name, cur->err_line_no, cur->err_msg); #endif /* define_variable_in_set */ rec_vis = cur->recorded_variables_in_set_head; cur->recorded_variables_in_set_head = cur->recorded_variables_in_set_tail = NULL; if (rec_vis) do { void *free_me = rec_vis; unsigned int name_length = rec_vis->name_entry->length; define_variable_in_set (incdep_flush_strcache_entry (rec_vis->name_entry), name_length, rec_vis->value, rec_vis->value_length, rec_vis->duplicate_value, rec_vis->origin, rec_vis->recursive, rec_vis->set, rec_vis->flocp); rec_vis = rec_vis->next; incdep_free_rec (cur, free_me); } while (rec_vis); /* do_variable_definition */ rec_vd = cur->recorded_variable_defs_head; cur->recorded_variable_defs_head = cur->recorded_variable_defs_tail = NULL; if (rec_vd) do { void *free_me = rec_vd; do_variable_definition_2 (rec_vd->flocp, incdep_flush_strcache_entry (rec_vd->name_entry), rec_vd->value, rec_vd->value_length, 0, rec_vd->value, rec_vd->origin, rec_vd->flavor, rec_vd->target_var); rec_vd = rec_vd->next; incdep_free_rec (cur, free_me); } while (rec_vd); /* record_files */ rec_f = cur->recorded_file_head; cur->recorded_file_head = cur->recorded_file_tail = NULL; if (rec_f) do { void *free_me = rec_f; struct dep *dep; for (dep = rec_f->deps; dep; dep = dep->next) dep->name = incdep_flush_strcache_entry ((struct strcache2_entry *)dep->name); incdep_commit_recorded_file (incdep_flush_strcache_entry (rec_f->filename_entry), rec_f->deps, rec_f->flocp); rec_f = rec_f->next; incdep_free_rec (cur, free_me); } while (rec_f); } #endif /* PARSE_IN_WORKER */ /* Record / issue a warning about a misformed dep file. */ static void incdep_warn (struct incdep *cur, unsigned int line_no, const char *msg) { if (cur->worker_tid == -1) #ifdef INCDEP_USE_KFSCACHE OSSNS (error,NILF, "%s/%s(%d): %s", cur->pFileObj->pParent->Obj.pszName, cur->pFileObj->pszName, line_no, msg); #else OSNS (error, NILF, "%s(%d): %s", cur->name, line_no, msg); #endif #ifdef PARSE_IN_WORKER else { cur->err_line_no = line_no; cur->err_msg = msg; } #endif } /* Dependency or file strcache allocation / recording. */ static const char * incdep_dep_strcache (struct incdep *cur, const char *str, int len) { const char *ret; if (cur->worker_tid == -1) { /* Make sure the string is terminated before we hand it to strcache_add_len so it does have to make a temporary copy of it on the stack. */ char ch = str[len]; ((char *)str)[len] = '\0'; ret = strcache_add_len (str, len); ((char *)str)[len] = ch; } else { /* Add it out the strcache of the thread. */ ret = strcache2_add (&incdep_dep_strcaches[cur->worker_tid], str, len); ret = (const char *)strcache2_get_entry(&incdep_dep_strcaches[cur->worker_tid], ret); } return ret; } /* Variable name allocation / recording. */ static const char * incdep_var_strcache (struct incdep *cur, const char *str, int len) { const char *ret; if (cur->worker_tid == -1) { /* XXX: we're leaking this memory now! This will be fixed later. */ ret = xmalloc (len + 1); memcpy ((char *)ret, str, len); ((char *)ret)[len] = '\0'; } else { /* Add it out the strcache of the thread. */ ret = strcache2_add (&incdep_var_strcaches[cur->worker_tid], str, len); ret = (const char *)strcache2_get_entry(&incdep_var_strcaches[cur->worker_tid], ret); } return ret; } /* Record / perform a variable definition in a set. The NAME is in the string cache. The VALUE is on the heap. The DUPLICATE_VALUE is always 0. */ static void incdep_record_variable_in_set (struct incdep *cur, const char *name, unsigned int name_length, const char *value, unsigned int value_length, int duplicate_value, enum variable_origin origin, int recursive, struct variable_set *set, const floc *flocp) { assert (!duplicate_value); if (cur->worker_tid == -1) define_variable_in_set (name, name_length, value, value_length, duplicate_value, origin, recursive, set, flocp); #ifdef PARSE_IN_WORKER else { struct incdep_variable_in_set *rec = (struct incdep_variable_in_set *)incdep_alloc_rec (cur); rec->name_entry = (struct strcache2_entry *)name; rec->value = value; rec->value_length = value_length; rec->duplicate_value = duplicate_value; rec->origin = origin; rec->recursive = recursive; rec->set = set; rec->flocp = flocp; rec->next = NULL; if (cur->recorded_variables_in_set_tail) cur->recorded_variables_in_set_tail->next = rec; else cur->recorded_variables_in_set_head = rec; cur->recorded_variables_in_set_tail = rec; } #endif } /* Record / perform a variable definition. The VALUE should be disposed of. */ static void incdep_record_variable_def (struct incdep *cur, const floc *flocp, const char *name, unsigned int name_length, char *value, unsigned int value_length, enum variable_origin origin, enum variable_flavor flavor, int target_var) { if (cur->worker_tid == -1) do_variable_definition_2 (flocp, name, value, value_length, 0, value, origin, flavor, target_var); #ifdef PARSE_IN_WORKER else { struct incdep_variable_def *rec = (struct incdep_variable_def *)incdep_alloc_rec (cur); rec->flocp = flocp; rec->name_entry = (struct strcache2_entry *)name; rec->value = value; rec->value_length = value_length; rec->origin = origin; rec->flavor = flavor; rec->target_var = target_var; rec->next = NULL; if (cur->recorded_variable_defs_tail) cur->recorded_variable_defs_tail->next = rec; else cur->recorded_variable_defs_head = rec; cur->recorded_variable_defs_tail = rec; } #else (void)name_length; #endif } /* Similar to record_files in read.c, only much much simpler. */ static void incdep_commit_recorded_file (const char *filename, struct dep *deps, const floc *flocp) { struct file *f; /* Perform some validations. */ if (filename[0] == '.' && ( streq(filename, ".POSIX") || streq(filename, ".EXPORT_ALL_VARIABLES") || streq(filename, ".INTERMEDIATE") || streq(filename, ".LOW_RESOLUTION_TIME") || streq(filename, ".NOTPARALLEL") || streq(filename, ".ONESHELL") || streq(filename, ".PHONY") || streq(filename, ".PRECIOUS") || streq(filename, ".SECONDARY") || streq(filename, ".SECONDTARGETEXPANSION") || streq(filename, ".SILENT") || streq(filename, ".SHELLFLAGS") || streq(filename, ".SUFFIXES") ) ) { OS (error, flocp, _("reserved filename '%s' used in dependency file, ignored"), filename); return; } /* Lookup or create an entry in the database. */ f = enter_file (filename); if (f->double_colon) { OS (error, flocp, _("dependency file '%s' has a double colon entry already, ignoring"), filename); return; } f->is_target = 1; /* Append dependencies. */ deps = enter_prereqs (deps, NULL); if (deps) { struct dep *last = f->deps; if (!last) f->deps = deps; else { while (last->next) last = last->next; last->next = deps; } } } /* Record a file.*/ static void incdep_record_file (struct incdep *cur, const char *filename, struct dep *deps, const floc *flocp) { if (cur->worker_tid == -1) incdep_commit_recorded_file (filename, deps, flocp); #ifdef PARSE_IN_WORKER else { struct incdep_recorded_file *rec = (struct incdep_recorded_file *) incdep_alloc_rec (cur); rec->filename_entry = (struct strcache2_entry *)filename; rec->deps = deps; rec->flocp = flocp; rec->next = NULL; if (cur->recorded_file_tail) cur->recorded_file_tail->next = rec; else cur->recorded_file_head = rec; cur->recorded_file_tail = rec; } #endif } /* no nonsense dependency file including. Because nobody wants bogus dependency files to break their incremental builds with hard to comprehend error messages, this function does not use the normal eval routine but does all the parsing itself. This isn't, as much work as it sounds, because the necessary feature set is very limited. eval_include_dep_file groks: define var endef var [|:|?|>]= value [\] [\] file: [deps] [\] */ static void eval_include_dep_file (struct incdep *curdep, floc *f) { unsigned line_no = 1; const char *file_end = curdep->file_end; const char *cur = curdep->file_base; const char *endp; /* if no file data, just return immediately. */ if (!cur) return; /* now parse the file. */ while (cur < file_end) { /* skip empty lines */ while (cur < file_end && ISSPACE (*cur) && *cur != '\n') ++cur; if (cur >= file_end) break; if (*cur == '#') { cur = memchr (cur, '\n', file_end - cur); if (!cur) break; } if (*cur == '\\') { unsigned eol_len = (file_end - cur > 1 && cur[1] == '\n') ? 2 : (file_end - cur > 2 && cur[1] == '\r' && cur[2] == '\n') ? 3 : (file_end - cur == 1) ? 1 : 0; if (eol_len) { cur += eol_len; line_no++; continue; } } if (*cur == '\n') { cur++; line_no++; continue; } /* define var ... endef */ if (strneq (cur, "define ", 7)) { const char *var; unsigned var_len; const char *value_start; const char *value_end; char *value; unsigned value_len; int found_endef = 0; /* extract the variable name. */ cur += 7; while (ISBLANK (*cur)) ++cur; value_start = endp = memchr (cur, '\n', file_end - cur); if (!endp) endp = cur; while (endp > cur && ISSPACE (endp[-1])) --endp; var_len = endp - cur; if (!var_len) { incdep_warn (curdep, line_no, "bogus define statement."); break; } var = incdep_var_strcache (curdep, cur, var_len); /* find the end of the variable. */ cur = value_end = value_start = value_start + 1; ++line_no; while (cur < file_end) { /* check for endef, don't bother with skipping leading spaces. */ if ( file_end - cur >= 5 && strneq (cur, "endef", 5)) { endp = cur + 5; while (endp < file_end && ISSPACE (*endp) && *endp != '\n') endp++; if (endp >= file_end || *endp == '\n') { found_endef = 1; cur = endp >= file_end ? file_end : endp + 1; break; } } /* skip a line ahead. */ cur = value_end = memchr (cur, '\n', file_end - cur); if (cur != NULL) ++cur; else cur = value_end = file_end; ++line_no; } if (!found_endef) { incdep_warn (curdep, line_no, "missing endef, dropping the rest of the file."); break; } value_len = value_end - value_start; if (memchr (value_start, '\0', value_len)) { incdep_warn (curdep, line_no, "'\\0' in define, dropping the rest of the file."); break; } /* make a copy of the value, converting \r\n to \n, and define it. */ value = incdep_xmalloc (curdep, value_len + 1); endp = memchr (value_start, '\r', value_len); if (endp) { const char *src = value_start; char *dst = value; for (;;) { size_t len = endp - src; memcpy (dst, src, len); dst += len; src = endp; if (src + 1 < file_end && src[1] == '\n') src++; /* skip the '\r' */ if (src >= value_end) break; endp = memchr (endp + 1, '\r', src - value_end); if (!endp) endp = value_end; } value_len = dst - value; } else memcpy (value, value_start, value_len); value [value_len] = '\0'; incdep_record_variable_in_set (curdep, var, var_len, value, value_len, 0 /* don't duplicate */, o_file, 0 /* defines are recursive but this is faster */, NULL /* global set */, f); } /* file: deps OR variable [:]= value */ else { const char *equalp; const char *eol; /* Look for a colon or and equal sign. In the assignment case, we require it to be on the same line as the variable name to simplify the code. Because of clang, we cannot make the same assumptions with file dependencies. So, start with the equal. */ assert (*cur != '\n'); eol = memchr (cur, '\n', file_end - cur); if (!eol) eol = file_end; equalp = memchr (cur, '=', eol - cur); if (equalp) { /* An assignment of some sort. */ const char *var; unsigned var_len; const char *value_start; const char *value_end; char *value; unsigned value_len; unsigned multi_line = 0; enum variable_flavor flavor; /* figure the flavor first. */ flavor = f_recursive; if (equalp > cur) { if (equalp[-1] == ':') flavor = f_simple; else if (equalp[-1] == '?') flavor = f_conditional; else if (equalp[-1] == '+') flavor = f_append; else if (equalp[-1] == '>') flavor = f_prepend; } /* extract the variable name. */ endp = flavor == f_recursive ? equalp : equalp - 1; while (endp > cur && ISBLANK (endp[-1])) --endp; var_len = endp - cur; if (!var_len) { incdep_warn (curdep, line_no, "empty variable. (includedep)"); break; } if ( memchr (cur, '$', var_len) || memchr (cur, ' ', var_len) || memchr (cur, '\t', var_len)) { incdep_warn (curdep, line_no, "fancy variable name. (includedep)"); break; } var = incdep_var_strcache (curdep, cur, var_len); /* find the start of the value. */ cur = equalp + 1; while (cur < file_end && ISBLANK (*cur)) cur++; value_start = cur; /* find the end of the value / line (this isn't 101% correct). */ value_end = cur; while (cur < file_end) { endp = value_end = memchr (cur, '\n', file_end - cur); if (!value_end) value_end = file_end; if (value_end - 1 >= cur && value_end[-1] == '\r') --value_end; if (value_end - 1 < cur || value_end[-1] != '\\') { cur = endp ? endp + 1 : file_end; break; } --value_end; if (value_end - 1 >= cur && value_end[-1] == '\\') { incdep_warn (curdep, line_no, "fancy escaping! (includedep)"); cur = NULL; break; } if (!endp) { cur = file_end; break; } cur = endp + 1; ++multi_line; ++line_no; } if (!cur) break; ++line_no; /* make a copy of the value, converting \r\n to \n, and define it. */ value_len = value_end - value_start; value = incdep_xmalloc (curdep, value_len + 1); if (!multi_line) memcpy (value, value_start, value_len); else { /* unescape it */ const char *src = value_start; char *dst = value; while (src < value_end) { const char *nextp; endp = memchr (src, '\n', value_end - src); if (!endp) nextp = endp = value_end; else nextp = endp + 1; if (endp > src && endp[-1] == '\r') --endp; if (endp > src && endp[-1] == '\\') --endp; if (src != value_start) *dst++ = ' '; memcpy (dst, src, endp - src); dst += endp - src; src = nextp; } value_len = dst - value; } value [value_len] = '\0'; /* do the definition */ if (flavor == f_recursive || ( flavor == f_simple && !memchr (value, '$', value_len))) incdep_record_variable_in_set (curdep, var, var_len, value, value_len, 0 /* don't duplicate */, o_file, flavor == f_recursive /* recursive */, NULL /* global set */, f); else incdep_record_variable_def (curdep, f, var, var_len, value, value_len, o_file, flavor, 0 /* not target var */); } else { /* Expecting: file: dependencies */ const char *filename; const char *fnnext; const char *fnend; const char *colonp; struct dep *deps = 0; struct dep **nextdep = &deps; struct dep *dep; /* Locate the next file colon. If it's not within the bounds of the current line, check that all new line chars are escaped, and simplify them while we're at it. */ colonp = memchr (cur, ':', file_end - cur); #ifdef HAVE_DOS_PATHS while ( colonp && colonp + 1 < file_end && (colonp[1] == '/' || colonp[1] == '\\') && colonp > cur && isalpha ((unsigned char)colonp[-1]) && ( colonp == cur + 1 || strchr (" \t(", colonp[-2]) != 0)) colonp = memchr (colonp + 1, ':', file_end - (colonp + 1)); #endif if (!colonp) { incdep_warn (curdep, line_no, "no colon."); break; } if ((uintptr_t)colonp >= (uintptr_t)eol) { const char *sol; if (memchr (eol, '=', colonp - eol)) { incdep_warn (curdep, line_no, "multi line assignment / dependency confusion."); break; } sol = cur; do { char *eol2 = (char *)eol - 1; if ((uintptr_t)eol2 >= (uintptr_t)sol && *eol2 == '\r') /* DOS line endings. */ eol2--; if ((uintptr_t)eol2 < (uintptr_t)sol || *eol2 != '\\') incdep_warn (curdep, line_no, "no colon."); else if (eol2 != sol && eol2[-1] == '\\') incdep_warn (curdep, line_no, "fancy EOL escape. (includedep)"); else { eol2[0] = ' '; eol2[1] = ' '; if (eol2 != eol - 1) eol2[2] = ' '; line_no++; sol = eol + 1; eol = memchr (sol, '\n', colonp - sol); continue; } sol = NULL; break; } while (eol != NULL); if (!sol) break; } /* Extract the first filename after trimming and basic checks. */ fnend = colonp; while ((uintptr_t)fnend > (uintptr_t)cur && ISBLANK (fnend[-1])) --fnend; if (cur == fnend) { incdep_warn (curdep, line_no, "empty filename."); break; } if (memchr (cur, '$', fnend - cur)) { incdep_warn (curdep, line_no, "fancy file name. (includedep)"); break; } fnnext = cur; while (fnnext != fnend && !ISBLANK (*fnnext)) fnnext++; filename = incdep_dep_strcache (curdep, cur, fnnext - cur); /* parse any dependencies. */ cur = colonp + 1; while (cur < file_end) { /* skip blanks and count lines. */ while (cur < file_end && ISSPACE (*cur) && *cur != '\n') ++cur; if (cur >= file_end) break; if (*cur == '\n') { cur++; line_no++; break; } /* continuation + eol? */ if (*cur == '\\') { unsigned eol_len = (file_end - cur > 1 && cur[1] == '\n') ? 2 : (file_end - cur > 2 && cur[1] == '\r' && cur[2] == '\n') ? 3 : (file_end - cur == 1) ? 1 : 0; if (eol_len) { cur += eol_len; line_no++; continue; } } /* find the end of the filename */ endp = cur; while (endp < file_end && !ISSPACE (*endp)) ++endp; /* add it to the list. */ *nextdep = dep = incdep_alloc_dep (curdep); dep->name = incdep_dep_strcache (curdep, cur, endp - cur); dep->includedep = 1; nextdep = &dep->next; cur = endp; } /* enter the file with its dependencies. */ incdep_record_file (curdep, filename, deps, f); /* More files? Record them with the same dependency list. */ if (fnnext != fnend) for (;;) { const char *filename_prev = filename; const char *fnstart; while (fnnext != fnend && ISBLANK (*fnnext)) fnnext++; if (fnnext == fnend) break; fnstart = fnnext; while (fnnext != fnend && !ISBLANK (*fnnext)) fnnext++; filename = incdep_dep_strcache (curdep, fnstart, fnnext - fnstart); if (filename != filename_prev) /* clang optimization. */ incdep_record_file (curdep, filename, incdep_dup_dep_list (curdep, deps), f); } } } } /* free the file data */ incdep_xfree (curdep, curdep->file_base); curdep->file_base = curdep->file_end = NULL; } /* Flushes the incdep todo and done lists. */ static void incdep_flush_it (floc *f) { incdep_lock (); for (;;) { struct incdep *cur = incdep_head_done; /* if the done list is empty, grab a todo list entry. */ if (!cur && incdep_head_todo) { cur = incdep_head_todo; if (cur->next) incdep_head_todo = cur->next; else incdep_head_todo = incdep_tail_todo = NULL; incdep_unlock (); incdep_read_file (cur, f); eval_include_dep_file (cur, f); incdep_freeit (cur); incdep_lock (); continue; } /* if the todo list and done list are empty we're either done or will have to wait for the thread(s) to finish. */ if (!cur && !incdep_num_reading) break; /* done */ if (!cur) { while (!incdep_head_done) incdep_wait_done (); cur = incdep_head_done; } /* we grab the entire done list and work thru it. */ incdep_head_done = incdep_tail_done = NULL; incdep_unlock (); while (cur) { struct incdep *next = cur->next; #ifdef PARSE_IN_WORKER incdep_flush_recorded_instructions (cur); #else eval_include_dep_file (cur, f); #endif incdep_freeit (cur); cur = next; } incdep_lock (); } /* outer loop */ incdep_unlock (); } /* splits up a list of file names and feeds it to eval_include_dep_file, employing threads to try speed up the file reading. */ void eval_include_dep (const char *names, floc *f, enum incdep_op op) { struct incdep *head = 0; struct incdep *tail = 0; struct incdep *cur; const char *names_iterator = names; const char *name; unsigned int name_len; /* loop through NAMES, creating a todo list out of them. */ while ((name = find_next_token (&names_iterator, &name_len)) != 0) { #ifdef INCDEP_USE_KFSCACHE KFSLOOKUPERROR enmError; PKFSOBJ pFileObj = kFsCacheLookupWithLengthA (g_pFsCache, name, name_len, &enmError); if (!pFileObj) continue; if (pFileObj->bObjType != KFSOBJ_TYPE_FILE) { kFsCacheObjRelease (g_pFsCache, pFileObj); continue; } cur = xmalloc (sizeof (*cur)); /* not incdep_xmalloc here */ cur->pFileObj = pFileObj; #else cur = xmalloc (sizeof (*cur) + name_len); /* not incdep_xmalloc here */ memcpy (cur->name, name, name_len); cur->name[name_len] = '\0'; #endif cur->file_base = cur->file_end = NULL; cur->worker_tid = -1; #ifdef PARSE_IN_WORKER cur->err_line_no = 0; cur->err_msg = NULL; cur->recorded_variables_in_set_head = NULL; cur->recorded_variables_in_set_tail = NULL; cur->recorded_variable_defs_head = NULL; cur->recorded_variable_defs_tail = NULL; cur->recorded_file_head = NULL; cur->recorded_file_tail = NULL; #endif cur->next = NULL; if (tail) tail->next = cur; else head = cur; tail = cur; } #ifdef ELECTRIC_HEAP if (1) #else if (op == incdep_read_it) #endif { /* work our way thru the files directly */ cur = head; while (cur) { struct incdep *next = cur->next; incdep_read_file (cur, f); eval_include_dep_file (cur, f); incdep_freeit (cur); cur = next; } } else { /* initialize the worker threads and related stuff the first time around. */ if (!incdep_initialized) incdep_init (f); /* queue the files and notify the worker threads. */ incdep_lock (); if (incdep_tail_todo) incdep_tail_todo->next = head; else incdep_head_todo = head; incdep_tail_todo = tail; incdep_signal_todo (); incdep_unlock (); /* flush the todo queue if we're requested to do so. */ if (op == incdep_flush) incdep_flush_it (f); } } #endif /* CONFIG_WITH_INCLUDEDEP */ kbuild-3149/src/kmk/rule.h0000644000175000017500000000417213252530201015372 0ustar locutuslocutus/* Definitions for using pattern rules in GNU Make. Copyright (C) 1988-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make 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 . */ /* Structure used for pattern (implicit) rules. */ struct rule { struct rule *next; const char **targets; /* Targets of the rule. */ unsigned int *lens; /* Lengths of each target. */ const char **suffixes; /* Suffixes (after '%') of each target. */ struct dep *deps; /* Dependencies of the rule. */ struct commands *cmds; /* Commands to execute. */ unsigned short num; /* Number of targets. */ char terminal; /* If terminal (double-colon). */ char in_use; /* If in use by a parent pattern_search. */ }; /* For calling install_pattern_rule. */ struct pspec { const char *target, *dep, *commands; }; extern struct rule *pattern_rules; extern struct rule *last_pattern_rule; extern unsigned int num_pattern_rules; extern unsigned int max_pattern_deps; extern unsigned int max_pattern_targets; extern unsigned int max_pattern_dep_length; extern struct file *suffix_file; extern unsigned int maxsuffix; void count_implicit_rule_limits (void); void convert_to_pattern (void); void install_pattern_rule (struct pspec *p, int terminal); void create_pattern_rule (const char **targets, const char **target_percents, unsigned int num, int terminal, struct dep *deps, struct commands *commands, int override); void print_rule_data_base (void); kbuild-3149/src/kmk/AUTHORS0000644000175000017500000000563713252530176015344 0ustar locutuslocutus----------------------------------- GNU make development up to version 3.75 by: Roland McGrath Development starting with GNU make 3.76 by: Paul D. Smith Additional development starting with GNU make 3.81 by: Boris Kolpackov GNU Make User's Manual Written by: Richard M. Stallman Edited by: Roland McGrath Bob Chassell Melissa Weisshaus Paul D. Smith ----------------------------------- GNU make porting efforts: Port to VMS by: Klaus Kaempf Hartmut Becker Archive support/Bug fixes by: John W. Eaton Martin Zinser Port to Amiga by: Aaron Digulla Port to MS-DOS (DJGPP), OS/2, and MS-Windows (native/MinGW) by: DJ Delorie Rob Tulloh Eli Zaretskii Jonathan Grant Andreas Beuning Earnie Boyd Troy Runkel ----------------------------------- Other contributors: Janet Carson Howard Chu Ludovic Courtès Paul Eggert Ramon Garcia Fernandez Klaus Heinz Michael Joosten Jim Kelton David Lubbren Tim Magill Markus Mauhart Greg McGary Thien-Thi Nguyen Thomas Riedl Han-Wen Nienhuys Andreas Schwab Carl Staelin (Princeton University) Ian Stewartson (Data Logic Limited) David A. Wheeler David Boyce Frank Heckenbach With suggestions/comments/bug reports from a cast of ... well ... hundreds, anyway :) ------------------------------------------------------------------------------- Copyright (C) 1997-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make 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 . kbuild-3149/src/kmk/default.c0000644000175000017500000005302513252530201016043 0ustar locutuslocutus/* Data base of default implicit rules for GNU Make. Copyright (C) 1988-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" #include #include "filedef.h" #include "variable.h" #include "rule.h" #include "dep.h" #include "job.h" #include "commands.h" /* Define GCC_IS_NATIVE if gcc is the native development environment on your system (gcc/bison/flex vs cc/yacc/lex). */ #if defined(__MSDOS__) || defined(__EMX__) # define GCC_IS_NATIVE #endif /* This is the default list of suffixes for suffix rules. '.s' must come last, so that a '.o' file will be made from a '.c' or '.p' or ... file rather than from a .s file. */ static char default_suffixes[] #ifndef CONFIG_NO_DEFAULT_SUFFIXES #ifdef VMS /* VMS should include all UNIX/POSIX + some VMS extensions */ = ".out .exe .a .olb .hlb .tlb .mlb .ln .o .obj .c .cxx .cc .cpp .pas .p \ .for .f .r .y .l .ym .yl .mar .s .ss .i .ii .mod .sym .def .h .info .dvi \ .tex .texinfo .texi .txinfo .mem .hlp .brn .rnh .rno .rnt .rnx .w .ch .cweb \ .web .com .sh .elc .el"; #elif defined(__EMX__) = ".out .a .ln .o .c .cc .C .cpp .p .f .F .m .r .y .l .ym .yl .s .S \ .mod .sym .def .h .info .dvi .tex .texinfo .texi .txinfo \ .w .ch .web .sh .elc .el .obj .exe .dll .lib"; #else = ".out .a .ln .o .c .cc .C .cpp .p .f .F .m .r .y .l .ym .yl .s .S \ .mod .sym .def .h .info .dvi .tex .texinfo .texi .txinfo \ .w .ch .web .sh .elc .el"; #endif #else /* CONFIG_NO_DEFAULT_SUFFIXES */ = ""; #endif /* CONFIG_NO_DEFAULT_SUFFIXES */ static struct pspec default_pattern_rules[] = { #ifndef CONFIG_NO_DEFAULT_PATTERN_RULES #ifdef VMS { "(%)", "%", "@if f$$search(\"$@\") .eqs. \"\" then $(LIBRARY)/CREATE/" "$(or " "$(patsubst %,TEXT,$(filter %.tlb %.TLB,$@))," "$(patsubst %,HELP,$(filter %.hlb %.HLB,$@))," "$(patsubst %,MACRO,$(filter %.mlb %.MLB,$@))," "$(and " "$(patsubst %,SHARE,$(filter %.olb %.OLB,$@))," "$(patsubst %,SHARE,$(filter %.exe %.EXE,$<)))," "OBJECT)" " $@\n" "$(AR) $(ARFLAGS) $@ $<" }, #else { "(%)", "%", "$(AR) $(ARFLAGS) $@ $<" }, #endif /* The X.out rules are only in BSD's default set because BSD Make has no null-suffix rules, so 'foo.out' and 'foo' are the same thing. */ #ifdef VMS { "%.exe", "%", "$(CP) $< $@" }, #endif { "%.out", "%", "@rm -f $@ \n cp $< $@" }, /* Syntax is "ctangle foo.w foo.ch foo.c". */ { "%.c", "%.w %.ch", "$(CTANGLE) $^ $@" }, { "%.tex", "%.w %.ch", "$(CWEAVE) $^ $@" }, #endif /* !CONFIG_NO_DEFAULT_PATTERN_RULES */ { 0, 0, 0 } }; static struct pspec default_terminal_rules[] = { #ifndef CONFIG_NO_DEFAULT_TERMINAL_RULES #ifdef VMS /* RCS. */ { "%", "%$$5lv", /* Multinet style */ "if f$$search(\"$@\") .nes. \"\" then +$(CHECKOUT,v)" }, { "%", "[.$$rcs]%$$5lv", /* Multinet style */ "if f$$search(\"$@\") .nes. \"\" then +$(CHECKOUT,v)" }, { "%", "%_v", /* Normal style */ "if f$$search(\"$@\") .nes. \"\" then +$(CHECKOUT,v)" }, { "%", "[.rcs]%_v", /* Normal style */ "if f$$search(\"$@\") .nes. \"\" then +$(CHECKOUT,v)" }, /* SCCS. */ /* ain't no SCCS on vms */ #else /* RCS. */ { "%", "%,v", "$(CHECKOUT,v)" }, { "%", "RCS/%,v", "$(CHECKOUT,v)" }, { "%", "RCS/%", "$(CHECKOUT,v)" }, /* SCCS. */ { "%", "s.%", "$(GET) $(GFLAGS) $(SCCS_OUTPUT_OPTION) $<" }, { "%", "SCCS/s.%", "$(GET) $(GFLAGS) $(SCCS_OUTPUT_OPTION) $<" }, #endif /* !VMS */ #endif /* !CONFIG_NO_DEFAULT_TERMINAL_RULES */ { 0, 0, 0 } }; static const char *default_suffix_rules[] = { #ifndef CONFIG_NO_DEFAULT_SUFFIX_RULES #ifdef VMS ".o", "$(LINK.obj) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".obj", "$(LINK.obj) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".s", "$(LINK.s) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".S", "$(LINK.S) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".c", "$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".cc", "$(LINK.cc) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".C", "$(LINK.C) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".cpp", "$(LINK.cpp) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".f", "$(LINK.f) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".m", "$(LINK.m) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".p", "$(LINK.p) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".F", "$(LINK.F) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".r", "$(LINK.r) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".mod", "$(COMPILE.mod) -o $@ -e $@ $^", ".def.sym", "$(COMPILE.def) -o $@ $<", ".sh", "copy $< >$@", ".obj.exe", "$(LINK.obj) $^ $(LOADLIBES) $(LDLIBS) $(CRT0) /exe=$@", ".mar.exe", "$(COMPILE.mar) $^ \n $(LINK.obj) $(subst .mar,.obj,$^) $(LOADLIBES) $(LDLIBS) $(CRT0) /exe=$@", ".s.o", "$(COMPILE.s) -o $@ $<", ".s.exe", "$(COMPILE.s) $^ \n $(LINK.obj) $(subst .s,.obj,$^) $(LOADLIBES) $(LDLIBS) $(CRT0) /exe=$@", ".c.exe", "$(COMPILE.c) $^ \n $(LINK.obj) $(subst .c,.obj,$^) $(LOADLIBES) $(LDLIBS) $(CRT0) /exe=$@", ".cc.exe", #ifdef GCC_IS_NATIVE "$(COMPILE.cc) $^ \n $(LINK.obj) $(CXXSTARTUP),sys$$disk:[]$(subst .cc,.obj,$^) $(LOADLIBES) $(LXLIBS) $(LDLIBS) $(CXXRT0) /exe=$@", #else "$(COMPILE.cc) $^ \n $(CXXLINK.obj) $(subst .cc,.obj,$^) $(LOADLIBES) $(LXLIBS) $(LDLIBS) $(CXXRT0) /exe=$@", ".cxx.exe", "$(COMPILE.cxx) $^ \n $(CXXLINK.obj) $(subst .cxx,.obj,$^) $(LOADLIBES) $(LXLIBS) $(LDLIBS) $(CXXRT0) /exe=$@", #endif ".for.exe", "$(COMPILE.for) $^ \n $(LINK.obj) $(subst .for,.obj,$^) $(LOADLIBES) $(LDLIBS) /exe=$@", ".pas.exe", "$(COMPILE.pas) $^ \n $(LINK.obj) $(subst .pas,.obj,$^) $(LOADLIBES) $(LDLIBS) /exe=$@", ".com", "copy $< >$@", ".mar.obj", "$(COMPILE.mar) /obj=$@ $<", ".s.obj", "$(COMPILE.s) /obj=$@ $<", ".ss.obj", "$(COMPILE.s) /obj=$@ $<", ".c.i", "$(COMPILE.c)/prep /list=$@ $<", ".c.s", "$(COMPILE.c)/noobj/machine /list=$@ $<", ".i.s", "$(COMPILE.c)/noprep/noobj/machine /list=$@ $<", ".c.obj", "$(COMPILE.c) /obj=$@ $<", ".c.o", "$(COMPILE.c) /obj=$@ $<", ".cc.ii", "$(COMPILE.cc)/prep /list=$@ $<", ".cc.ss", "$(COMPILE.cc)/noobj/machine /list=$@ $<", ".ii.ss", "$(COMPILE.cc)/noprep/noobj/machine /list=$@ $<", ".cc.obj", "$(COMPILE.cc) /obj=$@ $<", ".cc.o", "$(COMPILE.cc) /obj=$@ $<", ".cxx.obj", "$(COMPILE.cxx) /obj=$@ $<", ".cxx.o", "$(COMPILE.cxx) /obj=$@ $<", ".for.obj", "$(COMPILE.for) /obj=$@ $<", ".for.o", "$(COMPILE.for) /obj=$@ $<", ".pas.obj", "$(COMPILE.pas) /obj=$@ $<", ".pas.o", "$(COMPILE.pas) /obj=$@ $<", ".y.c", "$(YACC.y) $< \n rename y_tab.c $@", ".l.c", "$(LEX.l) $< \n rename lexyy.c $@", ".texinfo.info", "$(MAKEINFO) $<", ".tex.dvi", "$(TEX) $<", ".cpp.o", "$(COMPILE.cpp) $(OUTPUT_OPTION) $<", ".f.o", "$(COMPILE.f) $(OUTPUT_OPTION) $<", ".m.o", "$(COMPILE.m) $(OUTPUT_OPTION) $<", ".p.o", "$(COMPILE.p) $(OUTPUT_OPTION) $<", ".r.o", "$(COMPILE.r) $(OUTPUT_OPTION) $<", ".mod.o", "$(COMPILE.mod) -o $@ $<", ".c.ln", "$(LINT.c) -C$* $<", ".y.ln", "$(YACC.y) $< \n rename y_tab.c $@", ".l.ln", "@$(RM) $*.c\n $(LEX.l) $< > $*.c\n$(LINT.c) -i $*.c -o $@\n $(RM) $*.c", #else /* ! VMS */ ".o", "$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".s", "$(LINK.s) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".S", "$(LINK.S) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".c", "$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".cc", "$(LINK.cc) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".C", "$(LINK.C) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".cpp", "$(LINK.cpp) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".f", "$(LINK.f) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".m", "$(LINK.m) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".p", "$(LINK.p) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".F", "$(LINK.F) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".r", "$(LINK.r) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".mod", "$(COMPILE.mod) -o $@ -e $@ $^", ".def.sym", "$(COMPILE.def) -o $@ $<", ".sh", "cat $< >$@ \n chmod a+x $@", ".s.o", "$(COMPILE.s) -o $@ $<", ".S.o", "$(COMPILE.S) -o $@ $<", ".c.o", "$(COMPILE.c) $(OUTPUT_OPTION) $<", ".cc.o", "$(COMPILE.cc) $(OUTPUT_OPTION) $<", ".C.o", "$(COMPILE.C) $(OUTPUT_OPTION) $<", ".cpp.o", "$(COMPILE.cpp) $(OUTPUT_OPTION) $<", ".f.o", "$(COMPILE.f) $(OUTPUT_OPTION) $<", ".m.o", "$(COMPILE.m) $(OUTPUT_OPTION) $<", ".p.o", "$(COMPILE.p) $(OUTPUT_OPTION) $<", ".F.o", "$(COMPILE.F) $(OUTPUT_OPTION) $<", ".r.o", "$(COMPILE.r) $(OUTPUT_OPTION) $<", ".mod.o", "$(COMPILE.mod) -o $@ $<", ".c.ln", "$(LINT.c) -C$* $<", ".y.ln", #ifndef __MSDOS__ "$(YACC.y) $< \n $(LINT.c) -C$* y.tab.c \n $(RM) y.tab.c", #else "$(YACC.y) $< \n $(LINT.c) -C$* y_tab.c \n $(RM) y_tab.c", #endif ".l.ln", "@$(RM) $*.c\n $(LEX.l) $< > $*.c\n$(LINT.c) -i $*.c -o $@\n $(RM) $*.c", ".y.c", #ifndef __MSDOS__ "$(YACC.y) $< \n mv -f y.tab.c $@", #else "$(YACC.y) $< \n mv -f y_tab.c $@", #endif ".l.c", "@$(RM) $@ \n $(LEX.l) $< > $@", ".ym.m", "$(YACC.m) $< \n mv -f y.tab.c $@", ".lm.m", "@$(RM) $@ \n $(LEX.m) $< > $@", ".F.f", "$(PREPROCESS.F) $(OUTPUT_OPTION) $<", ".r.f", "$(PREPROCESS.r) $(OUTPUT_OPTION) $<", /* This might actually make lex.yy.c if there's no %R% directive in $*.l, but in that case why were you trying to make $*.r anyway? */ ".l.r", "$(LEX.l) $< > $@ \n mv -f lex.yy.r $@", ".S.s", "$(PREPROCESS.S) $< > $@", ".texinfo.info", "$(MAKEINFO) $(MAKEINFO_FLAGS) $< -o $@", ".texi.info", "$(MAKEINFO) $(MAKEINFO_FLAGS) $< -o $@", ".txinfo.info", "$(MAKEINFO) $(MAKEINFO_FLAGS) $< -o $@", ".tex.dvi", "$(TEX) $<", ".texinfo.dvi", "$(TEXI2DVI) $(TEXI2DVI_FLAGS) $<", ".texi.dvi", "$(TEXI2DVI) $(TEXI2DVI_FLAGS) $<", ".txinfo.dvi", "$(TEXI2DVI) $(TEXI2DVI_FLAGS) $<", ".w.c", "$(CTANGLE) $< - $@", /* The '-' says there is no '.ch' file. */ ".web.p", "$(TANGLE) $<", ".w.tex", "$(CWEAVE) $< - $@", /* The '-' says there is no '.ch' file. */ ".web.tex", "$(WEAVE) $<", #endif /* !VMS */ #endif /* !CONFIG_NO_DEFAULT_SUFFIX_RULES */ 0, 0, }; static const char *default_variables[] = { #ifndef CONFIG_NO_DEFAULT_VARIABLES #ifdef VMS #ifdef __ALPHA "ARCH", "ALPHA", #endif #ifdef __ia64 "ARCH", "IA64", #endif #ifdef __VAX "ARCH", "VAX", #endif "AR", "library", "LIBRARY", "library", "ARFLAGS", "/replace", "AS", "macro", "MACRO", "macro", #ifdef GCC_IS_NATIVE "CC", "gcc", #else "CC", "cc", #endif "CD", "builtin_cd", "ECHO", "builtin_echo", #ifdef GCC_IS_NATIVE "C++", "gcc/plus", "CXX", "gcc/plus", #else "C++", "cxx", "CXX", "cxx", #ifndef __ia64 "CXXLD", "cxxlink", "CXXLINK", "cxxlink", #else /* CXXLINK is not used on VMS/IA64 */ "CXXLD", "link", "CXXLINK", "link", #endif #endif "CO", "co", "CPP", "$(CC) /preprocess_only", "FC", "fortran", /* System V uses these, so explicit rules using them should work. However, there is no way to make implicit rules use them and FC. */ "F77", "$(FC)", "F77FLAGS", "$(FFLAGS)", "LD", "link", "LEX", "lex", "PC", "pascal", "YACC", "bison/yacc", "YFLAGS", "/Define/Verbose", "BISON", "bison", "MAKEINFO", "makeinfo", "TEX", "tex", "TEXINDEX", "texindex", "RM", "delete/nolog", "CSTARTUP", "", #ifdef GCC_IS_NATIVE "CRT0", ",sys$$library:vaxcrtl.olb/lib,gnu_cc_library:crt0.obj", "CXXSTARTUP", "gnu_cc_library:crtbegin.obj", "CXXRT0", ",sys$$library:vaxcrtl.olb/lib,gnu_cc_library:crtend.obj,gnu_cc_library:gxx_main.obj", "LXLIBS", ",gnu_cc_library:libstdcxx.olb/lib,gnu_cc_library:libgccplus.olb/lib", "LDLIBS", ",gnu_cc_library:libgcc.olb/lib", #else "CRT0", "", "CXXSTARTUP", "", "CXXRT0", "", "LXLIBS", "", "LDLIBS", "", #endif "LINK.o", "$(LD) $(LDFLAGS)", "LINK.obj", "$(LD) $(LDFLAGS)", #ifndef GCC_IS_NATIVE "CXXLINK.obj", "$(CXXLD) $(LDFLAGS)", "COMPILE.cxx", "$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH)", #endif "COMPILE.c", "$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH)", "LINK.c", "$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH)", "COMPILE.m", "$(OBJC) $(OBJCFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c", "LINK.m", "$(OBJC) $(OBJCFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)", "COMPILE.cc", "$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH)", "COMPILE.C", "$(COMPILE.cc)", "COMPILE.cpp", "$(COMPILE.cc)", "LINK.C", "$(LINK.cc)", "LINK.cpp", "$(LINK.cc)", "YACC.y", "$(YACC) $(YFLAGS)", "LEX.l", "$(LEX) $(LFLAGS)", "YACC.m", "$(YACC) $(YFLAGS)", "LEX.m", "$(LEX) $(LFLAGS) -t", "COMPILE.for", "$(FC) $(FFLAGS) $(TARGET_ARCH)", "COMPILE.f", "$(FC) $(FFLAGS) $(TARGET_ARCH) -c", "LINK.f", "$(FC) $(FFLAGS) $(LDFLAGS) $(TARGET_ARCH)", "COMPILE.F", "$(FC) $(FFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c", "LINK.F", "$(FC) $(FFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)", "COMPILE.r", "$(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -c", "LINK.r", "$(FC) $(FFLAGS) $(RFLAGS) $(LDFLAGS) $(TARGET_ARCH)", "COMPILE.pas", "$(PC) $(PFLAGS) $(CPPFLAGS) $(TARGET_ARCH)", "COMPILE.def", "$(M2C) $(M2FLAGS) $(DEFFLAGS) $(TARGET_ARCH)", "COMPILE.mod", "$(M2C) $(M2FLAGS) $(MODFLAGS) $(TARGET_ARCH)", "COMPILE.p", "$(PC) $(PFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c", "LINK.p", "$(PC) $(PFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)", "COMPILE.mar", "$(MACRO) $(MACROFLAGS)", "COMPILE.s", "$(AS) $(ASFLAGS) $(TARGET_MACH)", "LINK.S", "$(CC) $(ASFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_MACH)", "COMPILE.S", "$(CC) $(ASFLAGS) $(CPPFLAGS) $(TARGET_MACH) -c", "PREPROCESS.S", "$(CC) -E $(CPPFLAGS)", "PREPROCESS.F", "$(FC) $(FFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -F", "PREPROCESS.r", "$(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -F", "LINT.c", "$(LINT) $(LINTFLAGS) $(CPPFLAGS) $(TARGET_ARCH)", "MV", "rename/new_version", "CP", "copy", ".LIBPATTERNS", "%.olb lib%.a", #else /* !VMS */ "AR", "ar", "ARFLAGS", "rv", "AS", "as", #ifdef GCC_IS_NATIVE "CC", "gcc", # ifdef __MSDOS__ "CXX", "gpp", /* g++ is an invalid name on MSDOS */ # else "CXX", "gcc", # endif /* __MSDOS__ */ "OBJC", "gcc", #else "CC", "cc", "CXX", "g++", "OBJC", "cc", #endif /* This expands to $(CO) $(COFLAGS) $< $@ if $@ does not exist, and to the empty string if $@ does exist. */ "CHECKOUT,v", "+$(if $(wildcard $@),,$(CO) $(COFLAGS) $< $@)", "CO", "co", "COFLAGS", "", "CPP", "$(CC) -E", #ifdef CRAY "CF77PPFLAGS", "-P", "CF77PP", "/lib/cpp", "CFT", "cft77", "CF", "cf77", "FC", "$(CF)", #else /* Not CRAY. */ #ifdef _IBMR2 "FC", "xlf", #else #ifdef __convex__ "FC", "fc", #else "FC", "f77", #endif /* __convex__ */ #endif /* _IBMR2 */ /* System V uses these, so explicit rules using them should work. However, there is no way to make implicit rules use them and FC. */ "F77", "$(FC)", "F77FLAGS", "$(FFLAGS)", #endif /* Cray. */ "GET", SCCS_GET, "LD", "ld", #ifdef GCC_IS_NATIVE "LEX", "flex", #else "LEX", "lex", #endif "LINT", "lint", "M2C", "m2c", #ifdef pyr "PC", "pascal", #else #ifdef CRAY "PC", "PASCAL", "SEGLDR", "segldr", #else "PC", "pc", #endif /* CRAY. */ #endif /* pyr. */ #ifdef GCC_IS_NATIVE "YACC", "bison -y", #else "YACC", "yacc", /* Or "bison -y" */ #endif "MAKEINFO", "makeinfo", "TEX", "tex", "TEXI2DVI", "texi2dvi", "WEAVE", "weave", "CWEAVE", "cweave", "TANGLE", "tangle", "CTANGLE", "ctangle", "RM", "rm -f", "LINK.o", "$(CC) $(LDFLAGS) $(TARGET_ARCH)", "COMPILE.c", "$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c", "LINK.c", "$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)", "COMPILE.m", "$(OBJC) $(OBJCFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c", "LINK.m", "$(OBJC) $(OBJCFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)", "COMPILE.cc", "$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c", #ifndef HAVE_CASE_INSENSITIVE_FS /* On case-insensitive filesystems, treat *.C files as *.c files, to avoid erroneously compiling C sources as C++, which will probably fail. */ "COMPILE.C", "$(COMPILE.cc)", #else "COMPILE.C", "$(COMPILE.c)", #endif "COMPILE.cpp", "$(COMPILE.cc)", "LINK.cc", "$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)", #ifndef HAVE_CASE_INSENSITIVE_FS "LINK.C", "$(LINK.cc)", #else "LINK.C", "$(LINK.c)", #endif "LINK.cpp", "$(LINK.cc)", "YACC.y", "$(YACC) $(YFLAGS)", "LEX.l", "$(LEX) $(LFLAGS) -t", "YACC.m", "$(YACC) $(YFLAGS)", "LEX.m", "$(LEX) $(LFLAGS) -t", "COMPILE.f", "$(FC) $(FFLAGS) $(TARGET_ARCH) -c", "LINK.f", "$(FC) $(FFLAGS) $(LDFLAGS) $(TARGET_ARCH)", "COMPILE.F", "$(FC) $(FFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c", "LINK.F", "$(FC) $(FFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)", "COMPILE.r", "$(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -c", "LINK.r", "$(FC) $(FFLAGS) $(RFLAGS) $(LDFLAGS) $(TARGET_ARCH)", "COMPILE.def", "$(M2C) $(M2FLAGS) $(DEFFLAGS) $(TARGET_ARCH)", "COMPILE.mod", "$(M2C) $(M2FLAGS) $(MODFLAGS) $(TARGET_ARCH)", "COMPILE.p", "$(PC) $(PFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c", "LINK.p", "$(PC) $(PFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)", "LINK.s", "$(CC) $(ASFLAGS) $(LDFLAGS) $(TARGET_MACH)", "COMPILE.s", "$(AS) $(ASFLAGS) $(TARGET_MACH)", "LINK.S", "$(CC) $(ASFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_MACH)", "COMPILE.S", "$(CC) $(ASFLAGS) $(CPPFLAGS) $(TARGET_MACH) -c", "PREPROCESS.S", "$(CC) -E $(CPPFLAGS)", "PREPROCESS.F", "$(FC) $(FFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -F", "PREPROCESS.r", "$(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -F", "LINT.c", "$(LINT) $(LINTFLAGS) $(CPPFLAGS) $(TARGET_ARCH)", #ifndef NO_MINUS_C_MINUS_O "OUTPUT_OPTION", "-o $@", #endif #ifdef SCCS_GET_MINUS_G "SCCS_OUTPUT_OPTION", "-G$@", #endif #if defined(_AMIGA) ".LIBPATTERNS", "%.lib", #elif defined(__MSDOS__) ".LIBPATTERNS", "lib%.a $(DJDIR)/lib/lib%.a", #elif defined(__APPLE__) ".LIBPATTERNS", "lib%.dylib lib%.a", #elif defined(__CYGWIN__) || defined(WINDOWS32) ".LIBPATTERNS", "lib%.dll.a %.dll.a lib%.a %.lib lib%.dll %.dll", #else ".LIBPATTERNS", "lib%.so lib%.a", #endif #endif /* !VMS */ #endif /* !CONFIG_NO_DEFAULT_VARIABLES */ /* Make this assignment to avoid undefined variable warnings. */ "GNUMAKEFLAGS", "", 0, 0 }; /* Set up the default .SUFFIXES list. */ void set_default_suffixes (void) { suffix_file = enter_file (strcache_add (".SUFFIXES")); suffix_file->builtin = 1; if (no_builtin_rules_flag) define_variable_cname ("SUFFIXES", "", o_default, 0); else { struct dep *d; const char *p = default_suffixes; suffix_file->deps = enter_prereqs (PARSE_SIMPLE_SEQ ((char **)&p, struct dep), NULL); for (d = suffix_file->deps; d; d = d->next) d->file->builtin = 1; define_variable_cname ("SUFFIXES", default_suffixes, o_default, 0); } } /* Enter the default suffix rules as file rules. This used to be done in install_default_implicit_rules, but that loses because we want the suffix rules installed before reading makefiles, and the pattern rules installed after. */ void install_default_suffix_rules (void) { const char **s; if (no_builtin_rules_flag) return; for (s = default_suffix_rules; *s != 0; s += 2) { struct file *f = enter_file (strcache_add (s[0])); /* This function should run before any makefile is parsed. */ assert (f->cmds == 0); #ifndef CONFIG_WITH_ALLOC_CACHES f->cmds = xmalloc (sizeof (struct commands)); #else f->cmds = alloccache_alloc (&commands_cache); #endif f->cmds->fileinfo.filenm = 0; f->cmds->commands = xstrdup (s[1]); f->cmds->command_lines = 0; f->cmds->recipe_prefix = RECIPEPREFIX_DEFAULT; #ifdef CONFIG_WITH_MEMORY_OPTIMIZATIONS f->cmds->refs = 1000; #endif f->builtin = 1; } } /* Install the default pattern rules. */ void install_default_implicit_rules (void) { struct pspec *p; if (no_builtin_rules_flag) return; for (p = default_pattern_rules; p->target != 0; ++p) install_pattern_rule (p, 0); for (p = default_terminal_rules; p->target != 0; ++p) install_pattern_rule (p, 1); } void define_default_variables (void) { const char **s; if (no_builtin_variables_flag) return; for (s = default_variables; *s != 0; s += 2) define_variable (s[0], strlen (s[0]), s[1], o_default, 1); } void undefine_default_variables (void) { const char **s; for (s = default_variables; *s != 0; s += 2) undefine_variable_global (s[0], strlen (s[0]), o_default); } kbuild-3149/src/kmk/guile.c0000644000175000017500000000764713252530201015535 0ustar locutuslocutus/* GNU Guile interface for GNU Make. Copyright (C) 2011-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" #ifdef HAVE_GUILE #include "gnumake.h" #include "debug.h" #include "filedef.h" #include "dep.h" #include "variable.h" #include /* Pre-2.0 versions of Guile don't have a typedef for gsubr function types. */ #if SCM_MAJOR_VERSION < 2 # define GSUBR_TYPE SCM (*) () /* Guile 1.x doesn't really support i18n. */ # define EVAL_STRING(_s) scm_c_eval_string (_s) #else # define GSUBR_TYPE scm_t_subr # define EVAL_STRING(_s) scm_eval_string (scm_from_utf8_string (_s)) #endif static SCM make_mod = SCM_EOL; static SCM obj_to_str = SCM_EOL; /* Convert an SCM object into a string. */ static char * cvt_scm_to_str (SCM obj) { return scm_to_locale_string (scm_call_1 (obj_to_str, obj)); } /* Perform the GNU make expansion function. */ static SCM guile_expand_wrapper (SCM obj) { char *str = cvt_scm_to_str (obj); SCM ret; char *res; DB (DB_BASIC, (_("guile: Expanding '%s'\n"), str)); res = gmk_expand (str); ret = scm_from_locale_string (res); free (str); free (res); return ret; } /* Perform the GNU make eval function. */ static SCM guile_eval_wrapper (SCM obj) { char *str = cvt_scm_to_str (obj); DB (DB_BASIC, (_("guile: Evaluating '%s'\n"), str)); gmk_eval (str, 0); return SCM_BOOL_F; } /* Invoked by scm_c_define_module(), in the context of the GNU make module. */ static void guile_define_module (void *data UNUSED) { /* Ingest the predefined Guile module for GNU make. */ #include "gmk-default.h" /* Register a subr for GNU make's eval capability. */ scm_c_define_gsubr ("gmk-expand", 1, 0, 0, (GSUBR_TYPE) guile_expand_wrapper); /* Register a subr for GNU make's eval capability. */ scm_c_define_gsubr ("gmk-eval", 1, 0, 0, (GSUBR_TYPE) guile_eval_wrapper); /* Define the rest of the module. */ scm_c_eval_string (GUILE_module_defn); } /* Initialize the GNU make Guile module. */ static void * guile_init (void *arg UNUSED) { /* Define the module. */ make_mod = scm_c_define_module ("gnu make", guile_define_module, NULL); /* Get a reference to the object-to-string translator, for later. */ obj_to_str = scm_variable_ref (scm_c_module_lookup (make_mod, "obj-to-str")); /* Import the GNU make module exports into the generic space. */ scm_c_eval_string ("(use-modules (gnu make))"); return NULL; } static void * internal_guile_eval (void *arg) { return cvt_scm_to_str (EVAL_STRING (arg)); } /* This is the function registered with make */ static char * func_guile (const char *funcname UNUSED, unsigned int argc UNUSED, char **argv) { static int init = 0; if (! init) { /* Initialize the Guile interpreter. */ scm_with_guile (guile_init, NULL); init = 1; } if (argv[0] && argv[0][0] != '\0') return scm_with_guile (internal_guile_eval, argv[0]); return NULL; } /* ----- Public interface ----- */ /* We could send the flocp to define_new_function(), but since guile is "kind of" built-in, that didn't seem so useful. */ int guile_gmake_setup (const floc *flocp UNUSED) { /* Create a make function "guile". */ gmk_add_function ("guile", func_guile, 0, 1, GMK_FUNC_DEFAULT); return 1; } #else int guile_gmake_setup (const floc *flocp UNUSED) { return 1; } #endif kbuild-3149/src/kmk/commands.c0000644000175000017500000006273413252530201016227 0ustar locutuslocutus/* Command processing for GNU Make. Copyright (C) 1988-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" #include "filedef.h" #include "dep.h" #include "variable.h" #include "job.h" #include "commands.h" #ifdef WINDOWS32 #include #include "w32err.h" #endif #ifdef CONFIG_WITH_LAZY_DEPS_VARS # include #endif #if VMS # define FILE_LIST_SEPARATOR (vms_comma_separator ? ',' : ' ') #else # define FILE_LIST_SEPARATOR ' ' #endif #ifndef HAVE_UNISTD_H int getpid (); #endif #ifndef CONFIG_WITH_STRCACHE2 static unsigned long dep_hash_1 (const void *key) { const struct dep *d = key; return_STRING_HASH_1 (dep_name (d)); } static unsigned long dep_hash_2 (const void *key) { const struct dep *d = key; return_STRING_HASH_2 (dep_name (d)); } static int dep_hash_cmp (const void *x, const void *y) { const struct dep *dx = x; const struct dep *dy = y; return strcmp (dep_name (dx), dep_name (dy)); } #else /* CONFIG_WITH_STRCACHE2 */ /* Exploit the fact that all names are in the string cache. This means equal names shall have the same storage and there is no need for hashing or comparing. Use the address as the first hash, avoiding any touching of the name, and the length as the second. */ static unsigned long dep_hash_1 (const void *key) { const char *name = dep_name ((struct dep const *) key); assert (strcache2_is_cached (&file_strcache, name)); return (size_t) name / sizeof(void *); } static unsigned long dep_hash_2 (const void *key) { const char *name = dep_name ((struct dep const *) key); return strcache2_get_len (&file_strcache, name); } static int dep_hash_cmp (const void *x, const void *y) { struct dep *dx = (struct dep *) x; struct dep *dy = (struct dep *) y; const char *dxname = dep_name (dx); const char *dyname = dep_name (dy); int cmp = dxname == dyname ? 0 : 1; /* check preconds: both cached and the cache contains no duplicates. */ assert (strcache2_is_cached (&file_strcache, dxname)); assert (strcache2_is_cached (&file_strcache, dyname)); assert (cmp == 0 || strcmp (dxname, dyname) != 0); /* If the names are the same but ignore_mtimes are not equal, one of these is an order-only prerequisite and one isn't. That means that we should remove the one that isn't and keep the one that is. */ if (!cmp && dx->ignore_mtime != dy->ignore_mtime) dx->ignore_mtime = dy->ignore_mtime = 0; return cmp; } #endif /* CONFIG_WITH_STRCACHE2 */ #ifdef CONFIG_WITH_LAZY_DEPS_VARS /* Create as copy of DEPS without duplicates, similar to what set_file_variables does. Used by func_deps. */ struct dep *create_uniqute_deps_chain (struct dep *deps) { struct dep *d; struct dep *head = NULL; struct dep **ppnext= &head; struct hash_table dep_hash; void **slot; hash_init (&dep_hash, 500, dep_hash_1, dep_hash_2, dep_hash_cmp); for (d = deps; d != 0; d = d->next) { if (d->need_2nd_expansion) continue; slot = hash_find_slot (&dep_hash, d); if (HASH_VACANT (*slot)) { struct dep *n = alloc_dep(); *n = *d; n->next = NULL; *ppnext = n; ppnext = &n->next; hash_insert_at (&dep_hash, n, slot); } else { /* Upgrade order only if a normal dep exists. Note! Elected not to upgrade the original, only the sanitized list, need to check that out later. FIXME TODO */ struct dep *d2 = (struct dep *)*slot; if (d->ignore_mtime != d2->ignore_mtime) d->ignore_mtime = d2->ignore_mtime = 0; } } return head; } #endif /* CONFIG_WITH_LAZY_DEPS_VARS */ /* Set FILE's automatic variables up. */ void #if defined(CONFIG_WITH_COMMANDS_FUNC) || defined (CONFIG_WITH_DOT_MUST_MAKE) set_file_variables (struct file *file, int called_early) #else set_file_variables (struct file *file) #endif { struct dep *d; const char *at, *percent, *star, *less; #ifdef CONFIG_WITH_STRCACHE2 const char *org_stem = file->stem; #endif #ifndef NO_ARCHIVES /* If the target is an archive member 'lib(member)', then $@ is 'lib' and $% is 'member'. */ if (ar_name (file->name)) { unsigned int len; const char *cp; char *p; cp = strchr (file->name, '('); p = alloca (cp - file->name + 1); memcpy (p, file->name, cp - file->name); p[cp - file->name] = '\0'; at = p; len = strlen (cp + 1); p = alloca (len); memcpy (p, cp + 1, len - 1); p[len - 1] = '\0'; percent = p; } else #endif /* NO_ARCHIVES. */ { at = file->name; percent = ""; } /* $* is the stem from an implicit or static pattern rule. */ if (file->stem == 0) { /* In Unix make, $* is set to the target name with any suffix in the .SUFFIXES list stripped off for explicit rules. We store this in the 'stem' member. */ const char *name; unsigned int len; #ifndef NO_ARCHIVES if (ar_name (file->name)) { name = strchr (file->name, '(') + 1; len = strlen (name) - 1; } else #endif { name = file->name; #ifndef CONFIG_WITH_STRCACHE2 len = strlen (name); #else len = strcache2_get_len (&file_strcache, name); #endif } #ifndef CONFIG_WITH_STRCACHE2 for (d = enter_file (strcache_add (".SUFFIXES"))->deps; d ; d = d->next) { unsigned int slen = strlen (dep_name (d)); #else for (d = enter_file (suffixes_strcached)->deps; d ; d = d->next) { unsigned int slen = strcache2_get_len (&file_strcache, dep_name (d)); #endif if (len > slen && strneq (dep_name (d), name + (len - slen), slen)) { file->stem = strcache_add_len (name, len - slen); break; } } if (d == 0) file->stem = ""; } star = file->stem; /* $< is the first not order-only dependency. */ less = ""; for (d = file->deps; d != 0; d = d->next) if (!d->ignore_mtime) { if (!d->need_2nd_expansion) less = dep_name (d); break; } if (file->cmds == default_file->cmds) /* This file got its commands from .DEFAULT. In this case $< is the same as $@. */ less = at; #define DEFINE_VARIABLE(name, len, value) \ (void) define_variable_for_file (name,len,value,o_automatic,0,file) /* Define the variables. */ #ifndef CONFIG_WITH_RDONLY_VARIABLE_VALUE DEFINE_VARIABLE ("<", 1, less); DEFINE_VARIABLE ("*", 1, star); DEFINE_VARIABLE ("@", 1, at); DEFINE_VARIABLE ("%", 1, percent); #else /* CONFIG_WITH_RDONLY_VARIABLE_VALUE */ # define DEFINE_VARIABLE_RO_VAL(name, len, value, value_len) \ define_variable_in_set((name), (len), (value), (value_len), -1, \ (o_automatic), 0, (file)->variables->set, NILF) if (*less == '\0') DEFINE_VARIABLE_RO_VAL ("<", 1, "", 0); else if (less != at || at == file->name) DEFINE_VARIABLE_RO_VAL ("<", 1, less, strcache_get_len (less)); else DEFINE_VARIABLE ("<", 1, less); if (*star == '\0') DEFINE_VARIABLE_RO_VAL ("*", 1, "", 0); else if (file->stem != org_stem) DEFINE_VARIABLE_RO_VAL ("*", 1, star, strcache_get_len (star)); else DEFINE_VARIABLE ("*", 1, star); if (at == file->name) DEFINE_VARIABLE_RO_VAL ("@", 1, at, strcache_get_len (at)); else DEFINE_VARIABLE ("@", 1, at); if (*percent == '\0') DEFINE_VARIABLE_RO_VAL ("%", 1, "", 0); else DEFINE_VARIABLE ("%", 1, percent); #endif /* CONFIG_WITH_RDONLY_VARIABLE_VALUE */ #if defined(CONFIG_WITH_COMMANDS_FUNC) || defined (CONFIG_WITH_DOT_MUST_MAKE) /* The $^, $+, $? and $| variables should not be set if we're called early by a .MUST_MAKE invocation or $(commands ). */ if (called_early) return; #endif /* Compute the values for $^, $+, $?, and $|. */ #ifdef CONFIG_WITH_LAZY_DEPS_VARS /* Lazy doesn't work for double colon rules with multiple files with commands, nor for files that has been thru rehash_file() (vpath). */ if ( ( file->double_colon && ( file->double_colon != file || file->last != file)) || file->name != file->hname) /* XXX: Rehashed files should be fixable! */ #endif { static char *plus_value=0, *bar_value=0, *qmark_value=0; static unsigned int plus_max=0, bar_max=0, qmark_max=0; unsigned int qmark_len, plus_len, bar_len; char *cp; char *caret_value; char *qp; char *bp; unsigned int len; struct hash_table dep_hash; void **slot; /* Compute first the value for $+, which is supposed to contain duplicate dependencies as they were listed in the makefile. */ plus_len = 0; bar_len = 0; for (d = file->deps; d != 0; d = d->next) { if (!d->need_2nd_expansion) { if (d->ignore_mtime) #ifndef CONFIG_WITH_STRCACHE2 bar_len += strlen (dep_name (d)) + 1; #else bar_len += strcache2_get_len (&file_strcache, dep_name (d)) + 1; #endif else #ifndef CONFIG_WITH_STRCACHE2 plus_len += strlen (dep_name (d)) + 1; #else plus_len += strcache2_get_len (&file_strcache, dep_name (d)) + 1; #endif } } if (bar_len == 0) bar_len++; if (plus_len == 0) plus_len++; if (plus_len > plus_max) plus_value = xrealloc (plus_value, plus_max = plus_len); cp = plus_value; qmark_len = plus_len + 1; /* Will be this or less. */ for (d = file->deps; d != 0; d = d->next) if (! d->ignore_mtime && ! d->need_2nd_expansion) { const char *c = dep_name (d); #ifndef NO_ARCHIVES if (ar_name (c)) { c = strchr (c, '(') + 1; len = strlen (c) - 1; } else #endif #ifndef CONFIG_WITH_STRCACHE2 len = strlen (c); #else len = strcache2_get_len (&file_strcache, c); #endif memcpy (cp, c, len); cp += len; *cp++ = FILE_LIST_SEPARATOR; if (! (d->changed || always_make_flag)) qmark_len -= len + 1; /* Don't space in $? for this one. */ } /* Kill the last space and define the variable. */ cp[cp > plus_value ? -1 : 0] = '\0'; DEFINE_VARIABLE ("+", 1, plus_value); /* Compute the values for $^, $?, and $|. */ cp = caret_value = plus_value; /* Reuse the buffer; it's big enough. */ if (qmark_len > qmark_max) qmark_value = xrealloc (qmark_value, qmark_max = qmark_len); qp = qmark_value; if (bar_len > bar_max) bar_value = xrealloc (bar_value, bar_max = bar_len); bp = bar_value; /* Make sure that no dependencies are repeated in $^, $?, and $|. It would be natural to combine the next two loops but we can't do it because of a situation where we have two dep entries, the first is order-only and the second is normal (see below). */ hash_init (&dep_hash, 500, dep_hash_1, dep_hash_2, dep_hash_cmp); for (d = file->deps; d != 0; d = d->next) { if (d->need_2nd_expansion) continue; slot = hash_find_slot (&dep_hash, d); if (HASH_VACANT (*slot)) hash_insert_at (&dep_hash, d, slot); else { /* Check if the two prerequisites have different ignore_mtime. If so then we need to "upgrade" one that is order-only. */ struct dep* hd = (struct dep*) *slot; if (d->ignore_mtime != hd->ignore_mtime) d->ignore_mtime = hd->ignore_mtime = 0; } } for (d = file->deps; d != 0; d = d->next) { const char *c; if (d->need_2nd_expansion || hash_find_item (&dep_hash, d) != d) continue; c = dep_name (d); #ifndef NO_ARCHIVES if (ar_name (c)) { c = strchr (c, '(') + 1; len = strlen (c) - 1; } else #endif #ifndef CONFIG_WITH_STRCACHE2 len = strlen (c); #else len = strcache2_get_len (&file_strcache, c); #endif if (d->ignore_mtime) { memcpy (bp, c, len); bp += len; *bp++ = FILE_LIST_SEPARATOR; } else { memcpy (cp, c, len); cp += len; *cp++ = FILE_LIST_SEPARATOR; if (d->changed || always_make_flag) { memcpy (qp, c, len); qp += len; *qp++ = FILE_LIST_SEPARATOR; } } } hash_free (&dep_hash, 0); /* Kill the last spaces and define the variables. */ cp[cp > caret_value ? -1 : 0] = '\0'; DEFINE_VARIABLE ("^", 1, caret_value); qp[qp > qmark_value ? -1 : 0] = '\0'; DEFINE_VARIABLE ("?", 1, qmark_value); bp[bp > bar_value ? -1 : 0] = '\0'; DEFINE_VARIABLE ("|", 1, bar_value); } #undef DEFINE_VARIABLE } /* Chop CMDS up into individual command lines if necessary. Also set the 'lines_flags' and 'any_recurse' members. */ void chop_commands (struct commands *cmds) { unsigned int nlines, idx; char **lines; /* If we don't have any commands, or we already parsed them, never mind. */ if (!cmds || cmds->command_lines != 0) return; /* Chop CMDS->commands up into lines in CMDS->command_lines. */ if (one_shell) { int l = strlen (cmds->commands); nlines = 1; lines = xmalloc (nlines * sizeof (char *)); lines[0] = xstrdup (cmds->commands); /* Strip the trailing newline. */ if (l > 0 && lines[0][l-1] == '\n') lines[0][l-1] = '\0'; } else { const char *p; nlines = 5; lines = xmalloc (nlines * sizeof (char *)); idx = 0; p = cmds->commands; while (*p != '\0') { const char *end = p; find_end:; end = strchr (end, '\n'); if (end == 0) end = p + strlen (p); else if (end > p && end[-1] == '\\') { int backslash = 1; const char *b; for (b = end - 2; b >= p && *b == '\\'; --b) backslash = !backslash; if (backslash) { ++end; goto find_end; } } if (idx == nlines) { nlines += 2; lines = xrealloc (lines, nlines * sizeof (char *)); } lines[idx++] = xstrndup (p, end - p); p = end; if (*p != '\0') ++p; } if (idx != nlines) { nlines = idx; lines = xrealloc (lines, nlines * sizeof (char *)); } } /* Finally, set the corresponding CMDS->lines_flags elements and the CMDS->any_recurse flag. */ if (nlines > USHRT_MAX) ON (fatal, &cmds->fileinfo, _("Recipe has too many lines (%ud)"), nlines); cmds->ncommand_lines = nlines; cmds->command_lines = lines; cmds->any_recurse = 0; #ifndef CONFIG_WITH_COMMANDS_FUNC cmds->lines_flags = xmalloc (nlines); #else cmds->lines_flags = xmalloc (nlines * sizeof (cmds->lines_flags[0])); #endif for (idx = 0; idx < nlines; ++idx) { unsigned char flags = 0; const char *p = lines[idx]; while (ISBLANK (*p) || *p == '-' || *p == '@' || *p == '+' IF_WITH_COMMANDS_FUNC(|| *p == '%')) switch (*(p++)) { case '+': flags |= COMMANDS_RECURSE; break; case '@': flags |= COMMANDS_SILENT; break; case '-': flags |= COMMANDS_NOERROR; break; #ifdef CONFIG_WITH_COMMANDS_FUNC case '%': flags |= COMMAND_GETTER_SKIP_IT; break; #endif } /* If no explicit '+' was given, look for MAKE variable references. */ if (!(flags & COMMANDS_RECURSE) #ifndef KMK && (strstr (p, "$(MAKE)") != 0 || strstr (p, "${MAKE}") != 0)) #else && (strstr (p, "$(KMK)") != 0 || strstr (p, "${KMK}") != 0 || strstr (p, "$(MAKE)") != 0 || strstr (p, "${MAKE}") != 0)) #endif flags |= COMMANDS_RECURSE; #ifdef CONFIG_WITH_KMK_BUILTIN /* check if kmk builtin command */ if (!strncmp(p, "kmk_builtin_", sizeof("kmk_builtin_") - 1)) flags |= COMMANDS_KMK_BUILTIN; #endif cmds->lines_flags[idx] = flags; cmds->any_recurse |= flags & COMMANDS_RECURSE ? 1 : 0; } } #ifdef CONFIG_WITH_MEMORY_OPTIMIZATIONS /* This is for saving memory in func_commands. */ void free_chopped_commands (struct commands *cmds) { if ( cmds && cmds->command_lines != 0 && cmds->refs == 0) { unsigned idx = cmds->ncommand_lines; while (idx-- > 0) free (cmds->command_lines[idx]); free (cmds->command_lines); free (cmds->lines_flags); cmds->command_lines = 0; cmds->lines_flags = 0; cmds->ncommand_lines = 0; } } #endif /* CONFIG_WITH_MEMORY_OPTIMIZATIONS */ /* Execute the commands to remake FILE. If they are currently executing, return or have already finished executing, just return. Otherwise, fork off a child process to run the first command line in the sequence. */ void execute_file_commands (struct file *file) { const char *p; /* Don't go through all the preparations if the commands are nothing but whitespace. */ for (p = file->cmds->commands; *p != '\0'; ++p) if (!ISSPACE (*p) && *p != '-' && *p != '@' && *p != '+') break; if (*p == '\0') { /* If there are no commands, assume everything worked. */ #ifdef CONFIG_WITH_EXTENDED_NOTPARALLEL file->command_flags |= COMMANDS_NO_COMMANDS; #endif set_command_state (file, cs_running); file->update_status = us_success; notice_finished_file (file); return; } /* First set the automatic variables according to this file. */ initialize_file_variables (file, 0); #if defined(CONFIG_WITH_COMMANDS_FUNC) || defined (CONFIG_WITH_DOT_MUST_MAKE) set_file_variables (file, 0 /* final call */); #else set_file_variables (file); #endif /* If this is a loaded dynamic object, unload it before remaking. Some systems don't support overwriting a loaded object. */ if (file->loaded) unload_file (file->name); /* Start the commands running. */ new_job (file); } /* This is set while we are inside fatal_error_signal, so things can avoid nonreentrant operations. */ int handling_fatal_signal = 0; /* Handle fatal signals. */ RETSIGTYPE fatal_error_signal (int sig) { #ifdef __MSDOS__ extern int dos_status, dos_command_running; if (dos_command_running) { /* That was the child who got the signal, not us. */ dos_status |= (sig << 8); return; } remove_intermediates (1); exit (EXIT_FAILURE); #else /* not __MSDOS__ */ #ifdef _AMIGA remove_intermediates (1); if (sig == SIGINT) fputs (_("*** Break.\n"), stderr); exit (10); #else /* not Amiga */ #if defined (WINDOWS32) && !defined (CONFIG_NEW_WIN32_CTRL_EVENT) extern HANDLE main_thread; /* Windows creates a sperate thread for handling Ctrl+C, so we need to suspend the main thread, or else we will have race conditions when both threads call reap_children. */ if (main_thread) { DWORD susp_count = SuspendThread (main_thread); if (susp_count != 0) fprintf (stderr, "SuspendThread: suspend count = %ld\n", susp_count); else if (susp_count == (DWORD)-1) { DWORD ierr = GetLastError (); fprintf (stderr, "SuspendThread: error %ld: %s\n", ierr, map_windows32_error_to_string (ierr)); } } #endif handling_fatal_signal = 1; /* Set the handling for this signal to the default. It is blocked now while we run this handler. */ signal (sig, SIG_DFL); /* A termination signal won't be sent to the entire process group, but it means we want to kill the children. */ if (sig == SIGTERM) { struct child *c; for (c = children; c != 0; c = c->next) if (!c->remote) (void) kill (c->pid, SIGTERM); } /* If we got a signal that means the user wanted to kill make, remove pending targets. */ if (sig == SIGTERM || sig == SIGINT #ifdef SIGHUP || sig == SIGHUP #endif #ifdef SIGQUIT || sig == SIGQUIT #endif ) { struct child *c; /* Remote children won't automatically get signals sent to the process group, so we must send them. */ for (c = children; c != 0; c = c->next) if (c->remote) (void) remote_kill (c->pid, sig); for (c = children; c != 0; c = c->next) delete_child_targets (c); /* Clean up the children. We don't just use the call below because we don't want to print the "Waiting for children" message. */ while (job_slots_used > 0) reap_children (1, 0); } else /* Wait for our children to die. */ while (job_slots_used > 0) reap_children (1, 1); /* Delete any non-precious intermediate files that were made. */ remove_intermediates (1); #ifdef SIGQUIT if (sig == SIGQUIT) /* We don't want to send ourselves SIGQUIT, because it will cause a core dump. Just exit instead. */ exit (MAKE_TROUBLE); #endif #ifdef WINDOWS32 # ifndef CONFIG_NEW_WIN32_CTRL_EVENT if (main_thread) CloseHandle (main_thread); # endif /* !CONFIG_NEW_WIN32_CTRL_EVENT */ /* Cannot call W32_kill with a pid (it needs a handle). The exit status of 130 emulates what happens in Bash. */ exit (130); #else /* Signal the same code; this time it will really be fatal. The signal will be unblocked when we return and arrive then to kill us. */ if (kill (getpid (), sig) < 0) pfatal_with_name ("kill"); #endif /* not WINDOWS32 */ #endif /* not Amiga */ #endif /* not __MSDOS__ */ } /* Delete FILE unless it's precious or not actually a file (phony), and it has changed on disk since we last stat'd it. */ static void delete_target (struct file *file, const char *on_behalf_of) { struct stat st; int e; if (file->precious || file->phony) return; #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET assert (!file->multi_maybe); #endif #ifndef NO_ARCHIVES if (ar_name (file->name)) { time_t file_date = (file->last_mtime == NONEXISTENT_MTIME ? (time_t) -1 : (time_t) FILE_TIMESTAMP_S (file->last_mtime)); if (ar_member_date (file->name) != file_date) { if (on_behalf_of) OSS (error, NILF, _("*** [%s] Archive member '%s' may be bogus; not deleted"), on_behalf_of, file->name); else OS (error, NILF, _("*** Archive member '%s' may be bogus; not deleted"), file->name); } return; } #endif EINTRLOOP (e, stat (file->name, &st)); if (e == 0 && S_ISREG (st.st_mode) && FILE_TIMESTAMP_STAT_MODTIME (file->name, st) != file->last_mtime) { if (on_behalf_of) OSS (error, NILF, _("*** [%s] Deleting file '%s'"), on_behalf_of, file->name); else OS (error, NILF, _("*** Deleting file '%s'"), file->name); if (unlink (file->name) < 0 && errno != ENOENT) /* It disappeared; so what. */ perror_with_name ("unlink: ", file->name); } } /* Delete all non-precious targets of CHILD unless they were already deleted. Set the flag in CHILD to say they've been deleted. */ void delete_child_targets (struct child *child) { struct dep *d; if (child->deleted) return; /* Delete the target file if it changed. */ delete_target (child->file, NULL); /* Also remove any non-precious targets listed in the 'also_make' member. */ for (d = child->file->also_make; d != 0; d = d->next) delete_target (d->file, child->file->name); #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET /* Also remove any multi target siblings, except for the 'maybe' ones (we handle that here) and precious ones (delete_target deals with that). Note that CHILD is always the multi target head (see remake.c). */ if (child->file == child->file->multi_head) { struct file *f2; for (f2 = child->file->multi_next; f2; f2 = f2->multi_next) if (!f2->multi_maybe) delete_target (f2, child->file->name); } #endif child->deleted = 1; } /* Print out the commands in CMDS. */ void print_commands (const struct commands *cmds) { const char *s; fputs (_("# recipe to execute"), stdout); if (cmds->fileinfo.filenm == 0) puts (_(" (built-in):")); else printf (_(" (from '%s', line %lu):\n"), cmds->fileinfo.filenm, cmds->fileinfo.lineno); s = cmds->commands; while (*s != '\0') { const char *end; int bs; /* Print one full logical recipe line: find a non-escaped newline. */ for (end = s, bs = 0; *end != '\0'; ++end) { if (*end == '\n' && !bs) break; bs = *end == '\\' ? !bs : 0; } printf ("%c%.*s\n", cmd_prefix, (int) (end - s), s); s = end + (end[0] == '\n'); } } kbuild-3149/src/kmk/ChangeLog.20000644000175000017500000075164713252530201016204 0ustar locutuslocutus2000-06-22 Paul D. Smith * job.c (start_job_command): Increment commands_started before the special check for ":" (empty command) to avoid spurious "is up to date" messages. Also move the test for question_flag after we expand arguments, and only stop if the expansion provided an actual command to run, not just whitespace. This fixes PR/1780. 2000-06-21 Paul D. Smith * read.c (read_makefile): If we find a semicolon in the target definition, remember where it was. If the line turns out to be a target-specific variable, add back the semicolon and everything after it. Fixes PR/1709. 2000-06-19 Paul D. Smith * config.h-vms.template: #define uintmax_t for this system. * config.ami.template: Ditto. * config.h.W32.template: Ditto. * configure.in: We don't use select(2) anymore, so don't bother checking for it. * acconfig.h: Ditto. * acinclude.m4: Ditto. * file.c (all_secondary): New static global; if 1 it means .SECONDARY with no prerequisites was seen in the makefile. (snap_deps): Set it appropriately. (remove_intermediates): Check it. (num_intermediates): Remove this global, it's not used anywhere. (considered): Move this to remake.c and make it static. * NEWS: Document the change to .SECONDARY. * make.texinfo (Special Targets): Document the change to .SECONDARY. * implicit.c (pattern_search): Remove the increment of num_intermediates; it's not used. * filedef.h: Remove num_intermediates and considered. * function.c (handle_function): If the last argument was empty, we were pretending it didn't exist rather than providing an empty value. Keep looking until we're past the end, not just at the end. * implicit.c (pattern_search): Multi-target implicit rules weren't expanding the "also made" targets correctly if the pattern didn't contain a slash but the target did; in that case the directory part wasn't being added back to the stem on the "also made" targets. Reported by Seth M LaForge , with a patch. 2000-06-17 Eli Zaretskii * Makefile.DOS.template (DESTDIR, bindir, datadir, libdir) (infodir, mandir, includedir): Support installation under a non-default DESTDIR. * remake.c (f_mtime): Fix the spelling of __MSDOS__. * configh.DOS.template (HAVE_FDOPEN, HAVE_MKSTEMP): Define. 2000-06-14 Paul D. Smith * acinclude.m4 (pds_WITH_GETTEXT): rewrite fp_WITH_GETTEXT and rename it to avoid confusion. This version is very specific: it won't accept any gettext that isn't GNU. If the user doesn't explicitly ask for the included gettext, we look to see if the system gettext is GNU (testing both the actual libintl library, and the libintl.h header file). Only if the system gettext is really GNU gettext will we allow it to be used. (pds_CHECK_SYSTEM_GETTEXT): A helper function. 2000-06-13 Paul D. Smith * gettext.h: If we have libintl.h, use that instead of any of the contents of gettext.h. We won't check for libintl.h unless we're using the system gettext. * function.c (func_word): Clarify error message. 2000-06-10 Paul Eggert Support nanosecond resolution on hosts with 64-bit time_t and uintmax_t (e.g. 64-bit Sparc Solaris), by splitting FILE_TIMESTAMP into a 30-bit part for nanoseconds, with the rest for seconds, if FILE_TIMESTAMP is at least 64 bits wide. * make.h: Always define FILE_TIMESTAMP to be uintmax_t, for simplicity. * filedef.h (FILE_TIMESTAMP_HI_RES, FILE_TIMESTAMP_LO_BITS) (UNKNOWN_MTIME, NONEXISTENT_MTIME, OLD_MTIME) (ORDINARY_MTIME_MIN, ORDINARY_MTIME_MAX): New macros. (FILE_TIMESTAMP_STAT_MODTIME): Now takes fname arg. All uses changed. (FILE_TIMESTAMP_DIV, FILE_TIMESTAMP_MOD) (FILE_TIMESTAMP_FROM_S_AND_NS): Remove. (FILE_TIMESTAMP_S, FILE_TIMESTAMP_NS): Use shifts instead of multiplication and division. Offset the timestamps by ORDINARY_MTIME_MIN. (file_timestamp_cons): New decl. (NEW_MTIME): Now just the maximal timestamp value, as we no longer use -1 to refer to nonexistent files. * file.c (snap_deps, print_file): Use NONEXISTENT_MTIME, UNKNOWN_MTIME, and OLD_MTIME instead of magic constants. * filedef.h (file_mtime_1): Likewise. * main.c (main): Likewise. * remake.c (update_file_1, notice_finished_file, check_dep) (f_mtime, name_mtime, library_search): Likewise. * vpath.c (selective_vpath_search): Likewise. * remake.c (f_mtime): Do not assume that (time_t) -1 equals NONEXISTENT_MTIME. When futzing with time stamps, adjust by multiples of 2**30, not 10**9. Do not calculate timestamp adjustments on DOS unless they are needed. * commands.c (delete_target): Do not assume that FILE_TIMESTAMP_S yields -1 for a nonexistent file, as that is no longer true with the new representation. * file.c (file_timestamp_cons): New function, replacing FILE_TIMESTAMP_FROM_S_AND_NS. All uses changed. (file_timestamp_now): Use FILE_TIMESTAMP_HI_RES instead of 1 < FILE_TIMESTAMPS_PER_S to determine whether we're using hi-res timestamps. (print_file): Print OLD_MTIME values as "very old" instead of as a timestamp. 2000-05-31 Paul Eggert * remake.c (name_mtime): Check for stat failures. Retry if EINTR. 2000-05-24 Paul D. Smith * main.c (decode_switches): The "positive_int" switch uses atoi() which succeeds for any input, and doesn't notice if extra, non-digit text is after the number. This causes make to mis-parse command lines like "make -j 5foo" as "make -j5" (ignoring "foo" completely) instead of "make -j0 5foo" (where "5foo" is a target). Fix this by checking the value by hand. We could use strtol() if we were sure of having it; this is the only questionable use of atoi() I found so we'll just stick with that. Fixes PR/1716. * i18n/ja.po, i18n/nl.po, i18n/pt_BR.po: New translation files. * configure.in (ALL_LINGUAS): Added pt_BR. 2000-05-22 Paul Eggert * remake.c (f_mtime): Fix bug when handling future odd timestamps in the WINDOWS32 case. Do not bother initializing static var to zero. Simplify code that works around WINDOWS32 and __MSDOS__ time skew brain damage. 2000-05-22 Paul Eggert * job.c: Don't include time.h, as make.h already does this. 2000-05-22 Paul Eggert * configure.in (AC_CHECK_HEADERS): Add sys/time.h. (AC_HEADER_TIME): Add. (clock_gettime): Prefer -lrt to -lposix4, for Solaris 7. (gettimeofday): Add check for standard version of gettimeofday. This merges changes written by Paul D. Smith. * file.c (file_timestamp_now): Use gettimeofday if available and if clock_gettime does not work. Don't bother with high-resolution clocks if file timestamps have only one-second resolution. * make.h : Include, conditionally on the usual TIME_WITH_SYS_TIME and HAVE_SYS_TIME_H macros. This is needed for gettimeofday. 2000-05-20 Paul D. Smith * read.c (read_makefile): We weren't keeping makefile names around unless there was a rule defined in them; but now we need to keep them for variables as well. Forget trying to be fancy: just keep every makefile name we successfully open. * remote-cstms.c (start_remote_job_p): Change DB_EXTRA (?) to DB_JOBS. 2000-05-17 Paul Eggert * commands.c (chop_commands): Ensure ctype macro args are nonnegative. * expand.c (variable_expand_string): Likewise. * function.c (subst_expand, lookup_function, msdos_openpipe): Likewise. * job.c (vms_redirect, start_job_command, new_job, child_execute_job, construct_command_argv_internal, construct_command_argv): Likewise. * main.c (decode_env_switches, quote_for_env): Likewise. * misc.c (collapse_continuations, end_of_token, end_of_token_w32, next_token): Likewise. * read.c (read_makefile, do_define, conditional_line, find_char_unquote,get_next_mword): Likewise. * variable.c (try_variable_definition): Likewise. * vpath.c (construct_vpath_list): Likewise. * w32/pathstuff.c (convert_vpath_to_windows32): Likewise. 2000-05-10 Eli Zaretskii * main.c (main) [__MSDOS__]: Add SIGFPE to signals we block when running child programs, to prevent Make from dying on Windows 9X when the child triggers an FP exception. 2000-05-08 Paul D. Smith * dir.c (find_directory) [WINDOWS32]: If we strip a trailing "\" from the directory name, remember to add it back. The argument might really be inside a longer string (e.g. %Path%) and if you don't restore the "\" it'll be truncated permanently. Fixes PR/1722. Reported by 2000-05-02 Paul D. Smith * job.c (construct_command_argv_internal) [WINDOWS32]: Added "rd" and "rmdir" to the list of command.com commands. Reported by Elod Horvath 2000-04-24 Paul D. Smith * i18n/ja.po: New translation file from the Japanese language team. 2000-04-18 Paul D. Smith * remake.c (f_mtime): If ar_member_date() returns -1 (the member doesn't exist), then return (FILE_TIMESTAMP)-1 rather than returning the timestamp calculated from the value -1. Fixes PR/1696. Reported by Gilles Bourhis . 2000-04-17 Paul D. Smith * config.h.W32.template: Add LOCALEDIR macro resolving to "". * w32/subproc/sub_proc.c (process_begin): Remove reference to debug_flag; change it to a DB() call. Fixes PR/1700. Reported by Jim Smith 2000-04-17 Bruno Haible * arscan.c [BeOS]: Add replacement for nonexistent from GNU binutils. 2000-04-11 Paul D. Smith * function.c (expand_builtin_function): If no arguments were provided, just quit early rather than changing each function to test for this. (function_table[]): Change the min # of arguments to 0 for all those functions for which it makes sense (currently everything that used to take a minimum of 1 argument, except $(call ...)). Fixes PR/1689. 2000-04-09 Eli Zaretskii * README.DOS: Add instructions to install a binary distro. Mention latest versions of Windows. 2000-04-07 Eli Zaretskii * main.c (main): Rename TMP_TEMPLATE into DEFAULT_TMPDIR, and use it for the directory of the temporary file. If P_tmpdir is defined, use it in preference to "/tmp/". Try $TMPDIR, $TEMP, and $TMP in the environment before defaulting to DEFAULT_TMPDIR. (print_version): Add year 2000 to the Copyright line. 2000-04-04 Paul D. Smith * Version 3.79 released. * make.texinfo: Update documentation with new features for 3.79. * function.c (func_wordlist): Don't re-order arguments to wordlist. 2000-04-03 Paul D. Smith * remake.c (f_mtime): Archive member timestamps are stored as time_t, without nanoseconds. But, f_mtime() wants to return nanosecond info on those systems that support it. So, convert the return value of ar_member_date() into a FILE_TIMESTAMP, using 0 as the nanoseconds. 2000-03-28 Paul D. Smith * Version 3.78.92 released. * build.template: Updates for gettext support; some bugs fixed. 2000-03-27 Paul D. Smith * config.guess, config.sub: Updated from config CVS archive at :pserver:anoncvs@subversions.gnu.org:/home/cvs as of today. * read.c (record_files): Check if expanding a static pattern rule's prerequisite pattern leaves an empty string as the prerequisite, and issue an error if so. Fixes PR/1670. (read_makefile): Store the starting linenumber for a rule in TGTS_STARTED. (record_waiting_files): Use the TGTS_STARTED value for the file location passed to record_file() instead of the current linenumber, so error messages list the line where the target was defined instead of the line after the end of the rule definition. * remake.c (start_updating, finish_updating, is_updating): Fix PR/1671; circular dependencies in double-colon rules are not diagnosed. These macros set the updating flag in the root double-colon file instead of the current one, if it's part of a double-colon list. This solution provided by Tim Magill ; I just changed the macro names :). (update_file_1): Call them. (check_dep): Call them. The change to not automatically evaluate the $(call ...) function's arguments breaks recursive use of call. Although using $(if ...) and $(foreach ...) in $(call ...) macros is important, the error conditions generated are simply to obscure for me to feel comfortable with. If a method is devised to get both working, we'll revisit. For now, remove this change. * function.c (function_table): Turn on the expand bit for func_call. (func_call): Don't expand arguments for builtin functions; that will have already been done. 2000-03-26 Paul D. Smith * file.c (remove_intermediates): Never remove targets explicitly requested on the command-line by checking the cmd_target flag. Fixed PR/1669. 2000-03-23 Paul Eggert * filedef.h (FILE_TIMESTAMP_STAT_MODTIME): Use st_mtime instead of st_mtim.tv_sec; the latter doesn't work on Unixware. 2000-03-18 Paul D. Smith * file.c (file_hash_enter): If we're trying to change a file into itself, just return. We used to assert this wasn't true, but someone came up with a weird case involving archives. After playing with it for a while I decided it was OK to ignore it. * default.c: Define COFLAGS to empty to avoid spurious warnings. * filedef.h: Change #if ST_MTIM_NSEC to #ifdef; this is a macro containing the name of the nsec field, not true/false. * make.h: Ditto. Reported by Marco Franzen . 2000-03-08 Tim Magill * remake.c (update_file): Return the exit status of the pruned file when pruning, not just 0. Fixes PR/1634. 2000-02-24 Paul D. Smith * configure.in: Close a minor potential security hole; if you're reading makefiles from stdin (who does that?) you could run into a race condition with the temp file using mktemp() or tmpnam(). Add a check for mkstemp() and fdopen(). * main.c (open_tmpfile): New function to open a temporary file. If we have mkstemp() (and fdopen()), use that. If not use mktemp() or tmpnam(). If we have fdopen(), use open() to open the file O_CREAT|O_EXCL. If not, fall back to normal fopen() (insecure). (main): Call it. * job.c (child_execute_job) [VMS]: Call it. * variable.c (lookup_variable): If we find a variable which is being expanded, then note it but keep looking through the rest of the set list to see if we can find one that isn't. If we do, return that. If we don't, return the original. Fix for PR/1610. While implementing this I realized that it also solves PR/1380 in a much more elegant way. I don't know what I was smoking before. So, remove the hackage surrounding the original fix for that (see below). Change this function back to lookup_variable and remove the extra setlist argument. * variable.h (recursively_expand_setlist): Remove the macro, rename the prototype, and remove the extra setlist argument. (lookup_variable): Ditto. * expand.c (recursively_expand): Rename and remove the extra setlist argument. (reference_variable): Use lookup_variable() again. (allocated_variable_append): Remove the extra setlist argument. 2000-02-21 Paul D. Smith * README.template: A few updates. * i18n/de.po: New version from the German translation team. 2000-02-09 Paul D. Smith * Version 3.78.91 released. 2000-02-07 Paul D. Smith * read.c (read_makefile): Reset *p2 to ':', not *colonp. If any filenames contained backslashes the resulting output (without backslashes) will be shorter, so setting *colonp doesn't change the right character. Fix for PR/1586. For += target-specific variables we need to remember which variable set we found the variable in, so we can start looking from there in the next iteration (otherwise we might see it again in recursively_expand and fail!). This is turning into a hack; if it gets any worse we'll have to rethink this entire algorithm... implementing expansion of these references separately from the "normal" expansion, say, instead of using the same codepath. Actually, it's already "worse enough" :-/. Fix for PR/1380. * variable.h (recursively_expand_setlist): Rename recursively_expand to add a struct variable_set_list argument, and make a macro for recursively_expand. (lookup_variable_setlist): Rename lookup_variable to add a struct variable_set_list argument, and make a macro for lookup_variable. * expand.c (recursively_expand_setlist): Take an extra struct variable_set_list argument and pass it to allocated_variable_append(). (reference_variable): Use lookup_variable_setlist() and pass the returned variable_set_list to recursively_expand_setlist. (allocated_variable_append): Take an extra setlist argument and use this as the starting place when searching for the appended expansion. If it's null, use current_variable_set_list as before. * variable.c (lookup_variable_setlist): If the LISTP argument is not nil, set it to the list containing the variable we found. 2000-02-04 Paul D. Smith * variable.c (print_variable): Write out filename/linenumber information for the variable definition if present. (define_variable_in_set): Store filename information if provided. (define_variable, define_variable_for_file): Removed. (try_variable_definition): Use define_variable_loc() to keep variable definition location information. * read.c (read_makefile): Keep variable definition location info. (do_define): Ditto. (record_target_var): Ditto. * variable.h (define_variable_in_set): New fileinfo argument. (define_variable, define_variable_loc, define_variable_for_file): Declare new macros. Fix PR/1407: * filedef.h (struct file): Rename patvar to pat_variables and make it just a variable_set_list; we need our own copy of the pattern variable's variable set list here to avoid overwriting the global one. * variable.c (initialize_file_variables): Move the instantiation of the pat_variables pointer here. Only do the search after we're done reading the makefiles so we don't search too early. If there's a pat_variables value, set up the variables next ptr. * expand.c (variable_expand_for_file): Remove the setup of the pat_variables info; it's done earlier now to ensure the parent's pattern variables are set up correctly as well. 2000-02-03 Paul D. Smith * job.c (sh_chars_dos) [WINDOWS32]: Add "&" as a shell metacharacter for the W32 DOS shell. Reported by Warren Jones . 2000-02-02 Paul D. Smith Fixes for the OpenVMS port from Hartmut Becker * config.h-vms [VMS]: Define LOCALEDIR to something; needed for the expansion of bindtextdomain() even though it's a no-op. * vmsfunctions.c (strcmpi): Remove duplicate definition of strcmpi(). (readdir): Use DB() instead of testing debug_flag. * dir.c (file_impossible) [VMS]: Search "p" not "name". * job.c [VMS]: Switch from debug_flag to the new DB macro. Add some i18n _() macros (even though VMS doesn't yet support it). * function.c (patsubst_expand): Change "len" to not be unsigned to avoid type mismatches. * main.c (main): Declare signame_init() if we're going to call it. 2000-01-29 Eli Zaretskii * Makefile.DOS.template: Track changes in Makefile.in (install-recursive, uninstall-recursive): Add missing targets. (DESTDIR): Define. (install-binPROGRAMS, uninstall-binPROGRAMS): Use $(DESTDIR). * default.c (default_variables) [__MSDOS__]: Define CXX to gpp. 2000-01-27 Paul D. Smith * gettext.c: Some warning cleanups, and a fix for systems which don't define HAVE_ALLOCA (the workaround code was included twice). 2000-01-26 Paul D. Smith * Version 3.78.90 released. 2000-01-25 Paul D. Smith Change gettext support to use the simplified version in libit 0.7. * getopt.c, make.h: Use gettext.h instead of libintl.h. * ABOUT-NLS, gettext.h, gettext.c: New files from libit 0.7. Modified to remove some static declarations which aren't defined. * acconfig.h: Use new gettext #defines. * acinclude.m4: Add fp_WITH_GETTEXT; remove AM_GNU_GETTEXT. * configure.in: Call fp_WITH_GETTEXT instead. * Makefile.am: New gettext stuff. Also force inclusion of glob files for systems which have LIBC glob. * i18n/Makefile.am, i18n/.cvsignore: New dir for translation files. * i18n/de.po, i18n/es.po, i18n/fr.po, i18n/ko.po, i18n/nl.po: * i18n/pl.po, i18n/ru.po: Import translations already done for earlier versions of GNU make. Thanks for that work!! * po/Makefile.in.in, po/POTFILES.in: Removed. 2000-01-23 Paul D. Smith * main.c (decode_debug_flags): If debug_flag is set, enable all debugging levels. (debug_flag): Resurrect this flag variable. (switches): Make -d give the old behavior of turning on all debugging. Change --debug alone to emit basic debugging and take optional arguments to expand debugging. * NEWS: Document the new debugging options. * remake.c (no_rule_error): Remove this function. This tries to fix a real problem--see the description with the introduction of this function below. However, the cure is worse than the disease and this approach won't work. (remake_file): Put the code from no_rule_error back here. (update_file_1): Remove call to no_rule_error. * filedef.h (struct file): Remove mfile_status field. 2000-01-22 Paul D. Smith Integrate GNU gettext support. * configure.in: Add AM_GNU_GETTEXT. * Makefile.am: Add options for setting LOCALEDIR, -Iintl, etc. * acinclude.m4: Add gettext autoconf macros. * acconfig.h: Add new gettext #defines. * make.h: Include libintl.h. Make sure _() and N_() macros are declared. Make gettext() an empty macro is NLS is disabled. * main.c (struct command_switch switches[]): Can't initialize static data with _() (gettext calls), so use N_() there then use gettext() directly when printing the strings. * remake.c (no_rule_error): The string constants can't be static when initializing _() macros. * file.c (print_file): Reformat a few strings to work better for translation. * po/POTFILES.in, po/Makefile.in.in: New files. Take Makefile.in.in from the latest GNU tar distribution, as that version works better than the one that comes with gettext. * NEWS: Mention i18n ability. 2000-01-21 Paul D. Smith Installed patches for the VMS port. Patches provided by: Hartmut Becker * readme.vms, arscan.c, config.h-vms, default.c, dir.c, file.c: * implicit.c, job.c, make.h, makefile.com, makefile.vms, rule.c: * variable.c, vmsdir.h, vmsfunctions.c, vmsify.c, glob/glob.c: * glob/glob.h: Installed patches. See readme.vms for details. 2000-01-14 Andreas Schwab * dir.c (read_dirstream): Initialize d_type if it exists. 2000-01-11 Paul D. Smith Resolve PR/xxxx: don't automatically evaluate the $(call ...) function's arguments. While we're here, clean up argument passing protocol to always use simple nul-terminated strings, instead of sometimes using offset pointers to mark the end of arguments. This change also fixes PR/1517. Reported by Damien GIBOU . * function.c (struct function_table_entry): Remove the negative required_args hack; put in explicit min and max # of arguments. (function_table): Add in the max value. Turn off the expand bit for func_call. (expand_builtin_function): Test against minimum_args instead of the obsolete required_args. (handle_function): Rewrite this. We don't try to be fancy and pass one style of arguments to expanded functions and another style to non-expanded functions: pass pointers to nul-terminated strings to all functions. (func_call): Rewrite this. If we are invoking a builtin function and it's supposed to have its arguments expanded, do that (since it's not done by handle_function for $(call ...) anymore). For non-builtins, just add the variables as before but mark them as recursive so they'll be expanded later, as needed. (func_if): All arguments are vanilla nul-terminated strings: remove trickery with "argv[1]-1". (func_foreach): Ditto. * expand.c (expand_argument): If the second arg is NULL, expand the entire first argument. * job.c (new_job): Zero the child struct. This change was just made to keep some heap checking software happy, not because there was an actual bug (the important memory was being cleared properly). 1999-12-15 Paul D. Smith * variable.c (print_variable): Print the variable with += if the append flag is set. * implicit.c (pattern_search): Remove the extra check of the implicit flag added on 8/24/1998. This causes problems and the reason for the change was better resolved by the change made to check_deps() on 1998-08-26. This fixes PR/1423. 1999-12-08 Paul D. Smith * dir.c (dir_setup_glob): On 64 bit ReliantUNIX (5.44 and above) in LFS mode, stat() is actually a macro for stat64(). Assignment doesn't work in that case. So, stat is a macro, make a local wrapper function to invoke it. (local_stat): Wrapper function, if needed. Reported by Andrej Borsenkow . 1999-12-02 Paul D. Smith * remake.c (update_file): Move the considered test outside the double-colon loop, _but_ make sure we test the double_colon target not the "current" target. If we stop early because one double-colon target is running, mark all the rest considered and try to start their prerequisites (so they're marked considered). Fix for PR/1476 suggested by Tim Magill . 1999-11-22 Rob Tulloh * function.c (windows32_openpipe, func_shell): Correct Windows32 problem where $(shell nosuchfile) would incorrectly exit make. The fix is to print the error and let make continue. Reported by David Masterson . * w32/subproc/misc.c (arr2envblk): Memory leak fix. 1999-11-21 Paul D. Smith Rework GNU make debugging to provide different levels of output. * NEWS: mention it. * debug.h: New file. Define various debugging levels and macros. * function.c, implicit.c, job.c, main.c, misc.c, read.c, remake.c * remote-cstms.c, vmsfunctions.c: Replace all code depending on debug_flag with invocations of debugging macros. * make.h: Remove debug_flag and DEBUGPR, add db_level. 1999-11-18 Paul Eggert * acinclude.m4 (AC_SYS_LARGEFILE_FLAGS): Work around a problem with the QNX 4.25 shell, which doesn't propagate exit status of failed commands inside shell assignments. 1999-11-17 Paul D. Smith * function.c (func_if): Find the end of the arg list by testing the next item for NULL; any other test is not correct. Reported by Graham Reed (PR/1429). Fix += when used in a target-specific variable context. * variable.h: New bitfield APPEND set if we have a += target-specific variable. * variable.c (try_variable_definition): Add an argument to specify if we're trying a target-specific variable. If we are and it's an append style, don't append it, record it as normal recursive, but set the APPEND flag so it'll be expanded later. * main.c (handle_non_switch_argument): Use new try_variable_definition() signature. * read.c (read_makefile,record_target_var): Ditto. * expand.c (allocated_variable_append): New function: like allocated_variable_expand(), but we expand the same variable name in the context of the ``next'' variable set, then we append this expanded value. (recursively_expand): Invoke it, if the APPEND bit is set. 1999-11-10 Paul D. Smith * file.c (snap_deps): If the .NOTPARALLEL target is defined, turn off parallel builds for this make only (still allow submakes to be run in parallel). * main.c: New variable, ``not_parallel''. * make.h: Add an extern for it. * job.c (new_job): Test NOT_PARALLEL as well as JOB_SLOTS. * NEWS: Add info on .NOTPARALLEL. * make.texinfo (Special Targets): Document it. * configure.in (GLOBDIR): Set to "glob" if we need to build the glob library. * Makefile.am (SUBDIRS): Use the GLOBDIR variable instead of "glob" so we don't try to build glob if we don't need to (if we have GLIBC glob). Reported by Lars Hecking . * main.c (main): Don't put "***" in the clock skew warning message. Reported by karl@gnu.org. * make.h: Remove unneeded signal setup. * signame.c: Remove extraneous #includes; some versions of Ultrix don't protect against multiple inclusions and it causes compile errors. Reported by Simon Burge . 1999-10-15 Paul D. Smith * main.c (quote_for_env): Rename from quote_as_word(). * make.h, *.c: Prefer strchr() and strrchr() in the code rather than index() and rindex(). Define strchr/strrchr in terms of index/rindex if the former aren't supported. * default.c (CHECKOUT,v): Replace the fancy, complicated patsubst/filter expression with a simple $(if ...) expression. * main.c (print_usage): Add the bug reporting mailing address to the --help output, as per the GNU coding standards. Reported by Paul Eggert . * README.customs: Installed information on running Customs-ized GNU make and setuid root, collected by Ted Stern . * read.c (read_all_makefiles): PR/1394: Mark the end of the next token in the MAKEFILES value string _before_ we dup it. 1999-10-13 Paul D. Smith * configure.in (make_cv_sys_gnu_glob): We used to add the -Iglob flag to CPPFLAGS, but that loses if the user specifies his own CPPFLAGS; this one gets added _after_ his and if he happens to have an old or broken glob.h--boom. Instead, put it in GLOBINC and SUBST it. * Makefile.am (INCLUDES): Add @GLOBINC@ to the INCLUDES macro; these things get on the compile line well before the user's CPPFLAGS. 1999-10-12 Paul D. Smith * remake.c (notice_finished_file): If we get here and -n is set, see if all the command lines are marked recursive. If so, then we ran every command there is, so check the mtime on this file just like we would normally. If not, we assume the command we didn't run would updates the target and set mtime of the target to "very new". * job.c (start_job_command): Update lines_flags in the file's cmds structure with any per-line tokens we found (`@', `-', `+'). 1999-10-08 Paul D. Smith * variable.c (initialize_file_variables): Always recurse to initialize the parent's file variables: the parent might not have any rules to run so it might not have been initialized before this--we need this to set up the chain properly for target-specific variables. 1999-09-29 Paul Eggert * main.c (quote_as_word): Always quote for decode_env_switches instead of for the shell, so that arguments with strange characters are are passed to submakes correctly. Remove double_dollars arg; we always double dollars now. All callers changed. (decode_env_switches): Don't run off the end of an environment variable whose contents ends in a unescaped backslash. 1999-09-23 Paul D. Smith * commands.c, function.c, job.c, read.c: Cast arguments to ctype.h functions/macros to _unsigned_ char for portability. * remake.c, function.c: Compiler warning fixes: the second argument to find_next_token() should be an _unsigned_ int*. Reported by Han-Wen Nienhuys . 1999-09-23 Paul D. Smith * Version 3.78.1 released. * make.texinfo: Update version/date stamp. * main.c (main): Argh. For some reason we were closing _all_ the jobserver pipes before we re-exec'd due to changed makefiles. This means that any re-exec got a "jobserver unavailable" error :-/. I can't believe we didn't notice this before. 1999-09-22 Paul D. Smith * Version 3.78 released. * main.c (main): Only fail on multiple --jobserver-fds options if they aren't all the same. Some makefiles use things like $(MAKE) $(MFLAGS) which will cause multiple, identical copies of --jobserver-fds to show up. 1999-09-16 Paul D. Smith * main.c (define_makeflags): Zero out FLAGSTRING to avoid uninitialized memory reads when checking *p != '-' in the loop. 1999-09-15 Paul D. Smith * Version 3.77.97 released. * configure.in (MAKE_HOST): AC_SUBST this so it will go into the makefile. * Makefile.am (check-local): Print a success banner if the check succeeds. (check-regression): A bit of fine-tuning. 1999-09-15 Eli Zaretskii * README.DOS.template: Document requirements for the test suite. * Makefile.DOS.template: Updates to allow the test suite to run from "make check". * main.c (main): Handle it if argv[0] isn't an absolute path. 1999-09-13 Paul D. Smith * Version 3.77.96 released. * Makefile.am (loadavg): Use CPPFLAGS, etc. to make sure we get all the right #defines to compile. (check-regression): Look for the regression test suite in the make package itself. If we're building remotely, use symlinks to make a local copy. (dist-hook): Put the test suite into the tar file. * configure.in: Look for perl for the test suite. 1999-09-10 Paul Eggert * acinclude.m4 (AC_SYS_LARGEFILE_FLAGS): If on HP-UX 10.20 or later, and using GCC, define __STDC_EXT__; this works around a bug in GCC 2.95.1. 1999-09-08 Paul D. Smith * main.c (print_version): Ugh. GLIBC's configure tries to check make version strings and is too aggressive with their matching expressions. I've struck a deal with them to leave the version output as-is for 3.78, and they'll change their configure checks so that I can change this back in the future. 1999-09-07 Eli Zaretskii * job.c (construct_command_argv_internal) [__MSDOS__]: Add "echo" and "unset" to the list of builtin shell commands. * configh.DOS.template (MAKE_HOST): Define to "i386-pc-msdosdjgpp" which is the canonical name of the DJGPP host. 1999-09-05 Paul D. Smith * Version 3.77.95 released. * make.texinfo (Make Errors): Document some new jobserver error messages. 1999-09-04 Eli Zaretskii * make.texinfo (Make Errors): Document the hint about 8 spaces instead of a TAB. (Call Function, Quick Reference): Use @code{$(1)}, not @var. * main.c (main) [__MSDOS__]: Say "on this platform" instead of "on MS-DOS", since the MSDOS version could run on Windows. 1999-09-03 Paul D. Smith * remake.c (notice_finished_file): Always set mtime_before_update if it's not been set, not just if we ran some rules. Otherwise we may have a situation where a target's prerequisite was rebuilt but not changed, so this target's rules weren't run, then update_goal_chain() sees mtime_before_update != last_mtime and thinks that the top-level target changed when it really didn't. This can cause an infinite loop when remaking makefiles. (update_goal_chain): If we get back to the top and we don't know what the goal's last_mtime was, find it now. We need to know so we can compare it to mtime_before_update later (this is only crucial when remaking makefiles--should we only do it then?) 1999-09-02 Paul D. Smith * read.c (read_makefile): If "override" appears as the first prerequisite, look further to ensure this is really a target-specific variable definition, and not just some prerequisite named "override". 1999-09-01 Paul D. Smith * function.c (IS_PATHSEP) [WINDOWS32]: Allow backslash separators for W32 platforms. * read.c (record_files) [WINDOWS32]: Allow backslash separators for W32 platforms. * implicit.c (pattern_search) [WINDOWS32]: Allow backslash separators for W32 platforms. * configure.in (MAKE_HOST): Define it to be the canonical build host info, now that we need AC_CANONICAL_HOST anyway (for large file support). * version.c (make_host): Define a variable to MAKE_HOST so we're sure to get it from the local config.h. * main.c (print_version): Use it in the version information. * config.ami.template: Add MAKE_HOST. * configh.dos.template: Ditto. * config.h.W32.template: Ditto. * config.h-vms.template: Ditto. * main.c (main): Close the jobserver file descriptors if we need to re-exec ourselves. Also print more reasonable error if users force -jN for submakes. This may be common for a while until people use the jobserver feature. If it happens, we ignore the existing jobserver stuff and use whatever they specified on the commandline. (define_makeflags): Fixed a long-standing bug: if a long name only option comes immediately after a single letter option with no argument, then the option string is constructed incorrectly. For example, with -w and --jobserver-fds you get "-w-jobserver-fds..." instead of "-w --jobserver-fds..."; add in an extra " -". * make.texinfo (Phony Targets): Add another example of using .PHONY with subdirectories/recursive make. 1999-08-30 Paul D. Smith * README.W32.template: Renamed from README.W32 so it's autogenerated during the dist. A few minor modifications. * configure.in: Check for kstat_open before AC_FUNC_GETLOADAVG since the latter needs to know whether the former exists to give an accurate result. 1999-08-26 Rob Tulloh * NMakefile [WINDOWS32]: Now more robust. If you change a file under w32/subproc, the make.exe will be relinked. Also added some tests to make sure erase commands won't fail when executed in a pristine build environment. * w32/subproc/sub_proc.c [WINDOWS32]: Added support for HAVE_CYGWIN_SHELL. If you are using the Cygwin B20.1 release, it is now possible to have have native support for this shell without having to rely on klutzy BATCH_MODE_ONLY_SHELL. * config.h.W32 [WINDOWS32]: Added HAVE_CYGWIN_SHELL macro which users can define if they want to build make to use this shell. * README.W32 [WINDOWS32]: Added informaton about HAVE_CYGWIN_SHELL. Cleaned up text a bit to make it more current. 1999-08-26 Paul Eggert Support large files in AIX, HP-UX, and IRIX. * acinclude.m4 (AC_LFS): Remove. Superseded by AC_SYS_LARGEFILE. (AC_SYS_LARGEFILE_FLAGS, AC_SYS_LARGEFILE_SPACE_APPEND, AC_SYS_LARGEFILE_MACRO_VALUE, AC_SYS_LARGEFILE): New macros. (jm_AC_TYPE_UINTMAX_T): Check for busted compilers that can't shift or divide unsigned long long. (AM_PROG_CC_STDC): New macro; a temporary workaround of a bug in automake 1.4. * configure.in (AC_CANONICAL_HOST): Add; required by new AC_SYS_LARGEFILE. (AC_SYS_LARGEFILE): Renamed from AC_LFS. (AM_PROG_CC_STDC): Add. * config.guess, config.sub: New files, needed for AC_CANONICAL_HOST. 1999-08-25 Paul Eggert * make.h (CHAR_MAX): New macro. * main.c (struct command_switch): c is now int, so that it can store values greater than CHAR_MAX. (switches): Replace small numbers N with CHAR_MAX+N-1, to avoid problems with non-ASCII character sets. (short_option): New macro. (init_switches, print_usage, define_makeflags): Use it instead of isalnum. 1999-08-25 Paul D. Smith * Version 3.77.94 released. * main.c (main) [__MSDOS__]: If the user uses -j, warn that it's not supported and reset it. * make.h (ISDIGIT): Obtained this from the textutils distribution. * main.c (decode_switches): Use it. * function.c (is_numeric): Use it. * main.c (struct command_switch): Store the switch char in an unsigned char to shut up GCC about using it with ctype.h macros. Besides, it _is_ always unsigned. 1999-08-24 Paul D. Smith * make.texinfo: Change "dependency" to "prerequisite" and "dependencies" to "prerequisites". Various other cleanups related to the terminology change. * file.c: Change debugging and error messages to use "prerequisite" instead of "dependency". * implicit.c: Ditto. * remake.c: Ditto. * NEWS: Document it. 1999-08-23 Paul D. Smith * remake.c (update_file): Move the considered check into the double-colon rule loop, so we consider double-colon rules individually (otherwise after the first is pruned, the rest won't get run). * README.template: Minor changes. Remove the debugging features of the jobserver, so it no longer writes distinct tokens to the pipe. Thus, we don't need to store the token we get. A side effect of this is to remove a potential "unavailable token" situation: make-1 invokes make-2 with its special token and make-3 with a normal token; make-2 completes. Now we're waiting for make-3 but using 2 tokens; our special token is idle. In the new version we don't have special tokens per se, we merely decide if we already have a child or not. If we don't, we don't need a token. If we do, we have to get one to run the next child. Similar for putting tokens back: if we're cleaning up the last child, we don't put a token back. Otherwise, we do. * main.c: Add a new, internal flag --jobserver-fds instead of overloading the meaning of -j. Remove job_slots_str and add the stringlist jobserver_fds. (struct command_switch): We don't need the int_string type. (switches[]): Add a new option for --jobserver-fds and remove conditions around -j. Make the description for the former 0 so it doesn't print during "make --help". (main): Rework jobserver parsing. If we got --jobserver-fds make sure it's valid. We only get one and job_slots must be 0. If we're the toplevel make (-jN without --jobserver-fds) create the pipe and write generic tokens. Create the stringlist struct for the submakes. Clean up the stringlist where necessary. (init_switches): Remove int_string handling. (print_usage): Don't print internal flags (description ptr is 0). (decode_switches): Remove int_string handling. (define_makeflags): Remove int_string handling. * job.c: Remove my_job_token flag and all references to the child->job_token field. (free_job_token): Remove this and merge it into free_child(). (reap_children): Rework the "reaped a child" logic slightly. Don't call defunct free_job_token anymore. Always call free_child, even if we're dying. (free_child): If we're not freeing the only child, put a token back in the pipe. Then, if we're dying, don't bother to free. (new_job): If we are using the jobserver, loop checking to see if a) there are no children or b) we get a token from the pipe. * job.h (struct child): Remove the job_token field. 1999-08-20 Paul D. Smith * variable.c (try_variable_definition): Allocate for variable expansion in f_append with a simple variable: if we're looking at target-specific variables we don't want to trash the buffer. Noticed by Reiner Beninga . 1999-08-16 Eli Zaretskii * main.c (main) [__MSDOS__]: Mirror any backslashes in argv[0], to avoid problems in shell commands that use backslashes as escape characters. 1999-08-16 Paul D. Smith * Version 3.77.93 released. 1999-08-13 Paul D. Smith Another jobserver algorithm change. We conveniently forgot that the blocking bit is shared by all users of the pipe, it's not a per-process setting. Since we have many make processes all sharing the pipe we can't use the blocking bit as a signal handler flag. Instead, we'll dup the pipe's read FD and have the SIGCHLD handler close the dup'd FD. This will cause the read() to fail with EBADF the next time we invoke it, so we know we need to reap children. We then re-dup and reap. * main.c (main): Define the job_rfd variable to hold the dup'd FD. Actually dup the read side of the pipe. Don't bother setting the blocking bit on the file descriptor. * make.h: Declare the job_rfd variable. * job.c (child_handler): If the dup'd jobserver pipe is open, close it and assign -1 to job_rfd to notify the main program that we got a SIGCHLD. (start_job_command): Close the dup'd FD before exec'ing children. Since we open and close this thing so often it doesn't seem worth it to use the close-on-exec bit. (new_job): Remove code for testing/setting the blocking bit. Instead of EAGAIN, test for EBADF. If the dup'd FD has been closed, re-dup it before we reap children. * function.c (func_shell): Be a little more accurate about the length of the error string to allocate. * expand.c (variable_expand_for_file): If there's no filenm info (say, from a builtin command) then reset reading_file to 0. 1999-08-09 Paul D. Smith * maintMakefile: Use g in sed (s///g) to replace >1 variable per line. * Makefile.DOS.template [__MSDOS__]: Fix mostlyclean-aminfo to remove the right files. 1999-08-01 Eli Zaretskii * function.c (msdos_openpipe) [__MSDOS__]: *Really* return a FILE ptr. 1999-08-01 Paul D. Smith New jobserver algorithm to avoid a possible hole where we could miss SIGCHLDs and get into a deadlock. The original algorithm was suggested by Roland McGrath with a nice refinement by Paul Eggert. Many thanks as well to Tim Magill and Howard Chu, who also provided many viable ideas and critiques. We all had a fun week dreaming up interesting ways to use and abuse UNIX syscalls :). Previously we could miss a SIGCHLD if it happened after we reaped the children but before we re-entered the blocking read. If this happened to all makes and/or all children, make would never wake up. We avoid this by having the SIGCHLD handler reset the blocking bit on the jobserver pipe read FD (normally read does block in this algorithm). Now if the handler is called between the time we reap and the time we read(), and there are no tokens available, the read will merely return with EAGAIN instead of blocking. * main.c (main): Set the blocking bit explicitly here. * job.c (child_handler): If we have a jobserver pipe, set the non-blocking bit for it. (start_waiting_job): Move the token stuff back to new_job; if we do it here then we're not controlling the number of remote jobs started! (new_job): Move the check for job slots to _after_ we've created a child structure. If the read returns without getting a token, set the blocking bit then try to reap_children. * make.h (EINTR_SET): Define to test errno if EINTR is available, or 0 otherwise. Just some code cleanup. * arscan.c (ar_member_touch): Use it. * function.c (func_shell): Use it. * job.c (reap_children): Use it. * remake.c (touch_file): Use it. 1999-07-28 Paul D. Smith * make.h: Define _() and N_() macros as passthrough to initiate NLS support. * : Add _()/N_() around translatable strings. 1999-07-27 Paul D. Smith * read.c: Make sure make.h comes before other headers. 1999-07-26 Paul D. Smith * make.texinfo (Quick Reference): Update with the new features. 1999-07-25 Eli Zaretskii * remake.c [__MSDOS__]: Don't include variables.h, it's already included. * function.c (msdos_openpipe) [__MSDOS__]: Return FILE ptr. (func_shell) [__MSDOS__]: Fix the argument list. * Makefile.DOS.template: Update from Makefile.in. * README.DOS.template: Configure command fixed. * configh.dos.template: Update to provide definitions for uintmax_t, fd_set_size_t, and HAVE_SELECT. 1999-07-24 Paul D. Smith * Version 3.77.91 released. * configure.in: Changes to the boostrapping code: if build.sh.in doesn't exist configure spits an error and generates an empty build.sh file which causes make to be confused. * maintMakefile: Don't build README early. 1999-07-23 Paul D. Smith * job.c (my_job_token): This variable controls whether we've handed our personal token to a subprocess or not. Note we could probably infer this from the value of job_slots_used, but it's clearer to just keep it separately. Job_slots_used isn't really relevant when running the job server. (free_job_token): New function: free a job token. If we don't have one, no-op. If we have the personal token, reclaim it. If we have another token, write it back to the pipe. (reap_children): Call free_job_token. (free_child): Call free_job_token. (start_job_command): Remove duplicate test for '+' in the command. If we don't appear to be running a recursive make, close the jobserver filedescriptors. (start_waiting_job): If our personal token is available, use that instead of going to the server pipe. (*): Add the token value to many debugging statements, and print the child target name in addition to the ptr hex value. Change the default "no token" value from '\0' to '-' so it looks better in the output. * main.c (main): Install the child_handler with sigaction() instead of signal() if we have it. On SysV systems, signal() uses SysV semantics which are a pain. But sigaction() always does what we want. (main): If we got job server FDs from the environment, test them to see if they're open. If not, the parent make closed them because it didn't think we were a submake. Print a warning and suggestion to use "+" on the submake invocation, and hard-set to -j1 for this instance of make. (main): Change the algorithm for assigning slots to be more robust. Previously make checked to see if it thought a subprocess was a submake and if so, didn't give it a token. Since make's don't consume tokens we could spawn many of makes fighting for a small number of tokens. Plus this is unreliable because submakes might not be recognized by the parent (see above) then all the tokens could be used up by unrecognized makes, and no one could run. Now every make consumes a token from its parent. However, the make can also use this token to spawn a child. If the make wants more than one, it goes to the jobserver pipe. Thus there will never be more than N makes running for -jN, and N*2 processes (N makes and their N children). Every make can always run at least one job, and we'll never deadlock. (Note the closing of the pipe for non-submakes also solves this, but this is still a better algorithm.) So! Only put N-1 tokens into the pipe, since the topmost make keeps one for itself. * configure.in: Find sigaction. Disable job server support unless the system provides it, in addition to either waitpid() or wait3(). 1999-07-22 Rob Tulloh * arscan.c (ar_member_touch) [WINDOWS32]: The ar_date field is a string on Windows, not a timestamp. 1999-07-21 Paul D. Smith * Version 3.77.90 released. * Makefile.am (AUTOMAKE_OPTIONS): Require automake 1.4. * function.c: Rearrange so we don't need to predeclare the function_table array; K&R C compilers don't like that. * acinclude.m4 (AC_FUNC_SELECT): Ouch; this requires an ANSI C compiler! Change to work with K&R compilers as well. * configure.in (AC_OUTPUT): Put build.sh back. I don't know how I thought it would work this way :-/. We'll have to think of something else. * Makefile.am: Remove rule to create build.sh. * default.c (default_suffix_rules): Rearrange the default command lines to conform to POSIX rules (put the filename argument $< _after_ the OUTPUT_OPTION, not before it). * various: Changed !strncmp() calls to strneq() macros. * misc.c (sindex): Make slightly more efficient. * dir.c (file_impossible): Change savestring(X,strlen(X)) to xstrdup(). * implicit.c (pattern_search): Ditto. * main.c (enter_command_line_file): Ditto. (main): Ditto. * misc.c (copy_dep_chain): Ditto. * read.c (read_makefile): Ditto. (parse_file_seq): Ditto. (tilde_expand): Ditto. (multi_glob): Ditto. * rule.c (install_pattern_rule): Ditto. * variable.c (define_variable_in_set): Ditto. (define_automatic_variables): Ditto. * vpath.c (construct_vpath_list): Ditto. * misc.c (xrealloc): Some reallocs are non-standard: work around them in xrealloc by calling malloc if PTR is NULL. * main.c (main): Call xrealloc() directly instead of testing for NULL. * function.c (func_sort): Don't try to free NULL; some older, non-standard versions of free() don't like it. * configure.in (--enable-dmalloc): Install some support for using dmalloc (http://www.dmalloc.com/) with make. Use --enable-dmalloc with configure to enable it. * function.c (function_table_entry): Whoops! The function.c rewrite breaks backward compatibility: all text to a function is broken into arguments, and extras are ignored. So $(sort a,b,c) returns "a"! Etc. Ouch. Fix it by making a positive value in the REQUIRED_ARGS field mean exactly that many arguments to the function; any "extras" are considered part of the last argument as before. A negative value means at least that many, but may be more: in this case all text is broken on commas. (handle_function): Stop when we've seen REQUIRED_ARGS args, if >0. (expand_builtin_function): Compare number of args to the absolute value of REQUIRED_ARGS. 1999-07-20 Paul D. Smith * job.c (start_job_command): Ensure that the state of the target is cs_running. It might not be if we skipped all the lines due to -n (for example). * commands.c (execute_file_commands): If we discover that the command script is empty and succeed early, set cs_running so the modtime of the target is still rechecked. * rule.c (freerule): Free the dependency list for the rule. * implicit.c (pattern_search): When turning an intermediate file into a real target, keep the also_make list. Free the dep->name if we didn't use it during enter_file(). 1999-07-16 Paul D. Smith * read.c (read_makefile): Don't allocate the commands buffer until we're sure we found a makefile and won't return early (mem leak). * job.c (start_job_command): Broken #ifdef test: look for F_SETFD, not FD_SETFD. Close-on-exec isn't getting set on the bad_stdin file descriptor and it's leaking :-/. * getloadavg.c (getloadavg): Ditto. 1999-07-15 Paul D. Smith * read.c (read_makefile): Fix some potential memory stomps parsing `define' directives where no variable name is given. * function.c (func_call): Rename from func_apply. Various code cleanup and tightening. (function_table): Add "call" as a valid builtin function. * make.texinfo (Call Function): Document it. * NEWS: Announce it. 1999-07-09 Eli Zaretskii * variable.c (try_variable_definition) [__MSDOS__, WINDOWS32]: Treat "override SHELL=" the same as just "SHELL=". 1999-07-09 Paul D. Smith * job.c (start_waiting_job): Don't get a second job token if we already have one; if we're waiting on the load to go down start_waiting_job() might get called twice on the same file. * filedef.h (struct file): Add new field, mtime_before_update. When notice_finished_file runs it assigns the cached last_mtime to this field. * remake.c (update_goal_chain): Notice that a file wasn't updated by asking if it changed (g->changed) and comparing the current cached time (last_mtime) with the previous one, stored in mtime_before_update. The previous check ("did last_mtime changed during the run of update_file?") fails for parallel builds because last_mtime is set during reap_children, before update_file is run. This causes update_goal_chain to always return -1 (nothing rebuilt) when running parallel (-jN). This is OK during "normal" builds since our caller (main) treats these cases identically in that case, but if when rebuilding makefiles the difference is very important, as it controls whether we re-exec or not. * file.c (file_hash_enter): Copy the mtime_before_update field. (snap_deps): Initialize mtime_before_update to -1. * main.c (main): Initialize mtime_before_update on old (-o) and new (-W) files. 1999-07-08 Paul D. Smith * main.c (switches): Define a new switch -R (or --no-builtin-variables). This option disables the defining of all the GNU make builtin variables. (main): If -R was given, force -r as well. * default.c (define_default_variables): Test the new flag. * make.h: Declare global flag. * make.texinfo (Options Summary): Document the new option. (Implicit Variables): Ditto. 1999-07-06 Paul D. Smith * make.texinfo (Options Summary): Correct examples in --print-data-base option summary (problem reported by David Morse ). * arscan.c: Add support for archives in Windows (VC++). Frank Libbrecht provided info on how to do this. * NMakefile.template (CFLAGS_any): Remove NO_ARCHIVES from the compile line. * build_w32.bat: Ditto. * remake.c (no_rule_error): Fix -include/sinclude so it doesn't give errors if you try to -include the same file twice. (updating_makefiles): New variable: we need to know this info in no_rule_error() so we know whether to print an error or not. (update_file_1): Unconditionally call no_rule_error(), don't try to play games with the dontcare flag. 1999-06-14 Paul D. Smith * make.texinfo (Remaking Makefiles): Add a description of how to prevent implicit rule searches for makefiles. * make.1: Remove statement that make continues processing when -v is given. 1999-06-14 Paul D. Smith * read.c (read_makefile): Cast -1 arguments to variable_expand_string() to long. Alexandre Sauve reports that without casts, this breaks on a NEC SUPER-UX SX-4 system (and it's wrong without a cast anyway). Of course, (a) I'd really love to start using function prototypes, and (b) there's a whole slew of issues related to int vs. long and signed vs. unsigned in the length handling of variable buffers, etc. Gross. Needs a complete mucking-out. * expand.c (variable_expand): Ditto. * acinclude.m4 (AC_FUNC_SELECT): Slight enhancement for AIX 3.2 by Lars Hecking . * read.c (get_next_mword): Allow colons to be escaped in target names: fix for regression failure. 1999-04-26 Paul D. Smith * main.c (main): Reset read_makefiles to empty after processing so we get the right error message. 1999-04-25 Paul D. Smith * make.texinfo: Updates to @dircategory and @direntry suggested by Karl Berry . 1999-04-23 Eli Zaretskii * job.c (start_job_command) [__MSDOS__]: Call unblock_sigs before turning off dos_command_running, so child's signals produce the right effect. * commands.c (fatal_error_signal) [__MSDOS__]: Use EXIT_FAILURE instead of 1. 1999-04-18 Eli Zaretskii * configh.dos.template: Update to recognize that version 2.02 of DJGPP contains sys_siglist stuff. 1999-04-14 Paul D. Smith * make.texinfo (Options/Recursion): Document the job server. (Parallel): Tweaks. 1999-04-13 Paul D. Smith Implement a new "job server" feature; the implementation was suggested by Howard Chu . * configure.in (job-server): New disable option for job server support--it's enabled by default. If it works well this will go away. * NEWS: Summarize the new feature. * acconfig.h: New definition MAKE_JOBSERVER if job server support is enabled. * config.h-vms.template: Undef MAKE_JOBSERVER for this port. * config.h.W32.template: Ditto. * config.ami.template: Ditto. * main.c (struct command_switch): Add a new type: int_string. (switches[]) Use int_string for -j if MAKE_JOBSERVER. (init_switches): Initialize the new int_string switch type. (print_usage): New function, extracted from decode_switches(). (decode_switches): Call it. Decode the new int_string switch type. (define_makeflags): Add new int_string switch data to MAKEFLAGS. (job_fds[]) Array to contain the pipe file descriptors. (main): Parse the job_slots_str option results. If necessary, create the pipe and seed it with tokens. Set the non-blocking bit for the read fd. Enable the signal handler for SIGCHLD even if we have a non-hanging wait; it's needed to interrupt the select() in job.c:start_waiting_job(). * make.h: Declare job_fds[]. * job.h (struct child): Add job_token field to store the token for this job (if any). * job.c (reap_children): When a child is fully reaped, release the token back into the pipe. (free_child): If the child to be freed still has a token, put it back. (new_job): Initialize the job_token member. (start_waiting_job): For local jobs, if we're using the pipe, get a token before we check the load, etc. We do this by performing a non-blocking read in a loop. If the read fails, no token is available. Do a select on the fd to wait for a token. We need to re-enable the signal handler for SIGCHLD even if we have a non-hanging waitpid() or wait3(), so that the signal will interrupt the select() and we can wake up to reap children. (child_handler): Re-enable the signal handler. The count is still kept although it's not needed or used unless you don't have waitpid() or wait3(). 1999-04-10 Paul D. Smith * main.c (main): Reset the considered bit on all the makefiles if something failed to update; we need to examine them again if they appear as normal targets in order to get the proper error message. 1999-04-09 Paul D. Smith Performance enhancement from Tim Magill . * remake.c (update_file): If you have large numbers of dependencies and you run in parallel, make can spend considerable time each pass through the graph looking at branches it has already seen. Since we only reap_children() when starting a pass, not in the middle, if a branch has been seen already in that pass nothing interesting can happen until the next pass. So, we toggle a bit saying whether we've seen this target in this pass or not. (update_goal_chain): Initially set the global considered toggle to 1, since all targets initialize their boolean to 0. At the end of each pass, toggle the global considered variable. * filedef.h (struct file): Per-file considered toggle bit. * file.c: New global toggle variable considered. 1999-04-05 Paul D. Smith * arscan.c (ar_scan): Added support for ARFZMAG (compressed archives?) for Digital UNIX C++. Information provided by Patrick E. Krogel . (ar_member_touch): Ditto. 1999-04-03 Paul D. Smith * remake.c (f_mtime): If: a) we found a file and b) we didn't create it and c) it's not marked as an implicit target and d) it is marked as an intermediate target, then it was so marked due to an .INTERMEDIATE special target, but it already existed in the directory. In this case, unset the intermediate flag so we won't delete it when make is done. It feels like it would be cleaner to put this check in update_file_1() but I worry it'll get missed... 1999-04-01 Paul D. Smith * job.c (construct_command_argv_internal): Use bcopy() to copy overlapping strings, rather than strcpy(). ISO C says the latter is undefined. Found this in a bug report from 1996! Ouch! 1999-03-31 Paul D. Smith * read.c (readline): Ignore carriage returns at the end of the line, to allow Windows-y CRLF line terminators. 1999-03-30 Paul D. Smith * configure.in: Don't put build.sh here, since build.sh.in doesn't exist initially. This cause autoreconf and automake to fail when run on a clean CVS checkout. Instead, we create build.sh in the Makefile (see below). * Makefile.am: Remove BUILT_SOURCES; this is no longer relevant. Put those files directly into EXTRA_DIST so they're distributed. Create a local build rule to create build.sh. Create a local maintainer-clean rule to delete all the funky maintainers files. * maintMakefile: Makefile.in depends on README, since automake fails if it doesn't exist. Also don't remove glob/Makefile.in here, as it causes problems. 1999-03-26 Paul D. Smith * configure.in: Substitute GLOBLIB if we need the link the glob/libglob.a library. * Makefile.am (make_LDADD): Use the subst variable GLOBLIB so we don't link the local libglob.a at all if we don't need it. * build.template: Don't compile glob/*.o unless we want globlib. * maintMakefile (build.sh.in): Substitute the glob/*.o files separately. 1999-03-25 Paul D. Smith * make.texinfo: Various typos and additions, pointed out by James G. Sack . 1999-03-22 Paul D. Smith * make.texinfo (Functions): Add a new section documenting the new $(error ...) and $(warning ...) functions. Also updated copyright dates. * NEWS: Updated for the new functions. * function.c (func_error): Implement the new $(error ...) and $(warning ...) functions. (function_table): Insert new functions into the table. (func_firstword): Don't call find_next_token() with argv[0] itself, since that function modifies the pointer. * function.c: Cleanups and slight changes to the new method of calling functions. 1999-03-20 Han-Wen Nienhuys * function.c: Rewrite to use one C function per make function, instead of a huge switch statement. Also allows some cleanup of multi-architecture issues, and a cleaner API which makes things like func_apply() simple. * function.c (func_apply): Initial implementation. Expand either a builtin function or a make variable in the context of some arguments, provided as $1, $2, ... $N. 1999-03-19 Eli Zaretskii 1999-03-19 Rob Tulloh * job.c (construct_command_argv_internal): Don't treat _all_ backslashes as escapes, only those which really escape a special character. This allows most normal "\" directory separators to be treated normally. 1999-03-05 Paul D. Smith * configure.in: Check for a system strdup(). * misc.c (xstrdup): Created. Suggestion by Han-Wen Nienhuys . * make.h: Prototype xstrdup(). * remake.c (library_search): Use it. * main.c (main): Use it. (find_and_set_default_shell): Use it. * job.c (construct_command_argv_internal): Use it. * dir.c (find_directory): Use it. * Makefile.am, configure.in: Use AC_SUBST_FILE to insert the maintMakefile instead of "include", to avoid automake 1.4 incompatibility. 1999-03-04 Paul D. Smith * amiga.c, amiga.h, ar.c, arscan.c, commands.c, commands.h, * default.c, dep.h, dir.c, expand.c, file.c, filedef.h, function.c, * implicit.c, job.c, job.h, main.c, make.h, misc.c, read.c, remake.c * remote-cstms.c, remote-stub.c, rule.h, variable.c, variable.h, * vpath.c, Makefile.ami, NMakefile.template, build.template, * makefile.vms: Updated FSF address in the copyright notice. * variable.c (try_variable_definition): If we see a conditional variable and we decide to set it, re-type it as recursive so it will be expanded properly later. 1999-02-22 Paul D. Smith * NEWS: Mention new .LIBPATTERNS feature. * make.texinfo (Libraries/Search): Describe the use and ramifications of the new .LIBPATTERNS variable. * remake.c (library_search): Instead of searching only for the hardcoded expansion "libX.a" for a library reference "-lX", we obtain a list of patterns from the .LIBPATTERNS variable and search those in order. * default.c: Added a new default variable .LIBPATTERNS. The default for UNIX is "lib%.so lib%.a". Amiga and DOS values are also provided. * read.c: Remove bogus HAVE_GLOB_H references; always include vanilla glob.h. 1999-02-21 Paul D. Smith * function.c (expand_function): Set value to 0 to avoid freeing it. * variable.c (pop_variable_scope): Free the value of the variable. (try_variable_definition): For simple variables, use allocated_variable_expand() to avoid stomping on the variable buffer when we still need it for other things. * arscan.c: Modified to support AIX 4.3 big archives. The changes are based on information provided by Phil Adams . 1999-02-19 Paul D. Smith * configure.in: Check to see if the GNU glob library is already installed on the system. If so, _don't_ add -I./glob to the compile line. Using the system glob code with the local headers is very bad mojo! Rewrite SCCS macros to use more autoconf facilities. * Makefile.am: Move -Iglob out of INCLUDES; it'll get added to CPPFLAGS by configure now. Automake 1.4 introduced its own "include" feature which conflicts with the maintMakefile stuff. A hack that seems to work is add a space before the include :-/. * build.template: Move -Iglob out of the compile line; it'll get added to CPPFLAGS by configure now. 1999-02-16 Glenn D. Wolf * arscan.c (ar_scan) [VMS]: Initialized VMS_member_date before calling lbr$get_index since if the archive is empty, VMS_get_member_info won't get called at all, and any leftover date will be used. This bug shows up if any member of any archive is made, followed by a dependency check on a different, empty archive. 1998-12-13 Martin Zinser * config.h-vms [VMS]: Set _POSIX_C_SOURCE. Redefine the getopt functions so we don't use the broken VMS versions. * makefile.com [VMS]: Allow debugging. * dir.c (dir_setup_glob) [VMS]: Don't extern stat() on VMS. 1998-11-30 Paul D. Smith * signame.c (init_sig): Check the sizes of signals being set up to avoid array overwrites (if the system headers have problems). 1998-11-17 Paul D. Smith * read.c (record_files): Clean up some indentation. 1998-11-08 Han-Wen Nienhuys * rule.c (print_rule_data_base): Fix arguments to fatal() call. 1998-10-13 Paul D. Smith * job.c (start_job_command): If the command list resolves to no chars at all (e.g.: "foo:;$(empty)") then command_ptr is NULL; quit early. 1998-10-12 Andreas Schwab * rule.c (print_rule_data_base): Ignore num_pattern_rules if it is zero. 1998-10-09 Paul D. Smith * read.c (read_makefile): Allow non-empty lines to expand to the empty string after variable, etc., expansion, and be ignored. 1998-09-21 Paul D. Smith * job.c (construct_command_argv_internal): Only add COMMAND.COM "@echo off" line for non-UNIXy shells. 1998-09-09 Paul D. Smith * w32/subproc/sub_proc.c: Add in missing HAVE_MKS_SHELL tests. 1998-09-04 Paul D. Smith * read.c (read_makefile): If we hit the "missing separator" error, check for the common case of 8 spaces instead of a TAB and give an extra comment to help people out. 1998-08-29 Paul Eggert * configure.in (AC_STRUCT_ST_MTIM_NSEC): Renamed from AC_STRUCT_ST_MTIM. * acinclude.m4 (AC_STRUCT_ST_MTIM_NSEC): Likewise. Port to UnixWare 2.1.2 and pedantic Solaris 2.6. * acconfig.h (ST_MTIM_NSEC): Renamed from HAVE_ST_MTIM, with a new meaning. * filedef.h (FILE_TIMESTAMP_FROM_S_AND_NS): Use new ST_MTIM_NSEC macro. 1998-08-26 Paul D. Smith * remake.c (check_dep): For any intermediate file, not just secondary ones, try implicit and default rules if no explicit rules are given. I'm not sure why this was restricted to secondary rules in the first place. 1998-08-24 Paul D. Smith * make.texinfo (Special Targets): Update documentation for .INTERMEDIATE: if used with no dependencies, then it does nothing; old docs said it marked all targets as intermediate, which it didn't... and which would be silly :). * implicit.c (pattern_search): If we find a dependency in our internal tables, make sure it's not marked intermediate before accepting it as a found_file[]. 1998-08-20 Paul D. Smith * ar.c (ar_glob): Use existing alpha_compare() with qsort. (ar_glob_alphacompare): Remove it. Modify Paul Eggert's patch so we don't abandon older systems: * configure.in: Warn the user if neither waitpid() nor wait3() is available. * job.c (WAIT_NOHANG): Don't syntax error on ancient hosts. (child_handler, dead_children): Define these if WAIT_NOHANG is not available. (reap_children): Only track the dead_children count if no WAIT_NOHANG. Otherwise, it's a boolean. * main.c (main): Add back signal handler if no WAIT_NOHANG is available; only use default signal handler if it is. 1998-08-20 Paul Eggert Install a more robust signal handling mechanism for systems which support it. * job.c (WAIT_NOHANG): Define to a syntax error if our host is truly ancient; this should never happen. (child_handler, dead_children): Remove. (reap_children): Don't try to keep separate track of how many dead children we have, as this is too bug-prone. Just ask the OS instead. (vmsHandleChildTerm): Fix typo in error message; don't mention child_handler. * main.c (main): Make sure we're not ignoring SIGCHLD/SIGCLD; do this early, before we could possibly create a subprocess. Just use the default behavior; don't have our own handler. 1998-08-18 Eli Zaretskii * read.c (read_makefile) [__MSDOS__, WINDOWS32]: Add code to recognize library archive members when dealing with drive spec mess. Discovery and initial fix by George Racz . 1998-08-18 Paul D. Smith * configure.in: Check for stdlib.h explicitly (some hosts have it but don't have STDC_HEADERS). * make.h: Use HAVE_STDLIB_H. Clean up some #defines. * config.ami: Re-compute based on new config.h.in contents. * config.h-vms: Ditto. * config.h.W32: Ditto. * configh.dos: Ditto. * dir.c (find_directory) [WINDOWS32]: Windows stat() fails if directory names end with `\' so strip it. 1998-08-17 Paul D. Smith * make.texinfo: Added copyright year to the printed copy. Removed the price from the manual. Change the top-level reference to running make to be "Invoking make" instead of "make Invocation", to comply with GNU doc standards. * make.h (__format__, __printf__): Added support for these in __attribute__ macro. (message, error, fatal): Use ... prototype form under __STDC__. Add __format__ attributes for printf-style functions. * configure.in (AC_FUNC_VPRINTF): Check for vprintf()/_doprnt(). * misc.c (message, error, fatal): Add preprocessor stuff to enable creation of variable-argument functions with appropriate prototypes, that works with ANSI, pre-ANSI, varargs.h, stdarg.h, v*printf(), _doprnt(), or none of the above. Culled from GNU fileutils and slightly modified. (makefile_error, makefile_error): Removed (merged into error() and fatal(), respectively). * amiga.c: Use them. * ar.c: Use them. * arscan.c: Use them. * commands.c: Use them. * expand.c: Use them. * file.c: Use them. * function.c: Use them. * job.c: Use them. * main.c: Use them. * misc.c: Use them. * read.c: Use them. * remake.c: Use them. * remote-cstms.c: Use them. * rule.c: Use them. * variable.c: Use them. * make.h (struct floc): New structure to store file location information. * commands.h (struct commands): Use it. * variable.c (try_variable_definition): Use it. * commands.c: Use it. * default.c: Use it. * file.c: Use it. * function.c: Use it. * misc.c: Use it. * read.c: Use it. * rule.c: Use it. 1998-08-16 Paul Eggert * filedef.h (FILE_TIMESTAMP_PRINT_LEN_BOUND): Add 10, for nanoseconds. 1998-08-16 Paul Eggert * filedef.h (FLOOR_LOG2_SECONDS_PER_YEAR): New macro. (FILE_TIMESTAMP_PRINT_LEN_BOUND): Tighten bound, and try to make it easier to understand. 1998-08-14 Paul D. Smith * read.c (read_makefile): We've already unquoted any colon chars by the time we're done reading the targets, so arrange for parse_file_seq() on the target list to not do so again. 1998-08-05 Paul D. Smith * configure.in: Added glob/configure.in data. We'll have the glob code include the regular make config.h, rather than creating its own. * getloadavg.c (main): Change return type to int. 1998-08-01 Paul Eggert * job.c (reap_children): Ignore unknown children. 1998-07-31 Paul D. Smith * make.h, filedef.h, dep.h, rule.h, commands.h, remake.c: Add prototypes for functions. Some prototypes needed to be moved in order to get #include order reasonable. 1998-07-30 Paul D. Smith * make.h: Added MIN/MAX. * filedef.h: Use them; remove FILE_TIMESTAMP_MIN. 1998-07-30 Paul Eggert Add support for sub-second timestamp resolution on hosts that support it (just Solaris 2.6, so far). * acconfig.h (HAVE_ST_MTIM, uintmax_t): New undefs. * acinclude.m4 (jm_AC_HEADER_INTTYPES_H, AC_STRUCT_ST_MTIM, jm_AC_TYPE_UINTMAX_T): New defuns. * commands.c (delete_target): Convert file timestamp to seconds before comparing to archive timestamp. Extract mod time from struct stat using FILE_TIMESTAMP_STAT_MODTIME. * configure.in (C_STRUCT_ST_MTIM, jm_AC_TYPE_UINTMAX_T): Add. (AC_CHECK_LIB, AC_CHECK_FUNCS): Add clock_gettime. * file.c (snap_deps): Use FILE_TIMESTAMP, not time_t. (file_timestamp_now, file_timestamp_sprintf): New functions. (print_file): Print file timestamps as FILE_TIMESTAMP, not time_t. * filedef.h: Include if available and if HAVE_ST_MTIM. (FILE_TIMESTAMP, FILE_TIMESTAMP_STAT_MODTIME, FILE_TIMESTAMP_MIN, FILE_TIMESTAMPS_PER_S, FILE_TIMESTAMP_FROM_S_AND_NS, FILE_TIMESTAMP_DIV, FILE_TIMESTAMP_MOD, FILE_TIMESTAMP_S, FILE_TIMESTAMP_NS, FILE_TIMESTAMP_PRINT_LEN_BOUND): New macros. (file_timestamp_now, file_timestamp_sprintf): New decls. (struct file.last_mtime, f_mtime, file_mtime_1, NEW_MTIME): time_t -> FILE_TIMESTAMP. * implicit.c (pattern_search): Likewise. * vpath.c (vpath_search, selective_vpath_search): Likewise. * main.c (main): Likewise. * remake.c (check_dep, name_mtime, library_search, f_mtime): Likewise. (f_mtime): Use file_timestamp_now instead of `time'. Print file timestamp with file_timestamp_sprintf. * vpath.c (selective_vpath_search): Extract file time stamp from struct stat with FILE_TIMESTAMP_STAT_MODTIME. 1998-07-28 Paul D. Smith * Version 3.77 released. * dosbuild.bat: Change to DOS CRLF line terminators. * make-stds.texi: Update from latest version. * make.texinfo (Options Summary): Clarify that the -r option affects only rules, not builtin variables. 1998-07-27 Paul D. Smith * make.h: Make __attribute__ resolve to empty for non-GCC _and_ for GCC pre-2.5.x. * misc.c (log_access): Print UID/GID's as unsigned long int for maximum portability. * job.c (reap_children): Print PIDs as long int for maximum portability. 1998-07-24 Eli Zaretskii * Makefile.DOS (*_INSTALL, *_UNINSTALL): Replace `true' with `:'. 1998-07-25 Paul D. Smith * Version 3.76.94 released. 1998-07-23 Paul D. Smith * config.h.W32.template: Make sure all the #defines of macros here have a value (e.g., use ``#define HAVE_STRING_H 1'' instead of just ``#define HAVE_STRING_H''. Keeps the preprocessor happy in some contexts. * make.h: Remove __attribute__((format...)) stuff; using it with un-prototyped functions causes older GCC's to fail. * Version 3.76.93 released. 1998-07-22 Paul D. Smith * file.c (print_file_data_base): Fix average calculation. 1998-07-20 Paul D. Smith * main.c (die): Postpone the chdir() until after remove_intermediates() so that intermediate targets with relative pathnames are removed properly. 1998-07-17 Paul D. Smith * filedef.h (struct file): New flag: did we print an error or not? * remake.c (no_rule_error): New function to print error messages, extraced from remake_file(). * remake.c (remake_file): Invoke the new error print function. (update_file_1): Invoke the error print function if we see that we already tried this target and it failed, but that an error wasn't printed for it. This can happen if a file is included with -include or sinclude and couldn't be built, then later is also the dependency of another target. Without this change, make just silently stops :-/. 1998-07-16 Paul D. Smith * make.texinfo: Removed "beta" version designator. Updated ISBN for the next printing. 1998-07-13 Paul Eggert * acinclude.m4: New AC_LFS macro to determine if special compiler flags are needed to allow access to large files (e.g., Solaris 2.6). * configure.in: Invoke it. 1998-07-08 Eli Zaretskii * Makefile.DOS: track changes in Makefile.in. 1998-07-07 Paul D. Smith * remote-cstms.c (start_remote_job): Move gethostbyaddr() to the top so host is initialized early enough. * acinclude.m4: New file. Need some special autoconf macros to check for network libraries (-lsocket, -lnsl, etc.) when configuring Customs. * configure.in (make_try_customs): Invoke new network libs macro. 1998-07-06 Paul D. Smith * Version 3.76.92 released. * README.customs: Added to the distribution. * configure.in (make_try_customs): Rewrite to require an installed Customs library, rather than looking at the build directory. * Makefile.am (man_MANS): Install make.1. * make.1: Renamed from make.man. * make.texinfo (Bugs): New mailing list address for GNU make bug reports. 1998-07-02 Paul D. Smith * Version 3.76.91 released. * default.c: Added default rule for new-style RCS master file storage; ``% :: RCS/%''. Added default rules for DOS-style C++ files with suffix ".cpp". They use the new LINK.cpp and COMPILE.cpp macros, which are set by default to be equal to LINK.cc and COMPILE.cc. 1998-06-19 Eli Zaretskii * job.c (start_job_command): Reset execute_by_shell after an empty command was skipped. 1998-06-09 Paul D. Smith * main.c (main): Keep track of the temporary filename created when reading a makefile from stdin (-f-) and attempt to remove it as soon as we know we're not going to re-exec. If we are, add it to the exec'd make's cmd line with "-o" so the exec'd make doesn't try to rebuild it. We still have a hole: if make re-execs then the temporary file will never be removed. To fix this we'd need a brand new option that meant "really delete this". * AUTHORS, getopt.c, getopt1.c, getopt.h, main.c (print_version): Updated mailing addresses. 1998-06-08 Paul D. Smith * main.c (main): Andreas Luik points out that the check for makefile :: rules with commands but no dependencies causing a loop terminates incorrectly. * maintMakefile: Make a template for README.DOS to update version numbers. 1998-05-30 Andreas Schwab * remake.c (update_file_1): Don't free the memory for the dependency structure when dropping a circular dependency. 1998-05-30 Eli Zaretskii * dir.c (file_exists_p, file_impossible_p, file_impossible) [__MSDOS__, WINDOWS32]: Retain trailing slash in "d:/", and make dirname of "d:foo" be "d:". 1998-05-26 Andreas Schwab * read.c (read_makefile): Avoid running past EOS when scanning file name after `include'. 1998-05-26 Andreas Schwab * make.texinfo (Flavors): Correct description of conditional assignment, which is not equivalent to ifndef. (Setting): Likewise. 1998-05-24 Paul D. Smith * arscan.c (ar_name_equal): strncmp() might be implemented as a macro, so don't put preprocessor conditions inside the arguments list. 1998-05-23 Eli Zaretskii * read.c (read_makefile) [__MSDOS__, WINDOWS32]: Skip colons in drive specs when parsing targets, target-specific variables and static pattern rules. A colon can only be part of drive spec if it is after the first letter in a token. 1998-05-22 Eli Zaretskii * remake.c (f_mtime) [__MSDOS__]: Allow up to 3 sec of skew before yelling bloody murder. * dosbuild.bat: Use -DINCLUDEDIR= and -DLIBDIR= where appropriate. * read.c (parse_file_seq): Combine the special file-handling code for WINDOWS32 and __MSDOS__ into a single snippet. (get_next_mword) [__MSDOS__, WINDOWS32]: Allow a word to include a colon as part of a drive spec. * job.c (batch_mode_shell) [__MSDOS__]: Declare. 1998-05-20 Paul D. Smith * Version 3.76.90 released. 1998-05-19 Paul D. Smith * make.texinfo (Make Errors): Added a new appendix describing common errors make might generate and how to resolve them (or at least more information on what they mean). * maintMakefile (NMAKEFILES): Use the new automake 1.3 feature to create a dependency file to construct Makefile.DOS, SMakefile, and NMakefile. (.dep_segment): Generate the dependency fragment file. 1998-05-14 Paul D. Smith * make.man: Minor changes. 1998-05-13 Paul D. Smith * function.c (pattern_matches,expand_function): Change variables and types named "word" to something else, to avoid compilation problems on Cray C90 Unicos. * variable.h: Modify the function prototype. 1998-05-11 Rob Tulloh * job.c (construct_command_argv_internal) [WINDOWS32]: Turn off echo when using a batch file, and make sure the command ends in a newline. 1998-05-03 Paul D. Smith * configure.in (make_try_customs): Add some customs flags if the user configures custom support. * job.c, remote-cstms.c: Merge in changes for custom library. * remote-stub.c: Add option to stub start_remote_job_p(). 1998-05-01 Paul D. Smith * remake.c (f_mtime): Install VPATH+ handling for archives; use the hname field instead of the name field, and rehash when appropriate. 1998-04-30 Paul D. Smith * rule.c (print_rule_data_base): Print out any pattern-specific variable values into the rules database. * variable.c (print_variable_set): Make this variable extern, to be called by print_rule_data_base() for pattern-specific variables. * make.texinfo (Pattern-specific): Document pattern-specific variables. 1998-04-29 Paul D. Smith * expand.c (variable_expand_for_file): Make static; its only called internally. Look up this target in the list of pattern-specific variables and insert the variable set into the queue to be searched. * filedef.h (struct file): Add a new field to hold the previously-found pattern-specific variable reference. Add a new flag to remember whether we already searched for this file. * rule.h (struct pattern_var): New structure for storing pattern-specific variable values. Define new function prototypes. * rule.c: New variables pattern_vars and last_pattern_var for storage and handling of pattern-specific variable values. (create_pattern_var): Create a new pattern-specific variable value structure. (lookup_pattern_var): Try to match a target to one of the pattern-specific variable values. 1998-04-22 Paul D. Smith * make.texinfo (Target-specific): Document target-specific variables. 1998-04-21 Paul D. Smith * variable.c (define_variable_in_set): Made globally visible. (lookup_variable_in_set): New function: like lookup_variable but look only in a specific variable set. (target_environment): Use lookup_variable_in_set() to get the correct export rules for a target-specific variable. (create_new_variable_set): Create a new variable set, and just return it without installing it anywhere. (push_new_variable_scope): Reimplement in terms of create_new_variable_set. * read.c (record_target_var): Like record_files, but instead of files create a target-specific variable value for each of the listed targets. Invoked from read_makefile() when the target line turns out to be a target-specific variable assignment. 1998-04-19 Paul D. Smith * read.c (read_makefile): Rewrite the entire target parsing section to implement target-specific variables. In particular, we cannot expand the entire line as soon as it's read in, since we may want to evaluate parts of it with different variable contexts active. Instead, start expanding from the beginning until we find the `:' (or `::'), then determine what kind of line this is and continue appropriately. * read.c (get_next_mword): New function to parse a makefile line by "words", considering an entire variable or function as one word. Return the type read in, along with its starting position and length. (enum make_word_type): The types of words that are recognized by get_next_mword(). * variable.h (struct variable): Add a flag to specify a per-target variable. * expand.c: Make variable_buffer global. We need this during the new parsing of the makefile. (variable_expand_string): New function. Like variable_expand(), but start at a specific point in the buffer, not the beginning. (variable_expand): Rewrite to simply call variable_expand_string(). 1998-04-13 Paul D. Smith * remake.c (update_goal_chain): Allow the rebuilding makefiles step to use parallel jobs. Not sure why this was disabled: hopefully we won't find out :-/. 1998-04-11 Paul D. Smith * main.c (main): Set the CURDIR makefile variable. * make.texinfo (Recursion): Document it. 1998-03-17 Paul D. Smith * misc.c (makefile_fatal): If FILE is nil, invoke plain fatal(). * variable.c (try_variable_definition): Use new feature. 1998-03-10 Paul D. Smith * main.c (main): Don't pass included, rebuilt makefiles to re-exec'd makes with -o. Reopens a possible loop, but it caused too many problems. 1998-03-02 Paul D. Smith * variable.c (try_variable_definition): Implement ?=. * make.texinfo (Setting): Document it. 1998-02-28 Eli Zaretskii * job.c (start_job_command): Reset execute_by_shell after an empty command, like ":", has been seen. Tue Oct 07 15:00:00 1997 Phil Brooks * make.h [WINDOWS32]: make case sensitivity configurable * dir.c [WINDOWS32]: make case sensitivity configurable * README.W32: Document case sensitivity * config.ami: Share case warping code with Windows Mon Oct 6 18:48:45 CDT 1997 Rob Tulloh * w32/subproc/sub_proc.c: Added support for MKS toolkit shell (turn on HAVE_MKS_SHELL). * read.c [WINDOWS32]: Fixed a problem with multiple target rules reported by Gilbert Catipon (gcatipon@tibco.com). If multiple path tokens in a rule did not have drive letters, make would incorrectly concatenate the 2 tokens together. * main.c/variable.c [WINDOWS32]: changed SHELL detection code to follow what MSDOS did. In addition to watching for SHELL variable updates, make's main will attempt to default the value of SHELL before and after makefiles are parsed. * job.c/job.h [WINDOWS32]: The latest changes made to enable use of the GNUWIN32 shell from make could cause make to fail due to a concurrency condition between parent and child processes. Make now creates a batch file per job instead of trying to reuse the same singleton batch file. * job.c/job.h/function.c/config.h.W32 [WINDOWS32]: Renamed macro from HAVE_CYGNUS_GNUWIN32_TOOLS to BATCH_MODE_ONLY_SHELL. Reworked logic to reduce complexity. WINDOWS32 now uses the unixy_shell variable to detect Bourne-shell compatible environments. There is also a batch_mode_shell variable that determines whether not command lines should be executed via script files. A WINDOWS32 system with no sh.exe installed would have unixy_shell set to FALSE and batch_mode_shell set to TRUE. If you have a unixy shell that does not behave well when invoking things via 'sh -c xxx', you may want to turn on BATCH_MODE_ONLY_SHELL and see if things improve. * NMakefile: Added /D DEBUG to debug build flags so that unhandled exceptions could be debugged. Mon Oct 6 00:04:25 1997 Rob Tulloh * main.c [WINDOWS32]: The function define_variable() does not handle NULL. Test before calling it to set Path. * main.c [WINDOWS32]: Search Path again after makefiles have been parsed to detect sh.exe. * job.c [WINDOWS32]: Added support for Cygnus GNU WIN32 tools. To use, turn on HAVE_CYGNUS_GNUWIN32_TOOLS in config.h.W32. * config.h.W32: Added HAVE_CYGNUS_GNUWIN32_TOOLS macro. Sun Oct 5 22:43:59 1997 John W. Eaton * glob/glob.c (glob_in_dir) [VMS]: Globbing shouldn't be case-sensitive. * job.c (child_execute_job) [VMS]: Use a VMS .com file if the command contains a newline (e.g. from a define/enddef block). * vmsify.c (vmsify): Return relative pathnames wherever possible. * vmsify.c (vmsify): An input string like "../.." returns "[--]". Wed Oct 1 15:45:09 1997 Rob Tulloh * NMakefile: Changed nmake to $(MAKE). * subproc.bat: Take the make command name from the command line. If no command name was given, default to nmake. * job.c [MSDOS, WINDOWS32]: Fix memory stomp: temporary file names are now always created in heap memory. * w32/subproc/sub_proc.c: New implementation of make_command_line() which is more compatible with different Bourne shell implementations. Deleted the now obsolete fix_command_line() function. * main.c [WINDOWS32]: Any arbitrary spelling of Path can be detected. Make will ensure that the special spelling `Path' is inserted into the environment when the path variable is propagated within itself and to make's children. * main.c [WINDOWS32]: Detection of sh.exe was occurring too soon. The 2nd check for the existence of sh.exe must come after the call to read_all_makefiles(). Fri Sep 26 01:14:18 1997 * makefile.com [VMS]: Fixed definition of sys. * readme.vms: Comments on what's changed lately. Fri Sep 26 01:14:18 1997 John W. Eaton * read.c (read_all_makefiles): Allow make to find files named "MAKEFILE" with no extension on VMS. * file.c (lookup_file): Lowercase filenames on VMS. 1997-09-29 Paul D. Smith * read.c (read_makefile): Reworked target detection again; the old version had an obscure quirk. Fri Sep 19 09:20:49 1997 Paul D. Smith * Version 3.76.1 released. * Makefile.am: Add loadavg files to clean rules. * configure.in (AC_OUTPUT): Remove stamp-config; no longer needed. * Makefile.ami (distclean): Ditto. * SMakefile (distclean): Ditto. * main.c (main): Arg count should be int, not char! Major braino. Tue Sep 16 10:18:22 1997 Paul D. Smith * Version 3.76 released. Tue Sep 2 10:07:39 1997 Paul D. Smith * function.c (expand_function): When processing $(shell...) translate a CRLF (\r\n) sequence as well as a newline (\n) to a space. Also remove an ending \r\n sequence. * make.texinfo (Shell Function): Document it. Fri Aug 29 12:59:06 1997 Rob Tulloh * w32/pathstuff.c (convert_Path_to_windows32): Fix problem where paths which contain single character entries like `.' are not handled correctly. * README.W32: Document path handling issues on Windows systems. Fri Aug 29 02:01:27 1997 Paul D. Smith * Version 3.75.93. Thu Aug 28 19:39:06 1997 Rob Tulloh * job.c (exec_command) [WINDOWS32]: If exec_command() is invoked from main() to re-exec make, the call to execvp() would incorrectly return control to parent shell before the exec'ed command could run to completion. I believe this is a feature of the way that execvp() is implemented on top of WINDOWS32 APIs. To alleviate the problem, use the supplied process launch function in the sub_proc library and suspend the parent process until the child process has run. When the child exits, exit the parent make with the exit code of the child make. Thu Aug 28 17:04:47 1997 Paul D. Smith * Makefile.DOS.template (distdir): Fix a line that got wrapped in email. * Makefile.am (loadavg): Give the necessary cmdline options when linking loadavg. * configure.in: Check for pstat_getdynamic for getloadvg on HP. * job.c (start_job_command) [VMS, _AMIGA]: Don't perform empty command optimization on these systems; it doesn't make sense. Wed Aug 27 17:09:32 1997 Paul D. Smith * Version 3.75.92 Tue Aug 26 11:59:15 1997 Paul D. Smith * main.c (print_version): Add '97 to copyright years. * read.c (do_define): Check the length of the array before looking at a particular offset. * job.c (construct_command_argv_internal): Examine the last byte of the previous arg, not the byte after that. Sat Aug 23 1997 Eli Zaretskii * Makefile.DOS.template: New file (converted to Makefile.DOS in the distribution). * configure.bat: Rewrite to use Makefile.DOS instead of editing Makefile.in. Add support for building from outside of the source directory. Fail if the environment block is too small. * configh.dos: Use . * README.DOS: Update instructions. Fri Aug 22 1997 Eli Zaretskii * job.c (start_job_command) [__MSDOS__]: Don't test for "/bin/sh" literally, use value of unixy_shell instead. * filedef.h (NEW_MTIME): Use 1 less than maximum possible value if time_t is unsigned. Sat Aug 16 00:56:15 1997 John W. Eaton * vmsify.c (vmsify, case 11): After translating `..' elements, set nstate to N_OPEN if there are still more elements to process. (vmsify, case 2): After translating `foo/bar' up to the slash, set nstate to N_OPEN, not N_DOT. Fri Aug 8 15:18:09 1997 John W. Eaton * dir.c (vmsstat_dir): Leave name unmodified on exit. * make.h (PATH_SEPARATOR_CHAR): Set to comma for VMS. * vpath.c: Fix comments to refer to path separator, not colon. (selective_vpath_search): Avoid Unixy slash handling for VMS. Thu Aug 7 22:24:03 1997 John W. Eaton * ar.c [VMS]: Don't declare ar_member_touch. Delete VMS version of ar_member_date. Enable non-VMS versions of ar_member_date and ar_member_date_1 for VMS too. * arscan.c (VMS_get_member_info): New function. (ar_scan): Provide version for VMS systems. (ar_name_equal): Simply compare name and mem on VMS systems. Don't define ar_member_pos or ar_member_touch on VMS systems. * config.h-vms (pid_t, uid_t): Don't define. * remake.c: Delete declaration of vms_stat. (name_mtime): Don't call vms_stat. (f_mtime) [VMS]: Funky time value manipulation no longer necessary. * file.c (print_file): [VMS] Use ctime, not cvt_time. * make.h [VMS]: Don't define POSIX. * makefile.com (filelist): Include ar and arscan. Also include them in the link commands. Don't define NO_ARCHIVES in cc command. * makefile.vms (ARCHIVES, ARCHIVES_SRC): Uncomment. (defines): Delete NO_ARCHIVES from list. * remake.c (f_mtime): Only check to see if intermediate file is out of date if it also exists (i.e., mtime != (time_t) -1). * vmsdir.h (u_long, u_short): Skip typedefs if using DEC C. Fri Jun 20 23:02:07 1997 Rob Tulloh * w32/subproc/sub_proc.c: Get W32 sub_proc to handle shebang (#!/bin/sh) in script files correctly. Fixed a couple of memory leaks. Fixed search order in find_file() (w32/subproc/sub_proc.c) so that files with extensions are preferred over files without extensions. Added search for files with .cmd extension too. * w32/subproc/misc.c (arr2envblk): Fixed memory leak. Mon Aug 18 09:41:08 1997 Paul D. Smith * Version 3.75.91 Fri Aug 15 13:50:54 1997 Paul D. Smith * read.c (do_define): Remember to count the newline after the endef. Thu Aug 14 23:14:37 1997 Paul D. Smith * many: Rewrote builds to use Automake 1.2. * AUTHORS: New file. * maintMakefile: Contains maintainer-only make snippets. * GNUmakefile: This now only runs the initial auto* tools. * COPYING,texinfo.tex,mkinstalldirs,install-sh: Removed (obtained automatically by automake). * compatMakefile: Removed (not needed anymore). * README,build.sh.in: Removed (built from templates). * config.h.in,Makefile.in: Removed (built by tools). Wed Aug 13 02:22:08 1997 Paul D. Smith * make.texinfo: Updates for DOS/Windows information (Eli Zaretskii) * README,README.DOS: Ditto. * remake.c (update_file_1,f_mtime): Fix GPATH handling. * vpath.c (gpath_search): Ditto. * file.c (rename_file): New function: rehash, but also rename to the hashname. * filedef.h: Declare it. * variable.c (merge_variable_set_lists): Remove free() of variable set; since various files can share variable sets we don't want to free them here. Tue Aug 12 10:51:54 1997 Paul D. Smith * configure.in: Require autoconf 2.12 * make.texinfo: Replace all "cd subdir; $(MAKE)" examples with a more stylistically correct "cd subdir && $(MAKE)". * main.c: Global variable `clock_skew_detected' defined. (main): Print final warning if it's set. * make.h: Declare it. * remake.c (f_mtime): Test and set it. * job.c (start_job_command): Add special optimizations for "do-nothing" rules, containing just the shell no-op ":". This is useful for timestamp files and can make a real difference if you have a lot of them (requested by Fergus Henderson ). * configure.in,Makefile.in: Rewrote to use the new autoconf program_transform_name macro. * function.c (function_strip): Strip newlines as well as spaces and TABs. Fri Jun 6 23:41:04 1997 Rob Tulloh * remake.c (f_mtime): Datestamps on FAT-based files are rounded to even seconds when stored, so if the date check fails on WINDOWS32 systems, see if this "off-by-one" error is the problem. * General: If your TZ environment variable is not set correctly then all your timestamps will be off by hours. So, set it! Mon Apr 7 02:06:22 1997 Paul D. Smith * Version 3.75.1 * compatMakefile (objs): Define & use the $(GLOB) variable so that it's removed correctly from build.sh.in when it's built. * configure.in: On Solaris we can use the kstat_*() functions to get load averages without needing special permissions. Add a check for -lkstat to see if we have it. * getloadavg.c (getloadavg): Use HAVE_LIBKSTAT instead of SUN5 as the test to enable kstat_open(), etc. processing. Fri Apr 4 20:21:18 1997 Eli Zaretskii * : Fixes to work in the DJGPP DOS environment. Mon Mar 31 02:42:52 1997 Paul D. Smith * function.c (expand_function): Added new function $(wordlist). * make.texinfo (Filename Functions): Document $(wordlist) function. * vpath.c (build_vpath_lists): Construct the GPATH variable information in the same manner we used to construct VPATH. (gpath_search): New function to search GPATH. * make.h: Declare the new function. * remake.c (update_file_1): Call it, and keep VPATH if it's found. * make.texinfo (Search Algorithm): Document GPATH variable. Sun Mar 30 20:57:16 1997 Paul D. Smith * main.c (handle_non_switch_argument): Defined the MAKECMDGOALS variable to contain the user options passed in on the cmd line. * make.texinfo (Goals): Document MAKECMDGOALS variable. * remake.c (f_mtime): Print a warning if we detect a clock skew error, rather than failing. * main.c (main): If we rebuild any makefiles and need to re-exec, add "-o" options for each makefile rebuilt to avoid infinite looping. Fri Mar 28 15:26:05 1997 Paul D. Smith * job.c (construct_command_argv_internal): Track whether the last arg in the cmd string was empty or not (Roland). (construct_command_argv_internal): If the shell line is empty, don't do anything (Roland). * glob/glob.h,glob/glob.c,glob/fnmatch.c,glob/fnmatch.h: Install the latest changes from the GLIBC version of glob (Ulrich Drepper). * getloadavg.c,make-stds.texi: New version (Roland). * (ALL): Changed WIN32 to W32 or WINDOWS32 (RMS). Mon Mar 24 15:33:34 1997 Rob Tulloh * README.W32: Describe preliminary FAT support. * build_w32.bat: Use a variable for the final exe name. * dir.c (find_directory): W32: Find the filesystem type. (dir_contents_file_exists_p): W32: for FAT filesystems, always rehash since FAT doesn't change directory mtime on change. * main.c (handle_runtime_exceptions): W32: Add an UnhandledExceptionFilter so that when make bombs due to ^C or a bug, it won't cause a GUI requestor to pop up unless debug is turned on. (main): Call it. Mon Mar 24 00:57:34 1997 Paul D. Smith * configure.in, config.h.in, config.ami, config.h-vms, config.h.w32: Check for memmove() function. * make.h (bcopy): If memmove() available, define bcopy() to use it. Otherwise just use bcopy(). Don't use memcpy(); it's not guaranteed to handle overlapping moves. * read.c (read_makefile): Fix some uninitialized memory reads (reported by Purify). * job.c (construct_command_argv_internal): Use bcopy() not strcpy(); strcpy() isn't guaranteed to handle overlapping moves. * Makefile.in: Change install-info option ``--infodir'' to ``--info-dir'' for use with new texinfo. * function.c (expand_function): $(basename) and $(suffix) should only search for suffixes as far back as the last directory (e.g., only the final filename in the path). Sun Mar 23 00:13:05 1997 Paul D. Smith * make.texinfo: Add @dircategory/@direntry information. (Top): Remove previous reference to (dir) (from RMS). (Static Usage): Add "all:" rule to example. (Automatic Dependencies): fix .d file creation example. * Install VPATH+ patch: * filedef.h (struct file): Add in hname field to store the hashed filename, and a flag to remember if we're using the vpath filename or not. Renamed a few functions for more clarity. * file.c (lookup_file,enter_file,file_hash_enter): Store filenames in the hash table based on their "hash name". We can change this while keeping the original target in "name". (rehash_file): Renamed from "rename_file" to be more accurate. Changes the hash name, but not the target name. * remake.c (update_file_1): Modify -d output for more detailed VPATH info. If we don't need to rebuild, use the VPATH name. (f_mtime): Don't search for vpath if we're ignoring it. Call renamed function rehash_file. Call name_mtime instead of file_mtime, to avoid infinite recursion since the file wasn't actually renamed. * implicit.c (pattern_search): if we find an implicit file in VPATH, save the original name not the VPATH name. * make.texinfo (Directory Search): Add a section on the new VPATH functionality. Sun Dec 1 18:36:04 1996 Andreas Schwab * dir.c (file_exists_p, file_impossible, file_impossible_p): If dirname is empty replace it by the name of the root directory. Note that this doesn't work (yet) for W32, Amiga, or VMS. Tue Oct 08 13:57:03 1996 Rob Tulloh * main.c (main): W32 bug fix for PATH vars. Tue Sep 17 1996 Paul Eggert * filedef.h (NEW_MTIME): Don't assume that time_t is a signed 32-bit quantity. * make.h: (CHAR_BIT, INTEGER_TYPE_SIGNED, INTEGER_TYPE_MAXIMUM, INTEGER_TYPE_MINIMUM): New macros. Tue Aug 27 01:06:34 1996 Roland McGrath * Version 3.75 released. * main.c (print_version): Print out bug-reporting address. Mon Aug 26 19:55:47 1996 Roland McGrath * main.c (print_data_base): Don't declare ctime; headers do it for us already. Sun Jul 28 15:37:09 1996 Rob Tulloh (tulloh@tivoli.com) * w32/pathstuff.c: Turned convert_vpath_to_w32() into a real function. This was done so that VPATH could contain white space separated pathnames. Please note that directory paths (in VPATH/vpath context) containing white space are not supported (just as they are not under Unix). See README.W32 for suggestions. * w32/include/pathstuff.h: Added prototype for the new function convert_vpath_to_w32. Deleted macro for same. * README.W32: Added some notes about why I chose not to try and support pathnames which contain white space and some workaround suggestions. Thu Jul 25 19:53:31 1996 Roland McGrath * GNUmakefile (mkdep-nolib): Use -MM option unconditionally. * Version 3.74.7. * main.c (define_makeflags): Back up P to point at null terminator when killing final space and dash before setting MFLAGS. From Robert Hoehne : * dir.c [__MSDOS__ && DJGPP > 1]: Include and defin `__opendir_flags' initialized to 0. (dosify) [__MSDOS__ && DJGPP > 1]: Return name unchanged if _USE_LFN. (find_directory) [__MSDOS__ && DJGPP > 1]: If _USE_LGN, set __opendir_flags to __OPENDIR_PRESERVE_CASE. * vmsfunctions.c (vms_stat): `sys$dassgn (DevChan);' added by kkaempf. * GNUmakefile (w32files): Add NMakefile. * NMakefile (LDFLAGS_debug): Value fixed by tulloh. Sat Jul 20 12:32:10 1996 Klaus Kämpf (kkaempf@progis.de) * remake.c (f_mtime) [VMS]: Add missing `if' conditional for future modtime check. * config.h-vms, makefile.vms, readme.vms, vmsify.c: Update address. Sat Jul 20 05:29:43 1996 Roland McGrath * configure.in: Require autoconf 2.10 or later. Fri Jul 19 16:57:27 1996 Roland McGrath * Version 3.74.6. * GNUmakefile (w32files): New variable. (distfiles): Add it. * w32: Updated by Rob Tulloh. * makefile.vms (LOADLIBES): Fix typo. Sun Jul 14 12:59:27 1996 Roland McGrath * job.c (construct_command_argv_internal): Fix up #else, #endifs. * configh.dos: Define HAVE_DIRENT_H instead of DIRENT. * remake.c (f_mtime): Don't compare MTIME to NOW if MTIME == -1. * Version 3.74.5. * main.c (main): Exit with status 2 when update_goal_chain returns 2. Sat Jun 22 14:56:05 1996 Roland McGrath * configure.in: Don't check for _sys_siglist. * make.h [HAVE__SYS_SIGLIST]: Don't test this; just punt if there is no strsignal or sys_siglist. * read.c (conditional_line): Strip ws in `ifeq (a , b)' so it is the same as `ifeq (a, b)'. * job.c (reap_children): Don't call die if handling_fatal_signal. * file.c (file_hash_enter): Allow renaming :: to : when latter is non-target, or : to :: when former is non-target. * job.c (start_job_command): Call block_sigs. (block_sigs): New function, broken out of start_job_command. (reap_children): Block fatal signals around removing dead child from chain and adjusting job_slots_used. * job.h: Declare block_sigs. * remote-stub.c (remote_setup, remote_cleanup): New (empty) functions. * main.c (main): Call remote_setup. (die): Call remote_cleanup. * job.c (reap_children): Quiescent value of shell_function_pid is zero, not -1. * main.c (print_version): Add 96 to copyright years. Sat Jun 15 20:30:01 1996 Andreas Schwab * read.c (find_char_unquote): Avoid calling strlen on every call just to throw away the value most of the time. Sun Jun 2 12:24:01 1996 Roland McGrath * main.c (decode_env_switches): Prepend '-' to ARGV[1] if it contains no '=', regardless of ARGC. (define_makeflags): Elide leading '-' from MAKEFLAGS value if first word is short option, regardless of WORDS. Wed May 22 17:24:51 1996 Roland McGrath * makefile.vms: Set LOADLIBES. * makefile.com (link_using_library): Fix typo. Wed May 15 17:37:26 1996 Roland McGrath * dir.c (print_dir_data_base): Use %ld dev and ino and cast them to long. Wed May 15 10:14:14 CDT 1996 Rob Tulloh * dir.c: W32 does not support inode. For now, fully qualified pathname along with st_mtime will be keys for files. Fixed problem where vpath can be confused when files are added to a directory after the directory has already been read in. The code now attempts to reread the directory if it discovers that the datestamp on the directory has changed since it was cached by make. This problem only seems to occur on W32 right now so it is lumped under port #ifdef WINDOWS32. * function.c: W32: call subproc library (CreateProcess()) instead of fork/exec. * job.c: W32: Added the code to do fork/exec/waitpid style processing on W32 systems via calls to subproc library. * main.c: W32: Several things added here. First, there is code for dealing with PATH and SHELL defaults. Make tries to figure out if the user has %PATH% set in the environment and sets it to %Path% if it is not set already. Make also looks to see if sh.exe is anywhere to be found. Code path through job.c will change based on existence of a working Bourne shell. The checking for default shell is done twice: once before makefiles are read in and again after. Fall back to MSDOS style execution mode if no sh.exe is found. Also added some debug support that allows user to pause make with -D switch and attach a debugger. This is especially useful for debugging recursive calls to make where problems appear only in the sub-make. * make.h: W32: A few macros and header files for W32 support. * misc.c: W32: Added a function end_of_token_w32() to assist in parsing code in read.c. * read.c: W32: Fixes similar to MSDOS which allow colon to appear in filenames. Use of colon in filenames would otherwise confuse make. * remake.c: W32: Added include of io.h to eliminate compiler warnings. Added some code to default LIBDIR if it is not set on W32. * variable.c: W32: Added support for detecting Path/PATH and converting them to semicolon separated lists for make's internal use. New function sync_Path_environment() which is called in job.c and function.c before creating a new process. Caller must set Path in environment since we don't have fork() to do this for us. * vpath.c: W32: Added detection for filenames containing forward or backward slashes. * NMakefile: W32: Visual C compatible makefile for use with nmake. Use this to build GNU make the first time on Windows NT or Windows 95. * README.W32: W32: Contains some helpful notes. * build_w32.bat: W32: If you don't like nmake, use this the first time you build GNU make on Windows NT or Windows 95. * config.h.W32: W32 version of config.h * subproc.bat: W32: A bat file used to build the subproc library from the top-level NMakefile. Needed because WIndows 95 (nmake) doesn't allow you to cd in a make rule. * w32/include/dirent.h * w32/compat/dirent.c: W32: opendir, readdir, closedir, etc. * w32/include/pathstuff.h: W32: used by files needed functions defined in pathstuff.c (prototypes). * w32/include/sub_proc.h: W32: prototypes for subproc.lib functions. * w32/include/w32err.h: W32: prototypes for w32err.c. * w32/pathstuff.c: W32: File and Path/Path conversion functions. * w32/subproc/build.bat: W32: build script for subproc library if you don't wish to use nmake. * w32/subproc/NMakefile: W32: Visual C compatible makefile for use with nmake. Used to build subproc library. * w32/subproc/misc.c: W32: subproc library support code * w32/subproc/proc.h: W32: subproc library support code * w32/subproc/sub_proc.c: W32: subproc library source code * w32/subproc/w32err.c: W32: subproc library support code Mon May 13 14:37:42 1996 Roland McGrath * Version 3.74.4. * GNUmakefile (vmsfiles): Fix typo. * GNUmakefile (amigafiles): Add amiga.h. Sun May 12 19:19:43 1996 Aaron Digulla * dir.c: New function: amigafy() to fold filenames Changes HASH() to HASHI() to fold filenames on Amiga. Stringcompares use strieq() instead of streq() The current directory on Amiga is "" instead of "." * file.c: Likewise. * amiga.c: New function wildcard_expansion(). Allows to use Amiga wildcards with $(wildcard ) * amiga.h: New file. Prototypes for amiga.c * function.c: Use special function wildcard_expansion() for $(wildcard ) to allow Amiga wildcards The current directory on Amiga is "" instead of "." * job.c: No Pipes on Amiga, too (load_too_high) Neither on Amiga ENV variable on Amiga are in a special directory and are not passed as third argument to main(). * job.h: No envp on Amiga * make.h: Added HASHI(). This is the same as HASH() but converts it's second parameter to lowercase on Amiga to fold filenames. * main.c: (main), variable.c Changed handling of ENV-vars. Make stores now the names of the variables only and reads their contents when they are accessed to reflect that these variables are really global (i.e., they CAN change WHILE make runs !) This handling is made in lookup_variable() * Makefile.ami: renamed file.h to filedep.h Updated dependencies * read.c: "find_semicolon" is declared as static but never defined. No difference between Makefile and makefile on Amiga; added SMakefile to *default_makefiles[]. (read_makefile) SAS/C want's two_colon and pattern_percent be set before use. The current directory on Amiga is "" instead of "." Strange #endif moved. * README.Amiga: updated feature list * SMakefile: Updated dependencies * variable.c: Handling of ENV variable happens inside lookup_variable() Sat May 11 17:58:32 1996 Roland McGrath * variable.c (try_variable_definition): Count parens in lhs variable refs to avoid seeing =/:=/+= inside a ref. Thu May 9 13:54:49 1996 Roland McGrath * commands.c (fatal_error_signal) [SIGQUIT]: Make SIGQUIT check conditional. * main.c (main): Use unsigned for fread return. * read.c (parse_file_seq): Use `int' for char arg to avoid widening conflict issues. * dep.h: Fix prototype. * function.c (expand_function) [_AMIGA]: Fix some typos. (patsubst_expand): Make len vars unsigned. * GNUmakefile (globfiles): Add AmigaDOS support files. (distfiles): Add $(amigafiles). (amigafiles): New variable. Thu Nov 7 10:18:16 1995 Aaron Digulla * Added Amiga support in commands.c, dir.c, function.c, job.c, main.c, make.h, read.c, remake.c * commands.c: Amiga has neither SIGHUP nor SIGQUIT * dir.c: Amiga has filenames with Upper- and Lowercase, but "FileName" is the same as "filename". Added strieq() which is use to compare filenames. This is like streq() on all other systems. Also there is no such thing as "." under AmigaDOS. * function.c: On Amiga, the environment is not passed as envp, there are no pipes and Amiga can't fork. Use my own function to create a new child. * job.c: default_shell is "" (The system automatically chooses a shell for me). Have to use the same workaround as MSDOS for running batch commands. Added HAVE_SYS_PARAM_H. NOFILE isn't known on Amiga. Cloned code to run children from MSDOS. Own version of sh_chars[] and sh_cmds[]. No dup2() or dup() on Amiga. * main.c: Force stack to 20000 bytes. Read environment from ENV: device. On Amiga, exec_command() does return, so I exit() afterwards. * make.h: Added strieq() to compare filenames. * read.c: Amiga needs special extension to have passwd. Only one include-dir. "Makefile" and "makefile" are the same. Added "SMakefile". Added special code to handle device names (xxx:) and "./" in rules. * remake.c: Only one lib-dir. Amiga link-libs are named "%s.lib" instead of "lib%s.a". * main.c, rule.c, variable.c: Avoid floats at all costs. * vpath.c: Get rid of as many alloca()s as possible. Thu May 9 13:20:43 1996 Roland McGrath * read.c (read_makefile): Grok `sinclude' as alias for `-include'. Wed Mar 20 09:52:27 1996 Roland McGrath * GNUmakefile (vmsfiles): New variable. (distfiles): Include $(vmsfiles). Tue Mar 19 20:21:34 1996 Roland McGrath Merged VMS port from Klaus Kaempf . * make.h (PARAMS): New macro. * config.h-vms: New file. * makefile.com: New file. * makefile.vms: New file. * readme.vms: New file. * vmsdir.h: New file. * vmsfunctions.c: New file. * vmsify.c: New file. * file.h: Renamed to filedef.h to avoid conflict with VMS system hdr. * ar.c: Added prototypes and changes for VMS. * commands.c: Likewise. * commands.h: Likewise. * default.c: Likewise. * dep.h: Likewise. * dir.c: Likewise. * expand.c: Likewise. * file.c: Likewise. * function.c: Likewise. * implicit.c: Likewise. * job.c: Likewise. * job.h: Likewise. * main.c: Likewise. * make.h: Likewise. * misc.c: Likewise. * read.c: Likewise. * remake.c: Likewise. * remote-stub.c: Likewise. * rule.c: Likewise. * rule.h: Likewise. * variable.c: Likewise. * variable.h: Likewise. * vpath.c: Likewise. * compatMakefile (srcs): Rename file.h to filedef.h. Sat Aug 19 23:11:00 1995 Richard Stallman * remake.c (check_dep): For a secondary file, try implicit and default rules if appropriate. Wed Aug 2 04:29:42 1995 Richard Stallman * remake.c (check_dep): If an intermediate file exists, do consider its actual date. Sun Jul 30 00:49:53 1995 Richard Stallman * file.h (struct file): New field `secondary'. * file.c (snap_deps): Check for .INTERMEDIATE and .SECONDARY. (remove_intermediates): Don't delete .SECONDARY files. Sat Mar 2 16:26:52 1996 Roland McGrath * compatMakefile (srcs): Add getopt.h; prepend $(srcdir)/ to getopt*. Fri Mar 1 12:04:47 1996 Roland McGrath * Version 3.74.3. * remake.c (f_mtime): Move future modtime check before FILE is clobbered by :: loop. * dir.c: Use canonical code from autoconf manual for dirent include. [_D_NAMLEN]: Redefine NAMLEN using this. (dir_contents_file_exists_p): Use NAMLEN macro. (read_dirstream) [_DIRENT_HAVE_D_NAMLEN]: Only set d_namlen #if this. * compatMakefile (objs): Add missing backslash. Wed Feb 28 03:56:20 1996 Roland McGrath * default.c (default_terminal_rules): Remove + prefix from RCS cmds. (default_variables): Put + prefix in $(CHECKOUT,v) value instead. * remake.c (f_mtime): Check for future timestamps; give error and mark file as "failed to update". Fri Jan 12 18:09:36 1996 Roland McGrath * job.c: Don't declare unblock_sigs; job.h already does. Sat Jan 6 16:24:44 1996 Roland McGrath * acconfig.h (HAVE_SYSCONF_OPEN_MAX): #undef removed. * job.c (NGROUPS_MAX): Don't try to define this macro. Fri Dec 22 18:44:44 1995 Roland McGrath * compatMakefile (GETOPT, GETOPT_SRC, GLOB): Variables removed. (objs, srcs): Include their values here instead of references. Thu Dec 14 06:21:29 1995 Roland McGrath * Version 3.74.2. * job.c (reap_children): Call unblock_sigs after start_job_command. Thu Dec 14 07:22:03 1995 Roland McGrath * dir.c (dir_setup_glob): Don't use lstat; glob never calls it anyway. Avoid & before function names to silence bogus sunos4 compiler. * configure.in: Remove check for `sysconf (_SC_OPEN_MAX)'. Tue Dec 12 00:48:42 1995 Roland McGrath * Version 3.74.1. * dir.c (read_dirstream): Fix braino: fill in the buffer when not reallocating it! Mon Dec 11 22:26:15 1995 Roland McGrath * misc.c (collapse_continuations): Fix skipping of trailing \s so it can never dereference before the beginning of the array. * read.c (find_semicolon): Function removed. (read_makefile): Don't use find_semicolon or remove_comments for rule lines. Use find_char_unquote directly and handle quoted comments properly. * default.c: Remove all [M_XENIX] code. * dir.c [HAVE_D_NAMLEN]: Define this for __GNU_LIBRARY__ > 1. (D_NAMLEN): Macro removed. (FAKE_DIR_ENTRY): New macro. (dir_contents_file_exists_p): Test HAVE_D_NAMLEN instead of using D_NAMLEN. (read_dirstream): Return a struct dirent * for new glob interface. (init_dir): Function removed. (dir_setup_glob): New function. * main.c (main): Don't call init_dir. * read.c (multi_glob): Call dir_setup_glob on our glob_t and use GLOB_ALTDIRFUNC flag. * misc.c (safe_stat): Function removed. * read.c, commands.c, remake.c, vpath.c: Use plain stat instead of safe_stat. Sat Nov 25 20:35:18 1995 Roland McGrath * job.c [HAVE_UNION_WAIT]: Include sys/wait.h. * main.c (log_working_directory): Made global. Print entering msg only once. * make.h (log_working_directory): Declare it. * misc.c (message): Take new arg PREFIX. Print "make: " only if nonzero. Call log_working_directory. * remake.c: Pass new arg in `message' calls. * job.c (start_job_command): Pass new arg to `message'; fix inverted test in that call. Tue Nov 21 19:01:12 1995 Roland McGrath * job.c (start_job_command): Use `message' to print the command, and call it with null if the command is silent. * remake.c (touch_file): Use message instead of printf. Tue Oct 10 14:59:30 1995 Roland McGrath * main.c (enter_command_line_file): Barf if NAME is "". Sat Sep 9 06:33:20 1995 Roland McGrath * commands.c (delete_target): Ignore unlink failure if it is ENOENT. Thu Aug 17 15:08:57 1995 Roland McGrath * configure.in: Don't check for getdtablesize. * job.c (getdtablesize): Remove decls and macros. Thu Aug 10 19:10:03 1995 Roland McGrath * main.c (define_makeflags): Omit command line variable definitions from MFLAGS value. * arscan.c (ar_scan) [AIAMAG]: Check for zero MEMBER_OFFSET, indicating a valid, but empty, archive. Mon Aug 7 15:40:03 1995 Roland McGrath * dir.c (file_impossible_p): Correctly reset FILENAME to name within directory before hash search. * job.c (child_error): Do nothing if IGNORED under -s. * job.c (exec_command): Correctly use ARGV[0] for script name when running shell directly. Tue Aug 1 14:39:14 1995 Roland McGrath * job.c (child_execute_job): Close STDIN_FD and STDOUT_FD after dup'ing from them. Don't try to close all excess descriptors; getdtablesize might return a huge value. Any open descriptors in the parent should have FD_CLOEXEC set. (start_job_command): Set FD_CLOEXEC flag on BAD_STDIN descriptor. Tue Jun 20 03:47:15 1995 Roland McGrath * read.c (read_all_makefiles): Properly append default makefiles to the end of the `read_makefiles' chain. Fri May 19 16:36:32 1995 Roland McGrath * Version 3.74 released. Wed May 10 17:43:34 1995 Roland McGrath * Version 3.73.3. Tue May 9 17:15:23 1995 Roland McGrath * compatMakefile ($(infodir)/make.info): Make sure $$dir is set in install-info cmd. Wed May 3 15:56:06 1995 Roland McGrath * file.c (print_file): Grok update_status of 1 for -q. Thu Apr 27 12:39:35 1995 Roland McGrath * Version 3.73.2. Wed Apr 26 17:15:57 1995 Roland McGrath * file.c (remove_intermediates): Fix inverted test to bail under -n for signal case. Bail under -q or -t. Skip files with update_status==-1. * job.c (job_next_command): Skip empty lines. (new_job): Don't test the return of job_next_command. Just let start_waiting_job handle the case of empty commands. Wed Apr 19 03:25:54 1995 Roland McGrath * function.c [__MSDOS__]: Include . From DJ Delorie. * Version 3.73.1. Sat Apr 8 14:53:24 1995 Roland McGrath * remake.c (notice_finished_file): Set FILE->update_status to zero if it's -1. Wed Apr 5 00:20:24 1995 Roland McGrath * Version 3.73 released. Tue Mar 28 13:25:46 1995 Roland McGrath * main.c (main): Fixed braino in assert. * Version 3.72.13. Mon Mar 27 05:29:12 1995 Roland McGrath * main.c: Avoid string in assert expression. Some systems are broken. Fri Mar 24 00:32:32 1995 Roland McGrath * main.c (main): Handle 1 and 2 returns from update_goal_chain makefile run properly. * Version 3.72.12. * main.c (handle_non_switch_argument): New function, broken out of decode_switches. (decode_switches): Set optind to 0 to reinitialize getopt, not to 1. When getopt_long returns EOF, break the loop and handle remaining args with a simple second loop. * remake.c (remake_file): Set update_status to 2 instead of 1 for no rule to make. Mention parent (dependent) in error message. (update_file_1): Handle FILE->update_status == 2 in -d printout. * job.c (start_job_command, reap_children): Set update_status to 2 instead of 1 for failed commands. Tue Mar 21 16:23:38 1995 Roland McGrath * job.c (search_path): Function removed (was already #if 0'd out). * configure.in: Remove AC_TYPE_GETGROUPS; nothing needs it any more. Fri Mar 17 15:57:40 1995 Roland McGrath * configure.bat: Write @CPPFLAGS@ translation. Mon Mar 13 00:45:59 1995 Roland McGrath * read.c (parse_file_seq): Rearranged `l(a b)' -> `l(a) l(b)' loop to not skip the elt immediately preceding `l(...'. Fri Mar 10 13:56:49 1995 Roland McGrath * Version 3.72.11. * read.c (find_char_unquote): Make second arg a string of stop chars instead of a single stop char. Stop when any char in the string is hit. All callers changed. (find_semicolon): Pass stop chars "#;" to one find_char_unquote call, instead of using two calls. If the match is not a ; but a #, return zero. * misc.c: Changed find_char_unquote callers here too. * Version 3.72.10. * read.c (read_makefile, parse_file_seq): Fix typo __MS_DOS__ -> __MSDOS__. * GNUmakefile (globfiles): Add glob/configure.bat. (distfiles): Add configh.dos, configure.bat. Wed Mar 8 13:10:57 1995 Roland McGrath Fixes for MS-DOS from DJ Delorie. * read.c (read_makefile, parse_file_seq) [__MS_DOS__]: Don't see : as separator in "C:\...". * configh.dos (STDC_HEADERS): Define only if undefined. (HAVE_SYS_PARAM_H): Don't define this. (HAVE_STRERROR): Define this. * job.c (construct_command_argv_internal) [__MSDOS__]: Fix typos. * Version 3.72.9. * main.c (decode_switches): Reset optind to 1 instead of 0. Tue Mar 7 17:31:06 1995 Roland McGrath * main.c (decode_switches): If non-option arg is "-", ignore it. Mon Mar 6 23:57:38 1995 Roland McGrath * Version 3.72.8. Wed Feb 22 21:26:36 1995 Roland McGrath * Version 3.72.7. Tue Feb 21 22:10:43 1995 Roland McGrath * main.c (main): Pass missing arg to tmpnam. * configure.in: Check for strsignal. * job.c (child_error): Use strsignal. * main.c (main): Don't call signame_init #ifdef HAVE_STRSIGNAL. * misc.c (strerror): Fix swapped args in sprintf. Mon Feb 13 11:50:08 1995 Roland McGrath * configure.in (CFLAGS, LDFLAGS): Don't set these variables. Fri Feb 10 18:44:12 1995 Roland McGrath * main.c (print_version): Add 95 to copyright years. * Version 3.72.6. * job.c (start_job_command): Remember to call notice_finished_file under -n when not recursing. To do this, consolidate that code under the empty command case and goto there for the -n case. Tue Feb 7 13:36:03 1995 Roland McGrath * make.h [! STDC_HEADERS]: Don't declare qsort. Sun headers declare it int. Mon Feb 6 17:37:01 1995 Roland McGrath * read.c (read_makefile): For bogus line starting with tab, ignore it if blank after removing comments. * main.c: Cast results of `alloca' to `char *'. * expand.c: Likewise. Sun Feb 5 18:35:46 1995 Roland McGrath * Version 3.72.5. * configure.in: Check for mktemp. * main.c (main) [! HAVE_MKTEMP]: Use tmpnam instead of mktemp. * configure.in (make_cv_sysconf_open_max): New check for `sysconf (_SC_OPEN_MAX)'. * acconfig.h: Added #undef HAVE_SYSCONF_OPEN_MAX. * job.c [HAVE_SYSCONF_OPEN_MAX] (getdtablesize): Define as macro using sysconf. Fri Jan 27 04:42:09 1995 Roland McGrath * remake.c (update_file_1): When !MUST_MAKE, don't set FILE->update_status to zero before calling notice_finished_file. (notice_finished_file): Touch only when FILE->update_status is zero. (remake_file): Set FILE->update_status to zero after not calling execute_file_command and deciding to touch instead. Thu Jan 26 01:29:32 1995 Roland McGrath * main.c (debug_signal_handler): New function; toggles debug_flag. (main): Handle SIGUSR1 with that. Mon Jan 16 15:46:56 1995 Roland McGrath * compatMakefile (realclean): Remove Info files. Sun Jan 15 08:23:09 1995 Roland McGrath * Version 3.72.4. * job.c (start_job_command): Save and restore environ around vfork call. (search_path): Function #if 0'd out. (exec_command): Use execvp instead of search_path. * expand.c (variable_expand): Rewrote computed variable name and substitution reference handling to be simpler. First expand the entire text between the parens if it contains any $s, then examine the result of that for subtitution references and do no further expansion while parsing them. * job.c (construct_command_argv_internal): Handle " quoting too, when no backslash, $ or ` characters appear inside the quotes. * configure.in (union wait check): If WEXITSTATUS and WTERMSIG are defined, just use int. Tue Jan 10 06:27:27 1995 Roland McGrath * default.c (default_variables) [__hpux]: Remove special definition of ARFLAGS. Existence of the `f' flag is not consistent across HPUX versions; and one might be using GNU ar anyway. * compatMakefile (clean): Don't remove Info files. * compatMakefile (check): Remove gratuitous target declaration. Sat Jan 7 11:38:23 1995 Roland McGrath * compatMakefile (ETAGS, CTAGS): Don't use -t. * arscan.c (ar_name_equal) [cray]: Subtract 1 like [__hpux]. * main.c (decode_switches): For --help, print usage to stdout. Mon Dec 5 12:42:18 1994 Roland McGrath * Version 3.72.3. * remake.c (update_file_1): Do set_command_state (FILE, cs_not_started) only if old state was deps_running. Mon Nov 28 14:24:03 1994 Roland McGrath * job.c (start_waiting_job): Use set_command_state. * build.template (CPPFLAGS): New variable. (prefix, exec_prefix): Set from @...@. (compilation loop): Pass $CPPFLAGS to compiler. * GNUmakefile (build.sh.in): Make it executable. * GNUmakefile (globfiles): Add configure.in, configure. * Version 3.72.2. * configure.in (AC_OUTPUT): Don't write glob/Makefile. * configure.in (AC_CHECK_SYMBOL): Use AC_DEFINE_UNQUOTED. * configure.in: Don't check for ranlib. Tue Nov 22 22:42:40 1994 Roland McGrath * remake.c (notice_finished_file): Only mark also_make's as updated if really ran cmds. Tue Nov 15 06:32:46 1994 Roland McGrath * configure.in: Put dnls before random whitespace. Sun Nov 13 05:02:25 1994 Roland McGrath * compatMakefile (CPPFLAGS): New variable, set from @CPPFLAGS@. (RANLIB): Variable removed. (prefix, exec_prefix): Set these from @...@. (.c.o): Use $(CPPFLAGS). (glob/libglob.a): Don't pass down variables to sub-make. glob/Makefile should be configured properly by configure. (distclean): Remove config.log and config.cache (autoconf stuff). Mon Nov 7 13:58:06 1994 Roland McGrath * acconfig.h: Add #undef HAVE_UNION_WAIT. * configure.in: Converted to Autoconf v2. * dir.c: Test HAVE_DIRENT_H, HAVE_SYS_DIR_H, HAVE_NDIR_H instead of DIRENT, SYSDIR, NDIR. * build.sh.in (prefix, exec_prefix): Set these from @...@. (CPPFLAGS): New variable, set from @CPPFLAGS@. (compiling loop): Pass $CPPFLAGS before $CFLAGS. * install.sh: File renamed to install-sh. * main.c (define_makeflags): When no flags, set WORDS to zero. Sun Nov 6 18:34:01 1994 Roland McGrath * Version 3.72.1. * main.c (define_makeflags): Terminate properly when FLAGSTRING is empty. Fri Nov 4 16:02:51 1994 Roland McGrath * Version 3.72. Tue Nov 1 01:18:10 1994 Roland McGrath * Version 3.71.5. * job.c (start_job_command): When ARGV is nil, only set update_state and call notice_finished_file if job_next_command returns zero. * job.c (start_job_command): Call notice_finished_file for empty command line. Thu Oct 27 02:02:45 1994 Roland McGrath * file.c (snap_deps): Set COMMANDS_SILENT for .SILENT, not COMMANDS_NOERROR. Wed Oct 26 02:14:10 1994 Roland McGrath * Version 3.71.4. Tue Oct 25 22:49:24 1994 Roland McGrath * file.c (snap_deps): Set command_flags bits in all :: entries. Mon Oct 24 18:47:50 1994 Roland McGrath * make.h (posix_pedantic): Declare it. * main.c (main): Move checks .IGNORE, .SILENT, .POSIX to snap_deps. * file.c (snap_deps): Check .IGNORE, .SILENT, .POSIX here instead of in main. If .IGNORE has deps, OR COMMANDS_NOERROR into their command_flags and don't set -i. Likewise .SILENT. * job.c (start_job_command): In FLAGS initialization, OR in CHILD->file->command_flags. * file.h (struct file): New member `command_flags'. Sun Oct 16 01:01:51 1994 Roland McGrath * main.c (switches): Bump flag values for --no-print-directory and --warn-undefined-variables, so neither is 1 (which indicates a nonoption argument). Sat Oct 15 23:39:48 1994 Roland McGrath * main.c (main): Add missing code in .IGNORE test. Mon Oct 10 04:09:03 1994 Roland McGrath * variable.c (define_automatic_variables): Define +D and +F. Sat Oct 1 04:07:48 1994 Roland McGrath * main.c (main): Define hidden automatic variable with command vars, and MAKEOVERRIDES to a reference to that. (define_makeflags): If posix_pedantic, write a reference to that instead. Thu Sep 29 00:14:26 1994 Roland McGrath * main.c (posix_pedantic): New variable. (main): Set posix_pedantic if .POSIX is a target. Fix .IGNORE and .SILENT checks to require is_target. * commands.c (set_file_variables): Define new automatic variable $+, like $^ but before calling uniquize_deps. * job.c (reap_children): Call delete_child_targets for non-signal error if .DELETE_ON_ERROR is a target. Tue Sep 27 01:57:14 1994 Roland McGrath * Version 3.71.3. Mon Sep 26 18:16:55 1994 Roland McGrath * job.c (reap_children): Don't change C->file->command_state when dying. Test it only after calling start_job_command for a new command line. When no more cmds, just set C->file->update_status. (start_job_command): When the last line is empty or under -n, set C->file->update_status. (start_waiting_job): Grok cs_not_started after start_job_command as success. (new_job): Set C->file->update_status when there are no cmds. (job_next_command): When out of lines, don't set CHILD->file->update_status or CHILD->file->command_state. * main.c (quote_as_word): Renamed from shell_quote. Take new arg; if nonzero, also double $s. (main): Define MAKEOVERRIDES from command_variables here. (define_makeflags): Don't use command_variables here; instead write a reference $(MAKEOVERRIDES) in MAKEFLAGS. Make vars recursive. * dir.c [__MSDOS__]: Fixed typo. * vpath.c (selective_vpath_search): Reset EXISTS when stat fails. Sat Sep 10 03:01:35 1994 Roland McGrath * remake.c: Include and use assert instead of printfs and abort. * main.c (decode_switches): Loop until optind hits ARGC, not just until getopt_long returns EOF. Initialize C to zero before loop; in loop if C is EOF, set optarg from ARGV[optind++], else call getopt_long. (decode_env_switches): Use variable_expand instead of allocated_variable_expand. Allocate a fresh buffer to copy split words into; scan characters by hand to break words and debackslashify. (shell_quote): New function. (define_makeflags): Allocate doubled space for switch args, and command variable names and values; use shell_quote to quote those things. Fri Sep 9 01:37:47 1994 Roland McGrath * Version 3.71.2. * acconfig.h: Add HAVE_SYS_SIGLIST and HAVE__SYS_SIGLIST. * main.c (decode_switches): The non-option return from getopt is 1, not 0. (command_variables): New type and variable. (decode_switches, decode_env_switches): After making a variable definition, record the struct variable pointer in the command_variables chain. (define_makeflags): If ALL, write variable definitions for command_variables. * main.c (other_args): Variable removed. (goals, lastgoal): New static variables (moved from auto in main). (main): Don't process OTHER_ARGS at all. Don't set variable MAKEOVERRIDES at all; define MAKE to just $(MAKE_COMMAND). (init_switches): Prepend a - {return in order} instead of a + {require order}. (decode_switches): Don't set OTHER_ARGS at all. Grok '\0' return from getopt_long as non-option argument; try variable definition and (if !ENV) enter goal targets here. (decode_env_switches): Use allocated_variable_expand to store value. Use find_next_token to simplify word-splitting loop. Don't prepend a dash to uninterpreted value. Instead, if split into only one word, try variable definition and failing that prepend a dash to the word and pass it to decode_switches as a single arg. Wed Sep 7 03:02:46 1994 Roland McGrath * remake.c (notice_finished_file): Only recheck modtimes if FILE->command_state was cs_running on entry (meaning the commands actually just ran). (update_file_1): Whenever we set FILE->update_status, call notice_finished_file instead of just set_command_state. * job.c (start_job_command): Whenever we set CHILD->file->update_status, call notice_finished_file instead of just set_command_state. Tue Sep 6 19:13:54 1994 Roland McGrath * default.c: Add missing ". * job.c: Changed all assignments of command_state members to calls to set_command_state. * remake.c: Likewise. * file.c (set_command_state): New function. * file.h: Declare set_command_state. * main.c (init_switches): Put a + first in options. Mon Jul 25 18:07:46 1994 Roland McGrath Merge MSDOS/GO32 port from DJ Delorie . * vpath.c: Changed all uses of ':' to PATH_SEPARATOR_CHAR. * main.c (directory_before_chdir): New variable, moved out of main (was local). (main) [__MSDOS__]: Look for \ or : to delimit last component of PROGRAM. Don't frob ARGV[0] before setting MAKE_COMMAND variable. (die): Change back to `directory_before_chdir' before dying. * make.h (PATH_SEPARATOR_CHAR): New macro; differing defns for [__MSDOS__] and not. * job.c [__MSDOS__]: Include . [__MSDOS__] (dos_pid, dos_status, dos_bname, dos_bename, dos_batch_file): New variables. (reap_children) [__MSDOS__]: Don't call wait; just examine those vars. (unblock_sigs) [__MSDOS__]: Do nothing. (start_job_command) [__MSDOS__]: Use spawnvpe instead of vfork & exec. (load_too_high) [__MSDOS__]: Always return true. (search_path) [__MSDOS__]: Check for : or / in FILE to punt. Use PATH_SEPARATOR_CHAR instead of ':'. (construct_command_argv_internal) [__MSDOS__]: Wholly different values for sh_chars and sh_cmds. Wholly new code to handle shell scripts. * function.c (expand_function: `shell') [__MSDOS__]: Wholly new implementation. * dir.c [__MSDOS__] (dosify): New function. (dir_contents_file_exists_p) [__MSDOS__]: Call it on FILENAME and process the result instead of FILENAME itself. (file_impossible_p) [__MSDOS__]: Likewise. * default.c [__MSDOS__]: Define GCC_IS_NATIVE. (default_suffix_rules) [__MSDOS__]: Use `y_tab.c' instead of `y.tab.c'. (default_variables) [GCC_IS_NATIVE]: Set CC and CXX to `gcc', YACC to `bison -y', and LEX to `flex'. * configure.bat, configh.dos: New files. * commands.c (fatal_error_signal) [__MSDOS__]: Just remove intermediates and exit. * commands.c (set_file_variables): Add parens in length computation in .SUFFIXES dep loop to quiet compiler warning. From Jim Meyering. * read.c (read_makefile): Free FILENAME if we allocated it. From Jim Meyering. Mon Jul 4 17:47:08 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * misc.c (safe_stat): New function, EINTR-safe wrapper around stat. * vpath.c (selective_vpath_search): Use safe_stat in place of stat. * read.c (construct_include_path): Use safe_stat in place of stat. * job.c (search_path): Use safe_stat in place of stat. * dir.c (find_directory): Use safe_stat in place of stat. * commands.c (delete_target): Use safe_stat in place of stat. * arscan.c (ar_member_touch) [EINTR]: Do EINTR looping around fstat. * remake.c (name_mtime): Use safe_stat in place of stat. (touch_file) [EINTR]: Do EINTR looping around fstat. Fri Jun 24 05:40:24 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * read.c (read_makefile): Check for a shell command first, and then strip leading tabs before further checking if it's not a shell command line. * make.h [__arm]: Undefine POSIX. [!__GNU_LIBRARY__ && !POSIX && !_POSIX_VERSION]: Don't declare system functions that return int. * job.c (construct_command_argv_internal): After swallowing a backslash-newline combination, if INSTRING is set goto string_char (new label) for normal INSTRING handling code. Sat Jun 4 01:11:20 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu) * configure.in: Don't check for sys_siglist and _sys_siglist with AC_HAVE_FUNCS. Instead use two AC_COMPILE_CHECKs. Mon May 23 18:20:38 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.71.1 released. * make.h [!__GNU_LIBRARY__ && !POSIX]: Also test #ifndef _POSIX_VERSION for these declarations. * misc.c [GETLOADAVG_PRIVILEGED] [POSIX]: Remove bogus #ifndefs around #undefs of HAVE_SETREUID and HAVE_SETREGID. Sat May 21 16:26:38 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.71 released. * misc.c [GETLOADAVG_PRIVILEGED] [POSIX]: Don't test [HAVE_SETUID] and [HAVE_SETGID]. Every system has those, and configure doesn't check for them. * make.h [_POSIX_VERSION]: Don't #define POSIX #ifdef ultrix. * compatMakefile (loadavg): Depend on and use loadavg.c instead of getloadavg.c. (loadavg.c): Link or copy it from getloadavg.c. (distclean): Remove loadavg.c. Mon May 16 22:59:04 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.70.4. * misc.c [GETLOADAVG_PRIVILEGED] [! POSIX]: Undefine HAVE_SETEUID and HAVE_SETEGID. * default.c (default_terminal_rules): In SCCS rules, put $(SCCS_OUTPUT_OPTION) before $<. On some systems -G is grokked only before the file name. * configure.in (SCCS_GET_MINUS_G check): Put -G flag before file name. Tue May 10 16:27:38 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * job.c (construct_command_argv_internal): Swallow backslash-newline combinations inside '' strings too. Thu May 5 04:15:10 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * read.c (do_define): Call collapse_continuations on each line before all else. Mon Apr 25 19:32:02 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * job.c (construct_command_argv_internal): Notice newline inside '' string when RESTP is non-null. Fri Apr 22 17:33:30 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu) * Version 3.70.3. * remake.c (update_goal_chain): Reset FILE to G->file after the double-colon loop so it is never null for following code. * read.c (read_makefile): Fix `override define' parsing to skip whitespace after `define' properly. * compatMakefile (srcdir): Define as @srcdir@; don't reference $(VPATH). (glob/Makefile): New target. Thu Apr 21 16:16:55 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu) * Version 3.70.2. * misc.c (remove_comments): Use find_char_unquote. * make.h (find_char_unquote): Declare it. * read.c (find_char_unquote): New function, generalized from find_percent. (find_percent, find_semicolon, parse_file_seq): Use that. Wed Apr 20 18:42:39 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * implicit.c (pattern_search): Always allocate new storage for FILE->stem. It is not safe to store STEM's address because it might be auto storage. * configure.in: Check for seteuid and setegid. * misc.c [HAVE_SETEUID]: Declare seteuid. [HAVE_SETEGID]: Declare setegid. (make_access, user_access) [HAVE_SETEUID]: Use seteuid. [HAVE_SETEGID]: Use setegid. * remake.c (update_goal_chain): Set STATUS to FILE->update_status, to preserve whether it's 2 for error or 1 for -q trigger. When STATUS gets nonzero and -q is set, always stop immediately. * main.c (main, decode_switches): Die with 2 for errors. (main): Accept 2 return from update_goal_chain and die with that. * misc.c (fatal, makefile_fatal): Die with 2; 1 is reserved for -q answer. * job.c (reap_children): Die with 2 for error. (start_job_command): Set update_status to 2 for error. Set it to 1 when we would run a command and question_flag is set. * read.c (read_makefile): Don't mark makefiles as precious. Just like other targets, they can be left inconsistent and in need of remaking by aborted commands. * read.c (read_makefile): Write no error msg for -include file. Tue Apr 5 05:22:19 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * commands.c (fatal_error_signal): Don't unblock signals. * file.h (struct file): Change member `double_colon' from flag to `struct file *'. * read.c (record_files): Set double_colon pointer instead of flag. * main.c (main): When disqualifying makefiles for updating, use double_colon pointer to find all entries for a file. * file.c (enter_file): If there is already a double-colon entry for the file, set NEW->double_colon to that pointer. (file_hash_enter): Use FILE->double_colon to find all entries to set name. * remake.c (update_goal_chain): Do inner loop on double-colon entries. (update_file): Use FILE->double_colon pointer to find all entries. (f_mtime): Likewise. (notice_finished_file): Propagate mtime change to all entries. * variable.c (try_variable_definition): Return after abort. Fri Apr 1 18:44:15 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * read.c (read_makefile): Remove unused variable. (parse_file_seq): When removing an elt that is just `)', properly fix up the previous elt's next pointer. Mon Mar 28 18:31:49 1994 Roland McGrath (roland@mole.gnu.ai.mit.edu) * configure.in: Do AC_SET_MAKE. * GNUmakefile (Makefile.in): Edit MAKE assignment into @SET_MAKE@. Fri Mar 4 00:02:32 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * function.c (subst_expand): If BY_WORD or SUFFIX_ONLY is set and the search string is the empty string, find a match at the end of each word (using end_of_token in place of sindex). * misc.c (end_of_token): Don't treat backslashes specially; you can no longer escape blanks with backslashes in export, unexport, and vpath. This was never documented anyway. Thu Mar 3 23:53:46 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * read.c (read_makefile): Variable name for `define' is not just first token; use whole rest of line and strip trailing blanks. Wed Feb 16 16:03:45 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.70.1. * read.c (read_makefile): Add -d msg stating args. * read.c (read_makefile): Use isspace to skip over leading whitespace, and explicitly avoid skipping over tabs. Don't want to skip just spaces though; formfeeds et al should be skipped. * default.c (default_variables) [__hpux]: Add f in ARFLAGS. * arscan.c (ar_name_equal) [__hpux]: Subtract 2 instead of 1 from sizeof ar_name for max length to compare. * misc.c [GETLOADAVG_PRIVILEGED] [POSIX]: Undefine HAVE_SETREUID #ifdef HAVE_SETUID; likewise HAVE_SETREGID and HAVE_SETGID. * main.c (main): Call user_access after setting `program', in case it needs to use it in an error message. * read.c (read_makefile): Ignore an empty line starting with a tab. Thu Feb 10 21:45:31 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * configure.in (AC_SYS_SIGLIST_DECLARED): Use this instead of AC_COMPILE_CHECK that is now its contents. Fri Feb 4 16:28:54 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * make.h: #undef strerror after #include . [! ANSI_STRING]: Declare strerror. Thu Feb 3 02:21:22 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * misc.c (strerror): #undef any macro before function definition. Mon Jan 31 19:07:23 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * variable.c (try_variable_definition): Calculate BEG before loop to strip blanks by decrementing END. Don't decr END to before BEG. * read.c (read_makefile): Skip over leading space characters, but not tabs, after removing continuations and comments (it used to use isspace). Tue Jan 25 16:45:05 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * variable.c (define_automatic_variables): In $(@D) et al, use patsubst to remove trailing slash. * commands.c (delete_target): New function, broken out of delete_child_targets. Check for archive members and give special msg. (delete_child_targets): Use delete_target. Mon Jan 17 17:03:22 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * default.c (default_suffix_rules): Use $(TEXI2DVI_FLAGS) in texi2dvi rules. Use $(MAKEINFO_FLAGS) in makeinfo rules. Tue Jan 11 19:29:55 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * GNUmakefile (tarfiles): Omit make-doc. (make-$(version).tar): Include make.info*. Fri Jan 7 16:27:00 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * compatMakefile (configure, config.h.in): Comment out rules. Thu Jan 6 18:08:08 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * compatMakefile (binprefix, manprefix): New variables. (instname): Variable removed. (install): Use $({bin,man}prefix)make in place of $(instname). File targets likewised renamed. Mon Jan 3 17:50:25 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.70 released. Thu Dec 23 14:46:54 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.69.3. * read.c (parse_file_seq): Inside multi-word archive ref translation loop, check NEW1==0 at end and break out of the loop. * GNUmakefile (make-$(version).tar): Distribute install.sh. * install.sh: New file. * configure.in (SCCS_GET_MINUS_G check): Put redirection for admin cmds outside subshell parens, to avoid "command not found" msgs from the shell. Wed Dec 22 17:00:43 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * configure.in (SCCS_GET_MINUS_G check): Put -G flag last in get cmd. Redirect output & error from get to /dev/null. Fix reversed sense of test. Fri Dec 17 15:31:36 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * configure.in (SCCS_GET_MINUS_G check): Use parens instead of braces inside if condition command; some shells lose. Thu Dec 16 15:10:23 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.69.2. * arscan.c [M_UNIX]: Move #undef M_XENIX for PORTAR stuff. (PORTAR) [M_XENIX]: Define to 0 instead of 1. * main.c (define_makeflags): Only export MAKEFLAGS if !ALL. Wed Dec 15 17:47:48 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * main.c (main): Cast result of pointer arith to unsigned int before passing to define_variable for envars. Matters when sizeof(unsigned)!=sizeof(ptrdiff_t). Tue Dec 14 14:21:16 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * configure.in: Add new check for SCCS_GET_MINUS_G. * config.h.in: Add #undef SCCS_GET_MINUS_G. * default.c (default_terminal_rules): Use `$(SCCS_OUTPUT_OPTION)' in place of `-G $@' in SCCS commands. (default_variables) [SCCS_GET_MINUS_G]: Define SCCS_OUTPUT_OPTION to "-G$@". * configure.in (AC_OUTPUT): Put touch stamp-config in second arg (so it goes in config.status), rather than afterward. * ar.c (ar_member_date): Don't call enter_file on the archive file if it doesn't exist (by file_exists_p). * compatMakefile ($(infodir)/make.info): Replace `$$d/foo.info' with `$$dir/make.info' in install-info invocation (oops). * vpath.c (construct_vpath_list): Only set LASTPATH set PATH when we do not unlink and free PATH. * file.c (print_file_data_base): Fix inverted calculation for average files per hash bucket. * read.c (readline): When we see a NUL, give only a warning and synthesize a newline to terminate the building line (used to fatal). Move fgets call into the loop condition, and after the loop test ferror (used to test !feof in the loop). Fri Dec 3 16:40:31 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * configure.in: Check for strerror in AC_HAVE_FUNCS. Thu Dec 2 15:37:50 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) Differentiate different flavors of missing makefile error msgs, removing gratuitous `fopen: ' and giving caller for included makefiles. * misc.c [! HAVE_STRERROR]: Define our own strerror here. (perror_with_name, pfatal_with_name): Use strerror instead of replicating its functionality. * read.c (read_makefile): Return int instead of void. (read_all_makefiles, read_makefile): Change callers to notice zero return and give error msg. Thu Nov 11 11:47:36 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.69.1. * default.c: Put `-G $@' before $< in SCCS cmds. Wed Nov 10 06:06:14 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * read.c (read_makefile): After trying a variable defn, notice if the line begins with a tab, and diagnose an error. Sun Nov 7 08:07:37 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.69. Wed Nov 3 06:54:33 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.68.10. * implicit.c (try_implicit_rule): Look for a normal rule before an archive rule. Fri Oct 29 16:45:28 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * function.c (expand_function: `sort'): Double NWORDS when it overflows, instead of adding five. * compatMakefile (clean): Remove loadavg. Wed Oct 27 17:58:33 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.68.9. * file.h (NEW_MTIME): Define new macro. * main.c (main): Set time of NEW_FILES to NEW_MTIME, not to current time returned from system. Removed variable NOW. * remake.c (notice_finished_file): Use NEW_MTIME in place of current time here too. Tue Oct 26 19:45:35 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.68.8. * remake.c (update_file_1): Don't clear MUST_MAKE when FILE has no cmds and !DEPS_CHANGED unless also !NOEXIST. Mon Oct 25 15:25:21 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * read.c (parse_file_seq): When converting multi-word archive refs, ignore a word beginning with a '('. Fri Oct 22 02:53:38 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * configure.in: Check for sys/timeb.h. * make.h [HAVE_SYS_TIMEB_H]: Test this before including it. Thu Oct 21 16:48:17 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.68.7. * rule.c (convert_suffix_rule): New local TARGPERCENT. Set it to TARGNAME+1 for "(%.o)", to TARGNAME for "%.?". Use it in place of TARGNAME to initialize PERCENTS[0]. Mon Oct 18 06:49:35 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * configure.in: Use AC_HAVE_HEADERS(unistd.h) instead of AC_UNISTD_H. Remove AC_USG; it is no longer used. * file.c (print_file): New function, broken out of print_file_data_base. (print_file_data_base): Call it. * rule.c (print_rule): New function, broken out of print_rule_data_base. (print_rule_data_base): Call it. Thu Oct 14 14:54:03 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * default.c (install_default_suffix_rules): New function, broken out of install_default_implicit_rules. (install_default_implicit_rules): Move suffix rule code there. * make.h: Declare install_default_suffix_rules. * main.c (main): Call install_default_suffix_rules before reading makefiles. Move convert_to_pattern call before install_default_implicit_rules. * job.h (struct child): Make `pid' member type `pid_t' instead of `int'. * compatMakefile (RANLIB): New variable, set by configure. (glob/libglob.a): Pass RANLIB value down to submake. Fixes for SCO 3.2 "devsys 4.2" from pss@tfn.com (Peter Salvitti). * make.h: Include before for SCO lossage. * job.c [! getdtablesize] [! HAVE_GETDTABLESIZE]: If NOFILE is not defined but NOFILES_MAX is, define it to be that. Mon Oct 11 19:47:33 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * GNUmakefile (make-$(version).tar): Depend on acconfig.h, so it is distributed. Sun Oct 3 15:15:33 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * default.c (default_terminal_rules): Add `-G $@' to SCCS get cmds. Tue Sep 28 14:18:20 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * job.c (construct_command_argv_internal): Add ^ to SH_CHARS; it is another symbol for | in some shells. * main.c (main): Add it to CMD_DEFS quoting list as well. Mon Sep 20 18:05:24 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * job.c (construct_command_argv_internal): Remove '=' from SH_CHARS. Only punt on '=' if it is unquoted in a word before the first word without an unquoted '='. * main.c (define_makeflags): Set v_export for MAKEFLAGS. Fri Sep 17 00:37:18 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * remake.c (update_file_1): Use .DEFAULT cmds for phony targets. * make.h [_AIX && _POSIX_SOURCE]: Define POSIX. * commands.c (delete_child_targets): Don't delete phony files. * job.c (start_job_command): Set COMMANDS_RECURSE in FLAGS if we see a `+' at the beginning of the command line. Thu Sep 9 17:57:14 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.68.6. Wed Sep 8 20:14:21 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * main.c (define_makeflags): Define MAKEFLAGS with o_file, not o_env. Mon Aug 30 12:31:58 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * expand.c (variable_expand): Fatal on an unterminated reference. Thu Aug 19 16:27:53 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.68.5. * variable.c (define_automatic_variables): Define new o_default variable `MAKE_VERSION' from version_string and remote_description. * make.h (version_string, remote_description): Declare these here. * main.c: Don't declare version_string. (print_version): Don't declare remote_description. Wed Aug 18 15:01:24 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * read.c (read_makefile): Free space pointed to by CONDITIONALS before restoring the old pointer. Mon Aug 16 17:33:36 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * compatMakefile ($(objs)): Depend on config.h. * GNUmakefile (build.sh.in): Depend on compatMakefile. * configure.in: Touch stamp-config after AC_OUTPUT. Fri Aug 13 16:04:22 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.68.4. Thu Aug 12 17:18:57 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * make.h: Include instead of "config.h". Wed Aug 11 02:35:25 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * main.c (main): Make all variables interned from ENVP be v_export. * variable.c (try_variable_definition): In v_default case, don't check for an o_file variable that `getenv' finds. * job.c (reap_children): New local variable ANY_LOCAL; set it while setting ANY_REMOTE. If !ANY_LOCAL, don't wait for local kids. * main.c (main): Don't call decode_env_switches on MFLAGS. DOC THIS. * function.c (expand_function): #if 0 out freeing of ENVP since it is environ. Mon Aug 9 17:37:20 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.68.3. * remote-stub.c (remote_status): Set errno to ECHILD before return. * job.c (reap_children): Scan the chain for remote children and never call remote_status if there are none. * function.c (expand_function: `shell'): #if 0 out calling target_environment; just set ENVP to environ instead. * job.c (reap_children): Check for negative return from remote_status and fatal for it. When blocking local child wait returns 0, then try a blocking call to remote_status. Tue Aug 3 00:19:00 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * compatMakefile (clean): Delete make.info* and make.dvi here. (distclean): Not here. * dep.h (RM_*): Use #defines instead of enum to avoid lossage from compilers that don't like enum values used as ints. Mon Aug 2 16:46:34 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * compatMakefile (loadavg): Add $(LOADLIBES). Sun Aug 1 16:01:15 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.68.2. * compatMakefile (loadavg, check-loadavg): New targets. (check): Depend on check-loadavg. * compatMakefile (glob/libglob.a): Depend on config.h. * misc.c (log_access): Write to stderr instead of stdout. Fri Jul 30 00:07:02 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.68.1. Thu Jul 29 23:26:40 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * configure.in (SYS_SIGLIST_DECLARED): In test program include #ifdef HAVE_UNISTD_H. * compatMakefile (.PHONY): Put after `all' et al. * configure.in: Add AC_IRIX_SUN. Wed Jul 28 17:41:12 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.68. Mon Jul 26 14:36:49 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.67.8. Sun Jul 25 22:09:08 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.67.7. * compatMakefile ($(infodir)/make.info): Don't use $(instname). Run install-info script if present. Fri Jul 23 16:03:50 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * make.h [STAT_MACROS_BROKEN]: Test this instead of [uts]. * configure.in: Add AC_STAT_MACROS_BROKEN. Wed Jul 14 18:48:11 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.67.6. * read.c (read_makefile): Recognize directive `-include', like `include' but sets RM_DONTCARE flag. * variable.c (target_environment): If FILE is nil, use current_variable_set_list in place of FILE->variables. * function.c (expand_function: `shell'): Get an environment for the child from target_environment instead of using environ. * dep.h: Declare read_all_makefiles here. (RM_*): Define new enum constants. * read.c (read_makefile): Second arg is FLAGS instead of TYPE. Treat it as a bit mask containing RM_*. (read_all_makefiles): For default makefiles, set D->changed to RM_DONTCARE instead of 1. * main.c: Don't declare read_all_makefiles here. (main): Check `changed' member of read_makefiles elts for RM_* flags instead of specific integer values. Mon Jul 12 22:42:17 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * make.h [sequent && i386]: #undef POSIX. From trost@cse.ogi.edu. Thu Jul 8 19:51:23 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * vpath.c (construct_vpath_list): If ELEM is zero 0, free PATTERN as well as VPATH. (build_vpath_lists): Empty `vpaths' around construct_vpath_list call for $(VPATH). Expand $(strip $(VPATH)), not just $(VPATH). * rule.c (convert_suffix_rule): Use alloca instead of xmalloc for PERCENTS, whose storage is not consumed by create_pattern_rule. * make.h [__mips && _SYSTYPE_SVR3]: #undef POSIX. Wed Jun 30 18:11:40 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.67.5. * rule.c (max_pattern_targets): New variable. (count_implicit_rule_limits): Compute its value. * rule.h: Declare it. * implicit.c (pattern_search): Make TRYRULES max_target_patterns times bigger. Move adding new TRYRULES elt inside the inner targets loop, so each matching target gets its own elt in MATCHES and CHECKED_LASTSLASH. * file.c (remove_intermediates): If SIG!=0 say `intermediate file' instead of just `file' in error msg. Fri Jun 25 14:55:15 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * job.c (construct_command_argv): Turn off --warn-undefined-variables around expansion of SHELL and IFS. * read.c (tilde_expand): Likewise for HOME. (read_all_makefiles): Likewise for MAKEFILES. * vpath.c (build_vpath_lists): Likewise for VPATH. * main.c (warn_undefined_variables_flag): New flag variable. (switches): Add --warn-undefined-variables. * make.h (warn_undefined_variables_flag): Declare it. * expand.c (warn_undefined): New function. (reference_variable): Call it if the variable is undefined. (variable_expand): In substitution ref, call warn_undefined if the variable is undefined. * default.c (default_pattern_rules): Add `%.c: %.w %.ch' and `%.tex: %.w %.ch' rules. (default_suffix_rules: .w.c, .w.tex): Pass three args: $< - $@. (default_suffixes): Add `.ch'. Mon Jun 21 17:55:39 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * default.c (default_suffixes): Replace `.cweb' with `.w'. (default_suffix_rules): Rename `.cweb.c' and `.cweb.tex' to `.w.c' and `.w.tex'. Fri Jun 11 14:42:09 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * compatMakefile ($(bindir)/$(instname)): Add missing backslash. Thu Jun 10 18:14:08 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.67.4. * read.c (multi_glob): Don't free OLD and OLD->name in the FOUND!=0 fork. Use new block-local variable F instead of clobbering OLD. * ar.c (glob_pattern_p): New function, snarfed from glob/glob.c. (ar_glob): Call it; return nil immediately if MEMBER_PATTERN contains no metacharacters. Wed Jun 9 16:25:35 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * ar.c (ar_glob{_match,_alphacompare}): New function. * dep.h [! NO_ARCHIVES]: Declare it. * read.c (multi_glob) [! NO_ARCHIVES]: Use it on archive member elts. * read.c (read_makefile): Pass flag (1) to parse_file_seq, not to multi_glob (which doesn't take a 3rd arg). * rule.c (install_pattern_rule): Likewise. * default.c (set_default_suffixes): Here too. * function.c (string_glob): Don't pass gratuitous arg to multi_glob. * read.c (parse_file_seq) [! NO_ARCHIVES]: Add post-processing loop to translate archive refs "lib(a b)" into "lib(a) lib(b)". Mon Jun 7 19:26:51 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * compatMakefile (installdirs): Actually pass directory names. ($(bindir)/$(instname)): Test chgrp&&chmod exit status with `if'; if it fails, echo a warning msg, but don't make the rule fail. * read.c (tilde_expand): New function, broken out of tilde_expand. (multi_glob): Call it. (construct_include_path): Expand ~ in directory names. * dep.h: Declare tilde_expand. * main.c (enter_command_line_file): Expand ~ at the start of NAME. (main): Expand ~ in -C args. * read.c (read_makefile): Expand ~ in FILENAME unless TYPE==2. Fri Jun 4 13:34:47 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * main.c (decode_env_switches): Use xmalloc instead of alloca for ARGS. * main.c (main): Put result of alloca in temporary variable with simple assignment, to make SGI compiler happy. Thu Jun 3 20:15:46 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.67.3. * main.c (main): Before re-execing, remove intermediate files, and print the data base under -p. Sexier debugging message. * implicit.c (pattern_search): Allocate an extra copy of the name of a winning intermediate file when putting it in FOUND_FILES. Wed Jun 2 16:38:08 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * read.c (read_makefile): Pass flag (1) to parse_file_seq, not to multi_glob (which doesn't take a 3rd arg). * dir.c (dir_contents_file_exists_p): When reading dirents, ignore chars within D_NAMLEN that are NULs. * main.c (decode_switches): Don't savestring ARGV[0] to put it into `other_args'. For string switch, don't savestring `optarg'. (main): Don't free elts of makefiles->list that are "-". Use alloca'd rather than savestring'd storage for elts of makefiles->list that are temporary file names. * read.c (read_all_makefiles): Don't free *MAKEFILES. * file.c (enter_file): Don't strip `./'s. * main.c (enter_command_line_file): New function. (main): Use it in place of enter_file for command-line goals from other_files, and for old_files and new_files. Mon May 31 18:41:40 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.67.2. * compatMakefile (.SUFFIXES): Add .info. ($(infodir)/$(instname).info): Find make.info* in cwd if there, else in $srcdir. Use basename to remove dir name from installed name. Thu May 27 17:35:02 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * implicit.c (pattern_search): When interning FOUND_FILES, try lookup_file first; if found, free the storage for our copy of the name. Wed May 26 14:31:20 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.67.1. * main.c (decode_switches): In usage msg, write `--switch=ARG' or `--switch[=OPTARG]' rather than `--switch ARG' or `--switch [ARG]'. Mon May 24 16:17:31 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * rule.c (convert_suffix_rule): New function. (convert_to_pattern): Use it instead of doing all the work here several times. For target suffix `.a', generate both the archive magic rule and the normal rule. * compatMakefile (distclean): Remove stamp-config. Sat May 22 16:15:18 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.67. * file.c (remove_intermediates): Don't write extra space after `rm'. * main.c (struct command_switch.type): Remove `usage_and_exit'. (print_usage_flag): New variable. (switches: --help): Make type `flag', to set print_usage_flag. (init_switches): Remove `usage_and_exit' case. (decode_switches): Likewise. (decode_switches): Print usage if print_usage_flag is set. When printing usage, die with status of BAD. (main): Die with 0 if print_version_flag. Fri May 21 16:09:28 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.66. Wed May 19 21:30:44 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * compatMakefile (installdirs): New target. (install): Depend on it. Sun May 16 20:15:07 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.65.2. Fri May 14 16:40:09 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * vpath.c (construct_vpath_list): In removal loop for DIRPATH==0, set LASTPATH to PATH, not NEXT. * dir.c (read_dirstream): Break out of loop after incrementing DS->buckets such that it reaches DIRFILE_BUCKETS; avoid trying to dereference DS->contents->files[DIRFILE_BUCKETS]. * read.c (read_makefile): Clear no_targets after reading a targetful rule line. * main.c (main): If print_version_flag is set, exit after printing the version. (switches): Change --version docstring to say it exits. * make.h [butterfly]: #undef POSIX. Wed May 12 15:20:21 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) * Version 3.65.1. * arscan.c (ar_scan) [! AIAMAG]: Don't declare LONG_NAME. [AIAMAG]: Pass TRUNCATE flag arg to (*FUNCTION), always zero. * function.c (handle_function): Use fatal instead of makefile_fatal when reading_filename is nil. * configure.in: Add AC_GETGROUPS_T. * job.c (search_path): Use GETGROUPS_T in place of gid_t. Sun May 9 15:41:25 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.65. Fri May 7 18:34:56 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * function.c (handle_function): Fatal for unmatched paren. Thu May 6 16:13:41 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.64.3. * commands.c (handling_fatal_signal): New variable. (fatal_error_signal): Set it. * job.c (reap_children): Avoid nonreentrant operations if that is set. * make.h: Declare handling_fatal_signal. * expand.c (reference_variable): New function, snippet of code broken out of simple-reference case of variable_expand. (variable_expand): Use it for simple refs. (variable_expand): When checking for a computed variable name, notice a colon that comes before the final CLOSEPAREN. Expand only up to the colon, and then replace the pending text with a copy containing the expanded name and fall through to subst ref handling. (variable_expand): Don't bother expanding the name if a colon appears before the first $. (expand_argument): Use alloca instead of savestring. (variable_expand): For subst ref, expand both sides of = before passing to [pat]subst_expand. Use find_percent instead of lindex to check the lhs for a %. Wed May 5 14:45:52 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.64.2. Mon May 3 17:00:32 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * arscan.c (ar_name_equal) [AIAMAG]: Abort if TRUNCATED is nonzero. * read.c (read_makefile): Pass extra arg of 1 to parse_file_seq, not to multi_glob. Thu Apr 29 19:47:33 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.64.1. * arscan.c (ar_scan): New local flag var LONG_NAME. Set it when we read the member name in any of the fashions that allow it to be arbitrarily long. Pass its negation to FUNCTION. (describe_member): Take TRUNCATED from ar_scan and print it. (ar_name_equal): Take new arg TRUNCATED; if nonzero, compare only the first sizeof (struct ar_hdr.ar_name) chars. (ar_member_pos): Take TRUNCATED from ar_scan, pass to ar_name_equal. * ar.c (ar_member_date_1): Likewise. Wed Apr 28 21:18:22 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * job.c (reap_children): Before calling start_job_command to start the next command line, reset C->remote by calling start_remote_job_p. Mon Apr 26 15:56:15 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) * arscan.c (ar_scan): New local var NAMEMAP. In loop, rename NAME to NAMEBUF; new var NAME is a pointer; new flag IS_NAMEMAP. When extracting the member name, always put a null at its end first. If the name is "//" or "/ARFILENAMES", set IS_NAMEMAP. If we have already read in NAMEMAP, and NAME looks like " /N", get full name from NAMEMAP+N. Else if NAME looks like "#1/N", read N chars from the elt data to be the full name. At end of loop, if IS_NAMEMAP, read the elt's data into alloca'd NAMEMAP. (ar_name_equal): #if 0 truncating code. * make.h: Don't declare vfork at all. It returns int anyway, unless declared it; and we conflicted with some systems. * main.c (define_makeflags): If FLAGSTRING[1] is '-', define MAKEFLAGS to all of FLAGSTRING, not &FLAGSTRING[1]. Don't want to define it to something like "-no-print-directory". Use %g format instead of %f for floating-valued things. Thu Apr 22 18:40:58 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * GNUmakefile (Makefile.in): Use a substitution ref on nolib-deps to change remote-%.dep to remote-stub.dep. Wed Apr 21 15:17:54 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.64. Fri Apr 16 14:22:22 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * compatMakefile (install): Remove - prefix from chgrp+chmod. * Version 3.63.8. Thu Apr 15 18:24:07 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * acconfig.h: New file; contains "#undef SCCS_GET" for autoheader. * configure.in: If /usr/sccs/get exists, define SCCS_GET to that, else to "get". * default.c (default_variables): Set GET to macro SCCS_GET. * read.c (parse_file_seq): Take extra arg STRIP; strip `./' only if nonzero. I hope this is the last time this argument is added or removed. (read_makefile): Pass it 1 when parsing include file names. Pass it 1 when parsing target file names. Pass it 1 when parsing static pattern target pattern names. * rule.c (install_pattern_rule): Pass it 1 when parsing rule deps. * default.c (set_default_suffixes): Pass it 1 when parsing default_suffixes. * function.c (string_glob): Pass it 0 here. Wed Apr 14 11:32:05 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * misc.c (log_access): New function. ({init,user,make,child}_access): Call it. (child_access): Abort if !access_inited. * main.c (switches: --no-print-directory): Use 1 instead of -1 for single-letter option. (init_switches, decode_switches, define_makeflags): An option with no single-letter version is no longer indicated by a value of -1; instead a value that is !isalnum. (init_switches): Don't put such switches into the string, only into the long_option table. * make.h [!NSIG] [!_NSIG]: #define NSIG 32. * job.c [HAVE_WAITPID]: Remove #undef HAVE_UNION_WAIT. AIX's bsdcc defined WIF* to use union wait. * main.c (struct command_switch): Change member `c' to type int. (switches): Make const. (decode_switches): Use `const struct command_switch *'. (define_makeflags): Likewise. * default.c (default_suffix_rules): Add `-o $@' to makeinfo rules. Mon Apr 12 12:30:04 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.63.7. * configure.in (AC_HAVE_HEADERS): Check for string.h and memory.h. Removed AC_MEMORY_H. * make.h [USG, NeXT]: Don't test these. [HAVE_STRING_H]: Test this to include string.h and define ANSI_STRING. [HAVE_MEMORY_H]: Test this instead of NEED_MEMORY_H. [! ANSI_STRING]: Put decls of bcopy et al here. [sparc]: Don't test this for alloca.h; HAVE_ALLOCA_H is sufficient. [HAVE_SIGSETMASK]: Test this rather than USG. [__GNU_LIBRARY__ || POSIX]: Don't #include again. * main.c (main): Handle SIGCHLD if defined, and SIGCLD if defined. It doesn't hurt to do both if they are both defined, and testing USG is useless. * dir.c: Rationalize directory header conditionals. * arscan.c [HAVE_FCNTL_H]: Test this rather than USG || POSIX. * default.c (default_suffixes): Add `.txinfo'. (default_suffix_rules): Add `.txinfo.info' and `.txinfo.dvi' rules. * variable.c (try_variable_definition): Replace RECURSIVE flag with enum FLAVOR, which can be simple, recursive, or append. Recognize += as append flavor. Set new variable VALUE in a switch on FLAVOR. For append flavor, prepend the variable's old value. If the variable was previously defined recursive, set FLAVOR to recursive; if it was defined simple, expand the new value before appending it to the old value. Pass RECURSIVE flag to define_variable iff FLAVOR == recursive. * variable.c (try_variable_definition): Use alloca and bcopy for NAME, instead of savestring. Might as well use stack storage since we free it immediately anyway. Thu Apr 8 18:04:43 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * job.c (start_waiting_jobs): Move decl of JOB outside of loop. * main.c (define_makeflags): Rename `struct flag' member `switch' to `cs', which is not a reserved word. Wed Apr 7 15:30:51 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * job.c (new_job): Call start_waiting_jobs first thing. (start_waiting_job): Changed return type from void to int. Return 0 when putting the child on the waiting_jobs chain. (start_waiting_jobs): Don't check load and job_slots here. Always take a job off the chain and call start_waiting_job on it; give up and return when start_waiting_job returns zero. * main.c (define_makeflags: struct flag): Change member `char c' to `struct command_switch *switch'. (ADD_FLAG): Set that to CS instead of CS->c. If CS->c is -1, increment FLAGSLEN for the long name. When writing out FLAGS, handle FLAGS->switch->c == -1 and write the long name instead. * compatMakefile (stamp-config): New target of old config.h rule. Touch stamp-config after running config.status. (config.h): Just depend on stamp-config, and have empty commands. Mon Apr 5 20:14:02 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * job.c [HAVE_WAITPID]: #undef HAVE_UNION_WAIT. * configure.in (AC_HAVE_FUNCS): Check for psignal. Fri Apr 2 17:15:46 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * main.c (long_option_aliases): Remove "new"; it is already an unambiguous prefix of "new-file". Sun Mar 28 16:57:17 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) * Version 3.63.6. Wed Mar 24 14:26:19 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * vpath.c (selective_vpath_search): When adding the name-within-directory at the end of NAME, and we don't add a slash, don't copy FILENAME in one char too far into NAME. * variable.c (define_automatic_variables): Find default_shell's length with strlen, not numerology. Wed Mar 17 20:02:27 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * main.c (define_makeflags): Add the elts of a string option in reverse order, so they come out right when reversed again. Fri Mar 12 15:38:45 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) * compatMakefile (make.info): Use `-o make.info'. Thu Mar 11 14:13:00 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) * compatMakefile (REMOTE): Set to @REMOTE@; change comments to reflect new use. (objs): Replace remote.o with remote-$(REMOTE).o. (srcs): Replace remote.c with remote-$(REMOTE).c. (remote.o): Rule removed. * configure.in (REMOTE): Subst this in Makefile et al; default "stub". Use AC_WITH to grok --with-customs arg to set REMOTE=cstms. * GNUmakefile (build.sh.in): Filter out remote-% from objs list. * build.template (REMOTE): New var; set to @REMOTE@. (objs): Add remote-${REMOTE}.o. Wed Mar 10 15:12:24 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) * Version 3.63.5. * implicit.c (pattern_search): Fix "dependent"->"dependency" in "Rejecting impossible" -d msg. * file.c (file_hash_enter): New local vars {OLD,NEW}BUCKET. Store mod'd values there; never mod {OLD,NEW}HASH. Mon Mar 8 13:32:48 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) * remake.c [eta10]: Include instead of . * compatMakefile (VPATH): Set this to @srcdir@. (srcdir): Set this to $(VPATH). * main.c (main): New local var DIRECTORY_BEFORE_CHDIR. Save in it a copy of CURRENT_DIRECTORY after the first getcwd. Use it instead of CURRENT_DIRECTORY when chdir'ing back before re-execing. * remake.c (notice_finished_file): Pass missing SEARCH arg to f_mtime. * read.c (read_makefile): Remove extraneous arg to parse_file_seq. Mon Feb 22 14:19:38 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * compatMakefile ($(infodir)/$(instname).info): Use , instead of / as the sed delimiter char. Sun Feb 21 14:11:04 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.63.4. * rule.h (struct rule): Removed `subdir' member. * rule.c (new_pattern_rule): No need to clear it. (count_implicit_rule_limits): Set the `changed' flag in each dep that refers to a nonexistent directory. No longer set rule-global `subdir' flag with that information. (print_rule_data_base): Don't record info on `subdir' flags. * implicit.c (pattern_search): Check the DEP->changed flag rather than the (now gone) RULE->subdir flag. Also test CHECK_LASTSLASH; if it is set, the file might exist even though the DEP->changed flag is set. * rule.c (count_implicit_rule_limits): Pass "", not ".", as file name arg to dir_file_exists_p to check for existence of directory. * implicit.c (pattern_search): Inside dep-finding loop, set CHECK_LASTSLASH from the value recorded in CHECKED_LASTSLASH[I], rather than computing it anew. * commands.c (set_file_variables): Must alloca space for PERCENT and copy it, to avoid leaving the trailing `)' in the value. * misc.c (remove_comments): Fixed backslash-checking loop condition to allow it to look at the first char on the line. P2 >= LINE, not P2 > LINE. * compatMakefile ($(bindir)/$(instname)): Before moving $@.new to $@, rm $@.old and mv $@ to $@.old. * variable.c (try_variable_definition): Take new args FILENAME and LINENO. Fatal if the variable name is empty. * read.c (read_makefile): Change callers. * main.c (main): Likewise. * compatMakefile (group): Define to @KMEM_GROUP@, autoconf magic that configure will replace with the group owning /dev/kmem. Mon Feb 8 14:26:43 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) * vpath.c (vpath_search): Take second arg MTIME_PTR, pass thru to selective_vpath_search. (selective_vpath_search): Take second arg MTIME_PTR. If the dir cache thinks a file exists, stat it to make sure, and put the modtime in *MTIME_PTR. * remake.c (library_search): Take second arg MTIME_PTR. When we find a match, record its mtime there. Pass MTIME_PTR through to vpath_search to do same. (f_mtime): Pass &MTIME as new 2nd arg to {vpath,library}_search; store it in FILE->last_mtime if set nonzero. * implicit.c (pattern_search): Pass nil 2nd arg to vpath_search. * compatMakefile (remote.o): Prepend `$(srcdir)/' to `remote-*.c', so globbing looks somewhere it will find things. * compatMakefile ($(infodir)/$(instname).info): Install `make.info*' not `$(srcdir)/make.info*'; no need to use basename. Fri Feb 5 12:52:43 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) * Version 3.63.3. * compatMakefile (install): Add missing ;\s. Make -, @, and + prefixes on a pre-expanded command line affect all lines in the expansion, not just the first. * commands.h (struct commands): Replace `lines_recurse' member with `lines_flags'. (COMMANDS_{RECURSE,SILENT,NOERROR}): New macros, bits to set in that flag byte. * commands.c (chop_commands): Set `lines_flags' instead of `lines_recurse'. Record not only + but also @ and - prefixes. * remake.c (notice_finished_file): Check the COMMANDS_RECURSE bit in FILE->cmds->lines_flags, rather than FILE->cmds->lines_recurse. * job.c (start_job_command): Replaced RECURSIVE and NOPRINT local var with FLAGS; initialize it to the appropriate `lines_flags' byte. Set CHILD->noerror if the COMMANDS_NOERROR bit is set in FLAGS. Set the COMMANDS_SILENT bit in FLAGS for a @ prefix. * remake.c (update_goal_chain): Set G->file to its prev after checking for G being finished, since that check needs to examine G->file. * configure.in (union wait check) [HAVE_WAITPID]: Try using waitpid with a `union wait' STATUS arg. If waitpid and union wait don't work together, we should not use union wait. * Version 3.63.2. * remake.c (update_goal_chain): When G->file->updated, move G->file to its prev. We aren't finished until G->file is nil. Thu Feb 4 12:53:04 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * main.c (starting_directory): New global variable. (main): Set it to cwd after doing -Cs. (log_working_directory): Use it, rather than computing each time. * make.h: Declare it. * compatMakefile (SHELL): Define to /bin/sh for losing Unix makes. * main.c (decode_env_switches): Allocate (1 + LEN + 1) words for ARGV, rather than LEN words plus one byte. Wed Feb 3 18:13:52 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) * compatMakefile ($(bindir)/$(instname)): Put - before install_setgid command line, so its failure won't be an error. (infodir): New variable. (install): Depend on $(infodir)/$(instname).info. ($(infodir)/$(instname).info): New target. * read.c (read_makefile): If FILENAMES is nil when we see a line starting with a tab, don't treat it as a command. Just fall through, rather than giving an error. * read.c (read_makefile): If the NO_TARGETS flag is set when we see a command line, don't clear it before continuing. We want subsequent command lines to be ignored as well. * job.c (new_job): Before expanding each command line, collapse backslash-newline combinations that are inside var or fn references. Mon Feb 1 16:00:13 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) * compatMakefile (exec_prefix): Default to $(prefix), not /usr/local. * compatMakefile (make.info): Pass -I$(srcdir) to makeinfo. * job.c [POSIX] (unblock_sigs): Made global. [!POSIX] (unblock_sigs): Move defns to job.h. * job.h [POSIX] (unblock_sigs): Declare. Sun Jan 31 19:11:05 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) * read.c (read_makefile): In vpath parsing, after finding the pattern token, take entire rest of line as the search path, not just the next token. * compatMakefile (remote.o): Depend on remote-*.c. Thu Jan 28 16:40:29 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * commands.c (set_file_variables): Don't define any F or D versions. * variable.c (define_automatic_variables): Define them here as recursively-expanded variables that use the dir and notdir funcs. * variable.c (target_environment): In v_default case, don't export o_default or o_automatic variables. * configure.in (union wait check): Remove ` and ' inside C code; they confuse the shell script. Mon Jan 25 13:10:42 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.63.1. * vpath.c (construct_vpath_list): When skipping further processing of an elt that is ".", don't also skip the code that pushes P past the next separator. * compatMakefile (distclean): Don't remove make-*. * configure.in (HAVE_UNION_WAIT): Try to use WEXITSTATUS if it's defined. If one cannot use WEXITSTATUS with a `union wait' argument, we don't want to believe the system has `union wait' at all. * remake.c (update_file): Do nothing to print "up to date" msgs. (update_goal_chain): Do it here instead. Use the `changed' flag of each goal's `struct dep' to keep track of whether files_remade (now commands_started) changed around a call to update_file for that goal. When a goal is finished, and its file's update_status is zero (i.e., success or nothing done), test the `changed' flag and give an "up to date" msg iff it is clear. * make.h (files_remade): Renamed to commands_started. * remake.c: Changed defn. (update_goal_chain): Changed uses. * job.c (start_job_command): Increment commands_started here. (reap_children): Not here. * remake.c (update_goal_chain): Don't do anything with files' `prev' members. update_file now completely handles this. * variable.c (target_environment): Don't expand recursive variables if they came from the environment. * main.c (define_makeflags): For flags with omitted optional args, store {"", 0} with ADD_FLAG. When constructing FLAGSTRING, a flag so stored cannot have more flags appended to the same word. Fri Jan 22 14:46:16 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * variable.c (print_variable_set): In vars/bucket calculation, don't spuriously multiply by 100. * Version 3.63. * job.c [!HAVE_UNION_WAIT] (WTERMSIG, WCOREDUMP, WEXITSTATUS): Don't define if already defined. * remake.c (update_file): Don't keep track of the command_state before calling update_file_1. Remove local variable COMMANDS_FINISHED, and don't test it to decide to print the "is up to date" msg. Testing for files_remade having changed should always be sufficient. The old method lost when we are called in the goal chain run on a makefile, because the makefile's command_state is already `cs_finished' from the makefile chain run. * misc.c [HAVE_SETRE[GU]ID]: Test these to decl setre[gu]id. * configure.in: Rewrote wait checking. Use AC_HAVE_HEADERS to check for . Use AC_HAVE_FUNCS to check for waitpid and wait3. Use a compile check to test just for `union wait'. * job.c: Rewrote conditionals accordingly. [HAVE_WAITPID]: Test this only to define WAIT_NOHANG. [HAVE_WAIT3]: Likewise. [HAVE_UNION_WAIT]: Test this to define WAIT_T and W*. * configure.in: Set CFLAGS and LDFLAGS before all checks. * dir.c: Add static forward decls of {open,read}_dirstream. Thu Jan 21 17:18:00 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) * Version 3.62.31. * job.c [NGROUPS_MAX && NGROUPS_MAX==0]: #undef NGROUPS_MAX. * compatMakefile (CFLAGS, LDFLAGS): Set to @CFLAGS@/@LDFLAGS@. * build.template (CFLAGS, LDFLAGS): Same here. * configure.in: AC_SUBST(CFLAGS) and LDFLAGS. Set them to -g if not defined in the environment. * remake.c (library_search): Use LIBNAME consistently, setting it only once, to be the passed name sans `-l'. Pass new var FILE to be modified by vpath_search. Mon Jan 18 14:53:54 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.62.30. * job.c (start_waiting_jobs): Return when job_slots_used is equal to job_slots. * configure.in: Add AC_CONST for the sake of getopt. * read.c (read_makefile): Continue after parsing `override' directive, rather than falling through to lossage. Check for EOL or blank after "override define". * compatMakefile (.c.o, remote.o): Put $(CFLAGS) after other switches. Fri Jan 15 12:52:52 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.62.29. * main.c (define_makeflags): After writing everything into FLAGSTRING, only back up two chars if [-1] is a dash, meaning we just wrote " -". Always terminate the string at *P. * remake.c (library_search): When constructing names in std dirs, use &(*LIB)[2] for the stem, not LIBNAME (which points at the buffer we are writing into!). Thu Jan 14 13:50:06 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * read.c (read_makefile): Set IN_IGNORED_DEFINE for "override define" when IGNORING is true. * compatMakefile (distclean): Remove config.status and build.sh. Wed Jan 13 16:01:12 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.62.28. * misc.c (xmalloc, xrealloc): Cast result of malloc/realloc to (char *). * arscan.c (ar_scan) [AIAMAG]: Cast read arg to (char *). * variable.c (define_automatic_variables): Override SHELL value for origin o_env_override as well as o_env. * GNUmakefile (build.sh.in): Don't replace %globobjs%. Instead, add the names of the glob objects (w/subdir) to %objs%. * build.template (globobjs): Removed. Take basename of $objs before linking. Tue Jan 12 12:31:06 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) * Version 3.62.27. * configure.in (AC_OUTPUT): Also edit build.sh. * build.template: New file. * GNUmakefile (build.sh.in): New rule to create it from build.template. (make-$(version).tar.Z): Depend on build.sh.in. * main.c (die): Call print_data_base if -p. (main): Don't call it here. * compatMakefile (defines): Add @DEFS@. configure should turn this into -DHAVE_CONFIG_H. Mon Jan 11 14:39:23 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) * Version 3.62.26. * misc.c (init_access): Surround with #ifdef GETLOADAVG_PRIVILEGED. ({make,user,child}_access) [! GETLOADAVG_PRIVILEGED]: Make no-op. * compatMakefile (install_setgid): New var, set by configure. (install): Install setgid $(group) only if $(install_setgid) is true. Fri Jan 8 15:31:55 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * job.c (load_too_high): If getloadavg fails with errno==0, give a message saying that load limits are not supported. * vpath.c (construct_vpath_list): Rewrote path deletion code to not try to use PATH's next link after freeing PATH. * main.c (define_makeflags): Rewritten; now handles string-valued option, and has no arbitrary limits. (switches): Set `toenv' flag for -I and -v. * main.c (decode_env_switches): Cast return value of alloca to char *. * misc.c (child_access) [HAVE_SETREUID, HAVE_SETREGID]: Use setre[gu]id in place of set[gu]id. Wed Jan 6 15:06:12 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * main.c (main): Define MAKEOVERRIDES, MAKE, and MAKE_COMMAND with origin o_default. * make.h [POSIX]: Don't test this to use ANSI_STRING. Testing STDC_HEADERS should be sufficient. * job.h: Declare start_waiting_jobs. * read.c (read_makefile): Add missing parens in if stmt that find conditional directives. * main.c (main): Declare init_dir. * implicit.c (pattern_search): Always use two % specs in a DEBUGP2, and always pass two non-nil args. Cast field width args to int. Add missing parens in !RULE->subdir if stmt. * function.c (expand_function, patsubst_expand): Add parens around assignments inside `while' stmts. * commands.c (print_commands): Cast field width args to int. * read.c (do_define): Cast return value of alloca to (char *). * main.c (init_switches): New function, broken out of decode_switches. (decode_switches): Take new arg ENV. If set, ignore non-option args; print no error msgs; ignore options with clear `env' flags. (decode_env_switches): Rewritten to chop envar value into words and pass them to decode_switches. (switches): Set `env' flag for -I and -v. * dir.c (init_dir): Cast free to __glob_closedir_hook's type. Tue Jan 5 14:52:15 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.62.25. * job.c [HAVE_SYS_WAIT || !USG]: Don't #include and . interacts badly with , and we don't need these anyway. * configure.in (AC_HAVE_FUNCS): Check for setre[gu]id. * misc.c ({user,make}_access): Test #ifndef HAVE_SETRE[GU]ID, not #ifdef POSIX || USG. SunOS 4.1 is supposedly POSIX.1 compliant, but its set[gu]id functions aren't; its setre[gu]id functions work. * misc.c ({user,make,child}_access): Give name of caller in error msgs. * job.c (load_too_high): Say "cannot enforce load limit" in error msg. * configure.in: Call AC_PROG_CC. * compatMakefile (CC): Define to @CC@ (autoconf magic). * compatMakefile: Add .NOEXPORT magic target. Mon Jan 4 17:00:03 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) * main.c (print_version): Updated copyright to include 93. Thu Dec 31 12:26:15 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * make.h [_AIX]: Don't declare alloca. Tue Dec 29 13:45:13 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * Version 3.62.24. * compatMakefile (objs): Add signame.o. (srcs): Add signame.[ch]. * compatMakefile (srcs): Add config.h.in. (remote.o): Add -I. before -I$(srcdir). Mon Dec 28 15:51:26 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.62.23. * read.c (readline): Fatal when LEN==0, indicating a line starting with a NUL. (readline): Take new arg LINENO, for use in error msg. (read_makefile, do_define): Pass it. * compatMakefile (glob/libglob.a): Pass -DHAVE_CONFIG_H in CPPFLAGS. (.c.o): Add -I. before -I$(srcdir). Wed Dec 23 12:12:04 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * read.c (read_makefile): Accept and ignore a rule with no targets. * compatMakefile (ALLOCA_SRC): New variable. (srcs): Include its value. * read.c (struct conditional): Renamed member `max_ignoring' to `allocated'; added new member `seen_else'. (conditional_line): Initialize seen_else flag when starting an `if...'; set it when we see an `else'; fatal if set when we see `else'. (read_makefile): Fatal "missing `endif'" if there are any pending conditionals, not just if we are still ignoring. Tue Dec 22 15:36:28 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * compatMakefile (manext): Set to 1, not l. ($(mandir)/$(instname).$(manext)): Use $(srcdir) for make.man in cmds. * file.c (file_hash_enter): Don't call uniquize_deps here. * read.c (record_files): Likewise. * implicit.c (pattern_search): Likewise. * commands.c (set_file_variables): Call it only here. * default.c (default_variables) [__convex__]: FC=fc. * variable.c (target_environment): Expand the values of recursively expanded variables when putting them into the environment. * expand.c (recursively_expand): Made global. * make.h (recursively_expand): Declare it. * remake.c (check_dep): Set FILE->command_state to cs_deps_running when a dep's command_state is cs_running or cs_deps_running. * read.c (read_makefile): Changed error msg for spurious cmds to not say "first target". Sun Dec 20 17:56:09 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) * configure.in: Do AC_CONFIG_HEADER right after AC_INIT. * make.h (HAVE_CONFIG_H): #include "config.h", then #define this. * compatMakefile (config.h, configure, config.h.in): New rules. (defines): Removed @DEFS@. Thu Dec 17 16:11:40 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * compatMakefile (realclean): Just depend on distclean; no cmds. (distclean): Do what realclean did before; also remove Makefile and config.h; don't remove configure. (info, dvi): New targets; depend on make.{info,dvi}. (doc): Removed target. (MAKEINFO, TEXI2DVI): New vars. (make.info, make.dvi): Use them instead of explicit cmds. Wed Dec 16 16:25:24 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * configure.in: Added fcntl.h to AC_HAVE_HEADERS. getloadavg cares. Wed Dec 9 15:21:01 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * main.c (long_option_aliases): Add --new-file alias for -W. * default.c (default_variables): Change all C++ to CXX and C++FLAGS to CXXFLAGS. * read.c (do_define): Expand the variable name before using it. * main.c (main): Define variable "MAKE_COMMAND" to argv[0]; define "MAKE=$(MAKE_COMMAND) $(MAKEOVERRIDES)" always. * remake.c (library_search): Search for libNAME.a in cwd; look in vpath before looking in standard dirs, not after. Changed order of std dirs to: /lib, /usr/lib, ${prefix}/lib. Mon Nov 23 14:57:34 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * default.c (default_pattern_rules, default_terminal_rules): Added brackets around initializers. * variable.c (try_variable_definition): Don't check for LINE[0]=='\t'. (try_variable_definition): Expand the name before defining the var. * job.c (init_siglist): Removed function. Removed decl of `sys_siglist'. * make.h [! HAVE_SYS_SIGLIST]: #include "signame.h". [HAVE_SYS_SIGLIST && !SYS_SIGLIST_DECLARED]: Declare sys_siglist only under these conditions. * main.c (main): Don't declare init_siglist. (main) [! HAVE_SYS_SIGLIST]: Call signame_init instead of init_siglist. Wed Nov 18 14:52:51 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * read.c (record_files): Don't try to append to FIRSTDEPS if it's nil; instead just set it to MOREDEPS. Mon Nov 16 17:49:17 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * vpath.c (construct_vpath_list): Initialize P to DIRPATH before loop that sets MAXELEM. Fri Nov 13 18:23:18 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.62.22. Thu Nov 12 15:45:31 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * job.c (start_job_command): Under -n, increment files_remade after processing (i.e., printing) all command lines. Tue Nov 10 15:33:53 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * read.c (record_files): Append new deps if this rule has no commands; prepend them to existing deps if this rule has no commands. * dir.c (open_dirstream): Return nil if DIR->contents->files is nil. * read.c (parse_file_seq): Removed last arg STRIP. Always strip `./'s. (read_makefile): Changed callers. * function.c (string_glob): Likewise. * rule.c (install_pattern_rule): Likewise. Mon Nov 9 17:50:16 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * remake.c (files_remade): Made global. (notice_finished_file): Don't increment files_remade here; this function gets called in many situations where no remaking was in fact done. * job.c (reap_children): Do it here instead, when we know that actual commands have been run for the file. * make.h (files_remade): Declare it. Thu Nov 5 18:26:10 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * vpath.c (construct_vpath_list): Allow blanks as well as colons to separate elts in the search path. * read.c (read_makefile): Don't fatal on extra tokens in `vpath'. The search path can contain spaces now. Tue Nov 3 20:44:32 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * compatMakefile (check): New target; no-op. * file.c (file_hash_enter): Mod OLDHASH by FILE_BUCKETS after testing for OLDHASH==0 but before using the value. (rename_file): Don't mod OLDHASH by FILE_BUCKETS before passing it to file_hash_enter. * file.c (rename_file): Notice when OLDFILE->cmds came from default.c, and don't try to print ->filename in that case. Sun Oct 25 01:48:23 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * remake.c (update_file): Don't process F->also_make here. (notice_finished_file): Don't process FILE->also_make if no attempt to update FILE was actually made. Fixed to call f_mtime directly to refresh their modtimes. Sat Oct 24 22:08:59 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * read.c (find_percent): Don't increment P again after skipping an escaped %. * expand.c (variable_expand): In call to patsubst_expand, don't find `%'s ourselves; let that function do it. * read.c (read_makefile: record_waiting_files): Don't call record_files if FILENAMES is nil. (read_makefile): All alternatives in the parsing, except for rule lines, fall through to the end of the loop. At the end of the loop, do record_waiting_files so we notice later spurious cmds. Fri Oct 23 15:57:37 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * variable.c (define_automatic_variables): Free old value of SHELL before replacing it. Thu Oct 15 18:57:56 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * compatMakefile (.c.o): Add -I$(srcdir)/glob to flags. * dir.c (open_dirstream): Cast return value to __ptr_t. * default.c (default_variables: "GET") [_IBMR2]: Use USG defn. * make.h (MAXPATHLEN): Moved out of #ifndef POSIX. (GET_PATH_MAX): Moved from #ifdef POSIX to #ifdef PATH_MAX #else. Define as (get_path_max ()). [! PATH_MAX] (NEED_GET_PATH_MAX): Define. [! PATH_MAX] (get_path_max): Declare fn. * misc.c [NEED_GET_PATH_MAX] (get_path_max): New function. Mon Oct 12 13:34:45 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * Version 3.62.21. * job.c (sys_siglist): Only declare #ifndef SYS_SIGLIST_DECLARED. * make.h [! HAVE_SYS_SIGLIST && HAVE__SYS_SIGLIST]: #define SYS_SIGLIST_DECLARED. * dir.c (file_impossible): When initializing DIR->contents, set DIR->contents->dirstream to nil. * compatMakefile (GLOB): Define new variable. (objs): Use it, rather than glob/libglob.a explicitly. * read.c (parse_file_seq): When stripping "./", handle cases like ".///foo" and "./////". * file.c (lookup_file, enter_file): Likewise. Sun Oct 11 17:00:35 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * dir.c (struct dirstream, {open,read}_dirstream): New data type and functions to read a directory sequentially. (init_dir): New function to hook it into glob. * main.c (main): Call init_dir. * compatMakefile (objs): Added glob/libglob.a. * configure.in: Remove code to test for glob. Fri Oct 9 12:08:30 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * read.c (record_files): Generalized test for NAME pointing somewhere into F->name. * variable.c (define_variable_in_set): Free old value when replacing. * read.c (do_define): Free the linebuffer before returning. (record_files): When clearing .SUFFIXES deps, free their data. (multi_glob): Free OLD and its data when replacing it with results of glob run. * commands.c (set_file_variables): Use alloca in place of xmalloc for temp space for $^, $?, et al. * dir.c (struct directory): New member `contents' replaces `files' and `dirstream'. (struct directory_contents): New type. (directories_contents): New hash table. (dir_struct_file_exists_p): Take a struct directory_contents. (dir_file_exists_p): Pass it the `contents' member of the dir found. (dir_struct_file_exists_p): Renamed to dir_contents_file_exists_p; made static. Return 0 if DIR is nil (meaning it couldn't be stat'd). (dir_file_exists_p, find_directory): Change all callers. (file_impossible): Use DIR->contents, initializing it if nil. (print_dir_data_base): Use DIR->contents, and print out device and inode numbers with each directory. * Changes for performance win from John Gilmore : * dir.c (DIRECTORY_BUCKETS): Increase to 199. (DIRFILE_BUCKETS): Decrease to 107. (find_directory): Allocate and zero a multiple of sizeof (struct dirfile *), not of sizeof (struct dirfile). (dir_struct_file_exists_p): New function, nearly all code from dir_file_exists_p. (dir_file_exists_p): Just call find_directory+dir_struct_file_exists_p. * vpath.c (selective_vpath_search): Remove redundant dir_file_exists_p call. * configure.in: Comment out glob check; always use our code. Fri Oct 2 19:41:20 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * make.h [! HAVE_SYS_SIGLIST && HAVE__SYS_SIGLIST]: #define HAVE_SYS_SIGLIST; after doing #define sys_siglist _sys_siglist, we do have it. Wed Sep 30 19:21:01 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * main.c (main): Don't do -w automatically if -s. Tue Sep 29 21:07:55 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * main.c (printed_version): Move variable inside print_version. (print_version): Return immediately if printed_version is set. (die): Don't test printed_version here. (decode_switches): Under -v, do print_version before giving usage. (DESCRIPTION_COLUMN): New macro. (decode_switches): Use it when printing the usage message. Leave at least two spaces between options and their descriptions. Fri Sep 25 13:12:42 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * Version 3.62.20. Wed Sep 16 16:15:22 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * read.c (read_makefile): Save errno value from trying to open FILENAME, and restore it before erring; otherwise we get the errno value from the last elt of the search path. Tue Sep 15 15:12:47 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * main.c (long_option_aliases): Add --stop for -S. * read.c (word1eq): Do strncmp before dereferencing someplace that may be out in space. Wed Sep 9 15:50:41 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * remake.c (notice_finished_file): If all the command lines were recursive, don't do the touching. * job.c (start_job_command): Don't check for + here. * commands.c (chop_commands): Do it here instead. * default.c (default_terminal_rules): Prepend + to cmds for RCS. Wed Sep 2 17:53:08 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * compatMakefile (objs): Include $(ALLOCA). * make.h [CRAY]: Move #define signal bsdsignal to before #includes. Thu Aug 27 17:45:43 1992 Roland McGrath (roland@wookumz.gnu.ai.mit.edu) * read.c (default_include_directories): Add INCLUDEDIR first. * compatMakefile (includedir): Define. (defines): Add -D for INCLUDEDIR="$(includedir)". * read.c (read_makefile): Grok multiple files in `include'; globbing too. * remake.c (library_search): New function. (library_file_mtime): Remove function. (f_mtime): Use library_search instead of library_file_mtime. * compatMakefile (libdir): Define. (defines): Add -D for LIBDIR="$(libdir)". * make.texinfo (Libraries/Search): Document change. * file.c (rename_file): Fix file_hash_enter call with missing arg. Wed Aug 26 17:10:46 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * Version 3.62.19. * main.c (main): Set command_state to cs_finished for temp files made for stdin makefiles. * main.c (decode_switches): Don't tell getopt to return non-option args in order. Ignore an argument of `-'. Thu Aug 20 13:36:04 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * job.c (start_job_command): If (touch_flag && !RECURSIVE), ignore the command line and go to the next. (notice_finished_file): Under -t, touch FILE. * remake.c (remake_file): Don't touch it here. Wed Aug 19 16:06:09 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * function.c (pattern_matches): Use temporary for strlen (WORD) instead of two function calls. * compatMakefile (LOAD_AVG): Remove variable and comments. Tue Aug 18 14:58:58 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * make.texinfo (Running): Node renamed to `make Invocation'. Fri Aug 14 12:27:10 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * arscan.c (ar_name_equal): Don't compare [MAX-3..MAX] if NAMELEN != MEMLEN. Thu Aug 13 17:50:09 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.62.18. * main.c: Don't #include ; make.h already does. Mon Aug 10 17:03:01 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * implicit.c (pattern_search): Fixed copying of suffix when building also_make elts. * function.c (expand_function: `shell'): Make sure BUFFER is null-terminated before replacing newlines. * compatMakefile (mandir): Use man$(manext), not always manl. Sun Aug 2 01:42:50 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * rule.c (new_pattern_rule): Not static. * rule.h: Declare it. * file.c (file_hash_enter): New function, most code from rename_file. (rename_file): Call it. * file.h (file_hash_enter): Declare it. * dep.h: Doc fix. Thu Jul 30 15:40:48 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * main.c (decode_switches): Handle usage_and_exit when building long options vector. * default.c (default_terminal_rules): Make RCS rules use $(CHECKOUT,v). (default_variables): Define CHECKOUT,v (hairy). * make.h [!HAVE_SYS_SIGLIST && HAVE__SYS_SIGLIST]: #define sys_siglist to _sys_siglist. Sun Jul 26 16:56:32 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * NEWS: Add header and tail copyright info like Emacs NEWS. * make.h [ANSI_STRING]: Don't #define index, rindex, bcmp, bzero, bcopy if already #define'd. [STDC_HEADERS] (qsort, abort, exit): Declare here. [! __GNU_LIBRARY__ && !POSIX]: Not here. * make.h [_AIX]: #pragma alloca first thing. * job.c (start_waiting_job): Set the command_state to cs_running when we queue a job on waiting_jobs. Fri Jul 24 02:16:28 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * variable.c (define_automatic_variables): Use "" instead of nil for empty value. Thu Jul 23 22:31:18 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.62.17. * main.c (struct command_switch.type): Add alternative usage_and_exit. (command_switches): Add -h/--help. Thu Jul 16 14:27:50 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * GNUmakefile (make-$(version).tar.Z): Include NEWS, not CHANGES. * README.template: Mention NEWS. * CHANGES: Renamed to NEWS. * main.c [! STDC_HEADERS] [sun]: Don't declare exit. Tue Jul 14 18:48:41 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * main.c (main): Set -o files' command_states to cs_finished. * rule.c (count_implicit_rule_limits): Decrement num_pattern_rules when tossing a rule. * main.c (main): Use alloca only in simple local var assignment, for braindead SGI compiler. * rule.c (print_rule_data_base): Barf if num_pattern_rules is inconsistent with the number computed when listing them. Mon Jul 13 17:51:53 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * commands.c (set_file_variables): For $? and $^ elts that are archive member refs, use member name only. Fri Jul 10 00:05:04 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * variable.h (struct variable.export): Add new alternative v_ifset. * variable.c (target_environment): Check for it. (define_automatic_variables): Set it for MAKEFILES. Thu Jul 9 21:24:28 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * compatMakefile (objs): Remove getloadavg.o; $(extras) gets it. (remote.o): Use $(srcdir)/remote.c, not $remote.c<. (distclean, mostlyclean): New targets. Tue Jul 7 19:12:49 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.62.16. * compatMakefile (config.status): Remove rule. * job.c (start_waiting_job): Free C after using C->file, not before. Sat Jul 4 20:51:49 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * commands.c, job.c, main.c, make.h, remote-cstms.c: Use #ifdef HAVE_* instead of #ifndef *_MISSING. * configure.in: Use AC_HAVE_FUNCS instead of AC_MISSING_FUNCS (gone). Thu Jul 2 18:47:52 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * main.c (main): makelevel>0 or -C implies -w. Tue Jun 30 20:50:17 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * file.c, job.c, function.c: Don't #include . make.h: Do it here instead. * arscan.c (ar_member_touch): Don't declare errno. Thu Jun 25 17:06:55 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * GNUmakefile (make-$(version).tar.Z): Depend on INSTALL, configure.in. * remake.c (update_file): If commands or deps are running after update_file_1 returns, break out of the :: rule (->prev) loop and just return. * job.c (job_next_command): New function; code from start_job. (start_job_command): Renamed from start_job. Call job_next_command and recurse for empty command lines and -n. (start_waiting_job): Call start_job_command, not start_job. (new_job): Call job_next_command to prime the child structure, and then call start_waiting_job. (reap_children): Use job_next_command and start_job_command. (start_waiting_job): Call start_remote_job_p here, and store its result in C->remote. If zero, check the load average and maybe put C on waiting_jobs. (start_job_command): Test CHILD->remote rather than calling start_remote_job_p. Don't do load avg checking at all here. * main.c (main): Don't handle SIGILL, SIGIOT, SIGEMT, SIGBUS, SIGSEGV, SIGFPE or SIGTRAP. * compatMakefile (glob/libglob.a): Don't pass srcdir to sub-make. configure will set it in glob/Makefile. Wed Jun 24 19:40:34 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * dir.c [DIRENT] (direct): Don't define to dirent. [! DIRENT] (direct): Define to dirent. (dir_file_exists_p): Use struct dirent instead of struct direct. * make.h (getcwd): No space between macro and ( for args! * job.c (start_job): Don't put the job on waiting_jobs if job_slots_used==0. * make.texinfo (Missing): Shortened title. Tue Jun 23 18:42:21 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * file.c (remove_intermediates): Print "rm" commands under -n. Mon Jun 22 16:20:02 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * Version 3.62.15. Fri Jun 19 16:20:26 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * arscan.c [M_UNIX]: #undef M_XENIX. Wed Jun 17 17:59:28 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * default.c (default_terminal_rules): Put @ prefix on RCS cmds. Tue Jun 16 19:24:17 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * compatMakefile (getloadavg.o): Removed special rule. (CFLAGS): Don't include $(defines). (.c.o): Define suffix rule. (glob/libglob.a): Pass CPPFLAGS=$(defines) to submake. (GETOPT_SRC, srcs, tagsrcs): Prefix files with $(srcdir)/. * arscan.c (ar_name_equal): Moved local vars inside #if'd block. * make.h (max): Removed. * expand.c (variable_buffer_output): Don't use it. * compatMakefile (INSTALL): Define. (Makefile): New rule to make from Makefile.in. (srcdir): Define. (VPATH): Define. (getloadavg.o, remote.o): Use autoconf $foo< hack. * commands.c (fatal_error_signal): Removed return. Mon Jun 15 17:42:51 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.62.14. * make.texinfo (Summary): New node. (Special Targets): Mention .EXPORT_ALL_VARIABLES here. * variable.c (max): Moved to make.h. * compatMakefile (objs, srcs): Added ar & arscan. * job.c (start_waiting_job): New function, 2nd half of new_job. (new_job): Call it. (start_waiting_jobs): New function. * remake.c (update_goal_chain): Call start_waiting_jobs at the top of the main loop. * compatMakefile (objs, srcs): Removed load, added getloadavg. Fri Jun 12 19:33:16 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * job.c (load_too_high): New function. Uses getloadavg. (waiting_jobs): New variable. (start_job): Don't call wait_to_start_job. Instead, if load_too_high returns nonzero, add the child to the `waiting_jobs' chain and return without starting the job. Thu Jun 11 00:05:28 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * expand.c (variable_buffer_output): Made global again. * variable.h: And declare it. * arscan.c (PORTAR): Define for all systems if PORT5AR is not defined. (AR_NAMELEN, AR_TRAILING_SLASH): Removed. (ar_scan): Don't use it. Don't #ifdef AR_TRAILING_SLASH; just look for a slash in the archive at run time. (ar_name_equal): Rewrote .o hacking to not use AR_NAMELEN, and to cope with trailing-slash and non-trailing-slash archives. * main.c (main) [! SETVBUF_REVERSED]: Test this instead of USGr3 et al. [SETVBUF_REVERSED]: Always allocate a buffer ourselves. * load.c (load_average) [sgi]: Use sysmp call. * compatMakefile (INSTALL_DATA, INSTALL_PROGRAM): Define. ($(bindir)/$(instname), $(mandir)/make.$(manext)): Use them. * make.h [HAVE_VFORK_H]: #include . (vfork, VFORK_NAME): Don't define. * job.c (start_job): Use "vfork" in place of VFORK_NAME. * make.h [HAVE_LIMITS_H, HAVE_SYS_PARAM_H]: If #define'd, #include the each file. Rearranged PATH_MAX hacking. * job.c: Rearranged NGROUPS_MAX hacking. * remake.c (fstat, time): Don't declare. * compatMakefile (defines): Value is @DEFS@. (LOADLIBES): Value is @LIBS@. (extras): Value is @LIBOBJS@. (ARCHIVES, ARCHIVES_SRC, ALLOCASRC): Removed. * arscan.c, ar.c: Surround body with #ifndef NO_ARCHIVES. * misc.c [! HAVE_UNISTD_H]: Test instead of !POSIX to decl get*id. * make.h [GETCWD_MISSING]: Test instead of !USG && !POSIX et al. (getcwd): Just declare if present. If not, declare as a macro using getwd, and declare getwd. [PATH_MAX] (GET_PATH_MAX): #define to PATH_MAX. * main.c (main, log_working_directory): Use getcwd instead of getwd. * main.c (main) [SETLINEBUF_MISSING]: Test this instead of USG. * make.h (SIGHANDLER, SIGNAL): Removed. (RETSIGTYPE): Define if not #define'd. * main.c (main): Use signal in place of SIGNAL. * main.c [SYS_SIGLIST_MISSING]: Test instead of USG. * job.c (search_path) [GETGROUPS_MISSING]: Test instead of USG. [HAVE_UNISTD_H]: Test instead of POSIX to not decl getgroups. * main.c [! HAVE_UNISTD_H]: Test instead of !POSIX to decl chdir. [! STDC_HEADERS]: Test instead of !POSIX to decl exit & atof. * job.c (child_handler), commands.c (fatal_error_signal): Return RETSIGTYPE instead of int. * main.c (main): Declare fatal_error_signal and child_handler here to return RETSIGTYPE; removed top-level decl of former. * commands.c (fatal_error_signal), job.c (unblock_sigs, start_job), main.c [SIGSETMASK_MISSING]: Test this instead of USG. Wed Jun 10 22:06:13 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * job.c [HAVE_WAITPID]: Test this instead of USG. [! HAVE_UNISTD_H]: Test this instead of !POSIX to declare misc fns. (GID_T): Don't #define. (search_path): Use gid_t instead of GID_T. [GETDTABLESIZE_MISSING, SYS_SIGLIST_MISSING, DUP2_MISSING]: Test these individually instead of USG for all. * make.h (ctime): Don't declare. #include time.h instead. [HAVE_UNISTD_H]: #include and #define POSIX #ifdef _POSIX_VERSION. * dir.c [__GNU_LIBRARY__] (D_NAMLEN): Define to use d_namlen member. * make.h [NEED_MEMORY_H]: Only include memory.h #ifdef this. * arscan.c: Removed #ifdef mess about string.h et al. Just #include make.h instead. * make.h (fstat, atol): Declare. * commands.c (fatal_error_signal): Don't use sigmask to check for propagated signals; use ||s instead. (PROPAGATED_SIGNAL_MASK): Removed. (fatal_error_signal) [POSIX]: Use sigprocmask in place of sigsetmask. * variable.c (variable_buffer, variable_buffer_length, initialize_variable_output, variable_output): Moved to expand.c; made all static. (struct output_state, save_variable_output, restore_variable_output): Removed. * expand.c (initialize_variable_output): Put a NUL at the beginning of the new buffer after allocating it. (allocated_variable_expand_for_file): Don't use {save,restore}_variable_output. Do it by hand instead, keeping state on the stack instead of malloc'ing it. (allocated_variable_expand): Removed. * variable.h (allocated_variable_expand): Define here as macro. (variable_buffer_output, initialize_variable_output, save_variable_output, restore_variable_output): Removed decls. * read.c (conditional_line): For an if cmd, if any elt of the conditionals stack is ignoring, just push a new level that ignores and return 1; don't evaluate the condition. Thu Jun 4 21:01:20 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * main.c (main): Put #ifdef's around frobbing SIGSYS and SIGBUS. * job.c (getdtablesize): Don't declare or #define if already #define'd. Wed Jun 3 23:42:36 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * file.c (snap_deps): If `.EXPORT_ALL_VARIABLES' is a target, set export_all_variables. * make.texinfo (Variables/Recursion): Document .EXPORT_ALL_VARIABLES. Tue Jun 2 21:08:35 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * Version 3.62.13. * commands.c (set_file_variables): Calculate length for ^D and ?D individually, making sure to give them at least enough space for "./". * make.h [CRAY]: #define signal to bsdsignal. * default.c (default_variables) [CRAY]: Define PC, SEGLDR, CF77PPFLAGS, CF77PP, CFT, CF, and FC. * arscan.c (AR_HDR_SIZE): Define to sizeof (struct ar_hdr), if it wasn't defined by . Thu May 28 00:56:53 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * Version 3.62.12. Tue May 26 01:26:30 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * rule.c (new_pattern_rule): Initialize LASTRULE to nil, not pattern_rules. Mon May 25 19:02:15 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * main.c (decode_switches): Initialize all the long_option elt members. Thu May 21 16:34:24 1992 Roland McGrath (roland@wookumz.gnu.ai.mit.edu) * make.texinfo (Text Functions): Correct filter-out description. Tue May 19 20:50:01 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * compatMakefile (realclean): Don't remove backup files. * main.c (decode_switches): Allocate ARGC+1 elts in `other_args'. Sun May 17 16:38:48 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) * Version 3.62.11. Thu May 14 16:42:33 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) * job.c (reap_children): Don't die if wait returns EINTR. Wed May 13 18:28:25 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * job.c (reap_children): Always run the next command for a successful target. If we are going to die, we don't want to leave the target partially made. Tue May 12 00:39:19 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) * job.c (construct_command_argv_internal): After loop, if we only have one word, check it for being a shell command. * main.c (decode_switches): Allocate ARGC slots in other_args to begin with, so we never need to worry about growing it. If we get a non-option arg and POSIXLY_CORRECT is in the environment, break out of the loop. After the loop, add all remaining args to other_args list. * main.c (decode_switches): For positive_int and floating switches when optarg is nil, use next arg if it looks right (start with a digit, or maybe decimal point for floating). * variable.c (define_automatic_variables): Always set SHELL to default if it comes from the environment. Set its export bit. * make.texinfo (Environment): Document change. Mon May 11 00:32:46 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) * Version 3.62.10. * compatMakefile (tags, TAGS): Use vars for cmds. (ETAGS, CTAGS): Define. * main.c (decode_switches): If a switches elt has a nil long_name, make the long option name elt be "". Fixed loop to not ignore all the options. * make.texinfo (Option Summary): Added long options. * main.c (switches): Changed -m's description to "-b". (decode_switches): When printing the usage message, don't print switches whose descriptions start with -. When constructing the list of names for switch -C, search the switches vector for switches whose descriptions are "-C". * main.c (switches): Call -S --no-keep-going, not --dont-keep-going. Call -I --include-dir, not --include-path. (long_option_aliases): Added --new == -W, --assume-new == -W, --assume-old == -o, --max-load == -l, --dry-run == -n, --recon == -n, --makefile == -f. * main.c (switches): Removed bogus "silent" elt. (long_option_aliases): Define new var. (decode_switches): Add long_option_aliases onto the end of the long options vector created for getopt_long. Look through long_option_aliases for extra names to list in usage message. Sat May 9 00:21:05 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * main.c (log_working_directory): Fixed to properly not print the leaving message when we haven't printed the entering message. Fri May 8 21:55:35 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * main.c (struct command_switch): Added elts `long_name', `description', and `argdesc'. (switches): Added initializers for new members. (decode_switches): Rewritten to use getopt_long. * compatMakefile (GETOPT, GETOPT_SRC): Define. (objs, srcs): Include them. * job.c (child_died): Renamed to dead_children; made static. (child_handler): Increment dead_children instead of setting child_died. (reap_children): Decrement dead_children instead of clearing child_died. The point of all this is to avoid printing "waiting for unfinished jobs" when we don't actually need to block. This happened when multiple SIGCHLDs before reap_children was called. * job.c (reap_children): If ERR is set, so we don't call start_job on the child being reaped, instead set its command_state to cs_finished. (reap_children, child_handler, new_job): I added several debugging printf's while fixing this. I left them in if (debug_flag) because they may be useful for debugging this stuff again. Wed May 6 22:02:37 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) * read.c (read_makefile): v_export is not 1. Mon May 4 17:27:37 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.62.9. * variable.c (export_all_variables): New variable. (target_environment): Export variables whose `export' member is v_default if export_all_variables is set and their names are benign. * variable.h: Declare export_all_variables. * read.c (read_makefile): If export or unexport is given with no args, set or clear export_all_variables, respectively. * variable.c (target_environment): Exclude MAKELEVEL in the loop, so it isn't duplicated when we add it at the end. Sun May 3 17:44:48 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * Version 3.62.8. * variable.h (struct variable): Added new member `export'. * variable.c (define_variable_in_set): Initialize it to v_default. (target_environment): Don't check for .NOEXPORT. Export variables whose `export' member is v_default and that would have been exported under .NOEXPORT, and variables whose `export' member is v_export. (try_variable_definition): Return the variable defined. * variable.h (try_variable_definition): Changed decl. * read.c (read_makefile): Recognize `export' and `unexport' directives. Fri May 1 11:39:38 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) * main.c (main) [POSIX]: Reversed args to sigaddset. Thu Apr 30 17:33:32 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * job.c [POSIX || !USG] (unblock_sigs): New fn. (start_job): Block signals before forking. (new_job): Unblock signals after putting the new child on the chain. * main.c (main) [POSIX]: Use sigset_t fatal_signal_set instead of int fatal_signal_mask. * load.c [sgi] (LDAV_CVT): Define. Wed Apr 29 17:15:59 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) * Version 3.62.7. * load.c (load_average) [sgi]: Clear the high bit of the address from the symbol table before looking it up in kmem. * misc.c (fatal, makefile_fatal): Put *** in fatal error messages. (remake_file): No longer needed in message here. * main.c (die): Call reap_children with BLOCK==1. Tue Apr 28 20:44:35 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) * rule.c (freerule): Don't set LASTRULE->next if LASTRULE is nil. Sun Apr 26 15:09:51 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) * rule.c (count_implicit_rule_limits): Initialize LASTRULE to nil, not to head of chain. Extract next ptr before we might do freerule, and use that for next iteration. (freerule): Still do next ptr frobbing if LASTRULE is nil. Tue Apr 21 03:16:29 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * job.c (child_error): Removed extra %s from error msg format. * Version 3.62.6. * job.c (reap_children): Don't start later commands in a sequence if ERR is nonzero. * job.c (new_job): Always call reap_children with BLOCK==0 first thing. * job.c (reap_children): New function; work that used to be done in child_handler. (child_died): New global var. (child_handler): Now just sets child_died. (wait_for_children): Removed. (unknown_children_possible, block_signals, unblock_signals, push_signals_blocked_p, pop_signals_blocked_p): Removed. (child_execute_job): Removed call to unblock_signals. (new_job): Removed calls to push_signals_blocked_p and pop_signals_blocked_p. * job.h: Declare reap_children, not wait_for_children. * commands.c (fatal_error_signal), job.c (new_job), load.c [LDAV_BASED] (wait_to_start_job), main.c (die), remake.c (update_goal_chain), function.c (expand_function: `shell'): Changed wait_for_children calls to reap_children. Some needed to be loops to wait for all children to die. * commands.c (fatal_error_signal), main.c (main, log_working_directory), function.c (expand_function): Removed calls to push_signals_blocked_p and pop_signals_blocked_p. * job.h: Removed decls. * job.h: Added copyright notice. Wed Apr 15 02:02:40 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * job.c (child_error): No *** for ignored error. Tue Apr 14 18:31:21 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * implicit.c (DEBUGP2): Use do ... while (0) instead of if ... else to avoid compiler warnings. * read.c (parse_file_seq): Don't remove ./ when it is followed by a blank. Mon Apr 13 21:56:15 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * make.h (DEBUGPR): Use do ... while (0) instead of if ... else to avoid compiler warnings. * remake.c (notice_finished_file): Run file_mtime on the also_make files, so vpath_search can happen. * GNUmakefile (tests): Use perl test suite from csa@sw.stratus.com. (alpha-files): Include test suite tar file. Fri Apr 3 00:50:13 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * Version 3.62.5. Wed Apr 1 05:31:18 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * remake.c (update_file, update_file_1): Do check_renamed on elts of dep chains when traversing them. Something unrelated might have renamed one of the files the dep chain points to. * file.c (rename_file): If FILE has been renamed, follow its `renamed' ptr, so we get to the final real FILE. Using the renamed ones loses because they are not in the hash table, so the removal code loops infinitely. * read.c (read_all_makefiles): Clobber null terminator into MAKEFILES expansion, so string passed to read_makefile is properly terminated. Mon Mar 30 20:18:02 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * commands.c (set_file_variables): $* for archive member with explicit cmds is stem of member, not of whole `lib(member)'. Thu Mar 26 15:24:38 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) * Version 3.62.4. Tue Mar 24 05:20:51 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * rule.c (new_pattern_rule): Rules are identical only if all their targets match (regardless of order). Wed Mar 11 13:49:54 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) * remake.c (remake_file): Changed error "no way to make" to "no rule to make". Fiat Hugh. * make.texinfo (Last Resort): Describe %:: rules and new .DEFAULT behavior. * remake.c (update_file_1): Only use .DEFAULT cmds if FILE is not a target. Tue Mar 10 18:13:13 1992 Roland McGrath (roland@wookumz.gnu.ai.mit.edu) * remote-stub.c, remote-cstms.c (start_remote_job): Take new arg, environment to pass to child. * job.c (start_job): Pass it. Mon Mar 9 19:00:11 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * file.c (enter_file): Also strip ./s here, to get command-line target names. * remote-cstms.c: Add comment telling people to leave me alone. * compatMakefile (manpage install): Remove target before copying. Tue Mar 3 18:43:21 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * make.texinfo (Missing): Renamed to "Incompatibilities and ...". Added paragraph describing $? incompatibility with Unix and POSIX.2. Sun Mar 1 15:50:54 1992 Roland McGrath (roland@nutrimat.gnu.ai.mit.edu) * function.c (expand_function: `shell'): Don't declare fork or pipe. Use vfork instead of fork. Tue Feb 25 22:05:32 1992 Roland McGrath (roland@wookumz.gnu.ai.mit.edu) * make.texinfo (Chained Rules): Clarify .PRECIOUS to save intermediate files. * load.c [sun] (LDAV_CVT): Define to divide by FSCALE. Sun Feb 16 02:05:16 1992 Roland McGrath (roland@wookumz.gnu.ai.mit.edu) * Version 3.62.3. Sat Feb 15 17:12:20 1992 Roland McGrath (roland@wookumz.gnu.ai.mit.edu) * compatMakefile (makeinfo): Use emacs batch-texinfo-format fn. Fri Feb 14 00:11:55 1992 Roland McGrath (roland@wookumz.gnu.ai.mit.edu) * read.c (read_makefile): Correctly handle define & endef in ifdefs. * read.c (record_files): Pass arg for %s in error msg. * main.c (main) [__IBMR2, POSIX]: Use correct (a la USGr3) setvbuf call. Wed Feb 12 12:07:39 1992 Roland McGrath (roland@wookumz.gnu.ai.mit.edu) * make.texinfo (Libraries/Search): Say it does /usr/local/lib too. Sun Feb 9 23:06:24 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * read.c (read_makefile): Check for extraneous `endef' when ignoring. Thu Feb 6 16:15:48 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * Version 3.62.2. Tue Feb 4 20:04:46 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * job.c (construct_command_argv_internal): Correctly ignore whitespace after backslash-NL. Fri Jan 31 18:30:05 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * compatMakefile: Ignore errors from chgrp and chmod when installing. Wed Jan 29 18:13:30 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) * main.c (main): When setting MAKELEVEL in the env to re-exec, allocate space so as not to clobber past the end of the old string. * make.h [HAVE_ALLOCA_H]: Include * compatMakefile (defines): Document HAVE_ALLOCA_H. Mon Jan 20 13:40:05 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) * make.h [VFORK_MISSING]: Use fork instead. * compatMakefile (defines): Document same. * job.c (construct_command_argv_internal): Don't create an empty arg if backslash-NL is at beginning of word. Sun Jan 19 16:26:53 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) * main.c [DGUX]: Call setvbuf as for USGr3. * job.c (construct_command_argv_internal): Notice correctly that backslash-NL is the end of the arg (because it is replaced with a space). Thu Jan 16 18:42:38 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) * job.c (construct_command_argv_internal): If SHELL is nil, set it to default_shell before proceeding. * make.h [sgi]: No alloca.h, after all. Wed Jan 15 12:30:04 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) * read.c (multi_glob): Cons up the chain of the results of glob from back to front, so it comes out in forward order. * job.c (construct_command_argv_internal): Don't eat char following backslash-NL. Mon Jan 13 19:16:56 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) * Version 3.62.1. * default.c (default_variables) [ultrix]: GET=get, like USG. * job.c (construct_command_argv_internal): Remove tabs following backslash-NL combos in the input line, so they don't show up when that line is printed. * read.c (read_makefile): Don't collapse_continuations the line on input; do it on the copy we do remove_comments on. For rule lines, collapse_continuations the line after chopping ";cmds" off the end, so we don't eat conts in the cmds. Give error for ";cmds" with no rule. * job.c (construct_command_argv_internal): Eat backslash-NL combos when constructing the line to recurse on for slow, too. Sat Jan 11 02:20:27 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) * file.c (enter_file): Don't strip leading `./'s. * read.c (parse_file_seq): Take new arg STRIP; if nonzero, do it here. * default.c (set_default_suffixes), function.c (string_glob), read.c (read_makefile), rule.c (install_pattern_rule): Change callers. * default.c (default_variables) [_IBMR2]: FC=xlf * job.c (construct_command_argv_internal): Turn backslash-NL and following whitespace into a single space, rather than just eating the backslash. * make.texinfo (Copying): @include gpl.texinfo, rather than duplicating its contents. Fri Nov 8 20:06:03 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * job.c (construct_command_argv_internal): Make sure not to bother processing an empty line. * Version 3.62.0. * job.c (construct_command_argv_internal): Always recurse for slow; simple case didn't handle finding newlines. Tue Nov 5 18:51:10 1991 Roland McGrath (roland@wookumz.gnu.ai.mit.edu) * job.c (construct_command_argv_internal): Set RESTP properly when slow; don't \ify past a newline. Fri Nov 1 19:34:28 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) * make.h [sgi]: #include . See ChangeLog.1, available in the Git repository at: http://git.savannah.gnu.org/cgit/make.git/tree/ for earlier changes. Copyright (C) 1991-2007 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make 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 . kbuild-3149/src/kmk/amiga.c0000644000175000017500000000550313252530177015507 0ustar locutuslocutus/* Running commands on Amiga Copyright (C) 1995-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" #include "variable.h" #include "amiga.h" #include #include #include #include #include static const char Amiga_version[] = "$VER: Make 3.74.3 (12.05.96) \n" "Amiga Port by A. Digulla (digulla@home.lake.de)"; int MyExecute (char **argv) { char * buffer, * ptr; char ** aptr; int len = 0; int status; for (aptr=argv; *aptr; aptr++) { len += strlen (*aptr) + 4; } buffer = AllocMem (len, MEMF_ANY); if (!buffer) O (fatal, NILF, "MyExecute: Cannot allocate space for calling a command\n"); ptr = buffer; for (aptr=argv; *aptr; aptr++) { if (((*aptr)[0] == ';' && !(*aptr)[1])) { *ptr ++ = '"'; strcpy (ptr, *aptr); ptr += strlen (ptr); *ptr ++ = '"'; } else if ((*aptr)[0] == '@' && (*aptr)[1] == '@' && !(*aptr)[2]) { *ptr ++ = '\n'; continue; } else { strcpy (ptr, *aptr); ptr += strlen (ptr); } *ptr ++ = ' '; *ptr = 0; } ptr[-1] = '\n'; status = SystemTags (buffer, SYS_UserShell, TRUE, TAG_END); FreeMem (buffer, len); if (SetSignal (0L,0L) & SIGBREAKF_CTRL_C) status = 20; /* Warnings don't count */ if (status == 5) status = 0; return status; } char * wildcard_expansion (char *wc, char *o) { # define PATH_SIZE 1024 struct AnchorPath * apath; if ( (apath = AllocMem (sizeof (struct AnchorPath) + PATH_SIZE, MEMF_CLEAR)) ) { apath->ap_Strlen = PATH_SIZE; if (MatchFirst (wc, apath) == 0) { do { o = variable_buffer_output (o, apath->ap_Buf, strlen (apath->ap_Buf)); o = variable_buffer_output (o, " ",1); } while (MatchNext (apath) == 0); } MatchEnd (apath); FreeMem (apath, sizeof (struct AnchorPath) + PATH_SIZE); } return o; } kbuild-3149/src/kmk/COPYING0000644000175000017500000010451313252530204015310 0ustar locutuslocutus GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . kbuild-3149/src/kmk/tests/0000755000175000017500000000000013252530202015411 5ustar locutuslocutuskbuild-3149/src/kmk/tests/NEWS0000644000175000017500000001515513252530201016116 0ustar locutuslocutusChanges from 0.4.9 to 3.78 (Sep 6, 1999): Lots of new tests. Renamed to follow the GNU make scheme. Also added some support for using Purify with make. Rob Tulloh contributed some changes to get the test suite running on NT; I tweaked them a bit (hopefully I didn't break anything!) Note that NT doesn't grok the self-exec funkiness that Unix shells use, so instead I broke that out into a separate shell script "run_make_tests" that invokes perl with the (renamed) script run_make_tests.pl. Eli Zaretski contributed changes to get the test suite running on DOS with DJGPP. I also meddled in these somewhat. If you're on DOS or NT you should run "perl.exe run_make_tests.pl ..." If you're on Unix, you can continue to run "./run_make_tests ..." as before. Changes from 0.4.8 to 0.4.9 (May 14, 1998): Release by Paul D. Smith ; I'm the one to blame for problems in this version :). Add some perl to test_driver.pl to strip out GNU make clock skew warning messages from the output before comparing it to the known-good output. A new test for escaped :'s in filenames (someone on VMS found this didn't work anymore in 3.77): scripts/features/escape. Changes from 0.4.7 to 0.4.8 (May 14, 1998): Release by Paul D. Smith ; I'm the one to blame for problems in this version :). New tests for features to be included in GNU make 3.77. Changes from 0.4.6 to 0.4.7 (August 18, 1997): Release by Paul D. Smith ; I'm the one to blame for problems in this version :). Reworked some tests to make sure they all work with both perl4 and perl5. Work around a bug in perl 5.004 which doesn't clean the environment correctly in all cases (fixed in at least 5.004_02). Updated functions/strip to test for newline stripping. Keep a $PURIFYOPTIONS env variable if present. Changes from 0.4.5 to 0.4.6 (April 07, 1997): Release by Paul D. Smith ; I'm the one to blame for problems in this version :). Updated to work with GNU make 3.76 (and pretests). Added new tests and updated existing ones. Note that the new tests weren't tested with perl 4, however I think they should work. Ignore any tests whose filenames end in "~", so that Emacs backup files aren't run. Changes from 0.4.4 to 0.4.5 (April 29, 1995): Updated to be compatible with perl 5.001 as well as 4.036. Note: the test suite still won't work on 14-char filesystems (sorry, Kaveh), but I will get to it. Also, some tests and stuff still haven't made it in because I haven't had time to write the test scripts for them. But they, too, will get in eventually. Contributions of scripts (i.e., tests that I can just drop in) are particularly welcome and will be incorporated immediately. Changes from 0.4.3 to 0.4.4 (March 1995): Updated for changes in make 3.72.12, and to ignore CVS directories (thanks go to Jim Meyering for the patches for this). Fixed uname call to not make a mess on BSD/OS 2.0 (whose uname -a is very verbose). Let me know if this doesn't work correctly on your system. Changed to display test name while it is running, not just when it finishes. Note: the test suite still won't work on 14-char filesystems (sorry, Kaveh), but I will get to it. Also, some tests and stuff still haven't made it in because I haven't had time to write the test scripts for them. But they, too, will get in eventually. Changes from 0.4 to 0.4.3 (October 1994): Fixed bugs (like dependencies on environment variables). Caught up with changes in make. The load_limit test should now silently ignore a failure due to make not being able to read /dev/kmem. Reorganized tests into subdirs and renamed lots of things so that those poor souls who still have to deal with 14-char filename limits won't hate me any more. Thanks very much to Kaveh R. Ghazi for helping me with the implementation and testing of these changes, and for putting up with all my whining about it... Added a $| = 1 so that systems that don't seem to automatically flush their output for some reason will still print all the output. I'd hate for someone to miss out on the smiley that you're supposed to get when all the tests pass... :-) Changes from 0.3 to 0.4 (August 1993): Lost in the mists of time (and my hurry to get it out before I left my job). Changes from 0.2 to 0.3 (9-30-92): Several tests fixed to match the fact that MAKELEVEL > 0 or -C now imply -w. parallel_execution test fixed to not use double colon rules any more since their behavior has changed. errors_in_commands test fixed to handle different error messages and return codes from rm. Several tests fixed to handle -make_path with a relative path and/or a name other than "make" for make. dash-e-option test fixed to use $PATH instead of $USER (since the latter does not exist on some System V systems). This also removes the dependency on getlogin (which fails under certain weird conditions). test_driver_core changed so that you can give a test name like scripts/errors_in_commands and it will be handled correctly (handy if you have a shell with filename completion). Changes from 0.1 to 0.2 (5-4-92): README corrected to require perl 4.019, not 4.010. -make_path replaces -old. errors_in_commands test updated for change in format introduced in make 3.62.6. test_driver_core now uses a better way of figuring what OS it is running on (thanks to meyering@cs.utexas.edu (Jim Meyering) for suggesting this, as well as discovering the hard way that the old way (testing for /mnt) fails on his machine). Some new tests were added. ------------------------------------------------------------------------------- Copyright (C) 1992-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make 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 . kbuild-3149/src/kmk/tests/run_make_tests.com0000644000175000017500000002021213252530201021130 0ustar locutuslocutus$! Test_make.com $! $! This is a wrapper for the GNU make perl test programs on VMS. $! $! Parameter "-help" for description on how to use described below. $! $! Copyright (C) 2014-2016 Free Software Foundation, Inc. $! This file is part of GNU Make. $! $! GNU Make 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. $! $! GNU Make 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 . $! $! $! Allow more than 8 paramters with using commas as a delimiter. $! $ params = "''p1',''p2',''p3',''p4',''p5',''p6',''p7',''p8'" $! $ test_flags = ",verbose,detail,keep,usage,help,debug," $ test_flags_len = f$length(test_flags) $ verbose_flag = "" $ detail_flag = "" $ keep_flag = "" $ usage_flag = "" $ help_flag = "" $ debug_flag = "" $! $ ignored_options = "profile,make,srcdir,valgrind,memcheck,massif," $ ignored_option_len = f$length(ignored_options) $! $ testname = "" $ make :== $bin:make.exe" $! $ i = 0 $param_loop: $ param = f$element(i, ",", params) $ i = i + 1 $ if param .eqs. "" then goto param_loop $ if param .eqs. "," then goto param_loop_end $ param_len = f$length(param) $ if f$locate("/", param) .lt. param_len $ then $ if testname .nes. "" $ then $ write sys$output "Only the last test name specified will be run!" $ endif $ testname = param $ goto param_loop $ endif $ lc_param = f$edit(param,"LOWERCASE") - "-" $ if f$locate(",''lc_param',", ignored_options) .lt. ignored_option_len $ then $ write sys$output "parameter ''param' is ignored on VMS for now." $ goto param_loop $ endif $ if f$locate(",''lc_param',", test_flags) .lt. test_flags_len $ then $ 'lc_param'_flag = "-" + lc_param $ goto param_loop $ endif $ write sys$output "parameter ''param' is not known to VMS." $ goto param_loop $! $param_loop_end: $! $no_gnv = 1 $no_perl = 1 $! $! Find GNV 2.1.3 + manditory updates $! If properly updated, the GNV$GNU logical name is present. $! Updated GNV utilities have a gnv$ prefix on them. $ gnv_root = f$trnlnm("GNV$GNU", "LNM$SYSTEM_TABLE") $ if gnv_root .nes. "" $ then $ no_gnv = 0 $ ! Check for update ar utility. $ new_ar = "gnv$gnu:[usr.bin]gnv$ar.exe" $ if f$search(new_ar) .nes. "" $ then $ ! See if a new port of ar exists. $ ar :== $'new_ar' $ else $ ! Fall back to legacy GNV AR wrapper. $ old_ar = "gnv$gnu:[bin]ar.exe" $ if f$search(old_ar) .nes. "" $ then $ ar :== $'old_ar' $ else $ no_gnv = 1 $ endif $ endif $ ! Check for updated bash $ if no_gnv .eq. 0 $ then $ new_bash = "gnv$gnu:[bin]gnv$bash.exe" $ if f$search(new_bash) .nes. "" $ then $ bash :== $'new_bash' $ sh :== $'new_bash' $ else $ no_gnv = 1 $ endif $ endif $ ! Check for updated coreutils $ if no_gnv .eq. 0 $ then $ new_cat = "gnv$gnu:[bin]gnv$cat.exe" $ if f$search(new_cat) .nes. "" $ then $ cat :== $'new_cat' $ cp :== $gnv$gnu:[bin]gnv$cp.exe $ echo :== $gnv$gnu:[bin]gnv$echo.exe $ false :== $gnv$gnu:[bin]gnv$false.exe $ true :== $gnv$gnu:[bin]gnv$true.exe $ touch :== $gnv$gnu:[bin]gnv$touch.exe $ mkdir :== $gnv$gnu:[bin]gnv$mkdir.exe $ rm :== $gnv$gnu:[bin]gnv$rm.exe $ sleep :== $gnv$gnu:[bin]gnv$sleep.exe $ else $ no_gnv = 1 $ endif $ endif $ ! Check for updated diff utility. $ if no_gnv .eq. 0 $ then $ new_diff = "gnv$gnu:[usr.bin]gnv$diff.exe" $ if f$search(new_diff) .nes. "" $ then $ ! See if a new port of diff exists. $ diff :== $'new_diff' $ else $ ! Fall back to legacy GNV diff $ old_diff = "gnv$gnu:[bin]diff.exe" $ if f$search(old_diff) .nes. "" $ then $ diff :== $'old_diff' $ else $ no_gnv = 1 $ endif $ endif $ endif $ endif $! $if no_gnv $then $ write sys$output "Could not find an up to date GNV installed!" $ help_flag = 1 $endif $! $! Find perl 5.18.1 or later. $! $! look in perl_root:[000000]perl_setup.com $ perl_root = f$trnlnm("perl_root") $ ! This works with known perl installed from PCSI kits. $ if perl_root .nes. "" $ then $ perl_ver = f$element(1, ".", perl_root) $ if f$locate("-", perl_ver) .lt. f$length(perl_ver) $ then $ no_perl = 0 $ endif $ endif $ if no_perl $ then $! look for sys$common:[perl-*]perl_setup.com $ perl_setup = f$search("sys$common:[perl-*]perl_setup.com") $ if perl_setup .eqs. "" $ then $ if gnv_root .nes. "" $ then $ gnv_device = f$parse(gnv_root,,,"DEVICE") $ perl_templ = "[vms$common.perl-*]perl_setup.com" $ perl_search = f$parse(perl_templ, gnv_device) $ perl_setup = f$search(perl_search) $ endif $ endif $ if perl_setup .nes. "" $ then $ @'perl_setup' $ no_perl = 0 $ endif $ endif $! $ if no_perl $ then $ write sys$output "Could not find an up to date Perl installed!" $ help_flag = "-help" $ endif $! $! $ if help_flag .nes. "" $ then $ type sys$input $DECK This is a test script wrapper for the run_make_tests.pl script. This wrapper makes sure that the DCL symbols and logical names needed to run the perl script are in place. The test wrapper currently requires that the DCL symbols be global symbols. Those symbols will be left behind after the procedure is run. The PERL_ROOT will be set to a compatible perl if such a perl is found and is not the default PERL_ROOT:. This setting will persist after the test. This wrapper should be run with the default set to the base directory of the make source. The HELP parameter will bring up this text and then run the help script for the Perl wrapper. Not all options for the perl script have been implemented, such as valgrind or specifying the make path or source path. Running the wrapper script requires: Perl 5.18 or later. PCSI kits available from http://sourceforge.net/projects/vmsperlkit/files/ GNV 2.1.3 or later. GNV 3.0.1 has not tested with this script. Bash 4.2.47 or later. Coreutils 8.21 or later. http://sourceforge.net/projects/gnv/files/ Read before installing: http://sourceforge.net/p/gnv/wiki/InstallingGNVPackages/ As updates for other GNV components get posted, those updates should be used. $EOD $ endif $! $ if no_gnv .or. no_perl then exit 44 $! $! $ default = f$environment("DEFAULT") $ default_dev = f$element(0, ":", default) + ":" $ this = f$environment("PROCEDURE") $ on error then goto all_error $ set default 'default_dev''f$parse(this,,,"DIRECTORY")' $! $! Need to make sure that the config-flags.pm exists. $ if f$search("config-flags.pm") .eqs. "" $ then $ @config_flags_pm.com $ endif $ define/user bin 'default_dev'[-],gnv$gnu:[bin] $ define/user decc$filename_unix_noversion enable $ define/user decc$filename_unix_report enable $ define/user decc$readdir_dropdotnotype enable $ flags = "" $ if verbose_flag .nes. "" then flags = verbose_flag $ if detail_flag .nes. "" then flags = flags + " " + detail_flag $ if keep_flag .nes. "" then flags = flags + " " + keep_flag $ if usage_flag .nes. "" then flags = flags + " " + usage_flag $ if help_flag .nes. "" then flags = flags + " " + help_flag $ if debug_flag .nes. "" then flags = flags + " " + debug_flag $ flags = f$edit(flags, "TRIM, COMPRESS") $ if testname .nes. "" $ then $ perl run_make_tests.pl "''testname'" 'flags' $ else $ perl run_make_tests.pl 'flags' $ endif $all_error: $ set default 'default' $! kbuild-3149/src/kmk/tests/COPYING0000644000175000017500000010451313252530202016450 0ustar locutuslocutus GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . kbuild-3149/src/kmk/tests/config_flags_pm.com0000644000175000017500000000325113252530202021227 0ustar locutuslocutus$! $! config_flags_pm.com - Build config-flags.pm on VMS. $! $! Just good enough to run the self tests for now. $! $! Copyright (C) 2014-2016 Free Software Foundation, Inc. $! This file is part of GNU Make. $! $! GNU Make 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. $! $! GNU Make 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 . $! $! $ open/read cfpm_in config-flags.pm.in $! $ outfile = "sys$disk:[]config-flags.pm" $! $ cflags = "/include=([],[.glob]" $! $ create 'outfile' $ open/append cfpm 'outfile' $! $cfpm_read_loop: $ read cfpm_in/end=cfpm_read_loop_end line_in $ line_in_len = f$length(line_in) $ if f$locate("@", line_in) .lt. line_in_len $ then $ part1 = f$element(0, "@", line_in) $ key = f$element(1, "@", line_in) $ part2 = f$element(2, "@", line_in) $ value = "" $ if key .eqs. "CC" then value = "CC" $ if key .eqs. "CPP" then value = "CPP" $ if key .eqs. "CFLAGS" then value = cflags $ if key .eqs. "GUILE_CFLAGS" then value = cflags $ write cfpm part1, value, part2 $ goto cfpm_read_loop $ endif $ write cfpm line_in $ goto cfpm_read_loop $cfpm_read_loop_end: $ close cfpm_in $ close cfpm $! kbuild-3149/src/kmk/tests/test_driver.pl0000644000175000017500000012032113252530202020277 0ustar locutuslocutus#!/usr/bin/perl # -*-perl-*- # # Modification history: # Written 91-12-02 through 92-01-01 by Stephen McGee. # Modified 92-02-11 through 92-02-22 by Chris Arthur to further generalize. # # Copyright (C) 1991-2016 Free Software Foundation, Inc. # This file is part of GNU Make. # # GNU Make 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. # # GNU Make 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 . # Test driver routines used by a number of test suites, including # those for SCS, make, roll_dir, and scan_deps (?). # # this routine controls the whole mess; each test suite sets up a few # variables and then calls &toplevel, which does all the real work. # $Id$ # The number of test categories we've run $categories_run = 0; # The number of test categroies that have passed $categories_passed = 0; # The total number of individual tests that have been run $total_tests_run = 0; # The total number of individual tests that have passed $total_tests_passed = 0; # The number of tests in this category that have been run $tests_run = 0; # The number of tests in this category that have passed $tests_passed = 0; # Yeesh. This whole test environment is such a hack! $test_passed = 1; # Timeout in seconds. If the test takes longer than this we'll fail it. $test_timeout = 5; $test_timeout = 10 if $^O eq 'VMS'; # Path to Perl $perl_name = $^X; # %makeENV is the cleaned-out environment. %makeENV = (); # %extraENV are any extra environment variables the tests might want to set. # These are RESET AFTER EVERY TEST! %extraENV = (); sub vms_get_process_logicals { # Sorry for the long note here, but to keep this test running on # VMS, it is needed to be understood. # # Perl on VMS by default maps the %ENV array to the system wide logical # name table. # # This is a very large dynamically changing table. # On Linux, this would be the equivalent of a table that contained # every mount point, temporary pipe, and symbolic link on every # file system. You normally do not have permission to clear or replace it, # and if you did, the results would be catastrophic. # # On VMS, added/changed %ENV items show up in the process logical # name table. So to track changes, a copy of it needs to be captured. my $raw_output = `show log/process/access_mode=supervisor`; my @raw_output_lines = split('\n',$raw_output); my %log_hash; foreach my $line (@raw_output_lines) { if ($line =~ /^\s+"([A-Za-z\$_]+)"\s+=\s+"(.+)"$/) { $log_hash{$1} = $2; } } return \%log_hash } # %origENV is the caller's original environment if ($^O ne 'VMS') { %origENV = %ENV; } else { my $proc_env = vms_get_process_logicals; %origENV = %{$proc_env}; } sub resetENV { # We used to say "%ENV = ();" but this doesn't work in Perl 5.000 # through Perl 5.004. It was fixed in Perl 5.004_01, but we don't # want to require that here, so just delete each one individually. if ($^O ne 'VMS') { foreach $v (keys %ENV) { delete $ENV{$v}; } %ENV = %makeENV; } else { my $proc_env = vms_get_process_logicals(); my %delta = %{$proc_env}; foreach my $v (keys %delta) { if (exists $origENV{$v}) { if ($origENV{$v} ne $delta{$v}) { $ENV{$v} = $origENV{$v}; } } else { delete $ENV{$v}; } } } foreach $v (keys %extraENV) { $ENV{$v} = $extraENV{$v}; delete $extraENV{$v}; } } sub toplevel { # Pull in benign variables from the user's environment foreach (# UNIX-specific things 'TZ', 'TMPDIR', 'HOME', 'USER', 'LOGNAME', 'PATH', 'LD_LIBRARY_PATH', # Purify things 'PURIFYOPTIONS', # Windows NT-specific stuff 'Path', 'SystemRoot', # DJGPP-specific stuff 'DJDIR', 'DJGPP', 'SHELL', 'COMSPEC', 'HOSTNAME', 'LFN', 'FNCASE', '387', 'EMU387', 'GROUP' ) { $makeENV{$_} = $ENV{$_} if $ENV{$_}; } # Make sure our compares are not foiled by locale differences $makeENV{LC_ALL} = 'C'; # Replace the environment with the new one # %origENV = %ENV unless $^O eq 'VMS'; resetENV(); $| = 1; # unbuffered output $debug = 0; # debug flag $profile = 0; # profiling flag $verbose = 0; # verbose mode flag $detail = 0; # detailed verbosity $keep = 0; # keep temp files around $workdir = "work"; # The directory where the test will start running $scriptdir = "scripts"; # The directory where we find the test scripts $tmpfilesuffix = "t"; # the suffix used on tmpfiles $default_output_stack_level = 0; # used by attach_default_output, etc. $default_input_stack_level = 0; # used by attach_default_input, etc. $cwd = "."; # don't we wish we knew $cwdslash = ""; # $cwd . $pathsep, but "" rather than "./" $is_kmk = 0; # kmk flag. $is_fast = 0; # kmk_fgmake flag. &get_osname; # sets $osname, $vos, $pathsep, $short_filenames, # and $case_insensitive_fs &set_defaults; # suite-defined &parse_command_line (@ARGV); print "OS name = '$osname'\n" if $debug; $workpath = "$cwdslash$workdir"; $scriptpath = "$cwdslash$scriptdir"; &set_more_defaults; # suite-defined &print_banner; if ($osname eq 'VMS' && $cwdslash eq "") { # Porting this script to VMS revealed a small bug in opendir() not # handling search lists correctly when the directory only exists in # one of the logical_devices. Need to find the first directory in # the search list, as that is where things will be written to. my @dirs = split("/", $pwd); my $logical_device = $ENV{$dirs[1]}; if ($logical_device =~ /([A-Za-z0-9_]+):(:?.+:)+/) { # A search list was found. Grab the first logical device # and use it instead of the search list. $dirs[1]=$1; my $lcl_pwd = join('/', @dirs); $workpath = $lcl_pwd . '/' . $workdir } } if (-d $workpath) { print "Clearing $workpath...\n"; &remove_directory_tree("$workpath/") || &error ("Couldn't wipe out $workpath\n"); } else { mkdir ($workpath, 0777) || &error ("Couldn't mkdir $workpath: $!\n"); } if (!-d $scriptpath) { &error ("Failed to find $scriptpath containing perl test scripts.\n"); } if (@TESTS) { print "Making work dirs...\n"; foreach $test (@TESTS) { if ($test =~ /^([^\/]+)\//) { $dir = $1; push (@rmdirs, $dir); -d "$workpath/$dir" || mkdir ("$workpath/$dir", 0777) || &error ("Couldn't mkdir $workpath/$dir: $!\n"); } } } else { print "Finding tests...\n"; opendir (SCRIPTDIR, $scriptpath) || &error ("Couldn't opendir $scriptpath: $!\n"); @dirs = grep (!/^(\..*|CVS|RCS)$/, readdir (SCRIPTDIR) ); closedir (SCRIPTDIR); foreach $dir (@dirs) { next if ($dir =~ /^(\..*|CVS|RCS)$/ || ! -d "$scriptpath/$dir"); push (@rmdirs, $dir); # VMS can have overlayed file systems, so directories may repeat. next if -d "$workpath/$dir"; mkdir ("$workpath/$dir", 0777) || &error ("Couldn't mkdir $workpath/$dir: $!\n"); opendir (SCRIPTDIR, "$scriptpath/$dir") || &error ("Couldn't opendir $scriptpath/$dir: $!\n"); @files = grep (!/^(\..*|CVS|RCS|.*~)$/, readdir (SCRIPTDIR) ); closedir (SCRIPTDIR); foreach $test (@files) { -d $test and next; push (@TESTS, "$dir/$test"); } } } if (@TESTS == 0) { &error ("\nNo tests in $scriptpath, and none were specified.\n"); } print "\n"; run_all_tests(); foreach $dir (@rmdirs) { rmdir ("$workpath/$dir"); } $| = 1; $categories_failed = $categories_run - $categories_passed; $total_tests_failed = $total_tests_run - $total_tests_passed; if ($total_tests_failed) { print "\n$total_tests_failed Test"; print "s" unless $total_tests_failed == 1; print " in $categories_failed Categor"; print ($categories_failed == 1 ? "y" : "ies"); print " Failed (See .$diffext* files in $workdir dir for details) :-(\n\n"; return 0; } else { print "\n$total_tests_passed Test"; print "s" unless $total_tests_passed == 1; print " in $categories_passed Categor"; print ($categories_passed == 1 ? "y" : "ies"); print " Complete ... No Failures :-)\n\n"; return 1; } } sub get_osname { # Set up an initial value. In perl5 we can do it the easy way. $osname = defined($^O) ? $^O : ''; if ($osname eq 'VMS') { $vos = 0; $pathsep = "/"; return; } # Find a path to Perl # See if the filesystem supports long file names with multiple # dots. DOS doesn't. $short_filenames = 0; (open (TOUCHFD, "> fancy.file.name") && close (TOUCHFD)) || ($short_filenames = 1); unlink ("fancy.file.name") || ($short_filenames = 1); if (! $short_filenames) { # Thanks go to meyering@cs.utexas.edu (Jim Meyering) for suggesting a # better way of doing this. (We used to test for existence of a /mnt # dir, but that apparently fails on an SGI Indigo (whatever that is).) # Because perl on VOS translates /'s to >'s, we need to test for # VOSness rather than testing for Unixness (ie, try > instead of /). mkdir (".ostest", 0777) || &error ("Couldn't create .ostest: $!\n", 1); open (TOUCHFD, "> .ostest>ick") && close (TOUCHFD); chdir (".ostest") || &error ("Couldn't chdir to .ostest: $!\n", 1); } if (! $short_filenames && -f "ick") { $osname = "vos"; $vos = 1; $pathsep = ">"; } else { # the following is regrettably knarly, but it seems to be the only way # to not get ugly error messages if uname can't be found. # Hmmm, BSD/OS 2.0's uname -a is excessively verbose. Let's try it # with switches first. eval "chop (\$osname = `sh -c 'uname -nmsr 2>&1'`)"; if ($osname =~ /not found/i) { $osname = "(something posixy with no uname)"; } elsif ($@ ne "" || $?) { eval "chop (\$osname = `sh -c 'uname -a 2>&1'`)"; if ($@ ne "" || $?) { $osname = "(something posixy)"; } } $vos = 0; $pathsep = "/"; } if (! $short_filenames) { chdir ("..") || &error ("Couldn't chdir to ..: $!\n", 1); unlink (".ostest>ick"); rmdir (".ostest") || &error ("Couldn't rmdir .ostest: $!\n", 1); } # Check for case insensitive file system (bird) # The deal is that the 2nd unlink will fail because the first one # will already have removed the file if the fs ignore case. $case_insensitive_fs = 0; my $testfile1 = $short_filenames ? "CaseFs.rmt" : "CaseInSensitiveFs.check"; my $testfile2 = $short_filenames ? "casEfS.rmt" : "casEiNsensitivEfS.Check"; (open (TOUCHFD, "> $testfile1") && close (TOUCHFD)) || &error ("Couldn't create $testfile1: $!\n", 1); (open (TOUCHFD, "> $testfile2") && close (TOUCHFD)) || &error ("Couldn't create $testfile2: $!\n", 1); unlink ($testfile1) || &error ("Couldn't unlink $testfile1: $!\n", 1); unlink ($testfile2) || ($case_insensitive_fs = 1); } sub parse_command_line { @argv = @_; # use @ARGV if no args were passed in if (@argv == 0) { @argv = @ARGV; } # look at each option; if we don't recognize it, maybe the suite-specific # command line parsing code will... while (@argv) { $option = shift @argv; if ($option =~ /^-debug$/i) { print "\nDEBUG ON\n"; $debug = 1; } elsif ($option =~ /^-usage$/i) { &print_usage; exit 0; } elsif ($option =~ /^-(h|help)$/i) { &print_help; exit 0; } elsif ($option =~ /^-profile$/i) { $profile = 1; } elsif ($option =~ /^-verbose$/i) { $verbose = 1; } elsif ($option =~ /^-detail$/i) { $detail = 1; $verbose = 1; } elsif ($option =~ /^-keep$/i) { $keep = 1; } elsif ($option =~ /^-kmk/i) { $is_kmk = 1; } elsif ($option =~ /^-fast/i) { $is_fast = 1; } elsif (&valid_option($option)) { # The suite-defined subroutine takes care of the option } elsif ($option =~ /^-/) { print "Invalid option: $option\n"; &print_usage; exit 0; } else # must be the name of a test { $option =~ s/\.pl$//; push(@TESTS,$option); } } } sub max { local($num) = shift @_; local($newnum); while (@_) { $newnum = shift @_; if ($newnum > $num) { $num = $newnum; } } return $num; } sub print_centered { local($width, $string) = @_; local($pad); if (length ($string)) { $pad = " " x ( ($width - length ($string) + 1) / 2); print "$pad$string"; } } sub print_banner { local($info); local($line); local($len); $info = "Running tests for $testee on $osname\n"; # $testee is suite-defined $len = &max (length ($line), length ($testee_version), length ($banner_info), 73) + 5; $line = ("-" x $len) . "\n"; if ($len < 78) { $len = 78; } &print_centered ($len, $line); &print_centered ($len, $info); &print_centered ($len, $testee_version); # suite-defined &print_centered ($len, $banner_info); # suite-defined &print_centered ($len, $line); print "\n"; } sub run_all_tests { $categories_run = 0; $lasttest = ''; foreach $testname (sort @TESTS) { # Skip duplicates on VMS caused by logical name search lists. next if $testname eq $lasttest; $lasttest = $testname; $suite_passed = 1; # reset by test on failure $num_of_logfiles = 0; $num_of_tmpfiles = 0; $description = ""; $details = ""; $old_makefile = undef; $testname =~ s/^$scriptpath$pathsep//; $perl_testname = "$scriptpath$pathsep$testname"; $testname =~ s/(\.pl|\.perl)$//; $testpath = "$workpath$pathsep$testname"; # Leave enough space in the extensions to append a number, even # though it needs to fit into 8+3 limits. if ($short_filenames) { $logext = 'l'; $diffext = 'd'; $baseext = 'b'; $runext = 'r'; $extext = ''; } else { $logext = 'log'; $diffext = 'diff'; $baseext = 'base'; $runext = 'run'; $extext = '.'; } $extext = '_' if $^O eq 'VMS'; $log_filename = "$testpath.$logext"; $diff_filename = "$testpath.$diffext"; $base_filename = "$testpath.$baseext"; $run_filename = "$testpath.$runext"; $tmp_filename = "$testpath.$tmpfilesuffix"; setup_for_test(); $output = "........................................................ "; substr($output,0,length($testname)) = "$testname "; print $output; $tests_run = 0; $tests_passed = 0; # Run the test! $code = do $perl_testname; ++$categories_run; $total_tests_run += $tests_run; $total_tests_passed += $tests_passed; # How did it go? if (!defined($code)) { # Failed to parse or called die if (length ($@)) { warn "\n*** Test died ($testname): $@\n"; } else { warn "\n*** Couldn't parse $perl_testname\n"; } $status = "FAILED ($tests_passed/$tests_run passed)"; } elsif ($code == -1) { # Skipped... not supported $status = "N/A"; --$categories_run; } elsif ($code != 1) { # Bad result... this shouldn't really happen. Usually means that # the suite forgot to end with "1;". warn "\n*** Test returned $code\n"; $status = "FAILED ($tests_passed/$tests_run passed)"; } elsif ($tests_run == 0) { # Nothing was done!! $status = "FAILED (no tests found!)"; } elsif ($tests_run > $tests_passed) { # Lose! $status = "FAILED ($tests_passed/$tests_run passed)"; } else { # Win! ++$categories_passed; $status = "ok ($tests_passed passed)"; # Clean up for ($i = $num_of_tmpfiles; $i; $i--) { rmfiles($tmp_filename . num_suffix($i)); } for ($i = $num_of_logfiles ? $num_of_logfiles : 1; $i; $i--) { rmfiles($log_filename . num_suffix($i)); rmfiles($base_filename . num_suffix($i)); } } # If the verbose option has been specified, then a short description # of each test is printed before displaying the results of each test # describing WHAT is being tested. if ($verbose) { if ($detail) { print "\nWHAT IS BEING TESTED\n"; print "--------------------"; } print "\n\n$description\n\n"; } # If the detail option has been specified, then the details of HOW # the test is testing what it says it is testing in the verbose output # will be displayed here before the results of the test are displayed. if ($detail) { print "\nHOW IT IS TESTED\n"; print "----------------"; print "\n\n$details\n\n"; } print "$status\n"; } } # If the keep flag is not set, this subroutine deletes all filenames that # are sent to it. sub rmfiles { local(@files) = @_; if (!$keep) { return (unlink @files); } return 1; } sub print_standard_usage { local($plname,@moreusage) = @_; local($line); print "usage:\t$plname [testname] [-verbose] [-detail] [-keep]\n"; print "\t\t\t[-profile] [-usage] [-help] [-debug]\n"; foreach (@moreusage) { print "\t\t\t$_\n"; } } sub print_standard_help { local(@morehelp) = @_; local($line); local($tline); local($t) = " "; $line = "Test Driver For $testee"; print "$line\n"; $line = "=" x length ($line); print "$line\n"; &print_usage; print "\ntestname\n" . "${t}You may, if you wish, run only ONE test if you know the name\n" . "${t}of that test and specify this name anywhere on the command\n" . "${t}line. Otherwise ALL existing tests in the scripts directory\n" . "${t}will be run.\n" . "-verbose\n" . "${t}If this option is given, a description of every test is\n" . "${t}displayed before the test is run. (Not all tests may have\n" . "${t}descriptions at this time)\n" . "-detail\n" . "${t}If this option is given, a detailed description of every\n" . "${t}test is displayed before the test is run. (Not all tests\n" . "${t}have descriptions at this time)\n" . "-profile\n" . "${t}If this option is given, then the profile file\n" . "${t}is added to other profiles every time $testee is run.\n" . "${t}This option only works on VOS at this time.\n" . "-keep\n" . "${t}You may give this option if you DO NOT want ANY\n" . "${t}of the files generated by the tests to be deleted. \n" . "${t}Without this option, all files generated by the test will\n" . "${t}be deleted IF THE TEST PASSES.\n" . "-debug\n" . "${t}Use this option if you would like to see all of the system\n" . "${t}calls issued and their return status while running the tests\n" . "${t}This can be helpful if you're having a problem adding a test\n" . "${t}to the suite, or if the test fails!\n"; foreach $line (@morehelp) { $tline = $line; if (substr ($tline, 0, 1) eq "\t") { substr ($tline, 0, 1) = $t; } print "$tline\n"; } } ####################################################################### ########### Generic Test Driver Subroutines ########### ####################################################################### sub get_caller { local($depth); local($package); local($filename); local($linenum); $depth = defined ($_[0]) ? $_[0] : 1; ($package, $filename, $linenum) = caller ($depth + 1); return "$filename: $linenum"; } sub error { local($message) = $_[0]; local($caller) = &get_caller (1); if (defined ($_[1])) { $caller = &get_caller ($_[1] + 1) . " -> $caller"; } die "$caller: $message"; } sub compare_output { local($answer,$logfile) = @_; local($slurp, $answer_matched) = ('', 0); ++$tests_run; if (! defined $answer) { print "Ignoring output ........ " if $debug; $answer_matched = 1; } else { print "Comparing Output ........ " if $debug; $slurp = &read_file_into_string ($logfile); # For make, get rid of any time skew error before comparing--too bad this # has to go into the "generic" driver code :-/ $slurp =~ s/^.*modification time .*in the future.*\n//gm; $slurp =~ s/^.*Clock skew detected.*\n//gm; if ($slurp eq $answer) { $answer_matched = 1; } else { # See if it is a slash or CRLF problem local ($answer_mod, $slurp_mod) = ($answer, $slurp); $answer_mod =~ tr,\\,/,; $answer_mod =~ s,\r\n,\n,gs; $slurp_mod =~ tr,\\,/,; $slurp_mod =~ s,\r\n,\n,gs; $answer_matched = ($slurp_mod eq $answer_mod); if ($^O eq 'VMS') { # VMS has extra blank lines in output sometimes. # Ticket #41760 if (!$answer_matched) { $slurp_mod =~ s/\n\n+/\n/gm; $slurp_mod =~ s/\A\n+//g; $answer_matched = ($slurp_mod eq $answer_mod); } # VMS adding a "Waiting for unfinished jobs..." # Remove it for now to see what else is going on. if (!$answer_matched) { $slurp_mod =~ s/^.+\*\*\* Waiting for unfinished jobs.+$//m; $slurp_mod =~ s/\n\n/\n/gm; $slurp_mod =~ s/^\n+//gm; $answer_matched = ($slurp_mod eq $answer_mod); } # VMS wants target device to exist or generates an error, # Some test tagets look like VMS devices and trip this. if (!$answer_matched) { $slurp_mod =~ s/^.+\: no such device or address.*$//gim; $slurp_mod =~ s/\n\n/\n/gm; $slurp_mod =~ s/^\n+//gm; $answer_matched = ($slurp_mod eq $answer_mod); } # VMS error message has a different case if (!$answer_matched) { $slurp_mod =~ s/no such file /No such file /gm; $answer_matched = ($slurp_mod eq $answer_mod); } # VMS is putting comas instead of spaces in output if (!$answer_matched) { $slurp_mod =~ s/,/ /gm; $answer_matched = ($slurp_mod eq $answer_mod); } # VMS Is sometimes adding extra leading spaces to output? if (!$answer_matched) { my $slurp_mod = $slurp_mod; $slurp_mod =~ s/^ +//gm; $answer_matched = ($slurp_mod eq $answer_mod); } # VMS port not handling POSIX encoded child status # Translate error case it for now. if (!$answer_matched) { $slurp_mod =~ s/0x1035a00a/1/gim; $answer_matched = 1 if $slurp_mod =~ /\Q$answer_mod\E/i; } if (!$answer_matched) { $slurp_mod =~ s/0x1035a012/2/gim; $answer_matched = ($slurp_mod eq $answer_mod); } # Tests are using a UNIX null command, temp hack # until this can be handled by the VMS port. # ticket # 41761 if (!$answer_matched) { $slurp_mod =~ s/^.+DCL-W-NOCOMD.*$//gim; $slurp_mod =~ s/\n\n+/\n/gm; $slurp_mod =~ s/^\n+//gm; $answer_matched = ($slurp_mod eq $answer_mod); } # Tests are using exit 0; # this generates a warning that should stop the make, but does not if (!$answer_matched) { $slurp_mod =~ s/^.+NONAME-W-NOMSG.*$//gim; $slurp_mod =~ s/\n\n+/\n/gm; $slurp_mod =~ s/^\n+//gm; $answer_matched = ($slurp_mod eq $answer_mod); } # VMS is sometimes adding single quotes to output? if (!$answer_matched) { my $noq_slurp_mod = $slurp_mod; $noq_slurp_mod =~ s/\'//gm; $answer_matched = ($noq_slurp_mod eq $answer_mod); # And missing an extra space in output if (!$answer_matched) { $noq_answer_mod = $answer_mod; $noq_answer_mod =~ s/\h\h+/ /gm; $answer_matched = ($noq_slurp_mod eq $noq_answer_mod); } # VMS adding ; to end of some lines. if (!$answer_matched) { $noq_slurp_mod =~ s/;\n/\n/gm; $answer_matched = ($noq_slurp_mod eq $noq_answer_mod); } # VMS adding trailing space to end of some quoted lines. if (!$answer_matched) { $noq_slurp_mod =~ s/\h+\n/\n/gm; $answer_matched = ($noq_slurp_mod eq $noq_answer_mod); } # And VMS missing leading blank line if (!$answer_matched) { $noq_answer_mod =~ s/\A\n//g; $answer_matched = ($noq_slurp_mod eq $noq_answer_mod); } # Unix double quotes showing up as single quotes on VMS. if (!$answer_matched) { $noq_answer_mod =~ s/\"//g; $answer_matched = ($noq_slurp_mod eq $noq_answer_mod); } } } # If it still doesn't match, see if the answer might be a regex. if (!$answer_matched && $answer =~ m,^/(.+)/$,) { $answer_matched = ($slurp =~ /$1/); if (!$answer_matched && $answer_mod =~ m,^/(.+)/$,) { $answer_matched = ($slurp_mod =~ /$1/); } } } } if ($answer_matched && $test_passed) { print "ok\n" if $debug; ++$tests_passed; return 1; } if (! $answer_matched) { print "DIFFERENT OUTPUT\n" if $debug; &create_file (&get_basefile, $answer); &create_file (&get_runfile, $command_string); print "\nCreating Difference File ...\n" if $debug; # Create the difference file local($command) = "diff -c " . &get_basefile . " " . $logfile; &run_command_with_output(&get_difffile,$command); } return 0; } sub read_file_into_string { local($filename) = @_; local($oldslash) = $/; undef $/; open (RFISFILE, $filename) || return ""; local ($slurp) = ; close (RFISFILE); $/ = $oldslash; return $slurp; } my @OUTSTACK = (); my @ERRSTACK = (); sub attach_default_output { local ($filename) = @_; local ($code); if ($vos) { $code = system "++attach_default_output_hack $filename"; $code == -2 || &error ("adoh death\n", 1); return 1; } my $dup = undef; open($dup, '>&', STDOUT) or error("ado: $! duping STDOUT\n", 1); push @OUTSTACK, $dup; $dup = undef; open($dup, '>&', STDERR) or error("ado: $! duping STDERR\n", 1); push @ERRSTACK, $dup; open(STDOUT, '>', $filename) or error("ado: $filename: $!\n", 1); open(STDERR, ">&STDOUT") or error("ado: $filename: $!\n", 1); } # close the current stdout/stderr, and restore the previous ones from # the "stack." sub detach_default_output { local ($code); if ($vos) { $code = system "++detach_default_output_hack"; $code == -2 || &error ("ddoh death\n", 1); return 1; } @OUTSTACK or error("default output stack has flown under!\n", 1); close(STDOUT); close(STDERR) unless $^O eq 'VMS'; open (STDOUT, '>&', pop @OUTSTACK) or error("ddo: $! duping STDOUT\n", 1); open (STDERR, '>&', pop @ERRSTACK) or error("ddo: $! duping STDERR\n", 1); } # This runs a command without any debugging info. sub _run_command { my $code; # We reset this before every invocation. On Windows I think there is only # one environment, not one per process, so I think that variables set in # test scripts might leak into subsequent tests if this isn't reset--??? resetENV(); eval { if ($^O eq 'VMS') { local $SIG{ALRM} = sub { my $e = $ERRSTACK[0]; print $e "\nTest timed out after $test_timeout seconds\n"; die "timeout\n"; }; # alarm $test_timeout; system(@_); my $severity = ${^CHILD_ERROR_NATIVE} & 7; $code = 0; if (($severity & 1) == 0) { $code = 512; } # Get the vms status. my $vms_code = ${^CHILD_ERROR_NATIVE}; # Remove the print status bit $vms_code &= ~0x10000000; # Posix code translation. if (($vms_code & 0xFFFFF000) == 0x35a000) { $code = (($vms_code & 0xFFF) >> 3) * 256; } } else { my $pid = fork(); if (! $pid) { exec(@_) or die "Cannot execute $_[0]\n"; } local $SIG{ALRM} = sub { my $e = $ERRSTACK[0]; print $e "\nTest timed out after $test_timeout seconds\n"; die "timeout\n"; }; alarm $test_timeout; waitpid($pid, 0) > 0 or die "No such pid: $pid\n"; $code = $?; } alarm 0; }; if ($@) { # The eval failed. If it wasn't SIGALRM then die. $@ eq "timeout\n" or die "Command failed: $@"; # Timed out. Resend the alarm to our process group to kill the children. $SIG{ALRM} = 'IGNORE'; kill -14, $$; $code = 14; } return $code; } # run one command (passed as a list of arg 0 - n), returning 0 on success # and nonzero on failure. sub run_command { print "\nrun_command: @_\n" if $debug; my $code = _run_command(@_); print "run_command returned $code.\n" if $debug; print "vms status = ${^CHILD_ERROR_NATIVE}\n" if $debug and $^O eq 'VMS'; return $code; } # run one command (passed as a list of arg 0 - n, with arg 0 being the # second arg to this routine), returning 0 on success and non-zero on failure. # The first arg to this routine is a filename to connect to the stdout # & stderr of the child process. sub run_command_with_output { my $filename = shift; print "\nrun_command_with_output($filename,$runname): @_\n" if $debug; &attach_default_output ($filename); my $code = eval { _run_command(@_) }; my $err = $@; &detach_default_output; $err and die $err; print "run_command_with_output returned $code.\n" if $debug; print "vms status = ${^CHILD_ERROR_NATIVE}\n" if $debug and $^O eq 'VMS'; return $code; } # performs the equivalent of an "rm -rf" on the first argument. Like # rm, if the path ends in /, leaves the (now empty) directory; otherwise # deletes it, too. sub remove_directory_tree { local ($targetdir) = @_; local ($nuketop) = 1; local ($ch); $ch = substr ($targetdir, length ($targetdir) - 1); if ($ch eq "/" || $ch eq $pathsep) { $targetdir = substr ($targetdir, 0, length ($targetdir) - 1); $nuketop = 0; } if (! -e $targetdir) { return 1; } &remove_directory_tree_inner ("RDT00", $targetdir) || return 0; if ($nuketop) { rmdir $targetdir || return 0; } return 1; } sub remove_directory_tree_inner { local ($dirhandle, $targetdir) = @_; local ($object); local ($subdirhandle); opendir ($dirhandle, $targetdir) || return 0; $subdirhandle = $dirhandle; $subdirhandle++; while ($object = readdir ($dirhandle)) { if ($object =~ /^(\.\.?|CVS|RCS)$/) { next; } $object = "$targetdir$pathsep$object"; lstat ($object); if (-d _ && &remove_directory_tree_inner ($subdirhandle, $object)) { rmdir $object || return 0; } else { if ($^O ne 'VMS') { unlink $object || return 0; } else { # VMS can have multiple versions of a file. 1 while unlink $object; } } } closedir ($dirhandle); return 1; } # We used to use this behavior for this function: # #sub touch #{ # local (@filenames) = @_; # local ($now) = time; # local ($file); # # foreach $file (@filenames) # { # utime ($now, $now, $file) # || (open (TOUCHFD, ">> $file") && close (TOUCHFD)) # || &error ("Couldn't touch $file: $!\n", 1); # } # return 1; #} # # But this behaves badly on networked filesystems where the time is # skewed, because it sets the time of the file based on the _local_ # host. Normally when you modify a file, it's the _remote_ host that # determines the modtime, based on _its_ clock. So, instead, now we open # the file and write something into it to force the remote host to set # the modtime correctly according to its clock. # sub touch { local ($file); foreach $file (@_) { (open(T, ">> $file") && print(T "\n") && close(T)) || &error("Couldn't touch $file: $!\n", 1); } } # Touch with a time offset. To DTRT, call touch() then use stat() to get the # access/mod time for each file and apply the offset. sub utouch { local ($off) = shift; local ($file); &touch(@_); local (@s) = stat($_[0]); utime($s[8]+$off, $s[9]+$off, @_); } # open a file, write some stuff to it, and close it. sub create_file { local ($filename, @lines) = @_; open (CF, "> $filename") || &error ("Couldn't open $filename: $!\n", 1); foreach $line (@lines) { print CF $line; } close (CF); } # create a directory tree described by an associative array, wherein each # key is a relative pathname (using slashes) and its associated value is # one of: # DIR indicates a directory # FILE:contents indicates a file, which should contain contents +\n # LINK:target indicates a symlink, pointing to $basedir/target # The first argument is the dir under which the structure will be created # (the dir will be made and/or cleaned if necessary); the second argument # is the associative array. sub create_dir_tree { local ($basedir, %dirtree) = @_; local ($path); &remove_directory_tree ("$basedir"); mkdir ($basedir, 0777) || &error ("Couldn't mkdir $basedir: $!\n", 1); foreach $path (sort keys (%dirtree)) { if ($dirtree {$path} =~ /^DIR$/) { mkdir ("$basedir/$path", 0777) || &error ("Couldn't mkdir $basedir/$path: $!\n", 1); } elsif ($dirtree {$path} =~ /^FILE:(.*)$/) { &create_file ("$basedir/$path", $1 . "\n"); } elsif ($dirtree {$path} =~ /^LINK:(.*)$/) { symlink ("$basedir/$1", "$basedir/$path") || &error ("Couldn't symlink $basedir/$path -> $basedir/$1: $!\n", 1); } else { &error ("Bogus dirtree type: \"$dirtree{$path}\"\n", 1); } } if ($just_setup_tree) { die "Tree is setup...\n"; } } # compare a directory tree with an associative array in the format used # by create_dir_tree, above. # The first argument is the dir under which the structure should be found; # the second argument is the associative array. sub compare_dir_tree { local ($basedir, %dirtree) = @_; local ($path); local ($i); local ($bogus) = 0; local ($contents); local ($target); local ($fulltarget); local ($found); local (@files); local (@allfiles); opendir (DIR, $basedir) || &error ("Couldn't open $basedir: $!\n", 1); @allfiles = grep (!/^(\.\.?|CVS|RCS)$/, readdir (DIR) ); closedir (DIR); if ($debug) { print "dirtree: (%dirtree)\n$basedir: (@allfiles)\n"; } foreach $path (sort keys (%dirtree)) { if ($debug) { print "Checking $path ($dirtree{$path}).\n"; } $found = 0; foreach $i (0 .. $#allfiles) { if ($allfiles[$i] eq $path) { splice (@allfiles, $i, 1); # delete it if ($debug) { print " Zapped $path; files now (@allfiles).\n"; } lstat ("$basedir/$path"); $found = 1; last; } } if (!$found) { print "compare_dir_tree: $path does not exist.\n"; $bogus = 1; next; } if ($dirtree {$path} =~ /^DIR$/) { if (-d _ && opendir (DIR, "$basedir/$path") ) { @files = readdir (DIR); closedir (DIR); @files = grep (!/^(\.\.?|CVS|RCS)$/ && ($_ = "$path/$_"), @files); push (@allfiles, @files); if ($debug) { print " Read in $path; new files (@files).\n"; } } else { print "compare_dir_tree: $path is not a dir.\n"; $bogus = 1; } } elsif ($dirtree {$path} =~ /^FILE:(.*)$/) { if (-l _ || !-f _) { print "compare_dir_tree: $path is not a file.\n"; $bogus = 1; next; } if ($1 ne "*") { $contents = &read_file_into_string ("$basedir/$path"); if ($contents ne "$1\n") { print "compare_dir_tree: $path contains wrong stuff." . " Is:\n$contentsShould be:\n$1\n"; $bogus = 1; } } } elsif ($dirtree {$path} =~ /^LINK:(.*)$/) { $target = $1; if (!-l _) { print "compare_dir_tree: $path is not a link.\n"; $bogus = 1; next; } $contents = readlink ("$basedir/$path"); $contents =~ tr/>/\//; $fulltarget = "$basedir/$target"; $fulltarget =~ tr/>/\//; if (!($contents =~ /$fulltarget$/)) { if ($debug) { $target = $fulltarget; } print "compare_dir_tree: $path should be link to $target, " . "not $contents.\n"; $bogus = 1; } } else { &error ("Bogus dirtree type: \"$dirtree{$path}\"\n", 1); } } if ($debug) { print "leftovers: (@allfiles).\n"; } foreach $file (@allfiles) { print "compare_dir_tree: $file should not exist.\n"; $bogus = 1; } return !$bogus; } # this subroutine generates the numeric suffix used to keep tmp filenames, # log filenames, etc., unique. If the number passed in is 1, then a null # string is returned; otherwise, we return ".n", where n + 1 is the number # we were given. sub num_suffix { local($num) = @_; if (--$num > 0) { return "$extext$num"; } return ""; } # This subroutine returns a log filename with a number appended to # the end corresponding to how many logfiles have been created in the # current running test. An optional parameter may be passed (0 or 1). # If a 1 is passed, then it does NOT increment the logfile counter # and returns the name of the latest logfile. If either no parameter # is passed at all or a 0 is passed, then the logfile counter is # incremented and the new name is returned. sub get_logfile { local($no_increment) = @_; $num_of_logfiles += !$no_increment; return ($log_filename . &num_suffix ($num_of_logfiles)); } # This subroutine returns a base (answer) filename with a number # appended to the end corresponding to how many logfiles (and thus # base files) have been created in the current running test. # NO PARAMETERS ARE PASSED TO THIS SUBROUTINE. sub get_basefile { return ($base_filename . &num_suffix ($num_of_logfiles)); } # This subroutine returns a difference filename with a number appended # to the end corresponding to how many logfiles (and thus diff files) # have been created in the current running test. sub get_difffile { return ($diff_filename . &num_suffix ($num_of_logfiles)); } # This subroutine returns a command filename with a number appended # to the end corresponding to how many logfiles (and thus command files) # have been created in the current running test. sub get_runfile { return ($run_filename . &num_suffix ($num_of_logfiles)); } # just like logfile, only a generic tmp filename for use by the test. # they are automatically cleaned up unless -keep was used, or the test fails. # Pass an argument of 1 to return the same filename as the previous call. sub get_tmpfile { local($no_increment) = @_; $num_of_tmpfiles += !$no_increment; return ($tmp_filename . &num_suffix ($num_of_tmpfiles)); } 1; kbuild-3149/src/kmk/tests/config-flags.pm.in0000644000175000017500000000072613252530201020717 0ustar locutuslocutus# This is a -*-perl-*- script # # Set variables that were defined by configure, in case we need them # during the tests. %CONFIG_FLAGS = ( AM_LDFLAGS => '@AM_LDFLAGS@', AR => '@AR@', CC => '@CC@', CFLAGS => '@CFLAGS@', CPP => '@CPP@', CPPFLAGS => '@CPPFLAGS@', GUILE_CFLAGS => '@GUILE_CFLAGS@', GUILE_LIBS => '@GUILE_LIBS@', LDFLAGS => '@LDFLAGS@', LIBS => '@LIBS@' ); 1; kbuild-3149/src/kmk/tests/.gitignore0000644000175000017500000000002513252530201017375 0ustar locutuslocutusconfig-flags.pm work kbuild-3149/src/kmk/tests/run_make_tests.pl0000755000175000017500000003365713252530202021012 0ustar locutuslocutus#!/usr/bin/env perl # -*-perl-*- # Test driver for the Make test suite # Usage: run_make_tests [testname] # [-debug] # [-help] # [-verbose] # [-keep] # [-make ] # (and others) # Copyright (C) 1992-2016 Free Software Foundation, Inc. # This file is part of GNU Make. # # GNU Make 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. # # GNU Make 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 . %FEATURES = (); $valgrind = 0; # invoke make with valgrind $valgrind_args = ''; $memcheck_args = '--num-callers=15 --tool=memcheck --leak-check=full --suppressions=guile.supp'; $massif_args = '--num-callers=15 --tool=massif --alloc-fn=xmalloc --alloc-fn=xcalloc --alloc-fn=xrealloc --alloc-fn=xstrdup --alloc-fn=xstrndup'; $pure_log = undef; # The location of the GNU make source directory $srcdir = ''; $command_string = ''; $all_tests = 0; # rmdir broken in some Perls on VMS. if ($^O eq 'VMS') { require VMS::Filespec; VMS::Filespec->import(); sub vms_rmdir { my $vms_file = vmspath($_[0]); $vms_file = fileify($vms_file); my $ret = unlink(vmsify($vms_file)); return $ret }; *CORE::GLOBAL::rmdir = \&vms_rmdir; } require "test_driver.pl"; require "config-flags.pm"; # Some target systems might not have the POSIX module... $has_POSIX = eval { require "POSIX.pm" }; #$SIG{INT} = sub { print STDERR "Caught a signal!\n"; die @_; }; sub valid_option { local($option) = @_; if ($option =~ /^-make([-_]?path)?$/i) { $make_path = shift @argv; if (!-f $make_path) { print "$option $make_path: Not found.\n"; exit 0; } return 1; } if ($option =~ /^-srcdir$/i) { $srcdir = shift @argv; if (! -f "$srcdir/gnumake.h") { print "$option $srcdir: Not a valid GNU make source directory.\n"; exit 0; } return 1; } if ($option =~ /^-all([-_]?tests)?$/i) { $all_tests = 1; return 1; } if ($option =~ /^-(valgrind|memcheck)$/i) { $valgrind = 1; $valgrind_args = $memcheck_args; return 1; } if ($option =~ /^-massif$/i) { $valgrind = 1; $valgrind_args = $massif_args; return 1; } # This doesn't work--it _should_! Someone badly needs to fix this. # # elsif ($option =~ /^-work([-_]?dir)?$/) # { # $workdir = shift @argv; # return 1; # } return 0; } # This is an "all-in-one" function. Arguments are as follows: # # [0] (string): The makefile to be tested. undef means use the last one. # [1] (string): Arguments to pass to make. # [2] (string): Answer we should get back. # [3] (integer): Exit code we expect. A missing code means 0 (success) $old_makefile = undef; sub subst_make_string { local $_ = shift; $makefile and s/#MAKEFILE#/$makefile/g; s/#MAKEPATH#/$mkpath/g; s/#MAKE#/$make_name/g; s/#PERL#/$perl_name/g; s/#PWD#/$pwd/g; return $_; } sub run_make_test { local ($makestring, $options, $answer, $err_code, $timeout) = @_; my @call = caller; # If the user specified a makefile string, create a new makefile to contain # it. If the first value is not defined, use the last one (if there is # one). if (! defined $makestring) { defined $old_makefile || die "run_make_test(undef) invoked before run_make_test('...')\n"; $makefile = $old_makefile; } else { if (! defined($makefile)) { $makefile = &get_tmpfile(); } # Make sure it ends in a newline and substitute any special tokens. $makestring && $makestring !~ /\n$/s and $makestring .= "\n"; $makestring = subst_make_string($makestring); # Populate the makefile! open(MAKEFILE, "> $makefile") || die "Failed to open $makefile: $!\n"; print MAKEFILE $makestring; close(MAKEFILE) || die "Failed to write $makefile: $!\n"; } # Do the same processing on $answer as we did on $makestring. if (defined $answer) { $answer && $answer !~ /\n$/s and $answer .= "\n"; $answer = subst_make_string($answer); } run_make_with_options($makefile, $options, &get_logfile(0), $err_code, $timeout, @call); &compare_output($answer, &get_logfile(1)); $old_makefile = $makefile; $makefile = undef; } # The old-fashioned way... sub run_make_with_options { my ($filename,$options,$logname,$expected_code,$timeout,@call) = @_; @call = caller unless @call; local($code); local($command) = $make_path; $expected_code = 0 unless defined($expected_code); # Reset to reflect this one test. $test_passed = 1; if ($filename) { $command .= " -f $filename"; } if ($options) { if ($^O eq 'VMS') { # Try to make sure arguments are properly quoted. # This does not handle all cases. # VMS uses double quotes instead of single quotes. $options =~ s/\'/\"/g; # If the leading quote is inside non-whitespace, then the # quote must be doubled, because it will be enclosed in another # set of quotes. $options =~ s/(\S)(\".*\")/$1\"$2\"/g; # Options must be quoted to preserve case if not already quoted. $options =~ s/(\S+)/\"$1\"/g; # Special fixup for embedded quotes. $options =~ s/(\"\".+)\"(\s+)\"(.+\"\")/$1$2$3/g; $options =~ s/(\A)(?:\"\")(.+)(?:\"\")/$1\"$2\"/g; # Special fixup for misc/general4 test. $options =~ s/""\@echo" "cc""/\@echo cc"/; $options =~ s/"\@echo link"""/\@echo link"/; # Remove shell escapes expected to be removed by bash if ($options !~ /path=pre/) { $options =~ s/\\//g; } # special fixup for options/eval $options =~ s/"--eval=\$\(info" "eval/"--eval=\$\(info eval/; print ("Options fixup = -$options-\n") if $debug; } $command .= " $options"; } $command_string = ""; if (@call) { $command_string = "#$call[1]:$call[2]\n"; } $command_string .= "$command\n"; if ($valgrind) { print VALGRIND "\n\nExecuting: $command\n"; } { my $old_timeout = $test_timeout; $timeout and $test_timeout = $timeout; # If valgrind is enabled, turn off the timeout check $valgrind and $test_timeout = 0; $code = &run_command_with_output($logname,$command); $test_timeout = $old_timeout; } # Check to see if we have Purify errors. If so, keep the logfile. # For this to work you need to build with the Purify flag -exit-status=yes if ($pure_log && -f $pure_log) { if ($code & 0x7000) { $code &= ~0x7000; # If we have a purify log, save it $tn = $pure_testname . ($num_of_logfiles ? ".$num_of_logfiles" : ""); print("Renaming purify log file to $tn\n") if $debug; rename($pure_log, "$tn") || die "Can't rename $log to $tn: $!\n"; ++$purify_errors; } else { unlink($pure_log); } } if ($code != $expected_code) { print "Error running $make_path (expected $expected_code; got $code): $command\n"; $test_passed = 0; $runf = &get_runfile; &create_file (&get_runfile, $command_string); # If it's a SIGINT, stop here if ($code & 127) { print STDERR "\nCaught signal ".($code & 127)."!\n"; ($code & 127) == 2 and exit($code); } return 0; } if ($profile & $vos) { system "add_profile $make_path"; } return 1; } sub print_usage { &print_standard_usage ("run_make_tests", "[-make MAKE_PATHNAME] [-srcdir SRCDIR] [-memcheck] [-massif]",); } sub print_help { &print_standard_help ( "-make", "\tYou may specify the pathname of the copy of make to run.", "-srcdir", "\tSpecify the make source directory.", "-valgrind", "-memcheck", "\tRun the test suite under valgrind's memcheck tool.", "\tChange the default valgrind args with the VALGRIND_ARGS env var.", "-massif", "\tRun the test suite under valgrind's massif toool.", "\tChange the default valgrind args with the VALGRIND_ARGS env var." ); } sub get_this_pwd { $delete_command = 'rm -f'; if ($has_POSIX) { $__pwd = POSIX::getcwd(); } elsif ($vos) { $delete_command = "delete_file -no_ask"; $__pwd = `++(current_dir)`; } else { # No idea... just try using pwd as a last resort. chop ($__pwd = `pwd`); } return $__pwd; } sub set_defaults { # $profile = 1; $testee = "GNU make"; $make_path = "make"; $tmpfilesuffix = "mk"; $pwd = &get_this_pwd; } sub set_more_defaults { local($string); local($index); # find the type of the port. We do this up front to have a single # point of change if it needs to be tweaked. # # This is probably not specific enough. # if ($osname =~ /Windows/i || $osname =~ /MINGW32/i || $osname =~ /CYGWIN_NT/i) { $port_type = 'W32'; } # Bleah, the osname is so variable on DOS. This kind of bites. # Well, as far as I can tell if we check for some text at the # beginning of the line with either no spaces or a single space, then # a D, then either "OS", "os", or "ev" and a space. That should # match and be pretty specific. elsif ($osname =~ /^([^ ]*|[^ ]* [^ ]*)D(OS|os|ev) /) { $port_type = 'DOS'; } # Check for OS/2 elsif ($osname =~ m%OS/2%) { $port_type = 'OS/2'; } # VMS has a GNV Unix mode or a DCL mode. # The SHELL environment variable should not be defined in VMS-DCL mode. elsif ($osname eq 'VMS' && !defined $ENV{"SHELL"}) { $port_type = 'VMS-DCL'; } # Everything else, right now, is UNIX. Note that we should integrate # the VOS support into this as well and get rid of $vos; we'll do # that next time. else { $port_type = 'UNIX'; } # On DOS/Windows system the filesystem apparently can't track # timestamps with second granularity (!!). Change the sleep time # needed to force a file to be considered "old". $wtime = $port_type eq 'UNIX' ? 1 : $port_type eq 'OS/2' ? 2 : 4; print "Port type: $port_type\n" if $debug; print "Make path: $make_path\n" if $debug; print "fs type : case insensitive\n" if $debug && $case_insensitive_fs; # Find the full pathname of Make. For DOS systems this is more # complicated, so we ask make itself. if ($osname eq 'VMS') { $port_type = 'VMS-DCL' unless defined $ENV{"SHELL"}; # On VMS pre-setup make to be found with simply 'make'. $make_path = 'make'; } else { my $mk = `sh -c 'echo "all:;\@echo \\\$(MAKE)" | $make_path -f-'`; chop $mk; $mk or die "FATAL ERROR: Cannot determine the value of \$(MAKE):\n 'echo \"all:;\@echo \\\$(MAKE)\" | $make_path -f-' failed!\n"; $make_path = $mk; } print "Make\t= '$make_path'\n" if $debug; my $redir2 = '2> /dev/null'; $redir2 = '' if os_name eq 'VMS'; $string = `$make_path -v -f /dev/null $redir2`; $string =~ /^(GNU Make [^,\n]*)/; $testee_version = "$1\n"; my $redir = '2>&1'; $redir = '' if os_name eq 'VMS'; $string = `sh -c "$make_path -f /dev/null $redir"`; if ($string =~ /(.*): \*\*\* No targets\. Stop\./) { $make_name = $1; } else { $make_path =~ /^(?:.*$pathsep)?(.+)$/; $make_name = $1; } # prepend pwd if this is a relative path (ie, does not # start with a slash, but contains one). Thanks for the # clue, Roland. if (index ($make_path, ":") != 1 && index ($make_path, "/") > 0) { $mkpath = "$pwd$pathsep$make_path"; } else { $mkpath = $make_path; } # If srcdir wasn't provided on the command line, see if the # location of the make program gives us a clue. Don't fail if not; # we'll assume it's been installed into /usr/include or wherever. if (! $srcdir) { $make_path =~ /^(.*$pathsep)?/; my $d = $1 || '../'; -f "${d}gnumake.h" and $srcdir = $d; } # Not with the make program, so see if we can get it out of the makefile if (! $srcdir && open(MF, "< ../Makefile")) { local $/ = undef; $_ = ; close(MF); /^abs_srcdir\s*=\s*(.*?)\s*$/m; -f "$1/gnumake.h" and $srcdir = $1; } # Get Purify log info--if any. if (exists $ENV{PURIFYOPTIONS} && $ENV{PURIFYOPTIONS} =~ /.*-logfile=([^ ]+)/) { $pure_log = $1 || ''; $pure_log =~ s/%v/$make_name/; $purify_errors = 0; } $string = `sh -c "$make_path -j 2 -f /dev/null $redir"`; if ($string =~ /not supported/) { $parallel_jobs = 0; } else { $parallel_jobs = 1; } %FEATURES = map { $_ => 1 } split /\s+/, `sh -c "echo '\\\$(info \\\$(.FEATURES))' | $make_path -f- 2>/dev/null"`; # Set up for valgrind, if requested. $make_command = $make_path; if ($valgrind) { my $args = $valgrind_args; open(VALGRIND, "> valgrind.out") || die "Cannot open valgrind.out: $!\n"; # -q --leak-check=yes exists $ENV{VALGRIND_ARGS} and $args = $ENV{VALGRIND_ARGS}; $make_path = "valgrind --log-fd=".fileno(VALGRIND)." $args $make_path"; # F_SETFD is 2 fcntl(VALGRIND, 2, 0) or die "fcntl(setfd) failed: $!\n"; system("echo Starting on `date` 1>&".fileno(VALGRIND)); print "Enabled valgrind support.\n"; } } sub setup_for_test { $makefile = &get_tmpfile; if (-f $makefile) { unlink $makefile; } # Get rid of any Purify logs. if ($pure_log) { ($pure_testname = $testname) =~ tr,/,_,; $pure_testname = "$pure_log.$pure_testname"; system("rm -f $pure_testname*"); print("Purify testfiles are: $pure_testname*\n") if $debug; } } exit !&toplevel; kbuild-3149/src/kmk/tests/run_make_tests0000755000175000017500000000004413252530202020360 0ustar locutuslocutus#!/bin/sh exec perl $0.pl ${1+"$@"} kbuild-3149/src/kmk/tests/README0000644000175000017500000001110513252530201016266 0ustar locutuslocutusThe test suite was originally written by Steve McGee and Chris Arthur. It is covered by the GNU General Public License (Version 2), described in the file COPYING. It has been maintained as part of GNU make proper since GNU make 3.78. This entire test suite, including all test files, are copyright and distributed under the following terms: ----------------------------------------------------------------------------- Copyright (C) 1992-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make 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 . ----------------------------------------------------------------------------- The test suite requires Perl. These days, you should have at least Perl 5.004 (available from ftp.gnu.org, and portable to many machines). It used to work with Perl 4.036 but official support for Perl 4.x was abandoned a long time ago, due to lack of testbeds, as well as interest. The test suite assumes that the first "diff" it finds on your PATH is GNU diff, but that only matters if a test fails. To run the test suite on a UNIX system, use "perl ./run_make_tests" (or just "./run_make_tests" if you have a perl on your PATH). To run the test suite on Windows NT or DOS systems, use "perl.exe ./run_make-tests.pl". By default, the test engine picks up the first executable called "make" that it finds in your path. You may use the -make_path option (i.e., "perl run_make_tests -make_path /usr/local/src/make-3.78/make") if you want to run a particular copy. This now works correctly with relative paths and when make is called something other than "make" (like "gmake"). Tests cannot end with a "~" character, as the test suite will ignore any that do (I was tired of having it run my Emacs backup files as tests :)) Also, sometimes the tests may behave strangely on networked filesystems. You can use mkshadow to create a copy of the test suite in /tmp or similar, and try again. If the error disappears, it's an issue with your network or file server, not GNU make (I believe). This shouldn't happen very often anymore: I've done a lot of work on the tests to reduce the impacts of this situation. The options/dash-l test will not really test anything if the copy of make you are using can't obtain the system load. Some systems require make to be setgid sys or kmem for this; if you don't want to install make just to test it, make it setgid to kmem or whatever group /dev/kmem is (i.e., "chgrp kmem make;chmod g+s make" as root). In any case, the options/dash-l test should no longer *fail* because make can't read /dev/kmem. A directory named "work" will be created when the tests are run which will contain any makefiles and "diff" files of tests that fail so that you may look at them afterward to see the output of make and the expected result. There is a -help option which will give you more information about the other possible options for the test suite. Open Issues ----------- The test suite has a number of problems which should be addressed. One VERY serious one is that there is no real documentation. You just have to see the existing tests. Use the newer tests: many of the tests haven't been updated to use the latest/greatest test methods. See the ChangeLog in the tests directory for pointers. The second serious problem is that it's not parallelizable: it scribbles all over its installation directory and so can only test one make at a time. The third serious problem is that it's not relocatable: the only way it works when you build out of the source tree is to create symlinks, which doesn't work on every system and is bogus to boot. The fourth serious problem is that it doesn't create its own sandbox when running tests, so that if a test forgets to clean up after itself that can impact future tests. Bugs ---- Any complaints/suggestions/bugs/etc. for the test suite itself (as opposed to problems in make that the suite finds) should be handled the same way as normal GNU make bugs/problems (see the README for GNU make). Paul D. Smith Chris Arthur kbuild-3149/src/kmk/tests/scripts/0000755000175000017500000000000013252530202017100 5ustar locutuslocutuskbuild-3149/src/kmk/tests/scripts/features/0000755000175000017500000000000013252530202020716 5ustar locutuslocutuskbuild-3149/src/kmk/tests/scripts/features/echoing0000644000175000017500000000405713252530202022263 0ustar locutuslocutus# -*-perl-*- $description = "The following test creates a makefile to test command echoing. It tests that when a command line starts with a '\@', the echoing of that line is suppressed. It also tests the -n option which tells make to ONLY echo the commands and no execution happens. In this case, even the commands with '\@' are printed. Lastly, it tests the -s flag which tells make to prevent all echoing, as if all commands started with a '\@'."; $details = "This test is similar to the 'clean' test except that a '\@' has been placed in front of the delete command line. Four tests are run here. First, make is run normally and the first echo command should be executed. In this case there is no '\@' so we should expect make to display the command AND display the echoed message. Secondly, make is run with the clean target, but since there is a '\@' at the beginning of the command, we expect no output; just the deletion of a file which we check for. Third, we give the clean target again except this time we give make the -n option. We now expect the command to be displayed but not to be executed. In this case we need only to check the output since an error message would be displayed if it actually tried to run the delete command again and the file didn't exist. Lastly, we run the first test again with the -s option and check that make did not echo the echo command before printing the message.\n"; $example = "EXAMPLE_FILE"; touch($example); # TEST #1 # ------- run_make_test(" all: \techo This makefile did not clean the dir... good clean: \t\@$delete_command $example\n", '', 'echo This makefile did not clean the dir... good This makefile did not clean the dir... good'); # TEST #2 # ------- run_make_test(undef, 'clean', ''); if (-f $example) { $test_passed = 0; unlink($example); } # TEST #3 # ------- run_make_test(undef, '-n clean', "$delete_command $example\n"); # TEST #4 # ------- run_make_test(undef, '-s', "This makefile did not clean the dir... good\n"); 1; kbuild-3149/src/kmk/tests/scripts/features/rule_glob0000644000175000017500000000162413252530201022615 0ustar locutuslocutus# -*-perl-*- $description = "Test globbing in targets and prerequisites."; $details = ""; touch(qw(a.one a.two a.three)); # Test wildcards in regular targets and prerequisites run_make_test(q{ .PHONY: all a.one a.two a.three all: a.one* a.t[a-z0-9]o a.th[!q]ee a.o[Nn][Ee] a.t*: ; @echo $@ }, '', "a.one\na.two\na.three"); # Test wildcards in pattern targets and prerequisites run_make_test(q{ .PHONY: all all: a.four %.four : %.t* ; @echo $@: $(sort $^) }, '', "a.four: a.three a.two"); # Test wildcards in second expansion targets and prerequisites run_make_test(q{ .PHONY: all all: a.four .SECONDEXPANSION: %.four : $$(sort %.t*) ; @echo $@: $(sort $^) }, '', "a.four: a.three a.two"); unlink(qw(a.one a.two a.three)); # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/features/default_names0000644000175000017500000000244713252530201023456 0ustar locutuslocutus# -*-perl-*- $description = "This script tests to make sure that Make looks for default makefiles in the correct order (GNUmakefile,makefile,Makefile)"; # Create a makefile called "GNUmakefile" $makefile = "GNUmakefile"; open(MAKEFILE,"> $makefile"); print MAKEFILE "FIRST: ; \@echo It chose GNUmakefile\n"; close(MAKEFILE); # Create another makefile called "makefile" open(MAKEFILE,"> makefile"); print MAKEFILE "SECOND: ; \@echo It chose makefile\n"; close(MAKEFILE); # DOS/WIN32/MacOSX platforms are case-insensitive / case-preserving, so # Makefile is the same file as makefile. Just test what we can here. my $case_sensitive = 0; if (! -f 'Makefile') { # Create another makefile called "Makefile" $case_sensitive = 1; open(MAKEFILE,"> Makefile"); print MAKEFILE "THIRD: ; \@echo It chose Makefile\n"; close(MAKEFILE); } run_make_with_options("","",&get_logfile); compare_output("It chose GNUmakefile\n",&get_logfile(1)); unlink($makefile); run_make_with_options("","",&get_logfile); compare_output("It chose makefile\n",&get_logfile(1)); unlink("makefile"); if ($case_sensitive) { run_make_with_options("","",&get_logfile); compare_output("It chose Makefile\n",&get_logfile(1)); unlink("Makefile"); } 1; kbuild-3149/src/kmk/tests/scripts/features/se_explicit0000644000175000017500000000541413252530201023154 0ustar locutuslocutus# -*-perl-*- $description = "Test second expansion in ordinary rules."; $details = ""; # TEST #0: Test handing of '$' in prerequisites with and without second # expansion. # bird: Modified this test to use ${PRE} instead of $(PRE) as it failes # when make is built with NO_ARCHIVES defined. # If we don't support archives then the prerequisite is different my $prereq = exists $FEATURES{'archives'} ? '$' : '$(PRE)'; run_make_test(q! ifdef SE .SECONDEXPANSION: endif foo$$bar: bar$$baz bar$$biz ; @echo '$@ : $^' PRE = one two bar$$baz: $${PRE} baraz: $${PRE} PRE = three four .DEFAULT: ; @echo '$@' !, '', "$prereq\nbar\$biz\nfoo\$bar : bar\$baz bar\$biz"); run_make_test(undef, 'SE=1', "three\nfour\nbariz\nfoo\$bar : baraz bariz"); # TEST #1: automatic variables. # run_make_test(q! .SECONDEXPANSION: .DEFAULT: ; @echo '$@' foo: bar baz foo: biz | buz foo: $$@.1 \ $$<.2 \ $$(addsuffix .3,$$^) \ $$(addsuffix .4,$$+) \ $$|.5 \ $$*.6 !, '-j1', 'bar baz biz buz foo.1 bar.2 bar.3 baz.3 biz.3 bar.4 baz.4 biz.4 buz.5 .6 '); # Test #2: target/pattern -specific variables. # run_make_test(q! .SECONDEXPANSION: .DEFAULT: ; @echo '$@' foo.x: $$a $$b foo.x: a := bar %.x: b := baz !, '', 'bar baz '); # Test #3: order of prerequisites. # run_make_test(q! .SECONDEXPANSION: .DEFAULT: ; @echo '$@' all: foo bar baz # Subtest #1 foo: foo.1; @: foo: foo.2 foo: foo.3 # Subtest #2 bar: bar.2 bar: bar.1; @: bar: bar.3 # Subtest #3 baz: baz.1 baz: baz.2 baz: ; @: !, '-j1', 'foo.1 foo.2 foo.3 bar.1 bar.2 bar.3 baz.1 baz.2 '); # TEST #4: eval in a context where there is no reading_file run_make_test(q! .SECONDEXPANSION: all : $$(eval $$(info test)) !, '', "test\n#MAKE#: Nothing to be done for 'all'.\n"); # TEST #5: (NEGATIVE) catch eval in a prereq list trying to create new # target/prereq relationships. run_make_test(q! .SECONDEXPANSION: proj1.exe : proj1.o $$(eval $$(test)) define test proj1.o : proj1.c proj1.c: proj1.h endef !, '', "#MAKE#: *** prerequisites cannot be defined in recipes. Stop.\n", 512); # Automatic $$+ variable expansion issue. Savannah bug #25780 run_make_test(q! all : foo foo .SECONDEXPANSION: all : $$+ ; @echo '$+' foo : ; !, '', "foo foo foo foo\n"); # Automatic $$+ variable expansion issue. Savannah bug #25780 run_make_test(q! all : bar bar bar : ; q%x : ; .SECONDEXPANSION: a%l: q1x $$+ q2x ; @echo '$+' !, '', "q1x bar bar q2x bar bar\n"); # Allow patsubst shorthand in second expansion context. # Requires the colon to be quoted. Savannah bug #16545 run_make_test(q! .PHONY: foo.bar .SECONDEXPANSION: foo: $$(@\\:%=%.bar); @echo '$^' !, '', "foo.bar\n"); 1; kbuild-3149/src/kmk/tests/scripts/features/mult_targets0000644000175000017500000000241713252530202023357 0ustar locutuslocutus$description = "The following test creates a makefile to test that a \n " ."rule with multiple targets is equivalent to writing \n" ."many rules, each with one target, and all identical aside\n" ."from that."; $details = "A makefile is created with one rule and two targets. Make \n" ."is called twice, once for each target, and the output which \n" ."contains the target name with \$@ is looked at for the changes.\n" ."This test also tests the substitute function by replacing \n" ."the word output with nothing in the target name giving either\n" ."an output of \"I am little\" or \"I am big\""; open(MAKEFILE,"> $makefile"); # The Contents of the MAKEFILE ... print MAKEFILE "bigoutput littleoutput: test.h\n"; print MAKEFILE "\t\@echo I am \$(subst output,,\$@)\n"; # END of Contents of MAKEFILE close(MAKEFILE); &touch("test.h"); &run_make_with_options($makefile,"bigoutput",&get_logfile); # Create the answer to what should be produced by this Makefile $answer = "I am big\n"; &compare_output($answer,&get_logfile(1)); &run_make_with_options($makefile,"littleoutput",&get_logfile); $answer = "I am little\n"; &compare_output($answer,&get_logfile(1)); unlink "test.h"; 1; kbuild-3149/src/kmk/tests/scripts/features/parallelism0000644000175000017500000001422513252530201023151 0ustar locutuslocutus# -*-perl-*- $description = "Test parallelism (-j) option."; $details = "This test creates a makefile with two double-colon default rules. The first rule has a series of sleep and echo commands intended to run in series. The second and third have just an echo statement. When make is called in this test, it is given the -j option with a value of 4. This tells make that it may start up to four jobs simultaneously. In this case, since the first command is a sleep command, the output of the second and third commands will appear before the first if indeed make is running all of these commands in parallel."; if (!$parallel_jobs) { return -1; } if ($vos) { $sleep_command = "sleep -seconds"; } else { $sleep_command = "sleep"; } run_make_test(" all : def_1 def_2 def_3 def_1 : ; \@echo ONE; $sleep_command 3 ; echo TWO def_2 : ; \@$sleep_command 2 ; echo THREE def_3 : ; \@$sleep_command 1 ; echo FOUR", '-j4', "ONE\nFOUR\nTHREE\nTWO"); # Test parallelism with included files. Here we sleep/echo while # building the included files, to test that they are being built in # parallel. run_make_test(" all: 1 2; \@echo success -include 1.inc 2.inc 1.inc: ; \@echo ONE.inc; $sleep_command 2; echo TWO.inc; echo '1: ; \@echo ONE; $sleep_command 2; echo TWO' > \$\@ 2.inc: ; \@$sleep_command 1; echo THREE.inc; echo '2: ; \@$sleep_command 1; echo THREE' > \$\@", "-j4", "ONE.inc\nTHREE.inc\nTWO.inc\nONE\nTHREE\nTWO\nsuccess\n", 0, 7); rmfiles(qw(1.inc 2.inc)); # Test parallelism with included files--this time recurse first and make # sure the jobserver works. run_make_test(" recurse: ; \@\$(MAKE) --no-print-directory -f #MAKEFILE# INC=yes all all: 1 2; \@echo success INC = no ifeq (\$(INC),yes) -include 1.inc 2.inc endif 1.inc: ; \@echo ONE.inc; $sleep_command 2; echo TWO.inc; echo '1: ; \@echo ONE; $sleep_command 2; echo TWO' > \$\@ 2.inc: ; \@$sleep_command 1; echo THREE.inc; echo '2: ; \@$sleep_command 1; echo THREE' > \$\@", "-j4", "ONE.inc\nTHREE.inc\nTWO.inc\nONE\nTHREE\nTWO\nsuccess\n", 0, 7); rmfiles(qw(1.inc 2.inc)); # Grant Taylor reports a problem where tokens can be lost (not written back # to the pipe when they should be): this happened when there is a $(shell ...) # function in an exported recursive variable. I added some code to check # for this situation and print a message if it occurred. This test used # to trigger this code when I added it but no longer does after the fix. # We have to increase the timeout from the default (5s) on this test. run_make_test(" export HI = \$(shell \$(\$\@.CMD)) first.CMD = echo hi second.CMD = $sleep_command 4; echo hi .PHONY: all first second all: first second first second: ; \@echo \$\@; $sleep_command 1; echo \$\@", '-j2', "first\nfirst\nsecond\nsecond", 0, 7); # Michael Matz reported a bug where if make is running in # parallel without -k and two jobs die in a row, but not too close to each # other, then make will quit without waiting for the rest of the jobs to die. run_make_test(" .PHONY: all fail.1 fail.2 fail.3 ok all: fail.1 ok fail.2 fail.3 fail.1 fail.2 fail.3: \@$sleep_command \$(patsubst fail.%,%,\$\@) \@echo Fail \@exit 1 ok: \@$sleep_command 4 \@echo Ok done", '-rR -j5', (!$is_kmk) ? "Fail #MAKE#: *** [#MAKEFILE#:8: fail.1] Error 1 #MAKE#: *** Waiting for unfinished jobs.... Fail #MAKE#: *** [#MAKEFILE#:8: fail.2] Error 1 Fail #MAKE#: *** [#MAKEFILE#:8: fail.3] Error 1 Ok done" : 'Fail #MAKE#: *** [fail.1] Error 1 The failing command: @exit 1 #MAKE#: *** Waiting for unfinished jobs.... Fail #MAKE#: *** [fail.2] Error 1 The failing command: @exit 1 Fail #MAKE#: *** [fail.3] Error 1 The failing command: @exit 1 Ok done #MAKE#: *** Exiting with status 2', 512); # Test for Savannah bug #15641. # run_make_test(' .PHONY: all all:; @: -include foo.d foo.d: comp @echo building $@ comp: mod_a.o mod_b.o; @: mod_a.o mod_b.o: @exit 1 ', '-j2', ''); # TEST #9 -- Savannah bugs 3330 and 15919 # In earlier versions of make this will either give the wrong answer, or hang. utouch(-10, 'target'); run_make_test('target: intermed ; touch $@ .INTERMEDIATE: intermed intermed: | phony ; touch $@ .PHONY: phony phony: ; : phony', '-rR -j', ': phony'); rmfiles('target'); # TEST #11: Make sure -jN from MAKEFLAGS is processed even when we re-exec # See Savannah bug #33873 $extraENV{MAKEFLAGS} = '-j4'; run_make_test(q! things = thing1 thing2 all: $(things) thing1:; @sleep 1; echo '$@ start'; sleep 2; echo '$@ end' thing2:; @echo '$@ start'; sleep 2; echo '$@ end' -include inc.mk inc.mk: ; @touch $@ !, '', "thing2 start\nthing1 start\nthing2 end\nthing1 end\n"); delete $extraENV{MAKEFLAGS}; rmfiles('inc.mk'); # Ensure intermediate/secondary files are not pruned incorrectly. # See Savannah bug #30653 utouch(-15, 'file2'); utouch(-10, 'file4'); utouch(-5, 'file1'); run_make_test(q! .INTERMEDIATE: file3 file4: file3 ; @mv -f $< $@ file3: file2 ; touch $@ file2: file1 ; @touch $@ !, '--no-print-directory -j2', "touch file3"); rmfiles('file1', 'file2', 'file3', 'file4'); # Make sure that all jobserver FDs are closed if we need to re-exec the # master copy. # # First, find the "default" file descriptors we normally use # Then make sure they're still used. # # Right now we don't have a way to run a makefile and capture the output # without checking it, so we can't really write this test. # run_make_test(' # submake: ; @$(MAKE) --no-print-directory -f #MAKEFILE# fdprint 5>output # dependfile: ; @echo FOO=bar > $@ # INCL := true # FOO=foo # ifeq ($(INCL),true) # -include dependfile # endif # fdprint: ; @echo $(filter --jobserver%,$(MAKEFLAGS)) # recurse: ; @$(MAKE) --no-print-directory -f #MAKEFILE# submake INCL=true', # '-j2 INCL=false fdprint', # 'bar'); # rmfiles(qw(dependfile output)); # # Do it again, this time where the include is done by the non-master make. # run_make_test(undef, '-j2 recurse INCL=false', 'bar'); # rmfiles(qw(dependfile output)); 1; ### Local Variables: ### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) ### End: kbuild-3149/src/kmk/tests/scripts/features/reinvoke0000644000175000017500000000366413252530201022473 0ustar locutuslocutus# -*-mode: perl-*- $description = "Test GNU make's auto-reinvocation feature."; $details = "\ If the makefile or one it includes can be rebuilt then it is, and make is reinvoked. We create a rule to rebuild the makefile from a temp file, then touch the temp file to make it newer than the makefile."; $omkfile = $makefile; &utouch(-600, 'incl.mk'); # For some reason if we don't do this then the test fails for systems # with sub-second timestamps, maybe + NFS? Not sure. &utouch(-1, 'incl-1.mk'); run_make_test(' all: ; @echo running rules. #MAKEFILE# incl.mk: incl-1.mk @echo rebuilding $@ @echo >> $@ include incl.mk', '', "rebuilding incl.mk\nrunning rules.\n"); # Make sure updating the makefile itself also works &utouch(-600, $omkfile); run_make_test(undef, '', "rebuilding #MAKEFILE#\nrunning rules.\n"); &rmfiles('incl.mk', 'incl-1.mk'); # In this test we create an included file that's out-of-date, but then # the rule doesn't update it. Make shouldn't re-exec. &utouch(-600, 'b','a'); #&utouch(-10, 'a'); &touch('c'); run_make_test(' SHELL = /bin/sh all: ; @echo hello a : b ; echo >> $@ b : c ; [ -f $@ ] || echo >> $@ c: ; echo >> $@ include $(F)', 'F=a', "[ -f b ] || echo >> b\nhello\n"); # Now try with the file we're not updating being the actual file we're # including: this and the previous one test different parts of the code. run_make_test(undef, 'F=b', "[ -f b ] || echo >> b\nhello\n") &rmfiles('a','b','c'); # Ensure command line variables are preserved properly across re-exec # Tests for Savannah bug #30723 run_make_test(' ifdef RECURSE -include foo30723 endif recurse: ; @$(MAKE) -f $(MAKEFILE_LIST) RECURSE=1 test test: ; @echo F.O=$(F.O) foo30723: ; @touch $@ ', '--no-print-directory F.O=bar', "F.O=bar\n"); unlink('foo30723'); # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/features/targetvars0000644000175000017500000001331013252530201023020 0ustar locutuslocutus# -*-perl-*- $description = "Test target-specific variable settings."; $details = "\ Create a makefile containing various flavors of target-specific variable values, override and non-override, and using various variable expansion rules, semicolon interference, etc."; run_make_test(' SHELL = /bin/sh export FOO = foo export BAR = bar one: override FOO = one one two: ; @echo $(FOO) $(BAR) two: BAR = two three: ; BAR=1000 @echo $(FOO) $(BAR) # Some things that shouldn not be target vars funk : override funk : override adelic adelic override : ; echo $@ # Test per-target recursive variables four:FOO=x four:VAR$(FOO)=ok four: ; @echo "$(FOO) $(VAR$(FOO)) $(VAR) $(VARx)" five:FOO=x five six : VAR$(FOO)=good five six: ;@echo "$(FOO) $(VAR$(FOO)) $(VAR) $(VARx) $(VARfoo)" # Test per-target variable inheritance seven: eight seven eight: ; @echo $@: $(FOO) $(BAR) seven: BAR = seven seven: FOO = seven eight: BAR = eight # Test the export keyword with per-target variables nine: ; @echo $(FOO) $(BAR) $$FOO $$BAR nine: FOO = wallace nine-a: export BAZ = baz nine-a: ; @echo $$BAZ # Test = escaping EQ = = ten: one$(EQ)two ten: one $(EQ) two ten one$(EQ)two $(EQ):;@echo $@ .PHONY: one two three four five six seven eight nine ten $(EQ) one$(EQ)two # Test target-specific vars with pattern/suffix rules QVAR = qvar RVAR = = %.q : ; @echo $(QVAR) $(RVAR) foo.q : RVAR += rvar # Target-specific vars with multiple LHS pattern rules %.r %.s %.t: ; @echo $(QVAR) $(RVAR) $(SVAR) $(TVAR) foo.r : RVAR += rvar foo.t : TVAR := $(QVAR) ', "one two three", "one bar\nfoo two\nBAR=1000\nfoo bar\n"); # TEST #2 run_make_test(undef, "one two FOO=1 BAR=2", "one 2\n1 2\n"); # TEST #3 run_make_test(undef, "four", "x ok ok\n"); # TEST #4 run_make_test(undef, "seven", "eight: seven eight\nseven: seven seven\n"); # TEST #5 run_make_test(undef, "nine", "wallace bar wallace bar\n"); # TEST #5-a run_make_test(undef, "nine-a", "baz\n"); # TEST #6 run_make_test(undef, "ten", "one=two\none bar\n=\nfoo two\nten\n"); # TEST #6 run_make_test(undef, "foo.q bar.q", "qvar = rvar\nqvar =\n"); # TEST #7 run_make_test(undef, "foo.t bar.s", "qvar = qvar\nqvar =\n"); # TEST #8 # For PR/1378: Target-specific vars don't inherit correctly run_make_test(' foo: FOO = foo bar: BAR = bar foo: bar bar: baz baz: ; @echo $(FOO) $(BAR) ', "", "foo bar\n"); # TEST #9 # For PR/1380: Using += assignment in target-specific variables sometimes fails # Also PR/1831 run_make_test(' .PHONY: all one all: FOO += baz all: one; @echo $(FOO) FOO = bar one: FOO += biz one: FOO += boz one: ; @echo $(FOO) ', '', "bar baz biz boz\nbar baz\n"); # Test #10 run_make_test(undef, 'one', "bar biz boz\n"); # Test #11 # PR/1709: Test semicolons in target-specific variable values run_make_test(' foo : FOO = ; ok foo : ; @echo "$(FOO)" ', '', "; ok\n"); # Test #12 # PR/2020: More hassles with += target-specific vars. I _really_ think # I nailed it this time :-/. run_make_test(' .PHONY: a BLAH := foo COMMAND = echo $(BLAH) a: ; @$(COMMAND) a: BLAH := bar a: COMMAND += snafu $(BLAH) ', '', "bar snafu bar\n"); # Test #13 # Test double-colon rules with target-specific variable values run_make_test(' W = bad X = bad foo: W = ok foo:: ; @echo $(W) $(X) $(Y) $(Z) foo:: ; @echo $(W) $(X) $(Y) $(Z) foo: X = ok Y = foo bar: foo bar: Y = bar Z = nopat ifdef PATTERN fo% : Z = pat endif ', 'foo', "ok ok foo nopat\nok ok foo nopat\n"); # Test #14 # Test double-colon rules with target-specific variable values and # inheritance run_make_test(undef, 'bar', "ok ok bar nopat\nok ok bar nopat\n"); # Test #15 # Test double-colon rules with pattern-specific variable values run_make_test(undef, 'foo PATTERN=yes', "ok ok foo pat\nok ok foo pat\n"); # Test #16 # Test target-specific variables with very long command line # (> make default buffer length) run_make_test(' base_metals_fmd_reports.sun5 base_metals_fmd_reports CreateRealPositions CreateMarginFunds deals_changed_since : BUILD_OBJ=$(shell if [ -f "build_information.generate" ]; then echo "$(OBJ_DIR)/build_information.o"; else echo "no build information"; fi ) deals_changed_since: ; @echo $(BUILD_OBJ) ', '', "no build information\n"); # TEST #17 # Test a merge of set_lists for files, where one list is much longer # than the other. See Savannah bug #15757. mkdir('t1', 0777); touch('t1/rules.mk'); run_make_test(' VPATH = t1 include rules.mk .PHONY: all all: foo.x foo.x : rules.mk ; @echo MYVAR=$(MYVAR) FOOVAR=$(FOOVAR) ALLVAR=$(ALLVAR) all: ALLVAR = xxx foo.x: FOOVAR = bar rules.mk : MYVAR = foo .INTERMEDIATE: foo.x rules.mk ', '-I t1', 'MYVAR= FOOVAR=bar ALLVAR=xxx'); rmfiles('t1/rules.mk'); rmdir('t1'); # TEST #18 # Test appending to a simple variable containing a "$": avoid a # double-expansion. See Savannah bug #15913. run_make_test(' VAR := $$FOO foo: VAR += BAR foo: ; @echo '."'".'$(VAR)'."'".' ', '', '$FOO BAR'); # TEST #19: Override with append variables run_make_test(' a: override FOO += f1 a: FOO += f2 a: ; @echo "$(FOO)" ', '', "f1\n"); run_make_test(undef, 'FOO=C', "C f1\n"); # TEST #19: Conditional variables with command-line settings run_make_test(' a: FOO ?= f1 a: ; @echo "$(FOO)" ', '', "f1\n"); run_make_test(undef, 'FOO=C', "C\n"); # TEST #20: Check for continuation after semicolons run_make_test(q! a: A = 'hello;\ world' a: ; @echo $(A) !, '', "hello; world\n"); # TEST #19: Test define/endef variables as target-specific vars # run_make_test(' # define b # @echo global # endef # a: define b # @echo local # endef # a: ; $(b) # ', # '', "local\n"); 1; kbuild-3149/src/kmk/tests/scripts/features/vpath0000644000175000017500000000571113252530201021766 0ustar locutuslocutus# -*-perl-*- $description = "The following test creates a makefile to test the \n" ."vpath directive which allows you to specify a search \n" ."path for a particular class of filenames, those that\n" ."match a particular pattern."; $details = "This tests the vpath directive by specifying search directories\n" ."for one class of filenames with the form: vpath pattern directories" ."\nIn this test, we specify the working directory for all files\n" ."that end in c or h. We also test the variables $@ (which gives\n" ."target name) and $^ (which is a list of all dependencies \n" ."including the directories in which they were found). It also\n" ."uses the function firstword used to extract just the first\n" ."dependency from the entire list."; open(MAKEFILE,"> $makefile"); # The Contents of the MAKEFILE ... print MAKEFILE "vpath %.c foo\n"; print MAKEFILE "vpath %.c $workdir\n"; print MAKEFILE "vpath %.h $workdir\n"; print MAKEFILE "objects = main.o kbd.o commands.o display.o insert.o\n"; print MAKEFILE "edit: \$(objects)\n"; print MAKEFILE "\t\@echo cc -o \$@ \$^\n"; print MAKEFILE "main.o : main.c defs.h\n"; print MAKEFILE "\t\@echo cc -c \$(firstword \$^)\n"; print MAKEFILE "kbd.o : kbd.c defs.h command.h\n"; print MAKEFILE "\t\@echo cc -c kbd.c\n"; print MAKEFILE "commands.o : command.c defs.h command.h\n"; print MAKEFILE "\t\@echo cc -c commands.c\n"; print MAKEFILE "display.o : display.c defs.h buffer.h\n"; print MAKEFILE "\t\@echo cc -c display.c\n"; print MAKEFILE "insert.o : insert.c defs.h buffer.h\n"; print MAKEFILE "\t\@echo cc -c insert.c\n"; # END of Contents of MAKEFILE close(MAKEFILE); @files_to_touch = ("$workdir${pathsep}main.c","$workdir${pathsep}defs.h", "$workdir${pathsep}kbd.c","$workdir${pathsep}command.h", "$workdir${pathsep}commands.c","$workdir${pathsep}display.c", "$workdir${pathsep}buffer.h","$workdir${pathsep}insert.c", "$workdir${pathsep}command.c"); &touch(@files_to_touch); # kmk: this requires -j1 because of ordering. &run_make_with_options($makefile,"-j1",&get_logfile); # Create the answer to what should be produced by this Makefile $answer = "cc -c $workdir${pathsep}main.c\ncc -c kbd.c\ncc -c commands.c\n" ."cc -c display.c\n" ."cc -c insert.c\ncc -o edit main.o kbd.o commands.o display.o " ."insert.o\n"; if (&compare_output($answer,&get_logfile(1))) { unlink @files_to_touch; } # TEST 2: after vpath lookup ensure we don't get incorrect circular dependency # warnings due to change of struct file ptr. Savannah bug #13529. mkdir('vpath-d', 0777); run_make_test(q! vpath %.te vpath-d/ .SECONDARY: default: vpath-d/a vpath-d/b vpath-d/a: fail.te vpath-d/b : fail.te vpath-d/fail.te: !, '', "#MAKE#: Nothing to be done for 'default'.\n"); rmdir('vpath-d'); 1; kbuild-3149/src/kmk/tests/scripts/features/se_implicit0000644000175000017500000000721313252530202023145 0ustar locutuslocutus# -*-perl-*- $description = "Test second expansion in ordinary rules."; $details = ""; use Cwd; $dir = cwd; $dir =~ s,.*/([^/]+)$,../$1,; # Test #1: automatic variables. # run_make_test(q! .SECONDEXPANSION: .DEFAULT: ; @echo '$@' foo.a: bar baz foo.a: biz | buz foo.%: 1.$$@ \ 2.$$< \ $$(addprefix 3.,$$^) \ $$(addprefix 4.,$$+) \ 5.$$| \ 6.$$* @: 1.foo.a \ 2.bar \ 3.bar \ 3.baz \ 3.biz \ 4.bar \ 4.baz \ 4.biz \ 5.buz \ 6.a: @echo '$@' !, '-j1', '1.foo.a 2.bar 3.bar 3.baz 3.biz 4.bar 4.baz 4.biz 5.buz 6.a bar baz biz buz '); # Test #2: target/pattern -specific variables. # run_make_test(q! .SECONDEXPANSION: foo.x: foo.%: $$(%_a) $$(%_b) bar @: foo.x: x_a := bar %.x: x_b := baz bar baz: ; @echo '$@' !, '', "bar\nbaz\n"); # Test #3: order of prerequisites. # run_make_test(q! .SECONDEXPANSION: .DEFAULT: ; @echo '$@' all: foo bar baz # Subtest #1 # %oo: %oo.1; @: foo: foo.2 foo: foo.3 foo.1: ; @echo '$@' # Subtest #2 # bar: bar.2 %ar: %ar.1; @: bar: bar.3 bar.1: ; @echo '$@' # Subtest #3 # baz: baz.1 baz: baz.2 %az: ; @: !, '-j1', 'foo.1 foo.2 foo.3 bar.1 bar.2 bar.3 baz.1 baz.2 '); # Test #4: stem splitting logic. # run_make_test(q! .SECONDEXPANSION: $(dir)/tmp/bar.o: $(dir)/tmp/foo/bar.c: ; @echo '$@' $(dir)/tmp/bar/bar.c: ; @echo '$@' foo.h: ; @echo '$@' %.o: $$(addsuffix /%.c,foo bar) foo.h @echo '$@: {$<} $^' !, "dir=$dir", "$dir/tmp/foo/bar.c $dir/tmp/bar/bar.c foo.h $dir/tmp/bar.o: {$dir/tmp/foo/bar.c} $dir/tmp/foo/bar.c $dir/tmp/bar/bar.c foo.h "); # Test #5: stem splitting logic and order-only prerequisites. # run_make_test(q! .SECONDEXPANSION: $(dir)/tmp/foo.o: $(dir)/tmp/foo.c $(dir)/tmp/foo.c: ; @echo '$@' bar.h: ; @echo '$@' %.o: %.c|bar.h @echo '$@: {$<} {$|} $^' !, "dir=$dir", "$dir/tmp/foo.c bar.h $dir/tmp/foo.o: {$dir/tmp/foo.c} {bar.h} $dir/tmp/foo.c "); # Test #6: lack of implicit prerequisites. # run_make_test(q! .SECONDEXPANSION: foo.o: foo.c foo.c: ; @echo '$@' %.o: @echo '$@: {$<} $^' !, '', "foo.c\nfoo.o: {foo.c} foo.c\n"); # Test #7: Test stem from the middle of the name. # run_make_test(q! .SECONDEXPANSION: foobarbaz: foo%baz: % $$*.1 @echo '$*' bar bar.1: @echo '$@' !, '', "bar\nbar.1\nbar\n"); # Test #8: Make sure stem triple-expansion does not happen. # run_make_test(q! .SECONDEXPANSION: foo$$bar: f%r: % $$*.1 @echo '$*' oo$$ba oo$$ba.1: @echo '$@' !, '', 'oo$ba oo$ba.1 oo$ba '); # Test #9: Check the value of $^ run_make_test(q! .SECONDEXPANSION: %.so: | $$(extra) ; @echo $^ foo.so: extra := foo.o foo.so: foo.o: !, '', "\n"); # Test #10: Test second expansion with second expansion prerequisites # Ensures pattern_search() recurses with SE prereqs. touch('a'); run_make_test(q! .SECONDEXPANSION: sim_base_rgg := just_a_name sim_base_src := a sim_base_f := a a a sim_%.f: $${sim_$$*_f} echo $@ sim_%.src: $${sim_$$*_src} echo $@ sim_%: \ $$(if $$(sim_$$*_src),sim_%.src) \ $$(if $$(sim_$$*_f),sim_%.f) \ $$(if $$(sim_$$*_rgg),$$(sim_$$*_rgg).s) echo $@ !, '-s sim_base', "#MAKE#: *** No rule to make target 'sim_base'. Stop.", 512); unlink('a'); # Ensure that order-only tokens embedded in second expansions are parsed run_make_test(q! .SECONDEXPANSION: PREREQS=p1|p2 P2=p2 all : foo bar f%o: $$(PREREQS) ; @echo '$@' from '$^' and '$|' b%r: p1|$$(P2) ; @echo '$@' from '$^' and '$|' p% : ; : $@ !, "", ": p1\n: p2\nfoo from p1 and p2\nbar from p1 and p2\n"); # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/features/escape0000644000175000017500000000366213252530201022107 0ustar locutuslocutus# -*-perl-*- $description = "Test various types of escaping in makefiles."; $details = "\ Make sure that escaping of ':' works in target names. Make sure escaping of whitespace works in target names. Make sure that escaping of '#' works. Make sure that backslash before non-special characters are kept."; # TEST 1 run_make_test(' $(path)foo : ; @echo "touch ($@)" foo\ bar: ; @echo "touch ($@)" sharp: foo\#bar.ext foo\#bar.ext: ; @echo "foo#bar.ext = ($@)"', '', 'touch (foo)'); # TEST 2: This one should fail, since the ":" is unquoted. run_make_test(undef, 'path=pre:', "#MAKEFILE#:2: *** target pattern contains no '%' (target 'foo'). Stop.", 512); # TEST 3: This one should work, since we escape the ":". run_make_test(undef, "'path=pre\\:'", 'touch (pre:foo)'); # TEST 4: This one should fail, since the escape char is escaped. run_make_test(undef, "'path=pre\\\\:'", "#MAKEFILE#:2: *** target pattern contains no '%' (target 'foo'). Stop.", 512); # TEST 5: This one should work run_make_test(undef, "'foo bar'", 'touch (foo bar)'); # TEST 6: Test escaped comments run_make_test(undef, 'sharp', 'foo#bar.ext = (foo#bar.ext)'); # Test escaped colons in prerequisites # Quoting of backslashes in q!! is kind of messy. # Solaris sh does not properly handle backslashes even in '' so just # check the output make prints, not what the shell interprets. run_make_test(q! foo: foo\\:bar foo\\\\\\:bar foo\\\\\\\\\\:bar foo foo\\:bar foo\\\\\\:bar foo\\\\\\\\\\:bar: ; : '$@' !, '', ": 'foo:bar'\n: 'foo\\:bar'\n: 'foo\\\\:bar'\n: 'foo'\n"); # Test backslash before non-special chars: should be kept as-is run_make_test(q! all: ..\foo .DEFAULT: ; : '$@' !, '', ": '..\\foo'\n"); # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/features/jobserver0000644000175000017500000000703413252530202022646 0ustar locutuslocutus# -*-perl-*- $description = "Test jobserver."; $details = "These tests are ones that specifically are different when the jobserver feature is available. Most -j tests are the same whether or not jobserver is available, and those appear in the 'parallelism' test suite."; exists $FEATURES{'jobserver'} or return -1; if (!$parallel_jobs) { return -1; } # Shorthand my $np = '--no-print-directory'; # Simple test of MAKEFLAGS settings run_make_test(q! SHOW = $(patsubst --jobserver-auth=%,--jobserver-auth=,$(MAKEFLAGS)) recurse: ; @echo $@: "/$(SHOW)/"; $(MAKE) -f #MAKEFILE# all all:;@echo $@: "/$(SHOW)/" !, "-j2 $np", "recurse: /-j2 --jobserver-auth= $np/\nall: /-j2 --jobserver-auth= $np/\n"); # Setting parallelism with the environment # Command line should take precedence over the environment $extraENV{MAKEFLAGS} = "-j2 $np"; run_make_test(q! SHOW = $(patsubst --jobserver-auth=%,--jobserver-auth=,$(MAKEFLAGS)) recurse: ; @echo $@: "/$(SHOW)/"; $(MAKE) -f #MAKEFILE# all all:;@echo $@: "/$(SHOW)/" !, '', "recurse: /-j2 --jobserver-auth= $np/\nall: /-j2 --jobserver-auth= $np/\n"); delete $extraENV{MAKEFLAGS}; # Test override of -jN $extraENV{MAKEFLAGS} = "-j9 $np"; run_make_test(q! SHOW = $(patsubst --jobserver-auth=%,--jobserver-auth=,$(MAKEFLAGS)) recurse: ; @echo $@: "/$(SHOW)/"; $(MAKE) -j3 -f #MAKEFILE# recurse2 recurse2: ; @echo $@: "/$(SHOW)/"; $(MAKE) -f #MAKEFILE# all all:;@echo $@: "/$(SHOW)/" !, "-j2 $np", "recurse: /-j2 --jobserver-auth= $np/\n#MAKE#[1]: warning: -jN forced in submake: disabling jobserver mode.\nrecurse2: /-j3 --jobserver-auth= $np/\nall: /-j3 --jobserver-auth= $np/\n"); delete $extraENV{MAKEFLAGS}; # Test override of -jN with -j run_make_test(q! SHOW = $(patsubst --jobserver-auth=%,--jobserver-auth=,$(MAKEFLAGS)) recurse: ; @echo $@: "/$(SHOW)/"; $(MAKE) -j -f #MAKEFILE# recurse2 recurse2: ; @echo $@: "/$(SHOW)/"; $(MAKE) -f #MAKEFILE# all all:;@echo $@: "/$(SHOW)/" !, "-j2 $np", "recurse: /-j2 --jobserver-auth= $np/\n#MAKE#[1]: warning: -jN forced in submake: disabling jobserver mode.\nrecurse2: /-j $np/\nall: /-j $np/\n"); # Don't put --jobserver-auth into a re-exec'd MAKEFLAGS. # We can't test this directly because there's no way a makefile can # show the value of MAKEFLAGS we were re-exec'd with. We can intuit it # by looking for "disabling jobserver mode" warnings; we should only # get one from the original invocation and none from the re-exec. # See Savannah bug #18124 unlink('inc.mk'); run_make_test(q! -include inc.mk recur: # @echo 'MAKEFLAGS = $(MAKEFLAGS)' @rm -f inc.mk @$(MAKE) -j2 -f #MAKEFILE# all all: # @echo 'MAKEFLAGS = $(MAKEFLAGS)' @echo $@ inc.mk: # @echo 'MAKEFLAGS = $(MAKEFLAGS)' @echo 'FOO = bar' > $@ !, "$np -j2", "#MAKE#[1]: warning: -jN forced in submake: disabling jobserver mode.\nall\n"); unlink('inc.mk'); # Test recursion when make doesn't think it exists. # See Savannah bug #39934 # Or Red Hat bug https://bugzilla.redhat.com/show_bug.cgi?id=885474 open(MAKEFILE,"> Makefile2"); print MAKEFILE ' vpath %.c ../ foo: '; close(MAKEFILE); run_make_test(q! default: ; @ #MAKEPATH# -f Makefile2 !, "-j2 $np", "#MAKE#[1]: warning: jobserver unavailable: using -j1. Add '+' to parent make rule. #MAKE#[1]: Nothing to be done for 'foo'."); rmfiles('Makefile2'); 1; ### Local Variables: ### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) ### End: kbuild-3149/src/kmk/tests/scripts/features/conditionals0000644000175000017500000000507113252530201023331 0ustar locutuslocutus# -*-perl-*- $description = "Check GNU make conditionals."; $details = "Attempt various different flavors of GNU make conditionals."; run_make_test(' arg1 = first arg2 = second arg3 = third arg4 = cc arg5 = second all: ifeq ($(arg1),$(arg2)) @echo arg1 equals arg2 else @echo arg1 NOT equal arg2 endif ifeq \'$(arg2)\' "$(arg5)" @echo arg2 equals arg5 else @echo arg2 NOT equal arg5 endif ifneq \'$(arg3)\' \'$(arg4)\' @echo arg3 NOT equal arg4 else @echo arg3 equal arg4 endif ifndef undefined @echo variable is undefined else @echo variable undefined is defined endif ifdef arg4 @echo arg4 is defined else @echo arg4 is NOT defined endif', '', 'arg1 NOT equal arg2 arg2 equals arg5 arg3 NOT equal arg4 variable is undefined arg4 is defined'); # Test expansion of variables inside ifdef. run_make_test(' foo = 1 FOO = foo F = f DEF = no DEF2 = no ifdef $(FOO) DEF = yes endif ifdef $(F)oo DEF2 = yes endif DEF3 = no FUNC = $1 ifdef $(call FUNC,DEF)3 DEF3 = yes endif all:; @echo DEF=$(DEF) DEF2=$(DEF2) DEF3=$(DEF3)', '', 'DEF=yes DEF2=yes DEF3=yes'); # Test all the different "else if..." constructs run_make_test(' arg1 = first arg2 = second arg3 = third arg4 = cc arg5 = fifth result = ifeq ($(arg1),$(arg2)) result += arg1 equals arg2 else ifeq \'$(arg2)\' "$(arg5)" result += arg2 equals arg5 else ifneq \'$(arg3)\' \'$(arg3)\' result += arg3 NOT equal arg4 else ifndef arg5 result += variable is undefined else ifdef undefined result += arg4 is defined else result += success endif all: ; @echo $(result)', '', 'success'); # Test some random "else if..." construct nesting run_make_test(' arg1 = first arg2 = second arg3 = third arg4 = cc arg5 = second ifeq ($(arg1),$(arg2)) $(info failed 1) else ifeq \'$(arg2)\' "$(arg2)" ifdef undefined $(info failed 2) else $(info success) endif else ifneq \'$(arg3)\' \'$(arg3)\' $(info failed 3) else ifdef arg5 $(info failed 4) else ifdef undefined $(info failed 5) else $(info failed 6) endif .PHONY: all all: ; @:', '', 'success'); # SV 47960 : ensure variable assignments in non-taken legs don't cause problems run_make_test(' ifneq ($(FOO),yes) target: else BAR = bar target: endif @echo one ', '', "one\n"); # This tells the test driver that the perl test script executed properly. 1; ### Local Variables: ### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) ### End: kbuild-3149/src/kmk/tests/scripts/features/order_only0000644000175000017500000000433513252530202023022 0ustar locutuslocutus# -*-perl-*- $description = "Test order-only prerequisites."; $details = "\ Create makefiles with various combinations of normal and order-only prerequisites and ensure they behave properly. Test the \$| variable."; # TEST #0 -- Basics run_make_test(' %r: | baz ; @echo $< $^ $| bar: foo foo:;@: baz:;@:', '', "foo foo baz\n"); # TEST #1 -- First try: the order-only prereqs need to be built. run_make_test(q! foo: bar | baz @echo '$$^ = $^' @echo '$$| = $|' touch $@ .PHONY: baz bar baz: touch $@!, '', "touch bar\ntouch baz\n\$^ = bar\n\$| = baz\ntouch foo\n"); # TEST #2 -- now we do it again: baz is PHONY but foo should _NOT_ be updated run_make_test(undef, '', "touch baz\n"); unlink(qw(foo bar baz)); # TEST #3 -- Make sure the order-only prereq was promoted to normal. run_make_test(q! foo: bar | baz @echo '$$^ = $^' @echo '$$| = $|' touch $@ foo: baz .PHONY: baz bar baz: touch $@!, '', "touch bar\ntouch baz\n\$^ = bar baz\n\$| = \ntouch foo\n"); # TEST #4 -- now we do it again run_make_test(undef, '', "touch baz\n\$^ = bar baz\n\$| = \ntouch foo\n"); unlink(qw(foo bar baz)); # Test empty normal prereqs # TEST #5 -- make sure the parser was correct. run_make_test(q! foo:| baz @echo '$$^ = $^' @echo '$$| = $|' touch $@ .PHONY: baz baz: touch $@!, '', "touch baz\n\$^ = \n\$| = baz\ntouch foo\n"); # TEST #6 -- now we do it again: this time foo won't be built run_make_test(undef, '', "touch baz\n"); unlink(qw(foo baz)); # Test order-only in pattern rules # TEST #7 -- make sure the parser was correct. run_make_test(q! %.w : %.x | baz @echo '$$^ = $^' @echo '$$| = $|' touch $@ all: foo.w .PHONY: baz foo.x baz: touch $@!, '', "touch foo.x\ntouch baz\n\$^ = foo.x\n\$| = baz\ntouch foo.w\n"); # TEST #8 -- now we do it again: this time foo.w won't be built run_make_test(undef, '', "touch baz\n"); unlink(qw(foo.w foo.x baz)); # TEST #9 -- make sure that $< is set correctly in the face of order-only # prerequisites in pattern rules. run_make_test(' %r: | baz ; @echo $< $^ $| bar: foo foo:;@: baz:;@:', '', "foo foo baz\n"); 1; kbuild-3149/src/kmk/tests/scripts/features/ifcond0000644000175000017500000002440213252530202022105 0ustar locutuslocutus# $Id: ifcond 2413 2010-09-11 17:43:04Z bird $ -*-perl-*- ## @file # if conditionals. # # # Copyright (c) 2008-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # $description = "Tests the if conditionals"; $details = "..."; if ($is_kmk) { # TEST #0 - check that the feature is present. # -------------------------------------------- run_make_test(' ifneq ($(if-expr 1+1,1,0),1) $(error sub-test 0 failed) endif .PHONY: all all: ; @: ', '', ''); # TEST #1 - A more comprehensive, yet a bit large, test. # ------------------------------------------------------ run_make_test(' # # Note! The testcase are ordered by ascending operator precedence # with the exception of equal and not-equal because these # are kind of useful for performing tests on non-logical ops. # .PHONY: all all: ; @: # # Parenthesis # $(info unary operators: ( and )) if (1) else $(error ) endif if ((((1)))) else $(error ) endif # # Equal and Not Equal w/ some fundamental bits thrown in. # $(info binary operators: == and !=) if 1 == 1 else $(error ) endif if 2 == 3 $(error ) else endif if 2 != 3 else $(error ) endif if a != b else $(error ) endif if asdf == asdf else $(error ) endif if "asdf" == asdf else $(error ) endif if \'asdf\' == asdf else $(error ) endif if \'asdf\' == "asdf" else $(error ) endif if \'asdf\' == \'asdf\' else $(error ) endif if "asdf" == "asdf" else $(error ) endif if 0x1 == 1 else $(error ) endif if 0xfff == 4095 else $(error ) endif if 0xfff == 4095 else $(error ) endif if 0d10 == 10 else $(error ) endif if 0d10 == 10 else $(error ) endif if 0xa == 012 else $(error ) endif if 0b1110 == 016 else $(error ) endif # # Logical OR # $(info binary operator: ||) if 1 else $(error busted) endif if 1 || 1 else $(error ) endif if 0 || 0 $(error ) else endif if 1 || 0 else $(error ) endif if 0 || 1 else $(error ) endif if 0 || 0 || 0 || 0 || 0 || 0 || 0 $(error ) else endif if 0 || 0 || 0 || 1 || 0 || 0 || 0 else $(error ) endif if "asdf" || 0 else $(error ) endif if 0 || "asdf" else $(error ) endif if \'asdf\' || 0 else $(error ) endif if "" || 0 $(error ) endif if "" || 1 else $(error ) endif if \'\' || 0 $(error ) endif if \'\' || 1 else $(error ) endif if "" || \'\' $(error ) endif if "1" || \'\' else $(error ) endif if "1" || \'1\' else $(error ) endif if "" || \'1\' else $(error ) endif # # Logical AND # $(info binary operator: &&) if 1 && 1 else $(error ) endif if 1 && 0 $(error ) endif if 1234 && 0 $(error ) endif if 123434 && 0 && 123435 && 1 $(error ) endif if "" && 1 $(error ) endif if ("asdf" && 1) != 1 $(error ) endif if "1" && \'asdf\' else $(error ) endif if "1" && \'asdf\' && 0 $(error ) endif if 0 || 1 && 0 $(error ) endif # # Bitwise OR # $(info binary operator: |) if 1 | 0 else $(error ) endif if 1 | 1 else $(error ) endif if 11234 | 343423 else $(error ) endif if (1|2)!=3 $(error ) endif if 1|2 != 3 else $(error ) endif if (1|2|4|8)!=0xf $(error ) endif # # Bitwise XOR # $(info binary operator: ^) if 1 ^ 1 $(error ) endif if (2 ^ 1) != 3 $(error ) endif if 7 != (2 ^ 1 ^ 4) $(error ) endif if (2 ^ 1 | 2) != 3 $(error ) endif # # Bitwise AND # $(info binary operator: &) if (4097 & 1) != 1 $(error ) endif if (0xfff & 0x0f0) != 0xf0 $(error ) endif if (0x1e3 & 0x100 | 3) != 0x103 $(error ) endif # # Greater than # $(info binary operator: >) if 1 > 0 else $(error ) endif if 1024 > 1023 else $(error ) endif if 999 > 1023 $(error ) endif if (5 > 4 | 2) != 3 $(error ) endif if (1 & 8 > 4) != 1 $(error ) endif if (8 > 4 ^ 16) != 17 $(error ) endif if "b" > \'a\' else $(error ) endif if "abcdef" > \'ffdas\' $(error ) endif if abcdef > ffdas $(error ) endif # # Greater or equal than # $(info binary operator: >=) if 20 > 0 else $(error ) endif if 20 >= 20 else $(error ) endif if 19 >= 20 $(error ) endif if (1 & 8 >= 4) != 1 $(error ) endif if "x" >= \'x\' else $(error ) endif if "abdc" >= \'abcd\' else $(error ) endif if "ffdaaa" >= \'ffdasd\' $(error ) endif if asdf >= asdf else $(error ) endif # # Less than # if 1 < 1 $(error ) endif if -123 < -134 $(error ) endif if 123 <= 7777 else $(error ) endif if "b" < \'a\' $(error ) endif if b < a $(error ) endif if \'foobar\' < \'a$\' $(error ) endif if hhhh < ggggg $(error ) endif if qwerty < qwerty0 else $(error ) endif # # Less or equal than # $(info binary operator: >>) if 1 <= 0 $(error ) endif if 1 <= 1 else $(error ) endif if 123 <= 123 != 1 $(error ) endif if 560 <= 456 $(error ) endif if "a" <= \'a\' else $(error ) endif if "abcdef" <= \'abcdef\' else $(error ) endif if q12345z6 <= q12345z $(error ) endif if QWERTY <= ABCDE $(error ) endif # # Shift right # $(info binary operator: >>) if 1 >> 0 != 1 $(error ) endif if 1024 >> 2 != 256 $(error ) endif if 102435 >> 4 > 1234 != 1 $(error ) endif # # Shift left # $(info binary operator: <<) if 1 << 0 != 1 $(error ) endif if 1 << 1 != 2 $(error ) endif if 1 << 4 != 16 $(error ) endif if 1 << 10 != 1024 $(error ) endif if 34 << 10 != 0x8800 $(error ) endif if 1099511627776 << 21 != 2305843009213693952 $(error ) endif if 1 << 61 != 2305843009213693952 $(error ) endif if 2 << 60 > 123434323 != 1 $(error ) endif # # Subtraction # $(info binary operator: -) if 1-1 != 0 $(error ) endif if 1023-511 != 512 $(error ) endif if 4 - 3 << 3 != 8 $(error ) endif # # Addition # $(info binary operator: +) if 1+1 != 2 $(error ) endif if 1234+1000 != 2234 $(error ) endif if 2 + 2 << 4 != 64 $(error ) endif # # Modulus # $(info binary operator: %) if 0%2 != 0 $(error ) endif if 10%7 != 3 $(error ) endif if 10 + 100%70 - 3 != 37 $(error ) endif # # Division # $(info binary operator: /) if 0/1 != 0 $(error ) endif if 1000/2 != 500 $(error ) endif if 1000/2 + 4 != 504 $(error ) endif if 5 + 1000/4 != 255 $(error ) endif # # Multiplication # $(info binary operator: *) if 1*1 != 1 $(error ) endif if 10*10 != 100 $(error ) endif if 1024*64 != 65536 $(error ) endif if 10*10 - 10 != 90 $(error ) endif if 1000 - 10*10 != 900 $(error ) endif # # Logical NOT # $(info unary operator: !) if !1 $(error ) endif if !42 == 0 else $(error ) endif if !0 == 1 else $(error ) endif if !!0 == 0 else $(error ) endif if !0 * 123 != 123 $(error ) endif if !!!0 * 512 != 512 $(error ) endif # # Bitwise NOT # $(info unary operator: ~) if ~0xfff != 0xfffffffffffff000 $(error ) endif # # Pluss # $(info unary operator: +) if +2 != 2 $(error ) endif if 1++++++++++++2134 != 2135 $(error ) endif # # Minus (negation) # $(info unary operator: -) if --2 != 2 $(error ) endif if 1 - -2 != 3 $(error ) endif # # target # trg_deps_only: foobar trg_with_cmds: foobar echo $@ $(info unary operator: target) # This flushes stuff in read.c if target trg_with_cmds else $(error target trg_with_cmds) endif if target(trg_deps_only) $(error target trg_deps_only) endif if target ( foobar ) $(error target foobar) endif # # defined # $(info unary operator: defined) var_defined := 1 var_not_defined := if defined var_defined else $(error ) endif if defined(var_defined) else $(error ) endif if defined (var_defined) else $(error ) endif if !defined(var_defined) $(error ) endif if defined (var_not_defined) $(error ) endif # # bool # $(info unary operator: bool) if bool("Asdf") != 1 $(error ) endif if bool("") != 0 $(error ) endif # # bool # $(info unary operator: num) if num("1234") != 1235 - 1 $(error ) endif if num(\'1234\') != 1233 + 1 $(error ) endif # # str # $(info unary operator: str) if str(a < b) != 1 $(error ) endif if str(a < b) != \'1\' $(error ) endif if str( 1 ) != "1" $(error ) endif if str( 1 ) != "1" $(error ) endif if str( num(0x1000) ) != "4096" $(error ) endif if str(0x1000) != 0x1000 $(error ) endif # # Quick check of $(if-expr ) and $(expr ). # $(info $$(if-expr ,,)) ifeq ($(if-expr 0 || 2,42,500),42) else $(error ) endif ifeq ($(if-expr 5+3 == 231,42,500),42) $(error ) endif $(info $$(expr )) ifeq ($(expr 5+3),8) else $(error expr:$(expr 5+3) expected 8) endif ifeq ($(expr 25*25),625) else $(error expr:$(expr 25*25) expected 625) endif ifeq ($(expr 100/3),3) $(error ) endif ', '', 'unary operators: ( and ) binary operators: == and != binary operator: || binary operator: && binary operator: | binary operator: ^ binary operator: & binary operator: > binary operator: >= binary operator: >> binary operator: >> binary operator: << binary operator: - binary operator: + binary operator: % binary operator: / binary operator: * unary operator: ! unary operator: ~ unary operator: + unary operator: - unary operator: target unary operator: defined unary operator: bool unary operator: num unary operator: str $(if-expr ,,) $(expr ) '); } # TEST #2 - A bug. # ------------------------------------------------------ run_make_test(' .PHONY: all all: ; @: # # Assert sanity first on simple strings. # if abcd != "abcd" $(error ) endif if \'abcd\' != abcd $(error ) endif if abcd != abcd $(error ) endif # # String by reference, start with a few simple cases. # STR1 = abcd if "$(STR1)" != "abcd" $(error ) endif if \'$(STR1)\' == "abcd" # not expanded. $(error ) endif if \'$(STR1)\' != \'$(STR1)\' $(error ) endif if "$(STR1)" != "$(STR1)" $(error ) endif # # Now for the kmk 0.1.4 bug... # if $(STR1) != "$(STR1)" $(error ) endif if "$(STR1)" != $(STR1) $(error ) endif if $(STR1) != $(STR1) $(error ) endif # # And some extra for good measure. # STR2 = STR NUM1 = 1 if $($(STR2)$(NUM1)) != "abcd" $(error ) endif if "abcd" != $($(STR2)$(NUM1)) $(error ) endif if "abcd" != $(${STR2}$(NUM1)) $(error ) endif if "abcd" != ${$(STR2)$(NUM1)} $(error ) endif if "abcd" != ${${STR2}${NUM1}} $(error ) endif if ${${STR2}${NUM1}} != \'abcd\' $(error ) endif if "${${STR2}${NUM1}}" != \'abcd\' $(error ) endif ', '', ''); # Indicate that we're done. 1; kbuild-3149/src/kmk/tests/scripts/features/vpath20000644000175000017500000000233713252530202022052 0ustar locutuslocutus$description = "This is part 2 in a series to test the vpath directive\n" ."It tests the three forms of the directive:\n" ." vpath pattern directive\n" ." vpath pattern (clears path associated with pattern)\n" ." vpath (clears all paths specified with vpath)\n"; $details = "This test simply adds many search paths using various vpath\n" ."directive forms and clears them afterwards. It has a simple\n" ."rule to print a message at the end to confirm that the makefile\n" ."ran with no errors.\n"; open(MAKEFILE,"> $makefile"); # The Contents of the MAKEFILE ... print MAKEFILE "VPATH = $workdir:$sourcedir\n"; print MAKEFILE "vpath %.c foo\n"; print MAKEFILE "vpath %.c $workdir\n"; print MAKEFILE "vpath %.c $sourcedir\n"; print MAKEFILE "vpath %.h $workdir\n"; print MAKEFILE "vpath %.c\n"; print MAKEFILE "vpath\n"; print MAKEFILE "all:\n"; print MAKEFILE "\t\@echo ALL IS WELL\n"; # END of Contents of MAKEFILE close(MAKEFILE); &run_make_with_options($makefile,"",&get_logfile); # Create the answer to what should be produced by this Makefile $answer = "ALL IS WELL\n"; &compare_output($answer,&get_logfile(1)); 1; kbuild-3149/src/kmk/tests/scripts/features/patspecific_vars0000644000175000017500000000622213252530201024167 0ustar locutuslocutus# -*-perl-*- $description = "Test pattern-specific variable settings."; $details = "\ Create a makefile containing various flavors of pattern-specific variable settings, override and non-override, and using various variable expansion rules, semicolon interference, etc."; open(MAKEFILE,"> $makefile"); print MAKEFILE <<'EOF'; all: one.x two.x three.x FOO = foo BAR = bar BAZ = baz one.x: override FOO = one %.x: BAR = two t%.x: BAR = four thr% : override BAZ = three one.x two.x three.x: ; @echo $@: $(FOO) $(BAR) $(BAZ) four.x: baz ; @echo $@: $(FOO) $(BAR) $(BAZ) baz: ; @echo $@: $(FOO) $(BAR) $(BAZ) # test matching multiple patterns a%: AAA = aaa %b: BBB = ccc a%: BBB += ddd %b: AAA ?= xxx %b: AAA += bbb .PHONY: ab ab: ; @echo $(AAA); echo $(BBB) EOF close(MAKEFILE); # TEST #1 -- basics &run_make_with_options($makefile, "-j1", &get_logfile); $answer = "one.x: one two baz\ntwo.x: foo four baz\nthree.x: foo four three\n"; &compare_output($answer,&get_logfile(1)); # TEST #2 -- try the override feature &run_make_with_options($makefile, "-j1 BAZ=five", &get_logfile); $answer = "one.x: one two five\ntwo.x: foo four five\nthree.x: foo four three\n"; &compare_output($answer,&get_logfile(1)); # TEST #3 -- make sure patterns are inherited properly &run_make_with_options($makefile, "-j1 four.x", &get_logfile); $answer = "baz: foo two baz\nfour.x: foo two baz\n"; &compare_output($answer,&get_logfile(1)); # TEST #4 -- test multiple patterns matching the same target &run_make_with_options($makefile, "-j1 ab", &get_logfile); $answer = "aaa bbb\nccc ddd\n"; &compare_output($answer,&get_logfile(1)); # TEST #5 -- test pattern-specific exported variables # run_make_test(' /%: export foo := foo /bar: @echo $(foo) $$foo ', '-j1', 'foo foo'); # TEST #6 -- test expansion of pattern-specific simple variables # run_make_test(' .PHONY: all all: inherit := good $$t all: bar baz b%: pattern := good $$t global := original $$t # normal target # ifdef rec bar: a = global: $(global) pattern: $(pattern) inherit: $(inherit) else bar: a := global: $(global) pattern: $(pattern) inherit: $(inherit) endif bar: ; @echo \'normal: $a;\' # pattern target # ifdef rec %z: a = global: $(global) pattern: $(pattern) inherit: $(inherit) else %z: a := global: $(global) pattern: $(pattern) inherit: $(inherit) endif %z: ; @echo \'pattern: $a;\' global := new $$t ', '-j1', 'normal: global: original $t pattern: inherit: ; pattern: global: original $t pattern: inherit: ;'); # TEST #7 -- test expansion of pattern-specific recursive variables # run_make_test(undef, # reuse previous makefile '-j1 rec=1', 'normal: global: new $t pattern: good $t inherit: good $t; pattern: global: new $t pattern: good $t inherit: good $t;'); # TEST #8: override in pattern-specific variables run_make_test(' a%: override FOO += f1 a%: FOO += f2 ab: ; @echo "$(FOO)" ', '', "f1\n"); run_make_test(undef, 'FOO=C', "C f1\n"); # TEST #9: Test shortest stem selection in pattern-specific variables. run_make_test(' %-mt.x: x := two %.x: x := one all: foo.x foo-mt.x foo.x: ;@echo $x foo-mt.x: ;@echo $x ', '', "one\ntwo"); 1; kbuild-3149/src/kmk/tests/scripts/features/comments0000644000175000017500000000234313252530201022467 0ustar locutuslocutus$description = "The following test creates a makefile to test comments\n" ."and comment continuation to the next line using a \n" ."backslash within makefiles."; $details = "To test comments within a makefile, a semi-colon was placed \n" ."after a comment was started. This should not be reported as\n" ."an error since it is within a comment. We then continue the \n" ."comment to the next line using a backslash. To test whether\n" ."the comment really continued, we place an echo command with some\n" ."text on the line which should never execute since it should be \n" ."within a comment\n"; open(MAKEFILE,"> $makefile"); # The Contents of the MAKEFILE ... print MAKEFILE <<\EOF; # Test comment vs semicolon parsing and line continuation target: # this ; is just a comment \ @echo This is within a comment. @echo There should be no errors for this makefile. EOF # END of Contents of MAKEFILE close(MAKEFILE); &run_make_with_options($makefile,"",&get_logfile); # Create the answer to what should be produced by this Makefile $answer = "There should be no errors for this makefile.\n"; # COMPARE RESULTS &compare_output($answer,&get_logfile(1)) kbuild-3149/src/kmk/tests/scripts/features/output-sync0000644000175000017500000002162313252530202023157 0ustar locutuslocutus# -*-perl-*- $description = "Test --output-sync (-O) option."; $details = "Test the synchronization of output from parallel jobs."; # If we don't have output sync support, never mind. exists $FEATURES{'output-sync'} or return -1; # Output sync can't be tested without parallelization $parallel_jobs or return -1; if ($vos) { $sleep_command = "sleep -seconds"; } else { $sleep_command = "sleep"; } # The following subdirectories with Makefiles are used in several # of the following tests. The model is: # foo/Makefile - has a "foo" target that waits for the bar target # bar/Makefile - has a "bar" target that runs immediately # - has a "baz" target that waits for the foo target # # So, you start the two sub-makes in parallel and first the "bar" target is # built, followed by "foo", followed by "baz". The trick is that first each # target prints a "start" statement, then waits (if appropriate), then prints # an end statement. Thus we can tell if the -O flag is working, since # otherwise these statements would be mixed together. @syncfiles = (); sub output_sync_clean { rmfiles('foo/Makefile', 'bar/Makefile', @syncfiles); rmdir('foo'); rmdir('bar'); } # We synchronize the different jobs by having them wait for a sentinel file to # be created, instead of relying on a certain amount of time passing. # Unfortunately in this test we have to sleep after we see the sync file, # since we also want to make the obtaining of the write synchronization lock # reliable. If things are too fast, then sometimes a different job will steal # the output sync lock and the output is mis-ordered from what we expect. sub output_sync_wait { return "while [ ! -f ../mksync.$_[0] ]; do :; done; rm -f ../mksync.$_[0].wait; $sleep_command 1"; } sub output_sync_set { return "date > ../mksync.$_[0]"; } @syncfiles = qw(mksync.foo mksync.foo_start mksync.bar mksync.bar_start); $tmout = 30; output_sync_clean(); mkdir('foo', 0777); mkdir('bar', 0777); $set_foo = output_sync_set('foo'); $set_bar = output_sync_set('bar'); $set_foo_start = output_sync_set('foo_start'); $set_bar_start = output_sync_set('bar_start'); $wait_foo = output_sync_wait('foo'); $wait_bar = output_sync_wait('bar'); $wait_foo_start = output_sync_set('foo_start'); $wait_bar_start = output_sync_set('bar_start'); open(MAKEFILE,"> foo/Makefile"); print MAKEFILE < bar/Makefile"); print MAKEFILE <&2) !, '-w -Oline', "#MAKE#: Entering directory '#PWD#'\nfoo\n#MAKE#: Leaving directory '#PWD#'\n"); # Ensure that output generated while parsing makefiles is synced # when appropriate. run_make_test(q! $(shell echo foo 1>&2) all: ; echo bar !, '-s -w -Otarget', "#MAKE#: Entering directory '#PWD#'\nfoo\n#MAKE#: Leaving directory '#PWD#'\n#MAKE#: Entering directory '#PWD#'\nbar\n#MAKE#: Leaving directory '#PWD#'\n"); # Test recursion $m1 = get_tmpfile(); $m2 = get_tmpfile(); open(M1, "> $m1"); print M1 <<'EOF'; $(shell echo d1 stderr 1>&2) $(info d1 stdout) all:; @: EOF close(M1); open(M2, "> $m2"); print M2 <<'EOF'; $(shell echo d2 stderr 1>&2) $(info d2 stdout) all:; @: # Force an ordering on the output $(shell sleep 1) EOF close(M2); run_make_test(qq! all: t1 t2 t1: ; \@\$(MAKE) -f $m1 t2: ; \@\$(MAKE) -f $m2 !, "-j -Oline", "#MAKE#[1]: Entering directory '#PWD#'\nd1 stderr\nd1 stdout\n#MAKE#[1]: Leaving directory '#PWD#'\n#MAKE#[1]: Entering directory '#PWD#'\nd2 stderr\nd2 stdout\n#MAKE#[1]: Leaving directory '#PWD#'\n"); rmfiles($m1, $m2); # Ensure that output generated while parsing makefiles is synced # when appropriate. $m1 = get_tmpfile(); open(M1, "> $m1"); print M1 <<'EOF'; $(shell echo d1 stderr 1>&2) $(info d1 stdout) $(error d1 failed) all:; @: EOF close(M1); run_make_test(qq! all: t1 t1: ; -\@\$(MAKE) -f $m1 !, "-j -Oline", "#MAKE#[1]: Entering directory '#PWD#'\nd1 stderr\nd1 stdout\n$m1:3: *** d1 failed. Stop.\n#MAKE#[1]: Leaving directory '#PWD#'\n#MAKE#: [#MAKEFILE#:3: t1] Error 2 (ignored)\n"); rmfiles($m1); # Test $(error ...) functions in recipes run_make_test(q! foo: $(OBJS) ; echo $(or $(filter %.o,$^),$(error fail)) !, '-O', "#MAKEFILE#:2: *** fail. Stop.\n", 512); # SV 47365: Make sure exec failure error messages are shown # Is "127" not always the same everywhere? We may have to detect it? run_make_test(q! all:: ; @./foo bar baz !, '-O', "#MAKE#: ./foo: Command not found\n#MAKE#: *** [#MAKEFILE#:2: all] Error 127\n", 512); # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/features/archives0000644000175000017500000001406413252530201022451 0ustar locutuslocutus# -*-mode: perl-*- $description = "Test GNU make's archive management features."; $details = "\ This only works on systems that support it."; # If this instance of make doesn't support archives, skip it exists $FEATURES{archives} or return -1; # Create some .o files to work with if ($osname eq 'VMS') { use Cwd; my $pwd = getcwd; # VMS AR needs real object files at this time. foreach $afile ('a1', 'a2', 'a3') { # Use non-standard extension to prevent implicit rules from recreating # objects when the test tampers with the timestamp. 1 while unlink "$afile.c1"; 1 while unlink "$afile.o"; open (MYFILE, ">$afile.c1"); print MYFILE "int $afile(void) {return 1;}\n"; close MYFILE; system("cc $afile.c1 /object=$afile.o"); } } else { utouch(-60, qw(a1.o a2.o a3.o)); } my $ar = $CONFIG_FLAGS{AR}; # Fallback if configure did not find AR, such as VMS # which does not run configure. $ar = 'ar' if $ar eq ''; my $redir = '2>&1'; $redir = '' if $osname eq 'VMS'; my $arflags = 'rv'; my $arvar = "AR=$ar"; # Newer versions of binutils can be built with --enable-deterministic-archives # which forces all timestamps (among other things) to always be 0, defeating # GNU make's archive support. See if ar supports the U option to disable it. unlink('libxx.a'); $_ = `$ar U$arflags libxx.a a1.o $redir`; if ($? == 0) { $arflags = 'Urv'; $arvar = "$arvar ARFLAGS=$arflags"; } # Some versions of ar print different things on creation. Find out. unlink('libxx.a'); my $created = `$ar $arflags libxx.a a1.o $redir`; # Some versions of ar print different things on add. Find out. my $add = `$ar $arflags libxx.a a2.o $redir`; $add =~ s/a2\.o/#OBJECT#/g; # Some versions of ar print different things on replacement. Find out. my $repl = `$ar $arflags libxx.a a2.o $redir`; $repl =~ s/a2\.o/#OBJECT#/g; unlink('libxx.a'); # Very simple my $answer = "$ar $arflags libxx.a a1.o\n$created"; if ($port_type eq 'VMS-DCL') { $answer = 'library /replace libxx.a a1.o'; } run_make_test('all: libxx.a(a1.o)', $arvar, $answer); # Multiple .o's. Add a new one to the existing library ($_ = $add) =~ s/#OBJECT#/a2.o/g; $answer = "$ar $arflags libxx.a a2.o\n$_"; if ($port_type eq 'VMS-DCL') { $answer = 'library /replace libxx.a a2.o'; } run_make_test('all: libxx.a(a1.o a2.o)', $arvar, $answer); # Touch one of the .o's so it's rebuilt if ($port_type eq 'VMS-DCL') { # utouch is not changing what VMS library compare is testing for. # So do a real change by regenerating the file. 1 while unlink('a1.o'); # Later time stamp than last insertion. sleep(2); system('cc a1.c1 /object=a1.o'); # Next insertion will have a later timestamp. sleep(2); } else { utouch(-40, 'a1.o'); } ($_ = $repl) =~ s/#OBJECT#/a1.o/g; $answer = "$ar $arflags libxx.a a1.o\n$_"; if ($port_type eq 'VMS-DCL') { $answer = 'library /replace libxx.a a1.o'; } run_make_test(undef, $arvar, $answer); # Use wildcards $answer = "#MAKE#: Nothing to be done for 'all'.\n"; run_make_test('all: libxx.a(*.o)', $arvar, $answer); # Touch one of the .o's so it's rebuilt if ($port_type eq 'VMS-DCL') { # utouch is not changing what VMS library compare is testing for. # So do a real change by regenerating the file. 1 while unlink('a1.o'); # Make timestamp later than last insertion. sleep(2); system('cc a1.c1 /object=a1.o'); } else { utouch(-30, 'a1.o'); } ($_ = $repl) =~ s/#OBJECT#/a1.o/g; $answer = "$ar $arflags libxx.a a1.o\n$_"; if ($port_type eq 'VMS-DCL') { $answer = 'library /replace libxx.a a1.o'; } run_make_test(undef, $arvar, $answer); # Use both wildcards and simple names if ($port_type eq 'VMS-DCL') { # utouch is not changing what VMS library compare is testing for. # So do a real change by regenerating the file. 1 while unlink('a2.o'); sleep(2); system('cc a2.c1 /object=a2.o'); } else { utouch(-50, 'a2.o'); } ($_ = $add) =~ s/#OBJECT#/a3.o/g; $_ .= "$ar $arflags libxx.a a2.o\n"; ($_ .= $repl) =~ s/#OBJECT#/a2.o/g; $answer = "$ar $arflags libxx.a a3.o\n$_"; if ($port_type eq 'VMS-DCL') { $answer = 'library /replace libxx.a a3.o'; } run_make_test('all: libxx.a(a3.o *.o)', $arvar, $answer); # Check whitespace handling if ($port_type eq 'VMS-DCL') { # utouch is not changing what VMS library compare is testing for. # So do a real change by regenerating the file. 1 while unlink('a2.o'); sleep(2); system('cc a2.c1 /object=a2.o'); } else { utouch(-40, 'a2.o'); } ($_ = $repl) =~ s/#OBJECT#/a2.o/g; $answer = "$ar $arflags libxx.a a2.o\n$_"; if ($port_type eq 'VMS-DCL') { $answer = 'library /replace libxx.a a2.o'; } run_make_test('all: libxx.a( a3.o *.o )', $arvar, $answer); rmfiles(qw(a1.c1 a2.c1 a3.c1 a1.o a2.o a3.o libxx.a)); # Check non-archive targets # See Savannah bug #37878 $mk_string = q! all: foo(bar).baz foo(bar).baz: ; @echo '$@' !; if ($port_type eq 'VMS-DCL') { $mk_string =~ s/echo/write sys\$\$output/; $mk_string =~ s/\'/\"/g; } run_make_test($mk_string, $arvar, "foo(bar).baz\n"); # Check renaming of archive targets. # See Savannah bug #38442 mkdir('artest', 0777); touch('foo.vhd'); $mk_string = q! DIR = artest vpath % $(DIR) default: lib(foo) (%): %.vhd ; @cd $(DIR) && touch $(*F) && $(AR) $(ARFLAGS) $@ $(*F) >/dev/null 2>&1 && rm $(*F) .PHONY: default !; if ($port_type eq 'VMS-DCL') { $mk_string =~ s#= artest#= sys\$\$disk:\[.artest\]#; $mk_string =~ s#lib\(foo\)#lib.tlb\(foo\)#; $mk_string =~ s#; \@cd#; pipe SET DEFAULT#; $mk_string =~ s#touch \$\(\*F\)#touch \$\(\*F\) && library/create/text sys\$\$disk:\$\@#; $mk_string =~ s#library#if f\$\$search(\"\$\@\") \.eqs\. \"\" then library#; # VMS needs special handling for null extension $mk_string =~ s#\@ \$\(\*F\)#\@ \$\(\*F\)\.#; $mk_string =~ s#>/dev/null 2>&1 ##; } run_make_test($mk_string, $arvar, ""); run_make_test(undef, $arvar, "#MAKE#: Nothing to be done for 'default'.\n"); unlink('foo.vhd'); if ($osname eq 'VMS') { remove_directory_tree("$pwd/artest"); } else { remove_directory_tree('artest'); } # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/features/quoting0000644000175000017500000000131213252530202022324 0ustar locutuslocutus# -*-perl-*- $description = "The following test creates a makefile to test using \n" . "quotes within makefiles."; open(MAKEFILE,"> $makefile"); # The Contents of the MAKEFILE ... print MAKEFILE <<'EOM'; SHELL = /bin/sh TEXFONTS = NICEFONT DEFINES = -DDEFAULT_TFM_PATH=\".:$(TEXFONTS)\" test: ; @"echo" 'DEFINES = $(DEFINES)' EOM # END of Contents of MAKEFILE close(MAKEFILE); &run_make_with_options($makefile,"",&get_logfile); # Create the answer to what should be produced by this Makefile $answer = 'DEFINES = -DDEFAULT_TFM_PATH=\".:NICEFONT\"' . "\n"; # COMPARE RESULTS &compare_output($answer,&get_logfile(1)); 1; kbuild-3149/src/kmk/tests/scripts/features/varnesting0000644000175000017500000000116513252530202023024 0ustar locutuslocutus# -*-perl-*- $description = "Test recursive variables"; $details = ""; run_make_test(' x = variable1 variable2 := Hello y = $(subst 1,2,$(x)) z = y a := $($($(z))) all: @echo $(a) ', '', "Hello\n"); # This tests resetting the value of a variable while expanding it. # You may only see problems with this if you're using valgrind or # some other memory checker that poisons freed memory. # See Savannah patch #7534 run_make_test(' VARIABLE = $(eval VARIABLE := echo hi)$(VARIABLE) wololo: @$(VARIABLE) ', '', "hi\n"); 1; kbuild-3149/src/kmk/tests/scripts/features/load0000644000175000017500000000535313252530201021565 0ustar locutuslocutus# -*-perl-*- $description = "Test the load operator."; $details = "Test dynamic loading of modules."; # Don't do anything if this system doesn't support "load" exists $FEATURES{load} or return -1; # First build a shared object # Provide both a default and non-default load symbol unlink(qw(testload.c testload.so)); open(my $F, '> testload.c') or die "open: testload.c: $!\n"; print $F <<'EOF' ; #include #include #include "gnumake.h" int plugin_is_GPL_compatible; int testload_gmk_setup (gmk_floc *pos) { (void)pos; gmk_eval ("TESTLOAD = implicit", 0); return 1; } int explicit_setup (gmk_floc *pos) { (void)pos; gmk_eval ("TESTLOAD = explicit", 0); return 1; } EOF close($F) or die "close: testload.c: $!\n"; # Make sure we can compile # CONFIG_FLAGS are loaded from config-flags.pm and set by configure my $sobuild = "$CONFIG_FLAGS{CC} ".($srcdir? "-I$srcdir":'')." $CONFIG_FLAGS{CPPFLAGS} $CONFIG_FLAGS{CFLAGS} -shared -fPIC $CONFIG_FLAGS{LDFLAGS} -o testload.so testload.c"; my $clog = `$sobuild 2>&1`; if ($? != 0) { $verbose and print "Failed to build testload.so:\n$sobuild\n$_"; return -1; } # TEST 1 run_make_test(q! PRE := $(.LOADED) load testload.so POST := $(.LOADED) all: ; @echo pre=$(PRE) post=$(POST) $(TESTLOAD) !, '--warn-undefined-variables', "pre= post=testload.so implicit\n"); # TEST 2 # Load using an explicit function run_make_test(q! PRE := $(.LOADED) load ./testload.so(explicit_setup) POST := $(.LOADED) all: ; @echo pre=$(PRE) post=$(POST) $(TESTLOAD) !, '', "pre= post=testload.so explicit\n"); # TEST 4 # Check multiple loads run_make_test(q! PRE := $(.LOADED) load ./testload.so load testload.so(explicit_setup) POST := $(.LOADED) all: ; @echo pre=$(PRE) post=$(POST) $(TESTLOAD) !, '', "pre= post=testload.so implicit\n"); # TEST 5 # Check auto-rebuild of loaded file that's out of date utouch(-10, 'testload.so'); touch('testload.c'); run_make_test(q! PRE := $(.LOADED) load ./testload.so POST := $(.LOADED) all: ; @echo pre=$(PRE) post=$(POST) $(TESTLOAD) testload.so: testload.c ; @echo "rebuilding $@"; !.$sobuild, '', "rebuilding testload.so\npre= post=testload.so implicit\n"); # TEST 5 # Check auto-rebuild of loaded file when it doesn't exist unlink('testload.so'); run_make_test(q! PRE := $(.LOADED) -load ./testload.so(explicit_setup) POST := $(.LOADED) all: ; @echo pre=$(PRE) post=$(POST) $(TESTLOAD) %.so: %.c ; @echo "rebuilding $@"; !.$sobuild, '', "rebuilding testload.so\npre= post=testload.so explicit\n"); unlink(qw(testload.c testload.so)) unless $keep; # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/features/vpathgpath0000644000175000017500000000210413252530201023003 0ustar locutuslocutus# -*-perl-*- $description = "Tests VPATH+/GPATH functionality."; $details = ""; $VP = "$workdir$pathsep"; open(MAKEFILE,"> $makefile"); # The Contents of the MAKEFILE ... print MAKEFILE "VPATH = $VP\n"; print MAKEFILE <<'EOMAKE'; GPATH = $(VPATH) .SUFFIXES: .a .b .c .d .PHONY: general rename notarget intermediate %.a: %.b: %.c: %.d: %.a : %.b ; cat $^ > $@ %.b : %.c ; cat $^ > $@ %.c :: %.d ; cat $^ > $@ # General testing info: general: foo.b foo.b: foo.c bar.c EOMAKE close(MAKEFILE); @touchedfiles = (); $off = -500; sub touchfiles { foreach (@_) { ($f = $_) =~ s,VP/,$VP,g; &utouch($off, $f); $off += 10; push(@touchedfiles, $f); } } # Run the general-case test &touchfiles("VP/foo.d", "VP/bar.d", "VP/foo.c", "VP/bar.c", "foo.b", "bar.d"); &run_make_with_options($makefile,"general",&get_logfile()); push(@touchedfiles, "bar.c"); $answer = "$make_name: Nothing to be done for 'general'.\n"; &compare_output($answer,&get_logfile(1)); unlink(@touchedfiles) unless $keep; 1; kbuild-3149/src/kmk/tests/scripts/features/include0000644000175000017500000001175413252530201022273 0ustar locutuslocutus# -*-mode: perl; rm-trailing-spaces: nil-*- $description = "Test various forms of the GNU make 'include' command."; $details = "\ Test include, -include, sinclude and various regressions involving them. Test extra whitespace at the end of the include, multiple -includes and sincludes (should not give an error) and make sure that errors are reported for targets that were also -included."; $makefile2 = &get_tmpfile; open(MAKEFILE,"> $makefile"); # The contents of the Makefile ... print MAKEFILE < $makefile2"); print MAKEFILE "ANOTHER: ; \@echo This is another included makefile\n"; close(MAKEFILE); # Create the answer to what should be produced by this Makefile &run_make_with_options($makefile, "all", &get_logfile); $answer = "There should be no errors for this makefile.\n"; &compare_output($answer, &get_logfile(1)); &run_make_with_options($makefile, "ANOTHER", &get_logfile); $answer = "This is another included makefile\n"; &compare_output($answer, &get_logfile(1)); $makefile = undef; # Try to build the "error" target; this will fail since we don't know # how to create makeit.mk, but we should also get a message (even though # the -include suppressed it during the makefile read phase, we should # see one during the makefile run phase). run_make_test (' -include foo.mk error: foo.mk ; @echo $@ ', '', "#MAKE#: *** No rule to make target 'foo.mk', needed by 'error'. Stop.\n", 512 ); # Make sure that target-specific variables don't impact things. This could # happen because a file record is created when a target-specific variable is # set. run_make_test (' bar.mk: foo := baz -include bar.mk hello: ; @echo hello ', '', "hello\n" ); # Test inheritance of dontcare flag when rebuilding makefiles. # run_make_test(' .PHONY: all all: ; @: -include foo foo: bar; @: ', '', ''); # Make sure that we don't die when the command fails but we dontcare. # (Savannah bug #13216). # run_make_test(' .PHONY: all all:; @: -include foo foo: bar; @: bar:; @exit 1 ', '', ''); # Check include, sinclude, -include with no filenames. # (Savannah bug #1761). run_make_test(' .PHONY: all all:; @: include -include sinclude', '', ''); # Test that the diagnostics is issued even if the target has been # tried before with the dontcare flag (direct dependency case). # run_make_test(' -include foo all: bar foo: baz bar: baz ', '', "#MAKE#: *** No rule to make target 'baz', needed by 'bar'. Stop.\n", 512); # Test that the diagnostics is issued even if the target has been # tried before with the dontcare flag (indirect dependency case). # run_make_test(' -include foo all: bar foo: baz bar: baz baz: end ', '', "#MAKE#: *** No rule to make target 'end', needed by 'baz'. Stop.\n", 512); # Test that the diagnostics is issued even if the target has been # tried before with the dontcare flag (include/-include case). # run_make_test(' include bar -include foo all: foo: baz bar: baz baz: end ', '', "#MAKEFILE#:2: bar: No such file or directory #MAKE#: *** No rule to make target 'end', needed by 'baz'. Stop.\n", 512); # Test include of make-able file doesn't show an error (Savannah #102) run_make_test(q! .PHONY: default default:; @echo DONE inc1:; echo > $@ include inc1 include inc2 inc2:; echo > $@ !, '', "echo > inc2\necho > inc1\nDONE\n"); rmfiles('inc1', 'inc2'); # Test include of non-make-able file does show an error (Savannah #102) run_make_test(q! .PHONY: default default:; @echo DONE inc1:; echo > $@ include inc1 include inc2 !, '', "#MAKEFILE#:7: inc2: No such file or directory\n#MAKE#: *** No rule to make target 'inc2'. Stop.\n", 512); rmfiles('inc1'); # Include same file multiple times run_make_test(q! default:; @echo DEFAULT include inc1 inc1:; echo > $@ include inc1 !, '', "echo > inc1\nDEFAULT\n"); rmfiles('inc1'); # Included file has a prerequisite that fails to build run_make_test(q! default:; @echo DEFAULT include inc1 inc1: foo; echo > $@ foo:; exit 1 !, '', "exit 1\n#MAKEFILE#:3: inc1: No such file or directory\n#MAKE#: *** [#MAKEFILE#:5: foo] Error 1\n", 512); rmfiles('inc1'); # Included file has a prerequisite we don't know how to build run_make_test(q! default:; @echo DEFAULT include inc1 inc1: foo; echo > $@ !, '', "#MAKEFILE#:3: inc1: No such file or directory\n#MAKE#: *** No rule to make target 'foo', needed by 'inc1'. Stop.\n", 512); rmfiles('inc1'); # include a directory if ($all_tests) { # Test that include of a rebuild-able file doesn't show a warning # Savannah bug #102 run_make_test(q! include foo foo: ; @echo foo = bar > $@ !, '', "#MAKE#: 'foo' is up to date.\n"); rmfiles('foo'); } 1; kbuild-3149/src/kmk/tests/scripts/features/utf80000644000175000017500000000050013252530201021521 0ustar locutuslocutus# -*-perl-*- $description = "Test support for UTF-8."; $details = ""; # Verify that the UTF-8 BOM is ignored. run_make_test("\xEF\xBB\xBFall: ; \@echo \$\@\n", '', "all"); # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/features/shell_assignment0000644000175000017500000000341013252530201024175 0ustar locutuslocutus# -*-perl-*- $description = "Test BSD-style shell assignments (VAR != VAL) for variables."; $details = ""; # TEST 0: Basic shell assignment (!=). run_make_test(' .POSIX: demo1!=printf \' 1 2 3\n4\n\n5 \n \n 6\n\n\n\n\' demo2 != printf \'7 8\n \' demo3 != printf \'$$(demo2)\' demo4 != printf \' 2 3 \n\' demo5 != printf \' 2 3 \n\n\' all: ; @echo "<$(demo1)> <$(demo2)> <$(demo3)> <$(demo4)> <${demo5}>" ', '', "< 1 2 3 4 5 6 > <7 8 > <7 8 > < 2 3 > < 2 3 >\n"); # TEST 1: Handle '#' the same way as BSD make run_make_test(' foo1!=echo bar#baz hash != printf \'\043\' foo2!= echo "bar$(hash)baz" all: ; @echo "<$(foo1)> <$(hash)> <$(foo2)>" ', '', " <#> \n"); # TEST 2: shell assignment variables (from !=) should be recursive. # Note that variables are re-evaluated later, so the shell can output # a value like $(XYZZY) as part of !=. The $(XYZZY) will be EVALUATED # when the value containing it is evaluated. On the negative side, this # means if you don't want this, you need to escape dollar signs as $$. # On the positive side, it means that shell programs can output macros # that are then evaluated as they are traditionally evaluated.. and that # you can use traditional macro evaluation semantics to implement !=. run_make_test(' XYZZY = fiddle-dee-dee dollar = $$ VAR3 != printf \'%s\' \'$(dollar)(XYZZY)\' all: ; @echo "<$(VAR3)>" ', '', "\n"); # TEST 3: Overrides invoke shell anyway; they just don't store the result # in a way that is visible. run_make_test(' override != echo abc > ,abc ; cat ,abc all: ; @echo "<$(override)>" ; cat ,abc ', 'override=xyz', "\nabc\n"); unlink(',abc'); 1; kbuild-3149/src/kmk/tests/scripts/features/mult_rules0000644000175000017500000000335313252530201023037 0ustar locutuslocutus$description = "\ The following test creates a makefile to test the presence of multiple rules for one target. One file can be the target of several rules if at most one rule has commands; the other rules can only have dependencies."; $details = "\ The makefile created in this test contains two hardcoded rules for foo.o and bar.o. It then gives another multiple target rule with the same names as above but adding more dependencies. Additionally, another variable extradeps is listed as a dependency but is defined to be null. It can however be defined on the make command line as extradeps=extra.h which adds yet another dependency to the targets."; open(MAKEFILE,"> $makefile"); # The Contents of the MAKEFILE ... print MAKEFILE < $makefile"); # The Contents of the MAKEFILE ... print MAKEFILE "VPATH = $VP\n"; print MAKEFILE <<'EOMAKE'; SHELL = /bin/sh .SUFFIXES: .a .b .c .d .PHONY: general rename notarget intermediate %.a: %.b: %.c: %.d: %.a : %.b cat $^ > $@ %.b : %.c cat $^ > $@ 2>/dev/null || exit 1 %.c :: %.d cat $^ > $@ # General testing info: general: foo.b foo.b: foo.c bar.c # Rename testing info: rename: $(VPATH)/foo.c foo.d # Target not made testing info: notarget: notarget.b notarget.c: notarget.d -@echo "not creating $@ from $^" # Intermediate files: intermediate: inter.a EOMAKE close(MAKEFILE); @touchedfiles = (); $off = -500; sub touchfiles { foreach (@_) { &utouch($off, $_); $off += 10; push(@touchedfiles, $_); } } # Run the general-case test &touchfiles("$VP/foo.d", "$VP/bar.d", "$VP/foo.c", "$VP/bar.c", "foo.b", "bar.d"); &run_make_with_options($makefile,"general",&get_logfile); push(@touchedfiles, "bar.c"); $answer = "cat bar.d > bar.c cat ${VP}foo.c bar.c > foo.b 2>/dev/null || exit 1 "; &compare_output($answer,&get_logfile(1)); # Test rules that don't make the target correctly &touchfiles("$VP/notarget.c", "notarget.b", "notarget.d"); &run_make_with_options($makefile,"notarget",&get_logfile,512); $answer = "not creating notarget.c from notarget.d cat notarget.c > notarget.b 2>/dev/null || exit 1 $make_name: *** [$makefile:16: notarget.b] Error 1 "; &compare_output($answer,&get_logfile(1)); # Test intermediate file handling (part 1) &touchfiles("$VP/inter.d"); &run_make_with_options($makefile,"intermediate",&get_logfile); push(@touchedfiles, "inter.a", "inter.b"); $answer = "cat ${VP}inter.d > inter.c cat inter.c > inter.b 2>/dev/null || exit 1 cat inter.b > inter.a rm inter.b inter.c "; &compare_output($answer,&get_logfile(1)); # Test intermediate file handling (part 2) &utouch(-20, "inter.a"); &utouch(-10, "$VP/inter.b"); &touch("$VP/inter.d"); push(@touchedfiles, "$VP/inter.b", "$VP/inter.d"); &run_make_with_options($makefile,"intermediate",&get_logfile); $answer = "cat ${VP}inter.d > inter.c cat inter.c > inter.b 2>/dev/null || exit 1 cat inter.b > inter.a rm inter.c "; &compare_output($answer,&get_logfile(1)); unlink @touchedfiles unless $keep; 1; ### Local Variables: ### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) ### End: kbuild-3149/src/kmk/tests/scripts/features/double_colon0000644000175000017500000001111613252530202023305 0ustar locutuslocutus# -*-perl-*- $description = "Test handling of double-colon rules."; $details = "\ We test these features: - Multiple commands for the same (double-colon) target - Different prerequisites for targets: only out-of-date ones are rebuilt. - Double-colon targets that aren't the goal target. Then we do the same thing for parallel builds: double-colon targets should always be built serially."; # The Contents of the MAKEFILE ... open(MAKEFILE,"> $makefile"); print MAKEFILE <<'EOF'; all: baz foo:: f1.h ; @echo foo FIRST foo:: f2.h ; @echo foo SECOND bar:: ; @echo aaa; sleep 1; echo aaa done bar:: ; @echo bbb baz:: ; @echo aaa baz:: ; @echo bbb biz:: ; @echo aaa biz:: two ; @echo bbb two: ; @echo two f1.h f2.h: ; @echo $@ d :: ; @echo ok d :: d ; @echo oops EOF close(MAKEFILE); # TEST 0: A simple double-colon rule that isn't the goal target. &run_make_with_options($makefile, "all", &get_logfile, 0); $answer = "aaa\nbbb\n"; &compare_output($answer, &get_logfile(1)); # TEST 1: As above, in parallel if ($parallel_jobs) { &run_make_with_options($makefile, "-j10 all", &get_logfile, 0); $answer = "aaa\nbbb\n"; &compare_output($answer, &get_logfile(1)); } # TEST 2: A simple double-colon rule that is the goal target &run_make_with_options($makefile, "bar", &get_logfile, 0); $answer = "aaa\naaa done\nbbb\n"; &compare_output($answer, &get_logfile(1)); # TEST 3: As above, in parallel if ($parallel_jobs) { &run_make_with_options($makefile, "-j10 bar", &get_logfile, 0); $answer = "aaa\naaa done\nbbb\n"; &compare_output($answer, &get_logfile(1)); } # TEST 4: Each double-colon rule is supposed to be run individually &utouch(-5, 'f2.h'); &touch('foo'); &run_make_with_options($makefile, "foo", &get_logfile, 0); $answer = "f1.h\nfoo FIRST\n"; &compare_output($answer, &get_logfile(1)); # TEST 5: Again, in parallel. if ($parallel_jobs) { &run_make_with_options($makefile, "-j10 foo", &get_logfile, 0); $answer = "f1.h\nfoo FIRST\n"; &compare_output($answer, &get_logfile(1)); } # TEST 6: Each double-colon rule is supposed to be run individually &utouch(-5, 'f1.h'); unlink('f2.h'); &touch('foo'); &run_make_with_options($makefile, "foo", &get_logfile, 0); $answer = "f2.h\nfoo SECOND\n"; &compare_output($answer, &get_logfile(1)); # TEST 7: Again, in parallel. if ($parallel_jobs) { &run_make_with_options($makefile, "-j10 foo", &get_logfile, 0); $answer = "f2.h\nfoo SECOND\n"; &compare_output($answer, &get_logfile(1)); } # TEST 8: Test circular dependency check; PR/1671 &run_make_with_options($makefile, "d", &get_logfile, 0); $answer = "ok\n$make_name: Circular d <- d dependency dropped.\noops\n"; &compare_output($answer, &get_logfile(1)); # TEST 8: I don't grok why this is different than the above, but it is... # # Hmm... further testing indicates this might be timing-dependent? # #if ($parallel_jobs) { # &run_make_with_options($makefile, "-j10 biz", &get_logfile, 0); # $answer = "aaa\ntwo\nbbb\n"; # &compare_output($answer, &get_logfile(1)); #} unlink('foo','f1.h','f2.h'); # TEST 9: make sure all rules in s double colon family get executed # (Savannah bug #14334). # &touch('one'); &touch('two'); run_make_test(' .PHONY: all all: result result:: one @echo $^ >>$@ @echo $^ result:: two @echo $^ >>$@ @echo $^ ', '', 'one two'); unlink('result','one','two'); # TEST 10: SV 33399 : check for proper backslash handling run_make_test(' a\ xb :: ; @echo one a\ xb :: ; @echo two ', '', "one\ntwo\n"); # Test 11: SV 44742 : All double-colon rules should be run in parallel build. run_make_test('result :: 01 @echo update @touch $@ result :: 02 @echo update @touch $@ result :: 03 @echo update @touch $@ result :: 04 @echo update @touch $@ result :: 05 @echo update @touch $@ 01 02 03 04 05: @touch 01 02 03 04 05 ', '-j10 result', "update\nupdate\nupdate\nupdate\nupdate\n"); unlink('result', '01', '02', '03', '04', '05'); # Test 12: SV 44742 : Double-colon rules with parallelism run_make_test(' root: all echo root all:: echo all_one all:: 3 echo all_two %: sleep $* ', '-rs -j2 1 2 root', "all_one\nall_two\nroot\n"); # SV 47995 : Parallel double-colon rules with FORCE run_make_test(' all:: ; @echo one all:: joe ; @echo four joe: FORCE ; touch joe-is-forced FORCE: ', '-j5', "one\ntouch joe-is-forced\nfour\n"); unlink('joe-is-forced'); # This tells the test driver that the perl test script executed properly. 1; ### Local Variables: ### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) ### End: kbuild-3149/src/kmk/tests/scripts/features/patternrules0000644000175000017500000000744413252530201023401 0ustar locutuslocutus# -*-perl-*- $description = "Test pattern rules."; $details = ""; use Cwd; $dir = cwd; $dir =~ s,.*/([^/]+)$,../$1,; # TEST #0: Make sure that multiple patterns where the same target # can be built are searched even if the first one fails # to match properly. # run_make_test(q! .PHONY: all all: case.1 case.2 case.3 # We can't have this, due to "Implicit Rule Search Algorithm" step 5c #xxx: void # 1 - existing file %.1: void @exit 1 %.1: #MAKEFILE# @exit 0 # 2 - phony %.2: void @exit 1 %.2: 2.phony @exit 0 .PHONY: 2.phony # 3 - implicit-phony %.3: void @exit 1 %.3: 3.implicit-phony @exit 0 3.implicit-phony: !, '', ''); # TEST #1: make sure files that are built via implicit rules are marked # as targets (Savannah bug #12202). # run_make_test(' TARGETS := foo foo.out .PHONY: all foo.in all: $(TARGETS) %: %.in @echo $@ %.out: % @echo $@ foo.in: ; @: ', '', 'foo foo.out'); # TEST #2: make sure intermediate files that also happened to be # prerequisites are not removed (Savannah bug #12267). # run_make_test(' $(dir)/foo.o: $(dir)/foo.y: @echo $@ %.c: %.y touch $@ %.o: %.c @echo $@ .PHONY: install install: $(dir)/foo.c ', "dir=$dir", "$dir/foo.y touch $dir/foo.c $dir/foo.o"); unlink("$dir/foo.c"); # TEST #3: make sure precious flag is set properly for targets # that are built via implicit rules (Savannah bug #13218). # run_make_test(' .DELETE_ON_ERROR: .PRECIOUS: %.bar %.bar:; @touch $@ && exit 1 $(dir)/foo.bar: ', "dir=$dir", (!$is_kmk) ? "#MAKE#: *** [#MAKEFILE#:6: $dir/foo.bar] Error 1": "#MAKE#: *** [$dir/foo.bar] Error 1" . ' The failing command: @touch $@ && exit 1', 512); unlink("$dir/foo.bar"); # TEST #4: make sure targets of a matched implicit pattern rule are # never considered intermediate (Savannah bug #13022). # run_make_test(' .PHONY: all all: foo.c foo.o %.h %.c: %.in touch $*.h touch $*.c %.o: %.c %.h echo $+ >$@ %.o: %.c @echo wrong rule foo.in: touch $@ ', '-j1', 'touch foo.in touch foo.h touch foo.c echo foo.c foo.h >foo.o'); unlink('foo.in', 'foo.h', 'foo.c', 'foo.o'); # TEST #5: make sure both prefix and suffix patterns work with multiple # target patterns (Savannah bug #26593). # run_make_test(' all: foo.s1 foo.s2 p1.foo p2.foo p1.% p2.%: %.orig @echo $@ %.s1 %.s2: %.orig @echo $@ .PHONY: foo.orig ', '', "foo.s1\np1.foo\n"); # TEST 6: Make sure that non-target files are still eligible to be created # as part of implicit rule chaining. Savannah bug #17752. run_make_test(q! BIN = xyz COPY = $(BIN).cp SRC = $(BIN).c allbroken: $(COPY) $(BIN) ; @echo ok $(SRC): ; @echo 'main(){}' > $@ %.cp: % ; @cp $< $@ % : %.c ; @cp $< $@ clean: ; @rm -rf $(SRC) $(COPY) $(BIN) !, '', "ok\n"); unlink(qw(xyz xyz.cp xyz.c)); # TEST 7: Make sure that all prereqs of all "also_make" targets get created # before any of the things that depend on any of them. Savannah bug #19108. run_make_test(q! final: x ; @echo $@ x: x.t1 x.t2 ; @echo $@ x.t2: dep dep: ; @echo $@ %.t1 %.t2: ; @echo $*.t1 ; echo $*.t2 !, '', "dep\nx.t1\nx.t2\nx\nfinal\n"); # TEST 8: Verify we can remove pattern rules. Savannah bug #18622. my @f = (qw(foo.w foo.ch)); touch(@f); run_make_test(q! CWEAVE := : # Disable builtin rules %.tex : %.w %.tex : %.w %.ch !, 'foo.tex', "#MAKE#: *** No rule to make target 'foo.tex'. Stop.", 512); unlink(@f); # TEST #9: Test shortest stem selection in pattern rules. run_make_test(' %.x: ;@echo one %-mt.x: ;@echo two all: foo.x foo-mt.x ', '', "one\ntwo"); 1; # This tells the test driver that the perl test script executed properly. 1; ### Local Variables: ### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) ### End: kbuild-3149/src/kmk/tests/scripts/features/loadapi0000644000175000017500000000533713252530201022261 0ustar locutuslocutus# -*-perl-*- $description = "Test the shared object load API."; $details = "Verify the different aspects of the shared object API."; # Don't do anything if this system doesn't support "load" exists $FEATURES{load} or return -1; # First build a shared object # Provide both a default and non-default load symbol unlink(qw(testapi.c testapi.so)); open(my $F, '> testapi.c') or die "open: testapi.c: $!\n"; print $F <<'EOF' ; #include #include #include "gnumake.h" int plugin_is_GPL_compatible; static char * test_eval (const char *buf) { gmk_eval (buf, 0); return NULL; } static char * test_expand (const char *val) { return gmk_expand (val); } static char * test_noexpand (const char *val) { char *str = gmk_alloc (strlen (val) + 1); strcpy (str, val); return str; } static char * func_test (const char *funcname, unsigned int argc, char **argv) { char *mem; if (strcmp (funcname, "test-expand") == 0) return test_expand (argv[0]); if (strcmp (funcname, "test-eval") == 0) return test_eval (argv[0]); if (strcmp (funcname, "test-noexpand") == 0) return test_noexpand (argv[0]); mem = gmk_alloc (sizeof ("unknown")); strcpy (mem, "unknown"); return mem; } int testapi_gmk_setup () { gmk_add_function ("test-expand", func_test, 1, 1, GMK_FUNC_DEFAULT); gmk_add_function ("test-noexpand", func_test, 1, 1, GMK_FUNC_NOEXPAND); gmk_add_function ("test-eval", func_test, 1, 1, GMK_FUNC_DEFAULT); gmk_add_function ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.", func_test, 0, 0, 0); return 1; } EOF close($F) or die "close: testapi.c: $!\n"; my $sobuild = "$CONFIG_FLAGS{CC} ".($srcdir? "-I$srcdir":'')." $CONFIG_FLAGS{CPPFLAGS} $CONFIG_FLAGS{CFLAGS} -shared -fPIC $CONFIG_FLAGS{LDFLAGS} -o testapi.so testapi.c"; my $clog = `$sobuild 2>&1`; if ($? != 0) { $verbose and print "Failed to build testapi.so:\n$sobuild\n$_"; return -1; } # TEST 1 # Check the gmk_expand() function run_make_test(q! EXPAND = expansion all: ; @echo $(test-expand $$(EXPAND)) load testapi.so !, '', "expansion\n"); # TEST 2 # Check the eval operation. Prove that the argument is expanded only once run_make_test(q! load testapi.so TEST = bye ASSIGN = VAR = $(TEST) $(shell echo there) $(test-eval $(value ASSIGN)) TEST = hi all:;@echo '$(VAR)' !, '', "hi there\n"); # TEST 2 # Check the no-expand capability run_make_test(q! load testapi.so TEST = hi all:;@echo '$(test-noexpand $(TEST))' !, '', "\$(TEST)\n"); unlink(qw(testapi.c testapi.so)) unless $keep; # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/features/statipattrules0000644000175000017500000000432713252530202023737 0ustar locutuslocutus# -*-perl-*- $description = "Test handling of static pattern rules."; $details = "\ The makefile created in this test has three targets. The filter command is used to get those target names ending in .o and statically creates a compile command with the target name and the target name with .c. It also does the same thing for another target filtered with .elc and creates a command to emacs a .el file"; &touch('bar.c', 'lose.c'); # TEST #0 # ------- run_make_test(' files = foo.elc bar.o lose.o $(filter %.o,$(files)): %.o: %.c ; @echo CC -c $(CFLAGS) $< -o $@ $(filter %.elc,$(files)): %.elc: %.el ; @echo emacs $< ', '', 'CC -c bar.c -o bar.o'); # TEST #1 # ------- run_make_test(undef, 'lose.o', 'CC -c lose.c -o lose.o'); # TEST #2 # ------- &touch("foo.el"); run_make_test(undef, 'foo.elc', 'emacs foo.el'); # Clean up after the first tests. unlink('foo.el', 'bar.c', 'lose.c'); # TEST #3 -- PR/1670: don't core dump on invalid static pattern rules # ------- run_make_test(' .DEFAULT: ; @echo $@ foo: foo%: % %.x % % % y.% % ; @echo $@ ', '-j1', ".x\ny.\nfoo"); # TEST #4 -- bug #12180: core dump on a stat pattern rule with an empty # prerequisite list. run_make_test(' foo.x bar.x: %.x : ; @echo $@ ', '', 'foo.x'); # TEST #5 -- bug #13881: double colon static pattern rule does not # substitute %. run_make_test(' foo.bar:: %.bar: %.baz foo.baz: ;@: ', '', ''); # TEST #6: make sure the second stem does not overwrite the first # perprerequisite's stem (Savannah bug #16053). # run_make_test(' all.foo.bar: %.foo.bar: %.one all.foo.bar: %.bar: %.two all.foo.bar: @echo $* @echo $^ .DEFAULT:;@: ', '', 'all.foo all.one all.foo.two'); # TEST #7: make sure the second stem does not overwrite the first # perprerequisite's stem when second expansion is enabled # (Savannah bug #16053). # run_make_test(' .SECONDEXPANSION: all.foo.bar: %.foo.bar: %.one $$*-one all.foo.bar: %.bar: %.two $$*-two all.foo.bar: @echo $* @echo $^ .DEFAULT:;@: ', '', 'all.foo all.one all-one all.foo.two all.foo-two'); 1; kbuild-3149/src/kmk/tests/scripts/features/vpath30000644000175000017500000000170013252530201022043 0ustar locutuslocutus# -*-perl-*- $description = "Test the interaction of the -lfoo feature and vpath"; $details = ""; my @dirs_to_make = qw(a1 b1 a2 b2 b3); for my $d (@dirs_to_make) { mkdir($d, 0777); } my @files_to_touch = ("a1${pathsep}lib1.a", "a1${pathsep}libc.a", "b1${pathsep}lib1.so", "a2${pathsep}lib2.a", "b2${pathsep}lib2.so", "lib3.a", "b3${pathsep}lib3.so"); &touch(@files_to_touch); my $answer = "a1${pathsep}lib1.a a1${pathsep}libc.a " . "a2${pathsep}lib2.a lib3.a\n"; if ($port_type eq 'VMS-DCL') { $answer =~ s/ /,/g; } run_make_test(' vpath %.h b3 vpath %.a a1 vpath %.so b1 vpath % a2 b2 vpath % b3 all: -l1 -lc -l2 -l3; @echo $^ ', '', $answer); unlink(@files_to_touch); for my $d (@dirs_to_make) { rmdir($d); } 1; kbuild-3149/src/kmk/tests/scripts/features/recursion0000644000175000017500000000256513252530202022662 0ustar locutuslocutus# -*-perl-*- $description = "Test recursion."; $details = "DETAILS"; # Test some basic recursion. run_make_test(' all: $(MAKE) -f #MAKEFILE# foo foo: @echo $(MAKE) @echo MAKELEVEL = $('. (!$is_kmk ? 'MAKELEVEL' : 'KMK_LEVEL') .') $(MAKE) -f #MAKEFILE# last last: @echo $(MAKE) @echo MAKELEVEL = $('. (!$is_kmk ? 'MAKELEVEL' : 'KMK_LEVEL') .') @echo THE END ', ('CFLAGS=-O -w' . ($parallel_jobs ? ' -j 2' : '')), ($vos ? "#MAKE#: Entering directory '#PWD#' make 'CFLAGS=-O' -f #MAKEFILE# foo make CFLAGS=-O MAKELEVEL = 0 make 'CFLAGS=-O' -f #MAKEFILE# last make CFLAGS=-O MAKELEVEL = 0 THE END #MAKE#: Leaving directory '#PWD#'" : "#MAKE#: Entering directory '#PWD#' #MAKEPATH# -f #MAKEFILE# foo #MAKE#[1]: Entering directory '#PWD#' #MAKEPATH# MAKELEVEL = 1 #MAKEPATH# -f #MAKEFILE# last #MAKE#[2]: Entering directory '#PWD#' #MAKEPATH# MAKELEVEL = 2 THE END #MAKE#[2]: Leaving directory '#PWD#' #MAKE#[1]: Leaving directory '#PWD#' #MAKE#: Leaving directory '#PWD#'")); # Test command line overrides. run_make_test(' recur: all ; @$(MAKE) --no-print-directory -f #MAKEFILE# a=AA all all: ; @echo "MAKEOVERRIDES = $('. (!$is_kmk ? 'MAKEOVERRIDES' : 'KMK_OVERRIDES') .')" ', 'a=ZZ', 'MAKEOVERRIDES = a=ZZ MAKEOVERRIDES = a=AA '); 1; kbuild-3149/src/kmk/tests/scripts/features/errors0000644000175000017500000000524313252530201022160 0ustar locutuslocutus# -*-perl-*- $description = "The following tests the -i option and the '-' in front of \n" ."commands to test that make ignores errors in these commands\n" ."and continues processing."; $details = "This test runs two makes. The first runs on a target with a \n" ."command that has a '-' in front of it (and a command that is \n" ."intended to fail) and then a delete command after that is \n" ."intended to succeed. If make ignores the failure of the first\n" ."command as it is supposed to, then the second command should \n" ."delete a file and this is what we check for. The second make\n" ."that is run in this test is identical except that the make \n" ."command is given with the -i option instead of the '-' in \n" ."front of the command. They should run the same. "; if ($vos) { $rm_command = "delete_file"; } else { $rm_command = "rm"; } open(MAKEFILE,"> $makefile"); # The Contents of the MAKEFILE ... print MAKEFILE "clean:\n" ."\t-$rm_command cleanit\n" ."\t$rm_command foo\n" ."clean2: \n" ."\t$rm_command cleanit\n" ."\t$rm_command foo\n"; # END of Contents of MAKEFILE close(MAKEFILE); &touch("foo"); unlink("cleanit"); $cleanit_error = `sh -c "$rm_command cleanit 2>&1"`; chomp $cleanit_error; $delete_error_code = $? >> 8; # TEST #1 # ------- $answer = "$rm_command cleanit $cleanit_error $make_name: [$makefile:2: clean] Error $delete_error_code (ignored) $rm_command foo\n"; &run_make_with_options($makefile,"",&get_logfile); # If make acted as planned, it should ignore the error from the first # command in the target and execute the second which deletes the file "foo" # This file, therefore, should not exist if the test PASSES. if (-f "foo") { $test_passed = 0; } # The output for this on VOS is too hard to replicate, so we only check it # on unix. if (!$vos) { &compare_output($answer,&get_logfile(1)); } &touch("foo"); # TEST #2 # ------- $answer = "$rm_command cleanit $cleanit_error $make_name: [$makefile:5: clean2] Error $delete_error_code (ignored) $rm_command foo\n"; &run_make_with_options($makefile,"clean2 -i",&get_logfile); if (-f "foo") { $test_passed = 0; } if (!$vos) { &compare_output($answer,&get_logfile(1)); } # Test that error line offset works run_make_test(q! all: @echo hi @echo there @exit 1 !, '', "hi\nthere\n#MAKE#: *** [#MAKEFILE#:5: all] Error 1", 512); 1; ### Local Variables: ### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) ### End: kbuild-3149/src/kmk/tests/scripts/misc/0000755000175000017500000000000013252530202020033 5ustar locutuslocutuskbuild-3149/src/kmk/tests/scripts/misc/general40000644000175000017500000000374513252530202021470 0ustar locutuslocutus# -*-perl-*- $description = "\ This tests random features of make's algorithms, often somewhat obscure, which have either broken at some point in the past or seem likely to break."; run_make_test(' # Make sure that subdirectories built as prerequisites are actually handled # properly. all: dir/subdir/file.a dir/subdir: ; @echo mkdir -p dir/subdir dir/subdir/file.b: dir/subdir ; @echo touch dir/subdir/file.b dir/subdir/%.a: dir/subdir/%.b ; @echo cp $< $@', '', "mkdir -p dir/subdir\ntouch dir/subdir/file.b\ncp dir/subdir/file.b dir/subdir/file.a\n"); # Test implicit rules # kmk: No default implicit rules. &touch('foo.c'); run_make_test('foo: foo.o', 'CC="@echo cc" OUTPUT_OPTION=', !$is_kmk ? 'cc -c foo.c cc foo.o -o foo' : "#MAKE#: *** No rule to make target `foo.o', needed by `foo'. Stop.", !$is_kmk ? 0 : 512); unlink('foo.c'); # Test implicit rules with '$' in the name (see se_implicit) run_make_test(q! %.foo : baz$$bar ; @echo 'done $<' %.foo : bar$$baz ; @echo 'done $<' test.foo: baz$$bar bar$$baz: ; @echo '$@' !, '', "baz\$bar\ndone baz\$bar"); # Test implicit rules with '$' in the name (see se_implicit) # Use the '$' in the pattern. run_make_test(q! %.foo : %$$bar ; @echo 'done $<' test.foo: test$$bar: ; @echo '$@' !, '', "test\$bar\ndone test\$bar"); # Make sure that subdirectories built as prerequisites are actually handled # properly... this time with '$' run_make_test(q! all: dir/subdir/file.$$a dir/subdir: ; @echo mkdir -p '$@' dir/subdir/file.$$b: dir/subdir ; @echo touch '$@' dir/subdir/%.$$a: dir/subdir/%.$$b ; @echo 'cp $< $@' !, '', "mkdir -p dir/subdir\ntouch dir/subdir/file.\$b\ncp dir/subdir/file.\$b dir/subdir/file.\$a\n"); # Test odd whitespace at the beginning of a line run_make_test(" all: \f \\ \f \\ \013 \\ all: ; \@echo hi ", '', "hi\n"); 1; kbuild-3149/src/kmk/tests/scripts/misc/fopen-fail0000644000175000017500000000117613252530202022003 0ustar locutuslocutus# -*-perl-*- $description = "Make sure make exits with an error if fopen fails."; # Recurse infinitely until we run out of open files, and ensure we # fail with a non-zero exit code. Don't bother to test the output # since it's hard to know what it will be, exactly. # See Savannah bug #27374. # Use a longer-than-normal timeout: some systems have more FDs available? # We also set ulimit -n 512 in check-regression in Makefile.am, which see. # See Savannah bug #42390. run_make_test(q! include $(lastword $(MAKEFILE_LIST)) !, '', undef, 512, 300); 1; kbuild-3149/src/kmk/tests/scripts/misc/utf80000644000175000017500000000050213252530202020641 0ustar locutuslocutus# -*-perl-*- $description = "Test utf8 handling."; $details = ""; # Variable names containing UTF8 characters run_make_test(" \xe2\x96\xaa := hello \$(info \$(\xe2\x96\xaa)) all: ", '', "hello\n#MAKE#: Nothing to be done for 'all'."); 1; kbuild-3149/src/kmk/tests/scripts/misc/close_stdout0000644000175000017500000000037413252530202022471 0ustar locutuslocutus# -*-perl-*- $description = "Make sure make exits with an error if stdout is full."; if (-e '/dev/full') { run_make_test('', '-v > /dev/full', '/^#MAKE#: write error/', 256); } 1; kbuild-3149/src/kmk/tests/scripts/misc/general10000644000175000017500000000277613252530202021470 0ustar locutuslocutus# -*-perl-*- $description = "The following test creates a makefile to test the simple functionality of make. It mimics the rebuilding of a product with dependencies. It also tests the simple definition of VPATH."; open(MAKEFILE,"> $makefile"); print MAKEFILE < $makefile"); # The contents of the Makefile ... print MAKEFILE < $m1"); binmode(MAKEFILE); print MAKEFILE "FOO = foo \\\r\n"; close(MAKEFILE); my $m2 = get_tmpfile(); open(MAKEFILE, "> $m2"); print MAKEFILE "include $m1\ndefine BAR\nall: ; \@echo \$(FOO) bar\nendef\n\$(eval \$(BAR))\n"; close(MAKEFILE); run_make_with_options($m2, '', get_logfile()); compare_output("foo bar\n", get_logfile(1)); # Test different types of whitespace, and bsnl inside functions sub xlate { $_ = $_[0]; s/\\r/\r/g; s/\\t/\t/g; s/\\f/\f/g; s/\\v/\v/g; s/\\n/\n/g; return $_; } run_make_test(xlate(q! $(foreach\r a \t , b\t c \r ,$(info $a \r ) ) all:;@: !), '', "b \r \nc \r \n"); run_make_test(xlate(q! all:;@:$(foreach\r a \t , b\t c \r ,$(info $a \r ) ) !), '', "b \r \nc \r \n"); run_make_test(xlate(q! $(foreach \ \r a \t\ , b\t \ c \r ,$(info \ $a \r ) \ ) all:;@: !), '', "b \r \nc \r \n"); run_make_test(xlate(q! all:;@:$(foreach \ \r a \t\ , b\t \ c \r ,$(info \ $a \r ) \ ) !), '', "b \r \nc \r \n"); run_make_test(xlate(q! define FOO $(foreach \r a \t , b\t c \r ,$(info $a \r ) ) endef $(FOO) all:;@: !), '', "b \r \nc \r \n"); run_make_test(xlate(q! define FOO $(foreach \r a \t , b\t c \r ,$(info $a \r ) ) endef all:;@:$(FOO) !), '', "b \r \nc \r \n"); # Test variables in recipes that expand to multiple lines run_make_test(q! define var echo foo echo bar endef all:;$(var) !, '', "echo foo\nfoo\necho bar\nbar\n"); run_make_test(q! define var echo foo @ echo bar endef all:;$(var) !, '', "echo foo\nfoo\necho bar\nbar\n"); 1; kbuild-3149/src/kmk/tests/scripts/misc/general30000644000175000017500000000777313252530202021474 0ustar locutuslocutus# -*-perl-*- $description = "\ This tests random features of the parser that need to be supported, and which have either broken at some point in the past or seem likely to break."; run_make_test(" # We want to allow both empty commands _and_ commands that resolve to empty. EMPTY = .PHONY: all a1 a2 a3 a4 all: a1 a2 a3 a4 a1:; a2: \t a3:;\$(EMPTY) a4: \t\$(EMPTY) \# Non-empty lines that expand to nothing should also be ignored. STR = \# Some spaces TAB = \t \# A TAB and some spaces \$(STR) \$(STR) \$(TAB)", '', "#MAKE#: Nothing to be done for 'all'."); # TEST 2 # Make sure files without trailing newlines are handled properly. # Have to use the old style invocation to test this. $makefile2 = &get_tmpfile; open(MAKEFILE, "> $makefile2"); print MAKEFILE "all:;\@echo FOO = \$(FOO)\nFOO = foo"; close(MAKEFILE); &run_make_with_options($makefile2,"",&get_logfile); $answer = "FOO = foo\n"; &compare_output($answer,&get_logfile(1)); # TEST 3 # Check semicolons in variable references run_make_test(' $(if true,$(info true; true)) all: ; @: ', '', 'true; true'); # TEST 4 # Check that backslashes in command scripts are handled according to POSIX. # Checks Savannah bug # 1332. # Test the fastpath / no quotes run_make_test(' all: @echo foo\ bar @echo foo\ bar @echo foo\ bar @echo foo\ bar @echo foo \ bar @echo foo \ bar @echo foo \ bar @echo foo \ bar ', '', 'foobar foobar foo bar foo bar foo bar foo bar foo bar foo bar'); # Test the fastpath / single quotes run_make_test(" all: \@echo 'foo\\ bar' \@echo 'foo\\ bar' \@echo 'foo\\ bar' \@echo 'foo\\ bar' \@echo 'foo \\ bar' \@echo 'foo \\ bar' \@echo 'foo \\ bar' \@echo 'foo \\ bar' ", '', 'foo\ bar foo\ bar foo\ bar foo\ bar foo \ bar foo \ bar foo \ bar foo \ bar'); # Test the fastpath / double quotes run_make_test(' all: @echo "foo\ bar" @echo "foo\ bar" @echo "foo\ bar" @echo "foo\ bar" @echo "foo \ bar" @echo "foo \ bar" @echo "foo \ bar" @echo "foo \ bar" ', '', 'foobar foobar foo bar foo bar foo bar foo bar foo bar foo bar'); # Test the slow path / no quotes run_make_test(' all: @echo hi; echo foo\ bar @echo hi; echo foo\ bar @echo hi; echo foo\ bar @echo hi; echo foo\ bar @echo hi; echo foo \ bar @echo hi; echo foo \ bar @echo hi; echo foo \ bar @echo hi; echo foo \ bar ', '', 'hi foobar hi foobar hi foo bar hi foo bar hi foo bar hi foo bar hi foo bar hi foo bar'); # Test the slow path / no quotes. This time we put the slow path # determination _after_ the backslash-newline handling. run_make_test(' all: @echo foo\ bar; echo hi @echo foo\ bar; echo hi @echo foo\ bar; echo hi @echo foo\ bar; echo hi @echo foo \ bar; echo hi @echo foo \ bar; echo hi @echo foo \ bar; echo hi @echo foo \ bar; echo hi ', '', 'foobar hi foobar hi foo bar hi foo bar hi foo bar hi foo bar hi foo bar hi foo bar hi'); # Test the slow path / single quotes run_make_test(" all: \@echo hi; echo 'foo\\ bar' \@echo hi; echo 'foo\\ bar' \@echo hi; echo 'foo\\ bar' \@echo hi; echo 'foo\\ bar' \@echo hi; echo 'foo \\ bar' \@echo hi; echo 'foo \\ bar' \@echo hi; echo 'foo \\ bar' \@echo hi; echo 'foo \\ bar' ", '', 'hi foo\ bar hi foo\ bar hi foo\ bar hi foo\ bar hi foo \ bar hi foo \ bar hi foo \ bar hi foo \ bar'); # Test the slow path / double quotes run_make_test(' all: @echo hi; echo "foo\ bar" @echo hi; echo "foo\ bar" @echo hi; echo "foo\ bar" @echo hi; echo "foo\ bar" @echo hi; echo "foo \ bar" @echo hi; echo "foo \ bar" @echo hi; echo "foo \ bar" @echo hi; echo "foo \ bar" ', '', 'hi foobar hi foobar hi foo bar hi foo bar hi foo bar hi foo bar hi foo bar hi foo bar'); run_make_test('x:;@-exit 1', '', "#MAKE#: [#MAKEFILE#:1: x] Error 1 (ignored)\n"); 1; kbuild-3149/src/kmk/tests/scripts/variables/0000755000175000017500000000000013252530202021050 5ustar locutuslocutuskbuild-3149/src/kmk/tests/scripts/variables/special0000644000175000017500000000515213252530202022416 0ustar locutuslocutus# -*-perl-*- $description = "Test special GNU make variables."; $details = ""; &run_make_test(' X1 := $(sort $(filter FOO BAR,$(.VARIABLES))) FOO := foo X2 := $(sort $(filter FOO BAR,$(.VARIABLES))) BAR := bar all: ; @echo X1 = $(X1); echo X2 = $(X2); echo LAST = $(sort $(filter FOO BAR,$(.VARIABLES))) ', '', "X1 =\nX2 = FOO\nLAST = BAR FOO\n"); # SV 45728: Test that undefining a variable is reflected properly &run_make_test(' FOO := foo BAR := bar $(info one: $(sort $(filter FOO BAR BAZ,$(.VARIABLES)))) undefine BAR BAZ := baz $(info two: $(sort $(filter FOO BAR BAZ,$(.VARIABLES)))) all:;@: ', '', "one: BAR FOO\ntwo: BAZ FOO\n"); # $makefile2 = &get_tmpfile; # open(MAKEFILE, "> $makefile2"); # print MAKEFILE <<'EOF'; # X1 := $(sort $(.TARGETS)) # all: foo # @echo X1 = $(X1) # @echo X2 = $(X2) # @echo LAST = $(sort $(.TARGETS)) # X2 := $(sort $(.TARGETS)) # foo: # EOF # close(MAKEFILE); # # TEST #2 # # ------- # &run_make_with_options($makefile2, "", &get_logfile); # $answer = "X1 =\nX2 = all\nLAST = all foo\n"; # &compare_output($answer, &get_logfile(1)); # Test the .RECIPEPREFIX variable # kmk: This test isn't -j1 safe, haven't bother looking into why yet. &run_make_test(' define foo : foo-one\ foo-two : foo-three : foo-four endef orig: ; : orig-one : orig-two \ orig-three \ orig-four \ orig-five \\\\ : orig-six $(foo) .RECIPEPREFIX = > test: ; : test-one >: test-two \ test-three \ >test-four \ > test-five \\\\ >: test-six >$(foo) .RECIPEPREFIX = reset: ; : reset-one : reset-two \ reset-three \ reset-four \ reset-five \\\\ : reset-six $(foo) ', '-j1 orig test reset', ': orig-one : orig-two \ orig-three \ orig-four \ orig-five \\\\ : orig-six : foo-one foo-two : foo-three : foo-four : test-one : test-two \ test-three \ test-four \ test-five \\\\ : test-six : foo-one foo-two : foo-three : foo-four : reset-one : reset-two \ reset-three \ reset-four \ reset-five \\\\ : reset-six : foo-one foo-two : foo-three : foo-four'); # Test that the "did you mean TAB" message is printed properly run_make_test(q! $x. !, '', '#MAKEFILE#:2: *** missing separator. Stop.', 512); run_make_test(q! foo: bar !, '', '#MAKEFILE#:3: *** missing separator (did you mean TAB instead of 8 spaces?). Stop.', 512); run_make_test(q! .RECIPEPREFIX = : foo: bar !, '', '#MAKEFILE#:4: *** missing separator. Stop.', 512); 1; ### Local Variables: ### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) ### End: kbuild-3149/src/kmk/tests/scripts/variables/flavors0000644000175000017500000000263113252530202022451 0ustar locutuslocutus# -*-perl-*- $description = "Test various flavors of make variable setting."; $details = ""; # TEST 0: Recursive run_make_test(' ugh = Goodbye foo = $(bar) bar = ${ugh} ugh = Hello all: ; @echo $(foo) ', '', "Hello\n"); # TEST 1: Simple run_make_test(' bar = Goodbye foo := $(bar) bar = ${ugh} ugh = Hello all: ; @echo $(foo) ', '', "Goodbye\n"); # TEST 2: Append to recursive run_make_test(' foo = Hello ugh = Goodbye foo += $(bar) bar = ${ugh} ugh = Hello all: ; @echo $(foo) ', '', "Hello Hello\n"); # TEST 3: Append to simple run_make_test(' foo := Hello ugh = Goodbye bar = ${ugh} foo += $(bar) ugh = Hello all: ; @echo $(foo) ', '', "Hello Goodbye\n"); # TEST 4: Conditional pre-set run_make_test(' foo = Hello ugh = Goodbye bar = ${ugh} foo ?= $(bar) ugh = Hello all: ; @echo $(foo) ', '', "Hello\n"); # TEST 5: Conditional unset run_make_test(' ugh = Goodbye bar = ${ugh} foo ?= $(bar) ugh = Hello all: ; @echo $(foo) ', '', "Hello\n"); # TEST 6: Simple using POSIX syntax run_make_test(' bar = Goodbye foo ::= $(bar) bar = ${ugh} ugh = Hello all: ; @echo $(foo) ', '', "Goodbye\n"); # TEST 7: POSIX syntax no spaces run_make_test(' bar = Goodbye foo::=$(bar) bar = ${ugh} ugh = Hello all: ; @echo $(foo) ', '', "Goodbye\n"); 1; kbuild-3149/src/kmk/tests/scripts/variables/private0000644000175000017500000000454213252530202022452 0ustar locutuslocutus# -*-perl-*- $description = "Test 'private' variables."; $details = ""; # 1: Simple verification that private variables are not inherited &run_make_test(' a: F = g a: F = a b: private F = b a b c: ; @echo $@: F=$(F) a: b b: c ', '', "c: F=a\nb: F=b\na: F=a\n"); # 2: Again, but this time we start with "b" so "a"'s variable is not in scope &run_make_test(undef, 'b', "c: F=g\nb: F=b\n"); # 3: Verification with pattern-specific variables &run_make_test(' t.a: F1 = g F2 = g %.a: private F1 = a %.a: F2 = a t.a t.b: ; @echo $@: F1=$(F1) / F2=$(F2) t.a: t.b ', '', "t.b: F1=g / F2=a\nt.a: F1=a / F2=a\n"); # 4: Test private global variables &run_make_test(' a: private F = g G := $(F) a: b: F = b a b: ; @echo $@: F=$(F) / G=$(G) a: b ', '', "b: F=b / G=g\na: F= / G=g\n"); # 5: Multiple conditions on the same variable. Test export. delete $ENV{'_X'}; &run_make_test(' _X = x a: export override private _X = a a: ; @echo _X=$(_X) / _X=$$_X ', '', "_X=a / _X=a"); # 6: Test override. &run_make_test(undef, '_X=c', "_X=a / _X=a\n"); # 7: Ensure keywords still work as targets &run_make_test(' a: export override private foo bar foo bar export override private: ; @echo $@ ', '', "export\noverride\nprivate\nfoo\nbar\n"); # 8: Ensure keywords still work as variables &run_make_test(' private = g a: private = a a: b a b: ; @echo $@=$(private) ', '', "b=a\na=a\n"); # 9: make sure private suppresses inheritance run_make_test(q! DEFS = FOO all: bar1 bar1: private DEFS += 1 bar3: private DEFS += 3 bar1: bar2 bar2: bar3 bar1 bar2 bar3: ; @echo '$@: $(DEFS)' !, '', "bar3: FOO 3\nbar2: FOO\nbar1: FOO 1\n"); # 10: Test append with pattern-specific variables and private run_make_test(q! IA = global PA = global PS = global S = global PS = global SV = global b%: IA += b% b%: private PA += b% b%: private PS = b% bar: all bar: IA += bar bar: private PA += bar bar: private PS = bar a%: IA += a% a%: private PA += a% a%: private PS = a% all: IA += all all: private PA += all all: private PS = all bar all: ; @echo '$@: IA=$(IA)'; echo '$@: PA=$(PA)'; echo '$@: PS=$(PS)' !, '', "all: IA=global b% bar a% all all: PA=global a% all all: PS=all bar: IA=global b% bar bar: PA=global b% bar bar: PS=bar\n"); 1; kbuild-3149/src/kmk/tests/scripts/variables/MAKEFILE_LIST0000644000175000017500000000115313252530202023003 0ustar locutuslocutus# -*-perl-*- $description = "Test the MAKEFILE_LIST variable."; $makefile2 = &get_tmpfile; open(MAKEFILE,"> $makefile"); print MAKEFILE < $makefile2"); print MAKEFILE "m2 := \$(MAKEFILE_LIST)\n"; close(MAKEFILE); &run_make_with_options($makefile, "", &get_logfile); $answer = "$makefile\n$makefile $makefile2\n$makefile $makefile2\n"; &compare_output($answer,&get_logfile(1)); 1; kbuild-3149/src/kmk/tests/scripts/variables/undefine0000644000175000017500000000167313252530202022577 0ustar locutuslocutus# -*-perl-*- $description = "Test variable undefine."; $details = ""; # TEST 0: basic undefine functionality run_make_test(' a = a b := b define c c endef $(info $(flavor a) $(flavor b) $(flavor c)) n := b undefine a undefine $n undefine c $(info $(flavor a) $(flavor b) $(flavor c)) all: ;@: ', '', "recursive simple recursive\nundefined undefined undefined"); # TEST 1: override run_make_test(' undefine a override undefine b $(info $(flavor a) $(flavor b)) all: ;@: ', 'a=a b=b', "recursive undefined"); 1; # TEST 2: undefine in eval (make sure we undefine from the global var set) run_make_test(' define undef $(eval undefine $$1) endef a := a $(call undef,a) $(info $(flavor a)) all: ;@: ', '', "undefined"); # TEST 3: Missing variable name run_make_test(' a = undefine $a all: ;@echo ouch ', '', "#MAKEFILE#:3: *** empty variable name. Stop.\n", 512); 1; kbuild-3149/src/kmk/tests/scripts/variables/MAKEFLAGS0000644000175000017500000000227113252530202022267 0ustar locutuslocutus# -*-perl-*- $description = "Test proper behavior of MAKEFLAGS"; $details = "DETAILS"; # Normal flags aren't prefixed with "-" run_make_test(q! all: ; @echo $(MAKEFLAGS) !, '-e -r -R', 'erR'); # Long arguments mean everything is prefixed with "-" run_make_test(q! all: ; @echo $(MAKEFLAGS) !, '--no-print-directory -e -r -R --trace', "#MAKEFILE#:2: target 'all' does not exist echo erR --trace --no-print-directory erR --trace --no-print-directory"); # Recursive invocations of make should accumulate MAKEFLAGS values. # Savannah bug #2216 run_make_test(q! MSG = Fails all: @echo '$@: MAKEFLAGS=$(MAKEFLAGS)' @MSG=Works $(MAKE) -e -f #MAKEFILE# jump jump: @echo '$@ $(MSG): MAKEFLAGS=$(MAKEFLAGS)' @$(MAKE) -f #MAKEFILE# print print: @echo '$@ $(MSG): MAKEFLAGS=$(MAKEFLAGS)' .PHONY: all jump print !, '--no-print-directory', 'all: MAKEFLAGS= --no-print-directory jump Works: MAKEFLAGS=e --no-print-directory print Works: MAKEFLAGS=e --no-print-directory'); 1; ### Local Variables: ### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) ### End: kbuild-3149/src/kmk/tests/scripts/variables/GNUMAKEFLAGS0000644000175000017500000000252613252530202022644 0ustar locutuslocutus# -*-perl-*- $description = "Test proper behavior of GNUMAKEFLAGS"; # Accept flags from GNUMAKEFLAGS as well as MAKEFLAGS # Results always go in MAKEFLAGS $extraENV{'GNUMAKEFLAGS'} = '-e -r -R'; run_make_test(q! all: ; @echo $(MAKEFLAGS) !, '', 'erR'); # Long arguments mean everything is prefixed with "-" $extraENV{'GNUMAKEFLAGS'} = '--no-print-directory -e -r -R --trace'; run_make_test(q! all: ; @echo $(MAKEFLAGS) !, '', "#MAKEFILE#:2: target 'all' does not exist echo erR --trace --no-print-directory erR --trace --no-print-directory"); # Verify that re-exec / recursion doesn't duplicate flags from GNUMAKEFLAGS unlink('x.mk'); $extraENV{GNUMAKEFLAGS} = '-Itst/bad'; run_make_test(q! recurse: ; @echo $@; echo MAKEFLAGS = $$MAKEFLAGS; echo GNUMAKEFLAGS = $$GNUMAKEFLAGS; #MAKEPATH# -f #MAKEFILE# all all: ; @echo $@; echo MAKEFLAGS = $$MAKEFLAGS; echo GNUMAKEFLAGS = $$GNUMAKEFLAGS -include x.mk x.mk: ; @echo $@; echo MAKEFLAGS = $$MAKEFLAGS; echo GNUMAKEFLAGS = $$GNUMAKEFLAGS; echo > $@ !, "", "x.mk\nMAKEFLAGS = -Itst/bad\nGNUMAKEFLAGS =\nrecurse\nMAKEFLAGS = -Itst/bad\nGNUMAKEFLAGS =\n#MAKE#[1]: Entering directory '#PWD#'\nall\nMAKEFLAGS = w -Itst/bad\nGNUMAKEFLAGS =\n#MAKE#[1]: Leaving directory '#PWD#'\n"); unlink('x.mk'); 1; kbuild-3149/src/kmk/tests/scripts/variables/SHELL0000644000175000017500000000561513252530202021651 0ustar locutuslocutus# -*-perl-*- $description = "Test proper handling of SHELL."; # Find the default value when SHELL is not set. On UNIX it will be /bin/sh, # but on other platforms who knows? resetENV(); delete $ENV{SHELL}; $mshell = `echo 'all:;\@echo \$(SHELL)' | $make_path -f-`; chop $mshell; # According to POSIX, the value of SHELL in the environment has no impact on # the value in the makefile. # Note %extraENV takes precedence over the default value for the shell. $extraENV{SHELL} = '/dev/null'; run_make_test('all:;@echo "$(SHELL)"', '', $mshell); # According to POSIX, any value of SHELL set in the makefile should _NOT_ be # exported to the subshell! I wanted to set SHELL to be $^X (perl) in the # makefile, but make runs $(SHELL) -c 'commandline' and that doesn't work at # all when $(SHELL) is perl :-/. So, we just add an extra initial /./ which # works well on UNIX and seems to work OK on at least some non-UNIX systems. $extraENV{SHELL} = $mshell; run_make_test("SHELL := /./$mshell\n".' all:;@echo "$(SHELL) $$SHELL" ', '', "/./$mshell $mshell"); # As a GNU make extension, if make's SHELL variable is explicitly exported, # then we really _DO_ export it. $extraENV{SHELL} = $mshell; run_make_test("export SHELL := /./$mshell\n".' all:;@echo "$(SHELL) $$SHELL" ', '', "/./$mshell /./$mshell"); # Test out setting of SHELL, both exported and not, as a target-specific # variable. $extraENV{SHELL} = $mshell; run_make_test("all: SHELL := /./$mshell\n".' all:;@echo "$(SHELL) $$SHELL" ', '', "/./$mshell $mshell"); $extraENV{SHELL} = $mshell; # bird: This was wrong at some point, see Savannah bug #24655. Was first fixed in kBuild. run_make_test(" SHELL := /././$mshell one: two two: export SHELL := /./$mshell\n".' one two:;@echo "$@: $(SHELL) $$SHELL" ', '', "two: /./$mshell /./$mshell\none: /././$mshell $mshell\n"); # Test .SHELLFLAGS # We don't know the output here: on Solaris for example, every line printed # by the shell in -x mode has a trailing space (!!) my $script = 'true; true'; my $flags = '-xc'; my $out = `/bin/sh $flags '$script' 2>&1`; run_make_test(qq! .SHELLFLAGS = $flags all: ; \@$script !, '', $out); # Do it again but add spaces to SHELLFLAGS # Some shells (*shakes fist at Solaris*) cannot handle multiple flags in # separate arguments. my $t = `/bin/sh -e -c true 2>/dev/null`; my $multi_ok = $? == 0; if ($multi_ok) { $flags = '-x -c'; run_make_test(qq! .SHELLFLAGS = $flags all: ; \@$script !, '', $out); } # We can't just use "false" because on different systems it provides a # different exit code--once again Solaris: false exits with 255 not 1 $script = 'true; false; true'; $flags = '-xec'; $out = `/bin/sh $flags '$script' 2>&1`; my $err = $? >> 8; run_make_test(qq! .SHELLFLAGS = $flags all: ; \@$script !, '', "$out#MAKE#: *** [#MAKEFILE#:3: all] Error $err\n", 512); 1; kbuild-3149/src/kmk/tests/scripts/variables/MAKE0000644000175000017500000000073113252530202021511 0ustar locutuslocutus# -*-perl-*- $description = "Test proper behavior of the MAKE variable"; $details = "DETAILS"; run_make_test(q! TMP := $(MAKE) MAKE := $(subst X=$(X),,$(MAKE)) all: @echo $(TMP) $(MAKE) -f #MAKEFILE# foo foo: @echo $(MAKE) !, '', "#MAKEPATH#\n#MAKEPATH# -f #MAKEFILE# foo\n" . "#MAKE#[1]: Entering directory '#PWD#'\n" . "#MAKEPATH#\n#MAKE#[1]: Leaving directory '#PWD#'\n"); rmfiles("foo"); 1; kbuild-3149/src/kmk/tests/scripts/variables/MAKELEVEL0000644000175000017500000000151213252530202022277 0ustar locutuslocutus# -*-perl-*- $description = "The following test creates a makefile to test makelevels in Make. It prints \$(MAKELEVEL) and then prints the environment variable MAKELEVEL"; open(MAKEFILE,"> $makefile"); # The Contents of the MAKEFILE ... if (!$is_kmk) { print MAKEFILE < $makefile"); print MAKEFILE "\ .DEFAULT all: \@echo \$(MAKECMDGOALS) "; close(MAKEFILE); # TEST #1 &run_make_with_options($makefile, "", &get_logfile, 0); $answer = "\n"; &compare_output($answer,&get_logfile(1)); # TEST #2 &run_make_with_options($makefile, "all", &get_logfile, 0); $answer = "all\n"; &compare_output($answer,&get_logfile(1)); # TEST #3 &run_make_with_options($makefile, "foo bar baz yaz", &get_logfile, 0); $answer = "foo bar baz yaz\nfoo bar baz yaz\nfoo bar baz yaz\nfoo bar baz yaz\n"; &compare_output($answer,&get_logfile(1)); # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/variables/LIBPATTERNS0000644000175000017500000000156413252530202022570 0ustar locutuslocutus# -*-perl-*- $description = "Test .LIBPATTERNS special variable."; $details = ""; # TEST 0: basics touch('mtest_foo.a'); run_make_test(' .LIBPATTERNS = mtest_%.a all: -lfoo ; @echo "build $@ from $<" ', '', "build all from mtest_foo.a\n"); # TEST 1: Handle elements that are not patterns. run_make_test(' .LIBPATTERNS = mtest_foo.a mtest_%.a all: -lfoo ; @echo "build $@ from $<" ', '', "#MAKE#: .LIBPATTERNS element 'mtest_foo.a' is not a pattern build all from mtest_foo.a\n"); # TEST 2: target-specific override # Uncomment this when we add support, see Savannah bug #25703 # run_make_test(' # .LIBPATTERNS = mbad_%.a # all: .LIBPATTERNS += mtest_%.a # all: -lfoo ; @echo "build $@ from $<" # ', # '', "build all from mtest_foo.a\n"); unlink('mtest_foo.a'); 1; kbuild-3149/src/kmk/tests/scripts/variables/automatic0000644000175000017500000000602613252530202022765 0ustar locutuslocutus# -*-perl-*- $description = "Test automatic variable setting."; $details = ""; use Cwd; $dir = cwd; $dir =~ s,.*/([^/]+)$,../$1,; open(MAKEFILE, "> $makefile"); print MAKEFILE "dir = $dir\n"; print MAKEFILE <<'EOF'; .SUFFIXES: .SUFFIXES: .x .y .z $(dir)/foo.x : baz.z $(dir)/bar.y baz.z @echo '$$@ = $@, $$(@D) = $(@D), $$(@F) = $(@F)' @echo '$$* = $*, $$(*D) = $(*D), $$(*F) = $(*F)' @echo '$$< = $<, $$( $makefile2"); print MAKEFILE "dir = $dir\n"; print MAKEFILE <<'EOF'; .SECONDEXPANSION: .SUFFIXES: .DEFAULT: ; @echo '$@' $(dir)/foo $(dir)/bar: $@.x $$@.x $$$@.x $$$$@.x $$(@D).x $$(@F).x $(dir)/x.z $(dir)/y.z: $(dir)/%.z : $@.% $$@.% $$$@.% $$$$@.% $$(@D).% $$(@F).% $(dir)/biz: $$(@).x $${@}.x $${@D}.x $${@F}.x EOF close(MAKEFILE); &run_make_with_options($makefile2, "-j1 $dir/foo $dir/bar", &get_logfile); $answer = ".x\n$dir/foo.x\nx\n\$@.x\n$dir.x\nfoo.x\n$dir/bar.x\nbar.x\n"; &compare_output($answer, &get_logfile(1)); &run_make_with_options($makefile2, "-j1 $dir/x.z $dir/y.z", &get_logfile); $answer = ".x\n$dir/x.z.x\nx\n\$@.x\n$dir.x\nx.z.x\n.y\n$dir/y.z.y\n\y\n\$@.y\n$dir.y\ny.z.y\n"; &compare_output($answer, &get_logfile(1)); &run_make_with_options($makefile2, "-j1 $dir/biz", &get_logfile); $answer = "$dir/biz.x\n$dir.x\nbiz.x\n"; &compare_output($answer, &get_logfile(1)); # TEST #2 -- test for Savannah bug #12320. # run_make_test(' .SUFFIXES: .b .src mbr.b: mbr.src @echo $* mbr.src: ; @:', '', 'mbr'); # TEST #3 -- test for Savannah bug #8154 # Make sure that nonexistent prerequisites are listed in $?, since they are # considered reasons for the target to be rebuilt. # # See also Savannah bugs #16002 and #16051. touch('foo'); run_make_test(' foo: bar ; @echo "\$$? = $?" bar: ;', '', '$? = bar'); unlink('foo'); # TEST #4: ensure prereq ordering is correct when the commmand target has none # See Savannah bug #21198 run_make_test(' all : A B all : ; @echo $@ -- $^ -- $< all : C D all : E F A B C D E F G H : ; @: ', '', "all -- A B C D E F -- A\n"); 1; kbuild-3149/src/kmk/tests/scripts/variables/CURDIR0000644000175000017500000000067713252530202021775 0ustar locutuslocutus# -*-perl-*- $description = "This tests the CURDIR varaible."; $details = "Echo CURDIR both with and without -C. Also ensure overrides work."; open(MAKEFILE,"> $makefile"); print MAKEFILE "all: ; \@echo \$(CURDIR)\n"; close(MAKEFILE); # TEST #1 # ------- &run_make_with_options($makefile,"",&get_logfile); $answer = "$pwd\n"; &compare_output($answer,&get_logfile(1)); 1; kbuild-3149/src/kmk/tests/scripts/variables/MAKE_RESTARTS0000644000175000017500000000234513252530202023043 0ustar locutuslocutus# -*-perl-*- $description = "Test the MAKE_RESTARTS variable."; # Test basic capability run_make_test(' all: ; @: $(info MAKE_RESTARTS=$(MAKE_RESTARTS)) include foo.x foo.x: ; @touch $@ ', '', 'MAKE_RESTARTS= MAKE_RESTARTS=1'); rmfiles('foo.x'); # Test multiple restarts run_make_test(' all: ; @: $(info MAKE_RESTARTS=$(MAKE_RESTARTS)) include foo.x foo.x: ; @echo "include bar.x" > $@ bar.x: ; @touch $@ ', '', 'MAKE_RESTARTS= MAKE_RESTARTS=1 MAKE_RESTARTS=2'); rmfiles('foo.x', 'bar.x'); # Test multiple restarts and make sure the variable is cleaned up run_make_test(' recurse: @echo recurse MAKE_RESTARTS=$$MAKE_RESTARTS @$(MAKE) -f #MAKEFILE# all all: @echo all MAKE_RESTARTS=$$MAKE_RESTARTS $(info MAKE_RESTARTS=$(MAKE_RESTARTS)) include foo.x foo.x: ; @echo "include bar.x" > $@ bar.x: ; @touch $@ ', '', "MAKE_RESTARTS= MAKE_RESTARTS=1 MAKE_RESTARTS=2 recurse MAKE_RESTARTS= #MAKE#[1]: Entering directory '#PWD#' MAKE_RESTARTS= all MAKE_RESTARTS= #MAKE#[1]: Leaving directory '#PWD#'"); rmfiles('foo.x', 'bar.x'); 1; ### Local Variables: ### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) ### End: kbuild-3149/src/kmk/tests/scripts/variables/DEFAULT_GOAL0000644000175000017500000000225413252530202022664 0ustar locutuslocutus# -*-perl-*- $description = "Test the .DEFAULT_GOAL special variable."; $details = ""; # Test #1: basic logic. # run_make_test(' # Basics. # foo: ; @: ifneq ($(.DEFAULT_GOAL),foo) $(error ) endif # Reset to empty. # .DEFAULT_GOAL := bar: ; @: ifneq ($(.DEFAULT_GOAL),bar) $(error ) endif # Change to a different goal. # .DEFAULT_GOAL := baz baz: ; @echo $@ ', '', 'baz'); # Test #2: unknown goal. # run_make_test(' .DEFAULT_GOAL = foo ', '', "#MAKE#: *** No rule to make target 'foo'. Stop.", 512); # Test #3: more than one goal. # run_make_test(' .DEFAULT_GOAL := foo bar ', '', '#MAKE#: *** .DEFAULT_GOAL contains more than one target. Stop.', 512); # Test #4: Savannah bug #12226. # run_make_test(' define rule foo: ; @echo $$@ endef define make-rule $(eval $(rule)) endef $(call make-rule) ', '', 'foo'); # TEST #5: .DEFAULT_GOAL containing just whitespace (Savannah bug #25697) run_make_test(' N = .DEFAULT_GOAL = $N $N # Just whitespace foo: ; @echo "boo" ', '', "#MAKE#: *** No targets. Stop.\n", 512); # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/variables/MFILE_LIST0000644000175000017500000000115313252530202022462 0ustar locutuslocutus# -*-perl-*- $description = "Test the MAKEFILE_LIST variable."; $makefile2 = &get_tmpfile; open(MAKEFILE,"> $makefile"); print MAKEFILE < $makefile2"); print MAKEFILE "m2 := \$(MAKEFILE_LIST)\n"; close(MAKEFILE); &run_make_with_options($makefile, "", &get_logfile); $answer = "$makefile\n$makefile $makefile2\n$makefile $makefile2\n"; &compare_output($answer,&get_logfile(1)); 1; kbuild-3149/src/kmk/tests/scripts/variables/INCLUDE_DIRS0000644000175000017500000000150313252530202022676 0ustar locutuslocutus# -*-perl-*- $description = "Test the .INCLUDE_DIRS special variable."; $details = ""; use Cwd; $dir = cwd; $dir =~ s,.*/([^/]+)$,../$1,; # Test #1: The content of .INCLUDE_DIRS depends on the platform for which # make was built. What we know for sure is that it shouldn't be # empty. # run_make_test(' ifeq ($(.INCLUDE_DIRS),) $(warning .INCLUDE_DIRS is empty) endif .PHONY: all all:;@: ', '', ''); # Test #2: Make sure -I paths end up in .INCLUDE_DIRS. # run_make_test(' ifeq ($(dir),) $(warning dir is empty) endif ifeq ($(filter $(dir),$(.INCLUDE_DIRS)),) $(warning .INCLUDE_DIRS does not contain $(dir)) endif .PHONY: all all:;@: ', "-I$dir dir=$dir", ''); # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/variables/define0000644000175000017500000001042713252530202022231 0ustar locutuslocutus# -*-perl-*- $description = "Test define/endef variable assignments."; $details = ""; # TEST 0: old-style basic define/endef run_make_test(' define multi @echo hi echo there endef all: ; $(multi) ', '', "hi\necho there\nthere\n"); # TEST 1: Various new-style define/endef run_make_test(' FOO = foo define multi = echo hi @echo $(FOO) endef # this is the end define simple := @echo $(FOO) endef define posix ::= @echo $(FOO) endef append = @echo a define append += @echo b endef define cond ?= # this is a conditional @echo first endef define cond ?= @echo second endef FOO = there all: ; $(multi) $(simple) $(posix) $(append) $(cond) ', '', "echo hi\nhi\nthere\nfoo\nfoo\na\nb\nfirst\n"); # TEST 1a: Various new-style define/endef, with no spaces run_make_test(' FOO = foo define multi= echo hi @echo $(FOO) endef # this is the end define simple:= @echo $(FOO) endef define posix::= @echo $(FOO) endef append = @echo a define append+= @echo b endef define cond?= # this is a conditional @echo first endef define cond?= @echo second endef FOO = there all: ; $(multi) $(simple) $(posix) $(append) $(cond) ', '', "echo hi\nhi\nthere\nfoo\nfoo\na\nb\nfirst\n"); # TEST 2: define in true section of conditional (containing conditional) run_make_test(' FOO = foo NAME = def def = ifdef BOGUS define $(subst e,e,$(NAME)) = ifeq (1,1) FOO = bar endif endef endif $(eval $(def)) all: ; @echo $(FOO) ', 'BOGUS=1', "bar\n"); # TEST 3: define in false section of conditional (containing conditional) run_make_test(undef, '', "foo\n"); # TEST 4: nested define (supported?) run_make_test(' define outer define inner A = B endef endef $(eval $(outer)) outer: ; @echo $(inner) ', '', "A = B\n"); # TEST 5: NEGATIVE: Missing variable name run_make_test(' NAME = define $(NAME) = ouch endef all: ; @echo ouch ', '', "#MAKEFILE#:3: *** empty variable name. Stop.\n", 512); # TEST 6: NEGATIVE: extra text after define run_make_test(' NAME = define NAME = $(NAME) ouch endef all: ; @echo ok ', '', "#MAKEFILE#:3: extraneous text after 'define' directive\nok\n"); # TEST 7: NEGATIVE: extra text after endef run_make_test(' NAME = define NAME = ouch endef $(NAME) all: ; @echo ok ', '', "#MAKEFILE#:5: extraneous text after 'endef' directive\nok\n"); # TEST 8: NEGATIVE: missing endef run_make_test(' NAME = all: ; @echo ok define NAME = ouch endef$(NAME) ', '', "#MAKEFILE#:4: *** missing 'endef', unterminated 'define'. Stop.\n", 512); # ------------------------- # Make sure that prefix characters apply properly to define/endef values. # # There's a bit of oddness here if you try to use a variable to hold the # prefix character for a define. Even though something like this: # # define foo # echo bar # endef # # all: ; $(V)$(foo) # # (where V=@) can be seen by the user to be obviously different than this: # # define foo # $(V)echo bar # endef # # all: ; $(foo) # # and the user thinks it should behave the same as when the "@" is literal # instead of in a variable, that can't happen because by the time make # expands the variables for the command line and sees it begins with a "@" it # can't know anymore whether the prefix character came before the variable # reference or was included in the first line of the variable reference. # TEST #5 # ------- run_make_test(' define FOO $(V1)echo hello $(V2)echo world endef all: ; @$(FOO) ', '', 'hello world'); # TEST #6 # ------- run_make_test(undef, 'V1=@ V2=@', 'hello world'); # TEST #7 # ------- run_make_test(' define FOO $(V1)echo hello $(V2)echo world endef all: ; $(FOO) ', 'V1=@', 'hello echo world world'); # TEST #8 # ------- run_make_test(undef, 'V2=@', 'echo hello hello world'); # TEST #9 # ------- run_make_test(undef, 'V1=@ V2=@', 'hello world'); # TEST #10 # ------- # Test the basics; a "@" internally to the variable applies to only one line. # A "@" before the variable applies to the entire variable. run_make_test(' define FOO @echo hello echo world endef define BAR echo hello echo world endef all: foo bar foo: ; $(FOO) bar: ; @$(BAR) ', '', 'hello echo world world hello world '); 1; kbuild-3149/src/kmk/tests/scripts/variables/MAKEFILES0000644000175000017500000000207713252530202022301 0ustar locutuslocutus# -*-perl-*- $description = "Test the MAKEFILES variable."; $makefile2 = &get_tmpfile; $makefile3 = &get_tmpfile; open(MAKEFILE,"> $makefile"); print MAKEFILE 'all: ; @echo DEFAULT RULE: M2=$(M2) M3=$(M3)', "\n"; close(MAKEFILE); open(MAKEFILE,"> $makefile2"); print MAKEFILE < $makefile3"); print MAKEFILE < # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # $description = "Tests the .MUST_MAKE target variable"; $details = "The .MUST_MAKE target variable is expanded when make is deciding whether a file needs to be made or not. If it returns a non-empty string, when stripped, it will force the file to be made. If it returns an empty string GNU make decides the normal way. Note that .MUST_MAKE does NOT have to be expanded if make already knows the file needs building. Also, note that for multi target rules it may be invoked for each file."; if ($is_kmk) { # TEST #0 - check to see that it gets called and is made. # ------------------------------------------------------- &touch('foobar.1'); run_make_test(' foobar.1: .MUST_MAKE = $(info mustmake:{@=$@,<=$<})FORCE foobar.1: ;touch $@ ', '', 'mustmake:{@=foobar.1,<=} touch foobar.1' ); unlink('foobar.1'); # TEST #1 - check to see that it gets called and isn't made. # ---------------------------------------------------------- &touch('foobar.1'); run_make_test(' foobar.1: .MUST_MAKE = $(info mustmake:{@=$@,<=$<}) foobar.1: ;touch $@ ', '', 'mustmake:{@=foobar.1,<=} #MAKE#: `foobar.1\' is up to date.' ); unlink('foobar.1'); # TEST #2 - check to see that it doesn't get called unnecessary. # -------------------------------------------------------------- run_make_test(' foobar.1: .MUST_MAKE = $(info mustmake:{@=$@,<=$})FORCE foobar.1: ;@echo making $@ ', '', 'making foobar.1'); } # Indicate that we're done. 1; kbuild-3149/src/kmk/tests/scripts/targets/0000755000175000017500000000000013252530202020551 5ustar locutuslocutuskbuild-3149/src/kmk/tests/scripts/targets/clean0000644000175000017500000000216113252530202021556 0ustar locutuslocutus# -*-perl-*- $description = "The following test creates a makefile to delete a \n" ."file in the directory. It tests to see if make will \n" ."NOT execute the command unless the rule is given in \n" ."the make command line."; $example = "EXAMPLE_FILE"; open(MAKEFILE,"> $makefile"); # The Contents of the MAKEFILE ... print MAKEFILE "all: \n"; print MAKEFILE "\t\@echo This makefile did not clean the dir... good\n"; print MAKEFILE "clean: \n"; print MAKEFILE "\t$delete_command EXAMPLE_FILE\n"; # END of Contents of MAKEFILE close(MAKEFILE); &touch($example); &run_make_with_options($makefile,"",&get_logfile,0); # Create the answer to what should be produced by this Makefile $answer = "This makefile did not clean the dir... good\n"; &compare_output($answer,&get_logfile(1)) || &error ("abort"); $answer = "$delete_command $example\n"; &run_make_with_options($makefile,"clean",&get_logfile,0); if (-f $example) { $test_passed = 0; } &compare_output($answer,&get_logfile(1)) || &error ("abort"); 1; kbuild-3149/src/kmk/tests/scripts/targets/DEFAULT0000644000175000017500000000266313252530202021567 0ustar locutuslocutus$description = "The following test creates a makefile to override part\n" ."of one Makefile with Another Makefile with the .DEFAULT\n" ."rule."; $details = "This tests the use of the .DEFAULT special target to say that \n" ."to remake any target that cannot be made fram the information\n" ."in the containing makefile, make should look in another makefile\n" ."This test gives this makefile the target bar which is not \n" ."defined here but passes the target bar on to another makefile\n" ."which does have the target bar defined.\n"; $makefile2 = &get_tmpfile; open(MAKEFILE,"> $makefile"); # The Contents of the MAKEFILE ... print MAKEFILE "foo:\n"; print MAKEFILE "\t\@echo Executing rule FOO\n\n"; print MAKEFILE ".DEFAULT:\n"; print MAKEFILE "\t\@\$(MAKE) -f $makefile2 \$\@ \n"; # END of Contents of MAKEFILE close(MAKEFILE); open(MAKEFILE,"> $makefile2"); print MAKEFILE "bar:\n"; print MAKEFILE "\t\@echo Executing rule BAR\n\n"; close(MAKEFILE); &run_make_with_options($makefile,'bar',&get_logfile); # Create the answer to what should be produced by this Makefile $answer = "${make_name}[1]: Entering directory '$pwd'\n" . "Executing rule BAR\n" . "${make_name}[1]: Leaving directory '$pwd'\n"; # COMPARE RESULTS &compare_output($answer,&get_logfile(1)); # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/targets/INTERMEDIATE0000644000175000017500000000574613252530202022362 0ustar locutuslocutus# -*-perl-*- $description = "Test the behaviour of the .INTERMEDIATE target."; $details = "\ Test the behavior of the .INTERMEDIATE special target. Create a makefile where a file would not normally be considered intermediate, then specify it as .INTERMEDIATE. Build and ensure it's deleted properly. Rebuild to ensure that it's not created if it doesn't exist but doesn't need to be built. Change the original and ensure that the intermediate file and the ultimate target are both rebuilt, and that the intermediate file is again deleted. Try this with implicit rules and explicit rules: both should work.\n"; open(MAKEFILE,"> $makefile"); print MAKEFILE <<'EOF'; .INTERMEDIATE: foo.e bar.e # Implicit rule test %.d : %.e ; cp $< $@ %.e : %.f ; cp $< $@ foo.d: foo.e # Explicit rule test foo.c: foo.e bar.e; cat $^ > $@ EOF close(MAKEFILE); # TEST #0 &utouch(-20, 'foo.f', 'bar.f'); &run_make_with_options($makefile,'foo.d',&get_logfile); $answer = "cp foo.f foo.e\ncp foo.e foo.d\nrm foo.e\n"; &compare_output($answer, &get_logfile(1)); # TEST #1 &run_make_with_options($makefile,'foo.d',&get_logfile); $answer = "$make_name: 'foo.d' is up to date.\n"; &compare_output($answer, &get_logfile(1)); # TEST #2 &utouch(-10, 'foo.d'); &touch('foo.f'); &run_make_with_options($makefile,'foo.d',&get_logfile); $answer = "cp foo.f foo.e\ncp foo.e foo.d\nrm foo.e\n"; &compare_output($answer, &get_logfile(1)); # TEST #3 # kmk+fast: differs because of different hashing. &run_make_with_options($makefile,'foo.c',&get_logfile); $answer = "cp foo.f foo.e\ncp bar.f bar.e\ncat foo.e bar.e > foo.c\n" . (!$is_kmk && !$is_fast ? "rm bar.e foo.e\n" : "rm foo.e bar.e\n"); &compare_output($answer, &get_logfile(1)); # TEST #4 &run_make_with_options($makefile,'foo.c',&get_logfile); $answer = "$make_name: 'foo.c' is up to date.\n"; &compare_output($answer, &get_logfile(1)); # TEST #5 # kmk+fast: differs because of different hashing. &utouch(-10, 'foo.c'); &touch('foo.f'); &run_make_with_options($makefile,'foo.c',&get_logfile); $answer = "cp foo.f foo.e\ncp bar.f bar.e\ncat foo.e bar.e > foo.c\n" . (!$is_kmk && !$is_fast ? "rm bar.e foo.e\n" : "rm foo.e bar.e\n"); &compare_output($answer, &get_logfile(1)); # TEST #6 -- added for PR/1669: don't remove files mentioned on the cmd line. &run_make_with_options($makefile,'foo.e',&get_logfile); $answer = "cp foo.f foo.e\n"; &compare_output($answer, &get_logfile(1)); unlink('foo.f', 'foo.e', 'foo.d', 'foo.c', 'bar.f', 'bar.e', 'bar.d', 'bar.c'); # TEST #7 -- added for PR/1423 $makefile2 = &get_tmpfile; open(MAKEFILE, "> $makefile2"); print MAKEFILE <<'EOF'; all: foo foo.a: ; touch $@ %: %.a ; touch $@ .INTERMEDIATE: foo.a EOF close(MAKEFILE); &run_make_with_options($makefile2, '-R', &get_logfile); $answer = "touch foo.a\ntouch foo\nrm foo.a\n"; &compare_output($answer, &get_logfile(1)); unlink('foo'); # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/targets/SILENT0000644000175000017500000000156313252530202021477 0ustar locutuslocutus# -*-perl-*- $description = "The following tests the special target .SILENT. By simply\n" ."mentioning this as a target, it tells make not to print\n" ."commands before executing them."; $details = "This test is the same as the clean test except that it should\n" ."not echo its command before deleting the specified file.\n"; $example = "EXAMPLE_FILE"; open(MAKEFILE,"> $makefile"); # The Contents of the MAKEFILE ... print MAKEFILE ".SILENT : clean\n"; print MAKEFILE "clean: \n"; print MAKEFILE "\t$delete_command EXAMPLE_FILE\n"; # END of Contents of MAKEFILE close(MAKEFILE); &touch($example); $answer = ""; &run_make_with_options($makefile,"clean",&get_logfile,0); if (-f $example) { $test_passed = 0; } &compare_output($answer,&get_logfile(1)); 1; kbuild-3149/src/kmk/tests/scripts/targets/FORCE0000644000175000017500000000142113252530202021330 0ustar locutuslocutus# -*-perl-*- $description = "The following tests rules without Commands or Dependencies."; $details = "If the rule ...\n"; open(MAKEFILE,"> $makefile"); # The Contents of the MAKEFILE ... print MAKEFILE ".IGNORE :\n"; print MAKEFILE "clean: FORCE\n"; print MAKEFILE "\t$delete_command clean\n"; print MAKEFILE "FORCE:\n"; # END of Contents of MAKEFILE close(MAKEFILE); # Create a file named "clean". This is the same name as the target clean # and tricks the target into thinking that it is up to date. (Unless you # use the .PHONY target. &touch("clean"); $answer = "$delete_command clean\n"; &run_make_with_options($makefile,"clean",&get_logfile); &compare_output($answer,&get_logfile(1)); 1; kbuild-3149/src/kmk/tests/scripts/targets/DELETE_ON_ERROR0000644000175000017500000000106213252530202023002 0ustar locutuslocutus#! -*-perl-*- $description = "Test the behaviour of the .DELETE_ON_ERROR target."; $details = ""; run_make_test(' .DELETE_ON_ERROR: all: ; exit 1 > $@ ', '', "exit 1 > all\n#MAKE#: *** [#MAKEFILE#:3: all] Error 1\n#MAKE#: *** Deleting file 'all'", 512); run_make_test(' .DELETE_ON_ERROR: all: foo.x ; %.x : %.q ; echo > $@ %.q : ; exit 1 > $@ ', '', "exit 1 > foo.q\n#MAKE#: *** [#MAKEFILE#:5: foo.q] Error 1\n#MAKE#: *** Deleting file 'foo.q'", 512); # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/targets/ONESHELL0000644000175000017500000000265613252530202021716 0ustar locutuslocutus# -*-perl-*- $description = "Test the behaviour of the .ONESHELL target."; $details = ""; # Some shells (*shakes fist at Solaris*) cannot handle multiple flags in # separate arguments. my $t = `/bin/sh -e -c true 2>/dev/null`; my $multi_ok = $? == 0; # Simple run_make_test(q! .ONESHELL: all: a=$$$$ [ 0"$$a" -eq "$$$$" ] || echo fail !, '', 'a=$$ [ 0"$a" -eq "$$" ] || echo fail '); # Simple but use multi-word SHELLFLAGS if ($multi_ok) { run_make_test(q! .ONESHELL: .SHELLFLAGS = -e -c all: a=$$$$ [ 0"$$a" -eq "$$$$" ] || echo fail !, '', 'a=$$ [ 0"$a" -eq "$$" ] || echo fail '); } # Again, but this time with inner prefix chars run_make_test(q! .ONESHELL: all: a=$$$$ @-+ [ 0"$$a" -eq "$$$$" ] || echo fail !, '', 'a=$$ [ 0"$a" -eq "$$" ] || echo fail '); # This time with outer prefix chars run_make_test(q! .ONESHELL: all: @a=$$$$ [ 0"$$a" -eq "$$$$" ] || echo fail !, '', ''); # This time with outer and inner prefix chars run_make_test(q! .ONESHELL: all: @a=$$$$ -@ +[ 0"$$a" -eq "$$$$" ] || echo fail !, '', ''); # Now try using a different interpreter run_make_test(q! .RECIPEPREFIX = > .ONESHELL: SHELL = #PERL# .SHELLFLAGS = -e all: > @$$a=5 > +7; > @y=qw(a b c); >print "a = $$a, y = (@y)\n"; !, '', "a = 12, y = (a b c)\n"); 1; kbuild-3149/src/kmk/tests/scripts/targets/SECONDARY0000644000175000017500000000752513252530202022034 0ustar locutuslocutus#! -*-perl-*- $description = "Test the behaviour of the .SECONDARY target."; $details = "\ Test the behavior of the .SECONDARY special target. Create a makefile where a file would not normally be considered intermediate, then specify it as .SECONDARY. Build and note that it's not automatically deleted. Delete the file. Rebuild to ensure that it's not created if it doesn't exist but doesn't need to be built. Change the original and ensure that the secondary file and the ultimate target are both rebuilt, and that the secondary file is not deleted. Try this with implicit rules and explicit rules: both should work.\n"; open(MAKEFILE,"> $makefile"); print MAKEFILE <<'EOF'; .SECONDARY: foo.e # Implicit rule test %.d : %.e ; cp $< $@ %.e : %.f ; cp $< $@ foo.d: foo.e # Explicit rule test foo.c: foo.e ; cp $< $@ EOF close(MAKEFILE); # TEST #1 &utouch(-20, 'foo.f'); &run_make_with_options($makefile,'foo.d',&get_logfile); $answer = "cp foo.f foo.e\ncp foo.e foo.d\n"; &compare_output($answer, &get_logfile(1)); # TEST #2 unlink('foo.e'); &run_make_with_options($makefile,'foo.d',&get_logfile); $answer = "$make_name: 'foo.d' is up to date.\n"; &compare_output($answer, &get_logfile(1)); # TEST #3 &utouch(-10, 'foo.d'); &touch('foo.f'); &run_make_with_options($makefile,'foo.d',&get_logfile); $answer = "cp foo.f foo.e\ncp foo.e foo.d\n"; &compare_output($answer, &get_logfile(1)); # TEST #4 &run_make_with_options($makefile,'foo.c',&get_logfile); $answer = "cp foo.e foo.c\n"; &compare_output($answer, &get_logfile(1)); # TEST #5 unlink('foo.e'); &run_make_with_options($makefile,'foo.c',&get_logfile); $answer = "$make_name: 'foo.c' is up to date.\n"; &compare_output($answer, &get_logfile(1)); # TEST #6 &utouch(-10, 'foo.c'); &touch('foo.f'); &run_make_with_options($makefile,'foo.c',&get_logfile); $answer = "cp foo.f foo.e\ncp foo.e foo.c\n"; &compare_output($answer, &get_logfile(1)); unlink('foo.f', 'foo.e', 'foo.d', 'foo.c'); # TEST #7 -- test the "global" .SECONDARY, with no targets. $makefile2 = &get_tmpfile; open(MAKEFILE, "> $makefile2"); print MAKEFILE <<'EOF'; .SECONDARY: final: intermediate intermediate: source final intermediate source: echo $< > $@ EOF close(MAKEFILE); &utouch(-10, 'source'); touch('final'); &run_make_with_options($makefile2, '', &get_logfile); $answer = "$make_name: 'final' is up to date.\n"; &compare_output($answer, &get_logfile(1)); unlink('source', 'final', 'intermediate'); # TEST #8 -- test the "global" .SECONDARY, with .PHONY. touch('version2'); run_make_test(' .PHONY: version .SECONDARY: version2: version ; @echo GOOD all: version2', 'all', 'GOOD'); unlink('version2'); # TEST #9 -- Savannah bug #15919 # The original fix for this bug caused a new bug, shown here. touch(qw(1.a 2.a)); run_make_test(' %.c : %.b ; cp $< $@ %.b : %.a ; cp $< $@ all : 1.c 2.c 2.a: 1.c', '-rR -j', 'cp 1.a 1.b cp 1.b 1.c cp 2.a 2.b cp 2.b 2.c rm 1.b 2.b'); unlink(qw(1.a 2.a 1.c 2.c)); # TEST #10 -- Savannah bug #15919 touch('test.0'); run_make_test(' .SECONDARY : test.1 test.2 test.3 test : test.4 %.4 : %.int %.3 ; touch $@ %.int : %.3 %.2 ; touch $@ %.3 : | %.2 ; touch $@ %.2 : %.1 ; touch $@ %.1 : %.0 ; touch $@', '-rR -j 2', 'touch test.1 touch test.2 touch test.3 touch test.int touch test.4 rm test.int'); # After a touch of test.0 it should give the same output, except we don't need # to rebuild test.3 (order-only) sleep(1); touch('test.0'); run_make_test(undef, '-rR -j 2', 'touch test.1 touch test.2 touch test.int touch test.4 rm test.int'); # With both test.0 and test.3 updated it should still build everything except # test.3 sleep(1); touch('test.0', 'test.3'); run_make_test(undef, '-rR -j 2', 'touch test.1 touch test.2 touch test.int touch test.4 rm test.int'); unlink(qw(test.0 test.1 test.2 test.3 test.4)); # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/targets/POSIX0000644000175000017500000000305113252530202021375 0ustar locutuslocutus# -*-perl-*- $description = "Test the behaviour of the .POSIX target."; $details = ""; # Ensure turning on .POSIX enables the -e flag for the shell # We can't assume the exit value of "false" because on different systems it's # different. my $script = 'false; true'; my $flags = '-ec'; my $out = `/bin/sh $flags '$script' 2>&1`; my $err = $? >> 8; run_make_test(qq! .POSIX: all: ; \@$script !, '', "#MAKE#: *** [#MAKEFILE#:3: all] Error $err\n", 512); # User settings must override .POSIX $flags = '-xc'; $out = `/bin/sh $flags '$script' 2>&1`; run_make_test(qq! .SHELLFLAGS = $flags .POSIX: all: ; \@$script !, '', $out); # Test the default value of various POSIX-specific variables my %POSIX = (AR => 'ar', ARFLAGS => '-rv', YACC => 'yacc', YFLAGS => '', LEX => 'lex', LFLAGS => '', LDFLAGS => '', CC => 'c99', CFLAGS => '-O', FC => 'fort77', FFLAGS => '-O 1', GET => 'get', GFLAGS => '', SCCSFLAGS => '', SCCSGETFLAGS => '-s'); my $make = join('', map { "\t\@echo '$_=\$($_)'\n" } sort keys %POSIX); my $r = join('', map { "$_=$POSIX{$_}\n"} sort keys %POSIX); run_make_test(qq! .POSIX: all: $make !, '', $r); # Make sure that local settings take precedence %extraENV = map { $_ => "xx-$_" } keys %POSIX; $r = join('', map { "$_=xx-$_\n"} sort keys %POSIX); run_make_test(undef, '', $r); # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/targets/PHONY0000644000175000017500000000261013252530202021370 0ustar locutuslocutus# -*-perl-*- $description = "The following tests the use of a PHONY target. It makes\n" ."sure that the rules under a target get executed even if\n" ."a filename of the same name of the target exists in the\n" ."directory.\n"; $details = "This makefile in this test declares the target clean to be a \n" ."PHONY target. We then create a file named \"clean\" in the \n" ."directory. Although this file exists, the rule under the target\n" ."clean should still execute because of it's phony status."; $example = "EXAMPLE_FILE"; open(MAKEFILE,"> $makefile"); # The Contents of the MAKEFILE ... print MAKEFILE ".PHONY : clean \n"; print MAKEFILE "all: \n"; print MAKEFILE "\t\@echo This makefile did not clean the dir ... good\n"; print MAKEFILE "clean: \n"; print MAKEFILE "\t$delete_command $example clean\n"; # END of Contents of MAKEFILE close(MAKEFILE); &touch($example); # Create a file named "clean". This is the same name as the target clean # and tricks the target into thinking that it is up to date. (Unless you # use the .PHONY target. &touch("clean"); $answer = "$delete_command $example clean\n"; &run_make_with_options($makefile,"clean",&get_logfile); if (-f $example) { $test_passed = 0; } &compare_output($answer,&get_logfile(1)); 1; kbuild-3149/src/kmk/tests/scripts/test_template0000644000175000017500000000176713252530202021710 0ustar locutuslocutus# -*-perl-*- $description = ""; $details = ""; # Run a make test. See the documentation of run_make_test() in # run_make_tests.pl, but briefly the first argument is a string with the # contents of a makefile to be tested, the second is a string containing the # arguments to be passed to the make invocation, the third is a string # containing the expected output. The fourth is the expected exit code for # make. If not specified, it's assumed that the make program should succeed # (exit with 0). run_make_test('Your test makefile goes here', 'Arguments to pass to make go here', 'Expected output from the invocation goes here'); # There are various special tokens, options, etc. See the full documentation # in run_make_tests.pl. # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/options/0000755000175000017500000000000013252530202020573 5ustar locutuslocutuskbuild-3149/src/kmk/tests/scripts/options/dash-C0000644000175000017500000000332213252530202021615 0ustar locutuslocutus# -*-perl-*- $description = "Test the -C option to GNU make."; $details = "\ This test is similar to the clean test except that this test creates the file to delete in the work directory instead of the current directory. Make is called from another directory using the -C workdir option so that it can both find the makefile and the file to delete in the work directory."; $example = $workdir . $pathsep . "EXAMPLE"; open(MAKEFILE,"> $makefile"); print MAKEFILE < $makefile"); # The Contents of the MAKEFILE ... print MAKEFILE < $makefile2"); print MAKEFILE <<'EOF'; .SUFFIXES: all: exe1 exe2; @echo making $@ exe1 exe2: lib; @echo cp $^ $@ lib: foo.o; @echo cp $^ $@ foo.o: ; exit 1 EOF close(MAKEFILE); &run_make_with_options($makefile2, "-k", &get_logfile, $error_code); $answer = "exit 1 $make_name: *** [$makefile2:9: foo.o] Error 1 $make_name: Target 'all' not remade because of errors.\n"; &compare_output($answer, &get_logfile(1)); # TEST -- make sure we keep the error code if we can't create an included # makefile. run_make_test('all: ; @echo hi include ifile ifile: no-such-file; @false ', '-k', "#MAKEFILE#:2: ifile: No such file or directory #MAKE#: *** No rule to make target 'no-such-file', needed by 'ifile'. #MAKE#: Failed to remake makefile 'ifile'. hi\n", 512); 1; kbuild-3149/src/kmk/tests/scripts/options/dash-B0000644000175000017500000000337513252530202021624 0ustar locutuslocutus# -*-perl-*- $description = "Test make -B (always remake) option.\n"; $details = "\ Construct a simple makefile that builds a target. Invoke make once, so it builds everything. Invoke it again and verify that nothing is built. Then invoke it with -B and verify that everything is built again."; &touch('bar.x'); run_make_test(' .SUFFIXES: .PHONY: all all: foo foo: bar.x @echo cp $< $@ @echo "" > $@ ', '', 'cp bar.x foo'); run_make_test(undef, '', "#MAKE#: Nothing to be done for 'all'."); run_make_test(undef, '-B', 'cp bar.x foo'); # Put the timestamp for foo into the future; it should still be remade. utouch(1000, 'foo'); run_make_test(undef, '', "#MAKE#: Nothing to be done for 'all'."); run_make_test(undef, '-B', 'cp bar.x foo'); # Clean up rmfiles('bar.x', 'foo'); # Test -B with the re-exec feature: we don't want to re-exec forever # Savannah bug # 7566 run_make_test(' all: ; @: $(info MAKE_RESTARTS=$(MAKE_RESTARTS)) include foo.x foo.x: ; @touch $@ ', '-B', 'MAKE_RESTARTS= MAKE_RESTARTS=1'); rmfiles('foo.x'); # Test -B with the re-exec feature: we DO want -B in the "normal" part of the # makefile. &touch('blah.x'); run_make_test(' all: blah.x ; @echo $@ $(info MAKE_RESTARTS=$(MAKE_RESTARTS)) include foo.x foo.x: ; @touch $@ blah.x: ; @echo $@ ', '-B', 'MAKE_RESTARTS= MAKE_RESTARTS=1 blah.x all'); rmfiles('foo.x', 'blah.x'); # Test that $? is set properly with -B; all prerequisites will be newer! utouch(-10, 'x.b'); touch('x.a'); run_make_test(q! x.a: x.b ; @echo $? !, '-B', "x.b\n"); unlink(qw(x.a x.b)); 1; ### Local Variables: ### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) ### End: kbuild-3149/src/kmk/tests/scripts/options/warn-undefined-variables0000644000175000017500000000125513252530202025375 0ustar locutuslocutus# -*-perl-*- $description = "Test the --warn-undefined-variables option."; $details = "Verify that warnings are printed for referencing undefined variables."; # Without --warn-undefined-variables, nothing should happen run_make_test(' EMPTY = EREF = $(EMPTY) UREF = $(UNDEFINED) SEREF := $(EREF) SUREF := $(UREF) all: ; @echo ref $(EREF) $(UREF)', '', 'ref'); # With --warn-undefined-variables, it should warn me run_make_test(undef, '--warn-undefined-variables', "#MAKEFILE#:7: warning: undefined variable 'UNDEFINED' #MAKEFILE#:9: warning: undefined variable 'UNDEFINED' ref"); 1; kbuild-3149/src/kmk/tests/scripts/options/dash-q0000644000175000017500000000301113252530202021666 0ustar locutuslocutus# -*-perl-*- $description = "Test the -q option.\n"; $details = "Try various uses of -q and ensure they all give the correct results.\n"; # TEST 0 run_make_test(qq! one: two: ; three: ; : four: ; \$(.XY) five: ; \\ \$(.XY) six: ; \\ \$(.XY) \t\$(.XY) seven: ; \\ \$(.XY) \t: foo \t\$(.XY) !, '-q one', ''); # TEST 1 run_make_test(undef, '-q two', ''); # TEST 2 run_make_test(undef, '-q three', '', 256); # TEST 3 run_make_test(undef, '-q four', ''); # TEST 4 run_make_test(undef, '-q five', ''); # TEST 5 run_make_test(undef, '-q six', ''); # TEST 6 run_make_test(undef, '-q seven', '', 256); # TEST 7 : Savannah bug # 7144 run_make_test(' one:: ; @echo one one:: ; @echo two ', '-q', '', 256); # TEST 7 : Savannah bug # 42249 # Make sure we exit with 1 even for prerequisite updates run_make_test(' build-stamp: ; echo $@ build-arch: build-stamp build-x: build-arch build-y: build-x ', '-q build-y', '', 256); # TEST 8 # Make sure we exit with 2 on error even with -q run_make_test(' build-stamp: ; echo $@ build-arch: build-stamp-2 build-x: build-arch build-y: build-x ', '-q build-y', "#MAKE#: *** No rule to make target 'build-stamp-2', needed by 'build-arch'. Stop.\n", 512); # TEST 9 : Savannah bug # 47151 # Make sure we exit with 1 when invoking a recursive make run_make_test(' foo: bar ; echo foo bar: ; @$(MAKE) -f #MAKEFILE# baz baz: ; echo baz ', '-q foo', '', 256); 1; kbuild-3149/src/kmk/tests/scripts/options/dash-l0000644000175000017500000000300013252530202021657 0ustar locutuslocutus# -*-perl-*- # Date: Tue, 11 Aug 1992 09:34:26 -0400 # From: pds@lemming.webo.dg.com (Paul D. Smith) $description = "Test load balancing (-l) option."; $details = "\ This test creates a makefile where all depends on three rules which contain the same body. Each rule checks for the existence of a temporary file; if it exists an error is generated. If it doesn't exist then it is created, the rule sleeps, then deletes the temp file again. Thus if any of the rules are run in parallel the test will fail. When make is called in this test, it is given the -l option with a value of 0.0001. This ensures that the load will be above this number and make will therefore decide that it cannot run more than one job even though -j 4 was also specified on the command line."; open(MAKEFILE,"> $makefile"); # The Contents of the MAKEFILE ... print MAKEFILE <<'EOF'; SHELL = /bin/sh define test if [ ! -f test-file ]; then \ echo >> test-file; sleep 2; rm -f test-file; \ else \ echo $@ FAILED; \ fi endef all : ONE TWO THREE ONE : ; @$(test) TWO : ; @$(test) THREE : ; @$(test) EOF # END of Contents of MAKEFILE close(MAKEFILE); $mkoptions = "-l 0.0001"; $mkoptions .= " -j 4" if ($parallel_jobs); # We have to wait longer than the default (5s). &run_make_with_options($makefile, $mkoptions, &get_logfile, 0, 8); $slurp = &read_file_into_string (&get_logfile(1)); if ($slurp !~ /cannot enforce load limit/) { &compare_output("", &get_logfile(1)); } 1; kbuild-3149/src/kmk/tests/scripts/options/dash-f0000644000175000017500000000503113252530202021657 0ustar locutuslocutus$description = "The following test tests that if you specify greater \n" ."than one '-f makefilename' on the command line, \n" ."that make concatenates them. This test creates three \n" ."makefiles and specifies all of them with the -f option \n" ."on the command line. To make sure they were concatenated, \n" ."we then call make with the rules from the concatenated \n" ."makefiles one at a time. Finally, it calls all three \n" ."rules in one call to make and checks that the output\n" ."is in the correct order."; $makefile2 = &get_tmpfile; $makefile3 = &get_tmpfile; open(MAKEFILE,"> $makefile"); # The Contents of the MAKEFILE ... print MAKEFILE "all: \n"; print MAKEFILE "\t\@echo This is the output from the original makefile\n"; # END of Contents of MAKEFILE close(MAKEFILE); # Create a second makefile open(MAKEFILE,"> $makefile2"); print MAKEFILE "TWO: \n"; print MAKEFILE "\t\@echo This is the output from makefile 2\n"; close(MAKEFILE); # Create a third makefile open(MAKEFILE,"> $makefile3"); print MAKEFILE "THREE: \n"; print MAKEFILE "\t\@echo This is the output from makefile 3\n"; close(MAKEFILE); # Create the answer to what should be produced by this Makefile $answer = "This is the output from the original makefile\n"; # Run make to catch the default rule &run_make_with_options($makefile,"-f $makefile2 -f $makefile3",&get_logfile,0); &compare_output($answer,&get_logfile(1)); # Run Make again with the rule from the second makefile: TWO $answer = "This is the output from makefile 2\n"; &run_make_with_options($makefile,"-f $makefile2 -f $makefile3 TWO",&get_logfile,0); &compare_output($answer,&get_logfile(1)); # Run Make again with the rule from the third makefile: THREE $answer = "This is the output from makefile 3\n"; &run_make_with_options($makefile, "-f $makefile2 -f $makefile3 THREE", &get_logfile, 0); &compare_output($answer,&get_logfile(1)); # Run Make again with ALL three rules in the order 2 1 3 to make sure # that all rules are executed in the proper order $answer = "This is the output from makefile 2\n"; $answer .= "This is the output from the original makefile\n"; $answer .= "This is the output from makefile 3\n"; &run_make_with_options($makefile, "-f $makefile2 -f $makefile3 TWO all THREE", &get_logfile, 0); &compare_output($answer,&get_logfile(1)); kbuild-3149/src/kmk/tests/scripts/options/dash-I0000644000175000017500000000312113252530202021620 0ustar locutuslocutus# -*-perl-*- $description ="The following test creates a makefile to test the -I option."; $details = "\ This test tests the -I option by including a filename in another directory and giving make that directory name under -I in the command line. Without this option, the make would fail to find the included file. It also checks to make sure that the -I option gets passed to recursive makes."; $makefile2 = &get_tmpfile; open(MAKEFILE,"> $makefile"); # The Contents of the MAKEFILE ... $mf2 = substr ($makefile2, index ($makefile2, $pathsep) + 1); print MAKEFILE < $makefile2"); print MAKEFILE < dep # We'll make both dep and targ older than sym $pwd =~ m%/([^/]+)$%; $dirnm = $1; &utouch(-10, 'dep'); &utouch(-5, 'targ'); symlink("../$dirnm/dep", 'sym'); # Without -L, nothing should happen # With -L, it should update targ run_make_test('targ: sym ; @echo make $@ from $<', '', "#MAKE#: 'targ' is up to date."); run_make_test(undef, '-L', "make targ from sym"); # Now update dep; in all cases targ should be out of date. &touch('dep'); run_make_test(undef, '', "make targ from sym"); run_make_test(undef, '-L', "make targ from sym"); # Now update targ; in all cases targ should be up to date. &touch('targ'); run_make_test(undef, '', "#MAKE#: 'targ' is up to date."); run_make_test(undef, '-L', "#MAKE#: 'targ' is up to date."); # Add in a new link between sym and dep. Be sure it's newer than targ. sleep(1); rename('dep', 'dep1'); symlink('dep1', 'dep'); # Without -L, nothing should happen # With -L, it should update targ run_make_test(undef, '', "#MAKE#: 'targ' is up to date."); run_make_test(undef, '-L', "make targ from sym"); rmfiles('targ', 'dep', 'sym', 'dep1'); # Check handling when symlinks point to non-existent files. Without -L we # should get an error: with -L we should use the timestamp of the symlink. symlink("../$dirname/dep", 'sym'); run_make_test('targ: sym ; @echo make $@ from $<', '', "#MAKE#: *** No rule to make target 'sym', needed by 'targ'. Stop.", 512); run_make_test('targ: sym ; @echo make $@ from $<', '-L', 'make targ from sym'); rmfiles('targ', 'sym'); 1; } kbuild-3149/src/kmk/tests/scripts/options/dash-e0000644000175000017500000000066313252530202021664 0ustar locutuslocutus# -*-perl-*- $description = "The following test creates a makefile to ..."; $details = ""; $extraENV{GOOGLE} = 'boggle'; open(MAKEFILE,"> $makefile"); print MAKEFILE <<'EOF'; GOOGLE = bazzle all:; @echo "$(GOOGLE)" EOF close(MAKEFILE); &run_make_with_options($makefile, '-e' ,&get_logfile); $answer = "boggle\n"; &compare_output($answer,&get_logfile(1)); 1; kbuild-3149/src/kmk/tests/scripts/options/dash-t0000644000175000017500000000306613252530202021703 0ustar locutuslocutus# -*-perl-*- $description = "Test the -t option.\n"; $details = "Look out for regressions of prior bugs related to -t.\n"; # That means, nobody has even tried to make the tests below comprehensive # TEST 0 # bug reported by Henning Makholm on 2001-11-03: # make 3.79.1 touches only interm-[ab] but reports final-[a] as # 'up to date' without touching them. # The 'obvious' fix didn't work for double-colon rules, so pay special # attention to them. open(MAKEFILE, "> $makefile"); print MAKEFILE <<'EOMAKE'; final-a: interm-a ; echo >> $@ final-b: interm-b ; echo >> $@ interm-a:: orig1-a ; echo >> $@ interm-a:: orig2-a ; echo >> $@ interm-b:: orig1-b ; echo >> $@ interm-b:: orig2-b ; echo >> $@ EOMAKE close(MAKEFILE); &utouch(-30, 'orig1-a','orig2-b'); &utouch(-20, 'interm-a','interm-b'); &utouch(-10, 'final-a','final-b'); &touch('orig2-a','orig1-b'); &run_make_with_options($makefile, "-t final-a final-b", &get_logfile); $answer = "touch interm-a\ntouch final-a\ntouch interm-b\ntouch final-b\n"; &compare_output($answer, &get_logfile(1)); unlink('orig1-a', 'orig2-a', 'interm-a', 'final-a'); unlink('orig1-b', 'orig2-b', 'interm-b', 'final-b'); # TEST 1 # -t should not touch files with no commands. $makefile2 = &get_tmpfile; open(MAKEFILE, "> $makefile2"); print MAKEFILE <<'EOMAKE'; PHOOEY: xxx xxx: ; @: EOMAKE close(MAKEFILE); &run_make_with_options($makefile2, "-t", &get_logfile); $answer = "touch xxx\n"; &compare_output($answer, &get_logfile(1)); unlink('xxx'); 1; kbuild-3149/src/kmk/tests/scripts/options/dash-W0000644000175000017500000000364013252530202021644 0ustar locutuslocutus# -*-perl-*- $description = "Test make -W (what if) option.\n"; # Basic build run_make_test(' a.x: b.x a.x b.x: ; echo >> $@ ', '', "echo >> b.x\necho >> a.x"); # Run it again: nothing should happen run_make_test(undef, '', "#MAKE#: 'a.x' is up to date."); # Now run it with -W b.x: should rebuild a.x run_make_test(undef, '-W b.x', 'echo >> a.x'); # Put the timestamp for a.x into the future; it should still be remade. utouch(1000, 'a.x'); run_make_test(undef, '', "#MAKE#: 'a.x' is up to date."); run_make_test(undef, '-W b.x', 'echo >> a.x'); # Clean up rmfiles('a.x', 'b.x'); # Test -W with the re-exec feature: we don't want to re-exec forever # Savannah bug # 7566 # First set it up with a normal build run_make_test(' all: baz.x ; @: include foo.x foo.x: bar.x @echo "\$$(info restarts=\$$(MAKE_RESTARTS))" > $@ @echo "touch $@" bar.x: ; echo >> $@ baz.x: bar.x ; @echo "touch $@" ', '', 'echo >> bar.x touch foo.x restarts=1 touch baz.x'); # Now run with -W bar.x # Tweak foo.x's timestamp so the update will change it. &utouch(1000, 'foo.x'); run_make_test(undef, '-W bar.x', "restarts=\ntouch foo.x\nrestarts=1\ntouch baz.x"); rmfiles('foo.x', 'bar.x'); # Test -W on vpath-found files: it should take effect. # Savannah bug # 15341 mkdir('x-dir', 0777); utouch(-20, 'x-dir/x'); touch('y'); run_make_test(' y: x ; @echo cp $< $@ ', '-W x-dir/x VPATH=x-dir', 'cp x-dir/x y'); # Make sure ./ stripping doesn't interfere with the match. run_make_test(' y: x ; @echo cp $< $@ ', '-W ./x-dir/x VPATH=x-dir', 'cp x-dir/x y'); run_make_test(undef, '-W x-dir/x VPATH=./x-dir', 'cp ./x-dir/x y'); unlink(qw(y x-dir/x)); rmdir('x-dir'); 1; ### Local Variables: ### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) ### End: kbuild-3149/src/kmk/tests/scripts/options/eval0000644000175000017500000000146113252530202021447 0ustar locutuslocutus# -*-perl-*- $description = "Test the --eval option."; $details = "Verify that --eval options take effect, and are passed to sub-makes."; # Verify that --eval is evaluated first run_make_test(q! BAR = bar all: ; @echo all recurse: ; @$(MAKE) -f #MAKEFILE# && echo recurse!, '--eval=\$\(info\ eval\) FOO=\$\(BAR\)', "eval\nall"); # Make sure that --eval is handled correctly during recursion run_make_test(undef, '--no-print-directory --eval=\$\(info\ eval\) recurse', "eval\neval\nall\nrecurse"); # Make sure that --eval is handled correctly during restarting run_make_test(q! all: ; @echo $@ -include gen.mk gen.mk: ; @echo > $@ !, '--eval=\$\(info\ eval\)', "eval\neval\nall"); unlink('gen.mk'); 1; kbuild-3149/src/kmk/tests/scripts/options/print-directory0000644000175000017500000000132013252530202023650 0ustar locutuslocutus# -*-perl-*- $description = "Test the -w option to GNU make."; # Simple test without -w run_make_test(q! all: ; @echo hi !, "", "hi\n"); # Simple test with -w run_make_test(undef, "-w", "#MAKE#: Entering directory '#PWD#'\nhi\n#MAKE#: Leaving directory '#PWD#'\n"); # Test makefile rebuild to ensure no enter/leave run_make_test(q! include foo all: ;@: foo: ; touch foo !, "", "touch foo\n"); unlink('foo'); # Test makefile rebuild with -w run_make_test(q! include foo all: ;@: foo: ; touch foo !, "-w", "#MAKE#: Entering directory '#PWD#'\ntouch foo\n#MAKE#: Leaving directory '#PWD#'\n"); unlink('foo'); 1; kbuild-3149/src/kmk/tests/scripts/options/general0000644000175000017500000000173513252530202022141 0ustar locutuslocutus# -*-perl-*- $description = "Test generic option processing.\n"; open(MAKEFILE, "> $makefile"); # The Contents of the MAKEFILE ... print MAKEFILE "foo 1foo: ; \@echo \$\@\n"; close(MAKEFILE); # TEST 0 &run_make_with_options($makefile, "-j 1foo", &get_logfile); if (!$parallel_jobs) { $answer = "$make_name: Parallel jobs (-j) are not supported on this platform.\n$make_name: Resetting to single job (-j1) mode.\n1foo\n"; } else { $answer = "1foo\n"; } # TEST 1 # This test prints the usage string; I don't really know a good way to # test it. I guess I could invoke make with a known-bad option to see # what the usage looks like, then compare it to what I get here... :( # If I were always on UNIX, I could invoke it with 2>/dev/null, then # just check the error code. &run_make_with_options($makefile, "-j1foo 2>/dev/null", &get_logfile, 512); $answer = ""; &compare_output($answer, &get_logfile(1)); 1; kbuild-3149/src/kmk/tests/scripts/options/dash-n0000644000175000017500000000441613252530202021675 0ustar locutuslocutus# -*-perl-*- $description = "Test the -n option.\n"; $details = "Try various uses of -n and ensure they all give the correct results.\n"; touch('orig'); run_make_test(q! final: intermediate ; echo >> $@ intermediate: orig ; echo >> $@ !, '', "echo >> intermediate\necho >> final\n"); # TEST 1 run_make_test(undef, '-Worig -n', "echo >> intermediate\necho >> final\n"); rmfiles(qw(orig intermediate final)); # We consider the actual updated timestamp of targets with all # recursive commands, even with -n. Switching this to the new model # is non-trivial because we use a trick below to change the log content # before we compare it ... $makefile2 = &get_tmpfile; open(MAKEFILE, "> $makefile2"); print MAKEFILE <<'EOF'; .SUFFIXES: BAR = # nothing FOO = +$(BAR) a: b; echo > $@ b: c; $(FOO) EOF close(MAKEFILE); &utouch(-20, 'b'); &utouch(-10, 'a'); &touch('c'); # TEST 2 &run_make_with_options($makefile2, "", &get_logfile); $answer = "$make_name: 'a' is up to date.\n"; &compare_output($answer, &get_logfile(1)); # TEST 3 &run_make_with_options($makefile2, "-n", &get_logfile); $answer = "$make_name: 'a' is up to date.\n"; &compare_output($answer, &get_logfile(1)); # TEST 4 unlink(qw(a b)); &run_make_with_options($makefile2, "-t -n", &get_logfile); open(DASH_N_LOG, ">>" . &get_logfile(1)); print DASH_N_LOG "a exists but should not!\n" if -e 'a'; print DASH_N_LOG "b exists but should not!\n" if -e 'b'; close(DASH_N_LOG); &compare_output("touch b\ntouch a\n", &get_logfile(1)); # CLEANUP unlink(qw(a b c)); # Ensure -n continues to be included with recursive/re-execed make # See Savannah bug #38051 $topmake = &get_tmpfile; $submake = &get_tmpfile; open(MAKEFILE, "> $topmake"); print MAKEFILE <<"EOF"; foo: ; \@\$(MAKE) -f "$submake" bar EOF close(MAKEFILE); # The bar target should print what would happen, but not actually run open(MAKEFILE, "> $submake"); print MAKEFILE <<'EOF'; inc: ; touch $@ -include inc bar: ; @echo $(strip $(MAKEFLAGS)) EOF close(MAKEFILE); &run_make_with_options($topmake, '-n --no-print-directory', &get_logfile); $answer = "$make_command -f \"$submake\" bar\ntouch inc\necho n --no-print-directory\n"; &compare_output($answer, &get_logfile(1)); unlink('inc'); 1; kbuild-3149/src/kmk/tests/scripts/vms/0000755000175000017500000000000013252530202017705 5ustar locutuslocutuskbuild-3149/src/kmk/tests/scripts/vms/library0000644000175000017500000000342313252530202021276 0ustar locutuslocutus# -*-mode: perl-*- $description = "Test GNU make's VMS Library management features."; $details = "\ This only works on VMS systems."; return -1 if $osname ne 'VMS'; # Help library $mk_string = "help : help.hlb(file1.hlp)\n\n" . "file1.hlp :\n" . "\t\@pipe open/write xxx file1.hlp ; write xxx \"1 help\" ; close xxx\n"; my $answer = "library /replace help.hlb file1.hlp"; run_make_test($mk_string, '', $answer); unlink('help.hlb'); unlink('file1.hlp'); #Text library $mk_string = "text : text.tlb(file1.txt)\n\n" . "file1.txt :\n" . "\t\@pipe open/write xxx file1.txt ; write xxx \"text file\" ; close xxx\n"; my $answer = "library /replace text.tlb file1.txt"; run_make_test($mk_string, '', $answer); unlink('text.tlb'); unlink('file1.txt'); #Macro library $mk_string = "macro : macro.mlb(file1.mar)\n\n" . "file1.mar :\n" . "\t\pipe open/write xxx file1.mar ; " . "write xxx \".macro a b\" ; write xxx \".endm\" ; close xxx\n"; my $answer = "library /replace macro.mlb file1.mar"; run_make_test($mk_string, '', $answer); unlink('macro.mlb'); unlink('file1.mar'); $mk_string = "all:imagelib.olb(file2.exe)\n" . "file2.exe : file2.obj file2.opt\n" . "\t\@link /share=\$\@ \$\*,\$\*/opt\n\n" . "file2.opt :\n" . "\t\@pipe open/write xxx file2.opt ; " . "write xxx \"CASE_SENSITIVE=YES\" ; close xxx\n" . "file2.c :\n" . "\t\@pipe open/write xxx file2.c ; write xxx \"file2(){}\" ; close xxx\n"; my $answer = "library /replace imagelib.olb file2.exe"; run_make_test($mk_string, '', $answer); unlink('imagelib.olb'); unlink('file2.c'); unlink('file2.obj'); unlink('file2.exe'); unlink('file2.opt'); # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/functions/0000755000175000017500000000000013252530202021110 5ustar locutuslocutuskbuild-3149/src/kmk/tests/scripts/functions/if0000644000175000017500000000164713252530202021441 0ustar locutuslocutus# -*-perl-*- $description = "Test the if function.\n"; $details = "Try various uses of if and ensure they all give the correct results.\n"; open(MAKEFILE, "> $makefile"); print MAKEFILE < # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # $description = "Tests the $(translate ) function"; $details = "A few simple tests and edge cases."; if ($is_kmk) { # TEST #0 - check that the feature is present. # -------------------------------------------- run_make_test(' ifneq ($(translate abcdefghijklmnopqrstuvwxyz,abcde,01234),01234fghijklmnopqrstuvwxyz) $(error sub-test 0 failed) endif .PHONY: all all: ; @: ', '', ''); # TEST #1 - the real test. # ------------------------ run_make_test(' ifneq ($(translate abcdefghijklmnopqrstuvwxyz,abcde,01234),01234fghijklmnopqrstuvwxyz) $(error sub-test 0 failed) endif ifneq ($(translate abcdefghijklmnopqrstuvwxyz,abcde,,.),.....fghijklmnopqrstuvwxyz) $(error sub-test 1 failed) endif ifneq ($(translate abcdefghijklmnopqrstuvwxyz,abcde,),fghijklmnopqrstuvwxyz) $(error sub-test 2 failed) endif ifneq ($(translate abcdefghijklmnopqrstuvwxyz,abcde,x1),x1fghijklmnopqrstuvwxyz) $(error sub-test 3 failed) endif ifneq ($(translate abcdefghijklmnopqrstuvwxyz,bfh),acdegijklmnopqrstuvwxyz) $(error sub-test 4 failed) endif ifneq ($(translate abcdefghijklmnopqrstuvwxyz,z,Z),abcdefghijklmnopqrstuvwxyZ) $(error sub-test 5 failed) endif .PHONY: all all: ; @: ', '', ''); } # Indicate that we're done. 1; kbuild-3149/src/kmk/tests/scripts/functions/notdir0000644000175000017500000000214513252530202022334 0ustar locutuslocutus$description = "The following test creates a makefile to test the notdir " ."function."; $details = ""; # IF YOU NEED >1 MAKEFILE FOR THIS TEST, USE &get_tmpfile; TO GET # THE NAME OF THE MAKEFILE. THIS INSURES CONSISTENCY AND KEEPS TRACK OF # HOW MANY MAKEFILES EXIST FOR EASY DELETION AT THE END. # EXAMPLE: $makefile2 = &get_tmpfile; open(MAKEFILE,"> $makefile"); # The Contents of the MAKEFILE ... print MAKEFILE "string := \$(notdir ${pathsep}src${pathsep}foo.c hacks) \n" ."all: \n" ."\t\@echo \$(string) \n"; # END of Contents of MAKEFILE close(MAKEFILE); &run_make_with_options($makefile,"",&get_logfile,0); # Create the answer to what should be produced by this Makefile $answer = "foo.c hacks\n"; # COMPARE RESULTS # In this call to compare output, you should use the call &get_logfile(1) # to send the name of the last logfile created. You may also use # the special call &get_logfile(1) which returns the same as &get_logfile(1). &compare_output($answer,&get_logfile(1)); # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/functions/findstring0000644000175000017500000000223113252530202023200 0ustar locutuslocutus$description = "The following test creates a makefile to test the findstring " ."function."; $details = ""; # IF YOU NEED >1 MAKEFILE FOR THIS TEST, USE &get_tmpfile; TO GET # THE NAME OF THE MAKEFILE. THIS INSURES CONSISTENCY AND KEEPS TRACK OF # HOW MANY MAKEFILES EXIST FOR EASY DELETION AT THE END. # EXAMPLE: $makefile2 = &get_tmpfile; open(MAKEFILE,"> $makefile"); # The Contents of the MAKEFILE ... print MAKEFILE "string := \$(findstring port, reporter)\n" ."all: \n" ."\t\@echo \$(string) \n"; # END of Contents of MAKEFILE close(MAKEFILE); &run_make_with_options($makefile, "", &get_logfile, 0); # Create the answer to what should be produced by this Makefile $answer = "port\n"; # COMPARE RESULTS # In this call to compare output, you should use the call &get_logfile(1) # to send the name of the last logfile created. You may also use # the special call &get_logfile(1) which returns the same as &get_logfile(1). &compare_output($answer,&get_logfile(1)); # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/functions/length0000644000175000017500000000306513252530202022320 0ustar locutuslocutus# $Id: length 2413 2010-09-11 17:43:04Z bird $ -*-perl-*- ## @file # $(length text) # # # Copyright (c) 2008-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # $description = "Tests the $(length ) function"; $details = "A few simple tests, nothing spectacular."; if ($is_kmk) { # TEST #0 - check that the feature is present. # -------------------------------------------- run_make_test(' ifneq ($(length abcd),4) $(error sub-test 0 failed) endif .PHONY: all all: ; @: ', '', ''); # TEST #1 - the real test. # ------------------------ run_make_test(' ifneq ($(length asdf),4) $(error sub-test 0 failed) endif ifneq ($(length a),1) $(error sub-test 1 failed) endif ifneq ($(length 0123456789),10) $(error sub-test 2 failed) endif ifneq ($(length 0123456789 ),11) $(error sub-test 3 failed) endif .PHONY: all all: ; @: ', '', ''); } # Indicate that we're done. 1; kbuild-3149/src/kmk/tests/scripts/functions/select0000644000175000017500000000446313252530202022321 0ustar locutuslocutus# $Id: select 2413 2010-09-11 17:43:04Z bird $ -*-perl-*- ## @file # $(select when1-cond, when1-body[,whenN-cond, whenN-body]) # # # Copyright (c) 2008-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # $description = "Tests the $(select ) conditional function"; $details = "A few simple tests, nothing spectacular."; if ($is_kmk) { # TEST #0 - check that the feature is present. # -------------------------------------------- run_make_test(' ifneq ($(select 0,failed,1,success),success) $(error sub-test 0 failed) endif .PHONY: all all: ; @: ', '', ''); # TEST #1 - the real test. # ------------------------ run_make_test(' ifneq ($(select 0,failed,1-1,failed2,otherwise,success),success) $(error sub-test 0 failed) endif ifneq ($(select 0,failed,1-1,failed2,otherwise:,success),success) $(error sub-test 1 failed) endif ifneq ($(select 0,failed,1-1,failed2, otherwise:,success),success) $(error sub-test 2 failed) endif ifneq ($(select 0,failed,1-1,failed2, otherwise: ,success),success) $(error sub-test 3 failed) endif ifneq ($(select 0,failed,1-1,failed2, otherwise : ,success),success) $(error sub-test 4 failed) endif ifneq ($(select 0,failed,1-1,failed2, default: ,success),success) $(error sub-test 5 failed) endif ifneq ($(select 0,failed,1-1,failed2,default,success),success) $(error sub-test 6 failed) endif ifneq ($(select 0,failed),) $(error sub-test 10 failed) endif ifneq ($(select 1,works),works) $(error sub-test 11 failed) endif ifneq ($(select 0,failed,1,success,1,failed3,otherwise,failed4),success) $(error sub-test 12 failed) endif .PHONY: all all: ; @: ', '', ''); } # Indicate that we're done. 1; kbuild-3149/src/kmk/tests/scripts/functions/insert0000644000175000017500000000455013252530202022343 0ustar locutuslocutus# $Id: insert 2413 2010-09-11 17:43:04Z bird $ -*-perl-*- ## @file # $(insert in, str[, n[, length[, pad]]]) # # # Copyright (c) 2008-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # $description = "Tests the $(insert ) function"; $details = "Testing edges and some simple stuff."; if ($is_kmk) { # TEST #0 - check that the feature is present. # -------------------------------------------- run_make_test(' ifneq ($(insert a,b),ab) $(error sub-test 0 failed) endif .PHONY: all all: ; @: ', '', ''); # TEST #1 - the real test. # ------------------------ run_make_test(' ifneq ($(insert a,b,1),ab) $(error sub-test 0 failed) endif ifneq ($(insert a,b,2),ba) $(error sub-test 1 failed) endif ifneq ($(insert a,b,3),b a) $(error sub-test 2 failed) endif ifneq ($(insert a,b,0),ba) $(error sub-test 3 failed) endif ifneq ($(insert a,b,-1),ab) $(error sub-test 4 failed) endif ifneq ($(insert a,b,-2),ab) $(error sub-test 5 failed) endif ifneq ($(insert a,b,-10),ab) $(error sub-test 6 failed) endif ifneq ($(insert a,b,-10,0),b) $(error sub-test 10 failed) endif ifneq ($(insert aAAA,b,4,1),b a) $(error sub-test 11 failed) endif ifneq ($(insert a,bBbBbBb,4,4),bBba BbBb) $(error sub-test 12 failed) endif ifneq ($(insert a,bBbBbBb,4,4,z),bBbazzzBbBb) $(error sub-test 20 failed) endif ifneq ($(insert a,bBbBbBb,4,4,xy),bBbaxyxBbBb) $(error sub-test 21 failed) endif ifneq ($(insert a,bBbBbBb,4,4,xyz),bBbaxyzBbBb) $(error sub-test 22 failed) endif ifneq ($(insert a,bBbBbBb,4,4,xyzXYZ),bBbaxyzBbBb) $(error sub-test 23 failed) endif ifneq ($(insert a,bBbBbBb,4,4,),bBba BbBb) $(error sub-test 24 failed) endif .PHONY: all all: ; @: ', '', ''); } # Indicate that we're done. 1; kbuild-3149/src/kmk/tests/scripts/functions/lastpos0000644000175000017500000000543413252530202022526 0ustar locutuslocutus# $Id: lastpos 2413 2010-09-11 17:43:04Z bird $ -*-perl-*- ## @file # $(lastpos needle, haystack[, start]) # # # Copyright (c) 2008-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # $description = "Tests the $(lastpos ) function"; $details = "A few simple tests, nothing spectacular."; if ($is_kmk) { # TEST #0 - check that the feature is present. # -------------------------------------------- run_make_test(' ifneq ($(lastpos b,abc),2) $(error sub-test 0 failed) endif .PHONY: all all: ; @: ', '', ''); # TEST #1 - the real test. # ------------------------ run_make_test(' ifneq ($(lastpos t,abcdefghijklmnopqrstuvwxyz),20) $(error sub-test 0 failed) endif ifneq ($(lastpos tu,abcdefghijklmnopqrstuvwxyz),20) $(error sub-test 1 failed) endif ifneq ($(lastpos tuv,abcdefghijklmnopqrstuvwxyz),20) $(error sub-test 2 failed) endif ifneq ($(lastpos tuvw,abcdefghijklmnopqrstuvwxyz),20) $(error sub-test 3 failed) endif ifneq ($(lastpos tuvwx,abcdefghijklmnopqrstuvwxyz),20) $(error sub-test 4 failed) endif ifneq ($(lastpos tuvwxy,abcdefghijklmnopqrstuvwxyz),20) $(error sub-test 5 failed) endif ifneq ($(lastpos tuvwxyz,abcdefghijklmnopqrstuvwxyz),20) $(error sub-test 6 failed) endif ifneq ($(lastpos tuvwxyz!,abcdefghijklmnopqrstuvwxyz),0) $(error sub-test 7 failed) endif ifneq ($(lastpos a,ababababab),9) $(error sub-test 10 failed) endif ifneq ($(lastpos a,ababababab,8),7) $(error sub-test 11 failed) endif ifneq ($(lastpos a,ababababab,7),7) $(error sub-test 12 failed) endif ifneq ($(lastpos a,ababababab,4),3) $(error sub-test 13 failed) endif ifneq ($(lastpos a,ababababab,3),3) $(error sub-test 14 failed) endif ifneq ($(lastpos a,ababababab,2),1) $(error sub-test 15 failed) endif ifneq ($(lastpos a,ababababab,1),1) $(error sub-test 16 failed) endif ifneq ($(lastpos a,ababababab,-1),9) $(error sub-test 17 failed) endif ifneq ($(lastpos a,ababababab,-2),9) $(error sub-test 18 failed) endif ifneq ($(lastpos a,ababababab,-10),1) $(error sub-test 19 failed) endif ifneq ($(lastpos a,ababababab,-11),0) $(error sub-test 20 failed) endif .PHONY: all all: ; @: ', '', ''); } # Indicate that we're done. 1; kbuild-3149/src/kmk/tests/scripts/functions/origin0000644000175000017500000000263613252530202022331 0ustar locutuslocutus# -*-perl-*- $description = "Test the origin function."; $details = "This is a test of the origin function in gnu make. This function will report on where a variable was defined per the following list: 'undefined' never defined 'default' default definition 'environment' environment var without -e 'environment override' environment var with -e 'file' defined in makefile 'command line' defined on the command line 'override' defined by override in makefile 'automatic' Automatic variable\n"; # kmk: CC isn't a default. $CC_origin = $is_kmk ? "undefined" : "default"; # Set an environment variable $extraENV{MAKETEST} = 1; run_make_test(' foo := bletch garf auto_var = undefined CC MAKETEST MAKE foo CFLAGS WHITE @ av = $(foreach var, $(auto_var), $(origin $(var)) ) override WHITE := BLACK all: auto @echo $(origin undefined) @echo $(origin CC) @echo $(origin MAKETEST) @echo $(origin MAKE) @echo $(origin foo) @echo $(origin CFLAGS) @echo $(origin WHITE) @echo $(origin @) auto : @echo $(av)', '-e WHITE=WHITE CFLAGS=', 'undefined '. $CC_origin .' environment default file command line override automatic undefined '. $CC_origin .' environment default file command line override automatic'); # Reset an environment variable delete $extraENV{MAKETEST}; 1; kbuild-3149/src/kmk/tests/scripts/functions/expr0000644000175000017500000000322013252530202022006 0ustar locutuslocutus# $Id: expr 2413 2010-09-11 17:43:04Z bird $ -*-perl-*- ## @file # $(expr expr) # # # Copyright (c) 2008-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # $description = "Tests the \$(expr ) function"; $details = "Much of the basic testing is taken care of by features/ifcond. We only make sure \$(expr ) works here)."; if ($is_kmk) { # TEST #0 - check that the feature is present. # -------------------------------------------- run_make_test(' ifneq ($(expr 1+1),2) $(error sub-test 0 failed) endif .PHONY: all all: ; @: ', '', ''); # TEST #1 - basics, the $(expr test checks the rest). # --------------------------------------------------- run_make_test(' ifneq ($(expr 1==1),1) $(error sub-test 0 failed) endif ifneq ($(expr 1!=1),0) $(error sub-test 1 failed) endif ifneq ($(expr 2*2),4) $(error sub-test 1 failed) endif ifneq ($(expr 25*25),625) $(error sub-test 1 failed) endif .PHONY: all all: ; @: ', '', ''); } # Indicate that we're done. 1; kbuild-3149/src/kmk/tests/scripts/functions/pos0000644000175000017500000000530113252530202021633 0ustar locutuslocutus# $Id: pos 2413 2010-09-11 17:43:04Z bird $ -*-perl-*- ## @file # $(pos needle, haystack[, start]) # # # Copyright (c) 2008-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # $description = "Tests the $(pos ) function"; $details = "A few simple tests, nothing spectacular."; if ($is_kmk) { # TEST #0 - check that the feature is present. # -------------------------------------------- run_make_test(' ifneq ($(pos b,abc),2) $(error sub-test 0 failed) endif .PHONY: all all: ; @: ', '', ''); # TEST #1 - the real test. # ------------------------ run_make_test(' ifneq ($(pos t,abcdefghijklmnopqrstuvwxyz),20) $(error sub-test 0 failed) endif ifneq ($(pos tu,abcdefghijklmnopqrstuvwxyz),20) $(error sub-test 1 failed) endif ifneq ($(pos tuv,abcdefghijklmnopqrstuvwxyz),20) $(error sub-test 2 failed) endif ifneq ($(pos tuvw,abcdefghijklmnopqrstuvwxyz),20) $(error sub-test 3 failed) endif ifneq ($(pos tuvwx,abcdefghijklmnopqrstuvwxyz),20) $(error sub-test 4 failed) endif ifneq ($(pos tuvwxy,abcdefghijklmnopqrstuvwxyz),20) $(error sub-test 5 failed) endif ifneq ($(pos tuvwxyz,abcdefghijklmnopqrstuvwxyz),20) $(error sub-test 6 failed) endif ifneq ($(pos tuvwxyz!,abcdefghijklmnopqrstuvwxyz),0) $(error sub-test 7 failed) endif ifneq ($(pos a,ababababab),1) $(error sub-test 10 failed) endif ifneq ($(pos a,ababababab,2),3) $(error sub-test 11 failed) endif ifneq ($(pos a,ababababab,3),3) $(error sub-test 12 failed) endif ifneq ($(pos a,ababababab,8),9) $(error sub-test 13 failed) endif ifneq ($(pos a,ababababab,8),9) $(error sub-test 14 failed) endif ifneq ($(pos a,ababababab,9),9) $(error sub-test 15 failed) endif ifneq ($(pos a,ababababab,10),0) $(error sub-test 16 failed) endif ifneq ($(pos a,ababababab,-1),0) $(error sub-test 17 failed) endif ifneq ($(pos a,ababababab,-2),9) $(error sub-test 18 failed) endif ifneq ($(pos a,ababababab,-10),1) $(error sub-test 19 failed) endif ifneq ($(pos a,ababababab,-11),0) $(error sub-test 20 failed) endif .PHONY: all all: ; @: ', '', ''); } # Indicate that we're done. 1; kbuild-3149/src/kmk/tests/scripts/functions/intersects0000644000175000017500000000423213252530202023217 0ustar locutuslocutus# $Id: intersects 2413 2010-09-11 17:43:04Z bird $ -*-perl-*- ## @file # $(intersects set-a,set-b) # # # Copyright (c) 2008-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # $description = "Tests the $(intersecs ) predicate function"; $details = "A few simple tests, nothing spectacular."; if ($is_kmk) { # TEST #0 - check that the feature is present. # -------------------------------------------- run_make_test(' ifneq ($(intersects a b c d e f, a),1) $(error sub-test 0 failed) endif .PHONY: all all: ; @: ', '', ''); # TEST #1 - the real test. # ------------------------ run_make_test(' ifneq ($(intersects a b c d e f, f),1) $(error sub-test 0 failed) endif ifneq ($(intersects a b c d e f, f),1) $(error sub-test 1 failed) endif ifneq ($(intersects a b c d e f, d),1) $(error sub-test 2 failed) endif ifneq ($(intersects b c d e f, a),) $(error sub-test 3 failed) endif ifneq ($(intersects a b c d e f, a b c d e f),1) $(error sub-test 4 failed) endif ifneq ($(intersects a b c d e f, f e d c b a),1) $(error sub-test 5 failed) endif ifneq ($(intersects f e d c b a, a b c d e f),1) $(error sub-test 6 failed) endif SET-A = make foo bar SET-B = $(SET-A) ifeq ($(intersects $(SET-A),$(SET-B)),) $(error sub-test 7 failed) endif SET-B = foo ifeq ($(intersects $(SET-A),$(SET-B)),) $(error sub-test 8 failed) endif SET-B = foobar ifneq ($(intersects $(SET-A),$(SET-B)),) $(error sub-test 9 failed) endif .PHONY: all all: ; @: ', '', ''); } # Indicate that we're done. 1; kbuild-3149/src/kmk/tests/scripts/functions/foreach0000644000175000017500000000470213252530202022445 0ustar locutuslocutus# -*-perl-*- # $Id$ $description = "Test the foreach function."; $details = "This is a test of the foreach function in gnu make. This function starts with a space separated list of names and a variable. Each name in the list is subsituted into the variable and the given text evaluated. The general form of the command is $(foreach var,$list,$text). Several types of foreach loops are tested\n"; # TEST 0 # Set an environment variable that we can test in the makefile. # kmk: CC isn't a default. $extraENV{FOOFOO} = 'foo foo'; $CC_origin = $is_kmk ? "undefined" : "default"; run_make_test("space = ' '".' null := auto_var = udef space CC null FOOFOO MAKE foo CFLAGS WHITE @ < foo = bletch null @ garf av = $(foreach var, $(auto_var), $(origin $(var)) ) override WHITE := BLACK for_var = $(addsuffix .c,foo $(null) $(foo) $(space) $(av) ) fe = $(foreach var2, $(for_var),$(subst .c,.o, $(var2) ) ) all: auto for2 auto : ; @echo $(av) for2: ; @echo $(fe)', '-j1 -e WHITE=WHITE CFLAGS=', "undefined file ". $CC_origin ." file environment default file command line override automatic automatic foo.o bletch.o null.o @.o garf.o .o .o undefined.o file.o ". $CC_origin .".o file.o environment.o default.o file.o command.o line.o override.o automatic.o automatic.o"); delete $extraENV{FOOFOO}; # TEST 1: Test that foreach variables take precedence over global # variables in a global scope (like inside an eval). Tests bug #11913 run_make_test(' .PHONY: all target all: target x := BAD define mktarget target: x := $(x) target: ; @echo "$(x)" endef x := GLOBAL $(foreach x,FOREACH,$(eval $(value mktarget)))', '', 'FOREACH'); # Allow variable names with trailing space run_make_test(q! $(foreach \ a \ , b c d \ , $(info $a)) all:;@: !, "", "b\nc\nd\n"); # Allow empty variable names. We still expand the body. run_make_test(' x = $(foreach ,1 2 3,a) y := $x all: ; @echo $y', '', "a a a\n"); # Check some error conditions. run_make_test(' x = $(foreach ) y = $x all: ; @echo $y', '', "#MAKEFILE#:2: *** insufficient number of arguments (1) to function 'foreach'. Stop.", 512); run_make_test(' x = $(foreach x,y) y := $x all: ; @echo $y', '', "#MAKEFILE#:2: *** insufficient number of arguments (2) to function 'foreach'. Stop.", 512); 1; kbuild-3149/src/kmk/tests/scripts/functions/suffix0000644000175000017500000000404713252530202022344 0ustar locutuslocutus$description = "The following test creates a makefile to test the suffix\n" ."function. \n"; $details = "The suffix function will return the string following the last _._\n" ."the list provided. It will provide all of the unique suffixes found\n" ."in the list. The long strings are sorted to remove duplicates.\n"; # IF YOU NEED >1 MAKEFILE FOR THIS TEST, USE &get_tmpfile; TO GET # THE NAME OF THE MAKEFILE. THIS INSURES CONSISTENCY AND KEEPS TRACK OF # HOW MANY MAKEFILES EXIST FOR EASY DELETION AT THE END. # EXAMPLE: $makefile2 = &get_tmpfile; open(MAKEFILE,"> $makefile"); # The Contents of the MAKEFILE ... print MAKEFILE "string := word.pl general_test2.pl1 FORCE.pl word.pl3 generic_test.perl /tmp.c/bar foo.baz/bar.c MAKEFILES_variable.c\n" ."string2 := \$(string) \$(string) \$(string) \$(string) \$(string) \$(string) \$(string)\n" ."string3 := \$(string2) \$(string2) \$(string2) \$(string2) \$(string2) \$(string2) \$(string2)\n" ."string4 := \$(string3) \$(string3) \$(string3) \$(string3) \$(string3) \$(string3) \$(string3)\n" ."all: \n" ."\t\@echo \$(suffix \$(string)) \n" ."\t\@echo \$(sort \$(suffix \$(string4))) \n" ."\t\@echo \$(suffix \$(string) a.out) \n" ."\t\@echo \$(sort \$(suffix \$(string3))) \n"; # END of Contents of MAKEFILE close(MAKEFILE); &run_make_with_options($makefile,"",&get_logfile,0); # Create the answer to what should be produced by this Makefile # COMPARE RESULTS $answer = ".pl .pl1 .pl .pl3 .perl .c .c\n" .".c .perl .pl .pl1 .pl3\n" .".pl .pl1 .pl .pl3 .perl .c .c .out\n" .".c .perl .pl .pl1 .pl3\n"; # In this call to compare output, you should use the call &get_logfile(1) # to send the name of the last logfile created. You may also use # the special call &get_logfile(1) which returns the same as &get_logfile(1). &compare_output($answer,&get_logfile(1)); # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/functions/evalcall0000644000175000017500000000471013252530202022620 0ustar locutuslocutus# $Id: evalcall 2413 2010-09-11 17:43:04Z bird $ -*-perl-*- ## @file # $(evalcall var,argN...) # # # Copyright (c) 2008-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # $description = "Tests the $(evalcall ) function"; $details = "A few simple tests, nothing spectacular."; if ($is_kmk) { # TEST #0 - check that the feature is present. # -------------------------------------------- run_make_test(' FUNC = local .RETURN = $2 $1 ifneq ($(evalcall FUNC,a,b),b a) $(error sub-test 0 failed: $(evalcall FUNC,a,b)) endif .PHONY: all all: ; @: ', '', ''); # TEST #1 - the real test. # ------------------------ run_make_test(' FUNC = local .RETURN = $2 $1 ifneq ($(evalcall FUNC,a,b),b a) $(error sub-test 0 failed) endif ADD = local .RETURN = $(expr $1 + $2) ifneq ($(evalcall ADD,1,2),3) $(error sub-test 1 failed) endif define POP local words := $(words $($1)) local .RETURN := $(word $(words), $($1)) $1 := $(wordlist 1, $(expr $(words) - 1), $($1)) endef stack-var = a b c d ifneq ($(evalcall POP,stack-var),d) $(error sub-test 2d failed) endif ifneq ($(evalcall POP,stack-var),c) $(error sub-test 2c failed) endif ifneq ($(evalcall POP,stack-var),b) $(error sub-test 2b failed) endif ifneq ($(evalcall POP,stack-var),a) $(error sub-test 2a failed) endif # Negative tests: .RETURN = $2 $1 FUNC = ifneq ($(evalcall FUNC,a,b),) $(error sub-test 10 failed) endif .RETURN = FUNC = .RETURN = $2 $1 ifneq ($(evalcall FUNC,a,b),) $(error sub-test 11 failed) endif # Test .ARGC: FUNC = local .RETURN = $(.ARGC) ifneq ($(evalcall FUNC,a,b),2) $(error sub-test 20 failed) endif ifneq ($(evalcall FUNC),0) $(error sub-test 21 failed) endif ifneq ($(evalcall FUNC,aasdfasdf),1) $(error sub-test 22 failed) endif .PHONY: all all: ; @: ', '', ''); } # Indicate that we're done. 1; kbuild-3149/src/kmk/tests/scripts/functions/basename0000644000175000017500000000240013252530202022602 0ustar locutuslocutus$description = "The following test creates a makefile to test the suffix " ."function."; $details = ""; # IF YOU NEED >1 MAKEFILE FOR THIS TEST, USE &get_tmpfile; TO GET # THE NAME OF THE MAKEFILE. THIS INSURES CONSISTENCY AND KEEPS TRACK OF # HOW MANY MAKEFILES EXIST FOR EASY DELETION AT THE END. # EXAMPLE: $makefile2 = &get_tmpfile; open(MAKEFILE,"> $makefile"); # The Contents of the MAKEFILE ... print MAKEFILE "string := \$(basename src${pathsep}a.b.z.foo.c src${pathsep}hacks src.bar${pathsep}a.b.z.foo.c src.bar${pathsep}hacks hacks) \n" ."all: \n" ."\t\@echo \$(string) \n"; # END of Contents of MAKEFILE close(MAKEFILE); &run_make_with_options($makefile,"",&get_logfile,0); # Create the answer to what should be produced by this Makefile $answer = "src${pathsep}a.b.z.foo src${pathsep}hacks src.bar${pathsep}a.b.z.foo src.bar${pathsep}hacks hacks\n"; # COMPARE RESULTS # In this call to compare output, you should use the call &get_logfile(1) # to send the name of the last logfile created. You may also use # the special call &get_logfile(1) which returns the same as &get_logfile(1). &compare_output($answer,&get_logfile(1)); # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/functions/substitution0000644000175000017500000000157213252530202023614 0ustar locutuslocutus# -*-perl-*- $description = "Test the subst and patsubst functions"; $details = ""; # Generic patsubst test: test both the function and variable form. run_make_test(' foo := a.o b.o c.o bar := $(foo:.o=.c) bar2:= $(foo:%.o=%.c) bar3:= $(patsubst %.c,%.o,x.c.c bar.c) all:;@echo $(bar); echo $(bar2); echo $(bar3)', '', 'a.c b.c c.c a.c b.c c.c x.c.o bar.o'); # Patsubst without '%'--shouldn't match because the whole word has to match # in patsubst. Based on a bug report by Markus Mauhart run_make_test('all:;@echo $(patsubst Foo,Repl,FooFoo)', '', 'FooFoo'); # Variable subst where a pattern matches multiple times in a single word. # Based on a bug report by Markus Mauhart run_make_test(' A := fooBARfooBARfoo all:;@echo $(A:fooBARfoo=REPL)', '', 'fooBARREPL'); 1; kbuild-3149/src/kmk/tests/scripts/functions/addprefix0000644000175000017500000000220413252530202022777 0ustar locutuslocutus$description = "The following test creates a makefile to test the addprefix " ."function."; $details = ""; # IF YOU NEED >1 MAKEFILE FOR THIS TEST, USE &get_tmpfile; TO GET # THE NAME OF THE MAKEFILE. THIS INSURES CONSISTENCY AND KEEPS TRACK OF # HOW MANY MAKEFILES EXIST FOR EASY DELETION AT THE END. # EXAMPLE: $makefile2 = &get_tmpfile; open(MAKEFILE,"> $makefile"); # The Contents of the MAKEFILE ... print MAKEFILE "string := \$(addprefix src${pathsep},a.b.z.foo hacks) \n" ."all: \n" ."\t\@echo \$(string) \n"; # END of Contents of MAKEFILE close(MAKEFILE); &run_make_with_options($makefile,"",&get_logfile,0); # Create the answer to what should be produced by this Makefile $answer = "src${pathsep}a.b.z.foo src${pathsep}hacks\n"; # COMPARE RESULTS # In this call to compare output, you should use the call &get_logfile(1) # to send the name of the last logfile created. You may also use # the special call &get_logfile(1) which returns the same as &get_logfile(1). &compare_output($answer,&get_logfile(1)); # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/functions/andor0000644000175000017500000000252213252530202022137 0ustar locutuslocutus# -*-perl-*- $description = "Test the and & or functions.\n"; $details = "Try various uses of and & or to ensure they all give the correct results.\n"; # TEST #0 # For $(and ...), it will either be empty or the last value run_make_test(' NEQ = $(subst $1,,$2) f = t = true all: @echo 1 $(and ,$t) @echo 2 $(and $t) @echo 3 $(and $t,) @echo 4 $(and z,true,$f,false) @echo 5 $(and $t,$f,$(info bad short-circuit)) @echo 6 $(and $(call NEQ,a,b),true) @echo 7 $(and $(call NEQ,a,a),true) @echo 8 $(and z,true,fal,se) hi @echo 9 $(and ,true,fal,se)there @echo 10 $(and $(e) ,$t)', '', "1\n2 true\n3\n4\n5\n6 true\n7\n8 se hi\n9 there\n10\n"); # TEST #1 # For $(or ...), it will either be empty or the first true value run_make_test(' NEQ = $(subst $1,,$2) f = t = true all: @echo 1 $(or , ) @echo 2 $(or $t) @echo 3 $(or ,$t) @echo 4 $(or z,true,$f,false) @echo 5 $(or $t,$(info bad short-circuit)) @echo 6 $(or $(info short-circuit),$t) @echo 7 $(or $(call NEQ,a,b),true) @echo 8 $(or $(call NEQ,a,a),true) @echo 9 $(or z,true,fal,se) hi @echo 10 $(or ,true,fal,se)there @echo 11 $(or $(e) ,$f)', '', "short-circuit\n1\n2 true\n3 true\n4 z\n5 true\n6 true\n7 b\n8 true\n9 z hi\n10 truethere\n11\n"); 1; kbuild-3149/src/kmk/tests/scripts/functions/guile0000644000175000017500000000503413252530202022142 0ustar locutuslocutus# -*-perl-*- $description = 'Test the $(guile ...) function.'; $details = 'This only works on systems that support it.'; # If this instance of make doesn't support GNU Guile, skip it # This detects if guile is loaded using the "load" directive # $makefile = get_tmpfile(); # open(MAKEFILE, "> $makefile") || die "Failed to open $makefile: $!\n"; # print MAKEFILE q! # -load guile # all: ; @echo $(filter guile,$(.LOADED)) # !; # close(MAKEFILE) || die "Failed to write $makefile: $!\n"; # $cmd = subst_make_string("#MAKEPATH# -f $makefile"); # $log = get_logfile(0); # $code = run_command_with_output($log, $cmd); # read_file_into_string ($log) eq "guile\n" and $FEATURES{guile} = 1; # If we don't have Guile support, never mind. exists $FEATURES{guile} or return -1; # Verify simple data type conversions # Currently we don't support vectors: # echo '$(guile (vector 1 2 3))'; \ run_make_test(q! x:;@echo '$(guile #f)'; \ echo '$(guile #t)'; \ echo '$(guile #\c)'; \ echo '$(guile 1234)'; \ echo '$(guile 'foo)'; \ echo '$(guile "bar")'; \ echo '$(guile (cons 'a 'b))'; \ echo '$(guile '(a b (c . d) 1 (2) 3))' !, '', "\n#t\nc\n1234\nfoo\nbar\na b\na b c d 1 2 3"); # Verify the gmk-expand function run_make_test(q! VAR = $(guile (gmk-expand "$(shell echo hi)")) x:;@echo '$(VAR)' !, '', "hi"); # Verify the gmk-eval function # Prove that the string is expanded only once (by eval) run_make_test(q! TEST = bye EVAL = VAR = $(TEST) $(shell echo there) $(guile (gmk-eval "$(value EVAL)")) TEST = hi x:;@echo '$(VAR)' !, '', "hi there"); # Verify the gmk-eval function with a list run_make_test(q! $(guile (gmk-eval '(VAR = 1 (2) () 3))) x:;@echo '$(VAR)' !, '', "1 2 3"); # Verify the gmk-var function run_make_test(q! VALUE = hi $(shell echo there) VAR = $(guile (gmk-var "VALUE")) x:;@echo '$(VAR)' !, '', "hi there"); # Verify the gmk-var function with a symbol run_make_test(q! VALUE = hi $(shell echo there) VAR = $(guile (gmk-var 'VALUE)) x:;@echo '$(VAR)' !, '', "hi there"); # Write a Guile program using define and run it run_make_test(q! # Define the "fib" function in Guile define fib ;; A procedure for counting the n:th Fibonacci number ;; See SICP, p. 37 (define (fib n) (cond ((= n 0) 0) ((= n 1) 1) (else (+ (fib (- n 1)) (fib (- n 2)))))) endef $(guile $(fib)) # Now run it x:;@echo $(guile (fib $(FIB))) !, 'FIB=10', "55"); 1; kbuild-3149/src/kmk/tests/scripts/functions/flavor0000644000175000017500000000111713252530202022324 0ustar locutuslocutus# -*-perl-*- $description = "Test the flavor function."; $details = ""; # Test #1: Test general logic. # run_make_test(' s := s r = r $(info u $(flavor u)) $(info s $(flavor s)) $(info r $(flavor r)) ra += ra rc ?= rc $(info ra $(flavor ra)) $(info rc $(flavor rc)) s += s r += r $(info s $(flavor s)) $(info r $(flavor r)) .PHONY: all all:;@: ', '', 'u undefined s simple r recursive ra recursive rc recursive s simple r recursive'); # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/functions/sort0000644000175000017500000000333613252530202022027 0ustar locutuslocutus# -*-perl-*- $description = "The following test creates a makefile to verify the ability of make to sort lists of object. Sort will also remove any duplicate entries. This will also be tested."; $details = "The make file is built with a list of object in a random order and includes some duplicates. Make should sort all of the elements remove all duplicates\n"; run_make_test(' foo := moon_light days foo1:= jazz bar := captured bar2 = boy end, has rise A midnight bar3:= $(foo) s1 := _by s2 := _and_a t1 := $(addsuffix $(s1), $(bar) ) t2 := $(addsuffix $(s2), $(foo1) ) t3 := $(t2) $(t2) $(t2) $(t2) $(t2) $(t2) $(t2) $(t2) $(t2) $(t2) t4 := $(t3) $(t3) $(t3) $(t3) $(t3) $(t3) $(t3) $(t3) $(t3) $(t3) t5 := $(t4) $(t4) $(t4) $(t4) $(t4) $(t4) $(t4) $(t4) $(t4) $(t4) t6 := $(t5) $(t5) $(t5) $(t5) $(t5) $(t5) $(t5) $(t5) $(t5) $(t5) t7 := $(t6) $(t6) $(t6) p1 := $(addprefix $(foo1), $(s2) ) blank:= all: @echo $(sort $(bar2) $(foo) $(addsuffix $(s1), $(bar) ) $(t2) $(bar2) $(bar3)) @echo $(sort $(blank) $(foo) $(bar2) $(t1) $(p1) ) @echo $(sort $(foo) $(bar2) $(t1) $(t4) $(t5) $(t7) $(t6) ) ', '', 'A boy captured_by days end, has jazz_and_a midnight moon_light rise A boy captured_by days end, has jazz_and_a midnight moon_light rise A boy captured_by days end, has jazz_and_a midnight moon_light rise '); # Test with non-space/tab whitespace. Note that you can't see the # original bug except using valgrind. run_make_test("FOO = a b\tc\rd\fe \f \f \f \f \ff all: ; \@echo \$(words \$(sort \$(FOO)))\n", '', "6\n"); 1; ### Local Variables: ### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) ### End: kbuild-3149/src/kmk/tests/scripts/functions/dir0000644000175000017500000000214313252530202021611 0ustar locutuslocutus$description = "The following test creates a makefile to test the dir " ."function."; $details = ""; # IF YOU NEED >1 MAKEFILE FOR THIS TEST, USE &get_tmpfile; TO GET # THE NAME OF THE MAKEFILE. THIS INSURES CONSISTENCY AND KEEPS TRACK OF # HOW MANY MAKEFILES EXIST FOR EASY DELETION AT THE END. # EXAMPLE: $makefile2 = &get_tmpfile; open(MAKEFILE,"> $makefile"); # The Contents of the MAKEFILE ... print MAKEFILE "string := \$(dir src${pathsep}foo.c hacks) \n" ."all: \n" ."\t\@echo \$(string) \n"; # END of Contents of MAKEFILE close(MAKEFILE); &run_make_with_options($makefile,"",&get_logfile,0); # Create the answer to what should be produced by this Makefile $answer = "src${pathsep} .${pathsep}\n"; # COMPARE RESULTS # In this call to compare output, you should use the call &get_logfile(1) # to send the name of the last logfile created. You may also use # the special call &get_logfile(1) which returns the same as &get_logfile(1). &compare_output($answer,&get_logfile(1)); # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/functions/substr0000644000175000017500000000641013252530202022356 0ustar locutuslocutus# $Id: substr 2413 2010-09-11 17:43:04Z bird $ -*-perl-*- ## @file # $(substr str, start[, length[, pad]]) # # # Copyright (c) 2008-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # $description = "Tests the $(substr ) function"; $details = "A few simple tests and edge cases."; if ($is_kmk) { # TEST #0 - check that the feature is present. # -------------------------------------------- run_make_test(' ifneq ($(substr asdf,4),f) $(error sub-test 0 failed) endif .PHONY: all all: ; @: ', '', ''); # TEST #1 - the real test. # ------------------------ run_make_test(' ifneq ($(substr abcdefghijklmnopqrstuvwxyz,20),tuvwxyz) $(error sub-test 0 failed) endif ifneq ($(substr abcdefghijklmnopqrstuvwxyz,20,1),t) $(error sub-test 1 failed) endif ifneq ($(substr abcdefghijklmnopqrstuvwxyz,20,2),tu) $(error sub-test 2 failed) endif ifneq ($(substr abcdefghijklmnopqrstuvwxyz,20,0),) $(error sub-test 3 failed) endif ifneq ($(substr abcdefghijklmnopqrstuvwxyz,-1),z) $(error sub-test 4 failed) endif ifneq ($(substr abcdefghijklmnopqrstuvwxyz,-2),yz) $(error sub-test 5 failed) endif ifneq ($(substr abcdefghijklmnopqrstuvwxyz,-2,2),yz) $(error sub-test 6 failed) endif ifneq ($(substr abcdefghijklmnopqrstuvwxyz,-2,3),yz) $(error sub-test 7 failed) endif ifneq ($(substr abcdefghijklmnopqrstuvwxyz,-2,5,XYZ),yzXYZ) $(error sub-test 8 failed) endif ifneq ($(substr abcdefghijklmnopqrstuvwxyz,-25,1),b) $(error sub-test 9 failed) endif ifneq ($(substr abcdefghijklmnopqrstuvwxyz,-26,1),a) $(error sub-test 10 failed) endif ifneq ($(substr abcdefghijklmnopqrstuvwxyz,-27,1),) $(error sub-test 11 failed) endif ifneq ($(substr abcdefghijklmnopqrstuvwxyz,-27,2),a) $(error sub-test 12 failed) endif ifneq ($(substr abcdefghijklmnopqrstuvwxyz,-27,3),ab) $(error sub-test 13 failed) endif ifneq ($(substr abcdefghijklmnopqrstuvwxyz,-27,3,_),_ab) $(error sub-test 14 failed) endif ifneq ($(substr abcdefghijklmnopqrstuvwxyz,-28,4,.^),.^ab) $(error sub-test 15 failed) endif ifneq ($(substr abcdefghijklmnopqrstuvwxyz,-50,4),) $(error sub-test 16 failed) endif ifneq ($(substr abcdefghijklmnopqrstuvwxyz,-50,4,.^),.^.^) $(error sub-test 17 failed) endif ifneq ($(substr abcdefghijklmnopqrstuvwxyz,27,4,.^),.^.^) $(error sub-test 18 failed) endif ifneq ($(substr abcdefghijklmnopqrstuvwxyz,28,3,.^),.^.) $(error sub-test 19 failed) endif SP := $(subst ., ,.) ifneq (.$(substr abcdefghijklmnopqrstuvwxyz,100,3, ).,. .) $(error sub-test 20 failed) endif ifneq ($(substr abcdefghijklmnopqrstuvwxyz,100,3, ),$(SP)$(SP)$(SP)) $(error sub-test 21 failed) endif .PHONY: all all: ; @: ', '', ''); } # Indicate that we're done. 1; kbuild-3149/src/kmk/tests/scripts/functions/warning0000644000175000017500000000351713252530202022506 0ustar locutuslocutus# -*-Perl-*- $description = "\ The following test creates a makefile to test the warning function."; $details = ""; open(MAKEFILE,"> $makefile"); print MAKEFILE <<'EOF'; ifdef WARNING1 $(warning warning is $(WARNING1)) endif ifdef WARNING2 $(warning warning is $(WARNING2)) endif ifdef WARNING3 all: some; @echo hi $(warning warning is $(WARNING3)) endif ifdef WARNING4 all: some; @echo hi @echo there $(warning warning is $(WARNING4)) endif some: ; @echo Some stuff EOF close(MAKEFILE); # Test #1 &run_make_with_options($makefile, "WARNING1=yes", &get_logfile, 0); $answer = "$makefile:2: warning is yes\nSome stuff\n"; &compare_output($answer,&get_logfile(1)); # Test #2 &run_make_with_options($makefile, "WARNING2=no", &get_logfile, 0); $answer = "$makefile:6: warning is no\nSome stuff\n"; &compare_output($answer,&get_logfile(1)); # Test #3 &run_make_with_options($makefile, "WARNING3=maybe", &get_logfile, 0); $answer = "Some stuff\n$makefile:10: warning is maybe\nhi\n"; &compare_output($answer,&get_logfile(1)); # Test #4 &run_make_with_options($makefile, "WARNING4=definitely", &get_logfile, 0); $answer = "Some stuff\n$makefile:15: warning is definitely\nhi\nthere\n"; &compare_output($answer,&get_logfile(1)); # Test linenumber offset run_make_test(q! all: one two $(warning in $@ line 3) @true $(warning in $@ line 5) one two: $(warning in $@ line 8) @true $(warning in $@ line 10) !, '', "#MAKEFILE#:8: in one line 8 #MAKEFILE#:10: in one line 10 #MAKEFILE#:8: in two line 8 #MAKEFILE#:10: in two line 10 #MAKEFILE#:3: in all line 3 #MAKEFILE#:5: in all line 5\n"); # This tells the test driver that the perl test script executed properly. 1; ### Local Variables: ### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) ### End: kbuild-3149/src/kmk/tests/scripts/functions/join0000644000175000017500000000213613252530202021774 0ustar locutuslocutus$description = "The following test creates a makefile to test the join " ."function."; $details = ""; # IF YOU NEED >1 MAKEFILE FOR THIS TEST, USE &get_tmpfile; TO GET # THE NAME OF THE MAKEFILE. THIS INSURES CONSISTENCY AND KEEPS TRACK OF # HOW MANY MAKEFILES EXIST FOR EASY DELETION AT THE END. # EXAMPLE: $makefile2 = &get_tmpfile; open(MAKEFILE,"> $makefile"); # The Contents of the MAKEFILE ... print MAKEFILE "string := \$(join a b c,foo hacks .pl1) \n" ."all: \n" ."\t\@echo \$(string) \n"; # END of Contents of MAKEFILE close(MAKEFILE); &run_make_with_options($makefile,"",&get_logfile,0); # Create the answer to what should be produced by this Makefile $answer = "afoo bhacks c.pl1\n"; # COMPARE RESULTS # In this call to compare output, you should use the call &get_logfile(1) # to send the name of the last logfile created. You may also use # the special call &get_logfile(1) which returns the same as &get_logfile(1). &compare_output($answer,&get_logfile(1)); # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/functions/strip0000644000175000017500000000324613252530202022201 0ustar locutuslocutus# -*-perl-*- $description = "The following test creates a makefile to verify the ability of make to strip white space from lists of object.\n"; $details = "The make file is built with a list of objects that contain white space These are then run through the strip command to remove it. This is then verified by echoing the result.\n"; open(MAKEFILE,"> $makefile"); # The Contents of the MAKEFILE ... print MAKEFILE <<'EOMAKE'; TEST1 := "Is this TERMINAL fun? What makes you believe is this terminal fun? JAPAN is a WONDERFUL planet -- I wonder if we will ever reach their level of COMPARATIVE SHOPPING..." E := TEST2 := $E try this and this $E define TEST3 and these test out some blank lines endef .PHONY: all all: @echo '$(strip $(TEST1) )' @echo '$(strip $(TEST2) )' @echo '$(strip $(TEST3) )' space: ; @echo '$(strip ) $(strip )' EOMAKE # END of Contents of MAKEFILE close(MAKEFILE); &run_make_with_options($makefile,"",&get_logfile); $answer = "\"Is this TERMINAL fun? What makes you believe is this terminal fun? JAPAN is a WONDERFUL planet -- I wonder if we will ever reach their level of COMPARATIVE SHOPPING...\" try this and this and these test out some blank lines "; &compare_output($answer,&get_logfile(1)); &run_make_with_options($makefile,"space",&get_logfile); $answer = " \n"; &compare_output($answer,&get_logfile(1)); 1; kbuild-3149/src/kmk/tests/scripts/functions/wildcard0000644000175000017500000000460013252530202022624 0ustar locutuslocutus# -*-perl-*- $description = "The following test creates a makefile to test wildcard expansions and the ability to put a command on the same line as the target name separated by a semi-colon."; $details = "\ This test creates 4 files by the names of 1.example, two.example and 3.example. We execute three tests. The first executes the print1 target which tests the '*' wildcard by echoing all filenames by the name of '*.example'. The second test echo's all files which match '?.example' and [a-z0-9].example. Lastly we clean up all of the files using the '*' wildcard as in the first test"; open(MAKEFILE,"> $makefile"); # The Contents of the MAKEFILE ... print MAKEFILE < # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # $description = "Tests the \$(if-expr ) function"; $details = "A few simple tests, nothing spectacular. More comprehensive testing is preformed by functions/expr and features/ifcond."; if ($is_kmk) { # TEST #0 - check that the feature is present. # -------------------------------------------- run_make_test(' ifneq ($(if-expr 1+1,1,0),1) $(error sub-test 0 failed) endif .PHONY: all all: ; @: ', '', ''); # TEST #1 - basics, the $(expr test checks the rest). # --------------------------------------------------- run_make_test(' IF-EXPAND = 7 ELSE-EXPAND = -7 ifneq ($(if-expr 1==1,$(IF-EXPAND),$(ELSE-EXPAND)),7) $(error sub-test 0 failed) endif ifneq ($(if-expr 1!=1,$(IF-EXPAND),$(ELSE-EXPAND)),-7) $(error sub-test 1 failed) endif .PHONY: all all: ; @: ', '', ''); # TEST #2 - Checks that the optional 3 argument can be omitted. # ------------------------------------------------------------- run_make_test(' ifneq ($(if-expr 1==1,true),true) $(error sub-test 0 failed) endif ifneq ($(if-expr 2==1,true),) $(error sub-test 0 failed) endif .PHONY: all all: ; @: ', '', ''); } # Indicate that we're done. 1; kbuild-3149/src/kmk/tests/scripts/functions/realpath0000644000175000017500000000222613252530202022635 0ustar locutuslocutus# -*-perl-*- $description = "Test the realpath functions."; $details = ""; run_make_test(' ifneq ($(realpath .),$(CURDIR)) $(error ) endif ifneq ($(realpath ./),$(CURDIR)) $(error ) endif ifneq ($(realpath .///),$(CURDIR)) $(error ) endif ifneq ($(realpath /),/) $(error ) endif ifneq ($(realpath /.),/) $(error ) endif ifneq ($(realpath /./),/) $(error ) endif ifneq ($(realpath /.///),/) $(error ) endif ifneq ($(realpath /..),/) $(error ) endif ifneq ($(realpath /../),/) $(error ) endif ifneq ($(realpath /..///),/) $(error ) endif ifneq ($(realpath . /..),$(CURDIR) /) $(error ) endif .PHONY: all all: ; @: ', '', ''); # On Windows platforms, "//" means something special. So, don't do these # tests there. if ($port_type ne 'W32') { run_make_test(' ifneq ($(realpath ///),/) $(error ) endif ifneq ($(realpath ///.),/) $(error ) endif ifneq ($(realpath ///..),/) $(error ) endif .PHONY: all all: ; @:', '', ''); } # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/functions/addsuffix0000644000175000017500000000134113252530202023007 0ustar locutuslocutus# -*-perl-*- $description = "Test the addsuffix function."; $details = ""; open(MAKEFILE,"> $makefile"); # The Contents of the MAKEFILE ... print MAKEFILE < # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # $description = "Tests the $(printf ) function"; $details = "A few simple tests, nothing spectacular."; if ($is_kmk) { # TEST #0 - check that the feature is present. # -------------------------------------------- run_make_test(' ifneq ($(printf abcd),abcd) $(error sub-test 0 failed) endif .PHONY: all all: ; @: ', '', ''); # TEST #1 - the real test. # ------------------------ run_make_test(' ifneq ($(printf %s,abcde),abcde) $(error sub-test 0 failed) endif ifneq ($(printf %.4s,abcde),abcd) $(error sub-test 1 failed) endif ifneq ($(printf %.8s,abc),abc) $(error sub-test 2 failed) endif ifneq ($(printf %.2s%.3s,abc,zde),abzde) $(error sub-test 3 failed) endif define HASH # endef ifneq ($(printf %$(HASH)x,127),0x7f) $(error sub-test 4 failed) endif ifneq ($(printf %$(HASH)X,127),0X7F) $(error sub-test 5 failed) endif .PHONY: all all: ; @: ', '', ''); } # Indicate that we're done. 1; kbuild-3149/src/kmk/tests/scripts/functions/root0000644000175000017500000000701413252530202022020 0ustar locutuslocutus# $Id: root 2413 2010-09-11 17:43:04Z bird $ -*-perl-*- ## @file # $(root path...) # # # Copyright (c) 2008-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # $description = "Tests the $(path ) function"; $details = "Testing edges and some simple stuff."; if ($is_kmk) { # TEST #0 - check that the feature is present. # -------------------------------------------- run_make_test(' ifneq ($(root /a),/) $(error sub-test 0 failed) endif .PHONY: all all: ; @: ', '', ''); # TEST #1 - the real test. # ------------------------ run_make_test(' ifneq ($(root /asdf/asdf/adsf),/) $(error sub-test 0 failed:$(root /asdf/asdf/adsf)) endif ifneq ($(root asdf/asdf/adsf),) $(error sub-test 1 failed) endif ifneq ($(root asdf/asdf/adsf/),) $(error sub-test 2 failed) endif ifneq ($(root asdf/asdf/adsf/),) $(error sub-test 3 failed) endif ifneq ($(root a),) $(error sub-test 4 failed) endif ifneq ($(root ),) $(error sub-test 5 failed) endif ifneq ($(root //a),//) $(error sub-test 6 failed) endif ifneq ($(root /a),/) $(error sub-test 7 failed) endif ifneq ($(root ///a),///) $(error sub-test 8 failed) endif ifneq ($(root /a /b /c d /e),/ / / /) $(error sub-test 9 failed) endif .PHONY: all all: ; @: ', '', ''); # TEST #2 - DOS PATH stuff. # ------------------------ if ($port_type eq 'W32' || $port_type eq 'OS/2' || $port_type eq 'DOS') { run_make_test(' ifneq ($(root D:),D:) $(error sub-test 0 failed) endif ifneq ($(root D:/),D:/) $(error sub-test 1 failed) endif ifneq ($(root D:\\),D:\\) $(error sub-test 2 failed) endif ifneq ($(root D:\\\\),D:\\\\) $(error sub-test 3 failed) endif ifneq ($(root D:\\\\a),D:\\\\) $(error sub-test 4 failed) endif ifneq ($(root D:\\/a),D:\\/) $(error sub-test 5 failed) endif ifneq ($(root a:\\\\//asdf/asdf\\asdf),a:\\\\//) $(error sub-test 6 failed) endif ifneq ($(root z://\\\\asdf/asdf\\asdf),z://\\\\) $(error sub-test 7 failed) endif .PHONY: all all: ; @: ', '', ''); } # TEST #3 - UNC PATH stuff. # ------------------------ if ($port_type eq 'W32' || $port_type eq 'OS/2') { run_make_test(' ifneq ($(root //./),//./) $(error sub-test 0 failed) endif ifneq ($(root \\\\.\\),\\\\.\\) $(error sub-test 1 failed) endif ifneq ($(root \\\\\\.\\),\\\\\\) $(error sub-test 2 failed) endif ifneq ($(root ///.\\),///) $(error sub-test 3 failed) endif ifneq ($(root /\\.\\),/\\.\\) $(error sub-test 4 failed) endif ifneq ($(root \\/.\\),\\/.\\) $(error sub-test 5 failed) endif ifneq ($(root //srv/),//srv/) $(error sub-test 6 failed) endif ifneq ($(root //srv),) $(error sub-test 7 failed) endif ifneq ($(root //srv/share),//srv/share) $(error sub-test 8 failed) endif ifneq ($(root //srv/share/),//srv/share/) $(error sub-test 9 failed) endif ifneq ($(root //srv/share/asdf),//srv/share/) $(error sub-test 10 failed) endif .PHONY: all all: ; @: ', '', ''); } } # Indicate that we're done. 1; kbuild-3149/src/kmk/tests/scripts/functions/error0000644000175000017500000000321613252530202022166 0ustar locutuslocutus# -*-Perl-*- $description = "\ The following test creates a makefile to test the error function."; $details = ""; open(MAKEFILE,"> $makefile"); print MAKEFILE 'err = $(error Error found!) ifdef ERROR1 $(error error is $(ERROR1)) endif ifdef ERROR2 $(error error is $(ERROR2)) endif ifdef ERROR3 all: some; @echo $(error error is $(ERROR3)) endif ifdef ERROR4 all: some; @echo error is $(ERROR4) @echo $(error error is $(ERROR4)) endif some: ; @echo Some stuff testvar: ; @: $(err) '; close(MAKEFILE); # Test #1 &run_make_with_options($makefile, "ERROR1=yes", &get_logfile, 512); $answer = "$makefile:4: *** error is yes. Stop.\n"; &compare_output($answer,&get_logfile(1)); # Test #2 &run_make_with_options($makefile, "ERROR2=no", &get_logfile, 512); $answer = "$makefile:8: *** error is no. Stop.\n"; &compare_output($answer,&get_logfile(1)); # Test #3 &run_make_with_options($makefile, "ERROR3=maybe", &get_logfile, 512); $answer = "Some stuff\n$makefile:12: *** error is maybe. Stop.\n"; &compare_output($answer,&get_logfile(1)); # Test #4 &run_make_with_options($makefile, "ERROR4=definitely", &get_logfile, 512); $answer = "Some stuff\n$makefile:17: *** error is definitely. Stop.\n"; &compare_output($answer,&get_logfile(1)); # Test #5 &run_make_with_options($makefile, "testvar", &get_logfile, 512); $answer = "$makefile:22: *** Error found!. Stop.\n"; &compare_output($answer,&get_logfile(1)); # This tells the test driver that the perl test script executed properly. 1; ### Local Variables: ### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) ### End: kbuild-3149/src/kmk/tests/scripts/functions/file0000644000175000017500000000556413252530202021764 0ustar locutuslocutus# -*-perl-*- $description = 'Test the $(file ...) function.'; # Test > and >> run_make_test(q! define A a b endef B = c d $(file >file.out,$(A)) $(foreach L,$(B),$(file >> file.out,$L)) x:;@echo hi; cat file.out !, '', "hi\na\nb\nc\nd"); unlink('file.out'); # Test >> to a non-existent file run_make_test(q! define A a b endef $(file >> file.out,$(A)) x:;@cat file.out !, '', "a\nb"); unlink('file.out'); # Test > with no content run_make_test(q! $(file >4touch) .PHONY:x x:;@cat 4touch !, '', ''); # Test >> with no content run_make_test(q! $(file >>4touch) .PHONY:x x:;@cat 4touch !, '', ''); unlink('4touch'); # Test > to a read-only file touch('file.out'); chmod(0444, 'file.out'); # Find the error that will be printed # This seems complicated, but we need the message from the C locale my $loc = undef; if ($has_POSIX) { $loc = POSIX::setlocale(POSIX::LC_MESSAGES); POSIX::setlocale(POSIX::LC_MESSAGES, 'C'); } my $e; open(my $F, '>', 'file.out') and die "Opened read-only file!\n"; $e = "$!"; $loc and POSIX::setlocale(POSIX::LC_MESSAGES, $loc); run_make_test(q! define A a b endef $(file > file.out,$(A)) x:;@cat file.out !, '', "#MAKEFILE#:6: *** open: file.out: $e. Stop.", 512); unlink('file.out'); # Use variables for operator and filename run_make_test(q! define A a b endef OP = > FN = file.out $(file $(OP) $(FN),$(A)) x:;@cat file.out !, '', "a\nb"); unlink('file.out'); # Don't add newlines if one already exists run_make_test(q! define A a b endef $(file >file.out,$(A)) x:;@cat file.out !, '', "a\nb"); unlink('file.out'); # Empty text run_make_test(q! $(file >file.out,) $(file >>file.out,) x:;@cat file.out !, '', "\n\n"); unlink('file.out'); # Reading files run_make_test(q! $(file >file.out,A = foo) X1 := $(file >file.out,B = bar) $(eval $(file )', '', "#MAKEFILE#:1: *** file: missing filename. Stop.\n", 512); run_make_test('$(file >>)', '', "#MAKEFILE#:1: *** file: missing filename. Stop.\n", 512); run_make_test('$(file <)', '', "#MAKEFILE#:1: *** file: missing filename. Stop.\n", 512); # Bad call run_make_test('$(file foo)', '', "#MAKEFILE#:1: *** file: invalid file operation: foo. Stop.\n", 512); 1; kbuild-3149/src/kmk/tests/scripts/functions/length-var0000644000175000017500000000323013252530202023100 0ustar locutuslocutus# $Id: length-var 2413 2010-09-11 17:43:04Z bird $ -*-perl-*- ## @file # $(length-var var) # # # Copyright (c) 2008-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # $description = "Tests the $(length-var ) function"; $details = "A few simple tests, nothing spectacular."; if ($is_kmk) { # TEST #0 - check that the feature is present. # -------------------------------------------- run_make_test(' ifneq ($(length-var non-existing-variable),0) $(error sub-test 0 failed) endif .PHONY: all all: ; @: ', '', ''); # TEST #1 - the real test. # ------------------------ run_make_test(' VAR0 := asdf ifneq ($(length-var VAR0),4) $(error sub-test 0 failed) endif VAR1 = a ifneq ($(length-var VAR1),1) $(error sub-test 1 failed) endif VAR2 = 0123456789 ifneq ($(length-var VAR2),10) $(error sub-test 2 failed) endif VAR2 = $(VAR1) $(VAR0) ifneq ($(length-var VAR2),15) $(error sub-test 3 failed) endif .PHONY: all all: ; @: ', '', ''); } # Indicate that we're done. 1; kbuild-3149/src/kmk/tests/scripts/functions/eval0000644000175000017500000000670013252530202021765 0ustar locutuslocutus# -*-perl-*- $description = "Test the eval function."; $details = "This is a test of the eval function in GNU make. This function will evaluate inline makefile syntax and incorporate the results into its internal database.\n"; open(MAKEFILE,"> $makefile"); print MAKEFILE <<'EOF'; define Y all:: ; @echo $AA A = B endef X = $(eval $(value Y)) $(eval $(shell echo A = A)) $(eval $(Y)) $(eval A = C) $(eval $(X)) EOF close(MAKEFILE); &run_make_with_options($makefile, "", &get_logfile); # Create the answer to what should be produced by this Makefile $answer = "AA\nBA\n"; &compare_output($answer,&get_logfile(1)); # Test to make sure defining variables when we have extra scope pushed works # as expected. $makefile2 = &get_tmpfile; open(MAKEFILE,"> $makefile2"); print MAKEFILE <<'EOF'; VARS = A B VARSET = $(1) = $(2) $(foreach v,$(VARS),$(eval $(call VARSET,$v,$v))) all: ; @echo A = $(A) B = $(B) EOF close(MAKEFILE); &run_make_with_options($makefile2, "", &get_logfile); # Create the answer to what should be produced by this Makefile $answer = "A = A B = B\n"; &compare_output($answer,&get_logfile(1)); # Test to make sure eval'ing inside conditionals works properly $makefile3 = &get_tmpfile; open(MAKEFILE,"> $makefile3"); print MAKEFILE <<'EOF'; FOO = foo all:: ; @echo it define Y all:: ; @echo worked endef ifdef BAR $(eval $(Y)) endif EOF close(MAKEFILE); &run_make_with_options($makefile3, "", &get_logfile); $answer = "it\n"; &compare_output($answer,&get_logfile(1)); &run_make_with_options($makefile3, "BAR=1", &get_logfile); $answer = "it\nworked\n"; &compare_output($answer,&get_logfile(1)); # TEST very recursive invocation of eval $makefile3 = &get_tmpfile; open(MAKEFILE,"> $makefile3"); print MAKEFILE <<'EOF'; ..9 := 0 1 2 3 4 5 6 7 8 9 rev=$(eval res:=)$(foreach word,$1,$(eval res:=${word} ${res}))${res} a:=$(call rev,${..9}) all: ; @echo '[$(a)]' EOF close(MAKEFILE); &run_make_with_options($makefile3, "", &get_logfile); $answer = "[ 9 8 7 6 5 4 3 2 1 0 ]\n"; &compare_output($answer,&get_logfile(1)); # TEST eval with no filename context. # The trick here is that because EVAR is taken from the environment, it must # be evaluated before every command is invoked. Make sure that works, when # we have no file context for reading_file (bug # 6195) $makefile4 = &get_tmpfile; open(MAKEFILE,"> $makefile4"); print MAKEFILE <<'EOF'; EVAR = $(eval FOBAR = 1) all: ; @echo "OK" EOF close(MAKEFILE); $extraENV{EVAR} = '1'; &run_make_with_options($makefile4, "", &get_logfile); $answer = "OK\n"; &compare_output($answer,&get_logfile(1)); # Clean out previous information to allow new run_make_test() interface. # If we ever convert all the above to run_make_test() we can remove this line. $makefile = undef; # Test handling of backslashes in strings to be evaled. run_make_test(' define FOO all: ; @echo hello \ world endef $(eval $(FOO)) ', '', 'hello world'); run_make_test(' define FOO all: ; @echo '."'".'he\llo'."'".' @echo world endef $(eval $(FOO)) ', '', 'he\llo world'); # We don't allow new target/prerequisite relationships to be defined within a # command script, because these are evaluated after snap_deps() and that # causes lots of problems (like core dumps!) # See Savannah bug # 12124. run_make_test('deps: ; $(eval deps: foo)', '', '#MAKEFILE#:1: *** prerequisites cannot be defined in recipes. Stop.', 512); 1; kbuild-3149/src/kmk/tests/scripts/functions/word0000644000175000017500000001120013252530202022000 0ustar locutuslocutus# -*-perl-*- $description = "\ Test the word, words, wordlist, firstword, and lastword functions.\n"; $details = "\ Produce a variable with a large number of words in it, determine the number of words, and then read each one back.\n"; open(MAKEFILE,"> $makefile"); print MAKEFILE <<'EOF'; string := word.pl general_test2.pl FORCE.pl word.pl generic_test.perl MAKEFILES_variable.pl string2 := $(string) $(string) $(string) $(string) $(string) $(string) $(string) string3 := $(string2) $(string2) $(string2) $(string2) $(string2) $(string2) $(string2) string4 := $(string3) $(string3) $(string3) $(string3) $(string3) $(string3) $(string3) all: @echo $(words $(string)) @echo $(words $(string4)) @echo $(word 1, $(string)) @echo $(word 100, $(string)) @echo $(word 1, $(string)) @echo $(word 1000, $(string3)) @echo $(wordlist 3, 4, $(string)) @echo $(wordlist 4, 3, $(string)) @echo $(wordlist 1, 6, $(string)) @echo $(wordlist 5, 7, $(string)) @echo $(wordlist 100, 110, $(string)) @echo $(wordlist 7, 10, $(string2)) EOF close(MAKEFILE); &run_make_with_options($makefile, "", &get_logfile); $answer = "6\n" ."2058\n" ."word.pl\n" ."\n" ."word.pl\n" ."\n" ."FORCE.pl word.pl\n" ."\n" ."word.pl general_test2.pl FORCE.pl word.pl generic_test.perl MAKEFILES_variable.pl\n" ."generic_test.perl MAKEFILES_variable.pl\n" ."\n" ."word.pl general_test2.pl FORCE.pl word.pl\n"; &compare_output($answer, &get_logfile(1)); # Test error conditions run_make_test('FOO = foo bar biz baz word-e1: ; @echo $(word ,$(FOO)) word-e2: ; @echo $(word abc ,$(FOO)) word-e3: ; @echo $(word 1a,$(FOO)) wordlist-e1: ; @echo $(wordlist ,,$(FOO)) wordlist-e2: ; @echo $(wordlist abc ,,$(FOO)) wordlist-e3: ; @echo $(wordlist 1, 12a ,$(FOO))', 'word-e1', "#MAKEFILE#:3: *** non-numeric first argument to 'word' function: ''. Stop.", 512); run_make_test(undef, 'word-e2', "#MAKEFILE#:4: *** non-numeric first argument to 'word' function: 'abc '. Stop.", 512); run_make_test(undef, 'word-e3', "#MAKEFILE#:5: *** non-numeric first argument to 'word' function: '1a'. Stop.", 512); run_make_test(undef, 'wordlist-e1', "#MAKEFILE#:7: *** non-numeric first argument to 'wordlist' function: ''. Stop.", 512); run_make_test(undef, 'wordlist-e2', "#MAKEFILE#:8: *** non-numeric first argument to 'wordlist' function: 'abc '. Stop.", 512); run_make_test(undef, 'wordlist-e3', "#MAKEFILE#:9: *** non-numeric second argument to 'wordlist' function: ' 12a '. Stop.", 512); # Test error conditions again, but this time in a variable reference run_make_test('FOO = foo bar biz baz W = $(word $x,$(FOO)) WL = $(wordlist $s,$e,$(FOO)) word-e: ; @echo $(W) wordlist-e: ; @echo $(WL)', 'word-e x=', "#MAKEFILE#:3: *** non-numeric first argument to 'word' function: ''. Stop.", 512); run_make_test(undef, 'word-e x=abc', "#MAKEFILE#:3: *** non-numeric first argument to 'word' function: 'abc'. Stop.", 512); run_make_test(undef, 'word-e x=0', "#MAKEFILE#:3: *** first argument to 'word' function must be greater than 0. Stop.", 512); run_make_test(undef, 'wordlist-e s= e=', "#MAKEFILE#:4: *** non-numeric first argument to 'wordlist' function: ''. Stop.", 512); run_make_test(undef, 'wordlist-e s=abc e=', "#MAKEFILE#:4: *** non-numeric first argument to 'wordlist' function: 'abc'. Stop.", 512); run_make_test(undef, 'wordlist-e s=4 e=12a', "#MAKEFILE#:4: *** non-numeric second argument to 'wordlist' function: '12a'. Stop.", 512); run_make_test(undef, 'wordlist-e s=0 e=12', "#MAKEFILE#:4: *** invalid first argument to 'wordlist' function: '0'. Stop.", 512); # TEST #8 -- test $(firstword ) # run_make_test(' void := list := $(void) foo bar baz # a := $(word 1,$(list)) b := $(firstword $(list)) .PHONY: all all: @test "$a" = "$b" && echo $a ', '', 'foo'); # TEST #9 -- test $(lastword ) # run_make_test(' void := list := $(void) foo bar baz # a := $(word $(words $(list)),$(list)) b := $(lastword $(list)) .PHONY: all all: @test "$a" = "$b" && echo $a ', '', 'baz'); # This tells the test driver that the perl test script executed properly. 1; kbuild-3149/src/kmk/tests/scripts/functions/for0000644000175000017500000000342013252530202021620 0ustar locutuslocutus# $Id: for 2413 2010-09-11 17:43:04Z bird $ -*-perl-*- ## @file # $(for init,condition,next,body) # # # Copyright (c) 2008-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # $description = "Tests the $(for ) loop function"; $details = "A few simple tests, nothing spectacular."; if ($is_kmk) { # TEST #0 - check that the feature is present. # -------------------------------------------- run_make_test(' ifneq ($(for local i=0, $i <= 10, local i := $(expr $i + 1),$i),0 1 2 3 4 5 6 7 8 9 10) $(error sub-test 0 failed:$(for local i=0, $i <= 10, local i := $(expr $i + 1),$i)) endif .PHONY: all all: ; @: ', '', ''); # TEST #1 - the real test. # ------------------------ run_make_test(' ifneq ($(for local i=0, $i <= 10, local i := $(expr $i + 1),$i),0 1 2 3 4 5 6 7 8 9 10) $(error sub-test 0 failed) endif ifneq (.$(for local i=0, $i <= 3, local i := $(expr $i + 1), $i ).,. 0 1 2 3 .) $(error sub-test 1 failed) endif ifneq (.$(foreach i,0 1 2 3, $i ).,. 0 1 2 3 .) $(error sub-test 1b failed) endif .PHONY: all all: ; @: ', '', ''); } # Indicate that we're done. 1; kbuild-3149/src/kmk/tests/scripts/functions/call0000644000175000017500000000506213252530202021751 0ustar locutuslocutus# -*-perl-*- $description = "Test the call function.\n"; $details = "Try various uses of call and ensure they all give the correct results.\n"; run_make_test(q! # Simple, just reverse two things # reverse = $2 $1 # A complex 'map' function, using recursive 'call'. # map = $(foreach a,$2,$(call $1,$a)) # Test using a builtin; this is silly as it's simpler to do without call # my-notdir = $(call notdir,$(1)) # Test using non-expanded builtins # my-foreach = $(foreach $(1),$(2),$(3)) my-if = $(if $(1),$(2),$(3)) # Test recursive invocations of call with different arguments # one = $(1) $(2) $(3) two = $(call one,$(1),foo,$(2)) # Test recursion on the user-defined function. As a special case make # won't error due to this. # Implement transitive closure using $(call ...) # DEP_foo = bar baz quux DEP_baz = quux blarp rest = $(wordlist 2,$(words ${1}),${1}) tclose = $(if $1,$(firstword $1)\ $(call tclose,$(sort ${DEP_$(firstword $1)} $(call rest,$1)))) all: ; @echo '$(call reverse,bar,foo)'; \ echo '$(call map,origin,MAKE reverse map)'; \ echo '$(call my-notdir,a/b c/d e/f)'; \ echo '$(call my-foreach)'; \ echo '$(call my-foreach,a,,,)'; \ echo '$(call my-if,a,b,c)'; \ echo '$(call two,bar,baz)'; \ echo '$(call tclose,foo)'; !, "", "foo bar\ndefault file file\nb d f\n\n\nb\nbar foo baz\nfoo bar baz blarp quux \n"); # These won't work because call expands all its arguments first, before # passing them on, then marks them as resolved/simple, so they're not # expanded again by the function. # # echo '$(call my-foreach,a,x y z,$$(a)$$(a))'; \ # echo '$(call my-if,,$$(info don't print this),$$(info do print this))' # # $answer = "xx yy zz\ndo print this\n"; # TEST eclipsing of arguments when invoking sub-calls run_make_test(q! all = $1 $2 $3 $4 $5 $6 $7 $8 $9 level1 = $(call all,$1,$2,$3,$4,$5) level2 = $(call level1,$1,$2,$3) level3 = $(call level2,$1,$2,$3,$4,$5) all: @echo $(call all,1,2,3,4,5,6,7,8,9,10,11) @echo $(call level1,1,2,3,4,5,6,7,8) @echo $(call level2,1,2,3,4,5,6,7,8) @echo $(call level3,1,2,3,4,5,6,7,8) !, "", "1 2 3 4 5 6 7 8 9\n1 2 3 4 5\n1 2 3\n1 2 3\n"); # Ensure that variables are defined in global scope even in a $(call ...) delete $ENV{X123}; run_make_test(' tst = $(eval export X123) $(call tst) all: ; @echo "$${X123-not set}" ', '', "\n"); 1; ### Local Variables: ### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) ### End: kbuild-3149/src/kmk/tests/scripts/functions/filter-out0000644000175000017500000000275513252530202023136 0ustar locutuslocutus# -*-perl-*- $description = "Test the filter and filter-out functions."; $details = "The makefile created in this test has two variables. The filter-out function is first used to discard names ending in .o with a single simple pattern. The second filter-out function augments the simple pattern with three literal names, which are also added to the text argument. This tests an internal hash table which is only used if there are multiple literals present in both the pattern and text arguments. The result of both filter-out functions is the same single .elc name.\n"; # Basic test -- filter run_make_test(q! files1 := $(filter %.o, foo.elc bar.o lose.o) files2 := $(filter %.o foo.i, foo.i bar.i lose.i foo.elc bar.o lose.o) all: ; @echo '$(files1) $(files2)' !, '', "bar.o lose.o foo.i bar.o lose.o\n"); # Basic test -- filter-out run_make_test(q! files1 := $(filter-out %.o, foo.elc bar.o lose.o) files2 := $(filter-out foo.i bar.i lose.i %.o, foo.i bar.i lose.i foo.elc bar.o lose.o) all: ; @echo '$(files1) $(files2)' !, '', "foo.elc foo.elc\n"); # Escaped patterns run_make_test(q!all:;@echo '$(filter foo\%bar,foo%bar fooXbar)'!, '', "foo%bar\n"); run_make_test(q!all:;@echo '$(filter foo\%\%\\\\\%\%bar,foo%%\\%%bar fooX\\Ybar)'!, '', "foo%%\\%%bar\n"); run_make_test(q! X = $(filter foo\\\\\%bar,foo\%bar foo\Xbar) all:;@echo '$(X)'!, '', "foo\\%bar\n"); 1; kbuild-3149/src/kmk/tests/scripts/functions/shell0000644000175000017500000000253313252530202022145 0ustar locutuslocutus# -*-perl-*- $description = 'Test the $(shell ...) function.'; $details = ''; # Test standard shell run_make_test('.PHONY: all OUT := $(shell echo hi) all: ; @echo $(OUT) ','','hi'); # Test shells inside rules. run_make_test('.PHONY: all all: ; @echo $(shell echo hi) ','','hi'); # Verify .SHELLSTATUS run_make_test('.PHONY: all PRE := $(.SHELLSTATUS) $(shell exit 0) OK := $(.SHELLSTATUS) $(shell exit 1) BAD := $(.SHELLSTATUS) all: ; @echo PRE=$(PRE) OK=$(OK) BAD=$(BAD) ','','PRE= OK=0 BAD=1'); # Test unescaped comment characters in shells. Savannah bug #20513 if ($all_tests) { run_make_test(q! FOO := $(shell echo '#') foo: ; echo '$(FOO)' !, '', "#\n"); } # Test shells inside exported environment variables. # This is the test that fails if we try to put make exported variables into # the environment for a $(shell ...) call. run_make_test(' export HI = $(shell echo hi) .PHONY: all all: ; @echo $$HI ','','hi'); # Test shell errors in recipes including offset run_make_test(' all: @echo hi $(shell ./basdfdfsed there) @echo there ', '', "#MAKE#: ./basdfdfsed: Command not found\nhi\nthere\n"); 1; ### Local Variables: ### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) ### End: kbuild-3149/src/kmk/tests/scripts/functions/value0000644000175000017500000000133413252530202022150 0ustar locutuslocutus# -*-perl-*- $description = "Test the value function."; $details = "This is a test of the value function in GNU make. This function will evaluate to the value of the named variable with no further expansion performed on it.\n"; open(MAKEFILE,"> $makefile"); print MAKEFILE <<'EOF'; export FOO = foo recurse = FOO = $FOO static := FOO = $(value FOO) all: ; @echo $(recurse) $(value recurse) $(static) $(value static) EOF close(MAKEFILE); &run_make_with_options($makefile, "", &get_logfile); # Create the answer to what should be produced by this Makefile $answer = "FOO = OO FOO = foo FOO = foo FOO = foo\n"; &compare_output($answer,&get_logfile(1)); 1; kbuild-3149/src/kmk/tests/scripts/functions/while0000644000175000017500000000315513252530202022147 0ustar locutuslocutus# $Id: while 2413 2010-09-11 17:43:04Z bird $ -*-perl-*- ## @file # $(while condition,body) # # # Copyright (c) 2008-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # $description = "Tests the $(while ) loop function"; $details = "A few simple tests, nothing spectacular."; if ($is_kmk) { # TEST #0 - check that the feature is present. # -------------------------------------------- run_make_test(' VAR := 0 OUTPUT := $(while $(VAR)==0,$(eval VAR=1)works) ifneq ($(OUTPUT),works) $(error sub-test 0 failed:$(OUTPUT)) endif .PHONY: all all: ; @: ', '', ''); # TEST #1 - the real test. # ------------------------ run_make_test(' VAR := 0 OUTPUT := $(while $(VAR) < 3,$(eval VAR:=$(expr $(VAR) + 1))$(VAR)) ifneq ($(OUTPUT),1 2 3) $(error sub-test 0 failed:$(OUTPUT)) endif ifneq (.$(while 0,asdfasdfadsf).,..) $(error sub-test 1 failed) endif .PHONY: all all: ; @: ', '', ''); } # Indicate that we're done. 1; kbuild-3149/src/kmk/tests/guile.supp0000644000175000017500000000054713252530201017434 0ustar locutuslocutus# Guile valgrind suppression file # Created with Guile 1.8.7 # --- Garbage collection { guilegc Memcheck:Cond ... fun:scm_gc_for_newcell } { guilegc Memcheck:Value4 ... fun:scm_gc_for_newcell } { guilegc Memcheck:Value8 ... fun:scm_gc_for_newcell } # -- scm_alloc_struct { guileheap Memcheck:Leak ... fun:scm_alloc_struct } kbuild-3149/src/kmk/tests/mkshadow0000755000175000017500000000262013252530201017153 0ustar locutuslocutus#!/bin/sh # # Simple script to make a "shadow" test directory, using symbolic links. # Typically you'd put the shadow in /tmp or another local disk # # Copyright (C) 1992-2016 Free Software Foundation, Inc. # This file is part of GNU Make. # # GNU Make 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. # # GNU Make 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 . case "$1" in "") echo 'Usage: mkshadow '; exit 1 ;; esac dest="$1" if [ ! -d "$dest" ]; then echo "Destination directory '$dest' must exist!" exit 1 fi if [ ! -f run_make_tests ]; then echo "The current directory doesn't appear to contain the test suite!" exit 1 fi suite=`pwd | sed 's%^/tmp_mnt%%'` name=`basename "$suite"` files=`echo *` set -e mkdir "$dest/$name" cd "$dest/$name" ln -s "$suite" .testdir for f in $files; do ln -s .testdir/$f . done rm -rf work echo "Shadow test suite created in '$dest/$name'." exit 0 kbuild-3149/src/kmk/tests/ChangeLog.10000644000175000017500000013727413252530202017340 0ustar locutuslocutus2013-10-09 Paul Smith * scripts/features/patspecific_vars: Typo fixes. 2013-10-05 Paul Smith * test_driver.pl (run_all_tests): Rewrite to be more clear. * scripts/features/jobserver: Avoid using $ENV{HOME} as it doesn't exist everywhere. * scripts/features/default_names: End with 1; * scripts/features/loadapi: Use new calling signatures. Verify the NOEXPAND flag works. Test with all valid function name characters. 2013-09-29 Paul Smith * scripts/variables/SHELL: Solaris /bin/sh can't handle options in multiple words; skip that test. * scripts/targets/ONESHELL: Ditto. * scripts/variables/GNUMAKEFLAGS: Verify that GNUMAKEFLAGS is cleared and options are not duplicated. 2013-09-23 Paul Smith * scripts/options/print-directory: Rename dash-w to print-directory to avoid conflicts with dash-W on case-insensitive filesystems. 2013-09-22 Paul Smith * scripts/features/se_implicit: Verify that order-only tokens inside second expansion are parsed correctly. Test for Savannah bug #31155. * run_make_tests.pl (set_more_defaults): If we can't find gnumake.h based on the make program we might be running from a remote build directory. Parse the Makefile for the right path. Fix some test issues on Solaris. * scripts/features/archives: Determine what output ar gives when adding and replacing objects and compare with that. * scripts/features/escape: Solaris /bin/sh doesn't properly handle backslashes inside single quotes, so don't rely on it. * scripts/features/output-sync: false(1) gives different exit codes on different systems; use "exit 1" instead. * scripts/features/parallelism: Increase the timeout for slower systems. 2013-09-21 Paul Smith * scripts/features/archives: Some versions of ar (MacOSX) generate different output when creating archives. Run it and verify the real output. * scripts/features/default_names: MacOSX is, like Windows, case-preserving / case-insensitive. Redo the test to avoid checking for "UNIX". * test_driver.pl (attach_default_output): Don't dup stdout into stderr. Reported by Denis Excoffier * scripts/features/se_explicit: Fix a test that behaves differently with/without archive capability enabled. * scripts/features/output-sync: Don't test output-sync if it's not enabled. We also skip it if parallelism is not enabled, although strictly speaking some of the output-sync tests are valid even without parallelism. * scripts/features/jobserver: Move some tests that require the jobserver from features/parallelism to a separate suite. Only run this if jobserver mode is enabled. * scripts/features/output-sync: Test shell functions writing to stderr in recipes: ensure it's captured via output-sync. Test output generated while reading makefiles and make sure it's captured via output-sync. Make sure that fatal errors dump the output so it's not lost. * scripts/options/dash-w: Add a test for -w flag. 2013-09-15 Paul Smith * scripts/misc/fopen-fail: Check for failure on infinite recursion. * run_make_tests.pl (run_make_test): Allow the answer string to be undef, which means that we shouldn't compare it at all. Only the exit code matters in this case. * test_driver.pl (compare_output): Ditto. Test for Savannah bug #27374. * scripts/features/parallelism: Test broken jobserver on recursion. Test for Savannah bug #39934. * scripts/options/eval: Verify --eval during restart. Test for Savannah bug #39203. 2013-09-14 Paul Smith * scripts/features/output-sync: Verify -Orecurse properly. 2013-09-12 Paul Smith * scripts/features/output-sync: Modify for output sync behavior. * scripts/variables/MAKE_RESTARTS: Ditto. * scripts/variables/MAKEFLAGS: Remove mode for --trace. * scripts/variables/GNUMAKEFLAGS: Ditto. 2013-07-22 Paul Smith * scripts/features/rule_glob: Add tests for wildcards in rules. Test for Savannah bug #39310. 2013-07-09 Paul Smith * scripts/features/se_implicit: Add a test for SE rules depending on other SE rules to be built. 2013-05-26 Paul Smith * scripts/features/archives: Test for Savannah bug #38442. * scripts/misc/bs-nl: Test for Savannah bug #39035. Add a test for Savannah bug #38945. 2013-05-22 Paul Smith * scripts/options/dash-n: Fix results after MAKEFLAGS fixes. * scripts/variables/MAKEFLAGS: Ditto. * scripts/variables/GNUMAKEFLAGS: Ditto. 2013-05-14 Paul Smith * scripts/features/loadapi: Add plugin_is_GPL_compatible symbol. * scripts/features/load: Ditto. 2013-05-13 Paul Smith * scripts/features/output-sync (output_sync_set): Update for new --trace behavior. 2013-05-05 Paul Smith * scripts/features/output-sync (output_sync_set): Remove extraneous enter/leave lines, which are no longer printed. Add tests for syncing command line printing. (output_sync_set): Rename options: "job"->"line"; "make"->"recurse" 2013-05-04 Paul Smith * scripts/features/loadapi: Use the new alloc functions. * scripts/features/output-sync (output_sync_set): New test for ordered recursive output for -Ojob / -Otarget. 2013-05-03 Eli Zaretskii * scripts/features/load: Fix signatures of testload_gmk_setup and explicit_setup, to bring them in line with the documentation. 2013-04-28 Paul Smith * scripts/features/output-sync (output_sync_set): Add tests for the per-job syntax mode. (output_sync_set): Test improved error message location. 2013-04-15 Paul Smith * scripts/features/output-sync (output_sync_set): New arg syntax. 2013-04-14 Paul Smith * scripts/features/output-sync: Rewrite to be more reliable. * test_driver.pl (_run_command): Don't set SIGALRM until after we start the child. Print errors to the top-level output, which will be stderr. (attach_default_output): Use a list of file handles as the stack. (detach_default_output): Ditto. * scripts/features/output-sync: Add a test for output-sync. 2013-02-25 Paul Smith * run_make_tests.pl (valid_option): Support the -srcdir flag. (set_more_defaults): Set up $srcdir if it's not set yet. * scripts/functions/guile: Verify gmk-eval doesn't expand twice. * scripts/features/load: Rework to test just the load capability. * scripts/features/loadapi: New set of tests for the load API. 2013-01-19 Paul Smith * scripts/features/load: Test loaded files with and without "./" prefix. Add tests for automatically rebuilding loaded files if they are out of date or non-existent. 2013-01-13 Paul Smith * scripts/features/archives: Add a check targets that have parens, but are not archives. See Savannah bug #37878. * scripts/options/dash-n: Verify -n is preserved after recursive / re-exec. See Savannah bug #38051. 2013-01-12 Paul Smith * scripts/features/parallelism: Change rule so it doesn't depend on invocation order, etc. 2012-10-29 Paul Smith * scripts/features/load: New test suite for the "load" directive. 2012-09-09 Paul Smith * scripts/functions/file: Get errors in the C locale, not the current locale. Fixes Savannah bug #35764. * scripts/features/escape: Check that backslashes before non-special characters are not removed. * scripts/features/utf8: New test for UTF-8 support. See Savannah bug #36529. * scripts/targets/POSIX: Add tests for default macro values as specified by IEEE Std 1003.1-2008. See Savannah bug #37069. 2012-03-04 Paul Smith * scripts/features/se_explicit: Test $(x:%=%) format in secondary expansion prerequisite lists. See Savannah bug #16545. * scripts/features/escape: Test escaped ":" in prerequisite lists. See Savannah bug #12126. * scripts/variables/private: Test appending private variables in pattern-specific target rules. See Savannah bug #35468. 2012-03-03 Paul Smith * scripts/variables/SHELL: Ensure .SHELLFLAGS works with options separated by whitespace. * scripts/targets/ONESHELL: Try .ONESHELL in combination with whitespace-separated options in .SHELLFLAGS. See Savannah bug #35397. * scripts/functions/filter-out: Add filter tests and test escape operations. See Savannah bug #35410. * guile.supp: Suppress valgrind errors from Guile * run_make_tests.pl: Use the Guile suppression file. * scripts/misc/bs-nl: Check for POSIX and non-POSIX backslash/newline handling. Addresses Savannah bug #16670. 2012-01-29 Paul Smith * scripts/variables/flavors: Add tests for ::= * scripts/variables/define: Ditto * scripts/functions/file: Test the new $(file ...) function. 2012-01-12 Paul Smith * scripts/functions/guile: New regression tests for Guile support. 2011-12-10 Paul Smith * scripts/targets/SECONDARY: Add prereq statements to ensure rules are printed in the right order for test #9 2011-11-14 Paul Smith * scripts/features/double_colon: Check double-colon with escaped filenames. See Savannah bug #33399. 2011-09-18 Paul Smith * scripts/features/parallelism: On re-exec make sure we preserve the value of MAKEFLAGS when necessary. See Savannah bug #33873. * scripts/features/vpath3: Verify handling of -lfoo libraries found via vpath vs. the standard directory search. See Savannah bug #32511. 2011-09-12 Paul Smith * scripts/functions/call: Verify that using export in a $(call ...) context creates a global variable. See Savannah bug #32498. 2011-09-02 Paul Smith * scripts/options/dash-n: Verify that in "-n -t", the -n takes priority. Patch from Michael Witten . 2011-08-29 Paul Smith * scripts/features/varnesting: Test resetting of variables while expanding them. See Savannah patch #7534 2011-06-12 Paul Smith * scripts/features/archives: Check archives with whitespace at the beginning, end, and extra in the middle. Another test for Savannah bug #30612. 2011-05-07 Paul Smith * scripts/variables/private: Ensure we skip private variables when appending. Test for Savannah bug #32872. * scripts/functions/wildcard: Verify wildcard used to test for file existence/non-existence. 2011-05-02 Paul Smith * scripts/functions/sort: Add a test for Savannah bug #33125. 2011-04-17 David A. Wheeler * scripts/features/shell_assignment: Regression for "!=" feature 2010-11-06 Paul Smith * scripts/features/targetvars: Fix known-good output for BS/NL changes. * scripts/functions/call: Ditto. * scripts/variables/special: Ditto. * scripts/misc/bs-nl: New test suite for backslash/newline testing. 2010-08-29 Paul Smith * scripts/features/errors: Add new error message to output text. * scripts/variables/SHELL: Ditto. * scripts/targets/POSIX: Ditto. * scripts/options/dash-k: Ditto. * scripts/features/vpathplus: Ditto. * scripts/features/patternrules: Ditto. * scripts/features/parallelism: Ditto. 2010-08-13 Paul Smith * scripts/features/archives: New regression tests for archive support. Test for fix to Savannah bug #30612. * run_make_tests.pl (set_more_defaults): Set a %FEATURES hash to the features available in $(.FEATURES). 2010-08-10 Paul Smith * scripts/features/reinvoke: Ensure command line variable settings are preserved across make re-exec. Tests Savannah bug #30723. 2010-07-28 Paul Smith * scripts/targets/POSIX: Compatibility issues with Solaris (and Tru64?); "false" returns different exit codes, and set -x shows output with extra whitespace. Run the commands by hand first to find out what the real shell would do, then compare what make does. * scripts/variables/SHELL: Ditto. 2010-07-12 Paul Smith * test_driver.pl: Add a new $perl_name containing the path to Perl. * run_make_tests.pl (run_make_test): Replace the special string #PERL# in a makefile etc. with the path the Perl executable so makefiles can use it. * scripts/targets/ONESHELL: Add a new set of regression tests for the .ONESHELL feature. 2010-07-06 Paul Smith * scripts/variables/SHELL: Test the new .SHELLFLAGS variable. * scripts/targets/POSIX: New file. Test the .POSIX special target. Verify that enabling .POSIX changes the shell flags to set -e. 2010-07-01 Paul Smith * scripts/features/recursion: Add a space to separate command-line args. Fixes Savannah bug #29968. 2009-11-12 Boris Kolpackov * scripts/features/vpath3: Test for the new library search behavior. 2009-10-06 Boris Kolpackov * scripts/features/se_explicit: Enable the test for now fixed Savannah bug 25780. 2009-10-06 Boris Kolpackov * scripts/variables/undefine: Tests for the new undefine feature. 2009-10-03 Paul Smith * scripts/features/parallelism: Test for open Savannah bug #26846. * scripts/variables/MAKE: Rewrite for new run_make_test() format. * scripts/variables/MAKEFLAGS: Created. Add test for Savannah bug #2216 (still open). * scripts/features/include: Test for Savannah bug #102 (still open). 2009-09-30 Boris Kolpackov * scripts/features/include: Add diagnostics issuing tests for cases where targets have been updated and failed with the dontcare flag. Savannah bugs #15110, #25493, #12686, #17740. 2009-09-28 Paul Smith * scripts/functions/shell: Add regression test for Savannah bug #20513 (still open). * scripts/features/se_explicit: Add regression tests for Savannah bug #25780 (still open). * run_make_tests.pl (valid_option): Add a new flag, -all([-_]?tests)? that runs tests we know will fail. This allows us to add regression tests to the test suite for bugs that haven't been fixed yet. 2009-09-28 Boris Kolpackov * scripts/features/patspecific_vars: Add a test for the shortest stem first order. * scripts/features/patternrules: Add a test for the shortest stem first order. 2009-09-24 Paul Smith * scripts/features/se_implicit: Add a test for order-only secondary expansion prerequisites. 2009-09-23 Paul Smith * scripts/features/patternrules: Test that we can remove pattern rules, both single and multiple prerequisites. Savannah bug #18622. * scripts/features/echoing: Rework for run_make_test(). 2009-06-14 Paul Smith * scripts/features/vpath: Verify we don't get bogus circular dependency warnings if we choose a different file via vpath during update. Savannah bug #13529. 2009-06-13 Paul Smith * scripts/variables/MAKEFILES: Verify that MAKEFILES included files (and files included by them) don't set the default goal. Savannah bug #13401. * scripts/functions/wildcard: Test that wildcards with non-existent glob matchers return empty. 2009-06-09 Paul Smith * scripts/options/dash-B: Test the $? works correctly with -B. Savannah bug #17825. * scripts/features/patternrules: Test that dependencies of "also_make" targets are created properly. Savannah bug #19108. * test_driver.pl (compare_output): Create a "run" file for failed tests containing the command that was run. (get_runfile): New function. * run_make_tests.pl (valid_option): Enhanced support for valgrind: allow memcheck and massif tools. * scripts/features/patternrules: Have to comment out a line in the first test due to backing out a change that broke the implicit rule search algorithm. Savannah bug #17752. * scripts/misc/general4: Remove a test that is redundant with patternrules. * scripts/features/parallelism: Add a test for re-exec with jobserver master override. Savannah bug #18124. 2009-06-08 Paul Smith * scripts/features/targetvars: Add a test for continued target vars after a semicolon. Savannah bug #17521. 2009-06-07 Paul Smith * scripts/features/se_explicit: Make sure we catch defining prereqs during snap_deps(). Savannah bug #24622. * scripts/variables/automatic: Check prereq ordering when the target with the recipe has no prereqs. Savannah bug #21198. * scripts/variables/LIBPATTERNS: Add a new set of test for $(.LIBPATTERNS) (previously untested!) 2009-06-04 Paul Smith * scripts/variables/SHELL: The export target-specific SHELL test has an incorrect known-good-value. * scripts/misc/general4: Check for whitespace (ffeed, vtab, etc.) * scripts/features/se_explicit: Add tests for Savannah bug #24588. 2009-05-31 Paul Smith * scripts/variables/DEFAULT_GOAL: Add tests for Savannah bug #25697. * scripts/features/targetvars: Add tests of overrides for Savannah bug #26207. * scripts/features/patspecific_vars: Ditto. * scripts/features/patternrules: Add a test for Savannah bug #26593. 2009-05-30 Paul Smith * scripts/variables/flavors: Update with new variable flavor tests. * scripts/variables/define: Create a new set of tests for define/endef and move those aspects of the flavors suite here. 2009-05-25 Paul Smith * scripts/features/targetvars: Ditto. * scripts/features/export: Test new variable parsing abilities. 2009-02-23 Ramon Garcia * scripts/variables/private: Create a new suite of tests for 'private'. 2007-11-04 Paul Smith * scripts/functions/eval: Update error message for command -> recipe. * test_driver.pl (compare_output): Allow the answer to be a regex, if surrounded by '/'. * scripts/misc/close_stdout: Use a regex for the answer, since sometimes the error will have a description and sometimes it won't. 2007-09-10 Paul Smith * scripts/variables/special: Add tests for .RECIPEPREFIX variable. 2007-08-15 Paul Smith These test cases were contributed by Icarus Sparry and J. David Bryan for Savannah bugs #3330 and #15919. * scripts/targets/SECONDARY: Add tests for Savannah bugs 3330 and 15919. * scripts/features/parallelism: Add tests for wrong answer/hang combining INTERMEDIATE, order-only prereqs, and parallelism. See Savannah bugs 3330 and 15919. 2007-07-13 Paul Smith Install a timeout so tests can never loop infinitely. Original idea and patch for a single-test version provided by Icarus Sparry * test_driver.pl (_run_command): New function: this is called by other functions to actually run a command. Before we run it, install a SIGALRM handler and set up a timer to go off in the future (default is 5s; this can be overridden by individual tests). (run_command): Call it. (run_command_with_output): Call it. * run_make_tests.pl (run_make_with_options): Override the default timeout if the caller requests it. (run_make_test): Pass any timeout override to run_make_with_options. * scripts/features/parallelism: Increase the timeout for long tests. * scripts/options/dash-l: Ditto. 2006-10-01 Paul Smith * run_make_tests.pl (set_more_defaults): Remove setting of LANG in ENV here. This doesn't always work. * test_driver.pl (toplevel): Set LC_ALL to 'C' in the make environment. Fixes Savannah bug #16698. 2006-09-30 Paul Smith * scripts/variables/automatic: Add back the test for bug #8154. 2006-04-01 Paul D. Smith * scripts/functions/realpath: Don't run tests with multiple initial slashes on Windows: those paths mean something different. 2006-03-19 Paul D. Smith * scripts/features/parallelism: Test that the jobserver is properly managed when we have to re-exec the master instance of make. 2006-03-17 Boris Kolpackov * scripts/features/statipattrules: Add tests for bug #16053. 2006-03-09 Paul Smith * scripts/features/escape: Use "pre:" not "p:" to avoid conflicts with DOS drive letters. Fixes Savannah bug #15947. * test_driver.pl (run_each_test): Set the status properly even when a test fails to execute. Fixes Savannah bug #15942. * scripts/functions/foreach: Use a different environment variable other than PATH to avoid differences with Windows platforms. Fixes Savannah bug #15938. 2006-03-05 Paul D. Smith * run_make_tests.pl (set_more_defaults): Add CYGWIN_NT as a port type W32. Fixed Savannah bug #15937. * scripts/features/default_names: Don't call error() when the test fails. Fixes Savannah bug #15941. 2006-02-17 Paul D. Smith * scripts/features/targetvars: Test a complex construction which guarantees that we have to merge variable lists of different sizes. Tests for Savannah bug #15757. 2006-02-15 Paul D. Smith * scripts/functions/error: Make sure filename/lineno information is related to where the error is expanded, not where it's set. * scripts/functions/warning: Ditto. * scripts/functions/foreach: Check for different error conditions. * scripts/functions/word: Ditto. * scripts/variables/negative: Test some variable reference failure conditions. * scripts/options/warn-undefined-variables: Test the --warn-undefined-variables flag. 2006-02-09 Paul D. Smith * run_make_tests.pl (set_more_defaults): Update valgrind support for newer versions. * test_driver.pl (toplevel): Skip all hidden files/directories (ones beginning with "."). * scripts/functions/andor: Tests for $(and ...) and $(or ...) functions. 2006-02-08 Boris Kolpackov * scripts/features/parallelism: Add a test for bug #15641. 2006-02-06 Paul D. Smith * scripts/options/dash-W: Add a test for bug #15341. 2006-01-03 Paul D. Smith * scripts/variables/automatic: Add a test for bug #8154. * README: Update to reflect the current state of the test suite. 2005-12-12 Paul D. Smith * scripts/features/parallelism, scripts/functions/wildcard, scripts/targets/FORCE, scripts/targets/PHONY, scripts/targets/SILENT: Use the default setting for $delete_command. Fixes bug #15085. * run_make_tests.pl (get_this_pwd) [VMS]: Use -no_ask with delete_file. 2005-12-11 Paul D. Smith * scripts/misc/general4: Test implicit rules with '$' in the prereq list & prereq patterns. * scripts/features/se_implicit: Add in .SECONDEXPANSION settings. 2005-12-09 Boris Kolpackov * scripts/features/patternrules: Add a test for bug #13022. 2005-12-07 Boris Kolpackov * scripts/features/double_colon: Add a test for bug #14334. 2005-11-17 Boris Kolpackov * scripts/functions/flavor: Add a test for the flavor function. 2005-11-14 Boris Kolpackov * scripts/variables/INCLUDE_DIRS: Add a test for the .INCLUDE_DIRS special variable. 2005-10-24 Paul D. Smith * scripts/misc/general4: Test '$$' in prerequisites list. * scripts/features/statipattrules: Rewrite to use run_make_test(). Add various static pattern info. * scripts/features/se_statpat: Enable .SECONDEXPANSION target. * scripts/features/se_explicit: Add tests for handling '$$' in prerequisite lists with and without setting .SECONDEXPANSION. * scripts/features/order_only: Convert to run_make_test(). * run_make_tests.pl (set_more_defaults): If we can't get the value of $(MAKE) from make, then fatal immediately. 2005-08-31 Paul D. Smith * run_make_tests.pl (get_this_pwd): Require the POSIX module (in an eval to trap errors) and if it exists, use POSIX::getcwd to find the working directory. If it doesn't exist, go back to the previous methods. This tries to be more accurate on Windows systems. 2005-08-29 Paul D. Smith * scripts/functions/abspath: Add some text to the error messages to get a better idea of what's wrong. Make warnings instead of errors. * scripts/features/patspecific_vars: Don't use "test", which is UNIX specific. Print the values and let the test script match them. 2005-08-25 Paul Smith * scripts/variables/SHELL: Use a /./ prefix instead of //: the former works better with non-UNIX environments. Fixes Savannah bug #14129. 2005-08-13 Boris Kolpackov * scripts/functions/wildcard: Wrap calls to $(wildcard) with $(sort) so that the resulting order is no longer filesystem- dependent. 2005-08-10 Boris Kolpackov * scripts/features/statipattrules: Add a test for Savannah bug #13881. 2005-08-07 Paul D. Smith * scripts/features/parallelism: Add a test for a bug reported by Michael Matz (matz@suse.de) in which make exits without waiting for all its children in some situations during parallel builds. 2005-07-08 Paul D. Smith * test_driver.pl: Reset the environment to a clean value every time before we invoke make. I'm suspicious that the environment isn't handled the same way in Windows as it is in UNIX, and some variables are leaking out beyond the tests they are intended for. Create an %extraENV hash tests can set to add more env. vars. * tests/scripts/features/export: Change to use %extraENV. * tests/scripts/functions/eval: Ditto. * tests/scripts/functions/origin: Ditto. * tests/scripts/options/dash-e: Ditto. * tests/scripts/variables/SHELL: Ditto. 2005-06-27 Paul D. Smith * scripts/options/dash-W: Use 'echo >>' instead of touch to update files. * scripts/features/reinvoke: Rewrite to be safer on systems with subsecond timestamps. * scripts/features/patternrules: False exits with different error codes on different systems (for example, Linux => 1, Solaris => 255). * scripts/options/dash-W: Set the timestamp to foo.x in the future, to be sure it will be considered updated when it's remade. 2005-06-26 Paul D. Smith * scripts/functions/shell: New test suite for the shell function. 2005-06-25 Paul D. Smith * scripts/features/include: Test include/-include/sinclude with no arguments. Tests fix for Savannah bug #1761. * scripts/misc/general3: Implement comprehensive testing of backslash-newline behavior in command scripts: various types of quoting, fast path / slow path, etc. Tests fix for Savannah bug #1332. * scripts/options/symlinks: Test symlinks to non-existent files. Tests fix for Savannah bug #13280. * scripts/misc/general3: Test semicolons in variable references. Tests fix for Savannah bug #1454. * scripts/variables/MAKE_RESTARTS: New file: test the MAKE_RESTARTS variable. * scripts/options/dash-B: Test re-exec doesn't loop infinitely. Tests fix for Savannah bug #7566. * scripts/options/dash-W: New file: test the -W flag, including re-exec infinite looping. 2005-06-12 Paul D. Smith * scripts/misc/close_stdout: Add a test for Savannah bug #1328. This test only works on systems that have /dev/full (e.g., Linux). 2005-06-09 Paul D. Smith * scripts/functions/foreach: Add a test for Savannah bug #11913. 2005-05-31 Boris Kolpackov * scripts/features/include: Add a test for Savannah bug #13216. * scripts/features/patternrules: Add a test for Savannah bug #13218. 2005-05-13 Paul D. Smith * scripts/features/conditionals: Add tests for the new if... else if... endif syntax. 2005-05-03 Paul D. Smith * scripts/variables/DEFAULT_GOAL: Rename DEFAULT_TARGET to DEFAULT_GOAL. 2005-05-02 Paul D. Smith * scripts/features/parallelism: Add a test for exporting recursive variables containing $(shell) calls. Rewrite this script to use run_make_test() everywhere. 2005-04-07 Paul D. Smith * scripts/targets/SECONDARY: Add a test for Savannah bug #12331. 2005-03-15 Boris Kolpackov * scripts/variables/automatic: Add a test for Savannah bug #12320. 2005-03-10 Boris Kolpackov * scripts/features/patternrules: Add a test for Savannah bug #12267. 2005-03-09 Boris Kolpackov * scripts/variables/DEFAULT_TARGET: Add a test for Savannah bug #12266. 2005-03-04 Boris Kolpackov * scripts/features/patternrules: Add a test for Savannah bug #12202. 2005-03-03 Boris Kolpackov * scripts/features/se_implicit: Add a test for stem termination bug. Add a test for stem triple-expansion bug. * scripts/features/se_statpat: Add a test for stem triple-expansion bug. * scripts/features/statipattrules: Change test #4 to reflect new way empty prerequisite list is handled. 2005-03-01 Boris Kolpackov * scripts/features/statipattrules: Add a test for Savannah bug #12180. 2005-02-28 Paul D. Smith * scripts/options/dash-q: Add a test for Savannah bug # 7144. * scripts/options/symlinks: New file to test checking of symlink timestamps. Can't use filename dash-L because it conflicts with dash-l on case-insensitive filesystems. * scripts/variables/MAKEFILE_LIST, scripts/variables/MFILE_LIST: Rename MAKEFILE_LIST test to MFILE_LIST, for systems that need 8.3 unique filenames. 2005-02-28 Boris Kolpackov * scripts/variables/DEFAULT_TARGET: Test the .DEFAULT_TARGET special variable. 2005-02-27 Boris Kolpackov * scripts/features/se_explicit: Test the second expansion in explicit rules. * scripts/features/se_implicit: Test the second expansion in implicit rules. * scripts/features/se_statpat: Test the second expansion in static pattern rules. * scripts/variables/automatic: Fix to work with the second expansion. * scripts/misc/general4: Add a test for bug #12091. 2005-02-27 Paul D. Smith * scripts/functions/eval: Check that eval of targets within command scripts fails. See Savannah bug # 12124. 2005-02-26 Paul D. Smith * test_driver.pl (compare_output): If a basic comparison of the log and answer doesn't match, try harder: change all backslashes to slashes and all CRLF to LF. This helps on DOS/Windows systems. 2005-02-09 Paul D. Smith * scripts/features/recursion: Test command line variable settings: only one instance of a given variable should be provided. 2004-11-30 Boris Kolpackov * tests/scripts/functions/abspath: New file: test `abspath' built-in function. * tests/scripts/functions/realpath: New file: test `realpath' built-in function. 2004-11-28 Paul D. Smith * scripts/options/dash-C [WINDOWS32]: Add a test for bug #10252; this doesn't really test anything useful in UNIX but... * scripts/variables/SHELL: New file: test proper handling of SHELL according to POSIX rules. Fixes bug #1276. 2004-10-21 Boris Kolpackov * scripts/functions/word: Test $(firstword ) and $(lastword ). 2004-10-05 Boris Kolpackov * scripts/features/patspecific_vars: Test simple/recursive variable expansion. 2004-09-28 Boris Kolpackov * scripts/features/include: Test dontcare flag inheritance when rebuilding makefiles. 2004-09-27 Boris Kolpackov * scripts/features/patspecific_vars: Test exported variables. 2004-09-22 Paul D. Smith * run_make_tests.pl (run_make_test): Don't add newlines to the makestring or answer if they are completely empty. * scripts/features/patternrules: Rename from implicit_prereq_eval. * scripts/test_template: Rework the template. 2004-09-21 Boris Kolpackov * run_make_tests.pl: Change `#!/usr/local/bin/perl' to be `#!/usr/bin/env perl'. * scripts/features/implicit_prereq_eval: Test implicit rule prerequisite evaluation code. 2004-09-21 Paul D. Smith * run_make_tests.pl (run_make_test): Enhance to allow the make string to be undef: in that case it reuses the previous make string. Allows multiple tests on the same makefile. * scripts/variables/flavors: Add some tests for prefix characters interacting with define/endef variables. 2004-09-20 Paul D. Smith * scripts/functions/substitution: Rewrite to use run_make_test() interface, and add test for substitution failures reported by Markus Mauhart . 2004-03-22 Paul D. Smith * test_driver.pl (run_each_test, toplevel, compare_output): Change to track both the testing categories _AND_ the number of individual tests, and report both sets of numbers. 2004-02-21 Paul D. Smith * scripts/functions/origin: Set our own environment variable rather than relying on $HOME. 2004-01-21 Paul D. Smith * scripts/features/conditionals: Test arguments to ifn?def which contain whitespace (such as a function that is evaluated). Bug #7257. 2004-01-07 Paul D. Smith * scripts/features/order_only: Test order-only prerequisites in pattern rules (patch #2349). 2003-11-02 Paul D. Smith * scripts/functions/if: Test if on conditionals with trailing whitespace--bug #5798. * scripts/functions/eval: Test eval in a non-file context--bug #6195. 2003-04-19 Paul D. Smith * scripts/features/patspecific_vars: Test multiple patterns matching the same target--Bug #1405. 2003-04-09 Paul D. Smith * run_make_tests.pl (set_more_defaults): A new $port_type of 'OS/2' for (surprise!) OS/2. Also choose a wait time of 2 seconds for OS/2. 2003-03-28 Paul D. Smith * scripts/targets/SECONDARY: Test the "global" .SECONDARY (with not prerequisites)--Bug #2515. 2003-01-30 Paul D. Smith * scripts/features/targetvars: Test very long target-specific variable definition lines (longer than the default make buffer length). Tests patch # 1022. * scripts/functions/eval: Test very recursive $(eval ...) calls with simple variable expansion (bug #2238). * scripts/functions/word: Test error handling for word and wordlist functions (bug #2407). 2003-01-22 Paul D. Smith * scripts/functions/call: Test recursive argument masking (bug #1744). 2002-10-25 Paul D. Smith * scripts/functions/eval: Test using $(eval ...) inside conditionals (Bug #1516). 2002-10-14 Paul D. Smith * scripts/options/dash-t: Add a test for handling -t on targets with no commands (Bug #1418). 2002-10-13 Paul D. Smith * scripts/features/targetvars: Add a test for exporting target-specific vars (Bug #1391). 2002-10-05 Paul D. Smith * scripts/variables/automatic: Add tests for $$(@), $${@}, $${@D}, and $${@F}. 2002-09-23 Paul D. Smith * scripts/features/escape: Test handling of escaped comment characters in targets and prerequisites. 2002-09-18 Paul D. Smith * scripts/features/export: Test export/unexport of multiple variables in a single command. 2002-09-17 Paul D. Smith * scripts/features/targetvars: Tests for Bug #940: test target-specific and pattern-specific variables in conjunction with double-colon targets. 2002-09-10 Paul D. Smith * test_driver.pl (compare_output): Match the new format for time skew error messages. * scripts/features/export: Created. Add tests for export/unexport capabilities, including exporting/unexporting expanded variables. * scripts/features/conditionals: Add a test for expanded variables in ifdef conditionals. 2002-09-04 Paul D. Smith * scripts/features/reinvoke: Change touch/sleep combos to utouch invocations. * scripts/features/vpathgpath: Ditto. * scripts/features/vpathplus: Ditto. * scripts/options/dash-n: Ditto. * scripts/targets/INTERMEDIATE: Ditto. * scripts/targets/SECONDARY: Ditto. * scripts/options/dash-t: Added a test for the -t bug fixed by Henning Makholm. This test was also contributed by Henning. * scripts/misc/general4: Add a test suite for obscure algorithmic features of make. First test: make sure creation subdirectories as prerequisites of targets works properly. * scripts/misc/version: Remove this bogus test. 2002-08-07 Paul D. Smith * scripts/misc/general3: Add a test for makefiles that don't end in newlines. * scripts/variables/special: Create tests for the special variables (.VARIABLES and .TARGETS). Comment out .TARGETS test for now as it's not yet supported. 2002-08-01 Paul D. Smith * scripts/options/dash-B: Add a test for the new -B option. 2002-07-11 Paul D. Smith * run_make_tests.pl (valid_option): Add support for Valgrind. Use -valgrind option to the test suite. (set_more_defaults): Set up the file descriptor to capture Valgrind output. We have to unset its close-on-exec flag; we hardcode the value for F_SETFD (2) rather than load it; hopefully this will help us avoid breaking the Windows/DOS test suite. 2002-07-10 Paul D. Smith * scripts/variables/automatic: Add some tests for $$@, $$(@D), and $$(@F). * test_driver.pl (utouch): Create a new function that creates a file with a specific timestamp offset. Use of this function will let us avoid lots of annoying sleep() invocations in the tests just to get proper timestamping, which will make the tests run a lot faster. So far it's only used in the automatic test suite. 2002-07-09 Paul D. Smith * scripts/variables/automatic: Create a test for automatic variables. 2002-07-08 Paul D. Smith * scripts/features/order_only: Test new order-only prerequisites. 2002-07-07 Paul D. Smith * scripts/functions/eval: Test new function. * scripts/functions/value: Test new function. * scripts/variables/MAKEFILE_LIST: Test new variable. 2002-04-28 Paul D. Smith * scripts/functions/call: New test: transitive closure implementation using $(call ...) to test variable recursion. 2002-04-21 Paul D. Smith * test_driver.pl (compare_dir_tree): Ignore CVS and RCS directories in the script directories. 2001-05-02 Paul D. Smith * scripts/variables/flavors: Test define/endef scripts where only one of the command lines is quiet. 2000-06-22 Paul D. Smith * scripts/options/dash-q: New file; test the -q option. Includes a test for PR/1780. 2000-06-21 Paul D. Smith * scripts/features/targetvars: Added a test for PR/1709: allowing semicolons in target-specific variable values. 2000-06-19 Paul D. Smith * scripts/functions/addsuffix: Test for an empty final argument. Actually this bug might have happened for any function, but this one was handy. 2000-06-17 Eli Zaretskii * scripts/options/general: If parallel jobs are not supported, expect a warning message from Make. 2000-06-15 Eli Zaretskii * scripts/options/general: Don't try -jN with N != 1 if parallel jobs are not supported. 2000-05-24 Paul D. Smith * scripts/options/general: Test general option processing (PR/1716). 2000-04-11 Paul D. Smith * scripts/functions/strip: Test empty value to strip (PR/1689). 2000-04-08 Eli Zaretskii * scripts/features/reinvoke: Sleep before updating the target files in the first test, to ensure its time stamp really gets newer; otherwise Make might re-exec more than once. 2000-04-07 Eli Zaretskii * scripts/features/double_colon: Don't run the parallel tests if parallel jobs aren't supported. 2000-04-04 Paul D. Smith * scripts/functions/word: wordlist doesn't swap arguments anymore. 2000-03-27 Paul D. Smith * scripts/features/statipattrules: Test that static pattern rules whose prerequisite patterns resolve to empty strings throw an error (instead of dumping core). Fixes PR/1670. * scripts/features/reinvoke: Make more robust by touching "b" first, to ensure it's not newer than "a". Reported by Marco Franzen . * scripts/options/dash-n: Ditto. * scripts/functions/call: Whoops. The fix to PR/1527 caused recursive invocations of $(call ...) to break. I can't come up with any way to get both working at the same time, so I backed out the fix to 1527 and added a test case for recursive calls. This also tests the fix for PR/1610. * scripts/features/double_colon: Test that circular dependencies in double-colon rule sets are detected correctly (PR/1671). 2000-03-26 Paul D. Smith * scripts/targets/INTERMEDIATE: Test that make doesn't remove .INTERMEDIATE files when given on the command line (PR/1669). 2000-03-08 Paul D. Smith * scripts/options/dash-k: Add a test for error detection by multiple targets depending on the same prerequisite with -k. For PR/1634. 2000-02-07 Paul D. Smith * scripts/features/escape: Add a test for backslash-escaped spaces in a target name (PR/1586). 2000-02-04 Paul D. Smith * scripts/features/patspecific_vars: Add a test for pattern-specific target variables inherited from the parent target (PR/1407). 2000-02-02 Paul D. Smith * run_make_tests.pl (set_more_defaults): Hard-code the LANG to C to make sure sorting order, etc. is predictable. Reported by Andreas Jaeger . * run_make_tests.pl (set_more_defaults): Set the $wtime variable depending on the OS. Eli Zaretskii reports this seems to need to be *4* on DOS/Windows, not just 2. Keep it 1 for other systems. * scripts/features/vpathplus (touchfiles): Use the $wtime value instead of hardcoding 2. * scripts/targets/SECONDARY: Ditto. * scripts/targets/INTERMEDIATE: Ditto. 2000-01-27 Paul D. Smith * test_driver.pl (toplevel): Don't try to run test scripts which are really directories. 2000-01-23 Paul D. Smith * scripts/features/include: Remove a check; the fix caused more problems than the error, so I removed it and removed the test for it. 2000-01-11 Paul D. Smith * scripts/functions/call: Add a test for PR/1517 and PR/1527: make sure $(call ...) doesn't eval its arguments and that you can invoke foreach from it without looping forever. 1999-12-15 Paul D. Smith * scripts/targets/INTERMEDIATE: Add a test for PR/1423: make sure .INTERMEDIATE settings on files don't disable them as implicit intermediate possibilities. 1999-12-01 Paul D. Smith * scripts/features/double_colon: Add a test for PR/1476: Try double-colon rules as non-goal targets and during parallel builds to make sure they're handled serially. 1999-11-17 Paul D. Smith * scripts/functions/if: Add a test for PR/1429: put some text after an if-statement to make sure it works. * scripts/features/targetvars: Add a test for PR/1380: handling += in target-specific variable definitions correctly. 1999-10-15 Paul D. Smith * scripts/variables/MAKEFILES: This was really broken: it didn't test anything at all, really. Rewrote it, plus added a test for PR/1394. 1999-10-13 Paul D. Smith * scripts/options/dash-n: Add a test for PR/1379: "-n doesn't behave properly when used with recursive targets". 1999-10-08 Paul D. Smith * scripts/features/targetvars: Add a check for PR/1378: "Target-specific vars don't inherit correctly" 1999-09-29 Paul D. Smith * test_driver.pl (get_osname): Change $fancy_file_names to $short_filenames and reverse the logic. (run_each_test): Change test of non-existent $port_host to use $short_filenames--problem reported by Eli Zaretskii. 1999-09-23 Paul D. Smith * scripts/features/parallelism: Add a check to ensure that the jobserver works when we re-invoke. Also cleaned up the tests a little, reducing the number of rules we use so the test won't need as many "sleep" commands. 1999-09-16 Paul D. Smith * scripts/features/reinvoke: Remove invocations of "touch" in makefiles. See the comments on the touch function rewrite below. Note that UNIX touch behaves the same way if the file already exists: it sets the time to the _local_ time. We don't want this. This is probably a good tip for makefile writers in general, actually... where practical. * scripts/options/dash-l: Ditto. * scripts/options/dash-n: Ditto. * test_driver.pl (run_each_test): In retrospect, I don't like the .lN/.bN/.dN postfix required by DOS. So, for non-DOS systems I changed it back to use .log, .base, and .diff. * run_make_tests.pl (set_more_defaults): Move the check for the make pathname to here from set_defaults (that's too early since it happens before the command line processing). Create a new variable $port_type, calculated from $osname, to specify what kind of system we're running on. We should integrate the VOS stuff here, too. (valid_option): Comment out the workdir/-work stuff so people won't be fooled into thinking it works... someone needs to fix this, though! * scripts/functions/origin: Use $port_type instead of $osname. * scripts/functions/foreach: Ditto. * scripts/features/default_names: Ditto. 1999-09-15 Paul D. Smith * test_driver.pl (touch): Rewrite this function. Previously it used to use utime() to hard-set the time based on the current local clock, or, if the file didn't exist, it merely created it. This mirrors exactly what real UNIX touch does, but it fails badly on networked filesystems where the FS server clock is skewed from the local clock: normally modifying a file causes it to get a mod time based on the _server's_ clock. Hard-setting it based on the _local_ clock causes gratuitous errors and makes the tests unreliable except on local filesystems. The new function will simply modify the file, allowing the filesystem to set the mod time as it sees fit. * scripts/features/parallelism: The second test output could change depending on how fast some scripts completed; use "sleep" to force the order we want. * test_driver.pl (toplevel): A bug in Perl 5.000 to Perl 5.004 means that "%ENV = ();" doesn't do the right thing. This worked in Perl 4 and was fixed in Perl 5.004_01, but use a loop to delete the environment rather than require specific versions. * run_make_tests.pl (set_more_defaults): Don't use Perl 5 s/// modifier "s", so the tests will run with Perl 4. (set_more_defaults): Set $pure_log to empty if there's no -logfile option in PURIFYOPTIONS. (setup_for_test): Don't remove any logs unless $pure_log is set. 1999-09-15 Eli Zaretskii * scripts/features/reinvoke: Put the SHELL definition in the right test makefile. 1999-09-15 Paul D. Smith ChangeLog file for the test suite created. Copyright (C) 1992-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make 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 . kbuild-3149/src/kmk/strcache2.c0000644000175000017500000011556613252530201016306 0ustar locutuslocutus/* $Id: strcache2.c 3140 2018-03-14 21:28:10Z bird $ */ /** @file * strcache2 - New string cache. */ /* * Copyright (c) 2008-2010 knut st. osmundsen * * This file is part of kBuild. * * kBuild 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. * * kBuild 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 kBuild. If not, see * */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "makeint.h" #include "strcache2.h" #include #include "debug.h" #ifdef _MSC_VER typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; typedef signed char int8_t; typedef signed short int16_t; typedef signed int int32_t; #else # include #endif #ifdef WINDOWS32 # include # include # include # define PARSE_IN_WORKER #endif #ifdef __OS2__ # include #endif #ifdef HAVE_PTHREAD # include #endif /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /* The default size of a memory segment (1MB). */ #define STRCACHE2_SEG_SIZE (1024U*1024U) /* The default hash table shift (hash size give as a power of two). */ #define STRCACHE2_HASH_SHIFT 16 /** Does the modding / masking of a hash number into an index. */ #ifdef STRCACHE2_USE_MASK # define STRCACHE2_MOD_IT(cache, hash) ((hash) & (cache)->hash_mask) #else # define STRCACHE2_MOD_IT(cache, hash) ((hash) % (cache)->hash_div) #endif # if ( defined(__amd64__) || defined(__x86_64__) || defined(__AMD64__) || defined(_M_X64) || defined(__amd64) \ || defined(__i386__) || defined(__x86__) || defined(__X86__) || defined(_M_IX86) || defined(__i386)) \ && !defined(GCC_ADDRESS_SANITIZER) # define strcache2_get_unaligned_16bits(ptr) ( *((const uint16_t *)(ptr))) # else /* (endian doesn't matter) */ # define strcache2_get_unaligned_16bits(ptr) ( (((const uint8_t *)(ptr))[0] << 8) \ | (((const uint8_t *)(ptr))[1]) ) # endif /******************************************************************************* * Global Variables * *******************************************************************************/ /* List of initialized string caches. */ static struct strcache2 *strcache_head; #ifndef STRCACHE2_USE_MASK /** Finds the closest primary number for power of two value (or something else * useful if not support). */ MY_INLINE unsigned int strcache2_find_prime(unsigned int shift) { switch (shift) { case 5: return 31; case 6: return 61; case 7: return 127; case 8: return 251; case 9: return 509; case 10: return 1021; case 11: return 2039; case 12: return 4093; case 13: return 8191; case 14: return 16381; case 15: return 32749; case 16: return 65521; case 17: return 131063; case 18: return 262139; case 19: return 524269; case 20: return 1048573; case 21: return 2097143; case 22: return 4194301; case 23: return 8388593; default: assert (0); return (1 << shift) - 1; } } #endif /* The following is a bit experiment. It produces longer chains, i.e. worse distribution of the strings in the table, however the actual make performances is better (> 2); while (head-- > 0) { hash += strcache2_get_unaligned_16bits (str); tmp = (strcache2_get_unaligned_16bits (str + 2) << 11) ^ hash; hash = (hash << 16) ^ tmp; str += 2 * sizeof (uint16_t); hash += hash >> 11; } /* tail BIG_HASH_TAIL bytes (minus the odd ones) */ str += (len - BIG_HASH_HEAD - BIG_HASH_TAIL) & ~3U; head = (BIG_HASH_TAIL >> 2); while (head-- > 0) { hash += strcache2_get_unaligned_16bits (str); tmp = (strcache2_get_unaligned_16bits (str + 2) << 11) ^ hash; hash = (hash << 16) ^ tmp; str += 2 * sizeof (uint16_t); hash += hash >> 11; } /* force "avalanching" of final 127 bits. */ hash ^= hash << 3; hash += hash >> 5; hash ^= hash << 4; hash += hash >> 17; hash ^= hash << 25; hash += hash >> 6; return hash; } #endif /* BIG_HASH_SIZE */ MY_INLINE unsigned int strcache2_case_sensitive_hash (const char *str, unsigned int len) { #if 1 /* Paul Hsieh hash SuperFast function: http://www.azillionmonkeys.com/qed/hash.html This performs very good and as a sligtly better distribution than STRING_N_HASH_1 on a typical kBuild run. It is also 37% faster than return_STRING_N_HASH_1 when running the two 100 times over typical kBuild strings that end up here (did a fprintf here and built kBuild). Compiler was 32-bit gcc 4.0.1, darwin, with -O2. FIXME: A path for well aligned data should be added to speed up execution on alignment sensitive systems. */ unsigned int rem; uint32_t hash; uint32_t tmp; assert (sizeof (uint8_t) == sizeof (char)); # ifdef BIG_HASH_SIZE /* long string? */ # if 0 /*BIG_HASH_SIZE > 128*/ if (MY_PREDICT_FALSE(len >= BIG_HASH_SIZE)) # else if (len >= BIG_HASH_SIZE) # endif return strcache2_case_sensitive_hash_big (str, len); # endif /* short string: main loop, walking on 2 x uint16_t */ hash = len; rem = len & 3; len >>= 2; while (len > 0) { hash += strcache2_get_unaligned_16bits (str); tmp = (strcache2_get_unaligned_16bits (str + 2) << 11) ^ hash; hash = (hash << 16) ^ tmp; str += 2 * sizeof (uint16_t); hash += hash >> 11; len--; } /* the remainder */ switch (rem) { case 3: hash += strcache2_get_unaligned_16bits (str); hash ^= hash << 16; hash ^= str[sizeof (uint16_t)] << 18; hash += hash >> 11; break; case 2: hash += strcache2_get_unaligned_16bits (str); hash ^= hash << 11; hash += hash >> 17; break; case 1: hash += *str; hash ^= hash << 10; hash += hash >> 1; break; } /* force "avalanching" of final 127 bits. */ hash ^= hash << 3; hash += hash >> 5; hash ^= hash << 4; hash += hash >> 17; hash ^= hash << 25; hash += hash >> 6; return hash; #elif 1 /* Note! This implementation is 18% faster than return_STRING_N_HASH_1 when running the two 100 times over typical kBuild strings that end up here (did a fprintf here and built kBuild). Compiler was 32-bit gcc 4.0.1, darwin, with -O2. */ unsigned int hash = 0; if (MY_PREDICT_TRUE(len >= 2)) { unsigned int ch0 = *str++; hash = 0; len--; while (len >= 2) { unsigned int ch1 = *str++; hash += ch0 << (ch1 & 0xf); ch0 = *str++; hash += ch1 << (ch0 & 0xf); len -= 2; } if (len == 1) { unsigned ch1 = *str; hash += ch0 << (ch1 & 0xf); hash += ch1; } else hash += ch0; } else if (len) { hash = *str; hash += hash << (hash & 0xf); } else hash = 0; return hash; #elif 1 # if 0 /* This is SDBM. This specific form/unroll was benchmarked to be 28% faster than return_STRING_N_HASH_1. (Now the weird thing is that putting the (ch) first in the assignment made it noticably slower.) However, it is noticably slower in practice, most likely because of more collisions. Hrmpf. */ # define UPDATE_HASH(ch) hash = (hash << 6) + (hash << 16) - hash + (ch) unsigned int hash = 0; # else /* This is DJB2. This specific form/unroll was benchmarked to be 27% fast than return_STRING_N_HASH_1. Ditto. */ # define UPDATE_HASH(ch) hash = (hash << 5) + hash + (ch) unsigned int hash = 5381; # endif while (len >= 4) { UPDATE_HASH (str[0]); UPDATE_HASH (str[1]); UPDATE_HASH (str[2]); UPDATE_HASH (str[3]); str += 4; len -= 4; } switch (len) { default: case 0: return hash; case 1: UPDATE_HASH (str[0]); return hash; case 2: UPDATE_HASH (str[0]); UPDATE_HASH (str[1]); return hash; case 3: UPDATE_HASH (str[0]); UPDATE_HASH (str[1]); UPDATE_HASH (str[2]); return hash; } #endif } MY_INLINE unsigned int strcache2_case_insensitive_hash (const char *str, unsigned int len) { unsigned int hash = 0; if (MY_PREDICT_TRUE(len >= 2)) { unsigned int ch0 = *str++; ch0 = tolower (ch0); hash = 0; len--; while (len >= 2) { unsigned int ch1 = *str++; ch1 = tolower (ch1); hash += ch0 << (ch1 & 0xf); ch0 = *str++; ch0 = tolower (ch0); hash += ch1 << (ch0 & 0xf); len -= 2; } if (len == 1) { unsigned ch1 = *str; ch1 = tolower (ch1); hash += ch0 << (ch1 & 0xf); hash += ch1; } else hash += ch0; } else if (len) { hash = *str; hash += hash << (hash & 0xf); } else hash = 0; return hash; } #if 0 MY_INLINE int strcache2_memcmp_inline_short (const char *xs, const char *ys, unsigned int length) { if (length <= 8) { /* short string compare - ~50% of the kBuild calls. */ assert ( !((size_t)ys & 3) ); if (!((size_t)xs & 3)) { /* aligned */ int result; switch (length) { default: /* memcmp for longer strings */ return memcmp (xs, ys, length); case 8: result = *(int32_t*)(xs + 4) - *(int32_t*)(ys + 4); result |= *(int32_t*)xs - *(int32_t*)ys; return result; case 7: result = xs[6] - ys[6]; result |= xs[5] - ys[5]; result |= xs[4] - ys[4]; result |= *(int32_t*)xs - *(int32_t*)ys; return result; case 6: result = xs[5] - ys[5]; result |= xs[4] - ys[4]; result |= *(int32_t*)xs - *(int32_t*)ys; return result; case 5: result = xs[4] - ys[4]; result |= *(int32_t*)xs - *(int32_t*)ys; return result; case 4: return *(int32_t*)xs - *(int32_t*)ys; case 3: result = xs[2] - ys[2]; result |= xs[1] - ys[1]; result |= xs[0] - ys[0]; return result; case 2: result = xs[1] - ys[1]; result |= xs[0] - ys[0]; return result; case 1: return *xs - *ys; case 0: return 0; } } else { /* unaligned */ int result = 0; switch (length) { case 8: result |= xs[7] - ys[7]; case 7: result |= xs[6] - ys[6]; case 6: result |= xs[5] - ys[5]; case 5: result |= xs[4] - ys[4]; case 4: result |= xs[3] - ys[3]; case 3: result |= xs[2] - ys[2]; case 2: result |= xs[1] - ys[1]; case 1: result |= xs[0] - ys[0]; case 0: return result; } } } /* memcmp for longer strings */ return memcmp (xs, ys, length); } #endif MY_INLINE int strcache2_memcmp_inlined (const char *xs, const char *ys, unsigned int length) { #ifndef ELECTRIC_HEAP assert ( !((size_t)ys & 3) ); #endif if (!((size_t)xs & 3)) { /* aligned */ int result; unsigned reminder = length & 7; length >>= 3; while (length-- > 0) { result = *(int32_t*)xs - *(int32_t*)ys; result |= *(int32_t*)(xs + 4) - *(int32_t*)(ys + 4); if (MY_PREDICT_FALSE(result)) return result; xs += 8; ys += 8; } switch (reminder) { case 7: result = *(int32_t*)xs - *(int32_t*)ys; result |= xs[6] - ys[6]; result |= xs[5] - ys[5]; result |= xs[4] - ys[4]; return result; case 6: result = *(int32_t*)xs - *(int32_t*)ys; result |= xs[5] - ys[5]; result |= xs[4] - ys[4]; return result; case 5: result = *(int32_t*)xs - *(int32_t*)ys; result |= xs[4] - ys[4]; return result; case 4: return *(int32_t*)xs - *(int32_t*)ys; case 3: result = xs[2] - ys[2]; result |= xs[1] - ys[1]; result |= xs[0] - ys[0]; return result; case 2: result = xs[1] - ys[1]; result |= xs[0] - ys[0]; return result; case 1: return *xs - *ys; default: case 0: return 0; } } else { /* unaligned */ int result; unsigned reminder = length & 7; length >>= 3; while (length-- > 0) { #if defined(__i386__) || defined(__x86_64__) result = ( ((int32_t)xs[3] << 24) | ((int32_t)xs[2] << 16) | ((int32_t)xs[1] << 8) | xs[0] ) - *(int32_t*)ys; result |= ( ((int32_t)xs[7] << 24) | ((int32_t)xs[6] << 16) | ((int32_t)xs[5] << 8) | xs[4] ) - *(int32_t*)(ys + 4); #else result = xs[3] - ys[3]; result |= xs[2] - ys[2]; result |= xs[1] - ys[1]; result |= xs[0] - ys[0]; result |= xs[7] - ys[7]; result |= xs[6] - ys[6]; result |= xs[5] - ys[5]; result |= xs[4] - ys[4]; #endif if (MY_PREDICT_FALSE(result)) return result; xs += 8; ys += 8; } result = 0; switch (reminder) { case 7: result |= xs[6] - ys[6]; /* fall thru */ case 6: result |= xs[5] - ys[5]; /* fall thru */ case 5: result |= xs[4] - ys[4]; /* fall thru */ case 4: result |= xs[3] - ys[3]; /* fall thru */ case 3: result |= xs[2] - ys[2]; /* fall thru */ case 2: result |= xs[1] - ys[1]; /* fall thru */ case 1: result |= xs[0] - ys[0]; /* fall thru */ return result; default: case 0: return 0; } } } MY_INLINE int strcache2_is_equal (struct strcache2 *cache, struct strcache2_entry const *entry, const char *str, unsigned int length, unsigned int hash) { assert (!cache->case_insensitive); /* the simple stuff first. */ if ( entry->hash != hash || entry->length != length) return 0; #if 0 return memcmp (str, entry + 1, length) == 0; #elif 1 return strcache2_memcmp_inlined (str, (const char *)(entry + 1), length) == 0; #else return strcache2_memcmp_inline_short (str, (const char *)(entry + 1), length) == 0; #endif } #if defined(HAVE_CASE_INSENSITIVE_FS) MY_INLINE int strcache2_is_iequal (struct strcache2 *cache, struct strcache2_entry const *entry, const char *str, unsigned int length, unsigned int hash) { assert (cache->case_insensitive); /* the simple stuff first. */ if ( entry->hash != hash || entry->length != length) return 0; # if defined(_MSC_VER) || defined(__OS2__) return _memicmp (entry + 1, str, length) == 0; # else return strncasecmp ((const char *)(entry + 1), str, length) == 0; # endif } #endif /* HAVE_CASE_INSENSITIVE_FS */ static void strcache2_rehash (struct strcache2 *cache) { unsigned int src = cache->hash_size; struct strcache2_entry **src_tab = cache->hash_tab; struct strcache2_entry **dst_tab; #ifndef STRCACHE2_USE_MASK unsigned int hash_shift; #endif /* Allocate a new hash table twice the size of the current. */ cache->hash_size <<= 1; #ifdef STRCACHE2_USE_MASK cache->hash_mask <<= 1; cache->hash_mask |= 1; #else for (hash_shift = 1; (1U << hash_shift) < cache->hash_size; hash_shift++) /* nothing */; cache->hash_div = strcache2_find_prime (hash_shift); #endif cache->rehash_count <<= 1; cache->hash_tab = dst_tab = (struct strcache2_entry **) xmalloc (cache->hash_size * sizeof (struct strcache2_entry *)); memset (dst_tab, '\0', cache->hash_size * sizeof (struct strcache2_entry *)); /* Copy the entries from the old to the new hash table. */ cache->collision_count = 0; while (src-- > 0) { struct strcache2_entry *entry = src_tab[src]; while (entry) { struct strcache2_entry *next = entry->next; unsigned int dst = STRCACHE2_MOD_IT (cache, entry->hash); if ((entry->next = dst_tab[dst]) != 0) cache->collision_count++; dst_tab[dst] = entry; entry = next; } } /* That's it, just free the old table and we're done. */ free (src_tab); } static struct strcache2_seg * strcache2_new_seg (struct strcache2 *cache, unsigned int minlen) { struct strcache2_seg *seg; size_t size; size_t off; size = cache->def_seg_size; if (size < (size_t)minlen + sizeof (struct strcache2_seg) + STRCACHE2_ENTRY_ALIGNMENT) { size = (size_t)minlen * 2; size = (size + 0xfff) & ~(size_t)0xfff; } seg = xmalloc (size); seg->start = (char *)(seg + 1); seg->size = size - sizeof (struct strcache2_seg); off = (size_t)seg->start & (STRCACHE2_ENTRY_ALIGNMENT - 1); if (off) { off = STRCACHE2_ENTRY_ALIGNMENT - off; seg->start += off; seg->size -= off; } assert (seg->size > minlen); seg->cursor = seg->start; seg->avail = seg->size; seg->next = cache->seg_head; cache->seg_head = seg; return seg; } /* Internal worker that enters a new string into the cache. */ static const char * strcache2_enter_string (struct strcache2 *cache, unsigned int idx, const char *str, unsigned int length, unsigned int hash) { struct strcache2_entry *entry; struct strcache2_seg *seg; unsigned int size; char *str_copy; /* Allocate space for the string. */ size = length + 1 + sizeof (struct strcache2_entry); size = (size + STRCACHE2_ENTRY_ALIGNMENT - 1) & ~(STRCACHE2_ENTRY_ALIGNMENT - 1U); seg = cache->seg_head; if (MY_PREDICT_FALSE(seg->avail < size)) { do seg = seg->next; while (seg && seg->avail < size); if (!seg) seg = strcache2_new_seg (cache, size); } entry = (struct strcache2_entry *) seg->cursor; assert (!((size_t)entry & (STRCACHE2_ENTRY_ALIGNMENT - 1))); seg->cursor += size; seg->avail -= size; /* Setup the entry, copy the string and insert it into the hash table. */ entry->user = NULL; entry->length = length; entry->hash = hash; str_copy = (char *) memcpy (entry + 1, str, length); str_copy[length] = '\0'; if ((entry->next = cache->hash_tab[idx]) != 0) cache->collision_count++; cache->hash_tab[idx] = entry; cache->count++; if (cache->count >= cache->rehash_count) strcache2_rehash (cache); return str_copy; } /* The public add string interface. */ const char * strcache2_add (struct strcache2 *cache, const char *str, unsigned int length) { struct strcache2_entry const *entry; unsigned int hash = strcache2_case_sensitive_hash (str, length); unsigned int idx; assert (!cache->case_insensitive); assert (!memchr (str, '\0', length)); MAKE_STATS (cache->lookup_count++); /* Lookup the entry in the hash table, hoping for an early match. If not found, enter the string at IDX. */ idx = STRCACHE2_MOD_IT (cache, hash); entry = cache->hash_tab[idx]; if (!entry) return strcache2_enter_string (cache, idx, str, length, hash); if (strcache2_is_equal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_1st_count++); entry = entry->next; if (!entry) return strcache2_enter_string (cache, idx, str, length, hash); if (strcache2_is_equal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_2nd_count++); /* Loop the rest. */ for (;;) { entry = entry->next; if (!entry) return strcache2_enter_string (cache, idx, str, length, hash); if (strcache2_is_equal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_3rd_count++); } /* not reached */ } /* The public add string interface for prehashed strings. Use strcache2_hash_str to calculate the hash of a string. */ const char * strcache2_add_hashed (struct strcache2 *cache, const char *str, unsigned int length, unsigned int hash) { struct strcache2_entry const *entry; unsigned int idx; #ifndef NDEBUG unsigned correct_hash; assert (!cache->case_insensitive); assert (!memchr (str, '\0', length)); correct_hash = strcache2_case_sensitive_hash (str, length); MY_ASSERT_MSG (hash == correct_hash, ("%#x != %#x\n", hash, correct_hash)); #endif /* NDEBUG */ MAKE_STATS (cache->lookup_count++); /* Lookup the entry in the hash table, hoping for an early match. If not found, enter the string at IDX. */ idx = STRCACHE2_MOD_IT (cache, hash); entry = cache->hash_tab[idx]; if (!entry) return strcache2_enter_string (cache, idx, str, length, hash); if (strcache2_is_equal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_1st_count++); entry = entry->next; if (!entry) return strcache2_enter_string (cache, idx, str, length, hash); if (strcache2_is_equal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_2nd_count++); /* Loop the rest. */ for (;;) { entry = entry->next; if (!entry) return strcache2_enter_string (cache, idx, str, length, hash); if (strcache2_is_equal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_3rd_count++); } /* not reached */ } /* The public lookup (case sensitive) string interface. */ const char * strcache2_lookup (struct strcache2 *cache, const char *str, unsigned int length) { struct strcache2_entry const *entry; unsigned int hash = strcache2_case_sensitive_hash (str, length); unsigned int idx; assert (!cache->case_insensitive); assert (!memchr (str, '\0', length)); MAKE_STATS (cache->lookup_count++); /* Lookup the entry in the hash table, hoping for an early match. */ idx = STRCACHE2_MOD_IT (cache, hash); entry = cache->hash_tab[idx]; if (!entry) return NULL; if (strcache2_is_equal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_1st_count++); entry = entry->next; if (!entry) return NULL; if (strcache2_is_equal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_2nd_count++); /* Loop the rest. */ for (;;) { entry = entry->next; if (!entry) return NULL; if (strcache2_is_equal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_3rd_count++); } /* not reached */ } #if defined(HAVE_CASE_INSENSITIVE_FS) /* The public add string interface for case insensitive strings. */ const char * strcache2_iadd (struct strcache2 *cache, const char *str, unsigned int length) { struct strcache2_entry const *entry; unsigned int hash = strcache2_case_insensitive_hash (str, length); unsigned int idx; assert (cache->case_insensitive); assert (!memchr (str, '\0', length)); MAKE_STATS (cache->lookup_count++); /* Lookup the entry in the hash table, hoping for an early match. If not found, enter the string at IDX. */ idx = STRCACHE2_MOD_IT (cache, hash); entry = cache->hash_tab[idx]; if (!entry) return strcache2_enter_string (cache, idx, str, length, hash); if (strcache2_is_iequal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_1st_count++); entry = entry->next; if (!entry) return strcache2_enter_string (cache, idx, str, length, hash); if (strcache2_is_iequal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_2nd_count++); /* Loop the rest. */ for (;;) { entry = entry->next; if (!entry) return strcache2_enter_string (cache, idx, str, length, hash); if (strcache2_is_iequal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_3rd_count++); } /* not reached */ } /* The public add string interface for prehashed case insensitive strings. Use strcache2_hash_istr to calculate the hash of a string. */ const char * strcache2_iadd_hashed (struct strcache2 *cache, const char *str, unsigned int length, unsigned int hash) { struct strcache2_entry const *entry; unsigned int idx; #ifndef NDEBUG unsigned correct_hash; assert (cache->case_insensitive); assert (!memchr (str, '\0', length)); correct_hash = strcache2_case_insensitive_hash (str, length); MY_ASSERT_MSG (hash == correct_hash, ("%#x != %#x\n", hash, correct_hash)); #endif /* NDEBUG */ MAKE_STATS (cache->lookup_count++); /* Lookup the entry in the hash table, hoping for an early match. If not found, enter the string at IDX. */ idx = STRCACHE2_MOD_IT (cache, hash); entry = cache->hash_tab[idx]; if (!entry) return strcache2_enter_string (cache, idx, str, length, hash); if (strcache2_is_iequal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_1st_count++); entry = entry->next; if (!entry) return strcache2_enter_string (cache, idx, str, length, hash); if (strcache2_is_iequal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_2nd_count++); /* Loop the rest. */ for (;;) { entry = entry->next; if (!entry) return strcache2_enter_string (cache, idx, str, length, hash); if (strcache2_is_iequal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_3rd_count++); } /* not reached */ } /* The public lookup (case insensitive) string interface. */ const char * strcache2_ilookup (struct strcache2 *cache, const char *str, unsigned int length) { struct strcache2_entry const *entry; unsigned int hash = strcache2_case_insensitive_hash (str, length); unsigned int idx; assert (cache->case_insensitive); assert (!memchr (str, '\0', length)); MAKE_STATS (cache->lookup_count++); /* Lookup the entry in the hash table, hoping for an early match. */ idx = STRCACHE2_MOD_IT (cache, hash); entry = cache->hash_tab[idx]; if (!entry) return NULL; if (strcache2_is_iequal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_1st_count++); entry = entry->next; if (!entry) return NULL; if (strcache2_is_iequal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_2nd_count++); /* Loop the rest. */ for (;;) { entry = entry->next; if (!entry) return NULL; if (strcache2_is_iequal (cache, entry, str, length, hash)) return (const char *)(entry + 1); MAKE_STATS (cache->collision_3rd_count++); } /* not reached */ } #endif /* HAVE_CASE_INSENSITIVE_FS */ /* Is the given string cached? returns 1 if it is, 0 if it isn't. */ int strcache2_is_cached (struct strcache2 *cache, const char *str) { /* Check mandatory alignment first. */ if (!((size_t)str & (sizeof (void *) - 1))) { /* Check the segment list and consider the question answered if the string is within one of them. (Could check it more thoroughly...) */ struct strcache2_seg const *seg; for (seg = cache->seg_head; seg; seg = seg->next) if ((size_t)(str - seg->start) < seg->size) return 1; } return 0; } /* Verify the integrity of the specified string, returning 0 if OK. */ int strcache2_verify_entry (struct strcache2 *cache, const char *str) { struct strcache2_entry const *entry; unsigned int hash; unsigned int length; const char *end; entry = (struct strcache2_entry const *)str - 1; if ((size_t)entry & (STRCACHE2_ENTRY_ALIGNMENT - 1)) { fprintf (stderr, "strcache2[%s]: missaligned entry %p\nstring: %p=%s\n", cache->name, (void *)entry, (void *)str, str); return -1; } end = memchr (str, '\0', entry->length + 1); length = end - str; if (length != entry->length) { fprintf (stderr, "strcache2[%s]: corrupt entry %p, length: %u, expected %u;\nstring: %s\n", cache->name, (void *)entry, length, entry->length, str); return -1; } hash = cache->case_insensitive ? strcache2_case_insensitive_hash (str, entry->length) : strcache2_case_sensitive_hash (str, entry->length); if (hash != entry->hash) { fprintf (stderr, "strcache2[%s]: corrupt entry %p, hash: %x, expected %x;\nstring: %s\n", cache->name, (void *)entry, hash, entry->hash, str); return -1; } return 0; } /* Calculates the case sensitive hash values of the string. The first hash is returned, the other is put at HASH2P. */ unsigned int strcache2_hash_str (const char *str, unsigned int length, unsigned int *hash2p) { *hash2p = 1; return strcache2_case_sensitive_hash (str, length); } /* Calculates the case insensitive hash values of the string. The first hash is returned, the other is put at HASH2P. */ unsigned int strcache2_hash_istr (const char *str, unsigned int length, unsigned int *hash2p) { *hash2p = 1; return strcache2_case_insensitive_hash (str, length); } /* Initalizes a new cache. */ void strcache2_init (struct strcache2 *cache, const char *name, unsigned int size, unsigned int def_seg_size, int case_insensitive, int thread_safe) { unsigned hash_shift; assert (!thread_safe); /* calc the size as a power of two */ if (!size) hash_shift = STRCACHE2_HASH_SHIFT; else { assert (size <= (~0U / 2 + 1)); for (hash_shift = 8; (1U << hash_shift) < size; hash_shift++) /* nothing */; } /* adjust the default segment size */ if (!def_seg_size) def_seg_size = STRCACHE2_SEG_SIZE; else if (def_seg_size < sizeof (struct strcache2_seg) * 10) def_seg_size = sizeof (struct strcache2_seg) * 10; else if ((def_seg_size & 0xfff) < 0xf00) def_seg_size = ((def_seg_size + 0xfff) & ~0xfffU); /* init the structure. */ cache->case_insensitive = case_insensitive; #ifdef STRCACHE2_USE_MASK cache->hash_mask = (1U << hash_shift) - 1U; #else cache->hash_div = strcache2_find_prime(hash_shift); #endif cache->count = 0; cache->collision_count = 0; cache->lookup_count = 0; cache->collision_1st_count = 0; cache->collision_2nd_count = 0; cache->collision_3rd_count = 0; cache->rehash_count = (1U << hash_shift) / 4 * 3; /* rehash at 75% */ cache->init_size = 1U << hash_shift; cache->hash_size = 1U << hash_shift; cache->def_seg_size = def_seg_size; cache->lock = NULL; cache->name = name; /* allocate the hash table and first segment. */ cache->hash_tab = (struct strcache2_entry **) xmalloc (cache->init_size * sizeof (struct strcache2_entry *)); memset (cache->hash_tab, '\0', cache->init_size * sizeof (struct strcache2_entry *)); strcache2_new_seg (cache, 0); /* link it */ cache->next = strcache_head; strcache_head = cache; } /* Terminates a string cache, freeing all memory and other associated resources. */ void strcache2_term (struct strcache2 *cache) { /* unlink it */ if (strcache_head == cache) strcache_head = cache->next; else { struct strcache2 *prev = strcache_head; while (prev->next != cache) prev = prev->next; assert (prev); prev->next = cache->next; } /* free the memory segments */ do { void *free_it = cache->seg_head; cache->seg_head = cache->seg_head->next; free (free_it); } while (cache->seg_head); /* free the hash and clear the structure. */ free (cache->hash_tab); memset (cache, '\0', sizeof (struct strcache2)); } /* Print statistics a string cache. */ void strcache2_print_stats (struct strcache2 *cache, const char *prefix) { unsigned int seg_count = 0; unsigned long seg_total_bytes = 0; unsigned long seg_avg_bytes; unsigned long seg_avail_bytes = 0; unsigned long seg_max_bytes = 0; struct strcache2_seg *seg; unsigned int str_count = 0; unsigned long str_total_len = 0; unsigned int str_avg_len; unsigned int str_min_len = ~0U; unsigned int str_max_len = 0; unsigned int idx; unsigned int rehashes; unsigned int chain_depths[32]; printf (_("\n%s strcache2: %s\n"), prefix, cache->name); /* Segment statistics. */ for (seg = cache->seg_head; seg; seg = seg->next) { seg_count++; seg_total_bytes += seg->size; seg_avail_bytes += seg->avail; if (seg->size > seg_max_bytes) seg_max_bytes = seg->size; } seg_avg_bytes = seg_total_bytes / seg_count; printf (_("%s %u segments: total = %lu / max = %lu / avg = %lu / def = %u avail = %lu\n"), prefix, seg_count, seg_total_bytes, seg_max_bytes, seg_avg_bytes, cache->def_seg_size, seg_avail_bytes); /* String statistics. */ memset (chain_depths, '\0', sizeof (chain_depths)); idx = cache->hash_size; while (idx-- > 0) { struct strcache2_entry const *entry = cache->hash_tab[idx]; unsigned int depth = 0; for (; entry != 0; entry = entry->next, depth++) { unsigned int length = entry->length; str_total_len += length; if (length > str_max_len) str_max_len = length; if (length < str_min_len) str_min_len = length; str_count++; } chain_depths[depth >= 32 ? 31 : depth]++; } str_avg_len = cache->count ? str_total_len / cache->count : 0; printf (_("%s %u strings: total len = %lu / max = %u / avg = %u / min = %u\n"), prefix, cache->count, str_total_len, str_max_len, str_avg_len, str_min_len); if (str_count != cache->count) printf (_("%s string count mismatch! cache->count=%u, actual count is %u\n"), prefix, cache->count, str_count); /* Hash statistics. */ idx = cache->init_size; rehashes = 0; while (idx < cache->hash_size) { idx *= 2; rehashes++; } #ifdef STRCACHE2_USE_MASK printf (_("%s hash size = %u mask = %#x rehashed %u times"), prefix, cache->hash_size, cache->hash_mask, rehashes); #else printf (_("%s hash size = %u div = %#x rehashed %u times"), prefix, cache->hash_size, cache->hash_div, rehashes); #endif if (cache->lookup_count) printf (_("%s lookups = %lu\n" "%s hash collisions 1st = %lu (%u%%) 2nd = %lu (%u%%) 3rd = %lu (%u%%)"), prefix, cache->lookup_count, prefix, cache->collision_1st_count, (unsigned int)((100.0 * cache->collision_1st_count) / cache->lookup_count), cache->collision_2nd_count, (unsigned int)((100.0 * cache->collision_2nd_count) / cache->lookup_count), cache->collision_3rd_count, (unsigned int)((100.0 * cache->collision_3rd_count) / cache->lookup_count)); printf (_("\n%s hash insert collisions = %u (%u%%)\n"), prefix, cache->collision_count,(unsigned int)((100.0 * cache->collision_count) / cache->count)); printf (_("%s %5u (%u%%) empty hash table slots\n"), prefix, chain_depths[0], (unsigned int)((100.0 * chain_depths[0]) / cache->hash_size)); printf (_("%s %5u (%u%%) occupied hash table slots\n"), prefix, chain_depths[1], (unsigned int)((100.0 * chain_depths[1]) / cache->hash_size)); for (idx = 2; idx < 32; idx++) { unsigned strs_at_this_depth = chain_depths[idx]; unsigned i; for (i = idx + 1; i < 32; i++) strs_at_this_depth += chain_depths[i]; if (strs_at_this_depth) printf (_("%s %5u (%2u%%) with %u string%s chained on; %5u (%2u%%) strings at depth %u.\n"), prefix, chain_depths[idx], (unsigned int)((100.0 * chain_depths[idx]) / (cache->count - cache->collision_count)), idx - 1, idx == 2 ? " " : "s", strs_at_this_depth, (unsigned int)((100.0 * strs_at_this_depth) / cache->count), idx - 1); } } /* Print statistics for all string caches. */ void strcache2_print_stats_all (const char *prefix) { struct strcache2 *cur; for (cur = strcache_head; cur; cur = cur->next) strcache2_print_stats (cur, prefix); } kbuild-3149/src/kmk/config.h.darwin0000644000175000017500000003070513252530203017156 0ustar locutuslocutus/* config.h. Generated from config.h.in by configure. */ /* config.h.in. Generated from configure.in by autoheader. */ /* Define to 1 if the `closedir' function returns void instead of `int'. */ /* #undef CLOSEDIR_VOID */ /* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP systems. This function is required for `alloca.c' support on those systems. */ /* #undef CRAY_STACKSEG_END */ /* Define to 1 if using `alloca.c'. */ /* #undef C_ALLOCA */ /* Define to 1 if using `getloadavg.c'. */ /* #undef C_GETLOADAVG */ /* Define to 1 for DGUX with . */ /* #undef DGUX */ /* Use high resolution file timestamps if nonzero. */ #define FILE_TIMESTAMP_HI_RES 0 /* Define to 1 if the `getloadavg' function needs to be run setuid or setgid. */ /* #undef GETLOADAVG_PRIVILEGED */ /* Define to 1 if you have `alloca', as a function or macro. */ #define HAVE_ALLOCA 1 /* Define to 1 if you have and it should be used (not on Ultrix). */ #define HAVE_ALLOCA_H 1 /* Define to 1 if your compiler conforms to the ANSI C standard. */ #define HAVE_ANSI_COMPILER 1 /* Define to 1 if you have the `atexit' function. */ #define HAVE_ATEXIT 1 /* Define to 1 if you have the `bsd_signal' function. */ #define HAVE_BSD_SIGNAL 1 #define HAVE_DECL_BSD_SIGNAL 1 /* Use case insensitive file names */ /* #undef HAVE_CASE_INSENSITIVE_FS */ /* Define to 1 if you have the clock_gettime function. */ /* #undef HAVE_CLOCK_GETTIME */ /* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you don't. */ #define HAVE_DECL_SYS_SIGLIST 1 /* Define to 1 if you have the declaration of `_sys_siglist', and to 0 if you don't. */ #define HAVE_DECL__SYS_SIGLIST 0 /* Define to 1 if you have the declaration of `__sys_siglist', and to 0 if you don't. */ #define HAVE_DECL___SYS_SIGLIST 0 /* Define to 1 if you have the header file, and it defines `DIR'. */ #define HAVE_DIRENT_H 1 /* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ /* #undef HAVE_DOPRNT */ /* Use platform specific coding */ /* #undef HAVE_DOS_PATHS */ /* Define to 1 if you have the `dup2' function. */ #define HAVE_DUP2 1 /* Define to 1 if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define to 1 if you have the `fdopen' function. */ #define HAVE_FDOPEN 1 /* Define to 1 if you have the `fileno' function. */ #define HAVE_FILENO 1 /* Define to 1 if you have the `fork' function. */ #define HAVE_FORK 1 /* Define to 1 if you have the `getcwd' function. */ #define HAVE_GETCWD 1 /* Define to 1 if you have the `getgroups' function. */ #define HAVE_GETGROUPS 1 /* Define to 1 if you have the `gethostbyname' function. */ /* #undef HAVE_GETHOSTBYNAME */ /* Define to 1 if you have the `gethostname' function. */ /* #undef HAVE_GETHOSTNAME */ /* Define to 1 if you have the `getloadavg' function. */ #define HAVE_GETLOADAVG 1 /* Define to 1 if you have the `getrlimit' function. */ #define HAVE_GETRLIMIT 1 /* Define to 1 if you have a standard gettimeofday function */ #define HAVE_GETTIMEOFDAY 1 /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the `dgc' library (-ldgc). */ /* #undef HAVE_LIBDGC */ /* Define to 1 if you have the `kstat' library (-lkstat). */ /* #undef HAVE_LIBKSTAT */ /* Define to 1 if you have the header file. */ #define HAVE_LIMITS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_LOCALE_H 1 /* Define to 1 if you have the `lstat' function. */ #define HAVE_LSTAT 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_MACH_MACH_H */ /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if you have the `mkstemp' function. */ #define HAVE_MKSTEMP 1 /* Define to 1 if you have the `mktemp' function. */ #define HAVE_MKTEMP 1 /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_NDIR_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NLIST_H */ /* Define to 1 if you have the `pipe' function. */ #define HAVE_PIPE 1 /* Define to 1 if you have the `pstat_getdynamic' function. */ /* #undef HAVE_PSTAT_GETDYNAMIC */ /* Define to 1 if you have the `readlink' function. */ #define HAVE_READLINK 1 /* Define to 1 if you have the `realpath' function. */ #define HAVE_REALPATH 1 /* Define to 1 if defines the SA_RESTART constant. */ #define HAVE_SA_RESTART 1 /* Define to 1 if you have the `setegid' function. */ #define HAVE_SETEGID 1 /* Define to 1 if you have the `seteuid' function. */ #define HAVE_SETEUID 1 /* Define to 1 if you have the `setlinebuf' function. */ #define HAVE_SETLINEBUF 1 /* Define to 1 if you have the `setlocale' function. */ /* #undef HAVE_SETLOCALE */ /* Define to 1 if you have the `setregid' function. */ #define HAVE_SETREGID 1 /* Define to 1 if you have the `setreuid' function. */ #define HAVE_SETREUID 1 /* Define to 1 if you have the `setrlimit' function. */ #define HAVE_SETRLIMIT 1 /* Define to 1 if you have the `setvbuf' function. */ #define HAVE_SETVBUF 1 /* Define to 1 if you have the `sigaction' function. */ #define HAVE_SIGACTION 1 /* Define to 1 if you have the `sigsetmask' function. */ #define HAVE_SIGSETMASK 1 /* Define to 1 if you have the `socket' function. */ /* #undef HAVE_SOCKET */ /* Define to 1 if you have the header file. */ #define HAVE_STDARG_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the `strcasecmp' function. */ #define HAVE_STRCASECMP 1 /* Define to 1 if you have the `strcmpi' function. */ /* #undef HAVE_STRCMPI */ /* Define to 1 if you have the `strncasecmp' function. */ #define HAVE_STRNCASECMP 1 /* Define to 1 if you have the `strncmpi' function. */ /* #undef HAVE_STRNCMPI */ /* Define to 1 if you have the `strncmp' function. */ /* #undef HAVE_STRNICMP */ /* Define to 1 if you have the `strcoll' function and it is properly defined. */ #define HAVE_STRCOLL 1 /* Define to 1 if you have the `strdup' function. */ #define HAVE_STRDUP 1 /* Define to 1 if you have the `strndup' function. */ /* #undef HAVE_STRNDUP */ /* Define to 1 if you have the `strerror' function. */ #define HAVE_STRERROR 1 /* Define to 1 if you have the `stricmp' function. */ /* #undef HAVE_STRICMP */ /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the `strsignal' function. */ #define HAVE_STRSIGNAL 1 /* Define to 1 if `n_un.n_name' is member of `struct nlist'. */ /* #undef HAVE_STRUCT_NLIST_N_UN_N_NAME */ /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_SYS_DIR_H */ /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_SYS_NDIR_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_PARAM_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_RESOURCE_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIMEB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIME_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_WAIT_H 1 /* Define to 1 if you have the \`union wait' type in . */ /* #undef HAVE_UNION_WAIT */ /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_VARARGS_H */ /* Define to 1 if you have the `vfork' function. */ #define HAVE_VFORK 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_VFORK_H */ /* Define to 1 if you have the `vprintf' function. */ #define HAVE_VPRINTF 1 /* Define to 1 if you have the `wait3' function. */ #define HAVE_WAIT3 1 /* Define to 1 if you have the `waitpid' function. */ #define HAVE_WAITPID 1 /* Define to 1 if `fork' works. */ #define HAVE_WORKING_FORK 1 /* Define to 1 if `vfork' works. */ #define HAVE_WORKING_VFORK 1 /* Build host information. (not used by kmk) */ #define MAKE_HOST "i386-apple-darwin9.4.0" /* Define to 1 to enable job server support in GNU make. */ #define MAKE_JOBSERVER 1 /* Define to 1 to enable symbolic link timestamp checking. */ #define MAKE_SYMLINKS 1 /* Define to 1 if your `struct nlist' has an `n_un' member. Obsolete, depend on `HAVE_STRUCT_NLIST_N_UN_N_NAME */ /* #undef NLIST_NAME_UNION */ /* Define to 1 if struct nlist.n_name is a pointer rather than an array. */ /* #undef NLIST_STRUCT */ /* Define to 1 if your C compiler doesn't accept -c and -o together. */ /* #undef NO_MINUS_C_MINUS_O */ /* Name of package */ #define PACKAGE "make" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "bug-make@gnu.org" /* Define to the full name of this package. */ #define PACKAGE_NAME "GNU make" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "GNU make 3.82" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "make" /* Define to the version of this package. */ #define PACKAGE_VERSION "3.82" /* Define to the character that separates directories in PATH. */ #define PATH_SEPARATOR_CHAR ':' /* Define to 1 if the C compiler supports function prototypes. */ #define PROTOTYPES 1 /* Define as the return type of signal handlers (`int' or `void'). */ #define RETSIGTYPE void /* Define to the name of the SCCS 'get' command. */ #define SCCS_GET "get" /* Define to 1 if the SCCS 'get' command understands the '-G' option. */ /* #undef SCCS_GET_MINUS_G */ /* Define to 1 if the `setvbuf' function takes the buffering type as its second argument and the buffer pointer as the third, as on System V before release 3. */ /* #undef SETVBUF_REVERSED */ /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be automatically deduced at runtime. STACK_DIRECTION > 0 => grows toward higher addresses STACK_DIRECTION < 0 => grows toward lower addresses STACK_DIRECTION = 0 => direction of growth unknown */ /* #undef STACK_DIRECTION */ /* Define to 1 if the `S_IS*' macros in do not work properly. */ /* #undef STAT_MACROS_BROKEN */ /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define if struct stat contains a nanoseconds field */ /* #undef ST_MTIM_NSEC */ /* Define to 1 on System V Release 4. */ /* #undef SVR4 */ /* Define to 1 if you can safely include both and . */ #define TIME_WITH_SYS_TIME 1 /* Define to 1 for Encore UMAX. */ /* #undef UMAX */ /* Define to 1 for Encore UMAX 4.3 that has instead of . */ /* #undef UMAX4_3 */ /* Version number of package */ #define VERSION "3.82" /* Use platform specific coding */ /* #undef WINDOWS32 */ /* Define if using the dmalloc debugging malloc package */ /* #undef WITH_DMALLOC */ /* Define to 1 if on AIX 3. System headers sometimes define this. We just want to avoid a redefinition error message. */ #ifndef _ALL_SOURCE /* # undef _ALL_SOURCE */ #endif /* Number of bits in a file offset, on hosts where this is settable. */ /* #undef _FILE_OFFSET_BITS */ /* Define for large files, on AIX-style hosts. */ /* #undef _LARGE_FILES */ /* Define to 1 if on MINIX. */ /* #undef _MINIX */ /* Define to 2 if the system does not provide POSIX.1 features except with this defined. */ /* #undef _POSIX_1_SOURCE */ /* Define to 1 if you need to in order for `stat' and other things to work. */ /* #undef _POSIX_SOURCE */ /* Define like PROTOTYPES; this can be used by system headers. */ #define __PROTOTYPES 1 /* Define to empty if `const' does not conform to ANSI C. */ /* #undef const */ /* Define to `int' if doesn't define. */ /* #undef gid_t */ /* Define to `int' if does not define. */ /* #undef pid_t */ /* Define to `int' if doesn't define. */ /* #undef uid_t */ /* Define uintmax_t if not defined in or . */ /* #undef uintmax_t */ /* Define as `fork' if `vfork' does not work. */ /* #undef vfork */ #include "inlined_memchr.h" kbuild-3149/src/kmk/README.DOS.template0000644000175000017500000003706413252530177017412 0ustar locutuslocutusPort of GNU Make to 32-bit protected mode on MSDOS and MS-Windows. Builds with DJGPP v2 port of GNU C/C++ compiler and utilities. New (since 3.74) DOS-specific features: 1. Supports long filenames when run from DOS box on Windows 9x. 2. Supports both stock DOS COMMAND.COM and Unix-style shells (details in 'Notes' below). 3. Supports DOS drive letters in dependencies and pattern rules. 4. Better support for DOS-style backslashes in pathnames (but see 'Notes' below). 5. The $(shell) built-in can run arbitrary complex commands, including pipes and redirection, even when COMMAND.COM is your shell. 6. Can be built without floating-point code (see below). 7. Supports signals in child programs and restores the original directory if the child was interrupted. 8. Can be built without (a previous version of) Make. 9. The build process requires only standard tools. (Optional targets like "install:" and "clean:" still need additional programs, though, see below.) 10. Beginning with v3.78, the test suite works in the DJGPP environment (requires Perl and auxiliary tools; see below). To install a binary distribution: Simply unzip the makNNNb.zip file (where NNN is the version number) preserving the directory structure (-d switch if you use PKUNZIP). If you are installing Make on Windows 9X or Windows 2000, use an unzip program that supports long filenames in zip files. After unzipping, make sure the directory with make.exe is on your PATH, and that's all you need to use Make. To build from sources: 1. Unzip the archive, preserving the directory structure (-d switch if you use PKUNZIP). If you build Make on Windows 9X or Windows 2000, use an unzip program that supports long filenames in zip files. If you are unpacking an official GNU source distribution, use either DJTAR (which is part of the DJGPP development environment), or the DJGPP port of GNU Tar. 2. Invoke the 'configure.bat' batch file. If you are building Make in-place, i.e. in the same directory where its sources are kept, just type "configure.bat" and press [Enter]. Otherwise, you need to supply the path to the source directory as an argument to the batch file, like this: c:\djgpp\gnu\make-%VERSION%\configure.bat c:/djgpp/gnu/make-%VERSION% Note the forward slashes in the source path argument: you MUST use them here. 3. If configure.bat doesn't find a working Make, it will suggest to use the 'dosbuild.bat' batch file to build Make. Either do as it suggests or install another Make program (a pre-compiled binary should be available from the usual DJGPP sites) and rerun configure.bat. 4. If you will need to run Make on machines without an FPU, you might consider building a version of Make which doesn't issue floating-point instructions (they don't help much on MSDOS anyway). To this end, edit the Makefile created by configure.bat and add -DNO_FLOAT to the value of CPPFLAGS. 5. Invoke Make. If you are building from outside of the source directory, you need to tell Make where the sources are, like this: make srcdir=c:/djgpp/gnu/make-%VERSION% (configure.bat will tell you this when it finishes). You MUST use a full, not relative, name of the source directory here, or else Make might fail. 6. After Make finishes, if you have a Unix-style shell installed, you can use the 'install' target to install the package. You will also need GNU Fileutils and GNU Sed for this (they should be available from the DJGPP sites). By default, GNU make will install into your DJGPP installation area. If you wish to use a different directory, override the DESTDIR variable when invoking "make install", like this: make install DESTDIR=c:/other/dir This causes the make executable to be placed in c:/other/dir/bin, the man pages in c:/other/dir/man, etc. Without a Unix-style shell, you will have to install programs and the docs manually. Copy make.exe to a directory on your PATH, make.i* info files to your Info directory, and update the file 'dir' in your Info directory by adding the following item to the main menu: * Make: (make.info). The GNU make utility. If you have the 'install-info' program (from the GNU Texinfo package), it will do that for you if you invoke it like this: install-info --info-dir=c:/djgpp/info c:/djgpp/info/make.info (If your Info directory is other than C:\DJGPP\INFO, change this command accordingly.) 7. The 'clean' targets also require Unix-style shell, and GNU Sed and 'rm' programs (the latter from Fileutils). 8. To run the test suite, type "make check". This requires a Unix shell (I used the DJGPP port of Bash 2.03), Perl, Sed, Fileutils and Sh-utils. Notes: ----- 1. The shell issue. This is probably the most significant improvement, first introduced in the port of GNU Make 3.75. The original behavior of GNU Make is to invoke commands directly, as long as they don't include characters special to the shell or internal shell commands, because that is faster. When shell features like redirection or filename wildcards are involved, Make calls the shell. This port supports both DOS shells (the stock COMMAND.COM and its 4DOS/NDOS replacements), and Unix-style shells (tested with the venerable Stewartson's 'ms_sh' 2.3 and the DJGPP port of 'bash' by Daisuke Aoyama ). When the $SHELL variable points to a Unix-style shell, Make works just like you'd expect on Unix, calling the shell for any command that involves characters special to the shell or internal shell commands. The only difference is that, since there is no standard way to pass command lines longer than the infamous DOS 126-character limit, this port of Make writes the command line to a temporary disk file and then invokes the shell on that file. If $SHELL points to a DOS-style shell, however, Make will not call it automatically, as it does with Unix shells. Stock COMMAND.COM is too dumb and would unnecessarily limit the functionality of Make. For example, you would not be able to use long command lines in commands that use redirection or pipes. Therefore, when presented with a DOS shell, this port of Make will emulate most of the shell functionality, like redirection and pipes, and shall only call the shell when a batch file or a command internal to the shell is invoked. (Even when a command is an internal shell command, Make will first search the $PATH for it, so that if a Makefile calls 'mkdir', you can install, say, a port of GNU 'mkdir' and have it called in that case.) The key to all this is the extended functionality of 'spawn' and 'system' functions from the DJGPP library; this port just calls 'system' where it would invoke the shell on Unix. The most important aspect of these functions is that they use a special mechanism to pass long (up to 16KB) command lines to DJGPP programs. In addition, 'system' emulates some internal commands, like 'cd' (so that you can now use forward slashes with it, and can also change the drive if the directory is on another drive). Another aspect worth mentioning is that you can call Unix shell scripts directly, provided that the shell whose name is mentioned on the first line of the script is installed anywhere along the $PATH. It is impossible to tell here everything about these functions; refer to the DJGPP library reference for more details. The $(shell) built-in is implemented in this port by calling 'popen'. Since 'popen' calls 'system', the above considerations are valid for $(shell) as well. In particular, you can put arbitrary complex commands, including pipes and redirection, inside $(shell), which is in many cases a valid substitute for the Unix-style command substitution (`command`) feature. 2. "SHELL=/bin/sh" -- or is it? Many Unix Makefiles include a line which sets the SHELL, for those versions of Make which don't have this as the default. Since many DOS systems don't have 'sh' installed (in fact, most of them don't even have a '/bin' directory), this port takes such directives with a grain of salt. It will only honor such a directive if the basename of the shell name (like 'sh' in the above example) can indeed be found in the directory that is mentioned in the SHELL= line ('/bin' in the above example), or in the current working directory, or anywhere on the $PATH (in that order). If the basename doesn't include a filename extension, Make will look for any known extension that indicates an executable file (.exe, .com, .bat, .btm, .sh, and even .sed and .pl). If any such file is found, then $SHELL will be defined to the exact pathname of that file, and that shell will hence be used for the rest of processing. But if the named shell is *not* found, the line which sets it will be effectively ignored, leaving the value of $SHELL as it was before. Since a lot of decisions that this port makes depend on the gender of the shell, I feel it doesn't make any sense to tailor Make's behavior to a shell which is nowhere to be found. Note that the above special handling of "SHELL=" only happens for Makefiles; if you set $SHELL in the environment or on the Make command line, you are expected to give the complete pathname of the shell, including the filename extension. The default value of $SHELL is computed as on Unix (see the Make manual for details), except that if $SHELL is not defined in the environment, $COMSPEC is used. Also, if an environment variable named $MAKESHELL is defined, it takes precedence over both $COMSPEC and $SHELL. Note that, unlike Unix, $SHELL in the environment *is* used to set the shell (since on MSDOS, it's unlikely that the interactive shell will not be suitable for Makefile processing). The bottom line is that you can now write Makefiles where some of the targets require a real (i.e. Unix-like) shell, which will nevertheless work when such shell is not available (provided, of course, that the commands which should always work, don't require such a shell). More important, you can convert Unix Makefiles to MSDOS and leave the line which sets the shell intact, so that people who do have Unixy shell could use it for targets which aren't converted to DOS (like 'install' and 'uninstall', for example). 3. Default directories. GNU Make knows about standard directories where it searches for library and include files mentioned in the Makefile. Since MSDOS machines don't have standard places for these, this port will search ${DJDIR}/lib and ${DJDIR}/include respectively. $DJDIR is defined automatically by the DJGPP startup code as the root of the DJGPP installation tree (unless you've tampered with the DJGPP.ENV file). This should provide reasonable default values, unless you moved parts of DJGPP to other directories. 4. Letter-case in filenames. If you run Make on Windows 9x, you should be aware of the letter-case issue. Make is internally case-sensitive, but all file operations are case-insensitive on Windows 9x, so e.g. files 'FAQ', 'faq' and 'Faq' all refer to the same file, as far as Windows is concerned. The underlying DJGPP C library functions honor the letter-case of the filenames they get from the OS, except that by default, they down-case 8+3 DOS filenames which are stored in upper case in the directory and would break many Makefiles otherwise. (The details of which filenames are converted to lower case are explained in the DJGPP libc docs, under the '_preserve_fncase' and '_lfn_gen_short_fname' functions, but as a thumb rule, any filename that is stored in upper case in the directory, is a valid DOS 8+3 filename and doesn't include characters invalid on MSDOS FAT filesystems, will be automatically down-cased.) User reports that I have indicate that this default behavior is generally what you'd expect; however, your input is most welcome. In any case, if you hit a situation where you must force Make to get the 8+3 DOS filenames in upper case, set FNCASE=y in the environment or in the Makefile. 5. DOS-style pathnames. There are a lot of places throughout the program sources which make implicit assumptions about the pathname syntax. In particular, the directories are assumed to be separated by '/', and any pathname which doesn't begin with a '/' is assumed to be relative to the current directory. This port attempts to support DOS-style pathnames which might include the drive letter and use backslashes instead of forward slashes. However, this support is not complete; I feel that pursuing this support too far might break some more important features, particularly if you use a Unix-style shell (where a backslash is a quote character). I only consider support of backslashes desirable because some Makefiles invoke non-DJGPP programs which don't understand forward slashes. A notable example of such programs is the standard programs which come with MSDOS. Otherwise, you are advised to stay away from backslashes whenever possible. In particular, filename globbing won't work on pathnames with backslashes, because the GNU 'glob' library doesn't support them (backslash is special in filename wildcards, and I didn't want to break that). One feature which *does* work with backslashes is the filename- related built-in functions such as $(dir), $(notdir), etc. Drive letters in pathnames are also fully supported. Bug reports: ----------- Bugs that are clearly related to the MSDOS/DJGPP port should be reported first on the comp.os.msdos.djgpp news group (if you cannot post to Usenet groups, write to the DJGPP mailing list, , which is an email gateway into the above news group). For other bugs, please follow the procedure explained in the "Bugs" chapter of the Info docs. If you don't have an Info reader, look up that chapter in the 'make.i1' file with any text browser/editor. Enjoy, Eli Zaretskii ------------------------------------------------------------------------------- Copyright (C) 1996-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make 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 . kbuild-3149/src/kmk/dep.h0000644000175000017500000001546713252530201015204 0ustar locutuslocutus/* Definitions of dependency data structures for GNU Make. Copyright (C) 1988-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make 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 . */ /* Structure used in chains of names, for parsing and globbing. */ #define NAMESEQ(_t) \ _t *next; \ const char *name struct nameseq { NAMESEQ (struct nameseq); }; /* Flag bits for the second argument to 'read_makefile'. These flags are saved in the 'flags' field of each 'struct goaldep' in the chain returned by 'read_all_makefiles'. */ #define RM_NO_DEFAULT_GOAL (1 << 0) /* Do not set default goal. */ #define RM_INCLUDED (1 << 1) /* Search makefile search path. */ #define RM_DONTCARE (1 << 2) /* No error if it doesn't exist. */ #define RM_NO_TILDE (1 << 3) /* Don't expand ~ in file name. */ #define RM_NOFLAG 0 /* Structure representing one dependency of a file. Each struct file's 'deps' points to a chain of these, through 'next'. 'stem' is the stem for this dep line of static pattern rule or NULL. */ #ifndef CONFIG_WITH_INCLUDEDEP #define DEP(_t) \ NAMESEQ (_t); \ struct file *file; \ const char *stem; \ unsigned short flags : 8; \ unsigned short changed : 1; \ unsigned short ignore_mtime : 1; \ unsigned short staticpattern : 1; \ unsigned short need_2nd_expansion : 1 #else # define DEP(_t) \ NAMESEQ (_t); \ struct file *file; \ const char *stem; \ unsigned short flags : 8; \ unsigned short changed : 1; \ unsigned short ignore_mtime : 1; \ unsigned short staticpattern : 1; \ unsigned short need_2nd_expansion : 1; \ unsigned short includedep : 1 #endif struct dep { DEP (struct dep); }; /* Structure representing one goal. The goals to be built constitute a chain of these, chained through 'next'. 'stem' is not used, but it's simpler to include and ignore it. */ struct goaldep { DEP (struct goaldep); unsigned short error; floc floc; }; /* Options for parsing lists of filenames. */ #define PARSEFS_NONE 0x0000 #define PARSEFS_NOSTRIP 0x0001 #define PARSEFS_NOAR 0x0002 #define PARSEFS_NOGLOB 0x0004 #define PARSEFS_EXISTS 0x0008 #define PARSEFS_NOCACHE 0x0010 #ifndef CONFIG_WITH_ALLOC_CACHES #define PARSE_FILE_SEQ(_s,_t,_c,_p,_f) \ (_t *)parse_file_seq ((_s),sizeof (_t),(_c),(_p),(_f)) #define PARSE_SIMPLE_SEQ(_s,_t) \ (_t *)parse_file_seq ((_s),sizeof (_t),MAP_NUL,NULL,PARSEFS_NONE) #else # define PARSE_FILE_SEQ(_s,_t,_c,_p,_f) \ (_t *)parse_file_seq ((_s),sizeof (_t),(_c),(_p),(_f), \ &PARSE_FILE_SEQ_IGNORE_ ## _t ## _cache) # define PARSE_SIMPLE_SEQ(_s,_t) \ (_t *)parse_file_seq ((_s),sizeof (_t),MAP_NUL,NULL,PARSEFS_NONE, \ &PARSE_FILE_SEQ_IGNORE_ ## _t ## _cache) # define PARSE_FILE_SEQ_IGNORE_struct #endif #ifdef VMS void *parse_file_seq (); #else void *parse_file_seq (char **stringp, unsigned int size, int stopmap, const char *prefix, int flags IF_WITH_ALLOC_CACHES_PARAM(struct alloccache *cache)); #endif char *tilde_expand (const char *name); #ifndef NO_ARCHIVES struct nameseq *ar_glob (const char *arname, const char *member_pattern, unsigned int size); #endif #define dep_name(d) ((d)->name ? (d)->name : (d)->file->name) #ifndef CONFIG_WITH_ALLOC_CACHES #define alloc_seq_elt(_t) xcalloc (sizeof (_t)) void free_ns_chain (struct nameseq *n); #if defined(MAKE_MAINTAINER_MODE) && defined(__GNUC__) /* Use inline to get real type-checking. */ #define SI static inline SI struct nameseq *alloc_ns() { return alloc_seq_elt (struct nameseq); } SI struct dep *alloc_dep() { return alloc_seq_elt (struct dep); } SI struct goaldep *alloc_goaldep() { return alloc_seq_elt (struct goaldep); } SI void free_ns(struct nameseq *n) { free (n); } SI void free_dep(struct dep *d) { free_ns ((struct nameseq *)d); } SI void free_goaldep(struct goaldep *g) { free_dep ((struct dep *)g); } SI void free_dep_chain(struct dep *d) { free_ns_chain((struct nameseq *)d); } SI void free_goal_chain(struct goaldep *g) { free_dep_chain((struct dep *)g); } #else # define alloc_ns() alloc_seq_elt (struct nameseq) # define alloc_dep() alloc_seq_elt (struct dep) # define alloc_goaldep() alloc_seq_elt (struct goaldep) # define free_ns(_n) free (_n) # define free_dep(_d) free_ns (_d) # define free_goaldep(_g) free_dep (_g) # define free_dep_chain(_d) free_ns_chain ((struct nameseq *)(_d)) # define free_goal_chain(_g) free_ns_chain ((struct nameseq *)(_g)) #endif #else /* CONFIG_WITH_ALLOC_CACHES */ # include K_INLINE struct nameseq *alloc_ns (void) { return (struct nameseq *)alloccache_calloc (&nameseq_cache); } K_INLINE void free_ns (struct nameseq *n) { alloccache_free (&nameseq_cache, n); } void free_ns_chain (struct nameseq *n); K_INLINE struct dep *alloc_dep (void) { return (struct dep *)alloccache_calloc (&dep_cache); } K_INLINE void free_dep (struct dep *d) { alloccache_free (&dep_cache, d); } void free_dep_chain (struct dep *d); K_INLINE struct goaldep *alloc_goaldep (void) { return (struct goaldep *)alloccache_calloc (&goaldep_cache); } K_INLINE void free_goaldep (struct goaldep *g) { alloccache_free (&goaldep_cache, g); } void free_goal_chain (struct goaldep *g); #endif /* CONFIG_WITH_ALLOC_CACHES */ struct dep *copy_dep_chain (const struct dep *d); struct goaldep *read_all_makefiles (const char **makefiles); void eval_buffer (char *buffer, const floc *floc IF_WITH_VALUE_LENGTH(COMMA char *eos)); enum update_status update_goal_chain (struct goaldep *goals); #ifdef CONFIG_WITH_INCLUDEDEP /* incdep.c */ enum incdep_op { incdep_read_it, incdep_queue, incdep_flush }; void eval_include_dep (const char *name, floc *f, enum incdep_op op); void incdep_flush_and_term (void); #endif kbuild-3149/src/kmk/build.template0000644000175000017500000000474513252530177017130 0ustar locutuslocutus#!/bin/sh # Shell script to build GNU Make in the absence of any 'make' program. # @configure_input@ # Copyright (C) 1993-2016 Free Software Foundation, Inc. # This file is part of GNU Make. # # GNU Make 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. # # GNU Make 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 . # See Makefile.in for comments describing these variables. srcdir='@srcdir@' CC='@CC@' CFLAGS='@CFLAGS@ @GUILE_CFLAGS@' CPPFLAGS='@CPPFLAGS@' LDFLAGS='@AM_LDFLAGS@ @LDFLAGS@' ALLOCA='@ALLOCA@' LOADLIBES='@LIBS@ @GUILE_LIBS@ @LIBINTL@' eval extras=\'@LIBOBJS@\' REMOTE='@REMOTE@' GLOBLIB='@GLOBLIB@' PATH_SEPARATOR='@PATH_SEPARATOR@' OBJEXT='@OBJEXT@' EXEEXT='@EXEEXT@' # Common prefix for machine-independent installed files. prefix='@prefix@' # Common prefix for machine-dependent installed files. exec_prefix=`eval echo @exec_prefix@` # Directory to find libraries in for '-lXXX'. libdir=${exec_prefix}/lib # Directory to search by default for included makefiles. includedir=${prefix}/include localedir=${prefix}/share/locale aliaspath=${localedir}${PATH_SEPARATOR}. defines="-DLOCALEDIR=\"${localedir}\" -DLIBDIR=\"${libdir}\" -DINCLUDEDIR=\"${includedir}\""' @DEFS@' # Exit as soon as any command fails. set -e # These are all the objects we need to link together. objs="%objs% remote-${REMOTE}.${OBJEXT} ${extras} ${ALLOCA}" if [ x"$GLOBLIB" != x ]; then objs="$objs %globobjs%" globinc=-I${srcdir}/glob fi # Compile the source files into those objects. for file in `echo ${objs} | sed 's/\.'${OBJEXT}'/.c/g'`; do echo compiling ${file}... $CC $defines $CPPFLAGS $CFLAGS \ -c -I. -I${srcdir} ${globinc} ${srcdir}/$file done # The object files were actually all put in the current directory. # Remove the source directory names from the list. srcobjs="$objs" objs= for obj in $srcobjs; do objs="$objs `basename $obj`" done # Link all the objects together. echo linking make... $CC $CFLAGS $LDFLAGS $objs $LOADLIBES -o makenew${EXEEXT} echo done mv -f makenew${EXEEXT} make${EXEEXT} kbuild-3149/src/kmk/testcase-math.kmk0000644000175000017500000000651613252530203017526 0ustar locutuslocutus# $Id: testcase-math.kmk 2413 2010-09-11 17:43:04Z bird $ ## @file # kBuild - testcase for the math functions. # # # Copyright (c) 2007-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # DEPTH = ../.. include $(PATH_KBUILD)/header.kmk ifneq ($(not 1),) $(error The 'not' function is missing) endif ifneq ($(eq 1,1),1) $(error The 'eq' function is missing) endif ASSERT_TRUE = $(if $(not $(1)),$(error failure: '$(1)' isn't true)) ASSERT_FALSE = $(if $(1) ,$(error failure: '$(1)' isn't false)) $(call ASSERT_TRUE, $(int-eq 0x0, 0)) $(call ASSERT_FALSE,$(int-eq 1, 0)) $(call ASSERT_FALSE,$(int-eq 1123123123, 9898787987)) $(call ASSERT_TRUE, $(int-eq 1234567890, 1234567890)) $(call ASSERT_TRUE, $(int-eq 0x1c, 28)) $(call ASSERT_TRUE, $(int-eq 1c, 28)) $(call ASSERT_TRUE, $(int-ne 0x123, -0x123)) $(call ASSERT_TRUE, $(int-ne 123, -0x123)) $(call ASSERT_FALSE,$(int-ne 0x100, 256)) $(call ASSERT_FALSE,$(int-ne 0x0, 0)) $(call ASSERT_FALSE,$(int-ne 0x1c, 28)) $(call ASSERT_TRUE, $(int-le 0, 0)) $(call ASSERT_TRUE, $(int-le -0, 0)) $(call ASSERT_FALSE,$(int-le 5, 1)) $(call ASSERT_FALSE,$(int-lt 5, 1)) $(call ASSERT_FALSE,$(int-lt 5, 5)) $(call ASSERT_TRUE, $(int-lt 9, 10)) $(call ASSERT_TRUE, $(int-lt -9, -8)) $(call ASSERT_TRUE, $(int-ge 0, 0)) $(call ASSERT_TRUE, $(int-ge -0, 0)) $(call ASSERT_TRUE, $(int-ge 1, 0)) $(call ASSERT_TRUE, $(int-ge -55, -55)) $(call ASSERT_TRUE, $(int-ge 512, 400)) $(call ASSERT_TRUE, $(int-ge -18, -19)) $(call ASSERT_FALSE,$(int-ge -19, -18)) $(call ASSERT_FALSE,$(int-ge 15, 20)) $(call ASSERT_FALSE,$(int-gt 15, 20)) $(call ASSERT_FALSE,$(int-gt 15, 15)) $(call ASSERT_TRUE, $(int-gt 20, 15)) ASSERT2 = $(if $(not $(int-eq $(1),$(2))),$(error failure: '$(1)' -ne '$(2)')) $(call ASSERT2,$(int-add 1, 1),0x2) $(call ASSERT2,$(int-add 1, 1, 1, 1, 1, 1, 1),7) $(call ASSERT2,$(int-add 1, -1),0) $(call ASSERT2,$(int-sub 1, -1),2) $(call ASSERT2,$(int-sub 1, 5),-4) $(call ASSERT2,$(int-mul 0x10, 0x20),0x200) $(call ASSERT2,$(int-mul 0x20, 0x10),0x200) $(call ASSERT2,$(int-mul 4, 7),28) $(call ASSERT2,$(int-mul 2, 2, 2, 2, 2, 4, 1, 1, 1, 1),128) $(call ASSERT2,$(int-div 0x1000, 0x100),0x10) $(call ASSERT2,$(int-div 999, 10),99) $(call ASSERT2,$(int-div 4096, 4,2,2,2,2),64) #$(call ASSERT2,$(int-div 0x1230023213, 0),0x0) $(call ASSERT2,$(int-mod 19, 10),9) $(call ASSERT2,$(int-mod 9, 10),9) $(call ASSERT2,$(int-mod 30, 10),0) $(call ASSERT2,$(int-not 0),-1) $(call ASSERT2,$(int-and 1, 1),1) $(call ASSERT2,$(int-and 0x123123214, 0xfff),0x214) $(call ASSERT2,$(int-and 0x123123214, 0xf0f, 0xf),4) $(call ASSERT2,$(int-or 1, 1, 1, 2, 2),3) $(call ASSERT2,$(int-xor 1, 1, 2, 2),0) $(call ASSERT2,$(int-xor 1, 2, 4),7) all_recursive: $(ECHO) The math works. 6 * 7 = $(int-mul 6,7) kbuild-3149/src/kmk/strcache.c0000644000175000017500000002410213252530202016206 0ustar locutuslocutus/* Constant string caching for GNU Make. Copyright (C) 2006-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" #ifndef CONFIG_WITH_STRCACHE2 #include #include #include "hash.h" /* A string cached here will never be freed, so we don't need to worry about reference counting. We just store the string, and then remember it in a hash so it can be looked up again. */ typedef unsigned short int sc_buflen_t; struct strcache { struct strcache *next; /* The next block of strings. Must be first! */ sc_buflen_t end; /* Offset to the beginning of free space. */ sc_buflen_t bytesfree; /* Free space left in this buffer. */ sc_buflen_t count; /* # of strings in this buffer (for stats). */ char buffer[1]; /* The buffer comes after this. */ }; /* The size (in bytes) of each cache buffer. Try to pick something that will map well into the heap. This must be able to be represented by a short int (<=65535). */ #define CACHE_BUFFER_BASE (8192) #define CACHE_BUFFER_ALLOC(_s) ((_s) - (2 * sizeof (size_t))) #define CACHE_BUFFER_OFFSET (offsetof (struct strcache, buffer)) #define CACHE_BUFFER_SIZE(_s) (CACHE_BUFFER_ALLOC(_s) - CACHE_BUFFER_OFFSET) #define BUFSIZE CACHE_BUFFER_SIZE (CACHE_BUFFER_BASE) static struct strcache *strcache = NULL; static struct strcache *fullcache = NULL; static unsigned long total_buffers = 0; static unsigned long total_strings = 0; static unsigned long total_size = 0; /* Add a new buffer to the cache. Add it at the front to reduce search time. This can also increase the overhead, since it's less likely that older buffers will be filled in. However, GNU make has so many smaller strings that this doesn't seem to be much of an issue in practice. */ static struct strcache * new_cache (struct strcache **head, sc_buflen_t buflen) { struct strcache *new = xmalloc (buflen + CACHE_BUFFER_OFFSET); new->end = 0; new->count = 0; new->bytesfree = buflen; new->next = *head; *head = new; ++total_buffers; return new; } static const char * copy_string (struct strcache *sp, const char *str, unsigned int len) { /* Add the string to this cache. */ char *res = &sp->buffer[sp->end]; memmove (res, str, len); res[len++] = '\0'; sp->end += len; sp->bytesfree -= len; ++sp->count; return res; } static const char * add_string (const char *str, unsigned int len) { const char *res; struct strcache *sp; struct strcache **spp = &strcache; /* We need space for the nul char. */ unsigned int sz = len + 1; ++total_strings; total_size += sz; /* If the string we want is too large to fit into a single buffer, then no existing cache is large enough. Add it directly to the fullcache. */ if (sz > BUFSIZE) { sp = new_cache (&fullcache, sz); return copy_string (sp, str, len); } /* Find the first cache with enough free space. */ for (; *spp != NULL; spp = &(*spp)->next) if ((*spp)->bytesfree > sz) break; sp = *spp; /* If nothing is big enough, make a new cache at the front. */ if (sp == NULL) { sp = new_cache (&strcache, BUFSIZE); spp = &strcache; } /* Add the string to this cache. */ res = copy_string (sp, str, len); /* If the amount free in this cache is less than the average string size, consider it full and move it to the full list. */ if (total_strings > 20 && sp->bytesfree < (total_size / total_strings) + 1) { *spp = sp->next; sp->next = fullcache; fullcache = sp; } return res; } /* For strings too large for the strcache, we just save them in a list. */ struct hugestring { struct hugestring *next; /* The next string. */ char buffer[1]; /* The string. */ }; static struct hugestring *hugestrings = NULL; static const char * add_hugestring (const char *str, unsigned int len) { struct hugestring *new = xmalloc (sizeof (struct hugestring) + len); memcpy (new->buffer, str, len); new->buffer[len] = '\0'; new->next = hugestrings; hugestrings = new; return new->buffer; } /* Hash table of strings in the cache. */ static unsigned long str_hash_1 (const void *key) { return_ISTRING_HASH_1 ((const char *) key); } static unsigned long str_hash_2 (const void *key) { return_ISTRING_HASH_2 ((const char *) key); } static int str_hash_cmp (const void *x, const void *y) { return_ISTRING_COMPARE ((const char *) x, (const char *) y); } static struct hash_table strings; static unsigned long total_adds = 0; static const char * add_hash (const char *str, unsigned int len) { char *const *slot; const char *key; /* If it's too large for the string cache, just copy it. We don't bother trying to match these. */ if (len > USHRT_MAX - 1) return add_hugestring (str, len); /* Look up the string in the hash. If it's there, return it. */ slot = (char *const *) hash_find_slot (&strings, str); key = *slot; /* Count the total number of add operations we performed. */ ++total_adds; if (!HASH_VACANT (key)) return key; /* Not there yet so add it to a buffer, then into the hash table. */ key = add_string (str, len); hash_insert_at (&strings, key, slot); return key; } /* Returns true if the string is in the cache; false if not. */ int strcache_iscached (const char *str) { struct strcache *sp; for (sp = strcache; sp != 0; sp = sp->next) if (str >= sp->buffer && str < sp->buffer + sp->end) return 1; for (sp = fullcache; sp != 0; sp = sp->next) if (str >= sp->buffer && str < sp->buffer + sp->end) return 1; { struct hugestring *hp; for (hp = hugestrings; hp != 0; hp = hp->next) if (str == hp->buffer) return 1; } return 0; } /* If the string is already in the cache, return a pointer to the cached version. If not, add it then return a pointer to the cached version. Note we do NOT take control of the string passed in. */ const char * strcache_add (const char *str) { return add_hash (str, strlen (str)); } const char * strcache_add_len (const char *str, unsigned int len) { /* If we're not given a nul-terminated string we have to create one, because the hashing functions expect it. */ if (str[len] != '\0') { char *key = alloca (len + 1); memcpy (key, str, len); key[len] = '\0'; str = key; } return add_hash (str, len); } void strcache_init (void) { hash_init (&strings, 8000, str_hash_1, str_hash_2, str_hash_cmp); } /* Generate some stats output. */ void strcache_print_stats (const char *prefix) { const struct strcache *sp; unsigned long numbuffs = 0, fullbuffs = 0; unsigned long totfree = 0, maxfree = 0, minfree = BUFSIZE; if (! strcache) { printf (_("\n%s No strcache buffers\n"), prefix); return; } /* Count the first buffer separately since it's not full. */ for (sp = strcache->next; sp != NULL; sp = sp->next) { sc_buflen_t bf = sp->bytesfree; totfree += bf; maxfree = (bf > maxfree ? bf : maxfree); minfree = (bf < minfree ? bf : minfree); ++numbuffs; } for (sp = fullcache; sp != NULL; sp = sp->next) { sc_buflen_t bf = sp->bytesfree; totfree += bf; maxfree = (bf > maxfree ? bf : maxfree); minfree = (bf < minfree ? bf : minfree); ++numbuffs; ++fullbuffs; } /* Make sure we didn't lose any buffers. */ assert (total_buffers == numbuffs + 1); printf (_("\n%s strcache buffers: %lu (%lu) / strings = %lu / storage = %lu B / avg = %lu B\n"), prefix, numbuffs + 1, fullbuffs, total_strings, total_size, (total_size / total_strings)); printf (_("%s current buf: size = %hu B / used = %hu B / count = %hu / avg = %hu B\n"), prefix, (sc_buflen_t)BUFSIZE, strcache->end, strcache->count, (strcache->end / strcache->count)); if (numbuffs) { /* Show information about non-current buffers. */ unsigned long sz = total_size - strcache->end; unsigned long cnt = total_strings - strcache->count; sc_buflen_t avgfree = totfree / numbuffs; printf (_("%s other used: total = %lu B / count = %lu / avg = %lu B\n"), prefix, sz, cnt, sz / cnt); printf (_("%s other free: total = %lu B / max = %lu B / min = %lu B / avg = %hu B\n"), prefix, totfree, maxfree, minfree, avgfree); } printf (_("\n%s strcache performance: lookups = %lu / hit rate = %lu%%\n"), prefix, total_adds, (long unsigned)(100.0 * (total_adds - total_strings) / total_adds)); fputs (_("# hash-table stats:\n# "), stdout); hash_print_stats (&strings, stdout); } #else /* CONFIG_WITH_STRCACHE2 */ #include "strcache2.h" const char *suffixes_strcached; /* The file string cache. */ struct strcache2 file_strcache; void strcache_init (void) { strcache2_init(&file_strcache, "file", /* name */ 131072, /* hash size */ 0, /* default segment size*/ #ifdef HAVE_CASE_INSENSITIVE_FS 1, /* case insensitive */ #else 0, /* case insensitive */ #endif 0); /* thread safe */ /* .SUFFIXES is referenced in several loops, keep the added pointer in a global var so these can be optimized. */ suffixes_strcached = strcache_add_len (".SUFFIXES", sizeof (".SUFFIXES")-1); } void strcache_print_stats (const char *prefix) { strcache2_print_stats (&file_strcache, prefix); } #endif /* CONFIG_WITH_STRCACHE2 */ kbuild-3149/src/kmk/kmkbuiltin.h0000644000175000017500000001041013252530203016566 0ustar locutuslocutus/* $Id: kmkbuiltin.h 3108 2017-10-20 17:01:40Z bird $ */ /** @file * kMk Builtin command handling. */ /* * Copyright (c) 2005-2016 knut st. osmundsen * * This file is part of kBuild. * * kBuild 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. * * kBuild 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 kBuild. If not, see * */ #ifndef ___kmk_kmkbuiltin_h___ #define ___kmk_kmkbuiltin_h___ #ifdef _MSC_VER # ifndef pid_t /* see config.h.win */ # define pid_t intptr_t /* Note! sub_proc.c needs it to be pointer sized. */ # endif #else # include #endif /* For the GNU/hurd weirdo. */ #ifndef PATH_MAX # ifdef MAXPATHLEN # define PATH_MAX MAXPATHLEN # else # define PATH_MAX 4096 # endif #endif #ifndef MAXPATHLEN # define MAXPATHLEN PATH_MAX #endif #include "kbuild_version.h" struct child; int kmk_builtin_command(const char *pszCmd, struct child *pChild, char ***ppapszArgvToSpawn, pid_t *pPidSpawned); int kmk_builtin_command_parsed(int argc, char **argv, struct child *pChild, char ***ppapszArgvToSpawn, pid_t *pPidSpawned); extern int kmk_builtin_append(int argc, char **argv, char **envp); extern int kmk_builtin_cp(int argc, char **argv, char **envp); extern int kmk_builtin_cat(int argc, char **argv, char **envp); extern int kmk_builtin_chmod(int argc, char **argv, char **envp); extern int kmk_builtin_cmp(int argc, char **argv, char **envp); extern int kmk_builtin_dircache(int argc, char **argv, char **envp); extern int kmk_builtin_echo(int argc, char **argv, char **envp); extern int kmk_builtin_expr(int argc, char **argv, char **envp); extern int kmk_builtin_install(int argc, char **argv, char **envp); extern int kmk_builtin_ln(int argc, char **argv, char **envp); extern int kmk_builtin_md5sum(int argc, char **argv, char **envp); extern int kmk_builtin_mkdir(int argc, char **argv, char **envp); extern int kmk_builtin_mv(int argc, char **argv, char **envp); extern int kmk_builtin_printf(int argc, char **argv, char **envp); extern int kmk_builtin_redirect(int argc, char **argv, char **envp, struct child *pChild, pid_t *pPidSpawned); extern int kmk_builtin_rm(int argc, char **argv, char **envp); extern int kmk_builtin_rmdir(int argc, char **argv, char **envp); extern int kmk_builtin_sleep(int argc, char **argv, char **envp); extern int kmk_builtin_test(int argc, char **argv, char **envp #ifndef kmk_builtin_test , char ***ppapszArgvSpawn #endif ); extern int kmk_builtin_touch(int argc, char **argv, char **envp); #ifdef KBUILD_OS_WINDOWS extern int kmk_builtin_kSubmit(int argc, char **argv, char **envp, struct child *pChild, pid_t *pPidSpawned); extern int kSubmitSubProcGetResult(intptr_t pvUser, int *prcExit, int *piSigNo); extern int kSubmitSubProcKill(intptr_t pvUser, int iSignal); extern void kSubmitSubProcCleanup(intptr_t pvUser); #endif extern int kmk_builtin_kDepIDB(int argc, char **argv, char **envp); extern int kmk_builtin_kDepObj(int argc, char **argv, char **envp); extern char *kmk_builtin_func_printf(char *o, char **argv, const char *funcname); /* common-env-and-cwd-opt.c: */ extern int kBuiltinOptEnvSet(char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars, int cVerbosity, const char *pszValue); extern int kBuiltinOptEnvAppend(char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars, int cVerbosity, const char *pszValue); extern int kBuiltinOptEnvPrepend(char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars, int cVerbosity, const char *pszValue); extern int kBuiltinOptEnvUnset(char **papszEnv, unsigned *pcEnvVars, int cVerbosity, const char *pszVarToRemove); extern int kBuiltinOptChDir(char *pszCwd, size_t cbCwdBuf, const char *pszValue); #endif kbuild-3149/src/kmk/vms_export_symbol_test.com0000644000175000017500000000165113252530202021604 0ustar locutuslocutus$! VMS_EXPORT_SYMBOL_TEST.COM $! $! Verify the VMS_EXPORT_SYMBOL.C module $! $! 22-May-2014 J. Malmberg $! $!========================================================================= $! $ cc/names=(as_is)/define=(DEBUG=1,_POSIX_EXIT=1) vms_export_symbol.c $! $ link vms_export_symbol $! $ delete vms_export_symbol.obj;* $! $! Need a foreign command to test. $ vms_export_symbol := $sys$disk:[]vms_export_symbol.exe $ save_export_symbol = vms_export_symbol $! $ vms_export_symbol $ if $severity .ne. 1 $ then $ write sys$output "Test program failed!"; $ endif $! $ if vms_export_symbol .nes. save_export_symbol $ then $ write sys$output "Test failed to restore foreign command!" $ endif $ if f$type(test_export_symbol) .nes. "" $ then $ write sys$output "Test failed to clear exported symbol!" $ endif $ if f$type(test_putenv_symbol) .nes. "" $ then $ write sys$output "Test failed to clear putenv exported symbol!" $ endif $! kbuild-3149/src/kmk/strcache2.h0000644000175000017500000001556213252530203016310 0ustar locutuslocutus/* $Id: strcache2.h 2413 2010-09-11 17:43:04Z bird $ */ /** @file * strcache - New string cache. */ /* * Copyright (c) 2006-2010 knut st. osmundsen * * This file is part of kBuild. * * kBuild 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. * * kBuild 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 kBuild. If not, see * */ #ifndef ___strcache2_h #define ___strcache2_h #ifndef CHAR_BIT # error "include after make.h!" #endif #define STRCACHE2_USE_MASK 1 /* string cache memory segment. */ struct strcache2_seg { struct strcache2_seg *next; /* The next cache segment. */ char *start; /* The first byte in the segment. */ size_t size; /* The size of the segment. */ size_t avail; /* The number of available bytes. */ char *cursor; /* Allocation cursor. */ }; /* string cache hash table entry. */ struct strcache2_entry { struct strcache2_entry *next; /* Collision chain. */ void *user; unsigned int hash; unsigned int length; }; /* The entry alignment, cacheline size if it's known & sensible. On x86/AMD64 we assume a 64-byte cacheline size. As it is difficult to guess other right now, these default 16 chars as that shouldn't cause much trouble, even if it not the most optimial value. Override, or modify for other platforms. */ #ifndef STRCACHE2_ENTRY_ALIGN_SHIFT # if defined (__i386__) || defined(__x86_64__) # define STRCACHE2_ENTRY_ALIGN_SHIFT 6 # else # define STRCACHE2_ENTRY_ALIGN_SHIFT 4 # endif #endif #define STRCACHE2_ENTRY_ALIGNMENT (1 << STRCACHE2_ENTRY_ALIGN_SHIFT) struct strcache2 { struct strcache2_entry **hash_tab; /* The hash table. */ int case_insensitive; /* case insensitive or not. */ #ifdef STRCACHE2_USE_MASK unsigned int hash_mask; /* The AND mask matching hash_size.*/ #else unsigned int hash_div; /* The number (prime) to mod by. */ #endif unsigned long lookup_count; /* The number of lookups. */ unsigned long collision_1st_count; /* The number of 1st level collisions. */ unsigned long collision_2nd_count; /* The number of 2nd level collisions. */ unsigned long collision_3rd_count; /* The number of 3rd level collisions. */ unsigned int count; /* Number entries in the cache. */ unsigned int collision_count; /* Number of entries in chains. */ unsigned int rehash_count; /* When to rehash the table. */ unsigned int init_size; /* The initial hash table size. */ unsigned int hash_size; /* The hash table size. */ unsigned int def_seg_size; /* The default segment size. */ void *lock; /* The lock handle. */ struct strcache2_seg *seg_head; /* The memory segment list. */ struct strcache2 *next; /* The next string cache. */ const char *name; /* Cache name. */ }; void strcache2_init (struct strcache2 *cache, const char *name, unsigned int size, unsigned int def_seg_size, int case_insensitive, int thread_safe); void strcache2_term (struct strcache2 *cache); void strcache2_print_stats (struct strcache2 *cache, const char *prefix); void strcache2_print_stats_all (const char *prefix); const char *strcache2_add (struct strcache2 *cache, const char *str, unsigned int length); const char *strcache2_iadd (struct strcache2 *cache, const char *str, unsigned int length); const char *strcache2_add_hashed (struct strcache2 *cache, const char *str, unsigned int length, unsigned int hash); const char *strcache2_iadd_hashed (struct strcache2 *cache, const char *str, unsigned int length, unsigned int hash); const char *strcache2_lookup (struct strcache2 *cache, const char *str, unsigned int length); const char *strcache2_ilookup (struct strcache2 *cache, const char *str, unsigned int length); #ifdef HAVE_CASE_INSENSITIVE_FS # define strcache2_add_file strcache2_iadd # define strcache2_add_hashed_file strcache2_iadd_hashed # define strcache2_lookup_file strcache2_ilookup #else # define strcache2_add_file strcache2_add # define strcache2_add_hashed_file strcache2_add_hashed # define strcache2_lookup_file strcache2_lookup #endif int strcache2_is_cached (struct strcache2 *cache, const char *str); int strcache2_verify_entry (struct strcache2 *cache, const char *str); unsigned int strcache2_get_hash2_fallback (struct strcache2 *cache, const char *str); unsigned int strcache2_hash_str (const char *str, unsigned int length, unsigned int *hash2p); unsigned int strcache2_hash_istr (const char *str, unsigned int length, unsigned int *hash2p); /* Get the hash table entry pointer. */ MY_INLINE struct strcache2_entry const * strcache2_get_entry (struct strcache2 *cache, const char *str) { #ifndef NDEBUG strcache2_verify_entry (cache, str); #endif return (struct strcache2_entry const *)str - 1; } /* Get the string length. */ MY_INLINE unsigned int strcache2_get_len (struct strcache2 *cache, const char *str) { return strcache2_get_entry (cache, str)->length; } /* Get the first hash value for the string. */ MY_INLINE unsigned int strcache2_get_hash (struct strcache2 *cache, const char *str) { return strcache2_get_entry (cache, str)->hash; } /* Calc the pointer hash value for the string. This takes the string address, shift out the bits that are always zero due to alignment, and then returns the unsigned integer value of it. The results from using this is generally better than for any of the other hash values. It is also sligtly faster code as it does not involve any memory accesses, just a right SHIFT and an optional AND. */ MY_INLINE unsigned int strcache2_calc_ptr_hash (struct strcache2 *cache, const char *str) { (void)cache; return (size_t)str >> STRCACHE2_ENTRY_ALIGN_SHIFT; } /* Get the user value for the string. */ MY_INLINE void * strcache2_get_user_val (struct strcache2 *cache, const char *str) { return strcache2_get_entry (cache, str)->user; } /* Get the user value for the string. */ MY_INLINE void strcache2_set_user_val (struct strcache2 *cache, const char *str, void *value) { struct strcache2_entry *entry = (struct strcache2_entry *)str - 1; #ifndef NDEBUG strcache2_verify_entry (cache, str); #endif entry->user = value; } #endif kbuild-3149/src/kmk/testcase-local.kmk0000644000175000017500000000552213252530204017664 0ustar locutuslocutus# # local variables: # o The keyword will make sure the variable is defined in # current variable context instead of the global one. # o Local variables are readable by children but not writable, # writes goes to the globle space (a sideeffect / feature). # o Local variables hides global and parent variables. # # global variable. var_exists1 = 1 ## # A simple define that is $(eval)uated. define def_test1 # check that the existing variable is accessible. ifneq ($(var_exists1),1) $(error var_exists1=$(var_exists1) (def_test1/1)) endif # Quick check with a couple of local variables. local var_local1 = 2 ifneq ($(var_local1),2) $(error var_local1=$(var_local1) (def_test1/2)) endif local var_local2 = 3 ifneq ($(var_local2),3) $(error var_local2=$(var_local2) (def_test1/3)) endif # var_local1 and var_local2 should remain unchanged, var_local3 shouldn't exist. $(evalctx $(value def_test2)) ifneq ($(var_local1),2) $(error var_local1=$(var_local1) (def_test1/4)) endif ifneq ($(var_local2),3) $(error var_local2=$(var_local2) (def_test1/5)) endif ifneq ($(var_local3),) $(error var_local3=$(var_local3) (def_test1/6)) endif endef # def_test1 ## # Called by def_test1, this checks that the locals of def_test1 # are accessible and can be hidden by another local variable # or updated if assigned to. define def_test2 # check that the existing variables are accessible, including the def_test1 ones. ifneq ($(var_exists1),1) $(error var_exists1=$(var_exists1) (def_test2/1)) endif ifneq ($(var_local1),2) $(error var_local1=$(var_local1) (def_test2/2)) endif ifneq ($(var_local2),3) $(error var_local2=$(var_local2) (def_test2/3)) endif # Make a local var_local1 that hides the one in def_test1. local var_local1 = 20 ifneq ($(var_local1),20) $(error var_local1=$(var_local1) (def_test2/4)) endif # FEATURE: Update the var_local2 variable, this should be visible in the global space and not the local. var_local2 = 30 ifneq ($(var_local2),3) $(error var_local2=$(var_local2) (def_test2/5)) endif # create a new local variable that isn't accessible from def_test1. local var_local3 = 4 ifneq ($(var_local3),4) $(error var_local3=$(var_local3) (def_test2/6)) endif endef # def_test2 # # The test body # # None of the local variables should exist. ifneq ($(var_local1),) $(error var_local1=$(var_local1)) endif ifneq ($(var_local2),) $(error var_local2=$(var_local2)) endif ifneq ($(var_local3),) $(error var_local3=$(var_local3)) endif # Evaluate the function in a local context. $(evalctx $(value def_test1)) # FEATURE: see var_local2 = 30 in def_test2. ifneq ($(var_local2),30) $(error var_local2=$(var_local2)) endif # None of the other local variables should exist. ifneq ($(var_local1),) $(error var_local1=$(var_local1)) endif ifneq ($(var_local3),) $(error var_local3=$(var_local3)) endif # dummy all: echo local variables works. kbuild-3149/src/kmk/gnumake.h0000644000175000017500000000554013252530201016052 0ustar locutuslocutus/* External interfaces usable by dynamic objects loaded into GNU Make. --THIS API IS A "TECHNOLOGY PREVIEW" ONLY. IT IS NOT A STABLE INTERFACE-- Copyright (C) 2013-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make 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 . */ #ifndef _GNUMAKE_H_ #define _GNUMAKE_H_ /* Specify the location of elements read from makefiles. */ typedef struct { const char *filenm; unsigned long lineno; } gmk_floc; typedef char *(*gmk_func_ptr)(const char *nm, unsigned int argc, char **argv); #ifdef _WIN32 # ifdef GMK_BUILDING_MAKE # define GMK_EXPORT __declspec(dllexport) # else # define GMK_EXPORT __declspec(dllimport) # endif #else # define GMK_EXPORT #endif /* Free memory returned by the gmk_expand() function. */ GMK_EXPORT void gmk_free (char *str); /* Allocate memory in GNU make's context. */ GMK_EXPORT char *gmk_alloc (unsigned int len); /* Run $(eval ...) on the provided string BUFFER. */ GMK_EXPORT void gmk_eval (const char *buffer, const gmk_floc *floc); /* Run GNU make expansion on the provided string STR. Returns an allocated buffer that the caller must free with gmk_free(). */ GMK_EXPORT char *gmk_expand (const char *str); /* Register a new GNU make function NAME (maximum of 255 chars long). When the function is expanded in the makefile, FUNC will be invoked with the appropriate arguments. The return value of FUNC must be either NULL, in which case it expands to the empty string, or a pointer to the result of the expansion in a string created by gmk_alloc(). GNU make will free the memory when it's done. MIN_ARGS is the minimum number of arguments the function requires. MAX_ARGS is the maximum number of arguments (or 0 if there's no maximum). MIN_ARGS and MAX_ARGS may not exceed 255. The FLAGS value may be GMK_FUNC_DEFAULT, or one or more of the following flags OR'd together: GMK_FUNC_NOEXPAND: the arguments to the function will be not be expanded before FUNC is called. */ GMK_EXPORT void gmk_add_function (const char *name, gmk_func_ptr func, unsigned int min_args, unsigned int max_args, unsigned int flags); #define GMK_FUNC_DEFAULT 0x00 #define GMK_FUNC_NOEXPAND 0x01 #endif /* _GNUMAKE_H_ */ kbuild-3149/src/kmk/acinclude.m40000644000175000017500000001157213252530177016461 0ustar locutuslocutusdnl acinclude.m4 -- Extra macros needed for GNU make. dnl dnl Automake will incorporate this into its generated aclocal.m4. dnl Copyright (C) 1998-2016 Free Software Foundation, Inc. dnl This file is part of GNU Make. dnl dnl GNU Make is free software; you can redistribute it and/or modify it under dnl the terms of the GNU General Public License as published by the Free dnl Software Foundation; either version 3 of the License, or (at your option) dnl any later version. dnl dnl GNU Make is distributed in the hope that it will be useful, but WITHOUT dnl ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or dnl FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for. dnl more details. dnl dnl You should have received a copy of the GNU General Public License along dnl with this program. If not, see . dnl --------------------------------------------------------------------------- dnl Got this from the lynx 2.8 distribution. dnl by T.E.Dickey dnl and Jim Spath dnl and Philippe De Muyter dnl dnl Created: 1997/1/28 dnl Updated: 1997/12/23 dnl --------------------------------------------------------------------------- dnl After checking for functions in the default $LIBS, make a further check dnl for the functions that are netlib-related (these aren't always in the dnl libc, etc., and have to be handled specially because there are conflicting dnl and broken implementations. dnl Common library requirements (in order): dnl -lresolv -lsocket -lnsl dnl -lnsl -lsocket dnl -lsocket dnl -lbsd AC_DEFUN([CF_NETLIBS],[ cf_test_netlibs=no AC_MSG_CHECKING(for network libraries) AC_CACHE_VAL(cf_cv_netlibs,[ AC_MSG_RESULT(working...) cf_cv_netlibs="" cf_test_netlibs=yes AC_CHECK_FUNCS(gethostname,,[ CF_RECHECK_FUNC(gethostname,nsl,cf_cv_netlibs,[ CF_RECHECK_FUNC(gethostname,socket,cf_cv_netlibs)])]) # # FIXME: sequent needs this library (i.e., -lsocket -linet -lnsl), but # I don't know the entrypoints - 97/7/22 TD AC_CHECK_LIB(inet,main,cf_cv_netlibs="-linet $cf_cv_netlibs") # if test "$ac_cv_func_lsocket" != no ; then AC_CHECK_FUNCS(socket,,[ CF_RECHECK_FUNC(socket,socket,cf_cv_netlibs,[ CF_RECHECK_FUNC(socket,bsd,cf_cv_netlibs)])]) fi # AC_CHECK_FUNCS(gethostbyname,,[ CF_RECHECK_FUNC(gethostbyname,nsl,cf_cv_netlibs)]) ]) LIBS="$LIBS $cf_cv_netlibs" test $cf_test_netlibs = no && echo "$cf_cv_netlibs" >&AC_FD_MSG ])dnl dnl --------------------------------------------------------------------------- dnl Re-check on a function to see if we can pick it up by adding a library. dnl $1 = function to check dnl $2 = library to check in dnl $3 = environment to update (e.g., $LIBS) dnl $4 = what to do if this fails dnl dnl This uses 'unset' if the shell happens to support it, but leaves the dnl configuration variable set to 'unknown' if not. This is a little better dnl than the normal autoconf test, which gives misleading results if a test dnl for the function is made (e.g., with AC_CHECK_FUNC) after this macro is dnl used (autoconf does not distinguish between a null token and one that is dnl set to 'no'). AC_DEFUN([CF_RECHECK_FUNC],[ AC_CHECK_LIB($2,$1,[ CF_UPPER(cf_tr_func,$1) AC_DEFINE_UNQUOTED(HAVE_$cf_tr_func,1,[Define if you have function $1]) ac_cv_func_$1=yes $3="-l$2 [$]$3"],[ ac_cv_func_$1=unknown unset ac_cv_func_$1 2>/dev/null $4], [[$]$3]) ])dnl dnl --------------------------------------------------------------------------- dnl Make an uppercase version of a variable dnl $1=uppercase($2) AC_DEFUN([CF_UPPER], [ changequote(,)dnl $1=`echo $2 | tr '[a-z]' '[A-Z]'` changequote([,])dnl ])dnl dnl --------------------------------------------------------------------------- dnl From Paul Eggert dnl Update for Darwin by Troy Runkel dnl Update for AIX by Olexiy Buyanskyy (Savannah bug 32485) AC_DEFUN([AC_STRUCT_ST_MTIM_NSEC], [AC_CACHE_CHECK([for nanoseconds field of struct stat], ac_cv_struct_st_mtim_nsec, [ac_save_CPPFLAGS="$CPPFLAGS" ac_cv_struct_st_mtim_nsec=no # st_mtim.tv_nsec -- the usual case # st_mtim._tv_nsec -- Solaris 2.6, if # (defined _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED == 1 # && !defined __EXTENSIONS__) # st_mtim.st__tim.tv_nsec -- UnixWare 2.1.2 # st_mtime_n -- AIX 5.2 and above # st_mtimespec.tv_nsec -- Darwin (Mac OSX) for ac_val in st_mtim.tv_nsec st_mtim._tv_nsec st_mtim.st__tim.tv_nsec st_mtime_n st_mtimespec.tv_nsec; do CPPFLAGS="$ac_save_CPPFLAGS -DST_MTIM_NSEC=$ac_val" AC_TRY_COMPILE([#include #include ], [struct stat s; s.ST_MTIM_NSEC;], [ac_cv_struct_st_mtim_nsec=$ac_val; break]) done CPPFLAGS="$ac_save_CPPFLAGS" ]) if test $ac_cv_struct_st_mtim_nsec != no; then AC_DEFINE_UNQUOTED([ST_MTIM_NSEC], [$ac_cv_struct_st_mtim_nsec], [Define if struct stat contains a nanoseconds field]) fi ] ) kbuild-3149/src/kmk/job.h0000644000175000017500000001241013252530202015170 0ustar locutuslocutus/* Definitions for managing subprocesses in GNU Make. Copyright (C) 1992-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "output.h" #ifdef HAVE_FCNTL_H # include #else # include #endif /* How to set close-on-exec for a file descriptor. */ #if !defined(F_SETFD) || !defined(F_GETFD) # ifdef WINDOWS32 # define CLOSE_ON_EXEC(_d) process_noinherit(_d) # else # define CLOSE_ON_EXEC(_d) # endif #else # ifndef FD_CLOEXEC # define FD_CLOEXEC 1 # endif # define CLOSE_ON_EXEC(_d) (void) fcntl ((_d), F_SETFD, FD_CLOEXEC) #endif #ifdef NO_OUTPUT_SYNC # define RECORD_SYNC_MUTEX(m) \ O (error, NILF, \ _("-O[TYPE] (--output-sync[=TYPE]) is not configured for this build.")); #else # ifdef WINDOWS32 /* For emulations in w32/compat/posixfcn.c. */ # define F_GETFD 1 # define F_SETLKW 2 /* Implementation note: None of the values of l_type below can be zero -- they are compared with a static instance of the struct, so zero means unknown/invalid, see w32/compat/posixfcn.c. */ # define F_WRLCK 1 # define F_UNLCK 2 struct flock { short l_type; short l_whence; off_t l_start; off_t l_len; pid_t l_pid; }; /* This type is actually a HANDLE, but we want to avoid including windows.h as much as possible. */ typedef intptr_t sync_handle_t; /* Public functions emulated/provided in posixfcn.c. */ int fcntl (intptr_t fd, int cmd, ...); intptr_t create_mutex (void); int same_stream (FILE *f1, FILE *f2); # define RECORD_SYNC_MUTEX(m) record_sync_mutex(m) void record_sync_mutex (const char *str); void prepare_mutex_handle_string (intptr_t hdl); # else /* !WINDOWS32 */ typedef int sync_handle_t; /* file descriptor */ # define RECORD_SYNC_MUTEX(m) (void)(m) # endif #endif /* !NO_OUTPUT_SYNC */ /* Structure describing a running or dead child process. */ struct child { struct child *next; /* Link in the chain. */ struct file *file; /* File being remade. */ char **environment; /* Environment for commands. */ char *sh_batch_file; /* Script file for shell commands */ char **command_lines; /* Array of variable-expanded cmd lines. */ char *command_ptr; /* Ptr into command_lines[command_line]. */ #ifdef VMS char *comname; /* Temporary command file name */ int efn; /* Completion event flag number */ int cstatus; /* Completion status */ int vms_launch_status; /* non-zero if lib$spawn, etc failed */ #endif unsigned int command_line; /* Index into command_lines. */ struct output output; /* Output for this child. */ pid_t pid; /* Child process's ID number. */ unsigned int remote:1; /* Nonzero if executing remotely. */ unsigned int noerror:1; /* Nonzero if commands contained a '-'. */ unsigned int good_stdin:1; /* Nonzero if this child has a good stdin. */ unsigned int deleted:1; /* Nonzero if targets have been deleted. */ unsigned int recursive:1; /* Nonzero for recursive command ('+' etc.) */ unsigned int dontcare:1; /* Saved dontcare flag. */ #ifdef CONFIG_WITH_KMK_BUILTIN unsigned int has_status:1; /* Nonzero if status is available. */ int status; /* Status of the job. */ #endif #ifdef CONFIG_WITH_PRINT_TIME_SWITCH big_int start_ts; /* nano_timestamp of the first command. */ #endif }; extern struct child *children; /* A signal handler for SIGCHLD, if needed. */ RETSIGTYPE child_handler (int sig); int is_bourne_compatible_shell(const char *path); void new_job (struct file *file); void reap_children (int block, int err); void start_waiting_jobs (void); char **construct_command_argv (char *line, char **restp, struct file *file, int cmd_flags, char** batch_file); #ifdef VMS int child_execute_job (struct child *child, char *argv); #else # define FD_STDIN (fileno (stdin)) # define FD_STDOUT (fileno (stdout)) # define FD_STDERR (fileno (stderr)) int child_execute_job (struct output *out, int good_stdin, char **argv, char **envp); #endif #ifdef _AMIGA void exec_command (char **argv) __attribute__ ((noreturn)); #elif defined(__EMX__) int exec_command (char **argv, char **envp); #else void exec_command (char **argv, char **envp) __attribute__ ((noreturn)); #endif extern unsigned int job_slots_used; void block_sigs (void); #ifdef POSIX void unblock_sigs (void); #else #ifdef HAVE_SIGSETMASK extern int fatal_signal_mask; #define unblock_sigs() sigsetmask (0) #else #define unblock_sigs() #endif #endif extern unsigned int jobserver_tokens; kbuild-3149/src/kmk/vms_progname.c0000644000175000017500000003440113252530203017113 0ustar locutuslocutus/* File: vms_progname.c * * This module provides a fixup of the program name. * * This module is designed to be a plug in replacement for the * progname module used by many GNU utilities with a few enhancements * needed for GNU Make. * * It does not support the HAVE_DECL_PROGRAM_INVOCATION_* macros at this * time. * * Make sure that the program_name string is set as close as possible to * what the original command was given. * * When run from DCL, The argv[0] element is initialized with an absolute * path name. The decc$ feature logical names can control the format * of this pathname. In some cases it causes the UNIX format name to be * formatted incorrectly. * * This DCL provided name is usually incompatible with what is expected to * be provided by Unix programs and needs to be replaced. * * When run from an exec() call, the argv[0] element is initialized by the * program. This name is compatible with what is expected to be provided * by Unix programs and should be passed through unchanged. * * The DCL provided name can be detected because it always contains the * device name. * * DCL examples: * devname:[dir]program.exe;1 Normal VMS - remove path and .EXE;n * devname:[dir]facility$program.exe;1 Facility also needs removal. * /devname/dir/program.exe * /DISK$VOLUME/dir/program.exe.1 Bug version should not be there. * /DISK$VOLUME/dir/program. Bug Period should not be there. * */ /* Copyright (C) 2014-2016 Free Software Foundation, Inc. GNU Make 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. GNU Make 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 . */ /* Per copyright assignment agreement with the Free Software Foundation this software may be available under under other license agreements and copyrights. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include #include #include #ifdef USE_PROGNAME_H # include "progname.h" #endif #pragma member_alignment save #pragma nomember_alignment longword struct item_list_3 { unsigned short len; unsigned short code; void * bufadr; unsigned short * retlen; }; struct filescan_itmlst_2 { unsigned short length; unsigned short itmcode; char * component; }; #pragma member_alignment int SYS$GETDVIW (unsigned long efn, unsigned short chan, const struct dsc$descriptor_s * devnam, const struct item_list_3 * itmlst, void * iosb, void (* astadr)(unsigned long), unsigned long astprm, void * nullarg); int SYS$FILESCAN (const struct dsc$descriptor_s * srcstr, struct filescan_itmlst_2 * valuelist, unsigned long * fldflags, struct dsc$descriptor_s *auxout, unsigned short * retlen); /* String containing name the program is called with. To be initialized by main(). */ const char *program_name = NULL; static int internal_need_vms_symbol = 0; static char vms_new_nam[256]; int need_vms_symbol (void) { return internal_need_vms_symbol; } void set_program_name (const char *argv0) { int status; int result; #ifdef DEBUG printf ("original argv0 = %s\n", argv0); #endif /* Posix requires non-NULL argv[0] */ if (argv0 == NULL) { fputs ("A NULL argv[0] was passed through an exec system call.\n", stderr); abort (); } program_name = argv0; result = 0; internal_need_vms_symbol = 0; /* If the path name starts with a /, then it is an absolute path */ /* that may have been generated by the CRTL instead of the command name */ /* If it is the device name between the slashes, then this was likely */ /* from the run command and needs to be fixed up. */ /* If the DECC$POSIX_COMPLIANT_PATHNAMES is set to 2, then it is the */ /* DISK$VOLUME that will be present, and it will still need to be fixed. */ if (argv0[0] == '/') { char * nextslash; int length; struct item_list_3 itemlist[3]; unsigned short dvi_iosb[4]; char alldevnam[64]; unsigned short alldevnam_len; struct dsc$descriptor_s devname_dsc; char diskvolnam[256]; unsigned short diskvolnam_len; internal_need_vms_symbol = 1; /* Get some information about the disk */ /*--------------------------------------*/ itemlist[0].len = (sizeof alldevnam) - 1; itemlist[0].code = DVI$_ALLDEVNAM; itemlist[0].bufadr = alldevnam; itemlist[0].retlen = &alldevnam_len; itemlist[1].len = (sizeof diskvolnam) - 1 - 5; itemlist[1].code = DVI$_VOLNAM; itemlist[1].bufadr = &diskvolnam[5]; itemlist[1].retlen = &diskvolnam_len; itemlist[2].len = 0; itemlist[2].code = 0; /* Add the prefix for the volume name. */ /* SYS$GETDVI will append the volume name to this */ strcpy (diskvolnam, "DISK$"); nextslash = strchr (&argv0[1], '/'); if (nextslash != NULL) { length = nextslash - argv0 - 1; /* Cast needed for HP C compiler diagnostic */ devname_dsc.dsc$a_pointer = (char *)&argv0[1]; devname_dsc.dsc$w_length = length; devname_dsc.dsc$b_dtype = DSC$K_DTYPE_T; devname_dsc.dsc$b_class = DSC$K_CLASS_S; status = SYS$GETDVIW (EFN$C_ENF, 0, &devname_dsc, itemlist, dvi_iosb, NULL, 0, 0); if (!$VMS_STATUS_SUCCESS (status)) { /* If the sys$getdviw fails, then this path was passed by */ /* An exec() program and not from DCL, so do nothing */ /* An example is "/tmp/program" where tmp: does not exist */ #ifdef DEBUG printf ("sys$getdviw failed with status %d\n", status); #endif result = 0; } else if (!$VMS_STATUS_SUCCESS (dvi_iosb[0])) { #ifdef DEBUG printf ("sys$getdviw failed with iosb %d\n", dvi_iosb[0]); #endif result = 0; } else { char * devnam; int devnam_len; char argv_dev[64]; /* Null terminate the returned alldevnam */ alldevnam[alldevnam_len] = 0; devnam = alldevnam; devnam_len = alldevnam_len; /* Need to skip past any leading underscore */ if (devnam[0] == '_') { devnam++; devnam_len--; } /* And remove the trailing colon */ if (devnam[devnam_len - 1] == ':') { devnam_len--; devnam[devnam_len] = 0; } /* Null terminate the returned volnam */ diskvolnam_len += 5; diskvolnam[diskvolnam_len] = 0; /* Check first for normal CRTL behavior */ if (devnam_len == length) { strncpy (vms_new_nam, &argv0[1], length); vms_new_nam[length] = 0; result = (strcasecmp (devnam, vms_new_nam) == 0); } /* If we have not got a match, check for POSIX Compliant */ /* behavior. To be more accurate, we could also check */ /* to see if that feature is active. */ if ((result == 0) && (diskvolnam_len == length)) { strncpy (vms_new_nam, &argv0[1], length); vms_new_nam[length] = 0; result = (strcasecmp (diskvolnam, vms_new_nam) == 0); } } } } else { /* The path did not start with a slash, so it could be VMS format */ /* If it is vms format, it has a volume/device in it as it must */ /* be an absolute path */ struct dsc$descriptor_s path_desc; int status; unsigned long field_flags; struct filescan_itmlst_2 item_list[5]; char * volume; char * name; int name_len; char * ext; path_desc.dsc$a_pointer = (char *)argv0; /* cast ok */ path_desc.dsc$w_length = strlen (argv0); path_desc.dsc$b_dtype = DSC$K_DTYPE_T; path_desc.dsc$b_class = DSC$K_CLASS_S; /* Don't actually need to initialize anything buf itmcode */ /* I just do not like uninitialized input values */ /* Sanity check, this must be the same length as input */ item_list[0].itmcode = FSCN$_FILESPEC; item_list[0].length = 0; item_list[0].component = NULL; /* If the device is present, then it if a VMS spec */ item_list[1].itmcode = FSCN$_DEVICE; item_list[1].length = 0; item_list[1].component = NULL; /* we need the program name and type */ item_list[2].itmcode = FSCN$_NAME; item_list[2].length = 0; item_list[2].component = NULL; item_list[3].itmcode = FSCN$_TYPE; item_list[3].length = 0; item_list[3].component = NULL; /* End the list */ item_list[4].itmcode = 0; item_list[4].length = 0; item_list[4].component = NULL; status = SYS$FILESCAN ((const struct dsc$descriptor_s *)&path_desc, item_list, &field_flags, NULL, NULL); if ($VMS_STATUS_SUCCESS (status) && (item_list[0].length == path_desc.dsc$w_length) && (item_list[1].length != 0)) { char * dollar; int keep_ext; int i; /* We need the filescan to be successful, */ /* same length as input, and a volume to be present */ internal_need_vms_symbol = 1; /* We will assume that we only get to this path on a version */ /* of VMS that does not support the EFS character set */ /* There may be a xxx$ prefix on the image name. Linux */ /* programs do not handle that well, so strip the prefix */ name = item_list[2].component; name_len = item_list[2].length; dollar = strrchr (name, '$'); if (dollar != NULL) { dollar++; name_len = name_len - (dollar - name); name = dollar; } strncpy (vms_new_nam, name, name_len); vms_new_nam[name_len] = 0; /* Commit to using the new name */ program_name = vms_new_nam; /* We only keep the extension if it is not ".exe" */ keep_ext = 0; ext = item_list[3].component; if (item_list[3].length != 1) { keep_ext = 1; if (item_list[3].length == 4) { if ((ext[1] == 'e' || ext[1] == 'E') && (ext[2] == 'x' || ext[2] == 'X') && (ext[3] == 'e' || ext[3] == 'E')) keep_ext = 0; } } if (keep_ext == 1) strncpy (&vms_new_nam[name_len], ext, item_list[3].length); } } if (result) { char * lastslash; char * dollar; char * dotexe; char * lastdot; char * extension; /* This means it is probably the name from a DCL command */ /* Find the last slash which separates the file from the */ /* path. */ lastslash = strrchr (argv0, '/'); if (lastslash != NULL) { int i; lastslash++; /* There may be a xxx$ prefix on the image name. Linux */ /* programs do not handle that well, so strip the prefix */ dollar = strrchr (lastslash, '$'); if (dollar != NULL) { dollar++; lastslash = dollar; } strcpy (vms_new_nam, lastslash); /* In UNIX mode + EFS character set, there should not be a */ /* version present, as it is not possible when parsing to */ /* tell if it is a version or part of the UNIX filename as */ /* UNIX programs use numeric extensions for many reasons. */ lastdot = strrchr (vms_new_nam, '.'); if (lastdot != NULL) { int i; i = 1; while (isdigit (lastdot[i])) { i++; } if (lastdot[i] == 0) { *lastdot = 0; } } /* Find the .exe on the name (case insenstive) and toss it */ dotexe = strrchr (vms_new_nam, '.'); if (dotexe != NULL) { if ((dotexe[1] == 'e' || dotexe[1] == 'E') && (dotexe[2] == 'x' || dotexe[2] == 'X') && (dotexe[3] == 'e' || dotexe[3] == 'E') && (dotexe[4] == 0)) { *dotexe = 0; } else { /* Also need to handle a null extension because of a */ /* CRTL bug. */ if (dotexe[1] == 0) { *dotexe = 0; } } } /* Commit to new name */ program_name = vms_new_nam; } else { /* There is no way that the code should ever get here */ /* As we already verified that the '/' was present */ fprintf (stderr, "Sanity failure somewhere we lost a '/'\n"); } } } #ifdef DEBUG int main (int argc, char ** argv, char **env) { char command[1024]; set_program_name (argv[0]); printf ("modified argv[0] = %s\n", program_name); return 0; } #endif kbuild-3149/src/kmk/getopt1.c0000644000175000017500000001031313252530201015773 0ustar locutuslocutus/* getopt_long and getopt_long_only entry points for GNU getopt. Copyright (C) 1987-1994, 1996-2016 Free Software Foundation, Inc. NOTE: The canonical source of this file is maintained with the GNU C Library. Bugs can be reported to bug-glibc@gnu.org. GNU Make 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. GNU Make 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 . */ #ifdef HAVE_CONFIG_H #include #endif #include "getopt.h" #if !defined __STDC__ || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ #ifndef const #define const #endif #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 #include #if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION #define ELIDE_CODE #endif #endif #ifndef ELIDE_CODE /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ #include #endif #ifndef NULL #define NULL 0 #endif int getopt_long (int argc, char *const *argv, const char *options, const struct option *long_options, int *opt_index) { return _getopt_internal (argc, argv, options, long_options, opt_index, 0); } /* Like getopt_long, but '-' as well as '--' can indicate a long option. If an option that starts with '-' (not '--') doesn't match a long option, but does match a short option, it is parsed as a short option instead. */ int getopt_long_only (int argc, char *const *argv, const char *options, const struct option *long_options, int *opt_index) { return _getopt_internal (argc, argv, options, long_options, opt_index, 1); } #endif /* Not ELIDE_CODE. */ #ifdef TEST #include int main (int argc, char **argv) { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; int option_index = 0; static struct option long_options[] = { {"add", 1, 0, 0}, {"append", 0, 0, 0}, {"delete", 1, 0, 0}, {"verbose", 0, 0, 0}, {"create", 0, 0, 0}, {"file", 1, 0, 0}, {0, 0, 0, 0} }; c = getopt_long (argc, argv, "abc:d:0123456789", long_options, &option_index); if (c == -1) break; switch (c) { case 0: printf ("option %s", long_options[option_index].name); if (optarg) printf (" with arg %s", optarg); printf ("\n"); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value '%s'\n", optarg); break; case 'd': printf ("option d with value '%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ kbuild-3149/src/kmk/kdepdb.c0000644000175000017500000007570113252530202015656 0ustar locutuslocutus/* $Id: incdep.c 2283 2009-02-24 04:54:00Z bird $ */ /** @file * kdepdb - Dependency database. */ /* * Copyright (c) 2009-2010 knut st. osmundsen * * This file is part of kBuild. * * kBuild 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. * * kBuild 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 kBuild. If not, see * */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "makeint.h" #include "../lib/k/kDefs.h" #include "../lib/k/kTypes.h" #include #include #include "dep.h" #include "filedef.h" #include "job.h" #include "commands.h" #include "variable.h" #include "rule.h" #include "debug.h" #include "strcache2.h" #ifdef HAVE_FCNTL_H # include #else # include #endif #if K_OS == K_WINDOWS # include #else # include # include #endif /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** @def KDEPDB_ASSERT_SIZE * Check the size of an on-disk type. * * @param Type The type which size it being checked. * @param Size The size it should have. */ #ifdef __GNUC__ # define KDEPDB_ASSERT_SIZE(Type, Size) \ extern int kDepDbAssertSize[1] __attribute__((unused)), \ kDepDbAssertSize[sizeof(Type) == (Size)] __attribute__((unused)) #else # define KDEPDB_ASSERT_SIZE(Type, Size) \ typedef int kDepDbAssertSize[sizeof(Type) == (Size)] #endif KDEPDB_ASSERT_SIZE(KU8, 1); KDEPDB_ASSERT_SIZE(KU16, 2); KDEPDB_ASSERT_SIZE(KU32, 4); KDEPDB_ASSERT_SIZE(KU64, 8); /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * File header. * * @remarks All on-disk formats are in little-endian format. */ typedef struct KDEPDBHDR { /** The file magic. */ KU8 szMagic[8]; /** The major file format version. */ KU8 uVerMajor; /** The minor file format version. */ KU8 uVerMinor; /** Reserved \#2. */ KU16 uReserved2; /** Reserved \#1. */ KU32 uReserved1; /** The internal name of this file. */ KU8 szName[16]; } KDEPDBHDR; KDEPDB_ASSERT_SIZE(KDEPDBHDR, 32); /** The file header magic value. */ #define KDEPDBHDR_MAGIC "kDepDb\0" /** The current major file format version number. */ #define KDEPDBHDR_VERSION_MAJOR 0 /** The current minor file format version number. * Numbers above 240 indicate unsupported development variants. */ #define KDEPDBHDR_VERSION_MINOR 240 /** * Hash table file. * * The hash table is recreated in a new file when we have to grow it. */ typedef struct KDEPDBHASH { /** The file header. */ KDEPDBHDR Hdr; /** The number of hash table entries. */ KU32 cEntries; /** The number of hash table entries with content. */ KU32 cUsedEntries; /** The number of collisions on insert. */ KU32 cCollisions; /** Reserved member \#5. */ KU32 uReserved5; /** Reserved member \#4. */ KU32 uReserved4; /** Reserved member \#3. */ KU32 uReserved3; /** Reserved member \#2. */ KU32 uReserved2; /** Reserved member \#1. */ KU32 uReserved1; /** The hash table. */ KU32 auEntries[32]; } KDEPDBHASH; KDEPDB_ASSERT_SIZE(KDEPDBHASH, 32+32+4*32); /** The item value indicating that it is unused. */ #define KDEPDBHASH_UNUSED KU32_C(0xffffffff) /** The item indicating that it hash been deleted. */ #define KDEPDBHASH_DELETED KU32_C(0xfffffffe) /** The first special item value. */ #define KDEPDBHASH_END KU32_C(0xfffffff0) /** * A string table string entry. * * This should be a multiple of 32 bytes. */ typedef struct KDEPDBSTRING { /** The hash number for the string. */ KU32 uHash; /** The string length, excluding the zero terminator. */ KU32 cchString; /** The string. */ KU8 szString[24]; } KDEPDBSTRING; KDEPDB_ASSERT_SIZE(KDEPDBSTRING, 32); /** * String table file. * * The file is insertion only and will grow forever. */ typedef struct KDEPDBSTRTAB { /** The file header. */ KDEPDBHDR Hdr; /** The end of the valid string table indexes. */ KU32 iStringEnd; /** Reserved member \#7. */ KU32 uReserved7; /** Reserved member \#6. */ KU32 uReserved6; /** Reserved member \#5. */ KU32 uReserved5; /** Reserved member \#4. */ KU32 uReserved4; /** Reserved member \#3. */ KU32 uReserved3; /** Reserved member \#2. */ KU32 uReserved2; /** Reserved member \#1. */ KU32 uReserved1; /** The string table. */ KDEPDBSTRING aStrings[1]; } KDEPDBSTRTAB; KDEPDB_ASSERT_SIZE(KDEPDBSTRTAB, 32+32+32); /** The end of the valid string table indexes (exclusive). */ #define KDEPDBG_STRTAB_IDX_END KU32_C(0x80000000) /** The string was not found. */ #define KDEPDBG_STRTAB_IDX_NOT_FOUND KU32_C(0xfffffffd) /** Error during string table operation. */ #define KDEPDBG_STRTAB_IDX_ERROR KU32_C(0xfffffffe) /** Generic invalid string table index. */ #define KDEPDBG_STRTAB_IDX_INVALID KU32_C(0xffffffff) /** * Directory entry. */ typedef struct KDEPDBDIRENTRY { /** The string table index of the entry name. * Unused entries are set to KDEPDBG_STRTAB_IDX_INVALID. */ KU32 iName; /** The actual data stream size. * Unused entries are set to KU32_MAX. */ KU32 cbData; /** The number of blocks allocated for this stream. * Unused entries are set to KU32_MAX. */ KU32 cBlocks; /** The start block number. * The stream is a contiguous sequence of blocks. This optimizes and * simplifies reading the stream at the expense of operations extending it. * * In unused entries, this serves as the free chain pointer with KU32_MAX as * nil value. */ KU32 iStartBlock; } KDEPDBDIRENTRY; KDEPDB_ASSERT_SIZE(KDEPDBDIRENTRY, 16); /** * Directory file. */ typedef struct KDEPDBDIR { /** The file header. */ KDEPDBHDR Hdr; /** The number of entries. */ KU32 cEntries; /** The head of the free chain. (Index into aEntries.) */ KU32 iFreeHead; /** Reserved member \#6. */ KU32 uReserved6; /** Reserved member \#5. */ KU32 uReserved5; /** Reserved member \#4. */ KU32 uReserved4; /** Reserved member \#3. */ KU32 uReserved3; /** Reserved member \#2. */ KU32 uReserved2; /** Reserved member \#1. */ KU32 uReserved1; /** Directory entries. */ KDEPDBDIRENTRY aEntries[2]; } KDEPDBDIR; KDEPDB_ASSERT_SIZE(KDEPDBDIR, 32+32+32); /** * A block allocation bitmap. * * This can track 2^(12+8) = 2^20 = 1M blocks. */ typedef struct KDEPDBDATABITMAP { /** Bitmap where each bit is a block. * 0 indicates unused blocks and 1 indicates used ones. */ KU8 bm[4096]; } KDEPDBDATABITMAP; KDEPDB_ASSERT_SIZE(KDEPDBDATABITMAP, 4096); /** * Data file. * * The block numbering starts with this structure as block 0. */ typedef struct KDEPDBDATA { /** The file header. */ KDEPDBHDR Hdr; /** The size of a block. */ KU32 cbBlock; /** Reserved member \#7. */ KU32 uReserved7; /** Reserved member \#6. */ KU32 uReserved6; /** Reserved member \#5. */ KU32 uReserved5; /** Reserved member \#4. */ KU32 uReserved4; /** Reserved member \#3. */ KU32 uReserved3; /** Reserved member \#2. */ KU32 uReserved2; /** Reserved member \#1. */ KU32 uReserved1; /** Block numbers for the allocation bitmaps. */ KU32 aiBitmaps[4096]; } KDEPDBDATA; /** The end of the valid block indexes (exclusive). */ #define KDEPDB_BLOCK_IDX_END KU32_C(0xfffffff0) /** The index of an unallocated bitmap block. */ #define KDEPDB_BLOCK_IDX_UNALLOCATED KU32_C(0xffffffff) /** * Stream storing dependencies. * * The stream name gives the output file name, so all that we need is the list * of files it depends on. These are serialized as a list of string table * indexes. */ typedef struct KDEPDBDEPSTREAM { /** String table indexes for the dependencies. */ KU32 aiDeps[1]; } KDEPDBDEPSTREAM; /** * A file handle structure. */ typedef struct KDEPDBFH { #if K_OS == K_OS_WINDOWS /** The file handle. */ HANDLE hFile; /** The mapping object handle. */ HANDLE hMapObj; #else /** The file handle. */ int fd; #endif /** The current file size. */ KU32 cb; } KDEPDBFH; /** * Internal control structure for a string table. */ typedef struct KDEPDBINTSTRTAB { /** The hash file. */ KDEPDBHASH *pHash; /** The handle of the hash file. */ KDEPDBFH hHash; /** The string table file. */ KDEPDBSTRTAB *pStrTab; /** The handle of the string table file. */ KDEPDBFH hStrTab; /** The end of the allocated string table indexes (i.e. when to grow the * file). */ KU32 iStringAlloced; } KDEPDBINTSTRTAB; /** * Internal control structure for a data set. * * This governs the directory file, the directory hash file and the data file. */ typedef struct KDEPDBINTDATASET { /** The hash file. */ KDEPDBHASH pHash; /** The size of the hash file. */ KU32 cbHash; /** The size of the directory file. */ KU32 cbDir; /** The mapping of the directory file. */ KDEPDBHASH pDir; /** The data file. */ KDEPDBDATA pData; /** The size of the data file. */ KU32 cbData; /** The handle of the hash file. */ KDEPDBFH hHash; /** The handle of the directory file. */ KDEPDBFH hDir; /** The handle of the data file. */ KDEPDBFH hData; } KDEPDBINTDATASET; /** * The database instance. * * To simplifiy things the database uses 8 files for storing the different kinds * of data. This greatly reduces the complexity compared to a single file * solution. */ typedef struct KDEPDB { /** The string table. */ KDEPDBINTSTRTAB StrTab; /** The variable data set. */ KDEPDBINTDATASET DepSet; /** The command data set. */ KDEPDBINTDATASET CmdSet; } KDEPDB; /******************************************************************************* * Internal Functions * *******************************************************************************/ static void *kDepDbAlloc(KSIZE cb); static void kDepDbFree(void *pv); static void kDepDbFHInit(KDEPDBFH *pFH); static int kDepDbFHUpdateSize(KDEPDBFH *pFH); static int kDepDbFHOpen(KDEPDBFH *pFH, const char *pszFilename, KBOOL fCreate, KBOOL *pfNew); static int kDepDbFHClose(KDEPDBFH *pFH); static int kDepDbFHWriteAt(KDEPDBFH *pFH, KU32 off, void const *pvBuf, KSIZE cbBuf); static int kDepDbFHMap(KDEPDBFH *pFH, void **ppvMap); static int kDepDbFHUnmap(KDEPDBFH *pFH, void **ppvMap); static int kDepDbFHGrow(KDEPDBFH *pFH, KSIZE cbNew, void **ppvMap); static KU32 kDepDbHashString(const char *pszString, size_t cchString); /** xmalloc wrapper. */ static void *kDepDbAlloc(KSIZE cb) { return xmalloc(cb); } /** free wrapper. */ static void kDepDbFree(void *pv) { if (pv) free(pv); } /** * Initializes the file handle structure so closing it without first opening it * will work smoothly. * * @param pFH The file handle structure. */ static void kDepDbFHInit(KDEPDBFH *pFH) { #if K_OS == K_OS_WINDOWS pFH->hFile = INVALID_HANDLE_VALUE; pFH->hMapObj = INVALID_HANDLE_VALUE; #else pFH->fd = -1; #endif pFH->cb = 0; } /** * Updates the file size. * * @returns 0 on success. Some non-zero native error code on failure. * @param pFH The file handle structure. */ static int kDepDbFHUpdateSize(KDEPDBFH *pFH) { #if K_OS == K_OS_WINDOWS DWORD rc; DWORD dwHigh; DWORD dwLow; SetLastError(0); dwLow = GetFileSize(File, &High); rc = GetLastError(); if (rc) { pFH->cb = 0; return (int)rc; } if (High) pFH->cb = KU32_MAX; else pFH->cb = dwLow; #else off_t cb; cb = lseek(pFH->fd, 0, SEEK_END); if (cb == -1) { pFH->cb = 0; return errno; } pFH->cb = cb; if ((off_t)pFH->cb != cb) pFH->cb = KU32_MAX; #endif return 0; } /** * Opens an existing file or creates a new one. * * @returns 0 on success. Some non-zero native error code on failure. * * @param pFH The file handle structure. * @param pszFilename The name of the file. * @param fCreate Whether we should create the file or not. * @param pfCreated Where to return whether we created it or not. */ static int kDepDbFHOpen(KDEPDBFH *pFH, const char *pszFilename, KBOOL fCreate, KBOOL *pfCreated) { int rc; #if K_OS == K_OS_WINDOWS SECURITY_ATTRIBUTES SecAttr; SecAttr.bInheritHandle = FALSE; SecAttr.lpSecurityDescriptor = NULL; SecAttr.nLength = 0; pFH->cb = 0; SetLastError(0); pFH->hFile = CreateFile(pszFilename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, &SecAttr, fCreate ? OPEN_ALWAYS : OPEN_EXISTING, 0, NULL); if (pFH->hFile == INVALID_HANDLE_VALUE) return GetLastError(); *pfCreated = GetLastError() == 0; #else int fFlags = O_RDWR; # ifdef O_BINARY fFlags |= O_BINARY; # endif pFH->cb = 0; pFH->fd = open(pszFilename, fFlags, 0); if (pFH->fd >= 0) *pfCreated = K_FALSE; else if (!fCreate) return errno; else { pFH->fd = open(pszFilename, fFlags | O_EXCL | O_CREAT, 0666); if (pFH->fd < 0) return errno; *pfCreated = K_TRUE; } fcntl(pFH->fd, F_SETFD, FD_CLOEXEC); #endif /* update the size */ rc = kDepDbFHUpdateSize(pFH); if (rc) kDepDbFHClose(pFH); return rc; } /** * Closes an open file. * * @returns 0 on success. Some non-zero native error code on failure. * * @param pFH The file handle structure. */ static int kDepDbFHClose(KDEPDBFH *pFH) { #if K_OS == K_OS_WINDOWS if (pFH->hFile != INVALID_HANDLE_VALUE) { if (!CloseHandle(pFH->hFile)) return GetLastError(); pFH->hFile = INVALID_HANDLE_VALUE; } #else if (pFH->fd >= 0) { if (close(pFH->fd) != 0) return errno; pFH->fd = -1; } #endif pFH->cb = 0; return 0; } /** * Writes to a file. * * @returns 0 on success. Some non-zero native error code on failure. * * @param pFH The file handle structure. * @param off The offset into the file to start writing at. * @param pvBuf What to write. * @param cbBuf How much to write. */ static int kDepDbFHWriteAt(KDEPDBFH *pFH, KU32 off, void const *pvBuf, KSIZE cbBuf) { #if K_OS == K_OS_WINDOWS ULONG cbWritten; if (SetFilePointer(pFH->hFile, off, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER) return GetLastError(); if (!WriteFile(pFH->hFile, pvBuf, cbBuf, &cbWritten, NULL)) return GetLastError(); if (cbWritten != cbBuf) return -1; #else ssize_t cbWritten; if (lseek(pFH->fd, off, SEEK_SET) == -1) return errno; errno = 0; cbWritten = write(pFH->fd, pvBuf, cbBuf); if ((size_t)cbWritten != cbBuf) return errno ? errno : EIO; #endif return kDepDbFHUpdateSize(pFH); } /** * Creates a memory mapping of the file. * * @returns 0 on success. Some non-zero native error code on failure. * * @param pFH The file handle structure. * @param ppvMap Where to return the map address. */ static int kDepDbFHMap(KDEPDBFH *pFH, void **ppvMap) { #if K_OS == K_OS_WINDOWS *ppvMap = NULL; return -1; #else *ppvMap = mmap(NULL, pFH->cb, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, pFH->fd, 0); if (*ppvMap == (void *)-1) { *ppvMap = NULL; return errno; } #endif return 0; } /** * Flushes and destroys a memory of the file. * * @returns 0 on success. Some non-zero native error code on failure. * * @param pFH The file handle structure. * @param ppvMap The pointer to the mapping pointer. This will be set to * NULL on success. */ static int kDepDbFHUnmap(KDEPDBFH *pFH, void **ppvMap) { #if K_OS == K_OS_WINDOWS return -1; #else if (msync(*ppvMap, pFH->cb, MS_SYNC) == -1) return errno; if (munmap(*ppvMap, pFH->cb) == -1) return errno; *ppvMap = NULL; #endif return 0; } /** * Grows the memory mapping of the file. * * The content of the new space is undefined. * * @returns 0 on success. Some non-zero native error code on failure. * * @param pFH The file handle structure. * @param cbNew The new mapping size. * @param ppvMap The pointer to the mapping pointer. This may change and * may be set to NULL on failure. */ static int kDepDbFHGrow(KDEPDBFH *pFH, KSIZE cbNew, void **ppvMap) { #if K_OS == K_OS_WINDOWS return -1; #else if ((KU32)cbNew != cbNew) return ERANGE; if (cbNew <= pFH->cb) return 0; if (munmap(*ppvMap, pFH->cb) == -1) return errno; *ppvMap = NULL; pFH->cb = cbNew; return kDepDbFHMap(pFH, ppvMap); #endif } /** Macro for reading an potentially unaligned 16-bit word from a string. */ # if K_ARCH == K_ARCH_AMD64 \ || K_ARCH == K_ARCH_X86_32 \ || K_ARCH == K_ARCH_X86_16 # define kDepDbHashString_get_unaligned_16bits(ptr) ( *((const KU16 *)(ptr)) ) # elif K_ENDIAN == K_ENDIAN_LITTLE # define kDepDbHashString_get_unaligned_16bits(ptr) ( (((const KU8 *)(ptr))[0]) \ | (((const KU8 *)(ptr))[1] << 8) ) # else # define kDepDbHashString_get_unaligned_16bits(ptr) ( (((const KU8 *)(ptr))[0] << 8) \ | (((const KU8 *)(ptr))[1]) ) # endif /** * Hash a string. * * @returns Hash value. * * @param pszString The string to hash. * @param cchString How much to hash. */ static KU32 kDepDbHashString(const char *pszString, size_t cchString) { /* * Paul Hsieh hash SuperFast function: * http://www.azillionmonkeys.com/qed/hash.html */ /** @todo A path for well aligned data should be added to speed up execution on * alignment sensitive systems. */ unsigned int uRem; KU32 uHash; KU32 uTmp; assert(sizeof(KU8) == sizeof(char)); /* main loop, walking on 2 x KU16 */ uHash = cchString; uRem = cchString & 3; cchString >>= 2; while (cchString > 0) { uHash += kDepDbHashString_get_unaligned_16bits(pszString); uTmp = (kDepDbHashString_get_unaligned_16bits(pszString + 2) << 11) ^ uHash; uHash = (uHash << 16) ^ uTmp; pszString += 2 * sizeof(KU16); uHash += uHash >> 11; cchString--; } /* the remainder */ switch (uRem) { case 3: uHash += kDepDbHashString_get_unaligned_16bits(pszString); uHash ^= uHash << 16; uHash ^= pszString[sizeof(KU16)] << 18; uHash += uHash >> 11; break; case 2: uHash += kDepDbHashString_get_unaligned_16bits(pszString); uHash ^= uHash << 11; uHash += uHash >> 17; break; case 1: uHash += *pszString; uHash ^= uHash << 10; uHash += uHash >> 1; break; } /* force "avalanching" of final 127 bits. */ uHash ^= uHash << 3; uHash += uHash >> 5; uHash ^= uHash << 4; uHash += uHash >> 17; uHash ^= uHash << 25; uHash += uHash >> 6; return uHash; } /*** * Looks up a string in the string table. * * @returns The string table index. * @retval KDEPDBG_STRTAB_IDX_NOT_FOUND is not found. * @retval KDEPDBG_STRTAB_IDX_ERROR on internal inconsistency. * * @param pStrTab The string table. * @param pszString The string. * @param cchStringIn The string length. * @param uHash The hash of the string. */ static KU32 kDepDbStrTabLookupHashed(KDEPDBINTSTRTAB const *pStrTab, const char *pszString, size_t cchStringIn, KU32 uHash) { KU32 const cchString = (KU32)cchStringIn; KDEPDBHASH const *pHash = pStrTab->pHash; KDEPDBSTRING const *paStrings = &pStrTab->pStrTab->aStrings[0]; KU32 const iStringEnd = K_LE2H_U32(pStrTab->pStrTab->iStringEnd); KU32 iHash; /* sanity */ if (cchString != cchStringIn) return KDEPDBG_STRTAB_IDX_NOT_FOUND; /* * Hash lookup of the string. */ iHash = uHash % pHash->cEntries; for (;;) { KU32 iString = K_LE2H_U32(pHash->auEntries[iHash]); if (iString < iStringEnd) { KDEPDBSTRING const *pString = &paStrings[iString]; if ( K_LE2H_U32(pString->uHash) == uHash && K_LE2H_U32(pString->cchString) == cchString && !memcmp(pString->szString, pszString, cchString)) return iString; } else if (iString == KDEPDBHASH_UNUSED) return KDEPDBG_STRTAB_IDX_NOT_FOUND; else if (iString != KDEPDBHASH_DELETED) return KDEPDBG_STRTAB_IDX_ERROR; /* advance */ iHash = (iHash + 1) % pHash->cEntries; } } /** * Doubles the hash table size and rehashes it. * * @returns 0 on success, -1 on failure. * @param pStrTab The string table. * @todo Rebuild from string table, we'll be accessing it anyways. */ static int kDepDbStrTabReHash(KDEPDBINTSTRTAB *pStrTab) { KDEPDBSTRING const *paStrings = &pStrTab->pStrTab->aStrings[0]; KU32 const iStringEnd = K_LE2H_U32(pStrTab->pStrTab->iStringEnd); KDEPDBHASH *pHash = pStrTab->pHash; KDEPDBHASH HashHdr = *pHash; KU32 *pauNew; KU32 cEntriesNew; KU32 i; /* * Calc the size of the new hash table. */ if (pHash->cEntries >= KU32_C(0x80000000)) return -1; cEntriesNew = 1024; while (cEntriesNew <= pHash->cEntries) cEntriesNew <<= 1; /* * Allocate and initialize an empty hash table in memory. */ pauNew = kDepDbAlloc(cEntriesNew * sizeof(KU32)); if (!pauNew) return -1; i = cEntriesNew; while (i-- > 0) pauNew[i] = KDEPDBHASH_UNUSED; /* * Popuplate the new table. */ HashHdr.cEntries = K_LE2H_U32(cEntriesNew); HashHdr.cCollisions = 0; HashHdr.cUsedEntries = 0; i = pHash->cEntries; while (i-- > 0) { KU32 iString = K_LE2H_U32(pHash->auEntries[i]); if (iString < iStringEnd) { KU32 iHash = (paStrings[iString].uHash % cEntriesNew); if (pauNew[iHash] != K_H2LE_U32(KDEPDBHASH_UNUSED)) { do { iHash = (iHash + 1) % cEntriesNew; HashHdr.cCollisions++; } while (pauNew[iHash] != K_H2LE_U32(KDEPDBHASH_UNUSED)); } pauNew[iHash] = iString; HashHdr.cUsedEntries++; } else if ( iString != KDEPDBHASH_UNUSED && iString != KDEPDBHASH_DELETED) { kDepDbFree(pauNew); return -1; } } HashHdr.cCollisions = K_H2LE_U32(HashHdr.cCollisions); HashHdr.cUsedEntries = K_H2LE_U32(HashHdr.cUsedEntries); /* * Unmap the hash, write the new hash table and map it again. */ if (!kDepDbFHUnmap(&pStrTab->hHash, (void **)&pStrTab->pHash)) { if ( !kDepDbFHWriteAt(&pStrTab->hHash, 0, &HashHdr, K_OFFSETOF(KDEPDBHASH, auEntries)) && !kDepDbFHWriteAt(&pStrTab->hHash, K_OFFSETOF(KDEPDBHASH, auEntries), pauNew, sizeof(pauNew[0]) * cEntriesNew)) { kDepDbFree(pauNew); pauNew = NULL; if (!kDepDbFHMap(&pStrTab->hHash, (void **)&pStrTab->pHash)) return 0; } else kDepDbFHWriteAt(&pStrTab->hHash, 0, "\0\0\0\0", 4); /* file is screwed, trash the magic. */ } kDepDbFree(pauNew); return -1; } /** * Add a string to the string table. * * If already in the table, the index of the existing entry is returned. * * @returns String index on success, * @retval KDEPDBG_STRTAB_IDX_ERROR on I/O and inconsistency errors. * * @param pStrTab The string table. * @param pszString The string to add. * @param cchStringIn The length of the string. * @param uHash The hash of the string. */ static KU32 kDepDbStrTabAddHashed(KDEPDBINTSTRTAB *pStrTab, const char *pszString, size_t cchStringIn, KU32 uHash) { KU32 const cchString = (KU32)cchStringIn; KDEPDBHASH *pHash = pStrTab->pHash; KDEPDBSTRING *paStrings = &pStrTab->pStrTab->aStrings[0]; KU32 const iStringEnd = K_LE2H_U32(pStrTab->pStrTab->iStringEnd); KU32 iInsertAt = KDEPDBHASH_UNUSED; KU32 cCollisions = 0; KU32 iHash; KU32 iString; KU32 cEntries; KDEPDBSTRING *pNewString; /* sanity */ if (cchString != cchStringIn) return KDEPDBG_STRTAB_IDX_NOT_FOUND; /* * Hash lookup of the string, finding either an existing copy or where to * insert the new string at in the hash table. */ iHash = uHash % pHash->cEntries; for (;;) { iString = K_LE2H_U32(pHash->auEntries[iHash]); if (iString < iStringEnd) { KDEPDBSTRING const *pString = &paStrings[iString]; if ( K_LE2H_U32(pString->uHash) == uHash && K_LE2H_U32(pString->cchString) == cchString && !memcmp(pString->szString, pszString, cchString)) return iString; } else { if (iInsertAt == KDEPDBHASH_UNUSED) iInsertAt = iHash; if (iString == KDEPDBHASH_UNUSED) break; if (iString != KDEPDBHASH_DELETED) return KDEPDBG_STRTAB_IDX_ERROR; } /* advance */ cCollisions++; iHash = (iHash + 1) % pHash->cEntries; } /* * Add string to the string table. * The string table file is grown in 256KB increments and ensuring at least 64KB unused new space. */ cEntries = cchString + 1 <= sizeof(paStrings[0].szString) ? 1 : (cchString + 1 - sizeof(paStrings[0].szString) + sizeof(KDEPDBSTRING) - 1) / sizeof(KDEPDBSTRING); if (iStringEnd + cEntries > pStrTab->iStringAlloced) { KSIZE cbNewSize = K_ALIGN_Z((iStringEnd + cEntries) * sizeof(KDEPDBSTRING) + 64*1024, 256*1024); KU32 iStringAlloced = (pStrTab->hStrTab.cb - K_OFFSETOF(KDEPDBSTRTAB, aStrings)) / sizeof(KDEPDBSTRING); if ( iStringAlloced <= pStrTab->iStringAlloced || iStringAlloced >= KDEPDBG_STRTAB_IDX_END || iStringAlloced >= KDEPDBHASH_END) return KDEPDBG_STRTAB_IDX_ERROR; if (kDepDbFHGrow(&pStrTab->hStrTab, cbNewSize, (void **)&pStrTab->pStrTab) != 0) return KDEPDBG_STRTAB_IDX_ERROR; pStrTab->iStringAlloced = iStringAlloced; paStrings = &pStrTab->pStrTab->aStrings[0]; } pNewString = &paStrings[iStringEnd]; pNewString->uHash = K_H2LE_U32(uHash); pNewString->cchString = K_H2LE_U32(cchString); memcpy(&pNewString->szString, pszString, cchString); pNewString->szString[cchString] = '\0'; pStrTab->pStrTab->iStringEnd = K_H2LE_U32(iStringEnd + cEntries); /* * Insert hash table entry, rehash it if necessary. */ pHash->auEntries[iInsertAt] = K_H2LE_U32(iStringEnd); pHash->cUsedEntries = K_H2LE_U32(K_LE2H_U32(pHash->cUsedEntries) + 1); pHash->cCollisions = K_H2LE_U32(K_LE2H_U32(pHash->cCollisions) + cCollisions); if ( K_LE2H_U32(pHash->cUsedEntries) > K_LE2H_U32(pHash->cEntries) / 3 * 2 && kDepDbStrTabReHash(pStrTab) != 0) return KDEPDBG_STRTAB_IDX_ERROR; return iStringEnd; } /** Wrapper for kDepDbStrTabLookupHashed. */ static KU32 kDepDbStrTabLookupN(KDEPDBINTSTRTAB const *pStrTab, const char *pszString, size_t cchString) { return kDepDbStrTabLookupHashed(pStrTab, pszString, cchString, kDepDbHashString(pszString, cchString)); } /** Wrapper for kDepDbStrTabAddHashed. */ static KU32 kDepDbStrTabAddN(KDEPDBINTSTRTAB *pStrTab, const char *pszString, size_t cchString) { return kDepDbStrTabAddHashed(pStrTab, pszString, cchString, kDepDbHashString(pszString, cchString)); } /** Wrapper for kDepDbStrTabLookupHashed. */ static KU32 kDepDbStrTabLookup(KDEPDBINTSTRTAB const *pStrTab, const char *pszString) { return kDepDbStrTabLookupN(pStrTab, pszString, strlen(pszString)); } /** Wrapper for kDepDbStrTabAddHashed. */ static KU32 kDepDbStrTabAdd(KDEPDBINTSTRTAB *pStrTab, const char *pszString) { return kDepDbStrTabAddN(pStrTab, pszString, strlen(pszString)); } /** * Opens the string table files, creating them if necessary. */ static int kDepDbStrTabInit(KDEPDBINTSTRTAB *pStrTab, const char *pszFilenameBase) { size_t cchFilenameBase = strlen(pszFilenameBase); char szPath[4096]; int rc; KBOOL fNew; /* Basic member init, so kDepDbStrTabTerm always works. */ pStrTab->pHash = NULL; kDepDbFHInit(&pStrTab->hHash); pStrTab->pStrTab = NULL; kDepDbFHInit(&pStrTab->hStrTab); pStrTab->iStringAlloced = 0; /* check the length. */ if (cchFilenameBase + sizeof(".strtab.hash") > sizeof(szPath)) return -1; /* * Open the string table first. */ memcpy(szPath, pszFilenameBase, cchFilenameBase); memcpy(&szPath[cchFilenameBase], ".strtab", sizeof(".strtab")); rc = kDepDbFHOpen(&pStrTab->hStrTab, szPath, K_TRUE, &fNew); return -1; } kbuild-3149/src/kmk/vms_exit.c0000644000175000017500000000577013252530202016262 0ustar locutuslocutus/* vms_exit.c * * Wrapper for the VMS exit() command to tranlate UNIX codes to be * encoded for POSIX, but also have VMS severity levels. * The posix_exit() variant only sets a severity level for status code 1. * * Author: John E. Malmberg */ /* Copyright (C) 2014-2016 Free Software Foundation, Inc. GNU Make 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. GNU Make 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 . */ /* Per copyright assignment agreement with the Free Software Foundation this software may be available under under other license agreements and copyrights. */ #include #include void decc$exit (int status); #ifndef C_FACILITY_NO # define C_FACILITY_NO 0x350000 #endif /* Lowest legal non-success VMS exit code is 8 */ /* GNU make only defines codes 0, 1, 2 */ /* So assume any exit code > 8 is a VMS exit code */ #ifndef MAX_EXPECTED_EXIT_CODE # define MAX_EXPECTED_EXIT_CODE 7 #endif /* Build a Posix Exit with VMS severity */ void vms_exit (int status) { int vms_status; /* Fake the __posix_exit with severity added */ /* Undocumented correct way to do this. */ vms_status = 0; /* The default DECC definition is not compatible with doing a POSIX_EXIT */ /* So fix it. */ if (status == EXIT_FAILURE) status = MAKE_FAILURE; /* Trivial case exit success */ if (status == 0) decc$exit (STS$K_SUCCESS); /* Is this a VMS status then just take it */ if (status > MAX_EXPECTED_EXIT_CODE) { /* Make sure that the message inhibit is set since message has */ /* already been displayed. */ vms_status = status | STS$M_INHIB_MSG; decc$exit (vms_status); } /* Unix status codes are limited to 1 byte, so anything larger */ /* is a probably a VMS exit code and needs to be passed through */ /* A lower value can be set for a macro. */ /* Status 0 is always passed through as it is converted to SS$_NORMAL */ /* Always set the message inhibit bit */ vms_status = C_FACILITY_NO | 0xA000 | STS$M_INHIB_MSG; vms_status |= (status << 3); /* STS$K_ERROR is for status that stops makefile that a simple */ /* Rerun of the makefile will not fix. */ if (status == MAKE_FAILURE) vms_status |= STS$K_ERROR; else if (status == MAKE_TROUBLE) { /* Make trouble is for when make was told to do nothing and */ /* found that a target was not up to date. Since a second */ /* of make will produce the same condition, this is of */ /* Error severity */ vms_status |= STS$K_ERROR; } decc$exit (vms_status); } kbuild-3149/src/kmk/posixos.c0000644000175000017500000002501213252530201016116 0ustar locutuslocutus/* POSIX-based operating system interface for GNU Make. Copyright (C) 2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" #include #ifdef HAVE_FCNTL_H # include #endif #if defined(HAVE_PSELECT) && defined(HAVE_SYS_SELECT_H) # include #endif #include "debug.h" #include "job.h" #include "os.h" #ifdef MAKE_JOBSERVER /* This section provides OS-specific functions to support the jobserver. */ /* These track the state of the jobserver pipe. Passed to child instances. */ static int job_fds[2] = { -1, -1 }; /* Used to signal read() that a SIGCHLD happened. Always CLOEXEC. If we use pselect() this will never be created and always -1. */ static int job_rfd = -1; /* Token written to the pipe (could be any character...) */ static char token = '+'; static int make_job_rfd (void) { #ifdef HAVE_PSELECT /* Pretend we succeeded. */ return 0; #else EINTRLOOP (job_rfd, dup (job_fds[0])); if (job_rfd >= 0) CLOSE_ON_EXEC (job_rfd); return job_rfd; #endif } unsigned int jobserver_setup (int slots) { int r; EINTRLOOP (r, pipe (job_fds)); if (r < 0) pfatal_with_name (_("creating jobs pipe")); if (make_job_rfd () < 0) pfatal_with_name (_("duping jobs pipe")); while (slots--) { EINTRLOOP (r, write (job_fds[1], &token, 1)); if (r != 1) pfatal_with_name (_("init jobserver pipe")); } return 1; } unsigned int jobserver_parse_auth (const char *auth) { /* Given the command-line parameter, parse it. */ if (sscanf (auth, "%d,%d", &job_fds[0], &job_fds[1]) != 2) OS (fatal, NILF, _("internal error: invalid --jobserver-auth string '%s'"), auth); DB (DB_JOBS, (_("Jobserver client (fds %d,%d)\n"), job_fds[0], job_fds[1])); #ifdef HAVE_FCNTL_H # define FD_OK(_f) (fcntl ((_f), F_GETFD) != -1) #else # define FD_OK(_f) 1 #endif /* Make sure our pipeline is valid, and (possibly) create a duplicate pipe, that will be closed in the SIGCHLD handler. If this fails with EBADF, the parent has closed the pipe on us because it didn't think we were a submake. If so, warn and default to -j1. */ if (!FD_OK (job_fds[0]) || !FD_OK (job_fds[1]) || make_job_rfd () < 0) { if (errno != EBADF) pfatal_with_name (_("jobserver pipeline")); job_fds[0] = job_fds[1] = -1; return 0; } return 1; } char * jobserver_get_auth (void) { char *auth = xmalloc ((INTSTR_LENGTH * 2) + 2); sprintf (auth, "%d,%d", job_fds[0], job_fds[1]); return auth; } unsigned int jobserver_enabled (void) { return job_fds[0] >= 0; } void jobserver_clear (void) { if (job_fds[0] >= 0) close (job_fds[0]); if (job_fds[1] >= 0) close (job_fds[1]); if (job_rfd >= 0) close (job_rfd); job_fds[0] = job_fds[1] = job_rfd = -1; } void jobserver_release (int is_fatal) { int r; EINTRLOOP (r, write (job_fds[1], &token, 1)); if (r != 1) { if (is_fatal) pfatal_with_name (_("write jobserver")); perror_with_name ("write", ""); } } unsigned int jobserver_acquire_all (void) { unsigned int tokens = 0; /* Close the write side, so the read() won't hang. */ close (job_fds[1]); job_fds[1] = -1; while (1) { char intake; int r; EINTRLOOP (r, read (job_fds[0], &intake, 1)); if (r != 1) return tokens; ++tokens; } } /* Prepare the jobserver to start a child process. */ void jobserver_pre_child (int recursive) { /* If it's not a recursive make, avoid polutting the jobserver pipes. */ if (!recursive && job_fds[0] >= 0) { CLOSE_ON_EXEC (job_fds[0]); CLOSE_ON_EXEC (job_fds[1]); } } void jobserver_post_child (int recursive) { #if defined(F_GETFD) && defined(F_SETFD) if (!recursive && job_fds[0] >= 0) { unsigned int i; for (i = 0; i < 2; ++i) { int flags; EINTRLOOP (flags, fcntl (job_fds[i], F_GETFD)); if (flags >= 0) { int r; EINTRLOOP (r, fcntl (job_fds[i], F_SETFD, flags & ~FD_CLOEXEC)); } } } #endif } void jobserver_signal (void) { if (job_rfd >= 0) { close (job_rfd); job_rfd = -1; } } void jobserver_pre_acquire (void) { /* Make sure we have a dup'd FD. */ if (job_rfd < 0 && job_fds[0] >= 0 && make_job_rfd () < 0) pfatal_with_name (_("duping jobs pipe")); } #ifdef HAVE_PSELECT /* Use pselect() to atomically wait for both a signal and a file descriptor. It also provides a timeout facility so we don't need to use SIGALRM. This method relies on the fact that SIGCHLD will be blocked everywhere, and only unblocked (atomically) within the pselect() call, so we can never miss a SIGCHLD. */ unsigned int jobserver_acquire (int timeout) { sigset_t empty; fd_set readfds; struct timespec spec; struct timespec *specp = NULL; int r; char intake; sigemptyset (&empty); FD_ZERO (&readfds); FD_SET (job_fds[0], &readfds); if (timeout) { /* Alarm after one second (is this too granular?) */ spec.tv_sec = 1; spec.tv_nsec = 0; specp = &spec; } r = pselect (job_fds[0]+1, &readfds, NULL, NULL, specp, &empty); if (r == -1) { /* Better be SIGCHLD. */ if (errno != EINTR) pfatal_with_name (_("pselect jobs pipe")); return 0; } if (r == 0) /* Timeout. */ return 0; /* The read FD is ready: read it! */ EINTRLOOP (r, read (job_fds[0], &intake, 1)); if (r < 0) pfatal_with_name (_("read jobs pipe")); /* What does it mean if read() returns 0? It shouldn't happen because only the master make can reap all the tokens and close the write side...?? */ return r > 0; } #else /* This method uses a "traditional" UNIX model for waiting on both a signal and a file descriptor. However, it's complex and since we have a SIGCHLD handler installed we need to check ALL system calls for EINTR: painful! Read a token. As long as there's no token available we'll block. We enable interruptible system calls before the read(2) so that if we get a SIGCHLD while we're waiting, we'll return with EINTR and we can process the death(s) and return tokens to the free pool. Once we return from the read, we immediately reinstate restartable system calls. This allows us to not worry about checking for EINTR on all the other system calls in the program. There is one other twist: there is a span between the time reap_children() does its last check for dead children and the time the read(2) call is entered, below, where if a child dies we won't notice. This is extremely serious as it could cause us to deadlock, given the right set of events. To avoid this, we do the following: before we reap_children(), we dup(2) the read FD on the jobserver pipe. The read(2) call below uses that new FD. In the signal handler, we close that FD. That way, if a child dies during the section mentioned above, the read(2) will be invoked with an invalid FD and will return immediately with EBADF. */ static RETSIGTYPE job_noop (int sig UNUSED) { } /* Set the child handler action flags to FLAGS. */ static void set_child_handler_action_flags (int set_handler, int set_alarm) { struct sigaction sa; #ifdef __EMX__ /* The child handler must be turned off here. */ signal (SIGCHLD, SIG_DFL); #endif memset (&sa, '\0', sizeof sa); sa.sa_handler = child_handler; sa.sa_flags = set_handler ? 0 : SA_RESTART; #if defined SIGCHLD if (sigaction (SIGCHLD, &sa, NULL) < 0) pfatal_with_name ("sigaction: SIGCHLD"); #endif #if defined SIGCLD && SIGCLD != SIGCHLD if (sigaction (SIGCLD, &sa, NULL) < 0) pfatal_with_name ("sigaction: SIGCLD"); #endif #if defined SIGALRM if (set_alarm) { /* If we're about to enter the read(), set an alarm to wake up in a second so we can check if the load has dropped and we can start more work. On the way out, turn off the alarm and set SIG_DFL. */ if (set_handler) { sa.sa_handler = job_noop; sa.sa_flags = 0; if (sigaction (SIGALRM, &sa, NULL) < 0) pfatal_with_name ("sigaction: SIGALRM"); alarm (1); } else { alarm (0); sa.sa_handler = SIG_DFL; sa.sa_flags = 0; if (sigaction (SIGALRM, &sa, NULL) < 0) pfatal_with_name ("sigaction: SIGALRM"); } } #endif } unsigned int jobserver_acquire (int timeout) { char intake; int got_token; int saved_errno; /* Set interruptible system calls, and read() for a job token. */ set_child_handler_action_flags (1, timeout); EINTRLOOP (got_token, read (job_rfd, &intake, 1)); saved_errno = errno; set_child_handler_action_flags (0, timeout); if (got_token == 1) return 1; /* If the error _wasn't_ expected (EINTR or EBADF), fatal. Otherwise, go back and reap_children(), and try again. */ errno = saved_errno; if (errno != EINTR && errno != EBADF) pfatal_with_name (_("read jobs pipe")); if (errno == EBADF) DB (DB_JOBS, ("Read returned EBADF.\n")); return 0; } #endif #endif /* MAKE_JOBSERVER */ /* Create a "bad" file descriptor for stdin when parallel jobs are run. */ int get_bad_stdin (void) { static int bad_stdin = -1; /* Set up a bad standard input that reads from a broken pipe. */ if (bad_stdin == -1) { /* Make a file descriptor that is the read end of a broken pipe. This will be used for some children's standard inputs. */ int pd[2]; if (pipe (pd) == 0) { /* Close the write side. */ (void) close (pd[1]); /* Save the read side. */ bad_stdin = pd[0]; /* Set the descriptor to close on exec, so it does not litter any child's descriptor table. When it is dup2'd onto descriptor 0, that descriptor will not close on exec. */ CLOSE_ON_EXEC (bad_stdin); } } return bad_stdin; } kbuild-3149/src/kmk/expreval.c0000644000175000017500000015157613252530176016272 0ustar locutuslocutus#ifdef CONFIG_WITH_IF_CONDITIONALS /* $Id: expreval.c 3141 2018-03-14 21:58:32Z bird $ */ /** @file * expreval - Expressions evaluator, C / BSD make / nmake style. */ /* * Copyright (c) 2008-2010 knut st. osmundsen * * This file is part of kBuild. * * kBuild 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. * * kBuild 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 kBuild. If not, see * */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "makeint.h" #include #include #include "filedef.h" #include "dep.h" #include "job.h" #include "commands.h" #include "variable.h" #include "rule.h" #include "debug.h" #include "hash.h" #include #ifndef _MSC_VER # include #endif #include /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** The max length of a string representation of a number. */ #define EXPR_NUM_LEN ((sizeof("-9223372036854775802") + 4) & ~3) /** The max operator stack depth. */ #define EXPR_MAX_OPERATORS 72 /** The max operand depth. */ #define EXPR_MAX_OPERANDS 128 /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** The 64-bit signed integer type we're using. */ #ifdef _MSC_VER typedef __int64 EXPRINT64; #else # include typedef int64_t EXPRINT64; #endif /** Pointer to a evaluator instance. */ typedef struct EXPR *PEXPR; /** * Operand variable type. */ typedef enum { /** Invalid zero entry. */ kExprVar_Invalid = 0, /** A number. */ kExprVar_Num, /** A string in need of expanding (perhaps). */ kExprVar_String, /** A simple string that doesn't need expanding. */ kExprVar_SimpleString, /** A quoted string in need of expanding (perhaps). */ kExprVar_QuotedString, /** A simple quoted string that doesn't need expanding. */ kExprVar_QuotedSimpleString, /** The end of the valid variable types. */ kExprVar_End } EXPRVARTYPE; /** * Operand variable. */ typedef struct { /** The variable type. */ EXPRVARTYPE enmType; /** The variable. */ union { /** Pointer to the string. */ char *psz; /** The variable. */ EXPRINT64 i; } uVal; } EXPRVAR; /** Pointer to a operand variable. */ typedef EXPRVAR *PEXPRVAR; /** Pointer to a const operand variable. */ typedef EXPRVAR const *PCEXPRVAR; /** * Operator return statuses. */ typedef enum { kExprRet_Error = -1, kExprRet_Ok = 0, kExprRet_Operator, kExprRet_Operand, kExprRet_EndOfExpr, kExprRet_End } EXPRRET; /** * Operator. */ typedef struct { /** The operator. */ char szOp[11]; /** The length of the operator string. */ char cchOp; /** The pair operator. * This is used with '(' and '?'. */ char chPair; /** The precedence. Higher means higher. */ char iPrecedence; /** The number of arguments it takes. */ signed char cArgs; /** Pointer to the method implementing the operator. */ EXPRRET (*pfn)(PEXPR pThis); } EXPROP; /** Pointer to a const operator. */ typedef EXPROP const *PCEXPROP; /** * Expression evaluator instance. */ typedef struct EXPR { /** The full expression. */ const char *pszExpr; /** The current location. */ const char *psz; /** The current file location, used for errors. */ const floc *pFileLoc; /** Pending binary operator. */ PCEXPROP pPending; /** Top of the operator stack. */ int iOp; /** Top of the operand stack. */ int iVar; /** The operator stack. */ PCEXPROP apOps[EXPR_MAX_OPERATORS]; /** The operand stack. */ EXPRVAR aVars[EXPR_MAX_OPERANDS]; } EXPR; /******************************************************************************* * Global Variables * *******************************************************************************/ /** Operator start character map. * This indicates which characters that are starting operators and which aren't. */ static char g_auchOpStartCharMap[256]; /** Whether we've initialized the map. */ static int g_fExprInitializedMap = 0; /******************************************************************************* * Internal Functions * *******************************************************************************/ static void expr_unget_op(PEXPR pThis); static EXPRRET expr_get_binary_or_eoe_or_rparen(PEXPR pThis); /** * Displays an error message. * * The total string length must not exceed 256 bytes. * * @param pThis The evaluator instance. * @param pszError The message format string. * @param ... The message format args. */ static void expr_error(PEXPR pThis, const char *pszError, ...) { char szTmp[256]; va_list va; va_start(va, pszError); vsprintf(szTmp, pszError, va); va_end(va); OS(fatal,pThis->pFileLoc, "%s", szTmp); } /** * Converts a number to a string. * * @returns pszDst. * @param pszDst The string buffer to write into. Assumes length of EXPR_NUM_LEN. * @param iSrc The number to convert. */ static char *expr_num_to_string(char *pszDst, EXPRINT64 iSrc) { static const char s_szDigits[17] = "0123456789abcdef"; char szTmp[EXPR_NUM_LEN]; char *psz = &szTmp[EXPR_NUM_LEN - 1]; int fNegative; fNegative = iSrc < 0; if (fNegative) { /** @todo this isn't right for INT64_MIN. */ iSrc = -iSrc; } *psz = '\0'; do { #if 0 *--psz = s_szDigits[iSrc & 0xf]; iSrc >>= 4; #else *--psz = s_szDigits[iSrc % 10]; iSrc /= 10; #endif } while (iSrc); #if 0 *--psz = 'x'; *--psz = '0'; #endif if (fNegative) *--psz = '-'; /* copy it into the output buffer. */ return (char *)memcpy(pszDst, psz, &szTmp[EXPR_NUM_LEN] - psz); } /** * Attempts to convert a (simple) string into a number. * * @returns status code. * @param pThis The evaluator instance. This is optional when fQuiet is true. * @param piSrc Where to store the numeric value on success. * @param pszSrc The string to try convert. * @param fQuiet Whether we should be quiet or grumpy on failure. */ static EXPRRET expr_string_to_num(PEXPR pThis, EXPRINT64 *piDst, const char *pszSrc, int fQuiet) { EXPRRET rc = kExprRet_Ok; char const *psz = pszSrc; EXPRINT64 i; unsigned uBase; int fNegative; /* * Skip blanks. */ while (ISBLANK(*psz)) psz++; /* * Check for '-'. * * At this point we will not need to deal with operators, this is * just an indicator of negative numbers. If some operator ends up * here it's because it came from a string expansion and thus shall * not be interpreted. If this turns out to be an stupid restriction * it can be fixed, but for now it stays like this. */ fNegative = *psz == '-'; if (fNegative) psz++; /* * Determin base . * . * Recognize some exsotic prefixes here in addition to the two standard ones. */ if (*psz != '0' || psz[1] == '\0' || ISBLANK(psz[1])) uBase = 10; else if (psz[1] == 'x' || psz[1] == 'X') { uBase = 16; psz += 2; } else if (psz[1] == 'b' || psz[1] == 'B') { uBase = 2; psz += 2; } else if (psz[1] == 'd' || psz[1] == 'D') { uBase = 10; psz += 2; } else if (psz[1] == 'o' || psz[1] == 'O') { uBase = 8; psz += 2; } else if (isdigit(psz[1]) && psz[1] != '9' && psz[1] != '8') { uBase = 8; psz++; } else uBase = 10; /* * Convert until we hit a non-digit. */ i = 0; for (;;) { unsigned iDigit; int ch = *psz; switch (ch) { case '0': iDigit = 0; break; case '1': iDigit = 1; break; case '2': iDigit = 2; break; case '3': iDigit = 3; break; case '4': iDigit = 4; break; case '5': iDigit = 5; break; case '6': iDigit = 6; break; case '7': iDigit = 7; break; case '8': iDigit = 8; break; case '9': iDigit = 9; break; case 'a': case 'A': iDigit = 10; break; case 'b': case 'B': iDigit = 11; break; case 'c': case 'C': iDigit = 12; break; case 'd': case 'D': iDigit = 13; break; case 'e': case 'E': iDigit = 14; break; case 'f': case 'F': iDigit = 15; break; default: /* is the rest white space? */ while (ISSPACE(*psz)) psz++; if (*psz != '\0') { iDigit = uBase; break; } /* fall thru */ case '\0': if (fNegative) i = -i; *piDst = i; return rc; } if (iDigit >= uBase) { if (fNegative) i = -i; *piDst = i; if (!fQuiet) expr_error(pThis, "Invalid number \"%.80s\"", pszSrc); return kExprRet_Error; } /* add the digit and advance */ i *= uBase; i += iDigit; psz++; } /* not reached */ } /** * Checks if the variable is a string or not. * * @returns 1 if it's a string, 0 otherwise. * @param pVar The variable. */ static int expr_var_is_string(PCEXPRVAR pVar) { return pVar->enmType >= kExprVar_String; } /** * Checks if the variable contains a string that was quoted * in the expression. * * @returns 1 if if was a quoted string, otherwise 0. * @param pVar The variable. */ static int expr_var_was_quoted(PCEXPRVAR pVar) { return pVar->enmType >= kExprVar_QuotedString; } /** * Deletes a variable. * * @param pVar The variable. */ static void expr_var_delete(PEXPRVAR pVar) { if (expr_var_is_string(pVar)) { free(pVar->uVal.psz); pVar->uVal.psz = NULL; } pVar->enmType = kExprVar_Invalid; } /** * Initializes a new variables with a sub-string value. * * @param pVar The new variable. * @param psz The start of the string value. * @param cch The number of chars to copy. * @param enmType The string type. */ static void expr_var_init_substring(PEXPRVAR pVar, const char *psz, size_t cch, EXPRVARTYPE enmType) { /* convert string needing expanding into simple ones if possible. */ if ( enmType == kExprVar_String && !memchr(psz, '$', cch)) enmType = kExprVar_SimpleString; else if ( enmType == kExprVar_QuotedString && !memchr(psz, '$', cch)) enmType = kExprVar_QuotedSimpleString; pVar->enmType = enmType; pVar->uVal.psz = xmalloc(cch + 1); memcpy(pVar->uVal.psz, psz, cch); pVar->uVal.psz[cch] = '\0'; } #if 0 /* unused */ /** * Initializes a new variables with a string value. * * @param pVar The new variable. * @param psz The string value. * @param enmType The string type. */ static void expr_var_init_string(PEXPRVAR pVar, const char *psz, EXPRVARTYPE enmType) { expr_var_init_substring(pVar, psz, strlen(psz), enmType); } /** * Assigns a sub-string value to a variable. * * @param pVar The new variable. * @param psz The start of the string value. * @param cch The number of chars to copy. * @param enmType The string type. */ static void expr_var_assign_substring(PEXPRVAR pVar, const char *psz, size_t cch, EXPRVARTYPE enmType) { expr_var_delete(pVar); expr_var_init_substring(pVar, psz, cch, enmType); } /** * Assignes a string value to a variable. * * @param pVar The variable. * @param psz The string value. * @param enmType The string type. */ static void expr_var_assign_string(PEXPRVAR pVar, const char *psz, EXPRVARTYPE enmType) { expr_var_delete(pVar); expr_var_init_string(pVar, psz, enmType); } #endif /* unused */ /** * Simplifies a string variable. * * @param pVar The variable. */ static void expr_var_make_simple_string(PEXPRVAR pVar) { switch (pVar->enmType) { case kExprVar_Num: { char *psz = (char *)xmalloc(EXPR_NUM_LEN); expr_num_to_string(psz, pVar->uVal.i); pVar->uVal.psz = psz; pVar->enmType = kExprVar_SimpleString; break; } case kExprVar_String: case kExprVar_QuotedString: { char *psz; assert(strchr(pVar->uVal.psz, '$')); psz = allocated_variable_expand(pVar->uVal.psz); free(pVar->uVal.psz); pVar->uVal.psz = psz; pVar->enmType = pVar->enmType == kExprVar_String ? kExprVar_SimpleString : kExprVar_QuotedSimpleString; break; } case kExprVar_SimpleString: case kExprVar_QuotedSimpleString: /* nothing to do. */ break; default: assert(0); } } #if 0 /* unused */ /** * Turns a variable into a string value. * * @param pVar The variable. */ static void expr_var_make_string(PEXPRVAR pVar) { switch (pVar->enmType) { case kExprVar_Num: expr_var_make_simple_string(pVar); break; case kExprVar_String: case kExprVar_SimpleString: case kExprVar_QuotedString: case kExprVar_QuotedSimpleString: /* nothing to do. */ break; default: assert(0); } } #endif /* unused */ /** * Initializes a new variables with a integer value. * * @param pVar The new variable. * @param i The integer value. */ static void expr_var_init_num(PEXPRVAR pVar, EXPRINT64 i) { pVar->enmType = kExprVar_Num; pVar->uVal.i = i; } /** * Assigns a integer value to a variable. * * @param pVar The variable. * @param i The integer value. */ static void expr_var_assign_num(PEXPRVAR pVar, EXPRINT64 i) { expr_var_delete(pVar); expr_var_init_num(pVar, i); } /** * Turns the variable into a number. * * @returns status code. * @param pThis The evaluator instance. * @param pVar The variable. */ static EXPRRET expr_var_make_num(PEXPR pThis, PEXPRVAR pVar) { switch (pVar->enmType) { case kExprVar_Num: /* nothing to do. */ break; case kExprVar_String: expr_var_make_simple_string(pVar); /* fall thru */ case kExprVar_SimpleString: { EXPRINT64 i; EXPRRET rc = expr_string_to_num(pThis, &i, pVar->uVal.psz, 0 /* fQuiet */); if (rc < kExprRet_Ok) return rc; expr_var_assign_num(pVar, i); break; } case kExprVar_QuotedString: case kExprVar_QuotedSimpleString: expr_error(pThis, "Cannot convert a quoted string to a number"); return kExprRet_Error; default: assert(0); return kExprRet_Error; } return kExprRet_Ok; } /** * Try to turn the variable into a number. * * @returns status code. * @param pVar The variable. */ static EXPRRET expr_var_try_make_num(PEXPRVAR pVar) { switch (pVar->enmType) { case kExprVar_Num: /* nothing to do. */ break; case kExprVar_String: expr_var_make_simple_string(pVar); /* fall thru */ case kExprVar_SimpleString: { EXPRINT64 i; EXPRRET rc = expr_string_to_num(NULL, &i, pVar->uVal.psz, 1 /* fQuiet */); if (rc < kExprRet_Ok) return rc; expr_var_assign_num(pVar, i); break; } default: assert(0); case kExprVar_QuotedString: case kExprVar_QuotedSimpleString: /* can't do this */ return kExprRet_Error; } return kExprRet_Ok; } /** * Initializes a new variables with a boolean value. * * @param pVar The new variable. * @param f The boolean value. */ static void expr_var_init_bool(PEXPRVAR pVar, int f) { pVar->enmType = kExprVar_Num; pVar->uVal.i = !!f; } /** * Assigns a boolean value to a variable. * * @param pVar The variable. * @param f The boolean value. */ static void expr_var_assign_bool(PEXPRVAR pVar, int f) { expr_var_delete(pVar); expr_var_init_bool(pVar, f); } /** * Turns the variable into an boolean. * * @returns the boolean interpretation. * @param pVar The variable. */ static int expr_var_make_bool(PEXPRVAR pVar) { switch (pVar->enmType) { case kExprVar_Num: pVar->uVal.i = !!pVar->uVal.i; break; case kExprVar_String: expr_var_make_simple_string(pVar); /* fall thru */ case kExprVar_SimpleString: { /* * Try convert it to a number. If that fails, use the * GNU make boolean logic - not empty string means true. */ EXPRINT64 iVal; char const *psz = pVar->uVal.psz; while (ISBLANK(*psz)) psz++; if ( *psz && expr_string_to_num(NULL, &iVal, psz, 1 /* fQuiet */) >= kExprRet_Ok) expr_var_assign_bool(pVar, iVal != 0); else expr_var_assign_bool(pVar, *psz != '\0'); break; } case kExprVar_QuotedString: expr_var_make_simple_string(pVar); /* fall thru */ case kExprVar_QuotedSimpleString: /* * Use GNU make boolean logic (not empty string means true). * No stripping here, the string is quoted. */ expr_var_assign_bool(pVar, *pVar->uVal.psz != '\0'); break; default: assert(0); break; } return pVar->uVal.i; } /** * Pops a varable off the stack and deletes it. * @param pThis The evaluator instance. */ static void expr_pop_and_delete_var(PEXPR pThis) { expr_var_delete(&pThis->aVars[pThis->iVar]); pThis->iVar--; } /** * Tries to make the variables the same type. * * This will not convert numbers to strings, unless one of them * is a quoted string. * * this will try convert both to numbers if neither is quoted. Both * conversions will have to suceed for this to be commited. * * All strings will be simplified. * * @returns status code. Done complaining on failure. * * @param pThis The evaluator instance. * @param pVar1 The first variable. * @param pVar2 The second variable. */ static EXPRRET expr_var_unify_types(PEXPR pThis, PEXPRVAR pVar1, PEXPRVAR pVar2, const char *pszOp) { /* * Try make the variables the same type before comparing. */ if ( !expr_var_was_quoted(pVar1) && !expr_var_was_quoted(pVar2)) { if ( expr_var_is_string(pVar1) || expr_var_is_string(pVar2)) { if (!expr_var_is_string(pVar1)) expr_var_try_make_num(pVar2); else if (!expr_var_is_string(pVar2)) expr_var_try_make_num(pVar1); else { /* * Both are strings, simplify them then see if both can be made into numbers. */ EXPRINT64 iVar1; EXPRINT64 iVar2; expr_var_make_simple_string(pVar1); expr_var_make_simple_string(pVar2); if ( expr_string_to_num(NULL, &iVar1, pVar1->uVal.psz, 1 /* fQuiet */) >= kExprRet_Ok && expr_string_to_num(NULL, &iVar2, pVar2->uVal.psz, 1 /* fQuiet */) >= kExprRet_Ok) { expr_var_assign_num(pVar1, iVar1); expr_var_assign_num(pVar2, iVar2); } } } } else { expr_var_make_simple_string(pVar1); expr_var_make_simple_string(pVar2); } /* * Complain if they aren't the same type now. */ if (expr_var_is_string(pVar1) != expr_var_is_string(pVar2)) { expr_error(pThis, "Unable to unify types for \"%s\"", pszOp); return kExprRet_Error; } return kExprRet_Ok; } /** * Is variable defined, unary. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_defined(PEXPR pThis) { PEXPRVAR pVar = &pThis->aVars[pThis->iVar]; struct variable *pMakeVar; expr_var_make_simple_string(pVar); pMakeVar = lookup_variable(pVar->uVal.psz, strlen(pVar->uVal.psz)); expr_var_assign_bool(pVar, pMakeVar && *pMakeVar->value != '\0'); return kExprRet_Ok; } /** * Does file(/dir/whatever) exist, unary. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_exists(PEXPR pThis) { PEXPRVAR pVar = &pThis->aVars[pThis->iVar]; struct stat st; expr_var_make_simple_string(pVar); expr_var_assign_bool(pVar, stat(pVar->uVal.psz, &st) == 0); return kExprRet_Ok; } /** * Is target defined, unary. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_target(PEXPR pThis) { PEXPRVAR pVar = &pThis->aVars[pThis->iVar]; struct file *pFile = NULL; /* * Because of secondary target expansion, lookup the unexpanded * name first. */ #ifdef CONFIG_WITH_2ND_TARGET_EXPANSION if ( pVar->enmType == kExprVar_String || pVar->enmType == kExprVar_QuotedString) { pFile = lookup_file(pVar->uVal.psz); if ( pFile && !pFile->need_2nd_target_expansion) pFile = NULL; } if (!pFile) #endif { expr_var_make_simple_string(pVar); pFile = lookup_file(pVar->uVal.psz); } /* * Always inspect the head of a multiple target rule * and look for a file with commands. */ #ifdef CONFIG_WITH_EXPLICIT_MULTITARGET if (pFile && pFile->multi_head) pFile = pFile->multi_head; #endif while (pFile && !pFile->cmds) pFile = pFile->prev; expr_var_assign_bool(pVar, pFile != NULL && pFile->is_target); return kExprRet_Ok; } /** * Convert to boolean. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_bool(PEXPR pThis) { expr_var_make_bool(&pThis->aVars[pThis->iVar]); return kExprRet_Ok; } /** * Convert to number, works on quoted strings too. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_num(PEXPR pThis) { PEXPRVAR pVar = &pThis->aVars[pThis->iVar]; /* unquote the string */ if (pVar->enmType == kExprVar_QuotedSimpleString) pVar->enmType = kExprVar_SimpleString; else if (pVar->enmType == kExprVar_QuotedString) pVar->enmType = kExprVar_String; return expr_var_make_num(pThis, pVar); } /** * Convert to string (simplified and quoted) * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_str(PEXPR pThis) { PEXPRVAR pVar = &pThis->aVars[pThis->iVar]; expr_var_make_simple_string(pVar); pVar->enmType = kExprVar_QuotedSimpleString; return kExprRet_Ok; } /** * Pluss (dummy / make_integer) * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_pluss(PEXPR pThis) { return expr_var_make_num(pThis, &pThis->aVars[pThis->iVar]); } /** * Minus (negate) * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_minus(PEXPR pThis) { EXPRRET rc; PEXPRVAR pVar = &pThis->aVars[pThis->iVar]; rc = expr_var_make_num(pThis, pVar); if (rc >= kExprRet_Ok) pVar->uVal.i = -pVar->uVal.i; return rc; } /** * Bitwise NOT. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_bitwise_not(PEXPR pThis) { EXPRRET rc; PEXPRVAR pVar = &pThis->aVars[pThis->iVar]; rc = expr_var_make_num(pThis, pVar); if (rc >= kExprRet_Ok) pVar->uVal.i = ~pVar->uVal.i; return rc; } /** * Logical NOT. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_logical_not(PEXPR pThis) { PEXPRVAR pVar = &pThis->aVars[pThis->iVar]; expr_var_make_bool(pVar); pVar->uVal.i = !pVar->uVal.i; return kExprRet_Ok; } /** * Multiplication. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_multiply(PEXPR pThis) { EXPRRET rc = kExprRet_Ok; PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; rc = expr_var_make_num(pThis, pVar1); if (rc >= kExprRet_Ok) { rc = expr_var_make_num(pThis, pVar2); if (rc >= kExprRet_Ok) pVar1->uVal.i *= pVar2->uVal.i; } expr_pop_and_delete_var(pThis); return rc; } /** * Division. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_divide(PEXPR pThis) { EXPRRET rc = kExprRet_Ok; PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; rc = expr_var_make_num(pThis, pVar1); if (rc >= kExprRet_Ok) { rc = expr_var_make_num(pThis, pVar2); if (rc >= kExprRet_Ok) pVar1->uVal.i /= pVar2->uVal.i; } expr_pop_and_delete_var(pThis); return rc; } /** * Modulus. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_modulus(PEXPR pThis) { EXPRRET rc = kExprRet_Ok; PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; rc = expr_var_make_num(pThis, pVar1); if (rc >= kExprRet_Ok) { rc = expr_var_make_num(pThis, pVar2); if (rc >= kExprRet_Ok) pVar1->uVal.i %= pVar2->uVal.i; } expr_pop_and_delete_var(pThis); return rc; } /** * Addition (numeric). * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_add(PEXPR pThis) { EXPRRET rc = kExprRet_Ok; PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; rc = expr_var_make_num(pThis, pVar1); if (rc >= kExprRet_Ok) { rc = expr_var_make_num(pThis, pVar2); if (rc >= kExprRet_Ok) pVar1->uVal.i += pVar2->uVal.i; } expr_pop_and_delete_var(pThis); return rc; } /** * Subtract (numeric). * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_sub(PEXPR pThis) { EXPRRET rc = kExprRet_Ok; PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; rc = expr_var_make_num(pThis, pVar1); if (rc >= kExprRet_Ok) { rc = expr_var_make_num(pThis, pVar2); if (rc >= kExprRet_Ok) pVar1->uVal.i -= pVar2->uVal.i; } expr_pop_and_delete_var(pThis); return rc; } /** * Bitwise left shift. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_shift_left(PEXPR pThis) { EXPRRET rc = kExprRet_Ok; PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; rc = expr_var_make_num(pThis, pVar1); if (rc >= kExprRet_Ok) { rc = expr_var_make_num(pThis, pVar2); if (rc >= kExprRet_Ok) pVar1->uVal.i <<= pVar2->uVal.i; } expr_pop_and_delete_var(pThis); return rc; } /** * Bitwise right shift. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_shift_right(PEXPR pThis) { EXPRRET rc = kExprRet_Ok; PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; rc = expr_var_make_num(pThis, pVar1); if (rc >= kExprRet_Ok) { rc = expr_var_make_num(pThis, pVar2); if (rc >= kExprRet_Ok) pVar1->uVal.i >>= pVar2->uVal.i; } expr_pop_and_delete_var(pThis); return rc; } /** * Less than or equal * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_less_or_equal_than(PEXPR pThis) { EXPRRET rc = kExprRet_Ok; PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; rc = expr_var_unify_types(pThis, pVar1, pVar2, "<="); if (rc >= kExprRet_Ok) { if (!expr_var_is_string(pVar1)) expr_var_assign_bool(pVar1, pVar1->uVal.i <= pVar2->uVal.i); else expr_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) <= 0); } expr_pop_and_delete_var(pThis); return rc; } /** * Less than. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_less_than(PEXPR pThis) { EXPRRET rc = kExprRet_Ok; PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; rc = expr_var_unify_types(pThis, pVar1, pVar2, "<"); if (rc >= kExprRet_Ok) { if (!expr_var_is_string(pVar1)) expr_var_assign_bool(pVar1, pVar1->uVal.i < pVar2->uVal.i); else expr_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) < 0); } expr_pop_and_delete_var(pThis); return rc; } /** * Greater or equal than * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_greater_or_equal_than(PEXPR pThis) { EXPRRET rc = kExprRet_Ok; PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; rc = expr_var_unify_types(pThis, pVar1, pVar2, ">="); if (rc >= kExprRet_Ok) { if (!expr_var_is_string(pVar1)) expr_var_assign_bool(pVar1, pVar1->uVal.i >= pVar2->uVal.i); else expr_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) >= 0); } expr_pop_and_delete_var(pThis); return rc; } /** * Greater than. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_greater_than(PEXPR pThis) { EXPRRET rc = kExprRet_Ok; PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; rc = expr_var_unify_types(pThis, pVar1, pVar2, ">"); if (rc >= kExprRet_Ok) { if (!expr_var_is_string(pVar1)) expr_var_assign_bool(pVar1, pVar1->uVal.i > pVar2->uVal.i); else expr_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) > 0); } expr_pop_and_delete_var(pThis); return rc; } /** * Equal. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_equal(PEXPR pThis) { EXPRRET rc = kExprRet_Ok; PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; /* * The same type? */ if (expr_var_is_string(pVar1) == expr_var_is_string(pVar2)) { if (!expr_var_is_string(pVar1)) /* numbers are simple */ expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i); else { /* try a normal string compare. */ expr_var_make_simple_string(pVar1); expr_var_make_simple_string(pVar2); if (!strcmp(pVar1->uVal.psz, pVar2->uVal.psz)) expr_var_assign_bool(pVar1, 1); /* try convert and compare as number instead. */ else if ( expr_var_try_make_num(pVar1) >= kExprRet_Ok && expr_var_try_make_num(pVar2) >= kExprRet_Ok) expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i); /* ok, they really aren't equal. */ else expr_var_assign_bool(pVar1, 0); } } else { /* * If the type differs, there are now two options: * 1. Convert the string to a valid number and compare the numbers. * 2. Convert an empty string to a 'false' boolean value and compare * numerically. This one is a bit questionable, so we don't try this. */ if ( expr_var_try_make_num(pVar1) >= kExprRet_Ok && expr_var_try_make_num(pVar2) >= kExprRet_Ok) expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i); else { expr_error(pThis, "Cannot compare strings and numbers"); rc = kExprRet_Error; } } expr_pop_and_delete_var(pThis); return rc; } /** * Not equal. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_not_equal(PEXPR pThis) { EXPRRET rc = expr_op_equal(pThis); if (rc >= kExprRet_Ok) rc = expr_op_logical_not(pThis); return rc; } /** * Bitwise AND. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_bitwise_and(PEXPR pThis) { PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; EXPRRET rc; rc = expr_var_make_num(pThis, pVar1); if (rc >= kExprRet_Ok) { rc = expr_var_make_num(pThis, pVar2); if (rc >= kExprRet_Ok) pVar1->uVal.i &= pVar2->uVal.i; } expr_pop_and_delete_var(pThis); return kExprRet_Ok; } /** * Bitwise XOR. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_bitwise_xor(PEXPR pThis) { PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; EXPRRET rc; rc = expr_var_make_num(pThis, pVar1); if (rc >= kExprRet_Ok) { rc = expr_var_make_num(pThis, pVar2); if (rc >= kExprRet_Ok) pVar1->uVal.i ^= pVar2->uVal.i; } expr_pop_and_delete_var(pThis); return kExprRet_Ok; } /** * Bitwise OR. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_bitwise_or(PEXPR pThis) { PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; EXPRRET rc; rc = expr_var_make_num(pThis, pVar1); if (rc >= kExprRet_Ok) { rc = expr_var_make_num(pThis, pVar2); if (rc >= kExprRet_Ok) pVar1->uVal.i |= pVar2->uVal.i; } expr_pop_and_delete_var(pThis); return kExprRet_Ok; } /** * Logical AND. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_logical_and(PEXPR pThis) { PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; if ( expr_var_make_bool(pVar1) && expr_var_make_bool(pVar2)) expr_var_assign_bool(pVar1, 1); else expr_var_assign_bool(pVar1, 0); expr_pop_and_delete_var(pThis); return kExprRet_Ok; } /** * Logical OR. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_logical_or(PEXPR pThis) { PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; if ( expr_var_make_bool(pVar1) || expr_var_make_bool(pVar2)) expr_var_assign_bool(pVar1, 1); else expr_var_assign_bool(pVar1, 0); expr_pop_and_delete_var(pThis); return kExprRet_Ok; } /** * Left parenthesis. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_left_parenthesis(PEXPR pThis) { /* * There should be a right parenthesis operator lined up for us now, * eat it. If not found there is an inbalance. */ EXPRRET rc = expr_get_binary_or_eoe_or_rparen(pThis); if ( rc == kExprRet_Operator && pThis->apOps[pThis->iOp]->szOp[0] == ')') { /* pop it and get another one which we can leave pending. */ pThis->iOp--; rc = expr_get_binary_or_eoe_or_rparen(pThis); if (rc >= kExprRet_Ok) expr_unget_op(pThis); } else { expr_error(pThis, "Missing ')'"); rc = kExprRet_Error; } return rc; } /** * Right parenthesis, dummy that's never actually called. * * @returns Status code. * @param pThis The instance. */ static EXPRRET expr_op_right_parenthesis(PEXPR pThis) { assert(0); (void)pThis; return kExprRet_Ok; } /** * The operator table. * * This table is NOT ordered by precedence, but for linear search * allowing for first match to return the correct operator. This * means that || must come before |, or else | will match all. */ static const EXPROP g_aExprOps[] = { #define EXPR_OP(szOp, iPrecedence, cArgs, pfn) { szOp, sizeof(szOp) - 1, '\0', iPrecedence, cArgs, pfn } /* Name, iPrecedence, cArgs, pfn */ EXPR_OP("defined", 90, 1, expr_op_defined), EXPR_OP("exists", 90, 1, expr_op_exists), EXPR_OP("target", 90, 1, expr_op_target), EXPR_OP("bool", 90, 1, expr_op_bool), EXPR_OP("num", 90, 1, expr_op_num), EXPR_OP("str", 90, 1, expr_op_str), EXPR_OP("+", 80, 1, expr_op_pluss), EXPR_OP("-", 80, 1, expr_op_minus), EXPR_OP("~", 80, 1, expr_op_bitwise_not), EXPR_OP("*", 75, 2, expr_op_multiply), EXPR_OP("/", 75, 2, expr_op_divide), EXPR_OP("%", 75, 2, expr_op_modulus), EXPR_OP("+", 70, 2, expr_op_add), EXPR_OP("-", 70, 2, expr_op_sub), EXPR_OP("<<", 65, 2, expr_op_shift_left), EXPR_OP(">>", 65, 2, expr_op_shift_right), EXPR_OP("<=", 60, 2, expr_op_less_or_equal_than), EXPR_OP("<", 60, 2, expr_op_less_than), EXPR_OP(">=", 60, 2, expr_op_greater_or_equal_than), EXPR_OP(">", 60, 2, expr_op_greater_than), EXPR_OP("==", 55, 2, expr_op_equal), EXPR_OP("!=", 55, 2, expr_op_not_equal), EXPR_OP("!", 80, 1, expr_op_logical_not), EXPR_OP("^", 45, 2, expr_op_bitwise_xor), EXPR_OP("&&", 35, 2, expr_op_logical_and), EXPR_OP("&", 50, 2, expr_op_bitwise_and), EXPR_OP("||", 30, 2, expr_op_logical_or), EXPR_OP("|", 40, 2, expr_op_bitwise_or), { "(", 1, ')', 10, 1, expr_op_left_parenthesis }, { ")", 1, '(', 10, 0, expr_op_right_parenthesis }, /* { "?", 1, ':', 5, 2, expr_op_question }, { ":", 1, '?', 5, 2, expr_op_colon }, -- too weird for now. */ #undef EXPR_OP }; /** Dummy end of expression fake. */ static const EXPROP g_ExprEndOfExpOp = { "", 0, '\0', 0, 0, NULL }; /** * Initializes the opcode character map if necessary. */ static void expr_map_init(void) { unsigned i; if (g_fExprInitializedMap) return; /* * Initialize it. */ memset(&g_auchOpStartCharMap, 0, sizeof(g_auchOpStartCharMap)); for (i = 0; i < sizeof(g_aExprOps) / sizeof(g_aExprOps[0]); i++) { unsigned int ch = (unsigned int)g_aExprOps[i].szOp[0]; if (!g_auchOpStartCharMap[ch]) g_auchOpStartCharMap[ch] = (i << 1) | 1; } g_fExprInitializedMap = 1; } /** * Looks up a character in the map. * * @returns the value for that char. * @retval 0 if not a potential opcode start char. * @retval non-zero if it's a potential operator. The low bit is always set * while the remaining 7 bits is the index into the operator table * of the first match. * * @param ch The character. */ static unsigned char expr_map_get(char ch) { return g_auchOpStartCharMap[(unsigned int)ch]; } /** * Searches the operator table given a potential operator start char. * * @returns Pointer to the matching operator. NULL if not found. * @param psz Pointer to what can be an operator. * @param uchVal The expr_map_get value. * @param fUnary Whether it must be an unary operator or not. */ static PCEXPROP expr_lookup_op(char const *psz, unsigned char uchVal, int fUnary) { char ch = *psz; unsigned i; for (i = uchVal >> 1; i < sizeof(g_aExprOps) / sizeof(g_aExprOps[0]); i++) { /* compare the string... */ switch (g_aExprOps[i].cchOp) { case 1: if (g_aExprOps[i].szOp[0] != ch) continue; break; case 2: if ( g_aExprOps[i].szOp[0] != ch || g_aExprOps[i].szOp[1] != psz[1]) continue; break; default: if ( g_aExprOps[i].szOp[0] != ch || strncmp(&g_aExprOps[i].szOp[1], psz + 1, g_aExprOps[i].cchOp - 1)) continue; break; } /* ... and the operator type. */ if (fUnary == (g_aExprOps[i].cArgs == 1)) { /* got a match! */ return &g_aExprOps[i]; } } return NULL; } /** * Ungets a binary operator. * * The operator is poped from the stack and put in the pending position. * * @param pThis The evaluator instance. */ static void expr_unget_op(PEXPR pThis) { assert(pThis->pPending == NULL); assert(pThis->iOp >= 0); pThis->pPending = pThis->apOps[pThis->iOp]; pThis->apOps[pThis->iOp] = NULL; pThis->iOp--; } /** * Get the next token, it should be a binary operator, or the end of * the expression, or a right parenthesis. * * The operator is pushed onto the stack and the status code indicates * which of the two we found. * * @returns status code. Will grumble on failure. * @retval kExprRet_EndOfExpr if we encountered the end of the expression. * @retval kExprRet_Operator if we encountered a binary operator or right * parenthesis. It's on the operator stack. * * @param pThis The evaluator instance. */ static EXPRRET expr_get_binary_or_eoe_or_rparen(PEXPR pThis) { /* * See if there is anything pending first. */ PCEXPROP pOp = pThis->pPending; if (pOp) pThis->pPending = NULL; else { /* * Eat more of the expression. */ char const *psz = pThis->psz; /* spaces */ while (ISSPACE(*psz)) psz++; /* see what we've got. */ if (*psz) { unsigned char uchVal = expr_map_get(*psz); if (uchVal) pOp = expr_lookup_op(psz, uchVal, 0 /* fUnary */); if (!pOp) { expr_error(pThis, "Expected binary operator, found \"%.42s\"...", psz); return kExprRet_Error; } psz += pOp->cchOp; } else pOp = &g_ExprEndOfExpOp; pThis->psz = psz; } /* * Push it. */ if (pThis->iOp >= EXPR_MAX_OPERATORS - 1) { expr_error(pThis, "Operator stack overflow"); return kExprRet_Error; } pThis->apOps[++pThis->iOp] = pOp; return pOp->iPrecedence ? kExprRet_Operator : kExprRet_EndOfExpr; } /** * Get the next token, it should be an unary operator or an operand. * * This will fail if encountering the end of the expression since * it is implied that there should be something more. * * The token is pushed onto the respective stack and the status code * indicates which it is. * * @returns status code. On failure we'll be done bitching already. * @retval kExprRet_Operator if we encountered an unary operator. * It's on the operator stack. * @retval kExprRet_Operand if we encountered an operand operator. * It's on the operand stack. * * @param This The evaluator instance. */ static EXPRRET expr_get_unary_or_operand(PEXPR pThis) { EXPRRET rc; unsigned char uchVal; PCEXPROP pOp; char const *psz = pThis->psz; /* * Eat white space and make sure there is something after it. */ while (ISSPACE(*psz)) psz++; if (!*psz) { expr_error(pThis, "Unexpected end of expression"); return kExprRet_Error; } /* * Is it an operator? */ pOp = NULL; uchVal = expr_map_get(*psz); if (uchVal) pOp = expr_lookup_op(psz, uchVal, 1 /* fUnary */); if (pOp) { /* * Push the operator onto the stack. */ if (pThis->iVar < EXPR_MAX_OPERANDS - 1) { pThis->apOps[++pThis->iOp] = pOp; rc = kExprRet_Operator; } else { expr_error(pThis, "Operator stack overflow"); rc = kExprRet_Error; } psz += pOp->cchOp; } else if (pThis->iVar < EXPR_MAX_OPERANDS - 1) { /* * It's an operand. Figure out where it ends and * push it onto the stack. */ const char *pszStart; rc = kExprRet_Ok; if (*psz == '"') { pszStart = ++psz; while (*psz && *psz != '"') psz++; expr_var_init_substring(&pThis->aVars[++pThis->iVar], pszStart, psz - pszStart, kExprVar_QuotedString); if (*psz) psz++; } else if (*psz == '\'') { pszStart = ++psz; while (*psz && *psz != '\'') psz++; expr_var_init_substring(&pThis->aVars[++pThis->iVar], pszStart, psz - pszStart, kExprVar_QuotedSimpleString); if (*psz) psz++; } else { char achPars[20]; int iPar = -1; char chEndPar = '\0'; char ch, ch2; pszStart = psz; while ((ch = *psz) != '\0') { /* $(adsf) or ${asdf} needs special handling. */ if ( ch == '$' && ( (ch2 = psz[1]) == '(' || ch2 == '{')) { psz++; if (iPar > (int)(sizeof(achPars) / sizeof(achPars[0]))) { expr_error(pThis, "Too deep nesting of variable expansions"); rc = kExprRet_Error; break; } achPars[++iPar] = chEndPar = ch2 == '(' ? ')' : '}'; } else if (ch == chEndPar) { iPar--; chEndPar = iPar >= 0 ? achPars[iPar] : '\0'; } else if (!chEndPar) { /** @todo combine isspace and expr_map_get! */ unsigned chVal = expr_map_get(ch); if (chVal) { pOp = expr_lookup_op(psz, uchVal, 0 /* fUnary */); if (pOp) break; } if (ISSPACE(ch)) break; } /* next */ psz++; } if (rc == kExprRet_Ok) expr_var_init_substring(&pThis->aVars[++pThis->iVar], pszStart, psz - pszStart, kExprVar_String); } } else { expr_error(pThis, "Operand stack overflow"); rc = kExprRet_Error; } pThis->psz = psz; return rc; } /** * Evaluates the current expression. * * @returns status code. * * @param pThis The instance. */ static EXPRRET expr_eval(PEXPR pThis) { EXPRRET rc; PCEXPROP pOp; /* * The main loop. */ for (;;) { /* * Eat unary operators until we hit an operand. */ do rc = expr_get_unary_or_operand(pThis); while (rc == kExprRet_Operator); if (rc < kExprRet_Ok) break; /* * Look for a binary operator, right parenthesis or end of expression. */ rc = expr_get_binary_or_eoe_or_rparen(pThis); if (rc < kExprRet_Ok) break; expr_unget_op(pThis); /* * Pop operators and apply them. * * Parenthesis will be handed via precedence, where the left parenthesis * will go pop the right one and make another operator pending. */ while ( pThis->iOp >= 0 && pThis->apOps[pThis->iOp]->iPrecedence >= pThis->pPending->iPrecedence) { pOp = pThis->apOps[pThis->iOp--]; assert(pThis->iVar + 1 >= pOp->cArgs); rc = pOp->pfn(pThis); if (rc < kExprRet_Ok) break; } if (rc < kExprRet_Ok) break; /* * Get the next binary operator or end of expression. * There should be no right parenthesis here. */ rc = expr_get_binary_or_eoe_or_rparen(pThis); if (rc < kExprRet_Ok) break; pOp = pThis->apOps[pThis->iOp]; if (!pOp->iPrecedence) break; /* end of expression */ if (!pOp->cArgs) { expr_error(pThis, "Unexpected \"%s\"", pOp->szOp); rc = kExprRet_Error; break; } } return rc; } /** * Destroys the given instance. * * @param pThis The instance to destroy. */ static void expr_destroy(PEXPR pThis) { while (pThis->iVar >= 0) { expr_var_delete(pThis->aVars); pThis->iVar--; } free(pThis); } /** * Instantiates an expression evaluator. * * @returns The instance. * * @param pszExpr What to parse. * This must stick around until expr_destroy. */ static PEXPR expr_create(char const *pszExpr) { PEXPR pThis = (PEXPR)xmalloc(sizeof(*pThis)); pThis->pszExpr = pszExpr; pThis->psz = pszExpr; pThis->pFileLoc = NULL; pThis->pPending = NULL; pThis->iVar = -1; pThis->iOp = -1; expr_map_init(); return pThis; } /** * Evaluates the given if expression. * * @returns -1, 0 or 1. (GNU make conditional check convention, see read.c.) * @retval -1 if the expression is invalid. * @retval 0 if the expression is true * @retval 1 if the expression is false. * * @param line The expression. * @param flocp The file location, used for errors. */ int expr_eval_if_conditionals(const char *line, const floc *flocp) { /* * Instantiate the expression evaluator and let * it have a go at it. */ int rc = -1; PEXPR pExpr = expr_create(line); pExpr->pFileLoc = flocp; if (expr_eval(pExpr) >= kExprRet_Ok) { /* * Convert the result (on top of the stack) to boolean and * set our return value accordingly. */ if (expr_var_make_bool(&pExpr->aVars[0])) rc = 0; else rc = 1; } expr_destroy(pExpr); return rc; } /** * Evaluates the given expression and returns the result as a string. * * @returns variable buffer position. * * @param o The current variable buffer position. * @param expr The expression. */ char *expr_eval_to_string(char *o, const char *expr) { /* * Instantiate the expression evaluator and let * it have a go at it. */ PEXPR pExpr = expr_create(expr); if (expr_eval(pExpr) >= kExprRet_Ok) { /* * Convert the result (on top of the stack) to a string * and copy it out the variable buffer. */ PEXPRVAR pVar = &pExpr->aVars[0]; expr_var_make_simple_string(pVar); o = variable_buffer_output(o, pVar->uVal.psz, strlen(pVar->uVal.psz)); } else o = variable_buffer_output(o, "", sizeof("") - 1); expr_destroy(pExpr); return o; } #endif /* CONFIG_WITH_IF_CONDITIONALS */ kbuild-3149/src/kmk/config.h.haiku0000644000175000017500000003133713252530204016776 0ustar locutuslocutus/* config.h. Generated from config.h.in by configure. */ /* config.h.in. Generated from configure.in by autoheader. */ /* Define to 1 if the `closedir' function returns void instead of `int'. */ /* #undef CLOSEDIR_VOID */ /* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP systems. This function is required for `alloca.c' support on those systems. */ /* #undef CRAY_STACKSEG_END */ /* Define to 1 if using `alloca.c'. */ /* #undef C_ALLOCA */ /* Define to 1 if using `getloadavg.c'. */ #define C_GETLOADAVG 1 /* Define to 1 for DGUX with . */ /* #undef DGUX */ /* Use high resolution file timestamps if nonzero. */ #define FILE_TIMESTAMP_HI_RES 1 /* Define to 1 if the `getloadavg' function needs to be run setuid or setgid. */ /* #undef GETLOADAVG_PRIVILEGED */ /* Define to 1 if you have `alloca', as a function or macro. */ #define HAVE_ALLOCA 1 /* Define to 1 if you have and it should be used (not on Ultrix). */ #define HAVE_ALLOCA_H 1 /* Define to 1 if your compiler conforms to the ANSI C standard. */ #define HAVE_ANSI_COMPILER 1 /* Define to 1 if you have the `atexit' function. */ #define HAVE_ATEXIT 1 /* Use case insensitive file names */ /* #undef HAVE_CASE_INSENSITIVE_FS */ /* Define to 1 if you have the clock_gettime function. */ #define HAVE_CLOCK_GETTIME 1 /* Define to 1 if you have the declaration of `bsd_signal', and to 0 if you don't. */ #define HAVE_DECL_BSD_SIGNAL 0 /* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you don't. */ #define HAVE_DECL_SYS_SIGLIST 1 /* Define to 1 if you have the declaration of `_sys_siglist', and to 0 if you don't. */ #define HAVE_DECL__SYS_SIGLIST 0 /* Define to 1 if you have the declaration of `__sys_siglist', and to 0 if you don't. */ #define HAVE_DECL___SYS_SIGLIST 0 /* Define to 1 if you have the header file, and it defines `DIR'. */ #define HAVE_DIRENT_H 1 /* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ /* #undef HAVE_DOPRNT */ /* Use platform specific coding */ /* #undef HAVE_DOS_PATHS */ /* Define to 1 if you have the `dup2' function. */ #define HAVE_DUP2 1 /* Define to 1 if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define to 1 if you have the `fdopen' function. */ #define HAVE_FDOPEN 1 /* Define to 1 if you have the `fileno' function. */ #define HAVE_FILENO 1 /* Define to 1 if you have the `fork' function. */ #define HAVE_FORK 1 /* Define to 1 if you have the `getcwd' function. */ #define HAVE_GETCWD 1 /* Define to 1 if you have the `getgroups' function. */ #define HAVE_GETGROUPS 1 /* Define to 1 if you have the `gethostbyname' function. */ /* #undef HAVE_GETHOSTBYNAME */ /* Define to 1 if you have the `gethostname' function. */ /* #undef HAVE_GETHOSTNAME */ /* Define to 1 if you have the `getloadavg' function. */ /* #undef HAVE_GETLOADAVG */ /* Define to 1 if you have the `getrlimit' function. */ #define HAVE_GETRLIMIT 1 /* Define to 1 if you have a standard gettimeofday function */ #define HAVE_GETTIMEOFDAY 1 /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the `dgc' library (-ldgc). */ /* #undef HAVE_LIBDGC */ /* Define to 1 if you have the `kstat' library (-lkstat). */ /* #undef HAVE_LIBKSTAT */ /* Define to 1 if you have the header file. */ #define HAVE_LIMITS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_LOCALE_H 1 /* Define to 1 if you have the `lstat' function. */ #define HAVE_LSTAT 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_MACH_MACH_H */ /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if you have the `mkstemp' function. */ #define HAVE_MKSTEMP 1 /* Define to 1 if you have the `mktemp' function. */ #define HAVE_MKTEMP 1 /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_NDIR_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NLIST_H */ /* Define to 1 if you have the `pipe' function. */ #define HAVE_PIPE 1 /* Define to 1 if you have the `pstat_getdynamic' function. */ /* #undef HAVE_PSTAT_GETDYNAMIC */ /* Define to 1 if you have the `readlink' function. */ #define HAVE_READLINK 1 /* Define to 1 if you have the `realpath' function. */ #define HAVE_REALPATH 1 /* Define to 1 if defines the SA_RESTART constant. */ #define HAVE_SA_RESTART 1 /* Define to 1 if you have the `setegid' function. */ #define HAVE_SETEGID 1 /* Define to 1 if you have the `seteuid' function. */ #define HAVE_SETEUID 1 /* Define to 1 if you have the `setlinebuf' function. */ #define HAVE_SETLINEBUF 1 /* Define to 1 if you have the `setlocale' function. */ #define HAVE_SETLOCALE 1 /* Define to 1 if you have the `setregid' function. */ #define HAVE_SETREGID 1 /* Define to 1 if you have the `setreuid' function. */ #define HAVE_SETREUID 1 /* Define to 1 if you have the `setrlimit' function. */ #define HAVE_SETRLIMIT 1 /* Define to 1 if you have the `setvbuf' function. */ #define HAVE_SETVBUF 1 /* Define to 1 if you have the `sigaction' function. */ #define HAVE_SIGACTION 1 /* Define to 1 if you have the `sigsetmask' function. */ /* #undef HAVE_SIGSETMASK */ /* Define to 1 if you have the `socket' function. */ /* #undef HAVE_SOCKET */ /* Define to 1 if you have the header file. */ #define HAVE_STDARG_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the `strcasecmp' function. */ #define HAVE_STRCASECMP 1 /* Define to 1 if you have the `strcmpi' function. */ /* #undef HAVE_STRCMPI */ /* Define to 1 if you have the `strcoll' function and it is properly defined. */ #define HAVE_STRCOLL 1 /* Define to 1 if you have the `strdup' function. */ #define HAVE_STRDUP 1 /* Define to 1 if you have the `strerror' function. */ #define HAVE_STRERROR 1 /* Define to 1 if you have the `stricmp' function. */ /* #undef HAVE_STRICMP */ /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the `strncasecmp' function. */ #define HAVE_STRNCASECMP 1 /* Define to 1 if you have the `strncmpi' function. */ /* #undef HAVE_STRNCMPI */ /* Define to 1 if you have the `strndup' function. */ #define HAVE_STRNDUP 1 /* Define to 1 if you have the `strnicmp' function. */ /* #undef HAVE_STRNICMP */ /* Define to 1 if you have the `strsignal' function. */ #define HAVE_STRSIGNAL 1 /* Define to 1 if `n_un.n_name' is a member of `struct nlist'. */ /* #undef HAVE_STRUCT_NLIST_N_UN_N_NAME */ /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_SYS_DIR_H */ /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_SYS_NDIR_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_PARAM_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_RESOURCE_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIMEB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIME_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_WAIT_H 1 /* Define to 1 if you have the \`union wait' type in . */ /* #undef HAVE_UNION_WAIT */ /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_VARARGS_H */ /* Define to 1 if you have the `vfork' function. */ #define HAVE_VFORK 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_VFORK_H */ /* Define to 1 if you have the `vprintf' function. */ #define HAVE_VPRINTF 1 /* Define to 1 if you have the `wait3' function. */ /* #undef HAVE_WAIT3 */ /* Define to 1 if you have the `waitpid' function. */ #define HAVE_WAITPID 1 /* Define to 1 if `fork' works. */ #define HAVE_WORKING_FORK 1 /* Define to 1 if `vfork' works. */ #define HAVE_WORKING_VFORK 1 /* Build host information. (not used by kmk) */ #define MAKE_HOST "i586-pc-haiku" /* Define to 1 to enable job server support in GNU make. */ #define MAKE_JOBSERVER 1 /* Define to 1 to enable symbolic link timestamp checking. */ #define MAKE_SYMLINKS 1 /* Define to 1 if your `struct nlist' has an `n_un' member. Obsolete, depend on `HAVE_STRUCT_NLIST_N_UN_N_NAME */ /* #undef NLIST_NAME_UNION */ /* Define to 1 if struct nlist.n_name is a pointer rather than an array. */ /* #undef NLIST_STRUCT */ /* Define to 1 if your C compiler doesn't accept -c and -o together. */ /* #undef NO_MINUS_C_MINUS_O */ /* Name of package */ #define PACKAGE "make" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "bug-make@gnu.org" /* Define to the full name of this package. */ #define PACKAGE_NAME "GNU make" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "GNU make 3.82" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "make" /* Define to the home page for this package. */ #define PACKAGE_URL "http://www.gnu.org/software/make/" /* Define to the version of this package. */ #define PACKAGE_VERSION "3.82" /* Define to the character that separates directories in PATH. */ #define PATH_SEPARATOR_CHAR ':' /* Define as the return type of signal handlers (`int' or `void'). */ #define RETSIGTYPE void /* Define to the name of the SCCS 'get' command. */ #define SCCS_GET "get" /* Define to 1 if the SCCS 'get' command understands the '-G' option. */ /* #undef SCCS_GET_MINUS_G */ /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be automatically deduced at runtime. STACK_DIRECTION > 0 => grows toward higher addresses STACK_DIRECTION < 0 => grows toward lower addresses STACK_DIRECTION = 0 => direction of growth unknown */ /* #undef STACK_DIRECTION */ /* Define to 1 if the `S_IS*' macros in do not work properly. */ /* #undef STAT_MACROS_BROKEN */ /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define if struct stat contains a nanoseconds field */ #define ST_MTIM_NSEC tv_nsec /* Define to 1 on System V Release 4. */ /* #undef SVR4 */ /* Define to 1 if you can safely include both and . */ #define TIME_WITH_SYS_TIME 1 /* Define to 1 for Encore UMAX. */ /* #undef UMAX */ /* Define to 1 for Encore UMAX 4.3 that has instead of . */ /* #undef UMAX4_3 */ /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE # define _ALL_SOURCE 1 #endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE # define _GNU_SOURCE 1 #endif /* Enable threading extensions on Solaris. */ #ifndef _POSIX_PTHREAD_SEMANTICS # define _POSIX_PTHREAD_SEMANTICS 1 #endif /* Enable extensions on HP NonStop. */ #ifndef _TANDEM_SOURCE # define _TANDEM_SOURCE 1 #endif /* Enable general extensions on Solaris. */ #ifndef __EXTENSIONS__ # define __EXTENSIONS__ 1 #endif /* Version number of package */ #define VERSION "3.82" /* Use platform specific coding */ /* #undef WINDOWS32 */ /* Define if using the dmalloc debugging malloc package */ /* #undef WITH_DMALLOC */ /* Enable large inode numbers on Mac OS X 10.5. */ #ifndef _DARWIN_USE_64_BIT_INODE # define _DARWIN_USE_64_BIT_INODE 1 #endif /* Number of bits in a file offset, on hosts where this is settable. */ /* #undef _FILE_OFFSET_BITS */ /* Define for large files, on AIX-style hosts. */ /* #undef _LARGE_FILES */ /* Define to 1 if on MINIX. */ /* #undef _MINIX */ /* Define to 2 if the system does not provide POSIX.1 features except with this defined. */ /* #undef _POSIX_1_SOURCE */ /* Define to 1 if you need to in order for `stat' and other things to work. */ /* #undef _POSIX_SOURCE */ /* Define to empty if `const' does not conform to ANSI C. */ /* #undef const */ /* Define to `int' if doesn't define. */ /* #undef gid_t */ /* Define to `int' if does not define. */ /* #undef pid_t */ /* Define to `unsigned int' if does not define. */ /* #undef size_t */ /* Define to `int' if doesn't define. */ /* #undef uid_t */ /* Define uintmax_t if not defined in or . */ /* #undef uintmax_t */ /* Define as `fork' if `vfork' does not work. */ /* #undef vfork */ #include "inlined_memchr.h" kbuild-3149/src/kmk/loadapi.c0000644000175000017500000000411713252530201016026 0ustar locutuslocutus/* API for GNU Make dynamic objects. Copyright (C) 2013-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" #include "filedef.h" #include "variable.h" #include "dep.h" /* Allocate a buffer in our context, so we can free it. */ char * gmk_alloc (unsigned int len) { return xmalloc (len); } /* Free a buffer returned by gmk_expand(). */ void gmk_free (char *s) { free (s); } /* Evaluate a buffer as make syntax. Ideally eval_buffer() will take const char *, but not yet. */ void gmk_eval (const char *buffer, const gmk_floc *gfloc) { /* Preserve existing variable buffer context. */ char *pbuf; unsigned int plen; char *s; floc fl; floc *flp; if (gfloc) { fl.filenm = gfloc->filenm; fl.lineno = gfloc->lineno; fl.offset = 0; flp = &fl; } else flp = NULL; install_variable_buffer (&pbuf, &plen); s = xstrdup (buffer); eval_buffer (s, flp IF_WITH_VALUE_LENGTH_PARAM (strlen (s) /** @todo suboptimal */)); free (s); restore_variable_buffer (pbuf, plen); } /* Expand a string and return an allocated buffer. Caller must call gmk_free() with this buffer. */ char * gmk_expand (const char *ref) { return allocated_variable_expand (ref); } /* Register a function to be called from makefiles. */ void gmk_add_function (const char *name, gmk_func_ptr func, unsigned int min, unsigned int max, unsigned int flags) { define_new_function (reading_file, name, min, max, flags, func); } kbuild-3149/src/kmk/testcase-2ndtargetexp.kmk0000644000175000017500000000341713252530204021202 0ustar locutuslocutus# $Id: testcase-2ndtargetexp.kmk 2413 2010-09-11 17:43:04Z bird $ ## @file # kBuild - testcase for the 2nd target expansion feature. # # # Copyright (c) 2008-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # DEPTH = ../.. include $(PATH_KBUILD)/header.kmk # # Enable it. # .SECONDTARGETEXPANSION: # # This is expanded immediately. # foo1 = foo1 $(foo1): $(if $(eq $@,foo1),$(ECHO) "foo1 works",$(ECHO) "foo1 is busted @=$@"; exit 1) # Mostly for making sure the ifeq test works below. flush_command_recoding := 1 # see record_waiting_files() in read.c ifeq ($(strip $(commands foo1)),) $(error No commands for foo1: $(commands foo1)) endif # # This is expanded in the 2nd round. # $$(foo2): $(if $(eq $@,foo2),$(ECHO) "foo2 works",$(ECHO) "foo2 is busted @=$@"; exit 1) # Check that a $(foo2) file exists. flush_command_recoding := 1 # see record_waiting_files() in read.c # $ (info $$(foo2) commands: $(commands $$(foo2))) ifeq ($(strip $(commands $$(foo2))),) $(error No commands for $$(foo2): $(commands $$(foo2))) endif all_recursive: foo1 foo2 $(ECHO) "2nd target expansion passes smoke testing" # define this last foo2 = foo2 kbuild-3149/src/kmk/getopt.h0000644000175000017500000001057013252530202015725 0ustar locutuslocutus/* Declarations for getopt. Copyright (C) 1989-2016 Free Software Foundation, Inc. NOTE: The canonical source of this file is maintained with the GNU C Library. Bugs can be reported to bug-glibc@gnu.org. GNU Make 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. GNU Make 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 . */ #ifndef _GETOPT_H #define _GETOPT_H 1 #ifdef __cplusplus extern "C" { #endif /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ extern char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ extern int optind; /* Callers store zero here to inhibit the error message `getopt' prints for unrecognized options. */ extern int opterr; /* Set to an option character which was unrecognized. */ extern int optopt; /* Describe the long-named options requested by the application. The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector of `struct option' terminated by an element containing a name which is zero. The field `has_arg' is: no_argument (or 0) if the option does not take an argument, required_argument (or 1) if the option requires an argument, optional_argument (or 2) if the option takes an optional argument. If the field `flag' is not NULL, it points to a variable that is set to the value given in the field `val' when the option is found, but left unchanged if the option is not found. To have a long-named option do something other than set an `int' to a compiled-in constant, such as set a value from `optarg', set the option's `flag' field to zero and its `val' field to a nonzero value (the equivalent single-letter option character, if there is one). For long options that have a zero `flag' field, `getopt' returns the contents of the `val' field. */ struct option { #if defined (__STDC__) && __STDC__ const char *name; #else char *name; #endif /* has_arg can't be an enum because some compilers complain about type mismatches in all the code that assumes it is an int. */ int has_arg; int *flag; int val; }; /* Names for the values of the `has_arg' field of `struct option'. */ #define no_argument 0 #define required_argument 1 #define optional_argument 2 #if defined (__STDC__) && __STDC__ #ifdef __GNU_LIBRARY__ /* Many other libraries have conflicting prototypes for getopt, with differences in the consts, in stdlib.h. To avoid compilation errors, only prototype getopt for the GNU C library. */ extern int getopt (int argc, char *const *argv, const char *shortopts); #else /* not __GNU_LIBRARY__ */ extern int getopt (); #endif /* __GNU_LIBRARY__ */ extern int getopt_long (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind); extern int getopt_long_only (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind); /* Internal only. Users should not call this directly. */ extern int _getopt_internal (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind, int long_only); #else /* not __STDC__ */ extern int getopt (); extern int getopt_long (); extern int getopt_long_only (); extern int _getopt_internal (); #endif /* __STDC__ */ #ifdef __cplusplus } #endif #endif /* getopt.h */ kbuild-3149/src/kmk/misc.c0000644000175000017500000007201713252530201015354 0ustar locutuslocutus/* Miscellaneous generic support functions for GNU Make. Copyright (C) 1988-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" #include "filedef.h" #include "dep.h" #include "debug.h" /* GNU make no longer supports pre-ANSI89 environments. */ #include #ifdef HAVE_FCNTL_H # include #else # include #endif #if defined (CONFIG_WITH_VALUE_LENGTH) || defined (CONFIG_WITH_ALLOC_CACHES) # include #endif #ifdef CONFIG_WITH_PRINT_STATS_SWITCH # ifdef __APPLE__ # include # endif # if defined(__GLIBC__) || defined(HAVE_MALLINFO) # include # endif #endif #if defined (CONFIG_WITH_NANOTS) || defined (CONFIG_WITH_PRINT_TIME_SWITCH) # ifdef WINDOWS32 # include # endif #endif /* All bcopy calls in this file can be replaced by memcpy and save a tick or two. */ #ifdef CONFIG_WITH_OPTIMIZATION_HACKS # undef bcopy # if defined(__GNUC__) && defined(CONFIG_WITH_OPTIMIZATION_HACKS) # define bcopy(src, dst, size) __builtin_memcpy ((dst), (src), (size)) # else # define bcopy(src, dst, size) memcpy ((dst), (src), (size)) # endif #endif /* Compare strings *S1 and *S2. Return negative if the first is less, positive if it is greater, zero if they are equal. */ int alpha_compare (const void *v1, const void *v2) { const char *s1 = *((char **)v1); const char *s2 = *((char **)v2); if (*s1 != *s2) return *s1 - *s2; return strcmp (s1, s2); } /* Discard each backslash-newline combination from LINE. Backslash-backslash-newline combinations become backslash-newlines. This is done by copying the text at LINE into itself. */ #ifndef CONFIG_WITH_VALUE_LENGTH void collapse_continuations (char *line) #else char * collapse_continuations (char *line, unsigned int linelen) #endif { char *in, *out, *p; #ifndef CONFIG_WITH_VALUE_LENGTH in = strchr (line, '\n'); if (in == 0) return; #else assert (strlen (line) == linelen); in = memchr (line, '\n', linelen); if (in == 0) return line + linelen; if (in == line || in[-1] != '\\') { do { unsigned int off_in = in - line; if (off_in == linelen) return in; in = memchr (in + 1, '\n', linelen - off_in - 1); if (in == 0) return line + linelen; } while (in[-1] != '\\'); } #endif out = in; while (out > line && out[-1] == '\\') --out; while (*in != '\0') { /* BS_WRITE gets the number of quoted backslashes at the end just before IN, and BACKSLASH gets nonzero if the next character is quoted. */ unsigned int backslash = 0; unsigned int bs_write = 0; for (p = in - 1; p >= line && *p == '\\'; --p) { if (backslash) ++bs_write; backslash = !backslash; /* It should be impossible to go back this far without exiting, but if we do, we can't get the right answer. */ if (in == out - 1) abort (); } /* Output the appropriate number of backslashes. */ while (bs_write-- > 0) *out++ = '\\'; /* Skip the newline. */ ++in; if (backslash) { /* Backslash/newline handling: In traditional GNU make all trailing whitespace, consecutive backslash/newlines, and any leading non-newline whitespace on the next line is reduced to a single space. In POSIX, each backslash/newline and is replaced by a space. */ while (ISBLANK (*in)) ++in; if (! posix_pedantic) while (out > line && ISBLANK (out[-1])) --out; *out++ = ' '; } else /* If the newline isn't quoted, put it in the output. */ *out++ = '\n'; /* Now copy the following line to the output. Stop when we find backslashes followed by a newline. */ while (*in != '\0') if (*in == '\\') { p = in + 1; while (*p == '\\') ++p; if (*p == '\n') { in = p; break; } while (in < p) *out++ = *in++; } else *out++ = *in++; } *out = '\0'; #ifdef CONFIG_WITH_VALUE_LENGTH assert (strchr (line, '\0') == out); return out; #endif } /* Print N spaces (used in debug for target-depth). */ void print_spaces (unsigned int n) { while (n-- > 0) putchar (' '); } /* Return a string whose contents concatenate the NUM strings provided This string lives in static, re-used memory. */ const char * concat (unsigned int num, ...) { static unsigned int rlen = 0; static char *result = NULL; unsigned int ri = 0; va_list args; va_start (args, num); while (num-- > 0) { const char *s = va_arg (args, const char *); unsigned int l = xstrlen (s); if (l == 0) continue; if (ri + l > rlen) { rlen = ((rlen ? rlen : 60) + l) * 2; result = xrealloc (result, rlen); } memcpy (result + ri, s, l); ri += l; } va_end (args); /* Get some more memory if we don't have enough space for the terminating '\0'. */ if (ri == rlen) { rlen = (rlen ? rlen : 60) * 2; result = xrealloc (result, rlen); } result[ri] = '\0'; return result; } #ifndef HAVE_STRERROR #undef strerror char * strerror (int errnum) { extern int errno, sys_nerr; #ifndef __DECC extern char *sys_errlist[]; #endif static char buf[] = "Unknown error 12345678901234567890"; if (errno < sys_nerr) return sys_errlist[errnum]; sprintf (buf, _("Unknown error %d"), errnum); return buf; } #endif /* Like malloc but get fatal error if memory is exhausted. */ /* Don't bother if we're using dmalloc; it provides these for us. */ #if !defined(HAVE_DMALLOC_H) && !defined(ELECTRIC_HEAP) /* bird */ #undef xmalloc #undef xcalloc #undef xrealloc #undef xstrdup void * xmalloc (unsigned int size) { /* Make sure we don't allocate 0, for pre-ISO implementations. */ void *result = malloc (size ? size : 1); if (result == 0) OUT_OF_MEM(); #ifdef CONFIG_WITH_MAKE_STATS make_stats_allocations++; if (make_expensive_statistics) make_stats_allocated += SIZE_OF_HEAP_BLOCK (result); else make_stats_allocated += size; #endif return result; } void * xcalloc (unsigned int size) { /* Make sure we don't allocate 0, for pre-ISO implementations. */ void *result = calloc (size ? size : 1, 1); if (result == 0) OUT_OF_MEM(); #ifdef CONFIG_WITH_MAKE_STATS make_stats_allocations++; if (make_expensive_statistics) make_stats_allocated += SIZE_OF_HEAP_BLOCK (result); else make_stats_allocated += size; #endif return result; } void * xrealloc (void *ptr, unsigned int size) { void *result; #ifdef CONFIG_WITH_MAKE_STATS if (make_expensive_statistics && ptr != NULL) make_stats_allocated -= SIZE_OF_HEAP_BLOCK (ptr); if (ptr) make_stats_reallocations++; else make_stats_allocations++; #endif /* Some older implementations of realloc() don't conform to ISO. */ if (! size) size = 1; result = ptr ? realloc (ptr, size) : malloc (size); if (result == 0) OUT_OF_MEM(); #ifdef CONFIG_WITH_MAKE_STATS if (make_expensive_statistics) make_stats_allocated += SIZE_OF_HEAP_BLOCK (result); else make_stats_allocated += size; #endif return result; } char * xstrdup (const char *ptr) { char *result; #ifdef HAVE_STRDUP result = strdup (ptr); #else result = malloc (strlen (ptr) + 1); #endif if (result == 0) OUT_OF_MEM(); #ifdef CONFIG_WITH_MAKE_STATS make_stats_allocations++; if (make_expensive_statistics) make_stats_allocated += SIZE_OF_HEAP_BLOCK (result); else make_stats_allocated += strlen (ptr) + 1; #endif #ifdef HAVE_STRDUP return result; #else return strcpy (result, ptr); #endif } #endif /* HAVE_DMALLOC_H */ char * xstrndup (const char *str, unsigned int length) { char *result; #if defined(HAVE_STRNDUP) && !defined(KMK) result = strndup (str, length); if (result == 0) OUT_OF_MEM(); #else result = xmalloc (length + 1); if (length > 0) strncpy (result, str, length); result[length] = '\0'; #endif return result; } #ifndef CONFIG_WITH_OPTIMIZATION_HACKS /* This is really a reimplemntation of memchr, only slower. It's been replaced by a macro in the header file. */ /* Limited INDEX: Search through the string STRING, which ends at LIMIT, for the character C. Returns a pointer to the first occurrence, or nil if none is found. Like INDEX except that the string searched ends where specified instead of at the first null. */ char * lindex (const char *s, const char *limit, int c) { while (s < limit) if (*s++ == c) return (char *)(s - 1); return 0; } #endif /* CONFIG_WITH_OPTIMIZATION_HACKS */ /* Return the address of the first whitespace or null in the string S. */ char * end_of_token (const char *s) { #if 0 /* @todo def KMK */ for (;;) { unsigned char ch0, ch1, ch2, ch3; ch0 = *s; if (MY_PREDICT_FALSE(MY_IS_BLANK_OR_EOS(ch0))) return (char *)s; ch1 = s[1]; if (MY_PREDICT_FALSE(MY_IS_BLANK_OR_EOS(ch1))) return (char *)s + 1; ch2 = s[2]; if (MY_PREDICT_FALSE(MY_IS_BLANK_OR_EOS(ch2))) return (char *)s + 2; ch3 = s[3]; if (MY_PREDICT_FALSE(MY_IS_BLANK_OR_EOS(ch3))) return (char *)s + 3; s += 4; } #else END_OF_TOKEN (s); return (char *)s; #endif } /* Return the address of the first nonwhitespace or null in the string S. */ char * next_token (const char *s) { #if 0 /* @todo def KMK */ for (;;) { unsigned char ch0, ch1, ch2, ch3; ch0 = *s; if (MY_PREDICT_FALSE(!MY_IS_BLANK(ch0))) return (char *)s; ch1 = s[1]; if (MY_PREDICT_TRUE(!MY_IS_BLANK(ch1))) return (char *)s + 1; ch2 = s[2]; if (MY_PREDICT_FALSE(!MY_IS_BLANK(ch2))) return (char *)s + 2; ch3 = s[3]; if (MY_PREDICT_TRUE(!MY_IS_BLANK(ch3))) return (char *)s + 3; s += 4; } #else /* !KMK */ NEXT_TOKEN (s); return (char *)s; #endif /* !KMK */ } /* Find the next token in PTR; return the address of it, and store the length of the token into *LENGTHPTR if LENGTHPTR is not nil. Set *PTR to the end of the token, so this function can be called repeatedly in a loop. */ char * find_next_token (const char **ptr, unsigned int *lengthptr) { #ifdef KMK const char *p = *ptr; const char *e; /* skip blanks */ # if 0 /* a moderate version */ for (;; p++) { unsigned char ch = *p; if (!MY_IS_BLANK(ch)) { if (!ch) return NULL; break; } } # else /* (too) big unroll */ for (;; p += 4) { unsigned char ch0, ch1, ch2, ch3; ch0 = *p; if (MY_PREDICT_FALSE(!MY_IS_BLANK(ch0))) { if (!ch0) return NULL; break; } ch1 = p[1]; if (MY_PREDICT_TRUE(!MY_IS_BLANK(ch1))) { if (!ch1) return NULL; p += 1; break; } ch2 = p[2]; if (MY_PREDICT_FALSE(!MY_IS_BLANK(ch2))) { if (!ch2) return NULL; p += 2; break; } ch3 = p[3]; if (MY_PREDICT_TRUE(!MY_IS_BLANK(ch3))) { if (!ch3) return NULL; p += 3; break; } } # endif /* skip ahead until EOS or blanks. */ # if 0 /* a moderate version */ for (e = p + 1; ; e++) { unsigned char ch = *e; if (MY_PREDICT_FALSE(MY_IS_BLANK_OR_EOS(ch))) break; } # else /* (too) big unroll */ for (e = p + 1; ; e += 4) { unsigned char ch0, ch1, ch2, ch3; ch0 = *e; if (MY_PREDICT_FALSE(MY_IS_BLANK_OR_EOS(ch0))) break; ch1 = e[1]; if (MY_PREDICT_FALSE(MY_IS_BLANK_OR_EOS(ch1))) { e += 1; break; } ch2 = e[2]; if (MY_PREDICT_FALSE(MY_IS_BLANK_OR_EOS(ch2))) { e += 2; break; } ch3 = e[3]; if (MY_PREDICT_FALSE(MY_IS_BLANK_OR_EOS(ch3))) { e += 3; break; } } # endif *ptr = e; if (lengthptr != 0) *lengthptr = e - p; return (char *)p; #else const char *p = next_token (*ptr); if (*p == '\0') return 0; *ptr = end_of_token (p); if (lengthptr != 0) *lengthptr = *ptr - p; return (char *)p; #endif } #ifdef KMK /* Same as find_next_token with two exception: - The string ends at EOS or '\0'. - We keep track of $() and ${}, allowing functions to be used. */ char * find_next_token_eos (const char **ptr, const char *eos, unsigned int *lengthptr) { const char *p = *ptr; const char *e; int level = 0; /* skip blanks */ for (; p != eos; p++) { unsigned char ch = *p; if (!MY_IS_BLANK(ch)) { if (!ch) return NULL; break; } } if (p == eos) return NULL; /* skip ahead until EOS or blanks. */ for (e = p; e != eos; e++) { unsigned char ch = *e; if (MY_IS_BLANK_OR_EOS(ch)) { if (!ch || level == 0) break; } else if (ch == '$') { if (&e[1] != eos && (e[1] == '(' || e[1] == '{')) { level++; e++; } } else if ((ch == ')' || ch == '}') && level > 0) level--; } *ptr = e; if (lengthptr != 0) *lengthptr = e - p; return (char *)p; } #endif /* KMK */ /* Copy a chain of 'struct dep'. For 2nd expansion deps, dup the name. */ struct dep * copy_dep_chain (const struct dep *d) { struct dep *firstnew = 0; struct dep *lastnew = 0; while (d != 0) { #ifndef CONFIG_WITH_ALLOC_CACHES struct dep *c = xmalloc (sizeof (struct dep)); #else struct dep *c = alloccache_alloc(&dep_cache); #endif memcpy (c, d, sizeof (struct dep)); /** @todo KMK: Check if we need this duplication! */ if (c->need_2nd_expansion) c->name = xstrdup (c->name); c->next = 0; if (firstnew == 0) firstnew = lastnew = c; else lastnew = lastnew->next = c; d = d->next; } return firstnew; } /* Free a chain of struct nameseq. For struct dep chains use free_dep_chain. */ void free_ns_chain (struct nameseq *ns) { while (ns != 0) { struct nameseq *t = ns; ns = ns->next; #ifndef CONFIG_WITH_ALLOC_CACHES free_ns (t); #else alloccache_free (&nameseq_cache, t); #endif } } #ifdef CONFIG_WITH_ALLOC_CACHES void free_dep_chain (struct dep *d) { while (d != 0) { struct dep *tofree = d; d = d->next; alloccache_free (&dep_cache, tofree); } } void free_goal_chain (struct goaldep *g) { while (g != 0) { struct goaldep *tofree = g; g = g->next; alloccache_free (&dep_cache, tofree); } } #endif /* CONFIG_WITH_ALLOC_CACHES */ #if !HAVE_STRCASECMP && !HAVE_STRICMP && !HAVE_STRCMPI /* If we don't have strcasecmp() (from POSIX), or anything that can substitute for it, define our own version. */ int strcasecmp (const char *s1, const char *s2) { while (1) { int c1 = (int) *(s1++); int c2 = (int) *(s2++); if (isalpha (c1)) c1 = tolower (c1); if (isalpha (c2)) c2 = tolower (c2); if (c1 != '\0' && c1 == c2) continue; return (c1 - c2); } } #endif #if !HAVE_STRNCASECMP && !HAVE_STRNICMP && !HAVE_STRNCMPI /* If we don't have strncasecmp() (from POSIX), or anything that can substitute for it, define our own version. */ int strncasecmp (const char *s1, const char *s2, int n) { while (n-- > 0) { int c1 = (int) *(s1++); int c2 = (int) *(s2++); if (isalpha (c1)) c1 = tolower (c1); if (isalpha (c2)) c2 = tolower (c2); if (c1 != '\0' && c1 == c2) continue; return (c1 - c2); } return 0; } #endif #ifdef GETLOADAVG_PRIVILEGED #ifdef POSIX /* Hopefully if a system says it's POSIX.1 and has the setuid and setgid functions, they work as POSIX.1 says. Some systems (Alpha OSF/1 1.2, for example) which claim to be POSIX.1 also have the BSD setreuid and setregid functions, but they don't work as in BSD and only the POSIX.1 way works. */ #undef HAVE_SETREUID #undef HAVE_SETREGID #else /* Not POSIX. */ /* Some POSIX.1 systems have the seteuid and setegid functions. In a POSIX-like system, they are the best thing to use. However, some non-POSIX systems have them too but they do not work in the POSIX style and we must use setreuid and setregid instead. */ #undef HAVE_SETEUID #undef HAVE_SETEGID #endif /* POSIX. */ #ifndef HAVE_UNISTD_H extern int getuid (), getgid (), geteuid (), getegid (); extern int setuid (), setgid (); #ifdef HAVE_SETEUID extern int seteuid (); #else #ifdef HAVE_SETREUID extern int setreuid (); #endif /* Have setreuid. */ #endif /* Have seteuid. */ #ifdef HAVE_SETEGID extern int setegid (); #else #ifdef HAVE_SETREGID extern int setregid (); #endif /* Have setregid. */ #endif /* Have setegid. */ #endif /* No . */ /* Keep track of the user and group IDs for user- and make- access. */ static int user_uid = -1, user_gid = -1, make_uid = -1, make_gid = -1; #define access_inited (user_uid != -1) static enum { make, user } current_access; /* Under -d, write a message describing the current IDs. */ static void log_access (const char *flavor) { if (! ISDB (DB_JOBS)) return; /* All the other debugging messages go to stdout, but we write this one to stderr because it might be run in a child fork whose stdout is piped. */ fprintf (stderr, _("%s: user %lu (real %lu), group %lu (real %lu)\n"), flavor, (unsigned long) geteuid (), (unsigned long) getuid (), (unsigned long) getegid (), (unsigned long) getgid ()); fflush (stderr); } static void init_access (void) { #ifndef VMS user_uid = getuid (); user_gid = getgid (); make_uid = geteuid (); make_gid = getegid (); /* Do these ever fail? */ if (user_uid == -1 || user_gid == -1 || make_uid == -1 || make_gid == -1) pfatal_with_name ("get{e}[gu]id"); log_access (_("Initialized access")); current_access = make; #endif } #endif /* GETLOADAVG_PRIVILEGED */ /* Give the process appropriate permissions for access to user data (i.e., to stat files, or to spawn a child process). */ void user_access (void) { #ifdef GETLOADAVG_PRIVILEGED if (!access_inited) init_access (); if (current_access == user) return; /* We are in "make access" mode. This means that the effective user and group IDs are those of make (if it was installed setuid or setgid). We now want to set the effective user and group IDs to the real IDs, which are the IDs of the process that exec'd make. */ #ifdef HAVE_SETEUID /* Modern systems have the seteuid/setegid calls which set only the effective IDs, which is ideal. */ if (seteuid (user_uid) < 0) pfatal_with_name ("user_access: seteuid"); #else /* Not HAVE_SETEUID. */ #ifndef HAVE_SETREUID /* System V has only the setuid/setgid calls to set user/group IDs. There is an effective ID, which can be set by setuid/setgid. It can be set (unless you are root) only to either what it already is (returned by geteuid/getegid, now in make_uid/make_gid), the real ID (return by getuid/getgid, now in user_uid/user_gid), or the saved set ID (what the effective ID was before this set-ID executable (make) was exec'd). */ if (setuid (user_uid) < 0) pfatal_with_name ("user_access: setuid"); #else /* HAVE_SETREUID. */ /* In 4BSD, the setreuid/setregid calls set both the real and effective IDs. They may be set to themselves or each other. So you have two alternatives at any one time. If you use setuid/setgid, the effective will be set to the real, leaving only one alternative. Using setreuid/setregid, however, you can toggle between your two alternatives by swapping the values in a single setreuid or setregid call. */ if (setreuid (make_uid, user_uid) < 0) pfatal_with_name ("user_access: setreuid"); #endif /* Not HAVE_SETREUID. */ #endif /* HAVE_SETEUID. */ #ifdef HAVE_SETEGID if (setegid (user_gid) < 0) pfatal_with_name ("user_access: setegid"); #else #ifndef HAVE_SETREGID if (setgid (user_gid) < 0) pfatal_with_name ("user_access: setgid"); #else if (setregid (make_gid, user_gid) < 0) pfatal_with_name ("user_access: setregid"); #endif #endif current_access = user; log_access (_("User access")); #endif /* GETLOADAVG_PRIVILEGED */ } /* Give the process appropriate permissions for access to make data (i.e., the load average). */ void make_access (void) { #ifdef GETLOADAVG_PRIVILEGED if (!access_inited) init_access (); if (current_access == make) return; /* See comments in user_access, above. */ #ifdef HAVE_SETEUID if (seteuid (make_uid) < 0) pfatal_with_name ("make_access: seteuid"); #else #ifndef HAVE_SETREUID if (setuid (make_uid) < 0) pfatal_with_name ("make_access: setuid"); #else if (setreuid (user_uid, make_uid) < 0) pfatal_with_name ("make_access: setreuid"); #endif #endif #ifdef HAVE_SETEGID if (setegid (make_gid) < 0) pfatal_with_name ("make_access: setegid"); #else #ifndef HAVE_SETREGID if (setgid (make_gid) < 0) pfatal_with_name ("make_access: setgid"); #else if (setregid (user_gid, make_gid) < 0) pfatal_with_name ("make_access: setregid"); #endif #endif current_access = make; log_access (_("Make access")); #endif /* GETLOADAVG_PRIVILEGED */ } /* Give the process appropriate permissions for a child process. This is like user_access, but you can't get back to make_access. */ void child_access (void) { #ifdef GETLOADAVG_PRIVILEGED if (!access_inited) abort (); /* Set both the real and effective UID and GID to the user's. They cannot be changed back to make's. */ #ifndef HAVE_SETREUID if (setuid (user_uid) < 0) pfatal_with_name ("child_access: setuid"); #else if (setreuid (user_uid, user_uid) < 0) pfatal_with_name ("child_access: setreuid"); #endif #ifndef HAVE_SETREGID if (setgid (user_gid) < 0) pfatal_with_name ("child_access: setgid"); #else if (setregid (user_gid, user_gid) < 0) pfatal_with_name ("child_access: setregid"); #endif log_access (_("Child access")); #endif /* GETLOADAVG_PRIVILEGED */ } #ifdef NEED_GET_PATH_MAX unsigned int get_path_max (void) { static unsigned int value; if (value == 0) { long int x = pathconf ("/", _PC_PATH_MAX); if (x > 0) value = x; else return MAXPATHLEN; } return value; } #endif #ifdef CONFIG_WITH_PRINT_STATS_SWITCH /* Print heap statistics if supported by the platform. */ void print_heap_stats (void) { /* Darwin / Mac OS X */ # ifdef __APPLE__ malloc_statistics_t s; malloc_zone_statistics (NULL, &s); printf (_("\n# CRT Heap: %u bytes in use, in %u blocks, avg %u bytes/block\n"), (unsigned)s.size_in_use, (unsigned)s.blocks_in_use, (unsigned)(s.size_in_use / s.blocks_in_use)); printf (_("# %u bytes max in use (high water mark)\n"), (unsigned)s.max_size_in_use); printf (_("# %u bytes reserved, %u bytes free (estimate)\n"), (unsigned)s.size_allocated, (unsigned)(s.size_allocated - s.size_in_use)); # endif /* __APPLE__ */ /* MSC / Windows */ # ifdef _MSC_VER unsigned int blocks_used = 0; unsigned int bytes_used = 0; unsigned int blocks_avail = 0; unsigned int bytes_avail = 0; _HEAPINFO hinfo; memset (&hinfo, '\0', sizeof (hinfo)); while (_heapwalk(&hinfo) == _HEAPOK) { if (hinfo._useflag == _USEDENTRY) { blocks_used++; bytes_used += hinfo._size; } else { blocks_avail++; bytes_avail += hinfo._size; } } printf (_("\n# CRT Heap: %u bytes in use, in %u blocks, avg %u bytes/block\n"), bytes_used, blocks_used, bytes_used / blocks_used); printf (_("# %u bytes avail, in %u blocks, avg %u bytes/block\n"), bytes_avail, blocks_avail, bytes_avail / blocks_avail); # endif /* _MSC_VER */ /* Darwin Libc sources indicates that something like this may be found in GLIBC, however, it's not in any current one... */ # if 0 /* ??? */ struct mstats m; m = mstats(); printf (_("\n# CRT Heap: %zu blocks / %zu bytes in use, %zu blocks / %zu bytes free\n"), m.chunks_used, m.bytes_used, m.chunks_free, m.bytes_free); printf (_("# %zu bytes reserved\n"), m.bytes_total); # endif /* ??? */ /* XVID2/XPG mallinfo (displayed per GLIBC documentation). */ # if defined(__GLIBC__) || defined(HAVE_MALLINFO) struct mallinfo m; m = mallinfo(); printf (_("\n# CRT Heap: %d bytes in use, %d bytes free\n"), m.uordblks, m.fordblks); printf (_("# # free chunks=%d, # fastbin blocks=%d\n"), m.ordblks, m.smblks); printf (_("# # mapped regions=%d, space in mapped regions=%d\n"), m.hblks, m.hblkhd); printf (_("# non-mapped space allocated from system=%d\n"), m.arena); printf (_("# maximum total allocated space=%d\n"), m.usmblks); printf (_("# top-most releasable space=%d\n"), m.keepcost); # endif /* __GLIBC__ || HAVE_MALLINFO */ # ifdef CONFIG_WITH_MAKE_STATS printf(_("# %lu malloc calls, %lu realloc calls\n"), make_stats_allocations, make_stats_reallocations); printf(_("# %lu MBs alloc sum, not counting freed, add pinch of salt\n"), /* XXX: better wording */ make_stats_allocated / (1024*1024)); # endif /* XXX: windows */ } #endif /* CONFIG_WITH_PRINT_STATS_SWITCH */ #ifdef CONFIG_WITH_PRINT_TIME_SWITCH /* Get a nanosecond timestamp, from a monotonic time source if possible. Returns -1 after calling error() on failure. */ big_int nano_timestamp (void) { big_int ts; #if defined (WINDOWS32) static int s_state = -1; static LARGE_INTEGER s_freq; if (s_state == -1) s_state = QueryPerformanceFrequency (&s_freq); if (s_state) { LARGE_INTEGER pc; if (!QueryPerformanceCounter (&pc)) { s_state = 0; return nano_timestamp (); } ts = (big_int)((long double)pc.QuadPart / (long double)s_freq.QuadPart * 1000000000); } else { /* fall back to low resolution system time. */ LARGE_INTEGER bigint; FILETIME ft = {0,0}; GetSystemTimeAsFileTime (&ft); bigint.u.LowPart = ft.dwLowDateTime; bigint.u.HighPart = ft.dwLowDateTime; ts = bigint.QuadPart * 100; } #elif HAVE_GETTIMEOFDAY /* FIXME: Linux and others have the realtime clock_* api, detect and use it. */ struct timeval tv; if (!gettimeofday (&tv, NULL)) ts = (big_int)tv.tv_sec * 1000000000 + tv.tv_usec * 1000; else { O (error, NILF, _("gettimeofday failed")); ts = -1; } #else # error "PORTME" #endif return ts; } /* Formats the elapsed time (nano seconds) in the manner easiest to read, with millisecond percision for larger numbers. */ int format_elapsed_nano (char *buf, size_t size, big_int ts) { unsigned sz; if (ts < 1000) sz = sprintf (buf, "%uns", (unsigned)ts); else if (ts < 100000) sz = sprintf (buf, "%u.%03uus", (unsigned)(ts / 1000), (unsigned)(ts % 1000)); else { ts /= 1000; if (ts < 1000) sz = sprintf (buf, "%uus", (unsigned)ts); else if (ts < 100000) sz = sprintf (buf, "%u.%03ums", (unsigned)(ts / 1000), (unsigned)(ts % 1000)); else { ts /= 1000; if (ts < BIG_INT_C(60000)) sz = sprintf (buf, "%u.%03us", (unsigned)(ts / 1000), (unsigned)(ts % 1000)); else sz = sprintf (buf, "%um%u.%03us", (unsigned)( ts / BIG_INT_C(60000)), (unsigned)((ts % BIG_INT_C(60000)) / 1000), (unsigned)((ts % BIG_INT_C(60000)) % 1000)); } } if (sz >= size) ONN (fatal, NILF, _("format_elapsed_nano buffer overflow: %u written, %lu buffer"), sz, (unsigned long)size); return sz; } #endif /* CONFIG_WITH_PRINT_TIME_SWITCH */ kbuild-3149/src/kmk/hash.c0000644000175000017500000003252513252530202015345 0ustar locutuslocutus/* hash.c -- hash table maintenance Copyright (C) 1995, 1999, 2002, 2010 Free Software Foundation, Inc. Written by Greg McGary GNU Make 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" #include "hash.h" #ifdef CONFIG_WITH_STRCACHE2 # include #endif #define CALLOC(t, n) ((t *) xcalloc (sizeof (t) * (n))) #define MALLOC(t, n) ((t *) xmalloc (sizeof (t) * (n))) #define REALLOC(o, t, n) ((t *) xrealloc ((o), sizeof (t) * (n))) #define CLONE(o, t, n) ((t *) memcpy (MALLOC (t, (n)), (o), sizeof (t) * (n))) static void hash_rehash __P((struct hash_table* ht)); static unsigned long round_up_2 __P((unsigned long rough)); /* Implement double hashing with open addressing. The table size is always a power of two. The secondary ('increment') hash function is forced to return an odd-value, in order to be relatively prime to the table size. This guarantees that the increment can potentially hit every slot in the table during collision resolution. */ void *hash_deleted_item = &hash_deleted_item; /* Force the table size to be a power of two, possibly rounding up the given size. */ void hash_init (struct hash_table *ht, unsigned long size, hash_func_t hash_1, hash_func_t hash_2, hash_cmp_func_t hash_cmp) { ht->ht_size = round_up_2 (size); ht->ht_empty_slots = ht->ht_size; ht->ht_vec = (void**) CALLOC (struct token *, ht->ht_size); if (ht->ht_vec == 0) { fprintf (stderr, _("can't allocate %lu bytes for hash table: memory exhausted"), ht->ht_size * (unsigned long) sizeof (struct token *)); exit (MAKE_TROUBLE); } ht->ht_capacity = ht->ht_size - (ht->ht_size / 16); /* 93.75% loading factor */ ht->ht_fill = 0; ht->ht_collisions = 0; ht->ht_lookups = 0; ht->ht_rehashes = 0; ht->ht_hash_1 = hash_1; ht->ht_hash_2 = hash_2; ht->ht_compare = hash_cmp; #ifdef CONFIG_WITH_STRCACHE2 ht->ht_strcache = 0; ht->ht_off_string = 0; #endif } #ifdef CONFIG_WITH_STRCACHE2 /* Same as hash_init, except that no callbacks are needed since all keys - including the ones being searched for - are from a string cache. This means that any give string will only have one pointer value and that the hash and length can be retrived very cheaply, thus permitting some nice optimizations. STRCACHE points to the string cache, while OFF_STRING gives the offset of the string pointer in the item structures the hash table entries points to. */ void hash_init_strcached (struct hash_table *ht, unsigned long size, struct strcache2 *strcache, unsigned int off_string) { hash_init (ht, size, 0, 0, 0); ht->ht_strcache = strcache; ht->ht_off_string = off_string; } #endif /* CONFIG_WITH_STRCACHE2 */ /* Load an array of items into 'ht'. */ void hash_load (struct hash_table *ht, void *item_table, unsigned long cardinality, unsigned long size) { char *items = (char *) item_table; #ifndef CONFIG_WITH_STRCACHE2 while (cardinality--) { hash_insert (ht, items); items += size; } #else /* CONFIG_WITH_STRCACHE2 */ if (ht->ht_strcache) while (cardinality--) { hash_insert_strcached (ht, items); items += size; } else while (cardinality--) { hash_insert (ht, items); items += size; } #endif /* CONFIG_WITH_STRCACHE2 */ } /* Returns the address of the table slot matching 'key'. If 'key' is not found, return the address of an empty slot suitable for inserting 'key'. The caller is responsible for incrementing ht_fill on insertion. */ void ** hash_find_slot (struct hash_table *ht, const void *key) { void **slot; void **deleted_slot = 0; unsigned int hash_2 = 0; unsigned int hash_1 = (*ht->ht_hash_1) (key); #ifdef CONFIG_WITH_STRCACHE2 assert (ht->ht_strcache == 0); #endif MAKE_STATS (ht->ht_lookups++); MAKE_STATS_3 (make_stats_ht_lookups++); for (;;) { hash_1 &= (ht->ht_size - 1); slot = &ht->ht_vec[hash_1]; if (*slot == 0) return (deleted_slot ? deleted_slot : slot); if (*slot == hash_deleted_item) { if (deleted_slot == 0) deleted_slot = slot; } else { if (key == *slot) return slot; if ((*ht->ht_compare) (key, *slot) == 0) return slot; MAKE_STATS (ht->ht_collisions++); MAKE_STATS_3 (make_stats_ht_collisions++); } if (!hash_2) hash_2 = (*ht->ht_hash_2) (key) | 1; hash_1 += hash_2; } } #ifdef CONFIG_WITH_STRCACHE2 /* hash_find_slot version for tables created with hash_init_strcached. */ void ** hash_find_slot_strcached (struct hash_table *ht, const void *key) { void **slot; void **deleted_slot = 0; const char *str1 = *(const char **)((const char *)key + ht->ht_off_string); const char *str2; unsigned int hash_1 = strcache2_calc_ptr_hash (ht->ht_strcache, str1); unsigned int hash_2; #ifdef CONFIG_WITH_STRCACHE2 assert (ht->ht_strcache != 0); #endif MAKE_STATS (ht->ht_lookups++); MAKE_STATS_3 (make_stats_ht_lookups++); /* first iteration unrolled. */ hash_1 &= (ht->ht_size - 1); slot = &ht->ht_vec[hash_1]; if (*slot == 0) return slot; if (*slot != hash_deleted_item) { str2 = *(const char **)((const char *)(*slot) + ht->ht_off_string); if (str1 == str2) return slot; MAKE_STATS (ht->ht_collisions++); MAKE_STATS_3 (make_stats_ht_collisions++); } else deleted_slot = slot; /* the rest of the loop. */ hash_2 = strcache2_get_hash (ht->ht_strcache, str1) | 1; hash_1 += hash_2; for (;;) { hash_1 &= (ht->ht_size - 1); slot = &ht->ht_vec[hash_1]; if (*slot == 0) return (deleted_slot ? deleted_slot : slot); if (*slot == hash_deleted_item) { if (deleted_slot == 0) deleted_slot = slot; } else { str2 = *(const char **)((const char *)(*slot) + ht->ht_off_string); if (str1 == str2) return slot; MAKE_STATS (ht->ht_collisions++); MAKE_STATS_3 (make_stats_ht_collisions++); } hash_1 += hash_2; } } #endif /* CONFIG_WITH_STRCACHE2 */ void * hash_find_item (struct hash_table *ht, const void *key) { void **slot = hash_find_slot (ht, key); return ((HASH_VACANT (*slot)) ? 0 : *slot); } #ifdef CONFIG_WITH_STRCACHE2 void * hash_find_item_strcached (struct hash_table *ht, const void *key) { void **slot = hash_find_slot_strcached (ht, key); return ((HASH_VACANT (*slot)) ? 0 : *slot); } #endif /* CONFIG_WITH_STRCACHE2 */ void * hash_insert (struct hash_table *ht, const void *item) { void **slot = hash_find_slot (ht, item); const void *old_item = *slot; hash_insert_at (ht, item, slot); return (void *)((HASH_VACANT (old_item)) ? 0 : old_item); } #ifdef CONFIG_WITH_STRCACHE2 void * hash_insert_strcached (struct hash_table *ht, const void *item) { void **slot = hash_find_slot_strcached (ht, item); const void *old_item = slot ? *slot : 0; hash_insert_at (ht, item, slot); return (void *)((HASH_VACANT (old_item)) ? 0 : old_item); } #endif /* CONFIG_WITH_STRCACHE2 */ void * hash_insert_at (struct hash_table *ht, const void *item, const void *slot) { const void *old_item = *(void **) slot; if (HASH_VACANT (old_item)) { ht->ht_fill++; if (old_item == 0) ht->ht_empty_slots--; old_item = item; } *(void const **) slot = item; if (ht->ht_empty_slots < ht->ht_size - ht->ht_capacity) { hash_rehash (ht); #ifdef CONFIG_WITH_STRCACHE2 if (ht->ht_strcache) return (void *)hash_find_slot_strcached (ht, item); #endif /* CONFIG_WITH_STRCACHE2 */ return (void *) hash_find_slot (ht, item); } else return (void *) slot; } void * hash_delete (struct hash_table *ht, const void *item) { void **slot = hash_find_slot (ht, item); return hash_delete_at (ht, slot); } #ifdef CONFIG_WITH_STRCACHE2 void * hash_delete_strcached (struct hash_table *ht, const void *item) { void **slot = hash_find_slot_strcached (ht, item); return hash_delete_at (ht, slot); } #endif /* CONFIG_WITH_STRCACHE2 */ void * hash_delete_at (struct hash_table *ht, const void *slot) { void *item = *(void **) slot; if (!HASH_VACANT (item)) { *(void const **) slot = hash_deleted_item; ht->ht_fill--; return item; } else return 0; } void hash_free_items (struct hash_table *ht) { void **vec = ht->ht_vec; void **end = &vec[ht->ht_size]; for (; vec < end; vec++) { void *item = *vec; if (!HASH_VACANT (item)) free (item); *vec = 0; } ht->ht_fill = 0; ht->ht_empty_slots = ht->ht_size; } #ifdef CONFIG_WITH_ALLOC_CACHES void hash_free_items_cached (struct hash_table *ht, struct alloccache *cache) { void **vec = ht->ht_vec; void **end = &vec[ht->ht_size]; for (; vec < end; vec++) { void *item = *vec; if (!HASH_VACANT (item)) alloccache_free (cache, item); *vec = 0; } ht->ht_fill = 0; ht->ht_empty_slots = ht->ht_size; } #endif /* CONFIG_WITH_ALLOC_CACHES */ void hash_delete_items (struct hash_table *ht) { void **vec = ht->ht_vec; void **end = &vec[ht->ht_size]; for (; vec < end; vec++) *vec = 0; ht->ht_fill = 0; ht->ht_collisions = 0; ht->ht_lookups = 0; ht->ht_rehashes = 0; ht->ht_empty_slots = ht->ht_size; } void hash_free (struct hash_table *ht, int free_items) { if (free_items) hash_free_items (ht); else { ht->ht_fill = 0; ht->ht_empty_slots = ht->ht_size; } free (ht->ht_vec); ht->ht_vec = 0; ht->ht_capacity = 0; } #ifdef CONFIG_WITH_ALLOC_CACHES void hash_free_cached (struct hash_table *ht, int free_items, struct alloccache *cache) { if (free_items) hash_free_items_cached (ht, cache); else { ht->ht_fill = 0; ht->ht_empty_slots = ht->ht_size; } free (ht->ht_vec); ht->ht_vec = 0; ht->ht_capacity = 0; } #endif /* CONFIG_WITH_ALLOC_CACHES */ void hash_map (struct hash_table *ht, hash_map_func_t map) { void **slot; void **end = &ht->ht_vec[ht->ht_size]; for (slot = ht->ht_vec; slot < end; slot++) { if (!HASH_VACANT (*slot)) (*map) (*slot); } } void hash_map_arg (struct hash_table *ht, hash_map_arg_func_t map, void *arg) { void **slot; void **end = &ht->ht_vec[ht->ht_size]; for (slot = ht->ht_vec; slot < end; slot++) { if (!HASH_VACANT (*slot)) (*map) (*slot, arg); } } /* Double the size of the hash table in the event of overflow... */ static void hash_rehash (struct hash_table *ht) { unsigned long old_ht_size = ht->ht_size; void **old_vec = ht->ht_vec; void **ovp; if (ht->ht_fill >= ht->ht_capacity) { ht->ht_size *= 2; ht->ht_capacity = ht->ht_size - (ht->ht_size >> 4); } ht->ht_rehashes++; ht->ht_vec = (void **) CALLOC (struct token *, ht->ht_size); #ifndef CONFIG_WITH_STRCACHE2 for (ovp = old_vec; ovp < &old_vec[old_ht_size]; ovp++) { if (! HASH_VACANT (*ovp)) { void **slot = hash_find_slot (ht, *ovp); *slot = *ovp; } } #else /* CONFIG_WITH_STRCACHE2 */ if (ht->ht_strcache) for (ovp = old_vec; ovp < &old_vec[old_ht_size]; ovp++) { if (! HASH_VACANT (*ovp)) { void **slot = hash_find_slot_strcached (ht, *ovp); *slot = *ovp; } } else for (ovp = old_vec; ovp < &old_vec[old_ht_size]; ovp++) { if (! HASH_VACANT (*ovp)) { void **slot = hash_find_slot (ht, *ovp); *slot = *ovp; } } #endif /* CONFIG_WITH_STRCACHE2 */ ht->ht_empty_slots = ht->ht_size - ht->ht_fill; free (old_vec); } void hash_print_stats (struct hash_table *ht, FILE *out_FILE) { /* GKM FIXME: honor NO_FLOAT */ fprintf (out_FILE, _("Load=%ld/%ld=%.0f%%, "), ht->ht_fill, ht->ht_size, 100.0 * (double) ht->ht_fill / (double) ht->ht_size); fprintf (out_FILE, _("Rehash=%d, "), ht->ht_rehashes); MAKE_STATS( fprintf (out_FILE, _("Collisions=%ld/%ld=%.0f%%"), ht->ht_collisions, ht->ht_lookups, (ht->ht_lookups ? (100.0 * (double) ht->ht_collisions / (double) ht->ht_lookups) : 0)); ); } /* Dump all items into a NULL-terminated vector. Use the user-supplied vector, or malloc one. */ void ** hash_dump (struct hash_table *ht, void **vector_0, qsort_cmp_t compare) { void **vector; void **slot; void **end = &ht->ht_vec[ht->ht_size]; if (vector_0 == 0) vector_0 = MALLOC (void *, ht->ht_fill + 1); vector = vector_0; for (slot = ht->ht_vec; slot < end; slot++) if (!HASH_VACANT (*slot)) *vector++ = *slot; *vector = 0; if (compare) qsort (vector_0, ht->ht_fill, sizeof (void *), compare); return vector_0; } /* Round a given number up to the nearest power of 2. */ static unsigned long round_up_2 (unsigned long n) { n |= (n >> 1); n |= (n >> 2); n |= (n >> 4); n |= (n >> 8); n |= (n >> 16); #if !defined(HAVE_LIMITS_H) || ULONG_MAX > 4294967295 /* We only need this on systems where unsigned long is >32 bits. */ n |= (n >> 32); #endif return n + 1; } kbuild-3149/src/kmk/kbuild.c0000644000175000017500000030367513252530201015702 0ustar locutuslocutus/* $Id: kbuild.c 3140 2018-03-14 21:28:10Z bird $ */ /** @file * kBuild specific make functionality. */ /* * Copyright (c) 2006-2010 knut st. osmundsen * * This file is part of kBuild. * * kBuild 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. * * kBuild 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 kBuild. If not, see * */ /* No GNU coding style here! */ /******************************************************************************* * Header Files * *******************************************************************************/ #define NO_MEMCOPY_HACK #include "makeint.h" #include "filedef.h" #include "variable.h" #include "dep.h" #include "debug.h" #ifdef WINDOWS32 # include "pathstuff.h" # include #endif #if defined(__APPLE__) # include #endif #if defined(__FreeBSD__) # include # include #endif #include "kbuild.h" #include "k/kDefs.h" #include /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** Helper for passing a string constant to kbuild_get_variable_n. */ #define ST(strconst) strconst, sizeof(strconst) - 1 #if 1 # define my_memcpy(dst, src, len) \ do { \ if (len > 8) \ memcpy(dst, src, len); \ else \ switch (len) \ { \ case 8: dst[7] = src[7]; /* fall thru */ \ case 7: dst[6] = src[6]; /* fall thru */ \ case 6: dst[5] = src[5]; /* fall thru */ \ case 5: dst[4] = src[4]; /* fall thru */ \ case 4: dst[3] = src[3]; /* fall thru */ \ case 3: dst[2] = src[2]; /* fall thru */ \ case 2: dst[1] = src[1]; /* fall thru */ \ case 1: dst[0] = src[0]; /* fall thru */ \ case 0: break; \ } \ } while (0) #elif defined(__GNUC__) # define my_memcpy __builtin_memcpy #elif defined(_MSC_VER) # pragma instrinic(memcpy) # define my_memcpy memcpy #endif /******************************************************************************* * Global Variables * *******************************************************************************/ /** The argv[0] passed to main. */ static const char *g_pszExeName; /** The initial working directory. */ static char *g_pszInitialCwd; /** * Initialize kBuild stuff. * * @param argc Number of arguments to main(). * @param argv The main() argument vector. */ void init_kbuild(int argc, char **argv) { int rc; PATH_VAR(szTmp); /* * Get the initial cwd for use in my_abspath. */ #ifdef WINDOWS32 if (getcwd_fs(szTmp, GET_PATH_MAX) != 0) #else if (getcwd(szTmp, GET_PATH_MAX) != 0) #endif g_pszInitialCwd = xstrdup(szTmp); else O(fatal, NILF, _("getcwd failed")); /* * Determin the executable name. */ rc = -1; #if defined(__APPLE__) { const char *pszImageName = _dyld_get_image_name(0); if (pszImageName) { size_t cchImageName = strlen(pszImageName); if (cchImageName < GET_PATH_MAX) { memcpy(szTmp, pszImageName, cchImageName + 1); rc = 0; } } } #elif defined(__FreeBSD__) rc = readlink("/proc/curproc/file", szTmp, GET_PATH_MAX - 1); if (rc < 0 || rc == GET_PATH_MAX - 1) { rc = -1; # if 0 /* doesn't work because l_name isn't always absolute, it's just argv0 from exec or something. */ /* /proc is optional, try rtdl. */ void *hExe = dlopen(NULL, 0); rc = -1; if (hExe) { struct link_map const *pLinkMap = 0; if (dlinfo(hExe, RTLD_DI_LINKMAP, &pLinkMap) == 0) { const char *pszImageName = pLinkMap->l_name; size_t cchImageName = strlen(pszImageName); if (cchImageName < GET_PATH_MAX) { memcpy(szTmp, pszImageName, cchImageName + 1); rc = 0; } } } # endif } else szTmp[rc] = '\0'; #elif defined(__gnu_linux__) || defined(__linux__) rc = readlink("/proc/self/exe", szTmp, GET_PATH_MAX - 1); if (rc < 0 || rc == GET_PATH_MAX - 1) rc = -1; else szTmp[rc] = '\0'; #elif defined(__OS2__) _execname(szTmp, GET_PATH_MAX); rc = 0; #elif defined(__sun__) { char szTmp2[64]; snprintf(szTmp2, sizeof(szTmp2), "/proc/%ld/path/a.out", (long)getpid()); rc = readlink(szTmp2, szTmp, GET_PATH_MAX - 1); if (rc < 0 || rc == GET_PATH_MAX - 1) rc = -1; else szTmp[rc] = '\0'; } #elif defined(WINDOWS32) if (GetModuleFileName(GetModuleHandle(NULL), szTmp, GET_PATH_MAX)) rc = 0; #endif #if !defined(__OS2__) && !defined(WINDOWS32) /* fallback, try use the path to locate the binary. */ if ( rc < 0 && access(argv[0], X_OK)) { size_t cchArgv0 = strlen(argv[0]); const char *pszPath = getenv("PATH"); char *pszCopy = xstrdup(pszPath ? pszPath : "."); char *psz = pszCopy; while (*psz) { size_t cch; char *pszEnd = strchr(psz, PATH_SEPARATOR_CHAR); if (!pszEnd) pszEnd = strchr(psz, '\0'); cch = pszEnd - psz; if (cch + cchArgv0 + 2 <= GET_PATH_MAX) { memcpy(szTmp, psz, cch); szTmp[cch] = '/'; memcpy(&szTmp[cch + 1], argv[0], cchArgv0 + 1); if (!access(szTmp, X_OK)) { rc = 0; break; } } /* next */ psz = pszEnd; while (*psz == PATH_SEPARATOR_CHAR) psz++; } free(pszCopy); } #endif if (rc < 0) g_pszExeName = argv[0]; else g_pszExeName = xstrdup(szTmp); (void)argc; } /** * Wrapper that ensures correct starting_directory. */ static char *my_abspath(const char *pszIn, char *pszOut) { char *pszSaved, *pszRet; pszSaved = starting_directory; starting_directory = g_pszInitialCwd; pszRet = abspath(pszIn, pszOut); starting_directory = pszSaved; return pszRet; } /** * Determin the KBUILD_PATH value. * * @returns Pointer to static a buffer containing the value (consider it read-only). */ const char *get_kbuild_path(void) { static const char *s_pszPath = NULL; if (!s_pszPath) { PATH_VAR(szTmpPath); const char *pszEnvVar = getenv("KBUILD_PATH"); if ( !pszEnvVar || !my_abspath(pszEnvVar, szTmpPath)) { pszEnvVar = getenv("PATH_KBUILD"); if ( !pszEnvVar || !my_abspath(pszEnvVar, szTmpPath)) { #ifdef KBUILD_PATH return s_pszPath = KBUILD_PATH; #else /* $(abspath $(KBUILD_BIN_PATH)/../..)*/ size_t cch = strlen(get_kbuild_bin_path()); char *pszTmp2 = alloca(cch + sizeof("/../..")); strcat(strcpy(pszTmp2, get_kbuild_bin_path()), "/../.."); if (!my_abspath(pszTmp2, szTmpPath)) O(fatal, NILF, _("failed to determin KBUILD_PATH")); #endif } } s_pszPath = xstrdup(szTmpPath); } return s_pszPath; } /** * Determin the KBUILD_BIN_PATH value. * * @returns Pointer to static a buffer containing the value (consider it read-only). */ const char *get_kbuild_bin_path(void) { static const char *s_pszPath = NULL; if (!s_pszPath) { PATH_VAR(szTmpPath); const char *pszEnvVar = getenv("KBUILD_BIN_PATH"); if ( !pszEnvVar || !my_abspath(pszEnvVar, szTmpPath)) { pszEnvVar = getenv("PATH_KBUILD_BIN"); if ( !pszEnvVar || !my_abspath(pszEnvVar, szTmpPath)) { #ifdef KBUILD_PATH return s_pszPath = KBUILD_BIN_PATH; #else /* $(abspath $(dir $(ARGV0)).) */ size_t cch = strlen(g_pszExeName); char *pszTmp2 = alloca(cch + sizeof(".")); char *pszSep = pszTmp2 + cch - 1; memcpy(pszTmp2, g_pszExeName, cch); # ifdef HAVE_DOS_PATHS while (pszSep >= pszTmp2 && *pszSep != '/' && *pszSep != '\\' && *pszSep != ':') # else while (pszSep >= pszTmp2 && *pszSep != '/') # endif pszSep--; if (pszSep >= pszTmp2) strcpy(pszSep + 1, "."); else strcpy(pszTmp2, "."); if (!my_abspath(pszTmp2, szTmpPath)) OSS(fatal, NILF, _("failed to determin KBUILD_BIN_PATH (pszTmp2=%s szTmpPath=%s)"), pszTmp2, szTmpPath); #endif /* !KBUILD_PATH */ } } s_pszPath = xstrdup(szTmpPath); } return s_pszPath; } /** * Determin the location of default kBuild shell. * * @returns Pointer to static a buffer containing the location (consider it read-only). */ const char *get_default_kbuild_shell(void) { static char *s_pszDefaultShell = NULL; if (!s_pszDefaultShell) { #if defined(__OS2__) || defined(_WIN32) || defined(WINDOWS32) static const char s_szShellName[] = "/kmk_ash.exe"; #else static const char s_szShellName[] = "/kmk_ash"; #endif const char *pszBin = get_kbuild_bin_path(); size_t cchBin = strlen(pszBin); s_pszDefaultShell = xmalloc(cchBin + sizeof(s_szShellName)); memcpy(s_pszDefaultShell, pszBin, cchBin); memcpy(&s_pszDefaultShell[cchBin], s_szShellName, sizeof(s_szShellName)); } return s_pszDefaultShell; } #ifdef KMK_HELPERS /** * Applies the specified default path to any relative paths in *ppsz. * * @param pDefPath The default path. * @param ppsz Pointer to the string pointer. If we expand anything, *ppsz * will be replaced and the caller is responsible for calling free() on it. * @param pcch IN: *pcch contains the current string length. * OUT: *pcch contains the new string length. * @param pcchAlloc *pcchAlloc contains the length allocated for the string. Can be NULL. * @param fCanFree Whether *ppsz should be freed when we replace it. */ static void kbuild_apply_defpath(struct variable *pDefPath, char **ppsz, unsigned int *pcch, unsigned int *pcchAlloc, int fCanFree) { const char *pszIterator; const char *pszInCur; unsigned int cchInCur; unsigned int cchMaxRelative = 0; unsigned int cRelativePaths; /* * The first pass, count the relative paths. */ cRelativePaths = 0; pszIterator = *ppsz; while ((pszInCur = find_next_token(&pszIterator, &cchInCur)) != NULL) { /* is relative? */ #ifdef HAVE_DOS_PATHS if (pszInCur[0] != '/' && pszInCur[0] != '\\' && (cchInCur < 2 || pszInCur[1] != ':')) #else if (pszInCur[0] != '/') #endif { cRelativePaths++; if (cchInCur > cchMaxRelative) cchMaxRelative = cchInCur; } } /* * The second pass construct the new string. */ if (cRelativePaths) { size_t const cchAbsPathBuf = MAX(GET_PATH_MAX, pDefPath->value_length + cchInCur + 1 + 16); char *pszAbsPathOut = (char *)alloca(cchAbsPathBuf); char *pszAbsPathIn = (char *)alloca(cchAbsPathBuf); size_t cchAbsDefPath; size_t cchOut; char *pszOut; char *pszOutCur; const char *pszInNextCopy = *ppsz; /* make defpath absolute and have a trailing slash first. */ if (abspath(pDefPath->value, pszAbsPathIn) == NULL) memcpy(pszAbsPathIn, pDefPath->value, pDefPath->value_length); cchAbsDefPath = strlen(pszAbsPathIn); #ifdef HAVE_DOS_PATHS if (pszAbsPathIn[cchAbsDefPath - 1] != '/' && pszAbsPathIn[cchAbsDefPath - 1] != '\\') #else if (pszAbsPathIn[cchAbsDefPath - 1] != '/') #endif pszAbsPathIn[cchAbsDefPath++] = '/'; cchOut = *pcch + cRelativePaths * cchAbsDefPath + 1; pszOutCur = pszOut = xmalloc(cchOut); cRelativePaths = 0; pszIterator = *ppsz; while ((pszInCur = find_next_token(&pszIterator, &cchInCur))) { /* is relative? */ #ifdef HAVE_DOS_PATHS if (pszInCur[0] != '/' && pszInCur[0] != '\\' && (cchInCur < 2 || pszInCur[1] != ':')) #else if (pszInCur[0] != '/') #endif { const char *pszToCopy; size_t cchToCopy; /* Create the abspath input. */ memcpy(&pszAbsPathIn[cchAbsDefPath], pszInCur, cchInCur); pszAbsPathIn[cchAbsDefPath + cchInCur] = '\0'; pszToCopy = abspath(pszAbsPathIn, pszAbsPathOut); if (!pszToCopy) pszToCopy = pszAbsPathIn; /* copy leading input */ if (pszInCur != pszInNextCopy) { const size_t cchCopy = pszInCur - pszInNextCopy; memcpy(pszOutCur, pszInNextCopy, cchCopy); pszOutCur += cchCopy; } pszInNextCopy = pszInCur + cchInCur; /* copy out the abspath. */ cchToCopy = strlen(pszToCopy); assert(cchToCopy <= cchAbsDefPath + cchInCur); memcpy(pszOutCur, pszToCopy, cchToCopy); pszOutCur += cchToCopy; } /* else: Copy absolute paths as bulk when we hit then next relative one or the end. */ } /* the final copy (includes the nil). */ cchInCur = *ppsz + *pcch - pszInNextCopy; memcpy(pszOutCur, pszInNextCopy, cchInCur); pszOutCur += cchInCur; *pszOutCur = '\0'; assert((size_t)(pszOutCur - pszOut) < cchOut); /* set return values */ if (fCanFree) free(*ppsz); *ppsz = pszOut; *pcch = pszOutCur - pszOut; if (pcchAlloc) *pcchAlloc = cchOut; } } /** * Gets a variable that must exist. * Will cause a fatal failure if the variable doesn't exist. * * @returns Pointer to the variable. * @param pszName The variable name. * @param cchName The name length. */ MY_INLINE struct variable * kbuild_get_variable_n(const char *pszName, size_t cchName) { struct variable *pVar = lookup_variable(pszName, cchName); if (!pVar) fatal(NILF, cchName, _("variable `%.*s' isn't defined!"), (int)cchName, pszName); if (pVar->recursive) fatal(NILF, cchName, _("variable `%.*s' is defined as `recursive' instead of `simple'!"), (int)cchName, pszName); MY_ASSERT_MSG(strlen(pVar->value) == pVar->value_length, ("%u != %u %.*s\n", pVar->value_length, (unsigned int)strlen(pVar->value), (int)cchName, pVar->name)); return pVar; } /** * Gets a variable that must exist and can be recursive. * Will cause a fatal failure if the variable doesn't exist. * * @returns Pointer to the variable. * @param pszName The variable name. */ static struct variable * kbuild_get_recursive_variable(const char *pszName) { struct variable *pVar = lookup_variable(pszName, strlen(pszName)); if (!pVar) OS(fatal, NILF, _("variable `%s' isn't defined!"), pszName); MY_ASSERT_MSG(strlen(pVar->value) == pVar->value_length, ("%u != %u %s\n", pVar->value_length, (unsigned int)strlen(pVar->value), pVar->name)); return pVar; } /** * Gets a variable that doesn't have to exit, but if it does can be recursive. * * @returns Pointer to the variable. * NULL if not found. * @param pszName The variable name. Doesn't need to be terminated. * @param cchName The name length. */ static struct variable * kbuild_query_recursive_variable_n(const char *pszName, size_t cchName) { struct variable *pVar = lookup_variable(pszName, cchName); MY_ASSERT_MSG(!pVar || strlen(pVar->value) == pVar->value_length, ("%u != %u %.*s\n", pVar->value_length, (unsigned int)strlen(pVar->value), (int)cchName, pVar->name)); return pVar; } /** * Gets a variable that doesn't have to exit, but if it does can be recursive. * * @returns Pointer to the variable. * NULL if not found. * @param pszName The variable name. */ static struct variable * kbuild_query_recursive_variable(const char *pszName) { return kbuild_query_recursive_variable_n(pszName, strlen(pszName)); } /** * Converts the specified variable into a 'simple' one. * @returns pVar. * @param pVar The variable. */ static struct variable * kbuild_simplify_variable(struct variable *pVar) { if (memchr(pVar->value, '$', pVar->value_length)) { unsigned int value_len; char *pszExpanded = allocated_variable_expand_2(pVar->value, pVar->value_length, &value_len); #ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE if (pVar->rdonly_val) pVar->rdonly_val = 0; else #endif free(pVar->value); assert(pVar->origin != o_automatic); pVar->value = pszExpanded; pVar->value_length = value_len; pVar->value_alloc_len = value_len + 1; } pVar->recursive = 0; VARIABLE_CHANGED(pVar); return pVar; } /** * Looks up a variable. * The value_length field is valid upon successful return. * * @returns Pointer to the variable. NULL if not found. * @param pszName The variable name. * @param cchName The name length. */ MY_INLINE struct variable * kbuild_lookup_variable_n(const char *pszName, size_t cchName) { struct variable *pVar = lookup_variable(pszName, cchName); if (pVar) { MY_ASSERT_MSG(strlen(pVar->value) == pVar->value_length, ("%u != %u %.*s\n", pVar->value_length, (unsigned int)strlen(pVar->value), (int)cchName, pVar->name)); /* Make sure the variable is simple, convert it if necessary. Note! Must NOT do this for the dynamic INCS of sdks/ReorderCompilerIncs.kmk */ if (!pVar->recursive) { /* likely */ } else if ( cchName < sizeof("SDK_ReorderCompilerIncs_INCS.") - 1U || pszName[0] != 'S' || pszName[4] != 'R' || memcmp(pszName, "SDK_ReorderCompilerIncs_INCS.", sizeof("SDK_ReorderCompilerIncs_INCS.") - 1U) == 0) kbuild_simplify_variable(pVar); } return pVar; } /** * Looks up a variable. * The value_length field is valid upon successful return. * * @returns Pointer to the variable. NULL if not found. * @param pszName The variable name. */ MY_INLINE struct variable * kbuild_lookup_variable(const char *pszName) { return kbuild_lookup_variable_n(pszName, strlen(pszName)); } /** * Looks up a variable and applies default a path to all relative paths. * The value_length field is valid upon successful return. * * @returns Pointer to the variable. NULL if not found. * @param pDefPath The default path. * @param pszName The variable name. * @param cchName The name length. */ MY_INLINE struct variable * kbuild_lookup_variable_defpath_n(struct variable *pDefPath, const char *pszName, size_t cchName) { struct variable *pVar = kbuild_lookup_variable_n(pszName, cchName); if (pVar && pDefPath) { assert(pVar->origin != o_automatic); #ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE assert(!pVar->rdonly_val); #endif kbuild_apply_defpath(pDefPath, &pVar->value, &pVar->value_length, &pVar->value_alloc_len, 1); } return pVar; } /** * Looks up a variable and applies default a path to all relative paths. * The value_length field is valid upon successful return. * * @returns Pointer to the variable. NULL if not found. * @param pDefPath The default path. * @param pszName The variable name. */ MY_INLINE struct variable * kbuild_lookup_variable_defpath(struct variable *pDefPath, const char *pszName) { struct variable *pVar = kbuild_lookup_variable(pszName); if (pVar && pDefPath) { assert(pVar->origin != o_automatic); #ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE assert(!pVar->rdonly_val); #endif kbuild_apply_defpath(pDefPath, &pVar->value, &pVar->value_length, &pVar->value_alloc_len, 1); } return pVar; } /** * Gets the first defined property variable. */ static struct variable * kbuild_first_prop(struct variable *pTarget, struct variable *pSource, struct variable *pTool, struct variable *pType, struct variable *pBldTrg, struct variable *pBldTrgArch, const char *pszPropF1, char cchPropF1, const char *pszPropF2, char cchPropF2, const char *pszVarName) { struct variable *pVar; size_t cchBuf; char *pszBuf; char *psz, *psz1, *psz2, *psz3, *psz4, *pszEnd; /* calc and allocate a too big name buffer. */ cchBuf = cchPropF2 + 1 + cchPropF1 + 1 + pTarget->value_length + 1 + pSource->value_length + 1 + (pTool ? pTool->value_length + 1 : 0) + pType->value_length + 1 + pBldTrg->value_length + 1 + pBldTrgArch->value_length + 1; pszBuf = xmalloc(cchBuf); #define ADD_VAR(pVar) do { my_memcpy(psz, (pVar)->value, (pVar)->value_length); psz += (pVar)->value_length; } while (0) #define ADD_STR(pszStr, cchStr) do { my_memcpy(psz, (pszStr), (cchStr)); psz += (cchStr); } while (0) #define ADD_CSTR(pszStr) do { my_memcpy(psz, pszStr, sizeof(pszStr) - 1); psz += sizeof(pszStr) - 1; } while (0) #define ADD_CH(ch) do { *psz++ = (ch); } while (0) /* * $(target)_$(source)_$(type)$(propf2).$(bld_trg).$(bld_trg_arch) */ psz = pszBuf; ADD_VAR(pTarget); ADD_CH('_'); ADD_VAR(pSource); ADD_CH('_'); psz2 = psz; ADD_VAR(pType); ADD_STR(pszPropF2, cchPropF2); psz3 = psz; ADD_CH('.'); ADD_VAR(pBldTrg); psz4 = psz; ADD_CH('.'); ADD_VAR(pBldTrgArch); pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf); /* $(target)_$(source)_$(type)$(propf2).$(bld_trg) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf); /* $(target)_$(source)_$(type)$(propf2) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf); /* * $(target)_$(source)_$(propf2).$(bld_trg).$(bld_trg_arch) */ if (!pVar) { psz = psz2; ADD_STR(pszPropF2, cchPropF2); psz3 = psz; ADD_CH('.'); ADD_VAR(pBldTrg); psz4 = psz; ADD_CH('.'); ADD_VAR(pBldTrgArch); pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf); /* $(target)_$(source)_$(propf2).$(bld_trg) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf); /* $(target)_$(source)_$(propf2) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf); } /* * $(source)_$(type)$(propf2).$(bld_trg).$(bld_trg_arch) */ if (!pVar) { psz = pszBuf; ADD_VAR(pSource); ADD_CH('_'); psz2 = psz; ADD_VAR(pType); ADD_STR(pszPropF2, cchPropF2); psz3 = psz; ADD_CH('.'); ADD_VAR(pBldTrg); psz4 = psz; ADD_CH('.'); ADD_VAR(pBldTrgArch); pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf); /* $(source)_$(type)$(propf2).$(bld_trg) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf); /* $(source)_$(type)$(propf2) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf); /* * $(source)_$(propf2).$(bld_trg).$(bld_trg_arch) */ if (!pVar) { psz = psz2; ADD_STR(pszPropF2, cchPropF2); psz3 = psz; ADD_CH('.'); ADD_VAR(pBldTrg); psz4 = psz; ADD_CH('.'); ADD_VAR(pBldTrgArch); pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf); /* $(source)_$(propf2).$(bld_trg) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf); /* $(source)_$(propf2) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf); } } /* * $(target)_$(type)$(propf2).$(bld_trg).$(bld_trg_arch) */ if (!pVar) { psz = pszBuf; ADD_VAR(pTarget); ADD_CH('_'); psz2 = psz; ADD_VAR(pType); ADD_STR(pszPropF2, cchPropF2); psz3 = psz; ADD_CH('.'); ADD_VAR(pBldTrg); psz4 = psz; ADD_CH('.'); ADD_VAR(pBldTrgArch); pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf); /* $(target)_$(type)$(propf2).$(bld_trg) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf); /* $(target)_$(type)$(propf2) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf); /* $(target)_$(propf2).$(bld_trg).$(bld_trg_arch) */ if (!pVar) { psz = psz2; ADD_STR(pszPropF2, cchPropF2); psz3 = psz; ADD_CH('.'); ADD_VAR(pBldTrg); psz4 = psz; ADD_CH('.'); ADD_VAR(pBldTrgArch); pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf); } /* $(target)_$(propf2).$(bld_trg) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf); /* $(target)_$(propf2) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf); } /* * TOOL_$(tool)_$(type)$(propf2).$(bld_trg).$(bld_trg_arch) */ if (!pVar && pTool) { psz = pszBuf; ADD_CSTR("TOOL_"); ADD_VAR(pTool); ADD_CH('_'); psz2 = psz; ADD_VAR(pType); ADD_STR(pszPropF2, cchPropF2); psz3 = psz; ADD_CH('.'); ADD_VAR(pBldTrg); psz4 = psz; ADD_CH('.'); ADD_VAR(pBldTrgArch); pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf); /* TOOL_$(tool)_$(type)$(propf2).$(bld_trg) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf); /* TOOL_$(tool)_$(type)$(propf2) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf); /* TOOL_$(tool)_$(propf2).$(bld_trg).$(bld_trg_arch) */ if (!pVar) { psz = psz2; ADD_STR(pszPropF2, cchPropF2); psz3 = psz; ADD_CH('.'); ADD_VAR(pBldTrg); psz4 = psz; ADD_CH('.'); ADD_VAR(pBldTrgArch); pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf); /* TOOL_$(tool)_$(propf2).$(bld_trg) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf); /* TOOL_$(tool)_$(propf2) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf); } } /* * $(type)$(propf1).$(bld_trg).$(bld_trg_arch) */ if (!pVar) { psz = pszBuf; ADD_VAR(pType); ADD_STR(pszPropF1, cchPropF1); psz3 = psz; ADD_CH('.'); ADD_VAR(pBldTrg); psz4 = psz; ADD_CH('.'); ADD_VAR(pBldTrgArch); pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf); /* $(type)$(propf1).$(bld_trg) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf); /* $(type)$(propf1) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf); /* * $(propf1).$(bld_trg).$(bld_trg_arch) */ if (!pVar) { psz1 = pszBuf + pType->value_length; pVar = kbuild_lookup_variable_n(psz1, psz - psz1); /* $(propf1).$(bld_trg) */ if (!pVar) pVar = kbuild_lookup_variable_n(psz1, psz4 - psz1); /* $(propf1) */ if (!pVar) pVar = kbuild_lookup_variable_n(pszPropF1, cchPropF1); } } free(pszBuf); #undef ADD_VAR #undef ADD_STR #undef ADD_CSTR #undef ADD_CH if (pVar) { /* strip it */ psz = pVar->value; pszEnd = psz + pVar->value_length; while (ISBLANK(*psz)) psz++; while (pszEnd > psz && ISBLANK(pszEnd[-1])) pszEnd--; if (pszEnd > psz) { char chSaved = *pszEnd; *pszEnd = '\0'; pVar = define_variable_vl(pszVarName, strlen(pszVarName), psz, pszEnd - psz, 1 /* duplicate */, o_local, 0 /* !recursive */); *pszEnd = chSaved; if (pVar) return pVar; } } return NULL; } /* _SOURCE_TOOL = $(strip $(firstword \ $($(target)_$(source)_$(type)TOOL.$(bld_trg).$(bld_trg_arch)) \ $($(target)_$(source)_$(type)TOOL.$(bld_trg)) \ $($(target)_$(source)_$(type)TOOL) \ $($(target)_$(source)_TOOL.$(bld_trg).$(bld_trg_arch)) \ $($(target)_$(source)_TOOL.$(bld_trg)) \ $($(target)_$(source)_TOOL) \ $($(source)_$(type)TOOL.$(bld_trg).$(bld_trg_arch)) \ $($(source)_$(type)TOOL.$(bld_trg)) \ $($(source)_$(type)TOOL) \ $($(source)_TOOL.$(bld_trg).$(bld_trg_arch)) \ $($(source)_TOOL.$(bld_trg)) \ $($(source)_TOOL) \ $($(target)_$(type)TOOL.$(bld_trg).$(bld_trg_arch)) \ $($(target)_$(type)TOOL.$(bld_trg)) \ $($(target)_$(type)TOOL) \ $($(target)_TOOL.$(bld_trg).$(bld_trg_arch)) \ $($(target)_TOOL.$(bld_trg)) \ $($(target)_TOOL) \ $($(type)TOOL.$(bld_trg).$(bld_trg_arch)) \ $($(type)TOOL.$(bld_trg)) \ $($(type)TOOL) \ $(TOOL.$(bld_trg).$(bld_trg_arch)) \ $(TOOL.$(bld_trg)) \ $(TOOL) )) */ static struct variable * kbuild_get_source_tool(struct variable *pTarget, struct variable *pSource, struct variable *pType, struct variable *pBldTrg, struct variable *pBldTrgArch, const char *pszVarName) { struct variable *pVar = kbuild_first_prop(pTarget, pSource, NULL, pType, pBldTrg, pBldTrgArch, "TOOL", sizeof("TOOL") - 1, "TOOL", sizeof("TOOL") - 1, pszVarName); if (!pVar) OSS(fatal, NILF, _("no tool for source `%s' in target `%s'!"), pSource->value, pTarget->value); return pVar; } /* Implements _SOURCE_TOOL. */ char * func_kbuild_source_tool(char *o, char **argv, const char *pszFuncName) { struct variable *pVar = kbuild_get_source_tool(kbuild_get_variable_n(ST("target")), kbuild_get_variable_n(ST("source")), kbuild_get_variable_n(ST("type")), kbuild_get_variable_n(ST("bld_trg")), kbuild_get_variable_n(ST("bld_trg_arch")), argv[0]); if (pVar) o = variable_buffer_output(o, pVar->value, pVar->value_length); (void)pszFuncName; return o; } /* This has been extended a bit, it's now identical to _SOURCE_TOOL. $(firstword \ $($(target)_$(source)_OBJSUFF.$(bld_trg).$(bld_trg_arch))\ $($(target)_$(source)_OBJSUFF.$(bld_trg))\ $($(target)_$(source)_OBJSUFF)\ $($(source)_OBJSUFF.$(bld_trg).$(bld_trg_arch))\ $($(source)_OBJSUFF.$(bld_trg))\ $($(source)_OBJSUFF)\ $($(target)_OBJSUFF.$(bld_trg).$(bld_trg_arch))\ $($(target)_OBJSUFF.$(bld_trg))\ $($(target)_OBJSUFF)\ $(TOOL_$(tool)_$(type)OBJSUFF.$(bld_trg).$(bld_trg_arch))\ $(TOOL_$(tool)_$(type)OBJSUFF.$(bld_trg))\ $(TOOL_$(tool)_$(type)OBJSUFF)\ $(SUFF_OBJ)) */ static struct variable * kbuild_get_object_suffix(struct variable *pTarget, struct variable *pSource, struct variable *pTool, struct variable *pType, struct variable *pBldTrg, struct variable *pBldTrgArch, const char *pszVarName) { struct variable *pVar = kbuild_first_prop(pTarget, pSource, pTool, pType, pBldTrg, pBldTrgArch, "SUFF_OBJ", sizeof("SUFF_OBJ") - 1, "OBJSUFF", sizeof("OBJSUFF") - 1, pszVarName); if (!pVar) OSS(fatal, NILF, _("no OBJSUFF attribute or SUFF_OBJ default for source `%s' in target `%s'!"), pSource->value, pTarget->value); return pVar; } /* */ char * func_kbuild_object_suffix(char *o, char **argv, const char *pszFuncName) { struct variable *pVar = kbuild_get_object_suffix(kbuild_get_variable_n(ST("target")), kbuild_get_variable_n(ST("source")), kbuild_get_variable_n(ST("tool")), kbuild_get_variable_n(ST("type")), kbuild_get_variable_n(ST("bld_trg")), kbuild_get_variable_n(ST("bld_trg_arch")), argv[0]); if (pVar) o = variable_buffer_output(o, pVar->value, pVar->value_length); (void)pszFuncName; return o; } /* ## Figure out where to put object files. # @param $1 source file # @param $2 normalized main target # @remark There are two major hacks here: # 1. Source files in the output directory are translated into a gen/ subdir. # 2. Catch anyone specifying $(PATH_SUB_CURRENT)/sourcefile.c. _OBJECT_BASE = $(PATH_TARGET)/$(2)/$(call no-root-slash,$(call no-drive,$(basename \ $(patsubst $(PATH_ROOT)/%,%,$(patsubst $(PATH_SUB_CURRENT)/%,%,$(patsubst $(PATH_TARGET)/$(2)/%,gen/%,$(1))))))) */ static struct variable * kbuild_get_object_base(struct variable *pTarget, struct variable *pSource, const char *pszVarName) { struct variable *pPathTarget = kbuild_get_variable_n(ST("PATH_TARGET")); struct variable *pPathRoot = kbuild_get_variable_n(ST("PATH_ROOT")); struct variable *pPathSubCur = kbuild_get_variable_n(ST("PATH_SUB_CURRENT")); const char *pszSrcPrefix = NULL; size_t cchSrcPrefix = 0; size_t cchSrc = 0; const char *pszSrcEnd; char *pszSrc; char *pszResult; char *psz; char *pszDot; size_t cch; /* * Strip the source filename of any uncessary leading path and root specs. */ /* */ if ( pSource->value_length > pPathTarget->value_length && !strncmp(pSource->value, pPathTarget->value, pPathTarget->value_length)) { pszSrc = pSource->value + pPathTarget->value_length; pszSrcPrefix = "gen/"; cchSrcPrefix = sizeof("gen/") - 1; if ( *pszSrc == '/' && !strncmp(pszSrc + 1, pTarget->value, pTarget->value_length) && ( pszSrc[pTarget->value_length + 1] == '/' || pszSrc[pTarget->value_length + 1] == '\0')) pszSrc += 1 + pTarget->value_length; } else if ( pSource->value_length > pPathRoot->value_length && !strncmp(pSource->value, pPathRoot->value, pPathRoot->value_length)) { pszSrc = pSource->value + pPathRoot->value_length; if ( *pszSrc == '/' && !strncmp(pszSrc + 1, pPathSubCur->value, pPathSubCur->value_length) && ( pszSrc[pPathSubCur->value_length + 1] == '/' || pszSrc[pPathSubCur->value_length + 1] == '\0')) pszSrc += 1 + pPathSubCur->value_length; } else pszSrc = pSource->value; /* skip root specification */ #ifdef HAVE_DOS_PATHS if (isalpha(pszSrc[0]) && pszSrc[1] == ':') pszSrc += 2; #endif while (*pszSrc == '/' #ifdef HAVE_DOS_PATHS || *pszSrc == '\\' #endif ) pszSrc++; /* drop the source extension. */ pszSrcEnd = pSource->value + pSource->value_length; for (;;) { pszSrcEnd--; if ( pszSrcEnd <= pszSrc || *pszSrcEnd == '/' #ifdef HAVE_DOS_PATHS || *pszSrcEnd == '\\' || *pszSrcEnd == ':' #endif ) { pszSrcEnd = pSource->value + pSource->value_length; break; } if (*pszSrcEnd == '.') break; } /* * Assemble the string on the heap and define the objbase variable * which we then return. */ cchSrc = pszSrcEnd - pszSrc; cch = pPathTarget->value_length + 1 /* slash */ + pTarget->value_length + 1 /* slash */ + cchSrcPrefix + cchSrc + 1; psz = pszResult = xmalloc(cch); memcpy(psz, pPathTarget->value, pPathTarget->value_length); psz += pPathTarget->value_length; *psz++ = '/'; memcpy(psz, pTarget->value, pTarget->value_length); psz += pTarget->value_length; *psz++ = '/'; if (pszSrcPrefix) { memcpy(psz, pszSrcPrefix, cchSrcPrefix); psz += cchSrcPrefix; } pszDot = psz; memcpy(psz, pszSrc, cchSrc); psz += cchSrc; *psz = '\0'; /* convert '..' path elements in the source to 'dt'. */ while ((pszDot = memchr(pszDot, '.', psz - pszDot)) != NULL) { if ( pszDot[1] == '.' && ( pszDot == psz || pszDot[-1] == '/' #ifdef HAVE_DOS_PATHS || pszDot[-1] == '\\' || pszDot[-1] == ':' #endif ) && ( !pszDot[2] || pszDot[2] == '/' #ifdef HAVE_DOS_PATHS || pszDot[2] == '\\' || pszDot[2] == ':' #endif ) ) { *pszDot++ = 'd'; *pszDot++ = 't'; } else pszDot++; } /* * Define the variable in the current set and return it. */ return define_variable_vl(pszVarName, strlen(pszVarName), pszResult, cch - 1, 0 /* use pszResult */, o_local, 0 /* !recursive */); } /* Implements _OBJECT_BASE. */ char * func_kbuild_object_base(char *o, char **argv, const char *pszFuncName) { struct variable *pVar = kbuild_get_object_base(kbuild_lookup_variable("target"), kbuild_lookup_variable("source"), argv[0]); if (pVar) o = variable_buffer_output(o, pVar->value, pVar->value_length); (void)pszFuncName; return o; } struct kbuild_sdks { char *apsz[4]; struct variable *pa; unsigned c; unsigned iGlobal; unsigned cGlobal; unsigned iTarget; unsigned cTarget; unsigned iSource; unsigned cSource; unsigned iTargetSource; unsigned cTargetSource; unsigned int cchMax; }; /* Fills in the SDK struct (remember to free it). */ static void kbuild_get_sdks(struct kbuild_sdks *pSdks, struct variable *pTarget, struct variable *pSource, struct variable *pBldType, struct variable *pBldTrg, struct variable *pBldTrgArch) { unsigned i; unsigned j; size_t cchTmp, cch; char *pszTmp; unsigned cchCur; char *pszCur; const char *pszIterator; /** @todo rewrite this to avoid sprintf and allocated_varaible_expand_2. */ /* basic init. */ pSdks->cchMax = 0; pSdks->pa = NULL; pSdks->c = 0; i = 0; /* determin required tmp variable name space. */ cchTmp = sizeof("$(__SDKS) $(__SDKS.) $(__SDKS.) $(__SDKS.) $(__SDKS..)") + (pTarget->value_length + pSource->value_length) * 5 + pBldType->value_length + pBldTrg->value_length + pBldTrgArch->value_length + pBldTrg->value_length + pBldTrgArch->value_length; pszTmp = alloca(cchTmp); /* the global sdks. */ pSdks->iGlobal = i; pSdks->cGlobal = 0; cch = sprintf(pszTmp, "$(SDKS) $(SDKS.%s) $(SDKS.%s) $(SDKS.%s) $(SDKS.%s.%s)", pBldType->value, pBldTrg->value, pBldTrgArch->value, pBldTrg->value, pBldTrgArch->value); pszIterator = pSdks->apsz[0] = allocated_variable_expand_2(pszTmp, cch, NULL); while ((pszCur = find_next_token(&pszIterator, &cchCur)) != 0) pSdks->cGlobal++; i += pSdks->cGlobal; /* the target sdks.*/ pSdks->iTarget = i; pSdks->cTarget = 0; cch = sprintf(pszTmp, "$(%s_SDKS) $(%s_SDKS.%s) $(%s_SDKS.%s) $(%s_SDKS.%s) $(%s_SDKS.%s.%s)", pTarget->value, pTarget->value, pBldType->value, pTarget->value, pBldTrg->value, pTarget->value, pBldTrgArch->value, pTarget->value, pBldTrg->value, pBldTrgArch->value); pszIterator = pSdks->apsz[1] = allocated_variable_expand_2(pszTmp, cch, NULL); while ((pszCur = find_next_token(&pszIterator, &cchCur)) != 0) pSdks->cTarget++; i += pSdks->cTarget; /* the source sdks.*/ pSdks->iSource = i; pSdks->cSource = 0; cch = sprintf(pszTmp, "$(%s_SDKS) $(%s_SDKS.%s) $(%s_SDKS.%s) $(%s_SDKS.%s) $(%s_SDKS.%s.%s)", pSource->value, pSource->value, pBldType->value, pSource->value, pBldTrg->value, pSource->value, pBldTrgArch->value, pSource->value, pBldTrg->value, pBldTrgArch->value); pszIterator = pSdks->apsz[2] = allocated_variable_expand_2(pszTmp, cch, NULL); while ((pszCur = find_next_token(&pszIterator, &cchCur)) != 0) pSdks->cSource++; i += pSdks->cSource; /* the target + source sdks. */ pSdks->iTargetSource = i; pSdks->cTargetSource = 0; cch = sprintf(pszTmp, "$(%s_%s_SDKS) $(%s_%s_SDKS.%s) $(%s_%s_SDKS.%s) $(%s_%s_SDKS.%s) $(%s_%s_SDKS.%s.%s)", pTarget->value, pSource->value, pTarget->value, pSource->value, pBldType->value, pTarget->value, pSource->value, pBldTrg->value, pTarget->value, pSource->value, pBldTrgArch->value, pTarget->value, pSource->value, pBldTrg->value, pBldTrgArch->value); assert(cch < cchTmp); (void)cch; pszIterator = pSdks->apsz[3] = allocated_variable_expand_2(pszTmp, cch, NULL); while ((pszCur = find_next_token(&pszIterator, &cchCur)) != 0) pSdks->cTargetSource++; i += pSdks->cTargetSource; pSdks->c = i; if (!i) return; /* * Allocate the variable array and create the variables. */ pSdks->pa = (struct variable *)xmalloc(sizeof(pSdks->pa[0]) * i); memset(pSdks->pa, 0, sizeof(pSdks->pa[0]) * i); for (i = j = 0; j < sizeof(pSdks->apsz) / sizeof(pSdks->apsz[0]); j++) { pszIterator = pSdks->apsz[j]; while ((pszCur = find_next_token(&pszIterator, &cchCur)) != 0) { pSdks->pa[i].value = pszCur; pSdks->pa[i].value_length = cchCur; i++; } } assert(i == pSdks->c); /* terminate them (find_next_token won't work if we terminate them in the previous loop). */ while (i-- > 0) { pSdks->pa[i].value[pSdks->pa[i].value_length] = '\0'; /* calc the max variable length too. */ if (pSdks->cchMax < (unsigned int)pSdks->pa[i].value_length) pSdks->cchMax = pSdks->pa[i].value_length; } } /* releases resources allocated in the kbuild_get_sdks. */ static void kbuild_put_sdks(struct kbuild_sdks *pSdks) { unsigned j; for (j = 0; j < sizeof(pSdks->apsz) / sizeof(pSdks->apsz[0]); j++) free(pSdks->apsz[j]); free(pSdks->pa); } /* this kind of stuff: defs := $(kb-src-exp defs) $(TOOL_$(tool)_DEFS)\ $(TOOL_$(tool)_DEFS.$(bld_type))\ $(TOOL_$(tool)_DEFS.$(bld_trg))\ $(TOOL_$(tool)_DEFS.$(bld_trg_arch))\ $(TOOL_$(tool)_DEFS.$(bld_trg).$(bld_trg_arch))\ $(TOOL_$(tool)_DEFS.$(bld_trg_cpu))\ $(TOOL_$(tool)_$(type)DEFS)\ $(TOOL_$(tool)_$(type)DEFS.$(bld_type))\ $(foreach sdk, $(SDKS.$(bld_trg)) \ $(SDKS.$(bld_trg).$(bld_trg_arch)) \ $(SDKS.$(bld_type)) \ $(SDKS),\ $(SDK_$(sdk)_DEFS)\ $(SDK_$(sdk)_DEFS.$(bld_type))\ $(SDK_$(sdk)_DEFS.$(bld_trg))\ $(SDK_$(sdk)_DEFS.$(bld_trg_arch))\ $(SDK_$(sdk)_DEFS.$(bld_trg).$(bld_trg_arch))\ $(SDK_$(sdk)_DEFS.$(bld_trg_cpu))\ $(SDK_$(sdk)_$(type)DEFS)\ $(SDK_$(sdk)_$(type)DEFS.$(bld_type))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_arch))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg).$(bld_trg_arch))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_cpu)))\ $(DEFS)\ $(DEFS.$(bld_type))\ $(DEFS.$(bld_trg))\ $(DEFS.$(bld_trg_arch))\ $(DEFS.$(bld_trg).$(bld_trg_arch))\ $(DEFS.$(bld_trg_cpu))\ $($(type)DEFS)\ $($(type)DEFS.$(bld_type))\ $($(type)DEFS.$(bld_trg))\ $($(type)DEFS.$(bld_trg_arch))\ $($(type)DEFS.$(bld_trg).$(bld_trg_arch))\ $($(type)DEFS.$(bld_trg_cpu))\ $(foreach sdk, $($(target)_SDKS.$(bld_trg)) \ $($(target)_SDKS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_SDKS.$(bld_type)) \ $($(target)_SDKS),\ $(SDK_$(sdk)_DEFS)\ $(SDK_$(sdk)_DEFS.$(bld_type))\ $(SDK_$(sdk)_DEFS.$(bld_trg))\ $(SDK_$(sdk)_DEFS.$(bld_trg_arch))\ $(SDK_$(sdk)_DEFS.$(bld_trg).$(bld_trg_arch))\ $(SDK_$(sdk)_DEFS.$(bld_trg_cpu))\ $(SDK_$(sdk)_$(type)DEFS)\ $(SDK_$(sdk)_$(type)DEFS.$(bld_type))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_arch))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg).$(bld_trg_arch))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_cpu)))\ $($(target)_DEFS)\ $($(target)_DEFS.$(bld_type))\ $($(target)_DEFS.$(bld_trg))\ $($(target)_DEFS.$(bld_trg_arch))\ $($(target)_DEFS.$(bld_trg).$(bld_trg_arch))\ $($(target)_DEFS.$(bld_trg_cpu))\ $($(target)_$(type)DEFS)\ $($(target)_$(type)DEFS.$(bld_type))\ $($(target)_$(type)DEFS.$(bld_trg))\ $($(target)_$(type)DEFS.$(bld_trg_arch))\ $($(target)_$(type)DEFS.$(bld_trg).$(bld_trg_arch))\ $($(target)_$(type)DEFS.$(bld_trg_cpu))\ $(foreach sdk, $($(source)_SDKS.$(bld_trg)) \ $($(source)_SDKS.$(bld_trg).$(bld_trg_arch)) \ $($(source)_SDKS.$(bld_type)) \ $($(source)_SDKS),\ $(SDK_$(sdk)_DEFS)\ $(SDK_$(sdk)_DEFS.$(bld_type))\ $(SDK_$(sdk)_DEFS.$(bld_trg))\ $(SDK_$(sdk)_DEFS.$(bld_trg_arch))\ $(SDK_$(sdk)_DEFS.$(bld_trg).$(bld_trg_arch))\ $(SDK_$(sdk)_DEFS.$(bld_trg_cpu))\ $(SDK_$(sdk)_$(type)DEFS)\ $(SDK_$(sdk)_$(type)DEFS.$(bld_type))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_arch))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg).$(bld_trg_arch))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_cpu)))\ $($(source)_DEFS)\ $($(source)_DEFS.$(bld_type))\ $($(source)_DEFS.$(bld_trg))\ $($(source)_DEFS.$(bld_trg_arch))\ $($(source)_DEFS.$(bld_trg).$(bld_trg_arch))\ $($(source)_DEFS.$(bld_trg_cpu))\ $($(source)_$(type)DEFS)\ $($(source)_$(type)DEFS.$(bld_type))\ $($(source)_$(type)DEFS.$(bld_trg))\ $($(source)_$(type)DEFS.$(bld_trg_arch))\ $($(source)_$(type)DEFS.$(bld_trg).$(bld_trg_arch))\ $($(source)_$(type)DEFS.$(bld_trg_cpu))\ $(foreach sdk, $($(target)_$(source)_SDKS.$(bld_trg)) \ $($(target)_$(source)_SDKS.$(bld_trg).$(bld_trg_arch)) \ $($(target)_$(source)_SDKS.$(bld_type)) \ $($(target)_$(source)_SDKS),\ $(SDK_$(sdk)_DEFS)\ $(SDK_$(sdk)_DEFS.$(bld_type))\ $(SDK_$(sdk)_DEFS.$(bld_trg))\ $(SDK_$(sdk)_DEFS.$(bld_trg_arch))\ $(SDK_$(sdk)_DEFS.$(bld_trg).$(bld_trg_arch))\ $(SDK_$(sdk)_DEFS.$(bld_trg_cpu))\ $(SDK_$(sdk)_$(type)DEFS)\ $(SDK_$(sdk)_$(type)DEFS.$(bld_type))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_arch))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg).$(bld_trg_arch))\ $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_cpu)))\ $($(target)_$(source)_DEFS)\ $($(target)_$(source)_DEFS.$(bld_type))\ $($(target)_$(source)_DEFS.$(bld_trg))\ $($(target)_$(source)_DEFS.$(bld_trg_arch))\ $($(target)_$(source)_DEFS.$(bld_trg).$(bld_trg_arch))\ $($(target)_$(source)_DEFS.$(bld_trg_cpu))\ $($(target)_$(source)_$(type)DEFS)\ $($(target)_$(source)_$(type)DEFS.$(bld_type))\ $($(target)_$(source)_$(type)DEFS.$(bld_trg))\ $($(target)_$(source)_$(type)DEFS.$(bld_trg_arch))\ $($(target)_$(source)_$(type)DEFS.$(bld_trg).$(bld_trg_arch))\ $($(target)_$(source)_$(type)DEFS.$(bld_trg_cpu)) */ static struct variable * kbuild_collect_source_prop(struct variable *pTarget, struct variable *pSource, struct variable *pTool, struct kbuild_sdks *pSdks, struct variable *pType, struct variable *pBldType, struct variable *pBldTrg, struct variable *pBldTrgArch, struct variable *pBldTrgCpu, struct variable *pDefPath, const char *pszProp, size_t cchProp, const char *pszVarName, size_t cchVarName, int iDirection) { struct variable *pVar; unsigned iSdk, iSdkEnd; int cVars, iVar; size_t cchTotal, cchBuf; char *pszResult, *pszBuf, *psz, *psz2, *psz3; struct { struct variable *pVar; unsigned int cchExp; char *pszExp; } *paVars; assert(iDirection == 1 || iDirection == -1); /* * Calc and allocate a too big name buffer. */ cchBuf = cchProp + 1 + pTarget->value_length + 1 + pSource->value_length + 1 + pSdks->cchMax + 1 + (pTool ? pTool->value_length + 1 : 0) + pType->value_length + 1 + pBldTrg->value_length + 1 + pBldTrgArch->value_length + 1 + pBldTrgCpu->value_length + 1 + pBldType->value_length + 1; pszBuf = xmalloc(cchBuf); /* * Get the variables. * * The compiler will get a heart attack when it sees this code ... ;-) */ cVars = 12 * (pSdks->c + 5); paVars = alloca(cVars * sizeof(paVars[0])); iVar = 0; cchTotal = 0; #define ADD_VAR(pVar) do { my_memcpy(psz, (pVar)->value, (pVar)->value_length); psz += (pVar)->value_length; } while (0) #define ADD_STR(pszStr, cchStr) do { my_memcpy(psz, (pszStr), (cchStr)); psz += (cchStr); } while (0) #define ADD_CSTR(pszStr) do { my_memcpy(psz, pszStr, sizeof(pszStr) - 1); psz += sizeof(pszStr) - 1; } while (0) #define ADD_CH(ch) do { *psz++ = (ch); } while (0) #define DO_VAR_LOOKUP() \ do { \ pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf); \ if (pVar) \ { \ paVars[iVar].pVar = pVar; \ if ( !pVar->recursive \ || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR(pVar)) \ { \ paVars[iVar].pszExp = pVar->value; \ paVars[iVar].cchExp = pVar->value_length; \ if (pDefPath && paVars[iVar].cchExp) \ kbuild_apply_defpath(pDefPath, &paVars[iVar].pszExp, &paVars[iVar].cchExp, NULL, 0); \ if (paVars[iVar].cchExp) \ { \ cchTotal += paVars[iVar].cchExp + 1; \ iVar++; \ } \ } \ else \ { \ paVars[iVar].pszExp = allocated_variable_expand_2(pVar->value, pVar->value_length, &paVars[iVar].cchExp); \ if (pDefPath && paVars[iVar].cchExp) \ kbuild_apply_defpath(pDefPath, &paVars[iVar].pszExp, &paVars[iVar].cchExp, NULL, 1); \ if (paVars[iVar].cchExp) \ { \ cchTotal += paVars[iVar].cchExp + 1; \ iVar++; \ } \ else \ free(paVars[iVar].pszExp); \ } \ } \ } while (0) #define DO_SINGLE_PSZ3_VARIATION() \ do { \ DO_VAR_LOOKUP(); \ \ ADD_CH('.'); \ psz3 = psz; \ ADD_VAR(pBldType); \ DO_VAR_LOOKUP(); \ \ psz = psz3; \ ADD_VAR(pBldTrg); \ DO_VAR_LOOKUP(); \ \ psz = psz3; \ ADD_VAR(pBldTrgArch); \ DO_VAR_LOOKUP(); \ \ psz = psz3; \ ADD_VAR(pBldTrg); \ ADD_CH('.'); \ ADD_VAR(pBldTrgArch); \ DO_VAR_LOOKUP(); \ \ psz = psz3; \ ADD_VAR(pBldTrgCpu); \ DO_VAR_LOOKUP(); \ } while (0) #define DO_DOUBLE_PSZ2_VARIATION() \ do { \ psz2 = psz; \ ADD_STR(pszProp, cchProp); \ DO_SINGLE_PSZ3_VARIATION(); \ \ /* add prop before type */ \ psz = psz2; \ ADD_VAR(pType); \ ADD_STR(pszProp, cchProp); \ DO_SINGLE_PSZ3_VARIATION(); \ } while (0) /* the tool (lowest priority). */ psz = pszBuf; ADD_CSTR("TOOL_"); ADD_VAR(pTool); ADD_CH('_'); DO_DOUBLE_PSZ2_VARIATION(); /* the global sdks. */ iSdkEnd = iDirection == 1 ? pSdks->iGlobal + pSdks->cGlobal : pSdks->iGlobal - 1; for (iSdk = iDirection == 1 ? pSdks->iGlobal : pSdks->iGlobal + pSdks->cGlobal - 1; iSdk != iSdkEnd; iSdk += iDirection) { struct variable *pSdk = &pSdks->pa[iSdk]; psz = pszBuf; ADD_CSTR("SDK_"); ADD_VAR(pSdk); ADD_CH('_'); DO_DOUBLE_PSZ2_VARIATION(); } /* the globals. */ psz = pszBuf; DO_DOUBLE_PSZ2_VARIATION(); /* the target sdks. */ iSdkEnd = iDirection == 1 ? pSdks->iTarget + pSdks->cTarget : pSdks->iTarget - 1; for (iSdk = iDirection == 1 ? pSdks->iTarget : pSdks->iTarget + pSdks->cTarget - 1; iSdk != iSdkEnd; iSdk += iDirection) { struct variable *pSdk = &pSdks->pa[iSdk]; psz = pszBuf; ADD_CSTR("SDK_"); ADD_VAR(pSdk); ADD_CH('_'); DO_DOUBLE_PSZ2_VARIATION(); } /* the target. */ psz = pszBuf; ADD_VAR(pTarget); ADD_CH('_'); DO_DOUBLE_PSZ2_VARIATION(); /* the source sdks. */ iSdkEnd = iDirection == 1 ? pSdks->iSource + pSdks->cSource : pSdks->iSource - 1; for (iSdk = iDirection == 1 ? pSdks->iSource : pSdks->iSource + pSdks->cSource - 1; iSdk != iSdkEnd; iSdk += iDirection) { struct variable *pSdk = &pSdks->pa[iSdk]; psz = pszBuf; ADD_CSTR("SDK_"); ADD_VAR(pSdk); ADD_CH('_'); DO_DOUBLE_PSZ2_VARIATION(); } /* the source. */ psz = pszBuf; ADD_VAR(pSource); ADD_CH('_'); DO_DOUBLE_PSZ2_VARIATION(); /* the target + source sdks. */ iSdkEnd = iDirection == 1 ? pSdks->iTargetSource + pSdks->cTargetSource : pSdks->iTargetSource - 1; for (iSdk = iDirection == 1 ? pSdks->iTargetSource : pSdks->iTargetSource + pSdks->cTargetSource - 1; iSdk != iSdkEnd; iSdk += iDirection) { struct variable *pSdk = &pSdks->pa[iSdk]; psz = pszBuf; ADD_CSTR("SDK_"); ADD_VAR(pSdk); ADD_CH('_'); DO_DOUBLE_PSZ2_VARIATION(); } /* the target + source. */ psz = pszBuf; ADD_VAR(pTarget); ADD_CH('_'); ADD_VAR(pSource); ADD_CH('_'); DO_DOUBLE_PSZ2_VARIATION(); free(pszBuf); assert(iVar <= cVars); cVars = iVar; /* * Construct the result value. */ if (!cVars || !cchTotal) pVar = define_variable_vl(pszVarName, cchVarName, "", 0, 1 /* duplicate value */ , o_local, 0 /* !recursive */); else { psz = pszResult = xmalloc(cchTotal + 1); if (iDirection == 1) { for (iVar = 0; iVar < cVars; iVar++) { my_memcpy(psz, paVars[iVar].pszExp, paVars[iVar].cchExp); psz += paVars[iVar].cchExp; *psz++ = ' '; if (paVars[iVar].pszExp != paVars[iVar].pVar->value) free(paVars[iVar].pszExp); } } else { iVar = cVars; while (iVar-- > 0) { my_memcpy(psz, paVars[iVar].pszExp, paVars[iVar].cchExp); psz += paVars[iVar].cchExp; *psz++ = ' '; if (paVars[iVar].pszExp != paVars[iVar].pVar->value) free(paVars[iVar].pszExp); } } assert(psz != pszResult); assert(cchTotal == (size_t)(psz - pszResult)); psz[-1] = '\0'; cchTotal--; pVar = define_variable_vl(pszVarName, cchVarName, pszResult, cchTotal, 0 /* take pszResult */ , o_local, 0 /* !recursive */); } return pVar; #undef ADD_VAR #undef ADD_STR #undef ADD_CSTR #undef ADD_CH #undef DO_VAR_LOOKUP #undef DO_DOUBLE_PSZ2_VARIATION #undef DO_SINGLE_PSZ3_VARIATION } /* get a source property. */ char * func_kbuild_source_prop(char *o, char **argv, const char *pszFuncName) { struct variable *pTarget = kbuild_get_variable_n(ST("target")); struct variable *pSource = kbuild_get_variable_n(ST("source")); struct variable *pDefPath = NULL; struct variable *pType = kbuild_get_variable_n(ST("type")); struct variable *pTool = kbuild_get_variable_n(ST("tool")); struct variable *pBldType = kbuild_get_variable_n(ST("bld_type")); struct variable *pBldTrg = kbuild_get_variable_n(ST("bld_trg")); struct variable *pBldTrgArch = kbuild_get_variable_n(ST("bld_trg_arch")); struct variable *pBldTrgCpu = kbuild_get_variable_n(ST("bld_trg_cpu")); struct variable *pVar; struct kbuild_sdks Sdks; int iDirection; if (!strcmp(argv[2], "left-to-right")) iDirection = 1; else if (!strcmp(argv[2], "right-to-left")) iDirection = -1; else OS(fatal, NILF, _("incorrect direction argument `%s'!"), argv[2]); if (argv[3]) { const char *psz = argv[3]; while (ISSPACE(*psz)) psz++; if (*psz) pDefPath = kbuild_get_variable_n(ST("defpath")); } kbuild_get_sdks(&Sdks, pTarget, pSource, pBldType, pBldTrg, pBldTrgArch); pVar = kbuild_collect_source_prop(pTarget, pSource, pTool, &Sdks, pType, pBldType, pBldTrg, pBldTrgArch, pBldTrgCpu, pDefPath, argv[0], strlen(argv[0]), argv[1], strlen(argv[1]), iDirection); if (pVar) o = variable_buffer_output(o, pVar->value, pVar->value_length); kbuild_put_sdks(&Sdks); (void)pszFuncName; return o; } /* dep := $(obj)$(SUFF_DEP) obj := $(outbase)$(objsuff) dirdep := $(call DIRDEP,$(dir $(outbase))) PATH_$(target)_$(source) := $(patsubst %/,%,$(dir $(outbase))) */ static struct variable * kbuild_set_object_name_and_dep_and_dirdep_and_PATH_target_source(struct variable *pTarget, struct variable *pSource, struct variable *pOutBase, struct variable *pObjSuff, const char *pszVarName, struct variable **ppDep, struct variable **ppDirDep) { struct variable *pDepSuff = kbuild_get_variable_n(ST("SUFF_DEP")); struct variable *pObj; size_t cch = pOutBase->value_length + pObjSuff->value_length + pDepSuff->value_length + 1; char *pszResult = alloca(cch); char *pszName, *psz; /* * dep. */ psz = pszResult; memcpy(psz, pOutBase->value, pOutBase->value_length); psz += pOutBase->value_length; memcpy(psz, pObjSuff->value, pObjSuff->value_length); psz += pObjSuff->value_length; memcpy(psz, pDepSuff->value, pDepSuff->value_length + 1); *ppDep = define_variable_vl("dep", 3, pszResult, cch - 1, 1 /*dup*/, o_local, 0 /* !recursive */); /* * obj */ *psz = '\0'; pObj = define_variable_vl(pszVarName, strlen(pszVarName), pszResult, psz - pszResult, 1/* dup */, o_local, 0 /* !recursive */); /* * PATH_$(target)_$(source) - this is global! */ /* calc variable name. */ cch = sizeof("PATH_")-1 + pTarget->value_length + sizeof("_")-1 + pSource->value_length; psz = pszName = alloca(cch + 1); memcpy(psz, "PATH_", sizeof("PATH_") - 1); psz += sizeof("PATH_") - 1; memcpy(psz, pTarget->value, pTarget->value_length); psz += pTarget->value_length; *psz++ = '_'; memcpy(psz, pSource->value, pSource->value_length + 1); /* strip off the filename. */ psz = pszResult + pOutBase->value_length; for (;;) { psz--; if (psz <= pszResult) OS(fatal, NULL, "whut!?! no path? result=`%s'", pszResult); #ifdef HAVE_DOS_PATHS if (*psz == ':') { psz++; break; } #endif if ( *psz == '/' #ifdef HAVE_DOS_PATHS || *psz == '\\' #endif ) { while ( psz - 1 > pszResult && psz[-1] == '/' #ifdef HAVE_DOS_PATHS || psz[-1] == '\\' #endif ) psz--; #ifdef HAVE_DOS_PATHS if (psz == pszResult + 2 && pszResult[1] == ':') psz++; #endif break; } } *psz = '\0'; /* set global variable */ define_variable_vl_global(pszName, cch, pszResult, psz - pszResult, 1/*dup*/, o_file, 0 /* !recursive */, NILF); /* * dirdep */ if ( psz[-1] != '/' #ifdef HAVE_DOS_PATHS && psz[-1] != '\\' && psz[-1] != ':' #endif ) { *psz++ = '/'; *psz = '\0'; } *ppDirDep = define_variable_vl("dirdep", 6, pszResult, psz - pszResult, 1/*dup*/, o_local, 0 /* !recursive */); return pObj; } /* setup the base variables for def_target_source_c_cpp_asm_new: X := $(kb-src-tool tool) x := $(kb-obj-base outbase) x := $(kb-obj-suff objsuff) obj := $(outbase)$(objsuff) PATH_$(target)_$(source) := $(patsubst %/,%,$(dir $(outbase))) x := $(kb-src-prop DEFS,defs,left-to-right) x := $(kb-src-prop INCS,incs,right-to-left) x := $(kb-src-prop FLAGS,flags,right-to-left) x := $(kb-src-prop DEPS,deps,left-to-right) dirdep := $(call DIRDEP,$(dir $(outbase))) dep := $(obj)$(SUFF_DEP) */ char * func_kbuild_source_one(char *o, char **argv, const char *pszFuncName) { static int s_fNoCompileDepsDefined = -1; struct variable *pTarget = kbuild_get_variable_n(ST("target")); struct variable *pSource = kbuild_get_variable_n(ST("source")); struct variable *pDefPath = kbuild_get_variable_n(ST("defpath")); struct variable *pType = kbuild_get_variable_n(ST("type")); struct variable *pBldType = kbuild_get_variable_n(ST("bld_type")); struct variable *pBldTrg = kbuild_get_variable_n(ST("bld_trg")); struct variable *pBldTrgArch= kbuild_get_variable_n(ST("bld_trg_arch")); struct variable *pBldTrgCpu = kbuild_get_variable_n(ST("bld_trg_cpu")); struct variable *pTool = kbuild_get_source_tool(pTarget, pSource, pType, pBldTrg, pBldTrgArch, "tool"); struct variable *pOutBase = kbuild_get_object_base(pTarget, pSource, "outbase"); struct variable *pObjSuff = kbuild_get_object_suffix(pTarget, pSource, pTool, pType, pBldTrg, pBldTrgArch, "objsuff"); struct variable *pDeps, *pOrderDeps, *pDirDep, *pDep, *pVar, *pOutput, *pOutputMaybe; #if 0 /* not used */ struct variable *pDefs, *pIncs, *pFlags; #endif struct variable *pObj = kbuild_set_object_name_and_dep_and_dirdep_and_PATH_target_source(pTarget, pSource, pOutBase, pObjSuff, "obj", &pDep, &pDirDep); int fInstallOldVars = 0; char *pszDstVar, *pszDst, *pszSrcVar, *pszSrc, *pszVal, *psz; char *pszSavedVarBuf; unsigned cchSavedVarBuf; size_t cch; struct kbuild_sdks Sdks; int iVer; /* * argv[0] is the function version. Prior to r1792 (early 0.1.5) this * was undefined and footer.kmk always passed an empty string. * * Version 2, as implemented in r1797, will make use of the async * includedep queue feature. This means the files will be read by one or * more background threads, leaving the eval'ing to be done later on by * the main thread (in snap_deps). */ if (!argv[0][0]) iVer = 0; else switch (argv[0][0] | (argv[0][1] << 8)) { case '2': iVer = 2; break; case '3': iVer = 3; break; case '4': iVer = 4; break; case '5': iVer = 5; break; case '6': iVer = 6; break; case '7': iVer = 7; break; case '8': iVer = 8; break; case '9': iVer = 9; break; case '0': iVer = 0; break; case '1': iVer = 1; break; default: iVer = 0; psz = argv[0]; while (ISBLANK(*psz)) psz++; if (*psz) iVer = atoi(psz); break; } /* * Gather properties. */ kbuild_get_sdks(&Sdks, pTarget, pSource, pBldType, pBldTrg, pBldTrgArch); if (pDefPath && !pDefPath->value_length) pDefPath = NULL; /*pDefs =*/ kbuild_collect_source_prop(pTarget, pSource, pTool, &Sdks, pType, pBldType, pBldTrg, pBldTrgArch, pBldTrgCpu, NULL, ST("DEFS"), ST("defs"), 1/* left-to-right */); /*pIncs =*/ kbuild_collect_source_prop(pTarget, pSource, pTool, &Sdks, pType, pBldType, pBldTrg, pBldTrgArch, pBldTrgCpu, pDefPath, ST("INCS"), ST("incs"), -1/* right-to-left */); /*pFlags =*/ kbuild_collect_source_prop(pTarget, pSource, pTool, &Sdks, pType, pBldType, pBldTrg, pBldTrgArch, pBldTrgCpu, NULL, ST("FLAGS"), ST("flags"), 1/* left-to-right */); pDeps = kbuild_collect_source_prop(pTarget, pSource, pTool, &Sdks, pType, pBldType, pBldTrg, pBldTrgArch, pBldTrgCpu, pDefPath, ST("DEPS"), ST("deps"), 1/* left-to-right */); pOrderDeps = kbuild_collect_source_prop(pTarget, pSource, pTool, &Sdks, pType, pBldType, pBldTrg, pBldTrgArch, pBldTrgCpu, pDefPath, ST("ORDERDEPS"), ST("orderdeps"), 1/* left-to-right */); /* * If we've got a default path, we must expand the source now. * If we do this too early, "_property = stuff" won't work becuase * our 'source' value isn't what the user expects. */ if (pDefPath) { /** @todo assert(pSource->origin != o_automatic); We're changing 'source' * from the foreach loop! */ #ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE assert(!pSource->rdonly_val); #endif kbuild_apply_defpath(pDefPath, &pSource->value, &pSource->value_length, &pSource->value_alloc_len, 1 /* can free */); } /* # dependencies ifndef NO_COMPILE_DEPS _DEPFILES_INCLUDED += $(dep) $(if $(wildcard $(dep)),$(eval include $(dep))) endif */ if (s_fNoCompileDepsDefined == -1) s_fNoCompileDepsDefined = kbuild_lookup_variable_n(ST("NO_COMPILE_DEPS")) != NULL; if (!s_fNoCompileDepsDefined) { pVar = kbuild_query_recursive_variable_n("_DEPFILES_INCLUDED", sizeof("_DEPFILES_INCLUDED") - 1); if (pVar) { if (pVar->recursive) pVar = kbuild_simplify_variable(pVar); append_string_to_variable(pVar, pDep->value, pDep->value_length, 1 /* append */); } else define_variable_vl_global("_DEPFILES_INCLUDED", sizeof("_DEPFILES_INCLUDED") - 1, pDep->value, pDep->value_length, 1 /* duplicate_value */, o_file, 0 /* recursive */, NULL /* flocp */); eval_include_dep(pDep->value, NILF, iVer >= 2 ? incdep_queue : incdep_read_it); } /* # call the tool $(target)_$(source)_CMDS_ := $(TOOL_$(tool)_COMPILE_$(type)_CMDS) $(target)_$(source)_OUTPUT_ := $(TOOL_$(tool)_COMPILE_$(type)_OUTPUT) $(target)_$(source)_OUTPUT_MAYBE_ := $(TOOL_$(tool)_COMPILE_$(type)_OUTPUT_MAYBE) $(target)_$(source)_DEPEND_ := $(TOOL_$(tool)_COMPILE_$(type)_DEPEND) $(deps) $(source) $(target)_$(source)_DEPORD_ := $(TOOL_$(tool)_COMPILE_$(type)_DEPORD) $(dirdep) */ /** @todo Make all these local variables, if someone needs the info later it * can be recalculated. (Ticket #80.) */ cch = sizeof("TOOL_") + pTool->value_length + sizeof("_COMPILE_") + pType->value_length + sizeof("_OUTPUT_MAYBE"); if (cch < pTarget->value_length + sizeof("$(_2_OBJS)")) cch = pTarget->value_length + sizeof("$(_2_OBJS)"); psz = pszSrcVar = alloca(cch); memcpy(psz, "TOOL_", sizeof("TOOL_") - 1); psz += sizeof("TOOL_") - 1; memcpy(psz, pTool->value, pTool->value_length); psz += pTool->value_length; memcpy(psz, "_COMPILE_", sizeof("_COMPILE_") - 1); psz += sizeof("_COMPILE_") - 1; memcpy(psz, pType->value, pType->value_length); psz += pType->value_length; pszSrc = psz; cch = pTarget->value_length + 1 + pSource->value_length + sizeof("_OUTPUT_MAYBE_"); psz = pszDstVar = alloca(cch); memcpy(psz, pTarget->value, pTarget->value_length); psz += pTarget->value_length; *psz++ = '_'; memcpy(psz, pSource->value, pSource->value_length); psz += pSource->value_length; pszDst = psz; memcpy(pszSrc, "_CMDS", sizeof("_CMDS")); memcpy(pszDst, "_CMDS_", sizeof("_CMDS_")); pVar = kbuild_get_recursive_variable(pszSrcVar); do_variable_definition_2(NILF, pszDstVar, pVar->value, pVar->value_length, !pVar->recursive, 0, o_local, f_simple, 0 /* !target_var */); do_variable_definition_2(NILF, "kbsrc_cmds", pVar->value, pVar->value_length, !pVar->recursive, 0, o_local, f_simple, 0 /* !target_var */); memcpy(pszSrc, "_OUTPUT", sizeof("_OUTPUT")); memcpy(pszDst, "_OUTPUT_", sizeof("_OUTPUT_")); pVar = kbuild_get_recursive_variable(pszSrcVar); pOutput = do_variable_definition_2(NILF, pszDstVar, pVar->value, pVar->value_length, !pVar->recursive, 0, o_local, f_simple, 0 /* !target_var */); pOutput = do_variable_definition_2(NILF, "kbsrc_output", pVar->value, pVar->value_length, !pVar->recursive, 0, o_local, f_simple, 0 /* !target_var */); memcpy(pszSrc, "_OUTPUT_MAYBE", sizeof("_OUTPUT_MAYBE")); memcpy(pszDst, "_OUTPUT_MAYBE_", sizeof("_OUTPUT_MAYBE_")); pVar = kbuild_query_recursive_variable(pszSrcVar); if (pVar) { pOutputMaybe = do_variable_definition_2(NILF, pszDstVar, pVar->value, pVar->value_length, !pVar->recursive, 0, o_local, f_simple, 0 /* !target_var */); pOutputMaybe = do_variable_definition_2(NILF, "kbsrc_output_maybe", pVar->value, pVar->value_length, !pVar->recursive, 0, o_local, f_simple, 0 /* !target_var */); } else { pOutputMaybe = do_variable_definition_2(NILF, pszDstVar, "", 0, 1, 0, o_local, f_simple, 0 /* !target_var */); pOutputMaybe = do_variable_definition_2(NILF, "kbsrc_output_maybe", "", 0, 1, 0, o_local, f_simple, 0 /* !target_var */); } memcpy(pszSrc, "_DEPEND", sizeof("_DEPEND")); memcpy(pszDst, "_DEPEND_", sizeof("_DEPEND_")); pVar = kbuild_get_recursive_variable(pszSrcVar); psz = pszVal = xmalloc(pVar->value_length + 1 + pDeps->value_length + 1 + pSource->value_length + 1); memcpy(psz, pVar->value, pVar->value_length); psz += pVar->value_length; *psz++ = ' '; memcpy(psz, pDeps->value, pDeps->value_length); psz += pDeps->value_length; *psz++ = ' '; memcpy(psz, pSource->value, pSource->value_length + 1); do_variable_definition_2(NILF, pszDstVar, pszVal, pVar->value_length + 1 + pDeps->value_length + 1 + pSource->value_length, !pVar->recursive && !pDeps->recursive && !pSource->recursive, NULL, o_local, f_simple, 0 /* !target_var */); do_variable_definition_2(NILF, "kbsrc_depend", pszVal, pVar->value_length + 1 + pDeps->value_length + 1 + pSource->value_length, !pVar->recursive && !pDeps->recursive && !pSource->recursive, pszVal, o_local, f_simple, 0 /* !target_var */); memcpy(pszSrc, "_DEPORD", sizeof("_DEPORD")); memcpy(pszDst, "_DEPORD_", sizeof("_DEPORD_")); pVar = kbuild_get_recursive_variable(pszSrcVar); psz = pszVal = xmalloc(pVar->value_length + 1 + pDirDep->value_length + 1 + pOrderDeps->value_length + 1); memcpy(psz, pVar->value, pVar->value_length); psz += pVar->value_length; *psz++ = ' '; memcpy(psz, pDirDep->value, pDirDep->value_length); psz += pDirDep->value_length; *psz++ = ' '; memcpy(psz, pOrderDeps->value, pOrderDeps->value_length + 1); do_variable_definition_2(NILF, pszDstVar, pszVal, pVar->value_length + 1 + pDirDep->value_length + 1 + pOrderDeps->value_length, !pVar->recursive && !pDirDep->recursive && !pOrderDeps->recursive, NULL, o_local, f_simple, 0 /* !target_var */); do_variable_definition_2(NILF, "kbsrc_depord", pszVal, pVar->value_length + 1 + pDirDep->value_length + 1 + pOrderDeps->value_length, !pVar->recursive && !pDirDep->recursive && !pOrderDeps->recursive, pszVal, o_local, f_simple, 0 /* !target_var */); /* _OUT_FILES += $($(target)_$(source)_OUTPUT_) $($(target)_$(source)_OUTPUT_MAYBE_) */ pVar = kbuild_get_variable_n(ST("_OUT_FILES")); append_string_to_variable(pVar, pOutput->value, pOutput->value_length, 1 /* append */); if (pOutputMaybe->value_length) append_string_to_variable(pVar, pOutputMaybe->value, pOutputMaybe->value_length, 1 /* append */); /* $(target)_2_OBJS += $(obj) */ memcpy(pszDstVar + pTarget->value_length, "_2_OBJS", sizeof("_2_OBJS")); pVar = kbuild_query_recursive_variable_n(pszDstVar, pTarget->value_length + sizeof("_2_OBJS") - 1); fInstallOldVars |= iVer <= 2 && (!pVar || !pVar->value_length); if (pVar) { if (pVar->recursive) pVar = kbuild_simplify_variable(pVar); append_string_to_variable(pVar, pObj->value, pObj->value_length, 1 /* append */); } else define_variable_vl_global(pszDstVar, pTarget->value_length + sizeof("_2_OBJS") - 1, pObj->value, pObj->value_length, 1 /* duplicate_value */, o_file, 0 /* recursive */, NULL /* flocp */); /* * Install legacy variables. */ if (fInstallOldVars) { /* $(target)_OBJS_ = $($(target)_2_OBJS)*/ memcpy(pszDstVar + pTarget->value_length, "_OBJS_", sizeof("_OBJS_")); pszSrcVar[0] = '$'; pszSrcVar[1] = '('; memcpy(pszSrcVar + 2, pTarget->value, pTarget->value_length); psz = pszSrcVar + 2 + pTarget->value_length; memcpy(psz, "_2_OBJS)", sizeof("_2_OBJS)")); define_variable_vl_global(pszDstVar, pTarget->value_length + sizeof("_OBJS_") - 1, pszSrcVar, pTarget->value_length + sizeof("$(_2_OBJS)") - 1, 1 /* duplicate_value */, o_file, 1 /* recursive */, NULL /* flocp */); } /* $(eval $(def_target_source_rule)) */ pVar = kbuild_get_recursive_variable("def_target_source_rule"); pszVal = variable_expand_string_2 (o, pVar->value, pVar->value_length, &psz); assert(!((size_t)pszVal & 3)); install_variable_buffer(&pszSavedVarBuf, &cchSavedVarBuf); eval_buffer(pszVal, NULL, psz); restore_variable_buffer(pszSavedVarBuf, cchSavedVarBuf); kbuild_put_sdks(&Sdks); (void)pszFuncName; *pszVal = '\0'; return pszVal; } /* ## Inherit one template property in a non-accumulative manner. # @param $(prop) Property name # @param $(target) Target name # @todo fix the precedence order for some properties. define def_inherit_template_one ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop) ifndef $(target)_$(prop) $(target)_$(prop) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop)) endif endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg) ifndef $(target)_$(prop).$(bld_trg) $(target)_$(prop).$(bld_trg) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg)) endif endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch) ifndef $(target)_$(prop).$(bld_trg).$(bld_trg_arch) $(target)_$(prop).$(bld_trg).$(bld_trg_arch) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch)) endif endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch) ifndef $(target)_$(prop).$(bld_trg_arch) $(target)_$(prop).$(bld_trg_arch) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch)) endif endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu) ifndef $(target)_$(prop).$(bld_trg_cpu) $(target)_$(prop).$(bld_trg_cpu) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu)) endif endif endef ## Inherit one template property in a non-accumulative manner, deferred expansion. # @param 1: $(prop) Property name # @param 2: $(target) Target name # @todo fix the precedence order for some properties. # @remark this define relies on double evaluation define def_inherit_template_one_deferred ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop) ifndef $(target)_$(prop) $(target)_$(prop) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop)) endif endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg) ifndef $(target)_$(prop).$(bld_trg) $(target)_$(prop).$(bld_trg) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg)) endif endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch) ifndef $(target)_$(prop).$(bld_trg).$(bld_trg_arch) $(target)_$(prop).$(bld_trg).$(bld_trg_arch) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch)) endif endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch) ifndef $(target)_$(prop).$(bld_trg_arch) $(target)_$(prop).$(bld_trg_arch) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch)) endif endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu) ifndef $(target)_$(prop).$(bld_trg_cpu) $(target)_$(prop).$(bld_trg_cpu) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu)) endif endif endef ## Inherit one acculumlative template property where the 'most significant' items are at the left end. # @param $(prop) Property name # @param $(target) Target name define def_inherit_template_one_accumulate_l ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop) ifeq ($$(flavor $(target)_$(prop)),simple) $$(evalcall2 def_simple_2_recursive,$(target)_$(prop)) endif $(target)_$(prop) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop)) endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(KBUILD_TYPE) ifeq ($$(flavor $(target)_$(prop).$(KBUILD_TYPE)),simple) $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(KBUILD_TYPE)) endif $(target)_$(prop).$(KBUILD_TYPE) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(KBUILD_TYPE)) endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg) ifeq ($$(flavor $(target)_$(prop).$(bld_trg)),simple) $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg)) endif $(target)_$(prop).$(bld_trg) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg)) endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch) ifeq ($$(flavor $(target)_$(prop).$(bld_trg).$(bld_trg_arch)),simple) $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg).$(bld_trg_arch)) endif $(target)_$(prop).$(bld_trg).$(bld_trg_arch) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch)) endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu) ifeq ($$(flavor $(target)_$(prop).$(bld_trg_cpu)),simple) $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg_cpu)) endif $(target)_$(prop).$(bld_trg_cpu) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu)) endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch) ifeq ($$(flavor $(target)_$(prop).$(bld_trg_arch)),simple) $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg_arch)) endif $(target)_$(prop).$(bld_trg_arch) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch)) endif endef ## Inherit one acculumlative template property where the 'most significant' items are at the right end. # @param $(prop) Property name # @param $(target) Target name define def_inherit_template_one_accumulate_r ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop) ifeq ($$(flavor $(target)_$(prop)),simple) $$(evalcall2 def_simple_2_recursive,$(target)_$(prop)) endif $(target)_$(prop) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop)) endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(KBUILD_TYPE) ifeq ($$(flavor $(target)_$(prop).$(KBUILD_TYPE)),simple) $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(KBUILD_TYPE)) endif $(target)_$(prop).$(KBUILD_TYPE) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(KBUILD_TYPE)) endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg) ifeq ($$(flavor $(target)_$(prop).$(bld_trg)),simple) $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg)) endif $(target)_$(prop).$(bld_trg) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg)) endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch) ifeq ($$(flavor $(target)_$(prop).$(bld_trg).$(bld_trg_arch)),simple) $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg).$(bld_trg_arch)) endif $(target)_$(prop).$(bld_trg).$(bld_trg_arch) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch)) endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu) ifeq ($$(flavor $(target)_$(prop).$(bld_trg_cpu)),simple) $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg_cpu)) endif $(target)_$(prop).$(bld_trg_cpu) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu)) endif ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch) ifeq ($$(flavor $(target)_$(prop).$(bld_trg_arch)),simple) $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg_arch)) endif $(target)_$(prop).$(bld_trg_arch) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch)) endif endef ## Inherit template properties for on target. # @param $(target) Target name. define def_inherit_template # sanity check. ifdef _$(target)_ALREADY_PROCESSED $(error kBuild: The target $(target) appears more than once in the target lists! Please correct the makefile(s)) endif _$(target)_ALREADY_PROCESSED := 1 # Inherit any default template. ifdef TEMPLATE ifeq ($($(target)_TEMPLATE),) $(eval $(target)_TEMPLATE:=$(TEMPLATE)) endif endif # Expand the template if specified. ifneq ($($(target)_TEMPLATE),) $(foreach prop,$(PROPS_SINGLE),$(evalval def_inherit_template_one)) $(foreach prop,$(PROPS_DEFERRED),$(eval $(def_inherit_template_one_deferred))) # exploits the 2 evaluation, so no value! $(foreach prop,$(PROPS_ACCUMULATE_L),$(eval $(def_inherit_template_one_accumulate_l))) # += works fine without value $(foreach prop,$(PROPS_ACCUMULATE_R),$(eval $(def_inherit_template_one_accumulate_r))) # use <= (kmk addition) endif endef Invoked like this: $(kb-exp-tmpl 1,$(_ALL_TARGET_TARGETS),$(KBUILD_TARGET),$(KBUILD_TARGET_ARCH),$(KBUILD_TARGET_CPU),$(KBUILD_TYPE)) */ char * func_kbuild_expand_template(char *o, char **argv, const char *pszFuncName) { const char *pszVersion = argv[0]; const char *pszBldTrg = argv[2]; const char *pszBldTrgArch = argv[3]; const char *pszBldTrgCpu = argv[4]; const char *pszBldType = argv[5]; size_t cchBldTrg = strlen(pszBldTrg); size_t cchBldTrgArch = strlen(pszBldTrgArch); size_t cchBldTrgCpu = strlen(pszBldTrgCpu); size_t cchBldType = strlen(pszBldType); size_t cchMaxBld = cchBldTrg + cchBldTrgArch + cchBldTrgCpu + cchBldType; /* too big, but so what. */ struct kbet_key { unsigned int cch; char *psz; } aKeys[6]; unsigned int const cKeys = 6; unsigned int iKey; struct variable *pDefTemplate; struct variable *pProps; struct kbet_prop { const char *pch; unsigned int cch; enum kbet_prop_enum { kPropSingle, kPropDeferred, kPropAccumulateL, kPropAccumulateR } enmType; } *paProps; unsigned int cProps; unsigned int iProp; size_t cchMaxProp; struct variable *pVarTrg; struct variable *pVarSrc; const char *pszIter; const char *pszTarget; unsigned int cchTarget; char *pszSrc = 0; char *pszSrcRef = 0; char *pszSrcBuf = 0; size_t cchSrcBuf = 0; char *pszTrg = 0; size_t cchTrg = 0; /* * Validate input. */ if (pszVersion[0] != '1' || pszVersion[1]) OSS(fatal, NULL, "%s: Unsupported version `%s'", pszFuncName, pszVersion); if (!cchBldTrg) OS(fatal, NULL, "%s: missing bldtrg", pszFuncName); if (!cchBldTrgArch) OS(fatal, NULL, "%s: missing bld_trg_arch", pszFuncName); if (!cchBldTrgCpu) OS(fatal, NULL, "%s: missing bld_trg_cpu", pszFuncName); if (!cchBldType) OS(fatal, NULL, "%s: missing bld_type", pszFuncName); /* * Prepare the keywords, prepending dots for quicker copying. * This allows for an inner loop when processing properties, saving code * at the expense of a few xmallocs. */ /* the first entry is empty. */ aKeys[0].cch = 0; aKeys[0].psz = NULL; /* .$(bld_type) */ aKeys[1].cch = cchBldType + 1; aKeys[1].psz = xmalloc (aKeys[1].cch + 1); aKeys[1].psz[0] = '.'; memcpy(aKeys[1].psz + 1, pszBldType, cchBldType + 1); /* .$(bld_trg) */ aKeys[2].cch = cchBldTrg + 1; aKeys[2].psz = xmalloc (aKeys[2].cch + 1); aKeys[2].psz[0] = '.'; memcpy(aKeys[2].psz + 1, pszBldTrg, cchBldTrg + 1); /* .$(bld_trg).$(bld_trg_arch) */ aKeys[3].cch = cchBldTrg + 1 + cchBldTrgArch + 1; aKeys[3].psz = xmalloc (aKeys[3].cch + 1); aKeys[3].psz[0] = '.'; memcpy(aKeys[3].psz + 1, pszBldTrg, cchBldTrg); aKeys[3].psz[1 + cchBldTrg] = '.'; memcpy(aKeys[3].psz + 1 + cchBldTrg + 1, pszBldTrgArch, cchBldTrgArch + 1); /* .$(bld_trg_cpu) */ aKeys[4].cch = cchBldTrgCpu + 1; aKeys[4].psz = xmalloc (aKeys[4].cch + 1); aKeys[4].psz[0] = '.'; memcpy(aKeys[4].psz + 1, pszBldTrgCpu, cchBldTrgCpu + 1); /* .$(bld_trg_arch) */ aKeys[5].cch = cchBldTrgArch + 1; aKeys[5].psz = xmalloc (aKeys[5].cch + 1); aKeys[5].psz[0] = '.'; memcpy(aKeys[5].psz + 1, pszBldTrgArch, cchBldTrgArch + 1); /* * Prepare the properties, folding them into an array. * This way we won't have to reparse them for each an every target, though * it comes at the expense of one or more heap calls. */ #define PROP_ALLOC_INC 128 iProp = 0; cProps = PROP_ALLOC_INC; paProps = xmalloc(sizeof(*pProps) * cProps); pProps = kbuild_get_variable_n(ST("PROPS_SINGLE")); pszIter = pProps->value; while ((paProps[iProp].pch = find_next_token(&pszIter, &paProps[iProp].cch))) { paProps[iProp].enmType = kPropSingle; if (++iProp >= cProps) { cProps += PROP_ALLOC_INC; paProps = xrealloc(paProps, sizeof(*paProps) * cProps); } } pProps = kbuild_get_variable_n(ST("PROPS_DEFERRED")); pszIter = pProps->value; while ((paProps[iProp].pch = find_next_token(&pszIter, &paProps[iProp].cch))) { paProps[iProp].enmType = kPropDeferred; if (++iProp >= cProps) { cProps += PROP_ALLOC_INC; paProps = xrealloc(paProps, sizeof(*paProps) * cProps); } } pProps = kbuild_get_variable_n(ST("PROPS_ACCUMULATE_L")); pszIter = pProps->value; while ((paProps[iProp].pch = find_next_token(&pszIter, &paProps[iProp].cch))) { paProps[iProp].enmType = kPropAccumulateL; if (++iProp >= cProps) { cProps += PROP_ALLOC_INC; paProps = xrealloc(paProps, sizeof(*paProps) * cProps); } } pProps = kbuild_get_variable_n(ST("PROPS_ACCUMULATE_R")); pszIter = pProps->value; while ((paProps[iProp].pch = find_next_token(&pszIter, &paProps[iProp].cch))) { paProps[iProp].enmType = kPropAccumulateR; if (++iProp >= cProps) { cProps += PROP_ALLOC_INC; paProps = xrealloc(paProps, sizeof(*paProps) * cProps); } } #undef PROP_ALLOC_INC cProps = iProp; /* find the max prop length. */ cchMaxProp = paProps[0].cch; while (--iProp > 0) if (paProps[iProp].cch > cchMaxProp) cchMaxProp = paProps[iProp].cch; /* * Query and prepare (strip) the default template * (given by the TEMPLATE variable). */ pDefTemplate = kbuild_lookup_variable_n(ST("TEMPLATE")); if (pDefTemplate) { if ( pDefTemplate->value_length && ( ISSPACE(pDefTemplate->value[0]) || ISSPACE(pDefTemplate->value[pDefTemplate->value_length - 1]))) { unsigned int off; if (pDefTemplate->rdonly_val) OS(fatal, NULL, "%s: TEMPLATE is read-only", pszFuncName); /* head */ for (off = 0; ISSPACE(pDefTemplate->value[off]); off++) /* nothing */; if (off) { pDefTemplate->value_length -= off; memmove(pDefTemplate->value, pDefTemplate->value + off, pDefTemplate->value_length + 1); } /* tail */ off = pDefTemplate->value_length; while (off > 0 && ISSPACE(pDefTemplate->value[off - 1])) off--; pDefTemplate->value_length = off; pDefTemplate->value[off] = '\0'; VARIABLE_CHANGED(pDefTemplate); } if (!pDefTemplate->value_length) pDefTemplate = NULL; } /* * Iterate the target list. */ pszIter = argv[1]; while ((pszTarget = find_next_token(&pszIter, &cchTarget))) { char *pszTrgProp, *pszSrcProp; char *pszTrgKey, *pszSrcKey; struct variable *pTmpl; const char *pszTmpl; size_t cchTmpl, cchMax; /* resize the target buffer. */ cchMax = cchTarget + cchMaxProp + cchMaxBld + 10; if (cchTrg < cchMax) { cchTrg = (cchMax + 31U) & ~(size_t)31; pszTrg = xrealloc(pszTrg, cchTrg); } /* * Query the TEMPLATE property, if not found or zero-length fall back on the default. */ memcpy(pszTrg, pszTarget, cchTarget); pszTrgProp = pszTrg + cchTarget; memcpy(pszTrgProp, "_TEMPLATE", sizeof("_TEMPLATE")); pszTrgProp++; /* after '_'. */ /** @todo Change this to a recursive lookup with simplification below. That * will allow target_TEMPLATE = $(NO_SUCH_TEMPLATE) instead of having * to use target_TEMPLATE = DUMMY */ pTmpl = kbuild_lookup_variable_n(pszTrg, cchTarget + sizeof("_TEMPLATE") - 1); if (!pTmpl || !pTmpl->value_length) { if (!pDefTemplate) continue; /* no template */ pszTmpl = pDefTemplate->value; cchTmpl = pDefTemplate->value_length; } else { pszTmpl = pTmpl->value; cchTmpl = pTmpl->value_length; while (ISSPACE(*pszTmpl)) cchTmpl--, pszTmpl++; if (!cchTmpl) continue; /* no template */ } /* resize the source buffer. */ cchMax = sizeof("TEMPLATE_") + cchTmpl + cchMaxProp + cchMaxBld + 10 + sizeof(void *); if (cchSrcBuf < cchMax) { cchSrcBuf = (cchMax + 31U) & ~(size_t)31; pszSrcBuf = xrealloc(pszSrcBuf, cchSrcBuf); pszSrc = pszSrcBuf + sizeof(void *); assert(sizeof(void *) >= 2); pszSrcRef = pszSrc - 2; pszSrcRef[0] = '$'; pszSrcRef[1] = '('; } /* prepare the source buffer */ memcpy(pszSrc, "TEMPLATE_", sizeof("TEMPLATE_") - 1); pszSrcProp = pszSrc + sizeof("TEMPLATE_") - 1; memcpy(pszSrcProp, pszTmpl, cchTmpl); pszSrcProp += cchTmpl; *pszSrcProp++ = '_'; /* * Process properties. * Note! The single and deferred are handled in the same way now. */ #define BY_REF_LIMIT 64 /*(cchSrcVar * 4 > 64 ? cchSrcVar * 4 : 64)*/ for (iProp = 0; iProp < cProps; iProp++) { memcpy(pszTrgProp, paProps[iProp].pch, paProps[iProp].cch); pszTrgKey = pszTrgProp + paProps[iProp].cch; memcpy(pszSrcProp, paProps[iProp].pch, paProps[iProp].cch); pszSrcKey = pszSrcProp + paProps[iProp].cch; for (iKey = 0; iKey < cKeys; iKey++) { char *pszTrgEnd; size_t cchSrcVar; /* lookup source, skip ahead if it doesn't exist. */ memcpy(pszSrcKey, aKeys[iKey].psz, aKeys[iKey].cch); cchSrcVar = pszSrcKey - pszSrc + aKeys[iKey].cch; pszSrc[cchSrcVar] = '\0'; pVarSrc = kbuild_query_recursive_variable_n(pszSrc, cchSrcVar); if (!pVarSrc) continue; /* lookup target, skip ahead if it exists. */ memcpy(pszTrgKey, aKeys[iKey].psz, aKeys[iKey].cch); pszTrgEnd = pszTrgKey + aKeys[iKey].cch; *pszTrgEnd = '\0'; pVarTrg = kbuild_query_recursive_variable_n(pszTrg, pszTrgEnd - pszTrg); switch (paProps[iProp].enmType) { case kPropAccumulateL: case kPropAccumulateR: if (pVarTrg) { /* Append to existing variable. If the source is recursive, or we append by reference, we'll have to make sure the target is recusive as well. */ if ( !pVarTrg->recursive && ( pVarSrc->value_length >= BY_REF_LIMIT || pVarSrc->recursive)) pVarTrg->recursive = 1; if (pVarSrc->value_length < BY_REF_LIMIT) append_string_to_variable(pVarTrg, pVarSrc->value, pVarSrc->value_length, paProps[iProp].enmType == kPropAccumulateL /* append */); else { pszSrc[cchSrcVar] = ')'; pszSrc[cchSrcVar + 1] = '\0'; append_string_to_variable(pVarTrg, pszSrcRef, 2 + cchSrcVar + 1, paProps[iProp].enmType == kPropAccumulateL /* append */); } break; } /* else: the target variable doesn't exist, create it. */ /* fall thru */ case kPropSingle: case kPropDeferred: if (pVarTrg) continue; /* skip ahead if it already exists. */ /* copy the variable if its short, otherwise reference it. */ if (pVarSrc->value_length < BY_REF_LIMIT) define_variable_vl_global(pszTrg, pszTrgEnd - pszTrg, pVarSrc->value, pVarSrc->value_length, 1 /* duplicate_value */, o_file, pVarSrc->recursive, NULL /* flocp */); else { pszSrc[cchSrcVar] = ')'; pszSrc[cchSrcVar + 1] = '\0'; define_variable_vl_global(pszTrg, pszTrgEnd - pszTrg, pszSrcRef, 2 + cchSrcVar + 1, 1 /* duplicate_value */, o_file, 1 /* recursive */, NULL /* flocp */); } break; } } /* foreach key */ } /* foreach prop */ #undef BY_REF_LIMIT } /* foreach target */ /* * Cleanup. */ free(pszSrcBuf); free(pszTrg); free(paProps); for (iKey = 1; iKey < cKeys; iKey++) free(aKeys[iKey].psz); return o; } #endif /* KMK_HELPERS */ kbuild-3149/src/kmk/dir.c0000644000175000017500000012640613252530201015201 0ustar locutuslocutus/* Directory hashing for GNU Make. Copyright (C) 1988-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" #include "hash.h" #include "filedef.h" #include "dep.h" #ifdef HAVE_DIRENT_H # include # define NAMLEN(dirent) strlen((dirent)->d_name) # ifdef VMS /* its prototype is in vmsdir.h, which is not needed for HAVE_DIRENT_H */ const char *vmsify (const char *name, int type); # endif #else # define dirent direct # define NAMLEN(dirent) (dirent)->d_namlen # ifdef HAVE_SYS_NDIR_H # include # endif # ifdef HAVE_SYS_DIR_H # include # endif # ifdef HAVE_NDIR_H # include # endif # ifdef HAVE_VMSDIR_H # include "vmsdir.h" # endif /* HAVE_VMSDIR_H */ #endif /* bird: FreeBSD + smbfs -> readdir() + EBADF */ #ifdef __FreeBSD__ # include #endif /* bird: end */ #ifdef CONFIG_WITH_STRCACHE2 # include #endif /* In GNU systems, defines this macro for us. */ #ifdef _D_NAMLEN # undef NAMLEN # define NAMLEN(d) _D_NAMLEN(d) #endif #if (defined (POSIX) || defined (VMS) || defined (WINDOWS32)) && !defined (__GNU_LIBRARY__) /* Posix does not require that the d_ino field be present, and some systems do not provide it. */ # define REAL_DIR_ENTRY(dp) 1 # define FAKE_DIR_ENTRY(dp) #else # define REAL_DIR_ENTRY(dp) (dp->d_ino != 0) # define FAKE_DIR_ENTRY(dp) (dp->d_ino = 1) #endif /* POSIX */ #ifdef __MSDOS__ #include #include /* If it's MSDOS that doesn't have _USE_LFN, disable LFN support. */ #ifndef _USE_LFN #define _USE_LFN 0 #endif static const char * dosify (const char *filename) { static char dos_filename[14]; char *df; int i; if (filename == 0 || _USE_LFN) return filename; /* FIXME: what about filenames which violate 8+3 constraints, like "config.h.in", or ".emacs"? */ if (strpbrk (filename, "\"*+,;<=>?[\\]|") != 0) return filename; df = dos_filename; /* First, transform the name part. */ for (i = 0; i < 8 && ! STOP_SET (*filename, MAP_DOT|MAP_NUL); ++i) *df++ = tolower ((unsigned char)*filename++); /* Now skip to the next dot. */ while (! STOP_SET (*filename, MAP_DOT|MAP_NUL)) ++filename; if (*filename != '\0') { *df++ = *filename++; for (i = 0; i < 3 && ! STOP_SET (*filename, MAP_DOT|MAP_NUL); ++i) *df++ = tolower ((unsigned char)*filename++); } /* Look for more dots. */ while (! STOP_SET (*filename, MAP_DOT|MAP_NUL)) ++filename; if (*filename == '.') return filename; *df = 0; return dos_filename; } #endif /* __MSDOS__ */ #ifdef WINDOWS32 #include #include "pathstuff.h" #endif #ifdef _AMIGA #include #endif #ifdef HAVE_CASE_INSENSITIVE_FS static const char * downcase (const char *filename) { static PATH_VAR (new_filename); char *df; if (filename == 0) return 0; df = new_filename; while (*filename != '\0') { *df++ = tolower ((unsigned char)*filename); ++filename; } *df = 0; return new_filename; } #endif /* HAVE_CASE_INSENSITIVE_FS */ #ifdef VMS static char * downcase_inplace(char *filename) { char *name; name = filename; while (*name != '\0') { *name = tolower ((unsigned char)*name); ++name; } return filename; } #ifndef _USE_STD_STAT /* VMS 8.2 fixed the VMS stat output to have unique st_dev and st_ino when _USE_STD_STAT is used on the compile line. Prior to _USE_STD_STAT support, the st_dev is a pointer to thread static memory containing the device of the last filename looked up. Todo: find out if the ino_t still needs to be faked on a directory. */ /* Define this if the older VMS_INO_T is needed */ #define VMS_INO_T 1 static int vms_hash (const char *name) { int h = 0; while (*name) { unsigned char uc = *name; int g; #ifdef HAVE_CASE_INSENSITIVE_FS h = (h << 4) + (isupper (uc) ? tolower (uc) : uc); #else h = (h << 4) + uc; #endif name++; g = h & 0xf0000000; if (g) { h = h ^ (g >> 24); h = h ^ g; } } return h; } /* fake stat entry for a directory */ static int vmsstat_dir (const char *name, struct stat *st) { char *s; int h; DIR *dir; dir = opendir (name); if (dir == 0) return -1; closedir (dir); s = strchr (name, ':'); /* find device */ if (s) { /* to keep the compiler happy we said "const char *name", now we cheat */ *s++ = 0; st->st_dev = (char *)vms_hash (name); h = vms_hash (s); *(s-1) = ':'; } else { st->st_dev = 0; h = vms_hash (name); } st->st_ino[0] = h & 0xff; st->st_ino[1] = h & 0xff00; st->st_ino[2] = h >> 16; return 0; } # define stat(__path, __sbuf) vmsstat_dir (__path, __sbuf) #endif /* _USE_STD_STAT */ #endif /* VMS */ /* Hash table of directories. */ #ifndef DIRECTORY_BUCKETS #ifdef KMK # define DIRECTORY_BUCKETS 4096 # else # define DIRECTORY_BUCKETS 199 # endif #endif struct directory_contents { dev_t dev; /* Device and inode numbers of this dir. */ #ifdef WINDOWS32 /* Inode means nothing on WINDOWS32. Even file key information is * unreliable because it is random per file open and undefined for remote * filesystems. The most unique attribute I can come up with is the fully * qualified name of the directory. Beware though, this is also * unreliable. I'm open to suggestion on a better way to emulate inode. */ # ifndef CONFIG_WITH_STRCACHE2 char *path_key; # else char const *path_key; /* strcache'ed */ # endif time_t ctime; time_t mtime; /* controls check for stale directory cache */ int fs_flags; /* FS_FAT, FS_NTFS, ... */ # define FS_FAT 0x1 # define FS_NTFS 0x2 # define FS_UNKNOWN 0x4 # ifdef KMK time_t last_updated; /**< The last time the directory was re-read. */ # endif #else # ifdef VMS_INO_T ino_t ino[3]; # else ino_t ino; # endif #endif /* WINDOWS32 */ struct hash_table dirfiles; /* Files in this directory. */ DIR *dirstream; /* Stream reading this directory. */ }; static unsigned long directory_contents_hash_1 (const void *key_0) { const struct directory_contents *key = key_0; unsigned long hash; #ifdef WINDOWS32 # ifndef CONFIG_WITH_STRCACHE2 hash = 0; ISTRING_HASH_1 (key->path_key, hash); # else /* CONFIG_WITH_STRCACHE2 */ hash = strcache2_calc_ptr_hash (&file_strcache, key->path_key); # endif /* CONFIG_WITH_STRCACHE2 */ hash ^= ((unsigned int) key->dev << 4) ^ (unsigned int) key->ctime; #else # ifdef VMS_INO_T hash = (((unsigned int) key->dev << 4) ^ ((unsigned int) key->ino[0] + (unsigned int) key->ino[1] + (unsigned int) key->ino[2])); # else hash = ((unsigned int) key->dev << 4) ^ (unsigned int) key->ino; # endif #endif /* WINDOWS32 */ return hash; } static unsigned long directory_contents_hash_2 (const void *key_0) { const struct directory_contents *key = key_0; unsigned long hash; #ifdef WINDOWS32 # ifndef CONFIG_WITH_STRCACHE2 hash = 0; ISTRING_HASH_2 (key->path_key, hash); # else /* CONFIG_WITH_STRCACHE2 */ hash = strcache2_get_hash (&file_strcache, key->path_key); # endif /* CONFIG_WITH_STRCACHE2 */ hash ^= ((unsigned int) key->dev << 4) ^ (unsigned int) ~key->ctime; #else # ifdef VMS_INO_T hash = (((unsigned int) key->dev << 4) ^ ~((unsigned int) key->ino[0] + (unsigned int) key->ino[1] + (unsigned int) key->ino[2])); # else hash = ((unsigned int) key->dev << 4) ^ (unsigned int) ~key->ino; # endif #endif /* WINDOWS32 */ return hash; } /* Sometimes it's OK to use subtraction to get this value: result = X - Y; But, if we're not sure of the type of X and Y they may be too large for an int (on a 64-bit system for example). So, use ?: instead. See Savannah bug #15534. NOTE! This macro has side-effects! */ #define MAKECMP(_x,_y) ((_x)<(_y)?-1:((_x)==(_y)?0:1)) static int directory_contents_hash_cmp (const void *xv, const void *yv) { const struct directory_contents *x = xv; const struct directory_contents *y = yv; int result; #ifdef WINDOWS32 # ifndef CONFIG_WITH_STRCACHE2 ISTRING_COMPARE (x->path_key, y->path_key, result); if (result) return result; # else /* CONFIG_WITH_STRCACHE2 */ if (x->path_key != y->path_key) return -1; # endif /* CONFIG_WITH_STRCACHE2 */ result = MAKECMP(x->ctime, y->ctime); if (result) return result; #else # ifdef VMS_INO_T result = MAKECMP(x->ino[0], y->ino[0]); if (result) return result; result = MAKECMP(x->ino[1], y->ino[1]); if (result) return result; result = MAKECMP(x->ino[2], y->ino[2]); if (result) return result; # else result = MAKECMP(x->ino, y->ino); if (result) return result; # endif #endif /* WINDOWS32 */ return MAKECMP(x->dev, y->dev); } /* Table of directory contents hashed by device and inode number. */ static struct hash_table directory_contents; #ifdef CONFIG_WITH_ALLOC_CACHES /* Allocation cache for directory contents. */ struct alloccache directory_contents_cache; #endif struct directory { const char *name; /* Name of the directory. */ /* The directory's contents. This data may be shared by several entries in the hash table, which refer to the same directory (identified uniquely by 'dev' and 'ino') under different names. */ struct directory_contents *contents; }; #ifndef CONFIG_WITH_STRCACHE2 static unsigned long directory_hash_1 (const void *key) { return_ISTRING_HASH_1 (((const struct directory *) key)->name); } static unsigned long directory_hash_2 (const void *key) { return_ISTRING_HASH_2 (((const struct directory *) key)->name); } static int directory_hash_cmp (const void *x, const void *y) { return_ISTRING_COMPARE (((const struct directory *) x)->name, ((const struct directory *) y)->name); } #endif /* !CONFIG_WITH_STRCACHE2 */ /* Table of directories hashed by name. */ static struct hash_table directories; #ifdef CONFIG_WITH_ALLOC_CACHES /* Allocation cache for directories. */ struct alloccache directories_cache; #endif /* Never have more than this many directories open at once. */ #define MAX_OPEN_DIRECTORIES 10 static unsigned int open_directories = 0; /* Hash table of files in each directory. */ struct dirfile { const char *name; /* Name of the file. */ size_t length; short impossible; /* This file is impossible. */ }; #ifndef CONFIG_WITH_STRCACHE2 static unsigned long dirfile_hash_1 (const void *key) { return_ISTRING_HASH_1 (((struct dirfile const *) key)->name); } static unsigned long dirfile_hash_2 (const void *key) { return_ISTRING_HASH_2 (((struct dirfile const *) key)->name); } static int dirfile_hash_cmp (const void *xv, const void *yv) { const struct dirfile *x = xv; const struct dirfile *y = yv; int result = x->length - y->length; if (result) return result; return_ISTRING_COMPARE (x->name, y->name); } #endif /* !CONFIG_WITH_STRCACHE2 */ #ifndef DIRFILE_BUCKETS #define DIRFILE_BUCKETS 107 #endif #ifdef CONFIG_WITH_ALLOC_CACHES /* Allocation cache for dirfiles. */ struct alloccache dirfile_cache; #endif static int dir_contents_file_exists_p (struct directory_contents *dir, const char *filename); static struct directory *find_directory (const char *name); /* Find the directory named NAME and return its 'struct directory'. */ static struct directory * find_directory (const char *name) { struct directory *dir; struct directory **dir_slot; struct directory dir_key; #ifndef CONFIG_WITH_STRCACHE2 dir_key.name = name; dir_slot = (struct directory **) hash_find_slot (&directories, &dir_key); #else const char *p = name + strlen (name); # if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS) dir_key.name = strcache_add_len (downcase(name), p - name); # else dir_key.name = strcache_add_len (name, p - name); # endif dir_slot = (struct directory **) hash_find_slot_strcached (&directories, &dir_key); #endif dir = *dir_slot; if (HASH_VACANT (dir)) { /* The directory was not found. Create a new entry for it. */ #ifndef CONFIG_WITH_STRCACHE2 const char *p = name + strlen (name); #endif struct stat st; int r; #ifndef CONFIG_WITH_ALLOC_CACHES dir = xmalloc (sizeof (struct directory)); #else dir = alloccache_alloc (&directories_cache); #endif #ifndef CONFIG_WITH_STRCACHE2 #if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS) /* Todo: Why is this only needed on VMS? */ { char *lname = downcase_inplace (xstrdup (name)); dir->name = strcache_add_len (lname, p - name); free (lname); } #else dir->name = strcache_add_len (name, p - name); #endif #else /* CONFIG_WITH_STRCACHE2 */ dir->name = dir_key.name; #endif /* CONFIG_WITH_STRCACHE2 */ hash_insert_at (&directories, dir, dir_slot); /* The directory is not in the name hash table. Find its device and inode numbers, and look it up by them. */ #if defined(WINDOWS32) { char tem[MAXPATHLEN], *tstart, *tend; /* Remove any trailing slashes. Windows32 stat fails even on valid directories if they end in a slash. */ memcpy (tem, name, p - name + 1); tstart = tem; if (tstart[1] == ':') tstart += 2; for (tend = tem + (p - name - 1); tend > tstart && (*tend == '/' || *tend == '\\'); tend--) *tend = '\0'; r = stat (tem, &st); } #else EINTRLOOP (r, stat (name, &st)); #endif if (r < 0) { /* Couldn't stat the directory. Mark this by setting the 'contents' member to a nil pointer. */ dir->contents = 0; } else { /* Search the contents hash table; device and inode are the key. */ #ifdef WINDOWS32 char *w32_path; #endif struct directory_contents *dc; struct directory_contents **dc_slot; struct directory_contents dc_key; dc_key.dev = st.st_dev; #ifdef WINDOWS32 # ifndef CONFIG_WITH_STRCACHE2 dc_key.path_key = w32_path = w32ify (name, 1); # else /* CONFIG_WITH_STRCACHE2 */ w32_path = w32ify (name, 1); dc_key.path_key = strcache_add (w32_path); # endif /* CONFIG_WITH_STRCACHE2 */ dc_key.ctime = st.st_ctime; #else # ifdef VMS_INO_T dc_key.ino[0] = st.st_ino[0]; dc_key.ino[1] = st.st_ino[1]; dc_key.ino[2] = st.st_ino[2]; # else dc_key.ino = st.st_ino; # endif #endif dc_slot = (struct directory_contents **) hash_find_slot (&directory_contents, &dc_key); dc = *dc_slot; if (HASH_VACANT (dc)) { /* Nope; this really is a directory we haven't seen before. */ #ifdef WINDOWS32 char fs_label[BUFSIZ]; char fs_type[BUFSIZ]; unsigned long fs_serno; unsigned long fs_flags; unsigned long fs_len; #endif #if defined(WINDOWS32) && defined(KMK) static char s_last_volume[4]; static int s_last_flags; #endif #ifndef CONFIG_WITH_ALLOC_CACHES dc = (struct directory_contents *) xmalloc (sizeof (struct directory_contents)); #else dc = (struct directory_contents *) alloccache_alloc (&directory_contents_cache); #endif /* Enter it in the contents hash table. */ dc->dev = st.st_dev; #ifdef WINDOWS32 # ifndef CONFIG_WITH_STRCACHE2 dc->path_key = xstrdup (w32_path); # else /* CONFIG_WITH_STRCACHE2 */ dc->path_key = dc_key.path_key; # endif /* CONFIG_WITH_STRCACHE2 */ dc->ctime = st.st_ctime; dc->mtime = st.st_mtime; # ifdef KMK dc->last_updated = time(NULL); # endif /* NTFS is the only WINDOWS32 filesystem that bumps mtime on a directory when files are added/deleted from a directory. */ w32_path[3] = '\0'; # ifdef KMK /* Need for speed: Cache the GetVolumeInformation result. */ if ( s_last_volume[0] == w32_path[0] && s_last_volume[1] == w32_path[1] && s_last_volume[2] == w32_path[2] && s_last_volume[3] == w32_path[3]) dc->fs_flags = s_last_flags; else { # endif if (GetVolumeInformation (w32_path, fs_label, sizeof (fs_label), &fs_serno, &fs_len, &fs_flags, fs_type, sizeof (fs_type)) == FALSE) dc->fs_flags = FS_UNKNOWN; else if (!strcmp (fs_type, "FAT")) dc->fs_flags = FS_FAT; else if (!strcmp (fs_type, "NTFS")) dc->fs_flags = FS_NTFS; else dc->fs_flags = FS_UNKNOWN; # ifdef KMK s_last_volume[0] = w32_path[0]; s_last_volume[1] = w32_path[1]; s_last_volume[2] = w32_path[2]; s_last_volume[3] = w32_path[3]; s_last_flags = dc->fs_flags; # endif #else # ifdef VMS_INO_T dc->ino[0] = st.st_ino[0]; dc->ino[1] = st.st_ino[1]; dc->ino[2] = st.st_ino[2]; # else dc->ino = st.st_ino; # endif #endif /* WINDOWS32 */ hash_insert_at (&directory_contents, dc, dc_slot); ENULLLOOP (dc->dirstream, opendir (name)); if (dc->dirstream == 0) /* Couldn't open the directory. Mark this by setting the 'files' member to a nil pointer. */ dc->dirfiles.ht_vec = 0; else { #ifdef KMK int buckets = st.st_nlink * 2; if (buckets < DIRFILE_BUCKETS) buckets = DIRFILE_BUCKETS; hash_init_strcached (&dc->dirfiles, buckets, &file_strcache, offsetof (struct dirfile, name)); #else # ifndef CONFIG_WITH_STRCACHE2 hash_init (&dc->dirfiles, DIRFILE_BUCKETS, dirfile_hash_1, dirfile_hash_2, dirfile_hash_cmp); # else /* CONFIG_WITH_STRCACHE2 */ hash_init_strcached (&dc->dirfiles, DIRFILE_BUCKETS, &file_strcache, offsetof (struct dirfile, name)); # endif /* CONFIG_WITH_STRCACHE2 */ #endif ++open_directories; if (open_directories == MAX_OPEN_DIRECTORIES) /* We have too many directories open already. Read the entire directory and then close it. */ dir_contents_file_exists_p (dc, 0); } } /* Point the name-hashed entry for DIR at its contents data. */ dir->contents = dc; } } return dir; } /* Return 1 if the name FILENAME is entered in DIR's hash table. FILENAME must contain no slashes. */ static int dir_contents_file_exists_p (struct directory_contents *dir, const char *filename) { struct dirfile *df; struct dirent *d; #ifdef WINDOWS32 # ifndef KMK struct stat st; # endif int rehash = 0; #endif #ifdef KMK int ret = 0; #endif if (dir == 0 || dir->dirfiles.ht_vec == 0) /* The directory could not be stat'd or opened. */ return 0; #ifdef __MSDOS__ filename = dosify (filename); #endif #ifdef HAVE_CASE_INSENSITIVE_FS filename = downcase (filename); #endif #ifdef __EMX__ if (filename != 0) _fnlwr (filename); /* lower case for FAT drives */ #endif if (filename != 0) { struct dirfile dirfile_key; if (*filename == '\0') { /* Checking if the directory exists. */ return 1; } #ifndef CONFIG_WITH_STRCACHE2 dirfile_key.name = filename; dirfile_key.length = strlen (filename); df = hash_find_item (&dir->dirfiles, &dirfile_key); #else /* CONFIG_WITH_STRCACHE2 */ dirfile_key.length = strlen (filename); dirfile_key.name = filename = strcache_add_len (filename, dirfile_key.length); df = hash_find_item_strcached (&dir->dirfiles, &dirfile_key); #endif /* CONFIG_WITH_STRCACHE2 */ if (df) return !df->impossible; } /* The file was not found in the hashed list. Try to read the directory further. */ if (dir->dirstream == 0) { #if defined(WINDOWS32) && !defined(KMK) /* * Check to see if directory has changed since last read. FAT * filesystems force a rehash always as mtime does not change * on directories (ugh!). */ # ifdef KMK if (dir->path_key && time(NULL) > dc->last_updated + 2) /* KMK: Only recheck every 2 seconds. */ # else if (dir->path_key) # endif { if ((dir->fs_flags & FS_FAT) != 0) { dir->mtime = time ((time_t *) 0); rehash = 1; } # ifdef KMK else if ( birdStatModTimeOnly (dir->path_key, &st.st_mtim, 1) == 0 && st.st_mtime > dir->mtime) # else else if (stat (dir->path_key, &st) == 0 && st.st_mtime > dir->mtime) # endif { /* reset date stamp to show most recent re-process. */ dir->mtime = st.st_mtime; rehash = 1; } /* If it has been already read in, all done. */ if (!rehash) return 0; /* make sure directory can still be opened; if not return. */ dir->dirstream = opendir (dir->path_key); if (!dir->dirstream) return 0; # ifdef KMK dc->last_updated = time(NULL); # endif } else #endif /* The directory has been all read in. */ return 0; } while (1) { /* Enter the file in the hash table. */ unsigned int len; struct dirfile dirfile_key; struct dirfile **dirfile_slot; ENULLLOOP (d, readdir (dir->dirstream)); if (d == 0) { /* bird: Workaround for smbfs mounts returning EBADF at the end of the search. To exactly determin the cause here, I should probably do some smbfs tracing, but for now just ignoring the EBADF on seems to work. (The smb server is 64-bit vista, btw.) */ #if defined (__FreeBSD__) struct statfs stfs; int saved_errno = errno; errno = 0; if (saved_errno == EBADF && !fstatfs (dirfd (dir->dirstream), &stfs) && !(stfs.f_flags & MNT_LOCAL) && !strcmp(stfs.f_fstypename, "smbfs")) { /*fprintf (stderr, "EBADF on remote fs! dirfd=%d errno=%d\n", dirfd (dir->dirstream), errno);*/ saved_errno = 0; } errno = saved_errno; #endif /* bird: end */ if (errno) pfatal_with_name ("INTERNAL: readdir"); break; } #if defined(VMS) && defined(HAVE_DIRENT_H) /* In VMS we get file versions too, which have to be stripped off. Some versions of VMS return versions on Unix files even when the feature option to strip them is set. */ { char *p = strrchr (d->d_name, ';'); if (p) *p = '\0'; } #endif if (!REAL_DIR_ENTRY (d)) continue; len = NAMLEN (d); #ifndef CONFIG_WITH_STRCACHE2 dirfile_key.name = d->d_name; dirfile_key.length = len; dirfile_slot = (struct dirfile **) hash_find_slot (&dir->dirfiles, &dirfile_key); #else # if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS) dirfile_key.name = strcache_add_len (downcase(d->d_name), len); # else dirfile_key.name = strcache_add_len (d->d_name, len); # endif dirfile_key.length = len; dirfile_slot = (struct dirfile **) hash_find_slot_strcached (&dir->dirfiles, &dirfile_key); #endif #ifdef WINDOWS32 /* * If re-reading a directory, don't cache files that have * already been discovered. */ if (! rehash || HASH_VACANT (*dirfile_slot)) #endif { #ifndef CONFIG_WITH_ALLOC_CACHES df = xmalloc (sizeof (struct dirfile)); #else df = alloccache_alloc (&dirfile_cache); #endif #ifndef CONFIG_WITH_STRCACHE2 #if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS) /* TODO: Why is this only needed on VMS? */ df->name = strcache_add_len (downcase_inplace (d->d_name), len); #else df->name = strcache_add_len (d->d_name, len); #endif #else /* CONFIG_WITH_STRCACHE2 */ df->name = dirfile_key.name; #endif /* CONFIG_WITH_STRCACHE2 */ df->length = len; df->impossible = 0; hash_insert_at (&dir->dirfiles, df, dirfile_slot); } /* Check if the name matches the one we're searching for. */ #ifndef CONFIG_WITH_STRCACHE2 if (filename != 0 && patheq (d->d_name, filename)) #else if (filename != 0 && dirfile_key.name == filename) #endif #ifdef KMK ret = 1; /* Cache the whole dir. Prevents trouble on windows and os2 during 'rebuild'. */ #else return 1; #endif } /* If the directory has been completely read in, close the stream and reset the pointer to nil. */ if (d == 0) { --open_directories; closedir (dir->dirstream); dir->dirstream = 0; } #ifdef KMK return ret; #else return 0; #endif } /* Return 1 if the name FILENAME in directory DIRNAME is entered in the dir hash table. FILENAME must contain no slashes. */ int dir_file_exists_p (const char *dirname, const char *filename) { #ifdef VMS if ((filename != NULL) && (dirname != NULL)) { int want_vmsify; want_vmsify = (strpbrk (dirname, ":<[") != NULL); if (want_vmsify) filename = vmsify (filename, 0); } #endif return dir_contents_file_exists_p (find_directory (dirname)->contents, filename); } /* Return 1 if the file named NAME exists. */ int file_exists_p (const char *name) { const char *dirend; const char *dirname; const char *slash; #ifndef NO_ARCHIVES if (ar_name (name)) return ar_member_date (name) != (time_t) -1; #endif dirend = strrchr (name, '/'); #ifdef VMS if (dirend == 0) { dirend = strrchr (name, ']'); dirend == NULL ? dirend : dirend++; } if (dirend == 0) { dirend = strrchr (name, '>'); dirend == NULL ? dirend : dirend++; } if (dirend == 0) { dirend = strrchr (name, ':'); dirend == NULL ? dirend : dirend++; } #endif /* VMS */ #ifdef HAVE_DOS_PATHS /* Forward and backslashes might be mixed. We need the rightmost one. */ { const char *bslash = strrchr (name, '\\'); if (!dirend || bslash > dirend) dirend = bslash; /* The case of "d:file". */ if (!dirend && name[0] && name[1] == ':') dirend = name + 1; } #endif /* HAVE_DOS_PATHS */ if (dirend == 0) #ifndef _AMIGA return dir_file_exists_p (".", name); #else /* !AMIGA */ return dir_file_exists_p ("", name); #endif /* AMIGA */ slash = dirend; if (dirend == name) dirname = "/"; else { char *p; #ifdef HAVE_DOS_PATHS /* d:/ and d: are *very* different... */ if (dirend < name + 3 && name[1] == ':' && (*dirend == '/' || *dirend == '\\' || *dirend == ':')) dirend++; #endif p = alloca (dirend - name + 1); memcpy (p, name, dirend - name); p[dirend - name] = '\0'; dirname = p; } #ifdef VMS if (*slash == '/') slash++; #else slash++; #endif return dir_file_exists_p (dirname, slash); } /* Mark FILENAME as 'impossible' for 'file_impossible_p'. This means an attempt has been made to search for FILENAME as an intermediate file, and it has failed. */ void file_impossible (const char *filename) { const char *dirend; const char *p = filename; struct directory *dir; struct dirfile *new; dirend = strrchr (p, '/'); #ifdef VMS if (dirend == NULL) { dirend = strrchr (p, ']'); dirend == NULL ? dirend : dirend++; } if (dirend == NULL) { dirend = strrchr (p, '>'); dirend == NULL ? dirend : dirend++; } if (dirend == NULL) { dirend = strrchr (p, ':'); dirend == NULL ? dirend : dirend++; } #endif #ifdef HAVE_DOS_PATHS /* Forward and backslashes might be mixed. We need the rightmost one. */ { const char *bslash = strrchr (p, '\\'); if (!dirend || bslash > dirend) dirend = bslash; /* The case of "d:file". */ if (!dirend && p[0] && p[1] == ':') dirend = p + 1; } #endif /* HAVE_DOS_PATHS */ if (dirend == 0) #ifdef _AMIGA dir = find_directory (""); #else /* !AMIGA */ dir = find_directory ("."); #endif /* AMIGA */ else { const char *dirname; const char *slash = dirend; if (dirend == p) dirname = "/"; else { char *cp; #ifdef HAVE_DOS_PATHS /* d:/ and d: are *very* different... */ if (dirend < p + 3 && p[1] == ':' && (*dirend == '/' || *dirend == '\\' || *dirend == ':')) dirend++; #endif cp = alloca (dirend - p + 1); memcpy (cp, p, dirend - p); cp[dirend - p] = '\0'; dirname = cp; } dir = find_directory (dirname); #ifdef VMS if (*slash == '/') filename = p = slash + 1; else filename = p = slash; #else filename = p = slash + 1; #endif } if (dir->contents == 0) /* The directory could not be stat'd. We allocate a contents structure for it, but leave it out of the contents hash table. */ #ifndef CONFIG_WITH_ALLOC_CACHES dir->contents = xcalloc (sizeof (struct directory_contents)); #else dir->contents = alloccache_calloc (&directory_contents_cache); #endif if (dir->contents->dirfiles.ht_vec == 0) { #ifndef CONFIG_WITH_STRCACHE2 hash_init (&dir->contents->dirfiles, DIRFILE_BUCKETS, dirfile_hash_1, dirfile_hash_2, dirfile_hash_cmp); #else /* CONFIG_WITH_STRCACHE2 */ hash_init_strcached (&dir->contents->dirfiles, DIRFILE_BUCKETS, &file_strcache, offsetof (struct dirfile, name)); #endif /* CONFIG_WITH_STRCACHE2 */ } /* Make a new entry and put it in the table. */ #ifndef CONFIG_WITH_ALLOC_CACHES new = xmalloc (sizeof (struct dirfile)); #else new = alloccache_alloc (&dirfile_cache); #endif new->length = strlen (filename); #if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS) /* todo: Why is this only needed on VMS? */ new->name = strcache_add_len (downcase (filename), new->length); #else new->name = strcache_add_len (filename, new->length); #endif new->impossible = 1; #ifndef CONFIG_WITH_STRCACHE2 hash_insert (&dir->contents->dirfiles, new); #else /* CONFIG_WITH_STRCACHE2 */ hash_insert_strcached (&dir->contents->dirfiles, new); #endif /* CONFIG_WITH_STRCACHE2 */ } /* Return nonzero if FILENAME has been marked impossible. */ int file_impossible_p (const char *filename) { const char *dirend; struct directory_contents *dir; struct dirfile *dirfile; struct dirfile dirfile_key; #ifdef VMS int want_vmsify = 0; #endif dirend = strrchr (filename, '/'); #ifdef VMS if (dirend == NULL) { want_vmsify = (strpbrk (filename, "]>:^") != NULL); dirend = strrchr (filename, ']'); } if (dirend == NULL && want_vmsify) dirend = strrchr (filename, '>'); if (dirend == NULL && want_vmsify) dirend = strrchr (filename, ':'); #endif #ifdef HAVE_DOS_PATHS /* Forward and backslashes might be mixed. We need the rightmost one. */ { const char *bslash = strrchr (filename, '\\'); if (!dirend || bslash > dirend) dirend = bslash; /* The case of "d:file". */ if (!dirend && filename[0] && filename[1] == ':') dirend = filename + 1; } #endif /* HAVE_DOS_PATHS */ if (dirend == 0) #ifdef _AMIGA dir = find_directory ("")->contents; #else /* !AMIGA */ dir = find_directory (".")->contents; #endif /* AMIGA */ else { const char *dirname; const char *slash = dirend; if (dirend == filename) dirname = "/"; else { char *cp; #ifdef HAVE_DOS_PATHS /* d:/ and d: are *very* different... */ if (dirend < filename + 3 && filename[1] == ':' && (*dirend == '/' || *dirend == '\\' || *dirend == ':')) dirend++; #endif cp = alloca (dirend - filename + 1); memcpy (cp, filename, dirend - filename); cp[dirend - filename] = '\0'; dirname = cp; } dir = find_directory (dirname)->contents; #ifdef VMS if (*slash == '/') filename = slash + 1; else filename = slash; #else filename = slash + 1; #endif } if (dir == 0 || dir->dirfiles.ht_vec == 0) /* There are no files entered for this directory. */ return 0; #ifdef __MSDOS__ filename = dosify (filename); #endif #ifdef HAVE_CASE_INSENSITIVE_FS filename = downcase (filename); #endif #ifdef VMS if (want_vmsify) filename = vmsify (filename, 1); #endif #ifndef CONFIG_WITH_STRCACHE2 dirfile_key.name = filename; dirfile_key.length = strlen (filename); dirfile = hash_find_item (&dir->dirfiles, &dirfile_key); #else dirfile_key.length = strlen (filename); dirfile_key.name = strcache_add_len (filename, dirfile_key.length); dirfile = hash_find_item_strcached (&dir->dirfiles, &dirfile_key); #endif if (dirfile) return dirfile->impossible; return 0; } /* Return the already allocated name in the directory hash table that matches DIR. */ const char * dir_name (const char *dir) { return find_directory (dir)->name; } /* Print the data base of directories. */ void print_dir_data_base (void) { unsigned int files; unsigned int impossible; struct directory **dir_slot; struct directory **dir_end; puts (_("\n# Directories\n")); files = impossible = 0; dir_slot = (struct directory **) directories.ht_vec; dir_end = dir_slot + directories.ht_size; for ( ; dir_slot < dir_end; dir_slot++) { struct directory *dir = *dir_slot; if (! HASH_VACANT (dir)) { if (dir->contents == 0) printf (_("# %s: could not be stat'd.\n"), dir->name); else if (dir->contents->dirfiles.ht_vec == 0) { #ifdef WINDOWS32 printf (_("# %s (key %s, mtime %I64u): could not be opened.\n"), dir->name, dir->contents->path_key, (unsigned long long)dir->contents->mtime); #else /* WINDOWS32 */ #ifdef VMS_INO_T printf (_("# %s (device %d, inode [%d,%d,%d]): could not be opened.\n"), dir->name, dir->contents->dev, dir->contents->ino[0], dir->contents->ino[1], dir->contents->ino[2]); #else printf (_("# %s (device %ld, inode %ld): could not be opened.\n"), dir->name, (long int) dir->contents->dev, (long int) dir->contents->ino); #endif #endif /* WINDOWS32 */ } else { unsigned int f = 0; unsigned int im = 0; struct dirfile **files_slot; struct dirfile **files_end; files_slot = (struct dirfile **) dir->contents->dirfiles.ht_vec; files_end = files_slot + dir->contents->dirfiles.ht_size; for ( ; files_slot < files_end; files_slot++) { struct dirfile *df = *files_slot; if (! HASH_VACANT (df)) { if (df->impossible) ++im; else ++f; } } #ifdef WINDOWS32 printf (_("# %s (key %s, mtime %I64u): "), dir->name, dir->contents->path_key, (unsigned long long)dir->contents->mtime); #else /* WINDOWS32 */ #ifdef VMS_INO_T printf (_("# %s (device %d, inode [%d,%d,%d]): "), dir->name, dir->contents->dev, dir->contents->ino[0], dir->contents->ino[1], dir->contents->ino[2]); #else printf (_("# %s (device %ld, inode %ld): "), dir->name, (long)dir->contents->dev, (long)dir->contents->ino); #endif #endif /* WINDOWS32 */ if (f == 0) fputs (_("No"), stdout); else printf ("%u", f); fputs (_(" files, "), stdout); if (im == 0) fputs (_("no"), stdout); else printf ("%u", im); fputs (_(" impossibilities"), stdout); if (dir->contents->dirstream == 0) puts ("."); else puts (_(" so far.")); files += f; impossible += im; #ifdef KMK fputs ("# ", stdout); hash_print_stats (&dir->contents->dirfiles, stdout); fputs ("\n", stdout); #endif } } } fputs ("\n# ", stdout); if (files == 0) fputs (_("No"), stdout); else printf ("%u", files); fputs (_(" files, "), stdout); if (impossible == 0) fputs (_("no"), stdout); else printf ("%u", impossible); printf (_(" impossibilities in %lu directories.\n"), directories.ht_fill); #ifdef KMK fputs ("# directories: ", stdout); hash_print_stats (&directories, stdout); fputs ("\n# directory_contents: ", stdout); hash_print_stats (&directory_contents, stdout); fputs ("\n", stdout); #endif } #ifdef CONFIG_WITH_PRINT_STATS_SWITCH /* Print stats */ void print_dir_stats (void) { /** @todo normal dir stats. */ } #endif /* Hooks for globbing. */ /* Structure describing state of iterating through a directory hash table. */ struct dirstream { struct directory_contents *contents; /* The directory being read. */ struct dirfile **dirfile_slot; /* Current slot in table. */ }; /* Forward declarations. */ static __ptr_t open_dirstream (const char *); static struct dirent *read_dirstream (__ptr_t); static __ptr_t open_dirstream (const char *directory) { struct dirstream *new; struct directory *dir = find_directory (directory); if (dir->contents == 0 || dir->contents->dirfiles.ht_vec == 0) /* DIR->contents is nil if the directory could not be stat'd. DIR->contents->dirfiles is nil if it could not be opened. */ return 0; /* Read all the contents of the directory now. There is no benefit in being lazy, since glob will want to see every file anyway. */ dir_contents_file_exists_p (dir->contents, 0); new = xmalloc (sizeof (struct dirstream)); new->contents = dir->contents; new->dirfile_slot = (struct dirfile **) new->contents->dirfiles.ht_vec; return (__ptr_t) new; } static struct dirent * read_dirstream (__ptr_t stream) { static char *buf; static unsigned int bufsz; struct dirstream *const ds = (struct dirstream *) stream; struct directory_contents *dc = ds->contents; struct dirfile **dirfile_end = (struct dirfile **) dc->dirfiles.ht_vec + dc->dirfiles.ht_size; while (ds->dirfile_slot < dirfile_end) { struct dirfile *df = *ds->dirfile_slot++; if (! HASH_VACANT (df) && !df->impossible) { /* The glob interface wants a 'struct dirent', so mock one up. */ struct dirent *d; unsigned int len = df->length + 1; unsigned int sz = sizeof (*d) - sizeof (d->d_name) + len; if (sz > bufsz) { bufsz *= 2; if (sz > bufsz) bufsz = sz; buf = xrealloc (buf, bufsz); } d = (struct dirent *) buf; #ifdef __MINGW32__ # if __MINGW32_MAJOR_VERSION < 3 || (__MINGW32_MAJOR_VERSION == 3 && \ __MINGW32_MINOR_VERSION == 0) d->d_name = xmalloc (len); # endif #endif FAKE_DIR_ENTRY (d); #ifdef _DIRENT_HAVE_D_NAMLEN d->d_namlen = len - 1; #endif #ifdef _DIRENT_HAVE_D_TYPE d->d_type = DT_UNKNOWN; #endif memcpy (d->d_name, df->name, len); return d; } } return 0; } /* On 64 bit ReliantUNIX (5.44 and above) in LFS mode, stat() is actually a * macro for stat64(). If stat is a macro, make a local wrapper function to * invoke it. * * On MS-Windows, stat() "succeeds" for foo/bar/. where foo/bar is a * regular file; fix that here. */ #if !defined(stat) && !defined(WINDOWS32) || defined(VMS) # ifndef VMS # ifndef HAVE_SYS_STAT_H int stat (const char *path, struct stat *sbuf); # endif # else /* We are done with the fake stat. Go back to the real stat */ # ifdef stat # undef stat # endif # endif # define local_stat stat #else static int local_stat (const char *path, struct stat *buf) { int e; #ifdef WINDOWS32 size_t plen = strlen (path); /* Make sure the parent of "." exists and is a directory, not a file. This is because 'stat' on Windows normalizes the argument foo/. => foo without checking first that foo is a directory. */ if (plen > 1 && path[plen - 1] == '.' && (path[plen - 2] == '/' || path[plen - 2] == '\\')) { char parent[MAXPATHLEN]; strncpy (parent, path, plen - 2); parent[plen - 2] = '\0'; if (stat (parent, buf) < 0 || !_S_ISDIR (buf->st_mode)) return -1; } #endif EINTRLOOP (e, stat (path, buf)); return e; } #endif #ifdef KMK static int dir_exists_p (const char *dirname) { if (file_exists_p (dirname)) { struct directory *dir = find_directory (dirname); if (dir != NULL && dir->contents && dir->contents->dirfiles.ht_vec != NULL) return 1; } return 0; } #endif void dir_setup_glob (glob_t *gl) { gl->gl_opendir = open_dirstream; gl->gl_readdir = read_dirstream; gl->gl_closedir = free; gl->gl_stat = local_stat; #ifdef __EMX__ /* The FreeBSD implementation actually uses gl_lstat!! */ gl->gl_lstat = local_stat; #endif #ifdef GLOB_WITH_EXTENDED_KMK_MEMBERS gl->gl_exists = file_exists_p; gl->gl_isdir = dir_exists_p; #endif /* We don't bother setting gl_lstat, since glob never calls it. The slot is only there for compatibility with 4.4 BSD. */ } void hash_init_directories (void) { #ifndef CONFIG_WITH_STRCACHE2 hash_init (&directories, DIRECTORY_BUCKETS, directory_hash_1, directory_hash_2, directory_hash_cmp); #else /* CONFIG_WITH_STRCACHE2 */ hash_init_strcached (&directories, DIRECTORY_BUCKETS, &file_strcache, offsetof (struct directory, name)); #endif /* CONFIG_WITH_STRCACHE2 */ hash_init (&directory_contents, DIRECTORY_BUCKETS, directory_contents_hash_1, directory_contents_hash_2, directory_contents_hash_cmp); #ifdef CONFIG_WITH_ALLOC_CACHES alloccache_init (&directories_cache, sizeof (struct directory), "directories", NULL, NULL); alloccache_init (&directory_contents_cache, sizeof (struct directory_contents), "directory_contents", NULL, NULL); alloccache_init (&dirfile_cache, sizeof (struct dirfile), "dirfile", NULL, NULL); #endif /* CONFIG_WITH_ALLOC_CACHES */ } kbuild-3149/src/kmk/inlined_memchr.h0000644000175000017500000001076313252530203017405 0ustar locutuslocutus#define _GNU_SOURCE 1 #include #ifdef _MSC_VER _inline void * #else static __inline__ void * #endif my_inline_memchr(const void *pv, int ch, register size_t cb) { register const unsigned int uch = (unsigned)ch; register const unsigned char *pb = (const unsigned char *)pv; #if 0 /* 8-byte loop unroll */ while (cb >= 8) { if (*pb == uch) return (unsigned char *)pb; if (pb[1] == uch) return (unsigned char *)pb + 1; if (pb[2] == uch) return (unsigned char *)pb + 2; if (pb[3] == uch) return (unsigned char *)pb + 3; if (pb[4] == uch) return (unsigned char *)pb + 4; if (pb[5] == uch) return (unsigned char *)pb + 5; if (pb[6] == uch) return (unsigned char *)pb + 6; if (pb[7] == uch) return (unsigned char *)pb + 7; cb -= 8; pb += 8; } switch (cb & 7) { case 0: break; case 1: if (*pb == uch) return (unsigned char *)pb; break; case 2: if (*pb == uch) return (unsigned char *)pb; if (pb[1] == uch) return (unsigned char *)pb + 1; break; case 3: if (*pb == uch) return (unsigned char *)pb; if (pb[1] == uch) return (unsigned char *)pb + 1; if (pb[2] == uch) return (unsigned char *)pb + 2; break; case 4: if (*pb == uch) return (unsigned char *)pb; if (pb[1] == uch) return (unsigned char *)pb + 1; if (pb[2] == uch) return (unsigned char *)pb + 2; if (pb[3] == uch) return (unsigned char *)pb + 3; break; case 5: if (*pb == uch) return (unsigned char *)pb; if (pb[1] == uch) return (unsigned char *)pb + 1; if (pb[2] == uch) return (unsigned char *)pb + 2; if (pb[3] == uch) return (unsigned char *)pb + 3; if (pb[4] == uch) return (unsigned char *)pb + 4; break; case 6: if (*pb == uch) return (unsigned char *)pb; if (pb[1] == uch) return (unsigned char *)pb + 1; if (pb[2] == uch) return (unsigned char *)pb + 2; if (pb[3] == uch) return (unsigned char *)pb + 3; if (pb[4] == uch) return (unsigned char *)pb + 4; if (pb[5] == uch) return (unsigned char *)pb + 5; break; case 7: if (*pb == uch) return (unsigned char *)pb; if (pb[1] == uch) return (unsigned char *)pb + 1; if (pb[2] == uch) return (unsigned char *)pb + 2; if (pb[3] == uch) return (unsigned char *)pb + 3; if (pb[4] == uch) return (unsigned char *)pb + 4; if (pb[5] == uch) return (unsigned char *)pb + 5; if (pb[6] == uch) return (unsigned char *)pb + 6; break; } #elif 1 /* 4 byte loop unroll */ while (cb >= 4) { if (*pb == uch) return (unsigned char *)pb; if (pb[1] == uch) return (unsigned char *)pb + 1; if (pb[2] == uch) return (unsigned char *)pb + 2; if (pb[3] == uch) return (unsigned char *)pb + 3; cb -= 4; pb += 4; } switch (cb & 3) { case 0: break; case 1: if (*pb == uch) return (unsigned char *)pb; break; case 2: if (*pb == uch) return (unsigned char *)pb; if (pb[1] == uch) return (unsigned char *)pb + 1; break; case 3: if (*pb == uch) return (unsigned char *)pb; if (pb[1] == uch) return (unsigned char *)pb + 1; if (pb[2] == uch) return (unsigned char *)pb + 2; break; } #else /* the basic loop */ while (cb > 0) { if (*pb == uch) return (void *)pb; cb--; pb++; } #endif return 0; } #define memchr my_inline_memchr kbuild-3149/src/kmk/testcase-stack.kmk0000644000175000017500000000545713252530203017705 0ustar locutuslocutus# $Id: testcase-stack.kmk 2413 2010-09-11 17:43:04Z bird $ ## @file # kBuild - testcase for the functions. # # # Copyright (c) 2007-2010 knut st. osmundsen # # This file is part of kBuild. # # kBuild 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. # # kBuild 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 kBuild. If not, see # # DEPTH = ../.. include $(PATH_KBUILD)/header.kmk ifneq ($(not 1),) $(error The 'not' function is missing) endif ifneq ($(eq 1,1),1) $(error The 'eq' function is missing) endif ASSERT1 = $(if $(not $(eq $(STACK1),$(1))),$(error failure: STACK1:='$(STACK1)' expected='$(1)')) $(call stack-push,STACK1,1) $(call ASSERT,1) $(call stack-push,STACK1,2) $(call ASSERT,1 2) $(call stack-push,STACK1,3) $(call ASSERT,1 2 3) $(call stack-push,STACK1,4) $(call ASSERT,1 2 3 4) $(call stack-push,STACK1,5) $(call ASSERT,1 2 3 4 5) $(call stack-popv,STACK1) $(call ASSERT,1 2 3 4) $(call stack-push,STACK1,5) $(call ASSERT,1 2 3 4 5) $(call stack-popv,STACK1) $(call ASSERT,1 2 3 4) $(call stack-popv,STACK1) $(call ASSERT,1 2 3) $(call stack-push,STACK1,4) $(call ASSERT,1 2 3 4) $(call stack-push,STACK1,5) $(call ASSERT,1 2 3 4 5) top := $(call stack-top,STACK1) $(if $(not $(eq $(top),5)),$(error failure STACK1:='$(STACK1)' top:='$(top)' expected='5')) $(call ASSERT,1 2 3 4 5) top := $(call stack-pop,STACK1) $(if $(not $(eq $(top),5)),$(error failure STACK1:='$(STACK1)' top:='$(top)' expected='5')) $(call ASSERT,1 2 3 4) top := $(call stack-pop,STACK1) $(if $(not $(eq $(top),4)),$(error failure STACK1:='$(STACK1)' top:='$(top)' expected='4')) $(call ASSERT,1 2 3) top := $(call stack-pop,STACK1) $(if $(not $(eq $(top),3)),$(error failure STACK1:='$(STACK1)' top:='$(top)' expected='3')) $(call ASSERT,1 2) top := $(call stack-pop,STACK1) $(if $(not $(eq $(top),2)),$(error failure STACK1:='$(STACK1)' top:='$(top)' expected='2')) $(call ASSERT,1) top := $(call stack-top,STACK1) $(if $(not $(eq $(top),1)),$(error failure STACK1:='$(STACK1)' top:='$(top)' expected='1')) $(call ASSERT,1) top := $(call stack-pop,STACK1) $(if $(not $(eq $(top),1)),$(error failure STACK1:='$(STACK1)' top:='$(top)' expected='1')) $(call ASSERT,) top := $(call stack-pop,STACK1) $(if $(not $(eq $(top),)),$(error failure STACK1:='$(STACK1)' top:='$(top)' expected='')) $(call ASSERT,) all_recursive: $(ECHO) The stack works.$(STACK1) kbuild-3149/src/kmk/.gitignore0000644000175000017500000000117213252530201016237 0ustar locutuslocutus# Development artifacts ID TAGS .*gdbinit .gdb_history *~ #* .#* # Configure artifacts ABOUT-NLS Makefile Makefile.in aclocal.m4 autom4te.cache config.cache config.h config.h.in config.log config.status configure stamp-h1 # Build artifacts .deps gmk-default.h loadavg make *.o *.exe *.dll.a *.obj *.lib *.pdb *.sbr # Windows build artifacts WinDebug/ WinRel/ GccDebug/ GccRel/ # Distribution artifacts .dep_segment .check-git-HEAD ChangeLog Makefile.DOS NMakefile README README.DOS README.OS2 README.W32 SMakefile build.sh build.sh.in config.ami config.h-vms config.h.W32 configh.dos make-[0-9]*/ make-[0-9]*.tar.* checkcfg.*.log kbuild-3149/src/kmk/w32/0000755000175000017500000000000013252530203014663 5ustar locutuslocutuskbuild-3149/src/kmk/w32/subproc/0000755000175000017500000000000013252530203016340 5ustar locutuslocutuskbuild-3149/src/kmk/w32/subproc/proc.h0000644000175000017500000000172113252530203017455 0ustar locutuslocutus/* Definitions for Windows Copyright (C) 1996-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make 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 . */ #ifndef _PROC_H #define _PROC_H typedef int bool_t; #define E_SCALL 101 #define E_IO 102 #define E_NO_MEM 103 #define E_FORK 104 extern bool_t arr2envblk(char **arr, char **envblk_out, int *envsize_needed); #endif kbuild-3149/src/kmk/w32/subproc/misc.c0000644000175000017500000000453413252530203017445 0ustar locutuslocutus/* Process handling for Windows Copyright (C) 1996-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include "proc.h" /* * Description: Convert a NULL string terminated UNIX environment block to * an environment block suitable for a windows32 system call * * Returns: TRUE= success, FALSE=fail * * Notes/Dependencies: the environment block is sorted in case-insensitive * order, is double-null terminated, and is a char *, not a char ** */ int _cdecl compare(const void *a1, const void *a2) { return _stricoll(*((char**)a1),*((char**)a2)); } bool_t arr2envblk(char **arr, char **envblk_out, int *envsize_needed) { char **tmp; int size_needed; int arrcnt; char *ptr; arrcnt = 0; while (arr[arrcnt]) { arrcnt++; } tmp = (char**) calloc(arrcnt + 1, sizeof(char *)); if (!tmp) { return FALSE; } arrcnt = 0; size_needed = *envsize_needed = 0; while (arr[arrcnt]) { tmp[arrcnt] = arr[arrcnt]; size_needed += strlen(arr[arrcnt]) + 1; arrcnt++; } size_needed++; *envsize_needed = size_needed; qsort((void *) tmp, (size_t) arrcnt, sizeof (char*), compare); ptr = *envblk_out = calloc(size_needed, 1); if (!ptr) { free(tmp); return FALSE; } arrcnt = 0; while (tmp[arrcnt]) { strcpy(ptr, tmp[arrcnt]); ptr += strlen(tmp[arrcnt]) + 1; arrcnt++; } free(tmp); return TRUE; } kbuild-3149/src/kmk/w32/subproc/w32err.c0000644000175000017500000000600313252530203017627 0ustar locutuslocutus/* Error handling for Windows Copyright (C) 1996-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include "makeint.h" #include "w32err.h" /* * Description: the windows32 version of perror() * * Returns: a pointer to a static error * * Notes/Dependencies: I got this from * comp.os.ms-windows.programmer.win32 */ const char * map_windows32_error_to_string (DWORD ercode) { /* * We used to have an MSVC-specific '__declspec (thread)' qualifier * here, with the following comment: * * __declspec (thread) necessary if you will use multiple threads on MSVC * * However, Make was never multithreaded on Windows (except when * Ctrl-C is hit, in which case the main thread is stopped * immediately, so it doesn't matter in this context). The functions * on sub_proc.c that started and stopped additional threads were * never used, and are now #ifdef'ed away. Until we need more than * one thread, we have no problems with the following buffer being * static. (If and when we do need it to be in thread-local storage, * the corresponding GCC qualifier is '__thread'.) */ static char szMessageBuffer[128]; /* Fill message buffer with a default message in * case FormatMessage fails */ wsprintf (szMessageBuffer, "Error %ld\n", ercode); /* * Special code for winsock error handling. */ if (ercode > WSABASEERR) { #if 0 HMODULE hModule = GetModuleHandle("wsock32"); if (hModule != NULL) { FormatMessage(FORMAT_MESSAGE_FROM_HMODULE, hModule, ercode, LANG_NEUTRAL, szMessageBuffer, sizeof(szMessageBuffer), NULL); FreeLibrary(hModule); } #else O (fatal, NILF, szMessageBuffer); #endif } else { /* * Default system message handling */ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, ercode, LANG_NEUTRAL, szMessageBuffer, sizeof(szMessageBuffer), NULL); } return szMessageBuffer; } kbuild-3149/src/kmk/w32/subproc/Makefile.kup0000644000175000017500000000000013252530203020564 0ustar locutuslocutuskbuild-3149/src/kmk/w32/subproc/NMakefile0000644000175000017500000000353213252530203020121 0ustar locutuslocutus# NOTE: If you have no 'make' program at all to process this makefile, run # 'build.bat' instead. # # Copyright (C) 1996-2016 Free Software Foundation, Inc. # This file is part of GNU Make. # # GNU Make 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. # # GNU Make 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 . # # NMakefile for GNU Make (subproc library) # LIB = lib CC = cl MAKE = nmake OUTDIR=. MAKEFILE=NMakefile CFLAGS_any = /nologo /MT /W4 /GX /Z7 /YX /D WIN32 /D WINDOWS32 /D _WINDOWS -I. -I../include -I../../ CFLAGS_debug = $(CFLAGS_any) /Od /D _DEBUG /FR.\WinDebug\ /Fp.\WinDebug\subproc.pch /Fo.\WinDebug/ CFLAGS_release = $(CFLAGS_any) /O2 /FR.\WinRel\ /Fp.\WinRel\subproc.pch /Fo.\WinRel/ all: Release Debug Release: $(MAKE) /f $(MAKEFILE) OUTDIR=WinRel CFLAGS="$(CFLAGS_release)" WinRel/subproc.lib Debug: $(MAKE) /f $(MAKEFILE) OUTDIR=WinDebug CFLAGS="$(CFLAGS_debug)" WinDebug/subproc.lib clean: rmdir /s /q WinRel WinDebug erase *.pdb $(OUTDIR): if not exist .\$@\nul mkdir .\$@ OBJS = $(OUTDIR)/misc.obj $(OUTDIR)/w32err.obj $(OUTDIR)/sub_proc.obj $(OUTDIR)/subproc.lib: $(OUTDIR) $(OBJS) $(LIB) -out:$@ @<< $(OBJS) << .c{$(OUTDIR)}.obj: $(CC) $(CFLAGS) /c $< $(OUTDIR)/misc.obj: misc.c proc.h $(OUTDIR)/sub_proc.obj: sub_proc.c ../include/sub_proc.h ../include/w32err.h proc.h $(OUTDIR)/w32err.obj: w32err.c ../include/w32err.h kbuild-3149/src/kmk/w32/subproc/sub_proc.c0000644000175000017500000015733213252530203020333 0ustar locutuslocutus/* Process handling for Windows. Copyright (C) 1996-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include /* for _get_osfhandle */ #ifdef _MSC_VER # include /* for intptr_t */ #else # include #endif #include #include /* for msvc _beginthreadex, _endthreadex */ #include #include #include "makeint.h" #include "filedef.h" #include "variable.h" #include "sub_proc.h" #include "proc.h" #include "w32err.h" #include "debug.h" #ifdef KMK # include # include "kmkbuiltin.h" extern void kmk_cache_exec_image(const char *); /* imagecache.c */ #endif static char *make_command_line(char *shell_name, char *exec_path, char **argv); typedef struct sub_process_t { #ifdef KMK enum { kRegular = 0, kSubmit, kSubProcFreed } enmType; intptr_t clue; #endif intptr_t sv_stdin[2]; intptr_t sv_stdout[2]; intptr_t sv_stderr[2]; int using_pipes; char *inp; DWORD incnt; char * volatile outp; volatile DWORD outcnt; char * volatile errp; volatile DWORD errcnt; pid_t pid; int exit_code; int signal; long last_err; long lerrno; } sub_process; static long process_file_io_private(sub_process *pproc, BOOL fNeedToWait); /* bird */ /* keep track of children so we can implement a waitpid-like routine */ static sub_process *proc_array[MAXIMUM_WAIT_OBJECTS]; static int proc_index = 0; static int fake_exits_pending = 0; /* * Fill a HANDLE list with handles to wait for. */ DWORD process_set_handles(HANDLE *handles) { DWORD count = 0; int i; /* Build array of handles to wait for */ for (i = 0; i < proc_index; i++) { /* Don't wait on child processes that have already finished */ if (fake_exits_pending && proc_array[i]->exit_code) continue; handles[count++] = (HANDLE) proc_array[i]->pid; } return count; } #ifndef KMK /* Inefficient! */ /* * When a process has been waited for, adjust the wait state * array so that we don't wait for it again */ static void process_adjust_wait_state(sub_process* pproc) { int i; if (!proc_index) return; for (i = 0; i < proc_index; i++) if (proc_array[i]->pid == pproc->pid) break; if (i < proc_index) { proc_index--; if (i != proc_index) memmove(&proc_array[i], &proc_array[i+1], (proc_index-i) * sizeof(sub_process*)); proc_array[proc_index] = NULL; } } #endif /* !KMK */ /* * Waits for any of the registered child processes to finish. */ static sub_process * process_wait_for_any_private(int block, DWORD* pdwWaitStatus) { HANDLE handles[MAXIMUM_WAIT_OBJECTS]; DWORD retval, which; int i; if (!proc_index) return NULL; /* build array of handles to wait for */ for (i = 0; i < proc_index; i++) { handles[i] = (HANDLE) proc_array[i]->pid; if (fake_exits_pending && proc_array[i]->exit_code) break; } /* wait for someone to exit */ if (!fake_exits_pending) { #ifdef KMK l_wait_again: #endif retval = WaitForMultipleObjects(proc_index, handles, FALSE, (block ? INFINITE : 0)); which = retval - WAIT_OBJECT_0; } else { fake_exits_pending--; retval = !WAIT_FAILED; which = i; } /* If the pointer is not NULL, set the wait status result variable. */ if (pdwWaitStatus) *pdwWaitStatus = retval; /* return pointer to process */ if ((retval == WAIT_TIMEOUT) || (retval == WAIT_FAILED)) { return NULL; } else { sub_process* pproc = proc_array[which]; #ifdef KMK if (pproc->enmType == kSubmit) { /* Try get the result from kSubmit.c. This may not succeed if the whole result hasn't arrived yet, in which we just restart the wait. */ if (kSubmitSubProcGetResult(pproc->clue, &pproc->exit_code, &pproc->signal) != 0) { goto l_wait_again; } } #endif #ifndef KMK /* Inefficient! */ process_adjust_wait_state(pproc); #else proc_index--; if ((int)which < proc_index) proc_array[which] = proc_array[proc_index]; proc_array[proc_index] = NULL; #endif return pproc; } } /* * Terminate a process. */ BOOL process_kill(HANDLE proc, int signal) { sub_process* pproc = (sub_process*) proc; #ifdef KMK if (pproc->enmType == kRegular) { #endif pproc->signal = signal; return (TerminateProcess((HANDLE) pproc->pid, signal)); #ifdef KMK } else if (pproc->enmType == kSubmit) return kSubmitSubProcKill(pproc->clue, signal) == 0; assert(0); return FALSE; #endif } /* * Use this function to register processes you wish to wait for by * calling process_file_io(NULL) or process_wait_any(). This must be done * because it is possible for callers of this library to reuse the same * handle for multiple processes launches :-( */ void process_register(HANDLE proc) { #ifdef KMK assert(((sub_process *)proc)->enmType == kRegular); #endif if (proc_index < MAXIMUM_WAIT_OBJECTS) proc_array[proc_index++] = (sub_process *) proc; } #ifdef KMK /** * Interface used by kmkbuiltin/kSubmit.c to register stuff going down in a * worker process. * * @returns 0 on success, -1 if there are too many sub-processes already. * @param hEvent The event semaphore to wait on. * @param clue The clue to base. * @param pPid Where to return the pid that job.c expects. */ int process_kmk_register_submit(HANDLE hEvent, intptr_t clue, pid_t *pPid) { if (proc_index < MAXIMUM_WAIT_OBJECTS) { sub_process *pSubProc = (sub_process *)xcalloc(sizeof(*pSubProc)); pSubProc->enmType = kSubmit; pSubProc->clue = clue; pSubProc->pid = (intptr_t)hEvent; proc_array[proc_index++] = pSubProc; *pPid = (intptr_t)pSubProc; return 0; } return -1; } /** * Interface used by kmkbuiltin/kRedirect.c to register a spawned process. * * @returns 0 on success, -1 if there are too many sub-processes already. * @param hProcess The process handle. * @param pPid Where to return the pid that job.c expects. */ int process_kmk_register_redirect(HANDLE hProcess, pid_t *pPid) { if (proc_index < MAXIMUM_WAIT_OBJECTS) { sub_process *pSubProc = (sub_process *)xcalloc(sizeof(*pSubProc)); pSubProc->enmType = kRegular; pSubProc->pid = (intptr_t)hProcess; proc_array[proc_index++] = pSubProc; *pPid = (intptr_t)pSubProc; return 0; } return -1; } #endif /* KMK */ /* * Return the number of processes that we are still waiting for. */ int process_used_slots(void) { return proc_index; } /* * Public function which works kind of like waitpid(). Wait for any * of the children to die and return results. To call this function, * you must do 1 of things: * * x = process_easy(...); * * or * * x = process_init_fd(); * process_register(x); * * or * * x = process_init(); * process_register(x); * * You must NOT then call process_pipe_io() because this function is * not capable of handling automatic notification of any child * death. */ HANDLE process_wait_for_any(int block, DWORD* pdwWaitStatus) { sub_process* pproc = process_wait_for_any_private(block, pdwWaitStatus); if (!pproc) return NULL; else { /* * Ouch! can't tell caller if this fails directly. Caller * will have to use process_last_err() */ #ifdef KMK /* Invalidate negative directory cache entries now that a job has completed and possibly created new files that was missing earlier. */ dir_cache_invalid_after_job (); if (pproc->enmType == kRegular) { (void)process_file_io_private(pproc, FALSE); } #else (void) process_file_io(pproc); #endif return ((HANDLE) pproc); } } long process_signal(HANDLE proc) { if (proc == INVALID_HANDLE_VALUE) return 0; return (((sub_process *)proc)->signal); } long process_last_err(HANDLE proc) { if (proc == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE; return (((sub_process *)proc)->last_err); } long process_exit_code(HANDLE proc) { if (proc == INVALID_HANDLE_VALUE) return EXIT_FAILURE; return (((sub_process *)proc)->exit_code); } void process_noinherit(int fd) { HANDLE fh = (HANDLE)_get_osfhandle(fd); if (fh && fh != INVALID_HANDLE_VALUE) SetHandleInformation(fh, HANDLE_FLAG_INHERIT, 0); } /* 2006-02: All the following functions are currently unused. All of them would crash gmake if called with argument INVALID_HANDLE_VALUE. Hence whoever wants to use one of this functions must invent and implement a reasonable error handling for this function. char * process_outbuf(HANDLE proc) { return (((sub_process *)proc)->outp); } char * process_errbuf(HANDLE proc) { return (((sub_process *)proc)->errp); } int process_outcnt(HANDLE proc) { return (((sub_process *)proc)->outcnt); } int process_errcnt(HANDLE proc) { return (((sub_process *)proc)->errcnt); } void process_pipes(HANDLE proc, int pipes[3]) { pipes[0] = ((sub_process *)proc)->sv_stdin[0]; pipes[1] = ((sub_process *)proc)->sv_stdout[0]; pipes[2] = ((sub_process *)proc)->sv_stderr[0]; return; } */ HANDLE process_init() { sub_process *pproc; /* * open file descriptors for attaching stdin/stdout/sterr */ HANDLE stdin_pipes[2]; HANDLE stdout_pipes[2]; HANDLE stderr_pipes[2]; SECURITY_ATTRIBUTES inherit; BYTE sd[SECURITY_DESCRIPTOR_MIN_LENGTH]; pproc = malloc(sizeof(*pproc)); memset(pproc, 0, sizeof(*pproc)); /* We can't use NULL for lpSecurityDescriptor because that uses the default security descriptor of the calling process. Instead we use a security descriptor with no DACL. This allows nonrestricted access to the associated objects. */ if (!InitializeSecurityDescriptor((PSECURITY_DESCRIPTOR)(&sd), SECURITY_DESCRIPTOR_REVISION)) { pproc->last_err = GetLastError(); pproc->lerrno = E_SCALL; return((HANDLE)pproc); } inherit.nLength = sizeof(inherit); inherit.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR)(&sd); inherit.bInheritHandle = TRUE; // By convention, parent gets pipe[0], and child gets pipe[1] // This means the READ side of stdin pipe goes into pipe[1] // and the WRITE side of the stdout and stderr pipes go into pipe[1] if (CreatePipe( &stdin_pipes[1], &stdin_pipes[0], &inherit, 0) == FALSE || CreatePipe( &stdout_pipes[0], &stdout_pipes[1], &inherit, 0) == FALSE || CreatePipe( &stderr_pipes[0], &stderr_pipes[1], &inherit, 0) == FALSE) { pproc->last_err = GetLastError(); pproc->lerrno = E_SCALL; return((HANDLE)pproc); } // // Mark the parent sides of the pipes as non-inheritable // if (SetHandleInformation(stdin_pipes[0], HANDLE_FLAG_INHERIT, 0) == FALSE || SetHandleInformation(stdout_pipes[0], HANDLE_FLAG_INHERIT, 0) == FALSE || SetHandleInformation(stderr_pipes[0], HANDLE_FLAG_INHERIT, 0) == FALSE) { pproc->last_err = GetLastError(); pproc->lerrno = E_SCALL; return((HANDLE)pproc); } pproc->sv_stdin[0] = (intptr_t) stdin_pipes[0]; pproc->sv_stdin[1] = (intptr_t) stdin_pipes[1]; pproc->sv_stdout[0] = (intptr_t) stdout_pipes[0]; pproc->sv_stdout[1] = (intptr_t) stdout_pipes[1]; pproc->sv_stderr[0] = (intptr_t) stderr_pipes[0]; pproc->sv_stderr[1] = (intptr_t) stderr_pipes[1]; pproc->using_pipes = 1; pproc->lerrno = 0; return((HANDLE)pproc); } HANDLE process_init_fd(HANDLE stdinh, HANDLE stdouth, HANDLE stderrh) { sub_process *pproc; pproc = malloc(sizeof(*pproc)); if (pproc) { memset(pproc, 0, sizeof(*pproc)); /* * Just pass the provided file handles to the 'child * side' of the pipe, bypassing pipes altogether. */ pproc->sv_stdin[1] = (intptr_t) stdinh; pproc->sv_stdout[1] = (intptr_t) stdouth; pproc->sv_stderr[1] = (intptr_t) stderrh; pproc->last_err = pproc->lerrno = 0; } return((HANDLE)pproc); } static HANDLE find_file(const char *exec_path, const char *path_var, char *full_fname, DWORD full_len) { HANDLE exec_handle; char *fname; char *ext; DWORD req_len; int i; static const char *extensions[] = /* Should .com come before no-extension case? */ { ".exe", ".cmd", ".bat", "", ".com", NULL }; fname = xmalloc(strlen(exec_path) + 5); strcpy(fname, exec_path); ext = fname + strlen(fname); for (i = 0; extensions[i]; i++) { strcpy(ext, extensions[i]); if (((req_len = SearchPath (path_var, fname, NULL, full_len, full_fname, NULL)) > 0 /* For compatibility with previous code, which used OpenFile, and with Windows operation in general, also look in various default locations, such as Windows directory and Windows System directory. Warning: this also searches PATH in the Make's environment, which might not be what the Makefile wants, but it seems to be OK as a fallback, after the previous SearchPath failed to find on child's PATH. */ || (req_len = SearchPath (NULL, fname, NULL, full_len, full_fname, NULL)) > 0) && req_len <= full_len && (exec_handle = CreateFile(full_fname, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE) { free(fname); return(exec_handle); } } free(fname); return INVALID_HANDLE_VALUE; } /* * Return non-zero of FNAME specifies a batch file and its name * includes embedded whitespace. */ static int batch_file_with_spaces(const char *fname) { size_t fnlen = strlen(fname); return (fnlen > 4 && (_strnicmp(fname + fnlen - 4, ".bat", 4) == 0 || _strnicmp(fname + fnlen - 4, ".cmd", 4) == 0) /* The set of characters in the 2nd arg to strpbrk should be the same one used by make_command_line below to decide whether an argv[] element needs quoting. */ && strpbrk(fname, " \t") != NULL); } /* * Description: Create the child process to be helped * * Returns: success <=> 0 * * Notes/Dependencies: */ long process_begin( HANDLE proc, char **argv, char **envp, char *exec_path, char *as_user) { sub_process *pproc = (sub_process *)proc; char *shell_name = 0; int file_not_found=0; HANDLE exec_handle; char exec_fname[MAX_PATH]; const char *path_var = NULL; char **ep; char buf[MAX_PATH]; DWORD bytes_returned; DWORD flags; char *command_line; STARTUPINFO startInfo; PROCESS_INFORMATION procInfo; char *envblk=NULL; int envsize_needed = 0; int pass_null_exec_path = 0; #ifdef KMK size_t exec_path_len; extern int process_priority; assert (pproc->enmType == kRegular); #endif /* * Shell script detection... if the exec_path starts with #! then * we want to exec shell-script-name exec-path, not just exec-path * NT doesn't recognize #!/bin/sh or #!/etc/Tivoli/bin/perl. We do not * hard-code the path to the shell or perl or whatever: Instead, we * assume it's in the path somewhere (generally, the NT tools * bin directory) */ #ifdef KMK /* kmk performance: Don't bother looking for shell scripts in .exe files. */ exec_path_len = strlen(exec_path); if (exec_path_len > 4 && exec_path[exec_path_len - 4] == '.' && !stricmp(exec_path + exec_path_len - 3, "exe")) { exec_handle = INVALID_HANDLE_VALUE; exec_fname[0] = '\0'; } else { #endif /* KMK */ /* Use the Makefile's value of PATH to look for the program to execute, because it could be different from Make's PATH (e.g., if the target sets its own value. */ if (envp) for (ep = envp; *ep; ep++) { if (strncmp (*ep, "PATH=", 5) == 0 || strncmp (*ep, "Path=", 5) == 0) { path_var = *ep + 5; break; } } exec_handle = find_file(exec_path, path_var, exec_fname, sizeof(exec_fname)); #ifdef KMK } #endif /* * If we couldn't open the file, just assume that Windows will be * somehow able to find and execute it. If the first character * of the command is '/', assume they set SHELL to a Unixy shell * that have some magic mounts known only to it, and run the whole * command via $SHELL -c "COMMAND" instead. */ if (exec_handle == INVALID_HANDLE_VALUE) { if (exec_path[0] == '/') { char *new_argv0; char **argvi = argv; int arglen = 0; strcpy(buf, variable_expand ("$(SHELL)")); shell_name = &buf[0]; strcpy(exec_fname, "-c"); /* Construct a single command string in argv[0]. */ while (*argvi) { arglen += strlen(*argvi) + 1; argvi++; } new_argv0 = xmalloc(arglen + 1); new_argv0[0] = '\0'; for (argvi = argv; *argvi; argvi++) { strcat(new_argv0, *argvi); strcat(new_argv0, " "); } /* Remove the extra blank at the end. */ new_argv0[arglen-1] = '\0'; free(argv[0]); argv[0] = new_argv0; argv[1] = NULL; } else file_not_found++; } else { /* Attempt to read the first line of the file */ if (ReadFile( exec_handle, buf, sizeof(buf) - 1, /* leave room for trailing NULL */ &bytes_returned, 0) == FALSE || bytes_returned < 2) { pproc->last_err = GetLastError(); pproc->lerrno = E_IO; CloseHandle(exec_handle); return(-1); } if (buf[0] == '#' && buf[1] == '!') { /* * This is a shell script... Change the command line from * exec_path args to shell_name exec_path args */ char *p; /* Make sure buf is NULL terminated */ buf[bytes_returned] = 0; /* * Depending on the file system type, etc. the first line * of the shell script may end with newline or newline-carriage-return * Whatever it ends with, cut it off. */ p= strchr(buf, '\n'); if (p) *p = 0; p = strchr(buf, '\r'); if (p) *p = 0; /* * Find base name of shell */ shell_name = strrchr( buf, '/'); if (shell_name) { shell_name++; } else { shell_name = &buf[2];/* skipping "#!" */ } } CloseHandle(exec_handle); } flags = 0; if (file_not_found) command_line = make_command_line( shell_name, exec_path, argv); else { /* If exec_fname includes whitespace, CreateProcess behaves erratically and unreliably, and often fails if argv[0] also includes whitespace (and thus will be quoted by make_command_line below). So in that case, we don't pass exec_fname as the 1st arg to CreateProcess, but instead replace argv[0] with exec_fname (to keep its leading directories and extension as found by find_file), and pass NULL to CreateProcess as its 1st arg. This works around the bugs in CreateProcess, which are probably caused by its passing the command to cmd.exe with some incorrect quoting. */ if (!shell_name && batch_file_with_spaces(exec_fname) && _stricmp(exec_path, argv[0]) == 0) { char *new_argv, *p; char **argvi; int arglen, i; pass_null_exec_path = 1; /* Rewrite argv[] replacing argv[0] with exec_fname. */ for (argvi = argv + 1, arglen = strlen(exec_fname) + 1; *argvi; argvi++) { arglen += strlen(*argvi) + 1; } new_argv = xmalloc(arglen); p = strcpy(new_argv, exec_fname) + strlen(exec_fname) + 1; for (argvi = argv + 1, i = 1; *argvi; argvi++, i++) { strcpy(p, *argvi); argv[i] = p; p += strlen(*argvi) + 1; } argv[i] = NULL; free (argv[0]); argv[0] = new_argv; } command_line = make_command_line( shell_name, exec_fname, argv); } if ( command_line == NULL ) { pproc->last_err = 0; pproc->lerrno = E_NO_MEM; return(-1); } if (envp) { if (arr2envblk(envp, &envblk, &envsize_needed) == FALSE) { pproc->lerrno = E_NO_MEM; free( command_line ); if ((pproc->last_err == ERROR_INVALID_PARAMETER || pproc->last_err == ERROR_MORE_DATA) && envsize_needed > 32*1024) { fprintf (stderr, "CreateProcess failed, probably because environment is too large (%d bytes).\n", envsize_needed); } pproc->last_err = 0; return(-1); } } if (shell_name || file_not_found || pass_null_exec_path) { exec_path = 0; /* Search for the program in %Path% */ } else { exec_path = exec_fname; } /* * Set up inherited stdin, stdout, stderr for child */ memset(&startInfo, '\0', sizeof(startInfo)); GetStartupInfo(&startInfo); #ifndef KMK startInfo.dwFlags = STARTF_USESTDHANDLES; #endif startInfo.lpReserved = 0; startInfo.cbReserved2 = 0; startInfo.lpReserved2 = 0; #ifndef KMK startInfo.hStdInput = (HANDLE)pproc->sv_stdin[1]; startInfo.hStdOutput = (HANDLE)pproc->sv_stdout[1]; startInfo.hStdError = (HANDLE)pproc->sv_stderr[1]; #else if ( ((HANDLE)pproc->sv_stdin[1] != INVALID_HANDLE_VALUE && pproc->sv_stdin[1]) || ((HANDLE)pproc->sv_stdout[1] != INVALID_HANDLE_VALUE && pproc->sv_stdout[1]) || ((HANDLE)pproc->sv_stderr[1] != INVALID_HANDLE_VALUE && pproc->sv_stderr[1]) ) { startInfo.dwFlags = STARTF_USESTDHANDLES; startInfo.hStdInput = (HANDLE)pproc->sv_stdin[1]; startInfo.hStdOutput = (HANDLE)pproc->sv_stdout[1]; startInfo.hStdError = (HANDLE)pproc->sv_stderr[1]; } else { startInfo.dwFlags = 0; startInfo.hStdInput = 0; startInfo.hStdOutput = 0; startInfo.hStdError = 0; } #endif if (as_user) { free(envblk); return -1; } else { DB (DB_JOBS, ("CreateProcess(%s,%s,...)\n", exec_path ? exec_path : "NULL", command_line ? command_line : "NULL")); #ifdef KMK if (exec_fname[0]) kmk_cache_exec_image(exec_fname); else if (exec_path) kmk_cache_exec_image(exec_path); else if (argv[0]) kmk_cache_exec_image(argv[0]); switch (process_priority) { case 1: flags |= CREATE_SUSPENDED | IDLE_PRIORITY_CLASS; break; case 2: flags |= CREATE_SUSPENDED | BELOW_NORMAL_PRIORITY_CLASS; break; case 3: flags |= CREATE_SUSPENDED | NORMAL_PRIORITY_CLASS; break; case 4: flags |= CREATE_SUSPENDED | HIGH_PRIORITY_CLASS; break; case 5: flags |= CREATE_SUSPENDED | REALTIME_PRIORITY_CLASS; break; } #endif if (CreateProcess( exec_path, command_line, NULL, 0, /* default security attributes for thread */ TRUE, /* inherit handles (e.g. helper pipes, oserv socket) */ flags, envblk, 0, /* default starting directory */ &startInfo, &procInfo) == FALSE) { pproc->last_err = GetLastError(); pproc->lerrno = E_FORK; fprintf(stderr, "process_begin: CreateProcess(%s, %s, ...) failed.\n", exec_path ? exec_path : "NULL", command_line); free(envblk); free( command_line ); return(-1); } #ifdef KMK switch (process_priority) { case 1: SetThreadPriority(procInfo.hThread, THREAD_PRIORITY_IDLE); break; case 2: SetThreadPriority(procInfo.hThread, THREAD_PRIORITY_BELOW_NORMAL); break; case 3: SetThreadPriority(procInfo.hThread, THREAD_PRIORITY_NORMAL); break; case 4: SetThreadPriority(procInfo.hThread, THREAD_PRIORITY_HIGHEST); break; case 5: SetThreadPriority(procInfo.hThread, THREAD_PRIORITY_TIME_CRITICAL); break; } ResumeThread(procInfo.hThread); #endif } pproc->pid = (pid_t)procInfo.hProcess; /* Close the thread handle -- we'll just watch the process */ CloseHandle(procInfo.hThread); /* Close the halves of the pipes we don't need */ if ((HANDLE)pproc->sv_stdin[1] != INVALID_HANDLE_VALUE && pproc->sv_stdin[1]) CloseHandle((HANDLE)pproc->sv_stdin[1]); if ((HANDLE)pproc->sv_stdout[1] != INVALID_HANDLE_VALUE && pproc->sv_stdout[1]) CloseHandle((HANDLE)pproc->sv_stdout[1]); if ((HANDLE)pproc->sv_stderr[1] != INVALID_HANDLE_VALUE && pproc->sv_stderr[1]) CloseHandle((HANDLE)pproc->sv_stderr[1]); pproc->sv_stdin[1] = 0; pproc->sv_stdout[1] = 0; pproc->sv_stderr[1] = 0; free( command_line ); free(envblk); pproc->lerrno=0; return 0; } #if 0 /* unused */ static DWORD proc_stdin_thread(sub_process *pproc) { DWORD in_done; for (;;) { if (WriteFile( (HANDLE) pproc->sv_stdin[0], pproc->inp, pproc->incnt, &in_done, NULL) == FALSE) _endthreadex(0); // This if should never be true for anonymous pipes, but gives // us a chance to change I/O mechanisms later if (in_done < pproc->incnt) { pproc->incnt -= in_done; pproc->inp += in_done; } else { _endthreadex(0); } } return 0; // for compiler warnings only.. not reached } static DWORD proc_stdout_thread(sub_process *pproc) { DWORD bufsize = 1024; char c; DWORD nread; pproc->outp = malloc(bufsize); if (pproc->outp == NULL) _endthreadex(0); pproc->outcnt = 0; for (;;) { if (ReadFile( (HANDLE)pproc->sv_stdout[0], &c, 1, &nread, NULL) == FALSE) { /* map_windows32_error_to_string(GetLastError());*/ _endthreadex(0); } if (nread == 0) _endthreadex(0); if (pproc->outcnt + nread > bufsize) { bufsize += nread + 512; pproc->outp = realloc(pproc->outp, bufsize); if (pproc->outp == NULL) { pproc->outcnt = 0; _endthreadex(0); } } pproc->outp[pproc->outcnt++] = c; } return 0; } static DWORD proc_stderr_thread(sub_process *pproc) { DWORD bufsize = 1024; char c; DWORD nread; pproc->errp = malloc(bufsize); if (pproc->errp == NULL) _endthreadex(0); pproc->errcnt = 0; for (;;) { if (ReadFile( (HANDLE)pproc->sv_stderr[0], &c, 1, &nread, NULL) == FALSE) { map_windows32_error_to_string(GetLastError()); _endthreadex(0); } if (nread == 0) _endthreadex(0); if (pproc->errcnt + nread > bufsize) { bufsize += nread + 512; pproc->errp = realloc(pproc->errp, bufsize); if (pproc->errp == NULL) { pproc->errcnt = 0; _endthreadex(0); } } pproc->errp[pproc->errcnt++] = c; } return 0; } /* * Purpose: collects output from child process and returns results * * Description: * * Returns: * * Notes/Dependencies: */ long process_pipe_io( HANDLE proc, char *stdin_data, int stdin_data_len) { sub_process *pproc = (sub_process *)proc; bool_t stdin_eof = FALSE, stdout_eof = FALSE, stderr_eof = FALSE; HANDLE childhand = (HANDLE) pproc->pid; HANDLE tStdin = NULL, tStdout = NULL, tStderr = NULL; unsigned int dwStdin, dwStdout, dwStderr; HANDLE wait_list[4]; DWORD wait_count; DWORD wait_return; HANDLE ready_hand; bool_t child_dead = FALSE; BOOL GetExitCodeResult; #ifdef KMK assert (pproc->enmType == kRegular); #endif /* * Create stdin thread, if needed */ pproc->inp = stdin_data; pproc->incnt = stdin_data_len; if (!pproc->inp) { stdin_eof = TRUE; CloseHandle((HANDLE)pproc->sv_stdin[0]); pproc->sv_stdin[0] = 0; } else { tStdin = (HANDLE) _beginthreadex( 0, 1024, (unsigned (__stdcall *) (void *))proc_stdin_thread, pproc, 0, &dwStdin); if (tStdin == 0) { pproc->last_err = GetLastError(); pproc->lerrno = E_SCALL; goto done; } } /* * Assume child will produce stdout and stderr */ tStdout = (HANDLE) _beginthreadex( 0, 1024, (unsigned (__stdcall *) (void *))proc_stdout_thread, pproc, 0, &dwStdout); tStderr = (HANDLE) _beginthreadex( 0, 1024, (unsigned (__stdcall *) (void *))proc_stderr_thread, pproc, 0, &dwStderr); if (tStdout == 0 || tStderr == 0) { pproc->last_err = GetLastError(); pproc->lerrno = E_SCALL; goto done; } /* * Wait for all I/O to finish and for the child process to exit */ while (!stdin_eof || !stdout_eof || !stderr_eof || !child_dead) { wait_count = 0; if (!stdin_eof) { wait_list[wait_count++] = tStdin; } if (!stdout_eof) { wait_list[wait_count++] = tStdout; } if (!stderr_eof) { wait_list[wait_count++] = tStderr; } if (!child_dead) { wait_list[wait_count++] = childhand; } wait_return = WaitForMultipleObjects(wait_count, wait_list, FALSE, /* don't wait for all: one ready will do */ child_dead? 1000 :INFINITE); /* after the child dies, subthreads have one second to collect all remaining output */ if (wait_return == WAIT_FAILED) { /* map_windows32_error_to_string(GetLastError());*/ pproc->last_err = GetLastError(); pproc->lerrno = E_SCALL; goto done; } ready_hand = wait_list[wait_return - WAIT_OBJECT_0]; if (ready_hand == tStdin) { CloseHandle((HANDLE)pproc->sv_stdin[0]); pproc->sv_stdin[0] = 0; CloseHandle(tStdin); tStdin = 0; stdin_eof = TRUE; } else if (ready_hand == tStdout) { CloseHandle((HANDLE)pproc->sv_stdout[0]); pproc->sv_stdout[0] = 0; CloseHandle(tStdout); tStdout = 0; stdout_eof = TRUE; } else if (ready_hand == tStderr) { CloseHandle((HANDLE)pproc->sv_stderr[0]); pproc->sv_stderr[0] = 0; CloseHandle(tStderr); tStderr = 0; stderr_eof = TRUE; } else if (ready_hand == childhand) { DWORD ierr; GetExitCodeResult = GetExitCodeProcess(childhand, &ierr); if (ierr == CONTROL_C_EXIT) { pproc->signal = SIGINT; } else { pproc->exit_code = ierr; } if (GetExitCodeResult == FALSE) { pproc->last_err = GetLastError(); pproc->lerrno = E_SCALL; goto done; } child_dead = TRUE; } else { /* ?? Got back a handle we didn't query ?? */ pproc->last_err = 0; pproc->lerrno = E_FAIL; goto done; } } done: if (tStdin != 0) CloseHandle(tStdin); if (tStdout != 0) CloseHandle(tStdout); if (tStderr != 0) CloseHandle(tStderr); if (pproc->lerrno) return(-1); else return(0); } #endif /* unused */ #ifndef KMK /* unused */ /* * Purpose: collects output from child process and returns results * * Description: * * Returns: * * Notes/Dependencies: */ long process_file_io( HANDLE proc) { sub_process *pproc; if (proc == NULL) pproc = process_wait_for_any_private(1, 0); else pproc = (sub_process *)proc; /* some sort of internal error */ if (!pproc) return -1; return process_file_io_private(proc, TRUE); } #endif /* !KMK - unused */ /* private function, avoid some kernel calls. (bird) */ static long process_file_io_private( sub_process *pproc, BOOL fNeedToWait) { HANDLE childhand; DWORD wait_return; BOOL GetExitCodeResult; DWORD ierr; childhand = (HANDLE) pproc->pid; /* * This function is poorly named, and could also be used just to wait * for child death if you're doing your own pipe I/O. If that is * the case, close the pipe handles here. */ if (pproc->sv_stdin[0]) { CloseHandle((HANDLE)pproc->sv_stdin[0]); pproc->sv_stdin[0] = 0; } if (pproc->sv_stdout[0]) { CloseHandle((HANDLE)pproc->sv_stdout[0]); pproc->sv_stdout[0] = 0; } if (pproc->sv_stderr[0]) { CloseHandle((HANDLE)pproc->sv_stderr[0]); pproc->sv_stderr[0] = 0; } #ifdef KMK if (childhand == NULL || childhand == INVALID_HANDLE_VALUE) { goto done2; } #endif /* * Wait for the child process to exit */ if (fNeedToWait) { /* bird */ wait_return = WaitForSingleObject(childhand, INFINITE); if (wait_return != WAIT_OBJECT_0) { /* map_windows32_error_to_string(GetLastError());*/ pproc->last_err = GetLastError(); pproc->lerrno = E_SCALL; goto done2; } } /* bird */ GetExitCodeResult = GetExitCodeProcess(childhand, &ierr); if (ierr == CONTROL_C_EXIT) { pproc->signal = SIGINT; } else { pproc->exit_code = ierr; } if (GetExitCodeResult == FALSE) { pproc->last_err = GetLastError(); pproc->lerrno = E_SCALL; } done2: if (pproc->lerrno) return(-1); else return(0); } /* * Description: Clean up any leftover handles, etc. It is up to the * caller to manage and free the input, output, and stderr buffers. */ void process_cleanup( HANDLE proc) { sub_process *pproc = (sub_process *)proc; int i; #ifdef KMK if (pproc->enmType == kRegular) { #endif if (pproc->using_pipes) { for (i= 0; i <= 1; i++) { if ((HANDLE)pproc->sv_stdin[i] && (HANDLE)pproc->sv_stdin[i] != INVALID_HANDLE_VALUE) CloseHandle((HANDLE)pproc->sv_stdin[i]); if ((HANDLE)pproc->sv_stdout[i] && (HANDLE)pproc->sv_stdout[i] != INVALID_HANDLE_VALUE) CloseHandle((HANDLE)pproc->sv_stdout[i]); if ((HANDLE)pproc->sv_stderr[i] && (HANDLE)pproc->sv_stderr[i] != INVALID_HANDLE_VALUE) CloseHandle((HANDLE)pproc->sv_stderr[i]); } } if ((HANDLE)pproc->pid) CloseHandle((HANDLE)pproc->pid); #ifdef KMK } else if (pproc->enmType == kSubmit) { kSubmitSubProcCleanup(pproc->clue); } else { assert(0); return; } pproc->enmType = kSubProcFreed; #endif free(pproc); } /* * Description: * Create a command line buffer to pass to CreateProcess * * Returns: the buffer or NULL for failure * Shell case: sh_name a:/full/path/to/script argv[1] argv[2] ... * Otherwise: argv[0] argv[1] argv[2] ... * * Notes/Dependencies: * CreateProcess does not take an argv, so this command creates a * command line for the executable. */ static char * make_command_line( char *shell_name, char *full_exec_path, char **argv) { int argc = 0; char** argvi; int* enclose_in_quotes = NULL; int* enclose_in_quotes_i; unsigned int bytes_required = 0; char* command_line; char* command_line_i; int cygwin_mode = 0; /* HAVE_CYGWIN_SHELL */ int have_sh = 0; /* HAVE_CYGWIN_SHELL */ #undef HAVE_CYGWIN_SHELL /* bird: paranoia */ #ifdef HAVE_CYGWIN_SHELL have_sh = (shell_name != NULL || strstr(full_exec_path, "sh.exe")); cygwin_mode = 1; #endif if (shell_name && full_exec_path) { bytes_required = strlen(shell_name) + 1 + strlen(full_exec_path); /* * Skip argv[0] if any, when shell_name is given. * The special case of "-c" in full_exec_path means * argv[0] is not the shell name, but the command string * to pass to the shell. */ if (*argv && strcmp(full_exec_path, "-c")) argv++; /* * Add one for the intervening space. */ if (*argv) bytes_required++; } argvi = argv; while (*(argvi++)) argc++; if (argc) { enclose_in_quotes = (int*) calloc(1, argc * sizeof(int)); if (!enclose_in_quotes) { return NULL; } } /* We have to make one pass through each argv[i] to see if we need * to enclose it in ", so we might as well figure out how much * memory we'll need on the same pass. */ argvi = argv; enclose_in_quotes_i = enclose_in_quotes; while(*argvi) { char* p = *argvi; unsigned int backslash_count = 0; /* * We have to enclose empty arguments in ". */ if (!(*p)) *enclose_in_quotes_i = 1; while(*p) { switch (*p) { case '\"': /* * We have to insert a backslash for each " * and each \ that precedes the ". */ bytes_required += (backslash_count + 1); backslash_count = 0; break; #if !defined(HAVE_MKS_SHELL) && !defined(HAVE_CYGWIN_SHELL) case '\\': backslash_count++; break; #endif /* * At one time we set *enclose_in_quotes_i for '*' or '?' to suppress * wildcard expansion in programs linked with MSVC's SETARGV.OBJ so * that argv in always equals argv out. This was removed. Say you have * such a program named glob.exe. You enter * glob '*' * at the sh command prompt. Obviously the intent is to make glob do the * wildcarding instead of sh. If we set *enclose_in_quotes_i for '*' or '?', * then the command line that glob would see would be * glob "*" * and the _setargv in SETARGV.OBJ would _not_ expand the *. */ case ' ': case '\t': *enclose_in_quotes_i = 1; /* fall through */ default: backslash_count = 0; break; } /* * Add one for each character in argv[i]. */ bytes_required++; p++; } if (*enclose_in_quotes_i) { /* * Add one for each enclosing ", * and one for each \ that precedes the * closing ". */ bytes_required += (backslash_count + 2); } /* * Add one for the intervening space. */ if (*(++argvi)) bytes_required++; enclose_in_quotes_i++; } /* * Add one for the terminating NULL. */ bytes_required++; #ifdef KMK /* for the space before the final " in case we need it. */ bytes_required++; #endif command_line = (char*) malloc(bytes_required); if (!command_line) { free(enclose_in_quotes); return NULL; } command_line_i = command_line; if (shell_name && full_exec_path) { while(*shell_name) { *(command_line_i++) = *(shell_name++); } *(command_line_i++) = ' '; while(*full_exec_path) { *(command_line_i++) = *(full_exec_path++); } if (*argv) { *(command_line_i++) = ' '; } } argvi = argv; enclose_in_quotes_i = enclose_in_quotes; while(*argvi) { char* p = *argvi; unsigned int backslash_count = 0; if (*enclose_in_quotes_i) { *(command_line_i++) = '\"'; } while(*p) { if (*p == '\"') { if (cygwin_mode && have_sh) { /* HAVE_CYGWIN_SHELL */ /* instead of a \", cygwin likes "" */ *(command_line_i++) = '\"'; } else { /* * We have to insert a backslash for the " * and each \ that precedes the ". */ backslash_count++; while(backslash_count) { *(command_line_i++) = '\\'; backslash_count--; }; } #if !defined(HAVE_MKS_SHELL) && !defined(HAVE_CYGWIN_SHELL) } else if (*p == '\\') { backslash_count++; } else { backslash_count = 0; #endif } /* * Copy the character. */ *(command_line_i++) = *(p++); } if (*enclose_in_quotes_i) { #if !defined(HAVE_MKS_SHELL) && !defined(HAVE_CYGWIN_SHELL) /* * Add one \ for each \ that precedes the * closing ". */ while(backslash_count--) { *(command_line_i++) = '\\'; }; #endif #ifdef KMK /* * ash it put off by echo "hello world" ending up as: * G:/.../kmk_ash.exe -c "echo ""hello world""" * It wants a space before the last '"'. * (The 'test_shell' goals in Makefile.kmk tests this problem.) */ if (command_line_i[-1] == '\"' /* && cygwin_mode && have_sh*/ && !argvi[1]) { *(command_line_i++) = ' '; } #endif *(command_line_i++) = '\"'; } /* * Append an intervening space. */ if (*(++argvi)) { *(command_line_i++) = ' '; } enclose_in_quotes_i++; } /* * Append the terminating NULL. */ *command_line_i = '\0'; free(enclose_in_quotes); return command_line; } /* * Description: Given an argv and optional envp, launch the process * using the default stdin, stdout, and stderr handles. * Also, register process so that process_wait_for_any_private() * can be used via process_file_io(NULL) or * process_wait_for_any(). * * Returns: * * Notes/Dependencies: */ HANDLE process_easy( char **argv, char **envp, int outfd, int errfd) { HANDLE hIn = INVALID_HANDLE_VALUE; HANDLE hOut = INVALID_HANDLE_VALUE; HANDLE hErr = INVALID_HANDLE_VALUE; HANDLE hProcess, tmpIn, tmpOut, tmpErr; DWORD e; if (proc_index >= MAXIMUM_WAIT_OBJECTS) { DB (DB_JOBS, ("process_easy: All process slots used up\n")); return INVALID_HANDLE_VALUE; } #ifdef KMK /* We can effort here by lettering CreateProcess/kernel do the standard handle duplication. */ if (outfd != -1 || errfd != -1) { #endif /* Standard handles returned by GetStdHandle can be NULL or INVALID_HANDLE_VALUE if the parent process closed them. If that happens, we open the null device and pass its handle to CreateProcess as the corresponding handle to inherit. */ tmpIn = GetStdHandle(STD_INPUT_HANDLE); if (DuplicateHandle(GetCurrentProcess(), tmpIn, GetCurrentProcess(), &hIn, 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE) { if ((e = GetLastError()) == ERROR_INVALID_HANDLE) { tmpIn = CreateFile("NUL", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (tmpIn != INVALID_HANDLE_VALUE && DuplicateHandle(GetCurrentProcess(), tmpIn, GetCurrentProcess(), &hIn, 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE) CloseHandle(tmpIn); } if (hIn == INVALID_HANDLE_VALUE) { fprintf(stderr, "process_easy: DuplicateHandle(In) failed (e=%ld)\n", e); return INVALID_HANDLE_VALUE; } } if (outfd >= 0) tmpOut = (HANDLE)_get_osfhandle (outfd); else tmpOut = GetStdHandle (STD_OUTPUT_HANDLE); if (DuplicateHandle(GetCurrentProcess(), tmpOut, GetCurrentProcess(), &hOut, 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE) { if ((e = GetLastError()) == ERROR_INVALID_HANDLE) { tmpOut = CreateFile("NUL", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (tmpOut != INVALID_HANDLE_VALUE && DuplicateHandle(GetCurrentProcess(), tmpOut, GetCurrentProcess(), &hOut, 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE) CloseHandle(tmpOut); } if (hOut == INVALID_HANDLE_VALUE) { fprintf(stderr, "process_easy: DuplicateHandle(Out) failed (e=%ld)\n", e); return INVALID_HANDLE_VALUE; } } if (errfd >= 0) tmpErr = (HANDLE)_get_osfhandle (errfd); else tmpErr = GetStdHandle(STD_ERROR_HANDLE); if (DuplicateHandle(GetCurrentProcess(), tmpErr, GetCurrentProcess(), &hErr, 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE) { if ((e = GetLastError()) == ERROR_INVALID_HANDLE) { tmpErr = CreateFile("NUL", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (tmpErr != INVALID_HANDLE_VALUE && DuplicateHandle(GetCurrentProcess(), tmpErr, GetCurrentProcess(), &hErr, 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE) CloseHandle(tmpErr); } if (hErr == INVALID_HANDLE_VALUE) { fprintf(stderr, "process_easy: DuplicateHandle(Err) failed (e=%ld)\n", e); return INVALID_HANDLE_VALUE; } } #ifdef KMK /* saving effort */ } #endif hProcess = process_init_fd(hIn, hOut, hErr); if (process_begin(hProcess, argv, envp, argv[0], NULL)) { fake_exits_pending++; /* process_begin() failed: make a note of that. */ if (!((sub_process*) hProcess)->last_err) ((sub_process*) hProcess)->last_err = -1; #ifdef KMK if (!((sub_process*) hProcess)->exit_code) #endif ((sub_process*) hProcess)->exit_code = process_last_err(hProcess); /* close up unused handles */ if (hIn != INVALID_HANDLE_VALUE) CloseHandle(hIn); if (hOut != INVALID_HANDLE_VALUE) CloseHandle(hOut); if (hErr != INVALID_HANDLE_VALUE) CloseHandle(hErr); } process_register(hProcess); return hProcess; } kbuild-3149/src/kmk/w32/w32os.c0000644000175000017500000001247013252530203016010 0ustar locutuslocutus/* Windows32-based operating system interface for GNU Make. Copyright (C) 2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" #include #include #include #include #include #include "pathstuff.h" #include "sub_proc.h" #include "w32err.h" #include "os.h" #include "debug.h" /* This section provides OS-specific functions to support the jobserver. */ static char jobserver_semaphore_name[MAX_PATH + 1]; static HANDLE jobserver_semaphore = NULL; unsigned int jobserver_setup (int slots) { /* sub_proc.c cannot wait for more than MAXIMUM_WAIT_OBJECTS objects * and one of them is the job-server semaphore object. Limit the * number of available job slots to (MAXIMUM_WAIT_OBJECTS - 1). */ if (slots >= MAXIMUM_WAIT_OBJECTS) { slots = MAXIMUM_WAIT_OBJECTS - 1; DB (DB_JOBS, (_("Jobserver slots limited to %d\n"), slots)); } sprintf (jobserver_semaphore_name, "gmake_semaphore_%d", _getpid ()); jobserver_semaphore = CreateSemaphore ( NULL, /* Use default security descriptor */ slots, /* Initial count */ slots, /* Maximum count */ jobserver_semaphore_name); /* Semaphore name */ if (jobserver_semaphore == NULL) { DWORD err = GetLastError (); const char *estr = map_windows32_error_to_string (err); ONS (fatal, NILF, _("creating jobserver semaphore: (Error %ld: %s)"), err, estr); } return 1; } unsigned int jobserver_parse_auth (const char *auth) { jobserver_semaphore = OpenSemaphore ( SEMAPHORE_ALL_ACCESS, /* Semaphore access setting */ FALSE, /* Child processes DON'T inherit */ auth); /* Semaphore name */ if (jobserver_semaphore == NULL) { DWORD err = GetLastError (); const char *estr = map_windows32_error_to_string (err); fatal (NILF, strlen (auth) + INTSTR_LENGTH + strlen (estr), _("internal error: unable to open jobserver semaphore '%s': (Error %ld: %s)"), auth, err, estr); } DB (DB_JOBS, (_("Jobserver client (semaphore %s)\n"), auth)); return 1; } char * jobserver_get_auth () { return xstrdup (jobserver_semaphore_name); } unsigned int jobserver_enabled () { return jobserver_semaphore != NULL; } /* Close jobserver semaphore */ void jobserver_clear () { if (jobserver_semaphore != NULL) { CloseHandle (jobserver_semaphore); jobserver_semaphore = NULL; } } void jobserver_release (int is_fatal) { if (! ReleaseSemaphore ( jobserver_semaphore, /* handle to semaphore */ 1, /* increase count by one */ NULL)) /* not interested in previous count */ { if (is_fatal) { DWORD err = GetLastError (); const char *estr = map_windows32_error_to_string (err); ONS (fatal, NILF, _("release jobserver semaphore: (Error %ld: %s)"), err, estr); } perror_with_name ("release_jobserver_semaphore", ""); } } unsigned int jobserver_acquire_all () { unsigned int tokens = 0; while (1) { DWORD dwEvent = WaitForSingleObject ( jobserver_semaphore, /* Handle to semaphore */ 0); /* DON'T wait on semaphore */ if (dwEvent != WAIT_OBJECT_0) return tokens; ++tokens; } } void jobserver_signal () { } void jobserver_pre_child (int recursive) { } void jobserver_post_child (int recursive) { } void jobserver_pre_acquire () { } /* Returns 1 if we got a token, or 0 if a child has completed. The Windows implementation doesn't support load detection. */ unsigned int jobserver_acquire (int timeout) { HANDLE handles[MAXIMUM_WAIT_OBJECTS + 1]; /* bird: + 1 to prevent trashing the stack. */ DWORD dwHandleCount; DWORD dwEvent; /* Add jobserver semaphore to first slot. */ handles[0] = jobserver_semaphore; /* Build array of handles to wait for. */ dwHandleCount = 1 + process_set_handles (&handles[1]); dwEvent = WaitForMultipleObjects ( dwHandleCount, /* number of objects in array */ handles, /* array of objects */ FALSE, /* wait for any object */ INFINITE); /* wait until object is signalled */ if (dwEvent == WAIT_FAILED) { DWORD err = GetLastError (); const char *estr = map_windows32_error_to_string (err); ONS (fatal, NILF, _("semaphore or child process wait: (Error %ld: %s)"), err, estr); } /* WAIT_OBJECT_0 indicates that the semaphore was signalled. */ return dwEvent == WAIT_OBJECT_0; } kbuild-3149/src/kmk/w32/imagecache.c0000644000175000017500000001126613252530203017103 0ustar locutuslocutus/* $Id: imagecache.c 3140 2018-03-14 21:28:10Z bird $ */ /** @file * kBuild specific executable image cache for Windows. */ /* * Copyright (c) 2012 knut st. osmundsen * * This file is part of kBuild. * * kBuild 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. * * kBuild 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 kBuild. If not, see * */ /* No GNU coding style here! */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "makeint.h" #include /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ typedef struct EXECCACHEENTRY { /** The name hash value. */ unsigned uHash; /** The name length. */ unsigned cchName; /** Pointer to the next name with the same hash. */ struct EXECCACHEENTRY *pNext; /** When it was last referenced. */ unsigned uLastRef; /** The module handle. */ HMODULE hmod1; /** The module handle. */ HMODULE hmod2; /** The executable path. */ char szName[1]; } EXECCACHEENTRY; typedef EXECCACHEENTRY *PEXECCACHEENTRY; /******************************************************************************* * Global Variables * *******************************************************************************/ /** The number of cached images. */ static unsigned g_cCached; /** Used noting when entries was last used. * Increased on each kmk_cache_exec_image call. */ static unsigned g_uNow; /** The size of the hash table. */ #define EXECCACHE_HASHTAB_SIZE 128 /** The hash table. */ static PEXECCACHEENTRY g_apHashTab[EXECCACHE_HASHTAB_SIZE]; /* sdbm: This algorithm was created for sdbm (a public-domain reimplementation of ndbm) database library. it was found to do well in scrambling bits, causing better distribution of the keys and fewer splits. it also happens to be a good general hashing function with good distribution. the actual function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below is the faster version used in gawk. [there is even a faster, duff-device version] the magic constant 65599 was picked out of thin air while experimenting with different constants, and turns out to be a prime. this is one of the algorithms used in berkeley db (see sleepycat) and elsewhere. */ static unsigned execcache_calc_hash(const char *psz, unsigned *pcch) { unsigned char *puch = (unsigned char *)psz; unsigned hash = 0; int ch; while ((ch = *puch++)) hash = ch + (hash << 6) + (hash << 16) - hash; *pcch = (unsigned)(puch - psz - 1); return hash; } extern void kmk_cache_exec_image(const char *pszExec) { /* * Lookup the name. */ unsigned cchName; const unsigned uHash = execcache_calc_hash(pszExec, &cchName); PEXECCACHEENTRY *ppCur = &g_apHashTab[uHash % EXECCACHE_HASHTAB_SIZE]; PEXECCACHEENTRY pCur = *ppCur; while (pCur) { if ( pCur->uHash == uHash && pCur->cchName == cchName && !memcmp(pCur->szName, pszExec, cchName)) { pCur->uLastRef = ++g_uNow; return; } ppCur = &pCur->pNext; pCur = pCur->pNext; } /* * Not found, create a new entry. */ pCur = xmalloc(sizeof(*pCur) + cchName); pCur->uHash = uHash; pCur->cchName = cchName; pCur->pNext = NULL; pCur->uLastRef = ++g_uNow; memcpy(pCur->szName, pszExec, cchName + 1); pCur->hmod1 = LoadLibraryEx(pszExec, NULL, LOAD_LIBRARY_AS_DATAFILE); if (pCur->hmod1 != NULL) pCur->hmod2 = LoadLibraryEx(pszExec, NULL, DONT_RESOLVE_DLL_REFERENCES); else pCur->hmod2 = NULL; *ppCur = pCur; g_cCached++; } kbuild-3149/src/kmk/w32/Makefile.am0000644000175000017500000000204113252530203016714 0ustar locutuslocutus# Makefile.am to create libw32.a for mingw32 host. # Copyright (C) 1997-2016 Free Software Foundation, Inc. # This file is part of GNU Make. # # GNU Make 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. # # GNU Make 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 . AUTOMAKE_OPTIONS = subdir-objects noinst_LIBRARIES = libw32.a libw32_a_SOURCES = subproc/misc.c subproc/sub_proc.c subproc/w32err.c \ compat/posixfcn.c pathstuff.c w32os.c libw32_a_CPPFLAGS = -I$(srcdir)/include -I$(srcdir)/subproc -I$(top_srcdir) \ -I$(top_srcdir)/glob kbuild-3149/src/kmk/w32/pathstuff.c0000644000175000017500000002114213252530203017033 0ustar locutuslocutus/* Path conversion for Windows pathnames. Copyright (C) 1996-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" #include #include #include "pathstuff.h" #if 1 /* bird */ # include "nt_fullpath.h" #endif /* * Convert delimiter separated vpath to Canonical format. */ char * convert_vpath_to_windows32(char *Path, char to_delim) { char *etok; /* token separator for old Path */ /* * Convert all spaces to delimiters. Note that pathnames which * contain blanks get trounced here. Use 8.3 format as a workaround. */ for (etok = Path; etok && *etok; etok++) if (ISBLANK ((unsigned char) *etok)) *etok = to_delim; return (convert_Path_to_windows32(Path, to_delim)); } /* * Convert delimiter separated path to Canonical format. */ char * convert_Path_to_windows32(char *Path, char to_delim) { char *etok; /* token separator for old Path */ char *p; /* points to element of old Path */ /* is this a multi-element Path ? */ /* FIXME: Perhaps use ":;\"" in strpbrk to convert all quotes to delimiters as well, as a way to handle quoted directories in PATH? */ for (p = Path, etok = strpbrk(p, ":;"); etok; etok = strpbrk(p, ":;")) if ((etok - p) == 1) { if (*(etok - 1) == ';' || *(etok - 1) == ':') { etok[-1] = to_delim; etok[0] = to_delim; p = ++etok; continue; /* ignore empty bucket */ } else if (!isalpha ((unsigned char) *p)) { /* found one to count, handle things like '.' */ *etok = to_delim; p = ++etok; } else if ((*etok == ':') && (etok = strpbrk(etok+1, ":;"))) { /* found one to count, handle drive letter */ *etok = to_delim; p = ++etok; } else /* all finished, force abort */ p += strlen(p); } else if (*p == '"') { /* a quoted directory */ for (p++; *p && *p != '"'; p++) /* skip quoted part */ ; etok = strpbrk(p, ":;"); /* find next delimiter */ if (etok) { *etok = to_delim; p = ++etok; } else p += strlen(p); } else { /* found another one, no drive letter */ *etok = to_delim; p = ++etok; } return Path; } /* * Convert to forward slashes. Resolve to full pathname optionally */ char * w32ify(const char *filename, int resolve) { static char w32_path[FILENAME_MAX]; char *p; #if 1 /* bird */ if (resolve) { nt_fullpath_cached(filename, w32_path, sizeof(w32_path)); } else { w32_path[0] = '\0'; strncat(w32_path, filename, sizeof(w32_path)); } #else /* !bird */ if (resolve) { _fullpath(w32_path, filename, sizeof (w32_path)); } else strncpy(w32_path, filename, sizeof (w32_path)); #endif /* !bird */ for (p = w32_path; p && *p; p++) if (*p == '\\') *p = '/'; return w32_path; } char * getcwd_fs(char* buf, int len) { char *p = getcwd(buf, len); if (p) { char *q = w32ify(buf, 0); #if 1 /* bird - UPSTREAM? */ buf[0] = '\0'; strncat(buf, q, len); #else /* !bird */ strncpy(buf, q, len); #endif } return p; } #ifdef unused /* * Convert delimiter separated pathnames (e.g. PATH) or single file pathname * (e.g. c:/foo, c:\bar) to NutC format. If we are handed a string that * _NutPathToNutc() fails to convert, just return the path we were handed * and assume the caller will know what to do with it (It was probably * a mistake to try and convert it anyway due to some of the bizarre things * that might look like pathnames in makefiles). */ char * convert_path_to_nutc(char *path) { int count; /* count of path elements */ char *nutc_path; /* new NutC path */ int nutc_path_len; /* length of buffer to allocate for new path */ char *pathp; /* pointer to nutc_path used to build it */ char *etok; /* token separator for old path */ char *p; /* points to element of old path */ char sep; /* what flavor of separator used in old path */ char *rval; /* is this a multi-element path ? */ for (p = path, etok = strpbrk(p, ":;"), count = 0; etok; etok = strpbrk(p, ":;")) if ((etok - p) == 1) { if (*(etok - 1) == ';' || *(etok - 1) == ':') { p = ++etok; continue; /* ignore empty bucket */ } else if (etok = strpbrk(etok+1, ":;")) /* found one to count, handle drive letter */ p = ++etok, count++; else /* all finished, force abort */ p += strlen(p); } else /* found another one, no drive letter */ p = ++etok, count++; if (count) { count++; /* x1;x2;x3 <- need to count x3 */ /* * Hazard a guess on how big the buffer needs to be. * We have to convert things like c:/foo to /c=/foo. */ nutc_path_len = strlen(path) + (count*2) + 1; nutc_path = xmalloc(nutc_path_len); pathp = nutc_path; *pathp = '\0'; /* * Loop through PATH and convert one elemnt of the path at at * a time. Single file pathnames will fail this and fall * to the logic below loop. */ for (p = path, etok = strpbrk(p, ":;"); etok; etok = strpbrk(p, ":;")) { /* don't trip up on device specifiers or empty path slots */ if ((etok - p) == 1) if (*(etok - 1) == ';' || *(etok - 1) == ':') { p = ++etok; continue; } else if ((etok = strpbrk(etok+1, ":;")) == NULL) break; /* thing found was a WINDOWS32 pathname */ /* save separator */ sep = *etok; /* terminate the current path element -- temporarily */ *etok = '\0'; #ifdef __NUTC__ /* convert to NutC format */ if (_NutPathToNutc(p, pathp, 0) == FALSE) { free(nutc_path); rval = savestring(path, strlen(path)); return rval; } #else *pathp++ = '/'; *pathp++ = p[0]; *pathp++ = '='; *pathp++ = '/'; strcpy(pathp, &p[2]); #endif pathp += strlen(pathp); *pathp++ = ':'; /* use Unix style path separtor for new path */ *pathp = '\0'; /* make sure we are null terminaed */ /* restore path separator */ *etok = sep; /* point p to first char of next path element */ p = ++etok; } } else { nutc_path_len = strlen(path) + 3; nutc_path = xmalloc(nutc_path_len); pathp = nutc_path; *pathp = '\0'; p = path; } /* * OK, here we handle the last element in PATH (e.g. c of a;b;c) * or the path was a single filename and will be converted * here. Note, testing p here assures that we don't trip up * on paths like a;b; which have trailing delimiter followed by * nothing. */ if (*p != '\0') { #ifdef __NUTC__ if (_NutPathToNutc(p, pathp, 0) == FALSE) { free(nutc_path); rval = savestring(path, strlen(path)); return rval; } #else *pathp++ = '/'; *pathp++ = p[0]; *pathp++ = '='; *pathp++ = '/'; strcpy(pathp, &p[2]); #endif } else *(pathp-1) = '\0'; /* we're already done, don't leave trailing : */ rval = savestring(nutc_path, strlen(nutc_path)); free(nutc_path); return rval; } #endif kbuild-3149/src/kmk/w32/include/0000755000175000017500000000000013252530203016306 5ustar locutuslocutuskbuild-3149/src/kmk/w32/include/sub_proc.h0000644000175000017500000000511113252530203020271 0ustar locutuslocutus/* Definitions for Windows process invocation. Copyright (C) 1996-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make 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 . */ #ifndef SUB_PROC_H #define SUB_PROC_H /* * Component Name: * * $Date$ * * $Source$ * * $Id$ */ #define EXTERN_DECL(entry, args) extern entry args #define VOID_DECL void EXTERN_DECL(HANDLE process_init, (VOID_DECL)); EXTERN_DECL(HANDLE process_init_fd, (HANDLE stdinh, HANDLE stdouth, HANDLE stderrh)); EXTERN_DECL(long process_begin, (HANDLE proc, char **argv, char **envp, char *exec_path, char *as_user)); EXTERN_DECL(long process_pipe_io, (HANDLE proc, char *stdin_data, int stdin_data_len)); #ifndef KMK /* unused */ EXTERN_DECL(long process_file_io, (HANDLE proc)); #endif EXTERN_DECL(void process_cleanup, (HANDLE proc)); EXTERN_DECL(HANDLE process_wait_for_any, (int block, DWORD* pdwWaitStatus)); EXTERN_DECL(void process_register, (HANDLE proc)); EXTERN_DECL(HANDLE process_easy, (char** argv, char** env, int outfd, int errfd)); EXTERN_DECL(BOOL process_kill, (HANDLE proc, int signal)); EXTERN_DECL(int process_used_slots, (VOID_DECL)); EXTERN_DECL(DWORD process_set_handles, (HANDLE *handles)); #ifdef KMK EXTERN_DECL(int process_kmk_register_submit, (HANDLE hEvent, intptr_t clue, pid_t *pPid)); EXTERN_DECL(int process_kmk_register_redirect, (HANDLE hProcess, pid_t *pPid)); #endif /* support routines */ EXTERN_DECL(long process_errno, (HANDLE proc)); EXTERN_DECL(long process_last_err, (HANDLE proc)); EXTERN_DECL(long process_exit_code, (HANDLE proc)); EXTERN_DECL(long process_signal, (HANDLE proc)); EXTERN_DECL(char * process_outbuf, (HANDLE proc)); EXTERN_DECL(char * process_errbuf, (HANDLE proc)); EXTERN_DECL(int process_outcnt, (HANDLE proc)); EXTERN_DECL(int process_errcnt, (HANDLE proc)); EXTERN_DECL(void process_pipes, (HANDLE proc, int pipes[3])); EXTERN_DECL(void process_noinherit, (int fildes)); #endif kbuild-3149/src/kmk/w32/include/dirent.h0000644000175000017500000000312413252530203017744 0ustar locutuslocutus/* Windows version of dirent.h Copyright (C) 1996-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make 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 . */ #ifndef _DIRENT_H #define _DIRENT_H #ifdef KMK # include # include "nt/ntdir.h" #else /* !KMK */ #ifdef __MINGW32__ # include # include_next #else #include #include #include #include #ifndef NAME_MAX #define NAME_MAX 255 #endif #define __DIRENT_COOKIE 0xfefeabab struct dirent { ino_t d_ino; /* unused - no equivalent on WINDOWS32 */ char d_name[NAME_MAX+1]; }; typedef struct dir_struct { ULONG dir_ulCookie; HANDLE dir_hDirHandle; DWORD dir_nNumFiles; char dir_pDirectoryName[NAME_MAX+1]; struct dirent dir_sdReturn; } DIR; DIR *opendir(const char *); struct dirent *readdir(DIR *); void rewinddir(DIR *); void closedir(DIR *); int telldir(DIR *); void seekdir(DIR *, long); #endif /* !__MINGW32__ */ #endif /* !KMK */ #endif kbuild-3149/src/kmk/w32/include/dlfcn.h0000644000175000017500000000176013252530203017551 0ustar locutuslocutus/* dlfcn.h replacement for MS-Windows build. Copyright (C) 2013-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make 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 . */ #ifndef DLFCN_H #define DLFCN_H #define RTLD_LAZY 1 #define RTLD_NOW 2 #define RTLD_GLOBAL 4 extern void *dlopen (const char *, int); extern void *dlsym (void *, const char *); extern char *dlerror (void); extern int dlclose (void *); #endif /* DLFCN_H */ kbuild-3149/src/kmk/w32/include/w32err.h0000644000175000017500000000166313252530203017611 0ustar locutuslocutus/* Definitions for Windows error handling. Copyright (C) 1996-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make 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 . */ #ifndef _W32ERR_H_ #define _W32ERR_H_ #ifndef EXTERN_DECL #define EXTERN_DECL(entry, args) entry args #endif EXTERN_DECL(const char * map_windows32_error_to_string, (DWORD error)); #endif /* !_W32ERR_H */ kbuild-3149/src/kmk/w32/include/pathstuff.h0000644000175000017500000000175013252530203020466 0ustar locutuslocutus/* Definitions for Windows path manipulation. Copyright (C) 1996-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make 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 . */ #ifndef _PATHSTUFF_H #define _PATHSTUFF_H char *convert_Path_to_windows32(char *Path, char to_delim); char *convert_vpath_to_windows32(char *Path, char to_delim); char *w32ify(const char *filename, int resolve); char *getcwd_fs(char *buf, int len); #endif kbuild-3149/src/kmk/w32/tstFileInfo.c0000644000175000017500000001167613252530203017270 0ustar locutuslocutus/* $Id: $ */ /** @file * Test program for some NtQueryInformationFile functionality. */ /* * Copyright (c) 2007-2010 knut st. osmundsen * * This file is part of kBuild. * * kBuild 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. * * kBuild 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 kBuild. If not, see * */ #include #include typedef enum _FILE_INFORMATION_CLASS { FileDirectoryInformation = 1, FileFullDirectoryInformation, // 2 FileBothDirectoryInformation, // 3 FileBasicInformation, // 4 wdm FileStandardInformation, // 5 wdm FileInternalInformation, // 6 FileEaInformation, // 7 FileAccessInformation, // 8 FileNameInformation, // 9 FileRenameInformation, // 10 FileLinkInformation, // 11 FileNamesInformation, // 12 FileDispositionInformation, // 13 FilePositionInformation, // 14 wdm FileFullEaInformation, // 15 FileModeInformation, // 16 FileAlignmentInformation, // 17 FileAllInformation, // 18 FileAllocationInformation, // 19 FileEndOfFileInformation, // 20 wdm FileAlternateNameInformation, // 21 FileStreamInformation, // 22 FilePipeInformation, // 23 FilePipeLocalInformation, // 24 FilePipeRemoteInformation, // 25 FileMailslotQueryInformation, // 26 FileMailslotSetInformation, // 27 FileCompressionInformation, // 28 FileObjectIdInformation, // 29 FileCompletionInformation, // 30 FileMoveClusterInformation, // 31 FileQuotaInformation, // 32 FileReparsePointInformation, // 33 FileNetworkOpenInformation, // 34 FileAttributeTagInformation, // 35 FileTrackingInformation, // 36 FileIdBothDirectoryInformation, // 37 FileIdFullDirectoryInformation, // 38 FileMaximumInformation } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; typedef struct _FILE_NAME_INFORMATION { ULONG FileNameLength; WCHAR FileName[1]; } FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION; typedef LONG NTSTATUS; typedef struct _IO_STATUS_BLOCK { union { NTSTATUS Status; PVOID Pointer; }; ULONG_PTR Information; } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; NTSYSAPI NTSTATUS NTAPI NtQueryInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass); int main(int argc, char **argv) { int rc = 0; int i; NTSTATUS (NTAPI *pfnNtQueryInformationFile)(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass); pfnNtQueryInformationFile = GetProcAddress(LoadLibrary("ntdll.dll"), "NtQueryInformationFile"); for (i = 1; i < argc; i++) { HANDLE hFile = CreateFile(argv[i], GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (hFile) { long rcNt; char abBuf[4096]; IO_STATUS_BLOCK Ios; memset(abBuf, 0, sizeof(abBuf)); memset(&Ios, 0, sizeof(Ios)); rcNt = pfnNtQueryInformationFile(hFile, &Ios, abBuf, sizeof(abBuf), FileNameInformation); if (rcNt >= 0) { PFILE_NAME_INFORMATION pFileNameInfo = (PFILE_NAME_INFORMATION)abBuf; printf("#%d: %s - rcNt=%#x - FileNameInformation:\n" " FileName: %ls\n" " FileNameLength: %lu\n", i, argv[i], rcNt, pFileNameInfo->FileName, pFileNameInfo->FileNameLength ); } else printf("#%d: %s - rcNt=%#x - FileNameInformation!\n", i, argv[i], rcNt); CloseHandle(hFile); } else { printf("#%d: %s - open failed, last error %d\n", i, argv[i], GetLastError()); rc = 1; } } return rc; } kbuild-3149/src/kmk/w32/Makefile.kup0000644000175000017500000000000013252530203017107 0ustar locutuslocutuskbuild-3149/src/kmk/w32/compat/0000755000175000017500000000000013252530203016146 5ustar locutuslocutuskbuild-3149/src/kmk/w32/compat/posixfcn.c0000644000175000017500000003347613252530203020160 0ustar locutuslocutus/* Replacements for Posix functions and Posix functionality for MS-Windows. Copyright (C) 2013-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include "dlfcn.h" #include "makeint.h" #include "job.h" #ifndef NO_OUTPUT_SYNC /* Support for OUTPUT_SYNC and related functionality. */ /* Emulation of fcntl that supports only F_GETFD and F_SETLKW. */ int fcntl (intptr_t fd, int cmd, ...) { va_list ap; va_start (ap, cmd); switch (cmd) { case F_GETFD: va_end (ap); /* Could have used GetHandleInformation, but that isn't supported on Windows 9X. */ if (_get_osfhandle (fd) == -1) return -1; return 0; case F_SETLKW: { void *buf = va_arg (ap, void *); struct flock *fl = (struct flock *)buf; HANDLE hmutex = (HANDLE)fd; static struct flock last_fl; short last_type = last_fl.l_type; va_end (ap); if (hmutex == INVALID_HANDLE_VALUE || !hmutex) return -1; last_fl = *fl; switch (fl->l_type) { case F_WRLCK: { DWORD result; if (last_type == F_WRLCK) { /* Don't call WaitForSingleObject if we already own the mutex, because doing so will require us to call ReleaseMutex an equal number of times, before the mutex is actually released. */ return 0; } result = WaitForSingleObject (hmutex, INFINITE); switch (result) { case WAIT_OBJECT_0: /* We don't care if the mutex owner crashed or exited. */ case WAIT_ABANDONED: return 0; case WAIT_FAILED: case WAIT_TIMEOUT: /* cannot happen, really */ { DWORD err = GetLastError (); /* Invalidate the last command. */ memset (&last_fl, 0, sizeof (last_fl)); switch (err) { case ERROR_INVALID_HANDLE: case ERROR_INVALID_FUNCTION: errno = EINVAL; return -1; default: errno = EDEADLOCK; return -1; } } } } case F_UNLCK: { /* FIXME: Perhaps we should call ReleaseMutex repatedly until it errors out, to make sure the mutext is released even if we somehow managed to to take ownership multiple times? */ BOOL status = ReleaseMutex (hmutex); if (status) return 0; else { DWORD err = GetLastError (); if (err == ERROR_NOT_OWNER) errno = EPERM; else { memset (&last_fl, 0, sizeof (last_fl)); errno = EINVAL; } return -1; } } default: errno = ENOSYS; return -1; } } default: errno = ENOSYS; va_end (ap); return -1; } } static intptr_t mutex_handle = -1; /* Record in a static variable the mutex handle we were requested to use. That nameless mutex was created by the top-level Make, and its handle was passed to us via inheritance. The value of that handle is passed via the command-line arguments, so that we know which handle to use. */ void record_sync_mutex (const char *str) { char *endp; intptr_t hmutex = strtol (str, &endp, 16); if (*endp == '\0') mutex_handle = hmutex; else { mutex_handle = -1; errno = EINVAL; } } /* Create a new mutex or reuse one created by our parent. */ intptr_t create_mutex (void) { SECURITY_ATTRIBUTES secattr; intptr_t hmutex = -1; /* If we have a mutex handle passed from the parent Make, just use that. */ if (mutex_handle > 0) return mutex_handle; /* We are the top-level Make, and we want the handle to be inherited by our child processes. */ secattr.nLength = sizeof (secattr); secattr.lpSecurityDescriptor = NULL; /* use default security descriptor */ secattr.bInheritHandle = TRUE; hmutex = (intptr_t)CreateMutex (&secattr, FALSE, NULL); if (!hmutex) { DWORD err = GetLastError (); fprintf (stderr, "CreateMutex: error %lu\n", err); errno = ENOLCK; hmutex = -1; } mutex_handle = hmutex; return hmutex; } /* Return non-zero if F1 and F2 are 2 streams representing the same file or pipe or device. */ int same_stream (FILE *f1, FILE *f2) { HANDLE fh1 = (HANDLE)_get_osfhandle (fileno (f1)); HANDLE fh2 = (HANDLE)_get_osfhandle (fileno (f2)); /* Invalid file descriptors get treated as different streams. */ if (fh1 && fh1 != INVALID_HANDLE_VALUE && fh2 && fh2 != INVALID_HANDLE_VALUE) { if (fh1 == fh2) return 1; else { DWORD ftyp1 = GetFileType (fh1), ftyp2 = GetFileType (fh2); if (ftyp1 != ftyp2 || ftyp1 == FILE_TYPE_UNKNOWN || ftyp2 == FILE_TYPE_UNKNOWN) return 0; else if (ftyp1 == FILE_TYPE_CHAR) { /* For character devices, check if they both refer to a console. This loses if both handles refer to the null device (FIXME!), but in that case we don't care in the context of Make. */ DWORD conmode1, conmode2; /* Each process on Windows can have at most 1 console, so if both handles are for the console device, they are the same. We also compare the console mode to distinguish between stdin and stdout/stderr. */ if (GetConsoleMode (fh1, &conmode1) && GetConsoleMode (fh2, &conmode2) && conmode1 == conmode2) return 1; } else { /* For disk files and pipes, compare their unique attributes. */ BY_HANDLE_FILE_INFORMATION bhfi1, bhfi2; /* Pipes get zero in the volume serial number, but do appear to have meaningful information in file index attributes. We test file attributes as well, for a good measure. */ if (GetFileInformationByHandle (fh1, &bhfi1) && GetFileInformationByHandle (fh2, &bhfi2)) return (bhfi1.dwVolumeSerialNumber == bhfi2.dwVolumeSerialNumber && bhfi1.nFileIndexLow == bhfi2.nFileIndexLow && bhfi1.nFileIndexHigh == bhfi2.nFileIndexHigh && bhfi1.dwFileAttributes == bhfi2.dwFileAttributes); } } } return 0; } /* A replacement for tmpfile, since the MSVCRT implementation creates the file in the root directory of the current drive, which might not be writable by our user. Most of the code borrowed from create_batch_file, see job.c. */ FILE * tmpfile (void) { char temp_path[MAXPATHLEN]; unsigned path_size = GetTempPath (sizeof temp_path, temp_path); int path_is_dot = 0; /* The following variable is static so we won't try to reuse a name that was generated a little while ago, because that file might not be on disk yet, since we use FILE_ATTRIBUTE_TEMPORARY below, which tells the OS it doesn't need to flush the cache to disk. If the file is not yet on disk, we might think the name is available, while it really isn't. This happens in parallel builds, where Make doesn't wait for one job to finish before it launches the next one. */ static unsigned uniq = 0; static int second_loop = 0; const char base[] = "gmake_tmpf"; const unsigned sizemax = sizeof base - 1 + 4 + 10 + 10; unsigned pid = GetCurrentProcessId (); if (path_size == 0) { path_size = GetCurrentDirectory (sizeof temp_path, temp_path); path_is_dot = 1; } ++uniq; if (uniq >= 0x10000 && !second_loop) { /* If we already had 64K batch files in this process, make a second loop through the numbers, looking for free slots, i.e. files that were deleted in the meantime. */ second_loop = 1; uniq = 1; } while (path_size > 0 && path_size + sizemax < sizeof temp_path && !(uniq >= 0x10000 && second_loop)) { HANDLE h; sprintf (temp_path + path_size, "%s%s%u-%x.tmp", temp_path[path_size - 1] == '\\' ? "" : "\\", base, pid, uniq); h = CreateFile (temp_path, /* file name */ GENERIC_READ | GENERIC_WRITE | DELETE, /* desired access */ FILE_SHARE_READ | FILE_SHARE_WRITE, /* share mode */ NULL, /* default security attributes */ CREATE_NEW, /* creation disposition */ FILE_ATTRIBUTE_NORMAL | /* flags and attributes */ FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL); /* no template file */ if (h == INVALID_HANDLE_VALUE) { const DWORD er = GetLastError (); if (er == ERROR_FILE_EXISTS || er == ERROR_ALREADY_EXISTS) { ++uniq; if (uniq == 0x10000 && !second_loop) { second_loop = 1; uniq = 1; } } /* The temporary path is not guaranteed to exist, or might not be writable by user. Use the current directory as fallback. */ else if (path_is_dot == 0) { path_size = GetCurrentDirectory (sizeof temp_path, temp_path); path_is_dot = 1; } else { errno = EACCES; break; } } else { int fd = _open_osfhandle ((intptr_t)h, 0); return _fdopen (fd, "w+b"); } } if (uniq >= 0x10000) errno = EEXIST; return NULL; } #endif /* !NO_OUTPUT_SYNC */ #if MAKE_LOAD /* Support for dynamic loading of objects. */ static DWORD last_err; void * dlopen (const char *file, int mode) { char dllfn[MAX_PATH], *p; HANDLE dllhandle; if ((mode & ~(RTLD_LAZY | RTLD_NOW | RTLD_GLOBAL)) != 0) { errno = EINVAL; last_err = ERROR_INVALID_PARAMETER; return NULL; } if (!file) dllhandle = GetModuleHandle (NULL); else { /* MSDN says to be sure to use backslashes in the DLL file name. */ strcpy (dllfn, file); for (p = dllfn; *p; p++) if (*p == '/') *p = '\\'; dllhandle = LoadLibrary (dllfn); } if (!dllhandle) last_err = GetLastError (); return dllhandle; } char * dlerror (void) { static char errbuf[1024]; DWORD ret; if (!last_err) return NULL; ret = FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_err, 0, errbuf, sizeof (errbuf), NULL); while (ret > 0 && (errbuf[ret - 1] == '\n' || errbuf[ret - 1] == '\r')) --ret; errbuf[ret] = '\0'; if (!ret) sprintf (errbuf, "Error code %lu", last_err); last_err = 0; return errbuf; } void * dlsym (void *handle, const char *name) { FARPROC addr = NULL; if (!handle || handle == INVALID_HANDLE_VALUE) { last_err = ERROR_INVALID_PARAMETER; return NULL; } addr = GetProcAddress (handle, name); if (!addr) last_err = GetLastError (); return (void *)addr; } int dlclose (void *handle) { if (!handle || handle == INVALID_HANDLE_VALUE) return -1; if (!FreeLibrary (handle)) return -1; return 0; } #endif /* MAKE_LOAD */ /* MS runtime's isatty returns non-zero for any character device, including the null device, which is not what we want. */ int isatty (int fd) { HANDLE fh = (HANDLE) _get_osfhandle (fd); DWORD con_mode; if (fh == INVALID_HANDLE_VALUE) { errno = EBADF; return 0; } if (GetConsoleMode (fh, &con_mode)) return 1; errno = ENOTTY; return 0; } char * ttyname (int fd) { /* This "knows" that Make only asks about stdout and stderr. A more sophisticated implementation should test whether FD is open for input or output. We can do that by looking at the mode returned by GetConsoleMode. */ return "CONOUT$"; } kbuild-3149/src/kmk/w32/compat/dirent.c0000644000175000017500000001276313252530203017610 0ustar locutuslocutus/* Directory entry code for Window platforms. Copyright (C) 1996-2016 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make 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. GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #ifdef KMK_PRF # include #endif #include "dirent.h" DIR* opendir(const char* pDirName) { struct stat sb; DIR* pDir; char* pEndDirName; int nBufferLen; /* sanity checks */ if (!pDirName) { errno = EINVAL; return NULL; } if (stat(pDirName, &sb) != 0) { errno = ENOENT; return NULL; } if ((sb.st_mode & S_IFMT) != S_IFDIR) { errno = ENOTDIR; return NULL; } /* allocate a DIR structure to return */ pDir = (DIR *) malloc(sizeof (DIR)); if (!pDir) return NULL; /* input directory name length */ nBufferLen = strlen(pDirName); /* copy input directory name to DIR buffer */ strcpy(pDir->dir_pDirectoryName, pDirName); /* point to end of the copied directory name */ pEndDirName = &pDir->dir_pDirectoryName[nBufferLen - 1]; /* if directory name did not end in '/' or '\', add '/' */ if ((*pEndDirName != '/') && (*pEndDirName != '\\')) { pEndDirName++; *pEndDirName = '/'; } /* now append the wildcard character to the buffer */ pEndDirName++; *pEndDirName = '*'; pEndDirName++; *pEndDirName = '\0'; /* other values defaulted */ pDir->dir_nNumFiles = 0; pDir->dir_hDirHandle = INVALID_HANDLE_VALUE; pDir->dir_ulCookie = __DIRENT_COOKIE; #ifdef KMK_PRF fprintf(stderr, "opendir(%s) -> %p\n", pDirName, pDir); #endif return pDir; } void closedir(DIR *pDir) { /* got a valid pointer? */ if (!pDir) { errno = EINVAL; return; } /* sanity check that this is a DIR pointer */ if (pDir->dir_ulCookie != __DIRENT_COOKIE) { errno = EINVAL; return; } /* close the WINDOWS32 directory handle */ if (pDir->dir_hDirHandle != INVALID_HANDLE_VALUE) FindClose(pDir->dir_hDirHandle); free(pDir); return; } struct dirent * readdir(DIR* pDir) { WIN32_FIND_DATA wfdFindData; if (!pDir) { errno = EINVAL; return NULL; } /* sanity check that this is a DIR pointer */ if (pDir->dir_ulCookie != __DIRENT_COOKIE) { errno = EINVAL; return NULL; } if (pDir->dir_nNumFiles == 0) { pDir->dir_hDirHandle = FindFirstFile(pDir->dir_pDirectoryName, &wfdFindData); if (pDir->dir_hDirHandle == INVALID_HANDLE_VALUE) return NULL; } else if (!FindNextFile(pDir->dir_hDirHandle, &wfdFindData)) return NULL; /* bump count for next call to readdir() or telldir() */ pDir->dir_nNumFiles++; /* fill in struct dirent values */ pDir->dir_sdReturn.d_ino = (ino_t)-1; strcpy(pDir->dir_sdReturn.d_name, wfdFindData.cFileName); return &pDir->dir_sdReturn; } void rewinddir(DIR* pDir) { if (!pDir) { errno = EINVAL; return; } /* sanity check that this is a DIR pointer */ if (pDir->dir_ulCookie != __DIRENT_COOKIE) { errno = EINVAL; return; } /* close the WINDOWS32 directory handle */ if (pDir->dir_hDirHandle != INVALID_HANDLE_VALUE) if (!FindClose(pDir->dir_hDirHandle)) errno = EBADF; /* reset members which control readdir() */ pDir->dir_hDirHandle = INVALID_HANDLE_VALUE; pDir->dir_nNumFiles = 0; return; } int telldir(DIR* pDir) { if (!pDir) { errno = EINVAL; return -1; } /* sanity check that this is a DIR pointer */ if (pDir->dir_ulCookie != __DIRENT_COOKIE) { errno = EINVAL; return -1; } /* return number of times readdir() called */ return pDir->dir_nNumFiles; } void seekdir(DIR* pDir, long nPosition) { if (!pDir) return; /* sanity check that this is a DIR pointer */ if (pDir->dir_ulCookie != __DIRENT_COOKIE) return; /* go back to beginning of directory */ rewinddir(pDir); /* loop until we have found position we care about */ for (--nPosition; nPosition && readdir(pDir); nPosition--); /* flag invalid nPosition value */ if (nPosition) errno = EINVAL; return; } kbuild-3149/src/kmk/kbuild-object.c0000644000175000017500000014415313252530176017153 0ustar locutuslocutus/* $Id: kbuild-object.c 3141 2018-03-14 21:58:32Z bird $ */ /** @file * kBuild objects. */ /* * Copyright (c) 2011-2014 knut st. osmundsen * * This file is part of kBuild. * * kBuild 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. * * kBuild 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 kBuild. If not, see * */ /* No GNU coding style here! */ /******************************************************************************* * Header Files * *******************************************************************************/ #include "makeint.h" #include "filedef.h" #include "variable.h" #include "dep.h" #include "debug.h" #include "kbuild.h" #include #include /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ #define WORD_IS(a_pszWord, a_cchWord, a_szWord2) \ ( (a_cchWord) == sizeof(a_szWord2) - 1 && memcmp((a_pszWord), a_szWord2, sizeof(a_szWord2) - 1) == 0) /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** kBuild object type. */ enum kBuildType { kBuildType_Invalid, kBuildType_Target, kBuildType_Template, kBuildType_Tool, kBuildType_Sdk, kBuildType_Unit }; enum kBuildSeverity { kBuildSeverity_Warning, kBuildSeverity_Error, kBuildSeverity_Fatal }; /** * kBuild object data. */ struct kbuild_object { /** The object type. */ enum kBuildType enmType; /** Object name length. */ size_t cchName; /** The bare name of the define. */ char *pszName; /** The file location where this define was declared. */ floc FileLoc; /** Pointer to the next element in the global list. */ struct kbuild_object *pGlobalNext; /** The variable set associated with this define. */ struct variable_set_list *pVariables; /** The parent name, NULL if none. */ char *pszParent; /** The length of the parent name. */ size_t cchParent; /** Pointer to the parent. Resolved lazily, so it can be NULL even if we * have a parent. */ struct kbuild_object *pParent; /** The template, NULL if none. Only applicable to targets. Only covers the * primary template, not target or type specific templates. * @todo not sure if this is really necessary. */ char const *pszTemplate; /** The variable prefix. */ char *pszVarPrefix; /** The length of the variable prefix. */ size_t cchVarPrefix; }; /** * The data we stack during eval. */ struct kbuild_eval_data { /** Pointer to the element below us on the stack. */ struct kbuild_eval_data *pStackDown; /** Pointer to the object. */ struct kbuild_object *pObj; /** The saved current variable set, for restoring in kBuild-endef. */ struct variable_set_list *pVariablesSaved; }; /******************************************************************************* * Global Variables * *******************************************************************************/ /** Linked list (LIFO) of kBuild defines. * @todo use a hash! */ static struct kbuild_object *g_pHeadKbObjs = NULL; /** Stack of kBuild evalutation contexts. * This is for dealing with potential recursive kBuild object definition, * generally believed to only happen via $(eval ) or include similar. */ struct kbuild_eval_data *g_pTopKbEvalData = NULL; /** Cached variable name '_TEMPLATE'. */ static const char *g_pszVarNmTemplate = NULL; /** Zero if compatibility mode is disabled, non-zero if enabled. * If explicitily enabled, the value will be greater than 1. */ int g_fKbObjCompMode = 1; /******************************************************************************* * Internal Functions * *******************************************************************************/ static struct kbuild_object * resolve_kbuild_object_parent(struct kbuild_object *pObj, int fQuiet); static struct kbuild_object * get_kbuild_object_parent(struct kbuild_object *pObj, enum kBuildSeverity enmSeverity); static struct kbuild_object * parse_kbuild_object_variable_accessor(const char *pchExpr, size_t cchExpr, enum kBuildSeverity enmSeverity, const floc *pFileLoc, const char **ppchVarNm, size_t *pcchVarNm, enum kBuildType *penmType); /** * Initializes the kBuild object stuff. * * Requires the variable_cache to be initialized. */ void init_kbuild_object(void) { g_pszVarNmTemplate = strcache2_add(&variable_strcache, STRING_SIZE_TUPLE("_TEMPLATE")); } /** * Reports a problem with dynamic severity level. * * @param enmSeverity The severity level. * @param pFileLoc The file location. * @param pszFormat The format string. * @param ... Arguments for the format string. */ static void kbuild_report_problem(enum kBuildSeverity enmSeverity, const floc *pFileLoc, const char *pszFormat, ...) { char szBuf[8192]; va_list va; va_start(va, pszFormat); #ifdef _MSC_VER _vsnprintf(szBuf, sizeof(szBuf), pszFormat, va); #else vsnprintf(szBuf, sizeof(szBuf), pszFormat, va); #endif va_end(va); switch (enmSeverity) { case kBuildSeverity_Warning: OS(message, 0, "%s", szBuf); break; case kBuildSeverity_Error: OS(error, pFileLoc, "%s", szBuf); break; default: case kBuildSeverity_Fatal: OS(fatal, pFileLoc, "%s", szBuf); break; } } static const char * eval_kbuild_type_to_string(enum kBuildType enmType) { switch (enmType) { case kBuildType_Target: return "target"; case kBuildType_Template: return "template"; case kBuildType_Tool: return "tool"; case kBuildType_Sdk: return "sdk"; case kBuildType_Unit: return "unit"; default: case kBuildType_Invalid: return "invalid"; } } /** * Gets the length of the string representation of the given type. * * @returns The string length. * @param enmType The kBuild object type in question. */ static unsigned eval_kbuild_type_to_string_length(enum kBuildType enmType) { switch (enmType) { case kBuildType_Target: return sizeof("target") - 1; case kBuildType_Template: return sizeof("template") - 1; case kBuildType_Tool: return sizeof("tool") - 1; case kBuildType_Sdk: return sizeof("sdk") - 1; case kBuildType_Unit: return sizeof("unit") - 1; default: case kBuildType_Invalid: return sizeof("invalid") - 1; } } /** * Converts a string into an kBuild object type. * * @returns The type on success, kBuildType_Invalid on failure. * @param pchWord The pchWord. Not necessarily zero terminated. * @param cchWord The length of the word. */ static enum kBuildType eval_kbuild_type_from_string(const char *pchWord, size_t cchWord) { if (cchWord >= 3) { if (*pchWord == 't') { if (WORD_IS(pchWord, cchWord, "target")) return kBuildType_Target; if (WORD_IS(pchWord, cchWord, "template")) return kBuildType_Template; if (WORD_IS(pchWord, cchWord, "tool")) return kBuildType_Tool; } else { if (WORD_IS(pchWord, cchWord, "sdk")) return kBuildType_Sdk; if (WORD_IS(pchWord, cchWord, "unit")) return kBuildType_Unit; } } return kBuildType_Invalid; } #if 0 /* unused */ /** * Helper function for caching variable name strings. * * @returns The string cache variable name. * @param pszName The variable name. * @param ppszCache Cache variable, static or global. Initialize to * NULL. */ static const char * kbuild_variable_name(const char *pszName, const char **ppszCache) { const char *pszRet = *ppszCache; if (!pszRet) *ppszCache = pszRet = strcache2_add(&variable_strcache, pszName, strlen(pszName)); return pszRet; } #endif static struct kbuild_object * lookup_kbuild_object(enum kBuildType enmType, const char *pchName, size_t cchName) { /* Linear lookup for now. */ struct kbuild_object *pCur = g_pHeadKbObjs; while (pCur) { if ( pCur->enmType == enmType && pCur->cchName == cchName && !memcmp(pCur->pszName, pchName, cchName)) return pCur; pCur = pCur->pGlobalNext; } return NULL; } /** @name Defining and modifying variables * @{ */ /** * Checks if the variable name is valid. * * @returns 1 if valid, 0 if not. * @param pchName The variable name. * @param cchName The length of the variable name. */ static int is_valid_kbuild_object_variable_name(const char *pchName, size_t cchName) { if (cchName > 0) { if (!memchr(pchName, '[', cchName)) { /** @todo more? */ return 1; } } return 0; } static const char * kbuild_replace_special_accessors(const char *pchValue, size_t *pcchValue, int *pfDuplicateValue, const floc *pFileLoc) { size_t cchValue = *pcchValue; size_t cbAllocated = *pfDuplicateValue ? 0 : cchValue + 1; /* * Loop thru each potential special accessor occurance in the string. * * Unfortunately, we don't have a strnstr function in the C library, so * we'll using memchr and doing a few more rounds in this loop. */ size_t cchLeft = cchValue; char *pchLeft = (char *)pchValue; for (;;) { int fSuper; char *pch = (char *)memchr(pchLeft, '$', cchLeft); if (!pch) break; pch++; cchLeft -= pch - pchLeft; pchLeft = pch; /* [@self] is the shorter, quit if there isn't enough room for even it. */ if (cchLeft < sizeof("([@self]") - 1) break; /* We don't care how many dollars there are in front of a special accessor. */ if (*pchLeft == '$') { do { cchLeft--; pchLeft++; } while (cchLeft >= sizeof("([@self]") - 1 && *pchLeft == '$'); if (cchLeft < sizeof("([@self]") - 1) break; } /* Is it a special accessor? */ if ( pchLeft[2] != '@' || pchLeft[1] != '[' || pchLeft[0] != '(') continue; pchLeft += 2; cchLeft -= 2; if (!memcmp(pchLeft, STRING_SIZE_TUPLE("@self]"))) fSuper = 0; else if ( cchLeft >= sizeof("@super]") && !memcmp(pchLeft, STRING_SIZE_TUPLE("@super]"))) fSuper = 1; else continue; /* * We've got something to replace. First figure what with and then * resize the value buffer. */ if (g_pTopKbEvalData) { struct kbuild_object *pObj = g_pTopKbEvalData->pObj; size_t const cchSpecial = fSuper ? sizeof("@super") - 1 : sizeof("@self") - 1; size_t cchName; size_t cchType; long cchDelta; const char *pszName; if (fSuper) { pObj = get_kbuild_object_parent(pObj, kBuildSeverity_Error); if (!pObj) continue; } pszName = pObj->pszName; cchName = pObj->cchName; cchType = eval_kbuild_type_to_string_length(pObj->enmType); cchDelta = cchType + 1 + cchName - cchSpecial; if (cchValue + cchDelta >= cbAllocated) { size_t offLeft = pchLeft - pchValue; char *pszNewValue; cbAllocated = cchValue + cchDelta + 1; if (cchValue < 1024) cbAllocated = (cbAllocated + 31) & ~(size_t)31; else cbAllocated = (cbAllocated + 255) & ~(size_t)255; pszNewValue = (char *)xmalloc(cbAllocated); memcpy(pszNewValue, pchValue, offLeft); memcpy(pszNewValue + offLeft + cchSpecial + cchDelta, pchLeft + cchSpecial, cchLeft - cchSpecial + 1); if (*pfDuplicateValue == 0) free((char *)pchValue); else *pfDuplicateValue = 0; pchValue = pszNewValue; pchLeft = pszNewValue + offLeft; } else { assert(*pfDuplicateValue == 0); memmove(pchLeft + cchSpecial + cchDelta, pchLeft + cchSpecial, cchLeft - cchSpecial + 1); } cchLeft += cchDelta; cchValue += cchDelta; *pcchValue = cchValue; memcpy(pchLeft, eval_kbuild_type_to_string(pObj->enmType), cchType); pchLeft += cchType; *pchLeft++ = '@'; memcpy(pchLeft, pszName, cchName); pchLeft += cchName; cchLeft -= cchType + 1 + cchName; } else error(pFileLoc, 20, _("The '$([%.*s...' accessor can only be used in the context of a kBuild object"), (int)MIN(cchLeft, 20), pchLeft); } return pchValue; } static struct variable * define_kbuild_object_variable_cached(struct kbuild_object *pObj, const char *pszName, const char *pchValue, size_t cchValue, int fDuplicateValue, enum variable_origin enmOrigin, int fRecursive, int fNoSpecialAccessors, const floc *pFileLoc) { struct variable *pVar; size_t cchName = strcache2_get_len(&variable_strcache, pszName); if (fRecursive && !fNoSpecialAccessors) pchValue = kbuild_replace_special_accessors(pchValue, &cchValue, &fDuplicateValue, pFileLoc); pVar = define_variable_in_set(pszName, cchName, pchValue, cchValue, fDuplicateValue, enmOrigin, fRecursive, pObj->pVariables->set, pFileLoc); /* Single underscore prefixed variables gets a global alias. */ if ( pszName[0] == '_' && pszName[1] != '_' && g_fKbObjCompMode) { struct variable *pAlias; size_t cchPrefixed = pObj->cchVarPrefix + cchName; char *pszPrefixed = xmalloc(cchPrefixed + 1); memcpy(pszPrefixed, pObj->pszVarPrefix, pObj->cchVarPrefix); memcpy(&pszPrefixed[pObj->cchVarPrefix], pszName, cchName); pszPrefixed[cchPrefixed] = '\0'; pAlias = define_variable_alias_in_set(pszPrefixed, cchPrefixed, pVar, enmOrigin, &global_variable_set, pFileLoc); if (!pAlias->alias) OS(error, pFileLoc, _("Error defining alias '%s'"), pszPrefixed); } return pVar; } #if 0 struct variable * define_kbuild_object_variable(struct kbuild_object *pObj, const char *pchName, size_t cchName, const char *pchValue, size_t cchValue, int fDuplicateValue, enum variable_origin enmOrigin, int fRecursive, const floc *pFileLoc) { return define_kbuild_object_variable_cached(pObj, strcache2_add(&variable_strcache, pchName, cchName), pchValue, cchValue, fDuplicateValue, enmOrigin, fRecursive, pFileLoc); } #endif /** * Try define a kBuild object variable via a possible accessor * ([type@object]var). * * @returns Pointer to the defined variable on success. * @retval VAR_NOT_KBUILD_ACCESSOR if it isn't an accessor. * * @param pchName The variable name, not cached. * @param cchName The variable name length. This will not be ~0U. * @param pszValue The variable value. If @a fDuplicateValue is clear, * this should be assigned as the actual variable * value, otherwise it will be duplicated. In the * latter case it might not be properly null * terminated. * @param cchValue The value length. * @param fDuplicateValue Whether @a pszValue need to be duplicated on the * heap or is already there. * @param enmOrigin The variable origin. * @param fRecursive Whether it's a recursive variable. * @param pFileLoc The location of the variable definition. */ struct variable * try_define_kbuild_object_variable_via_accessor(const char *pchName, size_t cchName, const char *pszValue, size_t cchValue, int fDuplicateValue, enum variable_origin enmOrigin, int fRecursive, floc const *pFileLoc) { struct kbuild_object *pObj; const char *pchVarNm; size_t cchVarNm; pObj = parse_kbuild_object_variable_accessor(pchName, cchName, kBuildSeverity_Fatal, pFileLoc, &pchVarNm, &cchVarNm, NULL); if (pObj != KOBJ_NOT_KBUILD_ACCESSOR) { assert(pObj != NULL); if (!is_valid_kbuild_object_variable_name(pchVarNm, cchVarNm)) fatal(pFileLoc, cchVarNm + cchName, _("Invalid kBuild object variable name: '%.*s' ('%.*s')"), (int)cchVarNm, pchVarNm, (int)cchName, pchName); return define_kbuild_object_variable_cached(pObj, strcache2_add(&variable_strcache, pchVarNm, cchVarNm), pszValue, cchValue, fDuplicateValue, enmOrigin, fRecursive, 0 /*fNoSpecialAccessors*/, pFileLoc); } return VAR_NOT_KBUILD_ACCESSOR; } /** * Define a kBuild object variable in the topmost kBuild object. * * This won't be an variable accessor. * * @returns Pointer to the defined variable on success. * * @param pchName The variable name, not cached. * @param cchName The variable name length. This will not be ~0U. * @param pszValue The variable value. If @a fDuplicateValue is clear, * this should be assigned as the actual variable * value, otherwise it will be duplicated. In the * latter case it might not be properly null * terminated. * @param cchValue The value length. * @param fDuplicateValue Whether @a pszValue need to be duplicated on the * heap or is already there. * @param enmOrigin The variable origin. * @param fRecursive Whether it's a recursive variable. * @param pFileLoc The location of the variable definition. */ struct variable * define_kbuild_object_variable_in_top_obj(const char *pchName, size_t cchName, const char *pszValue, size_t cchValue, int fDuplicateValue, enum variable_origin enmOrigin, int fRecursive, floc const *pFileLoc) { assert(g_pTopKbEvalData != NULL); if (!is_valid_kbuild_object_variable_name(pchName, cchName)) fatal(pFileLoc, cchName, _("Invalid kBuild object variable name: '%.*s'"), (int)cchName, pchName); return define_kbuild_object_variable_cached(g_pTopKbEvalData->pObj, strcache2_add(&variable_strcache, pchName, cchName), pszValue, cchValue, fDuplicateValue, enmOrigin, fRecursive, 0 /*fNoSpecialAccessors*/, pFileLoc); } /** * Implements appending and prepending to a kBuild object variable. * * The variable is either accessed thru an accessor or by the topmost kBuild * object. * * @returns Pointer to the defined variable on success. * * @param pchName The variable name, not cached. * @param cchName The variable name length. This will not be ~0U. * @param pszValue The variable value. Must be duplicated. * @param cchValue The value length. * @param fSimpleValue Whether we've already figured that it's a simple * value. This is for optimizing appending/prepending * to an existing simple value variable. * @param enmOrigin The variable origin. * @param fAppend Append if set, prepend if clear. * @param pFileLoc The location of the variable definition. */ struct variable * kbuild_object_variable_pre_append(const char *pchName, size_t cchName, const char *pchValue, size_t cchValue, int fSimpleValue, enum variable_origin enmOrigin, int fAppend, const floc *pFileLoc) { struct kbuild_object *pObj; struct variable VarKey; /* * Resolve the relevant kBuild object first. */ if (cchName > 3 && pchName[0] == '[') { const char *pchVarNm; size_t cchVarNm; pObj = parse_kbuild_object_variable_accessor(pchName, cchName, kBuildSeverity_Fatal, pFileLoc, &pchVarNm, &cchVarNm, NULL); if (pObj != KOBJ_NOT_KBUILD_ACCESSOR) { pchName = pchVarNm; cchName = cchVarNm; } else pObj = g_pTopKbEvalData->pObj; } else pObj = g_pTopKbEvalData->pObj; /* * Make sure the variable name is valid. Raise fatal error if not. */ if (!is_valid_kbuild_object_variable_name(pchName, cchName)) fatal(pFileLoc, cchName, _("Invalid kBuild object variable name: '%.*s'"), (int)cchName, pchName); /* * Get the cached name and look it up in the object's variables. */ VarKey.name = strcache2_lookup(&variable_strcache, pchName, cchName); if (VarKey.name) { struct variable *pVar; VarKey.length = cchName; pVar = (struct variable *)hash_find_item_strcached(&pObj->pVariables->set->table, &VarKey); if (pVar) { /* Append/prepend to existing variable. */ int fDuplicateValue = 1; if (pVar->recursive && !fSimpleValue) pchValue = kbuild_replace_special_accessors(pchValue, &cchValue, &fDuplicateValue, pFileLoc); pVar = do_variable_definition_append(pFileLoc, pVar, pchValue, cchValue, fSimpleValue, enmOrigin, fAppend); if (fDuplicateValue == 0) free((char *)pchValue); return pVar; } /* * Not found. Check ancestors if the 'override' directive isn't applied. */ if (pObj->pszParent && enmOrigin != o_override) { struct kbuild_object *pParent = pObj; for (;;) { pParent = resolve_kbuild_object_parent(pParent, 0 /*fQuiet*/); if (!pParent) break; pVar = (struct variable *)hash_find_item_strcached(&pParent->pVariables->set->table, &VarKey); if (pVar) { if (pVar->value_length != ~0U) assert(pVar->value_length == strlen(pVar->value)); else pVar->value_length = strlen(pVar->value); /* * Combine the two values and define the variable in the * specified child object. We must disregard 'origin' a * little here, so we must do the gritty stuff our selves. */ if ( pVar->recursive || fSimpleValue || !cchValue || memchr(pchValue, '$', cchValue) == NULL ) { int fDuplicateValue = 1; size_t cchNewValue; char *pszNewValue; char *pszTmp; /* Just join up the two values. */ if (pVar->recursive && !fSimpleValue) pchValue = kbuild_replace_special_accessors(pchValue, &cchValue, &fDuplicateValue, pFileLoc); if (pVar->value_length == 0) { cchNewValue = cchValue; pszNewValue = xstrndup(pchValue, cchValue); } else if (!cchValue) { cchNewValue = pVar->value_length; pszNewValue = xmalloc(cchNewValue + 1); memcpy(pszNewValue, pVar->value, cchNewValue + 1); } else { cchNewValue = pVar->value_length + 1 + cchValue; pszNewValue = xmalloc(cchNewValue + 1); if (fAppend) { memcpy(pszNewValue, pVar->value, pVar->value_length); pszTmp = pszNewValue + pVar->value_length; *pszTmp++ = ' '; memcpy(pszTmp, pchValue, cchValue); pszTmp[cchValue] = '\0'; } else { memcpy(pszNewValue, pchValue, cchValue); pszTmp = pszNewValue + cchValue; *pszTmp++ = ' '; memcpy(pszNewValue, pVar->value, pVar->value_length); pszTmp[pVar->value_length] = '\0'; } } /* Define the new variable in the child. */ pVar = define_kbuild_object_variable_cached(pObj, VarKey.name, pszNewValue, cchNewValue, 0 /*fDuplicateValue*/, enmOrigin, pVar->recursive, 1 /*fNoSpecialAccessors*/, pFileLoc); if (fDuplicateValue == 0) free((char *)pchValue); } else { /* Lazy bird: Copy the variable from the ancestor and then do a normal append/prepend on it. */ pVar = define_kbuild_object_variable_cached(pObj, VarKey.name, pVar->value, pVar->value_length, 1 /*fDuplicateValue*/, enmOrigin, pVar->recursive, 1 /*fNoSpecialAccessors*/, pFileLoc); append_expanded_string_to_variable(pVar, pchValue, cchValue, fAppend); } return pVar; } } } } else VarKey.name = strcache2_add(&variable_strcache, pchName, cchName); /* Variable not found. */ return define_kbuild_object_variable_cached(pObj, VarKey.name, pchValue, cchValue, 1 /*fDuplicateValue*/, enmOrigin, 1 /*fRecursive */, 0 /*fNoSpecialAccessors*/, pFileLoc); } /** @} */ static char * allocate_expanded_next_token(const char **ppszCursor, const char *pszEos, size_t *pcchToken, int fStrip) { unsigned int cchToken; char *pszToken = find_next_token_eos(ppszCursor, pszEos, &cchToken); if (pszToken) { pszToken = allocated_variable_expand_2(pszToken, cchToken, &cchToken); if (pszToken) { if (fStrip) { unsigned int off = 0; while (MY_IS_BLANK(pszToken[off])) off++; if (off) { cchToken -= off; memmove(pszToken, &pszToken[off], cchToken + 1); } while (cchToken > 0 && MY_IS_BLANK(pszToken[cchToken - 1])) pszToken[--cchToken] = '\0'; } assert(cchToken == strlen(pszToken)); if (pcchToken) *pcchToken = cchToken; return pszToken; } } if (pcchToken) *pcchToken = 0; return NULL; } static struct kbuild_object * resolve_kbuild_object_parent(struct kbuild_object *pObj, int fQuiet) { if ( !pObj->pParent && pObj->pszParent) { struct kbuild_object *pCur = g_pHeadKbObjs; while (pCur) { if ( pCur->enmType == pObj->enmType && !strcmp(pCur->pszName, pObj->pszParent)) { if ( pCur->pszParent && ( pCur->pParent == pObj || !strcmp(pCur->pszParent, pObj->pszName)) ) OSS(fatal, &pObj->FileLoc, _("'%s' and '%s' are both trying to be each other children..."), pObj->pszName, pCur->pszName); pObj->pParent = pCur; pObj->pVariables->next = pObj->pVariables; return pCur; } pCur = pCur->pGlobalNext; } /* Not found. */ if (!fQuiet) OSS(error, &pObj->FileLoc, _("Could not locate parent '%s' of '%s'"), pObj->pszParent, pObj->pszName); } return pObj->pParent; } /** * Get the parent of the given object, it is expected to have one. * * @returns Pointer to the parent. NULL if we survive failure. * @param pObj The kBuild object. * @param enmSeverity The severity of a missing parent. */ static struct kbuild_object * get_kbuild_object_parent(struct kbuild_object *pObj, enum kBuildSeverity enmSeverity) { struct kbuild_object *pParent = pObj->pParent; if (pParent) return pParent; pParent = resolve_kbuild_object_parent(pObj, 1 /*fQuiet - complain below */); if (pParent) return pParent; if (pObj->pszParent) kbuild_report_problem(enmSeverity, &pObj->FileLoc, _("Could not local parent '%s' for kBuild object '%s'"), pObj->pszParent, pObj->pszName); else kbuild_report_problem(enmSeverity, &pObj->FileLoc, _("kBuild object '%s' has no parent ([@super])"), pObj->pszName); return NULL; } static int eval_kbuild_define_xxxx(struct kbuild_eval_data **ppData, const floc *pFileLoc, const char *pszLine, const char *pszEos, int fIgnoring, enum kBuildType enmType) { unsigned int cch; char ch; char *psz; const char *pszPrefix; struct kbuild_object *pObj; struct kbuild_eval_data *pData; if (fIgnoring) return 0; /* * Create a new kBuild object. */ pObj = xmalloc(sizeof(*pObj)); pObj->enmType = enmType; pObj->pszName = NULL; pObj->cchName = 0; pObj->FileLoc = *pFileLoc; pObj->pGlobalNext = g_pHeadKbObjs; g_pHeadKbObjs = pObj; pObj->pVariables = create_new_variable_set(); pObj->pszParent = NULL; pObj->cchParent = 0; pObj->pParent = NULL; pObj->pszTemplate = NULL; pObj->pszVarPrefix = NULL; pObj->cchVarPrefix = 0; /* * The first word is the name. */ pObj->pszName = allocate_expanded_next_token(&pszLine, pszEos, &pObj->cchName, 1 /*strip*/); if (!pObj->pszName || !*pObj->pszName) O(fatal, pFileLoc, _("The kBuild define requires a name")); psz = pObj->pszName; while ((ch = *psz++) != '\0') if (!isgraph(ch)) { OSS(error, pFileLoc, _("The 'kBuild-define-%s' name '%s' contains one or more invalid characters"), eval_kbuild_type_to_string(enmType), pObj->pszName); break; } /* * Calc the variable prefix. */ switch (enmType) { case kBuildType_Target: pszPrefix = ""; break; case kBuildType_Template: pszPrefix = "TEMPLATE_"; break; case kBuildType_Tool: pszPrefix = "TOOL_"; break; case kBuildType_Sdk: pszPrefix = "SDK_"; break; case kBuildType_Unit: pszPrefix = "UNIT_"; break; default: ON(fatal, pFileLoc, _("enmType=%d"), enmType); return -1; } cch = strlen(pszPrefix); pObj->cchVarPrefix = cch + pObj->cchName; pObj->pszVarPrefix = xmalloc(pObj->cchVarPrefix + 1); memcpy(pObj->pszVarPrefix, pszPrefix, cch); memcpy(&pObj->pszVarPrefix[cch], pObj->pszName, pObj->cchName); /* * Parse subsequent words. */ psz = find_next_token_eos(&pszLine, pszEos, &cch); while (psz) { if (WORD_IS(psz, cch, "extending")) { /* Inheritance directive. */ if (pObj->pszParent != NULL) O(fatal, pFileLoc, _("'extending' can only occure once")); pObj->pszParent = allocate_expanded_next_token(&pszLine, pszEos, &pObj->cchParent, 1 /*strip*/); if (!pObj->pszParent || !*pObj->pszParent) O(fatal, pFileLoc, _("'extending' requires a parent name")); } else if (WORD_IS(psz, cch, "using")) { char *pszTemplate; size_t cchTemplate; /* Template directive. */ if (enmType != kBuildType_Target) O(fatal, pFileLoc, _("'using