diff --git a/Makefile.am b/Makefile.am index 1903603..3d063da 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,8 @@ AUTOMAKE_OPTIONS = foreign -SUBDIRS = src doc tools +SUBDIRS = libcpp libiberty src doc tools + +src: libcpp libiberty EXTRA_DIST = \ COPYING \ diff --git a/configure.in b/configure.in index bfa1f61..bfb73d9 100644 --- a/configure.in +++ b/configure.in @@ -24,7 +24,7 @@ dnl -*- m4 -*- # force autoconf 2.5 on Debian systems AC_PREREQ(2.50) -AC_INIT(nesc, 1.2.9) +AC_INIT(nesc, 1.3.0alpha) AC_CONFIG_AUX_DIR(config-aux) AM_INIT_AUTOMAKE diff --git a/include/COPYING b/include/COPYING new file mode 100644 index 0000000..623b625 --- /dev/null +++ b/include/COPYING @@ -0,0 +1,340 @@ + 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 Library 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 Library General +Public License instead of this License. diff --git a/include/COPYING3 b/include/COPYING3 new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/include/COPYING3 @@ -0,0 +1,674 @@ + 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 +. diff --git a/include/ChangeLog b/include/ChangeLog new file mode 100644 index 0000000..7ea34d2 --- /dev/null +++ b/include/ChangeLog @@ -0,0 +1,388 @@ +2007-11-07 Joseph Myers + Daniel Jacobowitz + + * floatformat.h (struct floatformat): Add split_half field. + (floatformat_ibm_long_double): New. + +2007-09-06 Tom Tromey + + * libiberty.h (pex_free): Document process killing. + +2007-08-31 Douglas Gregor + + * demangle.h (enum demangle_component_type): Add + DEMANGLE_COMPONENT_RVALUE_REFERENCE. + +2007-07-25 Ben Elliston + + * ternary.h: Remove. + +2007-07-18 Bob Wilson + + * xtensa-config.h (XCHAL_HAVE_THREADPTR): New. + (XCHAL_HAVE_RELEASE_SYNC, XCHAL_HAVE_S32C1I): New. + +2007-07-17 Nick Clifton + + * COPYING3: New file. Contains version 3 of the GNU General + Public License. + +2007-07-12 Kai Tietz + + * splay-tree.h (libi_uhostptr_t, libi_shostptr_t): New types, + needed for WIN64 when a long is not wide enough for a pointer. + (splay_tree_key, splay_tree_value): Use the new types. + +2007-05-07 Nathan Froyd + + * libiberty.h (writeargv): Declare. + +2007-04-25 Mark Mitchell + + * demangle.h: Change license to LGPL + exception. + +2007-03-29 Joel Brobecker + + * filenames.h (FILENAME_CMP): Adjust define to call filename_cmp + regardless of the type of file system. + +2007-03-06 Jan Hubicka + + * ansidecl.h (ATTRIBUTE_COLD, ATTRIBUTE_HOT): New. + +2007-02-09 Joseph S. Myers + + * libiberty.h (pex_write_input): Remove prototype. + +2007-01-31 Vladimir Prus + + * libiberty.h (PEX_STDERR_TO_PIPE): New define. + (PEX_BINARY_ERROR): New define. + (pex_read_err): New function. + +2007-01-29 Simon Baldwin + + * demangle.h: New cplus_demangle_print_callback, + cplus_demangle_v3_callback, and java_demangle_v3_callback function + prototypes, and demangle_callbackref type definition. + +2006-12-06 Nick Clifton + + * ansidecl.h (ATTRIBUTE_PACKED): Define. + +2006-11-30 Andrew Stubbs + J"orn Rennecke + + PR driver/29931 + * libiberty.h (make_relative_prefix_ignore_links): Declare. + +2006-11-27 Bob Wilson + + * xtensa-config.h (XSHAL_ABI): New. + (XTHAL_ABI_WINDOWED, XTHAL_ABI_CALL0): New. + +2006-04-11 Jim Blandy + + * libiberty.h (pex_input_file, pex_input_pipe): New declarations. + +2006-01-18 DJ Delorie + + * md5.h: Include ansidecl.h + +2006-01-09 Bob Wilson + + * xtensa-config.h (XCHAL_HAVE_MUL32_HIGH): Define. + +2005-12-30 Bob Wilson + + * xtensa-config.h (XCHAL_HAVE_WIDE_BRANCHES): New. + +2005-12-10 Terry Laurenzo + + PR java/9861 + * demangle.h : Add DMGL_RET_POSTFIX define to enable alternative + output format for return types + +2005-10-31 Mark Kettenis + + * floatformat.h (enum floatformat_byteorders): Add + floatformat_vax. + (floatformat_vax_aingle, floatformat_vax_double): Declare. + +2005-09-26 Mark Mitchell + + * libiberty.h (expandargv): New function. + +2005-08-17 Mark Kettenis + + * floatformat.h (struct floatformat): Change type of large + argument for is_valid member to `const void *'. + (floatformat_to_double): Change type of second argument to `const + void *'. + (floatformat_from_double): Change type of last argument to `void + *'. + (floatformat_is_valid): Change type of last argument to `const + void *'. + +2005-07-12 Ben Elliston + + * xregex2.h (regexec): Qualify this prototype with __extension__ + when compiling with GNU C. + +2005-07-03 Steve Ellcey + + PR other/13906 + * ansidecl.h (ATTRIBUTE_ALIGNED_ALIGNOF): New. + * md5.h (md5_uintptr): New. + (md5_ctx): Align buffer field. + +2005-06-30 Daniel Berlin + + * hashtab.h (HTAB_DELETED_ENTRY): New macro. + (HTAB_EMPTY_ENTRY): New macro. + +2005-06-20 Geoffrey Keating + + * libiberty.h (strverscmp): Prototype. + +2005-06-06 Gabriel Dos Reis + + * libiberty.h (XOBFINISH): New. + +2005-06-01 Kaveh R. Ghazi + + * libiberty.h (vsnprintf): Add format attribute. + +2005-05-29 Kaveh R. Ghazi + + * ansidecl.h: Add ATTRIBUTE_FPTR_PRINTF. + +2005-05-28 Eli Zaretskii + + * libiberty.h: (snprintf) [!HAVE_DECL_SNPRINTF]: Declare if + needed. + (vsnprintf) [!HAVE_DECL_VSNPRINTF]: Declare if needed. + +2005-05-25 Richard Henderson + + * demangle.h (DEMANGLE_COMPONENT_HIDDEN_ALIAS): New. + +2005-05-24 Gabriel Dos Reis + + * libiberty.h (ACONCAT): Properly cast value of alloca(). + + * ansidecl.h (ATTRIBUTE_UNUSED_LABEL): Don't define if + __cplusplus. + +2005-05-12 Steve Ellcey + + libiberty.h: Do not define empty basename prototype. + +2005-05-10 Nick Clifton + + * Update the address and phone number of the FSF organization in + the GPL notices in the following files: + COPYING, ansidecl.h, bfdlink.h, bout.h, demangle.h, dis-asm.h, + dyn-string.h, fibheap.h, filenames.h, floatformat.h, + fnmatch.h, gdbm.h, getopt.h, hashtab.h, hp-symtab.h, ieee.h, + libiberty.h, md5.h, oasys.h, objalloc.h, obstack.h, os9k.h, + partition.h, progress.h, safe-ctype.h, sort.h, splay-tree.h, + symcat.h, ternary.h, xregex2.h, xtensa-config.h, + xtensa-isa-internal.h, xtensa-isa.h + +2005-04-25 Kaveh R. Ghazi + + * libiberty.h (unlock_std_streams): New. + +2005-04-19 Kaveh R. Ghazi + + * hashtab.h, libiberty.h, objalloc.h, splay-tree.h, ternary.h: + Don't use the PTR macro. + + * sort.h: Don't use the PARAMS macro. + +2005-04-16 Kaveh R. Ghazi + + * libiberty.h (unlock_stream): New. + +2005-04-13 Kaveh R. Ghazi + + * libiberty.h (fopen_unlocked, fdopen_unlocked, freopen_unlocked): + Remove parameter names. + +2005-04-11 Kaveh R. Ghazi + + * libiberty.h (fopen_unlocked, fdopen_unlocked, freopen_unlocked): + Provide prototypes for new functions. + +2005-03-29 Ian Lance Taylor + + * libiberty.h: Fix indentation. + +2005-03-28 Ian Lance Taylor + + * libiberty.h: Include . + (PEX_RECORD_TIMES, PEX_USE_PIPES, PEX_SAVE_TEMPS): Define. + (PEX_LAST, PEX_SEARCH, PEX_SUFFIX, PEX_STDERR_TO_STDOUT): Define. + (PEX_BINARY_INPUT, PEX_BINARY_OUTPUT): Define. + (pex_init, pex_run, pex_read_output): Declare. + (pex_get_status, pex_get_times, pex_free, pex_one): Declare. + (struct pex_time): Define. + +2005-03-28 Mark Mitchell + + * libiberty.h (ffs): Declare, if necessary. + +2005-03-27 Gabriel Dos Reis + + * xregex2.h (_RE_ARGS): Remove definition and uses. + +2005-03-27 Gabriel Dos Reis + + * ternary.h: Don't use PARAMS anymore. + +2005-03-27 Gabriel Dos Reis + + * partition.h: Remove use of PARAMS. + * obstack.h: Remove conditional prototypes __STDC__. + * objalloc.h: Remove use of PARAMS. + * splay-tree.h: Likewise. + +2005-03-27 Gabriel Dos Reis + + * md5.h: Remove definition and uses of __P. + * dyn-string.h: Remove uses of PARAMS. + * fibheap.h: Likewise. + * floatformat.h: Likewise. + * hashtab.h: Likewise. + +2005-03-26 Gabriel Dos Reis + + * demangle.h: Remove uses of PARAMS. + + * libiberty.h (ANSI_PROTOTYPES): Remove guard since + ANSI_PROTOTYPES is always assumed. + Remove uses of PARAMS throughout. + +2005-03-24 Kaveh R. Ghazi + + * libiberty.h (xstrndup): Declare. + +2005-03-22 Kaveh R. Ghazi + + * libiberty.h (make_relative_prefix): Add ATTRIBUTE_MALLOC. + +2005-03-09 Mark Mitchell + + * libiberty.h (gettimeofday): Declare. + +2005-03-01 Jan Beulich + + * libiberty.h: Declare unlink_if_ordinary. + +2005-02-14 Paolo Bonzini + + PR bootstrap/19818 + * ansidecl.h (PARAMS): Guard from redefinition. + +2004-12-11 Ben Elliston + + * fibheap.h (struct fibnode): Only use unsigned long bitfields + when __GNUC__ is defined and ints are less than 32-bits wide. + +2004-10-07 Bob Wilson + + * xtensa-config.h (XSHAL_USE_ABSOLUTE_LITERALS, + XCHAL_HAVE_PREDICTED_BRANCHES, XCHAL_INST_FETCH_WIDTH): New. + (XCHAL_EXTRA_SA_SIZE, XCHAL_EXTRA_SA_ALIGN): Delete. + +2004-09-13 Aaron W. LaFramboise + + * libiberty.h (basename): Prototype for __MINGW32__. + +2004-09-04 Kaveh R. Ghazi + + * ansidecl.h (ATTRIBUTE_SENTINEL): Define. + * libiberty.h (concat, reconcat, concat_length, concat_copy, + concat_copy2): Use ATTRIBUTE_SENTINEL. + +2004-08-02 Gabriel Dos Reis + + * libiberty.h (XDELETE, XDELETEVEC, XRESIZEVEC): Remove any + const-qualification before disposal. + +2004-07-24 Bernardo Innocenti + + * ansidecl.h (ARG_UNUSED): New Macro. + +2004-07-24 Bernardo Innocenti + + * libiberty.h (XNEW, XCNEW, XNEWVEC, XCNEWVEC, XOBNEW): Move here from + libcpp/internal.h. + (XDELETE, XRESIZEVEC, XDELETEVEC, XNEWVAR, XCNEWVAR, XRESIZEVAR): New + macros. + +2004-07-21 Paolo Bonzini + + * ansidecl.h (ATTRIBUTE_PURE): New. + +2004-07-13 Bernardo Innocenti + + * libiberty.h (ASTRDUP): Add casts required for stricter + type conversion rules of C++. + * obstack.h (obstack_free): Likewise. + +2004-05-04 Andreas Jaeger + + * demangle.h: Do not use C++ reserved keyword typename as + parameter for cplus_demangle_fill_builtin_type. + +2004-04-22 Richard Henderson + + * hashtab.h (struct htab): Add size_prime_index. + +2004-04-13 Jeff Law + + * hashtab.h (htab_remove_elt_with_hash): Prototype new function. + +2004-03-30 Zack Weinberg + + * hashtab.h, splay-tree.h: Use new shorter form of GTY markers. + +2004-02-24 Ian Lance Taylor + + * dyn-string.h: Update copyright date. + +2004-02-23 Ian Lance Taylor + + * dyn-string.h: Remove test of IN_LIBGCC2 and IN_GLIBCPP_V3 and + the associated #defines. + +2004-01-12 Ian Lance Taylor + + * demangle.h: Instead of checking ANSI_PROTOTYPES, just include + "libiberty.h". + + * demangle.h: If ANSI_PROTOTYPES is defined, include . + + * demangle.h (enum demangle_component_type): Define. + (struct demangle_operator_info): Declare. + (struct demangle_builtin_type_info): Declare. + (struct demangle_component): Define. + (cplus_demangle_fill_component): Declare. + (cplus_demangle_fill_name): Declare. + (cplus_demangle_fill_builtin_type): Declare. + (cplus_demangle_fill_operator): Declare. + (cplus_demangle_fill_extended_operator): Declare. + (cplus_demangle_fill_ctor, cplus_demangle_fill_dtor): Declare. + (cplus_demangle_v3_components): Declare. + (cplus_demangle_print): Declare. + +For older changes see ChangeLog-9103 + +Local Variables: +mode: change-log +left-margin: 8 +fill-column: 74 +version-control: never +End: diff --git a/include/ChangeLog-9103 b/include/ChangeLog-9103 new file mode 100644 index 0000000..f4f7aa1 --- /dev/null +++ b/include/ChangeLog-9103 @@ -0,0 +1,2682 @@ +2003-12-19 Andreas Tobler + + * include/fibheap.h (fibnode): Use __extension__ for + bit-fields mark and degree if __GNUC__. + +2003-12-18 Kazu Hirata + + * include/fibheap.h (fibnode): Use unsigned long int for + bit-fields if __GNUC__ is defined. + +2003-12-19 Andreas Tobler + + * fibheap.h (fibnode): Use __extension__ for + bit-fields mark and degree if __GNUC__. + +2003-12-18 Kazu Hirata + + * fibheap.h (fibnode): Use unsigned long int for + bit-fields if __GNUC__ is defined. + +2003-12-04 H.J. Lu + + * bfdlink.h (bfd_link_info): Change relax_finalizing to + need_relax_finalize. + +2003-12-03 Alan Modra + + * bfdlink.h (struct bfd_link_hash_entry): Rename "next" to "und_next". + +2003-12-02 Alan Modra + + * bfdlink.h (struct bfd_link_info): Remove mpc860c0 field. + +2003-11-14 Nick Clifton + + * dis-asm.h (struct disassemble_info): Add new field + 'symbol_is_valid' which is a function which can tell the + disassembler to skip certain symbols as they should not be + displayed to the user. + (arm_symbol_is_valid): New prototype. This is the ARM + specific function for the symbol_is_valid field. + (generic_symbol_is_valid): New prototype. This is the default + function pointed to by the symbol_is_valid field. + +2003-11-06 Bruno Rohee + + * hp-symtab.h: Fix "the the" typo. + +2003-10-24 H.J. Lu + + * bfdlink.h (bfd_elf_version_expr): Add "symbol" and remove + "wildcard". + +2003-10-22 Joseph S. Myers + + * obstack.h: Merge the following change from gnulib: + 2003-10-21 Paul Eggert + * obstack.h (obstack_1grow_fast): Properly parenthesize arg. + (obstack_ptr_grow_fast, obstack_int_grow_fast): + Don't use lvalue casts, as GCC plans to remove support for them + in GCC 3.5. Reported by Joseph S. Myers. This bug + was also present in the non-GCC version, indicating that this + code had always been buggy and had never been widely used. + (obstack_1grow, obstack_ptr_grow, obstack_int_grow, obstack_blank): + Use the fast variant of each macro, rather than copying the + definiens of the fast variant; that way, we'll be more likely to + catch future bugs in the fast variants. + +2003-10-22 Jakub Jelinek + + * bfdlink.h (struct bfd_elf_version_expr): Remove match field. + Add wildcard and mask fields. + (BFD_ELF_VERSION_C_TYPE): Define. + (BFD_ELF_VERSION_CXX_TYPE): Likewise. + (BFD_ELF_VERSION_JAVA_TYPE): Likewise. + (struct bfd_elf_version_expr_head): New. + (struct bfd_elf_version_tree): Add match field. + Change type of globals and locals fields + to struct bfd_elf_version_expr_head. + +2003-09-22 Andrew Cagney + + * floatformat.h (struct floatformat): Add field "is_valid". + +2003-09-15 Andrew Cagney + + * floatformat.h (floatformat_to_double): Make input buffer constant. + (floatformat_from_double, floatformat_is_valid): Ditto. + +2003-09-15 Andrew Cagney + + * floatformat.h (struct floatformat): Make "exp_bias" signed. + +2003-09-15 Daniel Jacobowitz + + * floatformat.h (floatformat_is_valid): Add prototype. + +2003-08-27 Andrew Cagney + + * dis-asm.h (init_disassemble_info): Declare. + (INIT_DISASSEMBLE_INFO): Redefine as a call to + init_disassemble_info. + (INIT_DISASSEMBLE_INFO_NO_ARCH): Ditto. + +2003-08-20 Nick Clifton + + * bfdlink.h (enum report_method): New enum. Describes how to + report something. + (struct bfd_link_info): Delete fields 'no_undefined' and + 'allow_shlib_undefined'. Replace with + 'unresolved_symbols_in_objects' and + 'unresolved_symbols_in_shared_libs'. + +2003-08-07 Alan Modra + + * bfdlink.h: Remove PARAMS macro. Replace PTR with void *. + * dis-asm.h: Likewise. + +2003-07-09 Bob Wilson + + * xtensa-config.h: Undef all macros before defining them. + +2003-07-06 H.J. Lu + + * demangle.h: Support C++. + +2003-07-01 Zack Weinberg + + * filenames.h: New file imported from binutils. + +2003-06-30 Bob Wilson + + * xtensa-config.h: New file imported from binutils. + +2003-06-30 Bob Wilson + + * xtensa-config.h (XCHAL_HAVE_CONST16, XCHAL_HAVE_ABS, + XCHAL_HAVE_ADDX, XCHAL_HAVE_L32R): Define. + +2003-06-25 Alan Modra + + * bfdlink.h: Correct spelling of "relocatable". + +2003-06-22 Zack Weinberg + + * safe-ctype.h (HC_UNKNOWN, HC_ASCII, HC_EBCDIC): Rename to + HOST_CHARSET_UNKNOWN, HOST_CHARSET_ASCII, HOST_CHARSET_EBCDIC + respectively. + +2003-06-21 Zack Weinberg + + * safe-ctype.h (HC_UNKNOWN, HC_ASCII, HC_EBCDIC, HOST_CHARSET): + New #defines. + +2003-06-17 Kaveh R. Ghazi + + * ansidecl.h: Delete HAVE_LONG_DOUBLE GCC bootstrap support. + +2003-05-23 Jakub Jelinek + + * bfdlink.h (struct bfd_link_info): Add execstack and noexecstack. + +2003-06-03 H.J. Lu + + * bfdlink.h (LD_DEFINITION_IN_DISCARDED_SECTION): New. + +2003-05-30 Ulrich Drepper + Jakub Jelinek + + * bfdlink.h (struct bfd_link_info): Add pie and executable + bits. + +2003-05-21 Nick Clifton + + * bfdlink.h (struct bfd_link_hash_table): Fix typo in comment. + +2003-05-15 Jim Blandy + + * libiberty.h (hex_value): Make the value an unsigned int, to + avoid unexpected sign-extension when cast to unsigned types larger + than int --- like bfd_vma, on some platforms. + (_hex_value): Update declaration. + +2003-05-09 Alan Modra + + * xtensa-isa-internal.h (xtensa_isa_module_struct): Remove const on + gen_num_opcodes_fn return type. + +2003-05-07 Jason Merrill + + * hashtab.h (iterative_hash): Prototype. + (iterative_hash_object): New macro. + +2003-04-28 H.J. Lu + + * bfdlink.h (bfd_link_info): Add relax_finalizing. + +2003-04-23 H.J. Lu + + * bfdlink.h (bfd_link_callbacks): Add error_handler. + +2003-04-02 Bob Wilson + + * xtensa-config.h: Remove comment indicating that this is a + generated file. + +2003-04-01 Bob Wilson + + * dis-asm.h (print_insn_xtensa): Declare. + * xtensa-config.h: New file. + * xtensa-isa-internal.h: Likewise. + * xtensa-isa.h: Likewise. + +2003-03-17 Kaveh R. Ghazi + + * ansidecl.h (ATTRIBUTE_NONNULL, ATTRIBUTE_NULL_PRINTF, + ATTRIBUTE_NULL_PRINTF_1, ATTRIBUTE_NULL_PRINTF_2, + ATTRIBUTE_NULL_PRINTF_3, ATTRIBUTE_NULL_PRINTF_4, + ATTRIBUTE_NULL_PRINTF_5): New. + (ATTRIBUTE_PRINTF): Add ATTRIBUTE_NONNULL. + +2003-03-17 Jan Hubicka + + * hashtab.h (htab_traverse_noresize): Declare. + +2003-02-27 Kaveh R. Ghazi + + * libiberty.h: Document return value of physmem routines. + +2003-02-20 Kaveh R. Ghazi + + * libiberty.h (physmem_total, physmem_available): Prototype. + +2003-02-20 Daniel Jacobowitz + + * libiberty.h (lrealpath): Add declaration. + +2003-01-31 Grant Grundler + + * hppa.h (ldwa, ldda): Add ordered opcodes. + +2003-01-26 Daniel Jacobowitz + + * hashtab.h (htab_alloc_with_arg, htab_free_with_arg): Add new types. + (struct htab): Add alloc_arg, alloc_with_arg_f, free_with_arg_f. + (htab_create_alloc_ex): New prototype. + (htab_set_functions_ex): New prototype. + +2002-07-17 Geoffrey Keating + + * splay-tree.h (GTY): Define if undefined. + (splay_tree_allocate_fn): Return PTR for compatibility, not void *. + (struct splay_tree_node_s): Support gengtype. + (struct splay_tree_s): Likewise. Make allocate_data a PTR, + not a void *. + +2002-01-02 Ben Elliston + + * dis-asm.h (print_insn_iq2000): Declare. + +2002-12-24 Dmitry Diky + + * dis-asm.h: Add msp430 disassembler prototype. + +2002-12-27 Chris Demetriou + + * dis-asm.h (print_mips_disassembler_options): Prototype. + +2002-12-23 Alan Modra + + * bfdlink.h (struct bfd_link_info): Add "strip_discarded". + +2002-12-20 Alan Modra + + * bfdlink.h (struct bfd_link_info): Replace bfd_boolean fields with + bit-fields. Rearrange to put all like types together. + +2002-11-30 Alan Modra + + * bfdlink.h: Replace boolean with bfd_boolean. Formatting. + +2002-11-23 Simon Burge + + * libiberty.h (basename): Add NetBSD to the list. + +2002-11-22 Daniel Jacobowitz + + * libiberty.h (make_relative_prefix): Add prototype. + +2002-11-14 Egor Duda + + * bfdlink.h (struct bfd_link_info): Add new boolean + field pei386_runtime_pseudo_reloc. + +2002-10-26 Roger Sayle + + * partition.h: Close the extern "C" scope when compiling with C++. + +2002-10-26 Roger Sayle + DJ Delorie + + PR bootstrap/8351 + * getopt.h: Avoid prototyping getopt with no arguments in C++. + +2002-10-24 Nathan Tallent + + * ansidecl.h (__STDC__): Add (__alpha && __cplusplus) to the + list of platform compilers that may look, smell and act + like __STDC__ but that may not define it. + +2002-10-11 David O'Brien + + * getopt.h: getopt is in unistd.h (based on SUSv2). + +2002-09-26 Andrew Cagney + + * regs/: Delete directory. + +2002-09-19 Alexandre Oliva + + * libiberty.h (asprintf, vasprintf): Don't declare them if the + corresponding HAVE_DECL_ macro is 1. + +2002-09-19 Nathan Tallent + + * dis-asm.h: Remove (errant) trailing semicolon (;) from the + extern "C" { } declaration. + +2002-09-04 Nick Clifton + + * dis-asm.h (print_ppc_disassembler_options): Prototype. + +2002-08-28 Michael Hayes + + * dis-asm.h: Add standard disassembler for tic4x. + +2002-08-07 H.J. Lu + + * bfdlink.h (bfd_link_info): Add allow_undefined_version. + (bfd_elf_version_expr): Add symver and script. + +2002-07-31 Ian Dall + + * bfdlink.h (bfd_link_common_skip_ar_symbols): New enum. + (struct bfd_link_info): Add new field 'common_skip_ar_symbols'. + +2002-07-19 Denis Chertykov + Matthew Green + + * dis-asm.h (print_insn_ip2k): Declare. + +2002-07-01 Alan Modra + + * bfdlink.h (struct bfd_sym_chain): Declare. + (struct bfd_link_info): Add gc_sym_list. Formatting fixes. + +2002-06-25 Alan Modra + + * demangle.h: #include "ansidecl.h" rather than #include . + * fibheap.h: Likewise. + * hashtab.h: Likewise. + * partition.h: Likewise. + * sort.h: Likewise. + * splay-tree.h: Likewise. + +2002-06-24 Alan Modra + + * libiberty.h (basename): Don't declare if HAVE_DECL_BASENAME. + * getopt.h (getopt): Don't declare if HAVE_DECL_GETOPT. + +2002-06-18 Dave Brolley + + From Catherine Moore: + * dis-asm.h (print_insn_frv): New prototype. + +2002-06-09 Andrew Cagney + + * remote-sim.h: Move to directory gdb/. + * callback.h: Move to directory gdb/. + +2002-06-07 Charles Wilson + + * bfdlink.h (struct bfd_link_info): Change type of + pei386_auto_import field to int so that -1 can mean enabled by + default and 1 can mean enabled by command line switch. + +2002-06-06 DJ Delorie + + * hashtab.h (htab): Rearrange new members for backward + compatibility. + (htab_create): Don't use a macro that requires other headers. + +2002-06-05 Geoffrey Keating + + * hashtab.h (htab_create): Restore prototype for backward + compatibility. + (htab_try_create): Likewise. + +2002-05-22 Geoffrey Keating + + * hashtab.h (struct htab): Update for change to length specifier. + +2002-05-10 Geoffrey Keating + + * hashtab.h (GTY): Define if undefined. + (htab_alloc): New typedef. + (htab_free): New typedef. + (struct htab): Support gengtype; allow user-specified memory + allocation. + (htab_create_alloc): New. + (htab_create): Replace with #define. + (htab_try_create): Delete. + +2002-05-28 Kuang Hwa Lin + + * dis-asm.h: Prototype print_insn_dlx. + +2002-05-23 Andrew Cagney + + * sim-d10v.h: Delete file. Moved to include/gdb/. + +2002-05-21 H.J. Lu (hjl@gnu.org) + + * bfdlink.h (bfd_link_info): Add allow_multiple_definition. + +2002-05-17 J"orn Rennecke + + * dis-asm.h (print_insn_shl, print_insn_sh64l): Remove prototype. + +2002-04-16 David S. Miller + + * xregex2.h (__restrict_arr): Define to __restrict on GCC + 3.1 and later. Do not redefine. + +2002-04-01 Phil Edwards + + * dyn-string.h: Also allow IN_GLIBCPP_V3 to redefine names. + +2002-03-10 Daniel Jacobowitz + + * gdb: New directory. + +2002-03-06 Andrew Cagney + + * floatformat.h (floatformat_arm_ext): Delete declaration. + +2002-02-21 Jim Blandy + + Allow the user to specify functions for allocating memory for + splay tree roots and nodes. + * splay-tree.h (splay_tree_allocate_fn, splay_tree_deallocate_fn): + New types. + (splay_tree): New fields: `allocate', `deallocate', and + `allocate_data'. + (splay_tree_new_with_allocator): New function declaration. + +2002-02-15 Alan Modra + + Support arbitrary length fill patterns. + * bfdlink.h (enum bfd_link_order_type): Remove bfd_fill_link_order. + (struct bfd_link_order): Remove fill. Add data.size. + +2002-02-08 Alexandre Oliva + + Contribute sh64-elf. + 2000-11-25 Hans-Peter Nilsson + * dis-asm.h (print_insn_sh64): New prototype. + (print_insn_sh64l): New prototype. + (print_insn_sh64x_media): New prototype. + +2002-02-05 Frank Ch. Eigler + + * dis-asm.h (disassemble_info): New field `insn_sets'. + (INIT_DISASSEMBLE_INFO): Clear it. + +2002-02-05 Jason Merrill + + * demangle.h (cplus_demangle_v3): Add "options" parm. + (cplus_demangle_v3_type): Remove prototype. + (DMGL_VERBOSE): New macro. + (DMGL_TYPES): New macro. + +2002-02-02 H.J. Lu (hjl@gnu.org) + + * demangle.h (cplus_demangle_v3_type): New prototype. + +2002-01-31 Ivan Guzvinec + + * dis-asm.h : Add support for or32 targets + +2002-01-28 Kaveh R. Ghazi + + * libiberty.h (C_alloca): Add ATTRIBUTE_MALLOC. + +2002-01-27 David O'Brien + + * cgen.h (BFD_VERSION): Use BFD_VERSION_DATE instead. + +2001-12-14 Nick Clifton + + * dis-asm.h (INIT_DISASSEMBLE_INFO_NO_ARCH): Initialise the + disassembler_options field (to NULL). + +2001-12-13 Jakub Jelinek + + * bfdlink.h (struct bfd_link_info): Add eh_frame_hdr field. + +2001-12-07 Geoffrey Keating + + * dis-asm.h (print_insn_xstormy16): Declare. + +2001-12-06 Richard Henderson + + * demangle.h (no_demangling): New. + (NO_DEMANGLING_STYLE_STRING): New. + +2001-11-14 Alan Modra + + * dis-asm.h (print_insn_i386): Declare. + +2001-11-11 Timothy Wall + + * dis-asm.h: Fix comment to refer to octets rather than bytes. + +2001-10-30 Hans-Peter Nilsson + + * dis-asm.h (print_insn_mmix): Add prototype. + +2001-10-24 Neil Booth + + * safe-ctype.h (_sch_isbasic, IS_ISOBASIC): New. + +2001-10-22 Kaveh R. Ghazi + + * libiberty.h (hex_init): Revert delete. + + * libiberty.h (_hex_value): Const-ify. + (hex_init): Delete. + +2001-10-16 Christopher Faylor + + * filenames.h: Add cygwin to the list of dosish style path systems. + +2001-10-07 Kaveh R. Ghazi + + * demangle.h (demangler_engine): Const-ify. + * libiberty.h (buildargv): Likewise. + +2001-10-03 Vassili Karpov + + * bfdlink.h (struct bfd_link_info): Add nocopyreloc field. + +2001-09-24 Kaveh R. Ghazi + + * libiberty.h (reconcat): New function. + +2001-09-18 Kaveh R. Ghazi + + * libiberty.h (concat, concat_length, concat_copy, concat_copy2, + ACONCAT): Improve comments. + +2001-09-18 Alan Modra + + * objalloc.h (OBJALLOC_ALIGN): Define using offsetof. + +2001-09-17 Kaveh R. Ghazi + + * libiberty.h (concat_length, concat_copy, concat_copy2, + libiberty_concat_ptr, ACONCAT): New. + + * libiberty.h (ASTRDUP): New macro. + libiberty_optr, libiberty_nptr, libiberty_len): Declare. + +2001-08-29 Kaveh R. Ghazi + + * ansidecl.h: Update comments reflecting previous change. + +2001-08-27 Kaveh R. Ghazi + + * ansidecl.h (VA_OPEN, VA_CLOSE): Allow multiple uses. + +2001-08-25 Nick Clifton + + * bfdlink.h (struct bfd_link_info): Change 'spare_dynamic_tags' to + unsigned to remove a compile time warning message. + +2001-08-24 H.J. Lu + + * bfdlink.h (bfd_link_hash_table_type): New. The linker hash + table type, bfd_link_generic_hash_table and + bfd_link_elf_hash_table. + (bfd_link_hash_table): Add a new field, type, for the linker + hash table type. + +2001-08-23 Jakub Jelinek + + * bfdlink.h (struct bfd_link_info): Add combreloc and + spare_dynamic_tags fields. + +2001-08-23 Lars Brinkhoff + + * dyn-string.h, fibheap.h, partition.h, sort.h, splay-tree.h: + replace "GNU CC" with "GCC". + +2001-08-21 Richard Henderson + + * fibheap.h: Tidy formatting. + (fibnode_t): Limit degree to 31 bits to avoid warning. + +2001-08-20 Daniel Berlin + + * fibheap.h: New file. Fibonacci heap. + +2001-08-20 Andrew Cagney + + * floatformat.h (floatformat_arm_ext): Document as deprecated. + (floatformat_arm_ext_big, floatformat_arm_ext_littlebyte_bigword) + (floatformat_ia64_spill_little, floatformat_ia64_quad_little) + (floatformat_ia64_spill_big, floatformat_ia64_quad_big) + (floatformat_m88110_harris_ext): Declare. + +2001-08-18 Zack Weinberg + + * ansidecl.h: Reorganize for readability, remove documentation + of obsolete macros, document PARAMS and VPARAMS. Add new + macros VA_OPEN, VA_CLOSE, and VA_FIXEDARG for nicer variadic + function implementation. + +2001-08-16 Richard Henderson + + * hashtab.h (htab_hash_string): Declare. + +2001-08-10 Andrew Cagney + + * libiberty.h (lbasename): Change function declaration to return a + const char pointer. + +2001-08-02 Mark Kettenis + + * xregex.h (_REGEX_RE_COMP): Define. + (re_comp): Define to xre_comp. + (re_exec): Define to xre_exec. + +2001-08-02 Charles Wilson + + * bfdlink.h (struct bfd_link_info): add new boolean + field pei386_auto_import. + +2001-07-18 Andreas Jaeger + + * xregex2.h: Place under LGPL version 2.1. + +2001-07-10 Jeff Johnston + + * xregex.h: New file to support libiberty regex. + * xregex2.h: Ditto. + +2001-06-15 Hans-Peter Nilsson + + * bfdlink.h (struct bfd_link_info): New member export_dynamic. + +2001-05-16 Matt Kraai + + * partition.h: Fix misspelling of `implementation'. + +2001-05-10 Kaveh R. Ghazi + + * ansidecl.h (NULL_PTR): Delete. + +2001-05-07 Zack Weinberg + + * demangle.h: Use PARAMS for all prototypes. + * ternary.h: Use PARAMS for all prototypes. Use PTR, not void *. + Make arguments constant where possible. + +2001-05-07 Mark Mitchell + + * splay-tree.h (splay_tree_max): New function. + (splay_tree_min): Likewise. + +2001-04-27 Johan Rydberg + + * dis-asm.h (print_insn_openrisc): Add prototype. + +2001-04-15 Daniel Berlin + + * ternary.h: New file - Ternary search tree header. + +2001-04-13 Jakub Jelinek + + * bfdlink.h (bfd_link_discard): Add discard_sec_merge. + +2001-04-03 Zack Weinberg + + * ansidecl.h: All logic from gcc/gansidecl.h moved here. + +2001-03-31 Kaveh R. Ghazi + + * libiberty.h (alloca): Handle setting C_ALLOCA. + +2001-03-20 Jim Blandy + + * demangle.h (enum gnu_v3_constructor_kinds, + is_gnu_v3_mangled_ctor, enum gnu_v3_destructor_kinds, + is_gnu_v3_mangled_dtor): New declarations. + +2001-03-14 Nick Clifton + + * ansidecl.h: Fix copyright dates. + * demangle.h: Fix copyright dates. + * floatformat.h: Fix copyright dates. + * fnmatch.h: Fix copyright dates. + * getopt.h: Fix copyright dates. + * libiberty.h: Add FSF copyright notice. + * md5.h: Fix copyright dates. + * obstack.h: Fix copyright dates. + * splay-tree.h: Fix copyright dates. + +2001-03-10 Neil Booth + John David Anglin + + * libiberty.h: Add lbasename. + +2001-03-06 Zack Weinberg + + * libiberty.h: Prototype C_alloca; define alloca to either + __builtin_alloca or C_alloca as appropriate. + +2001-03-01 John David Anglin + + * safe-ctype.h (_sch_test): Cast enum bit to unsigned short int for pcc + compatibility. + +2001-02-18 lars brinkhoff + + * dis-asm.h: Add PDP-11 target. + +2001-02-09 Martin Schwidefsky + + * dis-asm.h: Add linux target for S/390. + +2001-01-11 Peter Targett + + * dis-asm.h (arc_get_disassembler): Correct declaration. + +2001-01-09 Philip Blundell + + * bin-bugs.h (REPORT_BUGS_TO): Set to `bug-binutils@gnu.org'. + +2000-12-18 Joseph S. Myers + + * COPYING: Update to current + ftp://ftp.gnu.org/pub/gnu/Licenses/COPYING-2.0 (fixes references + to 19yy as example year in copyright notice). + +2000-12-19 Hans-Peter Nilsson + + * dis-asm.h (struct disassemble_info): New member "section". + (INIT_DISASSEMBLE_INFO_NO_ARCH): Initialize private_data member. + Initialize section member. + +2000-12-16 Herman A.J. ten Brugge + + * safe-ctype.h: Make code work on all targets and not just on + targets where a char is 8 bits. + +2000-12-10 Fred Fish + + * bfdlink.h (struct bfd_link_info): Add new allow_shlib_undefined + member to struct for systems where it is normal to have undefined + symbols in shared libraries at runtime and the runtime linker + takes care of redirecting them. + +2000-12-07 Zack Weinberg + + * safe-ctype.h: New file. + +2000-12-06 Rodney Brown + + * getopt.h obstack.h: Standarize copyright statement. + +2000-12-04 Richard Henderson + + * demangle.h: Change "new_abi" to "v3" everywhere. + +2000-11-22 Zack Weinberg + + * libiberty.h: Move #includes to top. Prototype xmalloc_failed. + +2000-11-15 Kenneth Block + + * demangle.h: Add gnat and java demangle styles. + +2000-11-04 Hans-Peter Nilsson + + * hashtab.h (struct htab): Add member return_allocation_failure. + (htab_try_create): New prototype. Mention which functions may + return NULL when this is used. + +2000-11-03 Hans-Peter Nilsson + + * hashtab.h: Change void * to PTR where necessary. + +2000-10-11 Mark Mitchell + + * splay-tree.h (splay_tree_predecessor): Declare. + +2000-09-29 Hans-Peter Nilsson + + * dis-asm.h: Declare cris_get_disassembler, not print_insn_cris. + Fix typo in comment. + +2000-09-28 John David Anglin + + * alloca-conf.h: New file (copied from libiberty). + +2000-09-05 John David Anglin + + * md5.h (md5_uint32): Choose via INT_MAX instead of UINT_MAX. + +2000-09-04 Alex Samuel + + * dyn-string.h: Adjust formatting. + (dyn_string_insert_char): New macro. New declaration. + +2000-08-28 Jason Merrill + + * md5.h: New file. + +2000-08-24 Greg McGary + + * libiberty.h (ARRAY_SIZE): New macro. + +2000-07-29 Nick Clifton + + * os9k.h: Add copyright notice. + Fix formatting. + +2000-07-22 Jason Eckhardt + + * dis-asm.h (print_insn_i860): Add prototype. + +2000-07-20 H.J. Lu + + * bfdlink.h (bfd_link_info): Add new_dtags. + +2000-07-20 Hans-Peter Nilsson + + * dis-asm.h (print_insn_cris): Declare. + +2000-07-19 H.J. Lu (hjl@gnu.org) + + * bfdlink.h (bfd_link_info): Add flags and flags_1. + +2000-06-05 DJ Delorie + + * MAINTAINERS: new + +2000-06-21 Alex Samuel + + * dyn-string.h (dyn_string_init, dyn_string_new, + dyn_string_delete, dyn_string_release, dyn_string_resize, + dyn_string_clear, dyn_string_copy, dyn_string_copy_cstr, + dyn_string_prepend, dyn_string_prepend_cstr, dyn_string_insert, + dyn_string_insert_cstr, dyn_string_append, dyn_string_append_cstr, + dyn_string_append_char, dyn_string_substring_dyn_string_eq): + Define as same name with __cxa_ prepended, if IN_LIBGCC2. + (dyn_string_init, dyn_string_copy, dyn_string_copy_cstr, + dyn_string_prepend, dyn_string_prepend_cstr, dyn_string_insert, + dyn_string_insert_cstr, dyn_string_append, dyn_string_append_cstr, + dyn_string_append_char, dyn_string_substring): Change return type + to int. + +2000-06-18 Stephane Carrez + + * dis-asm.h (print_insn_m68hc12): Define. + (print_insn_m68hc11): Likewise. + +2000-06-18 Nick Clifton + + * os9k.h: Change values of MODSYNC and CRCCON due to bug report + from Russ Magee . + +2000-06-07 Kaveh R. Ghazi + + * demangle.h (demangling_styles): Remove trailing comma in enum. + + * dyn-string.h (dyn_string_append_char): Change parameter from + char to int. + +2000-06-04 Alex Samuel + + * dyn-string.h: Move here from gcc/dyn-string.h. Add new functions. + + * demangle.h (DMGL_GNU_NEW_ABI): New macro. + (DMGL_STYLE_MASK): Or in DMGL_GNU_NEW_ABI. + (current_demangling_style): Add gnu_new_abi_demangling. + (GNU_NEW_ABI_DEMANGLING_STYLE_STRING): New macro. + (GNU_NEW_ABI_DEMANGLING): Likewise. + (cplus_demangle_new_abi): New declaration. + +Tue May 30 16:53:34 2000 Andrew Cagney + + * floatformat.h (struct floatformat): Add field name. + +2000-05-26 Eli Zaretskii + + * filenames.h: New file. + (HAVE_DOS_BASED_FILE_SYSTEM, IS_DIR_SEPARATOR) + (IS_ABSOLUTE_PATH, FILENAME_CMP): New macros. + +2000-05-23 Kaveh R. Ghazi + + * getopt.h (getopt): Also check HAVE_DECL_* when prototyping. + + * libiberty.h (basename): Likewise. + +2000-05-17 S. Bharadwaj Yadavalli + Rick Gorton + + * bfdlink.h (struct bfd_link_info): Add emitrelocations flag. + +2000-05-08 Alan Modra + + * dis-asm.h (print_insn_tic54x): Declare. + +2000-05-06 Zack Weinberg + + * ansidecl.h: #define __extension__ to nothing if + GCC_VERSION < 2008. + +2000-05-04 Kaveh R. Ghazi + + * demangle.h (demangler_engine): Constify. + +Thu May 4 17:15:26 2000 Philippe De Muyter + + * sort.h (sys/types.h): File included unconditionnaly. + (stddef.h): File include only #ifdef __STDC__. + +2000-05-03 Zack Weinberg + + * symcat.h: Remove #endif label. + +2000-04-28 Kenneth Block + Jason Merrill + + * demangle.h (libiberty_demanglers): new table for different styles. + (cplus_demangle_set_style): New function for setting style. + (cplus_demangle_name_to_style): New function to translate name. + +2000-04-24 Mark Mitchell + + * hashtab.h (hash_pointer): Declare. + (eq_pointer): Likewise. + +2000-04-23 Mark Mitchell + + * sort.h: New file. + +Fri Apr 21 13:20:53 2000 Richard Henderson + David Mosberger + + * dis-asm.h (print_insn_ia64): Declare. + +Tue Apr 18 16:22:30 2000 Richard Kenner + + * hashtab.h (enum insert_option): New type. + (htab_find_slot, htab_find_slot_with_hash): Use it. + +2000-04-17 Kaveh R. Ghazi + + * symcat.h: Honor autoconf macro HAVE_STRINGIZE. Add + comments/caveats with regard to traditional C behavior. + +2000-04-05 Richard Henderson + + * splay-tree.h (splay_tree_remove): Declare. + +2000-04-04 Alan Modra + + * bin-bugs.h (REPORT_BUGS_TO): Remove translated part. + +2000-04-03 Alan Modra + + * bin-bugs.h: New file. + +2000-03-30 Mark Mitchell + + * hashtab.h (hashval_t): New type. + (htab_find_with_hash): Use it as an argument. + (htab_find_slot_with_hash): Likewise. + +2000-03-27 Denis Chertykov + + * dis-asm.h (print_insn_avr): Declare. + +2000-03-14 Bernd Schmidt + + * hashtab.h (htab_trav): Modify type so that first arg is of type + void **. + (htab_find_with_hash, htab_find_slot_with_hash): Declare new + functions. + +2000-03-09 Alex Samuel + + * partition.h: New file. + +2000-03-09 Zack Weinberg + + * hashtab.h (struct htab): Add del_f. + (htab_del): New type. + (htab_create): Add fourth argument. + +2000-03-08 Zack Weinberg + + * hashtab.h (hash_table_t): Rename to htab_t. + (struct hash_table): Rename to struct htab. Shorten element + names. Reorder elements by size. + (htab_hash, htab_eq, htab_trav): New typedefs for the callback + function pointers. + (hash_table_entry_t): Discard; just use void * for element + type. + +2000-03-01 H.J. Lu + + * bfdlink.h (bfd_link_callbacks): Add a boolean arg to + the undefined_symbol callback. + +2000-02-23 Linas Vepstas + + * dis-asm.h (print_insn_i370): Declare. + +Tue Feb 22 15:19:54 2000 Andrew Cagney + + * remote-sim.h (sim_trace): Document return values. + (sim_set_trace): Declare. Deprecate. + +2000-02-21 Alan Modra + + * dis-asm.h (struct disassemble_info): Change `length' param of + read_memory_func to unsigned. Change type of `buffer_length' and + `octets_per_byte' to unsigned. + (buffer_read_memory): Change `length' param to unsigned. + +2000-02-16 Nick Clifton + + * dis-asm.h: Add prototypes for ARM register name functions. + +Wed Feb 9 18:45:49 2000 Andrew Cagney + + * wait.h: Delete. No longer used by GDB. + +Tue Feb 8 17:01:13 2000 Andrew Cagney + + * remote-sim.h (sim_resume): Clarify use of SIGGNAL. + (sim_stop_reason): Clarify meaning of sim_signalled. + +2000-02-03 Timothy Wall + + * dis-asm.h (struct disassemble_info): Added octets_per_byte + field and initialize it to one (1). + +2000-01-27 Nick Clifton + + * dis-asm.h: Add prototype for disassembler_usage(). + Add prototype for arm_disassembler_options(). + Remove prototype for arm_toggle_regnames(). + Add prototype for parse_arm_disassembler_option(). + +Sat Jan 1 19:06:52 2000 Hans-Peter Nilsson + + * symcat.h (STRINGX) [!__STDC__ || ALMOST_STDC]: Change "?" to "s" + to stringify argument s. + +Wed Dec 15 11:22:56 1999 Jeffrey A Law (law@cygnus.com) + + * hp-symtab.h (HP_LANGUAGE_FORTRAN): New enumeration constant. + (HP_LANGUAGE_F77): Define using HP_LANGUAGE_FORTRAN. + +1999-12-15 Doug Evans + + * dis-asm.h: Enclose in extern "C" ifdef __cplusplus. + +1999-12-05 Mark Mitchell + + * splay-tree.h (struct splay_tree_node): Rename to ... + (struct splay_tree_node_s): ... this. + (struct splay_tree): Rename to ... + (struct splay_tree_s): ... this. + +1999-11-30 Kaveh R. Ghazi + + * ansidecl.h (ATTRIBUTE_MALLOC): New macro. + + * libiberty.h (buildargv, dupargv, concat, choose_temp_base, + make_temp_file, xmalloc, xcalloc, xstrdup, xmemdup): Add + ATTRIBUTE_MALLOC. + (xatexit): Remove __GNUC__ check, add ATTRIBUTE_NORETURN. + +1999-11-28 Kaveh R. Ghazi + + * libiberty.h: Include stdarg.h when ANSI_PROTOTYPES is defined. + (asprintf, vasprintf): Provide declarations. + +Wed Nov 10 12:43:21 1999 Philippe De Muyter + Kaveh R. Ghazi + + * ansidecl.h: Define and test `GCC_VERSION', not `HAVE_GCC_VERSION'. + +1999-11-04 Jimmy Guo + + * hp-symtab.h (dntt_type_fparam): Add doc_ranges, misc_kind + fields, change location type to CORE_ADDR from int. + (dntt_type_const): Name the 5th field location_type. + +Sun Oct 24 19:11:32 1999 Andrew Cagney + + * sim-d10v.h (SIM_D10V_TS2_DMAP_REGNUM): Define. + +1999-10-23 08:51 -0700 Zack Weinberg + + * hashtab.h: Give hash_table_t a struct tag. Add prototypes + for clear_hash_table_slot and traverse_hash_table. Correct + prototype of all_hash_table_collisions. + +Sat Oct 23 19:00:13 1999 Andrew Cagney + + * sim-d10v.h: New file. + +Fri Oct 15 01:47:51 1999 Vladimir Makarov + + * hashtab.h: New file. + +1999-10-10 Kaveh R. Ghazi + + * ansidecl.h (HAVE_GCC_VERSION): New macro. Use it instead of + explicitly testing __GNUC__ and __GNUC_MINOR__. + + (ATTRIBUTE_PRINTF): Use `__format__', not `format'. + +1999-09-25 Kaveh R. Ghazi + + * libiberty.h (make_temp_file): Add a prototype. + +Tue Sep 14 00:35:02 1999 Marc Espie + + * libiberty.h (basename): OpenBSD has a correct prototype. + (xrealloc): Remove outdated comment. + +1999-09-07 Jeff Garzik + + * libiberty.h (xmemdup): Add prototype for new function. + +1999-09-04 Steve Chamberlain + + * dis-asm.h (print_insn_pj): Declare. + +1999-09-01 Kaveh R. Ghazi + + * obstack.h (obstack_grow, obstack_grow0): Move (char*) casts + in calls to `_obstack_memcpy' from here ... + + (_obstack_memcpy): ... to here, except in the __STDC__ case which + doesn't need it. + +1999-08-30 Kaveh R. Ghazi + + * libiberty.h (getpwd): Prototype. + +1999-08-01 Mark Mitchell + + * splay-tree.h (splay_tree_insert): Return the new node. + +1999-07-11 Ian Lance Taylor + + * ansidecl.h: Copy attribute support macros from egcs. + +1999-06-22 Mark Mitchell + + * bfdlink.h (struct bfd_link_hash_entry): Add init_function and + fini_function. + +1999-06-20 Mark Mitchell + + * mips.h (Elf32_Internal_Msym): New structure. + (Elf32_External_Msym): Likewise. + (ELF32_MS_REL_INDEX): New macro. + (ELF32_MS_FLAGS): Likewise. + (ELF32_MS_INFO): Likewise. + +1999-06-14 Nick Clifton + + * dis-asm.h (arm_toggle_regnames): New prototype. + (struct diassemble_info): New field: disassembler_options. + +1999-04-11 Richard Henderson + + * bfdlink.h (bfd_elf_version_expr): Rename `match' to `pattern'. + Add `match' callback function. + +1999-04-10 Richard Henderson + + * bfdlink.h (bfd_link_info): Add no_undefined. + +1999-04-08 Nick Clifton + + * dis-asm.h: Add prototype for print_insn_mcore. + +1999-04-02 Mark Mitchell + + * splay-tree.h (splay_tree_compare_pointers): Declare. + +1999-03-30 Mark Mitchell + + * splay-tree.h (splay_tree_compare_ints): Declare. + +Wed Mar 24 12:46:29 1999 Andrew Cagney + + * libiberty.h (basename): Cygwin{,32} should have the prototype. + +1999-02-22 Jim Lemke + + * bfdlink.h (bfd_link_info): add field "mpc860c0". + +Mon Feb 1 21:05:46 1999 Catherine Moore + + * dis-asm.h (print_insn_i386_att): Declare. + (print_insn_i386_intel): Declare. + +1998-12-30 Michael Meissner + + * dis-asm.h (INIT_DISASSEMBLE_INFO_NO_ARCH): Cast STREAM and + FPRINTF_FUNC to avoid compiler warnings. + +Wed Dec 30 16:07:14 1998 David Taylor + + * dis-asm.h: change void * to PTR (two places). + +Mon Dec 14 09:53:31 1998 Kaveh R. Ghazi + + * demangle.h: Don't check IN_GCC anymore. + * splay-tree.h: Likewise. + +Tue Dec 8 00:30:31 1998 Elena Zannoni + + The following changes were made by Elena Zannoni + and Edith Epstein + as part of a project to merge in + changes made by HP; HP did not create ChangeLog entries. + + * dis-asm.h (struct disassemble_info): change the type of stream + from FILE* to void*, for use with gdb's new type GDB_FILE. + (fprintf_ftype): change FILE* parameter type to void*. + + * demangle.h: (DMGL_EDG): new macro for Kuck and Associates + (DMGL_STYLE_MASK): modify to include Kuck and Assoc style + (demangling_styles): add new edg_demangling style + (EDG_DEMANGLING_STYLE_STRING): new macro + (EDG_DEMANGLING): new macro + (DMGL_HP): new macro, for HP/aCC compiler. + (DMGL_STYLE_MASK): modify to include new HP's style. + (demangling_styles): add new hp_demangling value. + (HP_DEMANGLING_STYLE_STRING): new macro. + (ARM_DEMANGLING): coerce to int. + (HP_DEMANGLING): new macro. + + * hp-symtab.h: rewritten, from HP. + (quick_procedure): change type of language field to unsigned int + (quick_module): change type of language field to unsigned int + (struct dntt_type_svar): add field thread_specific. + (hp_language): add languages modcal and dmpascal. + +Fri Nov 20 13:14:00 1998 Andrew Cagney + + * libiberty.h (basename): Add prototype for FreeBSD. + +Fri Nov 13 19:19:11 1998 Kaveh R. Ghazi + + * libiberty.h: Prototype xcalloc. + +Sun Nov 8 17:42:25 1998 Kaveh R. Ghazi + + * ansidecl.h: Wrap problematic macros with !IN_GCC. + + * demangle.h: Never define PARAMS(). + * splay-tree.h: Likewise. + +Sat Nov 7 18:30:20 1998 Peter Schauer + + * dis-asm.h (print_insn_vax): Declare. + +Sat Nov 7 16:04:03 1998 Kaveh R. Ghazi + + * demangle.h: Don't include gansidecl.h. + * splay-tree.h: Likewise. + +1998-10-26 16:03 Ulrich Drepper + + * bfdlink.h (struct bfd_link_info): Add new field optimize. + +Thu Oct 22 19:58:00 1998 Kaveh R. Ghazi + + * splay-tree.h: Wrap function pointer parameter declarations in + PARAMS() macro. + +1998-10-21 Mark Mitchell + + * splay-tree.h: New file. + +Fri Oct 9 00:02:03 1998 Jeffrey A Law (law@cygnus.com) + + * Merge devo and egcs include directories. + +Sat Sep 5 12:16:33 1998 Jeffrey A Law (law@cygnus.com) + + * getopt.h, obstack.h: Updated from gcc. + +1998-08-03 Jason Molenda (jsm@bugshack.cygnus.com) + + * libiberty.h (xexit): Change decl to use modern GCC attribute + to indicate exit does not return. + +Mon Jun 1 13:48:32 1998 Jason Molenda (crash@bugshack.cygnus.com) + + * obstack.h: Update to latest FSF version. + +Tue Feb 24 13:05:02 1998 Doug Evans + + * dis-asm.h (disassemble_info): Member `symbol' renamed to `symbols' + and made an "asymbol **". New member num_symbols. + (INIT_DISASSEMBLE_INFO_NO_ARCH): Update. + +Tue Feb 17 12:32:18 1998 Andrew Cagney + + * remote-sim.h (sim_fetch_register, sim_store_register): Add + register length parameter. Functions return actual length of + register. + +Thu Feb 12 16:29:01 1998 Ian Lance Taylor + + * getopt.h: Update to latest FSF version. + +Wed Feb 11 16:56:06 1998 Doug Evans + + * symcat.h: New file. + +Mon Feb 2 17:13:31 1998 Steve Haworth + + * dis-asm.h (print_insn_tic30): Declare. + +Thu Jan 22 16:23:59 1998 Fred Fish + + * dis-asm.h: Add flag INSN_HAS_RELOC to tell disassembly + function there is a reloc on this line. + +Mon Dec 8 11:22:23 1997 Nick Clifton + + * dis-asm.h: Remove prototype of disasm_symaddr() as this function + no longer exists. + +Tue Dec 2 10:20:53 1997 Nick Clifton + + * dis-asm.h (disasm_symaddr): New prototype. + +Mon Dec 1 11:29:35 1997 Doug Evans + + * callback.h (CB_SYSCALL): Comment out arg names in prototypes. + +Wed Nov 26 16:47:58 1997 Michael Meissner + + * callback.h (CB_SYSCALL): Consistantly use names for prototype + arguments. + +Wed Nov 26 11:39:30 1997 Doug Evans + + * callback.h (CB_SYSCALL): Change byte count arguments to + {read,write}_mem to `int'. New member `magic'. + (CB_SYSCALL_MAGIC,CB_SYSCALL_INIT): New macros. + +Tue Nov 25 01:35:52 1997 Doug Evans + + * callback.h (struct stat): Move forward decl up. + (host_callback): Pass stat struct pointer to stat,fstat. + (CB_SYS_nnn): Reorganize. + (CB_SYSCALL): New members p1,p2. + (cb_host_to_target_stat): Delete fourth arg. + +Sat Nov 22 23:34:15 1997 Andrew Cagney + + * remote-sim.h (sim_stop_reason): Clarify sim_signalled SIGRC + argument. + +Mon Nov 17 14:00:51 1997 Doug Evans + + * callback.h (CB_TARGET_DEFS_MAP): Renamed from target_defs_map. + (host_callback): Add stat, fstat, syscall_map, errno_map, open_map, + signal_map, stat_map. + (errn_map,open_map): Renamed to cb_init_foo_map. + (cb_host_to_target_errno,cb_target_to_host_open): Renamed from + host_to_target_errno,target_to_host_open. + (cb_read_target_syscall_maps): Add prototype. + (cb_target_to_host_syscall): Likewise. + (cb_host_to_target_stat): Likewise. + (cb_syscall): Likewise. + (CB_SYS_{exit,open,close,read,write,lseek,unlink,getpid,kill,fstat, + argvlen,argv,chdir,stat,chmod,utime,time}): Define. + (CB_SYSCALL): New type. + (CB_RC): New enum. + +Fri Nov 7 10:34:09 1997 Rob Savoye + + * libiberty.h: Add extern "C" { so it can be used with C++ + programs. + * remote-sim.h: Add extern "C" { so it can be used with C++ + programs. + +Tue Oct 14 16:07:51 1997 Nick Clifton + + * dis-asm.h (struct disassemble_info): New field + 'symbol_at_address_func'. + (INIT_DISASSEMBLE_INFO_NO_ARCH): Initialise new field with + generic_symbol_at_address. + +Mon Oct 13 10:17:15 1997 Andrew Cagney + + * remote-sim.h: Clarify sim_read, sim_write MEM argument. + +Wed Sep 24 18:03:10 1997 Stu Grossman + + * remote-sim.h (SIM_RC): Add a bunch of new return codes for + breakpoint stuff. + * Add functions to tell the simulator to set/clear/enable/disable + intrinsic breakpoints. + +Thu Aug 28 19:41:42 1997 Andrew Cagney + + * libiberty.h (dupargv): Add prototype. + +Tue Aug 26 12:25:49 1997 Andrew Cagney + + * remote-sim.h (sim_create_inferior): Add ABFD arg. Document. + +Mon Aug 25 10:50:51 1997 Andrew Cagney + + * remote-sim.h (sim_open): Add ABFD arg. Document. + +Fri Aug 8 16:43:56 1997 Doug Evans + + * dis-asm.h (arc_get_disassembler): Declare. + +Wed Jul 30 11:39:50 1997 Per Bothner + + * demangle.h (DMGL_JAVA): New option to request Java demangling. + +Tue Jul 22 17:59:54 1997 Ian Lance Taylor + + * libiberty.h (PEXECUTE_*): Define. + (pexecute, pwait): Declare. + +Fri Jun 6 13:02:33 1997 Andrew Cagney + + * remote-sim.h (sim_kill): Mark as depreciated. + +Fri May 23 13:43:41 1997 Fred Fish + + * bfdlink.h (struct bfd_link_info): Add task_link member. + +Thu May 22 11:32:49 1997 Andrew Cagney + + * remote-sim.h: Review documentation. Clarify restrictions on + when functions can be called. + +Wed May 21 16:47:53 1997 Andrew Cagney + + * remote-sim.h (sim_set_profile_size): Add prototype, document as + depreciated. + +Tue May 20 09:32:22 1997 Andrew Cagney + + * remote-sim.h (sim_open): Add callback struct. + (sim_set_callbacks): Drop SIM_DESC argument. Document. + (sim_size): Remove recently added SIM_DESC argument. Document. + +Mon May 19 19:14:44 1997 Andrew Cagney + + * remote-sim.h: Pass SD into sim_size. + +Thu May 15 01:24:16 1997 Mark Alexander + + * obstack.h (obstack_specify_allocation_with_arg, obstack_chunkfun, + obstack_freefun): Eliminate compile warnings in gdb. + +Tue Apr 22 10:24:34 1997 Fred Fish + + * floatformat.h (floatformat_byteorders): Add comments for previous + formats and add floatformat_littlebyte_bigword, primarily for ARM. + Add declaration for floatformat_ieee_double_littlebyte_bigword. + +Fri Apr 18 13:04:49 1997 Andrew Cagney + + * remote-sim.h (sim_stop): New interface - asynchronous + notification of a request to stop / suspend the running + simulation. + + * remote-sim.h (enum sim_stop): Add sim_running and sim_polling as + states for use internal to simulators. + + * callback.h (struct host_callback_strut): Put a magic number at + the end of the struct to allow basic checking. + (struct host_callback_struct ): Add poll_quit - so + that the console etc can be polled at regular intervals. + +Thu Apr 17 02:17:12 1997 Doug Evans + + * remote-sim.h (struct _bfd): Declare. + (sim_load): Return SIM_RC. New arg `abfd'. + (sim_create_inferior): Return SIM_RC. Delete arg `start_address'. + +Wed Apr 2 17:09:12 1997 Andrew Cagney + + * remote-sim.h (sim_trace, sim_size): Make these global. They + will go away shortly. + +Wed Apr 2 15:23:49 1997 Doug Evans + + * remote-sim.h (SIM_OPEN_KIND, SIM_RC): New enums. + (sim_open): New argument `kind'. + +Wed Apr 2 14:45:51 1997 Ian Lance Taylor + + * COPYING: Update FSF address. + +Fri Mar 28 15:29:54 1997 Mike Meissner + + * callback.h (top level): Include stdarg.h or varargs.h if + va_start is not defined. + (host_callback_struct): Make {,e}vprintf_filtered take a va_list + instead of void *, since va_list might be an array or structure + type. + +Fri Mar 28 15:44:41 1997 H.J. Lu + + * libiberty.h (basename): Add prototype for glibc and linux. + +Mon Mar 17 19:22:12 1997 Ian Lance Taylor + + * objalloc.h: New file. + +Mon Mar 17 14:57:55 1997 Andrew Cagney + + * remote-sim.h: New file, copied in from gdb/remote-sim.h. One + day this will be placed in a directory of its own. + +Sat Mar 15 19:00:14 1997 Ian Lance Taylor + + * obstack.h: Update to current FSF version. + +Thu Mar 6 15:46:59 1997 Andrew Cagney + + * callback.h (struct host_callback_struct): Add callbacks - + flush_stdout, write_stderr, flush_stderr, vprintf_filtered, + evprintf_filtered. Delete redundant callbacks - printf_filtered. + +Thu Feb 27 23:18:27 1997 Ian Lance Taylor + + * bfdlink.h (struct bfd_link_info): Remove lprefix and lprefix_len + fields. + +Tue Feb 25 00:10:49 1997 Ian Lance Taylor + + * dis-asm.h (INIT_DISASSEMBLE_INFO_NO_ARCH): Initialize + bytes_per_chunk and display_endian. + +Mon Feb 24 17:47:02 1997 Ian Lance Taylor + + From Eric Youngdale : + * bfdlink.h (struct bfd_elf_version_expr): Define. + (struct bfd_elf_version_deps): Define. + (struct bfd_elf_version_tree): Define. + +Thu Feb 6 14:20:01 1997 Martin M. Hunt + + * dis-asm.h: (disassemble_info): Add new fields + bytes_per_chunk and display_endian to control the + display of raw instructions. + +Fri Dec 27 22:17:37 1996 Fred Fish + + * dis-asm.h (print_insn_tic80): Declare. + +Sun Dec 8 17:11:12 1996 Doug Evans + + * callback.h (host_callback): New member `error'. + +Wed Nov 20 00:40:23 1996 Doug Evans + + * callback.h: New file, moved here from gdb. + +Mon Nov 18 16:34:00 1996 Dawn Perchik + + * libiberty.h: Checkin again; last checkin failed due to sticky tag. + +Wed Nov 13 08:22:00 1996 Dawn Perchik + + * libiberty.h: Revert last commit due to conflicts with hpux + system headers. + +Tue Nov 12 16:31:00 1996 Dawn Perchik + + * libiberty.h: Move prototypes from argv.c here. + +Thu Oct 31 14:56:18 1996 Doug Evans + + * ansidecl.h (VPARAMS,VA_START): Define. + +Fri Oct 25 12:08:04 1996 Ian Lance Taylor + + * dis-asm.h (disassemble_info): Add bytes_per_line field. + (INIT_DISASSEMBLE_INFO_NO_ARCH): Initialize bytes_per_line field. + +Thu Oct 24 17:10:01 1996 Ian Lance Taylor + + * dis-asm.h (disassemble_info): Add symbol field. + (INIT_DISASSEMBLE_INFO_NO_ARCH): Initialize symbol field. + +Thu Oct 17 11:17:40 1996 Doug Evans + + * dis-asm.h (print_insn_m32r): Declare. + +Mon Oct 14 23:56:52 1996 Ian Lance Taylor + + * libiberty.h: Declare parameter types for xmalloc and xrealloc. + +Thu Oct 3 13:45:27 1996 Ian Lance Taylor + + * fnmatch.h: New file. + +Thu Oct 3 10:33:14 1996 Jeffrey A Law (law@cygnus.com) + + * dis-asm.h (print_insn_mn10x00): Delete declaration. + (print_insn_mn10200, print_insn_mn10300): Declare. + +Wed Oct 2 21:24:43 1996 Jeffrey A Law (law@cygnus.com) + + * dis-asm.h (print_insn_mn10x00): Declare. + +Mon Sep 30 13:56:11 1996 Fred Fish + + * libiberty.h: Remove #ifndef PRIVATE_XMALLOC. + +Sat Aug 31 13:27:06 1996 Jeffrey A Law (law@cygnus.com) + + * dis-asm.h (print_insn_v850): Declare. + +Tue Aug 13 16:10:30 1996 Stu Grossman (grossman@critters.cygnus.com) + + * obstack.h: Change bcopy to memcpy. Works better on Posix + systems, which generally lack bcopy. + +Mon Aug 12 17:03:18 1996 Stu Grossman (grossman@critters.cygnus.com) + + * ansidecl.h: Change WIN32 to _WIN32. + +Fri Jul 26 13:58:18 1996 Ian Lance Taylor + + * dis-asm.h: Add flavour field. + (print_insn_alpha): Declare. + (print_insn_alpha_osf, print_insn_alpha_vms): Don't declare. + (INIT_DISASSEMBLE_INFO): Initialize flavour field. + +Tue Jul 23 17:37:58 1996 Fred Fish + + * libiberty.h (PRIVATE_XMALLOC): Enclose xmalloc/xrealloc + definitions inside #ifndef so that programs that want to + can define PRIVATE_XMALLOC and then define xmalloc and + xrealloc anyway they want. + (basename): Document in source that we can't declare the + parameter type because it is declared inconsistently across + different systems. + +Mon Jul 22 13:16:13 1996 Richard Henderson + + * dis-asm.h (print_insn_alpha): Don't declare. + (print_insn_alpha_osf, print_insn_alpha_vms): Declare. + +Wed Jul 17 14:45:12 1996 Martin M. Hunt + + * dis-asm.h: (print_insn_d10v): Declare. + +Mon Jul 15 16:55:38 1996 Stu Grossman (grossman@critters.cygnus.com) + + * dis-asm.h: Get rid of decls for print_insn_i8086, + print_insn_sparc64 and print_insn_sparclite. + * (INIT_DISASSEMBLE_INFO): Split into two pieces. One, + INIT_DISASSEMBLE_INFO_NO_ARCH inits everything except for endian, + mach, and arch. + +Fri Jul 12 10:19:27 1996 Stu Grossman (grossman@critters.cygnus.com) + + * dis-asm.h (print_insn_i8086): Declare. + +Wed Jul 3 16:02:39 1996 Stu Grossman (grossman@critters.cygnus.com) + + * dis-asm.h (print_insn_sparclite): Declare. + +Tue Jun 18 16:02:46 1996 Jeffrey A. Law + + * dis-asm.h (print_insn_h8300s): Declare. + +Tue Jun 18 15:11:33 1996 Klaus Kaempf + + * fopen-vms.h: New file. + +Tue Jun 4 18:58:16 1996 Ian Lance Taylor + + * bfdlink.h (struct bfd_link_info): Add notice_all field. + +Fri Apr 26 10:33:12 1996 Doug Evans + + * demangle.h (#ifdef IN_GCC): #include "gansidecl.h". + (PROTO,PTR,const): Delete. + +Mon Apr 22 17:27:42 1996 Ian Lance Taylor + + * bfdlink.h (struct bfd_link_info): Add traditional_format field. + +Mon Apr 15 15:16:56 1996 Doug Evans + + * libiberty.h (choose_temp_base): Add prototype. + +Tue Mar 12 17:29:46 1996 Ian Lance Taylor + + * bfdlink.h (bfd_wrapped_link_hash_lookup): Declare. + (struct bfd_link_info): Add wrap_hash field. + +Wed Feb 14 16:49:17 1996 Martin Anantharaman + + * ieee.h (ieee_record_enum_type): Define + ieee_external_reference_info_enum. + +Fri Feb 2 17:09:25 1996 Doug Evans + + * dis-asm.h (DISASM_RAW_INSN): Delete. + +Tue Jan 23 09:21:47 1996 Doug Evans + + * dis-asm.h (INIT_DISASSEMBLE_INFO): Set endian to BFD_ENDIAN_UNKNOWN. + New argument FPRINTF_FUNC. + +Mon Jan 22 16:37:59 1996 Doug Evans + + * dis-asm.h (disassemble_info): New members arch, mach, endian. + (INIT_DISASSEMBLE_INFO): Initialize them. + (DISASM_RAW_INSN{,FLAG}): Define. + +Thu Jan 18 11:32:38 1996 Ian Lance Taylor + + * demangle.h (cplus_demangle_opname): Change opname parameter to + const char *. + (cplus_mangle_opname): Change return type and opname parameter to + const char *. + +Fri Jan 5 00:01:22 1996 Ian Lance Taylor + + * ieee.h (enum ieee_record): Add ieee_asn_record_enum, + ieee_at_record_enum, ieee_ty_record_enum, ieee_atn_record_enum, + ieee_bb_record_enum, and ieee_be_record_enum. + +Wed Jan 3 13:12:09 1996 Fred Fish + + * obstack.h: Update copyright to 1996. + (_obstack_memory_used): Declare. + (obstack_memory_used): Define macro. + +Thu Dec 28 11:42:12 1995 Ian Lance Taylor + + * libiberty.h (xstrdup): Declare. + +Thu Dec 21 14:47:17 1995 Michael Meissner + + * wait.h: Protect all macros with #ifndef. + +Tue Oct 24 21:45:40 1995 Ian Lance Taylor + + * bfdlink.h (struct bfd_link_info): Add static_link field. + +Tue Sep 12 16:28:04 1995 Ian Lance Taylor + + * bfdlink.h (struct bfd_link_callbacks): Add symbol parameter to + warning callback. + +Fri Sep 1 13:11:51 1995 Ian Lance Taylor + + * bfdlink.h (struct bfd_link_callbacks): Change warning callback + to take BFD, section, and address arguments. + +Thu Aug 31 16:45:12 1995 steve chamberlain + + * bfdlink.h (struct bfd_link_info): Remove PE stuff. + +Tue Aug 22 03:18:23 1995 Ken Raeburn + + * libiberty.h: Declare xstrerror. From Pat Rankin. + +Mon Aug 21 18:11:36 1995 steve chamberlain + + * bfdlink.h (struct bfd_link_info): Remove PE stuff. + +Wed Aug 2 08:14:12 1995 Doug Evans + + * dis-asm.h (print_insn_sparc64): Declare. + +Mon Jul 10 13:26:49 1995 Eric Youngdale + + * bfdlink.h (struct bfd_link_info): Add new field symbolic. + +Sun Jul 2 17:48:40 1995 Ian Lance Taylor + + * bfdlink.h (struct bfd_link_info): Change type of base_file to + PTR. + +Thu Jun 29 00:02:45 1995 Steve Chamberlain + + * bfdlink.h (struct bfd_link_info): Added base_file member. + +Tue Jun 20 16:40:04 1995 Steve Chamberlain + + * ansidecl.h: win32s is ANSI enough. + +Thu May 18 04:25:50 1995 Ken Raeburn + + Wed May 10 14:28:16 1995 Richard Earnshaw (rearnsha@armltd.co.uk) + + * dis-asm.h (print_insn_arm): Delete declaration. + (print_insn_{little,big}_arm): New declarations. + + * floatformat.h (floatformat_arm_ext): Declare. + +Sat May 13 10:14:08 1995 Steve Chamberlain + + * bfdlink.h (subsytem, stack_heap_parameters): New. + +Thu May 4 14:36:42 1995 Jason Merrill + + * demangle.h: Don't include ansidecl.h if IN_GCC. + +Tue Feb 21 00:37:28 1995 Jeff Law (law@snake.cs.utah.edu) + + * hp-symtab.h: Don't use bitfield enumerations, the HP C compiler + does not handle them correctly. + +Thu Feb 9 14:20:27 1995 Ian Lance Taylor + + * libiberty.h (basename): Don't declare parameter type; some + systems have this in their header files. + +Wed Feb 8 17:35:38 1995 Ian Lance Taylor + + * bfdlink.h (struct bfd_link_hash_entry): Change format of common + symbol information, to remove restrictions on maximum size and + alignment power, by using a pointer to a structure instead. + +Mon Feb 6 14:55:32 1995 Ian Lance Taylor + + * bfdlink.h (enum bfd_link_hash_type): Rename bfd_link_hash_weak + to bfd_link_hash_undefweak. Add bfd_link_hash_defweak. + +Mon Jan 16 21:00:23 1995 Stan Shebs + + * dis-asm.h (GDB_INIT_DISASSEMBLE_INFO, etc): Remove all + GDB-specific definitions. + +Sun Jan 15 18:39:35 1995 Steve Chamberlain + + * dis-asm.h (print_insn_w65): Declare. + +Thu Jan 12 17:51:17 1995 Ken Raeburn + + * libiberty.h (hex_p): Fix sense of test. + +Wed Jan 11 22:36:40 1995 Ken Raeburn + + * libiberty.h (_hex_array_size, _hex_bad, _hex_value, hex_init, + hex_p, hex_value): New macros and declarations, for hex.c. + +Fri Jan 6 17:44:14 1995 Ian Lance Taylor + + * dis-asm.h: Make idempotent. + +Wed Dec 14 13:08:43 1994 Stan Shebs + + * progress.h: New file, empty definitions for progress macros. + +Fri Nov 25 00:14:05 1994 Jeff Law (law@snake.cs.utah.edu) + + * hp-symtab.h: New file describing the debug symbols emitted + by the HP C compilers. + +Fri Nov 11 15:48:37 1994 Ian Lance Taylor + + * bfdlink.h (struct bfd_link_hash_entry): Change u.c.size from 24 + to 26 bits, and change u.c.alignment_power from 8 to 6 bits. 6 + bit in the alignment power is enough for a 64 bit address space. + +Mon Oct 31 13:02:51 1994 Stan Shebs (shebs@andros.cygnus.com) + + * demangle.h (cplus_mangle_opname): Declare. + +Tue Oct 25 11:38:02 1994 Ian Lance Taylor + + * bfdlink.h (struct bfd_link_callbacks): Fix comments for + multiple_common field. + +Sun Sep 04 17:58:10 1994 Richard Earnshaw (rwe@pegasus.esprit.ec.org) + + * dis-asm.h: Add support for the ARM. + +Wed Aug 10 12:51:41 1994 Doug Evans (dje@canuck.cygnus.com) + + * libiberty.h (strsignal): Document its existence even if we + can't declare it. + +Tue Aug 2 14:40:03 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * os9k.h: Remove u_int16, u_int32, and owner_id typedefs and + expand their uses. Those names conflict with Mach headers. + +Fri Jul 22 14:17:12 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) + + * bfdlink.h (struct bfd_link_hash_entry): Change u.c.size into a + bitfield. Add field u.c.alignment_power. + +Sun Jul 10 00:26:39 1994 Ian Dall (dall@hfrd.dsto.gov.au) + + * dis-asm.h: Add print_insn_ns32k declaration. + +Mon Jun 20 17:13:29 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) + + * bfdlink.h (bfd_link_hash_table): Make creator a const pointer. + +Sat Jun 18 16:09:32 1994 Stan Shebs (shebs@andros.cygnus.com) + + * demangle.h (cplus_demangle_opname): Declare. + +Thu Jun 16 15:19:03 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * bfdlink.h (struct bfd_link_info): Add new field shared. + +Mon Jun 6 14:39:44 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * bfdlink.h (struct bfd_link_hash_entry): Remove written field: + not needed for all backends. + +Thu Apr 28 19:06:50 1994 Ken Raeburn (raeburn@cujo.cygnus.com) + + * dis-asm.h (disassembler): Declare. + +Fri Apr 1 00:38:17 1994 Jim Wilson (wilson@mole.gnu.ai.mit.edu) + + * obstack.h: Delete use of IN_GCC to control whether + stddef.h or gstddef.h is included. + +Tue Mar 22 13:06:02 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * bfdlink.h (enum bfd_link_order_type): Add bfd_data_link_order. + (struct bfd_link_order): Add data field to union. + +Mon Mar 21 18:45:26 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * bfdlink.h (struct bfd_link_callbacks): Change bitsize argument + to add_to_set to reloc. Remove bitsize argument from constructor. + Comment that reloc_overflow, reloc_dangerous and unattached_reloc + must handle NULL pointers for reloc location. + (enum bfd_link_order_type): Add bfd_section_reloc_link_order and + bfd_symbol_reloc_link_order. + (struct bfd_link_order): Add reloc field to union. + (struct bfd_link_order_reloc): Define. + +Mon Mar 14 12:27:50 1994 Ian Lance Taylor (ian@cygnus.com) + + * ieee-float.h: Removed; no longer used. + +Tue Mar 1 18:10:49 1994 Kung Hsu (kung@mexican.cygnus.com) + + * os9k.h: os9000 target specific header file, the header of the + object file is used now. + +Sun Feb 27 21:52:26 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * floatformat.h: New file, intended to replace ieee-float.h. + +Sun Feb 20 17:15:42 1994 Ian Lance Taylor (ian@lisa.cygnus.com) + + * ansidecl.h (ANSI_PROTOTYPES): Define if using ANSI prototypes. + +Wed Feb 16 01:07:12 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * libiberty.h: Don't declare strsignal, to avoid conflicts with + Solaris system header files. + +Sat Feb 12 22:11:32 1994 Jeffrey A. Law (law@snake.cs.utah.edu) + + * libiberty.h (xexit): Use __volatile__ to avoid losing if + compiling with gcc -traditional. + +Thu Feb 10 14:05:41 1994 Ian Lance Taylor (ian@cygnus.com) + + * libiberty.h: New file. Declares functions provided by + libiberty. + +Tue Feb 8 05:19:52 1994 David J. Mackenzie (djm@thepub.cygnus.com) + + Handle obstack_chunk_alloc returning NULL. This allows + obstacks to be used by libraries, without forcing them + to call exit or longjmp. + * obstack.h (struct obstack): Add alloc_failed flag. + _obstack_begin, _obstack_begin_1): Declare to return int, not void. + (obstack_finish): If alloc_failed, return NULL. + (obstack_base, obstack_next_free, objstack_object_size): + If alloc_failed, return 0. + (obstack_grow, obstack_grow0, obstack_1grow, obstack_ptr_grow, + obstack_int_grow, obstack_blank): If alloc_failed, do nothing that + could corrupt the obstack. + +Mon Jan 24 15:06:05 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * bfdlink.h (struct bfd_link_callbacks): Add name, reloc_name and + addend argments to reloc_overflow callback. + +Fri Jan 21 19:13:12 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * dis-asm.h (print_insn_big_powerpc, print_insn_little_powerpc, + print_insn_rs6000): Declare. + +Thu Jan 6 14:15:55 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * bfdlink.h (struct bfd_link_callbacks): Add bitsize argument to + add_to_set field. Add new callback named constructor. + +Thu Dec 30 10:44:06 1993 Ian Lance Taylor (ian@rtl.cygnus.com) + + * bfdlink.h: New file for new BFD linker backend routines. + +Mon Nov 29 10:43:57 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * dis-asm.h (enum dis_insn_tyupe): Remove non-ANSI trailing comma. + +Sat Oct 2 20:42:26 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * dis-asm.h: Move comment to right place. + +Mon Aug 9 19:03:35 1993 David J. Mackenzie (djm@thepub.cygnus.com) + + * obstack.h (obstack_chunkfun, obstack_freefun): Add defns from + previous version. Are these Cygnus local changes? + +Fri Aug 6 17:05:47 1993 David J. Mackenzie (djm@thepub.cygnus.com) + + * getopt.h, obstack.h: Update to latest FSF version. + +Mon Aug 2 14:45:29 1993 John Gilmore (gnu@cygnus.com) + + * dis-asm.h: Move enum outside of struct defn to avoid warnings. + +Mon Aug 2 08:49:30 1993 Stu Grossman (grossman at cygnus.com) + + * wait.h (WEXITSTATUS, WSTOPSIG): Mask down to 8 bits. This is + for systems that store stuff into the high 16 bits of a wait + status. + +Fri Jul 30 18:38:02 1993 John Gilmore (gnu@cygnus.com) + + * dis-asm.h: Add new fields insn_info_valid, branch_delay_insns, + data_size, insn_type, target, target2. These are used to return + information from the instruction decoders back to the calling + program. Add comments, make more readable. + +Mon Jul 19 22:14:14 1993 Fred Fish (fnf@deneb.cygnus.com) + + * nlm: New directory containing NLM/NetWare includes. + +Thu Jul 15 12:10:04 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) + + * dis-asm.h (struct disassemble_info): New field application_data. + +Thu Jul 15 12:41:15 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * dis-asm.h: Added declaration of print_insn_m88k. + +Fri Jul 2 10:31:59 1993 Ian Lance Taylor (ian@cygnus.com) + + * ansidecl.h: Use ANSI macros if __mips and _SYSTYPE_SVR4 are + defined, since RISC/OS cc handles ANSI declarations in SVR4 mode + but does not define __STDC__. + +Sun Jun 20 18:27:52 1993 Ken Raeburn (raeburn@poseidon.cygnus.com) + + * dis-asm.h: Don't need to include ansidecl.h any more. + +Fri Jun 18 03:22:10 1993 John Gilmore (gnu@cygnus.com) + + * oasys.h: Eliminate "int8_type", "int16_type", "int32_type", and + their variants. These changes are coordinated with corresponding + changes in ../bfd/oasys.c. + +Wed Jun 16 10:43:08 1993 Fred Fish (fnf@cygnus.com) + + * bfd.h: Note that it has been removed. + +Tue Jun 8 12:16:03 1993 Steve Chamberlain (sac@phydeaux.cygnus.com) + + Support for H8/300-H + * dis-asm.h (print_insn_h8300, print_insn_h8300h): Declare it. + +Tue Jun 1 07:35:03 1993 Ken Raeburn (raeburn@kr-pc.cygnus.com) + + * ansidecl.h (const): Don't define it if it's already defined. + +Thu May 27 18:19:51 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) + + * dis-asm.h (print_insn_hppa): Declare it. + + * bfd.h: Moved to bfd directory. Small stub here includes it + without requiring "-I../bfd". + +Thu Apr 29 12:06:13 1993 Ken Raeburn (raeburn@deneb.cygnus.com) + + * bfd.h: Updated with BSF_FUNCTION. + +Mon Apr 26 18:15:50 1993 Steve Chamberlain (sac@thepub.cygnus.com) + + * bfd.h, dis-asm.h: Updated with Hitachi SH. + +Fri Apr 23 18:41:38 1993 Steve Chamberlain (sac@thepub.cygnus.com) + + * bfd.h: Updated with alpha changes. + * dis-asm.h: Added alpha. + +Fri Apr 16 17:35:30 1993 Jim Kingdon (kingdon@cygnus.com) + + * bfd.h: Update for signed bfd_*get_*. + +Thu Apr 15 09:24:21 1993 Jim Kingdon (kingdon@cygnus.com) + + * bfd.h: Updated for file_truncated error. + +Thu Apr 8 10:53:47 1993 Ian Lance Taylor (ian@cygnus.com) + + * ansidecl.h: If no ANSI, define const to be empty. + +Thu Apr 1 09:00:10 1993 Jim Kingdon (kingdon@cygnus.com) + + * dis-asm.h: Declare a29k and i960 print_insn_*. + + * dis-asm.h: Add print_address_func and related stuff. + + * dis-asm.h (dis_asm_read_memory): Fix prototype. + +Wed Mar 31 17:40:16 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * dis-asm.h: Add print_insn_sparc. + +Wed Mar 31 17:51:42 1993 Ian Lance Taylor (ian@cygnus.com) + + * bfd.h: Updated for BFD_RELOC_MIPS_GPREL and bfd_[gs]et_gp_size + prototypes. + +Wed Mar 31 16:35:12 1993 Stu Grossman (grossman@cygnus.com) + + * dis-asm.h: (disassemble_info): Fix typo in prototype of + dis_asm_memory_error(). + +Tue Mar 30 19:09:23 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * dis-asm.h (disassembler_info): Add read_memory_func, + memory_error_func, buffer, and length. + ({GDB_,}INIT_DISASSEMBLE_INFO): Set them. + print_insn_*: Remove second argument. + +Tue Mar 30 14:48:55 1993 Steve Chamberlain (sac@thepub.cygnus.com) + + * bfd.h: Update for lma field of section. + +Tue Mar 30 12:22:55 1993 Jim Kingdon (kingdon@cygnus.com) + + * ansidecl.h: Use ANSI versions on AIX regardless of __STDC__. + +Fri Mar 19 14:49:49 1993 Steve Chamberlain (sac@thepub.cygnus.com) + + * dis-asm.h: Add h8500. + +Thu Mar 18 13:49:09 1993 Per Bothner (bothner@rtl.cygnus.com) + + * ieee-float.h: Moved from ../gdb. + * dis-asm.h: New file. Interface to dis-assembler. + +Thu Mar 11 10:52:57 1993 Fred Fish (fnf@cygnus.com) + + * demangle.h (DMGL_NO_OPTS): Add define (set to 0) to use + in place of bare 0, for readability reasons. + +Tue Mar 2 17:50:11 1993 Fred Fish (fnf@cygnus.com) + + * demangle.h: Replace all references to cfront with ARM. + +Tue Feb 23 12:21:14 1993 Ian Lance Taylor (ian@cygnus.com) + + * bfd.h: Update for new elements in JUMP_TABLE. + +Tue Feb 16 00:51:30 1993 John Gilmore (gnu@cygnus.com) + + * bfd.h: Update for BFD_VERSION 2.1. + +Tue Jan 26 11:49:20 1993 Ian Lance Taylor (ian@cygnus.com) + + * bfd.h: Update for SEC_IS_COMMON flag. + +Tue Jan 19 12:25:12 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * bfd.h: Update for bfd_asymbol_value bug fix. + +Fri Jan 8 16:37:18 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * bfd.h: Update to include ECOFF tdata and target_flavour. + +Sun Dec 27 17:52:30 1992 Fred Fish (fnf@cygnus.com) + + * bfd.h: Add declaration for bfd_get_size(). + +Tue Dec 22 22:42:46 1992 Fred Fish (fnf@cygnus.com) + + * demangle.h: Protect file from multiple inclusions with + #if !defined(DEMANGLE_H)...#define DEMANGLE_H...#endif. + +Mon Dec 21 21:25:50 1992 Stu Grossman (grossman at cygnus.com) + + * bfd.h: Update to get hppa_core_struct from bfd.c. + +Thu Dec 17 00:42:35 1992 John Gilmore (gnu@cygnus.com) + + * bfd.h: Update to get tekhex tdata name change from bfd. + +Mon Nov 9 23:55:42 1992 John Gilmore (gnu@cygnus.com) + + * ansidecl.h: Update comments to discourage use of EXFUN. + +Thu Nov 5 16:35:44 1992 Ian Lance Taylor (ian@cygnus.com) + + * bfd.h: Update to bring in SEC_SHARED_LIBRARY. + +Thu Nov 5 03:21:32 1992 John Gilmore (gnu@cygnus.com) + + * bfd.h: Update to match EXFUN, bfd_seclet_struct, and SDEF + cleanups in bfd. + +Wed Nov 4 07:28:05 1992 Ken Raeburn (raeburn@cygnus.com) + + * bout.h (N_CALLNAME, N_BALNAME): Define as char-type values, so + widening works consistently. + +Fri Oct 16 03:17:08 1992 John Gilmore (gnu@cygnus.com) + + * getopt.h: Update to Revised Standard FSF Version. + +Thu Oct 15 21:43:22 1992 K. Richard Pixley (rich@sendai.cygnus.com) + + * getopt.h (struct option): use the provided enum for has_arg. + + * demangle.h (AUTO_DEMANGLING, GNU_DEMANGLING, + LUCID_DEMANGLING): ultrix compilers require enums to be + enums and ints to be ints and casts where they meet. cast some + enums into ints. + +Thu Oct 15 04:35:51 1992 John Gilmore (gnu@cygnus.com) + + * bfd.h: Update after comment changes. + +Thu Oct 8 09:03:02 1992 Steve Chamberlain (sac@thepub.cygnus.com) + + * bfd.h (bfd_get_symbol_leading_char): new macro for getting in xvec + +Thu Sep 3 09:10:50 1992 Stu Grossman (grossman at cygnus.com) + + * bfd.h (struct reloc_howto_struct): size needs to be signed if + it's going to hold negative values. + +Sun Aug 30 17:50:27 1992 Per Bothner (bothner@rtl.cygnus.com) + + * demangle.h: New file, moved from ../gdb. Made independent + of gdb. Allow demangling style option to be passed as a + parameter to cplus_demangle(), but using the + current_demangling_style global as the default. + +Sat Aug 29 10:07:55 1992 Fred Fish (fnf@cygnus.com) + + * obstack.h: Merge comment change from current FSF version. + +Thu Aug 27 12:59:29 1992 Brendan Kehoe (brendan@cygnus.com) + + * bfd.h: add we32k + +Tue Aug 25 15:07:47 1992 Steve Chamberlain (sac@thepub.cygnus.com) + + * bfd.h: new after Z8000 stuff + +Mon Aug 17 09:01:23 1992 Ken Raeburn (raeburn@cygnus.com) + + * bfd.h: Regenerated after page/segment size changes. + +Sat Aug 1 13:46:31 1992 Fred Fish (fnf@cygnus.com) + + * obstack.h: Merge changes from current FSF version. + +Mon Jul 20 21:06:23 1992 Fred Fish (fnf@cygnus.com) + + * obstack.h (area_id, flags): Remove, replace with extra_arg, + use_extra_arg, and maybe_empty_object. + * obstack.h (OBSTACK_MAYBE_EMPTY_OBJECT, OBSTACK_MMALLOC_LIKE): + Remove, replaced by maybe_empty_object and use_extra_arg bitfields. + * obstack.h (obstack_full_begin, _obstack_begin): Remove area_id + and flags arguments. + * obstack.h (obstack_alloc_arg): New macro to set extra_arg. + +Thu Jul 16 08:12:44 1992 Steve Chamberlain (sac@thepub.cygnus.com) + + * bfd.h: new after adding BFD_IS_RELAXABLE + +Sat Jul 4 03:22:23 1992 John Gilmore (gnu at cygnus.com) + + * bfd.h: Regen after adding BSF_FILE. + +Mon Jun 29 14:18:36 1992 Fred Fish (fnf at sunfish) + + * obstack.h: Convert bcopy() use to memcpy(), which is more + portable, more standard, and can take advantage of gcc's builtin + functions for increased performance. + +Thu Jun 25 04:46:08 1992 John Gilmore (gnu at cygnus.com) + + * ansidecl.h (PARAMS): Incorporate this macro from gdb's defs.h. + It's a cleaner way to forward-declare function prototypes. + +Fri Jun 19 15:46:32 1992 Stu Grossman (grossman at cygnus.com) + + * bfd.h: HPPA merge. + +Tue Jun 16 21:30:56 1992 K. Richard Pixley (rich@cygnus.com) + + * getopt.h: gratuitous white space changes merged from other prep + releases. + +Thu Jun 11 01:10:55 1992 John Gilmore (gnu at cygnus.com) + + * bfd.h: Regen'd from bfd.c after removing elf_core_tdata_struct. + +Mon May 18 17:29:03 1992 K. Richard Pixley (rich@cygnus.com) + + * getopt.h: merged changes from make-3.62.11. + + * getopt.h: merged changes from grep-1.6 (alpha). + +Fri May 8 14:53:32 1992 K. Richard Pixley (rich@cygnus.com) + + * getopt.h: merged changes from bison-1.18. + +Sat Mar 14 17:25:20 1992 Fred Fish (fnf@cygnus.com) + + * obstack.h: Add "area_id" and "flags" members to obstack + structure. Add obstack_chunkfun() and obstack_freefun() to + set functions explicitly. Convert maybe_empty_object to + a bit in "flags". + +Thu Feb 27 22:01:02 1992 Per Bothner (bothner@cygnus.com) + + * wait.h (WIFSTOPPED): Add IBM rs6000-specific version. + +Fri Feb 21 20:49:20 1992 John Gilmore (gnu at cygnus.com) + + * obstack.h: Add obstack_full_begin. + * bfd.h, obstack.h: Protolint. + +Thu Jan 30 01:18:42 1992 John Gilmore (gnu at cygnus.com) + + * bfd.h: Remove comma from enum declaration. + +Mon Jan 27 22:01:13 1992 Steve Chamberlain (sac at cygnus.com) + + * bfd.h : new target entr, bfd_relax_section + +Wed Dec 18 17:19:44 1991 Stu Grossman (grossman at cygnus.com) + + * bfd.h, ieee.h: ANSIfy enums. + +Thu Dec 12 20:59:56 1991 John Gilmore (gnu at cygnus.com) + + * fopen-same.h, fopen-bin.h: New files for configuring + whether fopen distinguishes binary files or not. For use + by host-dependent config files. + +Sat Nov 30 20:46:43 1991 Steve Chamberlain (sac at rtl.cygnus.com) + + * bfd.h: change the documentation format. + + * created coff, elf and opcode and aout directories. Moved: + + aout64.h ==> aout/aout64.h + ar.h ==> aout/ar.h + a.out.encap.h ==> aout/encap.h + a.out.host.h ==> aout/host.h + a.out.hp.h ==> aout/hp.h + a.out.sun4.h ==> aout/sun4.h + ranlib.h ==> aout/ranlib.h + reloc.h ==> aout/reloc.h + stab.def ==> aout/stab.def + stab.gnu.h ==> aout/stab_gnu.h + + coff-a29k.h ==> coff/a29k.h + coff-h8300.h ==> coff/h8300.h + coff-i386.h ==> coff/i386.h + coff-i960.h ==> coff/i960.h + internalcoff.h ==> coff/internal.h + coff-m68k.h ==> coff/m68k.h + coff-m88k.h ==> coff/m88k.h + coff-mips.h ==> coff/mips.h + coff-rs6000.h ==> coff/rs6000.h + + elf-common.h ==> elf/common.h + dwarf.h ==> elf/dwarf.h + elf-external.h ==> elf/external.h + elf-internal.h ==> elf/internal.h + + a29k-opcode.h ==> opcode/a29k.h + arm-opcode.h ==> opcode/arm.h + h8300-opcode.h ==> opcode/h8300.h + i386-opcode.h ==> opcode/i386.h + i860-opcode.h ==> opcode/i860.h + i960-opcode.h ==> opcode/i960.h + m68k-opcode.h ==> opcode/m68k.h + m88k-opcode.h ==> opcode/m88k.h + mips-opcode.h ==> opcode/mips.h + np1-opcode.h ==> opcode/np1.h + ns32k-opcode.h ==> opcode/ns32k.h + pn-opcode.h ==> opcode/pn.h + pyr-opcode.h ==> opcode/pyr.h + sparc-opcode.h ==> opcode/sparc.h + tahoe-opcode.h ==> opcode/tahoe.h + vax-opcode.h ==> opcode/vax.h + + + +Wed Nov 27 10:38:31 1991 Steve Chamberlain (sac at rtl.cygnus.com) + + * internalcoff.h: (internal_scnhdr) took out #def dependency, now + s_nreloc and s_nlnno are always long. (internal_reloc): allways + has an offset field now. + +Fri Nov 22 08:12:58 1991 John Gilmore (gnu at cygnus.com) + + * coff-rs6000.h: Lint; use unsigned chars for external fields. + * internalcoff.h: Lint; cast storage classes to signed char. + +Thu Nov 21 21:01:05 1991 Per Bothner (bothner at cygnus.com) + + * stab.def: Remove the GNU extended type codes (e.g. N_SETT). + * aout64.h: The heuristic for distinguishing between + sunos-style and bsd-style ZMAGIC files (wrt. where the + text segment starts) is moved into (the default definition of) + the macro N_HEADER_IN_TEXT. This definition is only used + if no other definition is used - e.g. bfd/newsos3.c defines + N_HEADER_IN_TEXT(x) to be always 0 (as before). + +Thu Nov 21 11:53:03 1991 John Gilmore (gnu at cygnus.com) + + * aout64.h (N_TXTADDR, N_TXTOFF, N_TXTSIZE): New definitions + that should handle all uses. LOGICAL_ versions deleted. + Eliminate N_HEADER_IN_TEXT, using a_entry to determine which + kind of zmagic a.out file we are looking at. + * coff-rs6000.h: Typo. + +Tue Nov 19 18:43:37 1991 Per Bothner (bothner at cygnus.com) + + (Note: This is a revised entry, as was aout64.h.) + * aout64.h: Some cleanups of N_TXTADDR and N_TXTOFF: + Will now work for both old- and new-style ZMAGIC files, + depending on N_HEADER_IN_TEXT macro. + Add LOGICAL_TXTADDR, LOICAL_TXTOFF and LOGICAL_TXTSIZE + that don't count the exec header as part + of the text segment, to be consistent with bfd. + * a.out.sun4.h: Simplified/fixed for previous change. + +Mon Nov 18 00:02:06 1991 Fred Fish (fnf at cygnus.com) + + * dwarf.h: Update to DWARF draft 5 version from gcc2. + +Thu Nov 14 19:44:59 1991 Per Bothner (bothner at cygnus.com) + + * stab.def: Added defs for extended GNU symbol types, + such as N_SETT. These are normally ifdef'd out (because + of conflicts with a.out.gnu.h), but are used by bfb_stab_name(). + +Thu Nov 14 19:17:03 1991 Fred Fish (fnf at cygnus.com) + + * elf-common.h: Add defines to support ELF symbol table code. + +Mon Nov 11 19:01:06 1991 Fred Fish (fnf at cygnus.com) + + * elf-internal.h, elf-external.h, elf-common.h: Add support for + note sections, which are used in ELF core files to hold copies + of various /proc structures. + +Thu Nov 7 08:58:26 1991 Steve Chamberlain (sac at cygnus.com) + + * internalcoff.h: took out the M88 dependency in the lineno + struct. + * coff-m88k.h: defines GET_LINENO_LNNO and PUT_LINENO_LNNO to use + 32bit linno entries. + * a29k-opcode.h: fixed encoding of mtacc + +Sun Nov 3 11:54:22 1991 Per Bothner (bothner at cygnus.com) + + * bfd.h: Updated from ../bfd/bfd-in.h (q.v). + +Fri Nov 1 11:13:53 1991 John Gilmore (gnu at cygnus.com) + + * internalcoff.h: Add x_csect defines. + +Fri Oct 25 03:18:20 1991 John Gilmore (gnu at cygnus.com) + + * Rename COFF-related files in `coff-ARCH.h' form. + coff-a29k.h, coff-i386.h, coff-i960.h, coff-m68k.h, coff-m88k.h, + coff-mips.h, coff-rs6000.h to be exact. + +Thu Oct 24 22:11:11 1991 John Gilmore (gnu at cygnus.com) + + RS/6000 support, by Metin G. Ozisik, Mimi Phûông-Thåo Võ, and + John Gilmore. + + * a.out.gnu.h: Update slightly. + * bfd.h: Add new error code, fix doc, add bfd_arch_rs6000. + * internalcoff.h: Add more F_ codes for filehdr. Add + rs/6000-dependent fields to aouthdr. Add storage classes + to syments. Add 6000-specific auxent. Add r_size in reloc. + * rs6000coff.c: New file. + +Thu Oct 24 04:13:20 1991 Fred Fish (fnf at cygnus.com) + + * dwarf.h: New file for dwarf support. Copied from gcc2 + distribution. + +Wed Oct 16 13:31:45 1991 John Gilmore (gnu at cygnus.com) + + * aout64.h: Remove PAGE_SIZE defines; they are target-dependent. + Add N_FN_SEQ for N_FN symbol type used on Sequent machines. + * stab.def: Include N_FN_SEQ in table. + * bout.h: External formats of structures use unsigned chars. + +Fri Oct 11 12:40:43 1991 Steve Chamberlain (steve at cygnus.com) + + * bfd.h:upgrade from bfd.c + * internalcoff.h: add n_name, n_zeroes and n_offset macros + * amdcoff.h: Define OMAGIC and AOUTHDRSZ. + +Fri Oct 11 10:58:06 1991 Per Bothner (bothner at cygnus.com) + + * a.out.host.h: Change SEGMENT_SIZE to 0x1000 for Sony. + * bfd.h (align_power): Add (actually move) comment. + +Tue Oct 8 15:29:32 1991 Per Bothner (bothner at cygnus.com) + + * sys/h-rtbsd.h: Define MISSING_VFPRINT (for binutils/bucomm.c). + +Sun Oct 6 19:24:39 1991 John Gilmore (gnu at cygnus.com) + + * aout64.h: Move struct internal_exec to ../bfd/libaout.h so + it can be shared by all `a.out-family' code. Rename + EXTERNAL_LIST_SIZE to EXTERNAL_NLIST_SIZE. Use basic types + for nlist members, and make strx integral rather than pointer. + More commentary on n_type values. + * bout.h: Provide a struct external_exec rather than an + internal_exec. + * m68kcoff.h: Remove `tagentries' which snuck in from the i960 + COFF port. + +Fri Oct 4 01:25:59 1991 John Gilmore (gnu at cygnus.com) + + * h8300-opcode.h: Remove `_enum' from the typedef for an enum. + * bfd.h: Update to match bfd changes. + + * sys/h-i386mach.h, sysdep.h: Add 386 Mach host support. + +Tue Oct 1 04:58:42 1991 John Gilmore (gnu at cygnus.com) + + * bfd.h, elf-common.h, elf-external.h, elf-internal.h: + Add preliminary ELF support, sufficient for GDB, from Fred Fish. + * sysdep.h, sys/h-amix.h: Support Amiga SVR4. + + * sys/h-vaxult.h: Make it work. (David Taylor ) + * a.out.vax.h: Remove unused and confusing file. + +Mon Sep 30 12:52:35 1991 Per Bothner (bothner at cygnus.com) + + * sysdep.h: Define NEWSOS3_SYS, and use it. + +Fri Sep 20 13:38:21 1991 John Gilmore (gnu at cygnus.com) + + * a.out.gnu.h (N_FN): Its value *really is* 0x1F. + Fix it, and add comments warning about or-ing N_EXT with it + and/or N_WARNING. + * aout64.h (N_FN): Fix value, add comments about N_EXT. + * stab.def (table at end): Update to show all the type + values <0x20, including low order bits. Move N_FN to + its rightful place. + +Tue Sep 17 17:41:37 1991 Stu Grossman (grossman at cygnus.com) + + * sys/h-irix3.h: sgi/irix support. + +Tue Sep 17 07:52:59 1991 John Gilmore (gnu at cygint.cygnus.com) + + * stab.def (N_DEFD): Add GNU Modula-2 debug stab, from Andrew + Beers. + +Thu Sep 12 14:12:59 1991 John Gilmore (gnu at cygint.cygnus.com) + + * internalcoff.h (SYMNMLEN, FILNMLEN, DIMNUM): Define these + for internalcoff, separately from the various external coff's. + * amdcoff.h, bcs88kcoff.h, i386coff.h, intel-coff.h, m68kcoff.h, + m88k-bcs.h: Prefix SYMNMLEN, FILNMLEN, and DIMNUM with E_'s for + the external struct definitions. + * ecoff.h: Remove these #define's, kludge no longer needed. + + * sys/h-ultra3.h: Add new Ultracomputer host. + * sysdep.h: Add ULTRA3_SYM1_SYS and use it. + +Tue Sep 10 10:11:46 1991 John Gilmore (gnu at cygint.cygnus.com) + + * i386coff.h (LINESZ): Always 6, not based on sizeof(). + (Fix from Peter Schauer .) + +Wed Sep 4 08:58:37 1991 John Gilmore (gnu at cygint.cygnus.com) + + * a.out.gnu.h, aout64.h: Add N_WARNING. Change N_FN to 0x0E, + to match SunOS and BSD. Add N_COMM as 0x12 for SunOS shared lib + support. + * stab.def: Add N_COMM to table, fix overlap comment. + +Tue Sep 3 06:29:20 1991 John Gilmore (gnu at cygint.cygnus.com) + + Merge with latest FSF versions of these files. + + * stab.gnu.h: Add LAST_UNUSED_STAB_CODE. + * stab.def: Update to GPL2. Move N_WARNING out, since not a + debug symbol. Change comments, and reorder table to numeric + order. Update final table comment. + (N_DSLINE, N_BSLINE): Renumber from 0x66 and 0x68, to 0x46 and 0x48. + + * obstack.h: GPL2. Merge. + +Fri Aug 23 01:54:23 1991 John Gilmore (gnu at cygint.cygnus.com) + + * a.out.gnu.h, a.out.sun4.h: Make SEGMENT_SIZE able to depend + on the particular a.out being examined. + * a.out.sun4.h: Define segment sizes for Sun-3's and Sun-4's. + * FIXME: a.out.gnu.h is almost obsolete. + * FIXME: a.out.sun4.h should be renamed a.out.sun.h now. + +Wed Aug 21 20:32:13 1991 John Gilmore (gnu at cygint.cygnus.com) + + * Start a ChangeLog for the includes directory. + + * a.out.gnu.h (N_FN): Fix value -- was 15, should be 0x1E. + * stab.def: Update allocation table in comments at end, + to reflect reality as I know it. + + +Local Variables: +mode: change-log +left-margin: 8 +fill-column: 74 +version-control: never +End: diff --git a/libcpp/ansidecl.h b/include/ansidecl.h similarity index 100% rename from libcpp/ansidecl.h rename to include/ansidecl.h diff --git a/include/demangle.h b/include/demangle.h new file mode 100644 index 0000000..b55226d --- /dev/null +++ b/include/demangle.h @@ -0,0 +1,579 @@ +/* Defs for interface to demanglers. + Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, + 2003, 2004, 2005, 2007 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + In addition to the permissions in the GNU Library General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file into + combinations with other programs, and to distribute those + combinations without any restriction coming from the use of this + file. (The Library Public License restrictions do apply in other + respects; for example, they cover modification of the file, and + distribution when not linked into a combined executable.) + + 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library 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. */ + + +#if !defined (DEMANGLE_H) +#define DEMANGLE_H + +#include "libiberty.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Options passed to cplus_demangle (in 2nd parameter). */ + +#define DMGL_NO_OPTS 0 /* For readability... */ +#define DMGL_PARAMS (1 << 0) /* Include function args */ +#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ +#define DMGL_JAVA (1 << 2) /* Demangle as Java rather than C++. */ +#define DMGL_VERBOSE (1 << 3) /* Include implementation details. */ +#define DMGL_TYPES (1 << 4) /* Also try to demangle type encodings. */ +#define DMGL_RET_POSTFIX (1 << 5) /* Print function return types (when + present) after function signature */ + +#define DMGL_AUTO (1 << 8) +#define DMGL_GNU (1 << 9) +#define DMGL_LUCID (1 << 10) +#define DMGL_ARM (1 << 11) +#define DMGL_HP (1 << 12) /* For the HP aCC compiler; + same as ARM except for + template arguments, etc. */ +#define DMGL_EDG (1 << 13) +#define DMGL_GNU_V3 (1 << 14) +#define DMGL_GNAT (1 << 15) + +/* If none of these are set, use 'current_demangling_style' as the default. */ +#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM|DMGL_HP|DMGL_EDG|DMGL_GNU_V3|DMGL_JAVA|DMGL_GNAT) + +/* Enumeration of possible demangling styles. + + Lucid and ARM styles are still kept logically distinct, even though + they now both behave identically. The resulting style is actual the + union of both. I.E. either style recognizes both "__pt__" and "__rf__" + for operator "->", even though the first is lucid style and the second + is ARM style. (FIXME?) */ + +extern enum demangling_styles +{ + no_demangling = -1, + unknown_demangling = 0, + auto_demangling = DMGL_AUTO, + gnu_demangling = DMGL_GNU, + lucid_demangling = DMGL_LUCID, + arm_demangling = DMGL_ARM, + hp_demangling = DMGL_HP, + edg_demangling = DMGL_EDG, + gnu_v3_demangling = DMGL_GNU_V3, + java_demangling = DMGL_JAVA, + gnat_demangling = DMGL_GNAT +} current_demangling_style; + +/* Define string names for the various demangling styles. */ + +#define NO_DEMANGLING_STYLE_STRING "none" +#define AUTO_DEMANGLING_STYLE_STRING "auto" +#define GNU_DEMANGLING_STYLE_STRING "gnu" +#define LUCID_DEMANGLING_STYLE_STRING "lucid" +#define ARM_DEMANGLING_STYLE_STRING "arm" +#define HP_DEMANGLING_STYLE_STRING "hp" +#define EDG_DEMANGLING_STYLE_STRING "edg" +#define GNU_V3_DEMANGLING_STYLE_STRING "gnu-v3" +#define JAVA_DEMANGLING_STYLE_STRING "java" +#define GNAT_DEMANGLING_STYLE_STRING "gnat" + +/* Some macros to test what demangling style is active. */ + +#define CURRENT_DEMANGLING_STYLE current_demangling_style +#define AUTO_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_AUTO) +#define GNU_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU) +#define LUCID_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_LUCID) +#define ARM_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_ARM) +#define HP_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_HP) +#define EDG_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_EDG) +#define GNU_V3_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU_V3) +#define JAVA_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_JAVA) +#define GNAT_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNAT) + +/* Provide information about the available demangle styles. This code is + pulled from gdb into libiberty because it is useful to binutils also. */ + +extern const struct demangler_engine +{ + const char *const demangling_style_name; + const enum demangling_styles demangling_style; + const char *const demangling_style_doc; +} libiberty_demanglers[]; + +extern char * +cplus_demangle (const char *mangled, int options); + +extern int +cplus_demangle_opname (const char *opname, char *result, int options); + +extern const char * +cplus_mangle_opname (const char *opname, int options); + +/* Note: This sets global state. FIXME if you care about multi-threading. */ + +extern void +set_cplus_marker_for_demangling (int ch); + +extern enum demangling_styles +cplus_demangle_set_style (enum demangling_styles style); + +extern enum demangling_styles +cplus_demangle_name_to_style (const char *name); + +/* Callback typedef for allocation-less demangler interfaces. */ +typedef void (*demangle_callbackref) (const char *, size_t, void *); + +/* V3 ABI demangling entry points, defined in cp-demangle.c. Callback + variants return non-zero on success, zero on error. char* variants + return a string allocated by malloc on success, NULL on error. */ +extern int +cplus_demangle_v3_callback (const char *mangled, int options, + demangle_callbackref callback, void *opaque); + +extern char* +cplus_demangle_v3 (const char *mangled, int options); + +extern int +java_demangle_v3_callback (const char *mangled, + demangle_callbackref callback, void *opaque); + +extern char* +java_demangle_v3 (const char *mangled); + +enum gnu_v3_ctor_kinds { + gnu_v3_complete_object_ctor = 1, + gnu_v3_base_object_ctor, + gnu_v3_complete_object_allocating_ctor +}; + +/* Return non-zero iff NAME is the mangled form of a constructor name + in the G++ V3 ABI demangling style. Specifically, return an `enum + gnu_v3_ctor_kinds' value indicating what kind of constructor + it is. */ +extern enum gnu_v3_ctor_kinds + is_gnu_v3_mangled_ctor (const char *name); + + +enum gnu_v3_dtor_kinds { + gnu_v3_deleting_dtor = 1, + gnu_v3_complete_object_dtor, + gnu_v3_base_object_dtor +}; + +/* Return non-zero iff NAME is the mangled form of a destructor name + in the G++ V3 ABI demangling style. Specifically, return an `enum + gnu_v3_dtor_kinds' value, indicating what kind of destructor + it is. */ +extern enum gnu_v3_dtor_kinds + is_gnu_v3_mangled_dtor (const char *name); + +/* The V3 demangler works in two passes. The first pass builds a tree + representation of the mangled name, and the second pass turns the + tree representation into a demangled string. Here we define an + interface to permit a caller to build their own tree + representation, which they can pass to the demangler to get a + demangled string. This can be used to canonicalize user input into + something which the demangler might output. It could also be used + by other demanglers in the future. */ + +/* These are the component types which may be found in the tree. Many + component types have one or two subtrees, referred to as left and + right (a component type with only one subtree puts it in the left + subtree). */ + +enum demangle_component_type +{ + /* A name, with a length and a pointer to a string. */ + DEMANGLE_COMPONENT_NAME, + /* A qualified name. The left subtree is a class or namespace or + some such thing, and the right subtree is a name qualified by + that class. */ + DEMANGLE_COMPONENT_QUAL_NAME, + /* A local name. The left subtree describes a function, and the + right subtree is a name which is local to that function. */ + DEMANGLE_COMPONENT_LOCAL_NAME, + /* A typed name. The left subtree is a name, and the right subtree + describes that name as a function. */ + DEMANGLE_COMPONENT_TYPED_NAME, + /* A template. The left subtree is a template name, and the right + subtree is a template argument list. */ + DEMANGLE_COMPONENT_TEMPLATE, + /* A template parameter. This holds a number, which is the template + parameter index. */ + DEMANGLE_COMPONENT_TEMPLATE_PARAM, + /* A constructor. This holds a name and the kind of + constructor. */ + DEMANGLE_COMPONENT_CTOR, + /* A destructor. This holds a name and the kind of destructor. */ + DEMANGLE_COMPONENT_DTOR, + /* A vtable. This has one subtree, the type for which this is a + vtable. */ + DEMANGLE_COMPONENT_VTABLE, + /* A VTT structure. This has one subtree, the type for which this + is a VTT. */ + DEMANGLE_COMPONENT_VTT, + /* A construction vtable. The left subtree is the type for which + this is a vtable, and the right subtree is the derived type for + which this vtable is built. */ + DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE, + /* A typeinfo structure. This has one subtree, the type for which + this is the tpeinfo structure. */ + DEMANGLE_COMPONENT_TYPEINFO, + /* A typeinfo name. This has one subtree, the type for which this + is the typeinfo name. */ + DEMANGLE_COMPONENT_TYPEINFO_NAME, + /* A typeinfo function. This has one subtree, the type for which + this is the tpyeinfo function. */ + DEMANGLE_COMPONENT_TYPEINFO_FN, + /* A thunk. This has one subtree, the name for which this is a + thunk. */ + DEMANGLE_COMPONENT_THUNK, + /* A virtual thunk. This has one subtree, the name for which this + is a virtual thunk. */ + DEMANGLE_COMPONENT_VIRTUAL_THUNK, + /* A covariant thunk. This has one subtree, the name for which this + is a covariant thunk. */ + DEMANGLE_COMPONENT_COVARIANT_THUNK, + /* A Java class. This has one subtree, the type. */ + DEMANGLE_COMPONENT_JAVA_CLASS, + /* A guard variable. This has one subtree, the name for which this + is a guard variable. */ + DEMANGLE_COMPONENT_GUARD, + /* A reference temporary. This has one subtree, the name for which + this is a temporary. */ + DEMANGLE_COMPONENT_REFTEMP, + /* A hidden alias. This has one subtree, the encoding for which it + is providing alternative linkage. */ + DEMANGLE_COMPONENT_HIDDEN_ALIAS, + /* A standard substitution. This holds the name of the + substitution. */ + DEMANGLE_COMPONENT_SUB_STD, + /* The restrict qualifier. The one subtree is the type which is + being qualified. */ + DEMANGLE_COMPONENT_RESTRICT, + /* The volatile qualifier. The one subtree is the type which is + being qualified. */ + DEMANGLE_COMPONENT_VOLATILE, + /* The const qualifier. The one subtree is the type which is being + qualified. */ + DEMANGLE_COMPONENT_CONST, + /* The restrict qualifier modifying a member function. The one + subtree is the type which is being qualified. */ + DEMANGLE_COMPONENT_RESTRICT_THIS, + /* The volatile qualifier modifying a member function. The one + subtree is the type which is being qualified. */ + DEMANGLE_COMPONENT_VOLATILE_THIS, + /* The const qualifier modifying a member function. The one subtree + is the type which is being qualified. */ + DEMANGLE_COMPONENT_CONST_THIS, + /* A vendor qualifier. The left subtree is the type which is being + qualified, and the right subtree is the name of the + qualifier. */ + DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL, + /* A pointer. The one subtree is the type which is being pointed + to. */ + DEMANGLE_COMPONENT_POINTER, + /* A reference. The one subtree is the type which is being + referenced. */ + DEMANGLE_COMPONENT_REFERENCE, + /* C++0x: An rvalue reference. The one subtree is the type which is + being referenced. */ + DEMANGLE_COMPONENT_RVALUE_REFERENCE, + /* A complex type. The one subtree is the base type. */ + DEMANGLE_COMPONENT_COMPLEX, + /* An imaginary type. The one subtree is the base type. */ + DEMANGLE_COMPONENT_IMAGINARY, + /* A builtin type. This holds the builtin type information. */ + DEMANGLE_COMPONENT_BUILTIN_TYPE, + /* A vendor's builtin type. This holds the name of the type. */ + DEMANGLE_COMPONENT_VENDOR_TYPE, + /* A function type. The left subtree is the return type. The right + subtree is a list of ARGLIST nodes. Either or both may be + NULL. */ + DEMANGLE_COMPONENT_FUNCTION_TYPE, + /* An array type. The left subtree is the dimension, which may be + NULL, or a string (represented as DEMANGLE_COMPONENT_NAME), or an + expression. The right subtree is the element type. */ + DEMANGLE_COMPONENT_ARRAY_TYPE, + /* A pointer to member type. The left subtree is the class type, + and the right subtree is the member type. CV-qualifiers appear + on the latter. */ + DEMANGLE_COMPONENT_PTRMEM_TYPE, + /* An argument list. The left subtree is the current argument, and + the right subtree is either NULL or another ARGLIST node. */ + DEMANGLE_COMPONENT_ARGLIST, + /* A template argument list. The left subtree is the current + template argument, and the right subtree is either NULL or + another TEMPLATE_ARGLIST node. */ + DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, + /* An operator. This holds information about a standard + operator. */ + DEMANGLE_COMPONENT_OPERATOR, + /* An extended operator. This holds the number of arguments, and + the name of the extended operator. */ + DEMANGLE_COMPONENT_EXTENDED_OPERATOR, + /* A typecast, represented as a unary operator. The one subtree is + the type to which the argument should be cast. */ + DEMANGLE_COMPONENT_CAST, + /* A unary expression. The left subtree is the operator, and the + right subtree is the single argument. */ + DEMANGLE_COMPONENT_UNARY, + /* A binary expression. The left subtree is the operator, and the + right subtree is a BINARY_ARGS. */ + DEMANGLE_COMPONENT_BINARY, + /* Arguments to a binary expression. The left subtree is the first + argument, and the right subtree is the second argument. */ + DEMANGLE_COMPONENT_BINARY_ARGS, + /* A trinary expression. The left subtree is the operator, and the + right subtree is a TRINARY_ARG1. */ + DEMANGLE_COMPONENT_TRINARY, + /* Arguments to a trinary expression. The left subtree is the first + argument, and the right subtree is a TRINARY_ARG2. */ + DEMANGLE_COMPONENT_TRINARY_ARG1, + /* More arguments to a trinary expression. The left subtree is the + second argument, and the right subtree is the third argument. */ + DEMANGLE_COMPONENT_TRINARY_ARG2, + /* A literal. The left subtree is the type, and the right subtree + is the value, represented as a DEMANGLE_COMPONENT_NAME. */ + DEMANGLE_COMPONENT_LITERAL, + /* A negative literal. Like LITERAL, but the value is negated. + This is a minor hack: the NAME used for LITERAL points directly + to the mangled string, but since negative numbers are mangled + using 'n' instead of '-', we want a way to indicate a negative + number which involves neither modifying the mangled string nor + allocating a new copy of the literal in memory. */ + DEMANGLE_COMPONENT_LITERAL_NEG +}; + +/* Types which are only used internally. */ + +struct demangle_operator_info; +struct demangle_builtin_type_info; + +/* A node in the tree representation is an instance of a struct + demangle_component. Note that the field names of the struct are + not well protected against macros defined by the file including + this one. We can fix this if it ever becomes a problem. */ + +struct demangle_component +{ + /* The type of this component. */ + enum demangle_component_type type; + + union + { + /* For DEMANGLE_COMPONENT_NAME. */ + struct + { + /* A pointer to the name (which need not NULL terminated) and + its length. */ + const char *s; + int len; + } s_name; + + /* For DEMANGLE_COMPONENT_OPERATOR. */ + struct + { + /* Operator. */ + const struct demangle_operator_info *op; + } s_operator; + + /* For DEMANGLE_COMPONENT_EXTENDED_OPERATOR. */ + struct + { + /* Number of arguments. */ + int args; + /* Name. */ + struct demangle_component *name; + } s_extended_operator; + + /* For DEMANGLE_COMPONENT_CTOR. */ + struct + { + /* Kind of constructor. */ + enum gnu_v3_ctor_kinds kind; + /* Name. */ + struct demangle_component *name; + } s_ctor; + + /* For DEMANGLE_COMPONENT_DTOR. */ + struct + { + /* Kind of destructor. */ + enum gnu_v3_dtor_kinds kind; + /* Name. */ + struct demangle_component *name; + } s_dtor; + + /* For DEMANGLE_COMPONENT_BUILTIN_TYPE. */ + struct + { + /* Builtin type. */ + const struct demangle_builtin_type_info *type; + } s_builtin; + + /* For DEMANGLE_COMPONENT_SUB_STD. */ + struct + { + /* Standard substitution string. */ + const char* string; + /* Length of string. */ + int len; + } s_string; + + /* For DEMANGLE_COMPONENT_TEMPLATE_PARAM. */ + struct + { + /* Template parameter index. */ + long number; + } s_number; + + /* For other types. */ + struct + { + /* Left (or only) subtree. */ + struct demangle_component *left; + /* Right subtree. */ + struct demangle_component *right; + } s_binary; + + } u; +}; + +/* People building mangled trees are expected to allocate instances of + struct demangle_component themselves. They can then call one of + the following functions to fill them in. */ + +/* Fill in most component types with a left subtree and a right + subtree. Returns non-zero on success, zero on failure, such as an + unrecognized or inappropriate component type. */ + +extern int +cplus_demangle_fill_component (struct demangle_component *fill, + enum demangle_component_type, + struct demangle_component *left, + struct demangle_component *right); + +/* Fill in a DEMANGLE_COMPONENT_NAME. Returns non-zero on success, + zero for bad arguments. */ + +extern int +cplus_demangle_fill_name (struct demangle_component *fill, + const char *, int); + +/* Fill in a DEMANGLE_COMPONENT_BUILTIN_TYPE, using the name of the + builtin type (e.g., "int", etc.). Returns non-zero on success, + zero if the type is not recognized. */ + +extern int +cplus_demangle_fill_builtin_type (struct demangle_component *fill, + const char *type_name); + +/* Fill in a DEMANGLE_COMPONENT_OPERATOR, using the name of the + operator and the number of arguments which it takes (the latter is + used to disambiguate operators which can be both binary and unary, + such as '-'). Returns non-zero on success, zero if the operator is + not recognized. */ + +extern int +cplus_demangle_fill_operator (struct demangle_component *fill, + const char *opname, int args); + +/* Fill in a DEMANGLE_COMPONENT_EXTENDED_OPERATOR, providing the + number of arguments and the name. Returns non-zero on success, + zero for bad arguments. */ + +extern int +cplus_demangle_fill_extended_operator (struct demangle_component *fill, + int numargs, + struct demangle_component *nm); + +/* Fill in a DEMANGLE_COMPONENT_CTOR. Returns non-zero on success, + zero for bad arguments. */ + +extern int +cplus_demangle_fill_ctor (struct demangle_component *fill, + enum gnu_v3_ctor_kinds kind, + struct demangle_component *name); + +/* Fill in a DEMANGLE_COMPONENT_DTOR. Returns non-zero on success, + zero for bad arguments. */ + +extern int +cplus_demangle_fill_dtor (struct demangle_component *fill, + enum gnu_v3_dtor_kinds kind, + struct demangle_component *name); + +/* This function translates a mangled name into a struct + demangle_component tree. The first argument is the mangled name. + The second argument is DMGL_* options. This returns a pointer to a + tree on success, or NULL on failure. On success, the third + argument is set to a block of memory allocated by malloc. This + block should be passed to free when the tree is no longer + needed. */ + +extern struct demangle_component * +cplus_demangle_v3_components (const char *mangled, int options, void **mem); + +/* This function takes a struct demangle_component tree and returns + the corresponding demangled string. The first argument is DMGL_* + options. The second is the tree to demangle. The third is a guess + at the length of the demangled string, used to initially allocate + the return buffer. The fourth is a pointer to a size_t. On + success, this function returns a buffer allocated by malloc(), and + sets the size_t pointed to by the fourth argument to the size of + the allocated buffer (not the length of the returned string). On + failure, this function returns NULL, and sets the size_t pointed to + by the fourth argument to 0 for an invalid tree, or to 1 for a + memory allocation error. */ + +extern char * +cplus_demangle_print (int options, + const struct demangle_component *tree, + int estimated_length, + size_t *p_allocated_size); + +/* This function takes a struct demangle_component tree and passes back + a demangled string in one or more calls to a callback function. + The first argument is DMGL_* options. The second is the tree to + demangle. The third is a pointer to a callback function; on each call + this receives an element of the demangled string, its length, and an + opaque value. The fourth is the opaque value passed to the callback. + The callback is called once or more to return the full demangled + string. The demangled element string is always nul-terminated, though + its length is also provided for convenience. In contrast to + cplus_demangle_print(), this function does not allocate heap memory + to grow output strings (except perhaps where alloca() is implemented + by malloc()), and so is normally safe for use where the heap has been + corrupted. On success, this function returns 1; on failure, 0. */ + +extern int +cplus_demangle_print_callback (int options, + const struct demangle_component *tree, + demangle_callbackref callback, void *opaque); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* DEMANGLE_H */ diff --git a/include/dyn-string.h b/include/dyn-string.h new file mode 100644 index 0000000..44e33de --- /dev/null +++ b/include/dyn-string.h @@ -0,0 +1,60 @@ +/* An abstract string datatype. + Copyright (C) 1998, 1999, 2000, 2002, 2004 Free Software Foundation, Inc. + Contributed by Mark Mitchell (mark@markmitchell.com). + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + + +typedef struct dyn_string +{ + int allocated; /* The amount of space allocated for the string. */ + int length; /* The actual length of the string. */ + char *s; /* The string itself, NUL-terminated. */ +}* dyn_string_t; + +/* The length STR, in bytes, not including the terminating NUL. */ +#define dyn_string_length(STR) \ + ((STR)->length) + +/* The NTBS in which the contents of STR are stored. */ +#define dyn_string_buf(STR) \ + ((STR)->s) + +/* Compare DS1 to DS2 with strcmp. */ +#define dyn_string_compare(DS1, DS2) \ + (strcmp ((DS1)->s, (DS2)->s)) + + +extern int dyn_string_init (struct dyn_string *, int); +extern dyn_string_t dyn_string_new (int); +extern void dyn_string_delete (dyn_string_t); +extern char *dyn_string_release (dyn_string_t); +extern dyn_string_t dyn_string_resize (dyn_string_t, int); +extern void dyn_string_clear (dyn_string_t); +extern int dyn_string_copy (dyn_string_t, dyn_string_t); +extern int dyn_string_copy_cstr (dyn_string_t, const char *); +extern int dyn_string_prepend (dyn_string_t, dyn_string_t); +extern int dyn_string_prepend_cstr (dyn_string_t, const char *); +extern int dyn_string_insert (dyn_string_t, int, dyn_string_t); +extern int dyn_string_insert_cstr (dyn_string_t, int, const char *); +extern int dyn_string_insert_char (dyn_string_t, int, int); +extern int dyn_string_append (dyn_string_t, dyn_string_t); +extern int dyn_string_append_cstr (dyn_string_t, const char *); +extern int dyn_string_append_char (dyn_string_t, int); +extern int dyn_string_substring (dyn_string_t, dyn_string_t, int, int); +extern int dyn_string_eq (dyn_string_t, dyn_string_t); diff --git a/include/fibheap.h b/include/fibheap.h new file mode 100644 index 0000000..348c4ae --- /dev/null +++ b/include/fibheap.h @@ -0,0 +1,86 @@ +/* A Fibonacci heap datatype. + Copyright 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + Contributed by Daniel Berlin (dan@cgsoftware.com). + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* Fibonacci heaps are somewhat complex, but, there's an article in + DDJ that explains them pretty well: + + http://www.ddj.com/articles/1997/9701/9701o/9701o.htm?topic=algoritms + + Introduction to algorithms by Corman and Rivest also goes over them. + + The original paper that introduced them is "Fibonacci heaps and their + uses in improved network optimization algorithms" by Tarjan and + Fredman (JACM 34(3), July 1987). + + Amortized and real worst case time for operations: + + ExtractMin: O(lg n) amortized. O(n) worst case. + DecreaseKey: O(1) amortized. O(lg n) worst case. + Insert: O(2) amortized. O(1) actual. + Union: O(1) amortized. O(1) actual. */ + +#ifndef _FIBHEAP_H_ +#define _FIBHEAP_H_ + +#include "ansidecl.h" + +typedef long fibheapkey_t; + +typedef struct fibheap +{ + size_t nodes; + struct fibnode *min; + struct fibnode *root; +} *fibheap_t; + +typedef struct fibnode +{ + struct fibnode *parent; + struct fibnode *child; + struct fibnode *left; + struct fibnode *right; + fibheapkey_t key; + void *data; +#if defined (__GNUC__) && (!defined (SIZEOF_INT) || SIZEOF_INT < 4) + __extension__ unsigned long int degree : 31; + __extension__ unsigned long int mark : 1; +#else + unsigned int degree : 31; + unsigned int mark : 1; +#endif +} *fibnode_t; + +extern fibheap_t fibheap_new (void); +extern fibnode_t fibheap_insert (fibheap_t, fibheapkey_t, void *); +extern int fibheap_empty (fibheap_t); +extern fibheapkey_t fibheap_min_key (fibheap_t); +extern fibheapkey_t fibheap_replace_key (fibheap_t, fibnode_t, + fibheapkey_t); +extern void *fibheap_replace_key_data (fibheap_t, fibnode_t, + fibheapkey_t, void *); +extern void *fibheap_extract_min (fibheap_t); +extern void *fibheap_min (fibheap_t); +extern void *fibheap_replace_data (fibheap_t, fibnode_t, void *); +extern void *fibheap_delete_node (fibheap_t, fibnode_t); +extern void fibheap_delete (fibheap_t); +extern fibheap_t fibheap_union (fibheap_t, fibheap_t); + +#endif /* _FIBHEAP_H_ */ diff --git a/libcpp/filenames.h b/include/filenames.h similarity index 100% rename from libcpp/filenames.h rename to include/filenames.h diff --git a/include/floatformat.h b/include/floatformat.h new file mode 100644 index 0000000..c5f60a3 --- /dev/null +++ b/include/floatformat.h @@ -0,0 +1,149 @@ +/* IEEE floating point support declarations, for GDB, the GNU Debugger. + Copyright 1991, 1994, 1995, 1997, 2000, 2003, 2005 + Free Software Foundation, Inc. + +This file is part of GDB. + +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. */ + +#if !defined (FLOATFORMAT_H) +#define FLOATFORMAT_H 1 + +#include "ansidecl.h" + +/* A floatformat consists of a sign bit, an exponent and a mantissa. Once the + bytes are concatenated according to the byteorder flag, then each of those + fields is contiguous. We number the bits with 0 being the most significant + (i.e. BITS_BIG_ENDIAN type numbering), and specify which bits each field + contains with the *_start and *_len fields. */ + +/* What is the order of the bytes? */ + +enum floatformat_byteorders { + /* Standard little endian byte order. + EX: 1.2345678e10 => 00 00 80 c5 e0 fe 06 42 */ + floatformat_little, + + /* Standard big endian byte order. + EX: 1.2345678e10 => 42 06 fe e0 c5 80 00 00 */ + floatformat_big, + + /* Little endian byte order but big endian word order. + EX: 1.2345678e10 => e0 fe 06 42 00 00 80 c5 */ + floatformat_littlebyte_bigword, + + /* VAX byte order. Little endian byte order with 16-bit words. The + following example is an illustration of the byte order only; VAX + doesn't have a fully IEEE compliant floating-point format. + EX: 1.2345678e10 => 80 c5 00 00 06 42 e0 fe */ + floatformat_vax +}; + +enum floatformat_intbit { floatformat_intbit_yes, floatformat_intbit_no }; + +struct floatformat +{ + enum floatformat_byteorders byteorder; + unsigned int totalsize; /* Total size of number in bits */ + + /* Sign bit is always one bit long. 1 means negative, 0 means positive. */ + unsigned int sign_start; + + unsigned int exp_start; + unsigned int exp_len; + /* Bias added to a "true" exponent to form the biased exponent. It + is intentionally signed as, otherwize, -exp_bias can turn into a + very large number (e.g., given the exp_bias of 0x3fff and a 64 + bit long, the equation (long)(1 - exp_bias) evaluates to + 4294950914) instead of -16382). */ + int exp_bias; + /* Exponent value which indicates NaN. This is the actual value stored in + the float, not adjusted by the exp_bias. This usually consists of all + one bits. */ + unsigned int exp_nan; + + unsigned int man_start; + unsigned int man_len; + + /* Is the integer bit explicit or implicit? */ + enum floatformat_intbit intbit; + + /* Internal name for debugging. */ + const char *name; + + /* Validator method. */ + int (*is_valid) (const struct floatformat *fmt, const void *from); + + /* Is the format actually the sum of two smaller floating point + formats (IBM long double, as described in + gcc/config/rs6000/darwin-ldouble-format)? If so, this is the + smaller format in question, and the fields sign_start through + intbit describe the first half. If not, this is NULL. */ + const struct floatformat *split_half; +}; + +/* floatformats for IEEE single and double, big and little endian. */ + +extern const struct floatformat floatformat_ieee_single_big; +extern const struct floatformat floatformat_ieee_single_little; +extern const struct floatformat floatformat_ieee_double_big; +extern const struct floatformat floatformat_ieee_double_little; + +/* floatformat for ARM IEEE double, little endian bytes and big endian words */ + +extern const struct floatformat floatformat_ieee_double_littlebyte_bigword; + +/* floatformats for VAX. */ + +extern const struct floatformat floatformat_vax_f; +extern const struct floatformat floatformat_vax_d; +extern const struct floatformat floatformat_vax_g; + +/* floatformats for various extendeds. */ + +extern const struct floatformat floatformat_i387_ext; +extern const struct floatformat floatformat_m68881_ext; +extern const struct floatformat floatformat_i960_ext; +extern const struct floatformat floatformat_m88110_ext; +extern const struct floatformat floatformat_m88110_harris_ext; +extern const struct floatformat floatformat_arm_ext_big; +extern const struct floatformat floatformat_arm_ext_littlebyte_bigword; +/* IA-64 Floating Point register spilt into memory. */ +extern const struct floatformat floatformat_ia64_spill_big; +extern const struct floatformat floatformat_ia64_spill_little; +extern const struct floatformat floatformat_ia64_quad_big; +extern const struct floatformat floatformat_ia64_quad_little; +/* IBM long double (double+double). */ +extern const struct floatformat floatformat_ibm_long_double; + +/* Convert from FMT to a double. + FROM is the address of the extended float. + Store the double in *TO. */ + +extern void +floatformat_to_double (const struct floatformat *, const void *, double *); + +/* The converse: convert the double *FROM to FMT + and store where TO points. */ + +extern void +floatformat_from_double (const struct floatformat *, const double *, void *); + +/* Return non-zero iff the data at FROM is a valid number in format FMT. */ + +extern int +floatformat_is_valid (const struct floatformat *fmt, const void *from); + +#endif /* defined (FLOATFORMAT_H) */ diff --git a/include/fnmatch.h b/include/fnmatch.h new file mode 100644 index 0000000..5b9953c --- /dev/null +++ b/include/fnmatch.h @@ -0,0 +1,70 @@ +/* Copyright 1991, 1992, 1993, 1996 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@prep.ai.mit.edu. + +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, 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, 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#ifndef _FNMATCH_H + +#define _FNMATCH_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined (__cplusplus) || (defined (__STDC__) && __STDC__) +#undef __P +#define __P(args) args +#else /* Not C++ or ANSI C. */ +#undef __P +#define __P(args) () +/* We can get away without defining `const' here only because in this file + it is used only inside the prototype for `fnmatch', which is elided in + non-ANSI C where `const' is problematical. */ +#endif /* C++ or ANSI C. */ + + +/* We #undef these before defining them because some losing systems + (HP-UX A.08.07 for example) define these in . */ +#undef FNM_PATHNAME +#undef FNM_NOESCAPE +#undef FNM_PERIOD + +/* Bits set in the FLAGS argument to `fnmatch'. */ +#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */ +#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */ +#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */ + +#if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_GNU_SOURCE) +#define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */ +#define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */ +#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */ +#endif + +/* Value returned by `fnmatch' if STRING does not match PATTERN. */ +#define FNM_NOMATCH 1 + +/* Match STRING against the filename pattern PATTERN, + returning zero if it matches, FNM_NOMATCH if not. */ +extern int fnmatch __P ((const char *__pattern, const char *__string, + int __flags)); + +#ifdef __cplusplus +} +#endif + +#endif /* fnmatch.h */ diff --git a/include/getopt.h b/include/getopt.h new file mode 100644 index 0000000..5421cab --- /dev/null +++ b/include/getopt.h @@ -0,0 +1,144 @@ +/* Declarations for getopt. + Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 2000, + 2002 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. + + 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, 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. */ + +#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__ +/* HAVE_DECL_* is a three-state macro: undefined, 0 or 1. If it is + undefined, we haven't run the autoconf check so provide the + declaration without arguments. If it is 0, we checked and failed + to find the declaration so provide a fully prototyped one. If it + is 1, we found it so don't provide any declaration at all. */ +#if !HAVE_DECL_GETOPT +#if defined (__GNU_LIBRARY__) || defined (HAVE_DECL_GETOPT) +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in unistd.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 +#ifndef __cplusplus +extern int getopt (); +#endif /* __cplusplus */ +#endif +#endif /* !HAVE_DECL_GETOPT */ + +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 */ diff --git a/libcpp/hashtab.h b/include/hashtab.h similarity index 100% rename from libcpp/hashtab.h rename to include/hashtab.h diff --git a/libcpp/libiberty.h b/include/libiberty.h similarity index 100% rename from libcpp/libiberty.h rename to include/libiberty.h diff --git a/libcpp/md5.h b/include/md5.h similarity index 100% rename from libcpp/md5.h rename to include/md5.h diff --git a/include/objalloc.h b/include/objalloc.h new file mode 100644 index 0000000..36772d1 --- /dev/null +++ b/include/objalloc.h @@ -0,0 +1,115 @@ +/* objalloc.h -- routines to allocate memory for objects + Copyright 1997, 2001 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Cygnus Solutions. + +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, 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, 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#ifndef OBJALLOC_H +#define OBJALLOC_H + +#include "ansidecl.h" + +/* These routines allocate space for an object. The assumption is + that the object will want to allocate space as it goes along, but + will never want to free any particular block. There is a function + to free a block, which also frees all more recently allocated + blocks. There is also a function to free all the allocated space. + + This is essentially a specialization of obstacks. The main + difference is that a block may not be allocated a bit at a time. + Another difference is that these routines are always built on top + of malloc, and always pass an malloc failure back to the caller, + unlike more recent versions of obstacks. */ + +/* This is what an objalloc structure looks like. Callers should not + refer to these fields, nor should they allocate these structure + themselves. Instead, they should only create them via + objalloc_init, and only access them via the functions and macros + listed below. The structure is only defined here so that we can + access it via macros. */ + +struct objalloc +{ + char *current_ptr; + unsigned int current_space; + void *chunks; +}; + +/* Work out the required alignment. */ + +struct objalloc_align { char x; double d; }; + +#if defined (__STDC__) && __STDC__ +#ifndef offsetof +#include +#endif +#endif +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER) +#endif +#define OBJALLOC_ALIGN offsetof (struct objalloc_align, d) + +/* Create an objalloc structure. Returns NULL if malloc fails. */ + +extern struct objalloc *objalloc_create (void); + +/* Allocate space from an objalloc structure. Returns NULL if malloc + fails. */ + +extern void *_objalloc_alloc (struct objalloc *, unsigned long); + +/* The macro version of objalloc_alloc. We only define this if using + gcc, because otherwise we would have to evaluate the arguments + multiple times, or use a temporary field as obstack.h does. */ + +#if defined (__GNUC__) && defined (__STDC__) && __STDC__ + +/* NextStep 2.0 cc is really gcc 1.93 but it defines __GNUC__ = 2 and + does not implement __extension__. But that compiler doesn't define + __GNUC_MINOR__. */ +#if __GNUC__ < 2 || (__NeXT__ && !__GNUC_MINOR__) +#define __extension__ +#endif + +#define objalloc_alloc(o, l) \ + __extension__ \ + ({ struct objalloc *__o = (o); \ + unsigned long __len = (l); \ + if (__len == 0) \ + __len = 1; \ + __len = (__len + OBJALLOC_ALIGN - 1) &~ (OBJALLOC_ALIGN - 1); \ + (__len <= __o->current_space \ + ? (__o->current_ptr += __len, \ + __o->current_space -= __len, \ + (void *) (__o->current_ptr - __len)) \ + : _objalloc_alloc (__o, __len)); }) + +#else /* ! __GNUC__ */ + +#define objalloc_alloc(o, l) _objalloc_alloc ((o), (l)) + +#endif /* ! __GNUC__ */ + +/* Free an entire objalloc structure. */ + +extern void objalloc_free (struct objalloc *); + +/* Free a block allocated by objalloc_alloc. This also frees all more + recently allocated blocks. */ + +extern void objalloc_free_block (struct objalloc *, void *); + +#endif /* OBJALLOC_H */ diff --git a/libcpp/obstack.h b/include/obstack.h similarity index 100% rename from libcpp/obstack.h rename to include/obstack.h diff --git a/include/partition.h b/include/partition.h new file mode 100644 index 0000000..d8b554f --- /dev/null +++ b/include/partition.h @@ -0,0 +1,82 @@ +/* List implementation of a partition of consecutive integers. + Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. + Contributed by CodeSourcery, LLC. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING. If not, write to + the Free Software Foundation, 51 Franklin Street - Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* This package implements a partition of consecutive integers. The + elements are partitioned into classes. Each class is represented + by one of its elements, the canonical element, which is chosen + arbitrarily from elements in the class. The principal operations + on a partition are FIND, which takes an element, determines its + class, and returns the canonical element for that class, and UNION, + which unites the two classes that contain two given elements into a + single class. + + The list implementation used here provides constant-time finds. By + storing the size of each class with the class's canonical element, + it is able to perform unions over all the classes in the partition + in O (N log N) time. */ + +#ifndef _PARTITION_H +#define _PARTITION_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "ansidecl.h" +#include + +struct partition_elem +{ + /* The canonical element that represents the class containing this + element. */ + int class_element; + /* The next element in this class. Elements in each class form a + circular list. */ + struct partition_elem* next; + /* The number of elements in this class. Valid only if this is the + canonical element for its class. */ + unsigned class_count; +}; + +typedef struct partition_def +{ + /* The number of elements in this partition. */ + int num_elements; + /* The elements in the partition. */ + struct partition_elem elements[1]; +} *partition; + +extern partition partition_new (int); +extern void partition_delete (partition); +extern int partition_union (partition, int, int); +extern void partition_print (partition, FILE*); + +/* Returns the canonical element corresponding to the class containing + ELEMENT__ in PARTITION__. */ + +#define partition_find(partition__, element__) \ + ((partition__)->elements[(element__)].class_element) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _PARTITION_H */ diff --git a/libcpp/safe-ctype.h b/include/safe-ctype.h similarity index 100% rename from libcpp/safe-ctype.h rename to include/safe-ctype.h diff --git a/include/sort.h b/include/sort.h new file mode 100644 index 0000000..582af81 --- /dev/null +++ b/include/sort.h @@ -0,0 +1,48 @@ +/* Sorting algorithms. + Copyright (C) 2000, 2002 Free Software Foundation, Inc. + Contributed by Mark Mitchell . + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#ifndef SORT_H +#define SORT_H + +#include /* For size_t */ +#ifdef __STDC__ +#include +#endif /* __STDC__ */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "ansidecl.h" + +/* Sort an array of pointers. */ + +extern void sort_pointers (size_t, void **, void **); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SORT_H */ + + + + diff --git a/include/splay-tree.h b/include/splay-tree.h new file mode 100644 index 0000000..b03c581 --- /dev/null +++ b/include/splay-tree.h @@ -0,0 +1,152 @@ +/* A splay-tree datatype. + Copyright 1998, 1999, 2000, 2002, 2007 Free Software Foundation, Inc. + Contributed by Mark Mitchell (mark@markmitchell.com). + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING. If not, write to + the Free Software Foundation, 51 Franklin Street - Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* For an easily readable description of splay-trees, see: + + Lewis, Harry R. and Denenberg, Larry. Data Structures and Their + Algorithms. Harper-Collins, Inc. 1991. + + The major feature of splay trees is that all basic tree operations + are amortized O(log n) time for a tree with n nodes. */ + +#ifndef _SPLAY_TREE_H +#define _SPLAY_TREE_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "ansidecl.h" + +#ifndef _WIN64 + typedef unsigned long int libi_uhostptr_t; + typedef long int libi_shostptr_t; +#else + typedef unsigned long long libi_uhostptr_t; + typedef long long libi_shostptr_t; +#endif + +#ifndef GTY +#define GTY(X) +#endif + +/* Use typedefs for the key and data types to facilitate changing + these types, if necessary. These types should be sufficiently wide + that any pointer or scalar can be cast to these types, and then + cast back, without loss of precision. */ +typedef libi_uhostptr_t splay_tree_key; +typedef libi_uhostptr_t splay_tree_value; + +/* Forward declaration for a node in the tree. */ +typedef struct splay_tree_node_s *splay_tree_node; + +/* The type of a function which compares two splay-tree keys. The + function should return values as for qsort. */ +typedef int (*splay_tree_compare_fn) (splay_tree_key, splay_tree_key); + +/* The type of a function used to deallocate any resources associated + with the key. */ +typedef void (*splay_tree_delete_key_fn) (splay_tree_key); + +/* The type of a function used to deallocate any resources associated + with the value. */ +typedef void (*splay_tree_delete_value_fn) (splay_tree_value); + +/* The type of a function used to iterate over the tree. */ +typedef int (*splay_tree_foreach_fn) (splay_tree_node, void*); + +/* The type of a function used to allocate memory for tree root and + node structures. The first argument is the number of bytes needed; + the second is a data pointer the splay tree functions pass through + to the allocator. This function must never return zero. */ +typedef void *(*splay_tree_allocate_fn) (int, void *); + +/* The type of a function used to free memory allocated using the + corresponding splay_tree_allocate_fn. The first argument is the + memory to be freed; the latter is a data pointer the splay tree + functions pass through to the freer. */ +typedef void (*splay_tree_deallocate_fn) (void *, void *); + +/* The nodes in the splay tree. */ +struct splay_tree_node_s GTY(()) +{ + /* The key. */ + splay_tree_key GTY ((use_param1)) key; + + /* The value. */ + splay_tree_value GTY ((use_param2)) value; + + /* The left and right children, respectively. */ + splay_tree_node GTY ((use_params)) left; + splay_tree_node GTY ((use_params)) right; +}; + +/* The splay tree itself. */ +struct splay_tree_s GTY(()) +{ + /* The root of the tree. */ + splay_tree_node GTY ((use_params)) root; + + /* The comparision function. */ + splay_tree_compare_fn comp; + + /* The deallocate-key function. NULL if no cleanup is necessary. */ + splay_tree_delete_key_fn delete_key; + + /* The deallocate-value function. NULL if no cleanup is necessary. */ + splay_tree_delete_value_fn delete_value; + + /* Allocate/free functions, and a data pointer to pass to them. */ + splay_tree_allocate_fn allocate; + splay_tree_deallocate_fn deallocate; + void * GTY((skip)) allocate_data; +}; + +typedef struct splay_tree_s *splay_tree; + +extern splay_tree splay_tree_new (splay_tree_compare_fn, + splay_tree_delete_key_fn, + splay_tree_delete_value_fn); +extern splay_tree splay_tree_new_with_allocator (splay_tree_compare_fn, + splay_tree_delete_key_fn, + splay_tree_delete_value_fn, + splay_tree_allocate_fn, + splay_tree_deallocate_fn, + void *); +extern void splay_tree_delete (splay_tree); +extern splay_tree_node splay_tree_insert (splay_tree, + splay_tree_key, + splay_tree_value); +extern void splay_tree_remove (splay_tree, splay_tree_key); +extern splay_tree_node splay_tree_lookup (splay_tree, splay_tree_key); +extern splay_tree_node splay_tree_predecessor (splay_tree, splay_tree_key); +extern splay_tree_node splay_tree_successor (splay_tree, splay_tree_key); +extern splay_tree_node splay_tree_max (splay_tree); +extern splay_tree_node splay_tree_min (splay_tree); +extern int splay_tree_foreach (splay_tree, splay_tree_foreach_fn, void*); +extern int splay_tree_compare_ints (splay_tree_key, splay_tree_key); +extern int splay_tree_compare_pointers (splay_tree_key, splay_tree_key); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _SPLAY_TREE_H */ diff --git a/include/symcat.h b/include/symcat.h new file mode 100644 index 0000000..03a1292 --- /dev/null +++ b/include/symcat.h @@ -0,0 +1,49 @@ +/* Symbol concatenation utilities. + + Copyright (C) 1998, 2000 Free Software Foundation, Inc. + + 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. */ + +#ifndef SYM_CAT_H +#define SYM_CAT_H + +#if defined (__STDC__) || defined (ALMOST_STDC) || defined (HAVE_STRINGIZE) +#define CONCAT2(a,b) a##b +#define CONCAT3(a,b,c) a##b##c +#define CONCAT4(a,b,c,d) a##b##c##d +#define STRINGX(s) #s +#else +/* Note one should never pass extra whitespace to the CONCATn macros, + e.g. CONCAT2(foo, bar) because traditonal C will keep the space between + the two labels instead of concatenating them. Instead, make sure to + write CONCAT2(foo,bar). */ +#define CONCAT2(a,b) a/**/b +#define CONCAT3(a,b,c) a/**/b/**/c +#define CONCAT4(a,b,c,d) a/**/b/**/c/**/d +#define STRINGX(s) "s" +#endif + +#define XCONCAT2(a,b) CONCAT2(a,b) +#define XCONCAT3(a,b,c) CONCAT3(a,b,c) +#define XCONCAT4(a,b,c,d) CONCAT4(a,b,c,d) + +/* Note the layer of indirection here is typically used to allow + stringification of the expansion of macros. I.e. "#define foo + bar", "XSTRING(foo)", to yield "bar". Be aware that this only + works for __STDC__, not for traditional C which will still resolve + to "foo". */ +#define XSTRING(s) STRINGX(s) + +#endif /* SYM_CAT_H */ diff --git a/include/xregex.h b/include/xregex.h new file mode 100644 index 0000000..645195b --- /dev/null +++ b/include/xregex.h @@ -0,0 +1,28 @@ +/* This file redefines all regex external names before including + a renamed copy of glibc's regex.h. */ + +#ifndef _XREGEX_H +#define _XREGEX_H 1 + +# define regfree xregfree +# define regexec xregexec +# define regcomp xregcomp +# define regerror xregerror +# define re_set_registers xre_set_registers +# define re_match_2 xre_match_2 +# define re_match xre_match +# define re_search xre_search +# define re_compile_pattern xre_compile_pattern +# define re_set_syntax xre_set_syntax +# define re_search_2 xre_search_2 +# define re_compile_fastmap xre_compile_fastmap +# define re_syntax_options xre_syntax_options +# define re_max_failures xre_max_failures + +# define _REGEX_RE_COMP +# define re_comp xre_comp +# define re_exec xre_exec + +#include "xregex2.h" + +#endif /* xregex.h */ diff --git a/include/xregex2.h b/include/xregex2.h new file mode 100644 index 0000000..d3d0da1 --- /dev/null +++ b/include/xregex2.h @@ -0,0 +1,565 @@ +/* Definitions for data structures and routines for the regular + expression library, version 0.12. + + Copyright (C) 1985, 1989, 1990, 1991, 1992, 1993, 1995, 1996, 1997, + 1998, 2000, 2005 Free Software Foundation, Inc. + + This file is part of the GNU C Library. Its master source is NOT part of + the C library, however. The master source lives in /gd/gnu/lib. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. */ + +#ifndef _REGEX_H +#define _REGEX_H 1 + +/* Allow the use in C++ code. */ +#ifdef __cplusplus +extern "C" { +#endif + +/* POSIX says that must be included (by the caller) before + . */ + +#if !defined _POSIX_C_SOURCE && !defined _POSIX_SOURCE && defined VMS +/* VMS doesn't have `size_t' in , even though POSIX says it + should be there. */ +# include +#endif + +/* The following two types have to be signed and unsigned integer type + wide enough to hold a value of a pointer. For most ANSI compilers + ptrdiff_t and size_t should be likely OK. Still size of these two + types is 2 for Microsoft C. Ugh... */ +typedef long int s_reg_t; +typedef unsigned long int active_reg_t; + +/* The following bits are used to determine the regexp syntax we + recognize. The set/not-set meanings are chosen so that Emacs syntax + remains the value 0. The bits are given in alphabetical order, and + the definitions shifted by one from the previous bit; thus, when we + add or remove a bit, only one other definition need change. */ +typedef unsigned long int reg_syntax_t; + +/* If this bit is not set, then \ inside a bracket expression is literal. + If set, then such a \ quotes the following character. */ +#define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1) + +/* If this bit is not set, then + and ? are operators, and \+ and \? are + literals. + If set, then \+ and \? are operators and + and ? are literals. */ +#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1) + +/* If this bit is set, then character classes are supported. They are: + [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:], + [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:]. + If not set, then character classes are not supported. */ +#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1) + +/* If this bit is set, then ^ and $ are always anchors (outside bracket + expressions, of course). + If this bit is not set, then it depends: + ^ is an anchor if it is at the beginning of a regular + expression or after an open-group or an alternation operator; + $ is an anchor if it is at the end of a regular expression, or + before a close-group or an alternation operator. + + This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because + POSIX draft 11.2 says that * etc. in leading positions is undefined. + We already implemented a previous draft which made those constructs + invalid, though, so we haven't changed the code back. */ +#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1) + +/* If this bit is set, then special characters are always special + regardless of where they are in the pattern. + If this bit is not set, then special characters are special only in + some contexts; otherwise they are ordinary. Specifically, + * + ? and intervals are only special when not after the beginning, + open-group, or alternation operator. */ +#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1) + +/* If this bit is set, then *, +, ?, and { cannot be first in an re or + immediately after an alternation or begin-group operator. */ +#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1) + +/* If this bit is set, then . matches newline. + If not set, then it doesn't. */ +#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1) + +/* If this bit is set, then . doesn't match NUL. + If not set, then it does. */ +#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1) + +/* If this bit is set, nonmatching lists [^...] do not match newline. + If not set, they do. */ +#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1) + +/* If this bit is set, either \{...\} or {...} defines an + interval, depending on RE_NO_BK_BRACES. + If not set, \{, \}, {, and } are literals. */ +#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1) + +/* If this bit is set, +, ? and | aren't recognized as operators. + If not set, they are. */ +#define RE_LIMITED_OPS (RE_INTERVALS << 1) + +/* If this bit is set, newline is an alternation operator. + If not set, newline is literal. */ +#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1) + +/* If this bit is set, then `{...}' defines an interval, and \{ and \} + are literals. + If not set, then `\{...\}' defines an interval. */ +#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1) + +/* If this bit is set, (...) defines a group, and \( and \) are literals. + If not set, \(...\) defines a group, and ( and ) are literals. */ +#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1) + +/* If this bit is set, then \ matches . + If not set, then \ is a back-reference. */ +#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1) + +/* If this bit is set, then | is an alternation operator, and \| is literal. + If not set, then \| is an alternation operator, and | is literal. */ +#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1) + +/* If this bit is set, then an ending range point collating higher + than the starting range point, as in [z-a], is invalid. + If not set, then when ending range point collates higher than the + starting range point, the range is ignored. */ +#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1) + +/* If this bit is set, then an unmatched ) is ordinary. + If not set, then an unmatched ) is invalid. */ +#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1) + +/* If this bit is set, succeed as soon as we match the whole pattern, + without further backtracking. */ +#define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1) + +/* If this bit is set, do not process the GNU regex operators. + If not set, then the GNU regex operators are recognized. */ +#define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1) + +/* If this bit is set, turn on internal regex debugging. + If not set, and debugging was on, turn it off. + This only works if regex.c is compiled -DDEBUG. + We define this bit always, so that all that's needed to turn on + debugging is to recompile regex.c; the calling code can always have + this bit set, and it won't affect anything in the normal case. */ +#define RE_DEBUG (RE_NO_GNU_OPS << 1) + +/* If this bit is set, a syntactically invalid interval is treated as + a string of ordinary characters. For example, the ERE 'a{1' is + treated as 'a\{1'. */ +#define RE_INVALID_INTERVAL_ORD (RE_DEBUG << 1) + +/* This global variable defines the particular regexp syntax to use (for + some interfaces). When a regexp is compiled, the syntax used is + stored in the pattern buffer, so changing this does not affect + already-compiled regexps. */ +extern reg_syntax_t re_syntax_options; + +/* Define combinations of the above bits for the standard possibilities. + (The [[[ comments delimit what gets put into the Texinfo file, so + don't delete them!) */ +/* [[[begin syntaxes]]] */ +#define RE_SYNTAX_EMACS 0 + +#define RE_SYNTAX_AWK \ + (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \ + | RE_NO_BK_PARENS | RE_NO_BK_REFS \ + | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \ + | RE_DOT_NEWLINE | RE_CONTEXT_INDEP_ANCHORS \ + | RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS) + +#define RE_SYNTAX_GNU_AWK \ + ((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DEBUG) \ + & ~(RE_DOT_NOT_NULL | RE_INTERVALS | RE_CONTEXT_INDEP_OPS)) + +#define RE_SYNTAX_POSIX_AWK \ + (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \ + | RE_INTERVALS | RE_NO_GNU_OPS) + +#define RE_SYNTAX_GREP \ + (RE_BK_PLUS_QM | RE_CHAR_CLASSES \ + | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \ + | RE_NEWLINE_ALT) + +#define RE_SYNTAX_EGREP \ + (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \ + | RE_NEWLINE_ALT | RE_NO_BK_PARENS \ + | RE_NO_BK_VBAR) + +#define RE_SYNTAX_POSIX_EGREP \ + (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES \ + | RE_INVALID_INTERVAL_ORD) + +/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */ +#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC + +#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC + +/* Syntax bits common to both basic and extended POSIX regex syntax. */ +#define _RE_SYNTAX_POSIX_COMMON \ + (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \ + | RE_INTERVALS | RE_NO_EMPTY_RANGES) + +#define RE_SYNTAX_POSIX_BASIC \ + (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM) + +/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes + RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this + isn't minimal, since other operators, such as \`, aren't disabled. */ +#define RE_SYNTAX_POSIX_MINIMAL_BASIC \ + (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS) + +#define RE_SYNTAX_POSIX_EXTENDED \ + (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \ + | RE_NO_BK_PARENS | RE_NO_BK_VBAR \ + | RE_CONTEXT_INVALID_OPS | RE_UNMATCHED_RIGHT_PAREN_ORD) + +/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INDEP_OPS is + removed and RE_NO_BK_REFS is added. */ +#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \ + (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \ + | RE_NO_BK_PARENS | RE_NO_BK_REFS \ + | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD) +/* [[[end syntaxes]]] */ + +/* Maximum number of duplicates an interval can allow. Some systems + (erroneously) define this in other header files, but we want our + value, so remove any previous define. */ +#ifdef RE_DUP_MAX +# undef RE_DUP_MAX +#endif +/* If sizeof(int) == 2, then ((1 << 15) - 1) overflows. */ +#define RE_DUP_MAX (0x7fff) + + +/* POSIX `cflags' bits (i.e., information for `regcomp'). */ + +/* If this bit is set, then use extended regular expression syntax. + If not set, then use basic regular expression syntax. */ +#define REG_EXTENDED 1 + +/* If this bit is set, then ignore case when matching. + If not set, then case is significant. */ +#define REG_ICASE (REG_EXTENDED << 1) + +/* If this bit is set, then anchors do not match at newline + characters in the string. + If not set, then anchors do match at newlines. */ +#define REG_NEWLINE (REG_ICASE << 1) + +/* If this bit is set, then report only success or fail in regexec. + If not set, then returns differ between not matching and errors. */ +#define REG_NOSUB (REG_NEWLINE << 1) + + +/* POSIX `eflags' bits (i.e., information for regexec). */ + +/* If this bit is set, then the beginning-of-line operator doesn't match + the beginning of the string (presumably because it's not the + beginning of a line). + If not set, then the beginning-of-line operator does match the + beginning of the string. */ +#define REG_NOTBOL 1 + +/* Like REG_NOTBOL, except for the end-of-line. */ +#define REG_NOTEOL (1 << 1) + + +/* If any error codes are removed, changed, or added, update the + `re_error_msg' table in regex.c. */ +typedef enum +{ +#ifdef _XOPEN_SOURCE + REG_ENOSYS = -1, /* This will never happen for this implementation. */ +#endif + + REG_NOERROR = 0, /* Success. */ + REG_NOMATCH, /* Didn't find a match (for regexec). */ + + /* POSIX regcomp return error codes. (In the order listed in the + standard.) */ + REG_BADPAT, /* Invalid pattern. */ + REG_ECOLLATE, /* Not implemented. */ + REG_ECTYPE, /* Invalid character class name. */ + REG_EESCAPE, /* Trailing backslash. */ + REG_ESUBREG, /* Invalid back reference. */ + REG_EBRACK, /* Unmatched left bracket. */ + REG_EPAREN, /* Parenthesis imbalance. */ + REG_EBRACE, /* Unmatched \{. */ + REG_BADBR, /* Invalid contents of \{\}. */ + REG_ERANGE, /* Invalid range end. */ + REG_ESPACE, /* Ran out of memory. */ + REG_BADRPT, /* No preceding re for repetition op. */ + + /* Error codes we've added. */ + REG_EEND, /* Premature end. */ + REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */ + REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */ +} reg_errcode_t; + +/* This data structure represents a compiled pattern. Before calling + the pattern compiler, the fields `buffer', `allocated', `fastmap', + `translate', and `no_sub' can be set. After the pattern has been + compiled, the `re_nsub' field is available. All other fields are + private to the regex routines. */ + +#ifndef RE_TRANSLATE_TYPE +# define RE_TRANSLATE_TYPE char * +#endif + +struct re_pattern_buffer +{ +/* [[[begin pattern_buffer]]] */ + /* Space that holds the compiled pattern. It is declared as + `unsigned char *' because its elements are + sometimes used as array indexes. */ + unsigned char *buffer; + + /* Number of bytes to which `buffer' points. */ + unsigned long int allocated; + + /* Number of bytes actually used in `buffer'. */ + unsigned long int used; + + /* Syntax setting with which the pattern was compiled. */ + reg_syntax_t syntax; + + /* Pointer to a fastmap, if any, otherwise zero. re_search uses + the fastmap, if there is one, to skip over impossible + starting points for matches. */ + char *fastmap; + + /* Either a translate table to apply to all characters before + comparing them, or zero for no translation. The translation + is applied to a pattern when it is compiled and to a string + when it is matched. */ + RE_TRANSLATE_TYPE translate; + + /* Number of subexpressions found by the compiler. */ + size_t re_nsub; + + /* Zero if this pattern cannot match the empty string, one else. + Well, in truth it's used only in `re_search_2', to see + whether or not we should use the fastmap, so we don't set + this absolutely perfectly; see `re_compile_fastmap' (the + `duplicate' case). */ + unsigned can_be_null : 1; + + /* If REGS_UNALLOCATED, allocate space in the `regs' structure + for `max (RE_NREGS, re_nsub + 1)' groups. + If REGS_REALLOCATE, reallocate space if necessary. + If REGS_FIXED, use what's there. */ +#define REGS_UNALLOCATED 0 +#define REGS_REALLOCATE 1 +#define REGS_FIXED 2 + unsigned regs_allocated : 2; + + /* Set to zero when `regex_compile' compiles a pattern; set to one + by `re_compile_fastmap' if it updates the fastmap. */ + unsigned fastmap_accurate : 1; + + /* If set, `re_match_2' does not return information about + subexpressions. */ + unsigned no_sub : 1; + + /* If set, a beginning-of-line anchor doesn't match at the + beginning of the string. */ + unsigned not_bol : 1; + + /* Similarly for an end-of-line anchor. */ + unsigned not_eol : 1; + + /* If true, an anchor at a newline matches. */ + unsigned newline_anchor : 1; + +/* [[[end pattern_buffer]]] */ +}; + +typedef struct re_pattern_buffer regex_t; + +/* Type for byte offsets within the string. POSIX mandates this. */ +typedef int regoff_t; + + +/* This is the structure we store register match data in. See + regex.texinfo for a full description of what registers match. */ +struct re_registers +{ + unsigned num_regs; + regoff_t *start; + regoff_t *end; +}; + + +/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer, + `re_match_2' returns information about at least this many registers + the first time a `regs' structure is passed. */ +#ifndef RE_NREGS +# define RE_NREGS 30 +#endif + + +/* POSIX specification for registers. Aside from the different names than + `re_registers', POSIX uses an array of structures, instead of a + structure of arrays. */ +typedef struct +{ + regoff_t rm_so; /* Byte offset from string's start to substring's start. */ + regoff_t rm_eo; /* Byte offset from string's start to substring's end. */ +} regmatch_t; + +/* Declarations for routines. */ + +/* To avoid duplicating every routine declaration -- once with a + prototype (if we are ANSI), and once without (if we aren't) -- we + use the following macro to declare argument types. This + unfortunately clutters up the declarations a bit, but I think it's + worth it. */ + +/* Sets the current default syntax to SYNTAX, and return the old syntax. + You can also simply assign to the `re_syntax_options' variable. */ +extern reg_syntax_t re_set_syntax (reg_syntax_t syntax); + +/* Compile the regular expression PATTERN, with length LENGTH + and syntax given by the global `re_syntax_options', into the buffer + BUFFER. Return NULL if successful, and an error string if not. */ +extern const char *re_compile_pattern (const char *pattern, size_t length, + struct re_pattern_buffer *buffer); + + +/* Compile a fastmap for the compiled pattern in BUFFER; used to + accelerate searches. Return 0 if successful and -2 if was an + internal error. */ +extern int re_compile_fastmap (struct re_pattern_buffer *buffer); + + +/* Search in the string STRING (with length LENGTH) for the pattern + compiled into BUFFER. Start searching at position START, for RANGE + characters. Return the starting position of the match, -1 for no + match, or -2 for an internal error. Also return register + information in REGS (if REGS and BUFFER->no_sub are nonzero). */ +extern int re_search (struct re_pattern_buffer *buffer, const char *string, + int length, int start, int range, + struct re_registers *regs); + + +/* Like `re_search', but search in the concatenation of STRING1 and + STRING2. Also, stop searching at index START + STOP. */ +extern int re_search_2 (struct re_pattern_buffer *buffer, const char *string1, + int length1, const char *string2, int length2, + int start, int range, struct re_registers *regs, + int stop); + + +/* Like `re_search', but return how many characters in STRING the regexp + in BUFFER matched, starting at position START. */ +extern int re_match (struct re_pattern_buffer *buffer, const char *string, + int length, int start, struct re_registers *regs); + + +/* Relates to `re_match' as `re_search_2' relates to `re_search'. */ +extern int re_match_2 (struct re_pattern_buffer *buffer, const char *string1, + int length1, const char *string2, int length2, + int start, struct re_registers *regs, int stop); + + +/* Set REGS to hold NUM_REGS registers, storing them in STARTS and + ENDS. Subsequent matches using BUFFER and REGS will use this memory + for recording register information. STARTS and ENDS must be + allocated with malloc, and must each be at least `NUM_REGS * sizeof + (regoff_t)' bytes long. + + If NUM_REGS == 0, then subsequent matches should allocate their own + register data. + + Unless this function is called, the first search or match using + PATTERN_BUFFER will allocate its own register data, without + freeing the old data. */ +extern void re_set_registers (struct re_pattern_buffer *buffer, + struct re_registers *regs, + unsigned num_regs, regoff_t *starts, + regoff_t *ends); + +#if defined _REGEX_RE_COMP || defined _LIBC +# ifndef _CRAY +/* 4.2 bsd compatibility. */ +extern char *re_comp (const char *); +extern int re_exec (const char *); +# endif +#endif + +/* GCC 2.95 and later have "__restrict"; C99 compilers have + "restrict", and "configure" may have defined "restrict". */ +#ifndef __restrict +# if ! (2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__)) +# if defined restrict || 199901L <= __STDC_VERSION__ +# define __restrict restrict +# else +# define __restrict +# endif +# endif +#endif + +/* GCC 3.1 and later support declaring arrays as non-overlapping + using the syntax array_name[restrict] */ +#ifndef __restrict_arr +# if ! (3 < __GNUC__ || (3 == __GNUC__ && 1 <= __GNUC_MINOR__)) || defined (__GNUG__) +# define __restrict_arr +# else +# define __restrict_arr __restrict +# endif +#endif + +/* POSIX compatibility. */ +extern int regcomp (regex_t *__restrict __preg, + const char *__restrict __pattern, + int __cflags); + +#if (__GNUC__) +__extension__ +#endif +extern int regexec (const regex_t *__restrict __preg, + const char *__restrict __string, size_t __nmatch, + regmatch_t __pmatch[__restrict_arr], + int __eflags); + +extern size_t regerror (int __errcode, const regex_t *__preg, + char *__errbuf, size_t __errbuf_size); + +extern void regfree (regex_t *__preg); + + +#ifdef __cplusplus +} +#endif /* C++ */ + +#endif /* regex.h */ + +/* +Local variables: +make-backup-files: t +version-control: t +trim-versions-without-asking: nil +End: +*/ diff --git a/include/xtensa-config.h b/include/xtensa-config.h new file mode 100644 index 0000000..2aca5fe --- /dev/null +++ b/include/xtensa-config.h @@ -0,0 +1,166 @@ +/* Xtensa configuration settings. + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 + Free Software Foundation, Inc. + Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica. + + 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, 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, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef XTENSA_CONFIG_H +#define XTENSA_CONFIG_H + +/* The macros defined here match those with the same names in the Xtensa + compile-time HAL (Hardware Abstraction Layer). Please refer to the + Xtensa System Software Reference Manual for documentation of these + macros. */ + +#undef XCHAL_HAVE_BE +#define XCHAL_HAVE_BE 1 + +#undef XCHAL_HAVE_DENSITY +#define XCHAL_HAVE_DENSITY 1 + +#undef XCHAL_HAVE_CONST16 +#define XCHAL_HAVE_CONST16 0 + +#undef XCHAL_HAVE_ABS +#define XCHAL_HAVE_ABS 1 + +#undef XCHAL_HAVE_ADDX +#define XCHAL_HAVE_ADDX 1 + +#undef XCHAL_HAVE_L32R +#define XCHAL_HAVE_L32R 1 + +#undef XSHAL_USE_ABSOLUTE_LITERALS +#define XSHAL_USE_ABSOLUTE_LITERALS 0 + +#undef XCHAL_HAVE_MAC16 +#define XCHAL_HAVE_MAC16 0 + +#undef XCHAL_HAVE_MUL16 +#define XCHAL_HAVE_MUL16 0 + +#undef XCHAL_HAVE_MUL32 +#define XCHAL_HAVE_MUL32 0 + +#undef XCHAL_HAVE_MUL32_HIGH +#define XCHAL_HAVE_MUL32_HIGH 0 + +#undef XCHAL_HAVE_DIV32 +#define XCHAL_HAVE_DIV32 0 + +#undef XCHAL_HAVE_NSA +#define XCHAL_HAVE_NSA 1 + +#undef XCHAL_HAVE_MINMAX +#define XCHAL_HAVE_MINMAX 0 + +#undef XCHAL_HAVE_SEXT +#define XCHAL_HAVE_SEXT 0 + +#undef XCHAL_HAVE_LOOPS +#define XCHAL_HAVE_LOOPS 1 + +#undef XCHAL_HAVE_THREADPTR +#define XCHAL_HAVE_THREADPTR 1 + +#undef XCHAL_HAVE_RELEASE_SYNC +#define XCHAL_HAVE_RELEASE_SYNC 0 + +#undef XCHAL_HAVE_S32C1I +#define XCHAL_HAVE_S32C1I 0 + +#undef XCHAL_HAVE_BOOLEANS +#define XCHAL_HAVE_BOOLEANS 0 + +#undef XCHAL_HAVE_FP +#define XCHAL_HAVE_FP 0 + +#undef XCHAL_HAVE_FP_DIV +#define XCHAL_HAVE_FP_DIV 0 + +#undef XCHAL_HAVE_FP_RECIP +#define XCHAL_HAVE_FP_RECIP 0 + +#undef XCHAL_HAVE_FP_SQRT +#define XCHAL_HAVE_FP_SQRT 0 + +#undef XCHAL_HAVE_FP_RSQRT +#define XCHAL_HAVE_FP_RSQRT 0 + +#undef XCHAL_HAVE_WINDOWED +#define XCHAL_HAVE_WINDOWED 1 + +#undef XCHAL_HAVE_WIDE_BRANCHES +#define XCHAL_HAVE_WIDE_BRANCHES 0 + +#undef XCHAL_HAVE_PREDICTED_BRANCHES +#define XCHAL_HAVE_PREDICTED_BRANCHES 0 + + +#undef XCHAL_ICACHE_SIZE +#define XCHAL_ICACHE_SIZE 8192 + +#undef XCHAL_DCACHE_SIZE +#define XCHAL_DCACHE_SIZE 8192 + +#undef XCHAL_ICACHE_LINESIZE +#define XCHAL_ICACHE_LINESIZE 16 + +#undef XCHAL_DCACHE_LINESIZE +#define XCHAL_DCACHE_LINESIZE 16 + +#undef XCHAL_ICACHE_LINEWIDTH +#define XCHAL_ICACHE_LINEWIDTH 4 + +#undef XCHAL_DCACHE_LINEWIDTH +#define XCHAL_DCACHE_LINEWIDTH 4 + +#undef XCHAL_DCACHE_IS_WRITEBACK +#define XCHAL_DCACHE_IS_WRITEBACK 0 + + +#undef XCHAL_HAVE_MMU +#define XCHAL_HAVE_MMU 1 + +#undef XCHAL_MMU_MIN_PTE_PAGE_SIZE +#define XCHAL_MMU_MIN_PTE_PAGE_SIZE 12 + + +#undef XCHAL_HAVE_DEBUG +#define XCHAL_HAVE_DEBUG 1 + +#undef XCHAL_NUM_IBREAK +#define XCHAL_NUM_IBREAK 2 + +#undef XCHAL_NUM_DBREAK +#define XCHAL_NUM_DBREAK 2 + +#undef XCHAL_DEBUGLEVEL +#define XCHAL_DEBUGLEVEL 4 + + +#undef XCHAL_INST_FETCH_WIDTH +#define XCHAL_INST_FETCH_WIDTH 4 + + +#undef XSHAL_ABI +#undef XTHAL_ABI_WINDOWED +#undef XTHAL_ABI_CALL0 +#define XSHAL_ABI XTHAL_ABI_WINDOWED +#define XTHAL_ABI_WINDOWED 0 +#define XTHAL_ABI_CALL0 1 + +#endif /* !XTENSA_CONFIG_H */ diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h index e205be7..ac1d032 100644 --- a/libcpp/include/cpplib.h +++ b/libcpp/include/cpplib.h @@ -111,6 +111,7 @@ struct _cpp_file; OP(PLUS_PLUS, "++") /* increment */ \ OP(MINUS_MINUS, "--") \ OP(DEREF, "->") /* accessors */ \ + OP(FERED, "<-") /* wiring */ \ OP(DOT, ".") \ OP(SCOPE, "::") \ OP(DEREF_STAR, "->*") \ diff --git a/libiberty/_doprnt.c b/libiberty/_doprnt.c new file mode 100644 index 0000000..ca97bc8 --- /dev/null +++ b/libiberty/_doprnt.c @@ -0,0 +1,296 @@ +/* Provide a version of _doprnt in terms of fprintf. + Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + Contributed by Kaveh Ghazi (ghazi@caip.rutgers.edu) 3/29/98 + +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, 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, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "config.h" +#include "ansidecl.h" +#include "safe-ctype.h" + +#include +#include +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif + +#undef _doprnt + +#ifdef HAVE__DOPRNT +#define TEST +#endif + +#ifdef TEST /* Make sure to use the internal one. */ +#define _doprnt my_doprnt +#endif + +#define COPY_VA_INT \ + do { \ + const int value = abs (va_arg (ap, int)); \ + char buf[32]; \ + ptr++; /* Go past the asterisk. */ \ + *sptr = '\0'; /* NULL terminate sptr. */ \ + sprintf(buf, "%d", value); \ + strcat(sptr, buf); \ + while (*sptr) sptr++; \ + } while (0) + +#define PRINT_CHAR(CHAR) \ + do { \ + putc(CHAR, stream); \ + ptr++; \ + total_printed++; \ + continue; \ + } while (0) + +#define PRINT_TYPE(TYPE) \ + do { \ + int result; \ + TYPE value = va_arg (ap, TYPE); \ + *sptr++ = *ptr++; /* Copy the type specifier. */ \ + *sptr = '\0'; /* NULL terminate sptr. */ \ + result = fprintf(stream, specifier, value); \ + if (result == -1) \ + return -1; \ + else \ + { \ + total_printed += result; \ + continue; \ + } \ + } while (0) + +int +_doprnt (const char *format, va_list ap, FILE *stream) +{ + const char * ptr = format; + char specifier[128]; + int total_printed = 0; + + while (*ptr != '\0') + { + if (*ptr != '%') /* While we have regular characters, print them. */ + PRINT_CHAR(*ptr); + else /* We got a format specifier! */ + { + char * sptr = specifier; + int wide_width = 0, short_width = 0; + + *sptr++ = *ptr++; /* Copy the % and move forward. */ + + while (strchr ("-+ #0", *ptr)) /* Move past flags. */ + *sptr++ = *ptr++; + + if (*ptr == '*') + COPY_VA_INT; + else + while (ISDIGIT(*ptr)) /* Handle explicit numeric value. */ + *sptr++ = *ptr++; + + if (*ptr == '.') + { + *sptr++ = *ptr++; /* Copy and go past the period. */ + if (*ptr == '*') + COPY_VA_INT; + else + while (ISDIGIT(*ptr)) /* Handle explicit numeric value. */ + *sptr++ = *ptr++; + } + while (strchr ("hlL", *ptr)) + { + switch (*ptr) + { + case 'h': + short_width = 1; + break; + case 'l': + wide_width++; + break; + case 'L': + wide_width = 2; + break; + default: + abort(); + } + *sptr++ = *ptr++; + } + + switch (*ptr) + { + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + case 'c': + { + /* Short values are promoted to int, so just copy it + as an int and trust the C library printf to cast it + to the right width. */ + if (short_width) + PRINT_TYPE(int); + else + { + switch (wide_width) + { + case 0: + PRINT_TYPE(int); + break; + case 1: + PRINT_TYPE(long); + break; + case 2: + default: +#if defined(__GNUC__) || defined(HAVE_LONG_LONG) + PRINT_TYPE(long long); +#else + PRINT_TYPE(long); /* Fake it and hope for the best. */ +#endif + break; + } /* End of switch (wide_width) */ + } /* End of else statement */ + } /* End of integer case */ + break; + case 'f': + case 'e': + case 'E': + case 'g': + case 'G': + { + if (wide_width == 0) + PRINT_TYPE(double); + else + { +#if defined(__GNUC__) || defined(HAVE_LONG_DOUBLE) + PRINT_TYPE(long double); +#else + PRINT_TYPE(double); /* Fake it and hope for the best. */ +#endif + } + } + break; + case 's': + PRINT_TYPE(char *); + break; + case 'p': + PRINT_TYPE(void *); + break; + case '%': + PRINT_CHAR('%'); + break; + default: + abort(); + } /* End of switch (*ptr) */ + } /* End of else statement */ + } + + return total_printed; +} + +#ifdef TEST + +#include +#ifndef M_PI +#define M_PI (3.1415926535897932385) +#endif + +#define RESULT(x) do \ +{ \ + int i = (x); \ + printf ("printed %d characters\n", i); \ + fflush(stdin); \ +} while (0) + +static int checkit (const char * format, ...) ATTRIBUTE_PRINTF_1; + +static int +checkit (const char* format, ...) +{ + int result; + VA_OPEN (args, format); + VA_FIXEDARG (args, char *, format); + + result = _doprnt (format, args, stdout); + VA_CLOSE (args); + + return result; +} + +int +main (void) +{ + RESULT(checkit ("<%d>\n", 0x12345678)); + RESULT(printf ("<%d>\n", 0x12345678)); + + RESULT(checkit ("<%200d>\n", 5)); + RESULT(printf ("<%200d>\n", 5)); + + RESULT(checkit ("<%.300d>\n", 6)); + RESULT(printf ("<%.300d>\n", 6)); + + RESULT(checkit ("<%100.150d>\n", 7)); + RESULT(printf ("<%100.150d>\n", 7)); + + RESULT(checkit ("<%s>\n", + "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\ +777777777777777777333333333333366666666666622222222222777777777777733333")); + RESULT(printf ("<%s>\n", + "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\ +777777777777777777333333333333366666666666622222222222777777777777733333")); + + RESULT(checkit ("<%f><%0+#f>%s%d%s>\n", + 1.0, 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx")); + RESULT(printf ("<%f><%0+#f>%s%d%s>\n", + 1.0, 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx")); + + RESULT(checkit ("<%4f><%.4f><%%><%4.4f>\n", M_PI, M_PI, M_PI)); + RESULT(printf ("<%4f><%.4f><%%><%4.4f>\n", M_PI, M_PI, M_PI)); + + RESULT(checkit ("<%*f><%.*f><%%><%*.*f>\n", 3, M_PI, 3, M_PI, 3, 3, M_PI)); + RESULT(printf ("<%*f><%.*f><%%><%*.*f>\n", 3, M_PI, 3, M_PI, 3, 3, M_PI)); + + RESULT(checkit ("<%d><%i><%o><%u><%x><%X><%c>\n", + 75, 75, 75, 75, 75, 75, 75)); + RESULT(printf ("<%d><%i><%o><%u><%x><%X><%c>\n", + 75, 75, 75, 75, 75, 75, 75)); + + RESULT(checkit ("<%d><%i><%o><%u><%x><%X><%c>\n", + 75, 75, 75, 75, 75, 75, 75)); + RESULT(printf ("<%d><%i><%o><%u><%x><%X><%c>\n", + 75, 75, 75, 75, 75, 75, 75)); + + RESULT(checkit ("Testing (hd) short: <%d><%ld><%hd><%hd><%d>\n", 123, (long)234, 345, 123456789, 456)); + RESULT(printf ("Testing (hd) short: <%d><%ld><%hd><%hd><%d>\n", 123, (long)234, 345, 123456789, 456)); + +#if defined(__GNUC__) || defined (HAVE_LONG_LONG) + RESULT(checkit ("Testing (lld) long long: <%d><%lld><%d>\n", 123, 234234234234234234LL, 345)); + RESULT(printf ("Testing (lld) long long: <%d><%lld><%d>\n", 123, 234234234234234234LL, 345)); + RESULT(checkit ("Testing (Ld) long long: <%d><%Ld><%d>\n", 123, 234234234234234234LL, 345)); + RESULT(printf ("Testing (Ld) long long: <%d><%Ld><%d>\n", 123, 234234234234234234LL, 345)); +#endif + +#if defined(__GNUC__) || defined (HAVE_LONG_DOUBLE) + RESULT(checkit ("Testing (Lf) long double: <%.20f><%.20Lf><%0+#.20f>\n", + 1.23456, 1.234567890123456789L, 1.23456)); + RESULT(printf ("Testing (Lf) long double: <%.20f><%.20Lf><%0+#.20f>\n", + 1.23456, 1.234567890123456789L, 1.23456)); +#endif + + return 0; +} +#endif /* TEST */ diff --git a/libiberty/alloca.c b/libiberty/alloca.c new file mode 100644 index 0000000..9b2e9cb --- /dev/null +++ b/libiberty/alloca.c @@ -0,0 +1,483 @@ +/* alloca.c -- allocate automatically reclaimed memory + (Mostly) portable public-domain implementation -- D A Gwyn + + This implementation of the PWB library alloca function, + which is used to allocate space off the run-time stack so + that it is automatically reclaimed upon procedure exit, + was inspired by discussions with J. Q. Johnson of Cornell. + J.Otto Tennant contributed the Cray support. + + There are some preprocessor constants that can + be defined when compiling for your specific system, for + improved efficiency; however, the defaults should be okay. + + The general concept of this implementation is to keep + track of all alloca-allocated blocks, and reclaim any + that are found to be deeper in the stack than the current + invocation. This heuristic does not reclaim storage as + soon as it becomes invalid, but it will do so eventually. + + As a special case, alloca(0) reclaims storage without + allocating any. It is a good idea to use alloca(0) in + your main control loop, etc. to force garbage collection. */ + +/* + +@deftypefn Replacement void* alloca (size_t @var{size}) + +This function allocates memory which will be automatically reclaimed +after the procedure exits. The @libib{} implementation does not free +the memory immediately but will do so eventually during subsequent +calls to this function. Memory is allocated using @code{xmalloc} under +normal circumstances. + +The header file @file{alloca-conf.h} can be used in conjunction with the +GNU Autoconf test @code{AC_FUNC_ALLOCA} to test for and properly make +available this function. The @code{AC_FUNC_ALLOCA} test requires that +client code use a block of preprocessor code to be safe (see the Autoconf +manual for more); this header incorporates that logic and more, including +the possibility of a GCC built-in function. + +@end deftypefn + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif + +/* These variables are used by the ASTRDUP implementation that relies + on C_alloca. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +const char *libiberty_optr; +char *libiberty_nptr; +unsigned long libiberty_len; +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +/* If your stack is a linked list of frames, you have to + provide an "address metric" ADDRESS_FUNCTION macro. */ + +#if defined (CRAY) && defined (CRAY_STACKSEG_END) +static long i00afunc (); +#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg)) +#else +#define ADDRESS_FUNCTION(arg) &(arg) +#endif + +#ifndef NULL +#define NULL 0 +#endif + +/* Define STACK_DIRECTION if you know the direction of stack + growth for your system; otherwise it will be automatically + deduced at run-time. + + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ + +#ifndef STACK_DIRECTION +#define STACK_DIRECTION 0 /* Direction unknown. */ +#endif + +#if STACK_DIRECTION != 0 + +#define STACK_DIR STACK_DIRECTION /* Known at compile-time. */ + +#else /* STACK_DIRECTION == 0; need run-time code. */ + +static int stack_dir; /* 1 or -1 once known. */ +#define STACK_DIR stack_dir + +static void +find_stack_direction (void) +{ + static char *addr = NULL; /* Address of first `dummy', once known. */ + auto char dummy; /* To get stack address. */ + + if (addr == NULL) + { /* Initial entry. */ + addr = ADDRESS_FUNCTION (dummy); + + find_stack_direction (); /* Recurse once. */ + } + else + { + /* Second entry. */ + if (ADDRESS_FUNCTION (dummy) > addr) + stack_dir = 1; /* Stack grew upward. */ + else + stack_dir = -1; /* Stack grew downward. */ + } +} + +#endif /* STACK_DIRECTION == 0 */ + +/* An "alloca header" is used to: + (a) chain together all alloca'ed blocks; + (b) keep track of stack depth. + + It is very important that sizeof(header) agree with malloc + alignment chunk size. The following default should work okay. */ + +#ifndef ALIGN_SIZE +#define ALIGN_SIZE sizeof(double) +#endif + +typedef union hdr +{ + char align[ALIGN_SIZE]; /* To force sizeof(header). */ + struct + { + union hdr *next; /* For chaining headers. */ + char *deep; /* For stack depth measure. */ + } h; +} header; + +static header *last_alloca_header = NULL; /* -> last alloca header. */ + +/* Return a pointer to at least SIZE bytes of storage, + which will be automatically reclaimed upon exit from + the procedure that called alloca. Originally, this space + was supposed to be taken from the current stack frame of the + caller, but that method cannot be made to work for some + implementations of C, for example under Gould's UTX/32. */ + +/* @undocumented C_alloca */ + +PTR +C_alloca (size_t size) +{ + auto char probe; /* Probes stack depth: */ + register char *depth = ADDRESS_FUNCTION (probe); + +#if STACK_DIRECTION == 0 + if (STACK_DIR == 0) /* Unknown growth direction. */ + find_stack_direction (); +#endif + + /* Reclaim garbage, defined as all alloca'd storage that + was allocated from deeper in the stack than currently. */ + + { + register header *hp; /* Traverses linked list. */ + + for (hp = last_alloca_header; hp != NULL;) + if ((STACK_DIR > 0 && hp->h.deep > depth) + || (STACK_DIR < 0 && hp->h.deep < depth)) + { + register header *np = hp->h.next; + + free ((PTR) hp); /* Collect garbage. */ + + hp = np; /* -> next header. */ + } + else + break; /* Rest are not deeper. */ + + last_alloca_header = hp; /* -> last valid storage. */ + } + + if (size == 0) + return NULL; /* No allocation required. */ + + /* Allocate combined header + user data storage. */ + + { + register void *new_storage = XNEWVEC (char, sizeof (header) + size); + /* Address of header. */ + + if (new_storage == 0) + abort(); + + ((header *) new_storage)->h.next = last_alloca_header; + ((header *) new_storage)->h.deep = depth; + + last_alloca_header = (header *) new_storage; + + /* User storage begins just after header. */ + + return (PTR) ((char *) new_storage + sizeof (header)); + } +} + +#if defined (CRAY) && defined (CRAY_STACKSEG_END) + +#ifdef DEBUG_I00AFUNC +#include +#endif + +#ifndef CRAY_STACK +#define CRAY_STACK +#ifndef CRAY2 +/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */ +struct stack_control_header + { + long shgrow:32; /* Number of times stack has grown. */ + long shaseg:32; /* Size of increments to stack. */ + long shhwm:32; /* High water mark of stack. */ + long shsize:32; /* Current size of stack (all segments). */ + }; + +/* The stack segment linkage control information occurs at + the high-address end of a stack segment. (The stack + grows from low addresses to high addresses.) The initial + part of the stack segment linkage control information is + 0200 (octal) words. This provides for register storage + for the routine which overflows the stack. */ + +struct stack_segment_linkage + { + long ss[0200]; /* 0200 overflow words. */ + long sssize:32; /* Number of words in this segment. */ + long ssbase:32; /* Offset to stack base. */ + long:32; + long sspseg:32; /* Offset to linkage control of previous + segment of stack. */ + long:32; + long sstcpt:32; /* Pointer to task common address block. */ + long sscsnm; /* Private control structure number for + microtasking. */ + long ssusr1; /* Reserved for user. */ + long ssusr2; /* Reserved for user. */ + long sstpid; /* Process ID for pid based multi-tasking. */ + long ssgvup; /* Pointer to multitasking thread giveup. */ + long sscray[7]; /* Reserved for Cray Research. */ + long ssa0; + long ssa1; + long ssa2; + long ssa3; + long ssa4; + long ssa5; + long ssa6; + long ssa7; + long sss0; + long sss1; + long sss2; + long sss3; + long sss4; + long sss5; + long sss6; + long sss7; + }; + +#else /* CRAY2 */ +/* The following structure defines the vector of words + returned by the STKSTAT library routine. */ +struct stk_stat + { + long now; /* Current total stack size. */ + long maxc; /* Amount of contiguous space which would + be required to satisfy the maximum + stack demand to date. */ + long high_water; /* Stack high-water mark. */ + long overflows; /* Number of stack overflow ($STKOFEN) calls. */ + long hits; /* Number of internal buffer hits. */ + long extends; /* Number of block extensions. */ + long stko_mallocs; /* Block allocations by $STKOFEN. */ + long underflows; /* Number of stack underflow calls ($STKRETN). */ + long stko_free; /* Number of deallocations by $STKRETN. */ + long stkm_free; /* Number of deallocations by $STKMRET. */ + long segments; /* Current number of stack segments. */ + long maxs; /* Maximum number of stack segments so far. */ + long pad_size; /* Stack pad size. */ + long current_address; /* Current stack segment address. */ + long current_size; /* Current stack segment size. This + number is actually corrupted by STKSTAT to + include the fifteen word trailer area. */ + long initial_address; /* Address of initial segment. */ + long initial_size; /* Size of initial segment. */ + }; + +/* The following structure describes the data structure which trails + any stack segment. I think that the description in 'asdef' is + out of date. I only describe the parts that I am sure about. */ + +struct stk_trailer + { + long this_address; /* Address of this block. */ + long this_size; /* Size of this block (does not include + this trailer). */ + long unknown2; + long unknown3; + long link; /* Address of trailer block of previous + segment. */ + long unknown5; + long unknown6; + long unknown7; + long unknown8; + long unknown9; + long unknown10; + long unknown11; + long unknown12; + long unknown13; + long unknown14; + }; + +#endif /* CRAY2 */ +#endif /* not CRAY_STACK */ + +#ifdef CRAY2 +/* Determine a "stack measure" for an arbitrary ADDRESS. + I doubt that "lint" will like this much. */ + +static long +i00afunc (long *address) +{ + struct stk_stat status; + struct stk_trailer *trailer; + long *block, size; + long result = 0; + + /* We want to iterate through all of the segments. The first + step is to get the stack status structure. We could do this + more quickly and more directly, perhaps, by referencing the + $LM00 common block, but I know that this works. */ + + STKSTAT (&status); + + /* Set up the iteration. */ + + trailer = (struct stk_trailer *) (status.current_address + + status.current_size + - 15); + + /* There must be at least one stack segment. Therefore it is + a fatal error if "trailer" is null. */ + + if (trailer == 0) + abort (); + + /* Discard segments that do not contain our argument address. */ + + while (trailer != 0) + { + block = (long *) trailer->this_address; + size = trailer->this_size; + if (block == 0 || size == 0) + abort (); + trailer = (struct stk_trailer *) trailer->link; + if ((block <= address) && (address < (block + size))) + break; + } + + /* Set the result to the offset in this segment and add the sizes + of all predecessor segments. */ + + result = address - block; + + if (trailer == 0) + { + return result; + } + + do + { + if (trailer->this_size <= 0) + abort (); + result += trailer->this_size; + trailer = (struct stk_trailer *) trailer->link; + } + while (trailer != 0); + + /* We are done. Note that if you present a bogus address (one + not in any segment), you will get a different number back, formed + from subtracting the address of the first block. This is probably + not what you want. */ + + return (result); +} + +#else /* not CRAY2 */ +/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP. + Determine the number of the cell within the stack, + given the address of the cell. The purpose of this + routine is to linearize, in some sense, stack addresses + for alloca. */ + +static long +i00afunc (long address) +{ + long stkl = 0; + + long size, pseg, this_segment, stack; + long result = 0; + + struct stack_segment_linkage *ssptr; + + /* Register B67 contains the address of the end of the + current stack segment. If you (as a subprogram) store + your registers on the stack and find that you are past + the contents of B67, you have overflowed the segment. + + B67 also points to the stack segment linkage control + area, which is what we are really interested in. */ + + stkl = CRAY_STACKSEG_END (); + ssptr = (struct stack_segment_linkage *) stkl; + + /* If one subtracts 'size' from the end of the segment, + one has the address of the first word of the segment. + + If this is not the first segment, 'pseg' will be + nonzero. */ + + pseg = ssptr->sspseg; + size = ssptr->sssize; + + this_segment = stkl - size; + + /* It is possible that calling this routine itself caused + a stack overflow. Discard stack segments which do not + contain the target address. */ + + while (!(this_segment <= address && address <= stkl)) + { +#ifdef DEBUG_I00AFUNC + fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl); +#endif + if (pseg == 0) + break; + stkl = stkl - pseg; + ssptr = (struct stack_segment_linkage *) stkl; + size = ssptr->sssize; + pseg = ssptr->sspseg; + this_segment = stkl - size; + } + + result = address - this_segment; + + /* If you subtract pseg from the current end of the stack, + you get the address of the previous stack segment's end. + This seems a little convoluted to me, but I'll bet you save + a cycle somewhere. */ + + while (pseg != 0) + { +#ifdef DEBUG_I00AFUNC + fprintf (stderr, "%011o %011o\n", pseg, size); +#endif + stkl = stkl - pseg; + ssptr = (struct stack_segment_linkage *) stkl; + size = ssptr->sssize; + pseg = ssptr->sspseg; + result += size; + } + return (result); +} + +#endif /* not CRAY2 */ +#endif /* CRAY */ diff --git a/libiberty/argv.c b/libiberty/argv.c new file mode 100644 index 0000000..38bd449 --- /dev/null +++ b/libiberty/argv.c @@ -0,0 +1,513 @@ +/* Create and destroy argument vectors (argv's) + Copyright (C) 1992, 2001 Free Software Foundation, Inc. + Written by Fred Fish @ Cygnus Support + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + + +/* Create and destroy argument vectors. An argument vector is simply an + array of string pointers, terminated by a NULL pointer. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "ansidecl.h" +#include "libiberty.h" +#include "safe-ctype.h" + +/* Routines imported from standard C runtime libraries. */ + +#include +#include +#include +#include + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef EOS +#define EOS '\0' +#endif + +#define INITIAL_MAXARGC 8 /* Number of args + NULL in initial argv */ + + +/* + +@deftypefn Extension char** dupargv (char **@var{vector}) + +Duplicate an argument vector. Simply scans through @var{vector}, +duplicating each argument until the terminating @code{NULL} is found. +Returns a pointer to the argument vector if successful. Returns +@code{NULL} if there is insufficient memory to complete building the +argument vector. + +@end deftypefn + +*/ + +char ** +dupargv (char **argv) +{ + int argc; + char **copy; + + if (argv == NULL) + return NULL; + + /* the vector */ + for (argc = 0; argv[argc] != NULL; argc++); + copy = (char **) malloc ((argc + 1) * sizeof (char *)); + if (copy == NULL) + return NULL; + + /* the strings */ + for (argc = 0; argv[argc] != NULL; argc++) + { + int len = strlen (argv[argc]); + copy[argc] = (char *) malloc (len + 1); + if (copy[argc] == NULL) + { + freeargv (copy); + return NULL; + } + strcpy (copy[argc], argv[argc]); + } + copy[argc] = NULL; + return copy; +} + +/* + +@deftypefn Extension void freeargv (char **@var{vector}) + +Free an argument vector that was built using @code{buildargv}. Simply +scans through @var{vector}, freeing the memory for each argument until +the terminating @code{NULL} is found, and then frees @var{vector} +itself. + +@end deftypefn + +*/ + +void freeargv (char **vector) +{ + register char **scan; + + if (vector != NULL) + { + for (scan = vector; *scan != NULL; scan++) + { + free (*scan); + } + free (vector); + } +} + +/* + +@deftypefn Extension char** buildargv (char *@var{sp}) + +Given a pointer to a string, parse the string extracting fields +separated by whitespace and optionally enclosed within either single +or double quotes (which are stripped off), and build a vector of +pointers to copies of the string for each field. The input string +remains unchanged. The last element of the vector is followed by a +@code{NULL} element. + +All of the memory for the pointer array and copies of the string +is obtained from @code{malloc}. All of the memory can be returned to the +system with the single function call @code{freeargv}, which takes the +returned result of @code{buildargv}, as it's argument. + +Returns a pointer to the argument vector if successful. Returns +@code{NULL} if @var{sp} is @code{NULL} or if there is insufficient +memory to complete building the argument vector. + +If the input is a null string (as opposed to a @code{NULL} pointer), +then buildarg returns an argument vector that has one arg, a null +string. + +@end deftypefn + +The memory for the argv array is dynamically expanded as necessary. + +In order to provide a working buffer for extracting arguments into, +with appropriate stripping of quotes and translation of backslash +sequences, we allocate a working buffer at least as long as the input +string. This ensures that we always have enough space in which to +work, since the extracted arg is never larger than the input string. + +The argument vector is always kept terminated with a @code{NULL} arg +pointer, so it can be passed to @code{freeargv} at any time, or +returned, as appropriate. + +*/ + +char **buildargv (const char *input) +{ + char *arg; + char *copybuf; + int squote = 0; + int dquote = 0; + int bsquote = 0; + int argc = 0; + int maxargc = 0; + char **argv = NULL; + char **nargv; + + if (input != NULL) + { + copybuf = (char *) alloca (strlen (input) + 1); + /* Is a do{}while to always execute the loop once. Always return an + argv, even for null strings. See NOTES above, test case below. */ + do + { + /* Pick off argv[argc] */ + while (ISBLANK (*input)) + { + input++; + } + if ((maxargc == 0) || (argc >= (maxargc - 1))) + { + /* argv needs initialization, or expansion */ + if (argv == NULL) + { + maxargc = INITIAL_MAXARGC; + nargv = (char **) malloc (maxargc * sizeof (char *)); + } + else + { + maxargc *= 2; + nargv = (char **) realloc (argv, maxargc * sizeof (char *)); + } + if (nargv == NULL) + { + if (argv != NULL) + { + freeargv (argv); + argv = NULL; + } + break; + } + argv = nargv; + argv[argc] = NULL; + } + /* Begin scanning arg */ + arg = copybuf; + while (*input != EOS) + { + if (ISSPACE (*input) && !squote && !dquote && !bsquote) + { + break; + } + else + { + if (bsquote) + { + bsquote = 0; + *arg++ = *input; + } + else if (*input == '\\') + { + bsquote = 1; + } + else if (squote) + { + if (*input == '\'') + { + squote = 0; + } + else + { + *arg++ = *input; + } + } + else if (dquote) + { + if (*input == '"') + { + dquote = 0; + } + else + { + *arg++ = *input; + } + } + else + { + if (*input == '\'') + { + squote = 1; + } + else if (*input == '"') + { + dquote = 1; + } + else + { + *arg++ = *input; + } + } + input++; + } + } + *arg = EOS; + argv[argc] = strdup (copybuf); + if (argv[argc] == NULL) + { + freeargv (argv); + argv = NULL; + break; + } + argc++; + argv[argc] = NULL; + + while (ISSPACE (*input)) + { + input++; + } + } + while (*input != EOS); + } + return (argv); +} + +/* + +@deftypefn Extension int writeargv (const char **@var{argv}, FILE *@var{file}) + +Write each member of ARGV, handling all necessary quoting, to the file +named by FILE, separated by whitespace. Return 0 on success, non-zero +if an error occurred while writing to FILE. + +@end deftypefn + +*/ + +int +writeargv (char **argv, FILE *f) +{ + int status = 0; + + if (f == NULL) + return 1; + + while (*argv != NULL) + { + const char *arg = *argv; + + while (*arg != EOS) + { + char c = *arg; + + if (ISSPACE(c) || c == '\\' || c == '\'' || c == '"') + if (EOF == fputc ('\\', f)) + { + status = 1; + goto done; + } + + if (EOF == fputc (c, f)) + { + status = 1; + goto done; + } + arg++; + } + + if (EOF == fputc ('\n', f)) + { + status = 1; + goto done; + } + argv++; + } + + done: + return status; +} + +/* + +@deftypefn Extension void expandargv (int *@var{argcp}, char ***@var{argvp}) + +The @var{argcp} and @code{argvp} arguments are pointers to the usual +@code{argc} and @code{argv} arguments to @code{main}. This function +looks for arguments that begin with the character @samp{@@}. Any such +arguments are interpreted as ``response files''. The contents of the +response file are interpreted as additional command line options. In +particular, the file is separated into whitespace-separated strings; +each such string is taken as a command-line option. The new options +are inserted in place of the option naming the response file, and +@code{*argcp} and @code{*argvp} will be updated. If the value of +@code{*argvp} is modified by this function, then the new value has +been dynamically allocated and can be deallocated by the caller with +@code{freeargv}. However, most callers will simply call +@code{expandargv} near the beginning of @code{main} and allow the +operating system to free the memory when the program exits. + +@end deftypefn + +*/ + +void +expandargv (int *argcp, char ***argvp) +{ + /* The argument we are currently processing. */ + int i = 0; + /* Non-zero if ***argvp has been dynamically allocated. */ + int argv_dynamic = 0; + /* Loop over the arguments, handling response files. We always skip + ARGVP[0], as that is the name of the program being run. */ + while (++i < *argcp) + { + /* The name of the response file. */ + const char *filename; + /* The response file. */ + FILE *f; + /* An upper bound on the number of characters in the response + file. */ + long pos; + /* The number of characters in the response file, when actually + read. */ + size_t len; + /* A dynamically allocated buffer used to hold options read from a + response file. */ + char *buffer; + /* Dynamically allocated storage for the options read from the + response file. */ + char **file_argv; + /* The number of options read from the response file, if any. */ + size_t file_argc; + /* We are only interested in options of the form "@file". */ + filename = (*argvp)[i]; + if (filename[0] != '@') + continue; + /* Read the contents of the file. */ + f = fopen (++filename, "r"); + if (!f) + continue; + if (fseek (f, 0L, SEEK_END) == -1) + goto error; + pos = ftell (f); + if (pos == -1) + goto error; + if (fseek (f, 0L, SEEK_SET) == -1) + goto error; + buffer = (char *) xmalloc (pos * sizeof (char) + 1); + len = fread (buffer, sizeof (char), pos, f); + if (len != (size_t) pos + /* On Windows, fread may return a value smaller than POS, + due to CR/LF->CR translation when reading text files. + That does not in-and-of itself indicate failure. */ + && ferror (f)) + goto error; + /* Add a NUL terminator. */ + buffer[len] = '\0'; + /* Parse the string. */ + file_argv = buildargv (buffer); + /* If *ARGVP is not already dynamically allocated, copy it. */ + if (!argv_dynamic) + { + *argvp = dupargv (*argvp); + if (!*argvp) + { + fputs ("\nout of memory\n", stderr); + xexit (1); + } + } + /* Count the number of arguments. */ + file_argc = 0; + while (file_argv[file_argc] && *file_argv[file_argc]) + ++file_argc; + /* Now, insert FILE_ARGV into ARGV. The "+1" below handles the + NULL terminator at the end of ARGV. */ + *argvp = ((char **) + xrealloc (*argvp, + (*argcp + file_argc + 1) * sizeof (char *))); + memmove (*argvp + i + file_argc, *argvp + i + 1, + (*argcp - i) * sizeof (char *)); + memcpy (*argvp + i, file_argv, file_argc * sizeof (char *)); + /* The original option has been replaced by all the new + options. */ + *argcp += file_argc - 1; + /* Free up memory allocated to process the response file. We do + not use freeargv because the individual options in FILE_ARGV + are now in the main ARGV. */ + free (file_argv); + free (buffer); + /* Rescan all of the arguments just read to support response + files that include other response files. */ + --i; + error: + /* We're all done with the file now. */ + fclose (f); + } +} + +#ifdef MAIN + +/* Simple little test driver. */ + +static const char *const tests[] = +{ + "a simple command line", + "arg 'foo' is single quoted", + "arg \"bar\" is double quoted", + "arg \"foo bar\" has embedded whitespace", + "arg 'Jack said \\'hi\\'' has single quotes", + "arg 'Jack said \\\"hi\\\"' has double quotes", + "a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9", + + /* This should be expanded into only one argument. */ + "trailing-whitespace ", + + "", + NULL +}; + +int +main (void) +{ + char **argv; + const char *const *test; + char **targs; + + for (test = tests; *test != NULL; test++) + { + printf ("buildargv(\"%s\")\n", *test); + if ((argv = buildargv (*test)) == NULL) + { + printf ("failed!\n\n"); + } + else + { + for (targs = argv; *targs != NULL; targs++) + { + printf ("\t\"%s\"\n", *targs); + } + printf ("\n"); + } + freeargv (argv); + } + + return 0; +} + +#endif /* MAIN */ diff --git a/libiberty/asprintf.c b/libiberty/asprintf.c new file mode 100644 index 0000000..3cf5052 --- /dev/null +++ b/libiberty/asprintf.c @@ -0,0 +1,56 @@ +/* Like sprintf but provides a pointer to malloc'd storage, which must + be freed by the caller. + Copyright (C) 1997, 2003 Free Software Foundation, Inc. + Contributed by Cygnus Solutions. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "ansidecl.h" +#include "libiberty.h" + +#include + +/* + +@deftypefn Extension int asprintf (char **@var{resptr}, const char *@var{format}, ...) + +Like @code{sprintf}, but instead of passing a pointer to a buffer, you +pass a pointer to a pointer. This function will compute the size of +the buffer needed, allocate memory with @code{malloc}, and store a +pointer to the allocated memory in @code{*@var{resptr}}. The value +returned is the same as @code{sprintf} would return. If memory could +not be allocated, minus one is returned and @code{NULL} is stored in +@code{*@var{resptr}}. + +@end deftypefn + +*/ + +int +asprintf (char **buf, const char *fmt, ...) +{ + int status; + VA_OPEN (ap, fmt); + VA_FIXEDARG (ap, char **, buf); + VA_FIXEDARG (ap, const char *, fmt); + status = vasprintf (buf, fmt, ap); + VA_CLOSE (ap); + return status; +} diff --git a/libiberty/atexit.c b/libiberty/atexit.c new file mode 100644 index 0000000..e091f01 --- /dev/null +++ b/libiberty/atexit.c @@ -0,0 +1,27 @@ +/* Wrapper to implement ANSI C's atexit using SunOS's on_exit. */ +/* This function is in the public domain. --Mike Stump. */ + +/* + +@deftypefn Supplemental int atexit (void (*@var{f})()) + +Causes function @var{f} to be called at exit. Returns 0. + +@end deftypefn + +*/ + +#include "config.h" + +#ifdef HAVE_ON_EXIT + +int +atexit(void (*f)(void)) +{ + /* If the system doesn't provide a definition for atexit, use on_exit + if the system provides that. */ + on_exit (f, 0); + return 0; +} + +#endif diff --git a/libiberty/basename.c b/libiberty/basename.c new file mode 100644 index 0000000..0f2c069 --- /dev/null +++ b/libiberty/basename.c @@ -0,0 +1,62 @@ +/* Return the basename of a pathname. + This file is in the public domain. */ + +/* + +@deftypefn Supplemental char* basename (const char *@var{name}) + +Returns a pointer to the last component of pathname @var{name}. +Behavior is undefined if the pathname ends in a directory separator. + +@end deftypefn + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "ansidecl.h" +#include "libiberty.h" +#include "safe-ctype.h" + +#ifndef DIR_SEPARATOR +#define DIR_SEPARATOR '/' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ + defined (__OS2__) +#define HAVE_DOS_BASED_FILE_SYSTEM +#ifndef DIR_SEPARATOR_2 +#define DIR_SEPARATOR_2 '\\' +#endif +#endif + +/* Define IS_DIR_SEPARATOR. */ +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +char * +basename (const char *name) +{ + const char *base; + +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + /* Skip over the disk name in MSDOS pathnames. */ + if (ISALPHA (name[0]) && name[1] == ':') + name += 2; +#endif + + for (base = name; *name; name++) + { + if (IS_DIR_SEPARATOR (*name)) + { + base = name + 1; + } + } + return (char *) base; +} + diff --git a/libiberty/bcmp.c b/libiberty/bcmp.c new file mode 100644 index 0000000..c639f98 --- /dev/null +++ b/libiberty/bcmp.c @@ -0,0 +1,27 @@ +/* bcmp + This function is in the public domain. */ + +/* + +@deftypefn Supplemental int bcmp (char *@var{x}, char *@var{y}, int @var{count}) + +Compares the first @var{count} bytes of two areas of memory. Returns +zero if they are the same, nonzero otherwise. Returns zero if +@var{count} is zero. A nonzero result only indicates a difference, +it does not indicate any sorting order (say, by having a positive +result mean @var{x} sorts before @var{y}). + +@end deftypefn + +*/ + +#include + +extern int memcmp(const void *, const void *, size_t); + +int +bcmp (const void *s1, const void *s2, size_t count) +{ + return memcmp (s1, s2, count); +} + diff --git a/libiberty/bcopy.c b/libiberty/bcopy.c new file mode 100644 index 0000000..f9b7a8a --- /dev/null +++ b/libiberty/bcopy.c @@ -0,0 +1,31 @@ +/* bcopy -- copy memory regions of arbitary length + +@deftypefn Supplemental void bcopy (char *@var{in}, char *@var{out}, int @var{length}) + +Copies @var{length} bytes from memory region @var{in} to region +@var{out}. The use of @code{bcopy} is deprecated in new programs. + +@end deftypefn + +*/ + +#include + +void +bcopy (const void *src, void *dest, size_t len) +{ + if (dest < src) + { + const char *firsts = (const char *) src; + char *firstd = (char *) dest; + while (len--) + *firstd++ = *firsts++; + } + else + { + const char *lasts = (const char *)src + (len-1); + char *lastd = (char *)dest + (len-1); + while (len--) + *lastd-- = *lasts--; + } +} diff --git a/libiberty/bsearch.c b/libiberty/bsearch.c new file mode 100644 index 0000000..771d5de --- /dev/null +++ b/libiberty/bsearch.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 1990 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. [rescinded 22 July 1999] + * 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. + */ + +/* + +@deftypefn Supplemental void* bsearch (const void *@var{key}, const void *@var{base}, size_t @var{nmemb}, size_t @var{size}, int (*@var{compar})(const void *, const void *)) + +Performs a search over an array of @var{nmemb} elements pointed to by +@var{base} for a member that matches the object pointed to by @var{key}. +The size of each member is specified by @var{size}. The array contents +should be sorted in ascending order according to the @var{compar} +comparison function. This routine should take two arguments pointing to +the @var{key} and to an array member, in that order, and should return an +integer less than, equal to, or greater than zero if the @var{key} object +is respectively less than, matching, or greater than the array member. + +@end deftypefn + +*/ + +#include "config.h" +#include "ansidecl.h" +#include /* size_t */ +#include + +/* + * Perform a binary search. + * + * The code below is a bit sneaky. After a comparison fails, we + * divide the work in half by moving either left or right. If lim + * is odd, moving left simply involves halving lim: e.g., when lim + * is 5 we look at item 2, so we change lim to 2 so that we will + * look at items 0 & 1. If lim is even, the same applies. If lim + * is odd, moving right again involes halving lim, this time moving + * the base up one item past p: e.g., when lim is 5 we change base + * to item 3 and make lim 2 so that we will look at items 3 and 4. + * If lim is even, however, we have to shrink it by one before + * halving: e.g., when lim is 4, we still looked at item 2, so we + * have to make lim 3, then halve, obtaining 1, so that we will only + * look at item 3. + */ +void * +bsearch (register const void *key, const void *base0, + size_t nmemb, register size_t size, + register int (*compar)(const void *, const void *)) +{ + register const char *base = (const char *) base0; + register int lim, cmp; + register const void *p; + + for (lim = nmemb; lim != 0; lim >>= 1) { + p = base + (lim >> 1) * size; + cmp = (*compar)(key, p); + if (cmp == 0) + return (void *)p; + if (cmp > 0) { /* key > p: move right */ + base = (const char *)p + size; + lim--; + } /* else move left */ + } + return (NULL); +} diff --git a/libiberty/bzero.c b/libiberty/bzero.c new file mode 100644 index 0000000..44ad73d --- /dev/null +++ b/libiberty/bzero.c @@ -0,0 +1,23 @@ +/* Portable version of bzero for systems without it. + This function is in the public domain. */ + +/* + +@deftypefn Supplemental void bzero (char *@var{mem}, int @var{count}) + +Zeros @var{count} bytes starting at @var{mem}. Use of this function +is deprecated in favor of @code{memset}. + +@end deftypefn + +*/ + +#include + +extern void *memset(void *, int, size_t); + +void +bzero (void *to, size_t count) +{ + memset (to, 0, count); +} diff --git a/libiberty/calloc.c b/libiberty/calloc.c new file mode 100644 index 0000000..f4bd27b --- /dev/null +++ b/libiberty/calloc.c @@ -0,0 +1,34 @@ +/* calloc -- allocate memory which has been initialized to zero. + This function is in the public domain. */ + +/* + +@deftypefn Supplemental void* calloc (size_t @var{nelem}, size_t @var{elsize}) + +Uses @code{malloc} to allocate storage for @var{nelem} objects of +@var{elsize} bytes each, then zeros the memory. + +@end deftypefn + +*/ + +#include "ansidecl.h" +#include + +/* For systems with larger pointers than ints, this must be declared. */ +PTR malloc (size_t); +void bzero (PTR, size_t); + +PTR +calloc (size_t nelem, size_t elsize) +{ + register PTR ptr; + + if (nelem == 0 || elsize == 0) + nelem = elsize = 1; + + ptr = malloc (nelem * elsize); + if (ptr) bzero (ptr, nelem * elsize); + + return ptr; +} diff --git a/libiberty/choose-temp.c b/libiberty/choose-temp.c new file mode 100644 index 0000000..b1c2e5b --- /dev/null +++ b/libiberty/choose-temp.c @@ -0,0 +1,71 @@ +/* Utility to pick a temporary filename prefix. + Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include /* May get P_tmpdir. */ +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif + +#include "libiberty.h" +extern char *choose_tmpdir (void); + +/* Name of temporary file. + mktemp requires 6 trailing X's. */ +#define TEMP_FILE "ccXXXXXX" +#define TEMP_FILE_LEN (sizeof(TEMP_FILE) - 1) + +/* + +@deftypefn Extension char* choose_temp_base (void) + +Return a prefix for temporary file names or @code{NULL} if unable to +find one. The current directory is chosen if all else fails so the +program is exited if a temporary directory can't be found (@code{mktemp} +fails). The buffer for the result is obtained with @code{xmalloc}. + +This function is provided for backwards compatibility only. Its use is +not recommended. + +@end deftypefn + +*/ + +char * +choose_temp_base (void) +{ + const char *base = choose_tmpdir (); + char *temp_filename; + int len; + + len = strlen (base); + temp_filename = XNEWVEC (char, len + TEMP_FILE_LEN + 1); + strcpy (temp_filename, base); + strcpy (temp_filename + len, TEMP_FILE); + + if (mktemp (temp_filename) == 0) + abort (); + return temp_filename; +} diff --git a/libiberty/clock.c b/libiberty/clock.c new file mode 100644 index 0000000..07d902e --- /dev/null +++ b/libiberty/clock.c @@ -0,0 +1,103 @@ +/* ANSI-compatible clock function. + Copyright (C) 1994, 1995, 1999 Free Software Foundation, Inc. + +This file is part of the libiberty library. This library is free +software; you can 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, or (at your option) +any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + +As a special exception, if you link this library with files +compiled with a GNU compiler to produce an executable, this does not cause +the resulting executable to be covered by the GNU General Public License. +This exception does not however invalidate any other reasons why +the executable file might be covered by the GNU General Public License. */ + +/* + +@deftypefn Supplemental long clock (void) + +Returns an approximation of the CPU time used by the process as a +@code{clock_t}; divide this number by @samp{CLOCKS_PER_SEC} to get the +number of seconds used. + +@end deftypefn + +*/ + +#include "config.h" + +#ifdef HAVE_GETRUSAGE +#include +#include +#endif + +#ifdef HAVE_TIMES +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef _SC_CLK_TCK +#define GNU_HZ sysconf(_SC_CLK_TCK) +#else +#ifdef HZ +#define GNU_HZ HZ +#else +#ifdef CLOCKS_PER_SEC +#define GNU_HZ CLOCKS_PER_SEC +#endif +#endif +#endif + +/* FIXME: should be able to declare as clock_t. */ + +long +clock (void) +{ +#ifdef HAVE_GETRUSAGE + struct rusage rusage; + + getrusage (0, &rusage); + return (rusage.ru_utime.tv_sec * 1000000 + rusage.ru_utime.tv_usec + + rusage.ru_stime.tv_sec * 1000000 + rusage.ru_stime.tv_usec); +#else +#ifdef HAVE_TIMES + struct tms tms; + + times (&tms); + return (tms.tms_utime + tms.tms_stime) * (1000000 / GNU_HZ); +#else +#ifdef VMS + struct + { + int proc_user_time; + int proc_system_time; + int child_user_time; + int child_system_time; + } vms_times; + + times (&vms_times); + return (vms_times.proc_user_time + vms_times.proc_system_time) * 10000; +#else + /* A fallback, if nothing else available. */ + return 0; +#endif /* VMS */ +#endif /* HAVE_TIMES */ +#endif /* HAVE_GETRUSAGE */ +} + diff --git a/libiberty/concat.c b/libiberty/concat.c new file mode 100644 index 0000000..1f329ea --- /dev/null +++ b/libiberty/concat.c @@ -0,0 +1,232 @@ +/* Concatenate variable number of strings. + Copyright (C) 1991, 1994, 2001 Free Software Foundation, Inc. + Written by Fred Fish @ Cygnus Support + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + + +/* + +@deftypefn Extension char* concat (const char *@var{s1}, const char *@var{s2}, @dots{}, @code{NULL}) + +Concatenate zero or more of strings and return the result in freshly +@code{xmalloc}ed memory. Returns @code{NULL} if insufficient memory is +available. The argument list is terminated by the first @code{NULL} +pointer encountered. Pointers to empty strings are ignored. + +@end deftypefn + +NOTES + + This function uses xmalloc() which is expected to be a front end + function to malloc() that deals with low memory situations. In + typical use, if malloc() returns NULL then xmalloc() diverts to an + error handler routine which never returns, and thus xmalloc will + never return a NULL pointer. If the client application wishes to + deal with low memory situations itself, it should supply an xmalloc + that just directly invokes malloc and blindly returns whatever + malloc returns. + +*/ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "ansidecl.h" +#include "libiberty.h" +#include /* size_t */ + +#include + +# if HAVE_STRING_H +# include +# else +# if HAVE_STRINGS_H +# include +# endif +# endif + +#if HAVE_STDLIB_H +#include +#endif + +static inline unsigned long vconcat_length (const char *, va_list); +static inline unsigned long +vconcat_length (const char *first, va_list args) +{ + unsigned long length = 0; + const char *arg; + + for (arg = first; arg ; arg = va_arg (args, const char *)) + length += strlen (arg); + + return length; +} + +static inline char * +vconcat_copy (char *dst, const char *first, va_list args) +{ + char *end = dst; + const char *arg; + + for (arg = first; arg ; arg = va_arg (args, const char *)) + { + unsigned long length = strlen (arg); + memcpy (end, arg, length); + end += length; + } + *end = '\000'; + + return dst; +} + +/* @undocumented concat_length */ + +unsigned long +concat_length (const char *first, ...) +{ + unsigned long length; + + VA_OPEN (args, first); + VA_FIXEDARG (args, const char *, first); + length = vconcat_length (first, args); + VA_CLOSE (args); + + return length; +} + +/* @undocumented concat_copy */ + +char * +concat_copy (char *dst, const char *first, ...) +{ + char *save_dst; + + VA_OPEN (args, first); + VA_FIXEDARG (args, char *, dst); + VA_FIXEDARG (args, const char *, first); + vconcat_copy (dst, first, args); + save_dst = dst; /* With K&R C, dst goes out of scope here. */ + VA_CLOSE (args); + + return save_dst; +} + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +char *libiberty_concat_ptr; +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +/* @undocumented concat_copy2 */ + +char * +concat_copy2 (const char *first, ...) +{ + VA_OPEN (args, first); + VA_FIXEDARG (args, const char *, first); + vconcat_copy (libiberty_concat_ptr, first, args); + VA_CLOSE (args); + + return libiberty_concat_ptr; +} + +char * +concat (const char *first, ...) +{ + char *newstr; + + /* First compute the size of the result and get sufficient memory. */ + VA_OPEN (args, first); + VA_FIXEDARG (args, const char *, first); + newstr = XNEWVEC (char, vconcat_length (first, args) + 1); + VA_CLOSE (args); + + /* Now copy the individual pieces to the result string. */ + VA_OPEN (args, first); + VA_FIXEDARG (args, const char *, first); + vconcat_copy (newstr, first, args); + VA_CLOSE (args); + + return newstr; +} + +/* + +@deftypefn Extension char* reconcat (char *@var{optr}, const char *@var{s1}, @dots{}, @code{NULL}) + +Same as @code{concat}, except that if @var{optr} is not @code{NULL} it +is freed after the string is created. This is intended to be useful +when you're extending an existing string or building up a string in a +loop: + +@example + str = reconcat (str, "pre-", str, NULL); +@end example + +@end deftypefn + +*/ + +char * +reconcat (char *optr, const char *first, ...) +{ + char *newstr; + + /* First compute the size of the result and get sufficient memory. */ + VA_OPEN (args, first); + VA_FIXEDARG (args, char *, optr); + VA_FIXEDARG (args, const char *, first); + newstr = XNEWVEC (char, vconcat_length (first, args) + 1); + VA_CLOSE (args); + + /* Now copy the individual pieces to the result string. */ + VA_OPEN (args, first); + VA_FIXEDARG (args, char *, optr); + VA_FIXEDARG (args, const char *, first); + vconcat_copy (newstr, first, args); + if (optr) /* Done before VA_CLOSE so optr stays in scope for K&R C. */ + free (optr); + VA_CLOSE (args); + + return newstr; +} + +#ifdef MAIN +#define NULLP (char *)0 + +/* Simple little test driver. */ + +#include + +int +main (void) +{ + printf ("\"\" = \"%s\"\n", concat (NULLP)); + printf ("\"a\" = \"%s\"\n", concat ("a", NULLP)); + printf ("\"ab\" = \"%s\"\n", concat ("a", "b", NULLP)); + printf ("\"abc\" = \"%s\"\n", concat ("a", "b", "c", NULLP)); + printf ("\"abcd\" = \"%s\"\n", concat ("ab", "cd", NULLP)); + printf ("\"abcde\" = \"%s\"\n", concat ("ab", "c", "de", NULLP)); + printf ("\"abcdef\" = \"%s\"\n", concat ("", "a", "", "bcd", "ef", NULLP)); + return 0; +} + +#endif diff --git a/libiberty/copysign.c b/libiberty/copysign.c new file mode 100644 index 0000000..6793f22 --- /dev/null +++ b/libiberty/copysign.c @@ -0,0 +1,154 @@ +#include + +#ifdef __IEEE_BIG_ENDIAN + +typedef union +{ + double value; + struct + { + unsigned int sign : 1; + unsigned int exponent: 11; + unsigned int fraction0:4; + unsigned int fraction1:16; + unsigned int fraction2:16; + unsigned int fraction3:16; + + } number; + struct + { + unsigned int sign : 1; + unsigned int exponent: 11; + unsigned int quiet:1; + unsigned int function0:3; + unsigned int function1:16; + unsigned int function2:16; + unsigned int function3:16; + } nan; + struct + { + unsigned long msw; + unsigned long lsw; + } parts; + long aslong[2]; +} __ieee_double_shape_type; + +#endif + +#ifdef __IEEE_LITTLE_ENDIAN + +typedef union +{ + double value; + struct + { +#ifdef __SMALL_BITFIELDS + unsigned int fraction3:16; + unsigned int fraction2:16; + unsigned int fraction1:16; + unsigned int fraction0: 4; +#else + unsigned int fraction1:32; + unsigned int fraction0:20; +#endif + unsigned int exponent :11; + unsigned int sign : 1; + } number; + struct + { +#ifdef __SMALL_BITFIELDS + unsigned int function3:16; + unsigned int function2:16; + unsigned int function1:16; + unsigned int function0:3; +#else + unsigned int function1:32; + unsigned int function0:19; +#endif + unsigned int quiet:1; + unsigned int exponent: 11; + unsigned int sign : 1; + } nan; + struct + { + unsigned long lsw; + unsigned long msw; + } parts; + + long aslong[2]; + +} __ieee_double_shape_type; + +#endif + +#ifdef __IEEE_BIG_ENDIAN +typedef union +{ + float value; + struct + { + unsigned int sign : 1; + unsigned int exponent: 8; + unsigned int fraction0: 7; + unsigned int fraction1: 16; + } number; + struct + { + unsigned int sign:1; + unsigned int exponent:8; + unsigned int quiet:1; + unsigned int function0:6; + unsigned int function1:16; + } nan; + long p1; + +} __ieee_float_shape_type; +#endif + +#ifdef __IEEE_LITTLE_ENDIAN +typedef union +{ + float value; + struct + { + unsigned int fraction0: 7; + unsigned int fraction1: 16; + unsigned int exponent: 8; + unsigned int sign : 1; + } number; + struct + { + unsigned int function1:16; + unsigned int function0:6; + unsigned int quiet:1; + unsigned int exponent:8; + unsigned int sign:1; + } nan; + long p1; + +} __ieee_float_shape_type; +#endif + +#if defined(__IEEE_BIG_ENDIAN) || defined(__IEEE_LITTLE_ENDIAN) + +double +copysign (double x, double y) +{ + __ieee_double_shape_type a,b; + b.value = y; + a.value = x; + a.number.sign =b.number.sign; + return a.value; +} + +#else + +double +copysign (double x, double y) +{ + if ((x < 0 && y > 0) || (x > 0 && y < 0)) + return -x; + return x; +} + +#endif diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c new file mode 100644 index 0000000..3fc6a21 --- /dev/null +++ b/libiberty/cp-demangle.c @@ -0,0 +1,4537 @@ +/* Demangler for g++ V3 ABI. + Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. + Written by Ian Lance Taylor . + + This file is part of the libiberty library, which is part of GCC. + + This file is free software; you can 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. + + In addition to the permissions in the GNU General Public License, the + Free Software Foundation gives you unlimited permission to link the + compiled version of this file into combinations with other programs, + and to distribute those combinations without any restriction coming + from the use of this file. (The General Public License restrictions + do apply in other respects; for example, they cover modification of + the file, and distribution when not linked into a combined + executable.) + + 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. +*/ + +/* This code implements a demangler for the g++ V3 ABI. The ABI is + described on this web page: + http://www.codesourcery.com/cxx-abi/abi.html#mangling + + This code was written while looking at the demangler written by + Alex Samuel . + + This code first pulls the mangled name apart into a list of + components, and then walks the list generating the demangled + name. + + This file will normally define the following functions, q.v.: + char *cplus_demangle_v3(const char *mangled, int options) + char *java_demangle_v3(const char *mangled) + int cplus_demangle_v3_callback(const char *mangled, int options, + demangle_callbackref callback) + int java_demangle_v3_callback(const char *mangled, + demangle_callbackref callback) + enum gnu_v3_ctor_kinds is_gnu_v3_mangled_ctor (const char *name) + enum gnu_v3_dtor_kinds is_gnu_v3_mangled_dtor (const char *name) + + Also, the interface to the component list is public, and defined in + demangle.h. The interface consists of these types, which are + defined in demangle.h: + enum demangle_component_type + struct demangle_component + demangle_callbackref + and these functions defined in this file: + cplus_demangle_fill_name + cplus_demangle_fill_extended_operator + cplus_demangle_fill_ctor + cplus_demangle_fill_dtor + cplus_demangle_print + cplus_demangle_print_callback + and other functions defined in the file cp-demint.c. + + This file also defines some other functions and variables which are + only to be used by the file cp-demint.c. + + Preprocessor macros you can define while compiling this file: + + IN_LIBGCC2 + If defined, this file defines the following functions, q.v.: + char *__cxa_demangle (const char *mangled, char *buf, size_t *len, + int *status) + int __gcclibcxx_demangle_callback (const char *, + void (*) + (const char *, size_t, void *), + void *) + instead of cplus_demangle_v3[_callback]() and + java_demangle_v3[_callback](). + + IN_GLIBCPP_V3 + If defined, this file defines only __cxa_demangle() and + __gcclibcxx_demangle_callback(), and no other publically visible + functions or variables. + + STANDALONE_DEMANGLER + If defined, this file defines a main() function which demangles + any arguments, or, if none, demangles stdin. + + CP_DEMANGLE_DEBUG + If defined, turns on debugging mode, which prints information on + stdout about the mangled string. This is not generally useful. +*/ + +#if defined (_AIX) && !defined (__GNUC__) + #pragma alloca +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif + +#ifdef HAVE_ALLOCA_H +# include +#else +# ifndef alloca +# ifdef __GNUC__ +# define alloca __builtin_alloca +# else +extern char *alloca (); +# endif /* __GNUC__ */ +# endif /* alloca */ +#endif /* HAVE_ALLOCA_H */ + +#include "ansidecl.h" +#include "libiberty.h" +#include "demangle.h" +#include "cp-demangle.h" + +/* If IN_GLIBCPP_V3 is defined, some functions are made static. We + also rename them via #define to avoid compiler errors when the + static definition conflicts with the extern declaration in a header + file. */ +#ifdef IN_GLIBCPP_V3 + +#define CP_STATIC_IF_GLIBCPP_V3 static + +#define cplus_demangle_fill_name d_fill_name +static int d_fill_name (struct demangle_component *, const char *, int); + +#define cplus_demangle_fill_extended_operator d_fill_extended_operator +static int +d_fill_extended_operator (struct demangle_component *, int, + struct demangle_component *); + +#define cplus_demangle_fill_ctor d_fill_ctor +static int +d_fill_ctor (struct demangle_component *, enum gnu_v3_ctor_kinds, + struct demangle_component *); + +#define cplus_demangle_fill_dtor d_fill_dtor +static int +d_fill_dtor (struct demangle_component *, enum gnu_v3_dtor_kinds, + struct demangle_component *); + +#define cplus_demangle_mangled_name d_mangled_name +static struct demangle_component *d_mangled_name (struct d_info *, int); + +#define cplus_demangle_type d_type +static struct demangle_component *d_type (struct d_info *); + +#define cplus_demangle_print d_print +static char *d_print (int, const struct demangle_component *, int, size_t *); + +#define cplus_demangle_print_callback d_print_callback +static int d_print_callback (int, const struct demangle_component *, + demangle_callbackref, void *); + +#define cplus_demangle_init_info d_init_info +static void d_init_info (const char *, int, size_t, struct d_info *); + +#else /* ! defined(IN_GLIBCPP_V3) */ +#define CP_STATIC_IF_GLIBCPP_V3 +#endif /* ! defined(IN_GLIBCPP_V3) */ + +/* See if the compiler supports dynamic arrays. */ + +#ifdef __GNUC__ +#define CP_DYNAMIC_ARRAYS +#else +#ifdef __STDC__ +#ifdef __STDC_VERSION__ +#if __STDC_VERSION__ >= 199901L +#define CP_DYNAMIC_ARRAYS +#endif /* __STDC__VERSION >= 199901L */ +#endif /* defined (__STDC_VERSION__) */ +#endif /* defined (__STDC__) */ +#endif /* ! defined (__GNUC__) */ + +/* We avoid pulling in the ctype tables, to prevent pulling in + additional unresolved symbols when this code is used in a library. + FIXME: Is this really a valid reason? This comes from the original + V3 demangler code. + + As of this writing this file has the following undefined references + when compiled with -DIN_GLIBCPP_V3: realloc, free, memcpy, strcpy, + strcat, strlen. */ + +#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9') +#define IS_UPPER(c) ((c) >= 'A' && (c) <= 'Z') +#define IS_LOWER(c) ((c) >= 'a' && (c) <= 'z') + +/* The prefix prepended by GCC to an identifier represnting the + anonymous namespace. */ +#define ANONYMOUS_NAMESPACE_PREFIX "_GLOBAL_" +#define ANONYMOUS_NAMESPACE_PREFIX_LEN \ + (sizeof (ANONYMOUS_NAMESPACE_PREFIX) - 1) + +/* Information we keep for the standard substitutions. */ + +struct d_standard_sub_info +{ + /* The code for this substitution. */ + char code; + /* The simple string it expands to. */ + const char *simple_expansion; + /* The length of the simple expansion. */ + int simple_len; + /* The results of a full, verbose, expansion. This is used when + qualifying a constructor/destructor, or when in verbose mode. */ + const char *full_expansion; + /* The length of the full expansion. */ + int full_len; + /* What to set the last_name field of d_info to; NULL if we should + not set it. This is only relevant when qualifying a + constructor/destructor. */ + const char *set_last_name; + /* The length of set_last_name. */ + int set_last_name_len; +}; + +/* Accessors for subtrees of struct demangle_component. */ + +#define d_left(dc) ((dc)->u.s_binary.left) +#define d_right(dc) ((dc)->u.s_binary.right) + +/* A list of templates. This is used while printing. */ + +struct d_print_template +{ + /* Next template on the list. */ + struct d_print_template *next; + /* This template. */ + const struct demangle_component *template_decl; +}; + +/* A list of type modifiers. This is used while printing. */ + +struct d_print_mod +{ + /* Next modifier on the list. These are in the reverse of the order + in which they appeared in the mangled string. */ + struct d_print_mod *next; + /* The modifier. */ + const struct demangle_component *mod; + /* Whether this modifier was printed. */ + int printed; + /* The list of templates which applies to this modifier. */ + struct d_print_template *templates; +}; + +/* We use these structures to hold information during printing. */ + +struct d_growable_string +{ + /* Buffer holding the result. */ + char *buf; + /* Current length of data in buffer. */ + size_t len; + /* Allocated size of buffer. */ + size_t alc; + /* Set to 1 if we had a memory allocation failure. */ + int allocation_failure; +}; + +enum { D_PRINT_BUFFER_LENGTH = 256 }; +struct d_print_info +{ + /* The options passed to the demangler. */ + int options; + /* Fixed-length allocated buffer for demangled data, flushed to the + callback with a NUL termination once full. */ + char buf[D_PRINT_BUFFER_LENGTH]; + /* Current length of data in buffer. */ + size_t len; + /* The last character printed, saved individually so that it survives + any buffer flush. */ + char last_char; + /* Callback function to handle demangled buffer flush. */ + demangle_callbackref callback; + /* Opaque callback argument. */ + void *opaque; + /* The current list of templates, if any. */ + struct d_print_template *templates; + /* The current list of modifiers (e.g., pointer, reference, etc.), + if any. */ + struct d_print_mod *modifiers; + /* Set to 1 if we saw a demangling error. */ + int demangle_failure; +}; + +#ifdef CP_DEMANGLE_DEBUG +static void d_dump (struct demangle_component *, int); +#endif + +static struct demangle_component * +d_make_empty (struct d_info *); + +static struct demangle_component * +d_make_comp (struct d_info *, enum demangle_component_type, + struct demangle_component *, + struct demangle_component *); + +static struct demangle_component * +d_make_name (struct d_info *, const char *, int); + +static struct demangle_component * +d_make_builtin_type (struct d_info *, + const struct demangle_builtin_type_info *); + +static struct demangle_component * +d_make_operator (struct d_info *, + const struct demangle_operator_info *); + +static struct demangle_component * +d_make_extended_operator (struct d_info *, int, + struct demangle_component *); + +static struct demangle_component * +d_make_ctor (struct d_info *, enum gnu_v3_ctor_kinds, + struct demangle_component *); + +static struct demangle_component * +d_make_dtor (struct d_info *, enum gnu_v3_dtor_kinds, + struct demangle_component *); + +static struct demangle_component * +d_make_template_param (struct d_info *, long); + +static struct demangle_component * +d_make_sub (struct d_info *, const char *, int); + +static int +has_return_type (struct demangle_component *); + +static int +is_ctor_dtor_or_conversion (struct demangle_component *); + +static struct demangle_component *d_encoding (struct d_info *, int); + +static struct demangle_component *d_name (struct d_info *); + +static struct demangle_component *d_nested_name (struct d_info *); + +static struct demangle_component *d_prefix (struct d_info *); + +static struct demangle_component *d_unqualified_name (struct d_info *); + +static struct demangle_component *d_source_name (struct d_info *); + +static long d_number (struct d_info *); + +static struct demangle_component *d_identifier (struct d_info *, int); + +static struct demangle_component *d_operator_name (struct d_info *); + +static struct demangle_component *d_special_name (struct d_info *); + +static int d_call_offset (struct d_info *, int); + +static struct demangle_component *d_ctor_dtor_name (struct d_info *); + +static struct demangle_component ** +d_cv_qualifiers (struct d_info *, struct demangle_component **, int); + +static struct demangle_component * +d_function_type (struct d_info *); + +static struct demangle_component * +d_bare_function_type (struct d_info *, int); + +static struct demangle_component * +d_class_enum_type (struct d_info *); + +static struct demangle_component *d_array_type (struct d_info *); + +static struct demangle_component * +d_pointer_to_member_type (struct d_info *); + +static struct demangle_component * +d_template_param (struct d_info *); + +static struct demangle_component *d_template_args (struct d_info *); + +static struct demangle_component * +d_template_arg (struct d_info *); + +static struct demangle_component *d_expression (struct d_info *); + +static struct demangle_component *d_expr_primary (struct d_info *); + +static struct demangle_component *d_local_name (struct d_info *); + +static int d_discriminator (struct d_info *); + +static int +d_add_substitution (struct d_info *, struct demangle_component *); + +static struct demangle_component *d_substitution (struct d_info *, int); + +static void d_growable_string_init (struct d_growable_string *, size_t); + +static inline void +d_growable_string_resize (struct d_growable_string *, size_t); + +static inline void +d_growable_string_append_buffer (struct d_growable_string *, + const char *, size_t); +static void +d_growable_string_callback_adapter (const char *, size_t, void *); + +static void +d_print_init (struct d_print_info *, int, demangle_callbackref, void *); + +static inline void d_print_error (struct d_print_info *); + +static inline int d_print_saw_error (struct d_print_info *); + +static inline void d_print_flush (struct d_print_info *); + +static inline void d_append_char (struct d_print_info *, char); + +static inline void d_append_buffer (struct d_print_info *, + const char *, size_t); + +static inline void d_append_string (struct d_print_info *, const char *); + +static inline char d_last_char (struct d_print_info *); + +static void +d_print_comp (struct d_print_info *, const struct demangle_component *); + +static void +d_print_java_identifier (struct d_print_info *, const char *, int); + +static void +d_print_mod_list (struct d_print_info *, struct d_print_mod *, int); + +static void +d_print_mod (struct d_print_info *, const struct demangle_component *); + +static void +d_print_function_type (struct d_print_info *, + const struct demangle_component *, + struct d_print_mod *); + +static void +d_print_array_type (struct d_print_info *, + const struct demangle_component *, + struct d_print_mod *); + +static void +d_print_expr_op (struct d_print_info *, const struct demangle_component *); + +static void +d_print_cast (struct d_print_info *, const struct demangle_component *); + +static int d_demangle_callback (const char *, int, + demangle_callbackref, void *); +static char *d_demangle (const char *, int, size_t *); + +#ifdef CP_DEMANGLE_DEBUG + +static void +d_dump (struct demangle_component *dc, int indent) +{ + int i; + + if (dc == NULL) + { + if (indent == 0) + printf ("failed demangling\n"); + return; + } + + for (i = 0; i < indent; ++i) + putchar (' '); + + switch (dc->type) + { + case DEMANGLE_COMPONENT_NAME: + printf ("name '%.*s'\n", dc->u.s_name.len, dc->u.s_name.s); + return; + case DEMANGLE_COMPONENT_TEMPLATE_PARAM: + printf ("template parameter %ld\n", dc->u.s_number.number); + return; + case DEMANGLE_COMPONENT_CTOR: + printf ("constructor %d\n", (int) dc->u.s_ctor.kind); + d_dump (dc->u.s_ctor.name, indent + 2); + return; + case DEMANGLE_COMPONENT_DTOR: + printf ("destructor %d\n", (int) dc->u.s_dtor.kind); + d_dump (dc->u.s_dtor.name, indent + 2); + return; + case DEMANGLE_COMPONENT_SUB_STD: + printf ("standard substitution %s\n", dc->u.s_string.string); + return; + case DEMANGLE_COMPONENT_BUILTIN_TYPE: + printf ("builtin type %s\n", dc->u.s_builtin.type->name); + return; + case DEMANGLE_COMPONENT_OPERATOR: + printf ("operator %s\n", dc->u.s_operator.op->name); + return; + case DEMANGLE_COMPONENT_EXTENDED_OPERATOR: + printf ("extended operator with %d args\n", + dc->u.s_extended_operator.args); + d_dump (dc->u.s_extended_operator.name, indent + 2); + return; + + case DEMANGLE_COMPONENT_QUAL_NAME: + printf ("qualified name\n"); + break; + case DEMANGLE_COMPONENT_LOCAL_NAME: + printf ("local name\n"); + break; + case DEMANGLE_COMPONENT_TYPED_NAME: + printf ("typed name\n"); + break; + case DEMANGLE_COMPONENT_TEMPLATE: + printf ("template\n"); + break; + case DEMANGLE_COMPONENT_VTABLE: + printf ("vtable\n"); + break; + case DEMANGLE_COMPONENT_VTT: + printf ("VTT\n"); + break; + case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE: + printf ("construction vtable\n"); + break; + case DEMANGLE_COMPONENT_TYPEINFO: + printf ("typeinfo\n"); + break; + case DEMANGLE_COMPONENT_TYPEINFO_NAME: + printf ("typeinfo name\n"); + break; + case DEMANGLE_COMPONENT_TYPEINFO_FN: + printf ("typeinfo function\n"); + break; + case DEMANGLE_COMPONENT_THUNK: + printf ("thunk\n"); + break; + case DEMANGLE_COMPONENT_VIRTUAL_THUNK: + printf ("virtual thunk\n"); + break; + case DEMANGLE_COMPONENT_COVARIANT_THUNK: + printf ("covariant thunk\n"); + break; + case DEMANGLE_COMPONENT_JAVA_CLASS: + printf ("java class\n"); + break; + case DEMANGLE_COMPONENT_GUARD: + printf ("guard\n"); + break; + case DEMANGLE_COMPONENT_REFTEMP: + printf ("reference temporary\n"); + break; + case DEMANGLE_COMPONENT_HIDDEN_ALIAS: + printf ("hidden alias\n"); + break; + case DEMANGLE_COMPONENT_RESTRICT: + printf ("restrict\n"); + break; + case DEMANGLE_COMPONENT_VOLATILE: + printf ("volatile\n"); + break; + case DEMANGLE_COMPONENT_CONST: + printf ("const\n"); + break; + case DEMANGLE_COMPONENT_RESTRICT_THIS: + printf ("restrict this\n"); + break; + case DEMANGLE_COMPONENT_VOLATILE_THIS: + printf ("volatile this\n"); + break; + case DEMANGLE_COMPONENT_CONST_THIS: + printf ("const this\n"); + break; + case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: + printf ("vendor type qualifier\n"); + break; + case DEMANGLE_COMPONENT_POINTER: + printf ("pointer\n"); + break; + case DEMANGLE_COMPONENT_REFERENCE: + printf ("reference\n"); + break; + case DEMANGLE_COMPONENT_RVALUE_REFERENCE: + printf ("rvalue reference\n"); + break; + case DEMANGLE_COMPONENT_COMPLEX: + printf ("complex\n"); + break; + case DEMANGLE_COMPONENT_IMAGINARY: + printf ("imaginary\n"); + break; + case DEMANGLE_COMPONENT_VENDOR_TYPE: + printf ("vendor type\n"); + break; + case DEMANGLE_COMPONENT_FUNCTION_TYPE: + printf ("function type\n"); + break; + case DEMANGLE_COMPONENT_ARRAY_TYPE: + printf ("array type\n"); + break; + case DEMANGLE_COMPONENT_PTRMEM_TYPE: + printf ("pointer to member type\n"); + break; + case DEMANGLE_COMPONENT_ARGLIST: + printf ("argument list\n"); + break; + case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST: + printf ("template argument list\n"); + break; + case DEMANGLE_COMPONENT_CAST: + printf ("cast\n"); + break; + case DEMANGLE_COMPONENT_UNARY: + printf ("unary operator\n"); + break; + case DEMANGLE_COMPONENT_BINARY: + printf ("binary operator\n"); + break; + case DEMANGLE_COMPONENT_BINARY_ARGS: + printf ("binary operator arguments\n"); + break; + case DEMANGLE_COMPONENT_TRINARY: + printf ("trinary operator\n"); + break; + case DEMANGLE_COMPONENT_TRINARY_ARG1: + printf ("trinary operator arguments 1\n"); + break; + case DEMANGLE_COMPONENT_TRINARY_ARG2: + printf ("trinary operator arguments 1\n"); + break; + case DEMANGLE_COMPONENT_LITERAL: + printf ("literal\n"); + break; + case DEMANGLE_COMPONENT_LITERAL_NEG: + printf ("negative literal\n"); + break; + } + + d_dump (d_left (dc), indent + 2); + d_dump (d_right (dc), indent + 2); +} + +#endif /* CP_DEMANGLE_DEBUG */ + +/* Fill in a DEMANGLE_COMPONENT_NAME. */ + +CP_STATIC_IF_GLIBCPP_V3 +int +cplus_demangle_fill_name (struct demangle_component *p, const char *s, int len) +{ + if (p == NULL || s == NULL || len == 0) + return 0; + p->type = DEMANGLE_COMPONENT_NAME; + p->u.s_name.s = s; + p->u.s_name.len = len; + return 1; +} + +/* Fill in a DEMANGLE_COMPONENT_EXTENDED_OPERATOR. */ + +CP_STATIC_IF_GLIBCPP_V3 +int +cplus_demangle_fill_extended_operator (struct demangle_component *p, int args, + struct demangle_component *name) +{ + if (p == NULL || args < 0 || name == NULL) + return 0; + p->type = DEMANGLE_COMPONENT_EXTENDED_OPERATOR; + p->u.s_extended_operator.args = args; + p->u.s_extended_operator.name = name; + return 1; +} + +/* Fill in a DEMANGLE_COMPONENT_CTOR. */ + +CP_STATIC_IF_GLIBCPP_V3 +int +cplus_demangle_fill_ctor (struct demangle_component *p, + enum gnu_v3_ctor_kinds kind, + struct demangle_component *name) +{ + if (p == NULL + || name == NULL + || (kind < gnu_v3_complete_object_ctor + && kind > gnu_v3_complete_object_allocating_ctor)) + return 0; + p->type = DEMANGLE_COMPONENT_CTOR; + p->u.s_ctor.kind = kind; + p->u.s_ctor.name = name; + return 1; +} + +/* Fill in a DEMANGLE_COMPONENT_DTOR. */ + +CP_STATIC_IF_GLIBCPP_V3 +int +cplus_demangle_fill_dtor (struct demangle_component *p, + enum gnu_v3_dtor_kinds kind, + struct demangle_component *name) +{ + if (p == NULL + || name == NULL + || (kind < gnu_v3_deleting_dtor + && kind > gnu_v3_base_object_dtor)) + return 0; + p->type = DEMANGLE_COMPONENT_DTOR; + p->u.s_dtor.kind = kind; + p->u.s_dtor.name = name; + return 1; +} + +/* Add a new component. */ + +static struct demangle_component * +d_make_empty (struct d_info *di) +{ + struct demangle_component *p; + + if (di->next_comp >= di->num_comps) + return NULL; + p = &di->comps[di->next_comp]; + ++di->next_comp; + return p; +} + +/* Add a new generic component. */ + +static struct demangle_component * +d_make_comp (struct d_info *di, enum demangle_component_type type, + struct demangle_component *left, + struct demangle_component *right) +{ + struct demangle_component *p; + + /* We check for errors here. A typical error would be a NULL return + from a subroutine. We catch those here, and return NULL + upward. */ + switch (type) + { + /* These types require two parameters. */ + case DEMANGLE_COMPONENT_QUAL_NAME: + case DEMANGLE_COMPONENT_LOCAL_NAME: + case DEMANGLE_COMPONENT_TYPED_NAME: + case DEMANGLE_COMPONENT_TEMPLATE: + case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE: + case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: + case DEMANGLE_COMPONENT_PTRMEM_TYPE: + case DEMANGLE_COMPONENT_UNARY: + case DEMANGLE_COMPONENT_BINARY: + case DEMANGLE_COMPONENT_BINARY_ARGS: + case DEMANGLE_COMPONENT_TRINARY: + case DEMANGLE_COMPONENT_TRINARY_ARG1: + case DEMANGLE_COMPONENT_TRINARY_ARG2: + case DEMANGLE_COMPONENT_LITERAL: + case DEMANGLE_COMPONENT_LITERAL_NEG: + if (left == NULL || right == NULL) + return NULL; + break; + + /* These types only require one parameter. */ + case DEMANGLE_COMPONENT_VTABLE: + case DEMANGLE_COMPONENT_VTT: + case DEMANGLE_COMPONENT_TYPEINFO: + case DEMANGLE_COMPONENT_TYPEINFO_NAME: + case DEMANGLE_COMPONENT_TYPEINFO_FN: + case DEMANGLE_COMPONENT_THUNK: + case DEMANGLE_COMPONENT_VIRTUAL_THUNK: + case DEMANGLE_COMPONENT_COVARIANT_THUNK: + case DEMANGLE_COMPONENT_JAVA_CLASS: + case DEMANGLE_COMPONENT_GUARD: + case DEMANGLE_COMPONENT_REFTEMP: + case DEMANGLE_COMPONENT_HIDDEN_ALIAS: + case DEMANGLE_COMPONENT_POINTER: + case DEMANGLE_COMPONENT_REFERENCE: + case DEMANGLE_COMPONENT_RVALUE_REFERENCE: + case DEMANGLE_COMPONENT_COMPLEX: + case DEMANGLE_COMPONENT_IMAGINARY: + case DEMANGLE_COMPONENT_VENDOR_TYPE: + case DEMANGLE_COMPONENT_ARGLIST: + case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST: + case DEMANGLE_COMPONENT_CAST: + if (left == NULL) + return NULL; + break; + + /* This needs a right parameter, but the left parameter can be + empty. */ + case DEMANGLE_COMPONENT_ARRAY_TYPE: + if (right == NULL) + return NULL; + break; + + /* These are allowed to have no parameters--in some cases they + will be filled in later. */ + case DEMANGLE_COMPONENT_FUNCTION_TYPE: + case DEMANGLE_COMPONENT_RESTRICT: + case DEMANGLE_COMPONENT_VOLATILE: + case DEMANGLE_COMPONENT_CONST: + case DEMANGLE_COMPONENT_RESTRICT_THIS: + case DEMANGLE_COMPONENT_VOLATILE_THIS: + case DEMANGLE_COMPONENT_CONST_THIS: + break; + + /* Other types should not be seen here. */ + default: + return NULL; + } + + p = d_make_empty (di); + if (p != NULL) + { + p->type = type; + p->u.s_binary.left = left; + p->u.s_binary.right = right; + } + return p; +} + +/* Add a new name component. */ + +static struct demangle_component * +d_make_name (struct d_info *di, const char *s, int len) +{ + struct demangle_component *p; + + p = d_make_empty (di); + if (! cplus_demangle_fill_name (p, s, len)) + return NULL; + return p; +} + +/* Add a new builtin type component. */ + +static struct demangle_component * +d_make_builtin_type (struct d_info *di, + const struct demangle_builtin_type_info *type) +{ + struct demangle_component *p; + + if (type == NULL) + return NULL; + p = d_make_empty (di); + if (p != NULL) + { + p->type = DEMANGLE_COMPONENT_BUILTIN_TYPE; + p->u.s_builtin.type = type; + } + return p; +} + +/* Add a new operator component. */ + +static struct demangle_component * +d_make_operator (struct d_info *di, const struct demangle_operator_info *op) +{ + struct demangle_component *p; + + p = d_make_empty (di); + if (p != NULL) + { + p->type = DEMANGLE_COMPONENT_OPERATOR; + p->u.s_operator.op = op; + } + return p; +} + +/* Add a new extended operator component. */ + +static struct demangle_component * +d_make_extended_operator (struct d_info *di, int args, + struct demangle_component *name) +{ + struct demangle_component *p; + + p = d_make_empty (di); + if (! cplus_demangle_fill_extended_operator (p, args, name)) + return NULL; + return p; +} + +/* Add a new constructor component. */ + +static struct demangle_component * +d_make_ctor (struct d_info *di, enum gnu_v3_ctor_kinds kind, + struct demangle_component *name) +{ + struct demangle_component *p; + + p = d_make_empty (di); + if (! cplus_demangle_fill_ctor (p, kind, name)) + return NULL; + return p; +} + +/* Add a new destructor component. */ + +static struct demangle_component * +d_make_dtor (struct d_info *di, enum gnu_v3_dtor_kinds kind, + struct demangle_component *name) +{ + struct demangle_component *p; + + p = d_make_empty (di); + if (! cplus_demangle_fill_dtor (p, kind, name)) + return NULL; + return p; +} + +/* Add a new template parameter. */ + +static struct demangle_component * +d_make_template_param (struct d_info *di, long i) +{ + struct demangle_component *p; + + p = d_make_empty (di); + if (p != NULL) + { + p->type = DEMANGLE_COMPONENT_TEMPLATE_PARAM; + p->u.s_number.number = i; + } + return p; +} + +/* Add a new standard substitution component. */ + +static struct demangle_component * +d_make_sub (struct d_info *di, const char *name, int len) +{ + struct demangle_component *p; + + p = d_make_empty (di); + if (p != NULL) + { + p->type = DEMANGLE_COMPONENT_SUB_STD; + p->u.s_string.string = name; + p->u.s_string.len = len; + } + return p; +} + +/* ::= _Z + + TOP_LEVEL is non-zero when called at the top level. */ + +CP_STATIC_IF_GLIBCPP_V3 +struct demangle_component * +cplus_demangle_mangled_name (struct d_info *di, int top_level) +{ + if (! d_check_char (di, '_')) + return NULL; + if (! d_check_char (di, 'Z')) + return NULL; + return d_encoding (di, top_level); +} + +/* Return whether a function should have a return type. The argument + is the function name, which may be qualified in various ways. The + rules are that template functions have return types with some + exceptions, function types which are not part of a function name + mangling have return types with some exceptions, and non-template + function names do not have return types. The exceptions are that + constructors, destructors, and conversion operators do not have + return types. */ + +static int +has_return_type (struct demangle_component *dc) +{ + if (dc == NULL) + return 0; + switch (dc->type) + { + default: + return 0; + case DEMANGLE_COMPONENT_TEMPLATE: + return ! is_ctor_dtor_or_conversion (d_left (dc)); + case DEMANGLE_COMPONENT_RESTRICT_THIS: + case DEMANGLE_COMPONENT_VOLATILE_THIS: + case DEMANGLE_COMPONENT_CONST_THIS: + return has_return_type (d_left (dc)); + } +} + +/* Return whether a name is a constructor, a destructor, or a + conversion operator. */ + +static int +is_ctor_dtor_or_conversion (struct demangle_component *dc) +{ + if (dc == NULL) + return 0; + switch (dc->type) + { + default: + return 0; + case DEMANGLE_COMPONENT_QUAL_NAME: + case DEMANGLE_COMPONENT_LOCAL_NAME: + return is_ctor_dtor_or_conversion (d_right (dc)); + case DEMANGLE_COMPONENT_CTOR: + case DEMANGLE_COMPONENT_DTOR: + case DEMANGLE_COMPONENT_CAST: + return 1; + } +} + +/* ::= <(function) name> + ::= <(data) name> + ::= + + TOP_LEVEL is non-zero when called at the top level, in which case + if DMGL_PARAMS is not set we do not demangle the function + parameters. We only set this at the top level, because otherwise + we would not correctly demangle names in local scopes. */ + +static struct demangle_component * +d_encoding (struct d_info *di, int top_level) +{ + char peek = d_peek_char (di); + + if (peek == 'G' || peek == 'T') + return d_special_name (di); + else + { + struct demangle_component *dc; + + dc = d_name (di); + + if (dc != NULL && top_level && (di->options & DMGL_PARAMS) == 0) + { + /* Strip off any initial CV-qualifiers, as they really apply + to the `this' parameter, and they were not output by the + v2 demangler without DMGL_PARAMS. */ + while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS + || dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS + || dc->type == DEMANGLE_COMPONENT_CONST_THIS) + dc = d_left (dc); + + /* If the top level is a DEMANGLE_COMPONENT_LOCAL_NAME, then + there may be CV-qualifiers on its right argument which + really apply here; this happens when parsing a class + which is local to a function. */ + if (dc->type == DEMANGLE_COMPONENT_LOCAL_NAME) + { + struct demangle_component *dcr; + + dcr = d_right (dc); + while (dcr->type == DEMANGLE_COMPONENT_RESTRICT_THIS + || dcr->type == DEMANGLE_COMPONENT_VOLATILE_THIS + || dcr->type == DEMANGLE_COMPONENT_CONST_THIS) + dcr = d_left (dcr); + dc->u.s_binary.right = dcr; + } + + return dc; + } + + peek = d_peek_char (di); + if (dc == NULL || peek == '\0' || peek == 'E') + return dc; + return d_make_comp (di, DEMANGLE_COMPONENT_TYPED_NAME, dc, + d_bare_function_type (di, has_return_type (dc))); + } +} + +/* ::= + ::= + ::= + ::= + + ::= + ::= St + + ::= + ::= +*/ + +static struct demangle_component * +d_name (struct d_info *di) +{ + char peek = d_peek_char (di); + struct demangle_component *dc; + + switch (peek) + { + case 'N': + return d_nested_name (di); + + case 'Z': + return d_local_name (di); + + case 'L': + return d_unqualified_name (di); + + case 'S': + { + int subst; + + if (d_peek_next_char (di) != 't') + { + dc = d_substitution (di, 0); + subst = 1; + } + else + { + d_advance (di, 2); + dc = d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, + d_make_name (di, "std", 3), + d_unqualified_name (di)); + di->expansion += 3; + subst = 0; + } + + if (d_peek_char (di) != 'I') + { + /* The grammar does not permit this case to occur if we + called d_substitution() above (i.e., subst == 1). We + don't bother to check. */ + } + else + { + /* This is , which means that we just saw + , which is a substitution + candidate if we didn't just get it from a + substitution. */ + if (! subst) + { + if (! d_add_substitution (di, dc)) + return NULL; + } + dc = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, dc, + d_template_args (di)); + } + + return dc; + } + + default: + dc = d_unqualified_name (di); + if (d_peek_char (di) == 'I') + { + /* This is , which means that we just saw + , which is a substitution + candidate. */ + if (! d_add_substitution (di, dc)) + return NULL; + dc = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, dc, + d_template_args (di)); + } + return dc; + } +} + +/* ::= N [] E + ::= N [] E +*/ + +static struct demangle_component * +d_nested_name (struct d_info *di) +{ + struct demangle_component *ret; + struct demangle_component **pret; + + if (! d_check_char (di, 'N')) + return NULL; + + pret = d_cv_qualifiers (di, &ret, 1); + if (pret == NULL) + return NULL; + + *pret = d_prefix (di); + if (*pret == NULL) + return NULL; + + if (! d_check_char (di, 'E')) + return NULL; + + return ret; +} + +/* ::= + ::= + ::= + ::= + ::= + + ::= <(template) unqualified-name> + ::= + ::= +*/ + +static struct demangle_component * +d_prefix (struct d_info *di) +{ + struct demangle_component *ret = NULL; + + while (1) + { + char peek; + enum demangle_component_type comb_type; + struct demangle_component *dc; + + peek = d_peek_char (di); + if (peek == '\0') + return NULL; + + /* The older code accepts a here, but I don't see + that in the grammar. The older code does not accept a + here. */ + + comb_type = DEMANGLE_COMPONENT_QUAL_NAME; + if (IS_DIGIT (peek) + || IS_LOWER (peek) + || peek == 'C' + || peek == 'D' + || peek == 'L') + dc = d_unqualified_name (di); + else if (peek == 'S') + dc = d_substitution (di, 1); + else if (peek == 'I') + { + if (ret == NULL) + return NULL; + comb_type = DEMANGLE_COMPONENT_TEMPLATE; + dc = d_template_args (di); + } + else if (peek == 'T') + dc = d_template_param (di); + else if (peek == 'E') + return ret; + else + return NULL; + + if (ret == NULL) + ret = dc; + else + ret = d_make_comp (di, comb_type, ret, dc); + + if (peek != 'S' && d_peek_char (di) != 'E') + { + if (! d_add_substitution (di, ret)) + return NULL; + } + } +} + +/* ::= + ::= + ::= + ::= + + ::= L +*/ + +static struct demangle_component * +d_unqualified_name (struct d_info *di) +{ + char peek; + + peek = d_peek_char (di); + if (IS_DIGIT (peek)) + return d_source_name (di); + else if (IS_LOWER (peek)) + { + struct demangle_component *ret; + + ret = d_operator_name (di); + if (ret != NULL && ret->type == DEMANGLE_COMPONENT_OPERATOR) + di->expansion += sizeof "operator" + ret->u.s_operator.op->len - 2; + return ret; + } + else if (peek == 'C' || peek == 'D') + return d_ctor_dtor_name (di); + else if (peek == 'L') + { + struct demangle_component * ret; + + d_advance (di, 1); + + ret = d_source_name (di); + if (ret == NULL) + return NULL; + if (! d_discriminator (di)) + return NULL; + return ret; + } + else + return NULL; +} + +/* ::= <(positive length) number> */ + +static struct demangle_component * +d_source_name (struct d_info *di) +{ + long len; + struct demangle_component *ret; + + len = d_number (di); + if (len <= 0) + return NULL; + ret = d_identifier (di, len); + di->last_name = ret; + return ret; +} + +/* number ::= [n] <(non-negative decimal integer)> */ + +static long +d_number (struct d_info *di) +{ + int negative; + char peek; + long ret; + + negative = 0; + peek = d_peek_char (di); + if (peek == 'n') + { + negative = 1; + d_advance (di, 1); + peek = d_peek_char (di); + } + + ret = 0; + while (1) + { + if (! IS_DIGIT (peek)) + { + if (negative) + ret = - ret; + return ret; + } + ret = ret * 10 + peek - '0'; + d_advance (di, 1); + peek = d_peek_char (di); + } +} + +/* identifier ::= <(unqualified source code identifier)> */ + +static struct demangle_component * +d_identifier (struct d_info *di, int len) +{ + const char *name; + + name = d_str (di); + + if (di->send - name < len) + return NULL; + + d_advance (di, len); + + /* A Java mangled name may have a trailing '$' if it is a C++ + keyword. This '$' is not included in the length count. We just + ignore the '$'. */ + if ((di->options & DMGL_JAVA) != 0 + && d_peek_char (di) == '$') + d_advance (di, 1); + + /* Look for something which looks like a gcc encoding of an + anonymous namespace, and replace it with a more user friendly + name. */ + if (len >= (int) ANONYMOUS_NAMESPACE_PREFIX_LEN + 2 + && memcmp (name, ANONYMOUS_NAMESPACE_PREFIX, + ANONYMOUS_NAMESPACE_PREFIX_LEN) == 0) + { + const char *s; + + s = name + ANONYMOUS_NAMESPACE_PREFIX_LEN; + if ((*s == '.' || *s == '_' || *s == '$') + && s[1] == 'N') + { + di->expansion -= len - sizeof "(anonymous namespace)"; + return d_make_name (di, "(anonymous namespace)", + sizeof "(anonymous namespace)" - 1); + } + } + + return d_make_name (di, name, len); +} + +/* operator_name ::= many different two character encodings. + ::= cv + ::= v +*/ + +#define NL(s) s, (sizeof s) - 1 + +CP_STATIC_IF_GLIBCPP_V3 +const struct demangle_operator_info cplus_demangle_operators[] = +{ + { "aN", NL ("&="), 2 }, + { "aS", NL ("="), 2 }, + { "aa", NL ("&&"), 2 }, + { "ad", NL ("&"), 1 }, + { "an", NL ("&"), 2 }, + { "cl", NL ("()"), 0 }, + { "cm", NL (","), 2 }, + { "co", NL ("~"), 1 }, + { "dV", NL ("/="), 2 }, + { "da", NL ("delete[]"), 1 }, + { "de", NL ("*"), 1 }, + { "dl", NL ("delete"), 1 }, + { "dv", NL ("/"), 2 }, + { "eO", NL ("^="), 2 }, + { "eo", NL ("^"), 2 }, + { "eq", NL ("=="), 2 }, + { "ge", NL (">="), 2 }, + { "gt", NL (">"), 2 }, + { "ix", NL ("[]"), 2 }, + { "lS", NL ("<<="), 2 }, + { "le", NL ("<="), 2 }, + { "ls", NL ("<<"), 2 }, + { "lt", NL ("<"), 2 }, + { "mI", NL ("-="), 2 }, + { "mL", NL ("*="), 2 }, + { "mi", NL ("-"), 2 }, + { "ml", NL ("*"), 2 }, + { "mm", NL ("--"), 1 }, + { "na", NL ("new[]"), 1 }, + { "ne", NL ("!="), 2 }, + { "ng", NL ("-"), 1 }, + { "nt", NL ("!"), 1 }, + { "nw", NL ("new"), 1 }, + { "oR", NL ("|="), 2 }, + { "oo", NL ("||"), 2 }, + { "or", NL ("|"), 2 }, + { "pL", NL ("+="), 2 }, + { "pl", NL ("+"), 2 }, + { "pm", NL ("->*"), 2 }, + { "pp", NL ("++"), 1 }, + { "ps", NL ("+"), 1 }, + { "pt", NL ("->"), 2 }, + { "qu", NL ("?"), 3 }, + { "rM", NL ("%="), 2 }, + { "rS", NL (">>="), 2 }, + { "rm", NL ("%"), 2 }, + { "rs", NL (">>"), 2 }, + { "st", NL ("sizeof "), 1 }, + { "sz", NL ("sizeof "), 1 }, + { NULL, NULL, 0, 0 } +}; + +static struct demangle_component * +d_operator_name (struct d_info *di) +{ + char c1; + char c2; + + c1 = d_next_char (di); + c2 = d_next_char (di); + if (c1 == 'v' && IS_DIGIT (c2)) + return d_make_extended_operator (di, c2 - '0', d_source_name (di)); + else if (c1 == 'c' && c2 == 'v') + return d_make_comp (di, DEMANGLE_COMPONENT_CAST, + cplus_demangle_type (di), NULL); + else + { + /* LOW is the inclusive lower bound. */ + int low = 0; + /* HIGH is the exclusive upper bound. We subtract one to ignore + the sentinel at the end of the array. */ + int high = ((sizeof (cplus_demangle_operators) + / sizeof (cplus_demangle_operators[0])) + - 1); + + while (1) + { + int i; + const struct demangle_operator_info *p; + + i = low + (high - low) / 2; + p = cplus_demangle_operators + i; + + if (c1 == p->code[0] && c2 == p->code[1]) + return d_make_operator (di, p); + + if (c1 < p->code[0] || (c1 == p->code[0] && c2 < p->code[1])) + high = i; + else + low = i + 1; + if (low == high) + return NULL; + } + } +} + +/* ::= TV + ::= TT + ::= TI + ::= TS + ::= GV <(object) name> + ::= T <(base) encoding> + ::= Tc <(base) encoding> + Also g++ extensions: + ::= TC <(offset) number> _ <(base) type> + ::= TF + ::= TJ + ::= GR + ::= GA +*/ + +static struct demangle_component * +d_special_name (struct d_info *di) +{ + di->expansion += 20; + if (d_check_char (di, 'T')) + { + switch (d_next_char (di)) + { + case 'V': + di->expansion -= 5; + return d_make_comp (di, DEMANGLE_COMPONENT_VTABLE, + cplus_demangle_type (di), NULL); + case 'T': + di->expansion -= 10; + return d_make_comp (di, DEMANGLE_COMPONENT_VTT, + cplus_demangle_type (di), NULL); + case 'I': + return d_make_comp (di, DEMANGLE_COMPONENT_TYPEINFO, + cplus_demangle_type (di), NULL); + case 'S': + return d_make_comp (di, DEMANGLE_COMPONENT_TYPEINFO_NAME, + cplus_demangle_type (di), NULL); + + case 'h': + if (! d_call_offset (di, 'h')) + return NULL; + return d_make_comp (di, DEMANGLE_COMPONENT_THUNK, + d_encoding (di, 0), NULL); + + case 'v': + if (! d_call_offset (di, 'v')) + return NULL; + return d_make_comp (di, DEMANGLE_COMPONENT_VIRTUAL_THUNK, + d_encoding (di, 0), NULL); + + case 'c': + if (! d_call_offset (di, '\0')) + return NULL; + if (! d_call_offset (di, '\0')) + return NULL; + return d_make_comp (di, DEMANGLE_COMPONENT_COVARIANT_THUNK, + d_encoding (di, 0), NULL); + + case 'C': + { + struct demangle_component *derived_type; + long offset; + struct demangle_component *base_type; + + derived_type = cplus_demangle_type (di); + offset = d_number (di); + if (offset < 0) + return NULL; + if (! d_check_char (di, '_')) + return NULL; + base_type = cplus_demangle_type (di); + /* We don't display the offset. FIXME: We should display + it in verbose mode. */ + di->expansion += 5; + return d_make_comp (di, DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE, + base_type, derived_type); + } + + case 'F': + return d_make_comp (di, DEMANGLE_COMPONENT_TYPEINFO_FN, + cplus_demangle_type (di), NULL); + case 'J': + return d_make_comp (di, DEMANGLE_COMPONENT_JAVA_CLASS, + cplus_demangle_type (di), NULL); + + default: + return NULL; + } + } + else if (d_check_char (di, 'G')) + { + switch (d_next_char (di)) + { + case 'V': + return d_make_comp (di, DEMANGLE_COMPONENT_GUARD, d_name (di), NULL); + + case 'R': + return d_make_comp (di, DEMANGLE_COMPONENT_REFTEMP, d_name (di), + NULL); + + case 'A': + return d_make_comp (di, DEMANGLE_COMPONENT_HIDDEN_ALIAS, + d_encoding (di, 0), NULL); + + default: + return NULL; + } + } + else + return NULL; +} + +/* ::= h _ + ::= v _ + + ::= <(offset) number> + + ::= <(offset) number> _ <(virtual offset) number> + + The C parameter, if not '\0', is a character we just read which is + the start of the . + + We don't display the offset information anywhere. FIXME: We should + display it in verbose mode. */ + +static int +d_call_offset (struct d_info *di, int c) +{ + if (c == '\0') + c = d_next_char (di); + + if (c == 'h') + d_number (di); + else if (c == 'v') + { + d_number (di); + if (! d_check_char (di, '_')) + return 0; + d_number (di); + } + else + return 0; + + if (! d_check_char (di, '_')) + return 0; + + return 1; +} + +/* ::= C1 + ::= C2 + ::= C3 + ::= D0 + ::= D1 + ::= D2 +*/ + +static struct demangle_component * +d_ctor_dtor_name (struct d_info *di) +{ + if (di->last_name != NULL) + { + if (di->last_name->type == DEMANGLE_COMPONENT_NAME) + di->expansion += di->last_name->u.s_name.len; + else if (di->last_name->type == DEMANGLE_COMPONENT_SUB_STD) + di->expansion += di->last_name->u.s_string.len; + } + switch (d_peek_char (di)) + { + case 'C': + { + enum gnu_v3_ctor_kinds kind; + + switch (d_peek_next_char (di)) + { + case '1': + kind = gnu_v3_complete_object_ctor; + break; + case '2': + kind = gnu_v3_base_object_ctor; + break; + case '3': + kind = gnu_v3_complete_object_allocating_ctor; + break; + default: + return NULL; + } + d_advance (di, 2); + return d_make_ctor (di, kind, di->last_name); + } + + case 'D': + { + enum gnu_v3_dtor_kinds kind; + + switch (d_peek_next_char (di)) + { + case '0': + kind = gnu_v3_deleting_dtor; + break; + case '1': + kind = gnu_v3_complete_object_dtor; + break; + case '2': + kind = gnu_v3_base_object_dtor; + break; + default: + return NULL; + } + d_advance (di, 2); + return d_make_dtor (di, kind, di->last_name); + } + + default: + return NULL; + } +} + +/* ::= + ::= + ::= + ::= + ::= + ::= + ::= + ::= + ::= + ::= P + ::= R + ::= O (C++0x) + ::= C + ::= G + ::= U + + ::= various one letter codes + ::= u +*/ + +CP_STATIC_IF_GLIBCPP_V3 +const struct demangle_builtin_type_info +cplus_demangle_builtin_types[D_BUILTIN_TYPE_COUNT] = +{ + /* a */ { NL ("signed char"), NL ("signed char"), D_PRINT_DEFAULT }, + /* b */ { NL ("bool"), NL ("boolean"), D_PRINT_BOOL }, + /* c */ { NL ("char"), NL ("byte"), D_PRINT_DEFAULT }, + /* d */ { NL ("double"), NL ("double"), D_PRINT_FLOAT }, + /* e */ { NL ("long double"), NL ("long double"), D_PRINT_FLOAT }, + /* f */ { NL ("float"), NL ("float"), D_PRINT_FLOAT }, + /* g */ { NL ("__float128"), NL ("__float128"), D_PRINT_FLOAT }, + /* h */ { NL ("unsigned char"), NL ("unsigned char"), D_PRINT_DEFAULT }, + /* i */ { NL ("int"), NL ("int"), D_PRINT_INT }, + /* j */ { NL ("unsigned int"), NL ("unsigned"), D_PRINT_UNSIGNED }, + /* k */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT }, + /* l */ { NL ("long"), NL ("long"), D_PRINT_LONG }, + /* m */ { NL ("unsigned long"), NL ("unsigned long"), D_PRINT_UNSIGNED_LONG }, + /* n */ { NL ("__int128"), NL ("__int128"), D_PRINT_DEFAULT }, + /* o */ { NL ("unsigned __int128"), NL ("unsigned __int128"), + D_PRINT_DEFAULT }, + /* p */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT }, + /* q */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT }, + /* r */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT }, + /* s */ { NL ("short"), NL ("short"), D_PRINT_DEFAULT }, + /* t */ { NL ("unsigned short"), NL ("unsigned short"), D_PRINT_DEFAULT }, + /* u */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT }, + /* v */ { NL ("void"), NL ("void"), D_PRINT_VOID }, + /* w */ { NL ("wchar_t"), NL ("char"), D_PRINT_DEFAULT }, + /* x */ { NL ("long long"), NL ("long"), D_PRINT_LONG_LONG }, + /* y */ { NL ("unsigned long long"), NL ("unsigned long long"), + D_PRINT_UNSIGNED_LONG_LONG }, + /* z */ { NL ("..."), NL ("..."), D_PRINT_DEFAULT }, +}; + +CP_STATIC_IF_GLIBCPP_V3 +struct demangle_component * +cplus_demangle_type (struct d_info *di) +{ + char peek; + struct demangle_component *ret; + int can_subst; + + /* The ABI specifies that when CV-qualifiers are used, the base type + is substitutable, and the fully qualified type is substitutable, + but the base type with a strict subset of the CV-qualifiers is + not substitutable. The natural recursive implementation of the + CV-qualifiers would cause subsets to be substitutable, so instead + we pull them all off now. + + FIXME: The ABI says that order-insensitive vendor qualifiers + should be handled in the same way, but we have no way to tell + which vendor qualifiers are order-insensitive and which are + order-sensitive. So we just assume that they are all + order-sensitive. g++ 3.4 supports only one vendor qualifier, + __vector, and it treats it as order-sensitive when mangling + names. */ + + peek = d_peek_char (di); + if (peek == 'r' || peek == 'V' || peek == 'K') + { + struct demangle_component **pret; + + pret = d_cv_qualifiers (di, &ret, 0); + if (pret == NULL) + return NULL; + *pret = cplus_demangle_type (di); + if (! *pret || ! d_add_substitution (di, ret)) + return NULL; + return ret; + } + + can_subst = 1; + + switch (peek) + { + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': + case 'h': case 'i': case 'j': case 'l': case 'm': case 'n': + case 'o': case 's': case 't': + case 'v': case 'w': case 'x': case 'y': case 'z': + ret = d_make_builtin_type (di, + &cplus_demangle_builtin_types[peek - 'a']); + di->expansion += ret->u.s_builtin.type->len; + can_subst = 0; + d_advance (di, 1); + break; + + case 'u': + d_advance (di, 1); + ret = d_make_comp (di, DEMANGLE_COMPONENT_VENDOR_TYPE, + d_source_name (di), NULL); + break; + + case 'F': + ret = d_function_type (di); + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case 'N': + case 'Z': + ret = d_class_enum_type (di); + break; + + case 'A': + ret = d_array_type (di); + break; + + case 'M': + ret = d_pointer_to_member_type (di); + break; + + case 'T': + ret = d_template_param (di); + if (d_peek_char (di) == 'I') + { + /* This is . The + part is a substitution + candidate. */ + if (! d_add_substitution (di, ret)) + return NULL; + ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret, + d_template_args (di)); + } + break; + + case 'S': + /* If this is a special substitution, then it is the start of + . */ + { + char peek_next; + + peek_next = d_peek_next_char (di); + if (IS_DIGIT (peek_next) + || peek_next == '_' + || IS_UPPER (peek_next)) + { + ret = d_substitution (di, 0); + /* The substituted name may have been a template name and + may be followed by tepmlate args. */ + if (d_peek_char (di) == 'I') + ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret, + d_template_args (di)); + else + can_subst = 0; + } + else + { + ret = d_class_enum_type (di); + /* If the substitution was a complete type, then it is not + a new substitution candidate. However, if the + substitution was followed by template arguments, then + the whole thing is a substitution candidate. */ + if (ret != NULL && ret->type == DEMANGLE_COMPONENT_SUB_STD) + can_subst = 0; + } + } + break; + + case 'O': + d_advance (di, 1); + ret = d_make_comp (di, DEMANGLE_COMPONENT_RVALUE_REFERENCE, + cplus_demangle_type (di), NULL); + break; + + case 'P': + d_advance (di, 1); + ret = d_make_comp (di, DEMANGLE_COMPONENT_POINTER, + cplus_demangle_type (di), NULL); + break; + + case 'R': + d_advance (di, 1); + ret = d_make_comp (di, DEMANGLE_COMPONENT_REFERENCE, + cplus_demangle_type (di), NULL); + break; + + case 'C': + d_advance (di, 1); + ret = d_make_comp (di, DEMANGLE_COMPONENT_COMPLEX, + cplus_demangle_type (di), NULL); + break; + + case 'G': + d_advance (di, 1); + ret = d_make_comp (di, DEMANGLE_COMPONENT_IMAGINARY, + cplus_demangle_type (di), NULL); + break; + + case 'U': + d_advance (di, 1); + ret = d_source_name (di); + ret = d_make_comp (di, DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL, + cplus_demangle_type (di), ret); + break; + + default: + return NULL; + } + + if (can_subst) + { + if (! d_add_substitution (di, ret)) + return NULL; + } + + return ret; +} + +/* ::= [r] [V] [K] */ + +static struct demangle_component ** +d_cv_qualifiers (struct d_info *di, + struct demangle_component **pret, int member_fn) +{ + char peek; + + peek = d_peek_char (di); + while (peek == 'r' || peek == 'V' || peek == 'K') + { + enum demangle_component_type t; + + d_advance (di, 1); + if (peek == 'r') + { + t = (member_fn + ? DEMANGLE_COMPONENT_RESTRICT_THIS + : DEMANGLE_COMPONENT_RESTRICT); + di->expansion += sizeof "restrict"; + } + else if (peek == 'V') + { + t = (member_fn + ? DEMANGLE_COMPONENT_VOLATILE_THIS + : DEMANGLE_COMPONENT_VOLATILE); + di->expansion += sizeof "volatile"; + } + else + { + t = (member_fn + ? DEMANGLE_COMPONENT_CONST_THIS + : DEMANGLE_COMPONENT_CONST); + di->expansion += sizeof "const"; + } + + *pret = d_make_comp (di, t, NULL, NULL); + if (*pret == NULL) + return NULL; + pret = &d_left (*pret); + + peek = d_peek_char (di); + } + + return pret; +} + +/* ::= F [Y] E */ + +static struct demangle_component * +d_function_type (struct d_info *di) +{ + struct demangle_component *ret; + + if (! d_check_char (di, 'F')) + return NULL; + if (d_peek_char (di) == 'Y') + { + /* Function has C linkage. We don't print this information. + FIXME: We should print it in verbose mode. */ + d_advance (di, 1); + } + ret = d_bare_function_type (di, 1); + if (! d_check_char (di, 'E')) + return NULL; + return ret; +} + +/* ::= [J]+ */ + +static struct demangle_component * +d_bare_function_type (struct d_info *di, int has_return_type) +{ + struct demangle_component *return_type; + struct demangle_component *tl; + struct demangle_component **ptl; + char peek; + + /* Detect special qualifier indicating that the first argument + is the return type. */ + peek = d_peek_char (di); + if (peek == 'J') + { + d_advance (di, 1); + has_return_type = 1; + } + + return_type = NULL; + tl = NULL; + ptl = &tl; + while (1) + { + struct demangle_component *type; + + peek = d_peek_char (di); + if (peek == '\0' || peek == 'E') + break; + type = cplus_demangle_type (di); + if (type == NULL) + return NULL; + if (has_return_type) + { + return_type = type; + has_return_type = 0; + } + else + { + *ptl = d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, type, NULL); + if (*ptl == NULL) + return NULL; + ptl = &d_right (*ptl); + } + } + + /* There should be at least one parameter type besides the optional + return type. A function which takes no arguments will have a + single parameter type void. */ + if (tl == NULL) + return NULL; + + /* If we have a single parameter type void, omit it. */ + if (d_right (tl) == NULL + && d_left (tl)->type == DEMANGLE_COMPONENT_BUILTIN_TYPE + && d_left (tl)->u.s_builtin.type->print == D_PRINT_VOID) + { + di->expansion -= d_left (tl)->u.s_builtin.type->len; + tl = NULL; + } + + return d_make_comp (di, DEMANGLE_COMPONENT_FUNCTION_TYPE, return_type, tl); +} + +/* ::= */ + +static struct demangle_component * +d_class_enum_type (struct d_info *di) +{ + return d_name (di); +} + +/* ::= A <(positive dimension) number> _ <(element) type> + ::= A [<(dimension) expression>] _ <(element) type> +*/ + +static struct demangle_component * +d_array_type (struct d_info *di) +{ + char peek; + struct demangle_component *dim; + + if (! d_check_char (di, 'A')) + return NULL; + + peek = d_peek_char (di); + if (peek == '_') + dim = NULL; + else if (IS_DIGIT (peek)) + { + const char *s; + + s = d_str (di); + do + { + d_advance (di, 1); + peek = d_peek_char (di); + } + while (IS_DIGIT (peek)); + dim = d_make_name (di, s, d_str (di) - s); + if (dim == NULL) + return NULL; + } + else + { + dim = d_expression (di); + if (dim == NULL) + return NULL; + } + + if (! d_check_char (di, '_')) + return NULL; + + return d_make_comp (di, DEMANGLE_COMPONENT_ARRAY_TYPE, dim, + cplus_demangle_type (di)); +} + +/* ::= M <(class) type> <(member) type> */ + +static struct demangle_component * +d_pointer_to_member_type (struct d_info *di) +{ + struct demangle_component *cl; + struct demangle_component *mem; + struct demangle_component **pmem; + + if (! d_check_char (di, 'M')) + return NULL; + + cl = cplus_demangle_type (di); + + /* The ABI specifies that any type can be a substitution source, and + that M is followed by two types, and that when a CV-qualified + type is seen both the base type and the CV-qualified types are + substitution sources. The ABI also specifies that for a pointer + to a CV-qualified member function, the qualifiers are attached to + the second type. Given the grammar, a plain reading of the ABI + suggests that both the CV-qualified member function and the + non-qualified member function are substitution sources. However, + g++ does not work that way. g++ treats only the CV-qualified + member function as a substitution source. FIXME. So to work + with g++, we need to pull off the CV-qualifiers here, in order to + avoid calling add_substitution() in cplus_demangle_type(). But + for a CV-qualified member which is not a function, g++ does + follow the ABI, so we need to handle that case here by calling + d_add_substitution ourselves. */ + + pmem = d_cv_qualifiers (di, &mem, 1); + if (pmem == NULL) + return NULL; + *pmem = cplus_demangle_type (di); + if (*pmem == NULL) + return NULL; + + if (pmem != &mem && (*pmem)->type != DEMANGLE_COMPONENT_FUNCTION_TYPE) + { + if (! d_add_substitution (di, mem)) + return NULL; + } + + return d_make_comp (di, DEMANGLE_COMPONENT_PTRMEM_TYPE, cl, mem); +} + +/* ::= T_ + ::= T <(parameter-2 non-negative) number> _ +*/ + +static struct demangle_component * +d_template_param (struct d_info *di) +{ + long param; + + if (! d_check_char (di, 'T')) + return NULL; + + if (d_peek_char (di) == '_') + param = 0; + else + { + param = d_number (di); + if (param < 0) + return NULL; + param += 1; + } + + if (! d_check_char (di, '_')) + return NULL; + + ++di->did_subs; + + return d_make_template_param (di, param); +} + +/* ::= I + E */ + +static struct demangle_component * +d_template_args (struct d_info *di) +{ + struct demangle_component *hold_last_name; + struct demangle_component *al; + struct demangle_component **pal; + + /* Preserve the last name we saw--don't let the template arguments + clobber it, as that would give us the wrong name for a subsequent + constructor or destructor. */ + hold_last_name = di->last_name; + + if (! d_check_char (di, 'I')) + return NULL; + + al = NULL; + pal = &al; + while (1) + { + struct demangle_component *a; + + a = d_template_arg (di); + if (a == NULL) + return NULL; + + *pal = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, a, NULL); + if (*pal == NULL) + return NULL; + pal = &d_right (*pal); + + if (d_peek_char (di) == 'E') + { + d_advance (di, 1); + break; + } + } + + di->last_name = hold_last_name; + + return al; +} + +/* ::= + ::= X E + ::= +*/ + +static struct demangle_component * +d_template_arg (struct d_info *di) +{ + struct demangle_component *ret; + + switch (d_peek_char (di)) + { + case 'X': + d_advance (di, 1); + ret = d_expression (di); + if (! d_check_char (di, 'E')) + return NULL; + return ret; + + case 'L': + return d_expr_primary (di); + + default: + return cplus_demangle_type (di); + } +} + +/* ::= <(unary) operator-name> + ::= <(binary) operator-name> + ::= <(trinary) operator-name> + ::= st + ::= + ::= sr + ::= sr + ::= +*/ + +static struct demangle_component * +d_expression (struct d_info *di) +{ + char peek; + + peek = d_peek_char (di); + if (peek == 'L') + return d_expr_primary (di); + else if (peek == 'T') + return d_template_param (di); + else if (peek == 's' && d_peek_next_char (di) == 'r') + { + struct demangle_component *type; + struct demangle_component *name; + + d_advance (di, 2); + type = cplus_demangle_type (di); + name = d_unqualified_name (di); + if (d_peek_char (di) != 'I') + return d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, type, name); + else + return d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, type, + d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, name, + d_template_args (di))); + } + else + { + struct demangle_component *op; + int args; + + op = d_operator_name (di); + if (op == NULL) + return NULL; + + if (op->type == DEMANGLE_COMPONENT_OPERATOR) + di->expansion += op->u.s_operator.op->len - 2; + + if (op->type == DEMANGLE_COMPONENT_OPERATOR + && strcmp (op->u.s_operator.op->code, "st") == 0) + return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op, + cplus_demangle_type (di)); + + switch (op->type) + { + default: + return NULL; + case DEMANGLE_COMPONENT_OPERATOR: + args = op->u.s_operator.op->args; + break; + case DEMANGLE_COMPONENT_EXTENDED_OPERATOR: + args = op->u.s_extended_operator.args; + break; + case DEMANGLE_COMPONENT_CAST: + args = 1; + break; + } + + switch (args) + { + case 1: + return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op, + d_expression (di)); + case 2: + { + struct demangle_component *left; + + left = d_expression (di); + return d_make_comp (di, DEMANGLE_COMPONENT_BINARY, op, + d_make_comp (di, + DEMANGLE_COMPONENT_BINARY_ARGS, + left, + d_expression (di))); + } + case 3: + { + struct demangle_component *first; + struct demangle_component *second; + + first = d_expression (di); + second = d_expression (di); + return d_make_comp (di, DEMANGLE_COMPONENT_TRINARY, op, + d_make_comp (di, + DEMANGLE_COMPONENT_TRINARY_ARG1, + first, + d_make_comp (di, + DEMANGLE_COMPONENT_TRINARY_ARG2, + second, + d_expression (di)))); + } + default: + return NULL; + } + } +} + +/* ::= L <(value) number> E + ::= L <(value) float> E + ::= L E +*/ + +static struct demangle_component * +d_expr_primary (struct d_info *di) +{ + struct demangle_component *ret; + + if (! d_check_char (di, 'L')) + return NULL; + if (d_peek_char (di) == '_') + ret = cplus_demangle_mangled_name (di, 0); + else + { + struct demangle_component *type; + enum demangle_component_type t; + const char *s; + + type = cplus_demangle_type (di); + if (type == NULL) + return NULL; + + /* If we have a type we know how to print, we aren't going to + print the type name itself. */ + if (type->type == DEMANGLE_COMPONENT_BUILTIN_TYPE + && type->u.s_builtin.type->print != D_PRINT_DEFAULT) + di->expansion -= type->u.s_builtin.type->len; + + /* Rather than try to interpret the literal value, we just + collect it as a string. Note that it's possible to have a + floating point literal here. The ABI specifies that the + format of such literals is machine independent. That's fine, + but what's not fine is that versions of g++ up to 3.2 with + -fabi-version=1 used upper case letters in the hex constant, + and dumped out gcc's internal representation. That makes it + hard to tell where the constant ends, and hard to dump the + constant in any readable form anyhow. We don't attempt to + handle these cases. */ + + t = DEMANGLE_COMPONENT_LITERAL; + if (d_peek_char (di) == 'n') + { + t = DEMANGLE_COMPONENT_LITERAL_NEG; + d_advance (di, 1); + } + s = d_str (di); + while (d_peek_char (di) != 'E') + { + if (d_peek_char (di) == '\0') + return NULL; + d_advance (di, 1); + } + ret = d_make_comp (di, t, type, d_make_name (di, s, d_str (di) - s)); + } + if (! d_check_char (di, 'E')) + return NULL; + return ret; +} + +/* ::= Z <(function) encoding> E <(entity) name> [] + ::= Z <(function) encoding> E s [] +*/ + +static struct demangle_component * +d_local_name (struct d_info *di) +{ + struct demangle_component *function; + + if (! d_check_char (di, 'Z')) + return NULL; + + function = d_encoding (di, 0); + + if (! d_check_char (di, 'E')) + return NULL; + + if (d_peek_char (di) == 's') + { + d_advance (di, 1); + if (! d_discriminator (di)) + return NULL; + return d_make_comp (di, DEMANGLE_COMPONENT_LOCAL_NAME, function, + d_make_name (di, "string literal", + sizeof "string literal" - 1)); + } + else + { + struct demangle_component *name; + + name = d_name (di); + if (! d_discriminator (di)) + return NULL; + return d_make_comp (di, DEMANGLE_COMPONENT_LOCAL_NAME, function, name); + } +} + +/* ::= _ <(non-negative) number> + + We demangle the discriminator, but we don't print it out. FIXME: + We should print it out in verbose mode. */ + +static int +d_discriminator (struct d_info *di) +{ + long discrim; + + if (d_peek_char (di) != '_') + return 1; + d_advance (di, 1); + discrim = d_number (di); + if (discrim < 0) + return 0; + return 1; +} + +/* Add a new substitution. */ + +static int +d_add_substitution (struct d_info *di, struct demangle_component *dc) +{ + if (dc == NULL) + return 0; + if (di->next_sub >= di->num_subs) + return 0; + di->subs[di->next_sub] = dc; + ++di->next_sub; + return 1; +} + +/* ::= S _ + ::= S_ + ::= St + ::= Sa + ::= Sb + ::= Ss + ::= Si + ::= So + ::= Sd + + If PREFIX is non-zero, then this type is being used as a prefix in + a qualified name. In this case, for the standard substitutions, we + need to check whether we are being used as a prefix for a + constructor or destructor, and return a full template name. + Otherwise we will get something like std::iostream::~iostream() + which does not correspond particularly well to any function which + actually appears in the source. +*/ + +static const struct d_standard_sub_info standard_subs[] = +{ + { 't', NL ("std"), + NL ("std"), + NULL, 0 }, + { 'a', NL ("std::allocator"), + NL ("std::allocator"), + NL ("allocator") }, + { 'b', NL ("std::basic_string"), + NL ("std::basic_string"), + NL ("basic_string") }, + { 's', NL ("std::string"), + NL ("std::basic_string, std::allocator >"), + NL ("basic_string") }, + { 'i', NL ("std::istream"), + NL ("std::basic_istream >"), + NL ("basic_istream") }, + { 'o', NL ("std::ostream"), + NL ("std::basic_ostream >"), + NL ("basic_ostream") }, + { 'd', NL ("std::iostream"), + NL ("std::basic_iostream >"), + NL ("basic_iostream") } +}; + +static struct demangle_component * +d_substitution (struct d_info *di, int prefix) +{ + char c; + + if (! d_check_char (di, 'S')) + return NULL; + + c = d_next_char (di); + if (c == '_' || IS_DIGIT (c) || IS_UPPER (c)) + { + int id; + + id = 0; + if (c != '_') + { + do + { + if (IS_DIGIT (c)) + id = id * 36 + c - '0'; + else if (IS_UPPER (c)) + id = id * 36 + c - 'A' + 10; + else + return NULL; + if (id < 0) + return NULL; + c = d_next_char (di); + } + while (c != '_'); + + ++id; + } + + if (id >= di->next_sub) + return NULL; + + ++di->did_subs; + + return di->subs[id]; + } + else + { + int verbose; + const struct d_standard_sub_info *p; + const struct d_standard_sub_info *pend; + + verbose = (di->options & DMGL_VERBOSE) != 0; + if (! verbose && prefix) + { + char peek; + + peek = d_peek_char (di); + if (peek == 'C' || peek == 'D') + verbose = 1; + } + + pend = (&standard_subs[0] + + sizeof standard_subs / sizeof standard_subs[0]); + for (p = &standard_subs[0]; p < pend; ++p) + { + if (c == p->code) + { + const char *s; + int len; + + if (p->set_last_name != NULL) + di->last_name = d_make_sub (di, p->set_last_name, + p->set_last_name_len); + if (verbose) + { + s = p->full_expansion; + len = p->full_len; + } + else + { + s = p->simple_expansion; + len = p->simple_len; + } + di->expansion += len; + return d_make_sub (di, s, len); + } + } + + return NULL; + } +} + +/* Initialize a growable string. */ + +static void +d_growable_string_init (struct d_growable_string *dgs, size_t estimate) +{ + dgs->buf = NULL; + dgs->len = 0; + dgs->alc = 0; + dgs->allocation_failure = 0; + + if (estimate > 0) + d_growable_string_resize (dgs, estimate); +} + +/* Grow a growable string to a given size. */ + +static inline void +d_growable_string_resize (struct d_growable_string *dgs, size_t need) +{ + size_t newalc; + char *newbuf; + + if (dgs->allocation_failure) + return; + + /* Start allocation at two bytes to avoid any possibility of confusion + with the special value of 1 used as a return in *palc to indicate + allocation failures. */ + newalc = dgs->alc > 0 ? dgs->alc : 2; + while (newalc < need) + newalc <<= 1; + + newbuf = (char *) realloc (dgs->buf, newalc); + if (newbuf == NULL) + { + free (dgs->buf); + dgs->buf = NULL; + dgs->len = 0; + dgs->alc = 0; + dgs->allocation_failure = 1; + return; + } + dgs->buf = newbuf; + dgs->alc = newalc; +} + +/* Append a buffer to a growable string. */ + +static inline void +d_growable_string_append_buffer (struct d_growable_string *dgs, + const char *s, size_t l) +{ + size_t need; + + need = dgs->len + l + 1; + if (need > dgs->alc) + d_growable_string_resize (dgs, need); + + if (dgs->allocation_failure) + return; + + memcpy (dgs->buf + dgs->len, s, l); + dgs->buf[dgs->len + l] = '\0'; + dgs->len += l; +} + +/* Bridge growable strings to the callback mechanism. */ + +static void +d_growable_string_callback_adapter (const char *s, size_t l, void *opaque) +{ + struct d_growable_string *dgs = (struct d_growable_string*) opaque; + + d_growable_string_append_buffer (dgs, s, l); +} + +/* Initialize a print information structure. */ + +static void +d_print_init (struct d_print_info *dpi, int options, + demangle_callbackref callback, void *opaque) +{ + dpi->options = options; + dpi->len = 0; + dpi->last_char = '\0'; + dpi->templates = NULL; + dpi->modifiers = NULL; + + dpi->callback = callback; + dpi->opaque = opaque; + + dpi->demangle_failure = 0; +} + +/* Indicate that an error occurred during printing, and test for error. */ + +static inline void +d_print_error (struct d_print_info *dpi) +{ + dpi->demangle_failure = 1; +} + +static inline int +d_print_saw_error (struct d_print_info *dpi) +{ + return dpi->demangle_failure != 0; +} + +/* Flush buffered characters to the callback. */ + +static inline void +d_print_flush (struct d_print_info *dpi) +{ + dpi->buf[dpi->len] = '\0'; + dpi->callback (dpi->buf, dpi->len, dpi->opaque); + dpi->len = 0; +} + +/* Append characters and buffers for printing. */ + +static inline void +d_append_char (struct d_print_info *dpi, char c) +{ + if (dpi->len == sizeof (dpi->buf) - 1) + d_print_flush (dpi); + + dpi->buf[dpi->len++] = c; + dpi->last_char = c; +} + +static inline void +d_append_buffer (struct d_print_info *dpi, const char *s, size_t l) +{ + size_t i; + + for (i = 0; i < l; i++) + d_append_char (dpi, s[i]); +} + +static inline void +d_append_string (struct d_print_info *dpi, const char *s) +{ + d_append_buffer (dpi, s, strlen (s)); +} + +static inline char +d_last_char (struct d_print_info *dpi) +{ + return dpi->last_char; +} + +/* Turn components into a human readable string. OPTIONS is the + options bits passed to the demangler. DC is the tree to print. + CALLBACK is a function to call to flush demangled string segments + as they fill the intermediate buffer, and OPAQUE is a generalized + callback argument. On success, this returns 1. On failure, + it returns 0, indicating a bad parse. It does not use heap + memory to build an output string, so cannot encounter memory + allocation failure. */ + +CP_STATIC_IF_GLIBCPP_V3 +int +cplus_demangle_print_callback (int options, + const struct demangle_component *dc, + demangle_callbackref callback, void *opaque) +{ + struct d_print_info dpi; + + d_print_init (&dpi, options, callback, opaque); + + d_print_comp (&dpi, dc); + + d_print_flush (&dpi); + + return ! d_print_saw_error (&dpi); +} + +/* Turn components into a human readable string. OPTIONS is the + options bits passed to the demangler. DC is the tree to print. + ESTIMATE is a guess at the length of the result. This returns a + string allocated by malloc, or NULL on error. On success, this + sets *PALC to the size of the allocated buffer. On failure, this + sets *PALC to 0 for a bad parse, or to 1 for a memory allocation + failure. */ + +CP_STATIC_IF_GLIBCPP_V3 +char * +cplus_demangle_print (int options, const struct demangle_component *dc, + int estimate, size_t *palc) +{ + struct d_growable_string dgs; + + d_growable_string_init (&dgs, estimate); + + if (! cplus_demangle_print_callback (options, dc, + d_growable_string_callback_adapter, + &dgs)) + { + free (dgs.buf); + *palc = 0; + return NULL; + } + + *palc = dgs.allocation_failure ? 1 : dgs.alc; + return dgs.buf; +} + +/* Subroutine to handle components. */ + +static void +d_print_comp (struct d_print_info *dpi, + const struct demangle_component *dc) +{ + if (dc == NULL) + { + d_print_error (dpi); + return; + } + if (d_print_saw_error (dpi)) + return; + + switch (dc->type) + { + case DEMANGLE_COMPONENT_NAME: + if ((dpi->options & DMGL_JAVA) == 0) + d_append_buffer (dpi, dc->u.s_name.s, dc->u.s_name.len); + else + d_print_java_identifier (dpi, dc->u.s_name.s, dc->u.s_name.len); + return; + + case DEMANGLE_COMPONENT_QUAL_NAME: + case DEMANGLE_COMPONENT_LOCAL_NAME: + d_print_comp (dpi, d_left (dc)); + if ((dpi->options & DMGL_JAVA) == 0) + d_append_string (dpi, "::"); + else + d_append_char (dpi, '.'); + d_print_comp (dpi, d_right (dc)); + return; + + case DEMANGLE_COMPONENT_TYPED_NAME: + { + struct d_print_mod *hold_modifiers; + struct demangle_component *typed_name; + struct d_print_mod adpm[4]; + unsigned int i; + struct d_print_template dpt; + + /* Pass the name down to the type so that it can be printed in + the right place for the type. We also have to pass down + any CV-qualifiers, which apply to the this parameter. */ + hold_modifiers = dpi->modifiers; + i = 0; + typed_name = d_left (dc); + while (typed_name != NULL) + { + if (i >= sizeof adpm / sizeof adpm[0]) + { + d_print_error (dpi); + return; + } + + adpm[i].next = dpi->modifiers; + dpi->modifiers = &adpm[i]; + adpm[i].mod = typed_name; + adpm[i].printed = 0; + adpm[i].templates = dpi->templates; + ++i; + + if (typed_name->type != DEMANGLE_COMPONENT_RESTRICT_THIS + && typed_name->type != DEMANGLE_COMPONENT_VOLATILE_THIS + && typed_name->type != DEMANGLE_COMPONENT_CONST_THIS) + break; + + typed_name = d_left (typed_name); + } + + if (typed_name == NULL) + { + d_print_error (dpi); + return; + } + + /* If typed_name is a template, then it applies to the + function type as well. */ + if (typed_name->type == DEMANGLE_COMPONENT_TEMPLATE) + { + dpt.next = dpi->templates; + dpi->templates = &dpt; + dpt.template_decl = typed_name; + } + + /* If typed_name is a DEMANGLE_COMPONENT_LOCAL_NAME, then + there may be CV-qualifiers on its right argument which + really apply here; this happens when parsing a class which + is local to a function. */ + if (typed_name->type == DEMANGLE_COMPONENT_LOCAL_NAME) + { + struct demangle_component *local_name; + + local_name = d_right (typed_name); + while (local_name->type == DEMANGLE_COMPONENT_RESTRICT_THIS + || local_name->type == DEMANGLE_COMPONENT_VOLATILE_THIS + || local_name->type == DEMANGLE_COMPONENT_CONST_THIS) + { + if (i >= sizeof adpm / sizeof adpm[0]) + { + d_print_error (dpi); + return; + } + + adpm[i] = adpm[i - 1]; + adpm[i].next = &adpm[i - 1]; + dpi->modifiers = &adpm[i]; + + adpm[i - 1].mod = local_name; + adpm[i - 1].printed = 0; + adpm[i - 1].templates = dpi->templates; + ++i; + + local_name = d_left (local_name); + } + } + + d_print_comp (dpi, d_right (dc)); + + if (typed_name->type == DEMANGLE_COMPONENT_TEMPLATE) + dpi->templates = dpt.next; + + /* If the modifiers didn't get printed by the type, print them + now. */ + while (i > 0) + { + --i; + if (! adpm[i].printed) + { + d_append_char (dpi, ' '); + d_print_mod (dpi, adpm[i].mod); + } + } + + dpi->modifiers = hold_modifiers; + + return; + } + + case DEMANGLE_COMPONENT_TEMPLATE: + { + struct d_print_mod *hold_dpm; + struct demangle_component *dcl; + + /* Don't push modifiers into a template definition. Doing so + could give the wrong definition for a template argument. + Instead, treat the template essentially as a name. */ + + hold_dpm = dpi->modifiers; + dpi->modifiers = NULL; + + dcl = d_left (dc); + + if ((dpi->options & DMGL_JAVA) != 0 + && dcl->type == DEMANGLE_COMPONENT_NAME + && dcl->u.s_name.len == 6 + && strncmp (dcl->u.s_name.s, "JArray", 6) == 0) + { + /* Special-case Java arrays, so that JArray appears + instead as TYPE[]. */ + + d_print_comp (dpi, d_right (dc)); + d_append_string (dpi, "[]"); + } + else + { + d_print_comp (dpi, dcl); + if (d_last_char (dpi) == '<') + d_append_char (dpi, ' '); + d_append_char (dpi, '<'); + d_print_comp (dpi, d_right (dc)); + /* Avoid generating two consecutive '>' characters, to avoid + the C++ syntactic ambiguity. */ + if (d_last_char (dpi) == '>') + d_append_char (dpi, ' '); + d_append_char (dpi, '>'); + } + + dpi->modifiers = hold_dpm; + + return; + } + + case DEMANGLE_COMPONENT_TEMPLATE_PARAM: + { + long i; + struct demangle_component *a; + struct d_print_template *hold_dpt; + + if (dpi->templates == NULL) + { + d_print_error (dpi); + return; + } + i = dc->u.s_number.number; + for (a = d_right (dpi->templates->template_decl); + a != NULL; + a = d_right (a)) + { + if (a->type != DEMANGLE_COMPONENT_TEMPLATE_ARGLIST) + { + d_print_error (dpi); + return; + } + if (i <= 0) + break; + --i; + } + if (i != 0 || a == NULL) + { + d_print_error (dpi); + return; + } + + /* While processing this parameter, we need to pop the list of + templates. This is because the template parameter may + itself be a reference to a parameter of an outer + template. */ + + hold_dpt = dpi->templates; + dpi->templates = hold_dpt->next; + + d_print_comp (dpi, d_left (a)); + + dpi->templates = hold_dpt; + + return; + } + + case DEMANGLE_COMPONENT_CTOR: + d_print_comp (dpi, dc->u.s_ctor.name); + return; + + case DEMANGLE_COMPONENT_DTOR: + d_append_char (dpi, '~'); + d_print_comp (dpi, dc->u.s_dtor.name); + return; + + case DEMANGLE_COMPONENT_VTABLE: + d_append_string (dpi, "vtable for "); + d_print_comp (dpi, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_VTT: + d_append_string (dpi, "VTT for "); + d_print_comp (dpi, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE: + d_append_string (dpi, "construction vtable for "); + d_print_comp (dpi, d_left (dc)); + d_append_string (dpi, "-in-"); + d_print_comp (dpi, d_right (dc)); + return; + + case DEMANGLE_COMPONENT_TYPEINFO: + d_append_string (dpi, "typeinfo for "); + d_print_comp (dpi, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_TYPEINFO_NAME: + d_append_string (dpi, "typeinfo name for "); + d_print_comp (dpi, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_TYPEINFO_FN: + d_append_string (dpi, "typeinfo fn for "); + d_print_comp (dpi, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_THUNK: + d_append_string (dpi, "non-virtual thunk to "); + d_print_comp (dpi, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_VIRTUAL_THUNK: + d_append_string (dpi, "virtual thunk to "); + d_print_comp (dpi, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_COVARIANT_THUNK: + d_append_string (dpi, "covariant return thunk to "); + d_print_comp (dpi, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_JAVA_CLASS: + d_append_string (dpi, "java Class for "); + d_print_comp (dpi, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_GUARD: + d_append_string (dpi, "guard variable for "); + d_print_comp (dpi, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_REFTEMP: + d_append_string (dpi, "reference temporary for "); + d_print_comp (dpi, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_HIDDEN_ALIAS: + d_append_string (dpi, "hidden alias for "); + d_print_comp (dpi, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_SUB_STD: + d_append_buffer (dpi, dc->u.s_string.string, dc->u.s_string.len); + return; + + case DEMANGLE_COMPONENT_RESTRICT: + case DEMANGLE_COMPONENT_VOLATILE: + case DEMANGLE_COMPONENT_CONST: + { + struct d_print_mod *pdpm; + + /* When printing arrays, it's possible to have cases where the + same CV-qualifier gets pushed on the stack multiple times. + We only need to print it once. */ + + for (pdpm = dpi->modifiers; pdpm != NULL; pdpm = pdpm->next) + { + if (! pdpm->printed) + { + if (pdpm->mod->type != DEMANGLE_COMPONENT_RESTRICT + && pdpm->mod->type != DEMANGLE_COMPONENT_VOLATILE + && pdpm->mod->type != DEMANGLE_COMPONENT_CONST) + break; + if (pdpm->mod->type == dc->type) + { + d_print_comp (dpi, d_left (dc)); + return; + } + } + } + } + /* Fall through. */ + case DEMANGLE_COMPONENT_RESTRICT_THIS: + case DEMANGLE_COMPONENT_VOLATILE_THIS: + case DEMANGLE_COMPONENT_CONST_THIS: + case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: + case DEMANGLE_COMPONENT_POINTER: + case DEMANGLE_COMPONENT_REFERENCE: + case DEMANGLE_COMPONENT_RVALUE_REFERENCE: + case DEMANGLE_COMPONENT_COMPLEX: + case DEMANGLE_COMPONENT_IMAGINARY: + { + /* We keep a list of modifiers on the stack. */ + struct d_print_mod dpm; + + dpm.next = dpi->modifiers; + dpi->modifiers = &dpm; + dpm.mod = dc; + dpm.printed = 0; + dpm.templates = dpi->templates; + + d_print_comp (dpi, d_left (dc)); + + /* If the modifier didn't get printed by the type, print it + now. */ + if (! dpm.printed) + d_print_mod (dpi, dc); + + dpi->modifiers = dpm.next; + + return; + } + + case DEMANGLE_COMPONENT_BUILTIN_TYPE: + if ((dpi->options & DMGL_JAVA) == 0) + d_append_buffer (dpi, dc->u.s_builtin.type->name, + dc->u.s_builtin.type->len); + else + d_append_buffer (dpi, dc->u.s_builtin.type->java_name, + dc->u.s_builtin.type->java_len); + return; + + case DEMANGLE_COMPONENT_VENDOR_TYPE: + d_print_comp (dpi, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_FUNCTION_TYPE: + { + if ((dpi->options & DMGL_RET_POSTFIX) != 0) + d_print_function_type (dpi, dc, dpi->modifiers); + + /* Print return type if present */ + if (d_left (dc) != NULL) + { + struct d_print_mod dpm; + + /* We must pass this type down as a modifier in order to + print it in the right location. */ + dpm.next = dpi->modifiers; + dpi->modifiers = &dpm; + dpm.mod = dc; + dpm.printed = 0; + dpm.templates = dpi->templates; + + d_print_comp (dpi, d_left (dc)); + + dpi->modifiers = dpm.next; + + if (dpm.printed) + return; + + /* In standard prefix notation, there is a space between the + return type and the function signature. */ + if ((dpi->options & DMGL_RET_POSTFIX) == 0) + d_append_char (dpi, ' '); + } + + if ((dpi->options & DMGL_RET_POSTFIX) == 0) + d_print_function_type (dpi, dc, dpi->modifiers); + + return; + } + + case DEMANGLE_COMPONENT_ARRAY_TYPE: + { + struct d_print_mod *hold_modifiers; + struct d_print_mod adpm[4]; + unsigned int i; + struct d_print_mod *pdpm; + + /* We must pass this type down as a modifier in order to print + multi-dimensional arrays correctly. If the array itself is + CV-qualified, we act as though the element type were + CV-qualified. We do this by copying the modifiers down + rather than fiddling pointers, so that we don't wind up + with a d_print_mod higher on the stack pointing into our + stack frame after we return. */ + + hold_modifiers = dpi->modifiers; + + adpm[0].next = hold_modifiers; + dpi->modifiers = &adpm[0]; + adpm[0].mod = dc; + adpm[0].printed = 0; + adpm[0].templates = dpi->templates; + + i = 1; + pdpm = hold_modifiers; + while (pdpm != NULL + && (pdpm->mod->type == DEMANGLE_COMPONENT_RESTRICT + || pdpm->mod->type == DEMANGLE_COMPONENT_VOLATILE + || pdpm->mod->type == DEMANGLE_COMPONENT_CONST)) + { + if (! pdpm->printed) + { + if (i >= sizeof adpm / sizeof adpm[0]) + { + d_print_error (dpi); + return; + } + + adpm[i] = *pdpm; + adpm[i].next = dpi->modifiers; + dpi->modifiers = &adpm[i]; + pdpm->printed = 1; + ++i; + } + + pdpm = pdpm->next; + } + + d_print_comp (dpi, d_right (dc)); + + dpi->modifiers = hold_modifiers; + + if (adpm[0].printed) + return; + + while (i > 1) + { + --i; + d_print_mod (dpi, adpm[i].mod); + } + + d_print_array_type (dpi, dc, dpi->modifiers); + + return; + } + + case DEMANGLE_COMPONENT_PTRMEM_TYPE: + { + struct d_print_mod dpm; + + dpm.next = dpi->modifiers; + dpi->modifiers = &dpm; + dpm.mod = dc; + dpm.printed = 0; + dpm.templates = dpi->templates; + + d_print_comp (dpi, d_right (dc)); + + /* If the modifier didn't get printed by the type, print it + now. */ + if (! dpm.printed) + { + d_append_char (dpi, ' '); + d_print_comp (dpi, d_left (dc)); + d_append_string (dpi, "::*"); + } + + dpi->modifiers = dpm.next; + + return; + } + + case DEMANGLE_COMPONENT_ARGLIST: + case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST: + d_print_comp (dpi, d_left (dc)); + if (d_right (dc) != NULL) + { + d_append_string (dpi, ", "); + d_print_comp (dpi, d_right (dc)); + } + return; + + case DEMANGLE_COMPONENT_OPERATOR: + { + char c; + + d_append_string (dpi, "operator"); + c = dc->u.s_operator.op->name[0]; + if (IS_LOWER (c)) + d_append_char (dpi, ' '); + d_append_buffer (dpi, dc->u.s_operator.op->name, + dc->u.s_operator.op->len); + return; + } + + case DEMANGLE_COMPONENT_EXTENDED_OPERATOR: + d_append_string (dpi, "operator "); + d_print_comp (dpi, dc->u.s_extended_operator.name); + return; + + case DEMANGLE_COMPONENT_CAST: + d_append_string (dpi, "operator "); + d_print_cast (dpi, dc); + return; + + case DEMANGLE_COMPONENT_UNARY: + if (d_left (dc)->type != DEMANGLE_COMPONENT_CAST) + d_print_expr_op (dpi, d_left (dc)); + else + { + d_append_char (dpi, '('); + d_print_cast (dpi, d_left (dc)); + d_append_char (dpi, ')'); + } + d_append_char (dpi, '('); + d_print_comp (dpi, d_right (dc)); + d_append_char (dpi, ')'); + return; + + case DEMANGLE_COMPONENT_BINARY: + if (d_right (dc)->type != DEMANGLE_COMPONENT_BINARY_ARGS) + { + d_print_error (dpi); + return; + } + + /* We wrap an expression which uses the greater-than operator in + an extra layer of parens so that it does not get confused + with the '>' which ends the template parameters. */ + if (d_left (dc)->type == DEMANGLE_COMPONENT_OPERATOR + && d_left (dc)->u.s_operator.op->len == 1 + && d_left (dc)->u.s_operator.op->name[0] == '>') + d_append_char (dpi, '('); + + d_append_char (dpi, '('); + d_print_comp (dpi, d_left (d_right (dc))); + d_append_string (dpi, ") "); + d_print_expr_op (dpi, d_left (dc)); + d_append_string (dpi, " ("); + d_print_comp (dpi, d_right (d_right (dc))); + d_append_char (dpi, ')'); + + if (d_left (dc)->type == DEMANGLE_COMPONENT_OPERATOR + && d_left (dc)->u.s_operator.op->len == 1 + && d_left (dc)->u.s_operator.op->name[0] == '>') + d_append_char (dpi, ')'); + + return; + + case DEMANGLE_COMPONENT_BINARY_ARGS: + /* We should only see this as part of DEMANGLE_COMPONENT_BINARY. */ + d_print_error (dpi); + return; + + case DEMANGLE_COMPONENT_TRINARY: + if (d_right (dc)->type != DEMANGLE_COMPONENT_TRINARY_ARG1 + || d_right (d_right (dc))->type != DEMANGLE_COMPONENT_TRINARY_ARG2) + { + d_print_error (dpi); + return; + } + d_append_char (dpi, '('); + d_print_comp (dpi, d_left (d_right (dc))); + d_append_string (dpi, ") "); + d_print_expr_op (dpi, d_left (dc)); + d_append_string (dpi, " ("); + d_print_comp (dpi, d_left (d_right (d_right (dc)))); + d_append_string (dpi, ") : ("); + d_print_comp (dpi, d_right (d_right (d_right (dc)))); + d_append_char (dpi, ')'); + return; + + case DEMANGLE_COMPONENT_TRINARY_ARG1: + case DEMANGLE_COMPONENT_TRINARY_ARG2: + /* We should only see these are part of DEMANGLE_COMPONENT_TRINARY. */ + d_print_error (dpi); + return; + + case DEMANGLE_COMPONENT_LITERAL: + case DEMANGLE_COMPONENT_LITERAL_NEG: + { + enum d_builtin_type_print tp; + + /* For some builtin types, produce simpler output. */ + tp = D_PRINT_DEFAULT; + if (d_left (dc)->type == DEMANGLE_COMPONENT_BUILTIN_TYPE) + { + tp = d_left (dc)->u.s_builtin.type->print; + switch (tp) + { + case D_PRINT_INT: + case D_PRINT_UNSIGNED: + case D_PRINT_LONG: + case D_PRINT_UNSIGNED_LONG: + case D_PRINT_LONG_LONG: + case D_PRINT_UNSIGNED_LONG_LONG: + if (d_right (dc)->type == DEMANGLE_COMPONENT_NAME) + { + if (dc->type == DEMANGLE_COMPONENT_LITERAL_NEG) + d_append_char (dpi, '-'); + d_print_comp (dpi, d_right (dc)); + switch (tp) + { + default: + break; + case D_PRINT_UNSIGNED: + d_append_char (dpi, 'u'); + break; + case D_PRINT_LONG: + d_append_char (dpi, 'l'); + break; + case D_PRINT_UNSIGNED_LONG: + d_append_string (dpi, "ul"); + break; + case D_PRINT_LONG_LONG: + d_append_string (dpi, "ll"); + break; + case D_PRINT_UNSIGNED_LONG_LONG: + d_append_string (dpi, "ull"); + break; + } + return; + } + break; + + case D_PRINT_BOOL: + if (d_right (dc)->type == DEMANGLE_COMPONENT_NAME + && d_right (dc)->u.s_name.len == 1 + && dc->type == DEMANGLE_COMPONENT_LITERAL) + { + switch (d_right (dc)->u.s_name.s[0]) + { + case '0': + d_append_string (dpi, "false"); + return; + case '1': + d_append_string (dpi, "true"); + return; + default: + break; + } + } + break; + + default: + break; + } + } + + d_append_char (dpi, '('); + d_print_comp (dpi, d_left (dc)); + d_append_char (dpi, ')'); + if (dc->type == DEMANGLE_COMPONENT_LITERAL_NEG) + d_append_char (dpi, '-'); + if (tp == D_PRINT_FLOAT) + d_append_char (dpi, '['); + d_print_comp (dpi, d_right (dc)); + if (tp == D_PRINT_FLOAT) + d_append_char (dpi, ']'); + } + return; + + default: + d_print_error (dpi); + return; + } +} + +/* Print a Java dentifier. For Java we try to handle encoded extended + Unicode characters. The C++ ABI doesn't mention Unicode encoding, + so we don't it for C++. Characters are encoded as + __U+_. */ + +static void +d_print_java_identifier (struct d_print_info *dpi, const char *name, int len) +{ + const char *p; + const char *end; + + end = name + len; + for (p = name; p < end; ++p) + { + if (end - p > 3 + && p[0] == '_' + && p[1] == '_' + && p[2] == 'U') + { + unsigned long c; + const char *q; + + c = 0; + for (q = p + 3; q < end; ++q) + { + int dig; + + if (IS_DIGIT (*q)) + dig = *q - '0'; + else if (*q >= 'A' && *q <= 'F') + dig = *q - 'A' + 10; + else if (*q >= 'a' && *q <= 'f') + dig = *q - 'a' + 10; + else + break; + + c = c * 16 + dig; + } + /* If the Unicode character is larger than 256, we don't try + to deal with it here. FIXME. */ + if (q < end && *q == '_' && c < 256) + { + d_append_char (dpi, c); + p = q; + continue; + } + } + + d_append_char (dpi, *p); + } +} + +/* Print a list of modifiers. SUFFIX is 1 if we are printing + qualifiers on this after printing a function. */ + +static void +d_print_mod_list (struct d_print_info *dpi, + struct d_print_mod *mods, int suffix) +{ + struct d_print_template *hold_dpt; + + if (mods == NULL || d_print_saw_error (dpi)) + return; + + if (mods->printed + || (! suffix + && (mods->mod->type == DEMANGLE_COMPONENT_RESTRICT_THIS + || mods->mod->type == DEMANGLE_COMPONENT_VOLATILE_THIS + || mods->mod->type == DEMANGLE_COMPONENT_CONST_THIS))) + { + d_print_mod_list (dpi, mods->next, suffix); + return; + } + + mods->printed = 1; + + hold_dpt = dpi->templates; + dpi->templates = mods->templates; + + if (mods->mod->type == DEMANGLE_COMPONENT_FUNCTION_TYPE) + { + d_print_function_type (dpi, mods->mod, mods->next); + dpi->templates = hold_dpt; + return; + } + else if (mods->mod->type == DEMANGLE_COMPONENT_ARRAY_TYPE) + { + d_print_array_type (dpi, mods->mod, mods->next); + dpi->templates = hold_dpt; + return; + } + else if (mods->mod->type == DEMANGLE_COMPONENT_LOCAL_NAME) + { + struct d_print_mod *hold_modifiers; + struct demangle_component *dc; + + /* When this is on the modifier stack, we have pulled any + qualifiers off the right argument already. Otherwise, we + print it as usual, but don't let the left argument see any + modifiers. */ + + hold_modifiers = dpi->modifiers; + dpi->modifiers = NULL; + d_print_comp (dpi, d_left (mods->mod)); + dpi->modifiers = hold_modifiers; + + if ((dpi->options & DMGL_JAVA) == 0) + d_append_string (dpi, "::"); + else + d_append_char (dpi, '.'); + + dc = d_right (mods->mod); + while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS + || dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS + || dc->type == DEMANGLE_COMPONENT_CONST_THIS) + dc = d_left (dc); + + d_print_comp (dpi, dc); + + dpi->templates = hold_dpt; + return; + } + + d_print_mod (dpi, mods->mod); + + dpi->templates = hold_dpt; + + d_print_mod_list (dpi, mods->next, suffix); +} + +/* Print a modifier. */ + +static void +d_print_mod (struct d_print_info *dpi, + const struct demangle_component *mod) +{ + switch (mod->type) + { + case DEMANGLE_COMPONENT_RESTRICT: + case DEMANGLE_COMPONENT_RESTRICT_THIS: + d_append_string (dpi, " restrict"); + return; + case DEMANGLE_COMPONENT_VOLATILE: + case DEMANGLE_COMPONENT_VOLATILE_THIS: + d_append_string (dpi, " volatile"); + return; + case DEMANGLE_COMPONENT_CONST: + case DEMANGLE_COMPONENT_CONST_THIS: + d_append_string (dpi, " const"); + return; + case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: + d_append_char (dpi, ' '); + d_print_comp (dpi, d_right (mod)); + return; + case DEMANGLE_COMPONENT_POINTER: + /* There is no pointer symbol in Java. */ + if ((dpi->options & DMGL_JAVA) == 0) + d_append_char (dpi, '*'); + return; + case DEMANGLE_COMPONENT_REFERENCE: + d_append_char (dpi, '&'); + return; + case DEMANGLE_COMPONENT_RVALUE_REFERENCE: + d_append_string (dpi, "&&"); + return; + case DEMANGLE_COMPONENT_COMPLEX: + d_append_string (dpi, "complex "); + return; + case DEMANGLE_COMPONENT_IMAGINARY: + d_append_string (dpi, "imaginary "); + return; + case DEMANGLE_COMPONENT_PTRMEM_TYPE: + if (d_last_char (dpi) != '(') + d_append_char (dpi, ' '); + d_print_comp (dpi, d_left (mod)); + d_append_string (dpi, "::*"); + return; + case DEMANGLE_COMPONENT_TYPED_NAME: + d_print_comp (dpi, d_left (mod)); + return; + default: + /* Otherwise, we have something that won't go back on the + modifier stack, so we can just print it. */ + d_print_comp (dpi, mod); + return; + } +} + +/* Print a function type, except for the return type. */ + +static void +d_print_function_type (struct d_print_info *dpi, + const struct demangle_component *dc, + struct d_print_mod *mods) +{ + int need_paren; + int saw_mod; + int need_space; + struct d_print_mod *p; + struct d_print_mod *hold_modifiers; + + need_paren = 0; + saw_mod = 0; + need_space = 0; + for (p = mods; p != NULL; p = p->next) + { + if (p->printed) + break; + + saw_mod = 1; + switch (p->mod->type) + { + case DEMANGLE_COMPONENT_POINTER: + case DEMANGLE_COMPONENT_REFERENCE: + case DEMANGLE_COMPONENT_RVALUE_REFERENCE: + need_paren = 1; + break; + case DEMANGLE_COMPONENT_RESTRICT: + case DEMANGLE_COMPONENT_VOLATILE: + case DEMANGLE_COMPONENT_CONST: + case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: + case DEMANGLE_COMPONENT_COMPLEX: + case DEMANGLE_COMPONENT_IMAGINARY: + case DEMANGLE_COMPONENT_PTRMEM_TYPE: + need_space = 1; + need_paren = 1; + break; + case DEMANGLE_COMPONENT_RESTRICT_THIS: + case DEMANGLE_COMPONENT_VOLATILE_THIS: + case DEMANGLE_COMPONENT_CONST_THIS: + break; + default: + break; + } + if (need_paren) + break; + } + + if (d_left (dc) != NULL && ! saw_mod) + need_paren = 1; + + if (need_paren) + { + if (! need_space) + { + if (d_last_char (dpi) != '(' + && d_last_char (dpi) != '*') + need_space = 1; + } + if (need_space && d_last_char (dpi) != ' ') + d_append_char (dpi, ' '); + d_append_char (dpi, '('); + } + + hold_modifiers = dpi->modifiers; + dpi->modifiers = NULL; + + d_print_mod_list (dpi, mods, 0); + + if (need_paren) + d_append_char (dpi, ')'); + + d_append_char (dpi, '('); + + if (d_right (dc) != NULL) + d_print_comp (dpi, d_right (dc)); + + d_append_char (dpi, ')'); + + d_print_mod_list (dpi, mods, 1); + + dpi->modifiers = hold_modifiers; +} + +/* Print an array type, except for the element type. */ + +static void +d_print_array_type (struct d_print_info *dpi, + const struct demangle_component *dc, + struct d_print_mod *mods) +{ + int need_space; + + need_space = 1; + if (mods != NULL) + { + int need_paren; + struct d_print_mod *p; + + need_paren = 0; + for (p = mods; p != NULL; p = p->next) + { + if (! p->printed) + { + if (p->mod->type == DEMANGLE_COMPONENT_ARRAY_TYPE) + { + need_space = 0; + break; + } + else + { + need_paren = 1; + need_space = 1; + break; + } + } + } + + if (need_paren) + d_append_string (dpi, " ("); + + d_print_mod_list (dpi, mods, 0); + + if (need_paren) + d_append_char (dpi, ')'); + } + + if (need_space) + d_append_char (dpi, ' '); + + d_append_char (dpi, '['); + + if (d_left (dc) != NULL) + d_print_comp (dpi, d_left (dc)); + + d_append_char (dpi, ']'); +} + +/* Print an operator in an expression. */ + +static void +d_print_expr_op (struct d_print_info *dpi, + const struct demangle_component *dc) +{ + if (dc->type == DEMANGLE_COMPONENT_OPERATOR) + d_append_buffer (dpi, dc->u.s_operator.op->name, + dc->u.s_operator.op->len); + else + d_print_comp (dpi, dc); +} + +/* Print a cast. */ + +static void +d_print_cast (struct d_print_info *dpi, + const struct demangle_component *dc) +{ + if (d_left (dc)->type != DEMANGLE_COMPONENT_TEMPLATE) + d_print_comp (dpi, d_left (dc)); + else + { + struct d_print_mod *hold_dpm; + struct d_print_template dpt; + + /* It appears that for a templated cast operator, we need to put + the template parameters in scope for the operator name, but + not for the parameters. The effect is that we need to handle + the template printing here. */ + + hold_dpm = dpi->modifiers; + dpi->modifiers = NULL; + + dpt.next = dpi->templates; + dpi->templates = &dpt; + dpt.template_decl = d_left (dc); + + d_print_comp (dpi, d_left (d_left (dc))); + + dpi->templates = dpt.next; + + if (d_last_char (dpi) == '<') + d_append_char (dpi, ' '); + d_append_char (dpi, '<'); + d_print_comp (dpi, d_right (d_left (dc))); + /* Avoid generating two consecutive '>' characters, to avoid + the C++ syntactic ambiguity. */ + if (d_last_char (dpi) == '>') + d_append_char (dpi, ' '); + d_append_char (dpi, '>'); + + dpi->modifiers = hold_dpm; + } +} + +/* Initialize the information structure we use to pass around + information. */ + +CP_STATIC_IF_GLIBCPP_V3 +void +cplus_demangle_init_info (const char *mangled, int options, size_t len, + struct d_info *di) +{ + di->s = mangled; + di->send = mangled + len; + di->options = options; + + di->n = mangled; + + /* We can not need more components than twice the number of chars in + the mangled string. Most components correspond directly to + chars, but the ARGLIST types are exceptions. */ + di->num_comps = 2 * len; + di->next_comp = 0; + + /* Similarly, we can not need more substitutions than there are + chars in the mangled string. */ + di->num_subs = len; + di->next_sub = 0; + di->did_subs = 0; + + di->last_name = NULL; + + di->expansion = 0; +} + +/* Internal implementation for the demangler. If MANGLED is a g++ v3 ABI + mangled name, return strings in repeated callback giving the demangled + name. OPTIONS is the usual libiberty demangler options. On success, + this returns 1. On failure, returns 0. */ + +static int +d_demangle_callback (const char *mangled, int options, + demangle_callbackref callback, void *opaque) +{ + int type; + struct d_info di; + struct demangle_component *dc; + int status; + + if (mangled[0] == '_' && mangled[1] == 'Z') + type = 0; + else if (strncmp (mangled, "_GLOBAL_", 8) == 0 + && (mangled[8] == '.' || mangled[8] == '_' || mangled[8] == '$') + && (mangled[9] == 'D' || mangled[9] == 'I') + && mangled[10] == '_') + { + const char *intro; + + intro = (mangled[9] == 'I') + ? "global constructors keyed to " + : "global destructors keyed to "; + + callback (intro, strlen (intro), opaque); + callback (mangled + 11, strlen (mangled + 11), opaque); + return 1; + } + else + { + if ((options & DMGL_TYPES) == 0) + return 0; + type = 1; + } + + cplus_demangle_init_info (mangled, options, strlen (mangled), &di); + + { +#ifdef CP_DYNAMIC_ARRAYS + __extension__ struct demangle_component comps[di.num_comps]; + __extension__ struct demangle_component *subs[di.num_subs]; + + di.comps = comps; + di.subs = subs; +#else + di.comps = alloca (di.num_comps * sizeof (*di.comps)); + di.subs = alloca (di.num_subs * sizeof (*di.subs)); +#endif + + if (type) + dc = cplus_demangle_type (&di); + else + dc = cplus_demangle_mangled_name (&di, 1); + + /* If DMGL_PARAMS is set, then if we didn't consume the entire + mangled string, then we didn't successfully demangle it. If + DMGL_PARAMS is not set, we didn't look at the trailing + parameters. */ + if (((options & DMGL_PARAMS) != 0) && d_peek_char (&di) != '\0') + dc = NULL; + +#ifdef CP_DEMANGLE_DEBUG + d_dump (dc, 0); +#endif + + status = (dc != NULL) + ? cplus_demangle_print_callback (options, dc, callback, opaque) + : 0; + } + + return status; +} + +/* Entry point for the demangler. If MANGLED is a g++ v3 ABI mangled + name, return a buffer allocated with malloc holding the demangled + name. OPTIONS is the usual libiberty demangler options. On + success, this sets *PALC to the allocated size of the returned + buffer. On failure, this sets *PALC to 0 for a bad name, or 1 for + a memory allocation failure, and returns NULL. */ + +static char * +d_demangle (const char *mangled, int options, size_t *palc) +{ + struct d_growable_string dgs; + int status; + + d_growable_string_init (&dgs, 0); + + status = d_demangle_callback (mangled, options, + d_growable_string_callback_adapter, &dgs); + if (status == 0) + { + free (dgs.buf); + *palc = 0; + return NULL; + } + + *palc = dgs.allocation_failure ? 1 : 0; + return dgs.buf; +} + +#if defined(IN_LIBGCC2) || defined(IN_GLIBCPP_V3) + +extern char *__cxa_demangle (const char *, char *, size_t *, int *); + +/* ia64 ABI-mandated entry point in the C++ runtime library for + performing demangling. MANGLED_NAME is a NUL-terminated character + string containing the name to be demangled. + + OUTPUT_BUFFER is a region of memory, allocated with malloc, of + *LENGTH bytes, into which the demangled name is stored. If + OUTPUT_BUFFER is not long enough, it is expanded using realloc. + OUTPUT_BUFFER may instead be NULL; in that case, the demangled name + is placed in a region of memory allocated with malloc. + + If LENGTH is non-NULL, the length of the buffer containing the + demangled name, is placed in *LENGTH. + + The return value is a pointer to the start of the NUL-terminated + demangled name, or NULL if the demangling fails. The caller is + responsible for deallocating this memory using free. + + *STATUS is set to one of the following values: + 0: The demangling operation succeeded. + -1: A memory allocation failure occurred. + -2: MANGLED_NAME is not a valid name under the C++ ABI mangling rules. + -3: One of the arguments is invalid. + + The demangling is performed using the C++ ABI mangling rules, with + GNU extensions. */ + +char * +__cxa_demangle (const char *mangled_name, char *output_buffer, + size_t *length, int *status) +{ + char *demangled; + size_t alc; + + if (mangled_name == NULL) + { + if (status != NULL) + *status = -3; + return NULL; + } + + if (output_buffer != NULL && length == NULL) + { + if (status != NULL) + *status = -3; + return NULL; + } + + demangled = d_demangle (mangled_name, DMGL_PARAMS | DMGL_TYPES, &alc); + + if (demangled == NULL) + { + if (status != NULL) + { + if (alc == 1) + *status = -1; + else + *status = -2; + } + return NULL; + } + + if (output_buffer == NULL) + { + if (length != NULL) + *length = alc; + } + else + { + if (strlen (demangled) < *length) + { + strcpy (output_buffer, demangled); + free (demangled); + demangled = output_buffer; + } + else + { + free (output_buffer); + *length = alc; + } + } + + if (status != NULL) + *status = 0; + + return demangled; +} + +extern int __gcclibcxx_demangle_callback (const char *, + void (*) + (const char *, size_t, void *), + void *); + +/* Alternative, allocationless entry point in the C++ runtime library + for performing demangling. MANGLED_NAME is a NUL-terminated character + string containing the name to be demangled. + + CALLBACK is a callback function, called with demangled string + segments as demangling progresses; it is called at least once, + but may be called more than once. OPAQUE is a generalized pointer + used as a callback argument. + + The return code is one of the following values, equivalent to + the STATUS values of __cxa_demangle() (excluding -1, since this + function performs no memory allocations): + 0: The demangling operation succeeded. + -2: MANGLED_NAME is not a valid name under the C++ ABI mangling rules. + -3: One of the arguments is invalid. + + The demangling is performed using the C++ ABI mangling rules, with + GNU extensions. */ + +int +__gcclibcxx_demangle_callback (const char *mangled_name, + void (*callback) (const char *, size_t, void *), + void *opaque) +{ + int status; + + if (mangled_name == NULL || callback == NULL) + return -3; + + status = d_demangle_callback (mangled_name, DMGL_PARAMS | DMGL_TYPES, + callback, opaque); + if (status == 0) + return -2; + + return 0; +} + +#else /* ! (IN_LIBGCC2 || IN_GLIBCPP_V3) */ + +/* Entry point for libiberty demangler. If MANGLED is a g++ v3 ABI + mangled name, return a buffer allocated with malloc holding the + demangled name. Otherwise, return NULL. */ + +char * +cplus_demangle_v3 (const char *mangled, int options) +{ + size_t alc; + + return d_demangle (mangled, options, &alc); +} + +int +cplus_demangle_v3_callback (const char *mangled, int options, + demangle_callbackref callback, void *opaque) +{ + return d_demangle_callback (mangled, options, callback, opaque); +} + +/* Demangle a Java symbol. Java uses a subset of the V3 ABI C++ mangling + conventions, but the output formatting is a little different. + This instructs the C++ demangler not to emit pointer characters ("*"), to + use Java's namespace separator symbol ("." instead of "::"), and to output + JArray as TYPE[]. */ + +char * +java_demangle_v3 (const char *mangled) +{ + size_t alc; + + return d_demangle (mangled, DMGL_JAVA | DMGL_PARAMS | DMGL_RET_POSTFIX, &alc); +} + +int +java_demangle_v3_callback (const char *mangled, + demangle_callbackref callback, void *opaque) +{ + return d_demangle_callback (mangled, + DMGL_JAVA | DMGL_PARAMS | DMGL_RET_POSTFIX, + callback, opaque); +} + +#endif /* IN_LIBGCC2 || IN_GLIBCPP_V3 */ + +#ifndef IN_GLIBCPP_V3 + +/* Demangle a string in order to find out whether it is a constructor + or destructor. Return non-zero on success. Set *CTOR_KIND and + *DTOR_KIND appropriately. */ + +static int +is_ctor_or_dtor (const char *mangled, + enum gnu_v3_ctor_kinds *ctor_kind, + enum gnu_v3_dtor_kinds *dtor_kind) +{ + struct d_info di; + struct demangle_component *dc; + int ret; + + *ctor_kind = (enum gnu_v3_ctor_kinds) 0; + *dtor_kind = (enum gnu_v3_dtor_kinds) 0; + + cplus_demangle_init_info (mangled, DMGL_GNU_V3, strlen (mangled), &di); + + { +#ifdef CP_DYNAMIC_ARRAYS + __extension__ struct demangle_component comps[di.num_comps]; + __extension__ struct demangle_component *subs[di.num_subs]; + + di.comps = comps; + di.subs = subs; +#else + di.comps = alloca (di.num_comps * sizeof (*di.comps)); + di.subs = alloca (di.num_subs * sizeof (*di.subs)); +#endif + + dc = cplus_demangle_mangled_name (&di, 1); + + /* Note that because we did not pass DMGL_PARAMS, we don't expect + to demangle the entire string. */ + + ret = 0; + while (dc != NULL) + { + switch (dc->type) + { + default: + dc = NULL; + break; + case DEMANGLE_COMPONENT_TYPED_NAME: + case DEMANGLE_COMPONENT_TEMPLATE: + case DEMANGLE_COMPONENT_RESTRICT_THIS: + case DEMANGLE_COMPONENT_VOLATILE_THIS: + case DEMANGLE_COMPONENT_CONST_THIS: + dc = d_left (dc); + break; + case DEMANGLE_COMPONENT_QUAL_NAME: + case DEMANGLE_COMPONENT_LOCAL_NAME: + dc = d_right (dc); + break; + case DEMANGLE_COMPONENT_CTOR: + *ctor_kind = dc->u.s_ctor.kind; + ret = 1; + dc = NULL; + break; + case DEMANGLE_COMPONENT_DTOR: + *dtor_kind = dc->u.s_dtor.kind; + ret = 1; + dc = NULL; + break; + } + } + } + + return ret; +} + +/* Return whether NAME is the mangled form of a g++ V3 ABI constructor + name. A non-zero return indicates the type of constructor. */ + +enum gnu_v3_ctor_kinds +is_gnu_v3_mangled_ctor (const char *name) +{ + enum gnu_v3_ctor_kinds ctor_kind; + enum gnu_v3_dtor_kinds dtor_kind; + + if (! is_ctor_or_dtor (name, &ctor_kind, &dtor_kind)) + return (enum gnu_v3_ctor_kinds) 0; + return ctor_kind; +} + + +/* Return whether NAME is the mangled form of a g++ V3 ABI destructor + name. A non-zero return indicates the type of destructor. */ + +enum gnu_v3_dtor_kinds +is_gnu_v3_mangled_dtor (const char *name) +{ + enum gnu_v3_ctor_kinds ctor_kind; + enum gnu_v3_dtor_kinds dtor_kind; + + if (! is_ctor_or_dtor (name, &ctor_kind, &dtor_kind)) + return (enum gnu_v3_dtor_kinds) 0; + return dtor_kind; +} + +#endif /* IN_GLIBCPP_V3 */ + +#ifdef STANDALONE_DEMANGLER + +#include "getopt.h" +#include "dyn-string.h" + +static void print_usage (FILE* fp, int exit_value); + +#define IS_ALPHA(CHAR) \ + (((CHAR) >= 'a' && (CHAR) <= 'z') \ + || ((CHAR) >= 'A' && (CHAR) <= 'Z')) + +/* Non-zero if CHAR is a character than can occur in a mangled name. */ +#define is_mangled_char(CHAR) \ + (IS_ALPHA (CHAR) || IS_DIGIT (CHAR) \ + || (CHAR) == '_' || (CHAR) == '.' || (CHAR) == '$') + +/* The name of this program, as invoked. */ +const char* program_name; + +/* Prints usage summary to FP and then exits with EXIT_VALUE. */ + +static void +print_usage (FILE* fp, int exit_value) +{ + fprintf (fp, "Usage: %s [options] [names ...]\n", program_name); + fprintf (fp, "Options:\n"); + fprintf (fp, " -h,--help Display this message.\n"); + fprintf (fp, " -p,--no-params Don't display function parameters\n"); + fprintf (fp, " -v,--verbose Produce verbose demanglings.\n"); + fprintf (fp, "If names are provided, they are demangled. Otherwise filters standard input.\n"); + + exit (exit_value); +} + +/* Option specification for getopt_long. */ +static const struct option long_options[] = +{ + { "help", no_argument, NULL, 'h' }, + { "no-params", no_argument, NULL, 'p' }, + { "verbose", no_argument, NULL, 'v' }, + { NULL, no_argument, NULL, 0 }, +}; + +/* Main entry for a demangling filter executable. It will demangle + its command line arguments, if any. If none are provided, it will + filter stdin to stdout, replacing any recognized mangled C++ names + with their demangled equivalents. */ + +int +main (int argc, char *argv[]) +{ + int i; + int opt_char; + int options = DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES; + + /* Use the program name of this program, as invoked. */ + program_name = argv[0]; + + /* Parse options. */ + do + { + opt_char = getopt_long (argc, argv, "hpv", long_options, NULL); + switch (opt_char) + { + case '?': /* Unrecognized option. */ + print_usage (stderr, 1); + break; + + case 'h': + print_usage (stdout, 0); + break; + + case 'p': + options &= ~ DMGL_PARAMS; + break; + + case 'v': + options |= DMGL_VERBOSE; + break; + } + } + while (opt_char != -1); + + if (optind == argc) + /* No command line arguments were provided. Filter stdin. */ + { + dyn_string_t mangled = dyn_string_new (3); + char *s; + + /* Read all of input. */ + while (!feof (stdin)) + { + char c; + + /* Pile characters into mangled until we hit one that can't + occur in a mangled name. */ + c = getchar (); + while (!feof (stdin) && is_mangled_char (c)) + { + dyn_string_append_char (mangled, c); + if (feof (stdin)) + break; + c = getchar (); + } + + if (dyn_string_length (mangled) > 0) + { +#ifdef IN_GLIBCPP_V3 + s = __cxa_demangle (dyn_string_buf (mangled), NULL, NULL, NULL); +#else + s = cplus_demangle_v3 (dyn_string_buf (mangled), options); +#endif + + if (s != NULL) + { + fputs (s, stdout); + free (s); + } + else + { + /* It might not have been a mangled name. Print the + original text. */ + fputs (dyn_string_buf (mangled), stdout); + } + + dyn_string_clear (mangled); + } + + /* If we haven't hit EOF yet, we've read one character that + can't occur in a mangled name, so print it out. */ + if (!feof (stdin)) + putchar (c); + } + + dyn_string_delete (mangled); + } + else + /* Demangle command line arguments. */ + { + /* Loop over command line arguments. */ + for (i = optind; i < argc; ++i) + { + char *s; +#ifdef IN_GLIBCPP_V3 + int status; +#endif + + /* Attempt to demangle. */ +#ifdef IN_GLIBCPP_V3 + s = __cxa_demangle (argv[i], NULL, NULL, &status); +#else + s = cplus_demangle_v3 (argv[i], options); +#endif + + /* If it worked, print the demangled name. */ + if (s != NULL) + { + printf ("%s\n", s); + free (s); + } + else + { +#ifdef IN_GLIBCPP_V3 + fprintf (stderr, "Failed: %s (status %d)\n", argv[i], status); +#else + fprintf (stderr, "Failed: %s\n", argv[i]); +#endif + } + } + } + + return 0; +} + +#endif /* STANDALONE_DEMANGLER */ diff --git a/libiberty/cp-demint.c b/libiberty/cp-demint.c new file mode 100644 index 0000000..2e8f8d2 --- /dev/null +++ b/libiberty/cp-demint.c @@ -0,0 +1,234 @@ +/* Demangler component interface functions. + Copyright (C) 2004 Free Software Foundation, Inc. + Written by Ian Lance Taylor . + + This file is part of the libiberty library, which is part of GCC. + + This file is free software; you can 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. + + In addition to the permissions in the GNU General Public License, the + Free Software Foundation gives you unlimited permission to link the + compiled version of this file into combinations with other programs, + and to distribute those combinations without any restriction coming + from the use of this file. (The General Public License restrictions + do apply in other respects; for example, they cover modification of + the file, and distribution when not linked into a combined + executable.) + + 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. +*/ + +/* This file implements a few interface functions which are provided + for use with struct demangle_component trees. These functions are + declared in demangle.h. These functions are closely tied to the + demangler code in cp-demangle.c, and other interface functions can + be found in that file. We put these functions in a separate file + because they are not needed by the demangler, and so we avoid + having them pulled in by programs which only need the + demangler. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif + +#include "ansidecl.h" +#include "libiberty.h" +#include "demangle.h" +#include "cp-demangle.h" + +/* Fill in most component types. */ + +int +cplus_demangle_fill_component (struct demangle_component *p, + enum demangle_component_type type, + struct demangle_component *left, + struct demangle_component *right) +{ + if (p == NULL) + return 0; + switch (type) + { + case DEMANGLE_COMPONENT_QUAL_NAME: + case DEMANGLE_COMPONENT_LOCAL_NAME: + case DEMANGLE_COMPONENT_TYPED_NAME: + case DEMANGLE_COMPONENT_TEMPLATE: + case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE: + case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: + case DEMANGLE_COMPONENT_FUNCTION_TYPE: + case DEMANGLE_COMPONENT_ARRAY_TYPE: + case DEMANGLE_COMPONENT_PTRMEM_TYPE: + case DEMANGLE_COMPONENT_ARGLIST: + case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST: + case DEMANGLE_COMPONENT_UNARY: + case DEMANGLE_COMPONENT_BINARY: + case DEMANGLE_COMPONENT_BINARY_ARGS: + case DEMANGLE_COMPONENT_TRINARY: + case DEMANGLE_COMPONENT_TRINARY_ARG1: + case DEMANGLE_COMPONENT_TRINARY_ARG2: + case DEMANGLE_COMPONENT_LITERAL: + case DEMANGLE_COMPONENT_LITERAL_NEG: + break; + + /* These component types only have one subtree. */ + case DEMANGLE_COMPONENT_VTABLE: + case DEMANGLE_COMPONENT_VTT: + case DEMANGLE_COMPONENT_TYPEINFO: + case DEMANGLE_COMPONENT_TYPEINFO_NAME: + case DEMANGLE_COMPONENT_TYPEINFO_FN: + case DEMANGLE_COMPONENT_THUNK: + case DEMANGLE_COMPONENT_VIRTUAL_THUNK: + case DEMANGLE_COMPONENT_COVARIANT_THUNK: + case DEMANGLE_COMPONENT_JAVA_CLASS: + case DEMANGLE_COMPONENT_GUARD: + case DEMANGLE_COMPONENT_REFTEMP: + case DEMANGLE_COMPONENT_RESTRICT: + case DEMANGLE_COMPONENT_VOLATILE: + case DEMANGLE_COMPONENT_CONST: + case DEMANGLE_COMPONENT_RESTRICT_THIS: + case DEMANGLE_COMPONENT_VOLATILE_THIS: + case DEMANGLE_COMPONENT_CONST_THIS: + case DEMANGLE_COMPONENT_POINTER: + case DEMANGLE_COMPONENT_REFERENCE: + case DEMANGLE_COMPONENT_COMPLEX: + case DEMANGLE_COMPONENT_IMAGINARY: + case DEMANGLE_COMPONENT_VENDOR_TYPE: + case DEMANGLE_COMPONENT_CAST: + if (right != NULL) + return 0; + break; + + default: + /* Other types do not use subtrees. */ + return 0; + } + + p->type = type; + p->u.s_binary.left = left; + p->u.s_binary.right = right; + + return 1; +} + +/* Fill in a DEMANGLE_COMPONENT_BUILTIN_TYPE. */ + +int +cplus_demangle_fill_builtin_type (struct demangle_component *p, + const char *type_name) +{ + int len; + unsigned int i; + + if (p == NULL || type_name == NULL) + return 0; + len = strlen (type_name); + for (i = 0; i < D_BUILTIN_TYPE_COUNT; ++i) + { + if (len == cplus_demangle_builtin_types[i].len + && strcmp (type_name, cplus_demangle_builtin_types[i].name) == 0) + { + p->type = DEMANGLE_COMPONENT_BUILTIN_TYPE; + p->u.s_builtin.type = &cplus_demangle_builtin_types[i]; + return 1; + } + } + return 0; +} + +/* Fill in a DEMANGLE_COMPONENT_OPERATOR. */ + +int +cplus_demangle_fill_operator (struct demangle_component *p, + const char *opname, int args) +{ + int len; + unsigned int i; + + if (p == NULL || opname == NULL) + return 0; + len = strlen (opname); + for (i = 0; cplus_demangle_operators[i].name != NULL; ++i) + { + if (len == cplus_demangle_operators[i].len + && args == cplus_demangle_operators[i].args + && strcmp (opname, cplus_demangle_operators[i].name) == 0) + { + p->type = DEMANGLE_COMPONENT_OPERATOR; + p->u.s_operator.op = &cplus_demangle_operators[i]; + return 1; + } + } + return 0; +} + +/* Translate a mangled name into components. */ + +struct demangle_component * +cplus_demangle_v3_components (const char *mangled, int options, void **mem) +{ + size_t len; + int type; + struct d_info di; + struct demangle_component *dc; + + len = strlen (mangled); + + if (mangled[0] == '_' && mangled[1] == 'Z') + type = 0; + else + { + if ((options & DMGL_TYPES) == 0) + return NULL; + type = 1; + } + + cplus_demangle_init_info (mangled, options, len, &di); + + di.comps = ((struct demangle_component *) + malloc (di.num_comps * sizeof (struct demangle_component))); + di.subs = ((struct demangle_component **) + malloc (di.num_subs * sizeof (struct demangle_component *))); + if (di.comps == NULL || di.subs == NULL) + { + if (di.comps != NULL) + free (di.comps); + if (di.subs != NULL) + free (di.subs); + return NULL; + } + + if (! type) + dc = cplus_demangle_mangled_name (&di, 1); + else + dc = cplus_demangle_type (&di); + + /* If DMGL_PARAMS is set, then if we didn't consume the entire + mangled string, then we didn't successfully demangle it. */ + if ((options & DMGL_PARAMS) != 0 && d_peek_char (&di) != '\0') + dc = NULL; + + free (di.subs); + + if (dc != NULL) + *mem = di.comps; + else + free (di.comps); + + return dc; +} diff --git a/libiberty/cplus-dem.c b/libiberty/cplus-dem.c new file mode 100644 index 0000000..1f8b1fc --- /dev/null +++ b/libiberty/cplus-dem.c @@ -0,0 +1,4717 @@ +/* Demangler for GNU C++ + Copyright 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.uucp) + Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling + Modified by Satish Pai (pai@apollo.hp.com) for HP demangling + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +In addition to the permissions in the GNU Library General Public +License, the Free Software Foundation gives you unlimited permission +to link the compiled version of this file into combinations with other +programs, and to distribute those combinations without any restriction +coming from the use of this file. (The Library Public License +restrictions do apply in other respects; for example, they cover +modification of the file, and distribution when not linked into a +combined executable.) + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* This file exports two functions; cplus_mangle_opname and cplus_demangle. + + This file imports xmalloc and xrealloc, which are like malloc and + realloc except that they generate a fatal error if there is no + available memory. */ + +/* This file lives in both GCC and libiberty. When making changes, please + try not to break either. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "safe-ctype.h" + +#include +#include +#include + +#ifdef HAVE_STDLIB_H +#include +#else +char * malloc (); +char * realloc (); +#endif + +#include +#undef CURRENT_DEMANGLING_STYLE +#define CURRENT_DEMANGLING_STYLE work->options + +#include "libiberty.h" + +static char *ada_demangle (const char *, int); + +#define min(X,Y) (((X) < (Y)) ? (X) : (Y)) + +/* A value at least one greater than the maximum number of characters + that will be output when using the `%d' format with `printf'. */ +#define INTBUF_SIZE 32 + +extern void fancy_abort (void) ATTRIBUTE_NORETURN; + +/* In order to allow a single demangler executable to demangle strings + using various common values of CPLUS_MARKER, as well as any specific + one set at compile time, we maintain a string containing all the + commonly used ones, and check to see if the marker we are looking for + is in that string. CPLUS_MARKER is usually '$' on systems where the + assembler can deal with that. Where the assembler can't, it's usually + '.' (but on many systems '.' is used for other things). We put the + current defined CPLUS_MARKER first (which defaults to '$'), followed + by the next most common value, followed by an explicit '$' in case + the value of CPLUS_MARKER is not '$'. + + We could avoid this if we could just get g++ to tell us what the actual + cplus marker character is as part of the debug information, perhaps by + ensuring that it is the character that terminates the gcc_compiled + marker symbol (FIXME). */ + +#if !defined (CPLUS_MARKER) +#define CPLUS_MARKER '$' +#endif + +enum demangling_styles current_demangling_style = auto_demangling; + +static char cplus_markers[] = { CPLUS_MARKER, '.', '$', '\0' }; + +static char char_str[2] = { '\000', '\000' }; + +void +set_cplus_marker_for_demangling (int ch) +{ + cplus_markers[0] = ch; +} + +typedef struct string /* Beware: these aren't required to be */ +{ /* '\0' terminated. */ + char *b; /* pointer to start of string */ + char *p; /* pointer after last character */ + char *e; /* pointer after end of allocated space */ +} string; + +/* Stuff that is shared between sub-routines. + Using a shared structure allows cplus_demangle to be reentrant. */ + +struct work_stuff +{ + int options; + char **typevec; + char **ktypevec; + char **btypevec; + int numk; + int numb; + int ksize; + int bsize; + int ntypes; + int typevec_size; + int constructor; + int destructor; + int static_type; /* A static member function */ + int temp_start; /* index in demangled to start of template args */ + int type_quals; /* The type qualifiers. */ + int dllimported; /* Symbol imported from a PE DLL */ + char **tmpl_argvec; /* Template function arguments. */ + int ntmpl_args; /* The number of template function arguments. */ + int forgetting_types; /* Nonzero if we are not remembering the types + we see. */ + string* previous_argument; /* The last function argument demangled. */ + int nrepeats; /* The number of times to repeat the previous + argument. */ +}; + +#define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI) +#define PRINT_ARG_TYPES (work -> options & DMGL_PARAMS) + +static const struct optable +{ + const char *const in; + const char *const out; + const int flags; +} optable[] = { + {"nw", " new", DMGL_ANSI}, /* new (1.92, ansi) */ + {"dl", " delete", DMGL_ANSI}, /* new (1.92, ansi) */ + {"new", " new", 0}, /* old (1.91, and 1.x) */ + {"delete", " delete", 0}, /* old (1.91, and 1.x) */ + {"vn", " new []", DMGL_ANSI}, /* GNU, pending ansi */ + {"vd", " delete []", DMGL_ANSI}, /* GNU, pending ansi */ + {"as", "=", DMGL_ANSI}, /* ansi */ + {"ne", "!=", DMGL_ANSI}, /* old, ansi */ + {"eq", "==", DMGL_ANSI}, /* old, ansi */ + {"ge", ">=", DMGL_ANSI}, /* old, ansi */ + {"gt", ">", DMGL_ANSI}, /* old, ansi */ + {"le", "<=", DMGL_ANSI}, /* old, ansi */ + {"lt", "<", DMGL_ANSI}, /* old, ansi */ + {"plus", "+", 0}, /* old */ + {"pl", "+", DMGL_ANSI}, /* ansi */ + {"apl", "+=", DMGL_ANSI}, /* ansi */ + {"minus", "-", 0}, /* old */ + {"mi", "-", DMGL_ANSI}, /* ansi */ + {"ami", "-=", DMGL_ANSI}, /* ansi */ + {"mult", "*", 0}, /* old */ + {"ml", "*", DMGL_ANSI}, /* ansi */ + {"amu", "*=", DMGL_ANSI}, /* ansi (ARM/Lucid) */ + {"aml", "*=", DMGL_ANSI}, /* ansi (GNU/g++) */ + {"convert", "+", 0}, /* old (unary +) */ + {"negate", "-", 0}, /* old (unary -) */ + {"trunc_mod", "%", 0}, /* old */ + {"md", "%", DMGL_ANSI}, /* ansi */ + {"amd", "%=", DMGL_ANSI}, /* ansi */ + {"trunc_div", "/", 0}, /* old */ + {"dv", "/", DMGL_ANSI}, /* ansi */ + {"adv", "/=", DMGL_ANSI}, /* ansi */ + {"truth_andif", "&&", 0}, /* old */ + {"aa", "&&", DMGL_ANSI}, /* ansi */ + {"truth_orif", "||", 0}, /* old */ + {"oo", "||", DMGL_ANSI}, /* ansi */ + {"truth_not", "!", 0}, /* old */ + {"nt", "!", DMGL_ANSI}, /* ansi */ + {"postincrement","++", 0}, /* old */ + {"pp", "++", DMGL_ANSI}, /* ansi */ + {"postdecrement","--", 0}, /* old */ + {"mm", "--", DMGL_ANSI}, /* ansi */ + {"bit_ior", "|", 0}, /* old */ + {"or", "|", DMGL_ANSI}, /* ansi */ + {"aor", "|=", DMGL_ANSI}, /* ansi */ + {"bit_xor", "^", 0}, /* old */ + {"er", "^", DMGL_ANSI}, /* ansi */ + {"aer", "^=", DMGL_ANSI}, /* ansi */ + {"bit_and", "&", 0}, /* old */ + {"ad", "&", DMGL_ANSI}, /* ansi */ + {"aad", "&=", DMGL_ANSI}, /* ansi */ + {"bit_not", "~", 0}, /* old */ + {"co", "~", DMGL_ANSI}, /* ansi */ + {"call", "()", 0}, /* old */ + {"cl", "()", DMGL_ANSI}, /* ansi */ + {"alshift", "<<", 0}, /* old */ + {"ls", "<<", DMGL_ANSI}, /* ansi */ + {"als", "<<=", DMGL_ANSI}, /* ansi */ + {"arshift", ">>", 0}, /* old */ + {"rs", ">>", DMGL_ANSI}, /* ansi */ + {"ars", ">>=", DMGL_ANSI}, /* ansi */ + {"component", "->", 0}, /* old */ + {"pt", "->", DMGL_ANSI}, /* ansi; Lucid C++ form */ + {"rf", "->", DMGL_ANSI}, /* ansi; ARM/GNU form */ + {"indirect", "*", 0}, /* old */ + {"method_call", "->()", 0}, /* old */ + {"addr", "&", 0}, /* old (unary &) */ + {"array", "[]", 0}, /* old */ + {"vc", "[]", DMGL_ANSI}, /* ansi */ + {"compound", ", ", 0}, /* old */ + {"cm", ", ", DMGL_ANSI}, /* ansi */ + {"cond", "?:", 0}, /* old */ + {"cn", "?:", DMGL_ANSI}, /* pseudo-ansi */ + {"max", ">?", 0}, /* old */ + {"mx", ">?", DMGL_ANSI}, /* pseudo-ansi */ + {"min", "*", DMGL_ANSI}, /* ansi */ + {"sz", "sizeof ", DMGL_ANSI} /* pseudo-ansi */ +}; + +/* These values are used to indicate the various type varieties. + They are all non-zero so that they can be used as `success' + values. */ +typedef enum type_kind_t +{ + tk_none, + tk_pointer, + tk_reference, + tk_integral, + tk_bool, + tk_char, + tk_real +} type_kind_t; + +const struct demangler_engine libiberty_demanglers[] = +{ + { + NO_DEMANGLING_STYLE_STRING, + no_demangling, + "Demangling disabled" + } + , + { + AUTO_DEMANGLING_STYLE_STRING, + auto_demangling, + "Automatic selection based on executable" + } + , + { + GNU_DEMANGLING_STYLE_STRING, + gnu_demangling, + "GNU (g++) style demangling" + } + , + { + LUCID_DEMANGLING_STYLE_STRING, + lucid_demangling, + "Lucid (lcc) style demangling" + } + , + { + ARM_DEMANGLING_STYLE_STRING, + arm_demangling, + "ARM style demangling" + } + , + { + HP_DEMANGLING_STYLE_STRING, + hp_demangling, + "HP (aCC) style demangling" + } + , + { + EDG_DEMANGLING_STYLE_STRING, + edg_demangling, + "EDG style demangling" + } + , + { + GNU_V3_DEMANGLING_STYLE_STRING, + gnu_v3_demangling, + "GNU (g++) V3 ABI-style demangling" + } + , + { + JAVA_DEMANGLING_STYLE_STRING, + java_demangling, + "Java style demangling" + } + , + { + GNAT_DEMANGLING_STYLE_STRING, + gnat_demangling, + "GNAT style demangling" + } + , + { + NULL, unknown_demangling, NULL + } +}; + +#define STRING_EMPTY(str) ((str) -> b == (str) -> p) +#define APPEND_BLANK(str) {if (!STRING_EMPTY(str)) \ + string_append(str, " ");} +#define LEN_STRING(str) ( (STRING_EMPTY(str))?0:((str)->p - (str)->b)) + +/* The scope separator appropriate for the language being demangled. */ + +#define SCOPE_STRING(work) ((work->options & DMGL_JAVA) ? "." : "::") + +#define ARM_VTABLE_STRING "__vtbl__" /* Lucid/ARM virtual table prefix */ +#define ARM_VTABLE_STRLEN 8 /* strlen (ARM_VTABLE_STRING) */ + +/* Prototypes for local functions */ + +static void delete_work_stuff (struct work_stuff *); + +static void delete_non_B_K_work_stuff (struct work_stuff *); + +static char *mop_up (struct work_stuff *, string *, int); + +static void squangle_mop_up (struct work_stuff *); + +static void work_stuff_copy_to_from (struct work_stuff *, struct work_stuff *); + +#if 0 +static int +demangle_method_args (struct work_stuff *, const char **, string *); +#endif + +static char * +internal_cplus_demangle (struct work_stuff *, const char *); + +static int +demangle_template_template_parm (struct work_stuff *work, + const char **, string *); + +static int +demangle_template (struct work_stuff *work, const char **, string *, + string *, int, int); + +static int +arm_pt (struct work_stuff *, const char *, int, const char **, + const char **); + +static int +demangle_class_name (struct work_stuff *, const char **, string *); + +static int +demangle_qualified (struct work_stuff *, const char **, string *, + int, int); + +static int demangle_class (struct work_stuff *, const char **, string *); + +static int demangle_fund_type (struct work_stuff *, const char **, string *); + +static int demangle_signature (struct work_stuff *, const char **, string *); + +static int demangle_prefix (struct work_stuff *, const char **, string *); + +static int gnu_special (struct work_stuff *, const char **, string *); + +static int arm_special (const char **, string *); + +static void string_need (string *, int); + +static void string_delete (string *); + +static void +string_init (string *); + +static void string_clear (string *); + +#if 0 +static int string_empty (string *); +#endif + +static void string_append (string *, const char *); + +static void string_appends (string *, string *); + +static void string_appendn (string *, const char *, int); + +static void string_prepend (string *, const char *); + +static void string_prependn (string *, const char *, int); + +static void string_append_template_idx (string *, int); + +static int get_count (const char **, int *); + +static int consume_count (const char **); + +static int consume_count_with_underscores (const char**); + +static int demangle_args (struct work_stuff *, const char **, string *); + +static int demangle_nested_args (struct work_stuff*, const char**, string*); + +static int do_type (struct work_stuff *, const char **, string *); + +static int do_arg (struct work_stuff *, const char **, string *); + +static void +demangle_function_name (struct work_stuff *, const char **, string *, + const char *); + +static int +iterate_demangle_function (struct work_stuff *, + const char **, string *, const char *); + +static void remember_type (struct work_stuff *, const char *, int); + +static void remember_Btype (struct work_stuff *, const char *, int, int); + +static int register_Btype (struct work_stuff *); + +static void remember_Ktype (struct work_stuff *, const char *, int); + +static void forget_types (struct work_stuff *); + +static void forget_B_and_K_types (struct work_stuff *); + +static void string_prepends (string *, string *); + +static int +demangle_template_value_parm (struct work_stuff*, const char**, + string*, type_kind_t); + +static int +do_hpacc_template_const_value (struct work_stuff *, const char **, string *); + +static int +do_hpacc_template_literal (struct work_stuff *, const char **, string *); + +static int snarf_numeric_literal (const char **, string *); + +/* There is a TYPE_QUAL value for each type qualifier. They can be + combined by bitwise-or to form the complete set of qualifiers for a + type. */ + +#define TYPE_UNQUALIFIED 0x0 +#define TYPE_QUAL_CONST 0x1 +#define TYPE_QUAL_VOLATILE 0x2 +#define TYPE_QUAL_RESTRICT 0x4 + +static int code_for_qualifier (int); + +static const char* qualifier_string (int); + +static const char* demangle_qualifier (int); + +static int demangle_expression (struct work_stuff *, const char **, string *, + type_kind_t); + +static int +demangle_integral_value (struct work_stuff *, const char **, string *); + +static int +demangle_real_value (struct work_stuff *, const char **, string *); + +static void +demangle_arm_hp_template (struct work_stuff *, const char **, int, string *); + +static void +recursively_demangle (struct work_stuff *, const char **, string *, int); + +static void grow_vect (char **, size_t *, size_t, int); + +/* Translate count to integer, consuming tokens in the process. + Conversion terminates on the first non-digit character. + + Trying to consume something that isn't a count results in no + consumption of input and a return of -1. + + Overflow consumes the rest of the digits, and returns -1. */ + +static int +consume_count (const char **type) +{ + int count = 0; + + if (! ISDIGIT ((unsigned char)**type)) + return -1; + + while (ISDIGIT ((unsigned char)**type)) + { + count *= 10; + + /* Check for overflow. + We assume that count is represented using two's-complement; + no power of two is divisible by ten, so if an overflow occurs + when multiplying by ten, the result will not be a multiple of + ten. */ + if ((count % 10) != 0) + { + while (ISDIGIT ((unsigned char) **type)) + (*type)++; + return -1; + } + + count += **type - '0'; + (*type)++; + } + + if (count < 0) + count = -1; + + return (count); +} + + +/* Like consume_count, but for counts that are preceded and followed + by '_' if they are greater than 10. Also, -1 is returned for + failure, since 0 can be a valid value. */ + +static int +consume_count_with_underscores (const char **mangled) +{ + int idx; + + if (**mangled == '_') + { + (*mangled)++; + if (!ISDIGIT ((unsigned char)**mangled)) + return -1; + + idx = consume_count (mangled); + if (**mangled != '_') + /* The trailing underscore was missing. */ + return -1; + + (*mangled)++; + } + else + { + if (**mangled < '0' || **mangled > '9') + return -1; + + idx = **mangled - '0'; + (*mangled)++; + } + + return idx; +} + +/* C is the code for a type-qualifier. Return the TYPE_QUAL + corresponding to this qualifier. */ + +static int +code_for_qualifier (int c) +{ + switch (c) + { + case 'C': + return TYPE_QUAL_CONST; + + case 'V': + return TYPE_QUAL_VOLATILE; + + case 'u': + return TYPE_QUAL_RESTRICT; + + default: + break; + } + + /* C was an invalid qualifier. */ + abort (); +} + +/* Return the string corresponding to the qualifiers given by + TYPE_QUALS. */ + +static const char* +qualifier_string (int type_quals) +{ + switch (type_quals) + { + case TYPE_UNQUALIFIED: + return ""; + + case TYPE_QUAL_CONST: + return "const"; + + case TYPE_QUAL_VOLATILE: + return "volatile"; + + case TYPE_QUAL_RESTRICT: + return "__restrict"; + + case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE: + return "const volatile"; + + case TYPE_QUAL_CONST | TYPE_QUAL_RESTRICT: + return "const __restrict"; + + case TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT: + return "volatile __restrict"; + + case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT: + return "const volatile __restrict"; + + default: + break; + } + + /* TYPE_QUALS was an invalid qualifier set. */ + abort (); +} + +/* C is the code for a type-qualifier. Return the string + corresponding to this qualifier. This function should only be + called with a valid qualifier code. */ + +static const char* +demangle_qualifier (int c) +{ + return qualifier_string (code_for_qualifier (c)); +} + +int +cplus_demangle_opname (const char *opname, char *result, int options) +{ + int len, len1, ret; + string type; + struct work_stuff work[1]; + const char *tem; + + len = strlen(opname); + result[0] = '\0'; + ret = 0; + memset ((char *) work, 0, sizeof (work)); + work->options = options; + + if (opname[0] == '_' && opname[1] == '_' + && opname[2] == 'o' && opname[3] == 'p') + { + /* ANSI. */ + /* type conversion operator. */ + tem = opname + 4; + if (do_type (work, &tem, &type)) + { + strcat (result, "operator "); + strncat (result, type.b, type.p - type.b); + string_delete (&type); + ret = 1; + } + } + else if (opname[0] == '_' && opname[1] == '_' + && ISLOWER((unsigned char)opname[2]) + && ISLOWER((unsigned char)opname[3])) + { + if (opname[4] == '\0') + { + /* Operator. */ + size_t i; + for (i = 0; i < ARRAY_SIZE (optable); i++) + { + if (strlen (optable[i].in) == 2 + && memcmp (optable[i].in, opname + 2, 2) == 0) + { + strcat (result, "operator"); + strcat (result, optable[i].out); + ret = 1; + break; + } + } + } + else + { + if (opname[2] == 'a' && opname[5] == '\0') + { + /* Assignment. */ + size_t i; + for (i = 0; i < ARRAY_SIZE (optable); i++) + { + if (strlen (optable[i].in) == 3 + && memcmp (optable[i].in, opname + 2, 3) == 0) + { + strcat (result, "operator"); + strcat (result, optable[i].out); + ret = 1; + break; + } + } + } + } + } + else if (len >= 3 + && opname[0] == 'o' + && opname[1] == 'p' + && strchr (cplus_markers, opname[2]) != NULL) + { + /* see if it's an assignment expression */ + if (len >= 10 /* op$assign_ */ + && memcmp (opname + 3, "assign_", 7) == 0) + { + size_t i; + for (i = 0; i < ARRAY_SIZE (optable); i++) + { + len1 = len - 10; + if ((int) strlen (optable[i].in) == len1 + && memcmp (optable[i].in, opname + 10, len1) == 0) + { + strcat (result, "operator"); + strcat (result, optable[i].out); + strcat (result, "="); + ret = 1; + break; + } + } + } + else + { + size_t i; + for (i = 0; i < ARRAY_SIZE (optable); i++) + { + len1 = len - 3; + if ((int) strlen (optable[i].in) == len1 + && memcmp (optable[i].in, opname + 3, len1) == 0) + { + strcat (result, "operator"); + strcat (result, optable[i].out); + ret = 1; + break; + } + } + } + } + else if (len >= 5 && memcmp (opname, "type", 4) == 0 + && strchr (cplus_markers, opname[4]) != NULL) + { + /* type conversion operator */ + tem = opname + 5; + if (do_type (work, &tem, &type)) + { + strcat (result, "operator "); + strncat (result, type.b, type.p - type.b); + string_delete (&type); + ret = 1; + } + } + squangle_mop_up (work); + return ret; + +} + +/* Takes operator name as e.g. "++" and returns mangled + operator name (e.g. "postincrement_expr"), or NULL if not found. + + If OPTIONS & DMGL_ANSI == 1, return the ANSI name; + if OPTIONS & DMGL_ANSI == 0, return the old GNU name. */ + +const char * +cplus_mangle_opname (const char *opname, int options) +{ + size_t i; + int len; + + len = strlen (opname); + for (i = 0; i < ARRAY_SIZE (optable); i++) + { + if ((int) strlen (optable[i].out) == len + && (options & DMGL_ANSI) == (optable[i].flags & DMGL_ANSI) + && memcmp (optable[i].out, opname, len) == 0) + return optable[i].in; + } + return (0); +} + +/* Add a routine to set the demangling style to be sure it is valid and + allow for any demangler initialization that maybe necessary. */ + +enum demangling_styles +cplus_demangle_set_style (enum demangling_styles style) +{ + const struct demangler_engine *demangler = libiberty_demanglers; + + for (; demangler->demangling_style != unknown_demangling; ++demangler) + if (style == demangler->demangling_style) + { + current_demangling_style = style; + return current_demangling_style; + } + + return unknown_demangling; +} + +/* Do string name to style translation */ + +enum demangling_styles +cplus_demangle_name_to_style (const char *name) +{ + const struct demangler_engine *demangler = libiberty_demanglers; + + for (; demangler->demangling_style != unknown_demangling; ++demangler) + if (strcmp (name, demangler->demangling_style_name) == 0) + return demangler->demangling_style; + + return unknown_demangling; +} + +/* char *cplus_demangle (const char *mangled, int options) + + If MANGLED is a mangled function name produced by GNU C++, then + a pointer to a @code{malloc}ed string giving a C++ representation + of the name will be returned; otherwise NULL will be returned. + It is the caller's responsibility to free the string which + is returned. + + The OPTIONS arg may contain one or more of the following bits: + + DMGL_ANSI ANSI qualifiers such as `const' and `void' are + included. + DMGL_PARAMS Function parameters are included. + + For example, + + cplus_demangle ("foo__1Ai", DMGL_PARAMS) => "A::foo(int)" + cplus_demangle ("foo__1Ai", DMGL_PARAMS | DMGL_ANSI) => "A::foo(int)" + cplus_demangle ("foo__1Ai", 0) => "A::foo" + + cplus_demangle ("foo__1Afe", DMGL_PARAMS) => "A::foo(float,...)" + cplus_demangle ("foo__1Afe", DMGL_PARAMS | DMGL_ANSI)=> "A::foo(float,...)" + cplus_demangle ("foo__1Afe", 0) => "A::foo" + + Note that any leading underscores, or other such characters prepended by + the compilation system, are presumed to have already been stripped from + MANGLED. */ + +char * +cplus_demangle (const char *mangled, int options) +{ + char *ret; + struct work_stuff work[1]; + + if (current_demangling_style == no_demangling) + return xstrdup (mangled); + + memset ((char *) work, 0, sizeof (work)); + work->options = options; + if ((work->options & DMGL_STYLE_MASK) == 0) + work->options |= (int) current_demangling_style & DMGL_STYLE_MASK; + + /* The V3 ABI demangling is implemented elsewhere. */ + if (GNU_V3_DEMANGLING || AUTO_DEMANGLING) + { + ret = cplus_demangle_v3 (mangled, work->options); + if (ret || GNU_V3_DEMANGLING) + return ret; + } + + if (JAVA_DEMANGLING) + { + ret = java_demangle_v3 (mangled); + if (ret) + return ret; + } + + if (GNAT_DEMANGLING) + return ada_demangle(mangled,options); + + ret = internal_cplus_demangle (work, mangled); + squangle_mop_up (work); + return (ret); +} + + +/* Assuming *OLD_VECT points to an array of *SIZE objects of size + ELEMENT_SIZE, grow it to contain at least MIN_SIZE objects, + updating *OLD_VECT and *SIZE as necessary. */ + +static void +grow_vect (char **old_vect, size_t *size, size_t min_size, int element_size) +{ + if (*size < min_size) + { + *size *= 2; + if (*size < min_size) + *size = min_size; + *old_vect = XRESIZEVAR (char, *old_vect, *size * element_size); + } +} + +/* Demangle ada names: + 1. Discard final __{DIGIT}+ or ${DIGIT}+ + 2. Convert other instances of embedded "__" to `.'. + 3. Discard leading _ada_. + 4. Remove everything after first ___ if it is followed by 'X'. + 5. Put symbols that should be suppressed in <...> brackets. + The resulting string is valid until the next call of ada_demangle. */ + +static char * +ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED) +{ + int i, j; + int len0; + const char* p; + char *demangled = NULL; + int changed; + size_t demangled_size = 0; + + changed = 0; + + if (strncmp (mangled, "_ada_", 5) == 0) + { + mangled += 5; + changed = 1; + } + + if (mangled[0] == '_' || mangled[0] == '<') + goto Suppress; + + p = strstr (mangled, "___"); + if (p == NULL) + len0 = strlen (mangled); + else + { + if (p[3] == 'X') + { + len0 = p - mangled; + changed = 1; + } + else + goto Suppress; + } + + /* Make demangled big enough for possible expansion by operator name. */ + grow_vect (&demangled, + &demangled_size, 2 * len0 + 1, + sizeof (char)); + + if (ISDIGIT ((unsigned char) mangled[len0 - 1])) { + for (i = len0 - 2; i >= 0 && ISDIGIT ((unsigned char) mangled[i]); i -= 1) + ; + if (i > 1 && mangled[i] == '_' && mangled[i - 1] == '_') + { + len0 = i - 1; + changed = 1; + } + else if (mangled[i] == '$') + { + len0 = i; + changed = 1; + } + } + + for (i = 0, j = 0; i < len0 && ! ISALPHA ((unsigned char)mangled[i]); + i += 1, j += 1) + demangled[j] = mangled[i]; + + while (i < len0) + { + if (i < len0 - 2 && mangled[i] == '_' && mangled[i + 1] == '_') + { + demangled[j] = '.'; + changed = 1; + i += 2; j += 1; + } + else + { + demangled[j] = mangled[i]; + i += 1; j += 1; + } + } + demangled[j] = '\000'; + + for (i = 0; demangled[i] != '\0'; i += 1) + if (ISUPPER ((unsigned char)demangled[i]) || demangled[i] == ' ') + goto Suppress; + + if (! changed) + return NULL; + else + return demangled; + + Suppress: + grow_vect (&demangled, + &demangled_size, strlen (mangled) + 3, + sizeof (char)); + + if (mangled[0] == '<') + strcpy (demangled, mangled); + else + sprintf (demangled, "<%s>", mangled); + + return demangled; +} + +/* This function performs most of what cplus_demangle use to do, but + to be able to demangle a name with a B, K or n code, we need to + have a longer term memory of what types have been seen. The original + now initializes and cleans up the squangle code info, while internal + calls go directly to this routine to avoid resetting that info. */ + +static char * +internal_cplus_demangle (struct work_stuff *work, const char *mangled) +{ + + string decl; + int success = 0; + char *demangled = NULL; + int s1, s2, s3, s4; + s1 = work->constructor; + s2 = work->destructor; + s3 = work->static_type; + s4 = work->type_quals; + work->constructor = work->destructor = 0; + work->type_quals = TYPE_UNQUALIFIED; + work->dllimported = 0; + + if ((mangled != NULL) && (*mangled != '\0')) + { + string_init (&decl); + + /* First check to see if gnu style demangling is active and if the + string to be demangled contains a CPLUS_MARKER. If so, attempt to + recognize one of the gnu special forms rather than looking for a + standard prefix. In particular, don't worry about whether there + is a "__" string in the mangled string. Consider "_$_5__foo" for + example. */ + + if ((AUTO_DEMANGLING || GNU_DEMANGLING)) + { + success = gnu_special (work, &mangled, &decl); + } + if (!success) + { + success = demangle_prefix (work, &mangled, &decl); + } + if (success && (*mangled != '\0')) + { + success = demangle_signature (work, &mangled, &decl); + } + if (work->constructor == 2) + { + string_prepend (&decl, "global constructors keyed to "); + work->constructor = 0; + } + else if (work->destructor == 2) + { + string_prepend (&decl, "global destructors keyed to "); + work->destructor = 0; + } + else if (work->dllimported == 1) + { + string_prepend (&decl, "import stub for "); + work->dllimported = 0; + } + demangled = mop_up (work, &decl, success); + } + work->constructor = s1; + work->destructor = s2; + work->static_type = s3; + work->type_quals = s4; + return demangled; +} + + +/* Clear out and squangling related storage */ +static void +squangle_mop_up (struct work_stuff *work) +{ + /* clean up the B and K type mangling types. */ + forget_B_and_K_types (work); + if (work -> btypevec != NULL) + { + free ((char *) work -> btypevec); + } + if (work -> ktypevec != NULL) + { + free ((char *) work -> ktypevec); + } +} + + +/* Copy the work state and storage. */ + +static void +work_stuff_copy_to_from (struct work_stuff *to, struct work_stuff *from) +{ + int i; + + delete_work_stuff (to); + + /* Shallow-copy scalars. */ + memcpy (to, from, sizeof (*to)); + + /* Deep-copy dynamic storage. */ + if (from->typevec_size) + to->typevec = XNEWVEC (char *, from->typevec_size); + + for (i = 0; i < from->ntypes; i++) + { + int len = strlen (from->typevec[i]) + 1; + + to->typevec[i] = XNEWVEC (char, len); + memcpy (to->typevec[i], from->typevec[i], len); + } + + if (from->ksize) + to->ktypevec = XNEWVEC (char *, from->ksize); + + for (i = 0; i < from->numk; i++) + { + int len = strlen (from->ktypevec[i]) + 1; + + to->ktypevec[i] = XNEWVEC (char, len); + memcpy (to->ktypevec[i], from->ktypevec[i], len); + } + + if (from->bsize) + to->btypevec = XNEWVEC (char *, from->bsize); + + for (i = 0; i < from->numb; i++) + { + int len = strlen (from->btypevec[i]) + 1; + + to->btypevec[i] = XNEWVEC (char , len); + memcpy (to->btypevec[i], from->btypevec[i], len); + } + + if (from->ntmpl_args) + to->tmpl_argvec = XNEWVEC (char *, from->ntmpl_args); + + for (i = 0; i < from->ntmpl_args; i++) + { + int len = strlen (from->tmpl_argvec[i]) + 1; + + to->tmpl_argvec[i] = XNEWVEC (char, len); + memcpy (to->tmpl_argvec[i], from->tmpl_argvec[i], len); + } + + if (from->previous_argument) + { + to->previous_argument = XNEW (string); + string_init (to->previous_argument); + string_appends (to->previous_argument, from->previous_argument); + } +} + + +/* Delete dynamic stuff in work_stuff that is not to be re-used. */ + +static void +delete_non_B_K_work_stuff (struct work_stuff *work) +{ + /* Discard the remembered types, if any. */ + + forget_types (work); + if (work -> typevec != NULL) + { + free ((char *) work -> typevec); + work -> typevec = NULL; + work -> typevec_size = 0; + } + if (work->tmpl_argvec) + { + int i; + + for (i = 0; i < work->ntmpl_args; i++) + if (work->tmpl_argvec[i]) + free ((char*) work->tmpl_argvec[i]); + + free ((char*) work->tmpl_argvec); + work->tmpl_argvec = NULL; + } + if (work->previous_argument) + { + string_delete (work->previous_argument); + free ((char*) work->previous_argument); + work->previous_argument = NULL; + } +} + + +/* Delete all dynamic storage in work_stuff. */ +static void +delete_work_stuff (struct work_stuff *work) +{ + delete_non_B_K_work_stuff (work); + squangle_mop_up (work); +} + + +/* Clear out any mangled storage */ + +static char * +mop_up (struct work_stuff *work, string *declp, int success) +{ + char *demangled = NULL; + + delete_non_B_K_work_stuff (work); + + /* If demangling was successful, ensure that the demangled string is null + terminated and return it. Otherwise, free the demangling decl. */ + + if (!success) + { + string_delete (declp); + } + else + { + string_appendn (declp, "", 1); + demangled = declp->b; + } + return (demangled); +} + +/* + +LOCAL FUNCTION + + demangle_signature -- demangle the signature part of a mangled name + +SYNOPSIS + + static int + demangle_signature (struct work_stuff *work, const char **mangled, + string *declp); + +DESCRIPTION + + Consume and demangle the signature portion of the mangled name. + + DECLP is the string where demangled output is being built. At + entry it contains the demangled root name from the mangled name + prefix. I.E. either a demangled operator name or the root function + name. In some special cases, it may contain nothing. + + *MANGLED points to the current unconsumed location in the mangled + name. As tokens are consumed and demangling is performed, the + pointer is updated to continuously point at the next token to + be consumed. + + Demangling GNU style mangled names is nasty because there is no + explicit token that marks the start of the outermost function + argument list. */ + +static int +demangle_signature (struct work_stuff *work, + const char **mangled, string *declp) +{ + int success = 1; + int func_done = 0; + int expect_func = 0; + int expect_return_type = 0; + const char *oldmangled = NULL; + string trawname; + string tname; + + while (success && (**mangled != '\0')) + { + switch (**mangled) + { + case 'Q': + oldmangled = *mangled; + success = demangle_qualified (work, mangled, declp, 1, 0); + if (success) + remember_type (work, oldmangled, *mangled - oldmangled); + if (AUTO_DEMANGLING || GNU_DEMANGLING) + expect_func = 1; + oldmangled = NULL; + break; + + case 'K': + oldmangled = *mangled; + success = demangle_qualified (work, mangled, declp, 1, 0); + if (AUTO_DEMANGLING || GNU_DEMANGLING) + { + expect_func = 1; + } + oldmangled = NULL; + break; + + case 'S': + /* Static member function */ + if (oldmangled == NULL) + { + oldmangled = *mangled; + } + (*mangled)++; + work -> static_type = 1; + break; + + case 'C': + case 'V': + case 'u': + work->type_quals |= code_for_qualifier (**mangled); + + /* a qualified member function */ + if (oldmangled == NULL) + oldmangled = *mangled; + (*mangled)++; + break; + + case 'L': + /* Local class name follows after "Lnnn_" */ + if (HP_DEMANGLING) + { + while (**mangled && (**mangled != '_')) + (*mangled)++; + if (!**mangled) + success = 0; + else + (*mangled)++; + } + else + success = 0; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (oldmangled == NULL) + { + oldmangled = *mangled; + } + work->temp_start = -1; /* uppermost call to demangle_class */ + success = demangle_class (work, mangled, declp); + if (success) + { + remember_type (work, oldmangled, *mangled - oldmangled); + } + if (AUTO_DEMANGLING || GNU_DEMANGLING || EDG_DEMANGLING) + { + /* EDG and others will have the "F", so we let the loop cycle + if we are looking at one. */ + if (**mangled != 'F') + expect_func = 1; + } + oldmangled = NULL; + break; + + case 'B': + { + string s; + success = do_type (work, mangled, &s); + if (success) + { + string_append (&s, SCOPE_STRING (work)); + string_prepends (declp, &s); + string_delete (&s); + } + oldmangled = NULL; + expect_func = 1; + } + break; + + case 'F': + /* Function */ + /* ARM/HP style demangling includes a specific 'F' character after + the class name. For GNU style, it is just implied. So we can + safely just consume any 'F' at this point and be compatible + with either style. */ + + oldmangled = NULL; + func_done = 1; + (*mangled)++; + + /* For lucid/ARM/HP style we have to forget any types we might + have remembered up to this point, since they were not argument + types. GNU style considers all types seen as available for + back references. See comment in demangle_args() */ + + if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) + { + forget_types (work); + } + success = demangle_args (work, mangled, declp); + /* After picking off the function args, we expect to either + find the function return type (preceded by an '_') or the + end of the string. */ + if (success && (AUTO_DEMANGLING || EDG_DEMANGLING) && **mangled == '_') + { + ++(*mangled); + /* At this level, we do not care about the return type. */ + success = do_type (work, mangled, &tname); + string_delete (&tname); + } + + break; + + case 't': + /* G++ Template */ + string_init(&trawname); + string_init(&tname); + if (oldmangled == NULL) + { + oldmangled = *mangled; + } + success = demangle_template (work, mangled, &tname, + &trawname, 1, 1); + if (success) + { + remember_type (work, oldmangled, *mangled - oldmangled); + } + string_append (&tname, SCOPE_STRING (work)); + + string_prepends(declp, &tname); + if (work -> destructor & 1) + { + string_prepend (&trawname, "~"); + string_appends (declp, &trawname); + work->destructor -= 1; + } + if ((work->constructor & 1) || (work->destructor & 1)) + { + string_appends (declp, &trawname); + work->constructor -= 1; + } + string_delete(&trawname); + string_delete(&tname); + oldmangled = NULL; + expect_func = 1; + break; + + case '_': + if ((AUTO_DEMANGLING || GNU_DEMANGLING) && expect_return_type) + { + /* Read the return type. */ + string return_type; + + (*mangled)++; + success = do_type (work, mangled, &return_type); + APPEND_BLANK (&return_type); + + string_prepends (declp, &return_type); + string_delete (&return_type); + break; + } + else + /* At the outermost level, we cannot have a return type specified, + so if we run into another '_' at this point we are dealing with + a mangled name that is either bogus, or has been mangled by + some algorithm we don't know how to deal with. So just + reject the entire demangling. */ + /* However, "_nnn" is an expected suffix for alternate entry point + numbered nnn for a function, with HP aCC, so skip over that + without reporting failure. pai/1997-09-04 */ + if (HP_DEMANGLING) + { + (*mangled)++; + while (**mangled && ISDIGIT ((unsigned char)**mangled)) + (*mangled)++; + } + else + success = 0; + break; + + case 'H': + if (AUTO_DEMANGLING || GNU_DEMANGLING) + { + /* A G++ template function. Read the template arguments. */ + success = demangle_template (work, mangled, declp, 0, 0, + 0); + if (!(work->constructor & 1)) + expect_return_type = 1; + (*mangled)++; + break; + } + else + /* fall through */ + {;} + + default: + if (AUTO_DEMANGLING || GNU_DEMANGLING) + { + /* Assume we have stumbled onto the first outermost function + argument token, and start processing args. */ + func_done = 1; + success = demangle_args (work, mangled, declp); + } + else + { + /* Non-GNU demanglers use a specific token to mark the start + of the outermost function argument tokens. Typically 'F', + for ARM/HP-demangling, for example. So if we find something + we are not prepared for, it must be an error. */ + success = 0; + } + break; + } + /* + if (AUTO_DEMANGLING || GNU_DEMANGLING) + */ + { + if (success && expect_func) + { + func_done = 1; + if (LUCID_DEMANGLING || ARM_DEMANGLING || EDG_DEMANGLING) + { + forget_types (work); + } + success = demangle_args (work, mangled, declp); + /* Since template include the mangling of their return types, + we must set expect_func to 0 so that we don't try do + demangle more arguments the next time we get here. */ + expect_func = 0; + } + } + } + if (success && !func_done) + { + if (AUTO_DEMANGLING || GNU_DEMANGLING) + { + /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and + bar__3fooi is 'foo::bar(int)'. We get here when we find the + first case, and need to ensure that the '(void)' gets added to + the current declp. Note that with ARM/HP, the first case + represents the name of a static data member 'foo::bar', + which is in the current declp, so we leave it alone. */ + success = demangle_args (work, mangled, declp); + } + } + if (success && PRINT_ARG_TYPES) + { + if (work->static_type) + string_append (declp, " static"); + if (work->type_quals != TYPE_UNQUALIFIED) + { + APPEND_BLANK (declp); + string_append (declp, qualifier_string (work->type_quals)); + } + } + + return (success); +} + +#if 0 + +static int +demangle_method_args (struct work_stuff *work, const char **mangled, + string *declp) +{ + int success = 0; + + if (work -> static_type) + { + string_append (declp, *mangled + 1); + *mangled += strlen (*mangled); + success = 1; + } + else + { + success = demangle_args (work, mangled, declp); + } + return (success); +} + +#endif + +static int +demangle_template_template_parm (struct work_stuff *work, + const char **mangled, string *tname) +{ + int i; + int r; + int need_comma = 0; + int success = 1; + string temp; + + string_append (tname, "template <"); + /* get size of template parameter list */ + if (get_count (mangled, &r)) + { + for (i = 0; i < r; i++) + { + if (need_comma) + { + string_append (tname, ", "); + } + + /* Z for type parameters */ + if (**mangled == 'Z') + { + (*mangled)++; + string_append (tname, "class"); + } + /* z for template parameters */ + else if (**mangled == 'z') + { + (*mangled)++; + success = + demangle_template_template_parm (work, mangled, tname); + if (!success) + { + break; + } + } + else + { + /* temp is initialized in do_type */ + success = do_type (work, mangled, &temp); + if (success) + { + string_appends (tname, &temp); + } + string_delete(&temp); + if (!success) + { + break; + } + } + need_comma = 1; + } + + } + if (tname->p[-1] == '>') + string_append (tname, " "); + string_append (tname, "> class"); + return (success); +} + +static int +demangle_expression (struct work_stuff *work, const char **mangled, + string *s, type_kind_t tk) +{ + int need_operator = 0; + int success; + + success = 1; + string_appendn (s, "(", 1); + (*mangled)++; + while (success && **mangled != 'W' && **mangled != '\0') + { + if (need_operator) + { + size_t i; + size_t len; + + success = 0; + + len = strlen (*mangled); + + for (i = 0; i < ARRAY_SIZE (optable); ++i) + { + size_t l = strlen (optable[i].in); + + if (l <= len + && memcmp (optable[i].in, *mangled, l) == 0) + { + string_appendn (s, " ", 1); + string_append (s, optable[i].out); + string_appendn (s, " ", 1); + success = 1; + (*mangled) += l; + break; + } + } + + if (!success) + break; + } + else + need_operator = 1; + + success = demangle_template_value_parm (work, mangled, s, tk); + } + + if (**mangled != 'W') + success = 0; + else + { + string_appendn (s, ")", 1); + (*mangled)++; + } + + return success; +} + +static int +demangle_integral_value (struct work_stuff *work, + const char **mangled, string *s) +{ + int success; + + if (**mangled == 'E') + success = demangle_expression (work, mangled, s, tk_integral); + else if (**mangled == 'Q' || **mangled == 'K') + success = demangle_qualified (work, mangled, s, 0, 1); + else + { + int value; + + /* By default, we let the number decide whether we shall consume an + underscore. */ + int multidigit_without_leading_underscore = 0; + int leave_following_underscore = 0; + + success = 0; + + if (**mangled == '_') + { + if (mangled[0][1] == 'm') + { + /* Since consume_count_with_underscores does not handle the + `m'-prefix we must do it here, using consume_count and + adjusting underscores: we have to consume the underscore + matching the prepended one. */ + multidigit_without_leading_underscore = 1; + string_appendn (s, "-", 1); + (*mangled) += 2; + } + else + { + /* Do not consume a following underscore; + consume_count_with_underscores will consume what + should be consumed. */ + leave_following_underscore = 1; + } + } + else + { + /* Negative numbers are indicated with a leading `m'. */ + if (**mangled == 'm') + { + string_appendn (s, "-", 1); + (*mangled)++; + } + /* Since consume_count_with_underscores does not handle + multi-digit numbers that do not start with an underscore, + and this number can be an integer template parameter, + we have to call consume_count. */ + multidigit_without_leading_underscore = 1; + /* These multi-digit numbers never end on an underscore, + so if there is one then don't eat it. */ + leave_following_underscore = 1; + } + + /* We must call consume_count if we expect to remove a trailing + underscore, since consume_count_with_underscores expects + the leading underscore (that we consumed) if it is to handle + multi-digit numbers. */ + if (multidigit_without_leading_underscore) + value = consume_count (mangled); + else + value = consume_count_with_underscores (mangled); + + if (value != -1) + { + char buf[INTBUF_SIZE]; + sprintf (buf, "%d", value); + string_append (s, buf); + + /* Numbers not otherwise delimited, might have an underscore + appended as a delimeter, which we should skip. + + ??? This used to always remove a following underscore, which + is wrong. If other (arbitrary) cases are followed by an + underscore, we need to do something more radical. */ + + if ((value > 9 || multidigit_without_leading_underscore) + && ! leave_following_underscore + && **mangled == '_') + (*mangled)++; + + /* All is well. */ + success = 1; + } + } + + return success; +} + +/* Demangle the real value in MANGLED. */ + +static int +demangle_real_value (struct work_stuff *work, + const char **mangled, string *s) +{ + if (**mangled == 'E') + return demangle_expression (work, mangled, s, tk_real); + + if (**mangled == 'm') + { + string_appendn (s, "-", 1); + (*mangled)++; + } + while (ISDIGIT ((unsigned char)**mangled)) + { + string_appendn (s, *mangled, 1); + (*mangled)++; + } + if (**mangled == '.') /* fraction */ + { + string_appendn (s, ".", 1); + (*mangled)++; + while (ISDIGIT ((unsigned char)**mangled)) + { + string_appendn (s, *mangled, 1); + (*mangled)++; + } + } + if (**mangled == 'e') /* exponent */ + { + string_appendn (s, "e", 1); + (*mangled)++; + while (ISDIGIT ((unsigned char)**mangled)) + { + string_appendn (s, *mangled, 1); + (*mangled)++; + } + } + + return 1; +} + +static int +demangle_template_value_parm (struct work_stuff *work, const char **mangled, + string *s, type_kind_t tk) +{ + int success = 1; + + if (**mangled == 'Y') + { + /* The next argument is a template parameter. */ + int idx; + + (*mangled)++; + idx = consume_count_with_underscores (mangled); + if (idx == -1 + || (work->tmpl_argvec && idx >= work->ntmpl_args) + || consume_count_with_underscores (mangled) == -1) + return -1; + if (work->tmpl_argvec) + string_append (s, work->tmpl_argvec[idx]); + else + string_append_template_idx (s, idx); + } + else if (tk == tk_integral) + success = demangle_integral_value (work, mangled, s); + else if (tk == tk_char) + { + char tmp[2]; + int val; + if (**mangled == 'm') + { + string_appendn (s, "-", 1); + (*mangled)++; + } + string_appendn (s, "'", 1); + val = consume_count(mangled); + if (val <= 0) + success = 0; + else + { + tmp[0] = (char)val; + tmp[1] = '\0'; + string_appendn (s, &tmp[0], 1); + string_appendn (s, "'", 1); + } + } + else if (tk == tk_bool) + { + int val = consume_count (mangled); + if (val == 0) + string_appendn (s, "false", 5); + else if (val == 1) + string_appendn (s, "true", 4); + else + success = 0; + } + else if (tk == tk_real) + success = demangle_real_value (work, mangled, s); + else if (tk == tk_pointer || tk == tk_reference) + { + if (**mangled == 'Q') + success = demangle_qualified (work, mangled, s, + /*isfuncname=*/0, + /*append=*/1); + else + { + int symbol_len = consume_count (mangled); + if (symbol_len == -1) + return -1; + if (symbol_len == 0) + string_appendn (s, "0", 1); + else + { + char *p = XNEWVEC (char, symbol_len + 1), *q; + strncpy (p, *mangled, symbol_len); + p [symbol_len] = '\0'; + /* We use cplus_demangle here, rather than + internal_cplus_demangle, because the name of the entity + mangled here does not make use of any of the squangling + or type-code information we have built up thus far; it is + mangled independently. */ + q = cplus_demangle (p, work->options); + if (tk == tk_pointer) + string_appendn (s, "&", 1); + /* FIXME: Pointer-to-member constants should get a + qualifying class name here. */ + if (q) + { + string_append (s, q); + free (q); + } + else + string_append (s, p); + free (p); + } + *mangled += symbol_len; + } + } + + return success; +} + +/* Demangle the template name in MANGLED. The full name of the + template (e.g., S) is placed in TNAME. The name without the + template parameters (e.g. S) is placed in TRAWNAME if TRAWNAME is + non-NULL. If IS_TYPE is nonzero, this template is a type template, + not a function template. If both IS_TYPE and REMEMBER are nonzero, + the template is remembered in the list of back-referenceable + types. */ + +static int +demangle_template (struct work_stuff *work, const char **mangled, + string *tname, string *trawname, + int is_type, int remember) +{ + int i; + int r; + int need_comma = 0; + int success = 0; + int is_java_array = 0; + string temp; + + (*mangled)++; + if (is_type) + { + /* get template name */ + if (**mangled == 'z') + { + int idx; + (*mangled)++; + (*mangled)++; + + idx = consume_count_with_underscores (mangled); + if (idx == -1 + || (work->tmpl_argvec && idx >= work->ntmpl_args) + || consume_count_with_underscores (mangled) == -1) + return (0); + + if (work->tmpl_argvec) + { + string_append (tname, work->tmpl_argvec[idx]); + if (trawname) + string_append (trawname, work->tmpl_argvec[idx]); + } + else + { + string_append_template_idx (tname, idx); + if (trawname) + string_append_template_idx (trawname, idx); + } + } + else + { + if ((r = consume_count (mangled)) <= 0 + || (int) strlen (*mangled) < r) + { + return (0); + } + is_java_array = (work -> options & DMGL_JAVA) + && strncmp (*mangled, "JArray1Z", 8) == 0; + if (! is_java_array) + { + string_appendn (tname, *mangled, r); + } + if (trawname) + string_appendn (trawname, *mangled, r); + *mangled += r; + } + } + if (!is_java_array) + string_append (tname, "<"); + /* get size of template parameter list */ + if (!get_count (mangled, &r)) + { + return (0); + } + if (!is_type) + { + /* Create an array for saving the template argument values. */ + work->tmpl_argvec = XNEWVEC (char *, r); + work->ntmpl_args = r; + for (i = 0; i < r; i++) + work->tmpl_argvec[i] = 0; + } + for (i = 0; i < r; i++) + { + if (need_comma) + { + string_append (tname, ", "); + } + /* Z for type parameters */ + if (**mangled == 'Z') + { + (*mangled)++; + /* temp is initialized in do_type */ + success = do_type (work, mangled, &temp); + if (success) + { + string_appends (tname, &temp); + + if (!is_type) + { + /* Save the template argument. */ + int len = temp.p - temp.b; + work->tmpl_argvec[i] = XNEWVEC (char, len + 1); + memcpy (work->tmpl_argvec[i], temp.b, len); + work->tmpl_argvec[i][len] = '\0'; + } + } + string_delete(&temp); + if (!success) + { + break; + } + } + /* z for template parameters */ + else if (**mangled == 'z') + { + int r2; + (*mangled)++; + success = demangle_template_template_parm (work, mangled, tname); + + if (success + && (r2 = consume_count (mangled)) > 0 + && (int) strlen (*mangled) >= r2) + { + string_append (tname, " "); + string_appendn (tname, *mangled, r2); + if (!is_type) + { + /* Save the template argument. */ + int len = r2; + work->tmpl_argvec[i] = XNEWVEC (char, len + 1); + memcpy (work->tmpl_argvec[i], *mangled, len); + work->tmpl_argvec[i][len] = '\0'; + } + *mangled += r2; + } + if (!success) + { + break; + } + } + else + { + string param; + string* s; + + /* otherwise, value parameter */ + + /* temp is initialized in do_type */ + success = do_type (work, mangled, &temp); + string_delete(&temp); + if (!success) + break; + + if (!is_type) + { + s = ¶m; + string_init (s); + } + else + s = tname; + + success = demangle_template_value_parm (work, mangled, s, + (type_kind_t) success); + + if (!success) + { + if (!is_type) + string_delete (s); + success = 0; + break; + } + + if (!is_type) + { + int len = s->p - s->b; + work->tmpl_argvec[i] = XNEWVEC (char, len + 1); + memcpy (work->tmpl_argvec[i], s->b, len); + work->tmpl_argvec[i][len] = '\0'; + + string_appends (tname, s); + string_delete (s); + } + } + need_comma = 1; + } + if (is_java_array) + { + string_append (tname, "[]"); + } + else + { + if (tname->p[-1] == '>') + string_append (tname, " "); + string_append (tname, ">"); + } + + if (is_type && remember) + { + const int bindex = register_Btype (work); + remember_Btype (work, tname->b, LEN_STRING (tname), bindex); + } + + /* + if (work -> static_type) + { + string_append (declp, *mangled + 1); + *mangled += strlen (*mangled); + success = 1; + } + else + { + success = demangle_args (work, mangled, declp); + } + } + */ + return (success); +} + +static int +arm_pt (struct work_stuff *work, const char *mangled, + int n, const char **anchor, const char **args) +{ + /* Check if ARM template with "__pt__" in it ("parameterized type") */ + /* Allow HP also here, because HP's cfront compiler follows ARM to some extent */ + if ((ARM_DEMANGLING || HP_DEMANGLING) && (*anchor = strstr (mangled, "__pt__"))) + { + int len; + *args = *anchor + 6; + len = consume_count (args); + if (len == -1) + return 0; + if (*args + len == mangled + n && **args == '_') + { + ++*args; + return 1; + } + } + if (AUTO_DEMANGLING || EDG_DEMANGLING) + { + if ((*anchor = strstr (mangled, "__tm__")) + || (*anchor = strstr (mangled, "__ps__")) + || (*anchor = strstr (mangled, "__pt__"))) + { + int len; + *args = *anchor + 6; + len = consume_count (args); + if (len == -1) + return 0; + if (*args + len == mangled + n && **args == '_') + { + ++*args; + return 1; + } + } + else if ((*anchor = strstr (mangled, "__S"))) + { + int len; + *args = *anchor + 3; + len = consume_count (args); + if (len == -1) + return 0; + if (*args + len == mangled + n && **args == '_') + { + ++*args; + return 1; + } + } + } + + return 0; +} + +static void +demangle_arm_hp_template (struct work_stuff *work, const char **mangled, + int n, string *declp) +{ + const char *p; + const char *args; + const char *e = *mangled + n; + string arg; + + /* Check for HP aCC template spec: classXt1t2 where t1, t2 are + template args */ + if (HP_DEMANGLING && ((*mangled)[n] == 'X')) + { + char *start_spec_args = NULL; + int hold_options; + + /* First check for and omit template specialization pseudo-arguments, + such as in "Spec<#1,#1.*>" */ + start_spec_args = strchr (*mangled, '<'); + if (start_spec_args && (start_spec_args - *mangled < n)) + string_appendn (declp, *mangled, start_spec_args - *mangled); + else + string_appendn (declp, *mangled, n); + (*mangled) += n + 1; + string_init (&arg); + if (work->temp_start == -1) /* non-recursive call */ + work->temp_start = declp->p - declp->b; + + /* We want to unconditionally demangle parameter types in + template parameters. */ + hold_options = work->options; + work->options |= DMGL_PARAMS; + + string_append (declp, "<"); + while (1) + { + string_delete (&arg); + switch (**mangled) + { + case 'T': + /* 'T' signals a type parameter */ + (*mangled)++; + if (!do_type (work, mangled, &arg)) + goto hpacc_template_args_done; + break; + + case 'U': + case 'S': + /* 'U' or 'S' signals an integral value */ + if (!do_hpacc_template_const_value (work, mangled, &arg)) + goto hpacc_template_args_done; + break; + + case 'A': + /* 'A' signals a named constant expression (literal) */ + if (!do_hpacc_template_literal (work, mangled, &arg)) + goto hpacc_template_args_done; + break; + + default: + /* Today, 1997-09-03, we have only the above types + of template parameters */ + /* FIXME: maybe this should fail and return null */ + goto hpacc_template_args_done; + } + string_appends (declp, &arg); + /* Check if we're at the end of template args. + 0 if at end of static member of template class, + _ if done with template args for a function */ + if ((**mangled == '\000') || (**mangled == '_')) + break; + else + string_append (declp, ","); + } + hpacc_template_args_done: + string_append (declp, ">"); + string_delete (&arg); + if (**mangled == '_') + (*mangled)++; + work->options = hold_options; + return; + } + /* ARM template? (Also handles HP cfront extensions) */ + else if (arm_pt (work, *mangled, n, &p, &args)) + { + int hold_options; + string type_str; + + string_init (&arg); + string_appendn (declp, *mangled, p - *mangled); + if (work->temp_start == -1) /* non-recursive call */ + work->temp_start = declp->p - declp->b; + + /* We want to unconditionally demangle parameter types in + template parameters. */ + hold_options = work->options; + work->options |= DMGL_PARAMS; + + string_append (declp, "<"); + /* should do error checking here */ + while (args < e) { + string_delete (&arg); + + /* Check for type or literal here */ + switch (*args) + { + /* HP cfront extensions to ARM for template args */ + /* spec: Xt1Lv1 where t1 is a type, v1 is a literal value */ + /* FIXME: We handle only numeric literals for HP cfront */ + case 'X': + /* A typed constant value follows */ + args++; + if (!do_type (work, &args, &type_str)) + goto cfront_template_args_done; + string_append (&arg, "("); + string_appends (&arg, &type_str); + string_delete (&type_str); + string_append (&arg, ")"); + if (*args != 'L') + goto cfront_template_args_done; + args++; + /* Now snarf a literal value following 'L' */ + if (!snarf_numeric_literal (&args, &arg)) + goto cfront_template_args_done; + break; + + case 'L': + /* Snarf a literal following 'L' */ + args++; + if (!snarf_numeric_literal (&args, &arg)) + goto cfront_template_args_done; + break; + default: + /* Not handling other HP cfront stuff */ + { + const char* old_args = args; + if (!do_type (work, &args, &arg)) + goto cfront_template_args_done; + + /* Fail if we didn't make any progress: prevent infinite loop. */ + if (args == old_args) + { + work->options = hold_options; + return; + } + } + } + string_appends (declp, &arg); + string_append (declp, ","); + } + cfront_template_args_done: + string_delete (&arg); + if (args >= e) + --declp->p; /* remove extra comma */ + string_append (declp, ">"); + work->options = hold_options; + } + else if (n>10 && strncmp (*mangled, "_GLOBAL_", 8) == 0 + && (*mangled)[9] == 'N' + && (*mangled)[8] == (*mangled)[10] + && strchr (cplus_markers, (*mangled)[8])) + { + /* A member of the anonymous namespace. */ + string_append (declp, "{anonymous}"); + } + else + { + if (work->temp_start == -1) /* non-recursive call only */ + work->temp_start = 0; /* disable in recursive calls */ + string_appendn (declp, *mangled, n); + } + *mangled += n; +} + +/* Extract a class name, possibly a template with arguments, from the + mangled string; qualifiers, local class indicators, etc. have + already been dealt with */ + +static int +demangle_class_name (struct work_stuff *work, const char **mangled, + string *declp) +{ + int n; + int success = 0; + + n = consume_count (mangled); + if (n == -1) + return 0; + if ((int) strlen (*mangled) >= n) + { + demangle_arm_hp_template (work, mangled, n, declp); + success = 1; + } + + return (success); +} + +/* + +LOCAL FUNCTION + + demangle_class -- demangle a mangled class sequence + +SYNOPSIS + + static int + demangle_class (struct work_stuff *work, const char **mangled, + strint *declp) + +DESCRIPTION + + DECLP points to the buffer into which demangling is being done. + + *MANGLED points to the current token to be demangled. On input, + it points to a mangled class (I.E. "3foo", "13verylongclass", etc.) + On exit, it points to the next token after the mangled class on + success, or the first unconsumed token on failure. + + If the CONSTRUCTOR or DESTRUCTOR flags are set in WORK, then + we are demangling a constructor or destructor. In this case + we prepend "class::class" or "class::~class" to DECLP. + + Otherwise, we prepend "class::" to the current DECLP. + + Reset the constructor/destructor flags once they have been + "consumed". This allows demangle_class to be called later during + the same demangling, to do normal class demangling. + + Returns 1 if demangling is successful, 0 otherwise. + +*/ + +static int +demangle_class (struct work_stuff *work, const char **mangled, string *declp) +{ + int success = 0; + int btype; + string class_name; + char *save_class_name_end = 0; + + string_init (&class_name); + btype = register_Btype (work); + if (demangle_class_name (work, mangled, &class_name)) + { + save_class_name_end = class_name.p; + if ((work->constructor & 1) || (work->destructor & 1)) + { + /* adjust so we don't include template args */ + if (work->temp_start && (work->temp_start != -1)) + { + class_name.p = class_name.b + work->temp_start; + } + string_prepends (declp, &class_name); + if (work -> destructor & 1) + { + string_prepend (declp, "~"); + work -> destructor -= 1; + } + else + { + work -> constructor -= 1; + } + } + class_name.p = save_class_name_end; + remember_Ktype (work, class_name.b, LEN_STRING(&class_name)); + remember_Btype (work, class_name.b, LEN_STRING(&class_name), btype); + string_prepend (declp, SCOPE_STRING (work)); + string_prepends (declp, &class_name); + success = 1; + } + string_delete (&class_name); + return (success); +} + + +/* Called when there's a "__" in the mangled name, with `scan' pointing to + the rightmost guess. + + Find the correct "__"-sequence where the function name ends and the + signature starts, which is ambiguous with GNU mangling. + Call demangle_signature here, so we can make sure we found the right + one; *mangled will be consumed so caller will not make further calls to + demangle_signature. */ + +static int +iterate_demangle_function (struct work_stuff *work, const char **mangled, + string *declp, const char *scan) +{ + const char *mangle_init = *mangled; + int success = 0; + string decl_init; + struct work_stuff work_init; + + if (*(scan + 2) == '\0') + return 0; + + /* Do not iterate for some demangling modes, or if there's only one + "__"-sequence. This is the normal case. */ + if (ARM_DEMANGLING || LUCID_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING + || strstr (scan + 2, "__") == NULL) + { + demangle_function_name (work, mangled, declp, scan); + return 1; + } + + /* Save state so we can restart if the guess at the correct "__" was + wrong. */ + string_init (&decl_init); + string_appends (&decl_init, declp); + memset (&work_init, 0, sizeof work_init); + work_stuff_copy_to_from (&work_init, work); + + /* Iterate over occurrences of __, allowing names and types to have a + "__" sequence in them. We must start with the first (not the last) + occurrence, since "__" most often occur between independent mangled + parts, hence starting at the last occurence inside a signature + might get us a "successful" demangling of the signature. */ + + while (scan[2]) + { + demangle_function_name (work, mangled, declp, scan); + success = demangle_signature (work, mangled, declp); + if (success) + break; + + /* Reset demangle state for the next round. */ + *mangled = mangle_init; + string_clear (declp); + string_appends (declp, &decl_init); + work_stuff_copy_to_from (work, &work_init); + + /* Leave this underscore-sequence. */ + scan += 2; + + /* Scan for the next "__" sequence. */ + while (*scan && (scan[0] != '_' || scan[1] != '_')) + scan++; + + /* Move to last "__" in this sequence. */ + while (*scan && *scan == '_') + scan++; + scan -= 2; + } + + /* Delete saved state. */ + delete_work_stuff (&work_init); + string_delete (&decl_init); + + return success; +} + +/* + +LOCAL FUNCTION + + demangle_prefix -- consume the mangled name prefix and find signature + +SYNOPSIS + + static int + demangle_prefix (struct work_stuff *work, const char **mangled, + string *declp); + +DESCRIPTION + + Consume and demangle the prefix of the mangled name. + While processing the function name root, arrange to call + demangle_signature if the root is ambiguous. + + DECLP points to the string buffer into which demangled output is + placed. On entry, the buffer is empty. On exit it contains + the root function name, the demangled operator name, or in some + special cases either nothing or the completely demangled result. + + MANGLED points to the current pointer into the mangled name. As each + token of the mangled name is consumed, it is updated. Upon entry + the current mangled name pointer points to the first character of + the mangled name. Upon exit, it should point to the first character + of the signature if demangling was successful, or to the first + unconsumed character if demangling of the prefix was unsuccessful. + + Returns 1 on success, 0 otherwise. + */ + +static int +demangle_prefix (struct work_stuff *work, const char **mangled, + string *declp) +{ + int success = 1; + const char *scan; + int i; + + if (strlen(*mangled) > 6 + && (strncmp(*mangled, "_imp__", 6) == 0 + || strncmp(*mangled, "__imp_", 6) == 0)) + { + /* it's a symbol imported from a PE dynamic library. Check for both + new style prefix _imp__ and legacy __imp_ used by older versions + of dlltool. */ + (*mangled) += 6; + work->dllimported = 1; + } + else if (strlen(*mangled) >= 11 && strncmp(*mangled, "_GLOBAL_", 8) == 0) + { + char *marker = strchr (cplus_markers, (*mangled)[8]); + if (marker != NULL && *marker == (*mangled)[10]) + { + if ((*mangled)[9] == 'D') + { + /* it's a GNU global destructor to be executed at program exit */ + (*mangled) += 11; + work->destructor = 2; + if (gnu_special (work, mangled, declp)) + return success; + } + else if ((*mangled)[9] == 'I') + { + /* it's a GNU global constructor to be executed at program init */ + (*mangled) += 11; + work->constructor = 2; + if (gnu_special (work, mangled, declp)) + return success; + } + } + } + else if ((ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) && strncmp(*mangled, "__std__", 7) == 0) + { + /* it's a ARM global destructor to be executed at program exit */ + (*mangled) += 7; + work->destructor = 2; + } + else if ((ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) && strncmp(*mangled, "__sti__", 7) == 0) + { + /* it's a ARM global constructor to be executed at program initial */ + (*mangled) += 7; + work->constructor = 2; + } + + /* This block of code is a reduction in strength time optimization + of: + scan = strstr (*mangled, "__"); */ + + { + scan = *mangled; + + do { + scan = strchr (scan, '_'); + } while (scan != NULL && *++scan != '_'); + + if (scan != NULL) --scan; + } + + if (scan != NULL) + { + /* We found a sequence of two or more '_', ensure that we start at + the last pair in the sequence. */ + i = strspn (scan, "_"); + if (i > 2) + { + scan += (i - 2); + } + } + + if (scan == NULL) + { + success = 0; + } + else if (work -> static_type) + { + if (!ISDIGIT ((unsigned char)scan[0]) && (scan[0] != 't')) + { + success = 0; + } + } + else if ((scan == *mangled) + && (ISDIGIT ((unsigned char)scan[2]) || (scan[2] == 'Q') + || (scan[2] == 't') || (scan[2] == 'K') || (scan[2] == 'H'))) + { + /* The ARM says nothing about the mangling of local variables. + But cfront mangles local variables by prepending __ + to them. As an extension to ARM demangling we handle this case. */ + if ((LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING) + && ISDIGIT ((unsigned char)scan[2])) + { + *mangled = scan + 2; + consume_count (mangled); + string_append (declp, *mangled); + *mangled += strlen (*mangled); + success = 1; + } + else + { + /* A GNU style constructor starts with __[0-9Qt]. But cfront uses + names like __Q2_3foo3bar for nested type names. So don't accept + this style of constructor for cfront demangling. A GNU + style member-template constructor starts with 'H'. */ + if (!(LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)) + work -> constructor += 1; + *mangled = scan + 2; + } + } + else if (ARM_DEMANGLING && scan[2] == 'p' && scan[3] == 't') + { + /* Cfront-style parameterized type. Handled later as a signature. */ + success = 1; + + /* ARM template? */ + demangle_arm_hp_template (work, mangled, strlen (*mangled), declp); + } + else if (EDG_DEMANGLING && ((scan[2] == 't' && scan[3] == 'm') + || (scan[2] == 'p' && scan[3] == 's') + || (scan[2] == 'p' && scan[3] == 't'))) + { + /* EDG-style parameterized type. Handled later as a signature. */ + success = 1; + + /* EDG template? */ + demangle_arm_hp_template (work, mangled, strlen (*mangled), declp); + } + else if ((scan == *mangled) && !ISDIGIT ((unsigned char)scan[2]) + && (scan[2] != 't')) + { + /* Mangled name starts with "__". Skip over any leading '_' characters, + then find the next "__" that separates the prefix from the signature. + */ + if (!(ARM_DEMANGLING || LUCID_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) + || (arm_special (mangled, declp) == 0)) + { + while (*scan == '_') + { + scan++; + } + if ((scan = strstr (scan, "__")) == NULL || (*(scan + 2) == '\0')) + { + /* No separator (I.E. "__not_mangled"), or empty signature + (I.E. "__not_mangled_either__") */ + success = 0; + } + else + return iterate_demangle_function (work, mangled, declp, scan); + } + } + else if (*(scan + 2) != '\0') + { + /* Mangled name does not start with "__" but does have one somewhere + in there with non empty stuff after it. Looks like a global + function name. Iterate over all "__":s until the right + one is found. */ + return iterate_demangle_function (work, mangled, declp, scan); + } + else + { + /* Doesn't look like a mangled name */ + success = 0; + } + + if (!success && (work->constructor == 2 || work->destructor == 2)) + { + string_append (declp, *mangled); + *mangled += strlen (*mangled); + success = 1; + } + return (success); +} + +/* + +LOCAL FUNCTION + + gnu_special -- special handling of gnu mangled strings + +SYNOPSIS + + static int + gnu_special (struct work_stuff *work, const char **mangled, + string *declp); + + +DESCRIPTION + + Process some special GNU style mangling forms that don't fit + the normal pattern. For example: + + _$_3foo (destructor for class foo) + _vt$foo (foo virtual table) + _vt$foo$bar (foo::bar virtual table) + __vt_foo (foo virtual table, new style with thunks) + _3foo$varname (static data member) + _Q22rs2tu$vw (static data member) + __t6vector1Zii (constructor with template) + __thunk_4__$_7ostream (virtual function thunk) + */ + +static int +gnu_special (struct work_stuff *work, const char **mangled, string *declp) +{ + int n; + int success = 1; + const char *p; + + if ((*mangled)[0] == '_' + && strchr (cplus_markers, (*mangled)[1]) != NULL + && (*mangled)[2] == '_') + { + /* Found a GNU style destructor, get past "__" */ + (*mangled) += 3; + work -> destructor += 1; + } + else if ((*mangled)[0] == '_' + && (((*mangled)[1] == '_' + && (*mangled)[2] == 'v' + && (*mangled)[3] == 't' + && (*mangled)[4] == '_') + || ((*mangled)[1] == 'v' + && (*mangled)[2] == 't' + && strchr (cplus_markers, (*mangled)[3]) != NULL))) + { + /* Found a GNU style virtual table, get past "_vt" + and create the decl. Note that we consume the entire mangled + input string, which means that demangle_signature has no work + to do. */ + if ((*mangled)[2] == 'v') + (*mangled) += 5; /* New style, with thunks: "__vt_" */ + else + (*mangled) += 4; /* Old style, no thunks: "_vt" */ + while (**mangled != '\0') + { + switch (**mangled) + { + case 'Q': + case 'K': + success = demangle_qualified (work, mangled, declp, 0, 1); + break; + case 't': + success = demangle_template (work, mangled, declp, 0, 1, + 1); + break; + default: + if (ISDIGIT((unsigned char)*mangled[0])) + { + n = consume_count(mangled); + /* We may be seeing a too-large size, or else a + "." indicating a static local symbol. In + any case, declare victory and move on; *don't* try + to use n to allocate. */ + if (n > (int) strlen (*mangled)) + { + success = 1; + break; + } + } + else + { + n = strcspn (*mangled, cplus_markers); + } + string_appendn (declp, *mangled, n); + (*mangled) += n; + } + + p = strpbrk (*mangled, cplus_markers); + if (success && ((p == NULL) || (p == *mangled))) + { + if (p != NULL) + { + string_append (declp, SCOPE_STRING (work)); + (*mangled)++; + } + } + else + { + success = 0; + break; + } + } + if (success) + string_append (declp, " virtual table"); + } + else if ((*mangled)[0] == '_' + && (strchr("0123456789Qt", (*mangled)[1]) != NULL) + && (p = strpbrk (*mangled, cplus_markers)) != NULL) + { + /* static data member, "_3foo$varname" for example */ + (*mangled)++; + switch (**mangled) + { + case 'Q': + case 'K': + success = demangle_qualified (work, mangled, declp, 0, 1); + break; + case 't': + success = demangle_template (work, mangled, declp, 0, 1, 1); + break; + default: + n = consume_count (mangled); + if (n < 0 || n > (long) strlen (*mangled)) + { + success = 0; + break; + } + + if (n > 10 && strncmp (*mangled, "_GLOBAL_", 8) == 0 + && (*mangled)[9] == 'N' + && (*mangled)[8] == (*mangled)[10] + && strchr (cplus_markers, (*mangled)[8])) + { + /* A member of the anonymous namespace. There's information + about what identifier or filename it was keyed to, but + it's just there to make the mangled name unique; we just + step over it. */ + string_append (declp, "{anonymous}"); + (*mangled) += n; + + /* Now p points to the marker before the N, so we need to + update it to the first marker after what we consumed. */ + p = strpbrk (*mangled, cplus_markers); + break; + } + + string_appendn (declp, *mangled, n); + (*mangled) += n; + } + if (success && (p == *mangled)) + { + /* Consumed everything up to the cplus_marker, append the + variable name. */ + (*mangled)++; + string_append (declp, SCOPE_STRING (work)); + n = strlen (*mangled); + string_appendn (declp, *mangled, n); + (*mangled) += n; + } + else + { + success = 0; + } + } + else if (strncmp (*mangled, "__thunk_", 8) == 0) + { + int delta; + + (*mangled) += 8; + delta = consume_count (mangled); + if (delta == -1) + success = 0; + else + { + char *method = internal_cplus_demangle (work, ++*mangled); + + if (method) + { + char buf[50]; + sprintf (buf, "virtual function thunk (delta:%d) for ", -delta); + string_append (declp, buf); + string_append (declp, method); + free (method); + n = strlen (*mangled); + (*mangled) += n; + } + else + { + success = 0; + } + } + } + else if (strncmp (*mangled, "__t", 3) == 0 + && ((*mangled)[3] == 'i' || (*mangled)[3] == 'f')) + { + p = (*mangled)[3] == 'i' ? " type_info node" : " type_info function"; + (*mangled) += 4; + switch (**mangled) + { + case 'Q': + case 'K': + success = demangle_qualified (work, mangled, declp, 0, 1); + break; + case 't': + success = demangle_template (work, mangled, declp, 0, 1, 1); + break; + default: + success = do_type (work, mangled, declp); + break; + } + if (success && **mangled != '\0') + success = 0; + if (success) + string_append (declp, p); + } + else + { + success = 0; + } + return (success); +} + +static void +recursively_demangle(struct work_stuff *work, const char **mangled, + string *result, int namelength) +{ + char * recurse = (char *)NULL; + char * recurse_dem = (char *)NULL; + + recurse = XNEWVEC (char, namelength + 1); + memcpy (recurse, *mangled, namelength); + recurse[namelength] = '\000'; + + recurse_dem = cplus_demangle (recurse, work->options); + + if (recurse_dem) + { + string_append (result, recurse_dem); + free (recurse_dem); + } + else + { + string_appendn (result, *mangled, namelength); + } + free (recurse); + *mangled += namelength; +} + +/* + +LOCAL FUNCTION + + arm_special -- special handling of ARM/lucid mangled strings + +SYNOPSIS + + static int + arm_special (const char **mangled, + string *declp); + + +DESCRIPTION + + Process some special ARM style mangling forms that don't fit + the normal pattern. For example: + + __vtbl__3foo (foo virtual table) + __vtbl__3foo__3bar (bar::foo virtual table) + + */ + +static int +arm_special (const char **mangled, string *declp) +{ + int n; + int success = 1; + const char *scan; + + if (strncmp (*mangled, ARM_VTABLE_STRING, ARM_VTABLE_STRLEN) == 0) + { + /* Found a ARM style virtual table, get past ARM_VTABLE_STRING + and create the decl. Note that we consume the entire mangled + input string, which means that demangle_signature has no work + to do. */ + scan = *mangled + ARM_VTABLE_STRLEN; + while (*scan != '\0') /* first check it can be demangled */ + { + n = consume_count (&scan); + if (n == -1) + { + return (0); /* no good */ + } + scan += n; + if (scan[0] == '_' && scan[1] == '_') + { + scan += 2; + } + } + (*mangled) += ARM_VTABLE_STRLEN; + while (**mangled != '\0') + { + n = consume_count (mangled); + if (n == -1 + || n > (long) strlen (*mangled)) + return 0; + string_prependn (declp, *mangled, n); + (*mangled) += n; + if ((*mangled)[0] == '_' && (*mangled)[1] == '_') + { + string_prepend (declp, "::"); + (*mangled) += 2; + } + } + string_append (declp, " virtual table"); + } + else + { + success = 0; + } + return (success); +} + +/* + +LOCAL FUNCTION + + demangle_qualified -- demangle 'Q' qualified name strings + +SYNOPSIS + + static int + demangle_qualified (struct work_stuff *, const char *mangled, + string *result, int isfuncname, int append); + +DESCRIPTION + + Demangle a qualified name, such as "Q25Outer5Inner" which is + the mangled form of "Outer::Inner". The demangled output is + prepended or appended to the result string according to the + state of the append flag. + + If isfuncname is nonzero, then the qualified name we are building + is going to be used as a member function name, so if it is a + constructor or destructor function, append an appropriate + constructor or destructor name. I.E. for the above example, + the result for use as a constructor is "Outer::Inner::Inner" + and the result for use as a destructor is "Outer::Inner::~Inner". + +BUGS + + Numeric conversion is ASCII dependent (FIXME). + + */ + +static int +demangle_qualified (struct work_stuff *work, const char **mangled, + string *result, int isfuncname, int append) +{ + int qualifiers = 0; + int success = 1; + char num[2]; + string temp; + string last_name; + int bindex = register_Btype (work); + + /* We only make use of ISFUNCNAME if the entity is a constructor or + destructor. */ + isfuncname = (isfuncname + && ((work->constructor & 1) || (work->destructor & 1))); + + string_init (&temp); + string_init (&last_name); + + if ((*mangled)[0] == 'K') + { + /* Squangling qualified name reuse */ + int idx; + (*mangled)++; + idx = consume_count_with_underscores (mangled); + if (idx == -1 || idx >= work -> numk) + success = 0; + else + string_append (&temp, work -> ktypevec[idx]); + } + else + switch ((*mangled)[1]) + { + case '_': + /* GNU mangled name with more than 9 classes. The count is preceded + by an underscore (to distinguish it from the <= 9 case) and followed + by an underscore. */ + (*mangled)++; + qualifiers = consume_count_with_underscores (mangled); + if (qualifiers == -1) + success = 0; + break; + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + /* The count is in a single digit. */ + num[0] = (*mangled)[1]; + num[1] = '\0'; + qualifiers = atoi (num); + + /* If there is an underscore after the digit, skip it. This is + said to be for ARM-qualified names, but the ARM makes no + mention of such an underscore. Perhaps cfront uses one. */ + if ((*mangled)[2] == '_') + { + (*mangled)++; + } + (*mangled) += 2; + break; + + case '0': + default: + success = 0; + } + + if (!success) + return success; + + /* Pick off the names and collect them in the temp buffer in the order + in which they are found, separated by '::'. */ + + while (qualifiers-- > 0) + { + int remember_K = 1; + string_clear (&last_name); + + if (*mangled[0] == '_') + (*mangled)++; + + if (*mangled[0] == 't') + { + /* Here we always append to TEMP since we will want to use + the template name without the template parameters as a + constructor or destructor name. The appropriate + (parameter-less) value is returned by demangle_template + in LAST_NAME. We do not remember the template type here, + in order to match the G++ mangling algorithm. */ + success = demangle_template(work, mangled, &temp, + &last_name, 1, 0); + if (!success) + break; + } + else if (*mangled[0] == 'K') + { + int idx; + (*mangled)++; + idx = consume_count_with_underscores (mangled); + if (idx == -1 || idx >= work->numk) + success = 0; + else + string_append (&temp, work->ktypevec[idx]); + remember_K = 0; + + if (!success) break; + } + else + { + if (EDG_DEMANGLING) + { + int namelength; + /* Now recursively demangle the qualifier + * This is necessary to deal with templates in + * mangling styles like EDG */ + namelength = consume_count (mangled); + if (namelength == -1) + { + success = 0; + break; + } + recursively_demangle(work, mangled, &temp, namelength); + } + else + { + string_delete (&last_name); + success = do_type (work, mangled, &last_name); + if (!success) + break; + string_appends (&temp, &last_name); + } + } + + if (remember_K) + remember_Ktype (work, temp.b, LEN_STRING (&temp)); + + if (qualifiers > 0) + string_append (&temp, SCOPE_STRING (work)); + } + + remember_Btype (work, temp.b, LEN_STRING (&temp), bindex); + + /* If we are using the result as a function name, we need to append + the appropriate '::' separated constructor or destructor name. + We do this here because this is the most convenient place, where + we already have a pointer to the name and the length of the name. */ + + if (isfuncname) + { + string_append (&temp, SCOPE_STRING (work)); + if (work -> destructor & 1) + string_append (&temp, "~"); + string_appends (&temp, &last_name); + } + + /* Now either prepend the temp buffer to the result, or append it, + depending upon the state of the append flag. */ + + if (append) + string_appends (result, &temp); + else + { + if (!STRING_EMPTY (result)) + string_append (&temp, SCOPE_STRING (work)); + string_prepends (result, &temp); + } + + string_delete (&last_name); + string_delete (&temp); + return (success); +} + +/* + +LOCAL FUNCTION + + get_count -- convert an ascii count to integer, consuming tokens + +SYNOPSIS + + static int + get_count (const char **type, int *count) + +DESCRIPTION + + Assume that *type points at a count in a mangled name; set + *count to its value, and set *type to the next character after + the count. There are some weird rules in effect here. + + If *type does not point at a string of digits, return zero. + + If *type points at a string of digits followed by an + underscore, set *count to their value as an integer, advance + *type to point *after the underscore, and return 1. + + If *type points at a string of digits not followed by an + underscore, consume only the first digit. Set *count to its + value as an integer, leave *type pointing after that digit, + and return 1. + + The excuse for this odd behavior: in the ARM and HP demangling + styles, a type can be followed by a repeat count of the form + `Nxy', where: + + `x' is a single digit specifying how many additional copies + of the type to append to the argument list, and + + `y' is one or more digits, specifying the zero-based index of + the first repeated argument in the list. Yes, as you're + unmangling the name you can figure this out yourself, but + it's there anyway. + + So, for example, in `bar__3fooFPiN51', the first argument is a + pointer to an integer (`Pi'), and then the next five arguments + are the same (`N5'), and the first repeat is the function's + second argument (`1'). +*/ + +static int +get_count (const char **type, int *count) +{ + const char *p; + int n; + + if (!ISDIGIT ((unsigned char)**type)) + return (0); + else + { + *count = **type - '0'; + (*type)++; + if (ISDIGIT ((unsigned char)**type)) + { + p = *type; + n = *count; + do + { + n *= 10; + n += *p - '0'; + p++; + } + while (ISDIGIT ((unsigned char)*p)); + if (*p == '_') + { + *type = p + 1; + *count = n; + } + } + } + return (1); +} + +/* RESULT will be initialised here; it will be freed on failure. The + value returned is really a type_kind_t. */ + +static int +do_type (struct work_stuff *work, const char **mangled, string *result) +{ + int n; + int done; + int success; + string decl; + const char *remembered_type; + int type_quals; + type_kind_t tk = tk_none; + + string_init (&decl); + string_init (result); + + done = 0; + success = 1; + while (success && !done) + { + int member; + switch (**mangled) + { + + /* A pointer type */ + case 'P': + case 'p': + (*mangled)++; + if (! (work -> options & DMGL_JAVA)) + string_prepend (&decl, "*"); + if (tk == tk_none) + tk = tk_pointer; + break; + + /* A reference type */ + case 'R': + (*mangled)++; + string_prepend (&decl, "&"); + if (tk == tk_none) + tk = tk_reference; + break; + + /* An array */ + case 'A': + { + ++(*mangled); + if (!STRING_EMPTY (&decl) + && (decl.b[0] == '*' || decl.b[0] == '&')) + { + string_prepend (&decl, "("); + string_append (&decl, ")"); + } + string_append (&decl, "["); + if (**mangled != '_') + success = demangle_template_value_parm (work, mangled, &decl, + tk_integral); + if (**mangled == '_') + ++(*mangled); + string_append (&decl, "]"); + break; + } + + /* A back reference to a previously seen type */ + case 'T': + (*mangled)++; + if (!get_count (mangled, &n) || n >= work -> ntypes) + { + success = 0; + } + else + { + remembered_type = work -> typevec[n]; + mangled = &remembered_type; + } + break; + + /* A function */ + case 'F': + (*mangled)++; + if (!STRING_EMPTY (&decl) + && (decl.b[0] == '*' || decl.b[0] == '&')) + { + string_prepend (&decl, "("); + string_append (&decl, ")"); + } + /* After picking off the function args, we expect to either find the + function return type (preceded by an '_') or the end of the + string. */ + if (!demangle_nested_args (work, mangled, &decl) + || (**mangled != '_' && **mangled != '\0')) + { + success = 0; + break; + } + if (success && (**mangled == '_')) + (*mangled)++; + break; + + case 'M': + case 'O': + { + type_quals = TYPE_UNQUALIFIED; + + member = **mangled == 'M'; + (*mangled)++; + + string_append (&decl, ")"); + + /* We don't need to prepend `::' for a qualified name; + demangle_qualified will do that for us. */ + if (**mangled != 'Q') + string_prepend (&decl, SCOPE_STRING (work)); + + if (ISDIGIT ((unsigned char)**mangled)) + { + n = consume_count (mangled); + if (n == -1 + || (int) strlen (*mangled) < n) + { + success = 0; + break; + } + string_prependn (&decl, *mangled, n); + *mangled += n; + } + else if (**mangled == 'X' || **mangled == 'Y') + { + string temp; + do_type (work, mangled, &temp); + string_prepends (&decl, &temp); + string_delete (&temp); + } + else if (**mangled == 't') + { + string temp; + string_init (&temp); + success = demangle_template (work, mangled, &temp, + NULL, 1, 1); + if (success) + { + string_prependn (&decl, temp.b, temp.p - temp.b); + string_delete (&temp); + } + else + break; + } + else if (**mangled == 'Q') + { + success = demangle_qualified (work, mangled, &decl, + /*isfuncnam=*/0, + /*append=*/0); + if (!success) + break; + } + else + { + success = 0; + break; + } + + string_prepend (&decl, "("); + if (member) + { + switch (**mangled) + { + case 'C': + case 'V': + case 'u': + type_quals |= code_for_qualifier (**mangled); + (*mangled)++; + break; + + default: + break; + } + + if (*(*mangled)++ != 'F') + { + success = 0; + break; + } + } + if ((member && !demangle_nested_args (work, mangled, &decl)) + || **mangled != '_') + { + success = 0; + break; + } + (*mangled)++; + if (! PRINT_ANSI_QUALIFIERS) + { + break; + } + if (type_quals != TYPE_UNQUALIFIED) + { + APPEND_BLANK (&decl); + string_append (&decl, qualifier_string (type_quals)); + } + break; + } + case 'G': + (*mangled)++; + break; + + case 'C': + case 'V': + case 'u': + if (PRINT_ANSI_QUALIFIERS) + { + if (!STRING_EMPTY (&decl)) + string_prepend (&decl, " "); + + string_prepend (&decl, demangle_qualifier (**mangled)); + } + (*mangled)++; + break; + /* + } + */ + + /* fall through */ + default: + done = 1; + break; + } + } + + if (success) switch (**mangled) + { + /* A qualified name, such as "Outer::Inner". */ + case 'Q': + case 'K': + { + success = demangle_qualified (work, mangled, result, 0, 1); + break; + } + + /* A back reference to a previously seen squangled type */ + case 'B': + (*mangled)++; + if (!get_count (mangled, &n) || n >= work -> numb) + success = 0; + else + string_append (result, work->btypevec[n]); + break; + + case 'X': + case 'Y': + /* A template parm. We substitute the corresponding argument. */ + { + int idx; + + (*mangled)++; + idx = consume_count_with_underscores (mangled); + + if (idx == -1 + || (work->tmpl_argvec && idx >= work->ntmpl_args) + || consume_count_with_underscores (mangled) == -1) + { + success = 0; + break; + } + + if (work->tmpl_argvec) + string_append (result, work->tmpl_argvec[idx]); + else + string_append_template_idx (result, idx); + + success = 1; + } + break; + + default: + success = demangle_fund_type (work, mangled, result); + if (tk == tk_none) + tk = (type_kind_t) success; + break; + } + + if (success) + { + if (!STRING_EMPTY (&decl)) + { + string_append (result, " "); + string_appends (result, &decl); + } + } + else + string_delete (result); + string_delete (&decl); + + if (success) + /* Assume an integral type, if we're not sure. */ + return (int) ((tk == tk_none) ? tk_integral : tk); + else + return 0; +} + +/* Given a pointer to a type string that represents a fundamental type + argument (int, long, unsigned int, etc) in TYPE, a pointer to the + string in which the demangled output is being built in RESULT, and + the WORK structure, decode the types and add them to the result. + + For example: + + "Ci" => "const int" + "Sl" => "signed long" + "CUs" => "const unsigned short" + + The value returned is really a type_kind_t. */ + +static int +demangle_fund_type (struct work_stuff *work, + const char **mangled, string *result) +{ + int done = 0; + int success = 1; + char buf[INTBUF_SIZE + 5 /* 'int%u_t' */]; + unsigned int dec = 0; + type_kind_t tk = tk_integral; + + /* First pick off any type qualifiers. There can be more than one. */ + + while (!done) + { + switch (**mangled) + { + case 'C': + case 'V': + case 'u': + if (PRINT_ANSI_QUALIFIERS) + { + if (!STRING_EMPTY (result)) + string_prepend (result, " "); + string_prepend (result, demangle_qualifier (**mangled)); + } + (*mangled)++; + break; + case 'U': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "unsigned"); + break; + case 'S': /* signed char only */ + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "signed"); + break; + case 'J': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "__complex"); + break; + default: + done = 1; + break; + } + } + + /* Now pick off the fundamental type. There can be only one. */ + + switch (**mangled) + { + case '\0': + case '_': + break; + case 'v': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "void"); + break; + case 'x': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "long long"); + break; + case 'l': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "long"); + break; + case 'i': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "int"); + break; + case 's': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "short"); + break; + case 'b': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "bool"); + tk = tk_bool; + break; + case 'c': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "char"); + tk = tk_char; + break; + case 'w': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "wchar_t"); + tk = tk_char; + break; + case 'r': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "long double"); + tk = tk_real; + break; + case 'd': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "double"); + tk = tk_real; + break; + case 'f': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "float"); + tk = tk_real; + break; + case 'G': + (*mangled)++; + if (!ISDIGIT ((unsigned char)**mangled)) + { + success = 0; + break; + } + case 'I': + (*mangled)++; + if (**mangled == '_') + { + int i; + (*mangled)++; + for (i = 0; + i < (long) sizeof (buf) - 1 && **mangled && **mangled != '_'; + (*mangled)++, i++) + buf[i] = **mangled; + if (**mangled != '_') + { + success = 0; + break; + } + buf[i] = '\0'; + (*mangled)++; + } + else + { + strncpy (buf, *mangled, 2); + buf[2] = '\0'; + *mangled += min (strlen (*mangled), 2); + } + sscanf (buf, "%x", &dec); + sprintf (buf, "int%u_t", dec); + APPEND_BLANK (result); + string_append (result, buf); + break; + + /* fall through */ + /* An explicit type, such as "6mytype" or "7integer" */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + int bindex = register_Btype (work); + string btype; + string_init (&btype); + if (demangle_class_name (work, mangled, &btype)) { + remember_Btype (work, btype.b, LEN_STRING (&btype), bindex); + APPEND_BLANK (result); + string_appends (result, &btype); + } + else + success = 0; + string_delete (&btype); + break; + } + case 't': + { + string btype; + string_init (&btype); + success = demangle_template (work, mangled, &btype, 0, 1, 1); + string_appends (result, &btype); + string_delete (&btype); + break; + } + default: + success = 0; + break; + } + + return success ? ((int) tk) : 0; +} + + +/* Handle a template's value parameter for HP aCC (extension from ARM) + **mangled points to 'S' or 'U' */ + +static int +do_hpacc_template_const_value (struct work_stuff *work ATTRIBUTE_UNUSED, + const char **mangled, string *result) +{ + int unsigned_const; + + if (**mangled != 'U' && **mangled != 'S') + return 0; + + unsigned_const = (**mangled == 'U'); + + (*mangled)++; + + switch (**mangled) + { + case 'N': + string_append (result, "-"); + /* fall through */ + case 'P': + (*mangled)++; + break; + case 'M': + /* special case for -2^31 */ + string_append (result, "-2147483648"); + (*mangled)++; + return 1; + default: + return 0; + } + + /* We have to be looking at an integer now */ + if (!(ISDIGIT ((unsigned char)**mangled))) + return 0; + + /* We only deal with integral values for template + parameters -- so it's OK to look only for digits */ + while (ISDIGIT ((unsigned char)**mangled)) + { + char_str[0] = **mangled; + string_append (result, char_str); + (*mangled)++; + } + + if (unsigned_const) + string_append (result, "U"); + + /* FIXME? Some day we may have 64-bit (or larger :-) ) constants + with L or LL suffixes. pai/1997-09-03 */ + + return 1; /* success */ +} + +/* Handle a template's literal parameter for HP aCC (extension from ARM) + **mangled is pointing to the 'A' */ + +static int +do_hpacc_template_literal (struct work_stuff *work, const char **mangled, + string *result) +{ + int literal_len = 0; + char * recurse; + char * recurse_dem; + + if (**mangled != 'A') + return 0; + + (*mangled)++; + + literal_len = consume_count (mangled); + + if (literal_len <= 0) + return 0; + + /* Literal parameters are names of arrays, functions, etc. and the + canonical representation uses the address operator */ + string_append (result, "&"); + + /* Now recursively demangle the literal name */ + recurse = XNEWVEC (char, literal_len + 1); + memcpy (recurse, *mangled, literal_len); + recurse[literal_len] = '\000'; + + recurse_dem = cplus_demangle (recurse, work->options); + + if (recurse_dem) + { + string_append (result, recurse_dem); + free (recurse_dem); + } + else + { + string_appendn (result, *mangled, literal_len); + } + (*mangled) += literal_len; + free (recurse); + + return 1; +} + +static int +snarf_numeric_literal (const char **args, string *arg) +{ + if (**args == '-') + { + char_str[0] = '-'; + string_append (arg, char_str); + (*args)++; + } + else if (**args == '+') + (*args)++; + + if (!ISDIGIT ((unsigned char)**args)) + return 0; + + while (ISDIGIT ((unsigned char)**args)) + { + char_str[0] = **args; + string_append (arg, char_str); + (*args)++; + } + + return 1; +} + +/* Demangle the next argument, given by MANGLED into RESULT, which + *should be an uninitialized* string. It will be initialized here, + and free'd should anything go wrong. */ + +static int +do_arg (struct work_stuff *work, const char **mangled, string *result) +{ + /* Remember where we started so that we can record the type, for + non-squangling type remembering. */ + const char *start = *mangled; + + string_init (result); + + if (work->nrepeats > 0) + { + --work->nrepeats; + + if (work->previous_argument == 0) + return 0; + + /* We want to reissue the previous type in this argument list. */ + string_appends (result, work->previous_argument); + return 1; + } + + if (**mangled == 'n') + { + /* A squangling-style repeat. */ + (*mangled)++; + work->nrepeats = consume_count(mangled); + + if (work->nrepeats <= 0) + /* This was not a repeat count after all. */ + return 0; + + if (work->nrepeats > 9) + { + if (**mangled != '_') + /* The repeat count should be followed by an '_' in this + case. */ + return 0; + else + (*mangled)++; + } + + /* Now, the repeat is all set up. */ + return do_arg (work, mangled, result); + } + + /* Save the result in WORK->previous_argument so that we can find it + if it's repeated. Note that saving START is not good enough: we + do not want to add additional types to the back-referenceable + type vector when processing a repeated type. */ + if (work->previous_argument) + string_delete (work->previous_argument); + else + work->previous_argument = XNEW (string); + + if (!do_type (work, mangled, work->previous_argument)) + return 0; + + string_appends (result, work->previous_argument); + + remember_type (work, start, *mangled - start); + return 1; +} + +static void +remember_type (struct work_stuff *work, const char *start, int len) +{ + char *tem; + + if (work->forgetting_types) + return; + + if (work -> ntypes >= work -> typevec_size) + { + if (work -> typevec_size == 0) + { + work -> typevec_size = 3; + work -> typevec = XNEWVEC (char *, work->typevec_size); + } + else + { + work -> typevec_size *= 2; + work -> typevec + = XRESIZEVEC (char *, work->typevec, work->typevec_size); + } + } + tem = XNEWVEC (char, len + 1); + memcpy (tem, start, len); + tem[len] = '\0'; + work -> typevec[work -> ntypes++] = tem; +} + + +/* Remember a K type class qualifier. */ +static void +remember_Ktype (struct work_stuff *work, const char *start, int len) +{ + char *tem; + + if (work -> numk >= work -> ksize) + { + if (work -> ksize == 0) + { + work -> ksize = 5; + work -> ktypevec = XNEWVEC (char *, work->ksize); + } + else + { + work -> ksize *= 2; + work -> ktypevec + = XRESIZEVEC (char *, work->ktypevec, work->ksize); + } + } + tem = XNEWVEC (char, len + 1); + memcpy (tem, start, len); + tem[len] = '\0'; + work -> ktypevec[work -> numk++] = tem; +} + +/* Register a B code, and get an index for it. B codes are registered + as they are seen, rather than as they are completed, so map > + registers map > as B0, and temp as B1 */ + +static int +register_Btype (struct work_stuff *work) +{ + int ret; + + if (work -> numb >= work -> bsize) + { + if (work -> bsize == 0) + { + work -> bsize = 5; + work -> btypevec = XNEWVEC (char *, work->bsize); + } + else + { + work -> bsize *= 2; + work -> btypevec + = XRESIZEVEC (char *, work->btypevec, work->bsize); + } + } + ret = work -> numb++; + work -> btypevec[ret] = NULL; + return(ret); +} + +/* Store a value into a previously registered B code type. */ + +static void +remember_Btype (struct work_stuff *work, const char *start, + int len, int index) +{ + char *tem; + + tem = XNEWVEC (char, len + 1); + memcpy (tem, start, len); + tem[len] = '\0'; + work -> btypevec[index] = tem; +} + +/* Lose all the info related to B and K type codes. */ +static void +forget_B_and_K_types (struct work_stuff *work) +{ + int i; + + while (work -> numk > 0) + { + i = --(work -> numk); + if (work -> ktypevec[i] != NULL) + { + free (work -> ktypevec[i]); + work -> ktypevec[i] = NULL; + } + } + + while (work -> numb > 0) + { + i = --(work -> numb); + if (work -> btypevec[i] != NULL) + { + free (work -> btypevec[i]); + work -> btypevec[i] = NULL; + } + } +} +/* Forget the remembered types, but not the type vector itself. */ + +static void +forget_types (struct work_stuff *work) +{ + int i; + + while (work -> ntypes > 0) + { + i = --(work -> ntypes); + if (work -> typevec[i] != NULL) + { + free (work -> typevec[i]); + work -> typevec[i] = NULL; + } + } +} + +/* Process the argument list part of the signature, after any class spec + has been consumed, as well as the first 'F' character (if any). For + example: + + "__als__3fooRT0" => process "RT0" + "complexfunc5__FPFPc_PFl_i" => process "PFPc_PFl_i" + + DECLP must be already initialised, usually non-empty. It won't be freed + on failure. + + Note that g++ differs significantly from ARM and lucid style mangling + with regards to references to previously seen types. For example, given + the source fragment: + + class foo { + public: + foo::foo (int, foo &ia, int, foo &ib, int, foo &ic); + }; + + foo::foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; } + void foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; } + + g++ produces the names: + + __3fooiRT0iT2iT2 + foo__FiR3fooiT1iT1 + + while lcc (and presumably other ARM style compilers as well) produces: + + foo__FiR3fooT1T2T1T2 + __ct__3fooFiR3fooT1T2T1T2 + + Note that g++ bases its type numbers starting at zero and counts all + previously seen types, while lucid/ARM bases its type numbers starting + at one and only considers types after it has seen the 'F' character + indicating the start of the function args. For lucid/ARM style, we + account for this difference by discarding any previously seen types when + we see the 'F' character, and subtracting one from the type number + reference. + + */ + +static int +demangle_args (struct work_stuff *work, const char **mangled, + string *declp) +{ + string arg; + int need_comma = 0; + int r; + int t; + const char *tem; + char temptype; + + if (PRINT_ARG_TYPES) + { + string_append (declp, "("); + if (**mangled == '\0') + { + string_append (declp, "void"); + } + } + + while ((**mangled != '_' && **mangled != '\0' && **mangled != 'e') + || work->nrepeats > 0) + { + if ((**mangled == 'N') || (**mangled == 'T')) + { + temptype = *(*mangled)++; + + if (temptype == 'N') + { + if (!get_count (mangled, &r)) + { + return (0); + } + } + else + { + r = 1; + } + if ((HP_DEMANGLING || ARM_DEMANGLING || EDG_DEMANGLING) && work -> ntypes >= 10) + { + /* If we have 10 or more types we might have more than a 1 digit + index so we'll have to consume the whole count here. This + will lose if the next thing is a type name preceded by a + count but it's impossible to demangle that case properly + anyway. Eg if we already have 12 types is T12Pc "(..., type1, + Pc, ...)" or "(..., type12, char *, ...)" */ + if ((t = consume_count(mangled)) <= 0) + { + return (0); + } + } + else + { + if (!get_count (mangled, &t)) + { + return (0); + } + } + if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) + { + t--; + } + /* Validate the type index. Protect against illegal indices from + malformed type strings. */ + if ((t < 0) || (t >= work -> ntypes)) + { + return (0); + } + while (work->nrepeats > 0 || --r >= 0) + { + tem = work -> typevec[t]; + if (need_comma && PRINT_ARG_TYPES) + { + string_append (declp, ", "); + } + if (!do_arg (work, &tem, &arg)) + { + return (0); + } + if (PRINT_ARG_TYPES) + { + string_appends (declp, &arg); + } + string_delete (&arg); + need_comma = 1; + } + } + else + { + if (need_comma && PRINT_ARG_TYPES) + string_append (declp, ", "); + if (!do_arg (work, mangled, &arg)) + return (0); + if (PRINT_ARG_TYPES) + string_appends (declp, &arg); + string_delete (&arg); + need_comma = 1; + } + } + + if (**mangled == 'e') + { + (*mangled)++; + if (PRINT_ARG_TYPES) + { + if (need_comma) + { + string_append (declp, ","); + } + string_append (declp, "..."); + } + } + + if (PRINT_ARG_TYPES) + { + string_append (declp, ")"); + } + return (1); +} + +/* Like demangle_args, but for demangling the argument lists of function + and method pointers or references, not top-level declarations. */ + +static int +demangle_nested_args (struct work_stuff *work, const char **mangled, + string *declp) +{ + string* saved_previous_argument; + int result; + int saved_nrepeats; + + /* The G++ name-mangling algorithm does not remember types on nested + argument lists, unless -fsquangling is used, and in that case the + type vector updated by remember_type is not used. So, we turn + off remembering of types here. */ + ++work->forgetting_types; + + /* For the repeat codes used with -fsquangling, we must keep track of + the last argument. */ + saved_previous_argument = work->previous_argument; + saved_nrepeats = work->nrepeats; + work->previous_argument = 0; + work->nrepeats = 0; + + /* Actually demangle the arguments. */ + result = demangle_args (work, mangled, declp); + + /* Restore the previous_argument field. */ + if (work->previous_argument) + { + string_delete (work->previous_argument); + free ((char *) work->previous_argument); + } + work->previous_argument = saved_previous_argument; + --work->forgetting_types; + work->nrepeats = saved_nrepeats; + + return result; +} + +static void +demangle_function_name (struct work_stuff *work, const char **mangled, + string *declp, const char *scan) +{ + size_t i; + string type; + const char *tem; + + string_appendn (declp, (*mangled), scan - (*mangled)); + string_need (declp, 1); + *(declp -> p) = '\0'; + + /* Consume the function name, including the "__" separating the name + from the signature. We are guaranteed that SCAN points to the + separator. */ + + (*mangled) = scan + 2; + /* We may be looking at an instantiation of a template function: + foo__Xt1t2_Ft3t4, where t1, t2, ... are template arguments and a + following _F marks the start of the function arguments. Handle + the template arguments first. */ + + if (HP_DEMANGLING && (**mangled == 'X')) + { + demangle_arm_hp_template (work, mangled, 0, declp); + /* This leaves MANGLED pointing to the 'F' marking func args */ + } + + if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) + { + + /* See if we have an ARM style constructor or destructor operator. + If so, then just record it, clear the decl, and return. + We can't build the actual constructor/destructor decl until later, + when we recover the class name from the signature. */ + + if (strcmp (declp -> b, "__ct") == 0) + { + work -> constructor += 1; + string_clear (declp); + return; + } + else if (strcmp (declp -> b, "__dt") == 0) + { + work -> destructor += 1; + string_clear (declp); + return; + } + } + + if (declp->p - declp->b >= 3 + && declp->b[0] == 'o' + && declp->b[1] == 'p' + && strchr (cplus_markers, declp->b[2]) != NULL) + { + /* see if it's an assignment expression */ + if (declp->p - declp->b >= 10 /* op$assign_ */ + && memcmp (declp->b + 3, "assign_", 7) == 0) + { + for (i = 0; i < ARRAY_SIZE (optable); i++) + { + int len = declp->p - declp->b - 10; + if ((int) strlen (optable[i].in) == len + && memcmp (optable[i].in, declp->b + 10, len) == 0) + { + string_clear (declp); + string_append (declp, "operator"); + string_append (declp, optable[i].out); + string_append (declp, "="); + break; + } + } + } + else + { + for (i = 0; i < ARRAY_SIZE (optable); i++) + { + int len = declp->p - declp->b - 3; + if ((int) strlen (optable[i].in) == len + && memcmp (optable[i].in, declp->b + 3, len) == 0) + { + string_clear (declp); + string_append (declp, "operator"); + string_append (declp, optable[i].out); + break; + } + } + } + } + else if (declp->p - declp->b >= 5 && memcmp (declp->b, "type", 4) == 0 + && strchr (cplus_markers, declp->b[4]) != NULL) + { + /* type conversion operator */ + tem = declp->b + 5; + if (do_type (work, &tem, &type)) + { + string_clear (declp); + string_append (declp, "operator "); + string_appends (declp, &type); + string_delete (&type); + } + } + else if (declp->b[0] == '_' && declp->b[1] == '_' + && declp->b[2] == 'o' && declp->b[3] == 'p') + { + /* ANSI. */ + /* type conversion operator. */ + tem = declp->b + 4; + if (do_type (work, &tem, &type)) + { + string_clear (declp); + string_append (declp, "operator "); + string_appends (declp, &type); + string_delete (&type); + } + } + else if (declp->b[0] == '_' && declp->b[1] == '_' + && ISLOWER((unsigned char)declp->b[2]) + && ISLOWER((unsigned char)declp->b[3])) + { + if (declp->b[4] == '\0') + { + /* Operator. */ + for (i = 0; i < ARRAY_SIZE (optable); i++) + { + if (strlen (optable[i].in) == 2 + && memcmp (optable[i].in, declp->b + 2, 2) == 0) + { + string_clear (declp); + string_append (declp, "operator"); + string_append (declp, optable[i].out); + break; + } + } + } + else + { + if (declp->b[2] == 'a' && declp->b[5] == '\0') + { + /* Assignment. */ + for (i = 0; i < ARRAY_SIZE (optable); i++) + { + if (strlen (optable[i].in) == 3 + && memcmp (optable[i].in, declp->b + 2, 3) == 0) + { + string_clear (declp); + string_append (declp, "operator"); + string_append (declp, optable[i].out); + break; + } + } + } + } + } +} + +/* a mini string-handling package */ + +static void +string_need (string *s, int n) +{ + int tem; + + if (s->b == NULL) + { + if (n < 32) + { + n = 32; + } + s->p = s->b = XNEWVEC (char, n); + s->e = s->b + n; + } + else if (s->e - s->p < n) + { + tem = s->p - s->b; + n += tem; + n *= 2; + s->b = XRESIZEVEC (char, s->b, n); + s->p = s->b + tem; + s->e = s->b + n; + } +} + +static void +string_delete (string *s) +{ + if (s->b != NULL) + { + free (s->b); + s->b = s->e = s->p = NULL; + } +} + +static void +string_init (string *s) +{ + s->b = s->p = s->e = NULL; +} + +static void +string_clear (string *s) +{ + s->p = s->b; +} + +#if 0 + +static int +string_empty (string *s) +{ + return (s->b == s->p); +} + +#endif + +static void +string_append (string *p, const char *s) +{ + int n; + if (s == NULL || *s == '\0') + return; + n = strlen (s); + string_need (p, n); + memcpy (p->p, s, n); + p->p += n; +} + +static void +string_appends (string *p, string *s) +{ + int n; + + if (s->b != s->p) + { + n = s->p - s->b; + string_need (p, n); + memcpy (p->p, s->b, n); + p->p += n; + } +} + +static void +string_appendn (string *p, const char *s, int n) +{ + if (n != 0) + { + string_need (p, n); + memcpy (p->p, s, n); + p->p += n; + } +} + +static void +string_prepend (string *p, const char *s) +{ + if (s != NULL && *s != '\0') + { + string_prependn (p, s, strlen (s)); + } +} + +static void +string_prepends (string *p, string *s) +{ + if (s->b != s->p) + { + string_prependn (p, s->b, s->p - s->b); + } +} + +static void +string_prependn (string *p, const char *s, int n) +{ + char *q; + + if (n != 0) + { + string_need (p, n); + for (q = p->p - 1; q >= p->b; q--) + { + q[n] = q[0]; + } + memcpy (p->b, s, n); + p->p += n; + } +} + +static void +string_append_template_idx (string *s, int idx) +{ + char buf[INTBUF_SIZE + 1 /* 'T' */]; + sprintf(buf, "T%d", idx); + string_append (s, buf); +} diff --git a/libiberty/dyn-string.c b/libiberty/dyn-string.c new file mode 100644 index 0000000..9de50ed --- /dev/null +++ b/libiberty/dyn-string.c @@ -0,0 +1,397 @@ +/* An abstract string datatype. + Copyright (C) 1998, 1999, 2000, 2002, 2004 Free Software Foundation, Inc. + Contributed by Mark Mitchell (mark@markmitchell.com). + +This file is part of GNU CC. + +GNU CC is free software; you can 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, or (at your option) +any later version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file into combinations with other programs, +and to distribute those combinations without any restriction coming +from the use of this file. (The General Public License restrictions +do apply in other respects; for example, they cover modification of +the file, and distribution when not linked into a combined +executable.) + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#ifdef HAVE_STRING_H +#include +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif + +#include "libiberty.h" +#include "dyn-string.h" + +/* Performs in-place initialization of a dyn_string struct. This + function can be used with a dyn_string struct on the stack or + embedded in another object. The contents of of the string itself + are still dynamically allocated. The string initially is capable + of holding at least SPACE characeters, including the terminating + NUL. If SPACE is 0, it will silently be increated to 1. + + If RETURN_ON_ALLOCATION_FAILURE is defined and memory allocation + fails, returns 0. Otherwise returns 1. */ + +int +dyn_string_init (struct dyn_string *ds_struct_ptr, int space) +{ + /* We need at least one byte in which to store the terminating NUL. */ + if (space == 0) + space = 1; + +#ifdef RETURN_ON_ALLOCATION_FAILURE + ds_struct_ptr->s = (char *) malloc (space); + if (ds_struct_ptr->s == NULL) + return 0; +#else + ds_struct_ptr->s = XNEWVEC (char, space); +#endif + ds_struct_ptr->allocated = space; + ds_struct_ptr->length = 0; + ds_struct_ptr->s[0] = '\0'; + + return 1; +} + +/* Create a new dynamic string capable of holding at least SPACE + characters, including the terminating NUL. If SPACE is 0, it will + be silently increased to 1. If RETURN_ON_ALLOCATION_FAILURE is + defined and memory allocation fails, returns NULL. Otherwise + returns the newly allocated string. */ + +dyn_string_t +dyn_string_new (int space) +{ + dyn_string_t result; +#ifdef RETURN_ON_ALLOCATION_FAILURE + result = (dyn_string_t) malloc (sizeof (struct dyn_string)); + if (result == NULL) + return NULL; + if (!dyn_string_init (result, space)) + { + free (result); + return NULL; + } +#else + result = XNEW (struct dyn_string); + dyn_string_init (result, space); +#endif + return result; +} + +/* Free the memory used by DS. */ + +void +dyn_string_delete (dyn_string_t ds) +{ + free (ds->s); + free (ds); +} + +/* Returns the contents of DS in a buffer allocated with malloc. It + is the caller's responsibility to deallocate the buffer using free. + DS is then set to the empty string. Deletes DS itself. */ + +char* +dyn_string_release (dyn_string_t ds) +{ + /* Store the old buffer. */ + char* result = ds->s; + /* The buffer is no longer owned by DS. */ + ds->s = NULL; + /* Delete DS. */ + free (ds); + /* Return the old buffer. */ + return result; +} + +/* Increase the capacity of DS so it can hold at least SPACE + characters, plus the terminating NUL. This function will not (at + present) reduce the capacity of DS. Returns DS on success. + + If RETURN_ON_ALLOCATION_FAILURE is defined and a memory allocation + operation fails, deletes DS and returns NULL. */ + +dyn_string_t +dyn_string_resize (dyn_string_t ds, int space) +{ + int new_allocated = ds->allocated; + + /* Increase SPACE to hold the NUL termination. */ + ++space; + + /* Increase allocation by factors of two. */ + while (space > new_allocated) + new_allocated *= 2; + + if (new_allocated != ds->allocated) + { + ds->allocated = new_allocated; + /* We actually need more space. */ +#ifdef RETURN_ON_ALLOCATION_FAILURE + ds->s = (char *) realloc (ds->s, ds->allocated); + if (ds->s == NULL) + { + free (ds); + return NULL; + } +#else + ds->s = XRESIZEVEC (char, ds->s, ds->allocated); +#endif + } + + return ds; +} + +/* Sets the contents of DS to the empty string. */ + +void +dyn_string_clear (dyn_string_t ds) +{ + /* A dyn_string always has room for at least the NUL terminator. */ + ds->s[0] = '\0'; + ds->length = 0; +} + +/* Makes the contents of DEST the same as the contents of SRC. DEST + and SRC must be distinct. Returns 1 on success. On failure, if + RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */ + +int +dyn_string_copy (dyn_string_t dest, dyn_string_t src) +{ + if (dest == src) + abort (); + + /* Make room in DEST. */ + if (dyn_string_resize (dest, src->length) == NULL) + return 0; + /* Copy DEST into SRC. */ + strcpy (dest->s, src->s); + /* Update the size of DEST. */ + dest->length = src->length; + return 1; +} + +/* Copies SRC, a NUL-terminated string, into DEST. Returns 1 on + success. On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST + and returns 0. */ + +int +dyn_string_copy_cstr (dyn_string_t dest, const char *src) +{ + int length = strlen (src); + /* Make room in DEST. */ + if (dyn_string_resize (dest, length) == NULL) + return 0; + /* Copy DEST into SRC. */ + strcpy (dest->s, src); + /* Update the size of DEST. */ + dest->length = length; + return 1; +} + +/* Inserts SRC at the beginning of DEST. DEST is expanded as + necessary. SRC and DEST must be distinct. Returns 1 on success. + On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and + returns 0. */ + +int +dyn_string_prepend (dyn_string_t dest, dyn_string_t src) +{ + return dyn_string_insert (dest, 0, src); +} + +/* Inserts SRC, a NUL-terminated string, at the beginning of DEST. + DEST is expanded as necessary. Returns 1 on success. On failure, + if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */ + +int +dyn_string_prepend_cstr (dyn_string_t dest, const char *src) +{ + return dyn_string_insert_cstr (dest, 0, src); +} + +/* Inserts SRC into DEST starting at position POS. DEST is expanded + as necessary. SRC and DEST must be distinct. Returns 1 on + success. On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST + and returns 0. */ + +int +dyn_string_insert (dyn_string_t dest, int pos, dyn_string_t src) +{ + int i; + + if (src == dest) + abort (); + + if (dyn_string_resize (dest, dest->length + src->length) == NULL) + return 0; + /* Make room for the insertion. Be sure to copy the NUL. */ + for (i = dest->length; i >= pos; --i) + dest->s[i + src->length] = dest->s[i]; + /* Splice in the new stuff. */ + strncpy (dest->s + pos, src->s, src->length); + /* Compute the new length. */ + dest->length += src->length; + return 1; +} + +/* Inserts SRC, a NUL-terminated string, into DEST starting at + position POS. DEST is expanded as necessary. Returns 1 on + success. On failure, RETURN_ON_ALLOCATION_FAILURE, deletes DEST + and returns 0. */ + +int +dyn_string_insert_cstr (dyn_string_t dest, int pos, const char *src) +{ + int i; + int length = strlen (src); + + if (dyn_string_resize (dest, dest->length + length) == NULL) + return 0; + /* Make room for the insertion. Be sure to copy the NUL. */ + for (i = dest->length; i >= pos; --i) + dest->s[i + length] = dest->s[i]; + /* Splice in the new stuff. */ + strncpy (dest->s + pos, src, length); + /* Compute the new length. */ + dest->length += length; + return 1; +} + +/* Inserts character C into DEST starting at position POS. DEST is + expanded as necessary. Returns 1 on success. On failure, + RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */ + +int +dyn_string_insert_char (dyn_string_t dest, int pos, int c) +{ + int i; + + if (dyn_string_resize (dest, dest->length + 1) == NULL) + return 0; + /* Make room for the insertion. Be sure to copy the NUL. */ + for (i = dest->length; i >= pos; --i) + dest->s[i + 1] = dest->s[i]; + /* Add the new character. */ + dest->s[pos] = c; + /* Compute the new length. */ + ++dest->length; + return 1; +} + +/* Append S to DS, resizing DS if necessary. Returns 1 on success. + On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and + returns 0. */ + +int +dyn_string_append (dyn_string_t dest, dyn_string_t s) +{ + if (dyn_string_resize (dest, dest->length + s->length) == 0) + return 0; + strcpy (dest->s + dest->length, s->s); + dest->length += s->length; + return 1; +} + +/* Append the NUL-terminated string S to DS, resizing DS if necessary. + Returns 1 on success. On failure, if RETURN_ON_ALLOCATION_FAILURE, + deletes DEST and returns 0. */ + +int +dyn_string_append_cstr (dyn_string_t dest, const char *s) +{ + int len = strlen (s); + + /* The new length is the old length plus the size of our string, plus + one for the null at the end. */ + if (dyn_string_resize (dest, dest->length + len) == NULL) + return 0; + strcpy (dest->s + dest->length, s); + dest->length += len; + return 1; +} + +/* Appends C to the end of DEST. Returns 1 on success. On failiure, + if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */ + +int +dyn_string_append_char (dyn_string_t dest, int c) +{ + /* Make room for the extra character. */ + if (dyn_string_resize (dest, dest->length + 1) == NULL) + return 0; + /* Append the character; it will overwrite the old NUL. */ + dest->s[dest->length] = c; + /* Add a new NUL at the end. */ + dest->s[dest->length + 1] = '\0'; + /* Update the length. */ + ++(dest->length); + return 1; +} + +/* Sets the contents of DEST to the substring of SRC starting at START + and ending before END. START must be less than or equal to END, + and both must be between zero and the length of SRC, inclusive. + Returns 1 on success. On failure, if RETURN_ON_ALLOCATION_FAILURE, + deletes DEST and returns 0. */ + +int +dyn_string_substring (dyn_string_t dest, dyn_string_t src, + int start, int end) +{ + int i; + int length = end - start; + + if (start > end || start > src->length || end > src->length) + abort (); + + /* Make room for the substring. */ + if (dyn_string_resize (dest, length) == NULL) + return 0; + /* Copy the characters in the substring, */ + for (i = length; --i >= 0; ) + dest->s[i] = src->s[start + i]; + /* NUL-terimate the result. */ + dest->s[length] = '\0'; + /* Record the length of the substring. */ + dest->length = length; + + return 1; +} + +/* Returns non-zero if DS1 and DS2 have the same contents. */ + +int +dyn_string_eq (dyn_string_t ds1, dyn_string_t ds2) +{ + /* If DS1 and DS2 have different lengths, they must not be the same. */ + if (ds1->length != ds2->length) + return 0; + else + return !strcmp (ds1->s, ds2->s); +} diff --git a/libiberty/fdmatch.c b/libiberty/fdmatch.c new file mode 100644 index 0000000..f613cb3 --- /dev/null +++ b/libiberty/fdmatch.c @@ -0,0 +1,68 @@ +/* Compare two open file descriptors to see if they refer to the same file. + Copyright (C) 1991 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + + +/* + +@deftypefn Extension int fdmatch (int @var{fd1}, int @var{fd2}) + +Check to see if two open file descriptors refer to the same file. +This is useful, for example, when we have an open file descriptor for +an unnamed file, and the name of a file that we believe to correspond +to that fd. This can happen when we are exec'd with an already open +file (@code{stdout} for example) or from the SVR4 @file{/proc} calls +that return open file descriptors for mapped address spaces. All we +have to do is open the file by name and check the two file descriptors +for a match, which is done by comparing major and minor device numbers +and inode numbers. + +@end deftypefn + +BUGS + + (FIXME: does this work for networks?) + It works for NFS, which assigns a device number to each mount. + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "ansidecl.h" +#include "libiberty.h" +#include +#include + +int fdmatch (int fd1, int fd2) +{ + struct stat sbuf1; + struct stat sbuf2; + + if ((fstat (fd1, &sbuf1) == 0) && + (fstat (fd2, &sbuf2) == 0) && + (sbuf1.st_dev == sbuf2.st_dev) && + (sbuf1.st_ino == sbuf2.st_ino)) + { + return (1); + } + else + { + return (0); + } +} diff --git a/libiberty/ffs.c b/libiberty/ffs.c new file mode 100644 index 0000000..603cbe8 --- /dev/null +++ b/libiberty/ffs.c @@ -0,0 +1,26 @@ +/* ffs -- Find the first bit set in the parameter + +@deftypefn Supplemental int ffs (int @var{valu}) + +Find the first (least significant) bit set in @var{valu}. Bits are +numbered from right to left, starting with bit 1 (corresponding to the +value 1). If @var{valu} is zero, zero is returned. + +@end deftypefn + +*/ + +int +ffs (register int valu) +{ + register int bit; + + if (valu == 0) + return 0; + + for (bit = 1; !(valu & 1); bit++) + valu >>= 1; + + return bit; +} + diff --git a/libiberty/fibheap.c b/libiberty/fibheap.c new file mode 100644 index 0000000..c032149 --- /dev/null +++ b/libiberty/fibheap.c @@ -0,0 +1,478 @@ +/* A Fibonacci heap datatype. + Copyright 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + Contributed by Daniel Berlin (dan@cgsoftware.com). + +This file is part of GNU CC. + +GNU CC is free software; you can 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, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include "libiberty.h" +#include "fibheap.h" + + +#define FIBHEAPKEY_MIN LONG_MIN + +static void fibheap_ins_root (fibheap_t, fibnode_t); +static void fibheap_rem_root (fibheap_t, fibnode_t); +static void fibheap_consolidate (fibheap_t); +static void fibheap_link (fibheap_t, fibnode_t, fibnode_t); +static void fibheap_cut (fibheap_t, fibnode_t, fibnode_t); +static void fibheap_cascading_cut (fibheap_t, fibnode_t); +static fibnode_t fibheap_extr_min_node (fibheap_t); +static int fibheap_compare (fibheap_t, fibnode_t, fibnode_t); +static int fibheap_comp_data (fibheap_t, fibheapkey_t, void *, fibnode_t); +static fibnode_t fibnode_new (void); +static void fibnode_insert_after (fibnode_t, fibnode_t); +#define fibnode_insert_before(a, b) fibnode_insert_after (a->left, b) +static fibnode_t fibnode_remove (fibnode_t); + + +/* Create a new fibonacci heap. */ +fibheap_t +fibheap_new (void) +{ + return (fibheap_t) xcalloc (1, sizeof (struct fibheap)); +} + +/* Create a new fibonacci heap node. */ +static fibnode_t +fibnode_new (void) +{ + fibnode_t node; + + node = (fibnode_t) xcalloc (1, sizeof *node); + node->left = node; + node->right = node; + + return node; +} + +static inline int +fibheap_compare (fibheap_t heap ATTRIBUTE_UNUSED, fibnode_t a, fibnode_t b) +{ + if (a->key < b->key) + return -1; + if (a->key > b->key) + return 1; + return 0; +} + +static inline int +fibheap_comp_data (fibheap_t heap, fibheapkey_t key, void *data, fibnode_t b) +{ + struct fibnode a; + + a.key = key; + a.data = data; + + return fibheap_compare (heap, &a, b); +} + +/* Insert DATA, with priority KEY, into HEAP. */ +fibnode_t +fibheap_insert (fibheap_t heap, fibheapkey_t key, void *data) +{ + fibnode_t node; + + /* Create the new node. */ + node = fibnode_new (); + + /* Set the node's data. */ + node->data = data; + node->key = key; + + /* Insert it into the root list. */ + fibheap_ins_root (heap, node); + + /* If their was no minimum, or this key is less than the min, + it's the new min. */ + if (heap->min == NULL || node->key < heap->min->key) + heap->min = node; + + heap->nodes++; + + return node; +} + +/* Return the data of the minimum node (if we know it). */ +void * +fibheap_min (fibheap_t heap) +{ + /* If there is no min, we can't easily return it. */ + if (heap->min == NULL) + return NULL; + return heap->min->data; +} + +/* Return the key of the minimum node (if we know it). */ +fibheapkey_t +fibheap_min_key (fibheap_t heap) +{ + /* If there is no min, we can't easily return it. */ + if (heap->min == NULL) + return 0; + return heap->min->key; +} + +/* Union HEAPA and HEAPB into a new heap. */ +fibheap_t +fibheap_union (fibheap_t heapa, fibheap_t heapb) +{ + fibnode_t a_root, b_root, temp; + + /* If one of the heaps is empty, the union is just the other heap. */ + if ((a_root = heapa->root) == NULL) + { + free (heapa); + return heapb; + } + if ((b_root = heapb->root) == NULL) + { + free (heapb); + return heapa; + } + + /* Merge them to the next nodes on the opposite chain. */ + a_root->left->right = b_root; + b_root->left->right = a_root; + temp = a_root->left; + a_root->left = b_root->left; + b_root->left = temp; + heapa->nodes += heapb->nodes; + + /* And set the new minimum, if it's changed. */ + if (fibheap_compare (heapa, heapb->min, heapa->min) < 0) + heapa->min = heapb->min; + + free (heapb); + return heapa; +} + +/* Extract the data of the minimum node from HEAP. */ +void * +fibheap_extract_min (fibheap_t heap) +{ + fibnode_t z; + void *ret = NULL; + + /* If we don't have a min set, it means we have no nodes. */ + if (heap->min != NULL) + { + /* Otherwise, extract the min node, free the node, and return the + node's data. */ + z = fibheap_extr_min_node (heap); + ret = z->data; + free (z); + } + + return ret; +} + +/* Replace both the KEY and the DATA associated with NODE. */ +void * +fibheap_replace_key_data (fibheap_t heap, fibnode_t node, + fibheapkey_t key, void *data) +{ + void *odata; + fibheapkey_t okey; + fibnode_t y; + + /* If we wanted to, we could actually do a real increase by redeleting and + inserting. However, this would require O (log n) time. So just bail out + for now. */ + if (fibheap_comp_data (heap, key, data, node) > 0) + return NULL; + + odata = node->data; + okey = node->key; + node->data = data; + node->key = key; + y = node->parent; + + if (okey == key) + return odata; + + /* These two compares are specifically <= 0 to make sure that in the case + of equality, a node we replaced the data on, becomes the new min. This + is needed so that delete's call to extractmin gets the right node. */ + if (y != NULL && fibheap_compare (heap, node, y) <= 0) + { + fibheap_cut (heap, node, y); + fibheap_cascading_cut (heap, y); + } + + if (fibheap_compare (heap, node, heap->min) <= 0) + heap->min = node; + + return odata; +} + +/* Replace the DATA associated with NODE. */ +void * +fibheap_replace_data (fibheap_t heap, fibnode_t node, void *data) +{ + return fibheap_replace_key_data (heap, node, node->key, data); +} + +/* Replace the KEY associated with NODE. */ +fibheapkey_t +fibheap_replace_key (fibheap_t heap, fibnode_t node, fibheapkey_t key) +{ + int okey = node->key; + fibheap_replace_key_data (heap, node, key, node->data); + return okey; +} + +/* Delete NODE from HEAP. */ +void * +fibheap_delete_node (fibheap_t heap, fibnode_t node) +{ + void *ret = node->data; + + /* To perform delete, we just make it the min key, and extract. */ + fibheap_replace_key (heap, node, FIBHEAPKEY_MIN); + fibheap_extract_min (heap); + + return ret; +} + +/* Delete HEAP. */ +void +fibheap_delete (fibheap_t heap) +{ + while (heap->min != NULL) + free (fibheap_extr_min_node (heap)); + + free (heap); +} + +/* Determine if HEAP is empty. */ +int +fibheap_empty (fibheap_t heap) +{ + return heap->nodes == 0; +} + +/* Extract the minimum node of the heap. */ +static fibnode_t +fibheap_extr_min_node (fibheap_t heap) +{ + fibnode_t ret = heap->min; + fibnode_t x, y, orig; + + /* Attach the child list of the minimum node to the root list of the heap. + If there is no child list, we don't do squat. */ + for (x = ret->child, orig = NULL; x != orig && x != NULL; x = y) + { + if (orig == NULL) + orig = x; + y = x->right; + x->parent = NULL; + fibheap_ins_root (heap, x); + } + + /* Remove the old root. */ + fibheap_rem_root (heap, ret); + heap->nodes--; + + /* If we are left with no nodes, then the min is NULL. */ + if (heap->nodes == 0) + heap->min = NULL; + else + { + /* Otherwise, consolidate to find new minimum, as well as do the reorg + work that needs to be done. */ + heap->min = ret->right; + fibheap_consolidate (heap); + } + + return ret; +} + +/* Insert NODE into the root list of HEAP. */ +static void +fibheap_ins_root (fibheap_t heap, fibnode_t node) +{ + /* If the heap is currently empty, the new node becomes the singleton + circular root list. */ + if (heap->root == NULL) + { + heap->root = node; + node->left = node; + node->right = node; + return; + } + + /* Otherwise, insert it in the circular root list between the root + and it's right node. */ + fibnode_insert_after (heap->root, node); +} + +/* Remove NODE from the rootlist of HEAP. */ +static void +fibheap_rem_root (fibheap_t heap, fibnode_t node) +{ + if (node->left == node) + heap->root = NULL; + else + heap->root = fibnode_remove (node); +} + +/* Consolidate the heap. */ +static void +fibheap_consolidate (fibheap_t heap) +{ + fibnode_t a[1 + 8 * sizeof (long)]; + fibnode_t w; + fibnode_t y; + fibnode_t x; + int i; + int d; + int D; + + D = 1 + 8 * sizeof (long); + + memset (a, 0, sizeof (fibnode_t) * D); + + while ((w = heap->root) != NULL) + { + x = w; + fibheap_rem_root (heap, w); + d = x->degree; + while (a[d] != NULL) + { + y = a[d]; + if (fibheap_compare (heap, x, y) > 0) + { + fibnode_t temp; + temp = x; + x = y; + y = temp; + } + fibheap_link (heap, y, x); + a[d] = NULL; + d++; + } + a[d] = x; + } + heap->min = NULL; + for (i = 0; i < D; i++) + if (a[i] != NULL) + { + fibheap_ins_root (heap, a[i]); + if (heap->min == NULL || fibheap_compare (heap, a[i], heap->min) < 0) + heap->min = a[i]; + } +} + +/* Make NODE a child of PARENT. */ +static void +fibheap_link (fibheap_t heap ATTRIBUTE_UNUSED, + fibnode_t node, fibnode_t parent) +{ + if (parent->child == NULL) + parent->child = node; + else + fibnode_insert_before (parent->child, node); + node->parent = parent; + parent->degree++; + node->mark = 0; +} + +/* Remove NODE from PARENT's child list. */ +static void +fibheap_cut (fibheap_t heap, fibnode_t node, fibnode_t parent) +{ + fibnode_remove (node); + parent->degree--; + fibheap_ins_root (heap, node); + node->parent = NULL; + node->mark = 0; +} + +static void +fibheap_cascading_cut (fibheap_t heap, fibnode_t y) +{ + fibnode_t z; + + while ((z = y->parent) != NULL) + { + if (y->mark == 0) + { + y->mark = 1; + return; + } + else + { + fibheap_cut (heap, y, z); + y = z; + } + } +} + +static void +fibnode_insert_after (fibnode_t a, fibnode_t b) +{ + if (a == a->right) + { + a->right = b; + a->left = b; + b->right = a; + b->left = a; + } + else + { + b->right = a->right; + a->right->left = b; + a->right = b; + b->left = a; + } +} + +static fibnode_t +fibnode_remove (fibnode_t node) +{ + fibnode_t ret; + + if (node == node->left) + ret = NULL; + else + ret = node->left; + + if (node->parent != NULL && node->parent->child == node) + node->parent->child = ret; + + node->right->left = node->left; + node->left->right = node->right; + + node->parent = NULL; + node->left = node; + node->right = node; + + return ret; +} diff --git a/libiberty/filename_cmp.c b/libiberty/filename_cmp.c new file mode 100644 index 0000000..0a4d0d8 --- /dev/null +++ b/libiberty/filename_cmp.c @@ -0,0 +1,78 @@ +/* File name comparison routine. + + Copyright (C) 2007 Free Software Foundation, Inc. + + 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, 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. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STRING_H +#include +#endif + +#include "filenames.h" +#include "safe-ctype.h" + +/* + +@deftypefn Extension int filename_cmp (const char *@var{s1}, const char *@var{s2}) + +Return zero if the two file names @var{s1} and @var{s2} are equivalent. +If not equivalent, the returned value is similar to what @code{strcmp} +would return. In other words, it returns a negative value if @var{s1} +is less than @var{s2}, or a positive value if @var{s2} is greater than +@var{s2}. + +This function does not normalize file names. As a result, this function +will treat filenames that are spelled differently as different even in +the case when the two filenames point to the same underlying file. +However, it does handle the fact that on DOS-like file systems, forward +and backward slashes are equal. + +@end deftypefn + +*/ + +int +filename_cmp (const char *s1, const char *s2) +{ +#ifndef HAVE_DOS_BASED_FILE_SYSTEM + return strcmp(s1, s2); +#else + for (;;) + { + int c1 = TOLOWER (*s1); + int c2 = TOLOWER (*s2); + + /* On DOS-based file systems, the '/' and the '\' are equivalent. */ + if (c1 == '/') + c1 = '\\'; + if (c2 == '/') + c2 = '\\'; + + if (c1 != c2) + return (c1 - c2); + + if (c1 == '\0') + return 0; + + s1++; + s2++; + } +#endif +} + diff --git a/libiberty/floatformat.c b/libiberty/floatformat.c new file mode 100644 index 0000000..cbf13ea --- /dev/null +++ b/libiberty/floatformat.c @@ -0,0 +1,759 @@ +/* IEEE floating point support routines, for GDB, the GNU Debugger. + Copyright 1991, 1994, 1999, 2000, 2003, 2005, 2006 + Free Software Foundation, Inc. + +This file is part of GDB. + +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. */ + +/* This is needed to pick up the NAN macro on some systems. */ +#define _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#ifdef HAVE_STRING_H +#include +#endif + +/* On some platforms, provides DBL_QNAN. */ +#ifdef STDC_HEADERS +#include +#endif + +#include "ansidecl.h" +#include "libiberty.h" +#include "floatformat.h" + +#ifndef INFINITY +#ifdef HUGE_VAL +#define INFINITY HUGE_VAL +#else +#define INFINITY (1.0 / 0.0) +#endif +#endif + +#ifndef NAN +#ifdef DBL_QNAN +#define NAN DBL_QNAN +#else +#define NAN (0.0 / 0.0) +#endif +#endif + +static int mant_bits_set (const struct floatformat *, const unsigned char *); +static unsigned long get_field (const unsigned char *, + enum floatformat_byteorders, + unsigned int, + unsigned int, + unsigned int); +static int floatformat_always_valid (const struct floatformat *fmt, + const void *from); + +static int +floatformat_always_valid (const struct floatformat *fmt ATTRIBUTE_UNUSED, + const void *from ATTRIBUTE_UNUSED) +{ + return 1; +} + +/* The odds that CHAR_BIT will be anything but 8 are low enough that I'm not + going to bother with trying to muck around with whether it is defined in + a system header, what we do if not, etc. */ +#define FLOATFORMAT_CHAR_BIT 8 + +/* floatformats for IEEE single and double, big and little endian. */ +const struct floatformat floatformat_ieee_single_big = +{ + floatformat_big, 32, 0, 1, 8, 127, 255, 9, 23, + floatformat_intbit_no, + "floatformat_ieee_single_big", + floatformat_always_valid, + NULL +}; +const struct floatformat floatformat_ieee_single_little = +{ + floatformat_little, 32, 0, 1, 8, 127, 255, 9, 23, + floatformat_intbit_no, + "floatformat_ieee_single_little", + floatformat_always_valid, + NULL +}; +const struct floatformat floatformat_ieee_double_big = +{ + floatformat_big, 64, 0, 1, 11, 1023, 2047, 12, 52, + floatformat_intbit_no, + "floatformat_ieee_double_big", + floatformat_always_valid, + NULL +}; +const struct floatformat floatformat_ieee_double_little = +{ + floatformat_little, 64, 0, 1, 11, 1023, 2047, 12, 52, + floatformat_intbit_no, + "floatformat_ieee_double_little", + floatformat_always_valid, + NULL +}; + +/* floatformat for IEEE double, little endian byte order, with big endian word + ordering, as on the ARM. */ + +const struct floatformat floatformat_ieee_double_littlebyte_bigword = +{ + floatformat_littlebyte_bigword, 64, 0, 1, 11, 1023, 2047, 12, 52, + floatformat_intbit_no, + "floatformat_ieee_double_littlebyte_bigword", + floatformat_always_valid, + NULL +}; + +/* floatformat for VAX. Not quite IEEE, but close enough. */ + +const struct floatformat floatformat_vax_f = +{ + floatformat_vax, 32, 0, 1, 8, 129, 0, 9, 23, + floatformat_intbit_no, + "floatformat_vax_f", + floatformat_always_valid, + NULL +}; +const struct floatformat floatformat_vax_d = +{ + floatformat_vax, 64, 0, 1, 8, 129, 0, 9, 55, + floatformat_intbit_no, + "floatformat_vax_d", + floatformat_always_valid, + NULL +}; +const struct floatformat floatformat_vax_g = +{ + floatformat_vax, 64, 0, 1, 11, 1025, 0, 12, 52, + floatformat_intbit_no, + "floatformat_vax_g", + floatformat_always_valid, + NULL +}; + +static int floatformat_i387_ext_is_valid (const struct floatformat *fmt, + const void *from); + +static int +floatformat_i387_ext_is_valid (const struct floatformat *fmt, const void *from) +{ + /* In the i387 double-extended format, if the exponent is all ones, + then the integer bit must be set. If the exponent is neither 0 + nor ~0, the intbit must also be set. Only if the exponent is + zero can it be zero, and then it must be zero. */ + unsigned long exponent, int_bit; + const unsigned char *ufrom = (const unsigned char *) from; + + exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize, + fmt->exp_start, fmt->exp_len); + int_bit = get_field (ufrom, fmt->byteorder, fmt->totalsize, + fmt->man_start, 1); + + if ((exponent == 0) != (int_bit == 0)) + return 0; + else + return 1; +} + +const struct floatformat floatformat_i387_ext = +{ + floatformat_little, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64, + floatformat_intbit_yes, + "floatformat_i387_ext", + floatformat_i387_ext_is_valid, + NULL +}; +const struct floatformat floatformat_m68881_ext = +{ + /* Note that the bits from 16 to 31 are unused. */ + floatformat_big, 96, 0, 1, 15, 0x3fff, 0x7fff, 32, 64, + floatformat_intbit_yes, + "floatformat_m68881_ext", + floatformat_always_valid, + NULL +}; +const struct floatformat floatformat_i960_ext = +{ + /* Note that the bits from 0 to 15 are unused. */ + floatformat_little, 96, 16, 17, 15, 0x3fff, 0x7fff, 32, 64, + floatformat_intbit_yes, + "floatformat_i960_ext", + floatformat_always_valid, + NULL +}; +const struct floatformat floatformat_m88110_ext = +{ + floatformat_big, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64, + floatformat_intbit_yes, + "floatformat_m88110_ext", + floatformat_always_valid, + NULL +}; +const struct floatformat floatformat_m88110_harris_ext = +{ + /* Harris uses raw format 128 bytes long, but the number is just an ieee + double, and the last 64 bits are wasted. */ + floatformat_big,128, 0, 1, 11, 0x3ff, 0x7ff, 12, 52, + floatformat_intbit_no, + "floatformat_m88110_ext_harris", + floatformat_always_valid, + NULL +}; +const struct floatformat floatformat_arm_ext_big = +{ + /* Bits 1 to 16 are unused. */ + floatformat_big, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64, + floatformat_intbit_yes, + "floatformat_arm_ext_big", + floatformat_always_valid, + NULL +}; +const struct floatformat floatformat_arm_ext_littlebyte_bigword = +{ + /* Bits 1 to 16 are unused. */ + floatformat_littlebyte_bigword, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64, + floatformat_intbit_yes, + "floatformat_arm_ext_littlebyte_bigword", + floatformat_always_valid, + NULL +}; +const struct floatformat floatformat_ia64_spill_big = +{ + floatformat_big, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64, + floatformat_intbit_yes, + "floatformat_ia64_spill_big", + floatformat_always_valid, + NULL +}; +const struct floatformat floatformat_ia64_spill_little = +{ + floatformat_little, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64, + floatformat_intbit_yes, + "floatformat_ia64_spill_little", + floatformat_always_valid, + NULL +}; +const struct floatformat floatformat_ia64_quad_big = +{ + floatformat_big, 128, 0, 1, 15, 16383, 0x7fff, 16, 112, + floatformat_intbit_no, + "floatformat_ia64_quad_big", + floatformat_always_valid, + NULL +}; +const struct floatformat floatformat_ia64_quad_little = +{ + floatformat_little, 128, 0, 1, 15, 16383, 0x7fff, 16, 112, + floatformat_intbit_no, + "floatformat_ia64_quad_little", + floatformat_always_valid, + NULL +}; + +static int +floatformat_ibm_long_double_is_valid (const struct floatformat *fmt, + const void *from) +{ + const unsigned char *ufrom = (const unsigned char *) from; + const struct floatformat *hfmt = fmt->split_half; + long top_exp, bot_exp; + int top_nan = 0; + + top_exp = get_field (ufrom, hfmt->byteorder, hfmt->totalsize, + hfmt->exp_start, hfmt->exp_len); + bot_exp = get_field (ufrom + 8, hfmt->byteorder, hfmt->totalsize, + hfmt->exp_start, hfmt->exp_len); + + if ((unsigned long) top_exp == hfmt->exp_nan) + top_nan = mant_bits_set (hfmt, ufrom); + + /* A NaN is valid with any low part. */ + if (top_nan) + return 1; + + /* An infinity, zero or denormal requires low part 0 (positive or + negative). */ + if ((unsigned long) top_exp == hfmt->exp_nan || top_exp == 0) + { + if (bot_exp != 0) + return 0; + + return !mant_bits_set (hfmt, ufrom + 8); + } + + /* The top part is now a finite normal value. The long double value + is the sum of the two parts, and the top part must equal the + result of rounding the long double value to nearest double. Thus + the bottom part must be <= 0.5ulp of the top part in absolute + value, and if it is < 0.5ulp then the long double is definitely + valid. */ + if (bot_exp < top_exp - 53) + return 1; + if (bot_exp > top_exp - 53 && bot_exp != 0) + return 0; + if (bot_exp == 0) + { + /* The bottom part is 0 or denormal. Determine which, and if + denormal the first two set bits. */ + int first_bit = -1, second_bit = -1, cur_bit; + for (cur_bit = 0; (unsigned int) cur_bit < hfmt->man_len; cur_bit++) + if (get_field (ufrom + 8, hfmt->byteorder, hfmt->totalsize, + hfmt->man_start + cur_bit, 1)) + { + if (first_bit == -1) + first_bit = cur_bit; + else + { + second_bit = cur_bit; + break; + } + } + /* Bottom part 0 is OK. */ + if (first_bit == -1) + return 1; + /* The real exponent of the bottom part is -first_bit. */ + if (-first_bit < top_exp - 53) + return 1; + if (-first_bit > top_exp - 53) + return 0; + /* The bottom part is at least 0.5ulp of the top part. For this + to be OK, the bottom part must be exactly 0.5ulp (i.e. no + more bits set) and the top part must have last bit 0. */ + if (second_bit != -1) + return 0; + return !get_field (ufrom, hfmt->byteorder, hfmt->totalsize, + hfmt->man_start + hfmt->man_len - 1, 1); + } + else + { + /* The bottom part is at least 0.5ulp of the top part. For this + to be OK, it must be exactly 0.5ulp (i.e. no explicit bits + set) and the top part must have last bit 0. */ + if (get_field (ufrom, hfmt->byteorder, hfmt->totalsize, + hfmt->man_start + hfmt->man_len - 1, 1)) + return 0; + return !mant_bits_set (hfmt, ufrom + 8); + } +} + +const struct floatformat floatformat_ibm_long_double = +{ + floatformat_big, 128, 0, 1, 11, 1023, 2047, 12, 52, + floatformat_intbit_no, + "floatformat_ibm_long_double", + floatformat_ibm_long_double_is_valid, + &floatformat_ieee_double_big +}; + + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +/* Return 1 if any bits are explicitly set in the mantissa of UFROM, + format FMT, 0 otherwise. */ +static int +mant_bits_set (const struct floatformat *fmt, const unsigned char *ufrom) +{ + unsigned int mant_bits, mant_off; + int mant_bits_left; + + mant_off = fmt->man_start; + mant_bits_left = fmt->man_len; + while (mant_bits_left > 0) + { + mant_bits = min (mant_bits_left, 32); + + if (get_field (ufrom, fmt->byteorder, fmt->totalsize, + mant_off, mant_bits) != 0) + return 1; + + mant_off += mant_bits; + mant_bits_left -= mant_bits; + } + return 0; +} + +/* Extract a field which starts at START and is LEN bits long. DATA and + TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ +static unsigned long +get_field (const unsigned char *data, enum floatformat_byteorders order, + unsigned int total_len, unsigned int start, unsigned int len) +{ + unsigned long result = 0; + unsigned int cur_byte; + int lo_bit, hi_bit, cur_bitshift = 0; + int nextbyte = (order == floatformat_little) ? 1 : -1; + + /* Start is in big-endian bit order! Fix that first. */ + start = total_len - (start + len); + + /* Start at the least significant part of the field. */ + if (order == floatformat_little) + cur_byte = start / FLOATFORMAT_CHAR_BIT; + else + cur_byte = (total_len - start - 1) / FLOATFORMAT_CHAR_BIT; + + lo_bit = start % FLOATFORMAT_CHAR_BIT; + hi_bit = min (lo_bit + len, FLOATFORMAT_CHAR_BIT); + + do + { + unsigned int shifted = *(data + cur_byte) >> lo_bit; + unsigned int bits = hi_bit - lo_bit; + unsigned int mask = (1 << bits) - 1; + result |= (shifted & mask) << cur_bitshift; + len -= bits; + cur_bitshift += bits; + cur_byte += nextbyte; + lo_bit = 0; + hi_bit = min (len, FLOATFORMAT_CHAR_BIT); + } + while (len != 0); + + return result; +} + +/* Convert from FMT to a double. + FROM is the address of the extended float. + Store the double in *TO. */ + +void +floatformat_to_double (const struct floatformat *fmt, + const void *from, double *to) +{ + const unsigned char *ufrom = (const unsigned char *) from; + double dto; + long exponent; + unsigned long mant; + unsigned int mant_bits, mant_off; + int mant_bits_left; + int special_exponent; /* It's a NaN, denorm or zero */ + + /* Split values are not handled specially, since the top half has + the correctly rounded double value (in the only supported case of + split values). */ + + exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize, + fmt->exp_start, fmt->exp_len); + + /* If the exponent indicates a NaN, we don't have information to + decide what to do. So we handle it like IEEE, except that we + don't try to preserve the type of NaN. FIXME. */ + if ((unsigned long) exponent == fmt->exp_nan) + { + int nan = mant_bits_set (fmt, ufrom); + + /* On certain systems (such as GNU/Linux), the use of the + INFINITY macro below may generate a warning that can not be + silenced due to a bug in GCC (PR preprocessor/11931). The + preprocessor fails to recognise the __extension__ keyword in + conjunction with the GNU/C99 extension for hexadecimal + floating point constants and will issue a warning when + compiling with -pedantic. */ + if (nan) + dto = NAN; + else + dto = INFINITY; + + if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1)) + dto = -dto; + + *to = dto; + + return; + } + + mant_bits_left = fmt->man_len; + mant_off = fmt->man_start; + dto = 0.0; + + special_exponent = exponent == 0 || (unsigned long) exponent == fmt->exp_nan; + + /* Don't bias zero's, denorms or NaNs. */ + if (!special_exponent) + exponent -= fmt->exp_bias; + + /* Build the result algebraically. Might go infinite, underflow, etc; + who cares. */ + + /* If this format uses a hidden bit, explicitly add it in now. Otherwise, + increment the exponent by one to account for the integer bit. */ + + if (!special_exponent) + { + if (fmt->intbit == floatformat_intbit_no) + dto = ldexp (1.0, exponent); + else + exponent++; + } + + while (mant_bits_left > 0) + { + mant_bits = min (mant_bits_left, 32); + + mant = get_field (ufrom, fmt->byteorder, fmt->totalsize, + mant_off, mant_bits); + + /* Handle denormalized numbers. FIXME: What should we do for + non-IEEE formats? */ + if (special_exponent && exponent == 0 && mant != 0) + dto += ldexp ((double)mant, + (- fmt->exp_bias + - mant_bits + - (mant_off - fmt->man_start) + + 1)); + else + dto += ldexp ((double)mant, exponent - mant_bits); + if (exponent != 0) + exponent -= mant_bits; + mant_off += mant_bits; + mant_bits_left -= mant_bits; + } + + /* Negate it if negative. */ + if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1)) + dto = -dto; + *to = dto; +} + +static void put_field (unsigned char *, enum floatformat_byteorders, + unsigned int, + unsigned int, + unsigned int, + unsigned long); + +/* Set a field which starts at START and is LEN bits long. DATA and + TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ +static void +put_field (unsigned char *data, enum floatformat_byteorders order, + unsigned int total_len, unsigned int start, unsigned int len, + unsigned long stuff_to_put) +{ + unsigned int cur_byte; + int lo_bit, hi_bit; + int nextbyte = (order == floatformat_little) ? 1 : -1; + + /* Start is in big-endian bit order! Fix that first. */ + start = total_len - (start + len); + + /* Start at the least significant part of the field. */ + if (order == floatformat_little) + cur_byte = start / FLOATFORMAT_CHAR_BIT; + else + cur_byte = (total_len - start - 1) / FLOATFORMAT_CHAR_BIT; + + lo_bit = start % FLOATFORMAT_CHAR_BIT; + hi_bit = min (lo_bit + len, FLOATFORMAT_CHAR_BIT); + + do + { + unsigned char *byte_ptr = data + cur_byte; + unsigned int bits = hi_bit - lo_bit; + unsigned int mask = ((1 << bits) - 1) << lo_bit; + *byte_ptr = (*byte_ptr & ~mask) | ((stuff_to_put << lo_bit) & mask); + stuff_to_put >>= bits; + len -= bits; + cur_byte += nextbyte; + lo_bit = 0; + hi_bit = min (len, FLOATFORMAT_CHAR_BIT); + } + while (len != 0); +} + +/* The converse: convert the double *FROM to an extended float + and store where TO points. Neither FROM nor TO have any alignment + restrictions. */ + +void +floatformat_from_double (const struct floatformat *fmt, + const double *from, void *to) +{ + double dfrom; + int exponent; + double mant; + unsigned int mant_bits, mant_off; + int mant_bits_left; + unsigned char *uto = (unsigned char *) to; + + dfrom = *from; + memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT); + + /* Split values are not handled specially, since a bottom half of + zero is correct for any value representable as double (in the + only supported case of split values). */ + + /* If negative, set the sign bit. */ + if (dfrom < 0) + { + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1); + dfrom = -dfrom; + } + + if (dfrom == 0) + { + /* 0.0. */ + return; + } + + if (dfrom != dfrom) + { + /* NaN. */ + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, + fmt->exp_len, fmt->exp_nan); + /* Be sure it's not infinity, but NaN value is irrelevant. */ + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start, + 32, 1); + return; + } + + if (dfrom + dfrom == dfrom) + { + /* This can only happen for an infinite value (or zero, which we + already handled above). */ + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, + fmt->exp_len, fmt->exp_nan); + return; + } + + mant = frexp (dfrom, &exponent); + if (exponent + fmt->exp_bias - 1 > 0) + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, + fmt->exp_len, exponent + fmt->exp_bias - 1); + else + { + /* Handle a denormalized number. FIXME: What should we do for + non-IEEE formats? */ + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, + fmt->exp_len, 0); + mant = ldexp (mant, exponent + fmt->exp_bias - 1); + } + + mant_bits_left = fmt->man_len; + mant_off = fmt->man_start; + while (mant_bits_left > 0) + { + unsigned long mant_long; + mant_bits = mant_bits_left < 32 ? mant_bits_left : 32; + + mant *= 4294967296.0; + mant_long = (unsigned long)mant; + mant -= mant_long; + + /* If the integer bit is implicit, and we are not creating a + denormalized number, then we need to discard it. */ + if ((unsigned int) mant_bits_left == fmt->man_len + && fmt->intbit == floatformat_intbit_no + && exponent + fmt->exp_bias - 1 > 0) + { + mant_long &= 0x7fffffff; + mant_bits -= 1; + } + else if (mant_bits < 32) + { + /* The bits we want are in the most significant MANT_BITS bits of + mant_long. Move them to the least significant. */ + mant_long >>= 32 - mant_bits; + } + + put_field (uto, fmt->byteorder, fmt->totalsize, + mant_off, mant_bits, mant_long); + mant_off += mant_bits; + mant_bits_left -= mant_bits; + } +} + +/* Return non-zero iff the data at FROM is a valid number in format FMT. */ + +int +floatformat_is_valid (const struct floatformat *fmt, const void *from) +{ + return fmt->is_valid (fmt, from); +} + + +#ifdef IEEE_DEBUG + +#include + +/* This is to be run on a host which uses IEEE floating point. */ + +void +ieee_test (double n) +{ + double result; + + floatformat_to_double (&floatformat_ieee_double_little, &n, &result); + if ((n != result && (! isnan (n) || ! isnan (result))) + || (n < 0 && result >= 0) + || (n >= 0 && result < 0)) + printf ("Differ(to): %.20g -> %.20g\n", n, result); + + floatformat_from_double (&floatformat_ieee_double_little, &n, &result); + if ((n != result && (! isnan (n) || ! isnan (result))) + || (n < 0 && result >= 0) + || (n >= 0 && result < 0)) + printf ("Differ(from): %.20g -> %.20g\n", n, result); + +#if 0 + { + char exten[16]; + + floatformat_from_double (&floatformat_m68881_ext, &n, exten); + floatformat_to_double (&floatformat_m68881_ext, exten, &result); + if (n != result) + printf ("Differ(to+from): %.20g -> %.20g\n", n, result); + } +#endif + +#if IEEE_DEBUG > 1 + /* This is to be run on a host which uses 68881 format. */ + { + long double ex = *(long double *)exten; + if (ex != n) + printf ("Differ(from vs. extended): %.20g\n", n); + } +#endif +} + +int +main (void) +{ + ieee_test (0.0); + ieee_test (0.5); + ieee_test (256.0); + ieee_test (0.12345); + ieee_test (234235.78907234); + ieee_test (-512.0); + ieee_test (-0.004321); + ieee_test (1.2E-70); + ieee_test (1.2E-316); + ieee_test (4.9406564584124654E-324); + ieee_test (- 4.9406564584124654E-324); + ieee_test (- 0.0); + ieee_test (- INFINITY); + ieee_test (- NAN); + ieee_test (INFINITY); + ieee_test (NAN); + return 0; +} +#endif diff --git a/libiberty/fnmatch.c b/libiberty/fnmatch.c new file mode 100644 index 0000000..fc897be --- /dev/null +++ b/libiberty/fnmatch.c @@ -0,0 +1,220 @@ +/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. + +NOTE: This source is derived from an old version taken from the GNU C +Library (glibc). + +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, 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, 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +#if defined (CONFIG_BROKETS) +/* We use instead of "config.h" so that a compilation + using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h + (which it would do because it found this file in $srcdir). */ +#include +#else +#include "config.h" +#endif +#endif + + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +/* This code to undef const added in libiberty. */ +#ifndef __STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include +#include +#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. */ + +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) + + +#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS) +extern int errno; +#endif + +/* Match STRING against the filename pattern PATTERN, returning zero if + it matches, nonzero if not. */ +int +fnmatch (const char *pattern, const char *string, int flags) +{ + register const char *p = pattern, *n = string; + register unsigned char c; + +#define FOLD(c) ((flags & FNM_CASEFOLD) ? TOLOWER (c) : (c)) + + while ((c = *p++) != '\0') + { + c = FOLD (c); + + switch (c) + { + case '?': + if (*n == '\0') + return FNM_NOMATCH; + else if ((flags & FNM_FILE_NAME) && *n == '/') + return FNM_NOMATCH; + else if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + break; + + case '\\': + if (!(flags & FNM_NOESCAPE)) + { + c = *p++; + c = FOLD (c); + } + if (FOLD ((unsigned char)*n) != c) + return FNM_NOMATCH; + break; + + case '*': + if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + + for (c = *p++; c == '?' || c == '*'; c = *p++, ++n) + if (((flags & FNM_FILE_NAME) && *n == '/') || + (c == '?' && *n == '\0')) + return FNM_NOMATCH; + + if (c == '\0') + return 0; + + { + unsigned char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c; + c1 = FOLD (c1); + for (--p; *n != '\0'; ++n) + if ((c == '[' || FOLD ((unsigned char)*n) == c1) && + fnmatch (p, n, flags & ~FNM_PERIOD) == 0) + return 0; + return FNM_NOMATCH; + } + + case '[': + { + /* Nonzero if the sense of the character class is inverted. */ + register int negate; + + if (*n == '\0') + return FNM_NOMATCH; + + if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + + negate = (*p == '!' || *p == '^'); + if (negate) + ++p; + + c = *p++; + for (;;) + { + register unsigned char cstart = c, cend = c; + + if (!(flags & FNM_NOESCAPE) && c == '\\') + cstart = cend = *p++; + + cstart = cend = FOLD (cstart); + + if (c == '\0') + /* [ (unterminated) loses. */ + return FNM_NOMATCH; + + c = *p++; + c = FOLD (c); + + if ((flags & FNM_FILE_NAME) && c == '/') + /* [/] can never match. */ + return FNM_NOMATCH; + + if (c == '-' && *p != ']') + { + cend = *p++; + if (!(flags & FNM_NOESCAPE) && cend == '\\') + cend = *p++; + if (cend == '\0') + return FNM_NOMATCH; + cend = FOLD (cend); + + c = *p++; + } + + if (FOLD ((unsigned char)*n) >= cstart + && FOLD ((unsigned char)*n) <= cend) + goto matched; + + if (c == ']') + break; + } + if (!negate) + return FNM_NOMATCH; + break; + + matched:; + /* Skip the rest of the [...] that already matched. */ + while (c != ']') + { + if (c == '\0') + /* [... (unterminated) loses. */ + return FNM_NOMATCH; + + c = *p++; + if (!(flags & FNM_NOESCAPE) && c == '\\') + /* XXX 1003.2d11 is unclear if this is right. */ + ++p; + } + if (negate) + return FNM_NOMATCH; + } + break; + + default: + if (c != FOLD ((unsigned char)*n)) + return FNM_NOMATCH; + } + + ++n; + } + + if (*n == '\0') + return 0; + + if ((flags & FNM_LEADING_DIR) && *n == '/') + /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */ + return 0; + + return FNM_NOMATCH; +} + +#endif /* _LIBC or not __GNU_LIBRARY__. */ diff --git a/libiberty/fopen_unlocked.c b/libiberty/fopen_unlocked.c new file mode 100644 index 0000000..3c3cefe --- /dev/null +++ b/libiberty/fopen_unlocked.c @@ -0,0 +1,126 @@ +/* Implement fopen_unlocked and related functions. + Copyright (C) 2005 Free Software Foundation, Inc. + Written by Kaveh R. Ghazi . + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* + +@deftypefn Extension void unlock_stream (FILE * @var{stream}) + +If the OS supports it, ensure that the supplied stream is setup to +avoid any multi-threaded locking. Otherwise leave the @code{FILE} +pointer unchanged. If the @var{stream} is @code{NULL} do nothing. + +@end deftypefn + +@deftypefn Extension void unlock_std_streams (void) + +If the OS supports it, ensure that the standard I/O streams, +@code{stdin}, @code{stdout} and @code{stderr} are setup to avoid any +multi-threaded locking. Otherwise do nothing. + +@end deftypefn + +@deftypefn Extension {FILE *} fopen_unlocked (const char *@var{path}, const char * @var{mode}) + +Opens and returns a @code{FILE} pointer via @code{fopen}. If the +operating system supports it, ensure that the stream is setup to avoid +any multi-threaded locking. Otherwise return the @code{FILE} pointer +unchanged. + +@end deftypefn + +@deftypefn Extension {FILE *} fdopen_unlocked (int @var{fildes}, const char * @var{mode}) + +Opens and returns a @code{FILE} pointer via @code{fdopen}. If the +operating system supports it, ensure that the stream is setup to avoid +any multi-threaded locking. Otherwise return the @code{FILE} pointer +unchanged. + +@end deftypefn + +@deftypefn Extension {FILE *} freopen_unlocked (const char * @var{path}, const char * @var{mode}, FILE * @var{stream}) + +Opens and returns a @code{FILE} pointer via @code{freopen}. If the +operating system supports it, ensure that the stream is setup to avoid +any multi-threaded locking. Otherwise return the @code{FILE} pointer +unchanged. + +@end deftypefn + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#ifdef HAVE_STDIO_EXT_H +#include +#endif + +#include "libiberty.h" + +/* This is an inline helper function to consolidate attempts to unlock + a stream. */ + +static inline void +unlock_1 (FILE *const fp ATTRIBUTE_UNUSED) +{ +#if defined(HAVE___FSETLOCKING) && defined(FSETLOCKING_BYCALLER) + if (fp) + __fsetlocking (fp, FSETLOCKING_BYCALLER); +#endif +} + +void +unlock_stream (FILE *fp) +{ + unlock_1 (fp); +} + +void +unlock_std_streams (void) +{ + unlock_1 (stdin); + unlock_1 (stdout); + unlock_1 (stderr); +} + +FILE * +fopen_unlocked (const char *path, const char *mode) +{ + FILE *const fp = fopen (path, mode); + unlock_1 (fp); + return fp; +} + +FILE * +fdopen_unlocked (int fildes, const char *mode) +{ + FILE *const fp = fdopen (fildes, mode); + unlock_1 (fp); + return fp; +} + +FILE * +freopen_unlocked (const char *path, const char *mode, FILE *stream) +{ + FILE *const fp = freopen (path, mode, stream); + unlock_1 (fp); + return fp; +} diff --git a/libiberty/getcwd.c b/libiberty/getcwd.c new file mode 100644 index 0000000..28f26eb --- /dev/null +++ b/libiberty/getcwd.c @@ -0,0 +1,62 @@ +/* Emulate getcwd using getwd. + This function is in the public domain. */ + +/* + +@deftypefn Supplemental char* getcwd (char *@var{pathname}, int @var{len}) + +Copy the absolute pathname for the current working directory into +@var{pathname}, which is assumed to point to a buffer of at least +@var{len} bytes, and return a pointer to the buffer. If the current +directory's path doesn't fit in @var{len} characters, the result is +@code{NULL} and @code{errno} is set. If @var{pathname} is a null pointer, +@code{getcwd} will obtain @var{len} bytes of space using +@code{malloc}. + +@end deftypefn + +*/ + +#include "config.h" + +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#include +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif + +extern char *getwd (); +extern int errno; + +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif + +char * +getcwd (char *buf, size_t len) +{ + char ourbuf[MAXPATHLEN]; + char *result; + + result = getwd (ourbuf); + if (result) { + if (strlen (ourbuf) >= len) { + errno = ERANGE; + return 0; + } + if (!buf) { + buf = (char*)malloc(len); + if (!buf) { + errno = ENOMEM; + return 0; + } + } + strcpy (buf, ourbuf); + } + return buf; +} diff --git a/libiberty/getopt.c b/libiberty/getopt.c new file mode 100644 index 0000000..d9c3532 --- /dev/null +++ b/libiberty/getopt.c @@ -0,0 +1,1052 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to drepper@gnu.org + before changing it! + + Copyright (C) 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, + 1996, 1997, 1998, 2005 Free Software Foundation, Inc. + + NOTE: This source is derived from an old version taken from the GNU C + Library (glibc). + + 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, 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. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in . + Ditto for AIX 3.2 and . */ +#ifndef _NO_PROTO +# define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +# ifndef const +# define const +# endif +#endif + +#include "ansidecl.h" +#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__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +# include +# include +#endif /* GNU C library. */ + +#ifdef VMS +# include +# if HAVE_STRING_H - 0 +# include +# endif +#endif + +#ifndef _ +/* This is for other GNU distributions with internationalized messages. + When compiling libc, the _ macro is predefined. */ +# if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC +# include +# define _(msgid) gettext (msgid) +# else +# define _(msgid) (msgid) +# endif +#endif + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* 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. */ + +char *optarg = NULL; + +/* 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. */ + +/* 1003.2 says this must be 1 before any call. */ +int optind = 1; + +/* Formerly, initialization of getopt depended on optind==0, which + causes problems with re-calling getopt as programs generally don't + know that. */ + +int __getopt_initialized = 0; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return -1 with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +# include +# define my_index strchr +#else + +# if HAVE_STRING_H +# include +# else +# if HAVE_STRINGS_H +# include +# endif +# endif + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +#if HAVE_STDLIB_H && HAVE_DECL_GETENV +# include +#elif !defined(getenv) +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ +extern char *getenv (const char *); +# ifdef __cplusplus +} +# endif /* __cplusplus */ +#endif + +static char * +my_index (const char *str, int chr) +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +# if (!defined __STDC__ || !__STDC__) && !defined strlen +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int strlen (const char *); +# endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +#ifdef _LIBC +/* Bash 2.0 gives us an environment variable containing flags + indicating ARGV elements that should not be considered arguments. */ + +/* Defined in getopt_init.c */ +extern char *__getopt_nonoption_flags; + +static int nonoption_flags_max_len; +static int nonoption_flags_len; + +static int original_argc; +static char *const *original_argv; + +/* Make sure the environment variable bash 2.0 puts in the environment + is valid for the getopt call we must make sure that the ARGV passed + to getopt is that one passed to the process. */ +static void +__attribute__ ((unused)) +store_args_and_env (int argc, char *const *argv) +{ + /* XXX This is no good solution. We should rather copy the args so + that we can compare them later. But we must not use malloc(3). */ + original_argc = argc; + original_argv = argv; +} +# ifdef text_set_element +text_set_element (__libc_subinit, store_args_and_env); +# endif /* text_set_element */ + +# define SWAP_FLAGS(ch1, ch2) \ + if (nonoption_flags_len > 0) \ + { \ + char __tmp = __getopt_nonoption_flags[ch1]; \ + __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ + __getopt_nonoption_flags[ch2] = __tmp; \ + } +#else /* !_LIBC */ +# define SWAP_FLAGS(ch1, ch2) +#endif /* _LIBC */ + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +#if defined __STDC__ && __STDC__ +static void exchange (char **); +#endif + +static void +exchange (char **argv) +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + +#ifdef _LIBC + /* First make sure the handling of the `__getopt_nonoption_flags' + string can work normally. Our top argument must be in the range + of the string. */ + if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) + { + /* We must extend the array. The user plays games with us and + presents new arguments. */ + char *new_str = (char *) malloc (top + 1); + if (new_str == NULL) + nonoption_flags_len = nonoption_flags_max_len = 0; + else + { + memset (mempcpy (new_str, __getopt_nonoption_flags, + nonoption_flags_max_len), + '\0', top + 1 - nonoption_flags_max_len); + nonoption_flags_max_len = top + 1; + __getopt_nonoption_flags = new_str; + } + } +#endif + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + SWAP_FLAGS (bottom + i, middle + i); + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made. */ + +#if defined __STDC__ && __STDC__ +static const char *_getopt_initialize (int, char *const *, const char *); +#endif +static const char * +_getopt_initialize (int argc ATTRIBUTE_UNUSED, + char *const *argv ATTRIBUTE_UNUSED, + const char *optstring) +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind; + + nextchar = NULL; + + posixly_correct = getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + +#ifdef _LIBC + if (posixly_correct == NULL + && argc == original_argc && argv == original_argv) + { + if (nonoption_flags_max_len == 0) + { + if (__getopt_nonoption_flags == NULL + || __getopt_nonoption_flags[0] == '\0') + nonoption_flags_max_len = -1; + else + { + const char *orig_str = __getopt_nonoption_flags; + int len = nonoption_flags_max_len = strlen (orig_str); + if (nonoption_flags_max_len < argc) + nonoption_flags_max_len = argc; + __getopt_nonoption_flags = + (char *) malloc (nonoption_flags_max_len); + if (__getopt_nonoption_flags == NULL) + nonoption_flags_max_len = -1; + else + memset (mempcpy (__getopt_nonoption_flags, orig_str, len), + '\0', nonoption_flags_max_len - len); + } + } + nonoption_flags_len = nonoption_flags_max_len; + } + else + nonoption_flags_len = 0; +#endif + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns -1. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (int argc, char *const *argv, const char *optstring, + const struct option *longopts, + int *longind, int long_only) +{ + optarg = NULL; + + if (optind == 0 || !__getopt_initialized) + { + if (optind == 0) + optind = 1; /* Don't scan ARGV[0], the program name. */ + optstring = _getopt_initialize (argc, argv, optstring); + __getopt_initialized = 1; + } + + /* Test whether ARGV[optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. The later information + is only used when the used in the GNU libc. */ +#ifdef _LIBC +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ + || (optind < nonoption_flags_len \ + && __getopt_nonoption_flags[optind] == '1')) +#else +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') +#endif + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (last_nonopt > optind) + last_nonopt = optind; + if (first_nonopt > optind) + first_nonopt = optind; + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc && NONOPTION_P) + optind++; + last_nonopt = optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return -1; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) + { + if (ordering == REQUIRE_ORDER) + return -1; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) + == (unsigned int) strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + optopt = 0; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + { + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + _("%s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + _("%s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[optind - 1][0], pfound->name); + + nextchar += strlen (nextchar); + + optopt = pfound->val; + return '?'; + } + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index (optstring, *nextchar) == NULL) + { + if (opterr) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, _("%s: unrecognized option `--%s'\n"), + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + optopt = 0; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (opterr) + { + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: illegal option -- %c\n"), + argv[0], c); + else + fprintf (stderr, _("%s: invalid option -- %c\n"), + argv[0], c); + } + optopt = c; + return '?'; + } + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if (temp[0] == 'W' && temp[1] == ';') + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + + /* optarg is now the argument, see if it's in the + table of longopts. */ + + for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + fprintf (stderr, _("\ +%s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); + + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + nextchar = NULL; + return 'W'; /* Let the application handle it. */ + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, + _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt (int argc, char *const *argv, const char *optstring) +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (int argc, char **argv) +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == -1) + break; + + switch (c) + { + 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 '?': + 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 */ diff --git a/libiberty/getopt1.c b/libiberty/getopt1.c new file mode 100644 index 0000000..255b144 --- /dev/null +++ b/libiberty/getopt1.c @@ -0,0 +1,180 @@ +/* getopt_long and getopt_long_only entry points for GNU getopt. + Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98,2005 + Free Software Foundation, Inc. + + NOTE: This source is derived from an old version taken from the GNU C + Library (glibc). + + 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, 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. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + +#include "getopt.h" + +/* 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 */ diff --git a/libiberty/getpagesize.c b/libiberty/getpagesize.c new file mode 100644 index 0000000..1c3a263 --- /dev/null +++ b/libiberty/getpagesize.c @@ -0,0 +1,90 @@ +/* Emulation of getpagesize() for systems that need it. */ + +/* + +@deftypefn Supplemental int getpagesize (void) + +Returns the number of bytes in a page of memory. This is the +granularity of many of the system memory management routines. No +guarantee is made as to whether or not it is the same as the basic +memory management hardware page size. + +@end deftypefn + +BUGS + + Is intended as a reasonable replacement for systems where this + is not provided as a system call. The value of 4096 may or may + not be correct for the systems where it is returned as the default + value. + +*/ + +#ifndef VMS + +#include "config.h" + +#include +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#undef GNU_OUR_PAGESIZE +#if defined (HAVE_SYSCONF) && defined (HAVE_UNISTD_H) +#include +#ifdef _SC_PAGESIZE +#define GNU_OUR_PAGESIZE sysconf(_SC_PAGESIZE) +#endif +#endif + +#ifndef GNU_OUR_PAGESIZE +# ifdef PAGESIZE +# define GNU_OUR_PAGESIZE PAGESIZE +# else /* no PAGESIZE */ +# ifdef EXEC_PAGESIZE +# define GNU_OUR_PAGESIZE EXEC_PAGESIZE +# else /* no EXEC_PAGESIZE */ +# ifdef NBPG +# define GNU_OUR_PAGESIZE (NBPG * CLSIZE) +# ifndef CLSIZE +# define CLSIZE 1 +# endif /* CLSIZE */ +# else /* no NBPG */ +# ifdef NBPC +# define GNU_OUR_PAGESIZE NBPC +# else /* no NBPC */ +# define GNU_OUR_PAGESIZE 4096 /* Just punt and use reasonable value */ +# endif /* NBPC */ +# endif /* NBPG */ +# endif /* EXEC_PAGESIZE */ +# endif /* PAGESIZE */ +#endif /* GNU_OUR_PAGESIZE */ + +int +getpagesize (void) +{ + return (GNU_OUR_PAGESIZE); +} + +#else /* VMS */ + +#if 0 /* older distributions of gcc-vms are missing */ +#include +#endif +#ifndef SYI$_PAGE_SIZE /* VMS V5.4 and earlier didn't have this yet */ +#define SYI$_PAGE_SIZE 4452 +#endif +extern unsigned long lib$getsyi(const unsigned short *,...); + +int getpagesize (void) +{ + long pagsiz = 0L; + unsigned short itmcod = SYI$_PAGE_SIZE; + + (void) lib$getsyi (&itmcod, (void *) &pagsiz); + if (pagsiz == 0L) + pagsiz = 512L; /* VAX default */ + return (int) pagsiz; +} + +#endif /* VMS */ diff --git a/libiberty/getpwd.c b/libiberty/getpwd.c new file mode 100644 index 0000000..fa5c132 --- /dev/null +++ b/libiberty/getpwd.c @@ -0,0 +1,128 @@ +/* getpwd.c - get the working directory */ + +/* + +@deftypefn Supplemental char* getpwd (void) + +Returns the current working directory. This implementation caches the +result on the assumption that the process will not call @code{chdir} +between calls to @code{getpwd}. + +@end deftypefn + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#ifndef errno +extern int errno; +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_LIMITS_H +#include +#endif + +#include "libiberty.h" + +/* Virtually every UN*X system now in common use (except for pre-4.3-tahoe + BSD systems) now provides getcwd as called for by POSIX. Allow for + the few exceptions to the general rule here. */ + +#if !defined(HAVE_GETCWD) && defined(HAVE_GETWD) +/* Prototype in case the system headers doesn't provide it. */ +extern char *getwd (); +#define getcwd(buf,len) getwd(buf) +#endif + +#ifdef MAXPATHLEN +#define GUESSPATHLEN (MAXPATHLEN + 1) +#else +#define GUESSPATHLEN 100 +#endif + +#if !(defined (VMS) || (defined(_WIN32) && !defined(__CYGWIN__))) + +/* Get the working directory. Use the PWD environment variable if it's + set correctly, since this is faster and gives more uniform answers + to the user. Yield the working directory if successful; otherwise, + yield 0 and set errno. */ + +char * +getpwd (void) +{ + static char *pwd; + static int failure_errno; + + char *p = pwd; + size_t s; + struct stat dotstat, pwdstat; + + if (!p && !(errno = failure_errno)) + { + if (! ((p = getenv ("PWD")) != 0 + && *p == '/' + && stat (p, &pwdstat) == 0 + && stat (".", &dotstat) == 0 + && dotstat.st_ino == pwdstat.st_ino + && dotstat.st_dev == pwdstat.st_dev)) + + /* The shortcut didn't work. Try the slow, ``sure'' way. */ + for (s = GUESSPATHLEN; !getcwd (p = XNEWVEC (char, s), s); s *= 2) + { + int e = errno; + free (p); +#ifdef ERANGE + if (e != ERANGE) +#endif + { + errno = failure_errno = e; + p = 0; + break; + } + } + + /* Cache the result. This assumes that the program does + not invoke chdir between calls to getpwd. */ + pwd = p; + } + return p; +} + +#else /* VMS || _WIN32 && !__CYGWIN__ */ + +#ifndef MAXPATHLEN +#define MAXPATHLEN 255 +#endif + +char * +getpwd (void) +{ + static char *pwd = 0; + + if (!pwd) + pwd = getcwd (XNEWVEC (char, MAXPATHLEN + 1), MAXPATHLEN + 1 +#ifdef VMS + , 0 +#endif + ); + return pwd; +} + +#endif /* VMS || _WIN32 && !__CYGWIN__ */ diff --git a/libiberty/getruntime.c b/libiberty/getruntime.c new file mode 100644 index 0000000..82f3d2e --- /dev/null +++ b/libiberty/getruntime.c @@ -0,0 +1,116 @@ +/* Return time used so far, in microseconds. + Copyright (C) 1994, 1999, 2002 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#include "config.h" + +#include "ansidecl.h" +#include "libiberty.h" + +/* On some systems (such as WindISS), you must include + to get the definition of "time_t" before you include . */ +#include + +/* There are several ways to get elapsed execution time; unfortunately no + single way is available for all host systems, nor are there reliable + ways to find out which way is correct for a given host. */ + +#ifdef TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# ifdef HAVE_TIME_H +# include +# endif +# endif +#endif + +#if defined (HAVE_GETRUSAGE) && defined (HAVE_SYS_RESOURCE_H) +#include +#endif + +#ifdef HAVE_TIMES +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +/* This is a fallback; if wrong, it will likely make obviously wrong + results. */ + +#ifndef CLOCKS_PER_SEC +#define CLOCKS_PER_SEC 1 +#endif + +#ifdef _SC_CLK_TCK +#define GNU_HZ sysconf(_SC_CLK_TCK) +#else +#ifdef HZ +#define GNU_HZ HZ +#else +#ifdef CLOCKS_PER_SEC +#define GNU_HZ CLOCKS_PER_SEC +#endif +#endif +#endif + +/* + +@deftypefn Replacement long get_run_time (void) + +Returns the time used so far, in microseconds. If possible, this is +the time used by this process, else it is the elapsed time since the +process started. + +@end deftypefn + +*/ + +long +get_run_time (void) +{ +#if defined (HAVE_GETRUSAGE) && defined (HAVE_SYS_RESOURCE_H) + struct rusage rusage; + + getrusage (0, &rusage); + return (rusage.ru_utime.tv_sec * 1000000 + rusage.ru_utime.tv_usec + + rusage.ru_stime.tv_sec * 1000000 + rusage.ru_stime.tv_usec); +#else /* ! HAVE_GETRUSAGE */ +#ifdef HAVE_TIMES + struct tms tms; + + times (&tms); + return (tms.tms_utime + tms.tms_stime) * (1000000 / GNU_HZ); +#else /* ! HAVE_TIMES */ + /* Fall back on clock and hope it's correctly implemented. */ + const long clocks_per_sec = CLOCKS_PER_SEC; + if (clocks_per_sec <= 1000000) + return clock () * (1000000 / clocks_per_sec); + else + return clock () / clocks_per_sec; +#endif /* HAVE_TIMES */ +#endif /* HAVE_GETRUSAGE */ +} diff --git a/libiberty/gettimeofday.c b/libiberty/gettimeofday.c new file mode 100644 index 0000000..fca1679 --- /dev/null +++ b/libiberty/gettimeofday.c @@ -0,0 +1,30 @@ +#include "config.h" +#include "libiberty.h" +#ifdef HAVE_TIME_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif + +/* + +@deftypefn Supplemental int gettimeofday (struct timeval *@var{tp}, void *@var{tz}) + +Writes the current time to @var{tp}. This implementation requires +that @var{tz} be NULL. Returns 0 on success, -1 on failure. + +@end deftypefn + +*/ + +int +gettimeofday (struct timeval *tp, void *tz) +{ + if (tz) + abort (); + tp->tv_usec = 0; + if (time (&tp->tv_sec) == (time_t) -1) + return -1; + return 0; +} diff --git a/libiberty/hashtab.c b/libiberty/hashtab.c new file mode 100644 index 0000000..bf34a6d --- /dev/null +++ b/libiberty/hashtab.c @@ -0,0 +1,955 @@ +/* An expandable hash tables datatype. + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 + Free Software Foundation, Inc. + Contributed by Vladimir Makarov (vmakarov@cygnus.com). + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* This package implements basic hash table functionality. It is possible + to search for an entry, create an entry and destroy an entry. + + Elements in the table are generic pointers. + + The size of the table is not fixed; if the occupancy of the table + grows too high the hash table will be expanded. + + The abstract data implementation is based on generalized Algorithm D + from Knuth's book "The art of computer programming". Hash table is + expanded by creation of new hash table and transferring elements from + the old table to the new table. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_MALLOC_H +#include +#endif +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_STDINT_H +#include +#endif + +#include + +#include "libiberty.h" +#include "ansidecl.h" +#include "hashtab.h" + +#ifndef CHAR_BIT +#define CHAR_BIT 8 +#endif + +static unsigned int higher_prime_index (unsigned long); +static hashval_t htab_mod_1 (hashval_t, hashval_t, hashval_t, int); +static hashval_t htab_mod (hashval_t, htab_t); +static hashval_t htab_mod_m2 (hashval_t, htab_t); +static hashval_t hash_pointer (const void *); +static int eq_pointer (const void *, const void *); +static int htab_expand (htab_t); +static PTR *find_empty_slot_for_expand (htab_t, hashval_t); + +/* At some point, we could make these be NULL, and modify the + hash-table routines to handle NULL specially; that would avoid + function-call overhead for the common case of hashing pointers. */ +htab_hash htab_hash_pointer = hash_pointer; +htab_eq htab_eq_pointer = eq_pointer; + +/* Table of primes and multiplicative inverses. + + Note that these are not minimally reduced inverses. Unlike when generating + code to divide by a constant, we want to be able to use the same algorithm + all the time. All of these inverses (are implied to) have bit 32 set. + + For the record, here's the function that computed the table; it's a + vastly simplified version of the function of the same name from gcc. */ + +#if 0 +unsigned int +ceil_log2 (unsigned int x) +{ + int i; + for (i = 31; i >= 0 ; --i) + if (x > (1u << i)) + return i+1; + abort (); +} + +unsigned int +choose_multiplier (unsigned int d, unsigned int *mlp, unsigned char *shiftp) +{ + unsigned long long mhigh; + double nx; + int lgup, post_shift; + int pow, pow2; + int n = 32, precision = 32; + + lgup = ceil_log2 (d); + pow = n + lgup; + pow2 = n + lgup - precision; + + nx = ldexp (1.0, pow) + ldexp (1.0, pow2); + mhigh = nx / d; + + *shiftp = lgup - 1; + *mlp = mhigh; + return mhigh >> 32; +} +#endif + +struct prime_ent +{ + hashval_t prime; + hashval_t inv; + hashval_t inv_m2; /* inverse of prime-2 */ + hashval_t shift; +}; + +static struct prime_ent const prime_tab[] = { + { 7, 0x24924925, 0x9999999b, 2 }, + { 13, 0x3b13b13c, 0x745d1747, 3 }, + { 31, 0x08421085, 0x1a7b9612, 4 }, + { 61, 0x0c9714fc, 0x15b1e5f8, 5 }, + { 127, 0x02040811, 0x0624dd30, 6 }, + { 251, 0x05197f7e, 0x073260a5, 7 }, + { 509, 0x01824366, 0x02864fc8, 8 }, + { 1021, 0x00c0906d, 0x014191f7, 9 }, + { 2039, 0x0121456f, 0x0161e69e, 10 }, + { 4093, 0x00300902, 0x00501908, 11 }, + { 8191, 0x00080041, 0x00180241, 12 }, + { 16381, 0x000c0091, 0x00140191, 13 }, + { 32749, 0x002605a5, 0x002a06e6, 14 }, + { 65521, 0x000f00e2, 0x00110122, 15 }, + { 131071, 0x00008001, 0x00018003, 16 }, + { 262139, 0x00014002, 0x0001c004, 17 }, + { 524287, 0x00002001, 0x00006001, 18 }, + { 1048573, 0x00003001, 0x00005001, 19 }, + { 2097143, 0x00004801, 0x00005801, 20 }, + { 4194301, 0x00000c01, 0x00001401, 21 }, + { 8388593, 0x00001e01, 0x00002201, 22 }, + { 16777213, 0x00000301, 0x00000501, 23 }, + { 33554393, 0x00001381, 0x00001481, 24 }, + { 67108859, 0x00000141, 0x000001c1, 25 }, + { 134217689, 0x000004e1, 0x00000521, 26 }, + { 268435399, 0x00000391, 0x000003b1, 27 }, + { 536870909, 0x00000019, 0x00000029, 28 }, + { 1073741789, 0x0000008d, 0x00000095, 29 }, + { 2147483647, 0x00000003, 0x00000007, 30 }, + /* Avoid "decimal constant so large it is unsigned" for 4294967291. */ + { 0xfffffffb, 0x00000006, 0x00000008, 31 } +}; + +/* The following function returns an index into the above table of the + nearest prime number which is greater than N, and near a power of two. */ + +static unsigned int +higher_prime_index (unsigned long n) +{ + unsigned int low = 0; + unsigned int high = sizeof(prime_tab) / sizeof(prime_tab[0]); + + while (low != high) + { + unsigned int mid = low + (high - low) / 2; + if (n > prime_tab[mid].prime) + low = mid + 1; + else + high = mid; + } + + /* If we've run out of primes, abort. */ + if (n > prime_tab[low].prime) + { + fprintf (stderr, "Cannot find prime bigger than %lu\n", n); + abort (); + } + + return low; +} + +/* Returns a hash code for P. */ + +static hashval_t +hash_pointer (const PTR p) +{ + return (hashval_t) ((long)p >> 3); +} + +/* Returns non-zero if P1 and P2 are equal. */ + +static int +eq_pointer (const PTR p1, const PTR p2) +{ + return p1 == p2; +} + + +/* The parens around the function names in the next two definitions + are essential in order to prevent macro expansions of the name. + The bodies, however, are expanded as expected, so they are not + recursive definitions. */ + +/* Return the current size of given hash table. */ + +#define htab_size(htab) ((htab)->size) + +size_t +(htab_size) (htab_t htab) +{ + return htab_size (htab); +} + +/* Return the current number of elements in given hash table. */ + +#define htab_elements(htab) ((htab)->n_elements - (htab)->n_deleted) + +size_t +(htab_elements) (htab_t htab) +{ + return htab_elements (htab); +} + +/* Return X % Y. */ + +static inline hashval_t +htab_mod_1 (hashval_t x, hashval_t y, hashval_t inv, int shift) +{ + /* The multiplicative inverses computed above are for 32-bit types, and + requires that we be able to compute a highpart multiply. */ +#ifdef UNSIGNED_64BIT_TYPE + __extension__ typedef UNSIGNED_64BIT_TYPE ull; + if (sizeof (hashval_t) * CHAR_BIT <= 32) + { + hashval_t t1, t2, t3, t4, q, r; + + t1 = ((ull)x * inv) >> 32; + t2 = x - t1; + t3 = t2 >> 1; + t4 = t1 + t3; + q = t4 >> shift; + r = x - (q * y); + + return r; + } +#endif + + /* Otherwise just use the native division routines. */ + return x % y; +} + +/* Compute the primary hash for HASH given HTAB's current size. */ + +static inline hashval_t +htab_mod (hashval_t hash, htab_t htab) +{ + const struct prime_ent *p = &prime_tab[htab->size_prime_index]; + return htab_mod_1 (hash, p->prime, p->inv, p->shift); +} + +/* Compute the secondary hash for HASH given HTAB's current size. */ + +static inline hashval_t +htab_mod_m2 (hashval_t hash, htab_t htab) +{ + const struct prime_ent *p = &prime_tab[htab->size_prime_index]; + return 1 + htab_mod_1 (hash, p->prime - 2, p->inv_m2, p->shift); +} + +/* This function creates table with length slightly longer than given + source length. Created hash table is initiated as empty (all the + hash table entries are HTAB_EMPTY_ENTRY). The function returns the + created hash table, or NULL if memory allocation fails. */ + +htab_t +htab_create_alloc (size_t size, htab_hash hash_f, htab_eq eq_f, + htab_del del_f, htab_alloc alloc_f, htab_free free_f) +{ + htab_t result; + unsigned int size_prime_index; + + size_prime_index = higher_prime_index (size); + size = prime_tab[size_prime_index].prime; + + result = (htab_t) (*alloc_f) (1, sizeof (struct htab)); + if (result == NULL) + return NULL; + result->entries = (PTR *) (*alloc_f) (size, sizeof (PTR)); + if (result->entries == NULL) + { + if (free_f != NULL) + (*free_f) (result); + return NULL; + } + result->size = size; + result->size_prime_index = size_prime_index; + result->hash_f = hash_f; + result->eq_f = eq_f; + result->del_f = del_f; + result->alloc_f = alloc_f; + result->free_f = free_f; + return result; +} + +/* As above, but use the variants of alloc_f and free_f which accept + an extra argument. */ + +htab_t +htab_create_alloc_ex (size_t size, htab_hash hash_f, htab_eq eq_f, + htab_del del_f, void *alloc_arg, + htab_alloc_with_arg alloc_f, + htab_free_with_arg free_f) +{ + htab_t result; + unsigned int size_prime_index; + + size_prime_index = higher_prime_index (size); + size = prime_tab[size_prime_index].prime; + + result = (htab_t) (*alloc_f) (alloc_arg, 1, sizeof (struct htab)); + if (result == NULL) + return NULL; + result->entries = (PTR *) (*alloc_f) (alloc_arg, size, sizeof (PTR)); + if (result->entries == NULL) + { + if (free_f != NULL) + (*free_f) (alloc_arg, result); + return NULL; + } + result->size = size; + result->size_prime_index = size_prime_index; + result->hash_f = hash_f; + result->eq_f = eq_f; + result->del_f = del_f; + result->alloc_arg = alloc_arg; + result->alloc_with_arg_f = alloc_f; + result->free_with_arg_f = free_f; + return result; +} + +/* Update the function pointers and allocation parameter in the htab_t. */ + +void +htab_set_functions_ex (htab_t htab, htab_hash hash_f, htab_eq eq_f, + htab_del del_f, PTR alloc_arg, + htab_alloc_with_arg alloc_f, htab_free_with_arg free_f) +{ + htab->hash_f = hash_f; + htab->eq_f = eq_f; + htab->del_f = del_f; + htab->alloc_arg = alloc_arg; + htab->alloc_with_arg_f = alloc_f; + htab->free_with_arg_f = free_f; +} + +/* These functions exist solely for backward compatibility. */ + +#undef htab_create +htab_t +htab_create (size_t size, htab_hash hash_f, htab_eq eq_f, htab_del del_f) +{ + return htab_create_alloc (size, hash_f, eq_f, del_f, xcalloc, free); +} + +htab_t +htab_try_create (size_t size, htab_hash hash_f, htab_eq eq_f, htab_del del_f) +{ + return htab_create_alloc (size, hash_f, eq_f, del_f, calloc, free); +} + +/* This function frees all memory allocated for given hash table. + Naturally the hash table must already exist. */ + +void +htab_delete (htab_t htab) +{ + size_t size = htab_size (htab); + PTR *entries = htab->entries; + int i; + + if (htab->del_f) + for (i = size - 1; i >= 0; i--) + if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY) + (*htab->del_f) (entries[i]); + + if (htab->free_f != NULL) + { + (*htab->free_f) (entries); + (*htab->free_f) (htab); + } + else if (htab->free_with_arg_f != NULL) + { + (*htab->free_with_arg_f) (htab->alloc_arg, entries); + (*htab->free_with_arg_f) (htab->alloc_arg, htab); + } +} + +/* This function clears all entries in the given hash table. */ + +void +htab_empty (htab_t htab) +{ + size_t size = htab_size (htab); + PTR *entries = htab->entries; + int i; + + if (htab->del_f) + for (i = size - 1; i >= 0; i--) + if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY) + (*htab->del_f) (entries[i]); + + /* Instead of clearing megabyte, downsize the table. */ + if (size > 1024*1024 / sizeof (PTR)) + { + int nindex = higher_prime_index (1024 / sizeof (PTR)); + int nsize = prime_tab[nindex].prime; + + if (htab->free_f != NULL) + (*htab->free_f) (htab->entries); + else if (htab->free_with_arg_f != NULL) + (*htab->free_with_arg_f) (htab->alloc_arg, htab->entries); + if (htab->alloc_with_arg_f != NULL) + htab->entries = (PTR *) (*htab->alloc_with_arg_f) (htab->alloc_arg, nsize, + sizeof (PTR *)); + else + htab->entries = (PTR *) (*htab->alloc_f) (nsize, sizeof (PTR *)); + htab->size = nsize; + htab->size_prime_index = nindex; + } + else + memset (entries, 0, size * sizeof (PTR)); + htab->n_deleted = 0; + htab->n_elements = 0; +} + +/* Similar to htab_find_slot, but without several unwanted side effects: + - Does not call htab->eq_f when it finds an existing entry. + - Does not change the count of elements/searches/collisions in the + hash table. + This function also assumes there are no deleted entries in the table. + HASH is the hash value for the element to be inserted. */ + +static PTR * +find_empty_slot_for_expand (htab_t htab, hashval_t hash) +{ + hashval_t index = htab_mod (hash, htab); + size_t size = htab_size (htab); + PTR *slot = htab->entries + index; + hashval_t hash2; + + if (*slot == HTAB_EMPTY_ENTRY) + return slot; + else if (*slot == HTAB_DELETED_ENTRY) + abort (); + + hash2 = htab_mod_m2 (hash, htab); + for (;;) + { + index += hash2; + if (index >= size) + index -= size; + + slot = htab->entries + index; + if (*slot == HTAB_EMPTY_ENTRY) + return slot; + else if (*slot == HTAB_DELETED_ENTRY) + abort (); + } +} + +/* The following function changes size of memory allocated for the + entries and repeatedly inserts the table elements. The occupancy + of the table after the call will be about 50%. Naturally the hash + table must already exist. Remember also that the place of the + table entries is changed. If memory allocation failures are allowed, + this function will return zero, indicating that the table could not be + expanded. If all goes well, it will return a non-zero value. */ + +static int +htab_expand (htab_t htab) +{ + PTR *oentries; + PTR *olimit; + PTR *p; + PTR *nentries; + size_t nsize, osize, elts; + unsigned int oindex, nindex; + + oentries = htab->entries; + oindex = htab->size_prime_index; + osize = htab->size; + olimit = oentries + osize; + elts = htab_elements (htab); + + /* Resize only when table after removal of unused elements is either + too full or too empty. */ + if (elts * 2 > osize || (elts * 8 < osize && osize > 32)) + { + nindex = higher_prime_index (elts * 2); + nsize = prime_tab[nindex].prime; + } + else + { + nindex = oindex; + nsize = osize; + } + + if (htab->alloc_with_arg_f != NULL) + nentries = (PTR *) (*htab->alloc_with_arg_f) (htab->alloc_arg, nsize, + sizeof (PTR *)); + else + nentries = (PTR *) (*htab->alloc_f) (nsize, sizeof (PTR *)); + if (nentries == NULL) + return 0; + htab->entries = nentries; + htab->size = nsize; + htab->size_prime_index = nindex; + htab->n_elements -= htab->n_deleted; + htab->n_deleted = 0; + + p = oentries; + do + { + PTR x = *p; + + if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY) + { + PTR *q = find_empty_slot_for_expand (htab, (*htab->hash_f) (x)); + + *q = x; + } + + p++; + } + while (p < olimit); + + if (htab->free_f != NULL) + (*htab->free_f) (oentries); + else if (htab->free_with_arg_f != NULL) + (*htab->free_with_arg_f) (htab->alloc_arg, oentries); + return 1; +} + +/* This function searches for a hash table entry equal to the given + element. It cannot be used to insert or delete an element. */ + +PTR +htab_find_with_hash (htab_t htab, const PTR element, hashval_t hash) +{ + hashval_t index, hash2; + size_t size; + PTR entry; + + htab->searches++; + size = htab_size (htab); + index = htab_mod (hash, htab); + + entry = htab->entries[index]; + if (entry == HTAB_EMPTY_ENTRY + || (entry != HTAB_DELETED_ENTRY && (*htab->eq_f) (entry, element))) + return entry; + + hash2 = htab_mod_m2 (hash, htab); + for (;;) + { + htab->collisions++; + index += hash2; + if (index >= size) + index -= size; + + entry = htab->entries[index]; + if (entry == HTAB_EMPTY_ENTRY + || (entry != HTAB_DELETED_ENTRY && (*htab->eq_f) (entry, element))) + return entry; + } +} + +/* Like htab_find_slot_with_hash, but compute the hash value from the + element. */ + +PTR +htab_find (htab_t htab, const PTR element) +{ + return htab_find_with_hash (htab, element, (*htab->hash_f) (element)); +} + +/* This function searches for a hash table slot containing an entry + equal to the given element. To delete an entry, call this with + insert=NO_INSERT, then call htab_clear_slot on the slot returned + (possibly after doing some checks). To insert an entry, call this + with insert=INSERT, then write the value you want into the returned + slot. When inserting an entry, NULL may be returned if memory + allocation fails. */ + +PTR * +htab_find_slot_with_hash (htab_t htab, const PTR element, + hashval_t hash, enum insert_option insert) +{ + PTR *first_deleted_slot; + hashval_t index, hash2; + size_t size; + PTR entry; + + size = htab_size (htab); + if (insert == INSERT && size * 3 <= htab->n_elements * 4) + { + if (htab_expand (htab) == 0) + return NULL; + size = htab_size (htab); + } + + index = htab_mod (hash, htab); + + htab->searches++; + first_deleted_slot = NULL; + + entry = htab->entries[index]; + if (entry == HTAB_EMPTY_ENTRY) + goto empty_entry; + else if (entry == HTAB_DELETED_ENTRY) + first_deleted_slot = &htab->entries[index]; + else if ((*htab->eq_f) (entry, element)) + return &htab->entries[index]; + + hash2 = htab_mod_m2 (hash, htab); + for (;;) + { + htab->collisions++; + index += hash2; + if (index >= size) + index -= size; + + entry = htab->entries[index]; + if (entry == HTAB_EMPTY_ENTRY) + goto empty_entry; + else if (entry == HTAB_DELETED_ENTRY) + { + if (!first_deleted_slot) + first_deleted_slot = &htab->entries[index]; + } + else if ((*htab->eq_f) (entry, element)) + return &htab->entries[index]; + } + + empty_entry: + if (insert == NO_INSERT) + return NULL; + + if (first_deleted_slot) + { + htab->n_deleted--; + *first_deleted_slot = HTAB_EMPTY_ENTRY; + return first_deleted_slot; + } + + htab->n_elements++; + return &htab->entries[index]; +} + +/* Like htab_find_slot_with_hash, but compute the hash value from the + element. */ + +PTR * +htab_find_slot (htab_t htab, const PTR element, enum insert_option insert) +{ + return htab_find_slot_with_hash (htab, element, (*htab->hash_f) (element), + insert); +} + +/* This function deletes an element with the given value from hash + table (the hash is computed from the element). If there is no matching + element in the hash table, this function does nothing. */ + +void +htab_remove_elt (htab_t htab, PTR element) +{ + htab_remove_elt_with_hash (htab, element, (*htab->hash_f) (element)); +} + + +/* This function deletes an element with the given value from hash + table. If there is no matching element in the hash table, this + function does nothing. */ + +void +htab_remove_elt_with_hash (htab_t htab, PTR element, hashval_t hash) +{ + PTR *slot; + + slot = htab_find_slot_with_hash (htab, element, hash, NO_INSERT); + if (*slot == HTAB_EMPTY_ENTRY) + return; + + if (htab->del_f) + (*htab->del_f) (*slot); + + *slot = HTAB_DELETED_ENTRY; + htab->n_deleted++; +} + +/* This function clears a specified slot in a hash table. It is + useful when you've already done the lookup and don't want to do it + again. */ + +void +htab_clear_slot (htab_t htab, PTR *slot) +{ + if (slot < htab->entries || slot >= htab->entries + htab_size (htab) + || *slot == HTAB_EMPTY_ENTRY || *slot == HTAB_DELETED_ENTRY) + abort (); + + if (htab->del_f) + (*htab->del_f) (*slot); + + *slot = HTAB_DELETED_ENTRY; + htab->n_deleted++; +} + +/* This function scans over the entire hash table calling + CALLBACK for each live entry. If CALLBACK returns false, + the iteration stops. INFO is passed as CALLBACK's second + argument. */ + +void +htab_traverse_noresize (htab_t htab, htab_trav callback, PTR info) +{ + PTR *slot; + PTR *limit; + + slot = htab->entries; + limit = slot + htab_size (htab); + + do + { + PTR x = *slot; + + if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY) + if (!(*callback) (slot, info)) + break; + } + while (++slot < limit); +} + +/* Like htab_traverse_noresize, but does resize the table when it is + too empty to improve effectivity of subsequent calls. */ + +void +htab_traverse (htab_t htab, htab_trav callback, PTR info) +{ + if (htab_elements (htab) * 8 < htab_size (htab)) + htab_expand (htab); + + htab_traverse_noresize (htab, callback, info); +} + +/* Return the fraction of fixed collisions during all work with given + hash table. */ + +double +htab_collisions (htab_t htab) +{ + if (htab->searches == 0) + return 0.0; + + return (double) htab->collisions / (double) htab->searches; +} + +/* Hash P as a null-terminated string. + + Copied from gcc/hashtable.c. Zack had the following to say with respect + to applicability, though note that unlike hashtable.c, this hash table + implementation re-hashes rather than chain buckets. + + http://gcc.gnu.org/ml/gcc-patches/2001-08/msg01021.html + From: Zack Weinberg + Date: Fri, 17 Aug 2001 02:15:56 -0400 + + I got it by extracting all the identifiers from all the source code + I had lying around in mid-1999, and testing many recurrences of + the form "H_n = H_{n-1} * K + c_n * L + M" where K, L, M were either + prime numbers or the appropriate identity. This was the best one. + I don't remember exactly what constituted "best", except I was + looking at bucket-length distributions mostly. + + So it should be very good at hashing identifiers, but might not be + as good at arbitrary strings. + + I'll add that it thoroughly trounces the hash functions recommended + for this use at http://burtleburtle.net/bob/hash/index.html, both + on speed and bucket distribution. I haven't tried it against the + function they just started using for Perl's hashes. */ + +hashval_t +htab_hash_string (const PTR p) +{ + const unsigned char *str = (const unsigned char *) p; + hashval_t r = 0; + unsigned char c; + + while ((c = *str++) != 0) + r = r * 67 + c - 113; + + return r; +} + +/* DERIVED FROM: +-------------------------------------------------------------------- +lookup2.c, by Bob Jenkins, December 1996, Public Domain. +hash(), hash2(), hash3, and mix() are externally useful functions. +Routines to test the hash are included if SELF_TEST is defined. +You can use this free for any purpose. It has no warranty. +-------------------------------------------------------------------- +*/ + +/* +-------------------------------------------------------------------- +mix -- mix 3 32-bit values reversibly. +For every delta with one or two bit set, and the deltas of all three + high bits or all three low bits, whether the original value of a,b,c + is almost all zero or is uniformly distributed, +* If mix() is run forward or backward, at least 32 bits in a,b,c + have at least 1/4 probability of changing. +* If mix() is run forward, every bit of c will change between 1/3 and + 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.) +mix() was built out of 36 single-cycle latency instructions in a + structure that could supported 2x parallelism, like so: + a -= b; + a -= c; x = (c>>13); + b -= c; a ^= x; + b -= a; x = (a<<8); + c -= a; b ^= x; + c -= b; x = (b>>13); + ... + Unfortunately, superscalar Pentiums and Sparcs can't take advantage + of that parallelism. They've also turned some of those single-cycle + latency instructions into multi-cycle latency instructions. Still, + this is the fastest good hash I could find. There were about 2^^68 + to choose from. I only looked at a billion or so. +-------------------------------------------------------------------- +*/ +/* same, but slower, works on systems that might have 8 byte hashval_t's */ +#define mix(a,b,c) \ +{ \ + a -= b; a -= c; a ^= (c>>13); \ + b -= c; b -= a; b ^= (a<< 8); \ + c -= a; c -= b; c ^= ((b&0xffffffff)>>13); \ + a -= b; a -= c; a ^= ((c&0xffffffff)>>12); \ + b -= c; b -= a; b = (b ^ (a<<16)) & 0xffffffff; \ + c -= a; c -= b; c = (c ^ (b>> 5)) & 0xffffffff; \ + a -= b; a -= c; a = (a ^ (c>> 3)) & 0xffffffff; \ + b -= c; b -= a; b = (b ^ (a<<10)) & 0xffffffff; \ + c -= a; c -= b; c = (c ^ (b>>15)) & 0xffffffff; \ +} + +/* +-------------------------------------------------------------------- +hash() -- hash a variable-length key into a 32-bit value + k : the key (the unaligned variable-length array of bytes) + len : the length of the key, counting by bytes + level : can be any 4-byte value +Returns a 32-bit value. Every bit of the key affects every bit of +the return value. Every 1-bit and 2-bit delta achieves avalanche. +About 36+6len instructions. + +The best hash table sizes are powers of 2. There is no need to do +mod a prime (mod is sooo slow!). If you need less than 32 bits, +use a bitmask. For example, if you need only 10 bits, do + h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. + +If you are hashing n strings (ub1 **)k, do it like this: + for (i=0, h=0; i= 12) /* aligned */ + { + a += *(hashval_t *)(k+0); + b += *(hashval_t *)(k+4); + c += *(hashval_t *)(k+8); + mix(a,b,c); + k += 12; len -= 12; + } + else /* unaligned */ +#endif + while (len >= 12) + { + a += (k[0] +((hashval_t)k[1]<<8) +((hashval_t)k[2]<<16) +((hashval_t)k[3]<<24)); + b += (k[4] +((hashval_t)k[5]<<8) +((hashval_t)k[6]<<16) +((hashval_t)k[7]<<24)); + c += (k[8] +((hashval_t)k[9]<<8) +((hashval_t)k[10]<<16)+((hashval_t)k[11]<<24)); + mix(a,b,c); + k += 12; len -= 12; + } + + /*------------------------------------- handle the last 11 bytes */ + c += length; + switch(len) /* all the case statements fall through */ + { + case 11: c+=((hashval_t)k[10]<<24); + case 10: c+=((hashval_t)k[9]<<16); + case 9 : c+=((hashval_t)k[8]<<8); + /* the first byte of c is reserved for the length */ + case 8 : b+=((hashval_t)k[7]<<24); + case 7 : b+=((hashval_t)k[6]<<16); + case 6 : b+=((hashval_t)k[5]<<8); + case 5 : b+=k[4]; + case 4 : a+=((hashval_t)k[3]<<24); + case 3 : a+=((hashval_t)k[2]<<16); + case 2 : a+=((hashval_t)k[1]<<8); + case 1 : a+=k[0]; + /* case 0: nothing left to add */ + } + mix(a,b,c); + /*-------------------------------------------- report the result */ + return c; +} diff --git a/libiberty/hex.c b/libiberty/hex.c new file mode 100644 index 0000000..5eeafdb --- /dev/null +++ b/libiberty/hex.c @@ -0,0 +1,192 @@ +/* Hex character manipulation support. + Copyright (C) 1995, 2001 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#include /* for EOF */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "libiberty.h" +#include "safe-ctype.h" /* for HOST_CHARSET_ASCII */ + +#if EOF != -1 + #error "hex.c requires EOF == -1" +#endif + +/* + +@deftypefn Extension void hex_init (void) + +Initializes the array mapping the current character set to +corresponding hex values. This function must be called before any +call to @code{hex_p} or @code{hex_value}. If you fail to call it, a +default ASCII-based table will normally be used on ASCII systems. + +@end deftypefn + +@deftypefn Extension int hex_p (int @var{c}) + +Evaluates to non-zero if the given character is a valid hex character, +or zero if it is not. Note that the value you pass will be cast to +@code{unsigned char} within the macro. + +@end deftypefn + +@deftypefn Extension {unsigned int} hex_value (int @var{c}) + +Returns the numeric equivalent of the given character when interpreted +as a hexadecimal digit. The result is undefined if you pass an +invalid hex digit. Note that the value you pass will be cast to +@code{unsigned char} within the macro. + +The @code{hex_value} macro returns @code{unsigned int}, rather than +signed @code{int}, to make it easier to use in parsing addresses from +hex dump files: a signed @code{int} would be sign-extended when +converted to a wider unsigned type --- like @code{bfd_vma}, on some +systems. + +@end deftypefn + +@undocumented _hex_array_size +@undocumented _hex_bad +@undocumented _hex_value + +*/ + + +/* Are we ASCII? */ +#if HOST_CHARSET == HOST_CHARSET_ASCII + +const unsigned char _hex_value[_hex_array_size] = +{ + _hex_bad, _hex_bad, _hex_bad, _hex_bad, /* NUL SOH STX ETX */ + _hex_bad, _hex_bad, _hex_bad, _hex_bad, /* EOT ENQ ACK BEL */ + _hex_bad, _hex_bad, _hex_bad, _hex_bad, /* BS HT LF VT */ + _hex_bad, _hex_bad, _hex_bad, _hex_bad, /* FF CR SO SI */ + _hex_bad, _hex_bad, _hex_bad, _hex_bad, /* DLE DC1 DC2 DC3 */ + _hex_bad, _hex_bad, _hex_bad, _hex_bad, /* DC4 NAK SYN ETB */ + _hex_bad, _hex_bad, _hex_bad, _hex_bad, /* CAN EM SUB ESC */ + _hex_bad, _hex_bad, _hex_bad, _hex_bad, /* FS GS RS US */ + + _hex_bad, _hex_bad, _hex_bad, _hex_bad, /* SP ! " # */ + _hex_bad, _hex_bad, _hex_bad, _hex_bad, /* $ % & ' */ + _hex_bad, _hex_bad, _hex_bad, _hex_bad, /* ( ) * + */ + _hex_bad, _hex_bad, _hex_bad, _hex_bad, /* , - . / */ + 0, 1, 2, 3, /* 0 1 2 3 */ + 4, 5, 6, 7, /* 4 5 6 7 */ + 8, 9, _hex_bad, _hex_bad, /* 8 9 : ; */ + _hex_bad, _hex_bad, _hex_bad, _hex_bad, /* < = > ? */ + + _hex_bad, 10, 11, 12, /* @ A B C */ + 13, 14, 15, _hex_bad, /* D E F G */ + _hex_bad, _hex_bad, _hex_bad, _hex_bad, /* H I J K */ + _hex_bad, _hex_bad, _hex_bad, _hex_bad, /* L M N O */ + _hex_bad, _hex_bad, _hex_bad, _hex_bad, /* P Q R S */ + _hex_bad, _hex_bad, _hex_bad, _hex_bad, /* T U V W */ + _hex_bad, _hex_bad, _hex_bad, _hex_bad, /* X Y Z [ */ + _hex_bad, _hex_bad, _hex_bad, _hex_bad, /* \ ] ^ _ */ + + _hex_bad, 10, 11, 12, /* ` a b c */ + 13, 14, 15, _hex_bad, /* d e f g */ + _hex_bad, _hex_bad, _hex_bad, _hex_bad, /* h i j k */ + _hex_bad, _hex_bad, _hex_bad, _hex_bad, /* l m n o */ + _hex_bad, _hex_bad, _hex_bad, _hex_bad, /* p q r s */ + _hex_bad, _hex_bad, _hex_bad, _hex_bad, /* t u v w */ + _hex_bad, _hex_bad, _hex_bad, _hex_bad, /* x y z { */ + _hex_bad, _hex_bad, _hex_bad, _hex_bad, /* | } ~ DEL */ + + /* The high half of unsigned char, all values are _hex_bad. */ + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + _hex_bad, _hex_bad, _hex_bad, _hex_bad, + _hex_bad, _hex_bad, _hex_bad, _hex_bad, +}; +#define HEX_TABLE_INITIALIZED + +#else + +unsigned char _hex_value[_hex_array_size]; + +#endif /* not ASCII */ + +void +hex_init (void) +{ +#ifndef HEX_TABLE_INITIALIZED + int i; + + for (i=0; i<_hex_array_size; i++) + { + switch (i) + { + case '0': _hex_value[i] = 0; break; + case '1': _hex_value[i] = 1; break; + case '2': _hex_value[i] = 2; break; + case '3': _hex_value[i] = 3; break; + case '4': _hex_value[i] = 4; break; + case '5': _hex_value[i] = 5; break; + case '6': _hex_value[i] = 6; break; + case '7': _hex_value[i] = 7; break; + case '8': _hex_value[i] = 8; break; + case '9': _hex_value[i] = 9; break; + + case 'a': case 'A': _hex_value[i] = 10; break; + case 'b': case 'B': _hex_value[i] = 11; break; + case 'c': case 'C': _hex_value[i] = 12; break; + case 'd': case 'D': _hex_value[i] = 13; break; + case 'e': case 'E': _hex_value[i] = 14; break; + case 'f': case 'F': _hex_value[i] = 15; break; + + default: + _hex_value[i] = _hex_bad; + break; + } + } +#endif +} diff --git a/libiberty/index.c b/libiberty/index.c new file mode 100644 index 0000000..acd0a45 --- /dev/null +++ b/libiberty/index.c @@ -0,0 +1,21 @@ +/* Stub implementation of (obsolete) index(). */ + +/* + +@deftypefn Supplemental char* index (char *@var{s}, int @var{c}) + +Returns a pointer to the first occurrence of the character @var{c} in +the string @var{s}, or @code{NULL} if not found. The use of @code{index} is +deprecated in new programs in favor of @code{strchr}. + +@end deftypefn + +*/ + +extern char * strchr(const char *, int); + +char * +index (const char *s, int c) +{ + return strchr (s, c); +} diff --git a/libiberty/insque.c b/libiberty/insque.c new file mode 100644 index 0000000..3473bb9 --- /dev/null +++ b/libiberty/insque.c @@ -0,0 +1,50 @@ +/* insque(3C) routines + This file is in the public domain. */ + +/* + +@deftypefn Supplemental void insque (struct qelem *@var{elem}, struct qelem *@var{pred}) +@deftypefnx Supplemental void remque (struct qelem *@var{elem}) + +Routines to manipulate queues built from doubly linked lists. The +@code{insque} routine inserts @var{elem} in the queue immediately +after @var{pred}. The @code{remque} routine removes @var{elem} from +its containing queue. These routines expect to be passed pointers to +structures which have as their first members a forward pointer and a +back pointer, like this prototype (although no prototype is provided): + +@example +struct qelem @{ + struct qelem *q_forw; + struct qelem *q_back; + char q_data[]; +@}; +@end example + +@end deftypefn + +*/ + + +struct qelem { + struct qelem *q_forw; + struct qelem *q_back; +}; + + +void +insque (struct qelem *elem, struct qelem *pred) +{ + elem -> q_forw = pred -> q_forw; + pred -> q_forw -> q_back = elem; + elem -> q_back = pred; + pred -> q_forw = elem; +} + + +void +remque (struct qelem *elem) +{ + elem -> q_forw -> q_back = elem -> q_back; + elem -> q_back -> q_forw = elem -> q_forw; +} diff --git a/libiberty/lbasename.c b/libiberty/lbasename.c new file mode 100644 index 0000000..56fcd62 --- /dev/null +++ b/libiberty/lbasename.c @@ -0,0 +1,64 @@ +/* Libiberty basename. Like basename, but is not overridden by the + system C library. + Copyright (C) 2001, 2002 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* + +@deftypefn Replacement {const char*} lbasename (const char *@var{name}) + +Given a pointer to a string containing a typical pathname +(@samp{/usr/src/cmd/ls/ls.c} for example), returns a pointer to the +last component of the pathname (@samp{ls.c} in this case). The +returned pointer is guaranteed to lie within the original +string. This latter fact is not true of many vendor C +libraries, which return special strings or modify the passed +strings for particular input. + +In particular, the empty string returns the same empty string, +and a path ending in @code{/} returns the empty string after it. + +@end deftypefn + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "ansidecl.h" +#include "libiberty.h" +#include "safe-ctype.h" +#include "filenames.h" + +const char * +lbasename (const char *name) +{ + const char *base; + +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + /* Skip over a possible disk name. */ + if (ISALPHA (name[0]) && name[1] == ':') + name += 2; +#endif + + for (base = name; *name; name++) + if (IS_DIR_SEPARATOR (*name)) + base = name + 1; + + return base; +} diff --git a/libiberty/lrealpath.c b/libiberty/lrealpath.c new file mode 100644 index 0000000..b27c8de --- /dev/null +++ b/libiberty/lrealpath.c @@ -0,0 +1,157 @@ +/* Libiberty realpath. Like realpath, but more consistent behavior. + Based on gdb_realpath from GDB. + + Copyright 2003 Free Software Foundation, Inc. + + This file is part of the libiberty library. + + 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. */ + +/* + +@deftypefn Replacement {const char*} lrealpath (const char *@var{name}) + +Given a pointer to a string containing a pathname, returns a canonical +version of the filename. Symlinks will be resolved, and ``.'' and ``..'' +components will be simplified. The returned value will be allocated using +@code{malloc}, or @code{NULL} will be returned on a memory allocation error. + +@end deftypefn + +*/ + +#include "config.h" +#include "ansidecl.h" +#include "libiberty.h" + +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif + +/* On GNU libc systems the declaration is only visible with _GNU_SOURCE. */ +#if defined(HAVE_CANONICALIZE_FILE_NAME) \ + && defined(NEED_DECLARATION_CANONICALIZE_FILE_NAME) +extern char *canonicalize_file_name (const char *); +#endif + +#if defined(HAVE_REALPATH) +# if defined (PATH_MAX) +# define REALPATH_LIMIT PATH_MAX +# else +# if defined (MAXPATHLEN) +# define REALPATH_LIMIT MAXPATHLEN +# endif +# endif +#else + /* cygwin has realpath, so it won't get here. */ +# if defined (_WIN32) +# define WIN32_LEAN_AND_MEAN +# include /* for GetFullPathName */ +# endif +#endif + +char * +lrealpath (const char *filename) +{ + /* Method 1: The system has a compile time upper bound on a filename + path. Use that and realpath() to canonicalize the name. This is + the most common case. Note that, if there isn't a compile time + upper bound, you want to avoid realpath() at all costs. */ +#if defined(REALPATH_LIMIT) + { + char buf[REALPATH_LIMIT]; + const char *rp = realpath (filename, buf); + if (rp == NULL) + rp = filename; + return strdup (rp); + } +#endif /* REALPATH_LIMIT */ + + /* Method 2: The host system (i.e., GNU) has the function + canonicalize_file_name() which malloc's a chunk of memory and + returns that, use that. */ +#if defined(HAVE_CANONICALIZE_FILE_NAME) + { + char *rp = canonicalize_file_name (filename); + if (rp == NULL) + return strdup (filename); + else + return rp; + } +#endif + + /* Method 3: Now we're getting desperate! The system doesn't have a + compile time buffer size and no alternative function. Query the + OS, using pathconf(), for the buffer limit. Care is needed + though, some systems do not limit PATH_MAX (return -1 for + pathconf()) making it impossible to pass a correctly sized buffer + to realpath() (it could always overflow). On those systems, we + skip this. */ +#if defined (HAVE_REALPATH) && defined (HAVE_UNISTD_H) + { + /* Find out the max path size. */ + long path_max = pathconf ("/", _PC_PATH_MAX); + if (path_max > 0) + { + /* PATH_MAX is bounded. */ + char *buf, *rp, *ret; + buf = (char *) malloc (path_max); + if (buf == NULL) + return NULL; + rp = realpath (filename, buf); + ret = strdup (rp ? rp : filename); + free (buf); + return ret; + } + } +#endif + + /* The MS Windows method. If we don't have realpath, we assume we + don't have symlinks and just canonicalize to a Windows absolute + path. GetFullPath converts ../ and ./ in relative paths to + absolute paths, filling in current drive if one is not given + or using the current directory of a specified drive (eg, "E:foo"). + It also converts all forward slashes to back slashes. */ +#if defined (_WIN32) + { + char buf[MAX_PATH]; + char* basename; + DWORD len = GetFullPathName (filename, MAX_PATH, buf, &basename); + if (len == 0 || len > MAX_PATH - 1) + return strdup (filename); + else + { + /* The file system is case-preserving but case-insensitive, + Canonicalize to lowercase, using the codepage associated + with the process locale. */ + CharLowerBuff (buf, len); + return strdup (buf); + } + } +#endif + + /* This system is a lost cause, just duplicate the filename. */ + return strdup (filename); +} diff --git a/libiberty/make-relative-prefix.c b/libiberty/make-relative-prefix.c new file mode 100644 index 0000000..80e7f92 --- /dev/null +++ b/libiberty/make-relative-prefix.c @@ -0,0 +1,414 @@ +/* Relative (relocatable) prefix support. + Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is part of libiberty. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA +02110-1301, USA. */ + +/* + +@deftypefn Extension {const char*} make_relative_prefix (const char *@var{progname}, const char *@var{bin_prefix}, const char *@var{prefix}) + +Given three paths @var{progname}, @var{bin_prefix}, @var{prefix}, +return the path that is in the same position relative to +@var{progname}'s directory as @var{prefix} is relative to +@var{bin_prefix}. That is, a string starting with the directory +portion of @var{progname}, followed by a relative pathname of the +difference between @var{bin_prefix} and @var{prefix}. + +If @var{progname} does not contain any directory separators, +@code{make_relative_prefix} will search @env{PATH} to find a program +named @var{progname}. Also, if @var{progname} is a symbolic link, +the symbolic link will be resolved. + +For example, if @var{bin_prefix} is @code{/alpha/beta/gamma/gcc/delta}, +@var{prefix} is @code{/alpha/beta/gamma/omega/}, and @var{progname} is +@code{/red/green/blue/gcc}, then this function will return +@code{/red/green/blue/../../omega/}. + +The return value is normally allocated via @code{malloc}. If no +relative prefix can be found, return @code{NULL}. + +@end deftypefn + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + +#include + +#include "ansidecl.h" +#include "libiberty.h" + +#ifndef R_OK +#define R_OK 4 +#define W_OK 2 +#define X_OK 1 +#endif + +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) \ + || defined (__DJGPP__) || defined (__OS2__) +# define HAVE_DOS_BASED_FILE_SYSTEM +# define HAVE_HOST_EXECUTABLE_SUFFIX +# define HOST_EXECUTABLE_SUFFIX ".exe" +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# define PATH_SEPARATOR ';' +#else +# define PATH_SEPARATOR ':' +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif + +#define DIR_UP ".." + +static char *save_string (const char *, int); +static char **split_directories (const char *, int *); +static void free_split_directories (char **); + +static char * +save_string (const char *s, int len) +{ + char *result = (char *) malloc (len + 1); + + memcpy (result, s, len); + result[len] = 0; + return result; +} + +/* Split a filename into component directories. */ + +static char ** +split_directories (const char *name, int *ptr_num_dirs) +{ + int num_dirs = 0; + char **dirs; + const char *p, *q; + int ch; + + /* Count the number of directories. Special case MSDOS disk names as part + of the initial directory. */ + p = name; +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + if (name[1] == ':' && IS_DIR_SEPARATOR (name[2])) + { + p += 3; + num_dirs++; + } +#endif /* HAVE_DOS_BASED_FILE_SYSTEM */ + + while ((ch = *p++) != '\0') + { + if (IS_DIR_SEPARATOR (ch)) + { + num_dirs++; + while (IS_DIR_SEPARATOR (*p)) + p++; + } + } + + dirs = (char **) malloc (sizeof (char *) * (num_dirs + 2)); + if (dirs == NULL) + return NULL; + + /* Now copy the directory parts. */ + num_dirs = 0; + p = name; +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + if (name[1] == ':' && IS_DIR_SEPARATOR (name[2])) + { + dirs[num_dirs++] = save_string (p, 3); + if (dirs[num_dirs - 1] == NULL) + { + free (dirs); + return NULL; + } + p += 3; + } +#endif /* HAVE_DOS_BASED_FILE_SYSTEM */ + + q = p; + while ((ch = *p++) != '\0') + { + if (IS_DIR_SEPARATOR (ch)) + { + while (IS_DIR_SEPARATOR (*p)) + p++; + + dirs[num_dirs++] = save_string (q, p - q); + if (dirs[num_dirs - 1] == NULL) + { + dirs[num_dirs] = NULL; + free_split_directories (dirs); + return NULL; + } + q = p; + } + } + + if (p - 1 - q > 0) + dirs[num_dirs++] = save_string (q, p - 1 - q); + dirs[num_dirs] = NULL; + + if (dirs[num_dirs - 1] == NULL) + { + free_split_directories (dirs); + return NULL; + } + + if (ptr_num_dirs) + *ptr_num_dirs = num_dirs; + return dirs; +} + +/* Release storage held by split directories. */ + +static void +free_split_directories (char **dirs) +{ + int i = 0; + + if (dirs != NULL) + { + while (dirs[i] != NULL) + free (dirs[i++]); + + free ((char *) dirs); + } +} + +/* Given three strings PROGNAME, BIN_PREFIX, PREFIX, return a string that gets + to PREFIX starting with the directory portion of PROGNAME and a relative + pathname of the difference between BIN_PREFIX and PREFIX. + + For example, if BIN_PREFIX is /alpha/beta/gamma/gcc/delta, PREFIX is + /alpha/beta/gamma/omega/, and PROGNAME is /red/green/blue/gcc, then this + function will return /red/green/blue/../../omega/. + + If no relative prefix can be found, return NULL. */ + +static char * +make_relative_prefix_1 (const char *progname, const char *bin_prefix, + const char *prefix, const int resolve_links) +{ + char **prog_dirs = NULL, **bin_dirs = NULL, **prefix_dirs = NULL; + int prog_num, bin_num, prefix_num; + int i, n, common; + int needed_len; + char *ret = NULL, *ptr, *full_progname; + + if (progname == NULL || bin_prefix == NULL || prefix == NULL) + return NULL; + + /* If there is no full pathname, try to find the program by checking in each + of the directories specified in the PATH environment variable. */ + if (lbasename (progname) == progname) + { + char *temp; + + temp = getenv ("PATH"); + if (temp) + { + char *startp, *endp, *nstore; + size_t prefixlen = strlen (temp) + 1; + if (prefixlen < 2) + prefixlen = 2; + + nstore = (char *) alloca (prefixlen + strlen (progname) + 1); + + startp = endp = temp; + while (1) + { + if (*endp == PATH_SEPARATOR || *endp == 0) + { + if (endp == startp) + { + nstore[0] = '.'; + nstore[1] = DIR_SEPARATOR; + nstore[2] = '\0'; + } + else + { + strncpy (nstore, startp, endp - startp); + if (! IS_DIR_SEPARATOR (endp[-1])) + { + nstore[endp - startp] = DIR_SEPARATOR; + nstore[endp - startp + 1] = 0; + } + else + nstore[endp - startp] = 0; + } + strcat (nstore, progname); + if (! access (nstore, X_OK) +#ifdef HAVE_HOST_EXECUTABLE_SUFFIX + || ! access (strcat (nstore, HOST_EXECUTABLE_SUFFIX), X_OK) +#endif + ) + { + progname = nstore; + break; + } + + if (*endp == 0) + break; + endp = startp = endp + 1; + } + else + endp++; + } + } + } + + if ( resolve_links ) + { + full_progname = lrealpath (progname); + if (full_progname == NULL) + return NULL; + } + else + full_progname = strdup(progname); + + prog_dirs = split_directories (full_progname, &prog_num); + free (full_progname); + if (prog_dirs == NULL) + return NULL; + + bin_dirs = split_directories (bin_prefix, &bin_num); + if (bin_dirs == NULL) + goto bailout; + + /* Remove the program name from comparison of directory names. */ + prog_num--; + + /* If we are still installed in the standard location, we don't need to + specify relative directories. Also, if argv[0] still doesn't contain + any directory specifiers after the search above, then there is not much + we can do. */ + if (prog_num == bin_num) + { + for (i = 0; i < bin_num; i++) + { + if (strcmp (prog_dirs[i], bin_dirs[i]) != 0) + break; + } + + if (prog_num <= 0 || i == bin_num) + goto bailout; + } + + prefix_dirs = split_directories (prefix, &prefix_num); + if (prefix_dirs == NULL) + goto bailout; + + /* Find how many directories are in common between bin_prefix & prefix. */ + n = (prefix_num < bin_num) ? prefix_num : bin_num; + for (common = 0; common < n; common++) + { + if (strcmp (bin_dirs[common], prefix_dirs[common]) != 0) + break; + } + + /* If there are no common directories, there can be no relative prefix. */ + if (common == 0) + goto bailout; + + /* Two passes: first figure out the size of the result string, and + then construct it. */ + needed_len = 0; + for (i = 0; i < prog_num; i++) + needed_len += strlen (prog_dirs[i]); + needed_len += sizeof (DIR_UP) * (bin_num - common); + for (i = common; i < prefix_num; i++) + needed_len += strlen (prefix_dirs[i]); + needed_len += 1; /* Trailing NUL. */ + + ret = (char *) malloc (needed_len); + if (ret == NULL) + goto bailout; + + /* Build up the pathnames in argv[0]. */ + *ret = '\0'; + for (i = 0; i < prog_num; i++) + strcat (ret, prog_dirs[i]); + + /* Now build up the ..'s. */ + ptr = ret + strlen(ret); + for (i = common; i < bin_num; i++) + { + strcpy (ptr, DIR_UP); + ptr += sizeof (DIR_UP) - 1; + *(ptr++) = DIR_SEPARATOR; + } + *ptr = '\0'; + + /* Put in directories to move over to prefix. */ + for (i = common; i < prefix_num; i++) + strcat (ret, prefix_dirs[i]); + + bailout: + free_split_directories (prog_dirs); + free_split_directories (bin_dirs); + free_split_directories (prefix_dirs); + + return ret; +} + + +/* Do the full job, including symlink resolution. + This path will find files installed in the same place as the + program even when a soft link has been made to the program + from somwhere else. */ + +char * +make_relative_prefix (const char *progname, const char *bin_prefix, + const char *prefix) +{ + return make_relative_prefix_1 (progname, bin_prefix, prefix, 1); +} + +/* Make the relative pathname without attempting to resolve any links. + '..' etc may also be left in the pathname. + This will find the files the user meant the program to find if the + installation is patched together with soft links. */ + +char * +make_relative_prefix_ignore_links (const char *progname, + const char *bin_prefix, + const char *prefix) +{ + return make_relative_prefix_1 (progname, bin_prefix, prefix, 0); +} + diff --git a/libiberty/make-temp-file.c b/libiberty/make-temp-file.c new file mode 100644 index 0000000..5e21414 --- /dev/null +++ b/libiberty/make-temp-file.c @@ -0,0 +1,177 @@ +/* Utility to pick a temporary filename prefix. + Copyright (C) 1996, 1997, 1998, 2001 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include /* May get P_tmpdir. */ +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_SYS_FILE_H +#include /* May get R_OK, etc. on some systems. */ +#endif + +#ifndef R_OK +#define R_OK 4 +#define W_OK 2 +#define X_OK 1 +#endif + +#include "libiberty.h" +extern int mkstemps (char *, int); + +/* '/' works just fine on MS-DOS based systems. */ +#ifndef DIR_SEPARATOR +#define DIR_SEPARATOR '/' +#endif + +/* Name of temporary file. + mktemp requires 6 trailing X's. */ +#define TEMP_FILE "ccXXXXXX" +#define TEMP_FILE_LEN (sizeof(TEMP_FILE) - 1) + +/* Subroutine of choose_tmpdir. + If BASE is non-NULL, return it. + Otherwise it checks if DIR is a usable directory. + If success, DIR is returned. + Otherwise NULL is returned. */ + +static inline const char *try_dir (const char *, const char *); + +static inline const char * +try_dir (const char *dir, const char *base) +{ + if (base != 0) + return base; + if (dir != 0 + && access (dir, R_OK | W_OK | X_OK) == 0) + return dir; + return 0; +} + +static const char tmp[] = { DIR_SEPARATOR, 't', 'm', 'p', 0 }; +static const char usrtmp[] = +{ DIR_SEPARATOR, 'u', 's', 'r', DIR_SEPARATOR, 't', 'm', 'p', 0 }; +static const char vartmp[] = +{ DIR_SEPARATOR, 'v', 'a', 'r', DIR_SEPARATOR, 't', 'm', 'p', 0 }; + +static char *memoized_tmpdir; + +/* + +@deftypefn Replacement char* choose_tmpdir () + +Returns a pointer to a directory path suitable for creating temporary +files in. + +@end deftypefn + +*/ + +char * +choose_tmpdir (void) +{ + const char *base = 0; + char *tmpdir; + unsigned int len; + + if (memoized_tmpdir) + return memoized_tmpdir; + + base = try_dir (getenv ("TMPDIR"), base); + base = try_dir (getenv ("TMP"), base); + base = try_dir (getenv ("TEMP"), base); + +#ifdef P_tmpdir + base = try_dir (P_tmpdir, base); +#endif + + /* Try /var/tmp, /usr/tmp, then /tmp. */ + base = try_dir (vartmp, base); + base = try_dir (usrtmp, base); + base = try_dir (tmp, base); + + /* If all else fails, use the current directory! */ + if (base == 0) + base = "."; + + /* Append DIR_SEPARATOR to the directory we've chosen + and return it. */ + len = strlen (base); + tmpdir = XNEWVEC (char, len + 2); + strcpy (tmpdir, base); + tmpdir[len] = DIR_SEPARATOR; + tmpdir[len+1] = '\0'; + + memoized_tmpdir = tmpdir; + return tmpdir; +} + +/* + +@deftypefn Replacement char* make_temp_file (const char *@var{suffix}) + +Return a temporary file name (as a string) or @code{NULL} if unable to +create one. @var{suffix} is a suffix to append to the file name. The +string is @code{malloc}ed, and the temporary file has been created. + +@end deftypefn + +*/ + +char * +make_temp_file (const char *suffix) +{ + const char *base = choose_tmpdir (); + char *temp_filename; + int base_len, suffix_len; + int fd; + + if (suffix == 0) + suffix = ""; + + base_len = strlen (base); + suffix_len = strlen (suffix); + + temp_filename = XNEWVEC (char, base_len + + TEMP_FILE_LEN + + suffix_len + 1); + strcpy (temp_filename, base); + strcpy (temp_filename + base_len, TEMP_FILE); + strcpy (temp_filename + base_len + TEMP_FILE_LEN, suffix); + + fd = mkstemps (temp_filename, suffix_len); + /* If mkstemps failed, then something bad is happening. Maybe we should + issue a message about a possible security attack in progress? */ + if (fd == -1) + abort (); + /* Similarly if we can not close the file. */ + if (close (fd)) + abort (); + return temp_filename; +} diff --git a/libiberty/md5.c b/libiberty/md5.c new file mode 100644 index 0000000..83e0beb --- /dev/null +++ b/libiberty/md5.c @@ -0,0 +1,430 @@ +/* md5.c - Functions to compute MD5 message digest of files or memory blocks + according to the definition of MD5 in RFC 1321 from April 1992. + Copyright (C) 1995, 1996 Free Software Foundation, Inc. + + NOTE: This source is derived from an old version taken from the GNU C + Library (glibc). + + 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, 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. */ + +/* Written by Ulrich Drepper , 1995. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#if STDC_HEADERS || defined _LIBC +# include +# include +#else +# ifndef HAVE_MEMCPY +# define memcpy(d, s, n) bcopy ((s), (d), (n)) +# endif +#endif + +#include "ansidecl.h" +#include "md5.h" + +#ifdef _LIBC +# include +# if __BYTE_ORDER == __BIG_ENDIAN +# define WORDS_BIGENDIAN 1 +# endif +#endif + +#ifdef WORDS_BIGENDIAN +# define SWAP(n) \ + (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) +#else +# define SWAP(n) (n) +#endif + + +/* This array contains the bytes used to pad the buffer to the next + 64-byte boundary. (RFC 1321, 3.1: Step 1) */ +static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; + + +/* Initialize structure containing state of computation. + (RFC 1321, 3.3: Step 3) */ +void +md5_init_ctx (struct md5_ctx *ctx) +{ + ctx->A = (md5_uint32) 0x67452301; + ctx->B = (md5_uint32) 0xefcdab89; + ctx->C = (md5_uint32) 0x98badcfe; + ctx->D = (md5_uint32) 0x10325476; + + ctx->total[0] = ctx->total[1] = 0; + ctx->buflen = 0; +} + +/* Put result from CTX in first 16 bytes following RESBUF. The result + must be in little endian byte order. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +void * +md5_read_ctx (const struct md5_ctx *ctx, void *resbuf) +{ + ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A); + ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B); + ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C); + ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D); + + return resbuf; +} + +/* Process the remaining bytes in the internal buffer and the usual + prolog according to the standard and write the result to RESBUF. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +void * +md5_finish_ctx (struct md5_ctx *ctx, void *resbuf) +{ + /* Take yet unprocessed bytes into account. */ + md5_uint32 bytes = ctx->buflen; + size_t pad; + + /* Now count remaining bytes. */ + ctx->total[0] += bytes; + if (ctx->total[0] < bytes) + ++ctx->total[1]; + + pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; + memcpy (&ctx->buffer[bytes], fillbuf, pad); + + /* Put the 64-bit file length in *bits* at the end of the buffer. */ + *(md5_uint32 *) &ctx->buffer[bytes + pad] = SWAP (ctx->total[0] << 3); + *(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = SWAP ((ctx->total[1] << 3) | + (ctx->total[0] >> 29)); + + /* Process last bytes. */ + md5_process_block (ctx->buffer, bytes + pad + 8, ctx); + + return md5_read_ctx (ctx, resbuf); +} + +/* Compute MD5 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +int +md5_stream (FILE *stream, void *resblock) +{ + /* Important: BLOCKSIZE must be a multiple of 64. */ +#define BLOCKSIZE 4096 + struct md5_ctx ctx; + char buffer[BLOCKSIZE + 72]; + size_t sum; + + /* Initialize the computation context. */ + md5_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + do + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + } + while (sum < BLOCKSIZE && n != 0); + if (n == 0 && ferror (stream)) + return 1; + + /* If end of file is reached, end the loop. */ + if (n == 0) + break; + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 64 == 0 + */ + md5_process_block (buffer, BLOCKSIZE, &ctx); + } + + /* Add the last bytes if necessary. */ + if (sum > 0) + md5_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + md5_finish_ctx (&ctx, resblock); + return 0; +} + +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +void * +md5_buffer (const char *buffer, size_t len, void *resblock) +{ + struct md5_ctx ctx; + + /* Initialize the computation context. */ + md5_init_ctx (&ctx); + + /* Process whole buffer but last len % 64 bytes. */ + md5_process_bytes (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return md5_finish_ctx (&ctx, resblock); +} + + +void +md5_process_bytes (const void *buffer, size_t len, struct md5_ctx *ctx) +{ + /* When we already have some bits in our internal buffer concatenate + both inputs first. */ + if (ctx->buflen != 0) + { + size_t left_over = ctx->buflen; + size_t add = 128 - left_over > len ? len : 128 - left_over; + + memcpy (&ctx->buffer[left_over], buffer, add); + ctx->buflen += add; + + if (left_over + add > 64) + { + md5_process_block (ctx->buffer, (left_over + add) & ~63, ctx); + /* The regions in the following copy operation cannot overlap. */ + memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63], + (left_over + add) & 63); + ctx->buflen = (left_over + add) & 63; + } + + buffer = (const void *) ((const char *) buffer + add); + len -= add; + } + + /* Process available complete blocks. */ + if (len > 64) + { +#if !_STRING_ARCH_unaligned +/* To check alignment gcc has an appropriate operator. Other + compilers don't. */ +# if __GNUC__ >= 2 +# define UNALIGNED_P(p) (((md5_uintptr) p) % __alignof__ (md5_uint32) != 0) +# else +# define UNALIGNED_P(p) (((md5_uintptr) p) % sizeof (md5_uint32) != 0) +# endif + if (UNALIGNED_P (buffer)) + while (len > 64) + { + md5_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); + buffer = (const char *) buffer + 64; + len -= 64; + } + else +#endif + md5_process_block (buffer, len & ~63, ctx); + buffer = (const void *) ((const char *) buffer + (len & ~63)); + len &= 63; + } + + /* Move remaining bytes in internal buffer. */ + if (len > 0) + { + memcpy (ctx->buffer, buffer, len); + ctx->buflen = len; + } +} + + +/* These are the four functions used in the four steps of the MD5 algorithm + and defined in the RFC 1321. The first function is a little bit optimized + (as found in Colin Plumbs public domain implementation). */ +/* #define FF(b, c, d) ((b & c) | (~b & d)) */ +#define FF(b, c, d) (d ^ (b & (c ^ d))) +#define FG(b, c, d) FF (d, b, c) +#define FH(b, c, d) (b ^ c ^ d) +#define FI(b, c, d) (c ^ (b | ~d)) + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 64 == 0. */ + +void +md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx) +{ + md5_uint32 correct_words[16]; + const md5_uint32 *words = (const md5_uint32 *) buffer; + size_t nwords = len / sizeof (md5_uint32); + const md5_uint32 *endp = words + nwords; + md5_uint32 A = ctx->A; + md5_uint32 B = ctx->B; + md5_uint32 C = ctx->C; + md5_uint32 D = ctx->D; + + /* First increment the byte count. RFC 1321 specifies the possible + length of the file up to 2^64 bits. Here we only compute the + number of bytes. Do a double word increment. */ + ctx->total[0] += len; + if (ctx->total[0] < len) + ++ctx->total[1]; + + /* Process all bytes in the buffer with 64 bytes in each round of + the loop. */ + while (words < endp) + { + md5_uint32 *cwp = correct_words; + md5_uint32 A_save = A; + md5_uint32 B_save = B; + md5_uint32 C_save = C; + md5_uint32 D_save = D; + + /* First round: using the given function, the context and a constant + the next context is computed. Because the algorithms processing + unit is a 32-bit word and it is determined to work on words in + little endian byte order we perhaps have to change the byte order + before the computation. To reduce the work for the next steps + we store the swapped words in the array CORRECT_WORDS. */ + +#define OP(a, b, c, d, s, T) \ + do \ + { \ + a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \ + ++words; \ + CYCLIC (a, s); \ + a += b; \ + } \ + while (0) + + /* It is unfortunate that C does not provide an operator for + cyclic rotation. Hope the C compiler is smart enough. */ +#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s))) + + /* Before we start, one word to the strange constants. + They are defined in RFC 1321 as + + T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 + */ + + /* Round 1. */ + OP (A, B, C, D, 7, (md5_uint32) 0xd76aa478); + OP (D, A, B, C, 12, (md5_uint32) 0xe8c7b756); + OP (C, D, A, B, 17, (md5_uint32) 0x242070db); + OP (B, C, D, A, 22, (md5_uint32) 0xc1bdceee); + OP (A, B, C, D, 7, (md5_uint32) 0xf57c0faf); + OP (D, A, B, C, 12, (md5_uint32) 0x4787c62a); + OP (C, D, A, B, 17, (md5_uint32) 0xa8304613); + OP (B, C, D, A, 22, (md5_uint32) 0xfd469501); + OP (A, B, C, D, 7, (md5_uint32) 0x698098d8); + OP (D, A, B, C, 12, (md5_uint32) 0x8b44f7af); + OP (C, D, A, B, 17, (md5_uint32) 0xffff5bb1); + OP (B, C, D, A, 22, (md5_uint32) 0x895cd7be); + OP (A, B, C, D, 7, (md5_uint32) 0x6b901122); + OP (D, A, B, C, 12, (md5_uint32) 0xfd987193); + OP (C, D, A, B, 17, (md5_uint32) 0xa679438e); + OP (B, C, D, A, 22, (md5_uint32) 0x49b40821); + + /* For the second to fourth round we have the possibly swapped words + in CORRECT_WORDS. Redefine the macro to take an additional first + argument specifying the function to use. */ +#undef OP +#define OP(a, b, c, d, k, s, T) \ + do \ + { \ + a += FX (b, c, d) + correct_words[k] + T; \ + CYCLIC (a, s); \ + a += b; \ + } \ + while (0) + +#define FX(b, c, d) FG (b, c, d) + + /* Round 2. */ + OP (A, B, C, D, 1, 5, (md5_uint32) 0xf61e2562); + OP (D, A, B, C, 6, 9, (md5_uint32) 0xc040b340); + OP (C, D, A, B, 11, 14, (md5_uint32) 0x265e5a51); + OP (B, C, D, A, 0, 20, (md5_uint32) 0xe9b6c7aa); + OP (A, B, C, D, 5, 5, (md5_uint32) 0xd62f105d); + OP (D, A, B, C, 10, 9, (md5_uint32) 0x02441453); + OP (C, D, A, B, 15, 14, (md5_uint32) 0xd8a1e681); + OP (B, C, D, A, 4, 20, (md5_uint32) 0xe7d3fbc8); + OP (A, B, C, D, 9, 5, (md5_uint32) 0x21e1cde6); + OP (D, A, B, C, 14, 9, (md5_uint32) 0xc33707d6); + OP (C, D, A, B, 3, 14, (md5_uint32) 0xf4d50d87); + OP (B, C, D, A, 8, 20, (md5_uint32) 0x455a14ed); + OP (A, B, C, D, 13, 5, (md5_uint32) 0xa9e3e905); + OP (D, A, B, C, 2, 9, (md5_uint32) 0xfcefa3f8); + OP (C, D, A, B, 7, 14, (md5_uint32) 0x676f02d9); + OP (B, C, D, A, 12, 20, (md5_uint32) 0x8d2a4c8a); + +#undef FX +#define FX(b, c, d) FH (b, c, d) + + /* Round 3. */ + OP (A, B, C, D, 5, 4, (md5_uint32) 0xfffa3942); + OP (D, A, B, C, 8, 11, (md5_uint32) 0x8771f681); + OP (C, D, A, B, 11, 16, (md5_uint32) 0x6d9d6122); + OP (B, C, D, A, 14, 23, (md5_uint32) 0xfde5380c); + OP (A, B, C, D, 1, 4, (md5_uint32) 0xa4beea44); + OP (D, A, B, C, 4, 11, (md5_uint32) 0x4bdecfa9); + OP (C, D, A, B, 7, 16, (md5_uint32) 0xf6bb4b60); + OP (B, C, D, A, 10, 23, (md5_uint32) 0xbebfbc70); + OP (A, B, C, D, 13, 4, (md5_uint32) 0x289b7ec6); + OP (D, A, B, C, 0, 11, (md5_uint32) 0xeaa127fa); + OP (C, D, A, B, 3, 16, (md5_uint32) 0xd4ef3085); + OP (B, C, D, A, 6, 23, (md5_uint32) 0x04881d05); + OP (A, B, C, D, 9, 4, (md5_uint32) 0xd9d4d039); + OP (D, A, B, C, 12, 11, (md5_uint32) 0xe6db99e5); + OP (C, D, A, B, 15, 16, (md5_uint32) 0x1fa27cf8); + OP (B, C, D, A, 2, 23, (md5_uint32) 0xc4ac5665); + +#undef FX +#define FX(b, c, d) FI (b, c, d) + + /* Round 4. */ + OP (A, B, C, D, 0, 6, (md5_uint32) 0xf4292244); + OP (D, A, B, C, 7, 10, (md5_uint32) 0x432aff97); + OP (C, D, A, B, 14, 15, (md5_uint32) 0xab9423a7); + OP (B, C, D, A, 5, 21, (md5_uint32) 0xfc93a039); + OP (A, B, C, D, 12, 6, (md5_uint32) 0x655b59c3); + OP (D, A, B, C, 3, 10, (md5_uint32) 0x8f0ccc92); + OP (C, D, A, B, 10, 15, (md5_uint32) 0xffeff47d); + OP (B, C, D, A, 1, 21, (md5_uint32) 0x85845dd1); + OP (A, B, C, D, 8, 6, (md5_uint32) 0x6fa87e4f); + OP (D, A, B, C, 15, 10, (md5_uint32) 0xfe2ce6e0); + OP (C, D, A, B, 6, 15, (md5_uint32) 0xa3014314); + OP (B, C, D, A, 13, 21, (md5_uint32) 0x4e0811a1); + OP (A, B, C, D, 4, 6, (md5_uint32) 0xf7537e82); + OP (D, A, B, C, 11, 10, (md5_uint32) 0xbd3af235); + OP (C, D, A, B, 2, 15, (md5_uint32) 0x2ad7d2bb); + OP (B, C, D, A, 9, 21, (md5_uint32) 0xeb86d391); + + /* Add the starting values of the context. */ + A += A_save; + B += B_save; + C += C_save; + D += D_save; + } + + /* Put checksum in context given as argument. */ + ctx->A = A; + ctx->B = B; + ctx->C = C; + ctx->D = D; +} diff --git a/libiberty/memchr.c b/libiberty/memchr.c new file mode 100644 index 0000000..451f817 --- /dev/null +++ b/libiberty/memchr.c @@ -0,0 +1,32 @@ +/* + +@deftypefn Supplemental void* memchr (const void *@var{s}, int @var{c}, size_t @var{n}) + +This function searches memory starting at @code{*@var{s}} for the +character @var{c}. The search only ends with the first occurrence of +@var{c}, or after @var{length} characters; in particular, a null +character does not terminate the search. If the character @var{c} is +found within @var{length} characters of @code{*@var{s}}, a pointer +to the character is returned. If @var{c} is not found, then @code{NULL} is +returned. + +@end deftypefn + +*/ + +#include +#include + +PTR +memchr (register const PTR src_void, int c, size_t length) +{ + const unsigned char *src = (const unsigned char *)src_void; + + while (length-- > 0) + { + if (*src == c) + return (PTR)src; + src++; + } + return NULL; +} diff --git a/libiberty/memcmp.c b/libiberty/memcmp.c new file mode 100644 index 0000000..39edfca --- /dev/null +++ b/libiberty/memcmp.c @@ -0,0 +1,34 @@ +/* memcmp -- compare two memory regions. + This function is in the public domain. */ + +/* + +@deftypefn Supplemental int memcmp (const void *@var{x}, const void *@var{y}, size_t @var{count}) + +Compares the first @var{count} bytes of two areas of memory. Returns +zero if they are the same, a value less than zero if @var{x} is +lexically less than @var{y}, or a value greater than zero if @var{x} +is lexically greater than @var{y}. Note that lexical order is determined +as if comparing unsigned char arrays. + +@end deftypefn + +*/ + +#include +#include + +int +memcmp (const PTR str1, const PTR str2, size_t count) +{ + register const unsigned char *s1 = (const unsigned char*)str1; + register const unsigned char *s2 = (const unsigned char*)str2; + + while (count-- > 0) + { + if (*s1++ != *s2++) + return s1[-1] < s2[-1] ? -1 : 1; + } + return 0; +} + diff --git a/libiberty/memcpy.c b/libiberty/memcpy.c new file mode 100644 index 0000000..9b5b242 --- /dev/null +++ b/libiberty/memcpy.c @@ -0,0 +1,25 @@ +/* memcpy (the standard C function) + This function is in the public domain. */ + +/* + +@deftypefn Supplemental void* memcpy (void *@var{out}, const void *@var{in}, size_t @var{length}) + +Copies @var{length} bytes from memory region @var{in} to region +@var{out}. Returns a pointer to @var{out}. + +@end deftypefn + +*/ + +#include +#include + +void bcopy (const void*, void*, size_t); + +PTR +memcpy (PTR out, const PTR in, size_t length) +{ + bcopy(in, out, length); + return out; +} diff --git a/libiberty/memmove.c b/libiberty/memmove.c new file mode 100644 index 0000000..06a24fc --- /dev/null +++ b/libiberty/memmove.c @@ -0,0 +1,25 @@ +/* Wrapper to implement ANSI C's memmove using BSD's bcopy. */ +/* This function is in the public domain. --Per Bothner. */ + +/* + +@deftypefn Supplemental void* memmove (void *@var{from}, const void *@var{to}, size_t @var{count}) + +Copies @var{count} bytes from memory area @var{from} to memory area +@var{to}, returning a pointer to @var{to}. + +@end deftypefn + +*/ + +#include +#include + +void bcopy (const void*, void*, size_t); + +PTR +memmove (PTR s1, const PTR s2, size_t n) +{ + bcopy (s2, s1, n); + return s1; +} diff --git a/libiberty/mempcpy.c b/libiberty/mempcpy.c new file mode 100644 index 0000000..beda7df --- /dev/null +++ b/libiberty/mempcpy.c @@ -0,0 +1,41 @@ +/* Implement the mempcpy function. + Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + Written by Kaveh R. Ghazi . + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* + +@deftypefn Supplemental void* mempcpy (void *@var{out}, const void *@var{in}, size_t @var{length}) + +Copies @var{length} bytes from memory region @var{in} to region +@var{out}. Returns a pointer to @var{out} + @var{length}. + +@end deftypefn + +*/ + +#include +#include + +extern PTR memcpy (PTR, const PTR, size_t); + +PTR +mempcpy (PTR dst, const PTR src, size_t len) +{ + return (char *) memcpy (dst, src, len) + len; +} diff --git a/libiberty/memset.c b/libiberty/memset.c new file mode 100644 index 0000000..1951ad6 --- /dev/null +++ b/libiberty/memset.c @@ -0,0 +1,25 @@ +/* memset + This implementation is in the public domain. */ + +/* + +@deftypefn Supplemental void* memset (void *@var{s}, int @var{c}, size_t @var{count}) + +Sets the first @var{count} bytes of @var{s} to the constant byte +@var{c}, returning a pointer to @var{s}. + +@end deftypefn + +*/ + +#include +#include + +PTR +memset (PTR dest, register int val, register size_t len) +{ + register unsigned char *ptr = (unsigned char*)dest; + while (len-- > 0) + *ptr++ = val; + return dest; +} diff --git a/libiberty/mkstemps.c b/libiberty/mkstemps.c new file mode 100644 index 0000000..6c2e472 --- /dev/null +++ b/libiberty/mkstemps.c @@ -0,0 +1,140 @@ +/* Copyright (C) 1991, 1992, 1996, 1998, 2004 Free Software Foundation, Inc. + This file is derived from mkstemp.c from the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, + Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#include "ansidecl.h" + +/* We need to provide a type for gcc_uint64_t. */ +#ifdef __GNUC__ +__extension__ typedef unsigned long long gcc_uint64_t; +#else +typedef unsigned long gcc_uint64_t; +#endif + +#ifndef TMP_MAX +#define TMP_MAX 16384 +#endif + +#ifndef O_BINARY +# define O_BINARY 0 +#endif + +/* + +@deftypefn Replacement int mkstemps (char *@var{pattern}, int @var{suffix_len}) + +Generate a unique temporary file name from @var{pattern}. +@var{pattern} has the form: + +@example + @var{path}/ccXXXXXX@var{suffix} +@end example + +@var{suffix_len} tells us how long @var{suffix} is (it can be zero +length). The last six characters of @var{pattern} before @var{suffix} +must be @samp{XXXXXX}; they are replaced with a string that makes the +filename unique. Returns a file descriptor open on the file for +reading and writing. + +@end deftypefn + +*/ + +int +mkstemps (char *pattern, int suffix_len) +{ + static const char letters[] + = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + static gcc_uint64_t value; +#ifdef HAVE_GETTIMEOFDAY + struct timeval tv; +#endif + char *XXXXXX; + size_t len; + int count; + + len = strlen (pattern); + + if ((int) len < 6 + suffix_len + || strncmp (&pattern[len - 6 - suffix_len], "XXXXXX", 6)) + { + return -1; + } + + XXXXXX = &pattern[len - 6 - suffix_len]; + +#ifdef HAVE_GETTIMEOFDAY + /* Get some more or less random data. */ + gettimeofday (&tv, NULL); + value += ((gcc_uint64_t) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid (); +#else + value += getpid (); +#endif + + for (count = 0; count < TMP_MAX; ++count) + { + gcc_uint64_t v = value; + int fd; + + /* Fill in the random bits. */ + XXXXXX[0] = letters[v % 62]; + v /= 62; + XXXXXX[1] = letters[v % 62]; + v /= 62; + XXXXXX[2] = letters[v % 62]; + v /= 62; + XXXXXX[3] = letters[v % 62]; + v /= 62; + XXXXXX[4] = letters[v % 62]; + v /= 62; + XXXXXX[5] = letters[v % 62]; + + fd = open (pattern, O_BINARY|O_RDWR|O_CREAT|O_EXCL, 0600); + if (fd >= 0) + /* The file does not exist. */ + return fd; + + /* This is a random value. It is only necessary that the next + TMP_MAX values generated by adding 7777 to VALUE are different + with (module 2^32). */ + value += 7777; + } + + /* We return the null string if we can't find a unique file name. */ + pattern[0] = '\0'; + return -1; +} diff --git a/libiberty/msdos.c b/libiberty/msdos.c new file mode 100644 index 0000000..923e64d --- /dev/null +++ b/libiberty/msdos.c @@ -0,0 +1,15 @@ +char msg[] = "No vfork available - aborting\n"; +vfork() +{ + write(1, msg, sizeof(msg)); +} + +sigsetmask() +{ + /* no signals support in go32 (yet) */ +} + +waitpid() +{ + return -1; +} diff --git a/libiberty/objalloc.c b/libiberty/objalloc.c new file mode 100644 index 0000000..3ddac2c --- /dev/null +++ b/libiberty/objalloc.c @@ -0,0 +1,291 @@ +/* objalloc.c -- routines to allocate memory for objects + Copyright 1997 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Cygnus Solutions. + +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, 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, 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#include "config.h" +#include "ansidecl.h" + +#include "objalloc.h" + +/* Get a definition for NULL. */ +#include + +#if VMS +#include +#include +#else + +/* Get a definition for size_t. */ +#include + +#ifdef HAVE_STDLIB_H +#include +#else +/* For systems with larger pointers than ints, this must be declared. */ +extern PTR malloc (size_t); +extern void free (PTR); +#endif + +#endif + +/* These routines allocate space for an object. Freeing allocated + space may or may not free all more recently allocated space. + + We handle large and small allocation requests differently. If we + don't have enough space in the current block, and the allocation + request is for more than 512 bytes, we simply pass it through to + malloc. */ + +/* The objalloc structure is defined in objalloc.h. */ + +/* This structure appears at the start of each chunk. */ + +struct objalloc_chunk +{ + /* Next chunk. */ + struct objalloc_chunk *next; + /* If this chunk contains large objects, this is the value of + current_ptr when this chunk was allocated. If this chunk + contains small objects, this is NULL. */ + char *current_ptr; +}; + +/* The aligned size of objalloc_chunk. */ + +#define CHUNK_HEADER_SIZE \ + ((sizeof (struct objalloc_chunk) + OBJALLOC_ALIGN - 1) \ + &~ (OBJALLOC_ALIGN - 1)) + +/* We ask for this much memory each time we create a chunk which is to + hold small objects. */ + +#define CHUNK_SIZE (4096 - 32) + +/* A request for this amount or more is just passed through to malloc. */ + +#define BIG_REQUEST (512) + +/* Create an objalloc structure. */ + +struct objalloc * +objalloc_create (void) +{ + struct objalloc *ret; + struct objalloc_chunk *chunk; + + ret = (struct objalloc *) malloc (sizeof *ret); + if (ret == NULL) + return NULL; + + ret->chunks = (PTR) malloc (CHUNK_SIZE); + if (ret->chunks == NULL) + { + free (ret); + return NULL; + } + + chunk = (struct objalloc_chunk *) ret->chunks; + chunk->next = NULL; + chunk->current_ptr = NULL; + + ret->current_ptr = (char *) chunk + CHUNK_HEADER_SIZE; + ret->current_space = CHUNK_SIZE - CHUNK_HEADER_SIZE; + + return ret; +} + +/* Allocate space from an objalloc structure. */ + +PTR +_objalloc_alloc (struct objalloc *o, unsigned long len) +{ + /* We avoid confusion from zero sized objects by always allocating + at least 1 byte. */ + if (len == 0) + len = 1; + + len = (len + OBJALLOC_ALIGN - 1) &~ (OBJALLOC_ALIGN - 1); + + if (len <= o->current_space) + { + o->current_ptr += len; + o->current_space -= len; + return (PTR) (o->current_ptr - len); + } + + if (len >= BIG_REQUEST) + { + char *ret; + struct objalloc_chunk *chunk; + + ret = (char *) malloc (CHUNK_HEADER_SIZE + len); + if (ret == NULL) + return NULL; + + chunk = (struct objalloc_chunk *) ret; + chunk->next = (struct objalloc_chunk *) o->chunks; + chunk->current_ptr = o->current_ptr; + + o->chunks = (PTR) chunk; + + return (PTR) (ret + CHUNK_HEADER_SIZE); + } + else + { + struct objalloc_chunk *chunk; + + chunk = (struct objalloc_chunk *) malloc (CHUNK_SIZE); + if (chunk == NULL) + return NULL; + chunk->next = (struct objalloc_chunk *) o->chunks; + chunk->current_ptr = NULL; + + o->current_ptr = (char *) chunk + CHUNK_HEADER_SIZE; + o->current_space = CHUNK_SIZE - CHUNK_HEADER_SIZE; + + o->chunks = (PTR) chunk; + + return objalloc_alloc (o, len); + } +} + +/* Free an entire objalloc structure. */ + +void +objalloc_free (struct objalloc *o) +{ + struct objalloc_chunk *l; + + l = (struct objalloc_chunk *) o->chunks; + while (l != NULL) + { + struct objalloc_chunk *next; + + next = l->next; + free (l); + l = next; + } + + free (o); +} + +/* Free a block from an objalloc structure. This also frees all more + recently allocated blocks. */ + +void +objalloc_free_block (struct objalloc *o, PTR block) +{ + struct objalloc_chunk *p, *small; + char *b = (char *) block; + + /* First set P to the chunk which contains the block we are freeing, + and set Q to the last small object chunk we see before P. */ + small = NULL; + for (p = (struct objalloc_chunk *) o->chunks; p != NULL; p = p->next) + { + if (p->current_ptr == NULL) + { + if (b > (char *) p && b < (char *) p + CHUNK_SIZE) + break; + small = p; + } + else + { + if (b == (char *) p + CHUNK_HEADER_SIZE) + break; + } + } + + /* If we can't find the chunk, the caller has made a mistake. */ + if (p == NULL) + abort (); + + if (p->current_ptr == NULL) + { + struct objalloc_chunk *q; + struct objalloc_chunk *first; + + /* The block is in a chunk containing small objects. We can + free every chunk through SMALL, because they have certainly + been allocated more recently. After SMALL, we will not see + any chunks containing small objects; we can free any big + chunk if the current_ptr is greater than or equal to B. We + can then reset the new current_ptr to B. */ + + first = NULL; + q = (struct objalloc_chunk *) o->chunks; + while (q != p) + { + struct objalloc_chunk *next; + + next = q->next; + if (small != NULL) + { + if (small == q) + small = NULL; + free (q); + } + else if (q->current_ptr > b) + free (q); + else if (first == NULL) + first = q; + + q = next; + } + + if (first == NULL) + first = p; + o->chunks = (PTR) first; + + /* Now start allocating from this small block again. */ + o->current_ptr = b; + o->current_space = ((char *) p + CHUNK_SIZE) - b; + } + else + { + struct objalloc_chunk *q; + char *current_ptr; + + /* This block is in a large chunk by itself. We can free + everything on the list up to and including this block. We + then start allocating from the next chunk containing small + objects, setting current_ptr from the value stored with the + large chunk we are freeing. */ + + current_ptr = p->current_ptr; + p = p->next; + + q = (struct objalloc_chunk *) o->chunks; + while (q != p) + { + struct objalloc_chunk *next; + + next = q->next; + free (q); + q = next; + } + + o->chunks = (PTR) p; + + while (p->current_ptr != NULL) + p = p->next; + + o->current_ptr = current_ptr; + o->current_space = ((char *) p + CHUNK_SIZE) - current_ptr; + } +} diff --git a/libiberty/obstack.c b/libiberty/obstack.c new file mode 100644 index 0000000..a6dbaf0 --- /dev/null +++ b/libiberty/obstack.c @@ -0,0 +1,510 @@ +/* obstack.c - subroutines used implicitly by object stack macros + Copyright (C) 1988,89,90,91,92,93,94,96,97 Free Software Foundation, Inc. + + + NOTE: This source is derived from an old version taken from the GNU C + Library (glibc). + + 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, 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. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "obstack.h" + +/* NOTE BEFORE MODIFYING THIS FILE: This version number must be + incremented whenever callers compiled using an old obstack.h can no + longer properly call the functions in this obstack.c. */ +#define OBSTACK_INTERFACE_VERSION 1 + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself, and the installed library + supports the same library interface we do. 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. */ + +#include /* Random thing to get __GNU_LIBRARY__. */ +#if !defined (_LIBC) && defined (__GNU_LIBRARY__) && __GNU_LIBRARY__ > 1 +#include +#if _GNU_OBSTACK_INTERFACE_VERSION == OBSTACK_INTERFACE_VERSION +#define ELIDE_CODE +#endif +#endif + + +#ifndef ELIDE_CODE + + +#define POINTER void * + +/* Determine default alignment. */ +struct fooalign {char x; double d;}; +#define DEFAULT_ALIGNMENT \ + ((PTR_INT_TYPE) ((char *) &((struct fooalign *) 0)->d - (char *) 0)) +/* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT. + But in fact it might be less smart and round addresses to as much as + DEFAULT_ROUNDING. So we prepare for it to do that. */ +union fooround {long x; double d;}; +#define DEFAULT_ROUNDING (sizeof (union fooround)) + +/* When we copy a long block of data, this is the unit to do it with. + On some machines, copying successive ints does not work; + in such a case, redefine COPYING_UNIT to `long' (if that works) + or `char' as a last resort. */ +#ifndef COPYING_UNIT +#define COPYING_UNIT int +#endif + + +/* The functions allocating more room by calling `obstack_chunk_alloc' + jump to the handler pointed to by `obstack_alloc_failed_handler'. + This variable by default points to the internal function + `print_and_abort'. */ +static void print_and_abort (void); +void (*obstack_alloc_failed_handler) (void) = print_and_abort; + +/* Exit value used when `print_and_abort' is used. */ +#if defined __GNU_LIBRARY__ || defined HAVE_STDLIB_H +#include +#endif +#ifndef EXIT_FAILURE +#define EXIT_FAILURE 1 +#endif +int obstack_exit_failure = EXIT_FAILURE; + +/* The non-GNU-C macros copy the obstack into this global variable + to avoid multiple evaluation. */ + +struct obstack *_obstack; + +/* Define a macro that either calls functions with the traditional malloc/free + calling interface, or calls functions with the mmalloc/mfree interface + (that adds an extra first argument), based on the state of use_extra_arg. + For free, do not use ?:, since some compilers, like the MIPS compilers, + do not allow (expr) ? void : void. */ + +#if defined (__STDC__) && __STDC__ +#define CALL_CHUNKFUN(h, size) \ + (((h) -> use_extra_arg) \ + ? (*(h)->chunkfun) ((h)->extra_arg, (size)) \ + : (*(struct _obstack_chunk *(*) (long)) (h)->chunkfun) ((size))) + +#define CALL_FREEFUN(h, old_chunk) \ + do { \ + if ((h) -> use_extra_arg) \ + (*(h)->freefun) ((h)->extra_arg, (old_chunk)); \ + else \ + (*(void (*) (void *)) (h)->freefun) ((old_chunk)); \ + } while (0) +#else +#define CALL_CHUNKFUN(h, size) \ + (((h) -> use_extra_arg) \ + ? (*(h)->chunkfun) ((h)->extra_arg, (size)) \ + : (*(struct _obstack_chunk *(*) ()) (h)->chunkfun) ((size))) + +#define CALL_FREEFUN(h, old_chunk) \ + do { \ + if ((h) -> use_extra_arg) \ + (*(h)->freefun) ((h)->extra_arg, (old_chunk)); \ + else \ + (*(void (*) ()) (h)->freefun) ((old_chunk)); \ + } while (0) +#endif + + +/* Initialize an obstack H for use. Specify chunk size SIZE (0 means default). + Objects start on multiples of ALIGNMENT (0 means use default). + CHUNKFUN is the function to use to allocate chunks, + and FREEFUN the function to free them. + + Return nonzero if successful, zero if out of memory. + To recover from an out of memory error, + free up some memory, then call this again. */ + +int +_obstack_begin (struct obstack *h, int size, int alignment, + POINTER (*chunkfun) (long), void (*freefun) (void *)) +{ + register struct _obstack_chunk *chunk; /* points to new chunk */ + + if (alignment == 0) + alignment = (int) DEFAULT_ALIGNMENT; + if (size == 0) + /* Default size is what GNU malloc can fit in a 4096-byte block. */ + { + /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc. + Use the values for range checking, because if range checking is off, + the extra bytes won't be missed terribly, but if range checking is on + and we used a larger request, a whole extra 4096 bytes would be + allocated. + + These number are irrelevant to the new GNU malloc. I suspect it is + less sensitive to the size of the request. */ + int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1)) + + 4 + DEFAULT_ROUNDING - 1) + & ~(DEFAULT_ROUNDING - 1)); + size = 4096 - extra; + } + + h->chunkfun = (struct _obstack_chunk * (*)(void *, long)) chunkfun; + h->freefun = (void (*) (void *, struct _obstack_chunk *)) freefun; + h->chunk_size = size; + h->alignment_mask = alignment - 1; + h->use_extra_arg = 0; + + chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size); + if (!chunk) + (*obstack_alloc_failed_handler) (); + h->next_free = h->object_base = chunk->contents; + h->chunk_limit = chunk->limit + = (char *) chunk + h->chunk_size; + chunk->prev = 0; + /* The initial chunk now contains no empty object. */ + h->maybe_empty_object = 0; + h->alloc_failed = 0; + return 1; +} + +int +_obstack_begin_1 (struct obstack *h, int size, int alignment, + POINTER (*chunkfun) (POINTER, long), + void (*freefun) (POINTER, POINTER), POINTER arg) +{ + register struct _obstack_chunk *chunk; /* points to new chunk */ + + if (alignment == 0) + alignment = (int) DEFAULT_ALIGNMENT; + if (size == 0) + /* Default size is what GNU malloc can fit in a 4096-byte block. */ + { + /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc. + Use the values for range checking, because if range checking is off, + the extra bytes won't be missed terribly, but if range checking is on + and we used a larger request, a whole extra 4096 bytes would be + allocated. + + These number are irrelevant to the new GNU malloc. I suspect it is + less sensitive to the size of the request. */ + int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1)) + + 4 + DEFAULT_ROUNDING - 1) + & ~(DEFAULT_ROUNDING - 1)); + size = 4096 - extra; + } + + h->chunkfun = (struct _obstack_chunk * (*)(void *,long)) chunkfun; + h->freefun = (void (*) (void *, struct _obstack_chunk *)) freefun; + h->chunk_size = size; + h->alignment_mask = alignment - 1; + h->extra_arg = arg; + h->use_extra_arg = 1; + + chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size); + if (!chunk) + (*obstack_alloc_failed_handler) (); + h->next_free = h->object_base = chunk->contents; + h->chunk_limit = chunk->limit + = (char *) chunk + h->chunk_size; + chunk->prev = 0; + /* The initial chunk now contains no empty object. */ + h->maybe_empty_object = 0; + h->alloc_failed = 0; + return 1; +} + +/* Allocate a new current chunk for the obstack *H + on the assumption that LENGTH bytes need to be added + to the current object, or a new object of length LENGTH allocated. + Copies any partial object from the end of the old chunk + to the beginning of the new one. */ + +void +_obstack_newchunk (struct obstack *h, int length) +{ + register struct _obstack_chunk *old_chunk = h->chunk; + register struct _obstack_chunk *new_chunk; + register long new_size; + register long obj_size = h->next_free - h->object_base; + register long i; + long already; + + /* Compute size for new chunk. */ + new_size = (obj_size + length) + (obj_size >> 3) + 100; + if (new_size < h->chunk_size) + new_size = h->chunk_size; + + /* Allocate and initialize the new chunk. */ + new_chunk = CALL_CHUNKFUN (h, new_size); + if (!new_chunk) + (*obstack_alloc_failed_handler) (); + h->chunk = new_chunk; + new_chunk->prev = old_chunk; + new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size; + + /* Move the existing object to the new chunk. + Word at a time is fast and is safe if the object + is sufficiently aligned. */ + if (h->alignment_mask + 1 >= DEFAULT_ALIGNMENT) + { + for (i = obj_size / sizeof (COPYING_UNIT) - 1; + i >= 0; i--) + ((COPYING_UNIT *)new_chunk->contents)[i] + = ((COPYING_UNIT *)h->object_base)[i]; + /* We used to copy the odd few remaining bytes as one extra COPYING_UNIT, + but that can cross a page boundary on a machine + which does not do strict alignment for COPYING_UNITS. */ + already = obj_size / sizeof (COPYING_UNIT) * sizeof (COPYING_UNIT); + } + else + already = 0; + /* Copy remaining bytes one by one. */ + for (i = already; i < obj_size; i++) + new_chunk->contents[i] = h->object_base[i]; + + /* If the object just copied was the only data in OLD_CHUNK, + free that chunk and remove it from the chain. + But not if that chunk might contain an empty object. */ + if (h->object_base == old_chunk->contents && ! h->maybe_empty_object) + { + new_chunk->prev = old_chunk->prev; + CALL_FREEFUN (h, old_chunk); + } + + h->object_base = new_chunk->contents; + h->next_free = h->object_base + obj_size; + /* The new chunk certainly contains no empty object yet. */ + h->maybe_empty_object = 0; +} + +/* Return nonzero if object OBJ has been allocated from obstack H. + This is here for debugging. + If you use it in a program, you are probably losing. */ + +/* Suppress -Wmissing-prototypes warning. We don't want to declare this in + obstack.h because it is just for debugging. */ +int _obstack_allocated_p (struct obstack *h, POINTER obj); + +int +_obstack_allocated_p (struct obstack *h, POINTER obj) +{ + register struct _obstack_chunk *lp; /* below addr of any objects in this chunk */ + register struct _obstack_chunk *plp; /* point to previous chunk if any */ + + lp = (h)->chunk; + /* We use >= rather than > since the object cannot be exactly at + the beginning of the chunk but might be an empty object exactly + at the end of an adjacent chunk. */ + while (lp != 0 && ((POINTER) lp >= obj || (POINTER) (lp)->limit < obj)) + { + plp = lp->prev; + lp = plp; + } + return lp != 0; +} + +/* Free objects in obstack H, including OBJ and everything allocate + more recently than OBJ. If OBJ is zero, free everything in H. */ + +#undef obstack_free + +/* This function has two names with identical definitions. + This is the first one, called from non-ANSI code. */ + +void +_obstack_free (struct obstack *h, POINTER obj) +{ + register struct _obstack_chunk *lp; /* below addr of any objects in this chunk */ + register struct _obstack_chunk *plp; /* point to previous chunk if any */ + + lp = h->chunk; + /* We use >= because there cannot be an object at the beginning of a chunk. + But there can be an empty object at that address + at the end of another chunk. */ + while (lp != 0 && ((POINTER) lp >= obj || (POINTER) (lp)->limit < obj)) + { + plp = lp->prev; + CALL_FREEFUN (h, lp); + lp = plp; + /* If we switch chunks, we can't tell whether the new current + chunk contains an empty object, so assume that it may. */ + h->maybe_empty_object = 1; + } + if (lp) + { + h->object_base = h->next_free = (char *) (obj); + h->chunk_limit = lp->limit; + h->chunk = lp; + } + else if (obj != 0) + /* obj is not in any of the chunks! */ + abort (); +} + +/* This function is used from ANSI code. */ + +void +obstack_free (struct obstack *h, POINTER obj) +{ + register struct _obstack_chunk *lp; /* below addr of any objects in this chunk */ + register struct _obstack_chunk *plp; /* point to previous chunk if any */ + + lp = h->chunk; + /* We use >= because there cannot be an object at the beginning of a chunk. + But there can be an empty object at that address + at the end of another chunk. */ + while (lp != 0 && ((POINTER) lp >= obj || (POINTER) (lp)->limit < obj)) + { + plp = lp->prev; + CALL_FREEFUN (h, lp); + lp = plp; + /* If we switch chunks, we can't tell whether the new current + chunk contains an empty object, so assume that it may. */ + h->maybe_empty_object = 1; + } + if (lp) + { + h->object_base = h->next_free = (char *) (obj); + h->chunk_limit = lp->limit; + h->chunk = lp; + } + else if (obj != 0) + /* obj is not in any of the chunks! */ + abort (); +} + +int +_obstack_memory_used (struct obstack *h) +{ + register struct _obstack_chunk* lp; + register int nbytes = 0; + + for (lp = h->chunk; lp != 0; lp = lp->prev) + { + nbytes += lp->limit - (char *) lp; + } + return nbytes; +} + +/* Define the error handler. */ +#ifndef _ +# if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC +# include +# ifndef _ +# define _(Str) gettext (Str) +# endif +# else +# define _(Str) (Str) +# endif +#endif + +static void +print_and_abort (void) +{ + fputs (_("memory exhausted\n"), stderr); + exit (obstack_exit_failure); +} + +#if 0 +/* These are now turned off because the applications do not use it + and it uses bcopy via obstack_grow, which causes trouble on sysV. */ + +/* Now define the functional versions of the obstack macros. + Define them to simply use the corresponding macros to do the job. */ + +/* The function names appear in parentheses in order to prevent + the macro-definitions of the names from being expanded there. */ + +POINTER (obstack_base) (struct obstack *obstack) +{ + return obstack_base (obstack); +} + +POINTER (obstack_next_free) (struct obstack *obstack) +{ + return obstack_next_free (obstack); +} + +int (obstack_object_size) (struct obstack *obstack) +{ + return obstack_object_size (obstack); +} + +int (obstack_room) (struct obstack *obstack) +{ + return obstack_room (obstack); +} + +int (obstack_make_room) (struct obstack *obstack, int length) +{ + return obstack_make_room (obstack, length); +} + +void (obstack_grow) (struct obstack *obstack, POINTER pointer, int length) +{ + obstack_grow (obstack, pointer, length); +} + +void (obstack_grow0) (struct obstack *obstack, POINTER pointer, int length) +{ + obstack_grow0 (obstack, pointer, length); +} + +void (obstack_1grow) (struct obstack *obstack, int character) +{ + obstack_1grow (obstack, character); +} + +void (obstack_blank) (struct obstack *obstack, int length) +{ + obstack_blank (obstack, length); +} + +void (obstack_1grow_fast) (struct obstack *obstack, int character) +{ + obstack_1grow_fast (obstack, character); +} + +void (obstack_blank_fast) (struct obstack *obstack, int length) +{ + obstack_blank_fast (obstack, length); +} + +POINTER (obstack_finish) (struct obstack *obstack) +{ + return obstack_finish (obstack); +} + +POINTER (obstack_alloc) (struct obstack *obstack, int length) +{ + return obstack_alloc (obstack, length); +} + +POINTER (obstack_copy) (struct obstack *obstack, POINTER pointer, int length) +{ + return obstack_copy (obstack, pointer, length); +} + +POINTER (obstack_copy0) (struct obstack *obstack, POINTER pointer, int length) +{ + return obstack_copy0 (obstack, pointer, length); +} + +#endif /* 0 */ + +#endif /* !ELIDE_CODE */ diff --git a/libiberty/partition.c b/libiberty/partition.c new file mode 100644 index 0000000..5f0745c --- /dev/null +++ b/libiberty/partition.c @@ -0,0 +1,183 @@ +/* List implementation of a partition of consecutive integers. + Copyright (C) 2000, 2001 Free Software Foundation, Inc. + Contributed by CodeSourcery, LLC. + + This file is part of GNU CC. + + GNU CC is free software; you can 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, or (at your option) + any later version. + + GNU CC is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU CC; see the file COPYING. If not, write to + the Free Software Foundation, 51 Franklin Street - Fifth Floor, + Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef HAVE_STRING_H +#include +#endif + +#include "libiberty.h" +#include "partition.h" + +static int elem_compare (const void *, const void *); + +/* Creates a partition of NUM_ELEMENTS elements. Initially each + element is in a class by itself. */ + +partition +partition_new (int num_elements) +{ + int e; + + partition part = (partition) + xmalloc (sizeof (struct partition_def) + + (num_elements - 1) * sizeof (struct partition_elem)); + part->num_elements = num_elements; + for (e = 0; e < num_elements; ++e) + { + part->elements[e].class_element = e; + part->elements[e].next = &(part->elements[e]); + part->elements[e].class_count = 1; + } + + return part; +} + +/* Freeds a partition. */ + +void +partition_delete (partition part) +{ + free (part); +} + +/* Unites the classes containing ELEM1 and ELEM2 into a single class + of partition PART. If ELEM1 and ELEM2 are already in the same + class, does nothing. Returns the canonical element of the + resulting union class. */ + +int +partition_union (partition part, int elem1, int elem2) +{ + struct partition_elem *elements = part->elements; + struct partition_elem *e1; + struct partition_elem *e2; + struct partition_elem *p; + struct partition_elem *old_next; + /* The canonical element of the resulting union class. */ + int class_element = elements[elem1].class_element; + + /* If they're already in the same class, do nothing. */ + if (class_element == elements[elem2].class_element) + return class_element; + + /* Make sure ELEM1 is in the larger class of the two. If not, swap + them. This way we always scan the shorter list. */ + if (elements[elem1].class_count < elements[elem2].class_count) + { + int temp = elem1; + elem1 = elem2; + elem2 = temp; + class_element = elements[elem1].class_element; + } + + e1 = &(elements[elem1]); + e2 = &(elements[elem2]); + + /* Keep a count of the number of elements in the list. */ + elements[class_element].class_count + += elements[e2->class_element].class_count; + + /* Update the class fields in elem2's class list. */ + e2->class_element = class_element; + for (p = e2->next; p != e2; p = p->next) + p->class_element = class_element; + + /* Splice ELEM2's class list into ELEM1's. These are circular + lists. */ + old_next = e1->next; + e1->next = e2->next; + e2->next = old_next; + + return class_element; +} + +/* Compare elements ELEM1 and ELEM2 from array of integers, given a + pointer to each. Used to qsort such an array. */ + +static int +elem_compare (const void *elem1, const void *elem2) +{ + int e1 = * (const int *) elem1; + int e2 = * (const int *) elem2; + if (e1 < e2) + return -1; + else if (e1 > e2) + return 1; + else + return 0; +} + +/* Prints PART to the file pointer FP. The elements of each + class are sorted. */ + +void +partition_print (partition part, FILE *fp) +{ + char *done; + int num_elements = part->num_elements; + struct partition_elem *elements = part->elements; + int *class_elements; + int e; + + /* Flag the elements we've already printed. */ + done = (char *) xmalloc (num_elements); + memset (done, 0, num_elements); + + /* A buffer used to sort elements in a class. */ + class_elements = (int *) xmalloc (num_elements * sizeof (int)); + + fputc ('[', fp); + for (e = 0; e < num_elements; ++e) + /* If we haven't printed this element, print its entire class. */ + if (! done[e]) + { + int c = e; + int count = elements[elements[e].class_element].class_count; + int i; + + /* Collect the elements in this class. */ + for (i = 0; i < count; ++i) { + class_elements[i] = c; + done[c] = 1; + c = elements[c].next - elements; + } + /* Sort them. */ + qsort ((void *) class_elements, count, sizeof (int), elem_compare); + /* Print them. */ + fputc ('(', fp); + for (i = 0; i < count; ++i) + fprintf (fp, i == 0 ? "%d" : " %d", class_elements[i]); + fputc (')', fp); + } + fputc (']', fp); + + free (class_elements); + free (done); +} + diff --git a/libiberty/pex-common.c b/libiberty/pex-common.c new file mode 100644 index 0000000..7f35536 --- /dev/null +++ b/libiberty/pex-common.c @@ -0,0 +1,643 @@ +/* Common code for executing a program in a sub-process. + Copyright (C) 2005 Free Software Foundation, Inc. + Written by Ian Lance Taylor . + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#include "config.h" +#include "libiberty.h" +#include "pex-common.h" + +#include +#include +#ifdef NEED_DECLARATION_ERRNO +extern int errno; +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + +extern int mkstemps (char *, int); + +/* This file contains subroutines for the program execution routines + (pex_init, pex_run, etc.). This file is compiled on all + systems. */ + +static void pex_add_remove (struct pex_obj *, const char *, int); +static int pex_get_status_and_time (struct pex_obj *, int, const char **, + int *); + +/* Initialize a pex_obj structure. */ + +struct pex_obj * +pex_init_common (int flags, const char *pname, const char *tempbase, + const struct pex_funcs *funcs) +{ + struct pex_obj *obj; + + obj = XNEW (struct pex_obj); + obj->flags = flags; + obj->pname = pname; + obj->tempbase = tempbase; + obj->next_input = STDIN_FILE_NO; + obj->next_input_name = NULL; + obj->next_input_name_allocated = 0; + obj->stderr_pipe = -1; + obj->count = 0; + obj->children = NULL; + obj->status = NULL; + obj->time = NULL; + obj->number_waited = 0; + obj->input_file = NULL; + obj->read_output = NULL; + obj->read_err = NULL; + obj->remove_count = 0; + obj->remove = NULL; + obj->funcs = funcs; + obj->sysdep = NULL; + return obj; +} + +/* Add a file to be removed when we are done. */ + +static void +pex_add_remove (struct pex_obj *obj, const char *name, int allocated) +{ + char *add; + + ++obj->remove_count; + obj->remove = XRESIZEVEC (char *, obj->remove, obj->remove_count); + if (allocated) + add = (char *) name; + else + add = xstrdup (name); + obj->remove[obj->remove_count - 1] = add; +} + +/* Generate a temporary file name based on OBJ, FLAGS, and NAME. + Return NULL if we were unable to reserve a temporary filename. + + If non-NULL, the result is either allocated with malloc, or the + same pointer as NAME. */ +static char * +temp_file (struct pex_obj *obj, int flags, char *name) +{ + if (name == NULL) + { + if (obj->tempbase == NULL) + { + name = make_temp_file (NULL); + } + else + { + int len = strlen (obj->tempbase); + int out; + + if (len >= 6 + && strcmp (obj->tempbase + len - 6, "XXXXXX") == 0) + name = xstrdup (obj->tempbase); + else + name = concat (obj->tempbase, "XXXXXX", NULL); + + out = mkstemps (name, 0); + if (out < 0) + { + free (name); + return NULL; + } + + /* This isn't obj->funcs->close because we got the + descriptor from mkstemps, not from a function in + obj->funcs. Calling close here is just like what + make_temp_file does. */ + close (out); + } + } + else if ((flags & PEX_SUFFIX) != 0) + { + if (obj->tempbase == NULL) + name = make_temp_file (name); + else + name = concat (obj->tempbase, name, NULL); + } + + return name; +} + + +/* As for pex_run (), but permits the environment for the child process + to be specified. */ + +const char * +pex_run_in_environment (struct pex_obj *obj, int flags, const char *executable, + char * const * argv, char * const * env, + const char *orig_outname, const char *errname, + int *err) +{ + const char *errmsg; + int in, out, errdes; + char *outname; + int outname_allocated; + int p[2]; + int toclose; + long pid; + + in = -1; + out = -1; + errdes = -1; + outname = (char *) orig_outname; + outname_allocated = 0; + + /* If the user called pex_input_file, close the file now. */ + if (obj->input_file) + { + if (fclose (obj->input_file) == EOF) + { + errmsg = "closing pipeline input file"; + goto error_exit; + } + obj->input_file = NULL; + } + + /* Set IN. */ + + if (obj->next_input_name != NULL) + { + /* We have to make sure that the previous process has completed + before we try to read the file. */ + if (!pex_get_status_and_time (obj, 0, &errmsg, err)) + goto error_exit; + + in = obj->funcs->open_read (obj, obj->next_input_name, + (flags & PEX_BINARY_INPUT) != 0); + if (in < 0) + { + *err = errno; + errmsg = "open temporary file"; + goto error_exit; + } + if (obj->next_input_name_allocated) + { + free (obj->next_input_name); + obj->next_input_name_allocated = 0; + } + obj->next_input_name = NULL; + } + else + { + in = obj->next_input; + if (in < 0) + { + *err = 0; + errmsg = "pipeline already complete"; + goto error_exit; + } + } + + /* Set OUT and OBJ->NEXT_INPUT/OBJ->NEXT_INPUT_NAME. */ + + if ((flags & PEX_LAST) != 0) + { + if (outname == NULL) + out = STDOUT_FILE_NO; + else if ((flags & PEX_SUFFIX) != 0) + { + outname = concat (obj->tempbase, outname, NULL); + outname_allocated = 1; + } + obj->next_input = -1; + } + else if ((obj->flags & PEX_USE_PIPES) == 0) + { + outname = temp_file (obj, flags, outname); + if (! outname) + { + *err = 0; + errmsg = "could not create temporary file"; + goto error_exit; + } + + if (outname != orig_outname) + outname_allocated = 1; + + if ((obj->flags & PEX_SAVE_TEMPS) == 0) + { + pex_add_remove (obj, outname, outname_allocated); + outname_allocated = 0; + } + + /* Hand off ownership of outname to the next stage. */ + obj->next_input_name = outname; + obj->next_input_name_allocated = outname_allocated; + outname_allocated = 0; + } + else + { + if (obj->funcs->pipe (obj, p, (flags & PEX_BINARY_OUTPUT) != 0) < 0) + { + *err = errno; + errmsg = "pipe"; + goto error_exit; + } + + out = p[WRITE_PORT]; + obj->next_input = p[READ_PORT]; + } + + if (out < 0) + { + out = obj->funcs->open_write (obj, outname, + (flags & PEX_BINARY_OUTPUT) != 0); + if (out < 0) + { + *err = errno; + errmsg = "open temporary output file"; + goto error_exit; + } + } + + if (outname_allocated) + { + free (outname); + outname_allocated = 0; + } + + /* Set ERRDES. */ + + if (errname != NULL && (flags & PEX_STDERR_TO_PIPE) != 0) + { + *err = 0; + errmsg = "both ERRNAME and PEX_STDERR_TO_PIPE specified."; + goto error_exit; + } + + if (obj->stderr_pipe != -1) + { + *err = 0; + errmsg = "PEX_STDERR_TO_PIPE used in the middle of pipeline"; + goto error_exit; + } + + if (errname == NULL) + { + if (flags & PEX_STDERR_TO_PIPE) + { + if (obj->funcs->pipe (obj, p, (flags & PEX_BINARY_ERROR) != 0) < 0) + { + *err = errno; + errmsg = "pipe"; + goto error_exit; + } + + errdes = p[WRITE_PORT]; + obj->stderr_pipe = p[READ_PORT]; + } + else + { + errdes = STDERR_FILE_NO; + } + } + else + { + errdes = obj->funcs->open_write (obj, errname, + (flags & PEX_BINARY_ERROR) != 0); + if (errdes < 0) + { + *err = errno; + errmsg = "open error file"; + goto error_exit; + } + } + + /* If we are using pipes, the child process has to close the next + input pipe. */ + + if ((obj->flags & PEX_USE_PIPES) == 0) + toclose = -1; + else + toclose = obj->next_input; + + /* Run the program. */ + + pid = obj->funcs->exec_child (obj, flags, executable, argv, env, + in, out, errdes, toclose, &errmsg, err); + if (pid < 0) + goto error_exit; + + ++obj->count; + obj->children = XRESIZEVEC (long, obj->children, obj->count); + obj->children[obj->count - 1] = pid; + + return NULL; + + error_exit: + if (in >= 0 && in != STDIN_FILE_NO) + obj->funcs->close (obj, in); + if (out >= 0 && out != STDOUT_FILE_NO) + obj->funcs->close (obj, out); + if (errdes >= 0 && errdes != STDERR_FILE_NO) + obj->funcs->close (obj, errdes); + if (outname_allocated) + free (outname); + return errmsg; +} + +/* Run a program. */ + +const char * +pex_run (struct pex_obj *obj, int flags, const char *executable, + char * const * argv, const char *orig_outname, const char *errname, + int *err) +{ + return pex_run_in_environment (obj, flags, executable, argv, NULL, + orig_outname, errname, err); +} + +/* Return a FILE pointer for a temporary file to fill with input for + the pipeline. */ +FILE * +pex_input_file (struct pex_obj *obj, int flags, const char *in_name) +{ + char *name = (char *) in_name; + FILE *f; + + /* This must be called before the first pipeline stage is run, and + there must not have been any other input selected. */ + if (obj->count != 0 + || (obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO) + || obj->next_input_name) + { + errno = EINVAL; + return NULL; + } + + name = temp_file (obj, flags, name); + if (! name) + return NULL; + + f = fopen (name, (flags & PEX_BINARY_OUTPUT) ? "wb" : "w"); + if (! f) + { + free (name); + return NULL; + } + + obj->input_file = f; + obj->next_input_name = name; + obj->next_input_name_allocated = (name != in_name); + + return f; +} + +/* Return a stream for a pipe connected to the standard input of the + first stage of the pipeline. */ +FILE * +pex_input_pipe (struct pex_obj *obj, int binary) +{ + int p[2]; + FILE *f; + + /* You must call pex_input_pipe before the first pex_run or pex_one. */ + if (obj->count > 0) + goto usage_error; + + /* You must be using pipes. Implementations that don't support + pipes clear this flag before calling pex_init_common. */ + if (! (obj->flags & PEX_USE_PIPES)) + goto usage_error; + + /* If we have somehow already selected other input, that's a + mistake. */ + if ((obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO) + || obj->next_input_name) + goto usage_error; + + if (obj->funcs->pipe (obj, p, binary != 0) < 0) + return NULL; + + f = obj->funcs->fdopenw (obj, p[WRITE_PORT], binary != 0); + if (! f) + { + int saved_errno = errno; + obj->funcs->close (obj, p[READ_PORT]); + obj->funcs->close (obj, p[WRITE_PORT]); + errno = saved_errno; + return NULL; + } + + obj->next_input = p[READ_PORT]; + + return f; + + usage_error: + errno = EINVAL; + return NULL; +} + +/* Return a FILE pointer for the output of the last program + executed. */ + +FILE * +pex_read_output (struct pex_obj *obj, int binary) +{ + if (obj->next_input_name != NULL) + { + const char *errmsg; + int err; + + /* We have to make sure that the process has completed before we + try to read the file. */ + if (!pex_get_status_and_time (obj, 0, &errmsg, &err)) + { + errno = err; + return NULL; + } + + obj->read_output = fopen (obj->next_input_name, binary ? "rb" : "r"); + + if (obj->next_input_name_allocated) + { + free (obj->next_input_name); + obj->next_input_name_allocated = 0; + } + obj->next_input_name = NULL; + } + else + { + int o; + + o = obj->next_input; + if (o < 0 || o == STDIN_FILE_NO) + return NULL; + obj->read_output = obj->funcs->fdopenr (obj, o, binary); + obj->next_input = -1; + } + + return obj->read_output; +} + +FILE * +pex_read_err (struct pex_obj *obj, int binary) +{ + int o; + + o = obj->stderr_pipe; + if (o < 0 || o == STDIN_FILE_NO) + return NULL; + obj->read_err = obj->funcs->fdopenr (obj, o, binary); + return obj->read_err; +} + +/* Get the exit status and, if requested, the resource time for all + the child processes. Return 0 on failure, 1 on success. */ + +static int +pex_get_status_and_time (struct pex_obj *obj, int done, const char **errmsg, + int *err) +{ + int ret; + int i; + + if (obj->number_waited == obj->count) + return 1; + + obj->status = XRESIZEVEC (int, obj->status, obj->count); + if ((obj->flags & PEX_RECORD_TIMES) != 0) + obj->time = XRESIZEVEC (struct pex_time, obj->time, obj->count); + + ret = 1; + for (i = obj->number_waited; i < obj->count; ++i) + { + if (obj->funcs->wait (obj, obj->children[i], &obj->status[i], + obj->time == NULL ? NULL : &obj->time[i], + done, errmsg, err) < 0) + ret = 0; + } + obj->number_waited = i; + + return ret; +} + +/* Get exit status of executed programs. */ + +int +pex_get_status (struct pex_obj *obj, int count, int *vector) +{ + if (obj->status == NULL) + { + const char *errmsg; + int err; + + if (!pex_get_status_and_time (obj, 0, &errmsg, &err)) + return 0; + } + + if (count > obj->count) + { + memset (vector + obj->count, 0, (count - obj->count) * sizeof (int)); + count = obj->count; + } + + memcpy (vector, obj->status, count * sizeof (int)); + + return 1; +} + +/* Get process times of executed programs. */ + +int +pex_get_times (struct pex_obj *obj, int count, struct pex_time *vector) +{ + if (obj->status == NULL) + { + const char *errmsg; + int err; + + if (!pex_get_status_and_time (obj, 0, &errmsg, &err)) + return 0; + } + + if (obj->time == NULL) + return 0; + + if (count > obj->count) + { + memset (vector + obj->count, 0, + (count - obj->count) * sizeof (struct pex_time)); + count = obj->count; + } + + memcpy (vector, obj->time, count * sizeof (struct pex_time)); + + return 1; +} + +/* Free a pex_obj structure. */ + +void +pex_free (struct pex_obj *obj) +{ + if (obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO) + obj->funcs->close (obj, obj->next_input); + + /* If the caller forgot to wait for the children, we do it here, to + avoid zombies. */ + if (obj->status == NULL) + { + const char *errmsg; + int err; + + obj->flags &= ~ PEX_RECORD_TIMES; + pex_get_status_and_time (obj, 1, &errmsg, &err); + } + + if (obj->next_input_name_allocated) + free (obj->next_input_name); + if (obj->children != NULL) + free (obj->children); + if (obj->status != NULL) + free (obj->status); + if (obj->time != NULL) + free (obj->time); + if (obj->read_output != NULL) + fclose (obj->read_output); + if (obj->read_err != NULL) + fclose (obj->read_err); + + if (obj->remove_count > 0) + { + int i; + + for (i = 0; i < obj->remove_count; ++i) + { + remove (obj->remove[i]); + free (obj->remove[i]); + } + free (obj->remove); + } + + if (obj->funcs->cleanup != NULL) + obj->funcs->cleanup (obj); + + free (obj); +} diff --git a/libiberty/pex-djgpp.c b/libiberty/pex-djgpp.c new file mode 100644 index 0000000..bd27938 --- /dev/null +++ b/libiberty/pex-djgpp.c @@ -0,0 +1,294 @@ +/* Utilities to execute a program in a subprocess (possibly linked by pipes + with other subprocesses), and wait for it. DJGPP specialization. + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2005 + Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#include "pex-common.h" + +#include +#include +#ifdef NEED_DECLARATION_ERRNO +extern int errno; +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#include +#include +#include +#include + +/* Use ECHILD if available, otherwise use EINVAL. */ +#ifdef ECHILD +#define PWAIT_ERROR ECHILD +#else +#define PWAIT_ERROR EINVAL +#endif + +static int pex_djgpp_open_read (struct pex_obj *, const char *, int); +static int pex_djgpp_open_write (struct pex_obj *, const char *, int); +static pid_t pex_djgpp_exec_child (struct pex_obj *, int, const char *, + char * const *, char * const *, + int, int, int, int, + const char **, int *); +static int pex_djgpp_close (struct pex_obj *, int); +static int pex_djgpp_wait (struct pex_obj *, pid_t, int *, struct pex_time *, + int, const char **, int *); + +/* The list of functions we pass to the common routines. */ + +const struct pex_funcs funcs = +{ + pex_djgpp_open_read, + pex_djgpp_open_write, + pex_djgpp_exec_child, + pex_djgpp_close, + pex_djgpp_wait, + NULL, /* pipe */ + NULL, /* fdopenr */ + NULL, /* fdopenw */ + NULL /* cleanup */ +}; + +/* Return a newly initialized pex_obj structure. */ + +struct pex_obj * +pex_init (int flags, const char *pname, const char *tempbase) +{ + /* DJGPP does not support pipes. */ + flags &= ~ PEX_USE_PIPES; + return pex_init_common (flags, pname, tempbase, &funcs); +} + +/* Open a file for reading. */ + +static int +pex_djgpp_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, + const char *name, int binary) +{ + return open (name, O_RDONLY | (binary ? O_BINARY : O_TEXT)); +} + +/* Open a file for writing. */ + +static int +pex_djgpp_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, + const char *name, int binary) +{ + /* Note that we can't use O_EXCL here because gcc may have already + created the temporary file via make_temp_file. */ + return open (name, + (O_WRONLY | O_CREAT | O_TRUNC + | (binary ? O_BINARY : O_TEXT)), + S_IRUSR | S_IWUSR); +} + +/* Close a file. */ + +static int +pex_djgpp_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd) +{ + return close (fd); +} + +/* Execute a child. */ + +static pid_t +pex_djgpp_exec_child (struct pex_obj *obj, int flags, const char *executable, + char * const * argv, char * const * env, + int in, int out, int errdes, + int toclose ATTRIBUTE_UNUSED, const char **errmsg, + int *err) +{ + int org_in, org_out, org_errdes; + int status; + int *statuses; + + org_in = -1; + org_out = -1; + org_errdes = -1; + + if (in != STDIN_FILE_NO) + { + org_in = dup (STDIN_FILE_NO); + if (org_in < 0) + { + *err = errno; + *errmsg = "dup"; + return (pid_t) -1; + } + if (dup2 (in, STDIN_FILE_NO) < 0) + { + *err = errno; + *errmsg = "dup2"; + return (pid_t) -1; + } + if (close (in) < 0) + { + *err = errno; + *errmsg = "close"; + return (pid_t) -1; + } + } + + if (out != STDOUT_FILE_NO) + { + org_out = dup (STDOUT_FILE_NO); + if (org_out < 0) + { + *err = errno; + *errmsg = "dup"; + return (pid_t) -1; + } + if (dup2 (out, STDOUT_FILE_NO) < 0) + { + *err = errno; + *errmsg = "dup2"; + return (pid_t) -1; + } + if (close (out) < 0) + { + *err = errno; + *errmsg = "close"; + return (pid_t) -1; + } + } + + if (errdes != STDERR_FILE_NO + || (flags & PEX_STDERR_TO_STDOUT) != 0) + { + org_errdes = dup (STDERR_FILE_NO); + if (org_errdes < 0) + { + *err = errno; + *errmsg = "dup"; + return (pid_t) -1; + } + if (dup2 ((flags & PEX_STDERR_TO_STDOUT) != 0 ? STDOUT_FILE_NO : errdes, + STDERR_FILE_NO) < 0) + { + *err = errno; + *errmsg = "dup2"; + return (pid_t) -1; + } + if (errdes != STDERR_FILE_NO) + { + if (close (errdes) < 0) + { + *err = errno; + *errmsg = "close"; + return (pid_t) -1; + } + } + } + + if (env) + status = (((flags & PEX_SEARCH) != 0 ? spawnvpe : spawnve) + (P_WAIT, executable, argv, env)); + else + status = (((flags & PEX_SEARCH) != 0 ? spawnvp : spawnv) + (P_WAIT, executable, argv)); + + if (status == -1) + { + *err = errno; + *errmsg = ((flags & PEX_SEARCH) != 0) ? "spawnvp" : "spawnv"; + } + + if (in != STDIN_FILE_NO) + { + if (dup2 (org_in, STDIN_FILE_NO) < 0) + { + *err = errno; + *errmsg = "dup2"; + return (pid_t) -1; + } + if (close (org_in) < 0) + { + *err = errno; + *errmsg = "close"; + return (pid_t) -1; + } + } + + if (out != STDOUT_FILE_NO) + { + if (dup2 (org_out, STDOUT_FILE_NO) < 0) + { + *err = errno; + *errmsg = "dup2"; + return (pid_t) -1; + } + if (close (org_out) < 0) + { + *err = errno; + *errmsg = "close"; + return (pid_t) -1; + } + } + + if (errdes != STDERR_FILE_NO + || (flags & PEX_STDERR_TO_STDOUT) != 0) + { + if (dup2 (org_errdes, STDERR_FILE_NO) < 0) + { + *err = errno; + *errmsg = "dup2"; + return (pid_t) -1; + } + if (close (org_errdes) < 0) + { + *err = errno; + *errmsg = "close"; + return (pid_t) -1; + } + } + + /* Save the exit status for later. When we are called, obj->count + is the number of children which have executed before this + one. */ + statuses = (int *) obj->sysdep; + statuses = XRESIZEVEC (int, statuses, obj->count + 1); + statuses[obj->count] = status; + obj->sysdep = (void *) statuses; + + return (pid_t) obj->count; +} + +/* Wait for a child process to complete. Actually the child process + has already completed, and we just need to return the exit + status. */ + +static int +pex_djgpp_wait (struct pex_obj *obj, pid_t pid, int *status, + struct pex_time *time, int done ATTRIBUTE_UNUSED, + const char **errmsg ATTRIBUTE_UNUSED, + int *err ATTRIBUTE_UNUSED) +{ + int *statuses; + + if (time != NULL) + memset (time, 0, sizeof *time); + + statuses = (int *) obj->sysdep; + *status = statuses[pid]; + + return 0; +} diff --git a/libiberty/pex-msdos.c b/libiberty/pex-msdos.c new file mode 100644 index 0000000..ab4d736 --- /dev/null +++ b/libiberty/pex-msdos.c @@ -0,0 +1,319 @@ +/* Utilities to execute a program in a subprocess (possibly linked by pipes + with other subprocesses), and wait for it. Generic MSDOS specialization. + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2005 + Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#include "pex-common.h" + +#include +#include +#ifdef NEED_DECLARATION_ERRNO +extern int errno; +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif + +#include "safe-ctype.h" +#include + +/* The structure we keep in obj->sysdep. */ + +#define PEX_MSDOS_FILE_COUNT 3 + +#define PEX_MSDOS_FD_OFFSET 10 + +struct pex_msdos +{ + /* An array of file names. We refer to these using file descriptors + of 10 + array index. */ + const char *files[PEX_MSDOS_FILE_COUNT]; + /* Exit statuses of programs which have been run. */ + int *statuses; +}; + +static int pex_msdos_open (struct pex_obj *, const char *, int); +static int pex_msdos_open (struct pex_obj *, const char *, int); +static int pex_msdos_fdindex (struct pex_msdos *, int); +static pid_t pex_msdos_exec_child (struct pex_obj *, int, const char *, + char * const *, char * const *, + int, int, int, int, + int, const char **, int *); +static int pex_msdos_close (struct pex_obj *, int); +static int pex_msdos_wait (struct pex_obj *, pid_t, int *, struct pex_time *, + int, const char **, int *); +static void pex_msdos_cleanup (struct pex_obj *); + +/* The list of functions we pass to the common routines. */ + +const struct pex_funcs funcs = +{ + pex_msdos_open, + pex_msdos_open, + pex_msdos_exec_child, + pex_msdos_close, + pex_msdos_wait, + NULL, /* pipe */ + NULL, /* fdopenr */ + NULL, /* fdopenw */ + pex_msdos_cleanup +}; + +/* Return a newly initialized pex_obj structure. */ + +struct pex_obj * +pex_init (int flags, const char *pname, const char *tempbase) +{ + struct pex_obj *ret; + int i; + + /* MSDOS does not support pipes. */ + flags &= ~ PEX_USE_PIPES; + + ret = pex_init_common (flags, pname, tempbase, funcs); + + ret->sysdep = XNEW (struct pex_msdos); + for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i) + ret->files[i] = NULL; + ret->statuses = NULL; + + return ret; +} + +/* Open a file. FIXME: We ignore the binary argument, since we have + no way to handle it. */ + +static int +pex_msdos_open (struct pex_obj *obj, const char *name, + int binary ATTRIBUTE_UNUSED) +{ + struct pex_msdos *ms; + int i; + + ms = (struct pex_msdos *) obj->sysdep; + + for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i) + { + if (ms->files[i] == NULL) + { + ms->files[i] = xstrdup (name); + return i + PEX_MSDOS_FD_OFFSET; + } + } + + abort (); +} + +/* Get the index into msdos->files associated with an open file + descriptor. */ + +static int +pex_msdos_fdindex (struct pex_msdos *ms, int fd) +{ + fd -= PEX_MSDOS_FD_OFFSET; + if (fd < 0 || fd >= PEX_MSDOS_FILE_COUNT || ms->files[fd] == NULL) + abort (); + return fd; +} + + +/* Close a file. */ + +static int +pex_msdos_close (struct pex_obj *obj, int fd) +{ + struct pex_msdos *ms; + int fdinex; + + ms = (struct pex_msdos *) obj->sysdep; + fdindex = pe_msdos_fdindex (ms, fd); + free (ms->files[fdindex]); + ms->files[fdindex] = NULL; +} + +/* Execute a child. */ + +static pid_t +pex_msdos_exec_child (struct pex_obj *obj, int flags, const char *executable, + char * const * argv, char * const * env, int in, int out, + int toclose ATTRIBUTE_UNUSED, + int errdes ATTRIBUTE_UNUSED, const char **errmsg, + int *err) +{ + struct pex_msdos *ms; + char *temp_base; + int temp_base_allocated; + char *rf; + int inindex; + char *infile; + int outindex; + char *outfile; + char *scmd; + FILE *argfile; + int i; + int status; + + ms = (struct pex_msdos *) obj->sysdep; + + /* FIXME: I don't know how to redirect stderr, so we ignore ERRDES + and PEX_STDERR_TO_STDOUT. */ + + temp_base = obj->temp_base; + if (temp_base != NULL) + temp_base_allocated = 0; + else + { + temp_base = choose_temp_base (); + temp_base_allocated = 1; + } + + rf = concat (temp_base, ".gp", NULL); + + if (temp_base_allocated) + free (temp_base); + + if (in == STDIN_FILE_NO) + { + inindex = -1; + infile = ""; + } + else + { + inindex = pex_msdos_fdindex (ms, in); + infile = ms->files[inindex]; + } + + if (out == STDOUT_FILE_NO) + { + outindex = -1; + outfile = ""; + } + else + { + outindex = pex_msdos_fdindex (ms, out); + outfile = ms->files[outindex]; + } + + scmd = XNEWVEC (char, strlen (program) + + ((flags & PEXECUTE_SEARCH) != 0 ? 4 : 0) + + strlen (rf) + + strlen (infile) + + strlen (outfile) + + 10); + sprintf (scmd, "%s%s @%s%s%s%s%s", + program, + (flags & PEXECUTE_SEARCH) != 0 ? ".exe" : "", + rf, + inindex != -1 ? " <" : "", + infile, + outindex != -1 ? " >" : "", + outfile); + + argfile = fopen (rf, "w"); + if (argfile == NULL) + { + *err = errno; + free (scmd); + free (rf); + *errmsg = "cannot open temporary command file"; + return (pid_t) -1; + } + + for (i = 1; argv[i] != NULL; ++i) + { + char *p; + + for (p = argv[i]; *p != '\0'; ++p) + { + if (*p == '"' || *p == '\'' || *p == '\\' || ISSPACE (*p)) + putc ('\\', argfile); + putc (*p, argfile); + } + putc ('\n', argfile); + } + + fclose (argfile); + + status = system (scmd); + + if (status == -1) + { + *err = errno; + remove (rf); + free (scmd); + free (rf); + *errmsg = "system"; + return (pid_t) -1; + } + + remove (rf); + free (scmd); + free (rf); + + /* Save the exit status for later. When we are called, obj->count + is the number of children which have executed before this + one. */ + ms->statuses = XRESIZEVEC(int, ms->statuses, obj->count + 1); + ms->statuses[obj->count] = status; + + return (pid_t) obj->count; +} + +/* Wait for a child process to complete. Actually the child process + has already completed, and we just need to return the exit + status. */ + +static int +pex_msdos_wait (struct pex_obj *obj, pid_t pid, int *status, + struct pex_time *time, int done ATTRIBUTE_UNUSED, + const char **errmsg ATTRIBUTE_UNUSED, + int *err ATTRIBUTE_UNUSED) +{ + struct pex_msdos *ms; + + ms = (struct pex_msdos *) obj->sysdep; + + if (time != NULL) + memset (time, 0, sizeof *time); + + *status = ms->statuses[pid]; + + return 0; +} + +/* Clean up the pex_msdos structure. */ + +static void +pex_msdos_cleanup (struct pex_obj *obj) +{ + struct pex_msdos *ms; + int i; + + ms = (struct pex_msdos *) obj->sysdep; + for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i) + if (msdos->files[i] != NULL) + free (msdos->files[i]); + if (msdos->statuses != NULL) + free (msdos->statuses); + free (msdos); + obj->sysdep = NULL; +} diff --git a/libiberty/pex-one.c b/libiberty/pex-one.c new file mode 100644 index 0000000..696b8bc --- /dev/null +++ b/libiberty/pex-one.c @@ -0,0 +1,43 @@ +/* Execute a program and wait for a result. + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#include "config.h" +#include "libiberty.h" + +const char * +pex_one (int flags, const char *executable, char * const *argv, + const char *pname, const char *outname, const char *errname, + int *status, int *err) +{ + struct pex_obj *obj; + const char *errmsg; + + obj = pex_init (0, pname, NULL); + errmsg = pex_run (obj, flags, executable, argv, outname, errname, err); + if (errmsg == NULL) + { + if (!pex_get_status (obj, 1, status)) + { + *err = 0; + errmsg = "pex_get_status failed"; + } + } + pex_free (obj); + return errmsg; +} diff --git a/libiberty/pex-unix.c b/libiberty/pex-unix.c new file mode 100644 index 0000000..366e96e --- /dev/null +++ b/libiberty/pex-unix.c @@ -0,0 +1,538 @@ +/* Utilities to execute a program in a subprocess (possibly linked by pipes + with other subprocesses), and wait for it. Generic Unix version + (also used for UWIN and VMS). + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005 + Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#include "config.h" +#include "libiberty.h" +#include "pex-common.h" + +#include +#include +#include +#ifdef NEED_DECLARATION_ERRNO +extern int errno; +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + +#include + +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_SYS_WAIT_H +#include +#endif +#ifdef HAVE_GETRUSAGE +#include +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif + + +#ifdef vfork /* Autoconf may define this to fork for us. */ +# define VFORK_STRING "fork" +#else +# define VFORK_STRING "vfork" +#endif +#ifdef HAVE_VFORK_H +#include +#endif +#ifdef VMS +#define vfork() (decc$$alloc_vfork_blocks() >= 0 ? \ + lib$get_current_invo_context(decc$$get_vfork_jmpbuf()) : -1) +#endif /* VMS */ + + +/* File mode to use for private and world-readable files. */ + +#if defined (S_IRUSR) && defined (S_IWUSR) && defined (S_IRGRP) && defined (S_IWGRP) && defined (S_IROTH) && defined (S_IWOTH) +#define PUBLIC_MODE \ + (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) +#else +#define PUBLIC_MODE 0666 +#endif + +/* Get the exit status of a particular process, and optionally get the + time that it took. This is simple if we have wait4, slightly + harder if we have waitpid, and is a pain if we only have wait. */ + +static pid_t pex_wait (struct pex_obj *, pid_t, int *, struct pex_time *); + +#ifdef HAVE_WAIT4 + +static pid_t +pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status, + struct pex_time *time) +{ + pid_t ret; + struct rusage r; + +#ifdef HAVE_WAITPID + if (time == NULL) + return waitpid (pid, status, 0); +#endif + + ret = wait4 (pid, status, 0, &r); + + if (time != NULL) + { + time->user_seconds = r.ru_utime.tv_sec; + time->user_microseconds= r.ru_utime.tv_usec; + time->system_seconds = r.ru_stime.tv_sec; + time->system_microseconds= r.ru_stime.tv_usec; + } + + return ret; +} + +#else /* ! defined (HAVE_WAIT4) */ + +#ifdef HAVE_WAITPID + +#ifndef HAVE_GETRUSAGE + +static pid_t +pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status, + struct pex_time *time) +{ + if (time != NULL) + memset (time, 0, sizeof (struct pex_time)); + return waitpid (pid, status, 0); +} + +#else /* defined (HAVE_GETRUSAGE) */ + +static pid_t +pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status, + struct pex_time *time) +{ + struct rusage r1, r2; + pid_t ret; + + if (time == NULL) + return waitpid (pid, status, 0); + + getrusage (RUSAGE_CHILDREN, &r1); + + ret = waitpid (pid, status, 0); + if (ret < 0) + return ret; + + getrusage (RUSAGE_CHILDREN, &r2); + + time->user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec; + time->user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec; + if (r2.ru_utime.tv_usec < r1.ru_utime.tv_usec) + { + --time->user_seconds; + time->user_microseconds += 1000000; + } + + time->system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec; + time->system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec; + if (r2.ru_stime.tv_usec < r1.ru_stime.tv_usec) + { + --time->system_seconds; + time->system_microseconds += 1000000; + } + + return ret; +} + +#endif /* defined (HAVE_GETRUSAGE) */ + +#else /* ! defined (HAVE_WAITPID) */ + +struct status_list +{ + struct status_list *next; + pid_t pid; + int status; + struct pex_time time; +}; + +static pid_t +pex_wait (struct pex_obj *obj, pid_t pid, int *status, struct pex_time *time) +{ + struct status_list **pp; + + for (pp = (struct status_list **) &obj->sysdep; + *pp != NULL; + pp = &(*pp)->next) + { + if ((*pp)->pid == pid) + { + struct status_list *p; + + p = *pp; + *status = p->status; + if (time != NULL) + *time = p->time; + *pp = p->next; + free (p); + return pid; + } + } + + while (1) + { + pid_t cpid; + struct status_list *psl; + struct pex_time pt; +#ifdef HAVE_GETRUSAGE + struct rusage r1, r2; +#endif + + if (time != NULL) + { +#ifdef HAVE_GETRUSAGE + getrusage (RUSAGE_CHILDREN, &r1); +#else + memset (&pt, 0, sizeof (struct pex_time)); +#endif + } + + cpid = wait (status); + +#ifdef HAVE_GETRUSAGE + if (time != NULL && cpid >= 0) + { + getrusage (RUSAGE_CHILDREN, &r2); + + pt.user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec; + pt.user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec; + if (pt.user_microseconds < 0) + { + --pt.user_seconds; + pt.user_microseconds += 1000000; + } + + pt.system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec; + pt.system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec; + if (pt.system_microseconds < 0) + { + --pt.system_seconds; + pt.system_microseconds += 1000000; + } + } +#endif + + if (cpid < 0 || cpid == pid) + { + if (time != NULL) + *time = pt; + return cpid; + } + + psl = XNEW (struct status_list); + psl->pid = cpid; + psl->status = *status; + if (time != NULL) + psl->time = pt; + psl->next = (struct status_list *) obj->sysdep; + obj->sysdep = (void *) psl; + } +} + +#endif /* ! defined (HAVE_WAITPID) */ +#endif /* ! defined (HAVE_WAIT4) */ + +static void pex_child_error (struct pex_obj *, const char *, const char *, int) + ATTRIBUTE_NORETURN; +static int pex_unix_open_read (struct pex_obj *, const char *, int); +static int pex_unix_open_write (struct pex_obj *, const char *, int); +static pid_t pex_unix_exec_child (struct pex_obj *, int, const char *, + char * const *, char * const *, + int, int, int, int, + const char **, int *); +static int pex_unix_close (struct pex_obj *, int); +static int pex_unix_wait (struct pex_obj *, pid_t, int *, struct pex_time *, + int, const char **, int *); +static int pex_unix_pipe (struct pex_obj *, int *, int); +static FILE *pex_unix_fdopenr (struct pex_obj *, int, int); +static FILE *pex_unix_fdopenw (struct pex_obj *, int, int); +static void pex_unix_cleanup (struct pex_obj *); + +/* The list of functions we pass to the common routines. */ + +const struct pex_funcs funcs = +{ + pex_unix_open_read, + pex_unix_open_write, + pex_unix_exec_child, + pex_unix_close, + pex_unix_wait, + pex_unix_pipe, + pex_unix_fdopenr, + pex_unix_fdopenw, + pex_unix_cleanup +}; + +/* Return a newly initialized pex_obj structure. */ + +struct pex_obj * +pex_init (int flags, const char *pname, const char *tempbase) +{ + return pex_init_common (flags, pname, tempbase, &funcs); +} + +/* Open a file for reading. */ + +static int +pex_unix_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name, + int binary ATTRIBUTE_UNUSED) +{ + return open (name, O_RDONLY); +} + +/* Open a file for writing. */ + +static int +pex_unix_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name, + int binary ATTRIBUTE_UNUSED) +{ + /* Note that we can't use O_EXCL here because gcc may have already + created the temporary file via make_temp_file. */ + return open (name, O_WRONLY | O_CREAT | O_TRUNC, PUBLIC_MODE); +} + +/* Close a file. */ + +static int +pex_unix_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd) +{ + return close (fd); +} + +/* Report an error from a child process. We don't use stdio routines, + because we might be here due to a vfork call. */ + +static void +pex_child_error (struct pex_obj *obj, const char *executable, + const char *errmsg, int err) +{ +#define writeerr(s) (void) write (STDERR_FILE_NO, s, strlen (s)) + writeerr (obj->pname); + writeerr (": error trying to exec '"); + writeerr (executable); + writeerr ("': "); + writeerr (errmsg); + writeerr (": "); + writeerr (xstrerror (err)); + writeerr ("\n"); + _exit (-1); +} + +/* Execute a child. */ + +extern char **environ; + +static pid_t +pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable, + char * const * argv, char * const * env, + int in, int out, int errdes, + int toclose, const char **errmsg, int *err) +{ + pid_t pid; + + /* We declare these to be volatile to avoid warnings from gcc about + them being clobbered by vfork. */ + volatile int sleep_interval; + volatile int retries; + + sleep_interval = 1; + pid = -1; + for (retries = 0; retries < 4; ++retries) + { + pid = vfork (); + if (pid >= 0) + break; + sleep (sleep_interval); + sleep_interval *= 2; + } + + switch (pid) + { + case -1: + *err = errno; + *errmsg = VFORK_STRING; + return (pid_t) -1; + + case 0: + /* Child process. */ + if (in != STDIN_FILE_NO) + { + if (dup2 (in, STDIN_FILE_NO) < 0) + pex_child_error (obj, executable, "dup2", errno); + if (close (in) < 0) + pex_child_error (obj, executable, "close", errno); + } + if (out != STDOUT_FILE_NO) + { + if (dup2 (out, STDOUT_FILE_NO) < 0) + pex_child_error (obj, executable, "dup2", errno); + if (close (out) < 0) + pex_child_error (obj, executable, "close", errno); + } + if (errdes != STDERR_FILE_NO) + { + if (dup2 (errdes, STDERR_FILE_NO) < 0) + pex_child_error (obj, executable, "dup2", errno); + if (close (errdes) < 0) + pex_child_error (obj, executable, "close", errno); + } + if (toclose >= 0) + { + if (close (toclose) < 0) + pex_child_error (obj, executable, "close", errno); + } + if ((flags & PEX_STDERR_TO_STDOUT) != 0) + { + if (dup2 (STDOUT_FILE_NO, STDERR_FILE_NO) < 0) + pex_child_error (obj, executable, "dup2", errno); + } + + if (env) + environ = (char**) env; + + if ((flags & PEX_SEARCH) != 0) + { + execvp (executable, argv); + pex_child_error (obj, executable, "execvp", errno); + } + else + { + execv (executable, argv); + pex_child_error (obj, executable, "execv", errno); + } + + /* NOTREACHED */ + return (pid_t) -1; + + default: + /* Parent process. */ + if (in != STDIN_FILE_NO) + { + if (close (in) < 0) + { + *err = errno; + *errmsg = "close"; + return (pid_t) -1; + } + } + if (out != STDOUT_FILE_NO) + { + if (close (out) < 0) + { + *err = errno; + *errmsg = "close"; + return (pid_t) -1; + } + } + if (errdes != STDERR_FILE_NO) + { + if (close (errdes) < 0) + { + *err = errno; + *errmsg = "close"; + return (pid_t) -1; + } + } + + return pid; + } +} + +/* Wait for a child process to complete. */ + +static int +pex_unix_wait (struct pex_obj *obj, pid_t pid, int *status, + struct pex_time *time, int done, const char **errmsg, + int *err) +{ + /* If we are cleaning up when the caller didn't retrieve process + status for some reason, encourage the process to go away. */ + if (done) + kill (pid, SIGTERM); + + if (pex_wait (obj, pid, status, time) < 0) + { + *err = errno; + *errmsg = "wait"; + return -1; + } + + return 0; +} + +/* Create a pipe. */ + +static int +pex_unix_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p, + int binary ATTRIBUTE_UNUSED) +{ + return pipe (p); +} + +/* Get a FILE pointer to read from a file descriptor. */ + +static FILE * +pex_unix_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd, + int binary ATTRIBUTE_UNUSED) +{ + return fdopen (fd, "r"); +} + +static FILE * +pex_unix_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd, + int binary ATTRIBUTE_UNUSED) +{ + if (fcntl (fd, F_SETFD, FD_CLOEXEC) < 0) + return NULL; + return fdopen (fd, "w"); +} + +static void +pex_unix_cleanup (struct pex_obj *obj ATTRIBUTE_UNUSED) +{ +#if !defined (HAVE_WAIT4) && !defined (HAVE_WAITPID) + while (obj->sysdep != NULL) + { + struct status_list *this; + struct status_list *next; + + this = (struct status_list *) obj->sysdep; + next = this->next; + free (this); + obj->sysdep = (void *) next; + } +#endif +} diff --git a/libiberty/pex-win32.c b/libiberty/pex-win32.c new file mode 100644 index 0000000..05d44e9 --- /dev/null +++ b/libiberty/pex-win32.c @@ -0,0 +1,889 @@ +/* Utilities to execute a program in a subprocess (possibly linked by pipes + with other subprocesses), and wait for it. Generic Win32 specialization. + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#include "pex-common.h" + +#include + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_SYS_WAIT_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +/* mingw32 headers may not define the following. */ + +#ifndef _P_WAIT +# define _P_WAIT 0 +# define _P_NOWAIT 1 +# define _P_OVERLAY 2 +# define _P_NOWAITO 3 +# define _P_DETACH 4 + +# define WAIT_CHILD 0 +# define WAIT_GRANDCHILD 1 +#endif + +#define MINGW_NAME "Minimalist GNU for Windows" +#define MINGW_NAME_LEN (sizeof(MINGW_NAME) - 1) + +extern char *stpcpy (char *dst, const char *src); + +/* Ensure that the executable pathname uses Win32 backslashes. This + is not necessary on NT, but on W9x, forward slashes causes + failure of spawn* and exec* functions (and probably any function + that calls CreateProcess) *iff* the executable pathname (argv[0]) + is a quoted string. And quoting is necessary in case a pathname + contains embedded white space. You can't win. */ +static void +backslashify (char *s) +{ + while ((s = strchr (s, '/')) != NULL) + *s = '\\'; + return; +} + +static int pex_win32_open_read (struct pex_obj *, const char *, int); +static int pex_win32_open_write (struct pex_obj *, const char *, int); +static pid_t pex_win32_exec_child (struct pex_obj *, int, const char *, + char * const *, char * const *, + int, int, int, int, + const char **, int *); +static int pex_win32_close (struct pex_obj *, int); +static int pex_win32_wait (struct pex_obj *, pid_t, int *, + struct pex_time *, int, const char **, int *); +static int pex_win32_pipe (struct pex_obj *, int *, int); +static FILE *pex_win32_fdopenr (struct pex_obj *, int, int); +static FILE *pex_win32_fdopenw (struct pex_obj *, int, int); + +/* The list of functions we pass to the common routines. */ + +const struct pex_funcs funcs = +{ + pex_win32_open_read, + pex_win32_open_write, + pex_win32_exec_child, + pex_win32_close, + pex_win32_wait, + pex_win32_pipe, + pex_win32_fdopenr, + pex_win32_fdopenw, + NULL /* cleanup */ +}; + +/* Return a newly initialized pex_obj structure. */ + +struct pex_obj * +pex_init (int flags, const char *pname, const char *tempbase) +{ + return pex_init_common (flags, pname, tempbase, &funcs); +} + +/* Open a file for reading. */ + +static int +pex_win32_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name, + int binary) +{ + return _open (name, _O_RDONLY | (binary ? _O_BINARY : _O_TEXT)); +} + +/* Open a file for writing. */ + +static int +pex_win32_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name, + int binary) +{ + /* Note that we can't use O_EXCL here because gcc may have already + created the temporary file via make_temp_file. */ + return _open (name, + (_O_WRONLY | _O_CREAT | _O_TRUNC + | (binary ? _O_BINARY : _O_TEXT)), + _S_IREAD | _S_IWRITE); +} + +/* Close a file. */ + +static int +pex_win32_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd) +{ + return _close (fd); +} + +#ifdef USE_MINGW_MSYS +static const char *mingw_keys[] = {"SOFTWARE", "Microsoft", "Windows", "CurrentVersion", "Uninstall", NULL}; + +/* Tack the executable on the end of a (possibly slash terminated) buffer + and convert everything to \. */ +static const char * +tack_on_executable (char *buf, const char *executable) +{ + char *p = strchr (buf, '\0'); + if (p > buf && (p[-1] == '\\' || p[-1] == '/')) + p[-1] = '\0'; + backslashify (strcat (buf, executable)); + return buf; +} + +/* Walk down a registry hierarchy until the end. Return the key. */ +static HKEY +openkey (HKEY hStart, const char *keys[]) +{ + HKEY hKey, hTmp; + for (hKey = hStart; *keys; keys++) + { + LONG res; + hTmp = hKey; + res = RegOpenKey (hTmp, *keys, &hKey); + + if (hTmp != HKEY_LOCAL_MACHINE) + RegCloseKey (hTmp); + + if (res != ERROR_SUCCESS) + return NULL; + } + return hKey; +} + +/* Return the "mingw root" as derived from the mingw uninstall information. */ +static const char * +mingw_rootify (const char *executable) +{ + HKEY hKey, hTmp; + DWORD maxlen; + char *namebuf, *foundbuf; + DWORD i; + LONG res; + + /* Open the uninstall "directory". */ + hKey = openkey (HKEY_LOCAL_MACHINE, mingw_keys); + + /* Not found. */ + if (!hKey) + return executable; + + /* Need to enumerate all of the keys here looking for one the most recent + one for MinGW. */ + if (RegQueryInfoKey (hKey, NULL, NULL, NULL, NULL, &maxlen, NULL, NULL, + NULL, NULL, NULL, NULL) != ERROR_SUCCESS) + { + RegCloseKey (hKey); + return executable; + } + namebuf = XNEWVEC (char, ++maxlen); + foundbuf = XNEWVEC (char, maxlen); + foundbuf[0] = '\0'; + if (!namebuf || !foundbuf) + { + RegCloseKey (hKey); + if (namebuf) + free (namebuf); + if (foundbuf) + free (foundbuf); + return executable; + } + + /* Look through all of the keys for one that begins with Minimal GNU... + Try to get the latest version by doing a string compare although that + string never really works with version number sorting. */ + for (i = 0; RegEnumKey (hKey, i, namebuf, maxlen) == ERROR_SUCCESS; i++) + { + int match = strcasecmp (namebuf, MINGW_NAME); + if (match < 0) + continue; + if (match > 0 && strncasecmp (namebuf, MINGW_NAME, MINGW_NAME_LEN) > 0) + continue; + if (strcasecmp (namebuf, foundbuf) > 0) + strcpy (foundbuf, namebuf); + } + free (namebuf); + + /* If foundbuf is empty, we didn't find anything. Punt. */ + if (!foundbuf[0]) + { + free (foundbuf); + RegCloseKey (hKey); + return executable; + } + + /* Open the key that we wanted */ + res = RegOpenKey (hKey, foundbuf, &hTmp); + RegCloseKey (hKey); + free (foundbuf); + + /* Don't know why this would fail, but you gotta check */ + if (res != ERROR_SUCCESS) + return executable; + + maxlen = 0; + /* Get the length of the value pointed to by InstallLocation */ + if (RegQueryValueEx (hTmp, "InstallLocation", 0, NULL, NULL, + &maxlen) != ERROR_SUCCESS || maxlen == 0) + { + RegCloseKey (hTmp); + return executable; + } + + /* Allocate space for the install location */ + foundbuf = XNEWVEC (char, maxlen + strlen (executable)); + if (!foundbuf) + { + free (foundbuf); + RegCloseKey (hTmp); + } + + /* Read the install location into the buffer */ + res = RegQueryValueEx (hTmp, "InstallLocation", 0, NULL, (LPBYTE) foundbuf, + &maxlen); + RegCloseKey (hTmp); + if (res != ERROR_SUCCESS) + { + free (foundbuf); + return executable; + } + + /* Concatenate the install location and the executable, turn all slashes + to backslashes, and return that. */ + return tack_on_executable (foundbuf, executable); +} + +/* Read the install location of msys from it's installation file and + rootify the executable based on that. */ +static const char * +msys_rootify (const char *executable) +{ + size_t bufsize = 64; + size_t execlen = strlen (executable) + 1; + char *buf; + DWORD res = 0; + for (;;) + { + buf = XNEWVEC (char, bufsize + execlen); + if (!buf) + break; + res = GetPrivateProfileString ("InstallSettings", "InstallPath", NULL, + buf, bufsize, "msys.ini"); + if (!res) + break; + if (strlen (buf) < bufsize) + break; + res = 0; + free (buf); + bufsize *= 2; + if (bufsize > 65536) + { + buf = NULL; + break; + } + } + + if (res) + return tack_on_executable (buf, executable); + + /* failed */ + if (buf) + free (buf); + return executable; +} +#endif + +/* Return a Windows command-line from ARGV. It is the caller's + responsibility to free the string returned. */ + +static char * +argv_to_cmdline (char *const *argv) +{ + char *cmdline; + char *p; + size_t cmdline_len; + int i, j, k; + + cmdline_len = 0; + for (i = 0; argv[i]; i++) + { + /* We quote every last argument. This simplifies the problem; + we need only escape embedded double-quotes and immediately + preceeding backslash characters. A sequence of backslach characters + that is not follwed by a double quote character will not be + escaped. */ + for (j = 0; argv[i][j]; j++) + { + if (argv[i][j] == '"') + { + /* Escape preceeding backslashes. */ + for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--) + cmdline_len++; + /* Escape the qote character. */ + cmdline_len++; + } + } + /* Trailing backslashes also need to be escaped because they will be + followed by the terminating quote. */ + for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--) + cmdline_len++; + cmdline_len += j; + cmdline_len += 3; /* for leading and trailing quotes and space */ + } + cmdline = XNEWVEC (char, cmdline_len); + p = cmdline; + for (i = 0; argv[i]; i++) + { + *p++ = '"'; + for (j = 0; argv[i][j]; j++) + { + if (argv[i][j] == '"') + { + for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--) + *p++ = '\\'; + *p++ = '\\'; + } + *p++ = argv[i][j]; + } + for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--) + *p++ = '\\'; + *p++ = '"'; + *p++ = ' '; + } + p[-1] = '\0'; + return cmdline; +} + +/* We'll try the passed filename with all the known standard + extensions, and then without extension. We try no extension + last so that we don't try to run some random extension-less + file that might be hanging around. We try both extension + and no extension so that we don't need any fancy logic + to determine if a file has extension. */ +static const char *const +std_suffixes[] = { + ".com", + ".exe", + ".bat", + ".cmd", + "", + 0 +}; + +/* Returns the full path to PROGRAM. If SEARCH is true, look for + PROGRAM in each directory in PATH. */ + +static char * +find_executable (const char *program, BOOL search) +{ + char *full_executable; + char *e; + size_t fe_len; + const char *path = 0; + const char *const *ext; + const char *p, *q; + size_t proglen = strlen (program); + int has_slash = (strchr (program, '/') || strchr (program, '\\')); + HANDLE h; + + if (has_slash) + search = FALSE; + + if (search) + path = getenv ("PATH"); + if (!path) + path = ""; + + fe_len = 0; + for (p = path; *p; p = q) + { + q = p; + while (*q != ';' && *q != '\0') + q++; + if ((size_t)(q - p) > fe_len) + fe_len = q - p; + if (*q == ';') + q++; + } + fe_len = fe_len + 1 + proglen + 5 /* space for extension */; + full_executable = XNEWVEC (char, fe_len); + + p = path; + do + { + q = p; + while (*q != ';' && *q != '\0') + q++; + + e = full_executable; + memcpy (e, p, q - p); + e += (q - p); + if (q - p) + *e++ = '\\'; + strcpy (e, program); + + if (*q == ';') + q++; + + for (e = full_executable; *e; e++) + if (*e == '/') + *e = '\\'; + + /* At this point, e points to the terminating NUL character for + full_executable. */ + for (ext = std_suffixes; *ext; ext++) + { + /* Remove any current extension. */ + *e = '\0'; + /* Add the new one. */ + strcat (full_executable, *ext); + + /* Attempt to open this file. */ + h = CreateFile (full_executable, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (h != INVALID_HANDLE_VALUE) + goto found; + } + p = q; + } + while (*p); + free (full_executable); + return 0; + + found: + CloseHandle (h); + return full_executable; +} + +/* Low-level process creation function and helper. */ + +static int +env_compare (const void *a_ptr, const void *b_ptr) +{ + const char *a; + const char *b; + unsigned char c1; + unsigned char c2; + + a = *(const char **) a_ptr; + b = *(const char **) b_ptr; + + /* a and b will be of the form: VAR=VALUE + We compare only the variable name part here using a case-insensitive + comparison algorithm. It might appear that in fact strcasecmp () can + take the place of this whole function, and indeed it could, save for + the fact that it would fail in cases such as comparing A1=foo and + A=bar (because 1 is less than = in the ASCII character set). + (Environment variables containing no numbers would work in such a + scenario.) */ + + do + { + c1 = (unsigned char) tolower (*a++); + c2 = (unsigned char) tolower (*b++); + + if (c1 == '=') + c1 = '\0'; + + if (c2 == '=') + c2 = '\0'; + } + while (c1 == c2 && c1 != '\0'); + + return c1 - c2; +} + +static pid_t +win32_spawn (const char *executable, + BOOL search, + char *const *argv, + char *const *env, /* array of strings of the form: VAR=VALUE */ + DWORD dwCreationFlags, + LPSTARTUPINFO si, + LPPROCESS_INFORMATION pi) +{ + char *full_executable; + char *cmdline; + char **env_copy; + char *env_block = NULL; + + full_executable = NULL; + cmdline = NULL; + + if (env) + { + int env_size; + + /* Count the number of environment bindings supplied. */ + for (env_size = 0; env[env_size]; env_size++) + continue; + + /* Assemble an environment block, if required. This consists of + VAR=VALUE strings juxtaposed (with one null character between each + pair) and an additional null at the end. */ + if (env_size > 0) + { + int var; + int total_size = 1; /* 1 is for the final null. */ + char *bufptr; + + /* Windows needs the members of the block to be sorted by variable + name. */ + env_copy = (char **) alloca (sizeof (char *) * env_size); + memcpy (env_copy, env, sizeof (char *) * env_size); + qsort (env_copy, env_size, sizeof (char *), env_compare); + + for (var = 0; var < env_size; var++) + total_size += strlen (env[var]) + 1; + + env_block = XNEWVEC (char, total_size); + bufptr = env_block; + for (var = 0; var < env_size; var++) + bufptr = stpcpy (bufptr, env_copy[var]) + 1; + + *bufptr = '\0'; + } + } + + full_executable = find_executable (executable, search); + if (!full_executable) + goto error; + cmdline = argv_to_cmdline (argv); + if (!cmdline) + goto error; + + /* Create the child process. */ + if (!CreateProcess (full_executable, cmdline, + /*lpProcessAttributes=*/NULL, + /*lpThreadAttributes=*/NULL, + /*bInheritHandles=*/TRUE, + dwCreationFlags, + (LPVOID) env_block, + /*lpCurrentDirectory=*/NULL, + si, + pi)) + { + if (env_block) + free (env_block); + + free (full_executable); + + return (pid_t) -1; + } + + /* Clean up. */ + CloseHandle (pi->hThread); + free (full_executable); + if (env_block) + free (env_block); + + return (pid_t) pi->hProcess; + + error: + if (env_block) + free (env_block); + if (cmdline) + free (cmdline); + if (full_executable) + free (full_executable); + + return (pid_t) -1; +} + +static pid_t +spawn_script (const char *executable, char *const *argv, + char* const *env, + DWORD dwCreationFlags, + LPSTARTUPINFO si, + LPPROCESS_INFORMATION pi) +{ + pid_t pid = (pid_t) -1; + int save_errno = errno; + int fd = _open (executable, _O_RDONLY); + + if (fd >= 0) + { + char buf[MAX_PATH + 5]; + int len = _read (fd, buf, sizeof (buf) - 1); + _close (fd); + if (len > 3) + { + char *eol; + buf[len] = '\0'; + eol = strchr (buf, '\n'); + if (eol && strncmp (buf, "#!", 2) == 0) + { + char *executable1; + const char ** avhere = (const char **) --argv; + do + *eol = '\0'; + while (*--eol == '\r' || *eol == ' ' || *eol == '\t'); + for (executable1 = buf + 2; *executable1 == ' ' || *executable1 == '\t'; executable1++) + continue; + + backslashify (executable1); + *avhere = executable1; +#ifndef USE_MINGW_MSYS + executable = strrchr (executable1, '\\') + 1; + if (!executable) + executable = executable1; + pid = win32_spawn (executable, TRUE, argv, env, + dwCreationFlags, si, pi); +#else + if (strchr (executable1, '\\') == NULL) + pid = win32_spawn (executable1, TRUE, argv, env, + dwCreationFlags, si, pi); + else if (executable1[0] != '\\') + pid = win32_spawn (executable1, FALSE, argv, env, + dwCreationFlags, si, pi); + else + { + const char *newex = mingw_rootify (executable1); + *avhere = newex; + pid = win32_spawn (newex, FALSE, argv, env, + dwCreationFlags, si, pi); + if (executable1 != newex) + free ((char *) newex); + if ((long) pid < 0) + { + newex = msys_rootify (executable1); + if (newex != executable1) + { + *avhere = newex; + pid = win32_spawn (newex, FALSE, argv, env, + dwCreationFlags, si, pi); + free ((char *) newex); + } + } + } +#endif + } + } + } + if ((long) pid < 0) + errno = save_errno; + return pid; +} + +/* Execute a child. */ + +static pid_t +pex_win32_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, int flags, + const char *executable, char * const * argv, + char* const* env, + int in, int out, int errdes, + int toclose ATTRIBUTE_UNUSED, + const char **errmsg, + int *err) +{ + pid_t pid; + HANDLE stdin_handle; + HANDLE stdout_handle; + HANDLE stderr_handle; + DWORD dwCreationFlags; + OSVERSIONINFO version_info; + STARTUPINFO si; + PROCESS_INFORMATION pi; + + stdin_handle = INVALID_HANDLE_VALUE; + stdout_handle = INVALID_HANDLE_VALUE; + stderr_handle = INVALID_HANDLE_VALUE; + + stdin_handle = (HANDLE) _get_osfhandle (in); + stdout_handle = (HANDLE) _get_osfhandle (out); + if (!(flags & PEX_STDERR_TO_STDOUT)) + stderr_handle = (HANDLE) _get_osfhandle (errdes); + else + stderr_handle = stdout_handle; + + /* Determine the version of Windows we are running on. */ + version_info.dwOSVersionInfoSize = sizeof (version_info); + GetVersionEx (&version_info); + if (version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) + /* On Windows 95/98/ME the CREATE_NO_WINDOW flag is not + supported, so we cannot avoid creating a console window. */ + dwCreationFlags = 0; + else + { + HANDLE conout_handle; + + /* Determine whether or not we have an associated console. */ + conout_handle = CreateFile("CONOUT$", + GENERIC_WRITE, + FILE_SHARE_WRITE, + /*lpSecurityAttributes=*/NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + /*hTemplateFile=*/NULL); + if (conout_handle == INVALID_HANDLE_VALUE) + /* There is no console associated with this process. Since + the child is a console process, the OS would normally + create a new console Window for the child. Since we'll be + redirecting the child's standard streams, we do not need + the console window. */ + dwCreationFlags = CREATE_NO_WINDOW; + else + { + /* There is a console associated with the process, so the OS + will not create a new console. And, if we use + CREATE_NO_WINDOW in this situation, the child will have + no associated console. Therefore, if the child's + standard streams are connected to the console, the output + will be discarded. */ + CloseHandle(conout_handle); + dwCreationFlags = 0; + } + } + + /* Since the child will be a console process, it will, by default, + connect standard input/output to its console. However, we want + the child to use the handles specifically designated above. In + addition, if there is no console (such as when we are running in + a Cygwin X window), then we must redirect the child's + input/output, as there is no console for the child to use. */ + memset (&si, 0, sizeof (si)); + si.cb = sizeof (si); + si.dwFlags = STARTF_USESTDHANDLES; + si.hStdInput = stdin_handle; + si.hStdOutput = stdout_handle; + si.hStdError = stderr_handle; + + /* Create the child process. */ + pid = win32_spawn (executable, (flags & PEX_SEARCH) != 0, + argv, env, dwCreationFlags, &si, &pi); + if (pid == (pid_t) -1) + pid = spawn_script (executable, argv, env, dwCreationFlags, + &si, &pi); + if (pid == (pid_t) -1) + { + *err = ENOENT; + *errmsg = "CreateProcess"; + } + + /* Close the standard output and standard error handles in the + parent. */ + if (out != STDOUT_FILENO) + obj->funcs->close (obj, out); + if (errdes != STDERR_FILENO) + obj->funcs->close (obj, errdes); + + return pid; +} + +/* Wait for a child process to complete. MS CRTDLL doesn't return + enough information in status to decide if the child exited due to a + signal or not, rather it simply returns an integer with the exit + code of the child; eg., if the child exited with an abort() call + and didn't have a handler for SIGABRT, it simply returns with + status == 3. We fix the status code to conform to the usual WIF* + macros. Note that WIFSIGNALED will never be true under CRTDLL. */ + +static int +pex_win32_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, + int *status, struct pex_time *time, int done ATTRIBUTE_UNUSED, + const char **errmsg, int *err) +{ + DWORD termstat; + HANDLE h; + + if (time != NULL) + memset (time, 0, sizeof *time); + + h = (HANDLE) pid; + + /* FIXME: If done is non-zero, we should probably try to kill the + process. */ + if (WaitForSingleObject (h, INFINITE) != WAIT_OBJECT_0) + { + CloseHandle (h); + *err = ECHILD; + *errmsg = "WaitForSingleObject"; + return -1; + } + + GetExitCodeProcess (h, &termstat); + CloseHandle (h); + + /* A value of 3 indicates that the child caught a signal, but not + which one. Since only SIGABRT, SIGFPE and SIGINT do anything, we + report SIGABRT. */ + if (termstat == 3) + *status = SIGABRT; + else + *status = (termstat & 0xff) << 8; + + return 0; +} + +/* Create a pipe. */ + +static int +pex_win32_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p, + int binary) +{ + return _pipe (p, 256, binary ? _O_BINARY : _O_TEXT); +} + +/* Get a FILE pointer to read from a file descriptor. */ + +static FILE * +pex_win32_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd, + int binary) +{ + return fdopen (fd, binary ? "rb" : "r"); +} + +static FILE * +pex_win32_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd, + int binary) +{ + HANDLE h = (HANDLE) _get_osfhandle (fd); + if (h == INVALID_HANDLE_VALUE) + return NULL; + if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0)) + return NULL; + return fdopen (fd, binary ? "wb" : "w"); +} + +#ifdef MAIN +#include + +int +main (int argc ATTRIBUTE_UNUSED, char **argv) +{ + char const *errmsg; + int err; + argv++; + printf ("%ld\n", (long) pex_win32_exec_child (NULL, PEX_SEARCH, argv[0], argv, NULL, 0, 0, 1, 2, &errmsg, &err)); + exit (0); +} +#endif diff --git a/libiberty/pexecute.c b/libiberty/pexecute.c new file mode 100644 index 0000000..97f1574 --- /dev/null +++ b/libiberty/pexecute.c @@ -0,0 +1,124 @@ +/* Utilities to execute a program in a subprocess (possibly linked by pipes + with other subprocesses), and wait for it. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* pexecute is an old routine. This implementation uses the newer + pex_init/pex_run/pex_get_status/pex_free routines. Don't use + pexecute in new code. Use the newer routines instead. */ + +#include "config.h" +#include "libiberty.h" + +#ifdef HAVE_STDLIB_H +#include +#endif + +/* We only permit a single pexecute chain to execute at a time. This + was always true anyhow, though it wasn't documented. */ + +static struct pex_obj *pex; +static int idx; + +int +pexecute (const char *program, char * const *argv, const char *pname, + const char *temp_base, char **errmsg_fmt, char **errmsg_arg, + int flags) +{ + const char *errmsg; + int err; + + if ((flags & PEXECUTE_FIRST) != 0) + { + if (pex != NULL) + { + *errmsg_fmt = (char *) "pexecute already in progress"; + *errmsg_arg = NULL; + return -1; + } + pex = pex_init (PEX_USE_PIPES, pname, temp_base); + idx = 0; + } + else + { + if (pex == NULL) + { + *errmsg_fmt = (char *) "pexecute not in progress"; + *errmsg_arg = NULL; + return -1; + } + } + + errmsg = pex_run (pex, + (((flags & PEXECUTE_LAST) != 0 ? PEX_LAST : 0) + | ((flags & PEXECUTE_SEARCH) != 0 ? PEX_SEARCH : 0)), + program, argv, NULL, NULL, &err); + if (errmsg != NULL) + { + *errmsg_fmt = (char *) errmsg; + *errmsg_arg = NULL; + return -1; + } + + /* Instead of a PID, we just return a one-based index into the + status values. We avoid zero just because the old pexecute would + never return it. */ + return ++idx; +} + +int +pwait (int pid, int *status, int flags ATTRIBUTE_UNUSED) +{ + /* The PID returned by pexecute is one-based. */ + --pid; + + if (pex == NULL || pid < 0 || pid >= idx) + return -1; + + if (pid == 0 && idx == 1) + { + if (!pex_get_status (pex, 1, status)) + return -1; + } + else + { + int *vector; + + vector = XNEWVEC (int, idx); + if (!pex_get_status (pex, idx, vector)) + { + free (vector); + return -1; + } + *status = vector[pid]; + free (vector); + } + + /* Assume that we are done after the caller has retrieved the last + exit status. The original implementation did not require that + the exit statuses be retrieved in order, but this implementation + does. */ + if (pid + 1 == idx) + { + pex_free (pex); + pex = NULL; + idx = 0; + } + + return pid + 1; +} diff --git a/libiberty/physmem.c b/libiberty/physmem.c new file mode 100644 index 0000000..09fbf3f --- /dev/null +++ b/libiberty/physmem.c @@ -0,0 +1,305 @@ +/* Calculate the size of physical memory. + Copyright 2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc. + + 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, 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. */ + +/* Written by Paul Eggert. */ + +#if HAVE_CONFIG_H +# include +#endif + +#if HAVE_UNISTD_H +# include +#endif + +#if HAVE_SYS_PSTAT_H +# include +#endif + +#if HAVE_SYS_SYSMP_H +# include +#endif + +#if HAVE_SYS_SYSINFO_H && HAVE_MACHINE_HAL_SYSINFO_H +# include +# include +#endif + +#if HAVE_SYS_TABLE_H +# include +#endif + +#include + +#if HAVE_SYS_PARAM_H +# include +#endif + +#if HAVE_SYS_SYSCTL_H +# include +#endif + +#if HAVE_SYS_SYSTEMCFG_H +# include +#endif + +#ifdef _WIN32 +# define WIN32_LEAN_AND_MEAN +# include +/* MEMORYSTATUSEX is missing from older windows headers, so define + a local replacement. */ +typedef struct +{ + DWORD dwLength; + DWORD dwMemoryLoad; + DWORDLONG ullTotalPhys; + DWORDLONG ullAvailPhys; + DWORDLONG ullTotalPageFile; + DWORDLONG ullAvailPageFile; + DWORDLONG ullTotalVirtual; + DWORDLONG ullAvailVirtual; + DWORDLONG ullAvailExtendedVirtual; +} lMEMORYSTATUSEX; +typedef WINBOOL (WINAPI *PFN_MS_EX) (lMEMORYSTATUSEX*); +#endif + +#include "libiberty.h" + +/* Return the total amount of physical memory. */ +double +physmem_total (void) +{ +#if defined _SC_PHYS_PAGES && defined _SC_PAGESIZE + { /* This works on linux-gnu, solaris2 and cygwin. */ + double pages = sysconf (_SC_PHYS_PAGES); + double pagesize = sysconf (_SC_PAGESIZE); + if (0 <= pages && 0 <= pagesize) + return pages * pagesize; + } +#endif + +#if HAVE_PSTAT_GETSTATIC + { /* This works on hpux11. */ + struct pst_static pss; + if (0 <= pstat_getstatic (&pss, sizeof pss, 1, 0)) + { + double pages = pss.physical_memory; + double pagesize = pss.page_size; + if (0 <= pages && 0 <= pagesize) + return pages * pagesize; + } + } +#endif + +#if HAVE_SYSMP && defined MP_SAGET && defined MPSA_RMINFO && defined _SC_PAGESIZE + { /* This works on irix6. */ + struct rminfo realmem; + if (sysmp (MP_SAGET, MPSA_RMINFO, &realmem, sizeof realmem) == 0) + { + double pagesize = sysconf (_SC_PAGESIZE); + double pages = realmem.physmem; + if (0 <= pages && 0 <= pagesize) + return pages * pagesize; + } + } +#endif + +#if HAVE_GETSYSINFO && defined GSI_PHYSMEM + { /* This works on Tru64 UNIX V4/5. */ + int physmem; + + if (getsysinfo (GSI_PHYSMEM, (caddr_t) &physmem, sizeof (physmem), + NULL, NULL, NULL) == 1) + { + double kbytes = physmem; + + if (0 <= kbytes) + return kbytes * 1024.0; + } + } +#endif + +#if HAVE_SYSCTL && defined HW_PHYSMEM + { /* This works on *bsd and darwin. */ + unsigned int physmem; + size_t len = sizeof physmem; + static int mib[2] = { CTL_HW, HW_PHYSMEM }; + + if (sysctl (mib, ARRAY_SIZE (mib), &physmem, &len, NULL, 0) == 0 + && len == sizeof (physmem)) + return (double) physmem; + } +#endif + +#if HAVE__SYSTEM_CONFIGURATION + /* This works on AIX 4.3.3+. */ + return _system_configuration.physmem; +#endif + +#if defined _WIN32 + { /* this works on windows */ + PFN_MS_EX pfnex; + HMODULE h = GetModuleHandle ("kernel32.dll"); + + if (!h) + return 0.0; + + /* Use GlobalMemoryStatusEx if available. */ + if ((pfnex = (PFN_MS_EX) GetProcAddress (h, "GlobalMemoryStatusEx"))) + { + lMEMORYSTATUSEX lms_ex; + lms_ex.dwLength = sizeof lms_ex; + if (!pfnex (&lms_ex)) + return 0.0; + return (double) lms_ex.ullTotalPhys; + } + + /* Fall back to GlobalMemoryStatus which is always available. + but returns wrong results for physical memory > 4GB. */ + else + { + MEMORYSTATUS ms; + GlobalMemoryStatus (&ms); + return (double) ms.dwTotalPhys; + } + } +#endif + + /* Return 0 if we can't determine the value. */ + return 0; +} + +/* Return the amount of physical memory available. */ +double +physmem_available (void) +{ +#if defined _SC_AVPHYS_PAGES && defined _SC_PAGESIZE + { /* This works on linux-gnu, solaris2 and cygwin. */ + double pages = sysconf (_SC_AVPHYS_PAGES); + double pagesize = sysconf (_SC_PAGESIZE); + if (0 <= pages && 0 <= pagesize) + return pages * pagesize; + } +#endif + +#if HAVE_PSTAT_GETSTATIC && HAVE_PSTAT_GETDYNAMIC + { /* This works on hpux11. */ + struct pst_static pss; + struct pst_dynamic psd; + if (0 <= pstat_getstatic (&pss, sizeof pss, 1, 0) + && 0 <= pstat_getdynamic (&psd, sizeof psd, 1, 0)) + { + double pages = psd.psd_free; + double pagesize = pss.page_size; + if (0 <= pages && 0 <= pagesize) + return pages * pagesize; + } + } +#endif + +#if HAVE_SYSMP && defined MP_SAGET && defined MPSA_RMINFO && defined _SC_PAGESIZE + { /* This works on irix6. */ + struct rminfo realmem; + if (sysmp (MP_SAGET, MPSA_RMINFO, &realmem, sizeof realmem) == 0) + { + double pagesize = sysconf (_SC_PAGESIZE); + double pages = realmem.availrmem; + if (0 <= pages && 0 <= pagesize) + return pages * pagesize; + } + } +#endif + +#if HAVE_TABLE && defined TBL_VMSTATS + { /* This works on Tru64 UNIX V4/5. */ + struct tbl_vmstats vmstats; + + if (table (TBL_VMSTATS, 0, &vmstats, 1, sizeof (vmstats)) == 1) + { + double pages = vmstats.free_count; + double pagesize = vmstats.pagesize; + + if (0 <= pages && 0 <= pagesize) + return pages * pagesize; + } + } +#endif + +#if HAVE_SYSCTL && defined HW_USERMEM + { /* This works on *bsd and darwin. */ + unsigned int usermem; + size_t len = sizeof usermem; + static int mib[2] = { CTL_HW, HW_USERMEM }; + + if (sysctl (mib, ARRAY_SIZE (mib), &usermem, &len, NULL, 0) == 0 + && len == sizeof (usermem)) + return (double) usermem; + } +#endif + +#if defined _WIN32 + { /* this works on windows */ + PFN_MS_EX pfnex; + HMODULE h = GetModuleHandle ("kernel32.dll"); + + if (!h) + return 0.0; + + /* Use GlobalMemoryStatusEx if available. */ + if ((pfnex = (PFN_MS_EX) GetProcAddress (h, "GlobalMemoryStatusEx"))) + { + lMEMORYSTATUSEX lms_ex; + lms_ex.dwLength = sizeof lms_ex; + if (!pfnex (&lms_ex)) + return 0.0; + return (double) lms_ex.ullAvailPhys; + } + + /* Fall back to GlobalMemoryStatus which is always available. + but returns wrong results for physical memory > 4GB */ + else + { + MEMORYSTATUS ms; + GlobalMemoryStatus (&ms); + return (double) ms.dwAvailPhys; + } + } +#endif + + /* Guess 25% of physical memory. */ + return physmem_total () / 4; +} + + +#if DEBUG + +# include +# include + +int +main (void) +{ + printf ("%12.f %12.f\n", physmem_total (), physmem_available ()); + exit (0); +} + +#endif /* DEBUG */ + +/* +Local Variables: +compile-command: "gcc -DDEBUG -DHAVE_CONFIG_H -I.. -g -O -Wall -W physmem.c" +End: +*/ diff --git a/libiberty/putenv.c b/libiberty/putenv.c new file mode 100644 index 0000000..248f50e --- /dev/null +++ b/libiberty/putenv.c @@ -0,0 +1,84 @@ +/* Copyright (C) 1991, 1994, 1995, 1996, 2002 Free Software Foundation, Inc. + This file based on putenv.c in the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* + +@deftypefn Supplemental int putenv (const char *@var{string}) + +Uses @code{setenv} or @code{unsetenv} to put @var{string} into +the environment or remove it. If @var{string} is of the form +@samp{name=value} the string is added; if no @samp{=} is present the +name is unset/removed. + +@end deftypefn + +*/ + +#if defined (_AIX) && !defined (__GNUC__) + #pragma alloca +#endif + +#if HAVE_CONFIG_H +# include +#endif + +#include "ansidecl.h" + +#define putenv libiberty_putenv + +#if HAVE_STDLIB_H +# include +#endif +#if HAVE_STRING_H +# include +#endif + +#ifdef HAVE_ALLOCA_H +# include +#else +# ifndef alloca +# ifdef __GNUC__ +# define alloca __builtin_alloca +# else +extern char *alloca (); +# endif /* __GNUC__ */ +# endif /* alloca */ +#endif /* HAVE_ALLOCA_H */ + +#undef putenv + +/* Below this point, it's verbatim code from the glibc-2.0 implementation */ + + +/* Put STRING, which is of the form "NAME=VALUE", in the environment. */ +int +putenv (const char *string) +{ + const char *const name_end = strchr (string, '='); + + if (name_end) + { + char *name = (char *) alloca (name_end - string + 1); + memcpy (name, string, name_end - string); + name[name_end - string] = '\0'; + return setenv (name, name_end + 1, 1); + } + + unsetenv (string); + return 0; +} diff --git a/libiberty/random.c b/libiberty/random.c new file mode 100644 index 0000000..c306698 --- /dev/null +++ b/libiberty/random.c @@ -0,0 +1,403 @@ +/* + * Copyright (c) 1983 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. [rescinded 22 July 1999] + * 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. + */ + +/* + * This is derived from the Berkeley source: + * @(#)random.c 5.5 (Berkeley) 7/6/88 + * It was reworked for the GNU C Library by Roland McGrath. + */ + +/* + +@deftypefn Supplement {long int} random (void) +@deftypefnx Supplement void srandom (unsigned int @var{seed}) +@deftypefnx Supplement void* initstate (unsigned int @var{seed}, void *@var{arg_state}, unsigned long @var{n}) +@deftypefnx Supplement void* setstate (void *@var{arg_state}) + +Random number functions. @code{random} returns a random number in the +range 0 to @code{LONG_MAX}. @code{srandom} initializes the random +number generator to some starting point determined by @var{seed} +(else, the values returned by @code{random} are always the same for each +run of the program). @code{initstate} and @code{setstate} allow fine-grained +control over the state of the random number generator. + +@end deftypefn + +*/ + +#include + +#if 0 + +#include +#include +#include +#include + +#else + +#define ULONG_MAX ((unsigned long)(~0L)) /* 0xFFFFFFFF for 32-bits */ +#define LONG_MAX ((long)(ULONG_MAX >> 1)) /* 0x7FFFFFFF for 32-bits*/ + +#ifdef __STDC__ +# define PTR void * +# ifndef NULL +# define NULL (void *) 0 +# endif +#else +# define PTR char * +# ifndef NULL +# define NULL (void *) 0 +# endif +#endif + +#endif + +long int random (void); + +/* An improved random number generation package. In addition to the standard + rand()/srand() like interface, this package also has a special state info + interface. The initstate() routine is called with a seed, an array of + bytes, and a count of how many bytes are being passed in; this array is + then initialized to contain information for random number generation with + that much state information. Good sizes for the amount of state + information are 32, 64, 128, and 256 bytes. The state can be switched by + calling the setstate() function with the same array as was initiallized + with initstate(). By default, the package runs with 128 bytes of state + information and generates far better random numbers than a linear + congruential generator. If the amount of state information is less than + 32 bytes, a simple linear congruential R.N.G. is used. Internally, the + state information is treated as an array of longs; the zeroeth element of + the array is the type of R.N.G. being used (small integer); the remainder + of the array is the state information for the R.N.G. Thus, 32 bytes of + state information will give 7 longs worth of state information, which will + allow a degree seven polynomial. (Note: The zeroeth word of state + information also has some other information stored in it; see setstate + for details). The random number generation technique is a linear feedback + shift register approach, employing trinomials (since there are fewer terms + to sum up that way). In this approach, the least significant bit of all + the numbers in the state table will act as a linear feedback shift register, + and will have period 2^deg - 1 (where deg is the degree of the polynomial + being used, assuming that the polynomial is irreducible and primitive). + The higher order bits will have longer periods, since their values are + also influenced by pseudo-random carries out of the lower bits. The + total period of the generator is approximately deg*(2**deg - 1); thus + doubling the amount of state information has a vast influence on the + period of the generator. Note: The deg*(2**deg - 1) is an approximation + only good for large deg, when the period of the shift register is the + dominant factor. With deg equal to seven, the period is actually much + longer than the 7*(2**7 - 1) predicted by this formula. */ + + + +/* For each of the currently supported random number generators, we have a + break value on the amount of state information (you need at least thi + bytes of state info to support this random number generator), a degree for + the polynomial (actually a trinomial) that the R.N.G. is based on, and + separation between the two lower order coefficients of the trinomial. */ + +/* Linear congruential. */ +#define TYPE_0 0 +#define BREAK_0 8 +#define DEG_0 0 +#define SEP_0 0 + +/* x**7 + x**3 + 1. */ +#define TYPE_1 1 +#define BREAK_1 32 +#define DEG_1 7 +#define SEP_1 3 + +/* x**15 + x + 1. */ +#define TYPE_2 2 +#define BREAK_2 64 +#define DEG_2 15 +#define SEP_2 1 + +/* x**31 + x**3 + 1. */ +#define TYPE_3 3 +#define BREAK_3 128 +#define DEG_3 31 +#define SEP_3 3 + +/* x**63 + x + 1. */ +#define TYPE_4 4 +#define BREAK_4 256 +#define DEG_4 63 +#define SEP_4 1 + + +/* Array versions of the above information to make code run faster. + Relies on fact that TYPE_i == i. */ + +#define MAX_TYPES 5 /* Max number of types above. */ + +static int degrees[MAX_TYPES] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 }; +static int seps[MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 }; + + + +/* Initially, everything is set up as if from: + initstate(1, randtbl, 128); + Note that this initialization takes advantage of the fact that srandom + advances the front and rear pointers 10*rand_deg times, and hence the + rear pointer which starts at 0 will also end up at zero; thus the zeroeth + element of the state information, which contains info about the current + position of the rear pointer is just + (MAX_TYPES * (rptr - state)) + TYPE_3 == TYPE_3. */ + +static long int randtbl[DEG_3 + 1] = + { TYPE_3, + 0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342, + 0xde3b81e0, 0xdf0a6fb5, 0xf103bc02, 0x48f340fb, + 0x7449e56b, 0xbeb1dbb0, 0xab5c5918, 0x946554fd, + 0x8c2e680f, 0xeb3d799f, 0xb11ee0b7, 0x2d436b86, + 0xda672e2a, 0x1588ca88, 0xe369735d, 0x904f35f7, + 0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc, + 0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b, + 0xf5ad9d0e, 0x8999220b, 0x27fb47b9 + }; + +/* FPTR and RPTR are two pointers into the state info, a front and a rear + pointer. These two pointers are always rand_sep places aparts, as they + cycle through the state information. (Yes, this does mean we could get + away with just one pointer, but the code for random is more efficient + this way). The pointers are left positioned as they would be from the call: + initstate(1, randtbl, 128); + (The position of the rear pointer, rptr, is really 0 (as explained above + in the initialization of randtbl) because the state table pointer is set + to point to randtbl[1] (as explained below).) */ + +static long int *fptr = &randtbl[SEP_3 + 1]; +static long int *rptr = &randtbl[1]; + + + +/* The following things are the pointer to the state information table, + the type of the current generator, the degree of the current polynomial + being used, and the separation between the two pointers. + Note that for efficiency of random, we remember the first location of + the state information, not the zeroeth. Hence it is valid to access + state[-1], which is used to store the type of the R.N.G. + Also, we remember the last location, since this is more efficient than + indexing every time to find the address of the last element to see if + the front and rear pointers have wrapped. */ + +static long int *state = &randtbl[1]; + +static int rand_type = TYPE_3; +static int rand_deg = DEG_3; +static int rand_sep = SEP_3; + +static long int *end_ptr = &randtbl[sizeof(randtbl) / sizeof(randtbl[0])]; + +/* Initialize the random number generator based on the given seed. If the + type is the trivial no-state-information type, just remember the seed. + Otherwise, initializes state[] based on the given "seed" via a linear + congruential generator. Then, the pointers are set to known locations + that are exactly rand_sep places apart. Lastly, it cycles the state + information a given number of times to get rid of any initial dependencies + introduced by the L.C.R.N.G. Note that the initialization of randtbl[] + for default usage relies on values produced by this routine. */ +void +srandom (unsigned int x) +{ + state[0] = x; + if (rand_type != TYPE_0) + { + register long int i; + for (i = 1; i < rand_deg; ++i) + state[i] = (1103515145 * state[i - 1]) + 12345; + fptr = &state[rand_sep]; + rptr = &state[0]; + for (i = 0; i < 10 * rand_deg; ++i) + random(); + } +} + +/* Initialize the state information in the given array of N bytes for + future random number generation. Based on the number of bytes we + are given, and the break values for the different R.N.G.'s, we choose + the best (largest) one we can and set things up for it. srandom is + then called to initialize the state information. Note that on return + from srandom, we set state[-1] to be the type multiplexed with the current + value of the rear pointer; this is so successive calls to initstate won't + lose this information and will be able to restart with setstate. + Note: The first thing we do is save the current state, if any, just like + setstate so that it doesn't matter when initstate is called. + Returns a pointer to the old state. */ +PTR +initstate (unsigned int seed, PTR arg_state, unsigned long n) +{ + PTR ostate = (PTR) &state[-1]; + + if (rand_type == TYPE_0) + state[-1] = rand_type; + else + state[-1] = (MAX_TYPES * (rptr - state)) + rand_type; + if (n < BREAK_1) + { + if (n < BREAK_0) + { + errno = EINVAL; + return NULL; + } + rand_type = TYPE_0; + rand_deg = DEG_0; + rand_sep = SEP_0; + } + else if (n < BREAK_2) + { + rand_type = TYPE_1; + rand_deg = DEG_1; + rand_sep = SEP_1; + } + else if (n < BREAK_3) + { + rand_type = TYPE_2; + rand_deg = DEG_2; + rand_sep = SEP_2; + } + else if (n < BREAK_4) + { + rand_type = TYPE_3; + rand_deg = DEG_3; + rand_sep = SEP_3; + } + else + { + rand_type = TYPE_4; + rand_deg = DEG_4; + rand_sep = SEP_4; + } + + state = &((long int *) arg_state)[1]; /* First location. */ + /* Must set END_PTR before srandom. */ + end_ptr = &state[rand_deg]; + srandom(seed); + if (rand_type == TYPE_0) + state[-1] = rand_type; + else + state[-1] = (MAX_TYPES * (rptr - state)) + rand_type; + + return ostate; +} + +/* Restore the state from the given state array. + Note: It is important that we also remember the locations of the pointers + in the current state information, and restore the locations of the pointers + from the old state information. This is done by multiplexing the pointer + location into the zeroeth word of the state information. Note that due + to the order in which things are done, it is OK to call setstate with the + same state as the current state + Returns a pointer to the old state information. */ + +PTR +setstate (PTR arg_state) +{ + register long int *new_state = (long int *) arg_state; + register int type = new_state[0] % MAX_TYPES; + register int rear = new_state[0] / MAX_TYPES; + PTR ostate = (PTR) &state[-1]; + + if (rand_type == TYPE_0) + state[-1] = rand_type; + else + state[-1] = (MAX_TYPES * (rptr - state)) + rand_type; + + switch (type) + { + case TYPE_0: + case TYPE_1: + case TYPE_2: + case TYPE_3: + case TYPE_4: + rand_type = type; + rand_deg = degrees[type]; + rand_sep = seps[type]; + break; + default: + /* State info munged. */ + errno = EINVAL; + return NULL; + } + + state = &new_state[1]; + if (rand_type != TYPE_0) + { + rptr = &state[rear]; + fptr = &state[(rear + rand_sep) % rand_deg]; + } + /* Set end_ptr too. */ + end_ptr = &state[rand_deg]; + + return ostate; +} + +/* If we are using the trivial TYPE_0 R.N.G., just do the old linear + congruential bit. Otherwise, we do our fancy trinomial stuff, which is the + same in all ther other cases due to all the global variables that have been + set up. The basic operation is to add the number at the rear pointer into + the one at the front pointer. Then both pointers are advanced to the next + location cyclically in the table. The value returned is the sum generated, + reduced to 31 bits by throwing away the "least random" low bit. + Note: The code takes advantage of the fact that both the front and + rear pointers can't wrap on the same call by not testing the rear + pointer if the front one has wrapped. Returns a 31-bit random number. */ + +long int +random (void) +{ + if (rand_type == TYPE_0) + { + state[0] = ((state[0] * 1103515245) + 12345) & LONG_MAX; + return state[0]; + } + else + { + long int i; + *fptr += *rptr; + /* Chucking least random bit. */ + i = (*fptr >> 1) & LONG_MAX; + ++fptr; + if (fptr >= end_ptr) + { + fptr = state; + ++rptr; + } + else + { + ++rptr; + if (rptr >= end_ptr) + rptr = state; + } + return i; + } +} diff --git a/libiberty/regex.c b/libiberty/regex.c new file mode 100644 index 0000000..fa1df19 --- /dev/null +++ b/libiberty/regex.c @@ -0,0 +1,8202 @@ +/* Extended regular expression matching and search library, + version 0.12. + (Implements POSIX draft P1003.2/D11.2, except for some of the + internationalization features.) + + Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, + 2002, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. */ + +/* This file has been modified for usage in libiberty. It includes "xregex.h" + instead of . The "xregex.h" header file renames all external + routines with an "x" prefix so they do not collide with the native regex + routines or with other components regex routines. */ +/* AIX requires this to be the first thing in the file. */ +#if defined _AIX && !defined __GNUC__ && !defined REGEX_MALLOC + #pragma alloca +#endif + +#undef _GNU_SOURCE +#define _GNU_SOURCE + +#ifndef INSIDE_RECURSION +# ifdef HAVE_CONFIG_H +# include +# endif +#endif + +#include + +#ifndef INSIDE_RECURSION + +# if defined STDC_HEADERS && !defined emacs +# include +# else +/* We need this for `regex.h', and perhaps for the Emacs include files. */ +# include +# endif + +# define WIDE_CHAR_SUPPORT (HAVE_WCTYPE_H && HAVE_WCHAR_H && HAVE_BTOWC) + +/* For platform which support the ISO C amendement 1 functionality we + support user defined character classes. */ +# if defined _LIBC || WIDE_CHAR_SUPPORT +/* Solaris 2.5 has a bug: must be included before . */ +# include +# include +# endif + +# ifdef _LIBC +/* We have to keep the namespace clean. */ +# define regfree(preg) __regfree (preg) +# define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef) +# define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags) +# define regerror(errcode, preg, errbuf, errbuf_size) \ + __regerror(errcode, preg, errbuf, errbuf_size) +# define re_set_registers(bu, re, nu, st, en) \ + __re_set_registers (bu, re, nu, st, en) +# define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \ + __re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) +# define re_match(bufp, string, size, pos, regs) \ + __re_match (bufp, string, size, pos, regs) +# define re_search(bufp, string, size, startpos, range, regs) \ + __re_search (bufp, string, size, startpos, range, regs) +# define re_compile_pattern(pattern, length, bufp) \ + __re_compile_pattern (pattern, length, bufp) +# define re_set_syntax(syntax) __re_set_syntax (syntax) +# define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \ + __re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop) +# define re_compile_fastmap(bufp) __re_compile_fastmap (bufp) + +# define btowc __btowc + +/* We are also using some library internals. */ +# include +# include +# include +# include +# endif + +/* This is for other GNU distributions with internationalized messages. */ +# if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC +# include +# ifdef _LIBC +# undef gettext +# define gettext(msgid) __dcgettext ("libc", msgid, LC_MESSAGES) +# endif +# else +# define gettext(msgid) (msgid) +# endif + +# ifndef gettext_noop +/* This define is so xgettext can find the internationalizable + strings. */ +# define gettext_noop(String) String +# endif + +/* The `emacs' switch turns on certain matching commands + that make sense only in Emacs. */ +# ifdef emacs + +# include "lisp.h" +# include "buffer.h" +# include "syntax.h" + +# else /* not emacs */ + +/* If we are not linking with Emacs proper, + we can't use the relocating allocator + even if config.h says that we can. */ +# undef REL_ALLOC + +# if defined STDC_HEADERS || defined _LIBC +# include +# else +char *malloc (); +char *realloc (); +# endif + +/* When used in Emacs's lib-src, we need to get bzero and bcopy somehow. + If nothing else has been done, use the method below. */ +# ifdef INHIBIT_STRING_HEADER +# if !(defined HAVE_BZERO && defined HAVE_BCOPY) +# if !defined bzero && !defined bcopy +# undef INHIBIT_STRING_HEADER +# endif +# endif +# endif + +/* This is the normal way of making sure we have a bcopy and a bzero. + This is used in most programs--a few other programs avoid this + by defining INHIBIT_STRING_HEADER. */ +# ifndef INHIBIT_STRING_HEADER +# if defined HAVE_STRING_H || defined STDC_HEADERS || defined _LIBC +# include +# ifndef bzero +# ifndef _LIBC +# define bzero(s, n) (memset (s, '\0', n), (s)) +# else +# define bzero(s, n) __bzero (s, n) +# endif +# endif +# else +# include +# ifndef memcmp +# define memcmp(s1, s2, n) bcmp (s1, s2, n) +# endif +# ifndef memcpy +# define memcpy(d, s, n) (bcopy (s, d, n), (d)) +# endif +# endif +# endif + +/* Define the syntax stuff for \<, \>, etc. */ + +/* This must be nonzero for the wordchar and notwordchar pattern + commands in re_match_2. */ +# ifndef Sword +# define Sword 1 +# endif + +# ifdef SWITCH_ENUM_BUG +# define SWITCH_ENUM_CAST(x) ((int)(x)) +# else +# define SWITCH_ENUM_CAST(x) (x) +# endif + +# endif /* not emacs */ + +# if defined _LIBC || HAVE_LIMITS_H +# include +# endif + +# ifndef MB_LEN_MAX +# define MB_LEN_MAX 1 +# endif + +/* Get the interface, including the syntax bits. */ +# include "xregex.h" /* change for libiberty */ + +/* isalpha etc. are used for the character classes. */ +# include + +/* Jim Meyering writes: + + "... Some ctype macros are valid only for character codes that + isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when + using /bin/cc or gcc but without giving an ansi option). So, all + ctype uses should be through macros like ISPRINT... If + STDC_HEADERS is defined, then autoconf has verified that the ctype + macros don't need to be guarded with references to isascii. ... + Defining isascii to 1 should let any compiler worth its salt + eliminate the && through constant folding." + Solaris defines some of these symbols so we must undefine them first. */ + +# undef ISASCII +# if defined STDC_HEADERS || (!defined isascii && !defined HAVE_ISASCII) +# define ISASCII(c) 1 +# else +# define ISASCII(c) isascii(c) +# endif + +# ifdef isblank +# define ISBLANK(c) (ISASCII (c) && isblank (c)) +# else +# define ISBLANK(c) ((c) == ' ' || (c) == '\t') +# endif +# ifdef isgraph +# define ISGRAPH(c) (ISASCII (c) && isgraph (c)) +# else +# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c)) +# endif + +# undef ISPRINT +# define ISPRINT(c) (ISASCII (c) && isprint (c)) +# define ISDIGIT(c) (ISASCII (c) && isdigit (c)) +# define ISALNUM(c) (ISASCII (c) && isalnum (c)) +# define ISALPHA(c) (ISASCII (c) && isalpha (c)) +# define ISCNTRL(c) (ISASCII (c) && iscntrl (c)) +# define ISLOWER(c) (ISASCII (c) && islower (c)) +# define ISPUNCT(c) (ISASCII (c) && ispunct (c)) +# define ISSPACE(c) (ISASCII (c) && isspace (c)) +# define ISUPPER(c) (ISASCII (c) && isupper (c)) +# define ISXDIGIT(c) (ISASCII (c) && isxdigit (c)) + +# ifdef _tolower +# define TOLOWER(c) _tolower(c) +# else +# define TOLOWER(c) tolower(c) +# endif + +# ifndef NULL +# define NULL (void *)0 +# endif + +/* We remove any previous definition of `SIGN_EXTEND_CHAR', + since ours (we hope) works properly with all combinations of + machines, compilers, `char' and `unsigned char' argument types. + (Per Bothner suggested the basic approach.) */ +# undef SIGN_EXTEND_CHAR +# if __STDC__ +# define SIGN_EXTEND_CHAR(c) ((signed char) (c)) +# else /* not __STDC__ */ +/* As in Harbison and Steele. */ +# define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128) +# endif + +# ifndef emacs +/* How many characters in the character set. */ +# define CHAR_SET_SIZE 256 + +# ifdef SYNTAX_TABLE + +extern char *re_syntax_table; + +# else /* not SYNTAX_TABLE */ + +static char re_syntax_table[CHAR_SET_SIZE]; + +static void init_syntax_once (void); + +static void +init_syntax_once (void) +{ + register int c; + static int done = 0; + + if (done) + return; + bzero (re_syntax_table, sizeof re_syntax_table); + + for (c = 0; c < CHAR_SET_SIZE; ++c) + if (ISALNUM (c)) + re_syntax_table[c] = Sword; + + re_syntax_table['_'] = Sword; + + done = 1; +} + +# endif /* not SYNTAX_TABLE */ + +# define SYNTAX(c) re_syntax_table[(unsigned char) (c)] + +# endif /* emacs */ + +/* Integer type for pointers. */ +# if !defined _LIBC && !defined HAVE_UINTPTR_T +typedef unsigned long int uintptr_t; +# endif + +/* Should we use malloc or alloca? If REGEX_MALLOC is not defined, we + use `alloca' instead of `malloc'. This is because using malloc in + re_search* or re_match* could cause memory leaks when C-g is used in + Emacs; also, malloc is slower and causes storage fragmentation. On + the other hand, malloc is more portable, and easier to debug. + + Because we sometimes use alloca, some routines have to be macros, + not functions -- `alloca'-allocated space disappears at the end of the + function it is called in. */ + +# ifdef REGEX_MALLOC + +# define REGEX_ALLOCATE malloc +# define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize) +# define REGEX_FREE free + +# else /* not REGEX_MALLOC */ + +/* Emacs already defines alloca, sometimes. */ +# ifndef alloca + +/* Make alloca work the best possible way. */ +# ifdef __GNUC__ +# define alloca __builtin_alloca +# else /* not __GNUC__ */ +# if HAVE_ALLOCA_H +# include +# endif /* HAVE_ALLOCA_H */ +# endif /* not __GNUC__ */ + +# endif /* not alloca */ + +# define REGEX_ALLOCATE alloca + +/* Assumes a `char *destination' variable. */ +# define REGEX_REALLOCATE(source, osize, nsize) \ + (destination = (char *) alloca (nsize), \ + memcpy (destination, source, osize)) + +/* No need to do anything to free, after alloca. */ +# define REGEX_FREE(arg) ((void)0) /* Do nothing! But inhibit gcc warning. */ + +# endif /* not REGEX_MALLOC */ + +/* Define how to allocate the failure stack. */ + +# if defined REL_ALLOC && defined REGEX_MALLOC + +# define REGEX_ALLOCATE_STACK(size) \ + r_alloc (&failure_stack_ptr, (size)) +# define REGEX_REALLOCATE_STACK(source, osize, nsize) \ + r_re_alloc (&failure_stack_ptr, (nsize)) +# define REGEX_FREE_STACK(ptr) \ + r_alloc_free (&failure_stack_ptr) + +# else /* not using relocating allocator */ + +# ifdef REGEX_MALLOC + +# define REGEX_ALLOCATE_STACK malloc +# define REGEX_REALLOCATE_STACK(source, osize, nsize) realloc (source, nsize) +# define REGEX_FREE_STACK free + +# else /* not REGEX_MALLOC */ + +# define REGEX_ALLOCATE_STACK alloca + +# define REGEX_REALLOCATE_STACK(source, osize, nsize) \ + REGEX_REALLOCATE (source, osize, nsize) +/* No need to explicitly free anything. */ +# define REGEX_FREE_STACK(arg) + +# endif /* not REGEX_MALLOC */ +# endif /* not using relocating allocator */ + + +/* True if `size1' is non-NULL and PTR is pointing anywhere inside + `string1' or just past its end. This works if PTR is NULL, which is + a good thing. */ +# define FIRST_STRING_P(ptr) \ + (size1 && string1 <= (ptr) && (ptr) <= string1 + size1) + +/* (Re)Allocate N items of type T using malloc, or fail. */ +# define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t))) +# define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t))) +# define RETALLOC_IF(addr, n, t) \ + if (addr) RETALLOC((addr), (n), t); else (addr) = TALLOC ((n), t) +# define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t))) + +# define BYTEWIDTH 8 /* In bits. */ + +# define STREQ(s1, s2) ((strcmp (s1, s2) == 0)) + +# undef MAX +# undef MIN +# define MAX(a, b) ((a) > (b) ? (a) : (b)) +# define MIN(a, b) ((a) < (b) ? (a) : (b)) + +typedef char boolean; +# define false 0 +# define true 1 + +static reg_errcode_t byte_regex_compile (const char *pattern, size_t size, + reg_syntax_t syntax, + struct re_pattern_buffer *bufp); + +static int byte_re_match_2_internal (struct re_pattern_buffer *bufp, + const char *string1, int size1, + const char *string2, int size2, + int pos, + struct re_registers *regs, + int stop); +static int byte_re_search_2 (struct re_pattern_buffer *bufp, + const char *string1, int size1, + const char *string2, int size2, + int startpos, int range, + struct re_registers *regs, int stop); +static int byte_re_compile_fastmap (struct re_pattern_buffer *bufp); + +#ifdef MBS_SUPPORT +static reg_errcode_t wcs_regex_compile (const char *pattern, size_t size, + reg_syntax_t syntax, + struct re_pattern_buffer *bufp); + + +static int wcs_re_match_2_internal (struct re_pattern_buffer *bufp, + const char *cstring1, int csize1, + const char *cstring2, int csize2, + int pos, + struct re_registers *regs, + int stop, + wchar_t *string1, int size1, + wchar_t *string2, int size2, + int *mbs_offset1, int *mbs_offset2); +static int wcs_re_search_2 (struct re_pattern_buffer *bufp, + const char *string1, int size1, + const char *string2, int size2, + int startpos, int range, + struct re_registers *regs, int stop); +static int wcs_re_compile_fastmap (struct re_pattern_buffer *bufp); +#endif + +/* These are the command codes that appear in compiled regular + expressions. Some opcodes are followed by argument bytes. A + command code can specify any interpretation whatsoever for its + arguments. Zero bytes may appear in the compiled regular expression. */ + +typedef enum +{ + no_op = 0, + + /* Succeed right away--no more backtracking. */ + succeed, + + /* Followed by one byte giving n, then by n literal bytes. */ + exactn, + +# ifdef MBS_SUPPORT + /* Same as exactn, but contains binary data. */ + exactn_bin, +# endif + + /* Matches any (more or less) character. */ + anychar, + + /* Matches any one char belonging to specified set. First + following byte is number of bitmap bytes. Then come bytes + for a bitmap saying which chars are in. Bits in each byte + are ordered low-bit-first. A character is in the set if its + bit is 1. A character too large to have a bit in the map is + automatically not in the set. */ + /* ifdef MBS_SUPPORT, following element is length of character + classes, length of collating symbols, length of equivalence + classes, length of character ranges, and length of characters. + Next, character class element, collating symbols elements, + equivalence class elements, range elements, and character + elements follow. + See regex_compile function. */ + charset, + + /* Same parameters as charset, but match any character that is + not one of those specified. */ + charset_not, + + /* Start remembering the text that is matched, for storing in a + register. Followed by one byte with the register number, in + the range 0 to one less than the pattern buffer's re_nsub + field. Then followed by one byte with the number of groups + inner to this one. (This last has to be part of the + start_memory only because we need it in the on_failure_jump + of re_match_2.) */ + start_memory, + + /* Stop remembering the text that is matched and store it in a + memory register. Followed by one byte with the register + number, in the range 0 to one less than `re_nsub' in the + pattern buffer, and one byte with the number of inner groups, + just like `start_memory'. (We need the number of inner + groups here because we don't have any easy way of finding the + corresponding start_memory when we're at a stop_memory.) */ + stop_memory, + + /* Match a duplicate of something remembered. Followed by one + byte containing the register number. */ + duplicate, + + /* Fail unless at beginning of line. */ + begline, + + /* Fail unless at end of line. */ + endline, + + /* Succeeds if at beginning of buffer (if emacs) or at beginning + of string to be matched (if not). */ + begbuf, + + /* Analogously, for end of buffer/string. */ + endbuf, + + /* Followed by two byte relative address to which to jump. */ + jump, + + /* Same as jump, but marks the end of an alternative. */ + jump_past_alt, + + /* Followed by two-byte relative address of place to resume at + in case of failure. */ + /* ifdef MBS_SUPPORT, the size of address is 1. */ + on_failure_jump, + + /* Like on_failure_jump, but pushes a placeholder instead of the + current string position when executed. */ + on_failure_keep_string_jump, + + /* Throw away latest failure point and then jump to following + two-byte relative address. */ + /* ifdef MBS_SUPPORT, the size of address is 1. */ + pop_failure_jump, + + /* Change to pop_failure_jump if know won't have to backtrack to + match; otherwise change to jump. This is used to jump + back to the beginning of a repeat. If what follows this jump + clearly won't match what the repeat does, such that we can be + sure that there is no use backtracking out of repetitions + already matched, then we change it to a pop_failure_jump. + Followed by two-byte address. */ + /* ifdef MBS_SUPPORT, the size of address is 1. */ + maybe_pop_jump, + + /* Jump to following two-byte address, and push a dummy failure + point. This failure point will be thrown away if an attempt + is made to use it for a failure. A `+' construct makes this + before the first repeat. Also used as an intermediary kind + of jump when compiling an alternative. */ + /* ifdef MBS_SUPPORT, the size of address is 1. */ + dummy_failure_jump, + + /* Push a dummy failure point and continue. Used at the end of + alternatives. */ + push_dummy_failure, + + /* Followed by two-byte relative address and two-byte number n. + After matching N times, jump to the address upon failure. */ + /* ifdef MBS_SUPPORT, the size of address is 1. */ + succeed_n, + + /* Followed by two-byte relative address, and two-byte number n. + Jump to the address N times, then fail. */ + /* ifdef MBS_SUPPORT, the size of address is 1. */ + jump_n, + + /* Set the following two-byte relative address to the + subsequent two-byte number. The address *includes* the two + bytes of number. */ + /* ifdef MBS_SUPPORT, the size of address is 1. */ + set_number_at, + + wordchar, /* Matches any word-constituent character. */ + notwordchar, /* Matches any char that is not a word-constituent. */ + + wordbeg, /* Succeeds if at word beginning. */ + wordend, /* Succeeds if at word end. */ + + wordbound, /* Succeeds if at a word boundary. */ + notwordbound /* Succeeds if not at a word boundary. */ + +# ifdef emacs + ,before_dot, /* Succeeds if before point. */ + at_dot, /* Succeeds if at point. */ + after_dot, /* Succeeds if after point. */ + + /* Matches any character whose syntax is specified. Followed by + a byte which contains a syntax code, e.g., Sword. */ + syntaxspec, + + /* Matches any character whose syntax is not that specified. */ + notsyntaxspec +# endif /* emacs */ +} re_opcode_t; +#endif /* not INSIDE_RECURSION */ + + +#ifdef BYTE +# define CHAR_T char +# define UCHAR_T unsigned char +# define COMPILED_BUFFER_VAR bufp->buffer +# define OFFSET_ADDRESS_SIZE 2 +# define PREFIX(name) byte_##name +# define ARG_PREFIX(name) name +# define PUT_CHAR(c) putchar (c) +#else +# ifdef WCHAR +# define CHAR_T wchar_t +# define UCHAR_T wchar_t +# define COMPILED_BUFFER_VAR wc_buffer +# define OFFSET_ADDRESS_SIZE 1 /* the size which STORE_NUMBER macro use */ +# define CHAR_CLASS_SIZE ((__alignof__(wctype_t)+sizeof(wctype_t))/sizeof(CHAR_T)+1) +# define PREFIX(name) wcs_##name +# define ARG_PREFIX(name) c##name +/* Should we use wide stream?? */ +# define PUT_CHAR(c) printf ("%C", c); +# define TRUE 1 +# define FALSE 0 +# else +# ifdef MBS_SUPPORT +# define WCHAR +# define INSIDE_RECURSION +# include "regex.c" +# undef INSIDE_RECURSION +# endif +# define BYTE +# define INSIDE_RECURSION +# include "regex.c" +# undef INSIDE_RECURSION +# endif +#endif + +#ifdef INSIDE_RECURSION +/* Common operations on the compiled pattern. */ + +/* Store NUMBER in two contiguous bytes starting at DESTINATION. */ +/* ifdef MBS_SUPPORT, we store NUMBER in 1 element. */ + +# ifdef WCHAR +# define STORE_NUMBER(destination, number) \ + do { \ + *(destination) = (UCHAR_T)(number); \ + } while (0) +# else /* BYTE */ +# define STORE_NUMBER(destination, number) \ + do { \ + (destination)[0] = (number) & 0377; \ + (destination)[1] = (number) >> 8; \ + } while (0) +# endif /* WCHAR */ + +/* Same as STORE_NUMBER, except increment DESTINATION to + the byte after where the number is stored. Therefore, DESTINATION + must be an lvalue. */ +/* ifdef MBS_SUPPORT, we store NUMBER in 1 element. */ + +# define STORE_NUMBER_AND_INCR(destination, number) \ + do { \ + STORE_NUMBER (destination, number); \ + (destination) += OFFSET_ADDRESS_SIZE; \ + } while (0) + +/* Put into DESTINATION a number stored in two contiguous bytes starting + at SOURCE. */ +/* ifdef MBS_SUPPORT, we store NUMBER in 1 element. */ + +# ifdef WCHAR +# define EXTRACT_NUMBER(destination, source) \ + do { \ + (destination) = *(source); \ + } while (0) +# else /* BYTE */ +# define EXTRACT_NUMBER(destination, source) \ + do { \ + (destination) = *(source) & 0377; \ + (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8; \ + } while (0) +# endif + +# ifdef DEBUG +static void PREFIX(extract_number) (int *dest, UCHAR_T *source); +static void +PREFIX(extract_number) (int *dest, UCHAR_T *source) +{ +# ifdef WCHAR + *dest = *source; +# else /* BYTE */ + int temp = SIGN_EXTEND_CHAR (*(source + 1)); + *dest = *source & 0377; + *dest += temp << 8; +# endif +} + +# ifndef EXTRACT_MACROS /* To debug the macros. */ +# undef EXTRACT_NUMBER +# define EXTRACT_NUMBER(dest, src) PREFIX(extract_number) (&dest, src) +# endif /* not EXTRACT_MACROS */ + +# endif /* DEBUG */ + +/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number. + SOURCE must be an lvalue. */ + +# define EXTRACT_NUMBER_AND_INCR(destination, source) \ + do { \ + EXTRACT_NUMBER (destination, source); \ + (source) += OFFSET_ADDRESS_SIZE; \ + } while (0) + +# ifdef DEBUG +static void PREFIX(extract_number_and_incr) (int *destination, + UCHAR_T **source); +static void +PREFIX(extract_number_and_incr) (int *destination, UCHAR_T **source) +{ + PREFIX(extract_number) (destination, *source); + *source += OFFSET_ADDRESS_SIZE; +} + +# ifndef EXTRACT_MACROS +# undef EXTRACT_NUMBER_AND_INCR +# define EXTRACT_NUMBER_AND_INCR(dest, src) \ + PREFIX(extract_number_and_incr) (&dest, &src) +# endif /* not EXTRACT_MACROS */ + +# endif /* DEBUG */ + + + +/* If DEBUG is defined, Regex prints many voluminous messages about what + it is doing (if the variable `debug' is nonzero). If linked with the + main program in `iregex.c', you can enter patterns and strings + interactively. And if linked with the main program in `main.c' and + the other test files, you can run the already-written tests. */ + +# ifdef DEBUG + +# ifndef DEFINED_ONCE + +/* We use standard I/O for debugging. */ +# include + +/* It is useful to test things that ``must'' be true when debugging. */ +# include + +static int debug; + +# define DEBUG_STATEMENT(e) e +# define DEBUG_PRINT1(x) if (debug) printf (x) +# define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2) +# define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3) +# define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4) +# endif /* not DEFINED_ONCE */ + +# define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) \ + if (debug) PREFIX(print_partial_compiled_pattern) (s, e) +# define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) \ + if (debug) PREFIX(print_double_string) (w, s1, sz1, s2, sz2) + + +/* Print the fastmap in human-readable form. */ + +# ifndef DEFINED_ONCE +void +print_fastmap (char *fastmap) +{ + unsigned was_a_range = 0; + unsigned i = 0; + + while (i < (1 << BYTEWIDTH)) + { + if (fastmap[i++]) + { + was_a_range = 0; + putchar (i - 1); + while (i < (1 << BYTEWIDTH) && fastmap[i]) + { + was_a_range = 1; + i++; + } + if (was_a_range) + { + printf ("-"); + putchar (i - 1); + } + } + } + putchar ('\n'); +} +# endif /* not DEFINED_ONCE */ + + +/* Print a compiled pattern string in human-readable form, starting at + the START pointer into it and ending just before the pointer END. */ + +void +PREFIX(print_partial_compiled_pattern) (UCHAR_T *start, UCHAR_T *end) +{ + int mcnt, mcnt2; + UCHAR_T *p1; + UCHAR_T *p = start; + UCHAR_T *pend = end; + + if (start == NULL) + { + printf ("(null)\n"); + return; + } + + /* Loop over pattern commands. */ + while (p < pend) + { +# ifdef _LIBC + printf ("%td:\t", p - start); +# else + printf ("%ld:\t", (long int) (p - start)); +# endif + + switch ((re_opcode_t) *p++) + { + case no_op: + printf ("/no_op"); + break; + + case exactn: + mcnt = *p++; + printf ("/exactn/%d", mcnt); + do + { + putchar ('/'); + PUT_CHAR (*p++); + } + while (--mcnt); + break; + +# ifdef MBS_SUPPORT + case exactn_bin: + mcnt = *p++; + printf ("/exactn_bin/%d", mcnt); + do + { + printf("/%lx", (long int) *p++); + } + while (--mcnt); + break; +# endif /* MBS_SUPPORT */ + + case start_memory: + mcnt = *p++; + printf ("/start_memory/%d/%ld", mcnt, (long int) *p++); + break; + + case stop_memory: + mcnt = *p++; + printf ("/stop_memory/%d/%ld", mcnt, (long int) *p++); + break; + + case duplicate: + printf ("/duplicate/%ld", (long int) *p++); + break; + + case anychar: + printf ("/anychar"); + break; + + case charset: + case charset_not: + { +# ifdef WCHAR + int i, length; + wchar_t *workp = p; + printf ("/charset [%s", + (re_opcode_t) *(workp - 1) == charset_not ? "^" : ""); + p += 5; + length = *workp++; /* the length of char_classes */ + for (i=0 ; ibuffer; + + PREFIX(print_partial_compiled_pattern) (buffer, buffer + + bufp->used / sizeof(UCHAR_T)); + printf ("%ld bytes used/%ld bytes allocated.\n", + bufp->used, bufp->allocated); + + if (bufp->fastmap_accurate && bufp->fastmap) + { + printf ("fastmap: "); + print_fastmap (bufp->fastmap); + } + +# ifdef _LIBC + printf ("re_nsub: %Zd\t", bufp->re_nsub); +# else + printf ("re_nsub: %ld\t", (long int) bufp->re_nsub); +# endif + printf ("regs_alloc: %d\t", bufp->regs_allocated); + printf ("can_be_null: %d\t", bufp->can_be_null); + printf ("newline_anchor: %d\n", bufp->newline_anchor); + printf ("no_sub: %d\t", bufp->no_sub); + printf ("not_bol: %d\t", bufp->not_bol); + printf ("not_eol: %d\t", bufp->not_eol); + printf ("syntax: %lx\n", bufp->syntax); + /* Perhaps we should print the translate table? */ +} + + +void +PREFIX(print_double_string) (const CHAR_T *where, const CHAR_T *string1, + int size1, const CHAR_T *string2, int size2) +{ + int this_char; + + if (where == NULL) + printf ("(null)"); + else + { + int cnt; + + if (FIRST_STRING_P (where)) + { + for (this_char = where - string1; this_char < size1; this_char++) + PUT_CHAR (string1[this_char]); + + where = string2; + } + + cnt = 0; + for (this_char = where - string2; this_char < size2; this_char++) + { + PUT_CHAR (string2[this_char]); + if (++cnt > 100) + { + fputs ("...", stdout); + break; + } + } + } +} + +# ifndef DEFINED_ONCE +void +printchar (int c) +{ + putc (c, stderr); +} +# endif + +# else /* not DEBUG */ + +# ifndef DEFINED_ONCE +# undef assert +# define assert(e) + +# define DEBUG_STATEMENT(e) +# define DEBUG_PRINT1(x) +# define DEBUG_PRINT2(x1, x2) +# define DEBUG_PRINT3(x1, x2, x3) +# define DEBUG_PRINT4(x1, x2, x3, x4) +# endif /* not DEFINED_ONCE */ +# define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) +# define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) + +# endif /* not DEBUG */ + + + +# ifdef WCHAR +/* This convert a multibyte string to a wide character string. + And write their correspondances to offset_buffer(see below) + and write whether each wchar_t is binary data to is_binary. + This assume invalid multibyte sequences as binary data. + We assume offset_buffer and is_binary is already allocated + enough space. */ + +static size_t convert_mbs_to_wcs (CHAR_T *dest, const unsigned char* src, + size_t len, int *offset_buffer, + char *is_binary); +static size_t +convert_mbs_to_wcs (CHAR_T *dest, const unsigned char*src, size_t len, + int *offset_buffer, char *is_binary) + /* It hold correspondances between src(char string) and + dest(wchar_t string) for optimization. + e.g. src = "xxxyzz" + dest = {'X', 'Y', 'Z'} + (each "xxx", "y" and "zz" represent one multibyte character + corresponding to 'X', 'Y' and 'Z'.) + offset_buffer = {0, 0+3("xxx"), 0+3+1("y"), 0+3+1+2("zz")} + = {0, 3, 4, 6} + */ +{ + wchar_t *pdest = dest; + const unsigned char *psrc = src; + size_t wc_count = 0; + + mbstate_t mbs; + int i, consumed; + size_t mb_remain = len; + size_t mb_count = 0; + + /* Initialize the conversion state. */ + memset (&mbs, 0, sizeof (mbstate_t)); + + offset_buffer[0] = 0; + for( ; mb_remain > 0 ; ++wc_count, ++pdest, mb_remain -= consumed, + psrc += consumed) + { +#ifdef _LIBC + consumed = __mbrtowc (pdest, psrc, mb_remain, &mbs); +#else + consumed = mbrtowc (pdest, psrc, mb_remain, &mbs); +#endif + + if (consumed <= 0) + /* failed to convert. maybe src contains binary data. + So we consume 1 byte manualy. */ + { + *pdest = *psrc; + consumed = 1; + is_binary[wc_count] = TRUE; + } + else + is_binary[wc_count] = FALSE; + /* In sjis encoding, we use yen sign as escape character in + place of reverse solidus. So we convert 0x5c(yen sign in + sjis) to not 0xa5(yen sign in UCS2) but 0x5c(reverse + solidus in UCS2). */ + if (consumed == 1 && (int) *psrc == 0x5c && (int) *pdest == 0xa5) + *pdest = (wchar_t) *psrc; + + offset_buffer[wc_count + 1] = mb_count += consumed; + } + + /* Fill remain of the buffer with sentinel. */ + for (i = wc_count + 1 ; i <= len ; i++) + offset_buffer[i] = mb_count + 1; + + return wc_count; +} + +# endif /* WCHAR */ + +#else /* not INSIDE_RECURSION */ + +/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can + also be assigned to arbitrarily: each pattern buffer stores its own + syntax, so it can be changed between regex compilations. */ +/* This has no initializer because initialized variables in Emacs + become read-only after dumping. */ +reg_syntax_t re_syntax_options; + + +/* Specify the precise syntax of regexps for compilation. This provides + for compatibility for various utilities which historically have + different, incompatible syntaxes. + + The argument SYNTAX is a bit mask comprised of the various bits + defined in regex.h. We return the old syntax. */ + +reg_syntax_t +re_set_syntax (reg_syntax_t syntax) +{ + reg_syntax_t ret = re_syntax_options; + + re_syntax_options = syntax; +# ifdef DEBUG + if (syntax & RE_DEBUG) + debug = 1; + else if (debug) /* was on but now is not */ + debug = 0; +# endif /* DEBUG */ + return ret; +} +# ifdef _LIBC +weak_alias (__re_set_syntax, re_set_syntax) +# endif + +/* This table gives an error message for each of the error codes listed + in regex.h. Obviously the order here has to be same as there. + POSIX doesn't require that we do anything for REG_NOERROR, + but why not be nice? */ + +static const char *re_error_msgid[] = + { + gettext_noop ("Success"), /* REG_NOERROR */ + gettext_noop ("No match"), /* REG_NOMATCH */ + gettext_noop ("Invalid regular expression"), /* REG_BADPAT */ + gettext_noop ("Invalid collation character"), /* REG_ECOLLATE */ + gettext_noop ("Invalid character class name"), /* REG_ECTYPE */ + gettext_noop ("Trailing backslash"), /* REG_EESCAPE */ + gettext_noop ("Invalid back reference"), /* REG_ESUBREG */ + gettext_noop ("Unmatched [ or [^"), /* REG_EBRACK */ + gettext_noop ("Unmatched ( or \\("), /* REG_EPAREN */ + gettext_noop ("Unmatched \\{"), /* REG_EBRACE */ + gettext_noop ("Invalid content of \\{\\}"), /* REG_BADBR */ + gettext_noop ("Invalid range end"), /* REG_ERANGE */ + gettext_noop ("Memory exhausted"), /* REG_ESPACE */ + gettext_noop ("Invalid preceding regular expression"), /* REG_BADRPT */ + gettext_noop ("Premature end of regular expression"), /* REG_EEND */ + gettext_noop ("Regular expression too big"), /* REG_ESIZE */ + gettext_noop ("Unmatched ) or \\)") /* REG_ERPAREN */ + }; + +#endif /* INSIDE_RECURSION */ + +#ifndef DEFINED_ONCE +/* Avoiding alloca during matching, to placate r_alloc. */ + +/* Define MATCH_MAY_ALLOCATE unless we need to make sure that the + searching and matching functions should not call alloca. On some + systems, alloca is implemented in terms of malloc, and if we're + using the relocating allocator routines, then malloc could cause a + relocation, which might (if the strings being searched are in the + ralloc heap) shift the data out from underneath the regexp + routines. + + Here's another reason to avoid allocation: Emacs + processes input from X in a signal handler; processing X input may + call malloc; if input arrives while a matching routine is calling + malloc, then we're scrod. But Emacs can't just block input while + calling matching routines; then we don't notice interrupts when + they come in. So, Emacs blocks input around all regexp calls + except the matching calls, which it leaves unprotected, in the + faith that they will not malloc. */ + +/* Normally, this is fine. */ +# define MATCH_MAY_ALLOCATE + +/* When using GNU C, we are not REALLY using the C alloca, no matter + what config.h may say. So don't take precautions for it. */ +# ifdef __GNUC__ +# undef C_ALLOCA +# endif + +/* The match routines may not allocate if (1) they would do it with malloc + and (2) it's not safe for them to use malloc. + Note that if REL_ALLOC is defined, matching would not use malloc for the + failure stack, but we would still use it for the register vectors; + so REL_ALLOC should not affect this. */ +# if (defined C_ALLOCA || defined REGEX_MALLOC) && defined emacs +# undef MATCH_MAY_ALLOCATE +# endif +#endif /* not DEFINED_ONCE */ + +#ifdef INSIDE_RECURSION +/* Failure stack declarations and macros; both re_compile_fastmap and + re_match_2 use a failure stack. These have to be macros because of + REGEX_ALLOCATE_STACK. */ + + +/* Number of failure points for which to initially allocate space + when matching. If this number is exceeded, we allocate more + space, so it is not a hard limit. */ +# ifndef INIT_FAILURE_ALLOC +# define INIT_FAILURE_ALLOC 5 +# endif + +/* Roughly the maximum number of failure points on the stack. Would be + exactly that if always used MAX_FAILURE_ITEMS items each time we failed. + This is a variable only so users of regex can assign to it; we never + change it ourselves. */ + +# ifdef INT_IS_16BIT + +# ifndef DEFINED_ONCE +# if defined MATCH_MAY_ALLOCATE +/* 4400 was enough to cause a crash on Alpha OSF/1, + whose default stack limit is 2mb. */ +long int re_max_failures = 4000; +# else +long int re_max_failures = 2000; +# endif +# endif + +union PREFIX(fail_stack_elt) +{ + UCHAR_T *pointer; + long int integer; +}; + +typedef union PREFIX(fail_stack_elt) PREFIX(fail_stack_elt_t); + +typedef struct +{ + PREFIX(fail_stack_elt_t) *stack; + unsigned long int size; + unsigned long int avail; /* Offset of next open position. */ +} PREFIX(fail_stack_type); + +# else /* not INT_IS_16BIT */ + +# ifndef DEFINED_ONCE +# if defined MATCH_MAY_ALLOCATE +/* 4400 was enough to cause a crash on Alpha OSF/1, + whose default stack limit is 2mb. */ +int re_max_failures = 4000; +# else +int re_max_failures = 2000; +# endif +# endif + +union PREFIX(fail_stack_elt) +{ + UCHAR_T *pointer; + int integer; +}; + +typedef union PREFIX(fail_stack_elt) PREFIX(fail_stack_elt_t); + +typedef struct +{ + PREFIX(fail_stack_elt_t) *stack; + unsigned size; + unsigned avail; /* Offset of next open position. */ +} PREFIX(fail_stack_type); + +# endif /* INT_IS_16BIT */ + +# ifndef DEFINED_ONCE +# define FAIL_STACK_EMPTY() (fail_stack.avail == 0) +# define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0) +# define FAIL_STACK_FULL() (fail_stack.avail == fail_stack.size) +# endif + + +/* Define macros to initialize and free the failure stack. + Do `return -2' if the alloc fails. */ + +# ifdef MATCH_MAY_ALLOCATE +# define INIT_FAIL_STACK() \ + do { \ + fail_stack.stack = (PREFIX(fail_stack_elt_t) *) \ + REGEX_ALLOCATE_STACK (INIT_FAILURE_ALLOC * sizeof (PREFIX(fail_stack_elt_t))); \ + \ + if (fail_stack.stack == NULL) \ + return -2; \ + \ + fail_stack.size = INIT_FAILURE_ALLOC; \ + fail_stack.avail = 0; \ + } while (0) + +# define RESET_FAIL_STACK() REGEX_FREE_STACK (fail_stack.stack) +# else +# define INIT_FAIL_STACK() \ + do { \ + fail_stack.avail = 0; \ + } while (0) + +# define RESET_FAIL_STACK() +# endif + + +/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items. + + Return 1 if succeeds, and 0 if either ran out of memory + allocating space for it or it was already too large. + + REGEX_REALLOCATE_STACK requires `destination' be declared. */ + +# define DOUBLE_FAIL_STACK(fail_stack) \ + ((fail_stack).size > (unsigned) (re_max_failures * MAX_FAILURE_ITEMS) \ + ? 0 \ + : ((fail_stack).stack = (PREFIX(fail_stack_elt_t) *) \ + REGEX_REALLOCATE_STACK ((fail_stack).stack, \ + (fail_stack).size * sizeof (PREFIX(fail_stack_elt_t)), \ + ((fail_stack).size << 1) * sizeof (PREFIX(fail_stack_elt_t))),\ + \ + (fail_stack).stack == NULL \ + ? 0 \ + : ((fail_stack).size <<= 1, \ + 1))) + + +/* Push pointer POINTER on FAIL_STACK. + Return 1 if was able to do so and 0 if ran out of memory allocating + space to do so. */ +# define PUSH_PATTERN_OP(POINTER, FAIL_STACK) \ + ((FAIL_STACK_FULL () \ + && !DOUBLE_FAIL_STACK (FAIL_STACK)) \ + ? 0 \ + : ((FAIL_STACK).stack[(FAIL_STACK).avail++].pointer = POINTER, \ + 1)) + +/* Push a pointer value onto the failure stack. + Assumes the variable `fail_stack'. Probably should only + be called from within `PUSH_FAILURE_POINT'. */ +# define PUSH_FAILURE_POINTER(item) \ + fail_stack.stack[fail_stack.avail++].pointer = (UCHAR_T *) (item) + +/* This pushes an integer-valued item onto the failure stack. + Assumes the variable `fail_stack'. Probably should only + be called from within `PUSH_FAILURE_POINT'. */ +# define PUSH_FAILURE_INT(item) \ + fail_stack.stack[fail_stack.avail++].integer = (item) + +/* Push a fail_stack_elt_t value onto the failure stack. + Assumes the variable `fail_stack'. Probably should only + be called from within `PUSH_FAILURE_POINT'. */ +# define PUSH_FAILURE_ELT(item) \ + fail_stack.stack[fail_stack.avail++] = (item) + +/* These three POP... operations complement the three PUSH... operations. + All assume that `fail_stack' is nonempty. */ +# define POP_FAILURE_POINTER() fail_stack.stack[--fail_stack.avail].pointer +# define POP_FAILURE_INT() fail_stack.stack[--fail_stack.avail].integer +# define POP_FAILURE_ELT() fail_stack.stack[--fail_stack.avail] + +/* Used to omit pushing failure point id's when we're not debugging. */ +# ifdef DEBUG +# define DEBUG_PUSH PUSH_FAILURE_INT +# define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_INT () +# else +# define DEBUG_PUSH(item) +# define DEBUG_POP(item_addr) +# endif + + +/* Push the information about the state we will need + if we ever fail back to it. + + Requires variables fail_stack, regstart, regend, reg_info, and + num_regs_pushed be declared. DOUBLE_FAIL_STACK requires `destination' + be declared. + + Does `return FAILURE_CODE' if runs out of memory. */ + +# define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code) \ + do { \ + char *destination; \ + /* Must be int, so when we don't save any registers, the arithmetic \ + of 0 + -1 isn't done as unsigned. */ \ + /* Can't be int, since there is not a shred of a guarantee that int \ + is wide enough to hold a value of something to which pointer can \ + be assigned */ \ + active_reg_t this_reg; \ + \ + DEBUG_STATEMENT (failure_id++); \ + DEBUG_STATEMENT (nfailure_points_pushed++); \ + DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id); \ + DEBUG_PRINT2 (" Before push, next avail: %d\n", (fail_stack).avail);\ + DEBUG_PRINT2 (" size: %d\n", (fail_stack).size);\ + \ + DEBUG_PRINT2 (" slots needed: %ld\n", NUM_FAILURE_ITEMS); \ + DEBUG_PRINT2 (" available: %d\n", REMAINING_AVAIL_SLOTS); \ + \ + /* Ensure we have enough space allocated for what we will push. */ \ + while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS) \ + { \ + if (!DOUBLE_FAIL_STACK (fail_stack)) \ + return failure_code; \ + \ + DEBUG_PRINT2 ("\n Doubled stack; size now: %d\n", \ + (fail_stack).size); \ + DEBUG_PRINT2 (" slots available: %d\n", REMAINING_AVAIL_SLOTS);\ + } \ + \ + /* Push the info, starting with the registers. */ \ + DEBUG_PRINT1 ("\n"); \ + \ + if (1) \ + for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \ + this_reg++) \ + { \ + DEBUG_PRINT2 (" Pushing reg: %lu\n", this_reg); \ + DEBUG_STATEMENT (num_regs_pushed++); \ + \ + DEBUG_PRINT2 (" start: %p\n", regstart[this_reg]); \ + PUSH_FAILURE_POINTER (regstart[this_reg]); \ + \ + DEBUG_PRINT2 (" end: %p\n", regend[this_reg]); \ + PUSH_FAILURE_POINTER (regend[this_reg]); \ + \ + DEBUG_PRINT2 (" info: %p\n ", \ + reg_info[this_reg].word.pointer); \ + DEBUG_PRINT2 (" match_null=%d", \ + REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \ + DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \ + DEBUG_PRINT2 (" matched_something=%d", \ + MATCHED_SOMETHING (reg_info[this_reg])); \ + DEBUG_PRINT2 (" ever_matched=%d", \ + EVER_MATCHED_SOMETHING (reg_info[this_reg])); \ + DEBUG_PRINT1 ("\n"); \ + PUSH_FAILURE_ELT (reg_info[this_reg].word); \ + } \ + \ + DEBUG_PRINT2 (" Pushing low active reg: %ld\n", lowest_active_reg);\ + PUSH_FAILURE_INT (lowest_active_reg); \ + \ + DEBUG_PRINT2 (" Pushing high active reg: %ld\n", highest_active_reg);\ + PUSH_FAILURE_INT (highest_active_reg); \ + \ + DEBUG_PRINT2 (" Pushing pattern %p:\n", pattern_place); \ + DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend); \ + PUSH_FAILURE_POINTER (pattern_place); \ + \ + DEBUG_PRINT2 (" Pushing string %p: `", string_place); \ + DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2, \ + size2); \ + DEBUG_PRINT1 ("'\n"); \ + PUSH_FAILURE_POINTER (string_place); \ + \ + DEBUG_PRINT2 (" Pushing failure id: %u\n", failure_id); \ + DEBUG_PUSH (failure_id); \ + } while (0) + +# ifndef DEFINED_ONCE +/* This is the number of items that are pushed and popped on the stack + for each register. */ +# define NUM_REG_ITEMS 3 + +/* Individual items aside from the registers. */ +# ifdef DEBUG +# define NUM_NONREG_ITEMS 5 /* Includes failure point id. */ +# else +# define NUM_NONREG_ITEMS 4 +# endif + +/* We push at most this many items on the stack. */ +/* We used to use (num_regs - 1), which is the number of registers + this regexp will save; but that was changed to 5 + to avoid stack overflow for a regexp with lots of parens. */ +# define MAX_FAILURE_ITEMS (5 * NUM_REG_ITEMS + NUM_NONREG_ITEMS) + +/* We actually push this many items. */ +# define NUM_FAILURE_ITEMS \ + (((0 \ + ? 0 : highest_active_reg - lowest_active_reg + 1) \ + * NUM_REG_ITEMS) \ + + NUM_NONREG_ITEMS) + +/* How many items can still be added to the stack without overflowing it. */ +# define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail) +# endif /* not DEFINED_ONCE */ + + +/* Pops what PUSH_FAIL_STACK pushes. + + We restore into the parameters, all of which should be lvalues: + STR -- the saved data position. + PAT -- the saved pattern position. + LOW_REG, HIGH_REG -- the highest and lowest active registers. + REGSTART, REGEND -- arrays of string positions. + REG_INFO -- array of information about each subexpression. + + Also assumes the variables `fail_stack' and (if debugging), `bufp', + `pend', `string1', `size1', `string2', and `size2'. */ +# define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\ +{ \ + DEBUG_STATEMENT (unsigned failure_id;) \ + active_reg_t this_reg; \ + const UCHAR_T *string_temp; \ + \ + assert (!FAIL_STACK_EMPTY ()); \ + \ + /* Remove failure points and point to how many regs pushed. */ \ + DEBUG_PRINT1 ("POP_FAILURE_POINT:\n"); \ + DEBUG_PRINT2 (" Before pop, next avail: %d\n", fail_stack.avail); \ + DEBUG_PRINT2 (" size: %d\n", fail_stack.size); \ + \ + assert (fail_stack.avail >= NUM_NONREG_ITEMS); \ + \ + DEBUG_POP (&failure_id); \ + DEBUG_PRINT2 (" Popping failure id: %u\n", failure_id); \ + \ + /* If the saved string location is NULL, it came from an \ + on_failure_keep_string_jump opcode, and we want to throw away the \ + saved NULL, thus retaining our current position in the string. */ \ + string_temp = POP_FAILURE_POINTER (); \ + if (string_temp != NULL) \ + str = (const CHAR_T *) string_temp; \ + \ + DEBUG_PRINT2 (" Popping string %p: `", str); \ + DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2); \ + DEBUG_PRINT1 ("'\n"); \ + \ + pat = (UCHAR_T *) POP_FAILURE_POINTER (); \ + DEBUG_PRINT2 (" Popping pattern %p:\n", pat); \ + DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend); \ + \ + /* Restore register info. */ \ + high_reg = (active_reg_t) POP_FAILURE_INT (); \ + DEBUG_PRINT2 (" Popping high active reg: %ld\n", high_reg); \ + \ + low_reg = (active_reg_t) POP_FAILURE_INT (); \ + DEBUG_PRINT2 (" Popping low active reg: %ld\n", low_reg); \ + \ + if (1) \ + for (this_reg = high_reg; this_reg >= low_reg; this_reg--) \ + { \ + DEBUG_PRINT2 (" Popping reg: %ld\n", this_reg); \ + \ + reg_info[this_reg].word = POP_FAILURE_ELT (); \ + DEBUG_PRINT2 (" info: %p\n", \ + reg_info[this_reg].word.pointer); \ + \ + regend[this_reg] = (const CHAR_T *) POP_FAILURE_POINTER (); \ + DEBUG_PRINT2 (" end: %p\n", regend[this_reg]); \ + \ + regstart[this_reg] = (const CHAR_T *) POP_FAILURE_POINTER (); \ + DEBUG_PRINT2 (" start: %p\n", regstart[this_reg]); \ + } \ + else \ + { \ + for (this_reg = highest_active_reg; this_reg > high_reg; this_reg--) \ + { \ + reg_info[this_reg].word.integer = 0; \ + regend[this_reg] = 0; \ + regstart[this_reg] = 0; \ + } \ + highest_active_reg = high_reg; \ + } \ + \ + set_regs_matched_done = 0; \ + DEBUG_STATEMENT (nfailure_points_popped++); \ +} /* POP_FAILURE_POINT */ + +/* Structure for per-register (a.k.a. per-group) information. + Other register information, such as the + starting and ending positions (which are addresses), and the list of + inner groups (which is a bits list) are maintained in separate + variables. + + We are making a (strictly speaking) nonportable assumption here: that + the compiler will pack our bit fields into something that fits into + the type of `word', i.e., is something that fits into one item on the + failure stack. */ + + +/* Declarations and macros for re_match_2. */ + +typedef union +{ + PREFIX(fail_stack_elt_t) word; + struct + { + /* This field is one if this group can match the empty string, + zero if not. If not yet determined, `MATCH_NULL_UNSET_VALUE'. */ +# define MATCH_NULL_UNSET_VALUE 3 + unsigned match_null_string_p : 2; + unsigned is_active : 1; + unsigned matched_something : 1; + unsigned ever_matched_something : 1; + } bits; +} PREFIX(register_info_type); + +# ifndef DEFINED_ONCE +# define REG_MATCH_NULL_STRING_P(R) ((R).bits.match_null_string_p) +# define IS_ACTIVE(R) ((R).bits.is_active) +# define MATCHED_SOMETHING(R) ((R).bits.matched_something) +# define EVER_MATCHED_SOMETHING(R) ((R).bits.ever_matched_something) + + +/* Call this when have matched a real character; it sets `matched' flags + for the subexpressions which we are currently inside. Also records + that those subexprs have matched. */ +# define SET_REGS_MATCHED() \ + do \ + { \ + if (!set_regs_matched_done) \ + { \ + active_reg_t r; \ + set_regs_matched_done = 1; \ + for (r = lowest_active_reg; r <= highest_active_reg; r++) \ + { \ + MATCHED_SOMETHING (reg_info[r]) \ + = EVER_MATCHED_SOMETHING (reg_info[r]) \ + = 1; \ + } \ + } \ + } \ + while (0) +# endif /* not DEFINED_ONCE */ + +/* Registers are set to a sentinel when they haven't yet matched. */ +static CHAR_T PREFIX(reg_unset_dummy); +# define REG_UNSET_VALUE (&PREFIX(reg_unset_dummy)) +# define REG_UNSET(e) ((e) == REG_UNSET_VALUE) + +/* Subroutine declarations and macros for regex_compile. */ +static void PREFIX(store_op1) (re_opcode_t op, UCHAR_T *loc, int arg); +static void PREFIX(store_op2) (re_opcode_t op, UCHAR_T *loc, + int arg1, int arg2); +static void PREFIX(insert_op1) (re_opcode_t op, UCHAR_T *loc, + int arg, UCHAR_T *end); +static void PREFIX(insert_op2) (re_opcode_t op, UCHAR_T *loc, + int arg1, int arg2, UCHAR_T *end); +static boolean PREFIX(at_begline_loc_p) (const CHAR_T *pattern, + const CHAR_T *p, + reg_syntax_t syntax); +static boolean PREFIX(at_endline_loc_p) (const CHAR_T *p, + const CHAR_T *pend, + reg_syntax_t syntax); +# ifdef WCHAR +static reg_errcode_t wcs_compile_range (CHAR_T range_start, + const CHAR_T **p_ptr, + const CHAR_T *pend, + char *translate, + reg_syntax_t syntax, + UCHAR_T *b, + CHAR_T *char_set); +static void insert_space (int num, CHAR_T *loc, CHAR_T *end); +# else /* BYTE */ +static reg_errcode_t byte_compile_range (unsigned int range_start, + const char **p_ptr, + const char *pend, + char *translate, + reg_syntax_t syntax, + unsigned char *b); +# endif /* WCHAR */ + +/* Fetch the next character in the uncompiled pattern---translating it + if necessary. Also cast from a signed character in the constant + string passed to us by the user to an unsigned char that we can use + as an array index (in, e.g., `translate'). */ +/* ifdef MBS_SUPPORT, we translate only if character <= 0xff, + because it is impossible to allocate 4GB array for some encodings + which have 4 byte character_set like UCS4. */ +# ifndef PATFETCH +# ifdef WCHAR +# define PATFETCH(c) \ + do {if (p == pend) return REG_EEND; \ + c = (UCHAR_T) *p++; \ + if (translate && (c <= 0xff)) c = (UCHAR_T) translate[c]; \ + } while (0) +# else /* BYTE */ +# define PATFETCH(c) \ + do {if (p == pend) return REG_EEND; \ + c = (unsigned char) *p++; \ + if (translate) c = (unsigned char) translate[c]; \ + } while (0) +# endif /* WCHAR */ +# endif + +/* Fetch the next character in the uncompiled pattern, with no + translation. */ +# define PATFETCH_RAW(c) \ + do {if (p == pend) return REG_EEND; \ + c = (UCHAR_T) *p++; \ + } while (0) + +/* Go backwards one character in the pattern. */ +# define PATUNFETCH p-- + + +/* If `translate' is non-null, return translate[D], else just D. We + cast the subscript to translate because some data is declared as + `char *', to avoid warnings when a string constant is passed. But + when we use a character as a subscript we must make it unsigned. */ +/* ifdef MBS_SUPPORT, we translate only if character <= 0xff, + because it is impossible to allocate 4GB array for some encodings + which have 4 byte character_set like UCS4. */ + +# ifndef TRANSLATE +# ifdef WCHAR +# define TRANSLATE(d) \ + ((translate && ((UCHAR_T) (d)) <= 0xff) \ + ? (char) translate[(unsigned char) (d)] : (d)) +# else /* BYTE */ +# define TRANSLATE(d) \ + (translate ? (char) translate[(unsigned char) (d)] : (char) (d)) +# endif /* WCHAR */ +# endif + + +/* Macros for outputting the compiled pattern into `buffer'. */ + +/* If the buffer isn't allocated when it comes in, use this. */ +# define INIT_BUF_SIZE (32 * sizeof(UCHAR_T)) + +/* Make sure we have at least N more bytes of space in buffer. */ +# ifdef WCHAR +# define GET_BUFFER_SPACE(n) \ + while (((unsigned long)b - (unsigned long)COMPILED_BUFFER_VAR \ + + (n)*sizeof(CHAR_T)) > bufp->allocated) \ + EXTEND_BUFFER () +# else /* BYTE */ +# define GET_BUFFER_SPACE(n) \ + while ((unsigned long) (b - bufp->buffer + (n)) > bufp->allocated) \ + EXTEND_BUFFER () +# endif /* WCHAR */ + +/* Make sure we have one more byte of buffer space and then add C to it. */ +# define BUF_PUSH(c) \ + do { \ + GET_BUFFER_SPACE (1); \ + *b++ = (UCHAR_T) (c); \ + } while (0) + + +/* Ensure we have two more bytes of buffer space and then append C1 and C2. */ +# define BUF_PUSH_2(c1, c2) \ + do { \ + GET_BUFFER_SPACE (2); \ + *b++ = (UCHAR_T) (c1); \ + *b++ = (UCHAR_T) (c2); \ + } while (0) + + +/* As with BUF_PUSH_2, except for three bytes. */ +# define BUF_PUSH_3(c1, c2, c3) \ + do { \ + GET_BUFFER_SPACE (3); \ + *b++ = (UCHAR_T) (c1); \ + *b++ = (UCHAR_T) (c2); \ + *b++ = (UCHAR_T) (c3); \ + } while (0) + +/* Store a jump with opcode OP at LOC to location TO. We store a + relative address offset by the three bytes the jump itself occupies. */ +# define STORE_JUMP(op, loc, to) \ + PREFIX(store_op1) (op, loc, (int) ((to) - (loc) - (1 + OFFSET_ADDRESS_SIZE))) + +/* Likewise, for a two-argument jump. */ +# define STORE_JUMP2(op, loc, to, arg) \ + PREFIX(store_op2) (op, loc, (int) ((to) - (loc) - (1 + OFFSET_ADDRESS_SIZE)), arg) + +/* Like `STORE_JUMP', but for inserting. Assume `b' is the buffer end. */ +# define INSERT_JUMP(op, loc, to) \ + PREFIX(insert_op1) (op, loc, (int) ((to) - (loc) - (1 + OFFSET_ADDRESS_SIZE)), b) + +/* Like `STORE_JUMP2', but for inserting. Assume `b' is the buffer end. */ +# define INSERT_JUMP2(op, loc, to, arg) \ + PREFIX(insert_op2) (op, loc, (int) ((to) - (loc) - (1 + OFFSET_ADDRESS_SIZE)),\ + arg, b) + +/* This is not an arbitrary limit: the arguments which represent offsets + into the pattern are two bytes long. So if 2^16 bytes turns out to + be too small, many things would have to change. */ +/* Any other compiler which, like MSC, has allocation limit below 2^16 + bytes will have to use approach similar to what was done below for + MSC and drop MAX_BUF_SIZE a bit. Otherwise you may end up + reallocating to 0 bytes. Such thing is not going to work too well. + You have been warned!! */ +# ifndef DEFINED_ONCE +# if defined _MSC_VER && !defined WIN32 +/* Microsoft C 16-bit versions limit malloc to approx 65512 bytes. + The REALLOC define eliminates a flurry of conversion warnings, + but is not required. */ +# define MAX_BUF_SIZE 65500L +# define REALLOC(p,s) realloc ((p), (size_t) (s)) +# else +# define MAX_BUF_SIZE (1L << 16) +# define REALLOC(p,s) realloc ((p), (s)) +# endif + +/* Extend the buffer by twice its current size via realloc and + reset the pointers that pointed into the old block to point to the + correct places in the new one. If extending the buffer results in it + being larger than MAX_BUF_SIZE, then flag memory exhausted. */ +# if __BOUNDED_POINTERS__ +# define SET_HIGH_BOUND(P) (__ptrhigh (P) = __ptrlow (P) + bufp->allocated) +# define MOVE_BUFFER_POINTER(P) \ + (__ptrlow (P) += incr, SET_HIGH_BOUND (P), __ptrvalue (P) += incr) +# define ELSE_EXTEND_BUFFER_HIGH_BOUND \ + else \ + { \ + SET_HIGH_BOUND (b); \ + SET_HIGH_BOUND (begalt); \ + if (fixup_alt_jump) \ + SET_HIGH_BOUND (fixup_alt_jump); \ + if (laststart) \ + SET_HIGH_BOUND (laststart); \ + if (pending_exact) \ + SET_HIGH_BOUND (pending_exact); \ + } +# else +# define MOVE_BUFFER_POINTER(P) (P) += incr +# define ELSE_EXTEND_BUFFER_HIGH_BOUND +# endif +# endif /* not DEFINED_ONCE */ + +# ifdef WCHAR +# define EXTEND_BUFFER() \ + do { \ + UCHAR_T *old_buffer = COMPILED_BUFFER_VAR; \ + int wchar_count; \ + if (bufp->allocated + sizeof(UCHAR_T) > MAX_BUF_SIZE) \ + return REG_ESIZE; \ + bufp->allocated <<= 1; \ + if (bufp->allocated > MAX_BUF_SIZE) \ + bufp->allocated = MAX_BUF_SIZE; \ + /* How many characters the new buffer can have? */ \ + wchar_count = bufp->allocated / sizeof(UCHAR_T); \ + if (wchar_count == 0) wchar_count = 1; \ + /* Truncate the buffer to CHAR_T align. */ \ + bufp->allocated = wchar_count * sizeof(UCHAR_T); \ + RETALLOC (COMPILED_BUFFER_VAR, wchar_count, UCHAR_T); \ + bufp->buffer = (char*)COMPILED_BUFFER_VAR; \ + if (COMPILED_BUFFER_VAR == NULL) \ + return REG_ESPACE; \ + /* If the buffer moved, move all the pointers into it. */ \ + if (old_buffer != COMPILED_BUFFER_VAR) \ + { \ + int incr = COMPILED_BUFFER_VAR - old_buffer; \ + MOVE_BUFFER_POINTER (b); \ + MOVE_BUFFER_POINTER (begalt); \ + if (fixup_alt_jump) \ + MOVE_BUFFER_POINTER (fixup_alt_jump); \ + if (laststart) \ + MOVE_BUFFER_POINTER (laststart); \ + if (pending_exact) \ + MOVE_BUFFER_POINTER (pending_exact); \ + } \ + ELSE_EXTEND_BUFFER_HIGH_BOUND \ + } while (0) +# else /* BYTE */ +# define EXTEND_BUFFER() \ + do { \ + UCHAR_T *old_buffer = COMPILED_BUFFER_VAR; \ + if (bufp->allocated == MAX_BUF_SIZE) \ + return REG_ESIZE; \ + bufp->allocated <<= 1; \ + if (bufp->allocated > MAX_BUF_SIZE) \ + bufp->allocated = MAX_BUF_SIZE; \ + bufp->buffer = (UCHAR_T *) REALLOC (COMPILED_BUFFER_VAR, \ + bufp->allocated); \ + if (COMPILED_BUFFER_VAR == NULL) \ + return REG_ESPACE; \ + /* If the buffer moved, move all the pointers into it. */ \ + if (old_buffer != COMPILED_BUFFER_VAR) \ + { \ + int incr = COMPILED_BUFFER_VAR - old_buffer; \ + MOVE_BUFFER_POINTER (b); \ + MOVE_BUFFER_POINTER (begalt); \ + if (fixup_alt_jump) \ + MOVE_BUFFER_POINTER (fixup_alt_jump); \ + if (laststart) \ + MOVE_BUFFER_POINTER (laststart); \ + if (pending_exact) \ + MOVE_BUFFER_POINTER (pending_exact); \ + } \ + ELSE_EXTEND_BUFFER_HIGH_BOUND \ + } while (0) +# endif /* WCHAR */ + +# ifndef DEFINED_ONCE +/* Since we have one byte reserved for the register number argument to + {start,stop}_memory, the maximum number of groups we can report + things about is what fits in that byte. */ +# define MAX_REGNUM 255 + +/* But patterns can have more than `MAX_REGNUM' registers. We just + ignore the excess. */ +typedef unsigned regnum_t; + + +/* Macros for the compile stack. */ + +/* Since offsets can go either forwards or backwards, this type needs to + be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1. */ +/* int may be not enough when sizeof(int) == 2. */ +typedef long pattern_offset_t; + +typedef struct +{ + pattern_offset_t begalt_offset; + pattern_offset_t fixup_alt_jump; + pattern_offset_t inner_group_offset; + pattern_offset_t laststart_offset; + regnum_t regnum; +} compile_stack_elt_t; + + +typedef struct +{ + compile_stack_elt_t *stack; + unsigned size; + unsigned avail; /* Offset of next open position. */ +} compile_stack_type; + + +# define INIT_COMPILE_STACK_SIZE 32 + +# define COMPILE_STACK_EMPTY (compile_stack.avail == 0) +# define COMPILE_STACK_FULL (compile_stack.avail == compile_stack.size) + +/* The next available element. */ +# define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail]) + +# endif /* not DEFINED_ONCE */ + +/* Set the bit for character C in a list. */ +# ifndef DEFINED_ONCE +# define SET_LIST_BIT(c) \ + (b[((unsigned char) (c)) / BYTEWIDTH] \ + |= 1 << (((unsigned char) c) % BYTEWIDTH)) +# endif /* DEFINED_ONCE */ + +/* Get the next unsigned number in the uncompiled pattern. */ +# define GET_UNSIGNED_NUMBER(num) \ + { \ + while (p != pend) \ + { \ + PATFETCH (c); \ + if (c < '0' || c > '9') \ + break; \ + if (num <= RE_DUP_MAX) \ + { \ + if (num < 0) \ + num = 0; \ + num = num * 10 + c - '0'; \ + } \ + } \ + } + +# ifndef DEFINED_ONCE +# if defined _LIBC || WIDE_CHAR_SUPPORT +/* The GNU C library provides support for user-defined character classes + and the functions from ISO C amendement 1. */ +# ifdef CHARCLASS_NAME_MAX +# define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX +# else +/* This shouldn't happen but some implementation might still have this + problem. Use a reasonable default value. */ +# define CHAR_CLASS_MAX_LENGTH 256 +# endif + +# ifdef _LIBC +# define IS_CHAR_CLASS(string) __wctype (string) +# else +# define IS_CHAR_CLASS(string) wctype (string) +# endif +# else +# define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */ + +# define IS_CHAR_CLASS(string) \ + (STREQ (string, "alpha") || STREQ (string, "upper") \ + || STREQ (string, "lower") || STREQ (string, "digit") \ + || STREQ (string, "alnum") || STREQ (string, "xdigit") \ + || STREQ (string, "space") || STREQ (string, "print") \ + || STREQ (string, "punct") || STREQ (string, "graph") \ + || STREQ (string, "cntrl") || STREQ (string, "blank")) +# endif +# endif /* DEFINED_ONCE */ + +# ifndef MATCH_MAY_ALLOCATE + +/* If we cannot allocate large objects within re_match_2_internal, + we make the fail stack and register vectors global. + The fail stack, we grow to the maximum size when a regexp + is compiled. + The register vectors, we adjust in size each time we + compile a regexp, according to the number of registers it needs. */ + +static PREFIX(fail_stack_type) fail_stack; + +/* Size with which the following vectors are currently allocated. + That is so we can make them bigger as needed, + but never make them smaller. */ +# ifdef DEFINED_ONCE +static int regs_allocated_size; + +static const char ** regstart, ** regend; +static const char ** old_regstart, ** old_regend; +static const char **best_regstart, **best_regend; +static const char **reg_dummy; +# endif /* DEFINED_ONCE */ + +static PREFIX(register_info_type) *PREFIX(reg_info); +static PREFIX(register_info_type) *PREFIX(reg_info_dummy); + +/* Make the register vectors big enough for NUM_REGS registers, + but don't make them smaller. */ + +static void +PREFIX(regex_grow_registers) (int num_regs) +{ + if (num_regs > regs_allocated_size) + { + RETALLOC_IF (regstart, num_regs, const char *); + RETALLOC_IF (regend, num_regs, const char *); + RETALLOC_IF (old_regstart, num_regs, const char *); + RETALLOC_IF (old_regend, num_regs, const char *); + RETALLOC_IF (best_regstart, num_regs, const char *); + RETALLOC_IF (best_regend, num_regs, const char *); + RETALLOC_IF (PREFIX(reg_info), num_regs, PREFIX(register_info_type)); + RETALLOC_IF (reg_dummy, num_regs, const char *); + RETALLOC_IF (PREFIX(reg_info_dummy), num_regs, PREFIX(register_info_type)); + + regs_allocated_size = num_regs; + } +} + +# endif /* not MATCH_MAY_ALLOCATE */ + +# ifndef DEFINED_ONCE +static boolean group_in_compile_stack (compile_stack_type compile_stack, + regnum_t regnum); +# endif /* not DEFINED_ONCE */ + +/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX. + Returns one of error codes defined in `regex.h', or zero for success. + + Assumes the `allocated' (and perhaps `buffer') and `translate' + fields are set in BUFP on entry. + + If it succeeds, results are put in BUFP (if it returns an error, the + contents of BUFP are undefined): + `buffer' is the compiled pattern; + `syntax' is set to SYNTAX; + `used' is set to the length of the compiled pattern; + `fastmap_accurate' is zero; + `re_nsub' is the number of subexpressions in PATTERN; + `not_bol' and `not_eol' are zero; + + The `fastmap' and `newline_anchor' fields are neither + examined nor set. */ + +/* Return, freeing storage we allocated. */ +# ifdef WCHAR +# define FREE_STACK_RETURN(value) \ + return (free(pattern), free(mbs_offset), free(is_binary), free (compile_stack.stack), value) +# else +# define FREE_STACK_RETURN(value) \ + return (free (compile_stack.stack), value) +# endif /* WCHAR */ + +static reg_errcode_t +PREFIX(regex_compile) (const char *ARG_PREFIX(pattern), + size_t ARG_PREFIX(size), reg_syntax_t syntax, + struct re_pattern_buffer *bufp) +{ + /* We fetch characters from PATTERN here. Even though PATTERN is + `char *' (i.e., signed), we declare these variables as unsigned, so + they can be reliably used as array indices. */ + register UCHAR_T c, c1; + +#ifdef WCHAR + /* A temporary space to keep wchar_t pattern and compiled pattern. */ + CHAR_T *pattern, *COMPILED_BUFFER_VAR; + size_t size; + /* offset buffer for optimization. See convert_mbs_to_wc. */ + int *mbs_offset = NULL; + /* It hold whether each wchar_t is binary data or not. */ + char *is_binary = NULL; + /* A flag whether exactn is handling binary data or not. */ + char is_exactn_bin = FALSE; +#endif /* WCHAR */ + + /* A random temporary spot in PATTERN. */ + const CHAR_T *p1; + + /* Points to the end of the buffer, where we should append. */ + register UCHAR_T *b; + + /* Keeps track of unclosed groups. */ + compile_stack_type compile_stack; + + /* Points to the current (ending) position in the pattern. */ +#ifdef WCHAR + const CHAR_T *p; + const CHAR_T *pend; +#else /* BYTE */ + const CHAR_T *p = pattern; + const CHAR_T *pend = pattern + size; +#endif /* WCHAR */ + + /* How to translate the characters in the pattern. */ + RE_TRANSLATE_TYPE translate = bufp->translate; + + /* Address of the count-byte of the most recently inserted `exactn' + command. This makes it possible to tell if a new exact-match + character can be added to that command or if the character requires + a new `exactn' command. */ + UCHAR_T *pending_exact = 0; + + /* Address of start of the most recently finished expression. + This tells, e.g., postfix * where to find the start of its + operand. Reset at the beginning of groups and alternatives. */ + UCHAR_T *laststart = 0; + + /* Address of beginning of regexp, or inside of last group. */ + UCHAR_T *begalt; + + /* Address of the place where a forward jump should go to the end of + the containing expression. Each alternative of an `or' -- except the + last -- ends with a forward jump of this sort. */ + UCHAR_T *fixup_alt_jump = 0; + + /* Counts open-groups as they are encountered. Remembered for the + matching close-group on the compile stack, so the same register + number is put in the stop_memory as the start_memory. */ + regnum_t regnum = 0; + +#ifdef WCHAR + /* Initialize the wchar_t PATTERN and offset_buffer. */ + p = pend = pattern = TALLOC(csize + 1, CHAR_T); + mbs_offset = TALLOC(csize + 1, int); + is_binary = TALLOC(csize + 1, char); + if (pattern == NULL || mbs_offset == NULL || is_binary == NULL) + { + free(pattern); + free(mbs_offset); + free(is_binary); + return REG_ESPACE; + } + pattern[csize] = L'\0'; /* sentinel */ + size = convert_mbs_to_wcs(pattern, cpattern, csize, mbs_offset, is_binary); + pend = p + size; + if (size < 0) + { + free(pattern); + free(mbs_offset); + free(is_binary); + return REG_BADPAT; + } +#endif + +#ifdef DEBUG + DEBUG_PRINT1 ("\nCompiling pattern: "); + if (debug) + { + unsigned debug_count; + + for (debug_count = 0; debug_count < size; debug_count++) + PUT_CHAR (pattern[debug_count]); + putchar ('\n'); + } +#endif /* DEBUG */ + + /* Initialize the compile stack. */ + compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t); + if (compile_stack.stack == NULL) + { +#ifdef WCHAR + free(pattern); + free(mbs_offset); + free(is_binary); +#endif + return REG_ESPACE; + } + + compile_stack.size = INIT_COMPILE_STACK_SIZE; + compile_stack.avail = 0; + + /* Initialize the pattern buffer. */ + bufp->syntax = syntax; + bufp->fastmap_accurate = 0; + bufp->not_bol = bufp->not_eol = 0; + + /* Set `used' to zero, so that if we return an error, the pattern + printer (for debugging) will think there's no pattern. We reset it + at the end. */ + bufp->used = 0; + + /* Always count groups, whether or not bufp->no_sub is set. */ + bufp->re_nsub = 0; + +#if !defined emacs && !defined SYNTAX_TABLE + /* Initialize the syntax table. */ + init_syntax_once (); +#endif + + if (bufp->allocated == 0) + { + if (bufp->buffer) + { /* If zero allocated, but buffer is non-null, try to realloc + enough space. This loses if buffer's address is bogus, but + that is the user's responsibility. */ +#ifdef WCHAR + /* Free bufp->buffer and allocate an array for wchar_t pattern + buffer. */ + free(bufp->buffer); + COMPILED_BUFFER_VAR = TALLOC (INIT_BUF_SIZE/sizeof(UCHAR_T), + UCHAR_T); +#else + RETALLOC (COMPILED_BUFFER_VAR, INIT_BUF_SIZE, UCHAR_T); +#endif /* WCHAR */ + } + else + { /* Caller did not allocate a buffer. Do it for them. */ + COMPILED_BUFFER_VAR = TALLOC (INIT_BUF_SIZE / sizeof(UCHAR_T), + UCHAR_T); + } + + if (!COMPILED_BUFFER_VAR) FREE_STACK_RETURN (REG_ESPACE); +#ifdef WCHAR + bufp->buffer = (char*)COMPILED_BUFFER_VAR; +#endif /* WCHAR */ + bufp->allocated = INIT_BUF_SIZE; + } +#ifdef WCHAR + else + COMPILED_BUFFER_VAR = (UCHAR_T*) bufp->buffer; +#endif + + begalt = b = COMPILED_BUFFER_VAR; + + /* Loop through the uncompiled pattern until we're at the end. */ + while (p != pend) + { + PATFETCH (c); + + switch (c) + { + case '^': + { + if ( /* If at start of pattern, it's an operator. */ + p == pattern + 1 + /* If context independent, it's an operator. */ + || syntax & RE_CONTEXT_INDEP_ANCHORS + /* Otherwise, depends on what's come before. */ + || PREFIX(at_begline_loc_p) (pattern, p, syntax)) + BUF_PUSH (begline); + else + goto normal_char; + } + break; + + + case '$': + { + if ( /* If at end of pattern, it's an operator. */ + p == pend + /* If context independent, it's an operator. */ + || syntax & RE_CONTEXT_INDEP_ANCHORS + /* Otherwise, depends on what's next. */ + || PREFIX(at_endline_loc_p) (p, pend, syntax)) + BUF_PUSH (endline); + else + goto normal_char; + } + break; + + + case '+': + case '?': + if ((syntax & RE_BK_PLUS_QM) + || (syntax & RE_LIMITED_OPS)) + goto normal_char; + handle_plus: + case '*': + /* If there is no previous pattern... */ + if (!laststart) + { + if (syntax & RE_CONTEXT_INVALID_OPS) + FREE_STACK_RETURN (REG_BADRPT); + else if (!(syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + } + + { + /* Are we optimizing this jump? */ + boolean keep_string_p = false; + + /* 1 means zero (many) matches is allowed. */ + char zero_times_ok = 0, many_times_ok = 0; + + /* If there is a sequence of repetition chars, collapse it + down to just one (the right one). We can't combine + interval operators with these because of, e.g., `a{2}*', + which should only match an even number of `a's. */ + + for (;;) + { + zero_times_ok |= c != '+'; + many_times_ok |= c != '?'; + + if (p == pend) + break; + + PATFETCH (c); + + if (c == '*' + || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?'))) + ; + + else if (syntax & RE_BK_PLUS_QM && c == '\\') + { + if (p == pend) FREE_STACK_RETURN (REG_EESCAPE); + + PATFETCH (c1); + if (!(c1 == '+' || c1 == '?')) + { + PATUNFETCH; + PATUNFETCH; + break; + } + + c = c1; + } + else + { + PATUNFETCH; + break; + } + + /* If we get here, we found another repeat character. */ + } + + /* Star, etc. applied to an empty pattern is equivalent + to an empty pattern. */ + if (!laststart) + break; + + /* Now we know whether or not zero matches is allowed + and also whether or not two or more matches is allowed. */ + if (many_times_ok) + { /* More than one repetition is allowed, so put in at the + end a backward relative jump from `b' to before the next + jump we're going to put in below (which jumps from + laststart to after this jump). + + But if we are at the `*' in the exact sequence `.*\n', + insert an unconditional jump backwards to the ., + instead of the beginning of the loop. This way we only + push a failure point once, instead of every time + through the loop. */ + assert (p - 1 > pattern); + + /* Allocate the space for the jump. */ + GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE); + + /* We know we are not at the first character of the pattern, + because laststart was nonzero. And we've already + incremented `p', by the way, to be the character after + the `*'. Do we have to do something analogous here + for null bytes, because of RE_DOT_NOT_NULL? */ + if (TRANSLATE (*(p - 2)) == TRANSLATE ('.') + && zero_times_ok + && p < pend && TRANSLATE (*p) == TRANSLATE ('\n') + && !(syntax & RE_DOT_NEWLINE)) + { /* We have .*\n. */ + STORE_JUMP (jump, b, laststart); + keep_string_p = true; + } + else + /* Anything else. */ + STORE_JUMP (maybe_pop_jump, b, laststart - + (1 + OFFSET_ADDRESS_SIZE)); + + /* We've added more stuff to the buffer. */ + b += 1 + OFFSET_ADDRESS_SIZE; + } + + /* On failure, jump from laststart to b + 3, which will be the + end of the buffer after this jump is inserted. */ + /* ifdef WCHAR, 'b + 1 + OFFSET_ADDRESS_SIZE' instead of + 'b + 3'. */ + GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE); + INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump + : on_failure_jump, + laststart, b + 1 + OFFSET_ADDRESS_SIZE); + pending_exact = 0; + b += 1 + OFFSET_ADDRESS_SIZE; + + if (!zero_times_ok) + { + /* At least one repetition is required, so insert a + `dummy_failure_jump' before the initial + `on_failure_jump' instruction of the loop. This + effects a skip over that instruction the first time + we hit that loop. */ + GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE); + INSERT_JUMP (dummy_failure_jump, laststart, laststart + + 2 + 2 * OFFSET_ADDRESS_SIZE); + b += 1 + OFFSET_ADDRESS_SIZE; + } + } + break; + + + case '.': + laststart = b; + BUF_PUSH (anychar); + break; + + + case '[': + { + boolean had_char_class = false; +#ifdef WCHAR + CHAR_T range_start = 0xffffffff; +#else + unsigned int range_start = 0xffffffff; +#endif + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + +#ifdef WCHAR + /* We assume a charset(_not) structure as a wchar_t array. + charset[0] = (re_opcode_t) charset(_not) + charset[1] = l (= length of char_classes) + charset[2] = m (= length of collating_symbols) + charset[3] = n (= length of equivalence_classes) + charset[4] = o (= length of char_ranges) + charset[5] = p (= length of chars) + + charset[6] = char_class (wctype_t) + charset[6+CHAR_CLASS_SIZE] = char_class (wctype_t) + ... + charset[l+5] = char_class (wctype_t) + + charset[l+6] = collating_symbol (wchar_t) + ... + charset[l+m+5] = collating_symbol (wchar_t) + ifdef _LIBC we use the index if + _NL_COLLATE_SYMB_EXTRAMB instead of + wchar_t string. + + charset[l+m+6] = equivalence_classes (wchar_t) + ... + charset[l+m+n+5] = equivalence_classes (wchar_t) + ifdef _LIBC we use the index in + _NL_COLLATE_WEIGHT instead of + wchar_t string. + + charset[l+m+n+6] = range_start + charset[l+m+n+7] = range_end + ... + charset[l+m+n+2o+4] = range_start + charset[l+m+n+2o+5] = range_end + ifdef _LIBC we use the value looked up + in _NL_COLLATE_COLLSEQ instead of + wchar_t character. + + charset[l+m+n+2o+6] = char + ... + charset[l+m+n+2o+p+5] = char + + */ + + /* We need at least 6 spaces: the opcode, the length of + char_classes, the length of collating_symbols, the length of + equivalence_classes, the length of char_ranges, the length of + chars. */ + GET_BUFFER_SPACE (6); + + /* Save b as laststart. And We use laststart as the pointer + to the first element of the charset here. + In other words, laststart[i] indicates charset[i]. */ + laststart = b; + + /* We test `*p == '^' twice, instead of using an if + statement, so we only need one BUF_PUSH. */ + BUF_PUSH (*p == '^' ? charset_not : charset); + if (*p == '^') + p++; + + /* Push the length of char_classes, the length of + collating_symbols, the length of equivalence_classes, the + length of char_ranges and the length of chars. */ + BUF_PUSH_3 (0, 0, 0); + BUF_PUSH_2 (0, 0); + + /* Remember the first position in the bracket expression. */ + p1 = p; + + /* charset_not matches newline according to a syntax bit. */ + if ((re_opcode_t) b[-6] == charset_not + && (syntax & RE_HAT_LISTS_NOT_NEWLINE)) + { + BUF_PUSH('\n'); + laststart[5]++; /* Update the length of characters */ + } + + /* Read in characters and ranges, setting map bits. */ + for (;;) + { + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + PATFETCH (c); + + /* \ might escape characters inside [...] and [^...]. */ + if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\') + { + if (p == pend) FREE_STACK_RETURN (REG_EESCAPE); + + PATFETCH (c1); + BUF_PUSH(c1); + laststart[5]++; /* Update the length of chars */ + range_start = c1; + continue; + } + + /* Could be the end of the bracket expression. If it's + not (i.e., when the bracket expression is `[]' so + far), the ']' character bit gets set way below. */ + if (c == ']' && p != p1 + 1) + break; + + /* Look ahead to see if it's a range when the last thing + was a character class. */ + if (had_char_class && c == '-' && *p != ']') + FREE_STACK_RETURN (REG_ERANGE); + + /* Look ahead to see if it's a range when the last thing + was a character: if this is a hyphen not at the + beginning or the end of a list, then it's the range + operator. */ + if (c == '-' + && !(p - 2 >= pattern && p[-2] == '[') + && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^') + && *p != ']') + { + reg_errcode_t ret; + /* Allocate the space for range_start and range_end. */ + GET_BUFFER_SPACE (2); + /* Update the pointer to indicate end of buffer. */ + b += 2; + ret = wcs_compile_range (range_start, &p, pend, translate, + syntax, b, laststart); + if (ret != REG_NOERROR) FREE_STACK_RETURN (ret); + range_start = 0xffffffff; + } + else if (p[0] == '-' && p[1] != ']') + { /* This handles ranges made up of characters only. */ + reg_errcode_t ret; + + /* Move past the `-'. */ + PATFETCH (c1); + /* Allocate the space for range_start and range_end. */ + GET_BUFFER_SPACE (2); + /* Update the pointer to indicate end of buffer. */ + b += 2; + ret = wcs_compile_range (c, &p, pend, translate, syntax, b, + laststart); + if (ret != REG_NOERROR) FREE_STACK_RETURN (ret); + range_start = 0xffffffff; + } + + /* See if we're at the beginning of a possible character + class. */ + else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':') + { /* Leave room for the null. */ + char str[CHAR_CLASS_MAX_LENGTH + 1]; + + PATFETCH (c); + c1 = 0; + + /* If pattern is `[[:'. */ + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + for (;;) + { + PATFETCH (c); + if ((c == ':' && *p == ']') || p == pend) + break; + if (c1 < CHAR_CLASS_MAX_LENGTH) + str[c1++] = c; + else + /* This is in any case an invalid class name. */ + str[0] = '\0'; + } + str[c1] = '\0'; + + /* If isn't a word bracketed by `[:' and `:]': + undo the ending character, the letters, and leave + the leading `:' and `[' (but store them as character). */ + if (c == ':' && *p == ']') + { + wctype_t wt; + uintptr_t alignedp; + + /* Query the character class as wctype_t. */ + wt = IS_CHAR_CLASS (str); + if (wt == 0) + FREE_STACK_RETURN (REG_ECTYPE); + + /* Throw away the ] at the end of the character + class. */ + PATFETCH (c); + + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + /* Allocate the space for character class. */ + GET_BUFFER_SPACE(CHAR_CLASS_SIZE); + /* Update the pointer to indicate end of buffer. */ + b += CHAR_CLASS_SIZE; + /* Move data which follow character classes + not to violate the data. */ + insert_space(CHAR_CLASS_SIZE, + laststart + 6 + laststart[1], + b - 1); + alignedp = ((uintptr_t)(laststart + 6 + laststart[1]) + + __alignof__(wctype_t) - 1) + & ~(uintptr_t)(__alignof__(wctype_t) - 1); + /* Store the character class. */ + *((wctype_t*)alignedp) = wt; + /* Update length of char_classes */ + laststart[1] += CHAR_CLASS_SIZE; + + had_char_class = true; + } + else + { + c1++; + while (c1--) + PATUNFETCH; + BUF_PUSH ('['); + BUF_PUSH (':'); + laststart[5] += 2; /* Update the length of characters */ + range_start = ':'; + had_char_class = false; + } + } + else if (syntax & RE_CHAR_CLASSES && c == '[' && (*p == '=' + || *p == '.')) + { + CHAR_T str[128]; /* Should be large enough. */ + CHAR_T delim = *p; /* '=' or '.' */ +# ifdef _LIBC + uint32_t nrules = + _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); +# endif + PATFETCH (c); + c1 = 0; + + /* If pattern is `[[=' or '[[.'. */ + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + for (;;) + { + PATFETCH (c); + if ((c == delim && *p == ']') || p == pend) + break; + if (c1 < sizeof (str) - 1) + str[c1++] = c; + else + /* This is in any case an invalid class name. */ + str[0] = '\0'; + } + str[c1] = '\0'; + + if (c == delim && *p == ']' && str[0] != '\0') + { + unsigned int i, offset; + /* If we have no collation data we use the default + collation in which each character is in a class + by itself. It also means that ASCII is the + character set and therefore we cannot have character + with more than one byte in the multibyte + representation. */ + + /* If not defined _LIBC, we push the name and + `\0' for the sake of matching performance. */ + int datasize = c1 + 1; + +# ifdef _LIBC + int32_t idx = 0; + if (nrules == 0) +# endif + { + if (c1 != 1) + FREE_STACK_RETURN (REG_ECOLLATE); + } +# ifdef _LIBC + else + { + const int32_t *table; + const int32_t *weights; + const int32_t *extra; + const int32_t *indirect; + wint_t *cp; + + /* This #include defines a local function! */ +# include + + if(delim == '=') + { + /* We push the index for equivalence class. */ + cp = (wint_t*)str; + + table = (const int32_t *) + _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_TABLEWC); + weights = (const int32_t *) + _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_WEIGHTWC); + extra = (const int32_t *) + _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_EXTRAWC); + indirect = (const int32_t *) + _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_INDIRECTWC); + + idx = findidx ((const wint_t**)&cp); + if (idx == 0 || cp < (wint_t*) str + c1) + /* This is no valid character. */ + FREE_STACK_RETURN (REG_ECOLLATE); + + str[0] = (wchar_t)idx; + } + else /* delim == '.' */ + { + /* We push collation sequence value + for collating symbol. */ + int32_t table_size; + const int32_t *symb_table; + const unsigned char *extra; + int32_t idx; + int32_t elem; + int32_t second; + int32_t hash; + char char_str[c1]; + + /* We have to convert the name to a single-byte + string. This is possible since the names + consist of ASCII characters and the internal + representation is UCS4. */ + for (i = 0; i < c1; ++i) + char_str[i] = str[i]; + + table_size = + _NL_CURRENT_WORD (LC_COLLATE, + _NL_COLLATE_SYMB_HASH_SIZEMB); + symb_table = (const int32_t *) + _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_SYMB_TABLEMB); + extra = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_SYMB_EXTRAMB); + + /* Locate the character in the hashing table. */ + hash = elem_hash (char_str, c1); + + idx = 0; + elem = hash % table_size; + second = hash % (table_size - 2); + while (symb_table[2 * elem] != 0) + { + /* First compare the hashing value. */ + if (symb_table[2 * elem] == hash + && c1 == extra[symb_table[2 * elem + 1]] + && memcmp (char_str, + &extra[symb_table[2 * elem + 1] + + 1], c1) == 0) + { + /* Yep, this is the entry. */ + idx = symb_table[2 * elem + 1]; + idx += 1 + extra[idx]; + break; + } + + /* Next entry. */ + elem += second; + } + + if (symb_table[2 * elem] != 0) + { + /* Compute the index of the byte sequence + in the table. */ + idx += 1 + extra[idx]; + /* Adjust for the alignment. */ + idx = (idx + 3) & ~3; + + str[0] = (wchar_t) idx + 4; + } + else if (symb_table[2 * elem] == 0 && c1 == 1) + { + /* No valid character. Match it as a + single byte character. */ + had_char_class = false; + BUF_PUSH(str[0]); + /* Update the length of characters */ + laststart[5]++; + range_start = str[0]; + + /* Throw away the ] at the end of the + collating symbol. */ + PATFETCH (c); + /* exit from the switch block. */ + continue; + } + else + FREE_STACK_RETURN (REG_ECOLLATE); + } + datasize = 1; + } +# endif + /* Throw away the ] at the end of the equivalence + class (or collating symbol). */ + PATFETCH (c); + + /* Allocate the space for the equivalence class + (or collating symbol) (and '\0' if needed). */ + GET_BUFFER_SPACE(datasize); + /* Update the pointer to indicate end of buffer. */ + b += datasize; + + if (delim == '=') + { /* equivalence class */ + /* Calculate the offset of char_ranges, + which is next to equivalence_classes. */ + offset = laststart[1] + laststart[2] + + laststart[3] +6; + /* Insert space. */ + insert_space(datasize, laststart + offset, b - 1); + + /* Write the equivalence_class and \0. */ + for (i = 0 ; i < datasize ; i++) + laststart[offset + i] = str[i]; + + /* Update the length of equivalence_classes. */ + laststart[3] += datasize; + had_char_class = true; + } + else /* delim == '.' */ + { /* collating symbol */ + /* Calculate the offset of the equivalence_classes, + which is next to collating_symbols. */ + offset = laststart[1] + laststart[2] + 6; + /* Insert space and write the collationg_symbol + and \0. */ + insert_space(datasize, laststart + offset, b-1); + for (i = 0 ; i < datasize ; i++) + laststart[offset + i] = str[i]; + + /* In re_match_2_internal if range_start < -1, we + assume -range_start is the offset of the + collating symbol which is specified as + the character of the range start. So we assign + -(laststart[1] + laststart[2] + 6) to + range_start. */ + range_start = -(laststart[1] + laststart[2] + 6); + /* Update the length of collating_symbol. */ + laststart[2] += datasize; + had_char_class = false; + } + } + else + { + c1++; + while (c1--) + PATUNFETCH; + BUF_PUSH ('['); + BUF_PUSH (delim); + laststart[5] += 2; /* Update the length of characters */ + range_start = delim; + had_char_class = false; + } + } + else + { + had_char_class = false; + BUF_PUSH(c); + laststart[5]++; /* Update the length of characters */ + range_start = c; + } + } + +#else /* BYTE */ + /* Ensure that we have enough space to push a charset: the + opcode, the length count, and the bitset; 34 bytes in all. */ + GET_BUFFER_SPACE (34); + + laststart = b; + + /* We test `*p == '^' twice, instead of using an if + statement, so we only need one BUF_PUSH. */ + BUF_PUSH (*p == '^' ? charset_not : charset); + if (*p == '^') + p++; + + /* Remember the first position in the bracket expression. */ + p1 = p; + + /* Push the number of bytes in the bitmap. */ + BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH); + + /* Clear the whole map. */ + bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH); + + /* charset_not matches newline according to a syntax bit. */ + if ((re_opcode_t) b[-2] == charset_not + && (syntax & RE_HAT_LISTS_NOT_NEWLINE)) + SET_LIST_BIT ('\n'); + + /* Read in characters and ranges, setting map bits. */ + for (;;) + { + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + PATFETCH (c); + + /* \ might escape characters inside [...] and [^...]. */ + if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\') + { + if (p == pend) FREE_STACK_RETURN (REG_EESCAPE); + + PATFETCH (c1); + SET_LIST_BIT (c1); + range_start = c1; + continue; + } + + /* Could be the end of the bracket expression. If it's + not (i.e., when the bracket expression is `[]' so + far), the ']' character bit gets set way below. */ + if (c == ']' && p != p1 + 1) + break; + + /* Look ahead to see if it's a range when the last thing + was a character class. */ + if (had_char_class && c == '-' && *p != ']') + FREE_STACK_RETURN (REG_ERANGE); + + /* Look ahead to see if it's a range when the last thing + was a character: if this is a hyphen not at the + beginning or the end of a list, then it's the range + operator. */ + if (c == '-' + && !(p - 2 >= pattern && p[-2] == '[') + && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^') + && *p != ']') + { + reg_errcode_t ret + = byte_compile_range (range_start, &p, pend, translate, + syntax, b); + if (ret != REG_NOERROR) FREE_STACK_RETURN (ret); + range_start = 0xffffffff; + } + + else if (p[0] == '-' && p[1] != ']') + { /* This handles ranges made up of characters only. */ + reg_errcode_t ret; + + /* Move past the `-'. */ + PATFETCH (c1); + + ret = byte_compile_range (c, &p, pend, translate, syntax, b); + if (ret != REG_NOERROR) FREE_STACK_RETURN (ret); + range_start = 0xffffffff; + } + + /* See if we're at the beginning of a possible character + class. */ + + else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':') + { /* Leave room for the null. */ + char str[CHAR_CLASS_MAX_LENGTH + 1]; + + PATFETCH (c); + c1 = 0; + + /* If pattern is `[[:'. */ + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + for (;;) + { + PATFETCH (c); + if ((c == ':' && *p == ']') || p == pend) + break; + if (c1 < CHAR_CLASS_MAX_LENGTH) + str[c1++] = c; + else + /* This is in any case an invalid class name. */ + str[0] = '\0'; + } + str[c1] = '\0'; + + /* If isn't a word bracketed by `[:' and `:]': + undo the ending character, the letters, and leave + the leading `:' and `[' (but set bits for them). */ + if (c == ':' && *p == ']') + { +# if defined _LIBC || WIDE_CHAR_SUPPORT + boolean is_lower = STREQ (str, "lower"); + boolean is_upper = STREQ (str, "upper"); + wctype_t wt; + int ch; + + wt = IS_CHAR_CLASS (str); + if (wt == 0) + FREE_STACK_RETURN (REG_ECTYPE); + + /* Throw away the ] at the end of the character + class. */ + PATFETCH (c); + + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + for (ch = 0; ch < 1 << BYTEWIDTH; ++ch) + { +# ifdef _LIBC + if (__iswctype (__btowc (ch), wt)) + SET_LIST_BIT (ch); +# else + if (iswctype (btowc (ch), wt)) + SET_LIST_BIT (ch); +# endif + + if (translate && (is_upper || is_lower) + && (ISUPPER (ch) || ISLOWER (ch))) + SET_LIST_BIT (ch); + } + + had_char_class = true; +# else + int ch; + boolean is_alnum = STREQ (str, "alnum"); + boolean is_alpha = STREQ (str, "alpha"); + boolean is_blank = STREQ (str, "blank"); + boolean is_cntrl = STREQ (str, "cntrl"); + boolean is_digit = STREQ (str, "digit"); + boolean is_graph = STREQ (str, "graph"); + boolean is_lower = STREQ (str, "lower"); + boolean is_print = STREQ (str, "print"); + boolean is_punct = STREQ (str, "punct"); + boolean is_space = STREQ (str, "space"); + boolean is_upper = STREQ (str, "upper"); + boolean is_xdigit = STREQ (str, "xdigit"); + + if (!IS_CHAR_CLASS (str)) + FREE_STACK_RETURN (REG_ECTYPE); + + /* Throw away the ] at the end of the character + class. */ + PATFETCH (c); + + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + for (ch = 0; ch < 1 << BYTEWIDTH; ch++) + { + /* This was split into 3 if's to + avoid an arbitrary limit in some compiler. */ + if ( (is_alnum && ISALNUM (ch)) + || (is_alpha && ISALPHA (ch)) + || (is_blank && ISBLANK (ch)) + || (is_cntrl && ISCNTRL (ch))) + SET_LIST_BIT (ch); + if ( (is_digit && ISDIGIT (ch)) + || (is_graph && ISGRAPH (ch)) + || (is_lower && ISLOWER (ch)) + || (is_print && ISPRINT (ch))) + SET_LIST_BIT (ch); + if ( (is_punct && ISPUNCT (ch)) + || (is_space && ISSPACE (ch)) + || (is_upper && ISUPPER (ch)) + || (is_xdigit && ISXDIGIT (ch))) + SET_LIST_BIT (ch); + if ( translate && (is_upper || is_lower) + && (ISUPPER (ch) || ISLOWER (ch))) + SET_LIST_BIT (ch); + } + had_char_class = true; +# endif /* libc || wctype.h */ + } + else + { + c1++; + while (c1--) + PATUNFETCH; + SET_LIST_BIT ('['); + SET_LIST_BIT (':'); + range_start = ':'; + had_char_class = false; + } + } + else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == '=') + { + unsigned char str[MB_LEN_MAX + 1]; +# ifdef _LIBC + uint32_t nrules = + _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); +# endif + + PATFETCH (c); + c1 = 0; + + /* If pattern is `[[='. */ + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + for (;;) + { + PATFETCH (c); + if ((c == '=' && *p == ']') || p == pend) + break; + if (c1 < MB_LEN_MAX) + str[c1++] = c; + else + /* This is in any case an invalid class name. */ + str[0] = '\0'; + } + str[c1] = '\0'; + + if (c == '=' && *p == ']' && str[0] != '\0') + { + /* If we have no collation data we use the default + collation in which each character is in a class + by itself. It also means that ASCII is the + character set and therefore we cannot have character + with more than one byte in the multibyte + representation. */ +# ifdef _LIBC + if (nrules == 0) +# endif + { + if (c1 != 1) + FREE_STACK_RETURN (REG_ECOLLATE); + + /* Throw away the ] at the end of the equivalence + class. */ + PATFETCH (c); + + /* Set the bit for the character. */ + SET_LIST_BIT (str[0]); + } +# ifdef _LIBC + else + { + /* Try to match the byte sequence in `str' against + those known to the collate implementation. + First find out whether the bytes in `str' are + actually from exactly one character. */ + const int32_t *table; + const unsigned char *weights; + const unsigned char *extra; + const int32_t *indirect; + int32_t idx; + const unsigned char *cp = str; + int ch; + + /* This #include defines a local function! */ +# include + + table = (const int32_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); + weights = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB); + extra = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB); + indirect = (const int32_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB); + + idx = findidx (&cp); + if (idx == 0 || cp < str + c1) + /* This is no valid character. */ + FREE_STACK_RETURN (REG_ECOLLATE); + + /* Throw away the ] at the end of the equivalence + class. */ + PATFETCH (c); + + /* Now we have to go throught the whole table + and find all characters which have the same + first level weight. + + XXX Note that this is not entirely correct. + we would have to match multibyte sequences + but this is not possible with the current + implementation. */ + for (ch = 1; ch < 256; ++ch) + /* XXX This test would have to be changed if we + would allow matching multibyte sequences. */ + if (table[ch] > 0) + { + int32_t idx2 = table[ch]; + size_t len = weights[idx2]; + + /* Test whether the lenghts match. */ + if (weights[idx] == len) + { + /* They do. New compare the bytes of + the weight. */ + size_t cnt = 0; + + while (cnt < len + && (weights[idx + 1 + cnt] + == weights[idx2 + 1 + cnt])) + ++cnt; + + if (cnt == len) + /* They match. Mark the character as + acceptable. */ + SET_LIST_BIT (ch); + } + } + } +# endif + had_char_class = true; + } + else + { + c1++; + while (c1--) + PATUNFETCH; + SET_LIST_BIT ('['); + SET_LIST_BIT ('='); + range_start = '='; + had_char_class = false; + } + } + else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == '.') + { + unsigned char str[128]; /* Should be large enough. */ +# ifdef _LIBC + uint32_t nrules = + _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); +# endif + + PATFETCH (c); + c1 = 0; + + /* If pattern is `[[.'. */ + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + for (;;) + { + PATFETCH (c); + if ((c == '.' && *p == ']') || p == pend) + break; + if (c1 < sizeof (str)) + str[c1++] = c; + else + /* This is in any case an invalid class name. */ + str[0] = '\0'; + } + str[c1] = '\0'; + + if (c == '.' && *p == ']' && str[0] != '\0') + { + /* If we have no collation data we use the default + collation in which each character is the name + for its own class which contains only the one + character. It also means that ASCII is the + character set and therefore we cannot have character + with more than one byte in the multibyte + representation. */ +# ifdef _LIBC + if (nrules == 0) +# endif + { + if (c1 != 1) + FREE_STACK_RETURN (REG_ECOLLATE); + + /* Throw away the ] at the end of the equivalence + class. */ + PATFETCH (c); + + /* Set the bit for the character. */ + SET_LIST_BIT (str[0]); + range_start = ((const unsigned char *) str)[0]; + } +# ifdef _LIBC + else + { + /* Try to match the byte sequence in `str' against + those known to the collate implementation. + First find out whether the bytes in `str' are + actually from exactly one character. */ + int32_t table_size; + const int32_t *symb_table; + const unsigned char *extra; + int32_t idx; + int32_t elem; + int32_t second; + int32_t hash; + + table_size = + _NL_CURRENT_WORD (LC_COLLATE, + _NL_COLLATE_SYMB_HASH_SIZEMB); + symb_table = (const int32_t *) + _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_SYMB_TABLEMB); + extra = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_SYMB_EXTRAMB); + + /* Locate the character in the hashing table. */ + hash = elem_hash (str, c1); + + idx = 0; + elem = hash % table_size; + second = hash % (table_size - 2); + while (symb_table[2 * elem] != 0) + { + /* First compare the hashing value. */ + if (symb_table[2 * elem] == hash + && c1 == extra[symb_table[2 * elem + 1]] + && memcmp (str, + &extra[symb_table[2 * elem + 1] + + 1], + c1) == 0) + { + /* Yep, this is the entry. */ + idx = symb_table[2 * elem + 1]; + idx += 1 + extra[idx]; + break; + } + + /* Next entry. */ + elem += second; + } + + if (symb_table[2 * elem] == 0) + /* This is no valid character. */ + FREE_STACK_RETURN (REG_ECOLLATE); + + /* Throw away the ] at the end of the equivalence + class. */ + PATFETCH (c); + + /* Now add the multibyte character(s) we found + to the accept list. + + XXX Note that this is not entirely correct. + we would have to match multibyte sequences + but this is not possible with the current + implementation. Also, we have to match + collating symbols, which expand to more than + one file, as a whole and not allow the + individual bytes. */ + c1 = extra[idx++]; + if (c1 == 1) + range_start = extra[idx]; + while (c1-- > 0) + { + SET_LIST_BIT (extra[idx]); + ++idx; + } + } +# endif + had_char_class = false; + } + else + { + c1++; + while (c1--) + PATUNFETCH; + SET_LIST_BIT ('['); + SET_LIST_BIT ('.'); + range_start = '.'; + had_char_class = false; + } + } + else + { + had_char_class = false; + SET_LIST_BIT (c); + range_start = c; + } + } + + /* Discard any (non)matching list bytes that are all 0 at the + end of the map. Decrease the map-length byte too. */ + while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) + b[-1]--; + b += b[-1]; +#endif /* WCHAR */ + } + break; + + + case '(': + if (syntax & RE_NO_BK_PARENS) + goto handle_open; + else + goto normal_char; + + + case ')': + if (syntax & RE_NO_BK_PARENS) + goto handle_close; + else + goto normal_char; + + + case '\n': + if (syntax & RE_NEWLINE_ALT) + goto handle_alt; + else + goto normal_char; + + + case '|': + if (syntax & RE_NO_BK_VBAR) + goto handle_alt; + else + goto normal_char; + + + case '{': + if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES) + goto handle_interval; + else + goto normal_char; + + + case '\\': + if (p == pend) FREE_STACK_RETURN (REG_EESCAPE); + + /* Do not translate the character after the \, so that we can + distinguish, e.g., \B from \b, even if we normally would + translate, e.g., B to b. */ + PATFETCH_RAW (c); + + switch (c) + { + case '(': + if (syntax & RE_NO_BK_PARENS) + goto normal_backslash; + + handle_open: + bufp->re_nsub++; + regnum++; + + if (COMPILE_STACK_FULL) + { + RETALLOC (compile_stack.stack, compile_stack.size << 1, + compile_stack_elt_t); + if (compile_stack.stack == NULL) return REG_ESPACE; + + compile_stack.size <<= 1; + } + + /* These are the values to restore when we hit end of this + group. They are all relative offsets, so that if the + whole pattern moves because of realloc, they will still + be valid. */ + COMPILE_STACK_TOP.begalt_offset = begalt - COMPILED_BUFFER_VAR; + COMPILE_STACK_TOP.fixup_alt_jump + = fixup_alt_jump ? fixup_alt_jump - COMPILED_BUFFER_VAR + 1 : 0; + COMPILE_STACK_TOP.laststart_offset = b - COMPILED_BUFFER_VAR; + COMPILE_STACK_TOP.regnum = regnum; + + /* We will eventually replace the 0 with the number of + groups inner to this one. But do not push a + start_memory for groups beyond the last one we can + represent in the compiled pattern. */ + if (regnum <= MAX_REGNUM) + { + COMPILE_STACK_TOP.inner_group_offset = b + - COMPILED_BUFFER_VAR + 2; + BUF_PUSH_3 (start_memory, regnum, 0); + } + + compile_stack.avail++; + + fixup_alt_jump = 0; + laststart = 0; + begalt = b; + /* If we've reached MAX_REGNUM groups, then this open + won't actually generate any code, so we'll have to + clear pending_exact explicitly. */ + pending_exact = 0; + break; + + + case ')': + if (syntax & RE_NO_BK_PARENS) goto normal_backslash; + + if (COMPILE_STACK_EMPTY) + { + if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) + goto normal_backslash; + else + FREE_STACK_RETURN (REG_ERPAREN); + } + + handle_close: + if (fixup_alt_jump) + { /* Push a dummy failure point at the end of the + alternative for a possible future + `pop_failure_jump' to pop. See comments at + `push_dummy_failure' in `re_match_2'. */ + BUF_PUSH (push_dummy_failure); + + /* We allocated space for this jump when we assigned + to `fixup_alt_jump', in the `handle_alt' case below. */ + STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1); + } + + /* See similar code for backslashed left paren above. */ + if (COMPILE_STACK_EMPTY) + { + if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) + goto normal_char; + else + FREE_STACK_RETURN (REG_ERPAREN); + } + + /* Since we just checked for an empty stack above, this + ``can't happen''. */ + assert (compile_stack.avail != 0); + { + /* We don't just want to restore into `regnum', because + later groups should continue to be numbered higher, + as in `(ab)c(de)' -- the second group is #2. */ + regnum_t this_group_regnum; + + compile_stack.avail--; + begalt = COMPILED_BUFFER_VAR + COMPILE_STACK_TOP.begalt_offset; + fixup_alt_jump + = COMPILE_STACK_TOP.fixup_alt_jump + ? COMPILED_BUFFER_VAR + COMPILE_STACK_TOP.fixup_alt_jump - 1 + : 0; + laststart = COMPILED_BUFFER_VAR + COMPILE_STACK_TOP.laststart_offset; + this_group_regnum = COMPILE_STACK_TOP.regnum; + /* If we've reached MAX_REGNUM groups, then this open + won't actually generate any code, so we'll have to + clear pending_exact explicitly. */ + pending_exact = 0; + + /* We're at the end of the group, so now we know how many + groups were inside this one. */ + if (this_group_regnum <= MAX_REGNUM) + { + UCHAR_T *inner_group_loc + = COMPILED_BUFFER_VAR + COMPILE_STACK_TOP.inner_group_offset; + + *inner_group_loc = regnum - this_group_regnum; + BUF_PUSH_3 (stop_memory, this_group_regnum, + regnum - this_group_regnum); + } + } + break; + + + case '|': /* `\|'. */ + if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR) + goto normal_backslash; + handle_alt: + if (syntax & RE_LIMITED_OPS) + goto normal_char; + + /* Insert before the previous alternative a jump which + jumps to this alternative if the former fails. */ + GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE); + INSERT_JUMP (on_failure_jump, begalt, + b + 2 + 2 * OFFSET_ADDRESS_SIZE); + pending_exact = 0; + b += 1 + OFFSET_ADDRESS_SIZE; + + /* The alternative before this one has a jump after it + which gets executed if it gets matched. Adjust that + jump so it will jump to this alternative's analogous + jump (put in below, which in turn will jump to the next + (if any) alternative's such jump, etc.). The last such + jump jumps to the correct final destination. A picture: + _____ _____ + | | | | + | v | v + a | b | c + + If we are at `b', then fixup_alt_jump right now points to a + three-byte space after `a'. We'll put in the jump, set + fixup_alt_jump to right after `b', and leave behind three + bytes which we'll fill in when we get to after `c'. */ + + if (fixup_alt_jump) + STORE_JUMP (jump_past_alt, fixup_alt_jump, b); + + /* Mark and leave space for a jump after this alternative, + to be filled in later either by next alternative or + when know we're at the end of a series of alternatives. */ + fixup_alt_jump = b; + GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE); + b += 1 + OFFSET_ADDRESS_SIZE; + + laststart = 0; + begalt = b; + break; + + + case '{': + /* If \{ is a literal. */ + if (!(syntax & RE_INTERVALS) + /* If we're at `\{' and it's not the open-interval + operator. */ + || (syntax & RE_NO_BK_BRACES)) + goto normal_backslash; + + handle_interval: + { + /* If got here, then the syntax allows intervals. */ + + /* At least (most) this many matches must be made. */ + int lower_bound = -1, upper_bound = -1; + + /* Place in the uncompiled pattern (i.e., just after + the '{') to go back to if the interval is invalid. */ + const CHAR_T *beg_interval = p; + + if (p == pend) + goto invalid_interval; + + GET_UNSIGNED_NUMBER (lower_bound); + + if (c == ',') + { + GET_UNSIGNED_NUMBER (upper_bound); + if (upper_bound < 0) + upper_bound = RE_DUP_MAX; + } + else + /* Interval such as `{1}' => match exactly once. */ + upper_bound = lower_bound; + + if (! (0 <= lower_bound && lower_bound <= upper_bound)) + goto invalid_interval; + + if (!(syntax & RE_NO_BK_BRACES)) + { + if (c != '\\' || p == pend) + goto invalid_interval; + PATFETCH (c); + } + + if (c != '}') + goto invalid_interval; + + /* If it's invalid to have no preceding re. */ + if (!laststart) + { + if (syntax & RE_CONTEXT_INVALID_OPS + && !(syntax & RE_INVALID_INTERVAL_ORD)) + FREE_STACK_RETURN (REG_BADRPT); + else if (syntax & RE_CONTEXT_INDEP_OPS) + laststart = b; + else + goto unfetch_interval; + } + + /* We just parsed a valid interval. */ + + if (RE_DUP_MAX < upper_bound) + FREE_STACK_RETURN (REG_BADBR); + + /* If the upper bound is zero, don't want to succeed at + all; jump from `laststart' to `b + 3', which will be + the end of the buffer after we insert the jump. */ + /* ifdef WCHAR, 'b + 1 + OFFSET_ADDRESS_SIZE' + instead of 'b + 3'. */ + if (upper_bound == 0) + { + GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE); + INSERT_JUMP (jump, laststart, b + 1 + + OFFSET_ADDRESS_SIZE); + b += 1 + OFFSET_ADDRESS_SIZE; + } + + /* Otherwise, we have a nontrivial interval. When + we're all done, the pattern will look like: + set_number_at + set_number_at + succeed_n + + jump_n + (The upper bound and `jump_n' are omitted if + `upper_bound' is 1, though.) */ + else + { /* If the upper bound is > 1, we need to insert + more at the end of the loop. */ + unsigned nbytes = 2 + 4 * OFFSET_ADDRESS_SIZE + + (upper_bound > 1) * (2 + 4 * OFFSET_ADDRESS_SIZE); + + GET_BUFFER_SPACE (nbytes); + + /* Initialize lower bound of the `succeed_n', even + though it will be set during matching by its + attendant `set_number_at' (inserted next), + because `re_compile_fastmap' needs to know. + Jump to the `jump_n' we might insert below. */ + INSERT_JUMP2 (succeed_n, laststart, + b + 1 + 2 * OFFSET_ADDRESS_SIZE + + (upper_bound > 1) * (1 + 2 * OFFSET_ADDRESS_SIZE) + , lower_bound); + b += 1 + 2 * OFFSET_ADDRESS_SIZE; + + /* Code to initialize the lower bound. Insert + before the `succeed_n'. The `5' is the last two + bytes of this `set_number_at', plus 3 bytes of + the following `succeed_n'. */ + /* ifdef WCHAR, The '1+2*OFFSET_ADDRESS_SIZE' + is the 'set_number_at', plus '1+OFFSET_ADDRESS_SIZE' + of the following `succeed_n'. */ + PREFIX(insert_op2) (set_number_at, laststart, 1 + + 2 * OFFSET_ADDRESS_SIZE, lower_bound, b); + b += 1 + 2 * OFFSET_ADDRESS_SIZE; + + if (upper_bound > 1) + { /* More than one repetition is allowed, so + append a backward jump to the `succeed_n' + that starts this interval. + + When we've reached this during matching, + we'll have matched the interval once, so + jump back only `upper_bound - 1' times. */ + STORE_JUMP2 (jump_n, b, laststart + + 2 * OFFSET_ADDRESS_SIZE + 1, + upper_bound - 1); + b += 1 + 2 * OFFSET_ADDRESS_SIZE; + + /* The location we want to set is the second + parameter of the `jump_n'; that is `b-2' as + an absolute address. `laststart' will be + the `set_number_at' we're about to insert; + `laststart+3' the number to set, the source + for the relative address. But we are + inserting into the middle of the pattern -- + so everything is getting moved up by 5. + Conclusion: (b - 2) - (laststart + 3) + 5, + i.e., b - laststart. + + We insert this at the beginning of the loop + so that if we fail during matching, we'll + reinitialize the bounds. */ + PREFIX(insert_op2) (set_number_at, laststart, + b - laststart, + upper_bound - 1, b); + b += 1 + 2 * OFFSET_ADDRESS_SIZE; + } + } + pending_exact = 0; + break; + + invalid_interval: + if (!(syntax & RE_INVALID_INTERVAL_ORD)) + FREE_STACK_RETURN (p == pend ? REG_EBRACE : REG_BADBR); + unfetch_interval: + /* Match the characters as literals. */ + p = beg_interval; + c = '{'; + if (syntax & RE_NO_BK_BRACES) + goto normal_char; + else + goto normal_backslash; + } + +#ifdef emacs + /* There is no way to specify the before_dot and after_dot + operators. rms says this is ok. --karl */ + case '=': + BUF_PUSH (at_dot); + break; + + case 's': + laststart = b; + PATFETCH (c); + BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]); + break; + + case 'S': + laststart = b; + PATFETCH (c); + BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]); + break; +#endif /* emacs */ + + + case 'w': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + laststart = b; + BUF_PUSH (wordchar); + break; + + + case 'W': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + laststart = b; + BUF_PUSH (notwordchar); + break; + + + case '<': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (wordbeg); + break; + + case '>': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (wordend); + break; + + case 'b': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (wordbound); + break; + + case 'B': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (notwordbound); + break; + + case '`': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (begbuf); + break; + + case '\'': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (endbuf); + break; + + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + if (syntax & RE_NO_BK_REFS) + goto normal_char; + + c1 = c - '0'; + + if (c1 > regnum) + FREE_STACK_RETURN (REG_ESUBREG); + + /* Can't back reference to a subexpression if inside of it. */ + if (group_in_compile_stack (compile_stack, (regnum_t) c1)) + goto normal_char; + + laststart = b; + BUF_PUSH_2 (duplicate, c1); + break; + + + case '+': + case '?': + if (syntax & RE_BK_PLUS_QM) + goto handle_plus; + else + goto normal_backslash; + + default: + normal_backslash: + /* You might think it would be useful for \ to mean + not to translate; but if we don't translate it + it will never match anything. */ + c = TRANSLATE (c); + goto normal_char; + } + break; + + + default: + /* Expects the character in `c'. */ + normal_char: + /* If no exactn currently being built. */ + if (!pending_exact +#ifdef WCHAR + /* If last exactn handle binary(or character) and + new exactn handle character(or binary). */ + || is_exactn_bin != is_binary[p - 1 - pattern] +#endif /* WCHAR */ + + /* If last exactn not at current position. */ + || pending_exact + *pending_exact + 1 != b + + /* We have only one byte following the exactn for the count. */ + || *pending_exact == (1 << BYTEWIDTH) - 1 + + /* If followed by a repetition operator. */ + || *p == '*' || *p == '^' + || ((syntax & RE_BK_PLUS_QM) + ? *p == '\\' && (p[1] == '+' || p[1] == '?') + : (*p == '+' || *p == '?')) + || ((syntax & RE_INTERVALS) + && ((syntax & RE_NO_BK_BRACES) + ? *p == '{' + : (p[0] == '\\' && p[1] == '{')))) + { + /* Start building a new exactn. */ + + laststart = b; + +#ifdef WCHAR + /* Is this exactn binary data or character? */ + is_exactn_bin = is_binary[p - 1 - pattern]; + if (is_exactn_bin) + BUF_PUSH_2 (exactn_bin, 0); + else + BUF_PUSH_2 (exactn, 0); +#else + BUF_PUSH_2 (exactn, 0); +#endif /* WCHAR */ + pending_exact = b - 1; + } + + BUF_PUSH (c); + (*pending_exact)++; + break; + } /* switch (c) */ + } /* while p != pend */ + + + /* Through the pattern now. */ + + if (fixup_alt_jump) + STORE_JUMP (jump_past_alt, fixup_alt_jump, b); + + if (!COMPILE_STACK_EMPTY) + FREE_STACK_RETURN (REG_EPAREN); + + /* If we don't want backtracking, force success + the first time we reach the end of the compiled pattern. */ + if (syntax & RE_NO_POSIX_BACKTRACKING) + BUF_PUSH (succeed); + +#ifdef WCHAR + free (pattern); + free (mbs_offset); + free (is_binary); +#endif + free (compile_stack.stack); + + /* We have succeeded; set the length of the buffer. */ +#ifdef WCHAR + bufp->used = (uintptr_t) b - (uintptr_t) COMPILED_BUFFER_VAR; +#else + bufp->used = b - bufp->buffer; +#endif + +#ifdef DEBUG + if (debug) + { + DEBUG_PRINT1 ("\nCompiled pattern: \n"); + PREFIX(print_compiled_pattern) (bufp); + } +#endif /* DEBUG */ + +#ifndef MATCH_MAY_ALLOCATE + /* Initialize the failure stack to the largest possible stack. This + isn't necessary unless we're trying to avoid calling alloca in + the search and match routines. */ + { + int num_regs = bufp->re_nsub + 1; + + /* Since DOUBLE_FAIL_STACK refuses to double only if the current size + is strictly greater than re_max_failures, the largest possible stack + is 2 * re_max_failures failure points. */ + if (fail_stack.size < (2 * re_max_failures * MAX_FAILURE_ITEMS)) + { + fail_stack.size = (2 * re_max_failures * MAX_FAILURE_ITEMS); + +# ifdef emacs + if (! fail_stack.stack) + fail_stack.stack + = (PREFIX(fail_stack_elt_t) *) xmalloc (fail_stack.size + * sizeof (PREFIX(fail_stack_elt_t))); + else + fail_stack.stack + = (PREFIX(fail_stack_elt_t) *) xrealloc (fail_stack.stack, + (fail_stack.size + * sizeof (PREFIX(fail_stack_elt_t)))); +# else /* not emacs */ + if (! fail_stack.stack) + fail_stack.stack + = (PREFIX(fail_stack_elt_t) *) malloc (fail_stack.size + * sizeof (PREFIX(fail_stack_elt_t))); + else + fail_stack.stack + = (PREFIX(fail_stack_elt_t) *) realloc (fail_stack.stack, + (fail_stack.size + * sizeof (PREFIX(fail_stack_elt_t)))); +# endif /* not emacs */ + } + + PREFIX(regex_grow_registers) (num_regs); + } +#endif /* not MATCH_MAY_ALLOCATE */ + + return REG_NOERROR; +} /* regex_compile */ + +/* Subroutines for `regex_compile'. */ + +/* Store OP at LOC followed by two-byte integer parameter ARG. */ +/* ifdef WCHAR, integer parameter is 1 wchar_t. */ + +static void +PREFIX(store_op1) (re_opcode_t op, UCHAR_T *loc, int arg) +{ + *loc = (UCHAR_T) op; + STORE_NUMBER (loc + 1, arg); +} + + +/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2. */ +/* ifdef WCHAR, integer parameter is 1 wchar_t. */ + +static void +PREFIX(store_op2) (re_opcode_t op, UCHAR_T *loc, int arg1, int arg2) +{ + *loc = (UCHAR_T) op; + STORE_NUMBER (loc + 1, arg1); + STORE_NUMBER (loc + 1 + OFFSET_ADDRESS_SIZE, arg2); +} + + +/* Copy the bytes from LOC to END to open up three bytes of space at LOC + for OP followed by two-byte integer parameter ARG. */ +/* ifdef WCHAR, integer parameter is 1 wchar_t. */ + +static void +PREFIX(insert_op1) (re_opcode_t op, UCHAR_T *loc, int arg, UCHAR_T *end) +{ + register UCHAR_T *pfrom = end; + register UCHAR_T *pto = end + 1 + OFFSET_ADDRESS_SIZE; + + while (pfrom != loc) + *--pto = *--pfrom; + + PREFIX(store_op1) (op, loc, arg); +} + + +/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2. */ +/* ifdef WCHAR, integer parameter is 1 wchar_t. */ + +static void +PREFIX(insert_op2) (re_opcode_t op, UCHAR_T *loc, int arg1, + int arg2, UCHAR_T *end) +{ + register UCHAR_T *pfrom = end; + register UCHAR_T *pto = end + 1 + 2 * OFFSET_ADDRESS_SIZE; + + while (pfrom != loc) + *--pto = *--pfrom; + + PREFIX(store_op2) (op, loc, arg1, arg2); +} + + +/* P points to just after a ^ in PATTERN. Return true if that ^ comes + after an alternative or a begin-subexpression. We assume there is at + least one character before the ^. */ + +static boolean +PREFIX(at_begline_loc_p) (const CHAR_T *pattern, const CHAR_T *p, + reg_syntax_t syntax) +{ + const CHAR_T *prev = p - 2; + boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\'; + + return + /* After a subexpression? */ + (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash)) + /* After an alternative? */ + || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash)); +} + + +/* The dual of at_begline_loc_p. This one is for $. We assume there is + at least one character after the $, i.e., `P < PEND'. */ + +static boolean +PREFIX(at_endline_loc_p) (const CHAR_T *p, const CHAR_T *pend, + reg_syntax_t syntax) +{ + const CHAR_T *next = p; + boolean next_backslash = *next == '\\'; + const CHAR_T *next_next = p + 1 < pend ? p + 1 : 0; + + return + /* Before a subexpression? */ + (syntax & RE_NO_BK_PARENS ? *next == ')' + : next_backslash && next_next && *next_next == ')') + /* Before an alternative? */ + || (syntax & RE_NO_BK_VBAR ? *next == '|' + : next_backslash && next_next && *next_next == '|'); +} + +#else /* not INSIDE_RECURSION */ + +/* Returns true if REGNUM is in one of COMPILE_STACK's elements and + false if it's not. */ + +static boolean +group_in_compile_stack (compile_stack_type compile_stack, regnum_t regnum) +{ + int this_element; + + for (this_element = compile_stack.avail - 1; + this_element >= 0; + this_element--) + if (compile_stack.stack[this_element].regnum == regnum) + return true; + + return false; +} +#endif /* not INSIDE_RECURSION */ + +#ifdef INSIDE_RECURSION + +#ifdef WCHAR +/* This insert space, which size is "num", into the pattern at "loc". + "end" must point the end of the allocated buffer. */ +static void +insert_space (int num, CHAR_T *loc, CHAR_T *end) +{ + register CHAR_T *pto = end; + register CHAR_T *pfrom = end - num; + + while (pfrom >= loc) + *pto-- = *pfrom--; +} +#endif /* WCHAR */ + +#ifdef WCHAR +static reg_errcode_t +wcs_compile_range (CHAR_T range_start_char, const CHAR_T **p_ptr, + const CHAR_T *pend, RE_TRANSLATE_TYPE translate, + reg_syntax_t syntax, CHAR_T *b, CHAR_T *char_set) +{ + const CHAR_T *p = *p_ptr; + CHAR_T range_start, range_end; + reg_errcode_t ret; +# ifdef _LIBC + uint32_t nrules; + uint32_t start_val, end_val; +# endif + if (p == pend) + return REG_ERANGE; + +# ifdef _LIBC + nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); + if (nrules != 0) + { + const char *collseq = (const char *) _NL_CURRENT(LC_COLLATE, + _NL_COLLATE_COLLSEQWC); + const unsigned char *extra = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB); + + if (range_start_char < -1) + { + /* range_start is a collating symbol. */ + int32_t *wextra; + /* Retreive the index and get collation sequence value. */ + wextra = (int32_t*)(extra + char_set[-range_start_char]); + start_val = wextra[1 + *wextra]; + } + else + start_val = collseq_table_lookup(collseq, TRANSLATE(range_start_char)); + + end_val = collseq_table_lookup (collseq, TRANSLATE (p[0])); + + /* Report an error if the range is empty and the syntax prohibits + this. */ + ret = ((syntax & RE_NO_EMPTY_RANGES) + && (start_val > end_val))? REG_ERANGE : REG_NOERROR; + + /* Insert space to the end of the char_ranges. */ + insert_space(2, b - char_set[5] - 2, b - 1); + *(b - char_set[5] - 2) = (wchar_t)start_val; + *(b - char_set[5] - 1) = (wchar_t)end_val; + char_set[4]++; /* ranges_index */ + } + else +# endif + { + range_start = (range_start_char >= 0)? TRANSLATE (range_start_char): + range_start_char; + range_end = TRANSLATE (p[0]); + /* Report an error if the range is empty and the syntax prohibits + this. */ + ret = ((syntax & RE_NO_EMPTY_RANGES) + && (range_start > range_end))? REG_ERANGE : REG_NOERROR; + + /* Insert space to the end of the char_ranges. */ + insert_space(2, b - char_set[5] - 2, b - 1); + *(b - char_set[5] - 2) = range_start; + *(b - char_set[5] - 1) = range_end; + char_set[4]++; /* ranges_index */ + } + /* Have to increment the pointer into the pattern string, so the + caller isn't still at the ending character. */ + (*p_ptr)++; + + return ret; +} +#else /* BYTE */ +/* Read the ending character of a range (in a bracket expression) from the + uncompiled pattern *P_PTR (which ends at PEND). We assume the + starting character is in `P[-2]'. (`P[-1]' is the character `-'.) + Then we set the translation of all bits between the starting and + ending characters (inclusive) in the compiled pattern B. + + Return an error code. + + We use these short variable names so we can use the same macros as + `regex_compile' itself. */ + +static reg_errcode_t +byte_compile_range (unsigned int range_start_char, const char **p_ptr, + const char *pend, RE_TRANSLATE_TYPE translate, + reg_syntax_t syntax, unsigned char *b) +{ + unsigned this_char; + const char *p = *p_ptr; + reg_errcode_t ret; +# if _LIBC + const unsigned char *collseq; + unsigned int start_colseq; + unsigned int end_colseq; +# else + unsigned end_char; +# endif + + if (p == pend) + return REG_ERANGE; + + /* Have to increment the pointer into the pattern string, so the + caller isn't still at the ending character. */ + (*p_ptr)++; + + /* Report an error if the range is empty and the syntax prohibits this. */ + ret = syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR; + +# if _LIBC + collseq = (const unsigned char *) _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_COLLSEQMB); + + start_colseq = collseq[(unsigned char) TRANSLATE (range_start_char)]; + end_colseq = collseq[(unsigned char) TRANSLATE (p[0])]; + for (this_char = 0; this_char <= (unsigned char) -1; ++this_char) + { + unsigned int this_colseq = collseq[(unsigned char) TRANSLATE (this_char)]; + + if (start_colseq <= this_colseq && this_colseq <= end_colseq) + { + SET_LIST_BIT (TRANSLATE (this_char)); + ret = REG_NOERROR; + } + } +# else + /* Here we see why `this_char' has to be larger than an `unsigned + char' -- we would otherwise go into an infinite loop, since all + characters <= 0xff. */ + range_start_char = TRANSLATE (range_start_char); + /* TRANSLATE(p[0]) is casted to char (not unsigned char) in TRANSLATE, + and some compilers cast it to int implicitly, so following for_loop + may fall to (almost) infinite loop. + e.g. If translate[p[0]] = 0xff, end_char may equals to 0xffffffff. + To avoid this, we cast p[0] to unsigned int and truncate it. */ + end_char = ((unsigned)TRANSLATE(p[0]) & ((1 << BYTEWIDTH) - 1)); + + for (this_char = range_start_char; this_char <= end_char; ++this_char) + { + SET_LIST_BIT (TRANSLATE (this_char)); + ret = REG_NOERROR; + } +# endif + + return ret; +} +#endif /* WCHAR */ + +/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in + BUFP. A fastmap records which of the (1 << BYTEWIDTH) possible + characters can start a string that matches the pattern. This fastmap + is used by re_search to skip quickly over impossible starting points. + + The caller must supply the address of a (1 << BYTEWIDTH)-byte data + area as BUFP->fastmap. + + We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in + the pattern buffer. + + Returns 0 if we succeed, -2 if an internal error. */ + +#ifdef WCHAR +/* local function for re_compile_fastmap. + truncate wchar_t character to char. */ +static unsigned char truncate_wchar (CHAR_T c); + +static unsigned char +truncate_wchar (CHAR_T c) +{ + unsigned char buf[MB_CUR_MAX]; + mbstate_t state; + int retval; + memset (&state, '\0', sizeof (state)); +# ifdef _LIBC + retval = __wcrtomb (buf, c, &state); +# else + retval = wcrtomb (buf, c, &state); +# endif + return retval > 0 ? buf[0] : (unsigned char) c; +} +#endif /* WCHAR */ + +static int +PREFIX(re_compile_fastmap) (struct re_pattern_buffer *bufp) +{ + int j, k; +#ifdef MATCH_MAY_ALLOCATE + PREFIX(fail_stack_type) fail_stack; +#endif +#ifndef REGEX_MALLOC + char *destination; +#endif + + register char *fastmap = bufp->fastmap; + +#ifdef WCHAR + /* We need to cast pattern to (wchar_t*), because we casted this compiled + pattern to (char*) in regex_compile. */ + UCHAR_T *pattern = (UCHAR_T*)bufp->buffer; + register UCHAR_T *pend = (UCHAR_T*) (bufp->buffer + bufp->used); +#else /* BYTE */ + UCHAR_T *pattern = bufp->buffer; + register UCHAR_T *pend = pattern + bufp->used; +#endif /* WCHAR */ + UCHAR_T *p = pattern; + +#ifdef REL_ALLOC + /* This holds the pointer to the failure stack, when + it is allocated relocatably. */ + fail_stack_elt_t *failure_stack_ptr; +#endif + + /* Assume that each path through the pattern can be null until + proven otherwise. We set this false at the bottom of switch + statement, to which we get only if a particular path doesn't + match the empty string. */ + boolean path_can_be_null = true; + + /* We aren't doing a `succeed_n' to begin with. */ + boolean succeed_n_p = false; + + assert (fastmap != NULL && p != NULL); + + INIT_FAIL_STACK (); + bzero (fastmap, 1 << BYTEWIDTH); /* Assume nothing's valid. */ + bufp->fastmap_accurate = 1; /* It will be when we're done. */ + bufp->can_be_null = 0; + + while (1) + { + if (p == pend || *p == (UCHAR_T) succeed) + { + /* We have reached the (effective) end of pattern. */ + if (!FAIL_STACK_EMPTY ()) + { + bufp->can_be_null |= path_can_be_null; + + /* Reset for next path. */ + path_can_be_null = true; + + p = fail_stack.stack[--fail_stack.avail].pointer; + + continue; + } + else + break; + } + + /* We should never be about to go beyond the end of the pattern. */ + assert (p < pend); + + switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++)) + { + + /* I guess the idea here is to simply not bother with a fastmap + if a backreference is used, since it's too hard to figure out + the fastmap for the corresponding group. Setting + `can_be_null' stops `re_search_2' from using the fastmap, so + that is all we do. */ + case duplicate: + bufp->can_be_null = 1; + goto done; + + + /* Following are the cases which match a character. These end + with `break'. */ + +#ifdef WCHAR + case exactn: + fastmap[truncate_wchar(p[1])] = 1; + break; +#else /* BYTE */ + case exactn: + fastmap[p[1]] = 1; + break; +#endif /* WCHAR */ +#ifdef MBS_SUPPORT + case exactn_bin: + fastmap[p[1]] = 1; + break; +#endif + +#ifdef WCHAR + /* It is hard to distinguish fastmap from (multi byte) characters + which depends on current locale. */ + case charset: + case charset_not: + case wordchar: + case notwordchar: + bufp->can_be_null = 1; + goto done; +#else /* BYTE */ + case charset: + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))) + fastmap[j] = 1; + break; + + + case charset_not: + /* Chars beyond end of map must be allowed. */ + for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++) + fastmap[j] = 1; + + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))) + fastmap[j] = 1; + break; + + + case wordchar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) == Sword) + fastmap[j] = 1; + break; + + + case notwordchar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) != Sword) + fastmap[j] = 1; + break; +#endif /* WCHAR */ + + case anychar: + { + int fastmap_newline = fastmap['\n']; + + /* `.' matches anything ... */ + for (j = 0; j < (1 << BYTEWIDTH); j++) + fastmap[j] = 1; + + /* ... except perhaps newline. */ + if (!(bufp->syntax & RE_DOT_NEWLINE)) + fastmap['\n'] = fastmap_newline; + + /* Return if we have already set `can_be_null'; if we have, + then the fastmap is irrelevant. Something's wrong here. */ + else if (bufp->can_be_null) + goto done; + + /* Otherwise, have to check alternative paths. */ + break; + } + +#ifdef emacs + case syntaxspec: + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) == (enum syntaxcode) k) + fastmap[j] = 1; + break; + + + case notsyntaxspec: + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) != (enum syntaxcode) k) + fastmap[j] = 1; + break; + + + /* All cases after this match the empty string. These end with + `continue'. */ + + + case before_dot: + case at_dot: + case after_dot: + continue; +#endif /* emacs */ + + + case no_op: + case begline: + case endline: + case begbuf: + case endbuf: + case wordbound: + case notwordbound: + case wordbeg: + case wordend: + case push_dummy_failure: + continue; + + + case jump_n: + case pop_failure_jump: + case maybe_pop_jump: + case jump: + case jump_past_alt: + case dummy_failure_jump: + EXTRACT_NUMBER_AND_INCR (j, p); + p += j; + if (j > 0) + continue; + + /* Jump backward implies we just went through the body of a + loop and matched nothing. Opcode jumped to should be + `on_failure_jump' or `succeed_n'. Just treat it like an + ordinary jump. For a * loop, it has pushed its failure + point already; if so, discard that as redundant. */ + if ((re_opcode_t) *p != on_failure_jump + && (re_opcode_t) *p != succeed_n) + continue; + + p++; + EXTRACT_NUMBER_AND_INCR (j, p); + p += j; + + /* If what's on the stack is where we are now, pop it. */ + if (!FAIL_STACK_EMPTY () + && fail_stack.stack[fail_stack.avail - 1].pointer == p) + fail_stack.avail--; + + continue; + + + case on_failure_jump: + case on_failure_keep_string_jump: + handle_on_failure_jump: + EXTRACT_NUMBER_AND_INCR (j, p); + + /* For some patterns, e.g., `(a?)?', `p+j' here points to the + end of the pattern. We don't want to push such a point, + since when we restore it above, entering the switch will + increment `p' past the end of the pattern. We don't need + to push such a point since we obviously won't find any more + fastmap entries beyond `pend'. Such a pattern can match + the null string, though. */ + if (p + j < pend) + { + if (!PUSH_PATTERN_OP (p + j, fail_stack)) + { + RESET_FAIL_STACK (); + return -2; + } + } + else + bufp->can_be_null = 1; + + if (succeed_n_p) + { + EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */ + succeed_n_p = false; + } + + continue; + + + case succeed_n: + /* Get to the number of times to succeed. */ + p += OFFSET_ADDRESS_SIZE; + + /* Increment p past the n for when k != 0. */ + EXTRACT_NUMBER_AND_INCR (k, p); + if (k == 0) + { + p -= 2 * OFFSET_ADDRESS_SIZE; + succeed_n_p = true; /* Spaghetti code alert. */ + goto handle_on_failure_jump; + } + continue; + + + case set_number_at: + p += 2 * OFFSET_ADDRESS_SIZE; + continue; + + + case start_memory: + case stop_memory: + p += 2; + continue; + + + default: + abort (); /* We have listed all the cases. */ + } /* switch *p++ */ + + /* Getting here means we have found the possible starting + characters for one path of the pattern -- and that the empty + string does not match. We need not follow this path further. + Instead, look at the next alternative (remembered on the + stack), or quit if no more. The test at the top of the loop + does these things. */ + path_can_be_null = false; + p = pend; + } /* while p */ + + /* Set `can_be_null' for the last path (also the first path, if the + pattern is empty). */ + bufp->can_be_null |= path_can_be_null; + + done: + RESET_FAIL_STACK (); + return 0; +} + +#else /* not INSIDE_RECURSION */ + +int +re_compile_fastmap (struct re_pattern_buffer *bufp) +{ +# ifdef MBS_SUPPORT + if (MB_CUR_MAX != 1) + return wcs_re_compile_fastmap(bufp); + else +# endif + return byte_re_compile_fastmap(bufp); +} /* re_compile_fastmap */ +#ifdef _LIBC +weak_alias (__re_compile_fastmap, re_compile_fastmap) +#endif + + +/* Set REGS to hold NUM_REGS registers, storing them in STARTS and + ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use + this memory for recording register information. STARTS and ENDS + must be allocated using the malloc library routine, and must each + be at least NUM_REGS * sizeof (regoff_t) bytes long. + + If NUM_REGS == 0, then subsequent matches should allocate their own + register data. + + Unless this function is called, the first search or match using + PATTERN_BUFFER will allocate its own register data, without + freeing the old data. */ + +void +re_set_registers (struct re_pattern_buffer *bufp, + struct re_registers *regs, unsigned num_regs, + regoff_t *starts, regoff_t *ends) +{ + if (num_regs) + { + bufp->regs_allocated = REGS_REALLOCATE; + regs->num_regs = num_regs; + regs->start = starts; + regs->end = ends; + } + else + { + bufp->regs_allocated = REGS_UNALLOCATED; + regs->num_regs = 0; + regs->start = regs->end = (regoff_t *) 0; + } +} +#ifdef _LIBC +weak_alias (__re_set_registers, re_set_registers) +#endif + +/* Searching routines. */ + +/* Like re_search_2, below, but only one string is specified, and + doesn't let you say where to stop matching. */ + +int +re_search (struct re_pattern_buffer *bufp, const char *string, int size, + int startpos, int range, struct re_registers *regs) +{ + return re_search_2 (bufp, NULL, 0, string, size, startpos, range, + regs, size); +} +#ifdef _LIBC +weak_alias (__re_search, re_search) +#endif + + +/* Using the compiled pattern in BUFP->buffer, first tries to match the + virtual concatenation of STRING1 and STRING2, starting first at index + STARTPOS, then at STARTPOS + 1, and so on. + + STRING1 and STRING2 have length SIZE1 and SIZE2, respectively. + + RANGE is how far to scan while trying to match. RANGE = 0 means try + only at STARTPOS; in general, the last start tried is STARTPOS + + RANGE. + + In REGS, return the indices of the virtual concatenation of STRING1 + and STRING2 that matched the entire BUFP->buffer and its contained + subexpressions. + + Do not consider matching one past the index STOP in the virtual + concatenation of STRING1 and STRING2. + + We return either the position in the strings at which the match was + found, -1 if no match, or -2 if error (such as failure + stack overflow). */ + +int +re_search_2 (struct re_pattern_buffer *bufp, const char *string1, int size1, + const char *string2, int size2, int startpos, int range, + struct re_registers *regs, int stop) +{ +# ifdef MBS_SUPPORT + if (MB_CUR_MAX != 1) + return wcs_re_search_2 (bufp, string1, size1, string2, size2, startpos, + range, regs, stop); + else +# endif + return byte_re_search_2 (bufp, string1, size1, string2, size2, startpos, + range, regs, stop); +} /* re_search_2 */ +#ifdef _LIBC +weak_alias (__re_search_2, re_search_2) +#endif + +#endif /* not INSIDE_RECURSION */ + +#ifdef INSIDE_RECURSION + +#ifdef MATCH_MAY_ALLOCATE +# define FREE_VAR(var) if (var) REGEX_FREE (var); var = NULL +#else +# define FREE_VAR(var) if (var) free (var); var = NULL +#endif + +#ifdef WCHAR +# define MAX_ALLOCA_SIZE 2000 + +# define FREE_WCS_BUFFERS() \ + do { \ + if (size1 > MAX_ALLOCA_SIZE) \ + { \ + free (wcs_string1); \ + free (mbs_offset1); \ + } \ + else \ + { \ + FREE_VAR (wcs_string1); \ + FREE_VAR (mbs_offset1); \ + } \ + if (size2 > MAX_ALLOCA_SIZE) \ + { \ + free (wcs_string2); \ + free (mbs_offset2); \ + } \ + else \ + { \ + FREE_VAR (wcs_string2); \ + FREE_VAR (mbs_offset2); \ + } \ + } while (0) + +#endif + + +static int +PREFIX(re_search_2) (struct re_pattern_buffer *bufp, const char *string1, + int size1, const char *string2, int size2, + int startpos, int range, + struct re_registers *regs, int stop) +{ + int val; + register char *fastmap = bufp->fastmap; + register RE_TRANSLATE_TYPE translate = bufp->translate; + int total_size = size1 + size2; + int endpos = startpos + range; +#ifdef WCHAR + /* We need wchar_t* buffers correspond to cstring1, cstring2. */ + wchar_t *wcs_string1 = NULL, *wcs_string2 = NULL; + /* We need the size of wchar_t buffers correspond to csize1, csize2. */ + int wcs_size1 = 0, wcs_size2 = 0; + /* offset buffer for optimizatoin. See convert_mbs_to_wc. */ + int *mbs_offset1 = NULL, *mbs_offset2 = NULL; + /* They hold whether each wchar_t is binary data or not. */ + char *is_binary = NULL; +#endif /* WCHAR */ + + /* Check for out-of-range STARTPOS. */ + if (startpos < 0 || startpos > total_size) + return -1; + + /* Fix up RANGE if it might eventually take us outside + the virtual concatenation of STRING1 and STRING2. + Make sure we won't move STARTPOS below 0 or above TOTAL_SIZE. */ + if (endpos < 0) + range = 0 - startpos; + else if (endpos > total_size) + range = total_size - startpos; + + /* If the search isn't to be a backwards one, don't waste time in a + search for a pattern that must be anchored. */ + if (bufp->used > 0 && range > 0 + && ((re_opcode_t) bufp->buffer[0] == begbuf + /* `begline' is like `begbuf' if it cannot match at newlines. */ + || ((re_opcode_t) bufp->buffer[0] == begline + && !bufp->newline_anchor))) + { + if (startpos > 0) + return -1; + else + range = 1; + } + +#ifdef emacs + /* In a forward search for something that starts with \=. + don't keep searching past point. */ + if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == at_dot && range > 0) + { + range = PT - startpos; + if (range <= 0) + return -1; + } +#endif /* emacs */ + + /* Update the fastmap now if not correct already. */ + if (fastmap && !bufp->fastmap_accurate) + if (re_compile_fastmap (bufp) == -2) + return -2; + +#ifdef WCHAR + /* Allocate wchar_t array for wcs_string1 and wcs_string2 and + fill them with converted string. */ + if (size1 != 0) + { + if (size1 > MAX_ALLOCA_SIZE) + { + wcs_string1 = TALLOC (size1 + 1, CHAR_T); + mbs_offset1 = TALLOC (size1 + 1, int); + is_binary = TALLOC (size1 + 1, char); + } + else + { + wcs_string1 = REGEX_TALLOC (size1 + 1, CHAR_T); + mbs_offset1 = REGEX_TALLOC (size1 + 1, int); + is_binary = REGEX_TALLOC (size1 + 1, char); + } + if (!wcs_string1 || !mbs_offset1 || !is_binary) + { + if (size1 > MAX_ALLOCA_SIZE) + { + free (wcs_string1); + free (mbs_offset1); + free (is_binary); + } + else + { + FREE_VAR (wcs_string1); + FREE_VAR (mbs_offset1); + FREE_VAR (is_binary); + } + return -2; + } + wcs_size1 = convert_mbs_to_wcs(wcs_string1, string1, size1, + mbs_offset1, is_binary); + wcs_string1[wcs_size1] = L'\0'; /* for a sentinel */ + if (size1 > MAX_ALLOCA_SIZE) + free (is_binary); + else + FREE_VAR (is_binary); + } + if (size2 != 0) + { + if (size2 > MAX_ALLOCA_SIZE) + { + wcs_string2 = TALLOC (size2 + 1, CHAR_T); + mbs_offset2 = TALLOC (size2 + 1, int); + is_binary = TALLOC (size2 + 1, char); + } + else + { + wcs_string2 = REGEX_TALLOC (size2 + 1, CHAR_T); + mbs_offset2 = REGEX_TALLOC (size2 + 1, int); + is_binary = REGEX_TALLOC (size2 + 1, char); + } + if (!wcs_string2 || !mbs_offset2 || !is_binary) + { + FREE_WCS_BUFFERS (); + if (size2 > MAX_ALLOCA_SIZE) + free (is_binary); + else + FREE_VAR (is_binary); + return -2; + } + wcs_size2 = convert_mbs_to_wcs(wcs_string2, string2, size2, + mbs_offset2, is_binary); + wcs_string2[wcs_size2] = L'\0'; /* for a sentinel */ + if (size2 > MAX_ALLOCA_SIZE) + free (is_binary); + else + FREE_VAR (is_binary); + } +#endif /* WCHAR */ + + + /* Loop through the string, looking for a place to start matching. */ + for (;;) + { + /* If a fastmap is supplied, skip quickly over characters that + cannot be the start of a match. If the pattern can match the + null string, however, we don't need to skip characters; we want + the first null string. */ + if (fastmap && startpos < total_size && !bufp->can_be_null) + { + if (range > 0) /* Searching forwards. */ + { + register const char *d; + register int lim = 0; + int irange = range; + + if (startpos < size1 && startpos + range >= size1) + lim = range - (size1 - startpos); + + d = (startpos >= size1 ? string2 - size1 : string1) + startpos; + + /* Written out as an if-else to avoid testing `translate' + inside the loop. */ + if (translate) + while (range > lim + && !fastmap[(unsigned char) + translate[(unsigned char) *d++]]) + range--; + else + while (range > lim && !fastmap[(unsigned char) *d++]) + range--; + + startpos += irange - range; + } + else /* Searching backwards. */ + { + register CHAR_T c = (size1 == 0 || startpos >= size1 + ? string2[startpos - size1] + : string1[startpos]); + + if (!fastmap[(unsigned char) TRANSLATE (c)]) + goto advance; + } + } + + /* If can't match the null string, and that's all we have left, fail. */ + if (range >= 0 && startpos == total_size && fastmap + && !bufp->can_be_null) + { +#ifdef WCHAR + FREE_WCS_BUFFERS (); +#endif + return -1; + } + +#ifdef WCHAR + val = wcs_re_match_2_internal (bufp, string1, size1, string2, + size2, startpos, regs, stop, + wcs_string1, wcs_size1, + wcs_string2, wcs_size2, + mbs_offset1, mbs_offset2); +#else /* BYTE */ + val = byte_re_match_2_internal (bufp, string1, size1, string2, + size2, startpos, regs, stop); +#endif /* BYTE */ + +#ifndef REGEX_MALLOC +# ifdef C_ALLOCA + alloca (0); +# endif +#endif + + if (val >= 0) + { +#ifdef WCHAR + FREE_WCS_BUFFERS (); +#endif + return startpos; + } + + if (val == -2) + { +#ifdef WCHAR + FREE_WCS_BUFFERS (); +#endif + return -2; + } + + advance: + if (!range) + break; + else if (range > 0) + { + range--; + startpos++; + } + else + { + range++; + startpos--; + } + } +#ifdef WCHAR + FREE_WCS_BUFFERS (); +#endif + return -1; +} + +#ifdef WCHAR +/* This converts PTR, a pointer into one of the search wchar_t strings + `string1' and `string2' into an multibyte string offset from the + beginning of that string. We use mbs_offset to optimize. + See convert_mbs_to_wcs. */ +# define POINTER_TO_OFFSET(ptr) \ + (FIRST_STRING_P (ptr) \ + ? ((regoff_t)(mbs_offset1 != NULL? mbs_offset1[(ptr)-string1] : 0)) \ + : ((regoff_t)((mbs_offset2 != NULL? mbs_offset2[(ptr)-string2] : 0) \ + + csize1))) +#else /* BYTE */ +/* This converts PTR, a pointer into one of the search strings `string1' + and `string2' into an offset from the beginning of that string. */ +# define POINTER_TO_OFFSET(ptr) \ + (FIRST_STRING_P (ptr) \ + ? ((regoff_t) ((ptr) - string1)) \ + : ((regoff_t) ((ptr) - string2 + size1))) +#endif /* WCHAR */ + +/* Macros for dealing with the split strings in re_match_2. */ + +#define MATCHING_IN_FIRST_STRING (dend == end_match_1) + +/* Call before fetching a character with *d. This switches over to + string2 if necessary. */ +#define PREFETCH() \ + while (d == dend) \ + { \ + /* End of string2 => fail. */ \ + if (dend == end_match_2) \ + goto fail; \ + /* End of string1 => advance to string2. */ \ + d = string2; \ + dend = end_match_2; \ + } + +/* Test if at very beginning or at very end of the virtual concatenation + of `string1' and `string2'. If only one string, it's `string2'. */ +#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2) +#define AT_STRINGS_END(d) ((d) == end2) + + +/* Test if D points to a character which is word-constituent. We have + two special cases to check for: if past the end of string1, look at + the first character in string2; and if before the beginning of + string2, look at the last character in string1. */ +#ifdef WCHAR +/* Use internationalized API instead of SYNTAX. */ +# define WORDCHAR_P(d) \ + (iswalnum ((wint_t)((d) == end1 ? *string2 \ + : (d) == string2 - 1 ? *(end1 - 1) : *(d))) != 0 \ + || ((d) == end1 ? *string2 \ + : (d) == string2 - 1 ? *(end1 - 1) : *(d)) == L'_') +#else /* BYTE */ +# define WORDCHAR_P(d) \ + (SYNTAX ((d) == end1 ? *string2 \ + : (d) == string2 - 1 ? *(end1 - 1) : *(d)) \ + == Sword) +#endif /* WCHAR */ + +/* Disabled due to a compiler bug -- see comment at case wordbound */ +#if 0 +/* Test if the character before D and the one at D differ with respect + to being word-constituent. */ +#define AT_WORD_BOUNDARY(d) \ + (AT_STRINGS_BEG (d) || AT_STRINGS_END (d) \ + || WORDCHAR_P (d - 1) != WORDCHAR_P (d)) +#endif + +/* Free everything we malloc. */ +#ifdef MATCH_MAY_ALLOCATE +# ifdef WCHAR +# define FREE_VARIABLES() \ + do { \ + REGEX_FREE_STACK (fail_stack.stack); \ + FREE_VAR (regstart); \ + FREE_VAR (regend); \ + FREE_VAR (old_regstart); \ + FREE_VAR (old_regend); \ + FREE_VAR (best_regstart); \ + FREE_VAR (best_regend); \ + FREE_VAR (reg_info); \ + FREE_VAR (reg_dummy); \ + FREE_VAR (reg_info_dummy); \ + if (!cant_free_wcs_buf) \ + { \ + FREE_VAR (string1); \ + FREE_VAR (string2); \ + FREE_VAR (mbs_offset1); \ + FREE_VAR (mbs_offset2); \ + } \ + } while (0) +# else /* BYTE */ +# define FREE_VARIABLES() \ + do { \ + REGEX_FREE_STACK (fail_stack.stack); \ + FREE_VAR (regstart); \ + FREE_VAR (regend); \ + FREE_VAR (old_regstart); \ + FREE_VAR (old_regend); \ + FREE_VAR (best_regstart); \ + FREE_VAR (best_regend); \ + FREE_VAR (reg_info); \ + FREE_VAR (reg_dummy); \ + FREE_VAR (reg_info_dummy); \ + } while (0) +# endif /* WCHAR */ +#else +# ifdef WCHAR +# define FREE_VARIABLES() \ + do { \ + if (!cant_free_wcs_buf) \ + { \ + FREE_VAR (string1); \ + FREE_VAR (string2); \ + FREE_VAR (mbs_offset1); \ + FREE_VAR (mbs_offset2); \ + } \ + } while (0) +# else /* BYTE */ +# define FREE_VARIABLES() ((void)0) /* Do nothing! But inhibit gcc warning. */ +# endif /* WCHAR */ +#endif /* not MATCH_MAY_ALLOCATE */ + +/* These values must meet several constraints. They must not be valid + register values; since we have a limit of 255 registers (because + we use only one byte in the pattern for the register number), we can + use numbers larger than 255. They must differ by 1, because of + NUM_FAILURE_ITEMS above. And the value for the lowest register must + be larger than the value for the highest register, so we do not try + to actually save any registers when none are active. */ +#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH) +#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1) + +#else /* not INSIDE_RECURSION */ +/* Matching routines. */ + +#ifndef emacs /* Emacs never uses this. */ +/* re_match is like re_match_2 except it takes only a single string. */ + +int +re_match (struct re_pattern_buffer *bufp, const char *string, + int size, int pos, struct re_registers *regs) +{ + int result; +# ifdef MBS_SUPPORT + if (MB_CUR_MAX != 1) + result = wcs_re_match_2_internal (bufp, NULL, 0, string, size, + pos, regs, size, + NULL, 0, NULL, 0, NULL, NULL); + else +# endif + result = byte_re_match_2_internal (bufp, NULL, 0, string, size, + pos, regs, size); +# ifndef REGEX_MALLOC +# ifdef C_ALLOCA + alloca (0); +# endif +# endif + return result; +} +# ifdef _LIBC +weak_alias (__re_match, re_match) +# endif +#endif /* not emacs */ + +#endif /* not INSIDE_RECURSION */ + +#ifdef INSIDE_RECURSION +static boolean PREFIX(group_match_null_string_p) (UCHAR_T **p, + UCHAR_T *end, + PREFIX(register_info_type) *reg_info); +static boolean PREFIX(alt_match_null_string_p) (UCHAR_T *p, + UCHAR_T *end, + PREFIX(register_info_type) *reg_info); +static boolean PREFIX(common_op_match_null_string_p) (UCHAR_T **p, + UCHAR_T *end, + PREFIX(register_info_type) *reg_info); +static int PREFIX(bcmp_translate) (const CHAR_T *s1, const CHAR_T *s2, + int len, char *translate); +#else /* not INSIDE_RECURSION */ + +/* re_match_2 matches the compiled pattern in BUFP against the + the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1 + and SIZE2, respectively). We start matching at POS, and stop + matching at STOP. + + If REGS is non-null and the `no_sub' field of BUFP is nonzero, we + store offsets for the substring each group matched in REGS. See the + documentation for exactly how many groups we fill. + + We return -1 if no match, -2 if an internal error (such as the + failure stack overflowing). Otherwise, we return the length of the + matched substring. */ + +int +re_match_2 (struct re_pattern_buffer *bufp, const char *string1, int size1, + const char *string2, int size2, int pos, + struct re_registers *regs, int stop) +{ + int result; +# ifdef MBS_SUPPORT + if (MB_CUR_MAX != 1) + result = wcs_re_match_2_internal (bufp, string1, size1, string2, size2, + pos, regs, stop, + NULL, 0, NULL, 0, NULL, NULL); + else +# endif + result = byte_re_match_2_internal (bufp, string1, size1, string2, size2, + pos, regs, stop); + +#ifndef REGEX_MALLOC +# ifdef C_ALLOCA + alloca (0); +# endif +#endif + return result; +} +#ifdef _LIBC +weak_alias (__re_match_2, re_match_2) +#endif + +#endif /* not INSIDE_RECURSION */ + +#ifdef INSIDE_RECURSION + +#ifdef WCHAR +static int count_mbs_length (int *, int); + +/* This check the substring (from 0, to length) of the multibyte string, + to which offset_buffer correspond. And count how many wchar_t_characters + the substring occupy. We use offset_buffer to optimization. + See convert_mbs_to_wcs. */ + +static int +count_mbs_length(int *offset_buffer, int length) +{ + int upper, lower; + + /* Check whether the size is valid. */ + if (length < 0) + return -1; + + if (offset_buffer == NULL) + return 0; + + /* If there are no multibyte character, offset_buffer[i] == i. + Optmize for this case. */ + if (offset_buffer[length] == length) + return length; + + /* Set up upper with length. (because for all i, offset_buffer[i] >= i) */ + upper = length; + lower = 0; + + while (true) + { + int middle = (lower + upper) / 2; + if (middle == lower || middle == upper) + break; + if (offset_buffer[middle] > length) + upper = middle; + else if (offset_buffer[middle] < length) + lower = middle; + else + return middle; + } + + return -1; +} +#endif /* WCHAR */ + +/* This is a separate function so that we can force an alloca cleanup + afterwards. */ +#ifdef WCHAR +static int +wcs_re_match_2_internal (struct re_pattern_buffer *bufp, + const char *cstring1, int csize1, + const char *cstring2, int csize2, + int pos, + struct re_registers *regs, + int stop, + /* string1 == string2 == NULL means string1/2, size1/2 and + mbs_offset1/2 need seting up in this function. */ + /* We need wchar_t* buffers correspond to cstring1, cstring2. */ + wchar_t *string1, int size1, + wchar_t *string2, int size2, + /* offset buffer for optimizatoin. See convert_mbs_to_wc. */ + int *mbs_offset1, int *mbs_offset2) +#else /* BYTE */ +static int +byte_re_match_2_internal (struct re_pattern_buffer *bufp, + const char *string1, int size1, + const char *string2, int size2, + int pos, + struct re_registers *regs, int stop) +#endif /* BYTE */ +{ + /* General temporaries. */ + int mcnt; + UCHAR_T *p1; +#ifdef WCHAR + /* They hold whether each wchar_t is binary data or not. */ + char *is_binary = NULL; + /* If true, we can't free string1/2, mbs_offset1/2. */ + int cant_free_wcs_buf = 1; +#endif /* WCHAR */ + + /* Just past the end of the corresponding string. */ + const CHAR_T *end1, *end2; + + /* Pointers into string1 and string2, just past the last characters in + each to consider matching. */ + const CHAR_T *end_match_1, *end_match_2; + + /* Where we are in the data, and the end of the current string. */ + const CHAR_T *d, *dend; + + /* Where we are in the pattern, and the end of the pattern. */ +#ifdef WCHAR + UCHAR_T *pattern, *p; + register UCHAR_T *pend; +#else /* BYTE */ + UCHAR_T *p = bufp->buffer; + register UCHAR_T *pend = p + bufp->used; +#endif /* WCHAR */ + + /* Mark the opcode just after a start_memory, so we can test for an + empty subpattern when we get to the stop_memory. */ + UCHAR_T *just_past_start_mem = 0; + + /* We use this to map every character in the string. */ + RE_TRANSLATE_TYPE translate = bufp->translate; + + /* Failure point stack. Each place that can handle a failure further + down the line pushes a failure point on this stack. It consists of + restart, regend, and reg_info for all registers corresponding to + the subexpressions we're currently inside, plus the number of such + registers, and, finally, two char *'s. The first char * is where + to resume scanning the pattern; the second one is where to resume + scanning the strings. If the latter is zero, the failure point is + a ``dummy''; if a failure happens and the failure point is a dummy, + it gets discarded and the next next one is tried. */ +#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global. */ + PREFIX(fail_stack_type) fail_stack; +#endif +#ifdef DEBUG + static unsigned failure_id; + unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0; +#endif + +#ifdef REL_ALLOC + /* This holds the pointer to the failure stack, when + it is allocated relocatably. */ + fail_stack_elt_t *failure_stack_ptr; +#endif + + /* We fill all the registers internally, independent of what we + return, for use in backreferences. The number here includes + an element for register zero. */ + size_t num_regs = bufp->re_nsub + 1; + + /* The currently active registers. */ + active_reg_t lowest_active_reg = NO_LOWEST_ACTIVE_REG; + active_reg_t highest_active_reg = NO_HIGHEST_ACTIVE_REG; + + /* Information on the contents of registers. These are pointers into + the input strings; they record just what was matched (on this + attempt) by a subexpression part of the pattern, that is, the + regnum-th regstart pointer points to where in the pattern we began + matching and the regnum-th regend points to right after where we + stopped matching the regnum-th subexpression. (The zeroth register + keeps track of what the whole pattern matches.) */ +#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ + const CHAR_T **regstart, **regend; +#endif + + /* If a group that's operated upon by a repetition operator fails to + match anything, then the register for its start will need to be + restored because it will have been set to wherever in the string we + are when we last see its open-group operator. Similarly for a + register's end. */ +#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ + const CHAR_T **old_regstart, **old_regend; +#endif + + /* The is_active field of reg_info helps us keep track of which (possibly + nested) subexpressions we are currently in. The matched_something + field of reg_info[reg_num] helps us tell whether or not we have + matched any of the pattern so far this time through the reg_num-th + subexpression. These two fields get reset each time through any + loop their register is in. */ +#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global. */ + PREFIX(register_info_type) *reg_info; +#endif + + /* The following record the register info as found in the above + variables when we find a match better than any we've seen before. + This happens as we backtrack through the failure points, which in + turn happens only if we have not yet matched the entire string. */ + unsigned best_regs_set = false; +#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ + const CHAR_T **best_regstart, **best_regend; +#endif + + /* Logically, this is `best_regend[0]'. But we don't want to have to + allocate space for that if we're not allocating space for anything + else (see below). Also, we never need info about register 0 for + any of the other register vectors, and it seems rather a kludge to + treat `best_regend' differently than the rest. So we keep track of + the end of the best match so far in a separate variable. We + initialize this to NULL so that when we backtrack the first time + and need to test it, it's not garbage. */ + const CHAR_T *match_end = NULL; + + /* This helps SET_REGS_MATCHED avoid doing redundant work. */ + int set_regs_matched_done = 0; + + /* Used when we pop values we don't care about. */ +#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ + const CHAR_T **reg_dummy; + PREFIX(register_info_type) *reg_info_dummy; +#endif + +#ifdef DEBUG + /* Counts the total number of registers pushed. */ + unsigned num_regs_pushed = 0; +#endif + + DEBUG_PRINT1 ("\n\nEntering re_match_2.\n"); + + INIT_FAIL_STACK (); + +#ifdef MATCH_MAY_ALLOCATE + /* Do not bother to initialize all the register variables if there are + no groups in the pattern, as it takes a fair amount of time. If + there are groups, we include space for register 0 (the whole + pattern), even though we never use it, since it simplifies the + array indexing. We should fix this. */ + if (bufp->re_nsub) + { + regstart = REGEX_TALLOC (num_regs, const CHAR_T *); + regend = REGEX_TALLOC (num_regs, const CHAR_T *); + old_regstart = REGEX_TALLOC (num_regs, const CHAR_T *); + old_regend = REGEX_TALLOC (num_regs, const CHAR_T *); + best_regstart = REGEX_TALLOC (num_regs, const CHAR_T *); + best_regend = REGEX_TALLOC (num_regs, const CHAR_T *); + reg_info = REGEX_TALLOC (num_regs, PREFIX(register_info_type)); + reg_dummy = REGEX_TALLOC (num_regs, const CHAR_T *); + reg_info_dummy = REGEX_TALLOC (num_regs, PREFIX(register_info_type)); + + if (!(regstart && regend && old_regstart && old_regend && reg_info + && best_regstart && best_regend && reg_dummy && reg_info_dummy)) + { + FREE_VARIABLES (); + return -2; + } + } + else + { + /* We must initialize all our variables to NULL, so that + `FREE_VARIABLES' doesn't try to free them. */ + regstart = regend = old_regstart = old_regend = best_regstart + = best_regend = reg_dummy = NULL; + reg_info = reg_info_dummy = (PREFIX(register_info_type) *) NULL; + } +#endif /* MATCH_MAY_ALLOCATE */ + + /* The starting position is bogus. */ +#ifdef WCHAR + if (pos < 0 || pos > csize1 + csize2) +#else /* BYTE */ + if (pos < 0 || pos > size1 + size2) +#endif + { + FREE_VARIABLES (); + return -1; + } + +#ifdef WCHAR + /* Allocate wchar_t array for string1 and string2 and + fill them with converted string. */ + if (string1 == NULL && string2 == NULL) + { + /* We need seting up buffers here. */ + + /* We must free wcs buffers in this function. */ + cant_free_wcs_buf = 0; + + if (csize1 != 0) + { + string1 = REGEX_TALLOC (csize1 + 1, CHAR_T); + mbs_offset1 = REGEX_TALLOC (csize1 + 1, int); + is_binary = REGEX_TALLOC (csize1 + 1, char); + if (!string1 || !mbs_offset1 || !is_binary) + { + FREE_VAR (string1); + FREE_VAR (mbs_offset1); + FREE_VAR (is_binary); + return -2; + } + } + if (csize2 != 0) + { + string2 = REGEX_TALLOC (csize2 + 1, CHAR_T); + mbs_offset2 = REGEX_TALLOC (csize2 + 1, int); + is_binary = REGEX_TALLOC (csize2 + 1, char); + if (!string2 || !mbs_offset2 || !is_binary) + { + FREE_VAR (string1); + FREE_VAR (mbs_offset1); + FREE_VAR (string2); + FREE_VAR (mbs_offset2); + FREE_VAR (is_binary); + return -2; + } + size2 = convert_mbs_to_wcs(string2, cstring2, csize2, + mbs_offset2, is_binary); + string2[size2] = L'\0'; /* for a sentinel */ + FREE_VAR (is_binary); + } + } + + /* We need to cast pattern to (wchar_t*), because we casted this compiled + pattern to (char*) in regex_compile. */ + p = pattern = (CHAR_T*)bufp->buffer; + pend = (CHAR_T*)(bufp->buffer + bufp->used); + +#endif /* WCHAR */ + + /* Initialize subexpression text positions to -1 to mark ones that no + start_memory/stop_memory has been seen for. Also initialize the + register information struct. */ + for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++) + { + regstart[mcnt] = regend[mcnt] + = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE; + + REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE; + IS_ACTIVE (reg_info[mcnt]) = 0; + MATCHED_SOMETHING (reg_info[mcnt]) = 0; + EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0; + } + + /* We move `string1' into `string2' if the latter's empty -- but not if + `string1' is null. */ + if (size2 == 0 && string1 != NULL) + { + string2 = string1; + size2 = size1; + string1 = 0; + size1 = 0; +#ifdef WCHAR + mbs_offset2 = mbs_offset1; + csize2 = csize1; + mbs_offset1 = NULL; + csize1 = 0; +#endif + } + end1 = string1 + size1; + end2 = string2 + size2; + + /* Compute where to stop matching, within the two strings. */ +#ifdef WCHAR + if (stop <= csize1) + { + mcnt = count_mbs_length(mbs_offset1, stop); + end_match_1 = string1 + mcnt; + end_match_2 = string2; + } + else + { + if (stop > csize1 + csize2) + stop = csize1 + csize2; + end_match_1 = end1; + mcnt = count_mbs_length(mbs_offset2, stop-csize1); + end_match_2 = string2 + mcnt; + } + if (mcnt < 0) + { /* count_mbs_length return error. */ + FREE_VARIABLES (); + return -1; + } +#else + if (stop <= size1) + { + end_match_1 = string1 + stop; + end_match_2 = string2; + } + else + { + end_match_1 = end1; + end_match_2 = string2 + stop - size1; + } +#endif /* WCHAR */ + + /* `p' scans through the pattern as `d' scans through the data. + `dend' is the end of the input string that `d' points within. `d' + is advanced into the following input string whenever necessary, but + this happens before fetching; therefore, at the beginning of the + loop, `d' can be pointing at the end of a string, but it cannot + equal `string2'. */ +#ifdef WCHAR + if (size1 > 0 && pos <= csize1) + { + mcnt = count_mbs_length(mbs_offset1, pos); + d = string1 + mcnt; + dend = end_match_1; + } + else + { + mcnt = count_mbs_length(mbs_offset2, pos-csize1); + d = string2 + mcnt; + dend = end_match_2; + } + + if (mcnt < 0) + { /* count_mbs_length return error. */ + FREE_VARIABLES (); + return -1; + } +#else + if (size1 > 0 && pos <= size1) + { + d = string1 + pos; + dend = end_match_1; + } + else + { + d = string2 + pos - size1; + dend = end_match_2; + } +#endif /* WCHAR */ + + DEBUG_PRINT1 ("The compiled pattern is:\n"); + DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend); + DEBUG_PRINT1 ("The string to match is: `"); + DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2); + DEBUG_PRINT1 ("'\n"); + + /* This loops over pattern commands. It exits by returning from the + function if the match is complete, or it drops through if the match + fails at this starting point in the input data. */ + for (;;) + { +#ifdef _LIBC + DEBUG_PRINT2 ("\n%p: ", p); +#else + DEBUG_PRINT2 ("\n0x%x: ", p); +#endif + + if (p == pend) + { /* End of pattern means we might have succeeded. */ + DEBUG_PRINT1 ("end of pattern ... "); + + /* If we haven't matched the entire string, and we want the + longest match, try backtracking. */ + if (d != end_match_2) + { + /* 1 if this match ends in the same string (string1 or string2) + as the best previous match. */ + boolean same_str_p = (FIRST_STRING_P (match_end) + == MATCHING_IN_FIRST_STRING); + /* 1 if this match is the best seen so far. */ + boolean best_match_p; + + /* AIX compiler got confused when this was combined + with the previous declaration. */ + if (same_str_p) + best_match_p = d > match_end; + else + best_match_p = !MATCHING_IN_FIRST_STRING; + + DEBUG_PRINT1 ("backtracking.\n"); + + if (!FAIL_STACK_EMPTY ()) + { /* More failure points to try. */ + + /* If exceeds best match so far, save it. */ + if (!best_regs_set || best_match_p) + { + best_regs_set = true; + match_end = d; + + DEBUG_PRINT1 ("\nSAVING match as best so far.\n"); + + for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++) + { + best_regstart[mcnt] = regstart[mcnt]; + best_regend[mcnt] = regend[mcnt]; + } + } + goto fail; + } + + /* If no failure points, don't restore garbage. And if + last match is real best match, don't restore second + best one. */ + else if (best_regs_set && !best_match_p) + { + restore_best_regs: + /* Restore best match. It may happen that `dend == + end_match_1' while the restored d is in string2. + For example, the pattern `x.*y.*z' against the + strings `x-' and `y-z-', if the two strings are + not consecutive in memory. */ + DEBUG_PRINT1 ("Restoring best registers.\n"); + + d = match_end; + dend = ((d >= string1 && d <= end1) + ? end_match_1 : end_match_2); + + for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++) + { + regstart[mcnt] = best_regstart[mcnt]; + regend[mcnt] = best_regend[mcnt]; + } + } + } /* d != end_match_2 */ + + succeed_label: + DEBUG_PRINT1 ("Accepting match.\n"); + /* If caller wants register contents data back, do it. */ + if (regs && !bufp->no_sub) + { + /* Have the register data arrays been allocated? */ + if (bufp->regs_allocated == REGS_UNALLOCATED) + { /* No. So allocate them with malloc. We need one + extra element beyond `num_regs' for the `-1' marker + GNU code uses. */ + regs->num_regs = MAX (RE_NREGS, num_regs + 1); + regs->start = TALLOC (regs->num_regs, regoff_t); + regs->end = TALLOC (regs->num_regs, regoff_t); + if (regs->start == NULL || regs->end == NULL) + { + FREE_VARIABLES (); + return -2; + } + bufp->regs_allocated = REGS_REALLOCATE; + } + else if (bufp->regs_allocated == REGS_REALLOCATE) + { /* Yes. If we need more elements than were already + allocated, reallocate them. If we need fewer, just + leave it alone. */ + if (regs->num_regs < num_regs + 1) + { + regs->num_regs = num_regs + 1; + RETALLOC (regs->start, regs->num_regs, regoff_t); + RETALLOC (regs->end, regs->num_regs, regoff_t); + if (regs->start == NULL || regs->end == NULL) + { + FREE_VARIABLES (); + return -2; + } + } + } + else + { + /* These braces fend off a "empty body in an else-statement" + warning under GCC when assert expands to nothing. */ + assert (bufp->regs_allocated == REGS_FIXED); + } + + /* Convert the pointer data in `regstart' and `regend' to + indices. Register zero has to be set differently, + since we haven't kept track of any info for it. */ + if (regs->num_regs > 0) + { + regs->start[0] = pos; +#ifdef WCHAR + if (MATCHING_IN_FIRST_STRING) + regs->end[0] = mbs_offset1 != NULL ? + mbs_offset1[d-string1] : 0; + else + regs->end[0] = csize1 + (mbs_offset2 != NULL ? + mbs_offset2[d-string2] : 0); +#else + regs->end[0] = (MATCHING_IN_FIRST_STRING + ? ((regoff_t) (d - string1)) + : ((regoff_t) (d - string2 + size1))); +#endif /* WCHAR */ + } + + /* Go through the first `min (num_regs, regs->num_regs)' + registers, since that is all we initialized. */ + for (mcnt = 1; (unsigned) mcnt < MIN (num_regs, regs->num_regs); + mcnt++) + { + if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt])) + regs->start[mcnt] = regs->end[mcnt] = -1; + else + { + regs->start[mcnt] + = (regoff_t) POINTER_TO_OFFSET (regstart[mcnt]); + regs->end[mcnt] + = (regoff_t) POINTER_TO_OFFSET (regend[mcnt]); + } + } + + /* If the regs structure we return has more elements than + were in the pattern, set the extra elements to -1. If + we (re)allocated the registers, this is the case, + because we always allocate enough to have at least one + -1 at the end. */ + for (mcnt = num_regs; (unsigned) mcnt < regs->num_regs; mcnt++) + regs->start[mcnt] = regs->end[mcnt] = -1; + } /* regs && !bufp->no_sub */ + + DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n", + nfailure_points_pushed, nfailure_points_popped, + nfailure_points_pushed - nfailure_points_popped); + DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed); + +#ifdef WCHAR + if (MATCHING_IN_FIRST_STRING) + mcnt = mbs_offset1 != NULL ? mbs_offset1[d-string1] : 0; + else + mcnt = (mbs_offset2 != NULL ? mbs_offset2[d-string2] : 0) + + csize1; + mcnt -= pos; +#else + mcnt = d - pos - (MATCHING_IN_FIRST_STRING + ? string1 + : string2 - size1); +#endif /* WCHAR */ + + DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt); + + FREE_VARIABLES (); + return mcnt; + } + + /* Otherwise match next pattern command. */ + switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++)) + { + /* Ignore these. Used to ignore the n of succeed_n's which + currently have n == 0. */ + case no_op: + DEBUG_PRINT1 ("EXECUTING no_op.\n"); + break; + + case succeed: + DEBUG_PRINT1 ("EXECUTING succeed.\n"); + goto succeed_label; + + /* Match the next n pattern characters exactly. The following + byte in the pattern defines n, and the n bytes after that + are the characters to match. */ + case exactn: +#ifdef MBS_SUPPORT + case exactn_bin: +#endif + mcnt = *p++; + DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt); + + /* This is written out as an if-else so we don't waste time + testing `translate' inside the loop. */ + if (translate) + { + do + { + PREFETCH (); +#ifdef WCHAR + if (*d <= 0xff) + { + if ((UCHAR_T) translate[(unsigned char) *d++] + != (UCHAR_T) *p++) + goto fail; + } + else + { + if (*d++ != (CHAR_T) *p++) + goto fail; + } +#else + if ((UCHAR_T) translate[(unsigned char) *d++] + != (UCHAR_T) *p++) + goto fail; +#endif /* WCHAR */ + } + while (--mcnt); + } + else + { + do + { + PREFETCH (); + if (*d++ != (CHAR_T) *p++) goto fail; + } + while (--mcnt); + } + SET_REGS_MATCHED (); + break; + + + /* Match any character except possibly a newline or a null. */ + case anychar: + DEBUG_PRINT1 ("EXECUTING anychar.\n"); + + PREFETCH (); + + if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n') + || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000')) + goto fail; + + SET_REGS_MATCHED (); + DEBUG_PRINT2 (" Matched `%ld'.\n", (long int) *d); + d++; + break; + + + case charset: + case charset_not: + { + register UCHAR_T c; +#ifdef WCHAR + unsigned int i, char_class_length, coll_symbol_length, + equiv_class_length, ranges_length, chars_length, length; + CHAR_T *workp, *workp2, *charset_top; +#define WORK_BUFFER_SIZE 128 + CHAR_T str_buf[WORK_BUFFER_SIZE]; +# ifdef _LIBC + uint32_t nrules; +# endif /* _LIBC */ +#endif /* WCHAR */ + boolean negate = (re_opcode_t) *(p - 1) == charset_not; + + DEBUG_PRINT2 ("EXECUTING charset%s.\n", negate ? "_not" : ""); + PREFETCH (); + c = TRANSLATE (*d); /* The character to match. */ +#ifdef WCHAR +# ifdef _LIBC + nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); +# endif /* _LIBC */ + charset_top = p - 1; + char_class_length = *p++; + coll_symbol_length = *p++; + equiv_class_length = *p++; + ranges_length = *p++; + chars_length = *p++; + /* p points charset[6], so the address of the next instruction + (charset[l+m+n+2o+k+p']) equals p[l+m+n+2*o+p'], + where l=length of char_classes, m=length of collating_symbol, + n=equivalence_class, o=length of char_range, + p'=length of character. */ + workp = p; + /* Update p to indicate the next instruction. */ + p += char_class_length + coll_symbol_length+ equiv_class_length + + 2*ranges_length + chars_length; + + /* match with char_class? */ + for (i = 0; i < char_class_length ; i += CHAR_CLASS_SIZE) + { + wctype_t wctype; + uintptr_t alignedp = ((uintptr_t)workp + + __alignof__(wctype_t) - 1) + & ~(uintptr_t)(__alignof__(wctype_t) - 1); + wctype = *((wctype_t*)alignedp); + workp += CHAR_CLASS_SIZE; +# ifdef _LIBC + if (__iswctype((wint_t)c, wctype)) + goto char_set_matched; +# else + if (iswctype((wint_t)c, wctype)) + goto char_set_matched; +# endif + } + + /* match with collating_symbol? */ +# ifdef _LIBC + if (nrules != 0) + { + const unsigned char *extra = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB); + + for (workp2 = workp + coll_symbol_length ; workp < workp2 ; + workp++) + { + int32_t *wextra; + wextra = (int32_t*)(extra + *workp++); + for (i = 0; i < *wextra; ++i) + if (TRANSLATE(d[i]) != wextra[1 + i]) + break; + + if (i == *wextra) + { + /* Update d, however d will be incremented at + char_set_matched:, we decrement d here. */ + d += i - 1; + goto char_set_matched; + } + } + } + else /* (nrules == 0) */ +# endif + /* If we can't look up collation data, we use wcscoll + instead. */ + { + for (workp2 = workp + coll_symbol_length ; workp < workp2 ;) + { + const CHAR_T *backup_d = d, *backup_dend = dend; +# ifdef _LIBC + length = __wcslen (workp); +# else + length = wcslen (workp); +# endif + + /* If wcscoll(the collating symbol, whole string) > 0, + any substring of the string never match with the + collating symbol. */ +# ifdef _LIBC + if (__wcscoll (workp, d) > 0) +# else + if (wcscoll (workp, d) > 0) +# endif + { + workp += length + 1; + continue; + } + + /* First, we compare the collating symbol with + the first character of the string. + If it don't match, we add the next character to + the compare buffer in turn. */ + for (i = 0 ; i < WORK_BUFFER_SIZE-1 ; i++, d++) + { + int match; + if (d == dend) + { + if (dend == end_match_2) + break; + d = string2; + dend = end_match_2; + } + + /* add next character to the compare buffer. */ + str_buf[i] = TRANSLATE(*d); + str_buf[i+1] = '\0'; + +# ifdef _LIBC + match = __wcscoll (workp, str_buf); +# else + match = wcscoll (workp, str_buf); +# endif + if (match == 0) + goto char_set_matched; + + if (match < 0) + /* (str_buf > workp) indicate (str_buf + X > workp), + because for all X (str_buf + X > str_buf). + So we don't need continue this loop. */ + break; + + /* Otherwise(str_buf < workp), + (str_buf+next_character) may equals (workp). + So we continue this loop. */ + } + /* not matched */ + d = backup_d; + dend = backup_dend; + workp += length + 1; + } + } + /* match with equivalence_class? */ +# ifdef _LIBC + if (nrules != 0) + { + const CHAR_T *backup_d = d, *backup_dend = dend; + /* Try to match the equivalence class against + those known to the collate implementation. */ + const int32_t *table; + const int32_t *weights; + const int32_t *extra; + const int32_t *indirect; + int32_t idx, idx2; + wint_t *cp; + size_t len; + + /* This #include defines a local function! */ +# include + + table = (const int32_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEWC); + weights = (const wint_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTWC); + extra = (const wint_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAWC); + indirect = (const int32_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTWC); + + /* Write 1 collating element to str_buf, and + get its index. */ + idx2 = 0; + + for (i = 0 ; idx2 == 0 && i < WORK_BUFFER_SIZE - 1; i++) + { + cp = (wint_t*)str_buf; + if (d == dend) + { + if (dend == end_match_2) + break; + d = string2; + dend = end_match_2; + } + str_buf[i] = TRANSLATE(*(d+i)); + str_buf[i+1] = '\0'; /* sentinel */ + idx2 = findidx ((const wint_t**)&cp); + } + + /* Update d, however d will be incremented at + char_set_matched:, we decrement d here. */ + d = backup_d + ((wchar_t*)cp - (wchar_t*)str_buf - 1); + if (d >= dend) + { + if (dend == end_match_2) + d = dend; + else + { + d = string2; + dend = end_match_2; + } + } + + len = weights[idx2]; + + for (workp2 = workp + equiv_class_length ; workp < workp2 ; + workp++) + { + idx = (int32_t)*workp; + /* We already checked idx != 0 in regex_compile. */ + + if (idx2 != 0 && len == weights[idx]) + { + int cnt = 0; + while (cnt < len && (weights[idx + 1 + cnt] + == weights[idx2 + 1 + cnt])) + ++cnt; + + if (cnt == len) + goto char_set_matched; + } + } + /* not matched */ + d = backup_d; + dend = backup_dend; + } + else /* (nrules == 0) */ +# endif + /* If we can't look up collation data, we use wcscoll + instead. */ + { + for (workp2 = workp + equiv_class_length ; workp < workp2 ;) + { + const CHAR_T *backup_d = d, *backup_dend = dend; +# ifdef _LIBC + length = __wcslen (workp); +# else + length = wcslen (workp); +# endif + + /* If wcscoll(the collating symbol, whole string) > 0, + any substring of the string never match with the + collating symbol. */ +# ifdef _LIBC + if (__wcscoll (workp, d) > 0) +# else + if (wcscoll (workp, d) > 0) +# endif + { + workp += length + 1; + break; + } + + /* First, we compare the equivalence class with + the first character of the string. + If it don't match, we add the next character to + the compare buffer in turn. */ + for (i = 0 ; i < WORK_BUFFER_SIZE - 1 ; i++, d++) + { + int match; + if (d == dend) + { + if (dend == end_match_2) + break; + d = string2; + dend = end_match_2; + } + + /* add next character to the compare buffer. */ + str_buf[i] = TRANSLATE(*d); + str_buf[i+1] = '\0'; + +# ifdef _LIBC + match = __wcscoll (workp, str_buf); +# else + match = wcscoll (workp, str_buf); +# endif + + if (match == 0) + goto char_set_matched; + + if (match < 0) + /* (str_buf > workp) indicate (str_buf + X > workp), + because for all X (str_buf + X > str_buf). + So we don't need continue this loop. */ + break; + + /* Otherwise(str_buf < workp), + (str_buf+next_character) may equals (workp). + So we continue this loop. */ + } + /* not matched */ + d = backup_d; + dend = backup_dend; + workp += length + 1; + } + } + + /* match with char_range? */ +# ifdef _LIBC + if (nrules != 0) + { + uint32_t collseqval; + const char *collseq = (const char *) + _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQWC); + + collseqval = collseq_table_lookup (collseq, c); + + for (; workp < p - chars_length ;) + { + uint32_t start_val, end_val; + + /* We already compute the collation sequence value + of the characters (or collating symbols). */ + start_val = (uint32_t) *workp++; /* range_start */ + end_val = (uint32_t) *workp++; /* range_end */ + + if (start_val <= collseqval && collseqval <= end_val) + goto char_set_matched; + } + } + else +# endif + { + /* We set range_start_char at str_buf[0], range_end_char + at str_buf[4], and compared char at str_buf[2]. */ + str_buf[1] = 0; + str_buf[2] = c; + str_buf[3] = 0; + str_buf[5] = 0; + for (; workp < p - chars_length ;) + { + wchar_t *range_start_char, *range_end_char; + + /* match if (range_start_char <= c <= range_end_char). */ + + /* If range_start(or end) < 0, we assume -range_start(end) + is the offset of the collating symbol which is specified + as the character of the range start(end). */ + + /* range_start */ + if (*workp < 0) + range_start_char = charset_top - (*workp++); + else + { + str_buf[0] = *workp++; + range_start_char = str_buf; + } + + /* range_end */ + if (*workp < 0) + range_end_char = charset_top - (*workp++); + else + { + str_buf[4] = *workp++; + range_end_char = str_buf + 4; + } + +# ifdef _LIBC + if (__wcscoll (range_start_char, str_buf+2) <= 0 + && __wcscoll (str_buf+2, range_end_char) <= 0) +# else + if (wcscoll (range_start_char, str_buf+2) <= 0 + && wcscoll (str_buf+2, range_end_char) <= 0) +# endif + goto char_set_matched; + } + } + + /* match with char? */ + for (; workp < p ; workp++) + if (c == *workp) + goto char_set_matched; + + negate = !negate; + + char_set_matched: + if (negate) goto fail; +#else + /* Cast to `unsigned' instead of `unsigned char' in case the + bit list is a full 32 bytes long. */ + if (c < (unsigned) (*p * BYTEWIDTH) + && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) + negate = !negate; + + p += 1 + *p; + + if (!negate) goto fail; +#undef WORK_BUFFER_SIZE +#endif /* WCHAR */ + SET_REGS_MATCHED (); + d++; + break; + } + + + /* The beginning of a group is represented by start_memory. + The arguments are the register number in the next byte, and the + number of groups inner to this one in the next. The text + matched within the group is recorded (in the internal + registers data structure) under the register number. */ + case start_memory: + DEBUG_PRINT3 ("EXECUTING start_memory %ld (%ld):\n", + (long int) *p, (long int) p[1]); + + /* Find out if this group can match the empty string. */ + p1 = p; /* To send to group_match_null_string_p. */ + + if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE) + REG_MATCH_NULL_STRING_P (reg_info[*p]) + = PREFIX(group_match_null_string_p) (&p1, pend, reg_info); + + /* Save the position in the string where we were the last time + we were at this open-group operator in case the group is + operated upon by a repetition operator, e.g., with `(a*)*b' + against `ab'; then we want to ignore where we are now in + the string in case this attempt to match fails. */ + old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) + ? REG_UNSET (regstart[*p]) ? d : regstart[*p] + : regstart[*p]; + DEBUG_PRINT2 (" old_regstart: %d\n", + POINTER_TO_OFFSET (old_regstart[*p])); + + regstart[*p] = d; + DEBUG_PRINT2 (" regstart: %d\n", POINTER_TO_OFFSET (regstart[*p])); + + IS_ACTIVE (reg_info[*p]) = 1; + MATCHED_SOMETHING (reg_info[*p]) = 0; + + /* Clear this whenever we change the register activity status. */ + set_regs_matched_done = 0; + + /* This is the new highest active register. */ + highest_active_reg = *p; + + /* If nothing was active before, this is the new lowest active + register. */ + if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) + lowest_active_reg = *p; + + /* Move past the register number and inner group count. */ + p += 2; + just_past_start_mem = p; + + break; + + + /* The stop_memory opcode represents the end of a group. Its + arguments are the same as start_memory's: the register + number, and the number of inner groups. */ + case stop_memory: + DEBUG_PRINT3 ("EXECUTING stop_memory %ld (%ld):\n", + (long int) *p, (long int) p[1]); + + /* We need to save the string position the last time we were at + this close-group operator in case the group is operated + upon by a repetition operator, e.g., with `((a*)*(b*)*)*' + against `aba'; then we want to ignore where we are now in + the string in case this attempt to match fails. */ + old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) + ? REG_UNSET (regend[*p]) ? d : regend[*p] + : regend[*p]; + DEBUG_PRINT2 (" old_regend: %d\n", + POINTER_TO_OFFSET (old_regend[*p])); + + regend[*p] = d; + DEBUG_PRINT2 (" regend: %d\n", POINTER_TO_OFFSET (regend[*p])); + + /* This register isn't active anymore. */ + IS_ACTIVE (reg_info[*p]) = 0; + + /* Clear this whenever we change the register activity status. */ + set_regs_matched_done = 0; + + /* If this was the only register active, nothing is active + anymore. */ + if (lowest_active_reg == highest_active_reg) + { + lowest_active_reg = NO_LOWEST_ACTIVE_REG; + highest_active_reg = NO_HIGHEST_ACTIVE_REG; + } + else + { /* We must scan for the new highest active register, since + it isn't necessarily one less than now: consider + (a(b)c(d(e)f)g). When group 3 ends, after the f), the + new highest active register is 1. */ + UCHAR_T r = *p - 1; + while (r > 0 && !IS_ACTIVE (reg_info[r])) + r--; + + /* If we end up at register zero, that means that we saved + the registers as the result of an `on_failure_jump', not + a `start_memory', and we jumped to past the innermost + `stop_memory'. For example, in ((.)*) we save + registers 1 and 2 as a result of the *, but when we pop + back to the second ), we are at the stop_memory 1. + Thus, nothing is active. */ + if (r == 0) + { + lowest_active_reg = NO_LOWEST_ACTIVE_REG; + highest_active_reg = NO_HIGHEST_ACTIVE_REG; + } + else + highest_active_reg = r; + } + + /* If just failed to match something this time around with a + group that's operated on by a repetition operator, try to + force exit from the ``loop'', and restore the register + information for this group that we had before trying this + last match. */ + if ((!MATCHED_SOMETHING (reg_info[*p]) + || just_past_start_mem == p - 1) + && (p + 2) < pend) + { + boolean is_a_jump_n = false; + + p1 = p + 2; + mcnt = 0; + switch ((re_opcode_t) *p1++) + { + case jump_n: + is_a_jump_n = true; + case pop_failure_jump: + case maybe_pop_jump: + case jump: + case dummy_failure_jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + if (is_a_jump_n) + p1 += OFFSET_ADDRESS_SIZE; + break; + + default: + /* do nothing */ ; + } + p1 += mcnt; + + /* If the next operation is a jump backwards in the pattern + to an on_failure_jump right before the start_memory + corresponding to this stop_memory, exit from the loop + by forcing a failure after pushing on the stack the + on_failure_jump's jump in the pattern, and d. */ + if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump + && (re_opcode_t) p1[1+OFFSET_ADDRESS_SIZE] == start_memory + && p1[2+OFFSET_ADDRESS_SIZE] == *p) + { + /* If this group ever matched anything, then restore + what its registers were before trying this last + failed match, e.g., with `(a*)*b' against `ab' for + regstart[1], and, e.g., with `((a*)*(b*)*)*' + against `aba' for regend[3]. + + Also restore the registers for inner groups for, + e.g., `((a*)(b*))*' against `aba' (register 3 would + otherwise get trashed). */ + + if (EVER_MATCHED_SOMETHING (reg_info[*p])) + { + unsigned r; + + EVER_MATCHED_SOMETHING (reg_info[*p]) = 0; + + /* Restore this and inner groups' (if any) registers. */ + for (r = *p; r < (unsigned) *p + (unsigned) *(p + 1); + r++) + { + regstart[r] = old_regstart[r]; + + /* xx why this test? */ + if (old_regend[r] >= regstart[r]) + regend[r] = old_regend[r]; + } + } + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + PUSH_FAILURE_POINT (p1 + mcnt, d, -2); + + goto fail; + } + } + + /* Move past the register number and the inner group count. */ + p += 2; + break; + + + /* \ has been turned into a `duplicate' command which is + followed by the numeric value of as the register number. */ + case duplicate: + { + register const CHAR_T *d2, *dend2; + int regno = *p++; /* Get which register to match against. */ + DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno); + + /* Can't back reference a group which we've never matched. */ + if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno])) + goto fail; + + /* Where in input to try to start matching. */ + d2 = regstart[regno]; + + /* Where to stop matching; if both the place to start and + the place to stop matching are in the same string, then + set to the place to stop, otherwise, for now have to use + the end of the first string. */ + + dend2 = ((FIRST_STRING_P (regstart[regno]) + == FIRST_STRING_P (regend[regno])) + ? regend[regno] : end_match_1); + for (;;) + { + /* If necessary, advance to next segment in register + contents. */ + while (d2 == dend2) + { + if (dend2 == end_match_2) break; + if (dend2 == regend[regno]) break; + + /* End of string1 => advance to string2. */ + d2 = string2; + dend2 = regend[regno]; + } + /* At end of register contents => success */ + if (d2 == dend2) break; + + /* If necessary, advance to next segment in data. */ + PREFETCH (); + + /* How many characters left in this segment to match. */ + mcnt = dend - d; + + /* Want how many consecutive characters we can match in + one shot, so, if necessary, adjust the count. */ + if (mcnt > dend2 - d2) + mcnt = dend2 - d2; + + /* Compare that many; failure if mismatch, else move + past them. */ + if (translate + ? PREFIX(bcmp_translate) (d, d2, mcnt, translate) + : memcmp (d, d2, mcnt*sizeof(UCHAR_T))) + goto fail; + d += mcnt, d2 += mcnt; + + /* Do this because we've match some characters. */ + SET_REGS_MATCHED (); + } + } + break; + + + /* begline matches the empty string at the beginning of the string + (unless `not_bol' is set in `bufp'), and, if + `newline_anchor' is set, after newlines. */ + case begline: + DEBUG_PRINT1 ("EXECUTING begline.\n"); + + if (AT_STRINGS_BEG (d)) + { + if (!bufp->not_bol) break; + } + else if (d[-1] == '\n' && bufp->newline_anchor) + { + break; + } + /* In all other cases, we fail. */ + goto fail; + + + /* endline is the dual of begline. */ + case endline: + DEBUG_PRINT1 ("EXECUTING endline.\n"); + + if (AT_STRINGS_END (d)) + { + if (!bufp->not_eol) break; + } + + /* We have to ``prefetch'' the next character. */ + else if ((d == end1 ? *string2 : *d) == '\n' + && bufp->newline_anchor) + { + break; + } + goto fail; + + + /* Match at the very beginning of the data. */ + case begbuf: + DEBUG_PRINT1 ("EXECUTING begbuf.\n"); + if (AT_STRINGS_BEG (d)) + break; + goto fail; + + + /* Match at the very end of the data. */ + case endbuf: + DEBUG_PRINT1 ("EXECUTING endbuf.\n"); + if (AT_STRINGS_END (d)) + break; + goto fail; + + + /* on_failure_keep_string_jump is used to optimize `.*\n'. It + pushes NULL as the value for the string on the stack. Then + `pop_failure_point' will keep the current value for the + string, instead of restoring it. To see why, consider + matching `foo\nbar' against `.*\n'. The .* matches the foo; + then the . fails against the \n. But the next thing we want + to do is match the \n against the \n; if we restored the + string value, we would be back at the foo. + + Because this is used only in specific cases, we don't need to + check all the things that `on_failure_jump' does, to make + sure the right things get saved on the stack. Hence we don't + share its code. The only reason to push anything on the + stack at all is that otherwise we would have to change + `anychar's code to do something besides goto fail in this + case; that seems worse than this. */ + case on_failure_keep_string_jump: + DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump"); + + EXTRACT_NUMBER_AND_INCR (mcnt, p); +#ifdef _LIBC + DEBUG_PRINT3 (" %d (to %p):\n", mcnt, p + mcnt); +#else + DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt); +#endif + + PUSH_FAILURE_POINT (p + mcnt, NULL, -2); + break; + + + /* Uses of on_failure_jump: + + Each alternative starts with an on_failure_jump that points + to the beginning of the next alternative. Each alternative + except the last ends with a jump that in effect jumps past + the rest of the alternatives. (They really jump to the + ending jump of the following alternative, because tensioning + these jumps is a hassle.) + + Repeats start with an on_failure_jump that points past both + the repetition text and either the following jump or + pop_failure_jump back to this on_failure_jump. */ + case on_failure_jump: + on_failure: + DEBUG_PRINT1 ("EXECUTING on_failure_jump"); + + EXTRACT_NUMBER_AND_INCR (mcnt, p); +#ifdef _LIBC + DEBUG_PRINT3 (" %d (to %p)", mcnt, p + mcnt); +#else + DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt); +#endif + + /* If this on_failure_jump comes right before a group (i.e., + the original * applied to a group), save the information + for that group and all inner ones, so that if we fail back + to this point, the group's information will be correct. + For example, in \(a*\)*\1, we need the preceding group, + and in \(zz\(a*\)b*\)\2, we need the inner group. */ + + /* We can't use `p' to check ahead because we push + a failure point to `p + mcnt' after we do this. */ + p1 = p; + + /* We need to skip no_op's before we look for the + start_memory in case this on_failure_jump is happening as + the result of a completed succeed_n, as in \(a\)\{1,3\}b\1 + against aba. */ + while (p1 < pend && (re_opcode_t) *p1 == no_op) + p1++; + + if (p1 < pend && (re_opcode_t) *p1 == start_memory) + { + /* We have a new highest active register now. This will + get reset at the start_memory we are about to get to, + but we will have saved all the registers relevant to + this repetition op, as described above. */ + highest_active_reg = *(p1 + 1) + *(p1 + 2); + if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) + lowest_active_reg = *(p1 + 1); + } + + DEBUG_PRINT1 (":\n"); + PUSH_FAILURE_POINT (p + mcnt, d, -2); + break; + + + /* A smart repeat ends with `maybe_pop_jump'. + We change it to either `pop_failure_jump' or `jump'. */ + case maybe_pop_jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt); + { + register UCHAR_T *p2 = p; + + /* Compare the beginning of the repeat with what in the + pattern follows its end. If we can establish that there + is nothing that they would both match, i.e., that we + would have to backtrack because of (as in, e.g., `a*a') + then we can change to pop_failure_jump, because we'll + never have to backtrack. + + This is not true in the case of alternatives: in + `(a|ab)*' we do need to backtrack to the `ab' alternative + (e.g., if the string was `ab'). But instead of trying to + detect that here, the alternative has put on a dummy + failure point which is what we will end up popping. */ + + /* Skip over open/close-group commands. + If what follows this loop is a ...+ construct, + look at what begins its body, since we will have to + match at least one of that. */ + while (1) + { + if (p2 + 2 < pend + && ((re_opcode_t) *p2 == stop_memory + || (re_opcode_t) *p2 == start_memory)) + p2 += 3; + else if (p2 + 2 + 2 * OFFSET_ADDRESS_SIZE < pend + && (re_opcode_t) *p2 == dummy_failure_jump) + p2 += 2 + 2 * OFFSET_ADDRESS_SIZE; + else + break; + } + + p1 = p + mcnt; + /* p1[0] ... p1[2] are the `on_failure_jump' corresponding + to the `maybe_finalize_jump' of this case. Examine what + follows. */ + + /* If we're at the end of the pattern, we can change. */ + if (p2 == pend) + { + /* Consider what happens when matching ":\(.*\)" + against ":/". I don't really understand this code + yet. */ + p[-(1+OFFSET_ADDRESS_SIZE)] = (UCHAR_T) + pop_failure_jump; + DEBUG_PRINT1 + (" End of pattern: change to `pop_failure_jump'.\n"); + } + + else if ((re_opcode_t) *p2 == exactn +#ifdef MBS_SUPPORT + || (re_opcode_t) *p2 == exactn_bin +#endif + || (bufp->newline_anchor && (re_opcode_t) *p2 == endline)) + { + register UCHAR_T c + = *p2 == (UCHAR_T) endline ? '\n' : p2[2]; + + if (((re_opcode_t) p1[1+OFFSET_ADDRESS_SIZE] == exactn +#ifdef MBS_SUPPORT + || (re_opcode_t) p1[1+OFFSET_ADDRESS_SIZE] == exactn_bin +#endif + ) && p1[3+OFFSET_ADDRESS_SIZE] != c) + { + p[-(1+OFFSET_ADDRESS_SIZE)] = (UCHAR_T) + pop_failure_jump; +#ifdef WCHAR + DEBUG_PRINT3 (" %C != %C => pop_failure_jump.\n", + (wint_t) c, + (wint_t) p1[3+OFFSET_ADDRESS_SIZE]); +#else + DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n", + (char) c, + (char) p1[3+OFFSET_ADDRESS_SIZE]); +#endif + } + +#ifndef WCHAR + else if ((re_opcode_t) p1[3] == charset + || (re_opcode_t) p1[3] == charset_not) + { + int negate = (re_opcode_t) p1[3] == charset_not; + + if (c < (unsigned) (p1[4] * BYTEWIDTH) + && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) + negate = !negate; + + /* `negate' is equal to 1 if c would match, which means + that we can't change to pop_failure_jump. */ + if (!negate) + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); + } + } +#endif /* not WCHAR */ + } +#ifndef WCHAR + else if ((re_opcode_t) *p2 == charset) + { + /* We win if the first character of the loop is not part + of the charset. */ + if ((re_opcode_t) p1[3] == exactn + && ! ((int) p2[1] * BYTEWIDTH > (int) p1[5] + && (p2[2 + p1[5] / BYTEWIDTH] + & (1 << (p1[5] % BYTEWIDTH))))) + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); + } + + else if ((re_opcode_t) p1[3] == charset_not) + { + int idx; + /* We win if the charset_not inside the loop + lists every character listed in the charset after. */ + for (idx = 0; idx < (int) p2[1]; idx++) + if (! (p2[2 + idx] == 0 + || (idx < (int) p1[4] + && ((p2[2 + idx] & ~ p1[5 + idx]) == 0)))) + break; + + if (idx == p2[1]) + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); + } + } + else if ((re_opcode_t) p1[3] == charset) + { + int idx; + /* We win if the charset inside the loop + has no overlap with the one after the loop. */ + for (idx = 0; + idx < (int) p2[1] && idx < (int) p1[4]; + idx++) + if ((p2[2 + idx] & p1[5 + idx]) != 0) + break; + + if (idx == p2[1] || idx == p1[4]) + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); + } + } + } +#endif /* not WCHAR */ + } + p -= OFFSET_ADDRESS_SIZE; /* Point at relative address again. */ + if ((re_opcode_t) p[-1] != pop_failure_jump) + { + p[-1] = (UCHAR_T) jump; + DEBUG_PRINT1 (" Match => jump.\n"); + goto unconditional_jump; + } + /* Note fall through. */ + + + /* The end of a simple repeat has a pop_failure_jump back to + its matching on_failure_jump, where the latter will push a + failure point. The pop_failure_jump takes off failure + points put on by this pop_failure_jump's matching + on_failure_jump; we got through the pattern to here from the + matching on_failure_jump, so didn't fail. */ + case pop_failure_jump: + { + /* We need to pass separate storage for the lowest and + highest registers, even though we don't care about the + actual values. Otherwise, we will restore only one + register from the stack, since lowest will == highest in + `pop_failure_point'. */ + active_reg_t dummy_low_reg, dummy_high_reg; + UCHAR_T *pdummy = NULL; + const CHAR_T *sdummy = NULL; + + DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n"); + POP_FAILURE_POINT (sdummy, pdummy, + dummy_low_reg, dummy_high_reg, + reg_dummy, reg_dummy, reg_info_dummy); + } + /* Note fall through. */ + + unconditional_jump: +#ifdef _LIBC + DEBUG_PRINT2 ("\n%p: ", p); +#else + DEBUG_PRINT2 ("\n0x%x: ", p); +#endif + /* Note fall through. */ + + /* Unconditionally jump (without popping any failure points). */ + case jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p); /* Get the amount to jump. */ + DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt); + p += mcnt; /* Do the jump. */ +#ifdef _LIBC + DEBUG_PRINT2 ("(to %p).\n", p); +#else + DEBUG_PRINT2 ("(to 0x%x).\n", p); +#endif + break; + + + /* We need this opcode so we can detect where alternatives end + in `group_match_null_string_p' et al. */ + case jump_past_alt: + DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n"); + goto unconditional_jump; + + + /* Normally, the on_failure_jump pushes a failure point, which + then gets popped at pop_failure_jump. We will end up at + pop_failure_jump, also, and with a pattern of, say, `a+', we + are skipping over the on_failure_jump, so we have to push + something meaningless for pop_failure_jump to pop. */ + case dummy_failure_jump: + DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n"); + /* It doesn't matter what we push for the string here. What + the code at `fail' tests is the value for the pattern. */ + PUSH_FAILURE_POINT (NULL, NULL, -2); + goto unconditional_jump; + + + /* At the end of an alternative, we need to push a dummy failure + point in case we are followed by a `pop_failure_jump', because + we don't want the failure point for the alternative to be + popped. For example, matching `(a|ab)*' against `aab' + requires that we match the `ab' alternative. */ + case push_dummy_failure: + DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n"); + /* See comments just above at `dummy_failure_jump' about the + two zeroes. */ + PUSH_FAILURE_POINT (NULL, NULL, -2); + break; + + /* Have to succeed matching what follows at least n times. + After that, handle like `on_failure_jump'. */ + case succeed_n: + EXTRACT_NUMBER (mcnt, p + OFFSET_ADDRESS_SIZE); + DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt); + + assert (mcnt >= 0); + /* Originally, this is how many times we HAVE to succeed. */ + if (mcnt > 0) + { + mcnt--; + p += OFFSET_ADDRESS_SIZE; + STORE_NUMBER_AND_INCR (p, mcnt); +#ifdef _LIBC + DEBUG_PRINT3 (" Setting %p to %d.\n", p - OFFSET_ADDRESS_SIZE + , mcnt); +#else + DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p - OFFSET_ADDRESS_SIZE + , mcnt); +#endif + } + else if (mcnt == 0) + { +#ifdef _LIBC + DEBUG_PRINT2 (" Setting two bytes from %p to no_op.\n", + p + OFFSET_ADDRESS_SIZE); +#else + DEBUG_PRINT2 (" Setting two bytes from 0x%x to no_op.\n", + p + OFFSET_ADDRESS_SIZE); +#endif /* _LIBC */ + +#ifdef WCHAR + p[1] = (UCHAR_T) no_op; +#else + p[2] = (UCHAR_T) no_op; + p[3] = (UCHAR_T) no_op; +#endif /* WCHAR */ + goto on_failure; + } + break; + + case jump_n: + EXTRACT_NUMBER (mcnt, p + OFFSET_ADDRESS_SIZE); + DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt); + + /* Originally, this is how many times we CAN jump. */ + if (mcnt) + { + mcnt--; + STORE_NUMBER (p + OFFSET_ADDRESS_SIZE, mcnt); + +#ifdef _LIBC + DEBUG_PRINT3 (" Setting %p to %d.\n", p + OFFSET_ADDRESS_SIZE, + mcnt); +#else + DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p + OFFSET_ADDRESS_SIZE, + mcnt); +#endif /* _LIBC */ + goto unconditional_jump; + } + /* If don't have to jump any more, skip over the rest of command. */ + else + p += 2 * OFFSET_ADDRESS_SIZE; + break; + + case set_number_at: + { + DEBUG_PRINT1 ("EXECUTING set_number_at.\n"); + + EXTRACT_NUMBER_AND_INCR (mcnt, p); + p1 = p + mcnt; + EXTRACT_NUMBER_AND_INCR (mcnt, p); +#ifdef _LIBC + DEBUG_PRINT3 (" Setting %p to %d.\n", p1, mcnt); +#else + DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p1, mcnt); +#endif + STORE_NUMBER (p1, mcnt); + break; + } + +#if 0 + /* The DEC Alpha C compiler 3.x generates incorrect code for the + test WORDCHAR_P (d - 1) != WORDCHAR_P (d) in the expansion of + AT_WORD_BOUNDARY, so this code is disabled. Expanding the + macro and introducing temporary variables works around the bug. */ + + case wordbound: + DEBUG_PRINT1 ("EXECUTING wordbound.\n"); + if (AT_WORD_BOUNDARY (d)) + break; + goto fail; + + case notwordbound: + DEBUG_PRINT1 ("EXECUTING notwordbound.\n"); + if (AT_WORD_BOUNDARY (d)) + goto fail; + break; +#else + case wordbound: + { + boolean prevchar, thischar; + + DEBUG_PRINT1 ("EXECUTING wordbound.\n"); + if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d)) + break; + + prevchar = WORDCHAR_P (d - 1); + thischar = WORDCHAR_P (d); + if (prevchar != thischar) + break; + goto fail; + } + + case notwordbound: + { + boolean prevchar, thischar; + + DEBUG_PRINT1 ("EXECUTING notwordbound.\n"); + if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d)) + goto fail; + + prevchar = WORDCHAR_P (d - 1); + thischar = WORDCHAR_P (d); + if (prevchar != thischar) + goto fail; + break; + } +#endif + + case wordbeg: + DEBUG_PRINT1 ("EXECUTING wordbeg.\n"); + if (!AT_STRINGS_END (d) && WORDCHAR_P (d) + && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1))) + break; + goto fail; + + case wordend: + DEBUG_PRINT1 ("EXECUTING wordend.\n"); + if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1) + && (AT_STRINGS_END (d) || !WORDCHAR_P (d))) + break; + goto fail; + +#ifdef emacs + case before_dot: + DEBUG_PRINT1 ("EXECUTING before_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) >= point) + goto fail; + break; + + case at_dot: + DEBUG_PRINT1 ("EXECUTING at_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) != point) + goto fail; + break; + + case after_dot: + DEBUG_PRINT1 ("EXECUTING after_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) <= point) + goto fail; + break; + + case syntaxspec: + DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt); + mcnt = *p++; + goto matchsyntax; + + case wordchar: + DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n"); + mcnt = (int) Sword; + matchsyntax: + PREFETCH (); + /* Can't use *d++ here; SYNTAX may be an unsafe macro. */ + d++; + if (SYNTAX (d[-1]) != (enum syntaxcode) mcnt) + goto fail; + SET_REGS_MATCHED (); + break; + + case notsyntaxspec: + DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt); + mcnt = *p++; + goto matchnotsyntax; + + case notwordchar: + DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n"); + mcnt = (int) Sword; + matchnotsyntax: + PREFETCH (); + /* Can't use *d++ here; SYNTAX may be an unsafe macro. */ + d++; + if (SYNTAX (d[-1]) == (enum syntaxcode) mcnt) + goto fail; + SET_REGS_MATCHED (); + break; + +#else /* not emacs */ + case wordchar: + DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n"); + PREFETCH (); + if (!WORDCHAR_P (d)) + goto fail; + SET_REGS_MATCHED (); + d++; + break; + + case notwordchar: + DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n"); + PREFETCH (); + if (WORDCHAR_P (d)) + goto fail; + SET_REGS_MATCHED (); + d++; + break; +#endif /* not emacs */ + + default: + abort (); + } + continue; /* Successfully executed one pattern command; keep going. */ + + + /* We goto here if a matching operation fails. */ + fail: + if (!FAIL_STACK_EMPTY ()) + { /* A restart point is known. Restore to that state. */ + DEBUG_PRINT1 ("\nFAIL:\n"); + POP_FAILURE_POINT (d, p, + lowest_active_reg, highest_active_reg, + regstart, regend, reg_info); + + /* If this failure point is a dummy, try the next one. */ + if (!p) + goto fail; + + /* If we failed to the end of the pattern, don't examine *p. */ + assert (p <= pend); + if (p < pend) + { + boolean is_a_jump_n = false; + + /* If failed to a backwards jump that's part of a repetition + loop, need to pop this failure point and use the next one. */ + switch ((re_opcode_t) *p) + { + case jump_n: + is_a_jump_n = true; + case maybe_pop_jump: + case pop_failure_jump: + case jump: + p1 = p + 1; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + + if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n) + || (!is_a_jump_n + && (re_opcode_t) *p1 == on_failure_jump)) + goto fail; + break; + default: + /* do nothing */ ; + } + } + + if (d >= string1 && d <= end1) + dend = end_match_1; + } + else + break; /* Matching at this starting point really fails. */ + } /* for (;;) */ + + if (best_regs_set) + goto restore_best_regs; + + FREE_VARIABLES (); + + return -1; /* Failure to match. */ +} /* re_match_2 */ + +/* Subroutine definitions for re_match_2. */ + + +/* We are passed P pointing to a register number after a start_memory. + + Return true if the pattern up to the corresponding stop_memory can + match the empty string, and false otherwise. + + If we find the matching stop_memory, sets P to point to one past its number. + Otherwise, sets P to an undefined byte less than or equal to END. + + We don't handle duplicates properly (yet). */ + +static boolean +PREFIX(group_match_null_string_p) (UCHAR_T **p, UCHAR_T *end, + PREFIX(register_info_type) *reg_info) +{ + int mcnt; + /* Point to after the args to the start_memory. */ + UCHAR_T *p1 = *p + 2; + + while (p1 < end) + { + /* Skip over opcodes that can match nothing, and return true or + false, as appropriate, when we get to one that can't, or to the + matching stop_memory. */ + + switch ((re_opcode_t) *p1) + { + /* Could be either a loop or a series of alternatives. */ + case on_failure_jump: + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + + /* If the next operation is not a jump backwards in the + pattern. */ + + if (mcnt >= 0) + { + /* Go through the on_failure_jumps of the alternatives, + seeing if any of the alternatives cannot match nothing. + The last alternative starts with only a jump, + whereas the rest start with on_failure_jump and end + with a jump, e.g., here is the pattern for `a|b|c': + + /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6 + /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3 + /exactn/1/c + + So, we have to first go through the first (n-1) + alternatives and then deal with the last one separately. */ + + + /* Deal with the first (n-1) alternatives, which start + with an on_failure_jump (see above) that jumps to right + past a jump_past_alt. */ + + while ((re_opcode_t) p1[mcnt-(1+OFFSET_ADDRESS_SIZE)] == + jump_past_alt) + { + /* `mcnt' holds how many bytes long the alternative + is, including the ending `jump_past_alt' and + its number. */ + + if (!PREFIX(alt_match_null_string_p) (p1, p1 + mcnt - + (1 + OFFSET_ADDRESS_SIZE), + reg_info)) + return false; + + /* Move to right after this alternative, including the + jump_past_alt. */ + p1 += mcnt; + + /* Break if it's the beginning of an n-th alternative + that doesn't begin with an on_failure_jump. */ + if ((re_opcode_t) *p1 != on_failure_jump) + break; + + /* Still have to check that it's not an n-th + alternative that starts with an on_failure_jump. */ + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + if ((re_opcode_t) p1[mcnt-(1+OFFSET_ADDRESS_SIZE)] != + jump_past_alt) + { + /* Get to the beginning of the n-th alternative. */ + p1 -= 1 + OFFSET_ADDRESS_SIZE; + break; + } + } + + /* Deal with the last alternative: go back and get number + of the `jump_past_alt' just before it. `mcnt' contains + the length of the alternative. */ + EXTRACT_NUMBER (mcnt, p1 - OFFSET_ADDRESS_SIZE); + + if (!PREFIX(alt_match_null_string_p) (p1, p1 + mcnt, reg_info)) + return false; + + p1 += mcnt; /* Get past the n-th alternative. */ + } /* if mcnt > 0 */ + break; + + + case stop_memory: + assert (p1[1] == **p); + *p = p1 + 2; + return true; + + + default: + if (!PREFIX(common_op_match_null_string_p) (&p1, end, reg_info)) + return false; + } + } /* while p1 < end */ + + return false; +} /* group_match_null_string_p */ + + +/* Similar to group_match_null_string_p, but doesn't deal with alternatives: + It expects P to be the first byte of a single alternative and END one + byte past the last. The alternative can contain groups. */ + +static boolean +PREFIX(alt_match_null_string_p) (UCHAR_T *p, UCHAR_T *end, + PREFIX(register_info_type) *reg_info) +{ + int mcnt; + UCHAR_T *p1 = p; + + while (p1 < end) + { + /* Skip over opcodes that can match nothing, and break when we get + to one that can't. */ + + switch ((re_opcode_t) *p1) + { + /* It's a loop. */ + case on_failure_jump: + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + break; + + default: + if (!PREFIX(common_op_match_null_string_p) (&p1, end, reg_info)) + return false; + } + } /* while p1 < end */ + + return true; +} /* alt_match_null_string_p */ + + +/* Deals with the ops common to group_match_null_string_p and + alt_match_null_string_p. + + Sets P to one after the op and its arguments, if any. */ + +static boolean +PREFIX(common_op_match_null_string_p) (UCHAR_T **p, UCHAR_T *end, + PREFIX(register_info_type) *reg_info) +{ + int mcnt; + boolean ret; + int reg_no; + UCHAR_T *p1 = *p; + + switch ((re_opcode_t) *p1++) + { + case no_op: + case begline: + case endline: + case begbuf: + case endbuf: + case wordbeg: + case wordend: + case wordbound: + case notwordbound: +#ifdef emacs + case before_dot: + case at_dot: + case after_dot: +#endif + break; + + case start_memory: + reg_no = *p1; + assert (reg_no > 0 && reg_no <= MAX_REGNUM); + ret = PREFIX(group_match_null_string_p) (&p1, end, reg_info); + + /* Have to set this here in case we're checking a group which + contains a group and a back reference to it. */ + + if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE) + REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret; + + if (!ret) + return false; + break; + + /* If this is an optimized succeed_n for zero times, make the jump. */ + case jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + if (mcnt >= 0) + p1 += mcnt; + else + return false; + break; + + case succeed_n: + /* Get to the number of times to succeed. */ + p1 += OFFSET_ADDRESS_SIZE; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + + if (mcnt == 0) + { + p1 -= 2 * OFFSET_ADDRESS_SIZE; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + } + else + return false; + break; + + case duplicate: + if (!REG_MATCH_NULL_STRING_P (reg_info[*p1])) + return false; + break; + + case set_number_at: + p1 += 2 * OFFSET_ADDRESS_SIZE; + + default: + /* All other opcodes mean we cannot match the empty string. */ + return false; + } + + *p = p1; + return true; +} /* common_op_match_null_string_p */ + + +/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN + bytes; nonzero otherwise. */ + +static int +PREFIX(bcmp_translate) (const CHAR_T *s1, const CHAR_T *s2, register int len, + RE_TRANSLATE_TYPE translate) +{ + register const UCHAR_T *p1 = (const UCHAR_T *) s1; + register const UCHAR_T *p2 = (const UCHAR_T *) s2; + while (len) + { +#ifdef WCHAR + if (((*p1<=0xff)?translate[*p1++]:*p1++) + != ((*p2<=0xff)?translate[*p2++]:*p2++)) + return 1; +#else /* BYTE */ + if (translate[*p1++] != translate[*p2++]) return 1; +#endif /* WCHAR */ + len--; + } + return 0; +} + + +#else /* not INSIDE_RECURSION */ + +/* Entry points for GNU code. */ + +/* re_compile_pattern is the GNU regular expression compiler: it + compiles PATTERN (of length SIZE) and puts the result in BUFP. + Returns 0 if the pattern was valid, otherwise an error string. + + Assumes the `allocated' (and perhaps `buffer') and `translate' fields + are set in BUFP on entry. + + We call regex_compile to do the actual compilation. */ + +const char * +re_compile_pattern (const char *pattern, size_t length, + struct re_pattern_buffer *bufp) +{ + reg_errcode_t ret; + + /* GNU code is written to assume at least RE_NREGS registers will be set + (and at least one extra will be -1). */ + bufp->regs_allocated = REGS_UNALLOCATED; + + /* And GNU code determines whether or not to get register information + by passing null for the REGS argument to re_match, etc., not by + setting no_sub. */ + bufp->no_sub = 0; + + /* Match anchors at newline. */ + bufp->newline_anchor = 1; + +# ifdef MBS_SUPPORT + if (MB_CUR_MAX != 1) + ret = wcs_regex_compile (pattern, length, re_syntax_options, bufp); + else +# endif + ret = byte_regex_compile (pattern, length, re_syntax_options, bufp); + + if (!ret) + return NULL; + return gettext (re_error_msgid[(int) ret]); +} +#ifdef _LIBC +weak_alias (__re_compile_pattern, re_compile_pattern) +#endif + +/* Entry points compatible with 4.2 BSD regex library. We don't define + them unless specifically requested. */ + +#if defined _REGEX_RE_COMP || defined _LIBC + +/* BSD has one and only one pattern buffer. */ +static struct re_pattern_buffer re_comp_buf; + +char * +#ifdef _LIBC +/* Make these definitions weak in libc, so POSIX programs can redefine + these names if they don't use our functions, and still use + regcomp/regexec below without link errors. */ +weak_function +#endif +re_comp (const char *s) +{ + reg_errcode_t ret; + + if (!s) + { + if (!re_comp_buf.buffer) + return (char *) gettext ("No previous regular expression"); + return 0; + } + + if (!re_comp_buf.buffer) + { + re_comp_buf.buffer = (unsigned char *) malloc (200); + if (re_comp_buf.buffer == NULL) + return (char *) gettext (re_error_msgid[(int) REG_ESPACE]); + re_comp_buf.allocated = 200; + + re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH); + if (re_comp_buf.fastmap == NULL) + return (char *) gettext (re_error_msgid[(int) REG_ESPACE]); + } + + /* Since `re_exec' always passes NULL for the `regs' argument, we + don't need to initialize the pattern buffer fields which affect it. */ + + /* Match anchors at newlines. */ + re_comp_buf.newline_anchor = 1; + +# ifdef MBS_SUPPORT + if (MB_CUR_MAX != 1) + ret = wcs_regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf); + else +# endif + ret = byte_regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf); + + if (!ret) + return NULL; + + /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */ + return (char *) gettext (re_error_msgid[(int) ret]); +} + + +int +#ifdef _LIBC +weak_function +#endif +re_exec (const char *s) +{ + const int len = strlen (s); + return + 0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0); +} + +#endif /* _REGEX_RE_COMP */ + +/* POSIX.2 functions. Don't define these for Emacs. */ + +#ifndef emacs + +/* regcomp takes a regular expression as a string and compiles it. + + PREG is a regex_t *. We do not expect any fields to be initialized, + since POSIX says we shouldn't. Thus, we set + + `buffer' to the compiled pattern; + `used' to the length of the compiled pattern; + `syntax' to RE_SYNTAX_POSIX_EXTENDED if the + REG_EXTENDED bit in CFLAGS is set; otherwise, to + RE_SYNTAX_POSIX_BASIC; + `newline_anchor' to REG_NEWLINE being set in CFLAGS; + `fastmap' to an allocated space for the fastmap; + `fastmap_accurate' to zero; + `re_nsub' to the number of subexpressions in PATTERN. + + PATTERN is the address of the pattern string. + + CFLAGS is a series of bits which affect compilation. + + If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we + use POSIX basic syntax. + + If REG_NEWLINE is set, then . and [^...] don't match newline. + Also, regexec will try a match beginning after every newline. + + If REG_ICASE is set, then we considers upper- and lowercase + versions of letters to be equivalent when matching. + + If REG_NOSUB is set, then when PREG is passed to regexec, that + routine will report only success or failure, and nothing about the + registers. + + It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for + the return codes and their meanings.) */ + +int +regcomp (regex_t *preg, const char *pattern, int cflags) +{ + reg_errcode_t ret; + reg_syntax_t syntax + = (cflags & REG_EXTENDED) ? + RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC; + + /* regex_compile will allocate the space for the compiled pattern. */ + preg->buffer = 0; + preg->allocated = 0; + preg->used = 0; + + /* Try to allocate space for the fastmap. */ + preg->fastmap = (char *) malloc (1 << BYTEWIDTH); + + if (cflags & REG_ICASE) + { + int i; + + preg->translate + = (RE_TRANSLATE_TYPE) malloc (CHAR_SET_SIZE + * sizeof (*(RE_TRANSLATE_TYPE)0)); + if (preg->translate == NULL) + return (int) REG_ESPACE; + + /* Map uppercase characters to corresponding lowercase ones. */ + for (i = 0; i < CHAR_SET_SIZE; i++) + preg->translate[i] = ISUPPER (i) ? TOLOWER (i) : i; + } + else + preg->translate = NULL; + + /* If REG_NEWLINE is set, newlines are treated differently. */ + if (cflags & REG_NEWLINE) + { /* REG_NEWLINE implies neither . nor [^...] match newline. */ + syntax &= ~RE_DOT_NEWLINE; + syntax |= RE_HAT_LISTS_NOT_NEWLINE; + /* It also changes the matching behavior. */ + preg->newline_anchor = 1; + } + else + preg->newline_anchor = 0; + + preg->no_sub = !!(cflags & REG_NOSUB); + + /* POSIX says a null character in the pattern terminates it, so we + can use strlen here in compiling the pattern. */ +# ifdef MBS_SUPPORT + if (MB_CUR_MAX != 1) + ret = wcs_regex_compile (pattern, strlen (pattern), syntax, preg); + else +# endif + ret = byte_regex_compile (pattern, strlen (pattern), syntax, preg); + + /* POSIX doesn't distinguish between an unmatched open-group and an + unmatched close-group: both are REG_EPAREN. */ + if (ret == REG_ERPAREN) ret = REG_EPAREN; + + if (ret == REG_NOERROR && preg->fastmap) + { + /* Compute the fastmap now, since regexec cannot modify the pattern + buffer. */ + if (re_compile_fastmap (preg) == -2) + { + /* Some error occurred while computing the fastmap, just forget + about it. */ + free (preg->fastmap); + preg->fastmap = NULL; + } + } + + return (int) ret; +} +#ifdef _LIBC +weak_alias (__regcomp, regcomp) +#endif + + +/* regexec searches for a given pattern, specified by PREG, in the + string STRING. + + If NMATCH is zero or REG_NOSUB was set in the cflags argument to + `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at + least NMATCH elements, and we set them to the offsets of the + corresponding matched substrings. + + EFLAGS specifies `execution flags' which affect matching: if + REG_NOTBOL is set, then ^ does not match at the beginning of the + string; if REG_NOTEOL is set, then $ does not match at the end. + + We return 0 if we find a match and REG_NOMATCH if not. */ + +int +regexec (const regex_t *preg, const char *string, size_t nmatch, + regmatch_t pmatch[], int eflags) +{ + int ret; + struct re_registers regs; + regex_t private_preg; + int len = strlen (string); + boolean want_reg_info = !preg->no_sub && nmatch > 0; + + private_preg = *preg; + + private_preg.not_bol = !!(eflags & REG_NOTBOL); + private_preg.not_eol = !!(eflags & REG_NOTEOL); + + /* The user has told us exactly how many registers to return + information about, via `nmatch'. We have to pass that on to the + matching routines. */ + private_preg.regs_allocated = REGS_FIXED; + + if (want_reg_info) + { + regs.num_regs = nmatch; + regs.start = TALLOC (nmatch * 2, regoff_t); + if (regs.start == NULL) + return (int) REG_NOMATCH; + regs.end = regs.start + nmatch; + } + + /* Perform the searching operation. */ + ret = re_search (&private_preg, string, len, + /* start: */ 0, /* range: */ len, + want_reg_info ? ®s : (struct re_registers *) 0); + + /* Copy the register information to the POSIX structure. */ + if (want_reg_info) + { + if (ret >= 0) + { + unsigned r; + + for (r = 0; r < nmatch; r++) + { + pmatch[r].rm_so = regs.start[r]; + pmatch[r].rm_eo = regs.end[r]; + } + } + + /* If we needed the temporary register info, free the space now. */ + free (regs.start); + } + + /* We want zero return to mean success, unlike `re_search'. */ + return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH; +} +#ifdef _LIBC +weak_alias (__regexec, regexec) +#endif + + +/* Returns a message corresponding to an error code, ERRCODE, returned + from either regcomp or regexec. We don't use PREG here. */ + +size_t +regerror (int errcode, const regex_t *preg ATTRIBUTE_UNUSED, + char *errbuf, size_t errbuf_size) +{ + const char *msg; + size_t msg_size; + + if (errcode < 0 + || errcode >= (int) (sizeof (re_error_msgid) + / sizeof (re_error_msgid[0]))) + /* Only error codes returned by the rest of the code should be passed + to this routine. If we are given anything else, or if other regex + code generates an invalid error code, then the program has a bug. + Dump core so we can fix it. */ + abort (); + + msg = gettext (re_error_msgid[errcode]); + + msg_size = strlen (msg) + 1; /* Includes the null. */ + + if (errbuf_size != 0) + { + if (msg_size > errbuf_size) + { +#if defined HAVE_MEMPCPY || defined _LIBC + *((char *) mempcpy (errbuf, msg, errbuf_size - 1)) = '\0'; +#else + memcpy (errbuf, msg, errbuf_size - 1); + errbuf[errbuf_size - 1] = 0; +#endif + } + else + memcpy (errbuf, msg, msg_size); + } + + return msg_size; +} +#ifdef _LIBC +weak_alias (__regerror, regerror) +#endif + + +/* Free dynamically allocated space used by PREG. */ + +void +regfree (regex_t *preg) +{ + if (preg->buffer != NULL) + free (preg->buffer); + preg->buffer = NULL; + + preg->allocated = 0; + preg->used = 0; + + if (preg->fastmap != NULL) + free (preg->fastmap); + preg->fastmap = NULL; + preg->fastmap_accurate = 0; + + if (preg->translate != NULL) + free (preg->translate); + preg->translate = NULL; +} +#ifdef _LIBC +weak_alias (__regfree, regfree) +#endif + +#endif /* not emacs */ + +#endif /* not INSIDE_RECURSION */ + + +#undef STORE_NUMBER +#undef STORE_NUMBER_AND_INCR +#undef EXTRACT_NUMBER +#undef EXTRACT_NUMBER_AND_INCR + +#undef DEBUG_PRINT_COMPILED_PATTERN +#undef DEBUG_PRINT_DOUBLE_STRING + +#undef INIT_FAIL_STACK +#undef RESET_FAIL_STACK +#undef DOUBLE_FAIL_STACK +#undef PUSH_PATTERN_OP +#undef PUSH_FAILURE_POINTER +#undef PUSH_FAILURE_INT +#undef PUSH_FAILURE_ELT +#undef POP_FAILURE_POINTER +#undef POP_FAILURE_INT +#undef POP_FAILURE_ELT +#undef DEBUG_PUSH +#undef DEBUG_POP +#undef PUSH_FAILURE_POINT +#undef POP_FAILURE_POINT + +#undef REG_UNSET_VALUE +#undef REG_UNSET + +#undef PATFETCH +#undef PATFETCH_RAW +#undef PATUNFETCH +#undef TRANSLATE + +#undef INIT_BUF_SIZE +#undef GET_BUFFER_SPACE +#undef BUF_PUSH +#undef BUF_PUSH_2 +#undef BUF_PUSH_3 +#undef STORE_JUMP +#undef STORE_JUMP2 +#undef INSERT_JUMP +#undef INSERT_JUMP2 +#undef EXTEND_BUFFER +#undef GET_UNSIGNED_NUMBER +#undef FREE_STACK_RETURN + +# undef POINTER_TO_OFFSET +# undef MATCHING_IN_FRST_STRING +# undef PREFETCH +# undef AT_STRINGS_BEG +# undef AT_STRINGS_END +# undef WORDCHAR_P +# undef FREE_VAR +# undef FREE_VARIABLES +# undef NO_HIGHEST_ACTIVE_REG +# undef NO_LOWEST_ACTIVE_REG + +# undef CHAR_T +# undef UCHAR_T +# undef COMPILED_BUFFER_VAR +# undef OFFSET_ADDRESS_SIZE +# undef CHAR_CLASS_SIZE +# undef PREFIX +# undef ARG_PREFIX +# undef PUT_CHAR +# undef BYTE +# undef WCHAR + +# define DEFINED_ONCE diff --git a/libiberty/rename.c b/libiberty/rename.c new file mode 100644 index 0000000..ad342ff --- /dev/null +++ b/libiberty/rename.c @@ -0,0 +1,36 @@ +/* rename -- rename a file + This function is in the public domain. */ + +/* + +@deftypefn Supplemental int rename (const char *@var{old}, const char *@var{new}) + +Renames a file from @var{old} to @var{new}. If @var{new} already +exists, it is removed. + +@end deftypefn + +*/ + +#include "ansidecl.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +int +rename (const char *zfrom, const char *zto) +{ + if (link (zfrom, zto) < 0) + { + if (errno != EEXIST) + return -1; + if (unlink (zto) < 0 + || link (zfrom, zto) < 0) + return -1; + } + return unlink (zfrom); +} diff --git a/libiberty/rindex.c b/libiberty/rindex.c new file mode 100644 index 0000000..194ef9f --- /dev/null +++ b/libiberty/rindex.c @@ -0,0 +1,21 @@ +/* Stub implementation of (obsolete) rindex(). */ + +/* + +@deftypefn Supplemental char* rindex (const char *@var{s}, int @var{c}) + +Returns a pointer to the last occurrence of the character @var{c} in +the string @var{s}, or @code{NULL} if not found. The use of @code{rindex} is +deprecated in new programs in favor of @code{strrchr}. + +@end deftypefn + +*/ + +extern char *strrchr (const char *, int); + +char * +rindex (const char *s, int c) +{ + return strrchr (s, c); +} diff --git a/libiberty/safe-ctype.c b/libiberty/safe-ctype.c new file mode 100644 index 0000000..0972b4b --- /dev/null +++ b/libiberty/safe-ctype.c @@ -0,0 +1,255 @@ +/* replacement macros. + + Copyright (C) 2000, 2001, 2002, 2003, 2004, + 2005 Free Software Foundation, Inc. + Contributed by Zack Weinberg . + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* + +@defvr Extension HOST_CHARSET +This macro indicates the basic character set and encoding used by the +host: more precisely, the encoding used for character constants in +preprocessor @samp{#if} statements (the C "execution character set"). +It is defined by @file{safe-ctype.h}, and will be an integer constant +with one of the following values: + +@ftable @code +@item HOST_CHARSET_UNKNOWN +The host character set is unknown - that is, not one of the next two +possibilities. + +@item HOST_CHARSET_ASCII +The host character set is ASCII. + +@item HOST_CHARSET_EBCDIC +The host character set is some variant of EBCDIC. (Only one of the +nineteen EBCDIC varying characters is tested; exercise caution.) +@end ftable +@end defvr + +@deffn Extension ISALPHA (@var{c}) +@deffnx Extension ISALNUM (@var{c}) +@deffnx Extension ISBLANK (@var{c}) +@deffnx Extension ISCNTRL (@var{c}) +@deffnx Extension ISDIGIT (@var{c}) +@deffnx Extension ISGRAPH (@var{c}) +@deffnx Extension ISLOWER (@var{c}) +@deffnx Extension ISPRINT (@var{c}) +@deffnx Extension ISPUNCT (@var{c}) +@deffnx Extension ISSPACE (@var{c}) +@deffnx Extension ISUPPER (@var{c}) +@deffnx Extension ISXDIGIT (@var{c}) + +These twelve macros are defined by @file{safe-ctype.h}. Each has the +same meaning as the corresponding macro (with name in lowercase) +defined by the standard header @file{ctype.h}. For example, +@code{ISALPHA} returns true for alphabetic characters and false for +others. However, there are two differences between these macros and +those provided by @file{ctype.h}: + +@itemize @bullet +@item These macros are guaranteed to have well-defined behavior for all +values representable by @code{signed char} and @code{unsigned char}, and +for @code{EOF}. + +@item These macros ignore the current locale; they are true for these +fixed sets of characters: +@multitable {@code{XDIGIT}} {yada yada yada yada yada yada yada yada} +@item @code{ALPHA} @tab @kbd{A-Za-z} +@item @code{ALNUM} @tab @kbd{A-Za-z0-9} +@item @code{BLANK} @tab @kbd{space tab} +@item @code{CNTRL} @tab @code{!PRINT} +@item @code{DIGIT} @tab @kbd{0-9} +@item @code{GRAPH} @tab @code{ALNUM || PUNCT} +@item @code{LOWER} @tab @kbd{a-z} +@item @code{PRINT} @tab @code{GRAPH ||} @kbd{space} +@item @code{PUNCT} @tab @kbd{`~!@@#$%^&*()_-=+[@{]@}\|;:'",<.>/?} +@item @code{SPACE} @tab @kbd{space tab \n \r \f \v} +@item @code{UPPER} @tab @kbd{A-Z} +@item @code{XDIGIT} @tab @kbd{0-9A-Fa-f} +@end multitable + +Note that, if the host character set is ASCII or a superset thereof, +all these macros will return false for all values of @code{char} outside +the range of 7-bit ASCII. In particular, both ISPRINT and ISCNTRL return +false for characters with numeric values from 128 to 255. +@end itemize +@end deffn + +@deffn Extension ISIDNUM (@var{c}) +@deffnx Extension ISIDST (@var{c}) +@deffnx Extension IS_VSPACE (@var{c}) +@deffnx Extension IS_NVSPACE (@var{c}) +@deffnx Extension IS_SPACE_OR_NUL (@var{c}) +@deffnx Extension IS_ISOBASIC (@var{c}) +These six macros are defined by @file{safe-ctype.h} and provide +additional character classes which are useful when doing lexical +analysis of C or similar languages. They are true for the following +sets of characters: + +@multitable {@code{SPACE_OR_NUL}} {yada yada yada yada yada yada yada yada} +@item @code{IDNUM} @tab @kbd{A-Za-z0-9_} +@item @code{IDST} @tab @kbd{A-Za-z_} +@item @code{VSPACE} @tab @kbd{\r \n} +@item @code{NVSPACE} @tab @kbd{space tab \f \v \0} +@item @code{SPACE_OR_NUL} @tab @code{VSPACE || NVSPACE} +@item @code{ISOBASIC} @tab @code{VSPACE || NVSPACE || PRINT} +@end multitable +@end deffn + +*/ + +#include "ansidecl.h" +#include +#include /* for EOF */ + +#if EOF != -1 + #error " requires EOF == -1" +#endif + +/* Shorthand */ +#define bl _sch_isblank +#define cn _sch_iscntrl +#define di _sch_isdigit +#define is _sch_isidst +#define lo _sch_islower +#define nv _sch_isnvsp +#define pn _sch_ispunct +#define pr _sch_isprint +#define sp _sch_isspace +#define up _sch_isupper +#define vs _sch_isvsp +#define xd _sch_isxdigit + +/* Masks. */ +#define L (const unsigned short) (lo|is |pr) /* lower case letter */ +#define XL (const unsigned short) (lo|is|xd|pr) /* lowercase hex digit */ +#define U (const unsigned short) (up|is |pr) /* upper case letter */ +#define XU (const unsigned short) (up|is|xd|pr) /* uppercase hex digit */ +#define D (const unsigned short) (di |xd|pr) /* decimal digit */ +#define P (const unsigned short) (pn |pr) /* punctuation */ +#define _ (const unsigned short) (pn|is |pr) /* underscore */ + +#define C (const unsigned short) ( cn) /* control character */ +#define Z (const unsigned short) (nv |cn) /* NUL */ +#define M (const unsigned short) (nv|sp |cn) /* cursor movement: \f \v */ +#define V (const unsigned short) (vs|sp |cn) /* vertical space: \r \n */ +#define T (const unsigned short) (nv|sp|bl|cn) /* tab */ +#define S (const unsigned short) (nv|sp|bl|pr) /* space */ + +/* Are we ASCII? */ +#if HOST_CHARSET == HOST_CHARSET_ASCII + +const unsigned short _sch_istable[256] = +{ + Z, C, C, C, C, C, C, C, /* NUL SOH STX ETX EOT ENQ ACK BEL */ + C, T, V, M, M, V, C, C, /* BS HT LF VT FF CR SO SI */ + C, C, C, C, C, C, C, C, /* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ + C, C, C, C, C, C, C, C, /* CAN EM SUB ESC FS GS RS US */ + S, P, P, P, P, P, P, P, /* SP ! " # $ % & ' */ + P, P, P, P, P, P, P, P, /* ( ) * + , - . / */ + D, D, D, D, D, D, D, D, /* 0 1 2 3 4 5 6 7 */ + D, D, P, P, P, P, P, P, /* 8 9 : ; < = > ? */ + P, XU, XU, XU, XU, XU, XU, U, /* @ A B C D E F G */ + U, U, U, U, U, U, U, U, /* H I J K L M N O */ + U, U, U, U, U, U, U, U, /* P Q R S T U V W */ + U, U, U, P, P, P, P, _, /* X Y Z [ \ ] ^ _ */ + P, XL, XL, XL, XL, XL, XL, L, /* ` a b c d e f g */ + L, L, L, L, L, L, L, L, /* h i j k l m n o */ + L, L, L, L, L, L, L, L, /* p q r s t u v w */ + L, L, L, P, P, P, P, C, /* x y z { | } ~ DEL */ + + /* high half of unsigned char is locale-specific, so all tests are + false in "C" locale */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +const unsigned char _sch_tolower[256] = +{ + 0, 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, + + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + + 91, 92, 93, 94, 95, 96, + + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + + 123,124,125,126,127, + + 128,129,130,131, 132,133,134,135, 136,137,138,139, 140,141,142,143, + 144,145,146,147, 148,149,150,151, 152,153,154,155, 156,157,158,159, + 160,161,162,163, 164,165,166,167, 168,169,170,171, 172,173,174,175, + 176,177,178,179, 180,181,182,183, 184,185,186,187, 188,189,190,191, + + 192,193,194,195, 196,197,198,199, 200,201,202,203, 204,205,206,207, + 208,209,210,211, 212,213,214,215, 216,217,218,219, 220,221,222,223, + 224,225,226,227, 228,229,230,231, 232,233,234,235, 236,237,238,239, + 240,241,242,243, 244,245,246,247, 248,249,250,251, 252,253,254,255, +}; + +const unsigned char _sch_toupper[256] = +{ + 0, 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, + + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + + 91, 92, 93, 94, 95, 96, + + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + + 123,124,125,126,127, + + 128,129,130,131, 132,133,134,135, 136,137,138,139, 140,141,142,143, + 144,145,146,147, 148,149,150,151, 152,153,154,155, 156,157,158,159, + 160,161,162,163, 164,165,166,167, 168,169,170,171, 172,173,174,175, + 176,177,178,179, 180,181,182,183, 184,185,186,187, 188,189,190,191, + + 192,193,194,195, 196,197,198,199, 200,201,202,203, 204,205,206,207, + 208,209,210,211, 212,213,214,215, 216,217,218,219, 220,221,222,223, + 224,225,226,227, 228,229,230,231, 232,233,234,235, 236,237,238,239, + 240,241,242,243, 244,245,246,247, 248,249,250,251, 252,253,254,255, +}; + +#else +# if HOST_CHARSET == HOST_CHARSET_EBCDIC + #error "FIXME: write tables for EBCDIC" +# else + #error "Unrecognized host character set" +# endif +#endif diff --git a/libiberty/setenv.c b/libiberty/setenv.c new file mode 100644 index 0000000..355af5a --- /dev/null +++ b/libiberty/setenv.c @@ -0,0 +1,183 @@ +/* Copyright (C) 1992, 1995, 1996, 1997, 2002 Free Software Foundation, Inc. + This file based on setenv.c in the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, + Boston, MA 02110-1301, USA. */ + + +/* + +@deftypefn Supplemental int setenv (const char *@var{name}, const char *@var{value}, int @var{overwrite}) +@deftypefnx Supplemental void unsetenv (const char *@var{name}) + +@code{setenv} adds @var{name} to the environment with value +@var{value}. If the name was already present in the environment, +the new value will be stored only if @var{overwrite} is nonzero. +The companion @code{unsetenv} function removes @var{name} from the +environment. This implementation is not safe for multithreaded code. + +@end deftypefn + +*/ + +#if HAVE_CONFIG_H +# include +#endif + +#define setenv libiberty_setenv +#define unsetenv libiberty_unsetenv + +#include "ansidecl.h" +#include /* For `size_t' */ +#include /* For `NULL' */ + +#include +#if !defined(errno) && !defined(HAVE_ERRNO_DECL) +extern int errno; +#endif +#define __set_errno(ev) ((errno) = (ev)) + +#if HAVE_STDLIB_H +# include +#endif +#if HAVE_STRING_H +# include +#endif +#if HAVE_UNISTD_H +# include +#endif + +#define __environ environ +#ifndef HAVE_ENVIRON_DECL +extern char **environ; +#endif + +#undef setenv +#undef unsetenv + +/* LOCK and UNLOCK are defined as no-ops. This makes the libiberty + * implementation MT-Unsafe. */ +#define LOCK +#define UNLOCK + +/* Below this point, it's verbatim code from the glibc-2.0 implementation */ + +/* If this variable is not a null pointer we allocated the current + environment. */ +static char **last_environ; + + +int +setenv (const char *name, const char *value, int replace) +{ + register char **ep = 0; + register size_t size; + const size_t namelen = strlen (name); + const size_t vallen = strlen (value) + 1; + + LOCK; + + size = 0; + if (__environ != NULL) + { + for (ep = __environ; *ep != NULL; ++ep) + if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=') + break; + else + ++size; + } + + if (__environ == NULL || *ep == NULL) + { + char **new_environ; + if (__environ == last_environ && __environ != NULL) + /* We allocated this space; we can extend it. */ + new_environ = (char **) realloc (last_environ, + (size + 2) * sizeof (char *)); + else + new_environ = (char **) malloc ((size + 2) * sizeof (char *)); + + if (new_environ == NULL) + { + UNLOCK; + return -1; + } + + new_environ[size] = (char *) malloc (namelen + 1 + vallen); + if (new_environ[size] == NULL) + { + free ((char *) new_environ); + __set_errno (ENOMEM); + UNLOCK; + return -1; + } + + if (__environ != last_environ) + memcpy ((char *) new_environ, (char *) __environ, + size * sizeof (char *)); + + memcpy (new_environ[size], name, namelen); + new_environ[size][namelen] = '='; + memcpy (&new_environ[size][namelen + 1], value, vallen); + + new_environ[size + 1] = NULL; + + last_environ = __environ = new_environ; + } + else if (replace) + { + size_t len = strlen (*ep); + if (len + 1 < namelen + 1 + vallen) + { + /* The existing string is too short; malloc a new one. */ + char *new_string = (char *) malloc (namelen + 1 + vallen); + if (new_string == NULL) + { + UNLOCK; + return -1; + } + *ep = new_string; + } + memcpy (*ep, name, namelen); + (*ep)[namelen] = '='; + memcpy (&(*ep)[namelen + 1], value, vallen); + } + + UNLOCK; + + return 0; +} + +void +unsetenv (const char *name) +{ + const size_t len = strlen (name); + char **ep; + + LOCK; + + for (ep = __environ; *ep; ++ep) + if (!strncmp (*ep, name, len) && (*ep)[len] == '=') + { + /* Found it. Remove this pointer by moving later ones back. */ + char **dp = ep; + do + dp[0] = dp[1]; + while (*dp++); + /* Continue the loop in case NAME appears again. */ + } + + UNLOCK; +} diff --git a/libiberty/sigsetmask.c b/libiberty/sigsetmask.c new file mode 100644 index 0000000..3b708b1 --- /dev/null +++ b/libiberty/sigsetmask.c @@ -0,0 +1,40 @@ +/* Version of sigsetmask.c + Written by Steve Chamberlain (sac@cygnus.com). + Contributed by Cygnus Support. + This file is in the public doamin. */ + +/* + +@deftypefn Supplemental int sigsetmask (int @var{set}) + +Sets the signal mask to the one provided in @var{set} and returns +the old mask (which, for libiberty's implementation, will always +be the value @code{1}). + +@end deftypefn + +*/ + +#define _POSIX_SOURCE +#include +/* Including seems to be needed by ISC. */ +#include +#include + +extern void abort (void) ATTRIBUTE_NORETURN; + +#ifdef SIG_SETMASK +int +sigsetmask (int set) +{ + sigset_t new_sig; + sigset_t old_sig; + + sigemptyset (&new_sig); + if (set != 0) { + abort(); /* FIXME, we don't know how to translate old mask to new */ + } + sigprocmask(SIG_SETMASK, &new_sig, &old_sig); + return 1; /* FIXME, we always return 1 as old value. */ +} +#endif diff --git a/libiberty/snprintf.c b/libiberty/snprintf.c new file mode 100644 index 0000000..f1ba49f --- /dev/null +++ b/libiberty/snprintf.c @@ -0,0 +1,60 @@ +/* Implement the snprintf function. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Kaveh R. Ghazi . + +This file is part of the libiberty library. This library is free +software; you can 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, or (at your option) +any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + +As a special exception, if you link this library with files +compiled with a GNU compiler to produce an executable, this does not cause +the resulting executable to be covered by the GNU General Public License. +This exception does not however invalidate any other reasons why +the executable file might be covered by the GNU General Public License. */ + +/* + +@deftypefn Supplemental int snprintf (char *@var{buf}, size_t @var{n}, const char *@var{format}, ...) + +This function is similar to sprintf, but it will print at most @var{n} +characters. On error the return value is -1, otherwise it returns the +number of characters that would have been printed had @var{n} been +sufficiently large, regardless of the actual value of @var{n}. Note +some pre-C99 system libraries do not implement this correctly so users +cannot generally rely on the return value if the system version of +this function is used. + +@end deftypefn + +*/ + +#include "ansidecl.h" + +#include +#include + +int vsnprintf (char *, size_t, const char *, va_list); + +int +snprintf (char *s, size_t n, const char *format, ...) +{ + int result; + VA_OPEN (ap, format); + VA_FIXEDARG (ap, char *, s); + VA_FIXEDARG (ap, size_t, n); + VA_FIXEDARG (ap, const char *, format); + result = vsnprintf (s, n, format, ap); + VA_CLOSE (ap); + return result; +} diff --git a/libiberty/sort.c b/libiberty/sort.c new file mode 100644 index 0000000..3738dd7 --- /dev/null +++ b/libiberty/sort.c @@ -0,0 +1,186 @@ +/* Sorting algorithms. + Copyright (C) 2000 Free Software Foundation, Inc. + Contributed by Mark Mitchell . + +This file is part of GNU CC. + +GNU CC is free software; you can 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, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "libiberty.h" +#include "sort.h" +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif + +#ifndef UCHAR_MAX +#define UCHAR_MAX ((unsigned char)(-1)) +#endif + +/* POINTERS and WORK are both arrays of N pointers. When this + function returns POINTERS will be sorted in ascending order. */ + +void sort_pointers (size_t n, void **pointers, void **work) +{ + /* The type of a single digit. This can be any unsigned integral + type. When changing this, DIGIT_MAX should be changed as + well. */ + typedef unsigned char digit_t; + + /* The maximum value a single digit can have. */ +#define DIGIT_MAX (UCHAR_MAX + 1) + + /* The Ith entry is the number of elements in *POINTERSP that have I + in the digit on which we are currently sorting. */ + unsigned int count[DIGIT_MAX]; + /* Nonzero if we are running on a big-endian machine. */ + int big_endian_p; + size_t i; + size_t j; + + /* The algorithm used here is radix sort which takes time linear in + the number of elements in the array. */ + + /* The algorithm here depends on being able to swap the two arrays + an even number of times. */ + if ((sizeof (void *) / sizeof (digit_t)) % 2 != 0) + abort (); + + /* Figure out the endianness of the machine. */ + for (i = 0, j = 0; i < sizeof (size_t); ++i) + { + j *= (UCHAR_MAX + 1); + j += i; + } + big_endian_p = (((char *)&j)[0] == 0); + + /* Move through the pointer values from least significant to most + significant digits. */ + for (i = 0; i < sizeof (void *) / sizeof (digit_t); ++i) + { + digit_t *digit; + digit_t *bias; + digit_t *top; + unsigned int *countp; + void **pointerp; + + /* The offset from the start of the pointer will depend on the + endianness of the machine. */ + if (big_endian_p) + j = sizeof (void *) / sizeof (digit_t) - i; + else + j = i; + + /* Now, perform a stable sort on this digit. We use counting + sort. */ + memset (count, 0, DIGIT_MAX * sizeof (unsigned int)); + + /* Compute the address of the appropriate digit in the first and + one-past-the-end elements of the array. On a little-endian + machine, the least-significant digit is closest to the front. */ + bias = ((digit_t *) pointers) + j; + top = ((digit_t *) (pointers + n)) + j; + + /* Count how many there are of each value. At the end of this + loop, COUNT[K] will contain the number of pointers whose Ith + digit is K. */ + for (digit = bias; + digit < top; + digit += sizeof (void *) / sizeof (digit_t)) + ++count[*digit]; + + /* Now, make COUNT[K] contain the number of pointers whose Ith + digit is less than or equal to K. */ + for (countp = count + 1; countp < count + DIGIT_MAX; ++countp) + *countp += countp[-1]; + + /* Now, drop the pointers into their correct locations. */ + for (pointerp = pointers + n - 1; pointerp >= pointers; --pointerp) + work[--count[((digit_t *) pointerp)[j]]] = *pointerp; + + /* Swap WORK and POINTERS so that POINTERS contains the sorted + array. */ + pointerp = pointers; + pointers = work; + work = pointerp; + } +} + +/* Everything below here is a unit test for the routines in this + file. */ + +#ifdef UNIT_TEST + +#include + +void *xmalloc (size_t n) +{ + return malloc (n); +} + +int main (int argc, char **argv) +{ + int k; + int result; + size_t i; + void **pointers; + void **work; + + if (argc > 1) + k = atoi (argv[1]); + else + k = 10; + + pointers = XNEWVEC (void*, k); + work = XNEWVEC (void*, k); + + for (i = 0; i < k; ++i) + { + pointers[i] = (void *) random (); + printf ("%x\n", pointers[i]); + } + + sort_pointers (k, pointers, work); + + printf ("\nSorted\n\n"); + + result = 0; + + for (i = 0; i < k; ++i) + { + printf ("%x\n", pointers[i]); + if (i > 0 && (char*) pointers[i] < (char*) pointers[i - 1]) + result = 1; + } + + free (pointers); + free (work); + + return result; +} + +#endif diff --git a/libiberty/spaces.c b/libiberty/spaces.c new file mode 100644 index 0000000..67481c9 --- /dev/null +++ b/libiberty/spaces.c @@ -0,0 +1,72 @@ +/* Allocate memory region filled with spaces. + Copyright (C) 1991 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* + +@deftypefn Extension char* spaces (int @var{count}) + +Returns a pointer to a memory region filled with the specified +number of spaces and null terminated. The returned pointer is +valid until at least the next call. + +@end deftypefn + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "ansidecl.h" +#include "libiberty.h" + +#if VMS +#include +#include +#else +/* For systems with larger pointers than ints, these must be declared. */ +extern PTR malloc (size_t); +extern void free (PTR); +#endif + +const char * +spaces (int count) +{ + register char *t; + static char *buf; + static int maxsize; + + if (count > maxsize) + { + if (buf) + { + free (buf); + } + buf = (char *) malloc (count + 1); + if (buf == (char *) 0) + return 0; + for (t = buf + count ; t != buf ; ) + { + *--t = ' '; + } + maxsize = count; + buf[count] = '\0'; + } + return (const char *) (buf + maxsize - count); +} + diff --git a/libiberty/splay-tree.c b/libiberty/splay-tree.c new file mode 100644 index 0000000..060f900 --- /dev/null +++ b/libiberty/splay-tree.c @@ -0,0 +1,526 @@ +/* A splay-tree datatype. + Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + Contributed by Mark Mitchell (mark@markmitchell.com). + +This file is part of GNU CC. + +GNU CC is free software; you can 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, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* For an easily readable description of splay-trees, see: + + Lewis, Harry R. and Denenberg, Larry. Data Structures and Their + Algorithms. Harper-Collins, Inc. 1991. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif + +#include + +#include "libiberty.h" +#include "splay-tree.h" + +static void splay_tree_delete_helper (splay_tree, splay_tree_node); +static inline void rotate_left (splay_tree_node *, + splay_tree_node, splay_tree_node); +static inline void rotate_right (splay_tree_node *, + splay_tree_node, splay_tree_node); +static void splay_tree_splay (splay_tree, splay_tree_key); +static int splay_tree_foreach_helper (splay_tree, splay_tree_node, + splay_tree_foreach_fn, void*); + +/* Deallocate NODE (a member of SP), and all its sub-trees. */ + +static void +splay_tree_delete_helper (splay_tree sp, splay_tree_node node) +{ + splay_tree_node pending = 0; + splay_tree_node active = 0; + + if (!node) + return; + +#define KDEL(x) if (sp->delete_key) (*sp->delete_key)(x); +#define VDEL(x) if (sp->delete_value) (*sp->delete_value)(x); + + KDEL (node->key); + VDEL (node->value); + + /* We use the "key" field to hold the "next" pointer. */ + node->key = (splay_tree_key)pending; + pending = (splay_tree_node)node; + + /* Now, keep processing the pending list until there aren't any + more. This is a little more complicated than just recursing, but + it doesn't toast the stack for large trees. */ + + while (pending) + { + active = pending; + pending = 0; + while (active) + { + splay_tree_node temp; + + /* active points to a node which has its key and value + deallocated, we just need to process left and right. */ + + if (active->left) + { + KDEL (active->left->key); + VDEL (active->left->value); + active->left->key = (splay_tree_key)pending; + pending = (splay_tree_node)(active->left); + } + if (active->right) + { + KDEL (active->right->key); + VDEL (active->right->value); + active->right->key = (splay_tree_key)pending; + pending = (splay_tree_node)(active->right); + } + + temp = active; + active = (splay_tree_node)(temp->key); + (*sp->deallocate) ((char*) temp, sp->allocate_data); + } + } +#undef KDEL +#undef VDEL +} + +/* Rotate the edge joining the left child N with its parent P. PP is the + grandparents pointer to P. */ + +static inline void +rotate_left (splay_tree_node *pp, splay_tree_node p, splay_tree_node n) +{ + splay_tree_node tmp; + tmp = n->right; + n->right = p; + p->left = tmp; + *pp = n; +} + +/* Rotate the edge joining the right child N with its parent P. PP is the + grandparents pointer to P. */ + +static inline void +rotate_right (splay_tree_node *pp, splay_tree_node p, splay_tree_node n) +{ + splay_tree_node tmp; + tmp = n->left; + n->left = p; + p->right = tmp; + *pp = n; +} + +/* Bottom up splay of key. */ + +static void +splay_tree_splay (splay_tree sp, splay_tree_key key) +{ + if (sp->root == 0) + return; + + do { + int cmp1, cmp2; + splay_tree_node n, c; + + n = sp->root; + cmp1 = (*sp->comp) (key, n->key); + + /* Found. */ + if (cmp1 == 0) + return; + + /* Left or right? If no child, then we're done. */ + if (cmp1 < 0) + c = n->left; + else + c = n->right; + if (!c) + return; + + /* Next one left or right? If found or no child, we're done + after one rotation. */ + cmp2 = (*sp->comp) (key, c->key); + if (cmp2 == 0 + || (cmp2 < 0 && !c->left) + || (cmp2 > 0 && !c->right)) + { + if (cmp1 < 0) + rotate_left (&sp->root, n, c); + else + rotate_right (&sp->root, n, c); + return; + } + + /* Now we have the four cases of double-rotation. */ + if (cmp1 < 0 && cmp2 < 0) + { + rotate_left (&n->left, c, c->left); + rotate_left (&sp->root, n, n->left); + } + else if (cmp1 > 0 && cmp2 > 0) + { + rotate_right (&n->right, c, c->right); + rotate_right (&sp->root, n, n->right); + } + else if (cmp1 < 0 && cmp2 > 0) + { + rotate_right (&n->left, c, c->right); + rotate_left (&sp->root, n, n->left); + } + else if (cmp1 > 0 && cmp2 < 0) + { + rotate_left (&n->right, c, c->left); + rotate_right (&sp->root, n, n->right); + } + } while (1); +} + +/* Call FN, passing it the DATA, for every node below NODE, all of + which are from SP, following an in-order traversal. If FN every + returns a non-zero value, the iteration ceases immediately, and the + value is returned. Otherwise, this function returns 0. */ + +static int +splay_tree_foreach_helper (splay_tree sp, splay_tree_node node, + splay_tree_foreach_fn fn, void *data) +{ + int val; + + if (!node) + return 0; + + val = splay_tree_foreach_helper (sp, node->left, fn, data); + if (val) + return val; + + val = (*fn)(node, data); + if (val) + return val; + + return splay_tree_foreach_helper (sp, node->right, fn, data); +} + + +/* An allocator and deallocator based on xmalloc. */ +static void * +splay_tree_xmalloc_allocate (int size, void *data ATTRIBUTE_UNUSED) +{ + return (void *) xmalloc (size); +} + +static void +splay_tree_xmalloc_deallocate (void *object, void *data ATTRIBUTE_UNUSED) +{ + free (object); +} + + +/* Allocate a new splay tree, using COMPARE_FN to compare nodes, + DELETE_KEY_FN to deallocate keys, and DELETE_VALUE_FN to deallocate + values. Use xmalloc to allocate the splay tree structure, and any + nodes added. */ + +splay_tree +splay_tree_new (splay_tree_compare_fn compare_fn, + splay_tree_delete_key_fn delete_key_fn, + splay_tree_delete_value_fn delete_value_fn) +{ + return (splay_tree_new_with_allocator + (compare_fn, delete_key_fn, delete_value_fn, + splay_tree_xmalloc_allocate, splay_tree_xmalloc_deallocate, 0)); +} + + +/* Allocate a new splay tree, using COMPARE_FN to compare nodes, + DELETE_KEY_FN to deallocate keys, and DELETE_VALUE_FN to deallocate + values. */ + +splay_tree +splay_tree_new_with_allocator (splay_tree_compare_fn compare_fn, + splay_tree_delete_key_fn delete_key_fn, + splay_tree_delete_value_fn delete_value_fn, + splay_tree_allocate_fn allocate_fn, + splay_tree_deallocate_fn deallocate_fn, + void *allocate_data) +{ + splay_tree sp = (splay_tree) (*allocate_fn) (sizeof (struct splay_tree_s), + allocate_data); + sp->root = 0; + sp->comp = compare_fn; + sp->delete_key = delete_key_fn; + sp->delete_value = delete_value_fn; + sp->allocate = allocate_fn; + sp->deallocate = deallocate_fn; + sp->allocate_data = allocate_data; + + return sp; +} + +/* Deallocate SP. */ + +void +splay_tree_delete (splay_tree sp) +{ + splay_tree_delete_helper (sp, sp->root); + (*sp->deallocate) ((char*) sp, sp->allocate_data); +} + +/* Insert a new node (associating KEY with DATA) into SP. If a + previous node with the indicated KEY exists, its data is replaced + with the new value. Returns the new node. */ + +splay_tree_node +splay_tree_insert (splay_tree sp, splay_tree_key key, splay_tree_value value) +{ + int comparison = 0; + + splay_tree_splay (sp, key); + + if (sp->root) + comparison = (*sp->comp)(sp->root->key, key); + + if (sp->root && comparison == 0) + { + /* If the root of the tree already has the indicated KEY, just + replace the value with VALUE. */ + if (sp->delete_value) + (*sp->delete_value)(sp->root->value); + sp->root->value = value; + } + else + { + /* Create a new node, and insert it at the root. */ + splay_tree_node node; + + node = ((splay_tree_node) + (*sp->allocate) (sizeof (struct splay_tree_node_s), + sp->allocate_data)); + node->key = key; + node->value = value; + + if (!sp->root) + node->left = node->right = 0; + else if (comparison < 0) + { + node->left = sp->root; + node->right = node->left->right; + node->left->right = 0; + } + else + { + node->right = sp->root; + node->left = node->right->left; + node->right->left = 0; + } + + sp->root = node; + } + + return sp->root; +} + +/* Remove KEY from SP. It is not an error if it did not exist. */ + +void +splay_tree_remove (splay_tree sp, splay_tree_key key) +{ + splay_tree_splay (sp, key); + + if (sp->root && (*sp->comp) (sp->root->key, key) == 0) + { + splay_tree_node left, right; + + left = sp->root->left; + right = sp->root->right; + + /* Delete the root node itself. */ + if (sp->delete_value) + (*sp->delete_value) (sp->root->value); + (*sp->deallocate) (sp->root, sp->allocate_data); + + /* One of the children is now the root. Doesn't matter much + which, so long as we preserve the properties of the tree. */ + if (left) + { + sp->root = left; + + /* If there was a right child as well, hang it off the + right-most leaf of the left child. */ + if (right) + { + while (left->right) + left = left->right; + left->right = right; + } + } + else + sp->root = right; + } +} + +/* Lookup KEY in SP, returning VALUE if present, and NULL + otherwise. */ + +splay_tree_node +splay_tree_lookup (splay_tree sp, splay_tree_key key) +{ + splay_tree_splay (sp, key); + + if (sp->root && (*sp->comp)(sp->root->key, key) == 0) + return sp->root; + else + return 0; +} + +/* Return the node in SP with the greatest key. */ + +splay_tree_node +splay_tree_max (splay_tree sp) +{ + splay_tree_node n = sp->root; + + if (!n) + return NULL; + + while (n->right) + n = n->right; + + return n; +} + +/* Return the node in SP with the smallest key. */ + +splay_tree_node +splay_tree_min (splay_tree sp) +{ + splay_tree_node n = sp->root; + + if (!n) + return NULL; + + while (n->left) + n = n->left; + + return n; +} + +/* Return the immediate predecessor KEY, or NULL if there is no + predecessor. KEY need not be present in the tree. */ + +splay_tree_node +splay_tree_predecessor (splay_tree sp, splay_tree_key key) +{ + int comparison; + splay_tree_node node; + + /* If the tree is empty, there is certainly no predecessor. */ + if (!sp->root) + return NULL; + + /* Splay the tree around KEY. That will leave either the KEY + itself, its predecessor, or its successor at the root. */ + splay_tree_splay (sp, key); + comparison = (*sp->comp)(sp->root->key, key); + + /* If the predecessor is at the root, just return it. */ + if (comparison < 0) + return sp->root; + + /* Otherwise, find the rightmost element of the left subtree. */ + node = sp->root->left; + if (node) + while (node->right) + node = node->right; + + return node; +} + +/* Return the immediate successor KEY, or NULL if there is no + successor. KEY need not be present in the tree. */ + +splay_tree_node +splay_tree_successor (splay_tree sp, splay_tree_key key) +{ + int comparison; + splay_tree_node node; + + /* If the tree is empty, there is certainly no successor. */ + if (!sp->root) + return NULL; + + /* Splay the tree around KEY. That will leave either the KEY + itself, its predecessor, or its successor at the root. */ + splay_tree_splay (sp, key); + comparison = (*sp->comp)(sp->root->key, key); + + /* If the successor is at the root, just return it. */ + if (comparison > 0) + return sp->root; + + /* Otherwise, find the leftmost element of the right subtree. */ + node = sp->root->right; + if (node) + while (node->left) + node = node->left; + + return node; +} + +/* Call FN, passing it the DATA, for every node in SP, following an + in-order traversal. If FN every returns a non-zero value, the + iteration ceases immediately, and the value is returned. + Otherwise, this function returns 0. */ + +int +splay_tree_foreach (splay_tree sp, splay_tree_foreach_fn fn, void *data) +{ + return splay_tree_foreach_helper (sp, sp->root, fn, data); +} + +/* Splay-tree comparison function, treating the keys as ints. */ + +int +splay_tree_compare_ints (splay_tree_key k1, splay_tree_key k2) +{ + if ((int) k1 < (int) k2) + return -1; + else if ((int) k1 > (int) k2) + return 1; + else + return 0; +} + +/* Splay-tree comparison function, treating the keys as pointers. */ + +int +splay_tree_compare_pointers (splay_tree_key k1, splay_tree_key k2) +{ + if ((char*) k1 < (char*) k2) + return -1; + else if ((char*) k1 > (char*) k2) + return 1; + else + return 0; +} diff --git a/libiberty/stpcpy.c b/libiberty/stpcpy.c new file mode 100644 index 0000000..57b32d1 --- /dev/null +++ b/libiberty/stpcpy.c @@ -0,0 +1,43 @@ +/* Implement the stpcpy function. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Kaveh R. Ghazi . + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* + +@deftypefn Supplemental char* stpcpy (char *@var{dst}, const char *@var{src}) + +Copies the string @var{src} into @var{dst}. Returns a pointer to +@var{dst} + strlen(@var{src}). + +@end deftypefn + +*/ + +#include +#include + +extern size_t strlen (const char *); +extern PTR memcpy (PTR, const PTR, size_t); + +char * +stpcpy (char *dst, const char *src) +{ + const size_t len = strlen (src); + return (char *) memcpy (dst, src, len + 1) + len; +} diff --git a/libiberty/stpncpy.c b/libiberty/stpncpy.c new file mode 100644 index 0000000..f97206a --- /dev/null +++ b/libiberty/stpncpy.c @@ -0,0 +1,47 @@ +/* Implement the stpncpy function. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Kaveh R. Ghazi . + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* + +@deftypefn Supplemental char* stpncpy (char *@var{dst}, const char *@var{src}, size_t @var{len}) + +Copies the string @var{src} into @var{dst}, copying exactly @var{len} +and padding with zeros if necessary. If @var{len} < strlen(@var{src}) +then return @var{dst} + @var{len}, otherwise returns @var{dst} + +strlen(@var{src}). + +@end deftypefn + +*/ + +#include +#include + +extern size_t strlen (const char *); +extern char *strncpy (char *, const char *, size_t); + +char * +stpncpy (char *dst, const char *src, size_t len) +{ + size_t n = strlen (src); + if (n > len) + n = len; + return strncpy (dst, src, len) + n; +} diff --git a/libiberty/strcasecmp.c b/libiberty/strcasecmp.c new file mode 100644 index 0000000..131d81c --- /dev/null +++ b/libiberty/strcasecmp.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and that due credit is given + * to the University of California at Berkeley. The name of the University + * may not be used to endorse or promote products derived from this + * software without specific written prior permission. This software + * is provided ``as is'' without express or implied warranty. + */ + +/* + +@deftypefn Supplemental int strcasecmp (const char *@var{s1}, const char *@var{s2}) + +A case-insensitive @code{strcmp}. + +@end deftypefn + +*/ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strcasecmp.c 5.5 (Berkeley) 11/24/87"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include + +/* + * This array is designed for mapping upper and lower case letter + * together for a case independent comparison. The mappings are + * based upon ascii character sequences. + */ +typedef unsigned char uc; +static const unsigned char charmap[] = { + (uc)'\000',(uc)'\001',(uc)'\002',(uc)'\003',(uc)'\004',(uc)'\005',(uc)'\006',(uc)'\007', + (uc)'\010',(uc)'\011',(uc)'\012',(uc)'\013',(uc)'\014',(uc)'\015',(uc)'\016',(uc)'\017', + (uc)'\020',(uc)'\021',(uc)'\022',(uc)'\023',(uc)'\024',(uc)'\025',(uc)'\026',(uc)'\027', + (uc)'\030',(uc)'\031',(uc)'\032',(uc)'\033',(uc)'\034',(uc)'\035',(uc)'\036',(uc)'\037', + (uc)'\040',(uc)'\041',(uc)'\042',(uc)'\043',(uc)'\044',(uc)'\045',(uc)'\046',(uc)'\047', + (uc)'\050',(uc)'\051',(uc)'\052',(uc)'\053',(uc)'\054',(uc)'\055',(uc)'\056',(uc)'\057', + (uc)'\060',(uc)'\061',(uc)'\062',(uc)'\063',(uc)'\064',(uc)'\065',(uc)'\066',(uc)'\067', + (uc)'\070',(uc)'\071',(uc)'\072',(uc)'\073',(uc)'\074',(uc)'\075',(uc)'\076',(uc)'\077', + (uc)'\100',(uc)'\141',(uc)'\142',(uc)'\143',(uc)'\144',(uc)'\145',(uc)'\146',(uc)'\147', + (uc)'\150',(uc)'\151',(uc)'\152',(uc)'\153',(uc)'\154',(uc)'\155',(uc)'\156',(uc)'\157', + (uc)'\160',(uc)'\161',(uc)'\162',(uc)'\163',(uc)'\164',(uc)'\165',(uc)'\166',(uc)'\167', + (uc)'\170',(uc)'\171',(uc)'\172',(uc)'\133',(uc)'\134',(uc)'\135',(uc)'\136',(uc)'\137', + (uc)'\140',(uc)'\141',(uc)'\142',(uc)'\143',(uc)'\144',(uc)'\145',(uc)'\146',(uc)'\147', + (uc)'\150',(uc)'\151',(uc)'\152',(uc)'\153',(uc)'\154',(uc)'\155',(uc)'\156',(uc)'\157', + (uc)'\160',(uc)'\161',(uc)'\162',(uc)'\163',(uc)'\164',(uc)'\165',(uc)'\166',(uc)'\167', + (uc)'\170',(uc)'\171',(uc)'\172',(uc)'\173',(uc)'\174',(uc)'\175',(uc)'\176',(uc)'\177', + (uc)'\200',(uc)'\201',(uc)'\202',(uc)'\203',(uc)'\204',(uc)'\205',(uc)'\206',(uc)'\207', + (uc)'\210',(uc)'\211',(uc)'\212',(uc)'\213',(uc)'\214',(uc)'\215',(uc)'\216',(uc)'\217', + (uc)'\220',(uc)'\221',(uc)'\222',(uc)'\223',(uc)'\224',(uc)'\225',(uc)'\226',(uc)'\227', + (uc)'\230',(uc)'\231',(uc)'\232',(uc)'\233',(uc)'\234',(uc)'\235',(uc)'\236',(uc)'\237', + (uc)'\240',(uc)'\241',(uc)'\242',(uc)'\243',(uc)'\244',(uc)'\245',(uc)'\246',(uc)'\247', + (uc)'\250',(uc)'\251',(uc)'\252',(uc)'\253',(uc)'\254',(uc)'\255',(uc)'\256',(uc)'\257', + (uc)'\260',(uc)'\261',(uc)'\262',(uc)'\263',(uc)'\264',(uc)'\265',(uc)'\266',(uc)'\267', + (uc)'\270',(uc)'\271',(uc)'\272',(uc)'\273',(uc)'\274',(uc)'\275',(uc)'\276',(uc)'\277', + (uc)'\300',(uc)'\341',(uc)'\342',(uc)'\343',(uc)'\344',(uc)'\345',(uc)'\346',(uc)'\347', + (uc)'\350',(uc)'\351',(uc)'\352',(uc)'\353',(uc)'\354',(uc)'\355',(uc)'\356',(uc)'\357', + (uc)'\360',(uc)'\361',(uc)'\362',(uc)'\363',(uc)'\364',(uc)'\365',(uc)'\366',(uc)'\367', + (uc)'\370',(uc)'\371',(uc)'\372',(uc)'\333',(uc)'\334',(uc)'\335',(uc)'\336',(uc)'\337', + (uc)'\340',(uc)'\341',(uc)'\342',(uc)'\343',(uc)'\344',(uc)'\345',(uc)'\346',(uc)'\347', + (uc)'\350',(uc)'\351',(uc)'\352',(uc)'\353',(uc)'\354',(uc)'\355',(uc)'\356',(uc)'\357', + (uc)'\360',(uc)'\361',(uc)'\362',(uc)'\363',(uc)'\364',(uc)'\365',(uc)'\366',(uc)'\367', + (uc)'\370',(uc)'\371',(uc)'\372',(uc)'\373',(uc)'\374',(uc)'\375',(uc)'\376',(uc)'\377', +}; + +int +strcasecmp(const char *s1, const char *s2) +{ + register unsigned char u1, u2; + + for (;;) { + u1 = (unsigned char) *s1++; + u2 = (unsigned char) *s2++; + if (charmap[u1] != charmap[u2]) { + return charmap[u1] - charmap[u2]; + } + if (u1 == '\0') { + return 0; + } + } +} + diff --git a/libiberty/strchr.c b/libiberty/strchr.c new file mode 100644 index 0000000..935805e --- /dev/null +++ b/libiberty/strchr.c @@ -0,0 +1,28 @@ +/* Portable version of strchr() + This function is in the public domain. */ + +/* + +@deftypefn Supplemental char* strchr (const char *@var{s}, int @var{c}) + +Returns a pointer to the first occurrence of the character @var{c} in +the string @var{s}, or @code{NULL} if not found. If @var{c} is itself the +null character, the results are undefined. + +@end deftypefn + +*/ + +#include + +char * +strchr (register const char *s, int c) +{ + do { + if (*s == c) + { + return (char*)s; + } + } while (*s++); + return (0); +} diff --git a/libiberty/strdup.c b/libiberty/strdup.c new file mode 100644 index 0000000..78c2093 --- /dev/null +++ b/libiberty/strdup.c @@ -0,0 +1,27 @@ +/* + +@deftypefn Supplemental char* strdup (const char *@var{s}) + +Returns a pointer to a copy of @var{s} in memory obtained from +@code{malloc}, or @code{NULL} if insufficient memory was available. + +@end deftypefn + +*/ + +#include +#include + +extern size_t strlen (const char*); +extern PTR malloc (size_t); +extern PTR memcpy (PTR, const PTR, size_t); + +char * +strdup(const char *s) +{ + size_t len = strlen (s) + 1; + char *result = (char*) malloc (len); + if (result == (char*) 0) + return (char*) 0; + return (char*) memcpy (result, s, len); +} diff --git a/libiberty/strerror.c b/libiberty/strerror.c new file mode 100644 index 0000000..0efadc3 --- /dev/null +++ b/libiberty/strerror.c @@ -0,0 +1,809 @@ +/* Extended support for using errno values. + Written by Fred Fish. fnf@cygnus.com + This file is in the public domain. --Per Bothner. */ + +#include "config.h" + +#ifdef HAVE_SYS_ERRLIST +/* Note that errno.h (not sure what OS) or stdio.h (BSD 4.4, at least) + might declare sys_errlist in a way that the compiler might consider + incompatible with our later declaration, perhaps by using const + attributes. So we hide the declaration in errno.h (if any) using a + macro. */ +#define sys_nerr sys_nerr__ +#define sys_errlist sys_errlist__ +#endif + +#include "ansidecl.h" +#include "libiberty.h" + +#include +#include + +#ifdef HAVE_SYS_ERRLIST +#undef sys_nerr +#undef sys_errlist +#endif + +/* Routines imported from standard C runtime libraries. */ + +#ifdef HAVE_STDLIB_H +#include +#else +extern PTR malloc (); +#endif + +#ifdef HAVE_STRING_H +#include +#else +extern PTR memset (); +#endif + +#ifndef MAX +# define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +static void init_error_tables (void); + +/* Translation table for errno values. See intro(2) in most UNIX systems + Programmers Reference Manuals. + + Note that this table is generally only accessed when it is used at runtime + to initialize errno name and message tables that are indexed by errno + value. + + Not all of these errnos will exist on all systems. This table is the only + thing that should have to be updated as new error numbers are introduced. + It's sort of ugly, but at least its portable. */ + +struct error_info +{ + const int value; /* The numeric value from */ + const char *const name; /* The equivalent symbolic value */ +#ifndef HAVE_SYS_ERRLIST + const char *const msg; /* Short message about this value */ +#endif +}; + +#ifndef HAVE_SYS_ERRLIST +# define ENTRY(value, name, msg) {value, name, msg} +#else +# define ENTRY(value, name, msg) {value, name} +#endif + +static const struct error_info error_table[] = +{ +#if defined (EPERM) + ENTRY(EPERM, "EPERM", "Not owner"), +#endif +#if defined (ENOENT) + ENTRY(ENOENT, "ENOENT", "No such file or directory"), +#endif +#if defined (ESRCH) + ENTRY(ESRCH, "ESRCH", "No such process"), +#endif +#if defined (EINTR) + ENTRY(EINTR, "EINTR", "Interrupted system call"), +#endif +#if defined (EIO) + ENTRY(EIO, "EIO", "I/O error"), +#endif +#if defined (ENXIO) + ENTRY(ENXIO, "ENXIO", "No such device or address"), +#endif +#if defined (E2BIG) + ENTRY(E2BIG, "E2BIG", "Arg list too long"), +#endif +#if defined (ENOEXEC) + ENTRY(ENOEXEC, "ENOEXEC", "Exec format error"), +#endif +#if defined (EBADF) + ENTRY(EBADF, "EBADF", "Bad file number"), +#endif +#if defined (ECHILD) + ENTRY(ECHILD, "ECHILD", "No child processes"), +#endif +#if defined (EWOULDBLOCK) /* Put before EAGAIN, sometimes aliased */ + ENTRY(EWOULDBLOCK, "EWOULDBLOCK", "Operation would block"), +#endif +#if defined (EAGAIN) + ENTRY(EAGAIN, "EAGAIN", "No more processes"), +#endif +#if defined (ENOMEM) + ENTRY(ENOMEM, "ENOMEM", "Not enough space"), +#endif +#if defined (EACCES) + ENTRY(EACCES, "EACCES", "Permission denied"), +#endif +#if defined (EFAULT) + ENTRY(EFAULT, "EFAULT", "Bad address"), +#endif +#if defined (ENOTBLK) + ENTRY(ENOTBLK, "ENOTBLK", "Block device required"), +#endif +#if defined (EBUSY) + ENTRY(EBUSY, "EBUSY", "Device busy"), +#endif +#if defined (EEXIST) + ENTRY(EEXIST, "EEXIST", "File exists"), +#endif +#if defined (EXDEV) + ENTRY(EXDEV, "EXDEV", "Cross-device link"), +#endif +#if defined (ENODEV) + ENTRY(ENODEV, "ENODEV", "No such device"), +#endif +#if defined (ENOTDIR) + ENTRY(ENOTDIR, "ENOTDIR", "Not a directory"), +#endif +#if defined (EISDIR) + ENTRY(EISDIR, "EISDIR", "Is a directory"), +#endif +#if defined (EINVAL) + ENTRY(EINVAL, "EINVAL", "Invalid argument"), +#endif +#if defined (ENFILE) + ENTRY(ENFILE, "ENFILE", "File table overflow"), +#endif +#if defined (EMFILE) + ENTRY(EMFILE, "EMFILE", "Too many open files"), +#endif +#if defined (ENOTTY) + ENTRY(ENOTTY, "ENOTTY", "Not a typewriter"), +#endif +#if defined (ETXTBSY) + ENTRY(ETXTBSY, "ETXTBSY", "Text file busy"), +#endif +#if defined (EFBIG) + ENTRY(EFBIG, "EFBIG", "File too large"), +#endif +#if defined (ENOSPC) + ENTRY(ENOSPC, "ENOSPC", "No space left on device"), +#endif +#if defined (ESPIPE) + ENTRY(ESPIPE, "ESPIPE", "Illegal seek"), +#endif +#if defined (EROFS) + ENTRY(EROFS, "EROFS", "Read-only file system"), +#endif +#if defined (EMLINK) + ENTRY(EMLINK, "EMLINK", "Too many links"), +#endif +#if defined (EPIPE) + ENTRY(EPIPE, "EPIPE", "Broken pipe"), +#endif +#if defined (EDOM) + ENTRY(EDOM, "EDOM", "Math argument out of domain of func"), +#endif +#if defined (ERANGE) + ENTRY(ERANGE, "ERANGE", "Math result not representable"), +#endif +#if defined (ENOMSG) + ENTRY(ENOMSG, "ENOMSG", "No message of desired type"), +#endif +#if defined (EIDRM) + ENTRY(EIDRM, "EIDRM", "Identifier removed"), +#endif +#if defined (ECHRNG) + ENTRY(ECHRNG, "ECHRNG", "Channel number out of range"), +#endif +#if defined (EL2NSYNC) + ENTRY(EL2NSYNC, "EL2NSYNC", "Level 2 not synchronized"), +#endif +#if defined (EL3HLT) + ENTRY(EL3HLT, "EL3HLT", "Level 3 halted"), +#endif +#if defined (EL3RST) + ENTRY(EL3RST, "EL3RST", "Level 3 reset"), +#endif +#if defined (ELNRNG) + ENTRY(ELNRNG, "ELNRNG", "Link number out of range"), +#endif +#if defined (EUNATCH) + ENTRY(EUNATCH, "EUNATCH", "Protocol driver not attached"), +#endif +#if defined (ENOCSI) + ENTRY(ENOCSI, "ENOCSI", "No CSI structure available"), +#endif +#if defined (EL2HLT) + ENTRY(EL2HLT, "EL2HLT", "Level 2 halted"), +#endif +#if defined (EDEADLK) + ENTRY(EDEADLK, "EDEADLK", "Deadlock condition"), +#endif +#if defined (ENOLCK) + ENTRY(ENOLCK, "ENOLCK", "No record locks available"), +#endif +#if defined (EBADE) + ENTRY(EBADE, "EBADE", "Invalid exchange"), +#endif +#if defined (EBADR) + ENTRY(EBADR, "EBADR", "Invalid request descriptor"), +#endif +#if defined (EXFULL) + ENTRY(EXFULL, "EXFULL", "Exchange full"), +#endif +#if defined (ENOANO) + ENTRY(ENOANO, "ENOANO", "No anode"), +#endif +#if defined (EBADRQC) + ENTRY(EBADRQC, "EBADRQC", "Invalid request code"), +#endif +#if defined (EBADSLT) + ENTRY(EBADSLT, "EBADSLT", "Invalid slot"), +#endif +#if defined (EDEADLOCK) + ENTRY(EDEADLOCK, "EDEADLOCK", "File locking deadlock error"), +#endif +#if defined (EBFONT) + ENTRY(EBFONT, "EBFONT", "Bad font file format"), +#endif +#if defined (ENOSTR) + ENTRY(ENOSTR, "ENOSTR", "Device not a stream"), +#endif +#if defined (ENODATA) + ENTRY(ENODATA, "ENODATA", "No data available"), +#endif +#if defined (ETIME) + ENTRY(ETIME, "ETIME", "Timer expired"), +#endif +#if defined (ENOSR) + ENTRY(ENOSR, "ENOSR", "Out of streams resources"), +#endif +#if defined (ENONET) + ENTRY(ENONET, "ENONET", "Machine is not on the network"), +#endif +#if defined (ENOPKG) + ENTRY(ENOPKG, "ENOPKG", "Package not installed"), +#endif +#if defined (EREMOTE) + ENTRY(EREMOTE, "EREMOTE", "Object is remote"), +#endif +#if defined (ENOLINK) + ENTRY(ENOLINK, "ENOLINK", "Link has been severed"), +#endif +#if defined (EADV) + ENTRY(EADV, "EADV", "Advertise error"), +#endif +#if defined (ESRMNT) + ENTRY(ESRMNT, "ESRMNT", "Srmount error"), +#endif +#if defined (ECOMM) + ENTRY(ECOMM, "ECOMM", "Communication error on send"), +#endif +#if defined (EPROTO) + ENTRY(EPROTO, "EPROTO", "Protocol error"), +#endif +#if defined (EMULTIHOP) + ENTRY(EMULTIHOP, "EMULTIHOP", "Multihop attempted"), +#endif +#if defined (EDOTDOT) + ENTRY(EDOTDOT, "EDOTDOT", "RFS specific error"), +#endif +#if defined (EBADMSG) + ENTRY(EBADMSG, "EBADMSG", "Not a data message"), +#endif +#if defined (ENAMETOOLONG) + ENTRY(ENAMETOOLONG, "ENAMETOOLONG", "File name too long"), +#endif +#if defined (EOVERFLOW) + ENTRY(EOVERFLOW, "EOVERFLOW", "Value too large for defined data type"), +#endif +#if defined (ENOTUNIQ) + ENTRY(ENOTUNIQ, "ENOTUNIQ", "Name not unique on network"), +#endif +#if defined (EBADFD) + ENTRY(EBADFD, "EBADFD", "File descriptor in bad state"), +#endif +#if defined (EREMCHG) + ENTRY(EREMCHG, "EREMCHG", "Remote address changed"), +#endif +#if defined (ELIBACC) + ENTRY(ELIBACC, "ELIBACC", "Can not access a needed shared library"), +#endif +#if defined (ELIBBAD) + ENTRY(ELIBBAD, "ELIBBAD", "Accessing a corrupted shared library"), +#endif +#if defined (ELIBSCN) + ENTRY(ELIBSCN, "ELIBSCN", ".lib section in a.out corrupted"), +#endif +#if defined (ELIBMAX) + ENTRY(ELIBMAX, "ELIBMAX", "Attempting to link in too many shared libraries"), +#endif +#if defined (ELIBEXEC) + ENTRY(ELIBEXEC, "ELIBEXEC", "Cannot exec a shared library directly"), +#endif +#if defined (EILSEQ) + ENTRY(EILSEQ, "EILSEQ", "Illegal byte sequence"), +#endif +#if defined (ENOSYS) + ENTRY(ENOSYS, "ENOSYS", "Operation not applicable"), +#endif +#if defined (ELOOP) + ENTRY(ELOOP, "ELOOP", "Too many symbolic links encountered"), +#endif +#if defined (ERESTART) + ENTRY(ERESTART, "ERESTART", "Interrupted system call should be restarted"), +#endif +#if defined (ESTRPIPE) + ENTRY(ESTRPIPE, "ESTRPIPE", "Streams pipe error"), +#endif +#if defined (ENOTEMPTY) + ENTRY(ENOTEMPTY, "ENOTEMPTY", "Directory not empty"), +#endif +#if defined (EUSERS) + ENTRY(EUSERS, "EUSERS", "Too many users"), +#endif +#if defined (ENOTSOCK) + ENTRY(ENOTSOCK, "ENOTSOCK", "Socket operation on non-socket"), +#endif +#if defined (EDESTADDRREQ) + ENTRY(EDESTADDRREQ, "EDESTADDRREQ", "Destination address required"), +#endif +#if defined (EMSGSIZE) + ENTRY(EMSGSIZE, "EMSGSIZE", "Message too long"), +#endif +#if defined (EPROTOTYPE) + ENTRY(EPROTOTYPE, "EPROTOTYPE", "Protocol wrong type for socket"), +#endif +#if defined (ENOPROTOOPT) + ENTRY(ENOPROTOOPT, "ENOPROTOOPT", "Protocol not available"), +#endif +#if defined (EPROTONOSUPPORT) + ENTRY(EPROTONOSUPPORT, "EPROTONOSUPPORT", "Protocol not supported"), +#endif +#if defined (ESOCKTNOSUPPORT) + ENTRY(ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT", "Socket type not supported"), +#endif +#if defined (EOPNOTSUPP) + ENTRY(EOPNOTSUPP, "EOPNOTSUPP", "Operation not supported on transport endpoint"), +#endif +#if defined (EPFNOSUPPORT) + ENTRY(EPFNOSUPPORT, "EPFNOSUPPORT", "Protocol family not supported"), +#endif +#if defined (EAFNOSUPPORT) + ENTRY(EAFNOSUPPORT, "EAFNOSUPPORT", "Address family not supported by protocol"), +#endif +#if defined (EADDRINUSE) + ENTRY(EADDRINUSE, "EADDRINUSE", "Address already in use"), +#endif +#if defined (EADDRNOTAVAIL) + ENTRY(EADDRNOTAVAIL, "EADDRNOTAVAIL","Cannot assign requested address"), +#endif +#if defined (ENETDOWN) + ENTRY(ENETDOWN, "ENETDOWN", "Network is down"), +#endif +#if defined (ENETUNREACH) + ENTRY(ENETUNREACH, "ENETUNREACH", "Network is unreachable"), +#endif +#if defined (ENETRESET) + ENTRY(ENETRESET, "ENETRESET", "Network dropped connection because of reset"), +#endif +#if defined (ECONNABORTED) + ENTRY(ECONNABORTED, "ECONNABORTED", "Software caused connection abort"), +#endif +#if defined (ECONNRESET) + ENTRY(ECONNRESET, "ECONNRESET", "Connection reset by peer"), +#endif +#if defined (ENOBUFS) + ENTRY(ENOBUFS, "ENOBUFS", "No buffer space available"), +#endif +#if defined (EISCONN) + ENTRY(EISCONN, "EISCONN", "Transport endpoint is already connected"), +#endif +#if defined (ENOTCONN) + ENTRY(ENOTCONN, "ENOTCONN", "Transport endpoint is not connected"), +#endif +#if defined (ESHUTDOWN) + ENTRY(ESHUTDOWN, "ESHUTDOWN", "Cannot send after transport endpoint shutdown"), +#endif +#if defined (ETOOMANYREFS) + ENTRY(ETOOMANYREFS, "ETOOMANYREFS", "Too many references: cannot splice"), +#endif +#if defined (ETIMEDOUT) + ENTRY(ETIMEDOUT, "ETIMEDOUT", "Connection timed out"), +#endif +#if defined (ECONNREFUSED) + ENTRY(ECONNREFUSED, "ECONNREFUSED", "Connection refused"), +#endif +#if defined (EHOSTDOWN) + ENTRY(EHOSTDOWN, "EHOSTDOWN", "Host is down"), +#endif +#if defined (EHOSTUNREACH) + ENTRY(EHOSTUNREACH, "EHOSTUNREACH", "No route to host"), +#endif +#if defined (EALREADY) + ENTRY(EALREADY, "EALREADY", "Operation already in progress"), +#endif +#if defined (EINPROGRESS) + ENTRY(EINPROGRESS, "EINPROGRESS", "Operation now in progress"), +#endif +#if defined (ESTALE) + ENTRY(ESTALE, "ESTALE", "Stale NFS file handle"), +#endif +#if defined (EUCLEAN) + ENTRY(EUCLEAN, "EUCLEAN", "Structure needs cleaning"), +#endif +#if defined (ENOTNAM) + ENTRY(ENOTNAM, "ENOTNAM", "Not a XENIX named type file"), +#endif +#if defined (ENAVAIL) + ENTRY(ENAVAIL, "ENAVAIL", "No XENIX semaphores available"), +#endif +#if defined (EISNAM) + ENTRY(EISNAM, "EISNAM", "Is a named type file"), +#endif +#if defined (EREMOTEIO) + ENTRY(EREMOTEIO, "EREMOTEIO", "Remote I/O error"), +#endif + ENTRY(0, NULL, NULL) +}; + +#ifdef EVMSERR +/* This is not in the table, because the numeric value of EVMSERR (32767) + lies outside the range of sys_errlist[]. */ +static struct { int value; const char *name, *msg; } + evmserr = { EVMSERR, "EVMSERR", "VMS-specific error" }; +#endif + +/* Translation table allocated and initialized at runtime. Indexed by the + errno value to find the equivalent symbolic value. */ + +static const char **error_names; +static int num_error_names = 0; + +/* Translation table allocated and initialized at runtime, if it does not + already exist in the host environment. Indexed by the errno value to find + the descriptive string. + + We don't export it for use in other modules because even though it has the + same name, it differs from other implementations in that it is dynamically + initialized rather than statically initialized. */ + +#ifndef HAVE_SYS_ERRLIST + +#define sys_nerr sys_nerr__ +#define sys_errlist sys_errlist__ +static int sys_nerr; +static const char **sys_errlist; + +#else + +extern int sys_nerr; +extern char *sys_errlist[]; + +#endif + +/* + +NAME + + init_error_tables -- initialize the name and message tables + +SYNOPSIS + + static void init_error_tables (); + +DESCRIPTION + + Using the error_table, which is initialized at compile time, generate + the error_names and the sys_errlist (if needed) tables, which are + indexed at runtime by a specific errno value. + +BUGS + + The initialization of the tables may fail under low memory conditions, + in which case we don't do anything particularly useful, but we don't + bomb either. Who knows, it might succeed at a later point if we free + some memory in the meantime. In any case, the other routines know + how to deal with lack of a table after trying to initialize it. This + may or may not be considered to be a bug, that we don't specifically + warn about this particular failure mode. + +*/ + +static void +init_error_tables (void) +{ + const struct error_info *eip; + int nbytes; + + /* If we haven't already scanned the error_table once to find the maximum + errno value, then go find it now. */ + + if (num_error_names == 0) + { + for (eip = error_table; eip -> name != NULL; eip++) + { + if (eip -> value >= num_error_names) + { + num_error_names = eip -> value + 1; + } + } + } + + /* Now attempt to allocate the error_names table, zero it out, and then + initialize it from the statically initialized error_table. */ + + if (error_names == NULL) + { + nbytes = num_error_names * sizeof (char *); + if ((error_names = (const char **) malloc (nbytes)) != NULL) + { + memset (error_names, 0, nbytes); + for (eip = error_table; eip -> name != NULL; eip++) + { + error_names[eip -> value] = eip -> name; + } + } + } + +#ifndef HAVE_SYS_ERRLIST + + /* Now attempt to allocate the sys_errlist table, zero it out, and then + initialize it from the statically initialized error_table. */ + + if (sys_errlist == NULL) + { + nbytes = num_error_names * sizeof (char *); + if ((sys_errlist = (const char **) malloc (nbytes)) != NULL) + { + memset (sys_errlist, 0, nbytes); + sys_nerr = num_error_names; + for (eip = error_table; eip -> name != NULL; eip++) + { + sys_errlist[eip -> value] = eip -> msg; + } + } + } + +#endif + +} + +/* + + +@deftypefn Extension int errno_max (void) + +Returns the maximum @code{errno} value for which a corresponding +symbolic name or message is available. Note that in the case where we +use the @code{sys_errlist} supplied by the system, it is possible for +there to be more symbolic names than messages, or vice versa. In +fact, the manual page for @code{perror(3C)} explicitly warns that one +should check the size of the table (@code{sys_nerr}) before indexing +it, since new error codes may be added to the system before they are +added to the table. Thus @code{sys_nerr} might be smaller than value +implied by the largest @code{errno} value defined in @code{}. + +We return the maximum value that can be used to obtain a meaningful +symbolic name or message. + +@end deftypefn + +*/ + +int +errno_max (void) +{ + int maxsize; + + if (error_names == NULL) + { + init_error_tables (); + } + maxsize = MAX (sys_nerr, num_error_names); + return (maxsize - 1); +} + +#ifndef HAVE_STRERROR + +/* + +@deftypefn Supplemental char* strerror (int @var{errnoval}) + +Maps an @code{errno} number to an error message string, the contents +of which are implementation defined. On systems which have the +external variables @code{sys_nerr} and @code{sys_errlist}, these +strings will be the same as the ones used by @code{perror}. + +If the supplied error number is within the valid range of indices for +the @code{sys_errlist}, but no message is available for the particular +error number, then returns the string @samp{Error @var{num}}, where +@var{num} is the error number. + +If the supplied error number is not a valid index into +@code{sys_errlist}, returns @code{NULL}. + +The returned string is only guaranteed to be valid only until the +next call to @code{strerror}. + +@end deftypefn + +*/ + +char * +strerror (int errnoval) +{ + const char *msg; + static char buf[32]; + +#ifndef HAVE_SYS_ERRLIST + + if (error_names == NULL) + { + init_error_tables (); + } + +#endif + + if ((errnoval < 0) || (errnoval >= sys_nerr)) + { +#ifdef EVMSERR + if (errnoval == evmserr.value) + msg = evmserr.msg; + else +#endif + /* Out of range, just return NULL */ + msg = NULL; + } + else if ((sys_errlist == NULL) || (sys_errlist[errnoval] == NULL)) + { + /* In range, but no sys_errlist or no entry at this index. */ + sprintf (buf, "Error %d", errnoval); + msg = buf; + } + else + { + /* In range, and a valid message. Just return the message. */ + msg = (char *) sys_errlist[errnoval]; + } + + return (msg); +} + +#endif /* ! HAVE_STRERROR */ + + +/* + +@deftypefn Replacement {const char*} strerrno (int @var{errnum}) + +Given an error number returned from a system call (typically returned +in @code{errno}), returns a pointer to a string containing the +symbolic name of that error number, as found in @code{}. + +If the supplied error number is within the valid range of indices for +symbolic names, but no name is available for the particular error +number, then returns the string @samp{Error @var{num}}, where @var{num} +is the error number. + +If the supplied error number is not within the range of valid +indices, then returns @code{NULL}. + +The contents of the location pointed to are only guaranteed to be +valid until the next call to @code{strerrno}. + +@end deftypefn + +*/ + +const char * +strerrno (int errnoval) +{ + const char *name; + static char buf[32]; + + if (error_names == NULL) + { + init_error_tables (); + } + + if ((errnoval < 0) || (errnoval >= num_error_names)) + { +#ifdef EVMSERR + if (errnoval == evmserr.value) + name = evmserr.name; + else +#endif + /* Out of range, just return NULL */ + name = NULL; + } + else if ((error_names == NULL) || (error_names[errnoval] == NULL)) + { + /* In range, but no error_names or no entry at this index. */ + sprintf (buf, "Error %d", errnoval); + name = (const char *) buf; + } + else + { + /* In range, and a valid name. Just return the name. */ + name = error_names[errnoval]; + } + + return (name); +} + +/* + +@deftypefn Extension int strtoerrno (const char *@var{name}) + +Given the symbolic name of a error number (e.g., @code{EACCES}), map it +to an errno value. If no translation is found, returns 0. + +@end deftypefn + +*/ + +int +strtoerrno (const char *name) +{ + int errnoval = 0; + + if (name != NULL) + { + if (error_names == NULL) + { + init_error_tables (); + } + for (errnoval = 0; errnoval < num_error_names; errnoval++) + { + if ((error_names[errnoval] != NULL) && + (strcmp (name, error_names[errnoval]) == 0)) + { + break; + } + } + if (errnoval == num_error_names) + { +#ifdef EVMSERR + if (strcmp (name, evmserr.name) == 0) + errnoval = evmserr.value; + else +#endif + errnoval = 0; + } + } + return (errnoval); +} + + +/* A simple little main that does nothing but print all the errno translations + if MAIN is defined and this file is compiled and linked. */ + +#ifdef MAIN + +#include + +int +main (void) +{ + int errn; + int errnmax; + const char *name; + const char *msg; + char *strerror (); + + errnmax = errno_max (); + printf ("%d entries in names table.\n", num_error_names); + printf ("%d entries in messages table.\n", sys_nerr); + printf ("%d is max useful index.\n", errnmax); + + /* Keep printing values until we get to the end of *both* tables, not + *either* table. Note that knowing the maximum useful index does *not* + relieve us of the responsibility of testing the return pointer for + NULL. */ + + for (errn = 0; errn <= errnmax; errn++) + { + name = strerrno (errn); + name = (name == NULL) ? "" : name; + msg = strerror (errn); + msg = (msg == NULL) ? "" : msg; + printf ("%-4d%-18s%s\n", errn, name, msg); + } + + return 0; +} + +#endif diff --git a/libiberty/strncasecmp.c b/libiberty/strncasecmp.c new file mode 100644 index 0000000..47700dd --- /dev/null +++ b/libiberty/strncasecmp.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and that due credit is given + * to the University of California at Berkeley. The name of the University + * may not be used to endorse or promote products derived from this + * software without specific written prior permission. This software + * is provided ``as is'' without express or implied warranty. + */ + +/* + +@deftypefn Supplemental int strncasecmp (const char *@var{s1}, const char *@var{s2}) + +A case-insensitive @code{strncmp}. + +@end deftypefn + +*/ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strcasecmp.c 5.5 (Berkeley) 11/24/87"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include + +/* + * This array is designed for mapping upper and lower case letter + * together for a case independent comparison. The mappings are + * based upon ascii character sequences. + */ +static const unsigned char charmap[] = { + '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', + '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', + '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', + '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', + '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047', + '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057', + '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067', + '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077', + '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147', + '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', + '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', + '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137', + '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147', + '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', + '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', + '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177', + '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207', + '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217', + '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', + '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237', + '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247', + '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257', + '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267', + '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277', + '\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347', + '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', + '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', + '\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337', + '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', + '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', + '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', + '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377', +}; + +int +strncasecmp(const char *s1, const char *s2, register size_t n) +{ + register unsigned char u1, u2; + + for (; n != 0; --n) { + u1 = (unsigned char) *s1++; + u2 = (unsigned char) *s2++; + if (charmap[u1] != charmap[u2]) { + return charmap[u1] - charmap[u2]; + } + if (u1 == '\0') { + return 0; + } + } + return 0; +} diff --git a/libiberty/strncmp.c b/libiberty/strncmp.c new file mode 100644 index 0000000..916c2f0 --- /dev/null +++ b/libiberty/strncmp.c @@ -0,0 +1,33 @@ +/* strncmp -- compare two strings, stop after n bytes. + This function is in the public domain. */ + +/* + +@deftypefn Supplemental int strncmp (const char *@var{s1}, const char *@var{s2}, size_t @var{n}) + +Compares the first @var{n} bytes of two strings, returning a value as +@code{strcmp}. + +@end deftypefn + +*/ + +#include +#include + +int +strncmp(const char *s1, const char *s2, register size_t n) +{ + register unsigned char u1, u2; + + while (n-- > 0) + { + u1 = (unsigned char) *s1++; + u2 = (unsigned char) *s2++; + if (u1 != u2) + return u1 - u2; + if (u1 == '\0') + return 0; + } + return 0; +} diff --git a/libiberty/strndup.c b/libiberty/strndup.c new file mode 100644 index 0000000..9e9b4e2 --- /dev/null +++ b/libiberty/strndup.c @@ -0,0 +1,55 @@ +/* Implement the strndup function. + Copyright (C) 2005 Free Software Foundation, Inc. + Written by Kaveh R. Ghazi . + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* + +@deftypefn Extension char* strndup (const char *@var{s}, size_t @var{n}) + +Returns a pointer to a copy of @var{s} with at most @var{n} characters +in memory obtained from @code{malloc}, or @code{NULL} if insufficient +memory was available. The result is always NUL terminated. + +@end deftypefn + +*/ + +#include "ansidecl.h" +#include + +extern size_t strlen (const char*); +extern PTR malloc (size_t); +extern PTR memcpy (PTR, const PTR, size_t); + +char * +strndup (const char *s, size_t n) +{ + char *result; + size_t len = strlen (s); + + if (n < len) + len = n; + + result = (char *) malloc (len + 1); + if (!result) + return 0; + + result[len] = '\0'; + return (char *) memcpy (result, s, len); +} diff --git a/libiberty/strrchr.c b/libiberty/strrchr.c new file mode 100644 index 0000000..5cf7c14 --- /dev/null +++ b/libiberty/strrchr.c @@ -0,0 +1,28 @@ +/* Portable version of strrchr(). + This function is in the public domain. */ + +/* + +@deftypefn Supplemental char* strrchr (const char *@var{s}, int @var{c}) + +Returns a pointer to the last occurrence of the character @var{c} in +the string @var{s}, or @code{NULL} if not found. If @var{c} is itself the +null character, the results are undefined. + +@end deftypefn + +*/ + +#include + +char * +strrchr (register const char *s, int c) +{ + char *rtnval = 0; + + do { + if (*s == c) + rtnval = (char*) s; + } while (*s++); + return (rtnval); +} diff --git a/libiberty/strsignal.c b/libiberty/strsignal.c new file mode 100644 index 0000000..4ca9e21 --- /dev/null +++ b/libiberty/strsignal.c @@ -0,0 +1,608 @@ +/* Extended support for using signal values. + Written by Fred Fish. fnf@cygnus.com + This file is in the public domain. */ + +#include "config.h" +#include "ansidecl.h" +#include "libiberty.h" + +/* We need to declare sys_siglist, because even if the system provides + it we can't assume that it is declared in (for example, + SunOS provides sys_siglist, but it does not declare it in any + header file). However, we can't declare sys_siglist portably, + because on some systems it is declared with const and on some + systems it is declared without const. If we were using autoconf, + we could work out the right declaration. Until, then we just + ignore any declaration in the system header files, and always + declare it ourselves. With luck, this will always work. */ +#define sys_siglist no_such_symbol +#define sys_nsig sys_nsig__no_such_symbol + +#include +#include + +/* Routines imported from standard C runtime libraries. */ + +#ifdef HAVE_STDLIB_H +#include +#else +extern PTR malloc (); +#endif + +#ifdef HAVE_STRING_H +#include +#else +extern PTR memset (); +#endif + +/* Undefine the macro we used to hide the definition of sys_siglist + found in the system header files. */ +#undef sys_siglist +#undef sys_nsig + +#ifndef NULL +# define NULL (void *) 0 +#endif + +#ifndef MAX +# define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +static void init_signal_tables (void); + +/* Translation table for signal values. + + Note that this table is generally only accessed when it is used at runtime + to initialize signal name and message tables that are indexed by signal + value. + + Not all of these signals will exist on all systems. This table is the only + thing that should have to be updated as new signal numbers are introduced. + It's sort of ugly, but at least its portable. */ + +struct signal_info +{ + const int value; /* The numeric value from */ + const char *const name; /* The equivalent symbolic value */ +#ifndef HAVE_SYS_SIGLIST + const char *const msg; /* Short message about this value */ +#endif +}; + +#ifndef HAVE_SYS_SIGLIST +# define ENTRY(value, name, msg) {value, name, msg} +#else +# define ENTRY(value, name, msg) {value, name} +#endif + +static const struct signal_info signal_table[] = +{ +#if defined (SIGHUP) + ENTRY(SIGHUP, "SIGHUP", "Hangup"), +#endif +#if defined (SIGINT) + ENTRY(SIGINT, "SIGINT", "Interrupt"), +#endif +#if defined (SIGQUIT) + ENTRY(SIGQUIT, "SIGQUIT", "Quit"), +#endif +#if defined (SIGILL) + ENTRY(SIGILL, "SIGILL", "Illegal instruction"), +#endif +#if defined (SIGTRAP) + ENTRY(SIGTRAP, "SIGTRAP", "Trace/breakpoint trap"), +#endif +/* Put SIGIOT before SIGABRT, so that if SIGIOT==SIGABRT then SIGABRT + overrides SIGIOT. SIGABRT is in ANSI and POSIX.1, and SIGIOT isn't. */ +#if defined (SIGIOT) + ENTRY(SIGIOT, "SIGIOT", "IOT trap"), +#endif +#if defined (SIGABRT) + ENTRY(SIGABRT, "SIGABRT", "Aborted"), +#endif +#if defined (SIGEMT) + ENTRY(SIGEMT, "SIGEMT", "Emulation trap"), +#endif +#if defined (SIGFPE) + ENTRY(SIGFPE, "SIGFPE", "Arithmetic exception"), +#endif +#if defined (SIGKILL) + ENTRY(SIGKILL, "SIGKILL", "Killed"), +#endif +#if defined (SIGBUS) + ENTRY(SIGBUS, "SIGBUS", "Bus error"), +#endif +#if defined (SIGSEGV) + ENTRY(SIGSEGV, "SIGSEGV", "Segmentation fault"), +#endif +#if defined (SIGSYS) + ENTRY(SIGSYS, "SIGSYS", "Bad system call"), +#endif +#if defined (SIGPIPE) + ENTRY(SIGPIPE, "SIGPIPE", "Broken pipe"), +#endif +#if defined (SIGALRM) + ENTRY(SIGALRM, "SIGALRM", "Alarm clock"), +#endif +#if defined (SIGTERM) + ENTRY(SIGTERM, "SIGTERM", "Terminated"), +#endif +#if defined (SIGUSR1) + ENTRY(SIGUSR1, "SIGUSR1", "User defined signal 1"), +#endif +#if defined (SIGUSR2) + ENTRY(SIGUSR2, "SIGUSR2", "User defined signal 2"), +#endif +/* Put SIGCLD before SIGCHLD, so that if SIGCLD==SIGCHLD then SIGCHLD + overrides SIGCLD. SIGCHLD is in POXIX.1 */ +#if defined (SIGCLD) + ENTRY(SIGCLD, "SIGCLD", "Child status changed"), +#endif +#if defined (SIGCHLD) + ENTRY(SIGCHLD, "SIGCHLD", "Child status changed"), +#endif +#if defined (SIGPWR) + ENTRY(SIGPWR, "SIGPWR", "Power fail/restart"), +#endif +#if defined (SIGWINCH) + ENTRY(SIGWINCH, "SIGWINCH", "Window size changed"), +#endif +#if defined (SIGURG) + ENTRY(SIGURG, "SIGURG", "Urgent I/O condition"), +#endif +#if defined (SIGIO) + /* "I/O pending" has also been suggested, but is misleading since the + signal only happens when the process has asked for it, not everytime + I/O is pending. */ + ENTRY(SIGIO, "SIGIO", "I/O possible"), +#endif +#if defined (SIGPOLL) + ENTRY(SIGPOLL, "SIGPOLL", "Pollable event occurred"), +#endif +#if defined (SIGSTOP) + ENTRY(SIGSTOP, "SIGSTOP", "Stopped (signal)"), +#endif +#if defined (SIGTSTP) + ENTRY(SIGTSTP, "SIGTSTP", "Stopped (user)"), +#endif +#if defined (SIGCONT) + ENTRY(SIGCONT, "SIGCONT", "Continued"), +#endif +#if defined (SIGTTIN) + ENTRY(SIGTTIN, "SIGTTIN", "Stopped (tty input)"), +#endif +#if defined (SIGTTOU) + ENTRY(SIGTTOU, "SIGTTOU", "Stopped (tty output)"), +#endif +#if defined (SIGVTALRM) + ENTRY(SIGVTALRM, "SIGVTALRM", "Virtual timer expired"), +#endif +#if defined (SIGPROF) + ENTRY(SIGPROF, "SIGPROF", "Profiling timer expired"), +#endif +#if defined (SIGXCPU) + ENTRY(SIGXCPU, "SIGXCPU", "CPU time limit exceeded"), +#endif +#if defined (SIGXFSZ) + ENTRY(SIGXFSZ, "SIGXFSZ", "File size limit exceeded"), +#endif +#if defined (SIGWIND) + ENTRY(SIGWIND, "SIGWIND", "SIGWIND"), +#endif +#if defined (SIGPHONE) + ENTRY(SIGPHONE, "SIGPHONE", "SIGPHONE"), +#endif +#if defined (SIGLOST) + ENTRY(SIGLOST, "SIGLOST", "Resource lost"), +#endif +#if defined (SIGWAITING) + ENTRY(SIGWAITING, "SIGWAITING", "Process's LWPs are blocked"), +#endif +#if defined (SIGLWP) + ENTRY(SIGLWP, "SIGLWP", "Signal LWP"), +#endif +#if defined (SIGDANGER) + ENTRY(SIGDANGER, "SIGDANGER", "Swap space dangerously low"), +#endif +#if defined (SIGGRANT) + ENTRY(SIGGRANT, "SIGGRANT", "Monitor mode granted"), +#endif +#if defined (SIGRETRACT) + ENTRY(SIGRETRACT, "SIGRETRACT", "Need to relinguish monitor mode"), +#endif +#if defined (SIGMSG) + ENTRY(SIGMSG, "SIGMSG", "Monitor mode data available"), +#endif +#if defined (SIGSOUND) + ENTRY(SIGSOUND, "SIGSOUND", "Sound completed"), +#endif +#if defined (SIGSAK) + ENTRY(SIGSAK, "SIGSAK", "Secure attention"), +#endif + ENTRY(0, NULL, NULL) +}; + +/* Translation table allocated and initialized at runtime. Indexed by the + signal value to find the equivalent symbolic value. */ + +static const char **signal_names; +static int num_signal_names = 0; + +/* Translation table allocated and initialized at runtime, if it does not + already exist in the host environment. Indexed by the signal value to find + the descriptive string. + + We don't export it for use in other modules because even though it has the + same name, it differs from other implementations in that it is dynamically + initialized rather than statically initialized. */ + +#ifndef HAVE_SYS_SIGLIST + +static int sys_nsig; +static const char **sys_siglist; + +#else + +#ifdef NSIG +static int sys_nsig = NSIG; +#else +#ifdef _NSIG +static int sys_nsig = _NSIG; +#endif +#endif +extern const char * const sys_siglist[]; + +#endif + + +/* + +NAME + + init_signal_tables -- initialize the name and message tables + +SYNOPSIS + + static void init_signal_tables (); + +DESCRIPTION + + Using the signal_table, which is initialized at compile time, generate + the signal_names and the sys_siglist (if needed) tables, which are + indexed at runtime by a specific signal value. + +BUGS + + The initialization of the tables may fail under low memory conditions, + in which case we don't do anything particularly useful, but we don't + bomb either. Who knows, it might succeed at a later point if we free + some memory in the meantime. In any case, the other routines know + how to deal with lack of a table after trying to initialize it. This + may or may not be considered to be a bug, that we don't specifically + warn about this particular failure mode. + +*/ + +static void +init_signal_tables (void) +{ + const struct signal_info *eip; + int nbytes; + + /* If we haven't already scanned the signal_table once to find the maximum + signal value, then go find it now. */ + + if (num_signal_names == 0) + { + for (eip = signal_table; eip -> name != NULL; eip++) + { + if (eip -> value >= num_signal_names) + { + num_signal_names = eip -> value + 1; + } + } + } + + /* Now attempt to allocate the signal_names table, zero it out, and then + initialize it from the statically initialized signal_table. */ + + if (signal_names == NULL) + { + nbytes = num_signal_names * sizeof (char *); + if ((signal_names = (const char **) malloc (nbytes)) != NULL) + { + memset (signal_names, 0, nbytes); + for (eip = signal_table; eip -> name != NULL; eip++) + { + signal_names[eip -> value] = eip -> name; + } + } + } + +#ifndef HAVE_SYS_SIGLIST + + /* Now attempt to allocate the sys_siglist table, zero it out, and then + initialize it from the statically initialized signal_table. */ + + if (sys_siglist == NULL) + { + nbytes = num_signal_names * sizeof (char *); + if ((sys_siglist = (const char **) malloc (nbytes)) != NULL) + { + memset (sys_siglist, 0, nbytes); + sys_nsig = num_signal_names; + for (eip = signal_table; eip -> name != NULL; eip++) + { + sys_siglist[eip -> value] = eip -> msg; + } + } + } + +#endif + +} + + +/* + +@deftypefn Extension int signo_max (void) + +Returns the maximum signal value for which a corresponding symbolic +name or message is available. Note that in the case where we use the +@code{sys_siglist} supplied by the system, it is possible for there to +be more symbolic names than messages, or vice versa. In fact, the +manual page for @code{psignal(3b)} explicitly warns that one should +check the size of the table (@code{NSIG}) before indexing it, since +new signal codes may be added to the system before they are added to +the table. Thus @code{NSIG} might be smaller than value implied by +the largest signo value defined in @code{}. + +We return the maximum value that can be used to obtain a meaningful +symbolic name or message. + +@end deftypefn + +*/ + +int +signo_max (void) +{ + int maxsize; + + if (signal_names == NULL) + { + init_signal_tables (); + } + maxsize = MAX (sys_nsig, num_signal_names); + return (maxsize - 1); +} + + +/* + +@deftypefn Supplemental {const char *} strsignal (int @var{signo}) + +Maps an signal number to an signal message string, the contents of +which are implementation defined. On systems which have the external +variable @code{sys_siglist}, these strings will be the same as the +ones used by @code{psignal()}. + +If the supplied signal number is within the valid range of indices for +the @code{sys_siglist}, but no message is available for the particular +signal number, then returns the string @samp{Signal @var{num}}, where +@var{num} is the signal number. + +If the supplied signal number is not a valid index into +@code{sys_siglist}, returns @code{NULL}. + +The returned string is only guaranteed to be valid only until the next +call to @code{strsignal}. + +@end deftypefn + +*/ + +#ifndef HAVE_STRSIGNAL + +const char * +strsignal (int signo) +{ + const char *msg; + static char buf[32]; + +#ifndef HAVE_SYS_SIGLIST + + if (signal_names == NULL) + { + init_signal_tables (); + } + +#endif + + if ((signo < 0) || (signo >= sys_nsig)) + { + /* Out of range, just return NULL */ + msg = NULL; + } + else if ((sys_siglist == NULL) || (sys_siglist[signo] == NULL)) + { + /* In range, but no sys_siglist or no entry at this index. */ + sprintf (buf, "Signal %d", signo); + msg = (const char *) buf; + } + else + { + /* In range, and a valid message. Just return the message. */ + msg = (const char *) sys_siglist[signo]; + } + + return (msg); +} + +#endif /* ! HAVE_STRSIGNAL */ + +/* + +@deftypefn Extension {const char*} strsigno (int @var{signo}) + +Given an signal number, returns a pointer to a string containing the +symbolic name of that signal number, as found in @code{}. + +If the supplied signal number is within the valid range of indices for +symbolic names, but no name is available for the particular signal +number, then returns the string @samp{Signal @var{num}}, where +@var{num} is the signal number. + +If the supplied signal number is not within the range of valid +indices, then returns @code{NULL}. + +The contents of the location pointed to are only guaranteed to be +valid until the next call to @code{strsigno}. + +@end deftypefn + +*/ + +const char * +strsigno (int signo) +{ + const char *name; + static char buf[32]; + + if (signal_names == NULL) + { + init_signal_tables (); + } + + if ((signo < 0) || (signo >= num_signal_names)) + { + /* Out of range, just return NULL */ + name = NULL; + } + else if ((signal_names == NULL) || (signal_names[signo] == NULL)) + { + /* In range, but no signal_names or no entry at this index. */ + sprintf (buf, "Signal %d", signo); + name = (const char *) buf; + } + else + { + /* In range, and a valid name. Just return the name. */ + name = signal_names[signo]; + } + + return (name); +} + + +/* + +@deftypefn Extension int strtosigno (const char *@var{name}) + +Given the symbolic name of a signal, map it to a signal number. If no +translation is found, returns 0. + +@end deftypefn + +*/ + +int +strtosigno (const char *name) +{ + int signo = 0; + + if (name != NULL) + { + if (signal_names == NULL) + { + init_signal_tables (); + } + for (signo = 0; signo < num_signal_names; signo++) + { + if ((signal_names[signo] != NULL) && + (strcmp (name, signal_names[signo]) == 0)) + { + break; + } + } + if (signo == num_signal_names) + { + signo = 0; + } + } + return (signo); +} + + +/* + +@deftypefn Supplemental void psignal (int @var{signo}, char *@var{message}) + +Print @var{message} to the standard error, followed by a colon, +followed by the description of the signal specified by @var{signo}, +followed by a newline. + +@end deftypefn + +*/ + +#ifndef HAVE_PSIGNAL + +void +psignal (int signo, char *message) +{ + if (signal_names == NULL) + { + init_signal_tables (); + } + if ((signo <= 0) || (signo >= sys_nsig)) + { + fprintf (stderr, "%s: unknown signal\n", message); + } + else + { + fprintf (stderr, "%s: %s\n", message, sys_siglist[signo]); + } +} + +#endif /* ! HAVE_PSIGNAL */ + + +/* A simple little main that does nothing but print all the signal translations + if MAIN is defined and this file is compiled and linked. */ + +#ifdef MAIN + +#include + +int +main (void) +{ + int signo; + int maxsigno; + const char *name; + const char *msg; + + maxsigno = signo_max (); + printf ("%d entries in names table.\n", num_signal_names); + printf ("%d entries in messages table.\n", sys_nsig); + printf ("%d is max useful index.\n", maxsigno); + + /* Keep printing values until we get to the end of *both* tables, not + *either* table. Note that knowing the maximum useful index does *not* + relieve us of the responsibility of testing the return pointer for + NULL. */ + + for (signo = 0; signo <= maxsigno; signo++) + { + name = strsigno (signo); + name = (name == NULL) ? "" : name; + msg = strsignal (signo); + msg = (msg == NULL) ? "" : msg; + printf ("%-4d%-18s%s\n", signo, name, msg); + } + + return 0; +} + +#endif diff --git a/libiberty/strstr.c b/libiberty/strstr.c new file mode 100644 index 0000000..60902ea --- /dev/null +++ b/libiberty/strstr.c @@ -0,0 +1,41 @@ +/* Simple implementation of strstr for systems without it. + This function is in the public domain. */ + +/* + +@deftypefn Supplemental char* strstr (const char *@var{string}, const char *@var{sub}) + +This function searches for the substring @var{sub} in the string +@var{string}, not including the terminating null characters. A pointer +to the first occurrence of @var{sub} is returned, or @code{NULL} if the +substring is absent. If @var{sub} points to a string with zero +length, the function returns @var{string}. + +@end deftypefn + + +*/ + + +/* FIXME: The above description is ANSI compiliant. This routine has not + been validated to comply with it. -fnf */ + +#include + +extern char *strchr (const char *, int); +extern int strncmp (const void *, const void *, size_t); +extern size_t strlen (const char *); + +char * +strstr (const char *s1, const char *s2) +{ + const char *p = s1; + const size_t len = strlen (s2); + + for (; (p = strchr (p, *s2)) != 0; p++) + { + if (strncmp (p, s2, len) == 0) + return (char *)p; + } + return (0); +} diff --git a/libiberty/strtod.c b/libiberty/strtod.c new file mode 100644 index 0000000..adbc33b --- /dev/null +++ b/libiberty/strtod.c @@ -0,0 +1,136 @@ +/* Implementation of strtod for systems with atof. + Copyright (C) 1991, 1995, 2002 Free Software Foundation, Inc. + +This file is part of the libiberty library. This library is free +software; you can 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, or (at your option) +any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + +As a special exception, if you link this library with files +compiled with a GNU compiler to produce an executable, this does not cause +the resulting executable to be covered by the GNU General Public License. +This exception does not however invalidate any other reasons why +the executable file might be covered by the GNU General Public License. */ + +/* + +@deftypefn Supplemental double strtod (const char *@var{string}, char **@var{endptr}) + +This ISO C function converts the initial portion of @var{string} to a +@code{double}. If @var{endptr} is not @code{NULL}, a pointer to the +character after the last character used in the conversion is stored in +the location referenced by @var{endptr}. If no conversion is +performed, zero is returned and the value of @var{string} is stored in +the location referenced by @var{endptr}. + +@end deftypefn + +*/ + +#include "ansidecl.h" +#include "safe-ctype.h" + +extern double atof (const char *); + +/* Disclaimer: this is currently just used by CHILL in GDB and therefore + has not been tested well. It may have been tested for nothing except + that it compiles. */ + +double +strtod (char *str, char **ptr) +{ + char *p; + + if (ptr == (char **)0) + return atof (str); + + p = str; + + while (ISSPACE (*p)) + ++p; + + if (*p == '+' || *p == '-') + ++p; + + /* INF or INFINITY. */ + if ((p[0] == 'i' || p[0] == 'I') + && (p[1] == 'n' || p[1] == 'N') + && (p[2] == 'f' || p[2] == 'F')) + { + if ((p[3] == 'i' || p[3] == 'I') + && (p[4] == 'n' || p[4] == 'N') + && (p[5] == 'i' || p[5] == 'I') + && (p[6] == 't' || p[6] == 'T') + && (p[7] == 'y' || p[7] == 'Y')) + { + *ptr = p + 8; + return atof (str); + } + else + { + *ptr = p + 3; + return atof (str); + } + } + + /* NAN or NAN(foo). */ + if ((p[0] == 'n' || p[0] == 'N') + && (p[1] == 'a' || p[1] == 'A') + && (p[2] == 'n' || p[2] == 'N')) + { + p += 3; + if (*p == '(') + { + ++p; + while (*p != '\0' && *p != ')') + ++p; + if (*p == ')') + ++p; + } + *ptr = p; + return atof (str); + } + + /* digits, with 0 or 1 periods in it. */ + if (ISDIGIT (*p) || *p == '.') + { + int got_dot = 0; + while (ISDIGIT (*p) || (!got_dot && *p == '.')) + { + if (*p == '.') + got_dot = 1; + ++p; + } + + /* Exponent. */ + if (*p == 'e' || *p == 'E') + { + int i; + i = 1; + if (p[i] == '+' || p[i] == '-') + ++i; + if (ISDIGIT (p[i])) + { + while (ISDIGIT (p[i])) + ++i; + *ptr = p + i; + return atof (str); + } + } + *ptr = p; + return atof (str); + } + /* Didn't find any digits. Doesn't look like a number. */ + *ptr = str; + return 0.0; +} diff --git a/libiberty/strtol.c b/libiberty/strtol.c new file mode 100644 index 0000000..acc7882 --- /dev/null +++ b/libiberty/strtol.c @@ -0,0 +1,163 @@ +/*- + * Copyright (c) 1990 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. [rescinded 22 July 1999] + * 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. + */ + +/* + +@deftypefn Supplemental {long int} strtol (const char *@var{string}, char **@var{endptr}, int @var{base}) +@deftypefnx Supplemental {unsigned long int} strtoul (const char *@var{string}, char **@var{endptr}, int @var{base}) + +The @code{strtol} function converts the string in @var{string} to a +long integer value according to the given @var{base}, which must be +between 2 and 36 inclusive, or be the special value 0. If @var{base} +is 0, @code{strtol} will look for the prefixes @code{0} and @code{0x} +to indicate bases 8 and 16, respectively, else default to base 10. +When the base is 16 (either explicitly or implicitly), a prefix of +@code{0x} is allowed. The handling of @var{endptr} is as that of +@code{strtod} above. The @code{strtoul} function is the same, except +that the converted value is unsigned. + +@end deftypefn + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#include +#ifdef NEED_DECLARATION_ERRNO +extern int errno; +#endif +#include "safe-ctype.h" + +/* FIXME: It'd be nice to configure around these, but the include files are too + painful. These macros should at least be more portable than hardwired hex + constants. */ + +#ifndef ULONG_MAX +#define ULONG_MAX ((unsigned long)(~0L)) /* 0xFFFFFFFF */ +#endif + +#ifndef LONG_MAX +#define LONG_MAX ((long)(ULONG_MAX >> 1)) /* 0x7FFFFFFF */ +#endif + +#ifndef LONG_MIN +#define LONG_MIN ((long)(~LONG_MAX)) /* 0x80000000 */ +#endif + +/* + * Convert a string to a long integer. + * + * Ignores `locale' stuff. Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +long +strtol(const char *nptr, char **endptr, register int base) +{ + register const char *s = nptr; + register unsigned long acc; + register int c; + register unsigned long cutoff; + register int neg = 0, any, cutlim; + + /* + * Skip white space and pick up leading +/- sign if any. + * If base is 0, allow 0x for hex and 0 for octal, else + * assume decimal; if base is already 16, allow 0x. + */ + do { + c = *s++; + } while (ISSPACE(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else if (c == '+') + c = *s++; + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + + /* + * Compute the cutoff value between legal numbers and illegal + * numbers. That is the largest legal value, divided by the + * base. An input number that is greater than this value, if + * followed by a legal input character, is too big. One that + * is equal to this value may be valid or not; the limit + * between valid and invalid numbers is then based on the last + * digit. For instance, if the range for longs is + * [-2147483648..2147483647] and the input base is 10, + * cutoff will be set to 214748364 and cutlim to either + * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated + * a value > 214748364, or equal but the next digit is > 7 (or 8), + * the number is too big, and we will return a range error. + * + * Set any if any `digits' consumed; make it negative to indicate + * overflow. + */ + cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX; + cutlim = cutoff % (unsigned long)base; + cutoff /= (unsigned long)base; + for (acc = 0, any = 0;; c = *s++) { + if (ISDIGIT(c)) + c -= '0'; + else if (ISALPHA(c)) + c -= ISUPPER(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = neg ? LONG_MIN : LONG_MAX; + errno = ERANGE; + } else if (neg) + acc = -acc; + if (endptr != 0) + *endptr = (char *) (any ? s - 1 : nptr); + return (acc); +} diff --git a/libiberty/strtoul.c b/libiberty/strtoul.c new file mode 100644 index 0000000..ba80063 --- /dev/null +++ b/libiberty/strtoul.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 1990 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. [rescinded 22 July 1999] + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#include +#ifdef NEED_DECLARATION_ERRNO +extern int errno; +#endif +#if 0 +#include +#endif +#include "ansidecl.h" +#include "safe-ctype.h" + +#ifndef ULONG_MAX +#define ULONG_MAX ((unsigned long)(~0L)) /* 0xFFFFFFFF */ +#endif + +/* + * Convert a string to an unsigned long integer. + * + * Ignores `locale' stuff. Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +unsigned long +strtoul(const char *nptr, char **endptr, register int base) +{ + register const char *s = nptr; + register unsigned long acc; + register int c; + register unsigned long cutoff; + register int neg = 0, any, cutlim; + + /* + * See strtol for comments as to the logic used. + */ + do { + c = *s++; + } while (ISSPACE(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else if (c == '+') + c = *s++; + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + cutoff = (unsigned long)ULONG_MAX / (unsigned long)base; + cutlim = (unsigned long)ULONG_MAX % (unsigned long)base; + for (acc = 0, any = 0;; c = *s++) { + if (ISDIGIT(c)) + c -= '0'; + else if (ISALPHA(c)) + c -= ISUPPER(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = ULONG_MAX; + errno = ERANGE; + } else if (neg) + acc = -acc; + if (endptr != 0) + *endptr = (char *) (any ? s - 1 : nptr); + return (acc); +} diff --git a/libiberty/strverscmp.c b/libiberty/strverscmp.c new file mode 100644 index 0000000..04e1e4a --- /dev/null +++ b/libiberty/strverscmp.c @@ -0,0 +1,157 @@ +/* Compare strings while treating digits characters numerically. + Copyright (C) 1997, 2002, 2005 Free Software Foundation, Inc. + This file is part of the libiberty library. + Contributed by Jean-François Bignolles , 1997. + + Libiberty is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + Libiberty is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. */ + +#include "libiberty.h" +#include "safe-ctype.h" + +/* +@deftypefun int strverscmp (const char *@var{s1}, const char *@var{s2}) +The @code{strverscmp} function compares the string @var{s1} against +@var{s2}, considering them as holding indices/version numbers. Return +value follows the same conventions as found in the @code{strverscmp} +function. In fact, if @var{s1} and @var{s2} contain no digits, +@code{strverscmp} behaves like @code{strcmp}. + +Basically, we compare strings normally (character by character), until +we find a digit in each string - then we enter a special comparison +mode, where each sequence of digits is taken as a whole. If we reach the +end of these two parts without noticing a difference, we return to the +standard comparison mode. There are two types of numeric parts: +"integral" and "fractional" (those begin with a '0'). The types +of the numeric parts affect the way we sort them: + +@itemize @bullet +@item +integral/integral: we compare values as you would expect. + +@item +fractional/integral: the fractional part is less than the integral one. +Again, no surprise. + +@item +fractional/fractional: the things become a bit more complex. +If the common prefix contains only leading zeroes, the longest part is less +than the other one; else the comparison behaves normally. +@end itemize + +@smallexample +strverscmp ("no digit", "no digit") + @result{} 0 // @r{same behavior as strcmp.} +strverscmp ("item#99", "item#100") + @result{} <0 // @r{same prefix, but 99 < 100.} +strverscmp ("alpha1", "alpha001") + @result{} >0 // @r{fractional part inferior to integral one.} +strverscmp ("part1_f012", "part1_f01") + @result{} >0 // @r{two fractional parts.} +strverscmp ("foo.009", "foo.0") + @result{} <0 // @r{idem, but with leading zeroes only.} +@end smallexample + +This function is especially useful when dealing with filename sorting, +because filenames frequently hold indices/version numbers. +@end deftypefun + +*/ + +/* states: S_N: normal, S_I: comparing integral part, S_F: comparing + fractional parts, S_Z: idem but with leading Zeroes only */ +#define S_N 0x0 +#define S_I 0x4 +#define S_F 0x8 +#define S_Z 0xC + +/* result_type: CMP: return diff; LEN: compare using len_diff/diff */ +#define CMP 2 +#define LEN 3 + + +/* Compare S1 and S2 as strings holding indices/version numbers, + returning less than, equal to or greater than zero if S1 is less than, + equal to or greater than S2 (for more info, see the Glibc texinfo doc). */ + +int +strverscmp (const char *s1, const char *s2) +{ + const unsigned char *p1 = (const unsigned char *) s1; + const unsigned char *p2 = (const unsigned char *) s2; + unsigned char c1, c2; + int state; + int diff; + + /* Symbol(s) 0 [1-9] others (padding) + Transition (10) 0 (01) d (00) x (11) - */ + static const unsigned int next_state[] = + { + /* state x d 0 - */ + /* S_N */ S_N, S_I, S_Z, S_N, + /* S_I */ S_N, S_I, S_I, S_I, + /* S_F */ S_N, S_F, S_F, S_F, + /* S_Z */ S_N, S_F, S_Z, S_Z + }; + + static const int result_type[] = + { + /* state x/x x/d x/0 x/- d/x d/d d/0 d/- + 0/x 0/d 0/0 0/- -/x -/d -/0 -/- */ + + /* S_N */ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP, + CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, + /* S_I */ CMP, -1, -1, CMP, +1, LEN, LEN, CMP, + +1, LEN, LEN, CMP, CMP, CMP, CMP, CMP, + /* S_F */ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP, + CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, + /* S_Z */ CMP, +1, +1, CMP, -1, CMP, CMP, CMP, + -1, CMP, CMP, CMP + }; + + if (p1 == p2) + return 0; + + c1 = *p1++; + c2 = *p2++; + /* Hint: '0' is a digit too. */ + state = S_N | ((c1 == '0') + (ISDIGIT (c1) != 0)); + + while ((diff = c1 - c2) == 0 && c1 != '\0') + { + state = next_state[state]; + c1 = *p1++; + c2 = *p2++; + state |= (c1 == '0') + (ISDIGIT (c1) != 0); + } + + state = result_type[state << 2 | (((c2 == '0') + (ISDIGIT (c2) != 0)))]; + + switch (state) + { + case CMP: + return diff; + + case LEN: + while (ISDIGIT (*p1++)) + if (!ISDIGIT (*p2++)) + return 1; + + return ISDIGIT (*p2) ? -1 : diff; + + default: + return state; + } +} diff --git a/libiberty/tmpnam.c b/libiberty/tmpnam.c new file mode 100644 index 0000000..cc34333 --- /dev/null +++ b/libiberty/tmpnam.c @@ -0,0 +1,52 @@ +/* + +@deftypefn Supplemental char* tmpnam (char *@var{s}) + +This function attempts to create a name for a temporary file, which +will be a valid file name yet not exist when @code{tmpnam} checks for +it. @var{s} must point to a buffer of at least @code{L_tmpnam} bytes, +or be @code{NULL}. Use of this function creates a security risk, and it must +not be used in new projects. Use @code{mkstemp} instead. + +@end deftypefn + +*/ + +#include + +#ifndef L_tmpnam +#define L_tmpnam 100 +#endif +#ifndef P_tmpdir +#define P_tmpdir "/usr/tmp" +#endif + +static char tmpnam_buffer[L_tmpnam]; +static int tmpnam_counter; + +extern int getpid (void); + +char * +tmpnam (char *s) +{ + int pid = getpid (); + + if (s == NULL) + s = tmpnam_buffer; + + /* Generate the filename and make sure that there isn't one called + it already. */ + + while (1) + { + FILE *f; + sprintf (s, "%s/%s%x.%x", P_tmpdir, "t", pid, tmpnam_counter); + f = fopen (s, "r"); + if (f == NULL) + break; + tmpnam_counter++; + fclose (f); + } + + return s; +} diff --git a/libiberty/unlink-if-ordinary.c b/libiberty/unlink-if-ordinary.c new file mode 100644 index 0000000..c03b4dd --- /dev/null +++ b/libiberty/unlink-if-ordinary.c @@ -0,0 +1,72 @@ +/* unlink-if-ordinary.c - remove link to a file unless it is special + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of the libiberty library. This library is free +software; you can 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, or (at your option) +any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + +As a special exception, if you link this library with files +compiled with a GNU compiler to produce an executable, this does not cause +the resulting executable to be covered by the GNU General Public License. +This exception does not however invalidate any other reasons why +the executable file might be covered by the GNU General Public License. */ + +/* + +@deftypefn Supplemental int unlink_if_ordinary (const char*) + +Unlinks the named file, unless it is special (e.g. a device file). +Returns 0 when the file was unlinked, a negative value (and errno set) when +there was an error deleting the file, and a positive value if no attempt +was made to unlink the file because it is special. + +@end deftypefn + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#ifdef HAVE_UNISTD_H +#include +#endif +#if HAVE_SYS_STAT_H +#include +#endif + +#include "libiberty.h" + +#ifndef S_ISLNK +#ifdef S_IFLNK +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#else +#define S_ISLNK(m) 0 +#define lstat stat +#endif +#endif + +int +unlink_if_ordinary (const char *name) +{ + struct stat st; + + if (lstat (name, &st) == 0 + && (S_ISREG (st.st_mode) || S_ISLNK (st.st_mode))) + return unlink (name); + + return 1; +} diff --git a/libiberty/vasprintf.c b/libiberty/vasprintf.c new file mode 100644 index 0000000..b6cb94e --- /dev/null +++ b/libiberty/vasprintf.c @@ -0,0 +1,196 @@ +/* Like vsprintf but provides a pointer to malloc'd storage, which must + be freed by the caller. + Copyright (C) 1994, 2003 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include +#if !defined (va_copy) && defined (__va_copy) +# define va_copy(d,s) __va_copy((d),(s)) +#endif +#include +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#else +extern unsigned long strtoul (); +extern PTR malloc (); +#endif +#include "libiberty.h" + +#ifdef TEST +int global_total_width; +#endif + +/* + +@deftypefn Extension int vasprintf (char **@var{resptr}, const char *@var{format}, va_list @var{args}) + +Like @code{vsprintf}, but instead of passing a pointer to a buffer, +you pass a pointer to a pointer. This function will compute the size +of the buffer needed, allocate memory with @code{malloc}, and store a +pointer to the allocated memory in @code{*@var{resptr}}. The value +returned is the same as @code{vsprintf} would return. If memory could +not be allocated, minus one is returned and @code{NULL} is stored in +@code{*@var{resptr}}. + +@end deftypefn + +*/ + +static int int_vasprintf (char **, const char *, va_list); + +static int +int_vasprintf (char **result, const char *format, va_list args) +{ + const char *p = format; + /* Add one to make sure that it is never zero, which might cause malloc + to return NULL. */ + int total_width = strlen (format) + 1; + va_list ap; + +#ifdef va_copy + va_copy (ap, args); +#else + memcpy ((PTR) &ap, (PTR) &args, sizeof (va_list)); +#endif + + while (*p != '\0') + { + if (*p++ == '%') + { + while (strchr ("-+ #0", *p)) + ++p; + if (*p == '*') + { + ++p; + total_width += abs (va_arg (ap, int)); + } + else + total_width += strtoul (p, (char **) &p, 10); + if (*p == '.') + { + ++p; + if (*p == '*') + { + ++p; + total_width += abs (va_arg (ap, int)); + } + else + total_width += strtoul (p, (char **) &p, 10); + } + while (strchr ("hlL", *p)) + ++p; + /* Should be big enough for any format specifier except %s and floats. */ + total_width += 30; + switch (*p) + { + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + case 'c': + (void) va_arg (ap, int); + break; + case 'f': + case 'e': + case 'E': + case 'g': + case 'G': + (void) va_arg (ap, double); + /* Since an ieee double can have an exponent of 307, we'll + make the buffer wide enough to cover the gross case. */ + total_width += 307; + break; + case 's': + total_width += strlen (va_arg (ap, char *)); + break; + case 'p': + case 'n': + (void) va_arg (ap, char *); + break; + } + p++; + } + } +#ifdef va_copy + va_end (ap); +#endif +#ifdef TEST + global_total_width = total_width; +#endif + *result = (char *) malloc (total_width); + if (*result != NULL) + return vsprintf (*result, format, args); + else + return -1; +} + +int +vasprintf (char **result, const char *format, +#if defined (_BSD_VA_LIST_) && defined (__FreeBSD__) + _BSD_VA_LIST_ args) +#else + va_list args) +#endif +{ + return int_vasprintf (result, format, args); +} + +#ifdef TEST +static void ATTRIBUTE_PRINTF_1 +checkit (const char *format, ...) +{ + char *result; + VA_OPEN (args, format); + VA_FIXEDARG (args, const char *, format); + vasprintf (&result, format, args); + VA_CLOSE (args); + + if (strlen (result) < (size_t) global_total_width) + printf ("PASS: "); + else + printf ("FAIL: "); + printf ("%d %s\n", global_total_width, result); + + free (result); +} + +extern int main (void); + +int +main (void) +{ + checkit ("%d", 0x12345678); + checkit ("%200d", 5); + checkit ("%.300d", 6); + checkit ("%100.150d", 7); + checkit ("%s", "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\ +777777777777777777333333333333366666666666622222222222777777777777733333"); + checkit ("%f%s%d%s", 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx"); + + return 0; +} +#endif /* TEST */ diff --git a/libiberty/vfork.c b/libiberty/vfork.c new file mode 100644 index 0000000..eb4ff62 --- /dev/null +++ b/libiberty/vfork.c @@ -0,0 +1,22 @@ +/* Emulate vfork using just plain fork, for systems without a real vfork. + This function is in the public domain. */ + +/* + +@deftypefn Supplemental int vfork (void) + +Emulates @code{vfork} by calling @code{fork} and returning its value. + +@end deftypefn + +*/ + +#include "ansidecl.h" + +extern int fork (void); + +int +vfork (void) +{ + return (fork ()); +} diff --git a/libiberty/vfprintf.c b/libiberty/vfprintf.c new file mode 100644 index 0000000..9bd3ed5 --- /dev/null +++ b/libiberty/vfprintf.c @@ -0,0 +1,15 @@ +/* Provide a version vfprintf in terms of _doprnt. + By Kaveh Ghazi (ghazi@caip.rutgers.edu) 3/29/98 + Copyright (C) 1998 Free Software Foundation, Inc. + */ + +#include "ansidecl.h" +#include +#include +#undef vfprintf + +int +vfprintf (FILE *stream, const char *format, va_list ap) +{ + return _doprnt (format, ap, stream); +} diff --git a/libiberty/vprintf.c b/libiberty/vprintf.c new file mode 100644 index 0000000..c255316 --- /dev/null +++ b/libiberty/vprintf.c @@ -0,0 +1,26 @@ +/* + +@deftypefn Supplemental int vprintf (const char *@var{format}, va_list @var{ap}) +@deftypefnx Supplemental int vfprintf (FILE *@var{stream}, const char *@var{format}, va_list @var{ap}) +@deftypefnx Supplemental int vsprintf (char *@var{str}, const char *@var{format}, va_list @var{ap}) + +These functions are the same as @code{printf}, @code{fprintf}, and +@code{sprintf}, respectively, except that they are called with a +@code{va_list} instead of a variable number of arguments. Note that +they do not call @code{va_end}; this is the application's +responsibility. In @libib{} they are implemented in terms of the +nonstandard but common function @code{_doprnt}. + +@end deftypefn + +*/ + +#include +#include +#include +#undef vprintf +int +vprintf (const char *format, va_list ap) +{ + return vfprintf (stdout, format, ap); +} diff --git a/libiberty/vsnprintf.c b/libiberty/vsnprintf.c new file mode 100644 index 0000000..7df5bd8 --- /dev/null +++ b/libiberty/vsnprintf.c @@ -0,0 +1,145 @@ +/* Implement the vsnprintf function. + Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + Written by Kaveh R. Ghazi . + +This file is part of the libiberty library. This library is free +software; you can 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, or (at your option) +any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + +As a special exception, if you link this library with files +compiled with a GNU compiler to produce an executable, this does not cause +the resulting executable to be covered by the GNU General Public License. +This exception does not however invalidate any other reasons why +the executable file might be covered by the GNU General Public License. */ + +/* + +@deftypefn Supplemental int vsnprintf (char *@var{buf}, size_t @var{n}, const char *@var{format}, va_list @var{ap}) + +This function is similar to vsprintf, but it will print at most +@var{n} characters. On error the return value is -1, otherwise it +returns the number of characters that would have been printed had +@var{n} been sufficiently large, regardless of the actual value of +@var{n}. Note some pre-C99 system libraries do not implement this +correctly so users cannot generally rely on the return value if the +system version of this function is used. + +@end deftypefn + +*/ + +#include "config.h" +#include "ansidecl.h" + +#include +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif + +#include "libiberty.h" + +/* This implementation relies on a working vasprintf. */ +int +vsnprintf (char *s, size_t n, const char *format, va_list ap) +{ + char *buf = 0; + int result = vasprintf (&buf, format, ap); + + if (!buf) + return -1; + if (result < 0) + { + free (buf); + return -1; + } + + result = strlen (buf); + if (n > 0) + { + if ((long) n > result) + memcpy (s, buf, result+1); + else + { + memcpy (s, buf, n-1); + s[n - 1] = 0; + } + } + free (buf); + return result; +} + +#ifdef TEST +/* Set the buffer to a known state. */ +#define CLEAR(BUF) do { memset ((BUF), 'X', sizeof (BUF)); (BUF)[14] = '\0'; } while (0) +/* For assertions. */ +#define VERIFY(P) do { if (!(P)) abort(); } while (0) + +static int ATTRIBUTE_PRINTF_3 +checkit (char *s, size_t n, const char *format, ...) +{ + int result; + VA_OPEN (ap, format); + VA_FIXEDARG (ap, char *, s); + VA_FIXEDARG (ap, size_t, n); + VA_FIXEDARG (ap, const char *, format); + result = vsnprintf (s, n, format, ap); + VA_CLOSE (ap); + return result; +} + +extern int main (void); +int +main (void) +{ + char buf[128]; + int status; + + CLEAR (buf); + status = checkit (buf, 10, "%s:%d", "foobar", 9); + VERIFY (status==8 && memcmp (buf, "foobar:9\0XXXXX\0", 15) == 0); + + CLEAR (buf); + status = checkit (buf, 9, "%s:%d", "foobar", 9); + VERIFY (status==8 && memcmp (buf, "foobar:9\0XXXXX\0", 15) == 0); + + CLEAR (buf); + status = checkit (buf, 8, "%s:%d", "foobar", 9); + VERIFY (status==8 && memcmp (buf, "foobar:\0XXXXXX\0", 15) == 0); + + CLEAR (buf); + status = checkit (buf, 7, "%s:%d", "foobar", 9); + VERIFY (status==8 && memcmp (buf, "foobar\0XXXXXXX\0", 15) == 0); + + CLEAR (buf); + status = checkit (buf, 6, "%s:%d", "foobar", 9); + VERIFY (status==8 && memcmp (buf, "fooba\0XXXXXXXX\0", 15) == 0); + + CLEAR (buf); + status = checkit (buf, 2, "%s:%d", "foobar", 9); + VERIFY (status==8 && memcmp (buf, "f\0XXXXXXXXXXXX\0", 15) == 0); + + CLEAR (buf); + status = checkit (buf, 1, "%s:%d", "foobar", 9); + VERIFY (status==8 && memcmp (buf, "\0XXXXXXXXXXXXX\0", 15) == 0); + + CLEAR (buf); + status = checkit (buf, 0, "%s:%d", "foobar", 9); + VERIFY (status==8 && memcmp (buf, "XXXXXXXXXXXXXX\0", 15) == 0); + + return 0; +} +#endif /* TEST */ diff --git a/libiberty/vsprintf.c b/libiberty/vsprintf.c new file mode 100644 index 0000000..99e7044 --- /dev/null +++ b/libiberty/vsprintf.c @@ -0,0 +1,56 @@ +/* Simple implementation of vsprintf for systems without it. + Highly system-dependent, but should work on most "traditional" + implementations of stdio; newer ones should already have vsprintf. + Written by Per Bothner of Cygnus Support. + Based on libg++'s "form" (written by Doug Lea; dl@rocky.oswego.edu). + Copyright (C) 1991, 1995, 2002 Free Software Foundation, Inc. + +This file is part of the libiberty library. This library is free +software; you can 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, or (at your option) +any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + +As a special exception, if you link this library with files +compiled with a GNU compiler to produce an executable, this does not cause +the resulting executable to be covered by the GNU General Public License. +This exception does not however invalidate any other reasons why +the executable file might be covered by the GNU General Public License. */ + +#include +#include +#include +#undef vsprintf + +#if defined _IOSTRG && defined _IOWRT + +int +vsprintf (char *buf, const char *format, va_list ap) +{ + FILE b; + int ret; +#ifdef VMS + b->_flag = _IOWRT|_IOSTRG; + b->_ptr = buf; + b->_cnt = 12000; +#else + b._flag = _IOWRT|_IOSTRG; + b._ptr = buf; + b._cnt = 12000; +#endif + ret = _doprnt(format, ap, &b); + putc('\0', &b); + return ret; + +} + +#endif diff --git a/libiberty/waitpid.c b/libiberty/waitpid.c new file mode 100644 index 0000000..fd519d7 --- /dev/null +++ b/libiberty/waitpid.c @@ -0,0 +1,35 @@ +/* + +@deftypefn Supplemental int waitpid (int @var{pid}, int *@var{status}, int) + +This is a wrapper around the @code{wait} function. Any ``special'' +values of @var{pid} depend on your implementation of @code{wait}, as +does the return value. The third argument is unused in @libib{}. + +@end deftypefn + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "ansidecl.h" + +/* On some systems (such as WindISS), you must include + to get the definition of "pid_t" before you include . */ +#include + +#ifdef HAVE_SYS_WAIT_H +#include +#endif + +pid_t +waitpid (pid_t pid, int *stat_loc, int options ATTRIBUTE_UNUSED) +{ + for (;;) + { + int wpid = wait(stat_loc); + if (wpid == pid || wpid == -1) + return wpid; + } +} diff --git a/libiberty/xatexit.c b/libiberty/xatexit.c new file mode 100644 index 0000000..6fdad9e --- /dev/null +++ b/libiberty/xatexit.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 1990 Regents of the University of California. + * All rights reserved. + * + * %sccs.include.redist.c% + */ + + +/* + +@deftypefun int xatexit (void (*@var{fn}) (void)) + +Behaves as the standard @code{atexit} function, but with no limit on +the number of registered functions. Returns 0 on success, or @minus{}1 on +failure. If you use @code{xatexit} to register functions, you must use +@code{xexit} to terminate your program. + +@end deftypefun + +*/ + +/* Adapted from newlib/libc/stdlib/{,at}exit.[ch]. + If you use xatexit, you must call xexit instead of exit. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "ansidecl.h" +#include "libiberty.h" + +#include + +#include + +#if VMS +#include +#include +#else +/* For systems with larger pointers than ints, this must be declared. */ +PTR malloc (size_t); +#endif + +static void xatexit_cleanup (void); + +/* Pointer to function run by xexit. */ +extern void (*_xexit_cleanup) (void); + +#define XATEXIT_SIZE 32 + +struct xatexit { + struct xatexit *next; /* next in list */ + int ind; /* next index in this table */ + void (*fns[XATEXIT_SIZE]) (void); /* the table itself */ +}; + +/* Allocate one struct statically to guarantee that we can register + at least a few handlers. */ +static struct xatexit xatexit_first; + +/* Points to head of LIFO stack. */ +static struct xatexit *xatexit_head = &xatexit_first; + +/* Register function FN to be run by xexit. + Return 0 if successful, -1 if not. */ + +int +xatexit (void (*fn) (void)) +{ + register struct xatexit *p; + + /* Tell xexit to call xatexit_cleanup. */ + if (!_xexit_cleanup) + _xexit_cleanup = xatexit_cleanup; + + p = xatexit_head; + if (p->ind >= XATEXIT_SIZE) + { + if ((p = (struct xatexit *) malloc (sizeof *p)) == NULL) + return -1; + p->ind = 0; + p->next = xatexit_head; + xatexit_head = p; + } + p->fns[p->ind++] = fn; + return 0; +} + +/* Call any cleanup functions. */ + +static void +xatexit_cleanup (void) +{ + register struct xatexit *p; + register int n; + + for (p = xatexit_head; p; p = p->next) + for (n = p->ind; --n >= 0;) + (*p->fns[n]) (); +} diff --git a/libiberty/xexit.c b/libiberty/xexit.c new file mode 100644 index 0000000..421e5e2 --- /dev/null +++ b/libiberty/xexit.c @@ -0,0 +1,52 @@ +/* xexit.c -- Run any exit handlers, then exit. + Copyright (C) 1994, 95, 1997 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If not, write +to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* + +@deftypefn Replacement void xexit (int @var{code}) + +Terminates the program. If any functions have been registered with +the @code{xatexit} replacement function, they will be called first. +Termination is handled via the system's normal @code{exit} call. + +@end deftypefn + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#include "libiberty.h" + + +/* This variable is set by xatexit if it is called. This way, xmalloc + doesn't drag xatexit into the link. */ +void (*_xexit_cleanup) (void); + +void +xexit (int code) +{ + if (_xexit_cleanup != NULL) + (*_xexit_cleanup) (); + exit (code); +} diff --git a/libiberty/xmalloc.c b/libiberty/xmalloc.c new file mode 100644 index 0000000..3e97aab --- /dev/null +++ b/libiberty/xmalloc.c @@ -0,0 +1,184 @@ +/* memory allocation routines with error checking. + Copyright 1989, 90, 91, 92, 93, 94 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* + +@deftypefn Replacement void* xmalloc (size_t) + +Allocate memory without fail. If @code{malloc} fails, this will print +a message to @code{stderr} (using the name set by +@code{xmalloc_set_program_name}, +if any) and then call @code{xexit}. Note that it is therefore safe for +a program to contain @code{#define malloc xmalloc} in its source. + +@end deftypefn + +@deftypefn Replacement void* xrealloc (void *@var{ptr}, size_t @var{size}) +Reallocate memory without fail. This routine functions like @code{realloc}, +but will behave the same as @code{xmalloc} if memory cannot be found. + +@end deftypefn + +@deftypefn Replacement void* xcalloc (size_t @var{nelem}, size_t @var{elsize}) + +Allocate memory without fail, and set it to zero. This routine functions +like @code{calloc}, but will behave the same as @code{xmalloc} if memory +cannot be found. + +@end deftypefn + +@deftypefn Replacement void xmalloc_set_program_name (const char *@var{name}) + +You can use this to set the name of the program used by +@code{xmalloc_failed} when printing a failure message. + +@end deftypefn + +@deftypefn Replacement void xmalloc_failed (size_t) + +This function is not meant to be called by client code, and is listed +here for completeness only. If any of the allocation routines fail, this +function will be called to print an error message and terminate execution. + +@end deftypefn + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "ansidecl.h" +#include "libiberty.h" + +#include + +#include + +#if VMS +#include +#include +#else +/* For systems with larger pointers than ints, these must be declared. */ +# if HAVE_STDLIB_H && HAVE_UNISTD_H && HAVE_DECL_MALLOC \ + && HAVE_DECL_REALLOC && HAVE_DECL_CALLOC && HAVE_DECL_SBRK +# include +# include +# else +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ +void *malloc (size_t); +void *realloc (void *, size_t); +void *calloc (size_t, size_t); +void *sbrk (ptrdiff_t); +# ifdef __cplusplus +} +# endif /* __cplusplus */ +# endif /* HAVE_STDLIB_H ... */ +#endif /* VMS */ + +/* The program name if set. */ +static const char *name = ""; + +#ifdef HAVE_SBRK +/* The initial sbrk, set when the program name is set. Not used for win32 + ports other than cygwin32. */ +static char *first_break = NULL; +#endif /* HAVE_SBRK */ + +void +xmalloc_set_program_name (const char *s) +{ + name = s; +#ifdef HAVE_SBRK + /* Win32 ports other than cygwin32 don't have brk() */ + if (first_break == NULL) + first_break = (char *) sbrk (0); +#endif /* HAVE_SBRK */ +} + +void +xmalloc_failed (size_t size) +{ +#ifdef HAVE_SBRK + extern char **environ; + size_t allocated; + + if (first_break != NULL) + allocated = (char *) sbrk (0) - first_break; + else + allocated = (char *) sbrk (0) - (char *) &environ; + fprintf (stderr, + "\n%s%sout of memory allocating %lu bytes after a total of %lu bytes\n", + name, *name ? ": " : "", + (unsigned long) size, (unsigned long) allocated); +#else /* HAVE_SBRK */ + fprintf (stderr, + "\n%s%sout of memory allocating %lu bytes\n", + name, *name ? ": " : "", + (unsigned long) size); +#endif /* HAVE_SBRK */ + xexit (1); +} + +PTR +xmalloc (size_t size) +{ + PTR newmem; + + if (size == 0) + size = 1; + newmem = malloc (size); + if (!newmem) + xmalloc_failed (size); + + return (newmem); +} + +PTR +xcalloc (size_t nelem, size_t elsize) +{ + PTR newmem; + + if (nelem == 0 || elsize == 0) + nelem = elsize = 1; + + newmem = calloc (nelem, elsize); + if (!newmem) + xmalloc_failed (nelem * elsize); + + return (newmem); +} + +PTR +xrealloc (PTR oldmem, size_t size) +{ + PTR newmem; + + if (size == 0) + size = 1; + if (!oldmem) + newmem = malloc (size); + else + newmem = realloc (oldmem, size); + if (!newmem) + xmalloc_failed (size); + + return (newmem); +} diff --git a/libiberty/xmemdup.c b/libiberty/xmemdup.c new file mode 100644 index 0000000..d483116 --- /dev/null +++ b/libiberty/xmemdup.c @@ -0,0 +1,38 @@ +/* xmemdup.c -- Duplicate a memory buffer, using xcalloc. + This trivial function is in the public domain. + Jeff Garzik, September 1999. */ + +/* + +@deftypefn Replacement void* xmemdup (void *@var{input}, size_t @var{copy_size}, size_t @var{alloc_size}) + +Duplicates a region of memory without fail. First, @var{alloc_size} bytes +are allocated, then @var{copy_size} bytes from @var{input} are copied into +it, and the new memory is returned. If fewer bytes are copied than were +allocated, the remaining memory is zeroed. + +@end deftypefn + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "ansidecl.h" +#include "libiberty.h" + +#include /* For size_t. */ +#ifdef HAVE_STRING_H +#include +#else +# ifdef HAVE_STRINGS_H +# include +# endif +#endif + +PTR +xmemdup (const PTR input, size_t copy_size, size_t alloc_size) +{ + PTR output = xcalloc (1, alloc_size); + return (PTR) memcpy (output, input, copy_size); +} diff --git a/libiberty/xstrdup.c b/libiberty/xstrdup.c new file mode 100644 index 0000000..9ac2ea0 --- /dev/null +++ b/libiberty/xstrdup.c @@ -0,0 +1,36 @@ +/* xstrdup.c -- Duplicate a string in memory, using xmalloc. + This trivial function is in the public domain. + Ian Lance Taylor, Cygnus Support, December 1995. */ + +/* + +@deftypefn Replacement char* xstrdup (const char *@var{s}) + +Duplicates a character string without fail, using @code{xmalloc} to +obtain memory. + +@end deftypefn + +*/ + +#include +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef HAVE_STRING_H +#include +#else +# ifdef HAVE_STRINGS_H +# include +# endif +#endif +#include "ansidecl.h" +#include "libiberty.h" + +char * +xstrdup (const char *s) +{ + register size_t len = strlen (s) + 1; + register char *ret = XNEWVEC (char, len); + return (char *) memcpy (ret, s, len); +} diff --git a/libiberty/xstrerror.c b/libiberty/xstrerror.c new file mode 100644 index 0000000..2ea2200 --- /dev/null +++ b/libiberty/xstrerror.c @@ -0,0 +1,79 @@ +/* xstrerror.c -- jacket routine for more robust strerror() usage. + Fri Jun 16 18:30:00 1995 Pat Rankin + This code is in the public domain. */ + +/* + +@deftypefn Replacement char* xstrerror (int @var{errnum}) + +Behaves exactly like the standard @code{strerror} function, but +will never return a @code{NULL} pointer. + +@end deftypefn + +*/ + +#include + +#include "config.h" +#include "libiberty.h" + +#ifdef VMS +# include +# if !defined (__STRICT_ANSI__) && !defined (__HIDE_FORBIDDEN_NAMES) +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ +extern char *strerror (int,...); +# define DONT_DECLARE_STRERROR +# ifdef __cplusplus +} +# endif /* __cplusplus */ +# endif +#endif /* VMS */ + + +#ifndef DONT_DECLARE_STRERROR +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ +extern char *strerror (int); +# ifdef __cplusplus +} +# endif /* __cplusplus */ +#endif + +/* If strerror returns NULL, we'll format the number into a static buffer. */ + +#define ERRSTR_FMT "undocumented error #%d" +static char xstrerror_buf[sizeof ERRSTR_FMT + 20]; + +/* Like strerror, but result is never a null pointer. */ + +char * +xstrerror (int errnum) +{ + char *errstr; +#ifdef VMS + char *(*vmslib_strerror) (int,...); + + /* Override any possibly-conflicting declaration from system header. */ + vmslib_strerror = (char *(*) (int,...)) strerror; + /* Second argument matters iff first is EVMSERR, but it's simpler to + pass it unconditionally. `vaxc$errno' is declared in + and maintained by the run-time library in parallel to `errno'. + We assume that `errnum' corresponds to the last value assigned to + errno by the run-time library, hence vaxc$errno will be relevant. */ + errstr = (*vmslib_strerror) (errnum, vaxc$errno); +#else + errstr = strerror (errnum); +#endif + + /* If `errnum' is out of range, result might be NULL. We'll fix that. */ + if (!errstr) + { + sprintf (xstrerror_buf, ERRSTR_FMT, errnum); + errstr = xstrerror_buf; + } + return errstr; +} diff --git a/libiberty/xstrndup.c b/libiberty/xstrndup.c new file mode 100644 index 0000000..0a41f60 --- /dev/null +++ b/libiberty/xstrndup.c @@ -0,0 +1,60 @@ +/* Implement the xstrndup function. + Copyright (C) 2005 Free Software Foundation, Inc. + Written by Kaveh R. Ghazi . + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* + +@deftypefn Replacement char* xstrndup (const char *@var{s}, size_t @var{n}) + +Returns a pointer to a copy of @var{s} with at most @var{n} characters +without fail, using @code{xmalloc} to obtain memory. The result is +always NUL terminated. + +@end deftypefn + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#ifdef HAVE_STRING_H +#include +#else +# ifdef HAVE_STRINGS_H +# include +# endif +#endif +#include "ansidecl.h" +#include "libiberty.h" + +char * +xstrndup (const char *s, size_t n) +{ + char *result; + size_t len = strlen (s); + + if (n < len) + len = n; + + result = XNEWVEC (char, len + 1); + + result[len] = '\0'; + return (char *) memcpy (result, s, len); +} diff --git a/src/AST.h b/src/AST.h index 1a7acf0..4ad8622 100644 --- a/src/AST.h +++ b/src/AST.h @@ -44,7 +44,6 @@ typedef struct AST_node *noderef; #include "c-lex.h" #include "AST_types.h" #include "AST_list_node.h" -#include "config.h" #include "decls.h" #include "env.h" #include "types.h" diff --git a/src/AST_utils.c b/src/AST_utils.c index dcf21be..da72488 100644 --- a/src/AST_utils.c +++ b/src/AST_utils.c @@ -229,12 +229,12 @@ expression build_identifier(region r, location loc, data_declaration id) return CAST(expression, e); } -wchar_t asm_rwmode(string s) +int asm_rwmode(string s) { - if (s->ddecl->chars_length > 0) - return s->ddecl->chars[0]; + if (s->ddecl->schars.length > 0) + return s->ddecl->schars.data[0]; else - return (wchar_t)-1; + return -1; } declaration ignore_extensions(declaration d) @@ -327,21 +327,12 @@ char *ddecl2str(region r, data_declaration ddecl) Requires: ddecl->kind == decl_magic_string */ { - const wchar_t *wstr; - char *str; - int length_as_str; + assert(ddecl->kind == decl_magic_string); - wstr = ddecl->chars; - length_as_str = wcs_mb_size(wstr); - if (length_as_str < 0) - return NULL; - - str = rstralloc(r, length_as_str); - length_as_str = wcstombs(str, wstr, length_as_str); - assert(length_as_str >= 0); - str[length_as_str] = '\0'; - - return str; + if (!type_char(type_array_of(ddecl->type))) + return NULL; /* Wide string */ + else + return cstring2str(r, ddecl->schars); } /* True if arg is name or __name__ */ diff --git a/src/AST_utils.h b/src/AST_utils.h index acd9500..0b0b7c7 100644 --- a/src/AST_utils.h +++ b/src/AST_utils.h @@ -51,10 +51,10 @@ expression build_identifier(region r, location loc, data_declaration id); cval value_of_enumerator(enumerator e); -wchar_t asm_rwmode(string s); +int asm_rwmode(string s); /* Return: The first char of asm operand mode specifier s, this indicates the r/w mode for the operand (see gcc docs) - The result is (wchar_t)-1 if s is the empty string. + The result is -1 if s is the empty string. */ declaration ignore_extensions(declaration d); diff --git a/src/Makefile.am b/src/Makefile.am index 35f78bb..c63f38c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -43,7 +43,7 @@ endif ncclibdir=$(libdir)/ncc -INCLUDES = $(regionflags) -I$(srcdir)/$(regiondir) $(extra_inc) +INCLUDES = $(regionflags) -I$(srcdir)/$(regiondir) -I$(srcdir)/../libcpp/include -I$(srcdir)/../libcpp -I$(srcdir)/../include $(extra_inc) noinst_LIBRARIES = libparser.a ncclib_PROGRAMS = nesc1 @@ -100,8 +100,6 @@ libparser_a_SOURCES = \ graph.h \ init.c \ init.h \ - input.c \ - input.h \ lex.nd.c \ machine.c \ machine.h \ @@ -183,7 +181,12 @@ libparser_a_SOURCES = \ machine/sdcc-gperf.h nesc1_SOURCES = toplev.c -nesc1_LDADD = libparser.a $(libregions) -lm +nesc1_LDADD = libparser.a \ + $(libregions) \ + ../libcpp/libcpp.a \ + ../libiberty/libiberty.a \ + -lm \ + -liconv BUILT_SOURCES = \ AST_defs.h \ diff --git a/src/c-lex-state.h b/src/c-lex-state.h index 201c888..94315de 100644 --- a/src/c-lex-state.h +++ b/src/c-lex-state.h @@ -3,13 +3,17 @@ #include "c-parse.h" +struct file_stack +{ + struct file_stack *next; + struct location l; +}; + struct lex_state { - FILE *finput; - bool end_of_file; - bool token_buffer_valid; /* TRUE when token_buffer is from this file. */ - int indent_level; /* Number of { minus number of }. */ - int nextchar; /* Buffered-back input character; faster than using ungetc. */ + struct cpp_reader *finput; + struct line_maps *line_map; + struct file_stack *input; int token_s1, token_s2; struct yystype token_l1, token_l2; }; diff --git a/src/c-lex.c b/src/c-lex.c index d67dfda..b0c3d1a 100644 --- a/src/c-lex.c +++ b/src/c-lex.c @@ -28,35 +28,29 @@ Boston, MA 02111-1307, USA. */ #include "c-lex-int.h" #include "c-parse.h" #include "c-parse.tab.h" -#include "input.h" #include "semantics.h" #include "constants.h" #include "nesc-cpp.h" #include "machine.h" -#include +/* libcpp */ +#include "system.h" +#include "config.h" +#include "cpplib.h" +#include "line-map.h" +#undef bool +#define TRUE 1 +#define FALSE 0 -/* Define to support nested comments. Probably a bad idea given we're - pre-processing w/ gcc which doesn't know about nested comments */ -#undef NESTED_COMMENTS +static char_array doc_string; +static location doc_location; -/* MULTIBYTE_CHARS support only works for native compilers. - ??? Ideally what we want is to model widechar support after - the current floating point support. */ -#ifdef CROSS_COMPILE -#undef MULTIBYTE_CHARS -#endif +DECLARE_ARRAY(string_array, cpp_string) +DEFINE_ARRAY(string_array, cpp_string) +static string_array string_sequence; -#ifdef MULTIBYTE_CHARS -#include "mbchar.h" -#include -#include -#endif - -static int max_char_length = 1; /* Default value if not MULTIBYTE_CHARS */ - -/* Location of last token. Used for location of error nodes */ -location last_location; +/* Last token read. Used in syntax error reports. */ +static const cpp_token *last_token; location dummy_location, toplevel_location; @@ -88,58 +82,17 @@ location new_location(const char *filename, int lineno) return l; } -static size_t int_type_size; - -/* Cause the `yydebug' variable to be defined. */ -#define YYDEBUG 1 - -void lex_ungetc(int c) +static location last_location(void) { - ungetc (c, input_file_stack->lex.finput); + return make_location(current.lex.input->l); } -int lex_getc(void) -{ - /* Nuke CR from CR-LF */ - int c = getc (input_file_stack->lex.finput); - - if (c != '\r') - return c; - - c = getc (input_file_stack->lex.finput); - if (c == '\n') - return c; - - lex_ungetc(c); - - return '\r'; -} - -/* the declaration found for the last IDENTIFIER token read in. - yylex must look this up to detect typedefs, which get token type TYPENAME, - so it is left around in case the identifier is not a typedef but is - used in a context which makes it a reference to a variable. */ -/*tree lastiddecl;*/ - -extern int yydebug; - -static int maxtoken; /* Current nominal length of token buffer. */ -static char *traditional token_buffer; /* Pointer to token buffer. - Actual allocated length is maxtoken + 2. */ - -static wchar_array string_array; -static char_array docstring_array; - -static char *extend_token_buffer(char *); -static int check_newline(void); - /* Do not insert generated code into the source, instead, include it. This allows us to build gcc automatically even for targets that need to add or modify the reserved keyword lists. */ #include "c-gperf.h" -void -init_lex (void) +void init_lex(void) { static struct location dummy, toplevel; @@ -153,20 +106,8 @@ init_lex (void) toplevel.in_system_header = FALSE; toplevel_location = &toplevel; -#ifdef MULTIBYTE_CHARS - /* Change to the native locale for multibyte conversions. */ - setlocale (LC_CTYPE, ""); - literal_codeset = getenv ("LANG"); - max_char_length = local_mb_cur_max (); -#endif - - maxtoken = 40; - token_buffer = (char *) xmalloc (maxtoken + 2); - - string_array = new_wchar_array(parse_region, 512); - docstring_array = new_char_array(parse_region, 2048); - - int_type_size = type_size_int(int_type); + string_sequence = new_string_array(parse_region, 16); + doc_string = new_char_array(parse_region, 2048); /* Some options inhibit certain reserved words. Clear those words out of the hash table so they won't be recognized. */ @@ -184,6 +125,7 @@ init_lex (void) UNSET_RESERVED_WORD ("iterator"); UNSET_RESERVED_WORD ("complex"); } + if (flag_no_asm) { UNSET_RESERVED_WORD ("asm"); @@ -192,1801 +134,433 @@ init_lex (void) UNSET_RESERVED_WORD ("iterator"); UNSET_RESERVED_WORD ("complex"); } - } -void -start_lex (source_language l) +bool start_lex(source_language l, const char *path) { - input_file_stack->lex.end_of_file = 0; - input_file_stack->lex.nextchar = -1; - input_file_stack->lex.indent_level = 0; - input_file_stack->lex.token_s1 = input_file_stack->lex.token_s2 = -1; - - lex_ungetc(check_newline()); + cpp_options *cpp_opts; switch (l) { - case l_interface: case l_component: input_file_stack->lex.token_s1 = DISPATCH_NESC; break; - case l_c: input_file_stack->lex.token_s1 = DISPATCH_C; break; - default: assert(0); break; - } -} - -#ifdef RC_ADJUST -static size_t rc_adjust_yystype(void *x, int by) -{ - struct yystype *p = x; - RC_ADJUST_PREAMBLE; - - RC_ADJUST(p->u.ptr, by); - RC_ADJUST(p->idtoken.location.filename, by); - RC_ADJUST(p->idtoken.id.data, by); - RC_ADJUST(p->idtoken.decl, by); - - return sizeof *p; -} -#endif - -/* Function used when yydebug is set, to print a token in more detail. */ - -void -yyprint (file, yychar, yylval) - FILE *file; - int yychar; - YYSTYPE yylval; -{ - switch (yychar) - { - case IDENTIFIER: - fprintf(file, " '%s'", yylval.idtoken.id.data); + case l_interface: case l_component: + current.lex.token_s1 = DISPATCH_NESC; + break; + case l_c: + current.lex.token_s1 = DISPATCH_C; + break; + default: + assert(0); break; } -} - -/* flag to allow skipping of initial whitespace & * character */ -bool doc_skip_prefix; -unsigned long prev_cpp_docstring_line = ULONG_MAX; -struct location doc_location; -bool in_cpp_docstring = FALSE; - -/* initialize an accumulating documentation string */ -static void init_c_docstring() -{ - if(warn_unexpected_docstring && char_array_length(docstring_array) != 0) - warning("discarding unexpected docstring from %s:%ld.", doc_location.filename, doc_location.lineno); + current.lex.token_s2 = -1; - char_array_reset(docstring_array); - doc_skip_prefix = FALSE; - doc_location = input_file_stack->l; - in_cpp_docstring = FALSE; -} + current.lex.line_map = ralloc(current.fileregion, struct line_maps); + linemap_init(current.lex.line_map); + current.lex.finput = cpp_create_reader(CLK_GNUC89, NULL, current.lex.line_map); + cpp_opts = cpp_get_options(current.lex.finput); + cpp_opts->discard_comments = 0; + cpp_opts->dollars_in_ident = 0; + cpp_opts->wchar_precision = CHAR_BIT * target->wchar_t_size; + cpp_opts->int_precision = CHAR_BIT * target->tint.size; + cpp_opts->precision = CHAR_BIT * target->tlong.size; + cpp_opts->unsigned_char = !target->char_signed; + cpp_opts->unsigned_wchar = !target->wchar_t_signed; + cpp_opts->cplusplus_comments = 1; + //cpp_opts->extended_numbers = ?; + cpp_opts->bytes_big_endian = target->big_endian; -/* set up for a CPP style documentation string. This allows for - multiple comment lines to be strung together into a single comment */ -static void init_cpp_docstring() -{ - // FIXME - //fprintf(stderr, "init_cpp_docstring() %s:%ld\n", input_file_stack->l.filename, input_file_stack->l.lineno); - - if(!in_cpp_docstring || - prev_cpp_docstring_line + 1 != input_file_stack->l.lineno) { - if(warn_unexpected_docstring && char_array_length(docstring_array) != 0) - warning("discarding unexpected docstring from %s:%ld.", doc_location.filename, doc_location.lineno); - - char_array_reset(docstring_array); - } - prev_cpp_docstring_line = input_file_stack->l.lineno; - doc_skip_prefix = FALSE; - doc_location = input_file_stack->l; - in_cpp_docstring = TRUE; + return cpp_read_main_file(current.lex.finput, path) != NULL; } - -/* add chars to the a documentation comment string */ -static void add_to_docstring(int c) +void end_lex(void) { - /* skip the initial " *" stuff after a newline */ - if(doc_skip_prefix) { - if( c == ' ' || c == '\t' || c == '\r') - return; - doc_skip_prefix = FALSE; - if( c == '*' ) /* skip the first * char */ - return; - } - if(c == '\n') - doc_skip_prefix = TRUE; - - /* make sure there is space, and then copy the new char */ - { - char *p = char_array_extend(docstring_array, 1); - *p = c; - } + errorcount += cpp_finish(current.lex.finput, NULL); } -/* copy out the current docstring, if any */ -void get_latest_docstring(char **short_s, char **long_s, struct location **loc) +static cpp_reader *current_reader(void) { - char *str; - - str = get_docstring(); - separate_short_docstring(str, short_s, long_s); - - *loc = ralloc(parse_region, struct location); - **loc = doc_location; + return current.lex.finput; } -void separate_short_docstring(char *str, char **short_s, char **long_s) +static cstring make_token_cstring(const cpp_token *token) { - char *dot, *at; - assert(short_s != NULL); - assert(long_s != NULL); - - if(str == NULL) { - *short_s = NULL; - *long_s = NULL; - return; - } - - /* find the first period, followed by whitespace, or the first '@', preceded by whitespace */ - dot = str; - do { - dot = strchr(dot,'.'); - if(dot == NULL) break; - dot++; - } while(*dot != '\0' && *dot != ' ' && *dot != '\t' && *dot != '\r' && *dot != '\n'); - - at = str-2; - do { - at = strchr(at+2,'@'); - if(at == NULL) break; - at--; - if(at < str) at++; - } while(*at != ' ' && *at != '\t' && *at != '\r' && *at != '\n'); - - if (at && (!dot || at < dot)) - dot = at; - - - /* check for the beginning of the next sentance */ - if(dot != NULL) { - dot += strspn(dot, " \t\n\r."); - if( *dot == '\0' ) - dot = NULL; - } - - /* short description only */ - if(dot == NULL) { - *short_s = str; - *long_s = NULL; - } - - /* both short and long descriptions */ - else { - *(dot - 1)= '\0'; - *short_s = rstrdup(parse_region, str); - *(dot - 1)= ' '; - *long_s = str; - } -} + unsigned int len = cpp_token_len(token) + 1; + cstring tokcs = alloc_cstring(parse_region, len); + unsigned char *end; -/** - * Return the latest docstring, as a string - **/ -char *get_docstring() { - size_t length = char_array_length(docstring_array); - char *str; + end = cpp_spell_token(current_reader(), token, + (unsigned char *)tokcs.data, FALSE); + end[0] = '\0'; - /* no doc string available */ - if( length <= 0 ) - return NULL; - - - /* copy out the text, and reset docstring_array */ - str = rarrayalloc(parse_region, length + 1, char); - memcpy(str, char_array_data(docstring_array), length * sizeof(char)); - str[length] = '\0'; - prev_cpp_docstring_line = ULONG_MAX; - char_array_reset(docstring_array); - in_cpp_docstring = FALSE; - - return str; + return tokcs; } - - -/* Skip / *-style comment. */ -void skip_c_comment(void) +static void handle_comment(const cpp_token *token) { - int last_c = 0, c, depth = 1; - struct location start = input_file_stack->l; - bool docstring = FALSE; - - /* if the first char is '*', then this is a code documentation comment */ - c = lex_getc(); - if(c == '*') - { - /* handle empty comments */ - char c1 = lex_getc(); - if(c1 == '/') return; - else lex_ungetc(c1); - - docstring = TRUE; - init_c_docstring(); - } - else - { - lex_ungetc(c); - } - - - for (;;) + const cpp_string *comment = &token->val.str; + bool new_docstring = FALSE; + + if (!strncmp((char *)comment->text, "/**", 3)) + new_docstring = TRUE; + else if (!strncmp((char *)comment->text, "///", 3)) { - c = lex_getc(); - - switch (c) - { - case EOF: - error_with_location(&start, "unterminated comment"); - return; - case '\n': - input_file_stack->l.lineno++; - break; - case '/': - if (last_c == '*') - { - if (--depth == 0) - return; - } - break; - case '*': -#ifdef NESTED_COMMENTS - if (last_c == '/') - ++depth; -#endif - break; - } - - /* add to the docstring, skipping the final "* /" sequence */ - if( docstring ) { - if( last_c == '*' ) /* add any '*' that we skipped */ - add_to_docstring('*'); - - if( c != '*' ) /* skip '/', in case its the beginning of the end... */ - add_to_docstring(c); - } - - last_c = c; + if (doc_location && last_location()->filename == doc_location->filename && + last_location()->lineno + 1 == doc_location->lineno) + memcpy(char_array_extend(doc_string, comment->len), comment->text, + comment->len); + else + new_docstring = TRUE; } -} - - - -void skip_cpp_comment(void) -{ - int c; - bool docstring = FALSE; - - /* if the first char is '/', then this is a code documentation comment */ - c = lex_getc(); - if(c == '/') { - docstring = TRUE; - init_cpp_docstring(); - } else { - lex_ungetc(c); - } - - for (;;) + if (new_docstring) { - c = lex_getc(); + if (warn_unexpected_docstring && char_array_length(doc_string)) + warning_with_location(doc_location, "discarding unexpected docstring"); - switch (c) - { - case EOF: - return; - case '\n': - lex_ungetc(check_newline()); - return; - } - - if(docstring) - add_to_docstring( c ); + char_array_reset(doc_string); + memcpy(char_array_extend(doc_string, comment->len), comment->text, + comment->len); + doc_location = last_location(); } } -/* If C is not whitespace, return C. - Otherwise skip whitespace and return first nonwhite char read. */ - -static int -skip_white_space (c) - int c; -{ - static int newline_warning = 0; - int c1; - - for (;;) - { - switch (c) - { - case '/': - /* check for comments */ - c1 = lex_getc(); - - if (c1 == '/') - skip_cpp_comment(); - else if (c1 == '*') - skip_c_comment(); - else - { - lex_ungetc(c1); - return c; - } - c = lex_getc(); - break; - - case '\n': - c = check_newline (); - break; - - case ' ': - case '\t': - case '\f': - case '\v': - case '\b': - c = lex_getc(); - break; - - case '\r': - /* ANSI C says the effects of a carriage return in a source file - are undefined. */ - if (pedantic && !newline_warning) - { - warning ("carriage return in source file"); - warning ("(we only warn about the first carriage return)"); - newline_warning = 1; - } - c = lex_getc(); - break; - - case '\\': - c = lex_getc(); - if (c == '\n') - input_file_stack->l.lineno++; - else - error ("stray '\\' in program"); - c = lex_getc(); - break; - - default: - return (c); - } - } -} - -/* Make the token buffer longer, preserving the data in it. - P should point to just beyond the last valid character in the old buffer. - The value we return is a pointer to the new buffer - at a place corresponding to P. */ - -static char * -extend_token_buffer (p) - char *p; -{ - int offset = p - token_buffer; - - maxtoken = maxtoken * 2 + 10; - token_buffer = (char *) xrealloc (token_buffer, maxtoken + 2); - - return token_buffer + offset; -} - -static char *traditional token_ptr; -#define token_ungetc(c) (token_ptr--, lex_ungetc((c))) - -static int token_getc(void) -{ - int c = lex_getc(); - - if (c != EOF) - { - if (token_ptr == token_buffer + maxtoken) - token_ptr = extend_token_buffer(token_ptr); - *token_ptr++ = c; - } - return c; -} - -static cstring make_token_cstring(void) +void get_latest_docstring(char **short_s, char **long_s, struct location **loc) { - return make_cstring(parse_region, token_buffer, token_ptr - token_buffer); + *short_s = *long_s = NULL; + *loc = NULL; } - -#define GET_DIRECTIVE_LINE() get_directive_line (input_file_stack->lex.finput) +/* Convert a series of STRING and/or WSTRING tokens into a string, + performing string constant concatenation. TOK is the first of + these. VALP is the location to write the string into. + + This is unfortunately more work than it should be. If any of the + strings in the series has an L prefix, the result is a wide string + (6.4.5p4). Whether or not the result is a wide string affects the + meaning of octal and hexadecimal escapes (6.4.4.4p6,9). But escape + sequences do not continue across the boundary between two strings in + a series (6.4.5p7), so we must not lose the boundaries. Therefore + cpp_interpret_string takes a vector of cpp_string structures, which + we must arrange to provide. */ + +static void lex_string(const cpp_token *tok, struct yystype *lvalp) +{ + bool wide = FALSE; + location first_loc = last_location(); + cpp_string istr; + cstring cstr; + string_cst string_components = NULL, *next_sc = &string_components; + + /* Collect all consecutive string tokens */ + string_array_reset(string_sequence); + do + { + string_cst one_string = + new_string_cst(parse_region, last_location(), make_token_cstring(tok)); -/* Read the rest of a #-directive from input stream FINPUT. - In normal use, the directive name and the white space after it - have already been read, so they won't be included in the result. - We allow for the fact that the directive line may contain - a newline embedded within a character or string literal which forms - a part of the directive. + *next_sc = one_string; + next_sc = CASTPTR(string_cst, &one_string->next); - The value is a string in a reusable buffer. It remains valid - only until the next time this function is called. + *string_array_extend(string_sequence, 1) = tok->val.str; - The terminating character ('\n' or EOF) is left in FINPUT for the - caller to re-read. */ + if (tok->type == CPP_WSTRING) + wide = true; -char * -get_directive_line (finput) - FILE *finput; -{ - static char *directive_buffer = NULL; - static unsigned buffer_length = 0; - char *p; - char *buffer_limit; - int looking_for = 0; - int char_escaped = 0; - - if (buffer_length == 0) - { - directive_buffer = (char *)xmalloc (128); - buffer_length = 128; + do + tok = cpp_get_token(current_reader()); + while (tok->type == CPP_PADDING); } + while (tok->type == CPP_STRING || tok->type == CPP_WSTRING); - buffer_limit = &directive_buffer[buffer_length]; + /* We have read one more token than we want. */ + _cpp_backup_tokens(current_reader(), 1); - for (p = directive_buffer; ; ) + if (cpp_interpret_string(current_reader(), + string_array_data(string_sequence), + string_array_length(string_sequence), + &istr, wide)) { - int c; - - /* Make buffer bigger if it is full. */ - if (p >= buffer_limit) - { - unsigned bytes_used = (p - directive_buffer); - - buffer_length *= 2; - directive_buffer - = (char *)xrealloc (directive_buffer, buffer_length); - p = &directive_buffer[bytes_used]; - buffer_limit = &directive_buffer[buffer_length]; - } - - c = getc (finput); - - /* Discard initial whitespace. */ - if ((c == ' ' || c == '\t') && p == directive_buffer) - continue; - - /* Detect the end of the directive. */ - if (looking_for == 0 - && (c == '\n' || c == EOF)) - { - ungetc (c, finput); - c = '\0'; - } - - *p++ = c; - - if (c == 0) - return directive_buffer; - - /* Handle string and character constant syntax. */ - if (looking_for) - { - if (looking_for == c && !char_escaped) - looking_for = 0; /* Found terminator... stop looking. */ - } - else - if (c == '\'' || c == '"') - looking_for = c; /* Don't stop buffering until we see another - another one of these (or an EOF). */ - - /* Handle backslash. */ - char_escaped = (c == '\\' && ! char_escaped); + cstr = make_cstring(parse_region, (char *)istr.text, istr.len); + free((char *)istr.text); } -} - -static char *parse_string_token(string_cst c) -{ - char *s = string_cst_to_c(parse_region, c); - - /* If we can't decode the string, we punt and use its lexical rep (minus - the intrudoctory L", and final " -- we can only fail for wide strings) */ - if (!s) + else { - s = rstralloc(parse_region, c->cstring.length - 2); - s[c->cstring.length - 3] = '\0'; - memcpy(s, c->cstring.data + 2, c->cstring.length - 3); + /* Use empty string as the value in case of error. Assumes the + widest supported wchar_t is 32 bits */ + cstr = make_cstring(parse_region, "\0\0\0", + wide ? type_size_int(wchar_type) : 1); } - return s; + lvalp->u.string = fold_lexical_string(first_loc, string_components, cstr, wide); } -static bool token_isint(int token, struct yystype *lvalp) +static void lex_charconst(const cpp_token *token, struct yystype *lvalp) { - return token == CONSTANT && type_integral(lvalp->u.constant->type); -} + cppchar_t result; + unsigned int chars_seen; + int unsignedp; -static int token_intvalue(struct yystype *lvalp) -{ - return constant_sint_value(lvalp->u.constant->cst); + result = cpp_interpret_charconst(current_reader(), token, + &chars_seen, &unsignedp); + lvalp->u.constant = fold_lexical_char(last_location(), make_token_cstring(token), + token->type == CPP_WCHAR, result); } -/* Save the rest of the line in the directives list. Return '\n' */ -int save_directive(char *directive) +/* Interpret TOKEN, an integer with FLAGS as classified by cpplib. */ +static lexical_cst interpret_integer(const cpp_token *token, unsigned int flags) { - static char *directive_buffer = NULL; - static unsigned buffer_length = 0; - char *p; - char *buffer_limit; - int looking_for = 0; - int char_escaped = 0; - int ret, c; - - if (buffer_length == 0) - { - directive_buffer = (char *)xmalloc (128); - buffer_length = 128; - } - - buffer_limit = &directive_buffer[buffer_length]; - - /* Discard initial whitespace. */ - do - c = lex_getc(); - while (c == ' ' || c == '\t'); - - for (p = directive_buffer; ; ) - { - /* Make buffer bigger if it is full. */ - if (p >= buffer_limit) - { - unsigned bytes_used = (p - directive_buffer); - - buffer_length *= 2; - directive_buffer - = (char *)xrealloc (directive_buffer, buffer_length); - p = &directive_buffer[bytes_used]; - buffer_limit = &directive_buffer[buffer_length]; - } - - /* Detect the end of the directive. */ - if (c == EOF) - { - ret = ' '; - break; - } + type t; + cpp_num integer; + cpp_options *options = cpp_get_options(current_reader()); - if (looking_for == 0 && c == '\n' && !char_escaped) - { - ret = c; - break; - } - - if (c == '\n') - input_file_stack->l.lineno++; - - *p++ = c; - - if (c == '/') - { - int c2 = lex_getc(); - - if (c2 == '/') - { - --p; - skip_cpp_comment(); - } - else if (c2 == '*') - { - --p; - skip_c_comment(); - } - else - lex_ungetc(c2); - } - - /* Handle string and character constant syntax. */ - if (looking_for) - { - if (looking_for == c && !char_escaped) - looking_for = 0; /* Found terminator... stop looking. */ - } - else - if (c == '\'' || c == '"') - looking_for = c; /* Don't stop buffering until we see another - another one of these (or an EOF). */ - - /* Handle backslash. */ - char_escaped = (c == '\\' && ! char_escaped); - - c = lex_getc(); - } - - *p = '\0'; - handle_directive(directive, directive_buffer); - - return ret; -} - -/* At the beginning of a line, increment the line number - and process any #-directive on this line. - If the line is a #-directive, read the entire line and return a newline. - Otherwise, return the line's first non-whitespace character. */ - -static int -check_newline () -{ - int c; - int token; - struct yystype lval; - - input_file_stack->l.lineno++; - - /* Read first nonwhite char on the line. */ - - c = lex_getc(); - while (c == ' ' || c == '\t') - c = lex_getc(); - - if (c != '#') - { - /* If not #, return it so caller will use it. */ - return c; - } - - /* Read first nonwhite char after the `#'. */ - - c = lex_getc(); - while (c == ' ' || c == '\t') - c = lex_getc(); - - /* If a letter follows, then if the word here is `line', skip - it and ignore it; otherwise, ignore the line, with an error - if the word isn't `pragma', `ident', `define', or `undef'. */ - - if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) - { - if (c == 'p') - { - if (lex_getc() == 'r' - && lex_getc() == 'a' - && lex_getc() == 'g' - && lex_getc() == 'm' - && lex_getc() == 'a' - && ((c = lex_getc()) == ' ' || c == '\t' || c == '\n')) - { - return save_directive("pragma"); - } - } - - else if (c == 'd') - { - if (lex_getc() == 'e' - && lex_getc() == 'f' - && lex_getc() == 'i' - && lex_getc() == 'n' - && lex_getc() == 'e' - && ((c = lex_getc()) == ' ' || c == '\t' || c == '\n')) - { - return save_directive("define"); - } - } - else if (c == 'u') - { - if (lex_getc() == 'n' - && lex_getc() == 'd' - && lex_getc() == 'e' - && lex_getc() == 'f' - && ((c = lex_getc()) == ' ' || c == '\t' || c == '\n')) - { - return save_directive("undef"); - } - } - else if (c == 'l') - { - if (lex_getc() == 'i' - && lex_getc() == 'n' - && lex_getc() == 'e' - && ((c = lex_getc()) == ' ' || c == '\t')) - goto linenum; - } - else if (c == 'i') - { - if (lex_getc() == 'd' - && lex_getc() == 'e' - && lex_getc() == 'n' - && lex_getc() == 't' - && ((c = lex_getc()) == ' ' || c == '\t')) - { - /* #ident. The pedantic warning is now in cccp.c. */ - - /* Here we have just seen `#ident '. - A string constant should follow. */ - - while (c == ' ' || c == '\t') - c = lex_getc(); - - /* If no argument, ignore the line. */ - if (c == '\n') - return c; - - lex_ungetc (c); - token = yylex (&lval); - if (token != STRING) - { - error ("invalid #ident"); - goto skipline; - } - - /* Skip the rest of this line. */ - goto skipline; - } - } + integer = cpp_interpret_integer(current_reader(), token, flags); + integer = cpp_num_sign_extend(integer, options->precision); - error ("undefined or invalid # directive"); - goto skipline; - } - -linenum: - /* Here we have either `#line' or `# '. - In either case, it should be a line number; a digit should follow. */ - - while (c == ' ' || c == '\t') - c = lex_getc(); - - /* If the # is the only nonwhite char on the line, - just ignore it. Check the new newline. */ - if (c == '\n') - return c; - - /* Something follows the #; read a token. */ - - lex_ungetc (c); - token = yylex (&lval); - - if (token_isint(token, &lval)) - { - const char *new_filename; - int used_up = 0; - /* subtract one, because it is the following line that - gets the specified number */ - int l = token_intvalue(&lval) - 1; - - /* Is this the last nonwhite stuff on the line? */ - c = lex_getc(); - while (c == ' ' || c == '\t') - c = lex_getc(); - if (c == '\n') - { - /* No more: store the line number and check following line. */ - input_file_stack->l.lineno = l; - return c; - } - lex_ungetc (c); - - /* More follows: it must be a string constant (filename). */ - - /* Read the string constant. */ - token = yylex (&lval); - - if (token != STRING) - { - error ("invalid #line"); - goto skipline; - } - - new_filename = parse_string_token(CAST(string_cst, lval.u.constant)); - /* Each change of file name - reinitializes whether we are now in a system header. */ - input_file_stack->l.in_system_header = 0; - - /* Is this the last nonwhite stuff on the line? */ - c = lex_getc(); - while (c == ' ' || c == '\t') - c = lex_getc(); - if (c == '\n') - { - input_file_stack->l.filename = new_filename; - input_file_stack->l.lineno = l; - return c; - } - - lex_ungetc (c); - - token = yylex (&lval); - used_up = 0; - - /* `1' after file name means entering new file. - `2' after file name means just left a file. */ - - if (token_isint(token, &lval)) - { - int cst = token_intvalue(&lval); - - if (cst == 1) - { - push_input(); - used_up = 1; - } - else if (cst == 2) - { - /* Popping out of a file. */ - if (input_file_stack->next && - input_file_stack->lex.finput == input_file_stack->next->lex.finput) - { - int current_il = input_file_stack->lex.indent_level; - int previous_il = input_file_stack->next->lex.indent_level; - if (current_il != previous_il) - { - warning_with_location - (&input_file_stack->l, - "This file contains more `%c's than `%c's.", - current_il > previous_il ? '{' : '}', - current_il > previous_il ? '}' : '{'); - } - pop_input(); - } - else - error ("#-lines for entering and leaving files don't match"); - - used_up = 1; - } - } - - input_file_stack->l.filename = new_filename; - input_file_stack->l.lineno = l; + if (flags & CPP_N_UNSIGNED) + if ((flags & CPP_N_WIDTH) == CPP_N_SMALL) + t = unsigned_int_type; + else if ((flags & CPP_N_WIDTH) == CPP_N_MEDIUM) + t = unsigned_long_type; + else + t = unsigned_long_long_type; + else + if ((flags & CPP_N_WIDTH) == CPP_N_SMALL) + t = int_type; + else if ((flags & CPP_N_WIDTH) == CPP_N_MEDIUM) + t = long_type; + else + t = long_long_type; + + /* We're assuming that the our largest int type is the same as cpp's + HOST_WIDE_INT, and then ignoring the high field as we only handle + values that fit in largest_uint anyway */ + assert(sizeof(HOST_WIDE_INT) == sizeof(largest_uint)); + return fold_lexical_int(t, last_location(), make_token_cstring(token), + (flags & CPP_N_IMAGINARY) != 0, + integer.low, + integer.overflow); +} + +/* Interpret TOKEN, a floating point number with FLAGS as classified + by cpplib. This is a very hacky, partial implementation. */ +static lexical_cst interpret_float(const cpp_token *token, unsigned int flags) +{ + type t; + + /* Give up on _Fract and _Accum. */ + if (flags & CPP_N_FRACT || flags & CPP_N_ACCUM) + return NULL; + /* Give up on decimal and machine dependent values */ + if (flags & CPP_N_DFLOAT || flags & CPP_N_WIDTH_MD) + return NULL; - /* `3' after file name or 1, 2 means this is a system header file. */ + /* Decode type based on width and properties. */ + if ((flags & CPP_N_WIDTH) == CPP_N_LARGE) + t = long_double_type; + else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL/* || flag_single_precision_constant*/) + t = float_type; + else + t = double_type; - if (token_isint(token, &lval) && token_intvalue(&lval) == 3) - input_file_stack->l.in_system_header = 1; + if (flags & CPP_N_IMAGINARY) + t = make_complex_type(t); - /* We just ignore the rest of the line. - (we could complain about extra stuff, but, e.g., gcc 3.2 adds an - extra flag after 3 (if 4 means "needs to be extern "C" protected - - I'm ignoring this as it shouldn't be relevant to C stuff)) */ - } - else - error ("invalid #-line"); - - /* skip the rest of this line. */ - skipline: - if (c != '\n' && c != EOF && input_file_stack->lex.nextchar >= 0) - c = input_file_stack->lex.nextchar, input_file_stack->lex.nextchar = -1; - while (c != '\n' && c != EOF) - c = lex_getc(); - return c; + return fold_lexical_real(t, last_location(), make_token_cstring(token)); } - -#define ENDFILE -1 /* token that represents end-of-file */ - -/* Read an escape sequence, saving it in the token_buffer. - Return the escape sequence's value. - store 1 in *ignore_ptr if escape sequence is backslash-newline. */ -static int -readescape (int *ignore_ptr) +static int interpret_name(const cpp_token *token, struct yystype *lvalp) { - int c = token_getc(); - int code; - unsigned count; - unsigned firstdig = 0; - int nonnull; + ht_identifier *id = HT_NODE(token->val.node); + struct resword *ptr; + data_declaration decl; + int kind = IDENTIFIER; - switch (c) + /* Try to recognize a keyword. Uses minimum-perfect hash function */ + if ((ptr = is_reserved_word(id->str, id->len))) { - case 'x': - if (warn_traditional) - warning ("the meaning of `\\x' varies with -traditional"); + lvalp->u.itoken.i = ptr->rid; - if (flag_traditional) - return c; - - code = 0; - count = 0; - nonnull = 0; - while (1) - { - c = token_getc(); - if (!(c >= 'a' && c <= 'f') - && !(c >= 'A' && c <= 'F') - && !(c >= '0' && c <= '9')) - { - token_ungetc (c); - break; - } + /* Even if we decided to recognize asm, still perhaps warn. */ + if (pedantic && + (ptr->token == ASM_KEYWORD || ptr->token == TYPEOF || + ptr->rid == RID_INLINE) && + id->str[0] != '_') + pedwarn ("ANSI does not permit the keyword `%s'", id->str); - code *= 16; - if (c >= 'a' && c <= 'f') - code += c - 'a' + 10; - if (c >= 'A' && c <= 'F') - code += c - 'A' + 10; - if (c >= '0' && c <= '9') - code += c - '0'; - if (code != 0 || count != 0) - { - if (count == 0) - firstdig = code; - count++; - } - nonnull = 1; - } - if (! nonnull) - error ("\\x used with no following hex digits"); - else if (count == 0) - /* Digits are all 0's. Ok. */ - ; - else if (count - 1 >= int_type_size * 2 - || (count > 1 - && ((1 << (int_type_size * 8 - (count - 1) * 4)) - <= firstdig))) - pedwarn ("hex escape out of range"); - return code; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': - code = 0; - count = 0; - while ((c <= '7') && (c >= '0') && (count++ < 3)) - { - code = (code * 8) + (c - '0'); - c = token_getc(); - } - token_ungetc (c); - return code; - - case '\\': case '\'': case '"': - return c; - - case '\n': - input_file_stack->l.lineno++; - *ignore_ptr = 1; - return 0; - - /* SAME */ - case 'n': return '\n'; - case 't': return '\t'; - case 'r': return '\r'; - case 'f': return '\f'; - case 'b': return '\b'; - case '?': return '\?'; - - case 'a': - if (warn_traditional) - warning ("the meaning of `\\a' varies with -traditional"); - if (flag_traditional) - return c; - return '\a'; /* SAME */ - - case 'v': -#if 0 /* Vertical tab is present in common usage compilers. */ - if (flag_traditional) - return c; -#endif - return '\v'; /* SAME */ - - case 'e': - case 'E': - if (pedantic) - pedwarn ("non-ANSI-standard escape sequence, `\\%c'", c); - return 033; - - /* `\(', etc, are used at beginning of line to avoid confusing Emacs. */ - case '(': - case '{': - case '[': - /* `\%' is used to prevent SCCS from getting confused. */ - case '%': - if (pedantic) - pedwarn ("non-ANSI escape sequence `\\%c'", c); - return c; - - default: - if (c >= 040 && c < 0177) - pedwarn ("unknown escape sequence `\\%c'", c); - else - pedwarn ("unknown escape sequence: `\\' followed by char code 0x%x", c); - return c; + return ptr->token; } -} - -static int read_char(char *context, char terminating_char, - unsigned char *cp, wchar_t *wcp) -{ - unsigned width = wcp ? type_size_int(wchar_type) * BITSPERBYTE - : BITSPERBYTE; /* sizeof(char) == 1 */ - int c; -#ifdef MULTIBYTE_CHARS - (void) local_mbtowc (NULL_PTR, NULL_PTR, 0); -#endif - - tryagain: - c = token_getc (); - if (c == terminating_char) - return 0; + /* If we did not find a keyword, look for a typename */ + if (target->token) + kind = target->token((char *)id->str, id->len, lvalp); - if (c < 0) - return -1; - - if (c == '\\') - { - int ignore = 0; - c = readescape (&ignore); - if (ignore) - goto tryagain; - - if (width < sizeof(unsigned) * BITSPERBYTE - && (unsigned) c >= ((unsigned)1 << width)) - pedwarn ("escape sequence out of range for character"); - } - else if (c == '\n') - { - if (pedantic) - pedwarn ("ANSI C forbids newline in %s constant", context); - input_file_stack->l.lineno++; - } - else + if (kind == IDENTIFIER) { -#ifdef MULTIBYTE_CHARS - wchar_t wc; - int i; - int char_len = -1; - for (i = 0; i < max_char_length; ++i) - { - cp[i] = c; + lvalp->idtoken.location = last_location(); + lvalp->idtoken.id = make_token_cstring(token); + decl = lookup_id(lvalp->idtoken.id.data, FALSE); + lvalp->idtoken.decl = decl; - char_len = local_mbtowc (& wc, cp, i + 1); - if (char_len != -1) - break; - c = token_getc (); - } - if (char_len == -1) - { - warning ("Ignoring invalid multibyte character"); - /* Note: gcc just takes the character following the - invalid multibyte-char-sequence as being the next - character. This is obviously incorrect. */ - token_ungetc (c); - goto tryagain; - } - else - { - /* mbtowc sometimes needs an extra char before accepting */ - if (char_len <= i) - token_ungetc (c); - if (! wcp) - return i + 1; - else - { - *wcp = wc; - return 1; - } - } -#endif /* MULTIBYTE_CHARS */ + if (decl) + switch (decl->kind) + { + case decl_typedef: kind = TYPENAME; break; + case decl_magic_string: kind = MAGIC_STRING; break; + case decl_component_ref: kind = COMPONENTREF; break; + default: break; + } } - - if (wcp) - *wcp = c; - else - *cp = c; - - return 1; + return kind; } - -void -yyerror (char *string) +static int lex_token(struct yystype *lvalp) { - char buf[200]; - - strcpy (buf, string); + const cpp_token *tok; + enum cpp_ttype type; - /* We can't print string and character constants well - because the token_buffer contains the result of processing escapes. */ - /* XXX: This is not true anymore, but ignore that for a while */ - if (!input_file_stack->lex.token_buffer_valid) - ; - else if (input_file_stack->lex.end_of_file) - strcat (buf, " at end of input"); - else if (token_buffer[0] == 0) - strcat (buf, " at null character"); - else if (token_buffer[0] == '"') - strcat (buf, " before string constant"); - else if (token_buffer[0] == '\'') - strcat (buf, " before character constant"); - else if (token_buffer[0] < 040 || (unsigned char) token_buffer[0] >= 0177) - sprintf (buf + strlen (buf), " before character 0%o", - (unsigned char) token_buffer[0]); - else - strcat (buf, " before `%s'"); - - error (buf, token_buffer); -} - - -static int lextoken(struct yystype *lvalp) -{ - int c; - int value; - int wide_flag = 0; - - if (input_file_stack->lex.nextchar >= 0) - c = input_file_stack->lex.nextchar, input_file_stack->lex.nextchar = -1; - else - c = lex_getc(); - - /* Effectively do c = skip_white_space (c) - but do it faster in the usual cases. */ - while (1) - switch (c) - { - case ' ': - case '\t': - case '\f': - case '\v': - case '\b': - c = lex_getc(); - break; - - case '\r': - /* Call skip_white_space so we can warn if appropriate. */ - - case '\n': - case '/': - case '\\': - c = skip_white_space (c); - default: - goto found_nonwhite; - } - found_nonwhite: - - token_ptr = token_buffer; - *token_ptr++ = c; - - last_location = make_location(input_file_stack->l); - - lvalp->u.itoken.location = last_location; + retry: + last_token = tok = cpp_get_token(current_reader()); + type = tok->type; + lvalp->u.itoken.location = last_location(); lvalp->u.itoken.i = 0; - switch (c) + switch (type) { - case EOF: - input_file_stack->lex.end_of_file = 1; - token_buffer[0] = 0; - value = ENDFILE; - break; - - case 'L': - /* Capital L may start a wide-string or wide-character constant. */ - { - int c = token_getc(); - if (c == '\'') - { - wide_flag = 1; - goto char_constant; - } - if (c == '"') - { - wide_flag = 1; - goto string_constant; - } - token_ungetc (c); - } - goto letter; - - case 'A': case 'B': case 'C': case 'D': case 'E': - case 'F': case 'G': case 'H': case 'I': case 'J': - case 'K': case 'M': case 'N': case 'O': - case 'P': case 'Q': case 'R': case 'S': case 'T': - case 'U': case 'V': case 'W': case 'X': case 'Y': - case 'Z': - case 'a': case 'b': case 'c': case 'd': case 'e': - case 'f': case 'g': case 'h': case 'i': case 'j': - case 'k': case 'l': case 'm': case 'n': case 'o': - case 'p': case 'q': case 'r': case 's': case 't': - case 'u': case 'v': case 'w': case 'x': case 'y': - case 'z': - case '_': - case '$': - letter: - while (isalnum (c) || c == '_' || c == '$') - { - /* Make sure this char really belongs in an identifier. */ - if (c == '$') - { - if (! dollars_in_ident) - error ("`$' in identifier"); - else if (pedantic) - pedwarn ("`$' in identifier"); - } - - c = token_getc(); - } - - *token_ptr = 0; - token_ptr--; - input_file_stack->lex.nextchar = c; - - value = IDENTIFIER; - - /* Try to recognize a keyword. Uses minimum-perfect hash function */ - { - struct resword *ptr; + case CPP_EOF: + return -1; - *token_ptr = '\0'; - if ((ptr = is_reserved_word (token_buffer, token_ptr - token_buffer))) - { - value = (int) ptr->token; - lvalp->u.itoken.i = (int) ptr->rid; - - /* Even if we decided to recognize asm, still perhaps warn. */ - if (pedantic - && (value == ASM_KEYWORD || value == TYPEOF - || ptr->rid == RID_INLINE) - && token_buffer[0] != '_') - pedwarn ("ANSI does not permit the keyword `%s'", - token_buffer); - } - } + case CPP_PADDING: + goto retry; - /* If we did not find a keyword, look for an identifier - (or a typename). */ - if (value == IDENTIFIER) - { - data_declaration decl; - - lvalp->idtoken.location = last_location; - lvalp->idtoken.id = make_token_cstring(); - lvalp->idtoken.decl = NULL; + case CPP_COMMENT: + handle_comment(tok); + goto retry; - if (value == IDENTIFIER && target->token) - value = target->token(token_buffer, token_ptr - token_buffer, lvalp); + case CPP_NAME: + return interpret_name(tok, lvalp); - if (value == IDENTIFIER) - { - decl = lookup_id(lvalp->idtoken.id.data, FALSE); - lvalp->idtoken.decl = decl; - - if (decl) - switch (decl->kind) - { - case decl_typedef: value = TYPENAME; break; - case decl_magic_string: value = MAGIC_STRING; break; - case decl_component_ref: value = COMPONENTREF; break; - default: break; - } - } - } - - break; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - case '.': + case CPP_NUMBER: { - int base = 10; - int largest_digit = 0; - int numdigits = 0; - largest_uint cstvalue = 0, maxbase; - int overflow = 0; - - enum anon1 { NOT_FLOAT, AFTER_POINT, TOO_MANY_POINTS} floatflag - = NOT_FLOAT; + unsigned int flags = cpp_classify_number(current_reader(), tok); + lexical_cst num = NULL; - if (c == '0') + switch (flags & CPP_N_CATEGORY) { - c = token_getc(); - if ((c == 'x') || (c == 'X')) - { - base = 16; - c = token_getc(); - } - /* Leading 0 forces octal unless the 0 is the only digit. */ - else if (c >= '0' && c <= '9') - { - base = 8; - numdigits++; - } - else - numdigits++; - } - - /* Read all the digits-and-decimal-points. */ - /* Find the maximum value that can be multiplied by base without - overflowing a largest_uint, i.e., (1 << LARGEST_UINTBITS) / base */ - maxbase = (((largest_uint)1 << (LARGEST_UINTBITS - 1)) / base) << 1; - maxbase += ((((largest_uint)1 << (LARGEST_UINTBITS - 1)) % base) << 1) / base; - - while (c == '.' - || (isalnum (c) && c != 'l' && c != 'L' - && c != 'u' && c != 'U' - && c != 'i' && c != 'I' && c != 'j' && c != 'J' - && (floatflag == NOT_FLOAT || ((c != 'f') && (c != 'F'))))) - { - if (c == '.') - { - if (base == 16) - error ("floating constant may not be in radix 16"); - if (floatflag == TOO_MANY_POINTS) - /* We have already emitted an error. Don't need another. */ - ; - else if (floatflag == AFTER_POINT) - { - error ("malformed floating constant"); - floatflag = TOO_MANY_POINTS; - } - else - floatflag = AFTER_POINT; - - base = 10; - c = token_getc(); - /* Accept '.' as the start of a floating-point number - only when it is followed by a digit. - Otherwise, unread the following non-digit - and use the '.' as a structural token. */ - if (token_ptr == token_buffer + 2 && !isdigit (c)) - { - if (c == '.') - { - c = token_getc(); - if (c == '.') - { - value = ELLIPSIS; - goto done; - } - error ("parse error at `..'"); - } - token_ungetc (c); - value = '.'; - goto done; - } - } - else - { - /* It is not a decimal point. - It should be a digit (perhaps a hex digit). */ - - if (isdigit (c)) - { - c = c - '0'; - } - else if (base <= 10) - { - if (c == 'e' || c == 'E') - { - base = 10; - floatflag = AFTER_POINT; - break; /* start of exponent */ - } - error ("nondigits in number and not hexadecimal"); - c = 0; - } - else if (c >= 'a') - { - c = c - 'a' + 10; - } - else - { - c = c - 'A' + 10; - } - if (c >= largest_digit) - largest_digit = c; - numdigits++; - - /* Keep track of constants up to largest_uint's range (unsigned) */ - if (cstvalue > maxbase) - overflow = 1; - cstvalue = cstvalue * base; - if ((largest_uint)-1 - cstvalue < c) - overflow = 1; - cstvalue += c; - - c = token_getc(); - } - } - - if (numdigits == 0) - error ("numeric constant with no digits"); - - if (largest_digit >= base) - error ("numeric constant contains digits beyond the radix"); - - if (floatflag != NOT_FLOAT) - { - type ftype; - int imag = 0; - int fflag = 0, lflag = 0; - - /* Read explicit exponent if any, and put it in tokenbuf. */ - - if ((c == 'e') || (c == 'E')) - { - c = token_getc(); - if ((c == '+') || (c == '-')) - { - c = token_getc(); - } - if (! isdigit (c)) - error ("floating constant exponent has no digits"); - while (isdigit (c)) - { - c = token_getc(); - } - } - - while (1) - { - int lose = 0; - - /* Read the suffixes to choose a data type. */ - switch (c) - { - case 'f': case 'F': - if (fflag) - error ("more than one `f' in numeric constant"); - fflag = 1; - break; - - case 'l': case 'L': - if (lflag) - error ("more than one `l' in numeric constant"); - lflag = 1; - break; - - case 'i': case 'I': - if (imag) - error ("more than one `i' or `j' in numeric constant"); - else if (pedantic) - pedwarn ("ANSI C forbids imaginary numeric constants"); - imag = 1; - break; - - default: - lose = 1; - } - - if (lose) - break; - - c = token_getc(); - } - - token_ungetc(c); - - if (fflag) - { - if (lflag) - error ("both `f' and `l' in floating constant"); - - ftype = float_type; - } - else if (lflag) - ftype = long_double_type; - else - ftype = double_type; - - if (imag) - ftype = make_complex_type(ftype); - - lvalp->u.constant = fold_lexical_real(ftype, last_location, make_token_cstring()); - } - else - { - int spec_unsigned = 0; - int spec_long = 0; - int spec_long_long = 0; - int spec_imag = 0; - type itype; - - while (1) - { - if (c == 'u' || c == 'U') - { - if (spec_unsigned) - error ("two `u's in integer constant"); - spec_unsigned = 1; - } - else if (c == 'l' || c == 'L') - { - if (spec_long) - { - if (spec_long_long) - error ("three `l's in integer constant"); - else if (pedantic) - pedwarn ("ANSI C forbids long long integer constants"); - spec_long_long = 1; - } - spec_long = 1; - } - else if (c == 'i' || c == 'j' || c == 'I' || c == 'J') - { - if (spec_imag) - error ("more than one `i' or `j' in numeric constant"); - else if (pedantic) - pedwarn ("ANSI C forbids imaginary numeric constants"); - spec_imag = 1; - } - else - break; - c = token_getc(); - } - - token_ungetc (c); - - /* Collect type as specified in the lexeme. The constant folder - will expand the type if necessary. */ - if (base != 10) - spec_unsigned = 1; - - if (spec_long_long) - itype = spec_unsigned ? unsigned_long_long_type : long_long_type; - else if (spec_long) - itype = spec_unsigned ? unsigned_long_type : long_type; - else - itype = spec_unsigned ? unsigned_int_type : int_type; - - lvalp->u.constant = - fold_lexical_int(itype, last_location, make_token_cstring(), - spec_imag, cstvalue, overflow); + case CPP_N_INTEGER: + num = interpret_integer(tok, flags); + break; + case CPP_N_FLOATING: + num = interpret_float (tok, flags); + break; } - - if (isalnum (c) || c == '.' || c == '_' || c == '$' - || (!flag_traditional && (c == '-' || c == '+') - && (token_ptr[-1] == 'e' || token_ptr[-1] == 'E'))) - error ("missing white space after number `%s'", token_buffer); - - value = CONSTANT; break; + /* cpplib has issued an error or we ran into something we don't + support (e.g. fixed point), pretend the constant was 0 */ + if (num == NULL) + num = fold_lexical_int(int_type, last_location(), + make_token_cstring(tok), + FALSE, 0, FALSE); + + lvalp->u.constant = num; + return CONSTANT; } - case '\'': - char_constant: + case CPP_HASH: + case CPP_PASTE: + case CPP_SCOPE: + case CPP_DEREF_STAR: + case CPP_DOT_STAR: { - wchar_t wc; - unsigned char *cbuf = alloca(max_char_length); - int chars_seen = 0, count, result = 0; - unsigned width = wide_flag ? type_size_int(wchar_type) * BITSPERBYTE - : BITSPERBYTE; /* sizeof(char) == 1 */ - - for (;;) - { - count = read_char("character", '\'', cbuf, wide_flag ? &wc : NULL); - if (count <= 0) - break; - - chars_seen += count; - - if (wide_flag) - { - /* Note: read_char always returns 1 when wide_flag is true, - so chars_seen will always be 1 exactly once */ - assert(count == 1); - if (chars_seen == 1) - result = wc; - } - else - { - int i; - - /* Weird code if you ask me. But this is what gcc 2.95.3 does. - There's no particular consistency between compilers - on how to handle these (e.g., 'ab' gives different values - with Sun's cc and gcc). */ - for (i = 0; i < count && i < int_type_size; i++) - if (width < sizeof(unsigned) * BITSPERBYTE) - result = (result << width) | (cbuf[i] & ((1 << width) - 1)); - else - result = cbuf[i]; - } - } - - if (count < 0) - error ("malformatted character constant"); - else if (chars_seen == 0) - error ("empty character constant"); - else if (chars_seen > int_type_size) /* this is what gcc is testing */ - error ("character constant too long"); - else if (chars_seen != 1 && ! flag_traditional && warn_multichar) - warning ("multi-character character constant"); + unsigned char name[4]; - lvalp->u.constant = fold_lexical_char(last_location, make_token_cstring(), - wide_flag, result); + *cpp_spell_token(current_reader(), tok, name, true) = 0; - value = CONSTANT; - break; + error("stray %qs in program", name); } + goto retry; - case '"': - string_constant: + case CPP_OTHER: { - wchar_t wc; - unsigned char *cbuf = alloca(max_char_length); - int count; - - wchar_array_reset(string_array); - - for (;;) - { - wchar_t *p; - - count = read_char("string", '"', cbuf, wide_flag ? &wc : NULL); - if (count <= 0) - break; - - p = wchar_array_extend(string_array, count); - if (wide_flag) - { - assert(count == 1); - *p = wc; - } - else - { - int i; - - for (i = 0; i < count; i++) - *p++ = cbuf[i]; - } - } - if (count < 0) - error ("Unterminated string constant"); - - lvalp->u.string_cst = fold_lexical_string(last_location, make_token_cstring(), - wide_flag, string_array); - - value = STRING; + cppchar_t c = tok->val.str.text[0]; - break; - } - - case '+': - case '-': - case '&': - case '|': - case ':': - case '<': - case '>': - case '*': - case '/': - case '%': - case '^': - case '!': - case '=': - { - int c1; - - combine: - - c1 = token_getc(); - - if (c1 == '=') - { - value = ASSIGN; - switch (c) - { - case '<': - value = ARITHCOMPARE; lvalp->u.itoken.i = kind_leq; break; - case '>': - value = ARITHCOMPARE; lvalp->u.itoken.i = kind_geq; break; - case '!': - value = EQCOMPARE; lvalp->u.itoken.i = kind_ne; break; - case '=': - value = EQCOMPARE; lvalp->u.itoken.i = kind_eq; break; - - case '+': - lvalp->u.itoken.i = kind_plus_assign; break; - case '-': - lvalp->u.itoken.i = kind_minus_assign; break; - case '&': - lvalp->u.itoken.i = kind_bitand_assign; break; - case '|': - lvalp->u.itoken.i = kind_bitor_assign; break; - case '*': - lvalp->u.itoken.i = kind_times_assign; break; - case '/': - lvalp->u.itoken.i = kind_divide_assign; break; - case '%': - lvalp->u.itoken.i = kind_modulo_assign; break; - case '^': - lvalp->u.itoken.i = kind_bitxor_assign; break; - case LSHIFT: - lvalp->u.itoken.i = kind_lshift_assign; break; - case RSHIFT: - lvalp->u.itoken.i = kind_rshift_assign; break; - } - if (c != ':') - goto done; - } - else if (c == c1) - switch (c) - { - case '+': - value = PLUSPLUS; goto done; - case '-': - value = MINUSMINUS; goto done; - case '&': - value = ANDAND; goto done; - case '|': - value = OROR; goto done; - case '<': - c = LSHIFT; - goto combine; - case '>': - c = RSHIFT; - goto combine; - } + if (c == '"' || c == '\'') + error("missing terminating %c character", (int) c); + else if (ISGRAPH (c)) + error("stray %qc in program", (int) c); else - switch (c) - { - case '-': - if (c1 == '>') - { value = POINTSAT; goto done; } - break; - case ':': - if (c1 == '>') - { value = ']'; goto done; } - break; - case '<': - if (c1 == '%') - { value = '{'; input_file_stack->lex.indent_level++; goto done; } - if (c1 == ':') - { value = '['; goto done; } - break; - case '%': - if (c1 == '>') - { value = '}'; input_file_stack->lex.indent_level--; goto done; } - break; - } - token_ungetc (c1); - - if (c == '<') - { - c1 = token_getc(); - - if (c1 == '-') - value = TASTNIOP; - else - { - token_ungetc (c1); - value = '<'; - lvalp->u.itoken.i = kind_lt; - } - } - else if (c == '>') - { - value = '>'; - lvalp->u.itoken.i = kind_gt; - } - else - value = c; - goto done; + error("stray %<\\%o%> in program", (int) c); } + goto retry; - case 0: - /* Don't make yyparse think this is eof. */ - value = 1; - break; - - case '{': - input_file_stack->lex.indent_level++; - value = c; - break; - - case '}': - input_file_stack->lex.indent_level--; - value = c; - break; + case CPP_CHAR: + case CPP_WCHAR: + lex_charconst(tok, lvalp); + return CONSTANT; + case CPP_STRING: + case CPP_WSTRING: + lex_string(tok, lvalp); + return STRING; + + case CPP_PRAGMA: + goto retry; + + /* Translate to the parser's symbols - somewhat of a legacy effect, + but having the characters does make the parser more readable... */ + case CPP_EQ: return '='; + case CPP_NOT: return '!'; + case CPP_GREATER: return '>'; + case CPP_LESS: return '<'; + case CPP_PLUS: return '+'; + case CPP_MINUS: return '-'; + case CPP_MULT: return '*'; + case CPP_DIV: return '/'; + case CPP_MOD: return '%'; + case CPP_AND: return '&'; + case CPP_OR: return '|'; + case CPP_XOR: return '^'; + case CPP_RSHIFT: return RSHIFT; + case CPP_LSHIFT: return LSHIFT; + case CPP_COMPL: return '~'; + case CPP_AND_AND: return ANDAND; + case CPP_OR_OR: return OROR; + case CPP_QUERY: return '?'; + case CPP_COLON: return ':'; + case CPP_COMMA: return ','; + case CPP_OPEN_PAREN: return '('; + case CPP_CLOSE_PAREN: return ')'; + case CPP_EQ_EQ: lvalp->u.itoken.i = kind_eq; return EQCOMPARE; + case CPP_NOT_EQ: lvalp->u.itoken.i = kind_ne; return EQCOMPARE; + case CPP_GREATER_EQ: lvalp->u.itoken.i = kind_geq; return ARITHCOMPARE; + case CPP_LESS_EQ: lvalp->u.itoken.i = kind_leq; return ARITHCOMPARE; + case CPP_PLUS_EQ: lvalp->u.itoken.i = kind_plus_assign; return ASSIGN; + case CPP_MINUS_EQ: lvalp->u.itoken.i = kind_minus_assign; return ASSIGN; + case CPP_MULT_EQ: lvalp->u.itoken.i = kind_times_assign; return ASSIGN; + case CPP_DIV_EQ: lvalp->u.itoken.i = kind_divide_assign; return ASSIGN; + case CPP_MOD_EQ: lvalp->u.itoken.i = kind_modulo_assign; return ASSIGN; + case CPP_AND_EQ: lvalp->u.itoken.i = kind_bitand_assign; return ASSIGN; + case CPP_OR_EQ: lvalp->u.itoken.i = kind_bitor_assign; return ASSIGN; + case CPP_XOR_EQ: lvalp->u.itoken.i = kind_bitxor_assign; return ASSIGN; + case CPP_RSHIFT_EQ: lvalp->u.itoken.i = kind_rshift_assign; return ASSIGN; + case CPP_LSHIFT_EQ: lvalp->u.itoken.i = kind_lshift_assign; return ASSIGN; + case CPP_OPEN_SQUARE: return '['; + case CPP_CLOSE_SQUARE: return ']'; + case CPP_OPEN_BRACE: return '{'; + case CPP_CLOSE_BRACE: return '}'; + case CPP_SEMICOLON: return ';'; + case CPP_ELLIPSIS: return ELLIPSIS; + case CPP_PLUS_PLUS: return PLUSPLUS; + case CPP_MINUS_MINUS: return MINUSMINUS; + case CPP_DEREF: return POINTSAT; + case CPP_FERED: return TASTNIOP; + case CPP_DOT: return '.'; + case CPP_ATSIGN: return '@'; + + /* These tokens should not be visible outside cpplib. */ + case CPP_HEADER_NAME: + case CPP_MACRO_ARG: default: - value = c; + assert(0); } - -done: - *token_ptr = 0; - - return value; } /* We keep a 2-element queue of pre-read tokens to deal with the @@ -1999,50 +573,48 @@ static int lextoken(struct yystype *lvalp) This code could be optimised to use token_[sl][12] directly in yylex, but then it would be even more confusing. + + It would be nicer to just use _cpp_backup_tokens, but the comments + about pushing back more than one token when a macro is involed, + and the corresponding abort in the implementation are too worrying... */ static int poptoken(struct yystype *lvalp) { /* Check the queue first */ - if (input_file_stack->lex.token_s1 != -1) + if (current.lex.token_s1 != -1) { - int token = input_file_stack->lex.token_s1; - *lvalp = input_file_stack->lex.token_l1; + int token = current.lex.token_s1; + *lvalp = current.lex.token_l1; - input_file_stack->lex.token_s1 = input_file_stack->lex.token_s2; - input_file_stack->lex.token_l1 = input_file_stack->lex.token_l2; - input_file_stack->lex.token_s2 = -1; + current.lex.token_s1 = current.lex.token_s2; + current.lex.token_l1 = current.lex.token_l2; + current.lex.token_s2 = -1; - /* could set this true (it's only two tokens ahead at most) */ - input_file_stack->lex.token_buffer_valid = FALSE; return token; } else - { - input_file_stack->lex.token_buffer_valid = TRUE; - return lextoken(lvalp); - } + return lex_token(lvalp); } static void pushtoken(int t, struct yystype *lvalp) { /* Save token on our 2-element queue */ - if (input_file_stack->lex.token_s1 == -1) + if (current.lex.token_s1 == -1) { - input_file_stack->lex.token_s1 = t; - input_file_stack->lex.token_l1 = *lvalp; + current.lex.token_s1 = t; + current.lex.token_l1 = *lvalp; } else { - input_file_stack->lex.token_s2 = t; - input_file_stack->lex.token_l2 = *lvalp; + current.lex.token_s2 = t; + current.lex.token_l2 = *lvalp; } } int yylex(struct yystype *lvalp) { - int token = poptoken(lvalp); /* Detect component-ref '.' identifier, where the @@ -2080,24 +652,49 @@ yylex(struct yystype *lvalp) } else pushtoken(token1, &val1); - } return token; } +void yyerror(char *string) +{ + char buf[200]; + enum cpp_ttype ttype; + unsigned char *ttext; -/* Sets the value of the 'yydebug' variable to VALUE. - This is a function so we don't have to have YYDEBUG defined - in order to build the compiler. */ + if (!last_token) + { + error(string); + return; + } + + ttext = cpp_token_as_text(current_reader(), last_token); + ttype = last_token->type; + + strcpy (buf, string); -void -set_yydebug (value) - int value; + if ((ttype = last_token->type) == CPP_EOF) + strcat(buf, " at end of input"); + else if (ttype == CPP_STRING || ttype == CPP_WSTRING) + strcat(buf, " before string constant"); + else if (ttype == CPP_CHAR || ttype == CPP_WCHAR) + strcat(buf, " before character constant"); + else if (ttext[0] < 040 || ttext[0] >= 0177) + sprintf(buf + strlen (buf), " before character 0%o", ttext[0]); + else + strcat (buf, " before `%s'"); + + error(buf, ttext); +} + +/* Function used when yydebug is set, to print a token in more detail. */ +void yyprint (FILE *file, int yychar, YYSTYPE yylval) { -#if YYDEBUG != 0 - yydebug = value; -#else - warning ("YYDEBUG not defined."); -#endif + switch (yychar) + { + case IDENTIFIER: + fprintf(file, " '%s'", yylval.idtoken.id.data); + break; + } } diff --git a/src/c-lex.h b/src/c-lex.h index 9433916..e296b48 100644 --- a/src/c-lex.h +++ b/src/c-lex.h @@ -23,8 +23,6 @@ Boston, MA 02111-1307, USA. */ #ifndef C_LEX_H #define C_LEX_H -#include "config.h" - typedef enum { l_c, l_interface, l_component, l_implementation, l_any } source_language; typedef struct location @@ -35,7 +33,7 @@ typedef struct location bool in_system_header; } *location; -extern location last_location, dummy_location, toplevel_location; +extern location dummy_location, toplevel_location; location new_location(const char *filename, int lineno); @@ -74,7 +72,8 @@ enum rid #define NORID RID_UNUSED void init_lex(void); -void start_lex(source_language l); +bool start_lex(source_language l, const char *path); +void end_lex(void); int lex_getc(void); void lex_ungetc(int c); void skip_c_comment(void); @@ -85,8 +84,6 @@ void skip_cpp_comment(void); * place the documentation into the appropriate data_declaration. **/ void get_latest_docstring(char **short_s, char **long_s, struct location **loc); -char *get_docstring(); -void separate_short_docstring(char *str, char **short_s, char **long_s); location make_location(struct location l); diff --git a/src/c-parse.h b/src/c-parse.h index 3e84c80..cc973ce 100644 --- a/src/c-parse.h +++ b/src/c-parse.h @@ -32,7 +32,6 @@ struct yystype { attribute attribute; gcc_attribute gcc_attribute; lexical_cst constant; - string_cst string_cst; declaration decl; declarator declarator; nested_declarator nested; diff --git a/src/c-parse.y b/src/c-parse.y index b5a9e25..cbc851c 100644 --- a/src/c-parse.y +++ b/src/c-parse.y @@ -40,7 +40,6 @@ Boston, MA 02111-1307, USA. */ #include "c-lex.h" #include "c-lex-int.h" #include "semantics.h" -#include "input.h" #include "expr.h" #include "stmt.h" #include "init.h" @@ -102,8 +101,7 @@ void yyerror(); yylval is the node for the constant. */ %token CONSTANT -/* String constants in raw form. - yylval is a STRING_CST node. */ +/* String constants in raw form. */ %token STRING MAGIC_STRING /* "...", used for functions with variable arglists. */ @@ -160,8 +158,8 @@ void yyerror(); %type array_declarator fn_declarator array_or_fn_declarator %type absfn_declarator array_or_absfn_declarator %type cast_expr expr expr_no_commas exprlist init initlist_maybe_comma -%type initlist1 initelt nonnull_exprlist primary string_component -%type STRING string_list nonnull_exprlist_ initval restricted_expr +%type initlist1 initelt nonnull_exprlist primary string +%type nonnull_exprlist_ initval restricted_expr %type designator_list designator %type unary_expr xexpr function_call %type generic_type typelist @@ -177,7 +175,7 @@ void yyerror(); %type stmts xstmts compstmt_or_error compstmt %type labeled_stmt stmt stmt_or_error atomic_stmt %type do_stmt_start -%type asm_clobbers string +%type asm_clobbers STRING %type declspecs_nosc_nots_nosa_noea %type declspecs_nosc_nots_nosa_ea %type declspecs_nosc_nots_sa_noea @@ -421,7 +419,7 @@ declaration make_data_decl(type_element modifiers, declaration decls) declaration make_error_decl(void) { - return new_error_decl(pr, last_location); + return new_error_decl(pr, dummy_location); } declaration make_extension_decl(int old_pedantic, location l, declaration d) @@ -457,7 +455,7 @@ declarator make_identifier_declarator(location l, cstring id) statement make_error_stmt(void) { - return new_error_stmt(pr, last_location); + return new_error_stmt(pr, dummy_location); } /* Tell yyparse how to print a token's value, if yydebug is set. */ @@ -1150,11 +1148,11 @@ primary: $$ = make_identifier($1.location, $1.id, yychar == '('); } | CONSTANT { $$ = CAST(expression, $1); } - | string { $$ = CAST(expression, $1); } + | string { $$ = $1; } | '(' expr ')' { $$ = $2; $$->parens = TRUE; } | '(' error ')' - { $$ = make_error_expr(last_location); } + { $$ = make_error_expr(); } | '(' { if (current.function_decl == 0) { @@ -1215,25 +1213,10 @@ function_call: { $$ = make_function_call($2.location, $1, $3); } ; -/* Produces a STRING_CST with perhaps more STRING_CSTs chained onto it. */ -string: - string_list { $$ = make_string($1->location, expression_reverse($1)); } +string: STRING { $$ = CAST(expression, $1); } + | MAGIC_STRING { $$ = make_identifier($1.location, $1.id, FALSE); } ; -string_list: - string_component { $$ = $1; } - | string_list string_component - { $$ = expression_chain($2, $1); } - ; - -string_component: - STRING { $$ = CAST(expression, $1); } - | MAGIC_STRING - { $$ = make_identifier($1.location, $1.id, FALSE); - } - ; - - old_style_parm_decls: /* empty */ { $$ = NULL; } | datadecls @@ -1714,7 +1697,7 @@ notype_initdecls_: maybeasm: /* empty */ { $$ = NULL; } - | ASM_KEYWORD '(' string ')' + | ASM_KEYWORD '(' STRING ')' { $$ = new_asm_stmt(pr, $1.location, CAST(expression, $3), NULL, NULL, NULL, NULL); } ; @@ -1794,7 +1777,7 @@ target_attribute: restricted_expr: CONSTANT { $$ = CAST(expression, $1); } - | string { $$ = CAST(expression, $1); } + | string { $$ = $1; } | '(' expr ')' { $$ = $2; } ; @@ -1853,7 +1836,7 @@ init: initlist_maybe_comma '}' { $$ = make_init_list($1.location, $3); } | error - { $$ = make_error_expr(last_location); } + { $$ = make_error_expr(); } ; /* `initlist_maybe_comma' is the guts of an initializer in braces. */ @@ -1898,7 +1881,7 @@ initval: process_init_element(NULL); } | expr_no_commas { process_init_element($1); $$ = $1; } - | error { $$ = make_error_expr(last_location); } + | error { $$ = make_error_expr(); } ; designator_list: @@ -2574,19 +2557,15 @@ nonnull_asm_operands: asm_operand: STRING '(' expr ')' - { $$ = new_asm_operand(pr, $1->location, NULL, - make_string($1->location, CAST(expression, $1)), - $3); } + { $$ = new_asm_operand(pr, $1->location, NULL, $1, $3); } | '[' idword ']' STRING '(' expr ')' - { $$ = new_asm_operand(pr, $1.location, $2, - make_string($4->location, CAST(expression, $4)), - $6); } + { $$ = new_asm_operand(pr, $1.location, $2, $4, $6); } ; asm_clobbers: - string + STRING { $$ = $1; } - | asm_clobbers ',' string + | asm_clobbers ',' STRING { $$ = string_chain($1, $3); } ; @@ -2610,7 +2589,7 @@ parmlist_1: parmlist_1 { $$ = declaration_chain($1, $4); } | error ')' - { $$ = new_error_decl(pr, last_location); } + { $$ = make_error_decl(); } ; /* This is what appears inside the parens in a function declarator. @@ -2618,7 +2597,7 @@ parmlist_1: parmlist_2: /* empty */ { $$ = NULL; } | ELLIPSIS - { $$ = new_error_decl(pr, last_location); + { $$ = make_error_decl(); /* Gcc used to allow this as an extension. However, it does not work for all targets, and thus has been disabled. Also, since func (...) and func () are indistinguishable, diff --git a/src/configure.in b/src/configure.in index 503a84c..492ae0f 100644 --- a/src/configure.in +++ b/src/configure.in @@ -24,7 +24,7 @@ dnl -*- m4 -*- # force autoconf 2.5 on Debian systems AC_PREREQ(2.50) -AC_INIT(nesc, 1.2.9) +AC_INIT(nesc, 1.3.0alpha) AC_CONFIG_AUX_DIR(../config-aux) AC_CONFIG_SRCDIR(c-parse.y) AM_CONFIG_HEADER(autoconf.h) diff --git a/src/constants.c b/src/constants.c index e65079c..c7fd8f6 100644 --- a/src/constants.c +++ b/src/constants.c @@ -461,20 +461,17 @@ lexical_cst fold_lexical_char(location loc, cstring tok, return c; } -string_cst fold_lexical_string(location loc, cstring tok, - bool wide_flag, wchar_array stringvalue) +string fold_lexical_string(location loc, string_cst components, cstring value, + bool wide_flag) { - size_t length = wchar_array_length(stringvalue); - wchar_t *chars = rarrayalloc(parse_region, length + 1, wchar_t); - string_cst c = new_string_cst(parse_region, loc, tok, chars, length); + data_declaration sdecl = declare_string(NULL, value, wide_flag); + string s = new_string(parse_region, loc, components, sdecl); - c->type = wide_flag ? wchar_array_type : char_array_type; - memcpy(chars, wchar_array_data(stringvalue), length * sizeof(wchar_t)); - chars[length] = 0; + s->type = sdecl->type; + s->static_address = foldaddress_string(s); + s->lvalue = TRUE; - /* We don't set c->cst as a C string constant is a sequence of string_cst, - not a single one. See make_string. */ - return c; + return s; } lexical_cst fold_lexical_int(type itype, location loc, cstring tok, @@ -550,33 +547,6 @@ void constant_overflow_warning(known_cst c) { } -char *string_cst_to_c(region r, string_cst s) -{ - const wchar_t *wstr = s->chars; - char *str; - - if (type_wchararray(s->type, FALSE)) - { - int length_as_str = wcs_mb_size(wstr); - if (length_as_str < 0) - return NULL; - - str = rarrayalloc(r, length_as_str, char); - length_as_str = wcstombs(str, wstr, length_as_str); - assert(length_as_str >= 0); - } - else - { - size_t i; - - str = rarrayalloc(r, s->length + 1, char); - for (i = 0; i < s->length; i++) - str[i] = s->chars[i]; - } - - return str; -} - bool check_constant_once(expression e, cst_kind k) /* Effects: We want to check whether e is a constant, and possibly for valid constant values, exactly once (to avoid repeated errors and diff --git a/src/constants.h b/src/constants.h index 196047d..fe130cf 100644 --- a/src/constants.h +++ b/src/constants.h @@ -48,8 +48,8 @@ lexical_cst fold_lexical_real(type realtype, location loc, cstring tok); /* XXX: What's the right type for charvalue ? (must hold wchar_t or int) */ lexical_cst fold_lexical_char(location loc, cstring tok, bool wide_flag, int charvalue); -string_cst fold_lexical_string(location loc, cstring tok, - bool wide_flag, wchar_array stringvalue); +string fold_lexical_string(location loc, string_cst components, cstring value, + bool wide_flag); known_cst fold_label_address(expression e); known_cst fold_sizeof(expression e, type stype); @@ -133,12 +133,6 @@ void constant_overflow_warning(known_cst c); */ #define constant_boolvalue(c) cval_boolvalue((c)->cval) -char *string_cst_to_c(region r, string_cst s); -/* Returns: A C string representation of s allocated in r, or NULL if - no such representation can be created (which means s is a wide character - string and wcstombs failed) -*/ - typedef enum { cst_any, cst_numerical, diff --git a/src/cstring.h b/src/cstring.h index 2d7dc50..67a5f6d 100644 --- a/src/cstring.h +++ b/src/cstring.h @@ -43,4 +43,7 @@ cstring alloc_cstring(region r, int l); /* Make a new cstring with a copy of regular C string s */ cstring str2cstring(region r, const char *s); +/* Make a new C string with a copy of cstring s */ +char *cstring2str(region r, cstring s); + #endif diff --git a/src/decls.h b/src/decls.h index 9e1bc3e..4dd42cb 100644 --- a/src/decls.h +++ b/src/decls.h @@ -210,8 +210,7 @@ struct data_declaration { bool substitute; /* Substitute value when unparsing */ /* For magic_strings */ - const wchar_t *chars; - size_t chars_length; + cstring schars; /* For interface_ref */ nesc_declaration itype; diff --git a/src/dhash.c b/src/dhash.c index 2739497..1b3c563 100644 --- a/src/dhash.c +++ b/src/dhash.c @@ -52,8 +52,8 @@ struct dhash_table region sameregion r; void **sameregion elements; unsigned long size, used, log2size; - int (*traditional compare)(void *key, void *y); - unsigned long (*traditional hash)(void *x); + int (*compare)(void *key, void *y); + unsigned long (*hash)(void *x); }; dhash_table new_dhash_table(region r, unsigned long initial_size, diff --git a/src/edit.c b/src/edit.c index 8a0c51d..1552fc1 100644 --- a/src/edit.c +++ b/src/edit.c @@ -122,34 +122,13 @@ word build_word(region r, const char *cword) return new_word(r, dummy_location, str2cstring(r, cword)); } -static void wchar_copy(wchar_t *chars, const char *s, size_t l) -{ - size_t i; - - for (i = 0; i < l; i++) - chars[i] = s[i]; - chars[l] = 0; -} - -static string_cst build_string_cst(region r, location loc, const char *s) -{ - size_t l = strlen(s); - wchar_t *chars = rarrayalloc(r, l + 1, wchar_t); - - wchar_copy(chars, s, l); - return new_string_cst(r, loc, str2cstring(r, "oops"), chars, l); -} - expression build_string(region r, location loc, const char *str) { - string_cst elems = build_string_cst(r, loc, str); - string s = new_string(r, loc, CAST(expression, elems), NULL); - size_t total_length; - - total_length = strlen(str); - s->ddecl = declare_string(NULL, FALSE, total_length); - s->type = s->ddecl->type; - wchar_copy((wchar_t *)s->ddecl->chars, str, total_length); + string_cst elems = new_string_cst(r, loc, str2cstring(r, "oops")); + data_declaration sdecl = declare_string(NULL, str2cstring(r, str), FALSE); + string s = new_string(r, loc, elems, sdecl); + + s->type = sdecl->type; s->static_address = foldaddress_string(s); s->lvalue = TRUE; diff --git a/src/errors.c b/src/errors.c index 3d272aa..d7faaa8 100644 --- a/src/errors.c +++ b/src/errors.c @@ -26,9 +26,10 @@ Boston, MA 02111-1307, USA. */ #include "errors.h" #include "semantics.h" #include "nesc-semantics.h" -#include "input.h" #include "flags.h" +int input_file_stack_tick; + /* Name of program invoked (from argv[0]). */ const char *progname; @@ -51,12 +52,12 @@ void clear_error_location(void) location current_location(void) { - if (input_file_stack) - return &input_file_stack->l; + if (current.lex.input) + return ¤t.lex.input->l; else if (error_location) return error_location; else - return NULL; + return dummy_location; } /* Count an error or warning. Return 1 if the message should be printed. */ @@ -87,7 +88,7 @@ int count_error(int warningp) then we don't have to mention the function name. */ static function_decl last_error_function = NULL; -/* Used to detect when input_file_stack has changed since last described. */ +/* Used to detect when current.lex.input has changed since last described. */ static int last_error_tick; /* The default function to print out name of current function that caused @@ -141,12 +142,12 @@ void report_error_function(const char *file) { struct file_stack *p; - if (input_file_stack && input_file_stack->next != 0 + if (current.lex.input && current.lex.input->next != 0 && input_file_stack_tick != last_error_tick - && file == input_file_stack->l.filename) + && file == current.lex.input->l.filename) { fprintf (stderr, "In file included"); - for (p = input_file_stack->next; p; p = p->next) + for (p = current.lex.input->next; p; p = p->next) { fprintf (stderr, " from %s:%lu", p->l.filename, p->l.lineno); if (p->next) @@ -190,8 +191,8 @@ void verror_with_decl(declaration d, const char *format, va_list args) /* Report error msg at current filename, lineno */ void verror(const char *format, va_list args) { - if (input_file_stack) - verror_with_location(&input_file_stack->l, format, args); + if (current.lex.input) + verror_with_location(¤t.lex.input->l, format, args); else if (error_location) verror_with_location(error_location, format, args); else @@ -271,8 +272,8 @@ void vwarning_with_decl(declaration d, const char *format, va_list args) /* Report warning msg at current filename, lineno */ void vwarning(const char *format, va_list args) { - if (input_file_stack) - vwarning_with_location(&input_file_stack->l, format, args); + if (current.lex.input) + vwarning_with_location(¤t.lex.input->l, format, args); else if (error_location) vwarning_with_location(error_location, format, args); else if (count_error(TRUE)) diff --git a/src/expr.c b/src/expr.c index 6947f3d..74e99be 100644 --- a/src/expr.c +++ b/src/expr.c @@ -514,9 +514,9 @@ bool check_assignment(type lhstype, type rhstype, expression rhs, return FALSE; } -expression make_error_expr(location loc) +expression make_error_expr(void) { - expression result = CAST(expression, new_error_expr(parse_region, loc)); + expression result = CAST(expression, new_error_expr(parse_region, dummy_location)); result->type = error_type; @@ -1348,7 +1348,7 @@ expression make_identifier(location loc, cstring id, bool maybe_implicit) expression make_compound_expr(location loc, statement block) { if (is_error_stmt(block)) - return make_error_expr(loc); + return make_error_expr(); else { expression result = CAST(expression, new_compound_expr(parse_region, loc, block)); @@ -1715,62 +1715,3 @@ expression make_predecrement(location loc, expression e) return finish_increment(CAST(unary, new_predecrement(parse_region, loc, e)), "decrement"); } - -static size_t extract_strings(expression string_components, - wchar_t *into, bool *wide) -{ - size_t total_length = 0; - expression astring; - - *wide = FALSE; - scan_expression (astring, string_components) - { - const wchar_t *chars; - size_t length; - - if (!type_equal(type_array_of(astring->type), char_type)) - *wide = TRUE; - - if (is_identifier(astring)) - { - data_declaration dd = CAST(identifier, astring)->ddecl; - - chars = dd->chars; - length = dd->chars_length; - } - else - { - string_cst s = CAST(string_cst, astring); - - chars = s->chars; - length = s->length; - } - if (into) - { - memcpy(into, chars, length * sizeof(wchar_t)); - into += length; - } - - total_length += length; - } - if (into) - into[0] = 0; - - return total_length; -} - -string make_string(location loc, expression string_components) -{ - string s = new_string(parse_region, loc, string_components, NULL); - size_t total_length = 0; - bool wide; - - total_length = extract_strings(string_components, NULL, &wide); - s->ddecl = declare_string(NULL, wide, total_length); - s->type = s->ddecl->type; - extract_strings(string_components, (wchar_t *)s->ddecl->chars, &wide); - s->static_address = foldaddress_string(s); - s->lvalue = TRUE; - - return s; -} diff --git a/src/expr.h b/src/expr.h index 35d0990..940dce1 100644 --- a/src/expr.h +++ b/src/expr.h @@ -23,7 +23,7 @@ Boston, MA 02111-1307, USA. */ #ifndef EXPR_H #define EXPR_H -expression make_error_expr(location loc); +expression make_error_expr(void); expression make_comma(location loc, expression elist); expression make_dereference(location loc, expression e); @@ -53,8 +53,6 @@ expression make_preincrement(location loc, expression e); expression make_postdecrement(location loc, expression e); expression make_predecrement(location loc, expression e); -string make_string(location loc, expression string_components); - /* Return TRUE if no error and lhstype and rhstype are not error_type */ bool check_assignment(type lhstype, type rhstype, expression rhs, const char *context, data_declaration fundecl, diff --git a/src/flags.c b/src/flags.c index 2f7bca7..c158a92 100644 --- a/src/flags.c +++ b/src/flags.c @@ -20,8 +20,7 @@ along with nesC; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "config.h" -#include "flags.h" +#include "parser.h" /* -f flags. */ diff --git a/src/init.c b/src/init.c index 3344c65..3b7810d 100644 --- a/src/init.c +++ b/src/init.c @@ -41,7 +41,7 @@ static type set_array_length(type t, largest_int length) static largest_int string_constant_length(expression e) { - return CAST(string, e)->ddecl->chars_length + 1; + return CAST(string, e)->ddecl->schars.length + 1; } /* Make a version of tdecl (an array type) with its length set to the @@ -300,9 +300,10 @@ static bool digest_init(type t, expression init) if (!cval_istop(tcsize)) { largest_uint tsize = cval_uint_value(tcsize); + data_declaration sdecl = CAST(string, init)->ddecl; /* Don't count the null char (char x[1] = "a" is ok) */ - if (tsize && tsize < CAST(string, init)->ddecl->chars_length) + if (tsize && tsize < sdecl->schars.length / type_size_int(type_array_of(sdecl->type))) pedwarn_init ("initializer-string for array of chars is too long"); } diff --git a/src/input.c b/src/input.c index 4545cdd..54ea435 100644 --- a/src/input.c +++ b/src/input.c @@ -29,7 +29,7 @@ struct file_stack *input_file_stack; /* Incremented on each change to input_file_stack. */ int input_file_stack_tick; -void set_input(FILE *f, const char *filename) +void set_input(cpp_reader *f, const char *filename) { struct file_stack *p = (struct file_stack *)xmalloc(sizeof(struct file_stack)); p->next = input_file_stack; @@ -46,7 +46,7 @@ void set_input(FILE *f, const char *filename) void end_input(void) { - FILE *f = input_file_stack->lex.finput; + cpp_reader *f = input_file_stack->lex.finput; while (input_file_stack && input_file_stack->lex.finput == f) { @@ -58,8 +58,6 @@ void end_input(void) if (input_file_stack) input_file_stack->lex.token_buffer_valid = FALSE; - if (f) - fclose(f); input_file_stack_tick++; } diff --git a/src/input.h b/src/input.h index 449c40a..284dd20 100644 --- a/src/input.h +++ b/src/input.h @@ -23,22 +23,10 @@ Boston, MA 02111-1307, USA. */ #ifndef INPUT_H #define INPUT_H -#include "c-lex-state.h" - -struct file_stack - { - struct file_stack *next; - struct location l; - struct lex_state lex; /* internal info for lexer only */ - }; - -/* Stack of currently pending input files. */ -extern struct file_stack *input_file_stack; - -/* Incremented on each change to input_file_stack. */ +/* Incremented on each change to the input file stack. */ extern int input_file_stack_tick; -void set_input(FILE *f, const char *filename); +void set_input(cpp_reader *f, const char *filename); void end_input(void); void push_input(void); void pop_input(void); diff --git a/src/libcompat/regions.h b/src/libcompat/regions.h index a407832..99fe95d 100644 --- a/src/libcompat/regions.h +++ b/src/libcompat/regions.h @@ -35,7 +35,7 @@ #define REGIONS_H #define deletes -#define traditional +//#define traditional #define sameregion #define parentptr diff --git a/src/machine.h b/src/machine.h index b2c3d02..57ef395 100644 --- a/src/machine.h +++ b/src/machine.h @@ -12,7 +12,7 @@ typedef struct { void (*handle_option)(const char *opt); - bool pcc_bitfield_type_matters; + bool big_endian, pcc_bitfield_type_matters; size_t empty_field_boundary, structure_size_boundary; size_t word_size; diff --git a/src/machine/avr.c b/src/machine/avr.c index 5d440fb..e819cf5 100644 --- a/src/machine/avr.c +++ b/src/machine/avr.c @@ -20,6 +20,7 @@ static bool avr_decl_attribute(gcc_attribute attr, data_declaration ddecl) /* Basic pointer sizes and alignments for the AVR */ static machine_spec avr_machine = { "avr", NULL, + FALSE, /* big_endian */ FALSE, /* pcc_bitfield_type_matters */ 8, /* empty field boundary - in bits */ 8, /* structure size boundary - in bits */ diff --git a/src/machine/env_machine.c b/src/machine/env_machine.c index 9cf5525..a67a29f 100644 --- a/src/machine/env_machine.c +++ b/src/machine/env_machine.c @@ -32,6 +32,7 @@ Boston, MA 02111-1307, USA. */ static machine_spec env_machine = { "env", NULL, /* [default] */ /* [keyname] */ + FALSE, /* big_endian */ FALSE, /* pcc_bitfield_type_matters */ 8, /* empty_field_boundary */ 8, /* structure_size_boundary */ @@ -148,6 +149,19 @@ static bool scan_env_machine(machine_spec * machine, const char *envname) n_errors++; } } + else if (is_literali(name = "big_endian", begin, equal)) + { + int b = scan_boolean(value, space); + if (b != -1) + { + machine->big_endian = b ? TRUE : FALSE; + } + else + { + error("%s.%s, expected 'false' or 'true'", envname, name); + n_errors++; + } + } else if (is_literali(name = "empty_field_boundary", begin, equal)) { if (scan_intlist(value, space, intlist, 1) == TRUE) diff --git a/src/machine/keil.c b/src/machine/keil.c index 1046832..717abf6 100644 --- a/src/machine/keil.c +++ b/src/machine/keil.c @@ -1,5 +1,3 @@ -/* - /* Partial model for supporting Keil C (original version based on work by David Patnode (dpatnode@bradley.edu) for this file). @@ -82,6 +80,7 @@ declaration keil_special(location loc, cstring keyword, cstring name, /* Basic pointer sizes and alignments for the 8051's compiled w/ Keil C51 */ static machine_spec keil_machine = { "keil", NULL, + TRUE, /* big_endian */ FALSE, /* pcc_bitfield_type_matters */ 8, /* empty field boundary - in bits */ 8, /* structure size boundary - in bits */ diff --git a/src/machine/msp430.c b/src/machine/msp430.c index 6058abc..f79fc17 100644 --- a/src/machine/msp430.c +++ b/src/machine/msp430.c @@ -22,6 +22,7 @@ static bool msp430_decl_attribute(gcc_attribute attr, data_declaration ddecl) /* Basic pointer sizes and alignments for the TI MSP430 */ static machine_spec msp430_machine = { "msp430", NULL, + FALSE, /* big_endian */ FALSE, /* pcc_bitfield_type_matters */ 16, /* empty field boundary - in bits */ 8, /* structure size boundary - in bits */ diff --git a/src/machine/sdcc.c b/src/machine/sdcc.c index 514e544..a1746e9 100644 --- a/src/machine/sdcc.c +++ b/src/machine/sdcc.c @@ -49,6 +49,7 @@ static int sdcc_token(const char *token, int len, struct yystype *lvalp) static machine_spec sdcc_machine = { "sdcc", NULL, + FALSE, /* big_endian */ FALSE, /* pcc_bitfield_type_matters */ 8, /* empty field boundary - in bits */ 8, /* structure size boundary - in bits */ diff --git a/src/machine/self.c b/src/machine/self.c index f37f7cc..1e86bf8 100644 --- a/src/machine/self.c +++ b/src/machine/self.c @@ -59,6 +59,8 @@ static void self_handle_option(const char *arg) static machine_spec self_machine = { "pc", SELF_HANDLE_OPTION, + FALSE, /* FIXME big_endian */ + /* pcc_bitfield_type_matters */ sizeof(struct self_pcc1) != sizeof(struct self_pcc2), diff --git a/src/config.h b/src/nconfig.h similarity index 92% rename from src/config.h rename to src/nconfig.h index f03bb25..e87e707 100644 --- a/src/config.h +++ b/src/nconfig.h @@ -19,11 +19,17 @@ along with nesC; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef CONFIG_H -#define CONFIG_H +#ifndef NCONFIG_H +#define NCONFIG_H /* autoconf/configure options */ #include "autoconf.h" +#undef PACKAGE +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_BUGREPORT +#undef PACKAGE_VERSION /* Target type structure information. This setup assumes that we are compiling on self, with gcc diff --git a/src/nesc-c.c b/src/nesc-c.c index 2135d98..b039de2 100644 --- a/src/nesc-c.c +++ b/src/nesc-c.c @@ -20,7 +20,6 @@ Boston, MA 02111-1307, USA. */ #include "nesc-paths.h" #include "nesc-semantics.h" #include "c-parse.h" -#include "input.h" #include "nesc-cpp.h" declaration all_cdecls; diff --git a/src/nesc-component.c b/src/nesc-component.c index af459b1..b991342 100644 --- a/src/nesc-component.c +++ b/src/nesc-component.c @@ -27,7 +27,6 @@ Boston, MA 02111-1307, USA. */ #include "nesc-cg.h" #include "semantics.h" #include "c-parse.h" -#include "input.h" #include "edit.h" #include "nesc-abstract.h" #include "attributes.h" diff --git a/src/nesc-cpp.c b/src/nesc-cpp.c index 16d53c4..710c6eb 100644 --- a/src/nesc-cpp.c +++ b/src/nesc-cpp.c @@ -28,7 +28,6 @@ Boston, MA 02111-1307, USA. */ #include "flags.h" #include "semantics.h" #include "c-parse.h" -#include "input.h" static region pragma_region; dd_list pragmas; @@ -513,13 +512,13 @@ void handle_directive(const char *directive, const char *args) if (!strcmp(directive, "pragma")) { - save_pragma(input_file_stack->l, args); + save_pragma(current.lex.input->l, args); return; } /* If the filename starts with <, these are special macros (built in or from the command line) */ - if (input_file_stack && input_file_stack->l.filename[0] == '<') + if (current.lex.input && current.lex.input->l.filename[0] == '<') return; if (!(strcmp(directive, "define") == 0 || strcmp(directive, "undef") == 0)) diff --git a/src/nesc-semantics.c b/src/nesc-semantics.c index ad4c416..7a8e69a 100644 --- a/src/nesc-semantics.c +++ b/src/nesc-semantics.c @@ -20,7 +20,6 @@ Boston, MA 02111-1307, USA. */ #include "semantics.h" #include "nesc-decls.h" #include "c-parse.h" -#include "input.h" #include "AST_utils.h" #include "nesc-paths.h" #include "nesc-cpp.h" @@ -153,9 +152,9 @@ node compile(location loc, nesc_declaration container, source_language l = container ? container->kind : l_c; const char *path = name_is_path ? name : find_nesc_file(parse_region, l, name); - FILE *f = NULL; node parse_tree = NULL; struct semantic_state old_semantic_state = current; + bool ok; if (!path) error_with_location(loc, "%s %s not found", language_name(l), name); @@ -163,24 +162,17 @@ node compile(location loc, nesc_declaration container, { if (flag_verbose) fprintf(stderr, "preprocessing %s\n", path); - f = preprocess(path, l); - if (!f) + current.file = container; + current.fileregion = newregion(); + start_semantics(l_c, NULL, global_env); + ok = start_lex(l, path); + if (!ok) error_with_location(loc, "failed to preprocess %s", path); else - { - set_input(f, path); - - start_lex(l); - start_semantics(l_c, NULL, global_env); - current.file = container; - current.fileregion = newregion(); - parse_tree = parse(); - deleteregion_ptr(¤t.fileregion); - end_input(); - - preprocess_file_end(); - } + parse_tree = parse(); + deleteregion_ptr(¤t.fileregion); + end_lex(); } current = old_semantic_state; @@ -291,6 +283,7 @@ nesc_declaration load(source_language sl, location l, nesc_declaration start_nesc_entity(source_language sl, word name) { nesc_declaration decl; + location doc_location; /* If the kind of entity in the file matches the expected kind (passed to load), reuse the existing declaration. Otherwise @@ -301,11 +294,7 @@ nesc_declaration start_nesc_entity(source_language sl, word name) else decl = new_nesc_declaration(parse_region, sl, name->cstring.data); - char *docstring = get_docstring(); - - if (docstring) - separate_short_docstring(docstring, &decl->short_docstring, - &decl->long_docstring); + get_latest_docstring(&decl->short_docstring, &decl->long_docstring, &doc_location); start_semantics(sl, decl, decl->env); diff --git a/src/nesc-uses.c b/src/nesc-uses.c index 9c9e21e..bf45059 100644 --- a/src/nesc-uses.c +++ b/src/nesc-uses.c @@ -342,7 +342,7 @@ static void collect_uses_asm_operands(asm_operand operands, scan_asm_operand (aop, operands) { - wchar_t mode = asm_rwmode(aop->string); + int mode = asm_rwmode(aop->string); context c = exe_c; /* = is write, + is r/w, everything else is read */ diff --git a/src/nesc-xml.c b/src/nesc-xml.c index aa3a27c..cb81163 100644 --- a/src/nesc-xml.c +++ b/src/nesc-xml.c @@ -121,20 +121,23 @@ void xqputs(const char *s) } } -void xwqputs(const wchar_t *s) +void xqputcs(const cstring s) { + int i; + if (!xml_file) return; /* Output a wide-char string quoted to match XML AttValue rules */ - while (*s) + for (i = 0; i < s.length; i++) { - if ((unsigned char)*s == *s && isprint(*s) && - !(*s == '"' || *s == '<' || *s == '&')) - putc(*s, xml_file); + char c = s.data[i]; + + if ((unsigned char)c == c && isprint(c) && + !(c == '"' || c == '<' || c == '&')) + putc(c, xml_file); else - xprintf("&#%d;", *s); - s++; + xprintf("&#%d;", c); } } @@ -254,8 +257,9 @@ void xml_attr_cval(const char *name, cval val) /* XXX: We don't (yet) support strings with an offset */ if (ddecl && ddecl->kind == decl_magic_string && cval_knownbool(val)) { + /* Wide strings are printed as their byte-by-byte rep. FIXME */ xputs("S:"); - xwqputs(ddecl->chars); + xqputcs(ddecl->schars); } else unknown = TRUE; diff --git a/src/nesc-xml.h b/src/nesc-xml.h index 720803a..ca9e2ba 100644 --- a/src/nesc-xml.h +++ b/src/nesc-xml.h @@ -31,7 +31,7 @@ void xstartline_noindent(void); void xvprintf(char *format, va_list args); void xprintf(char *format, ...); void xqputs(const char *s); -void xwqputs(const wchar_t *s); +void xqputcs(cstring cs); void xputs(const char *s); /* Tag/attribute handling */ diff --git a/src/nodetypes.def b/src/nodetypes.def index d748667..7a6a969 100644 --- a/src/nodetypes.def +++ b/src/nodetypes.def @@ -70,7 +70,7 @@ (deffield cstring cstring (init)) (deffield word1 word (init tree)) (deffield word2 word (init tree)) -(deffield strings expression (init tree)) +(deffield strings string_cst (init tree)) (deffield args expression (init tree)) (deffield modifiers type_element (init tree)) (deffield qualifiers type_element (init tree)) @@ -95,7 +95,6 @@ (deffield incrementrc bool (init)) (deffield old_parms declaration (init)) (deffield attributes attribute (init tree)) -(deffield chars "wchar_t *" (init)) (deffield length size_t (init)) (deffield cval cval (init)) (deffield va_arg_call asttype (init)) @@ -546,9 +545,10 @@ ARG2 is a GCC extension") "A constant represented as in its unparsed lexical form CSTRING. These appear in the AST.") -(deftype string_cst lexical_cst (chars length) - "A single lexical string whose LENGTH characters are CHARS. The source -form of the constant can be found in CSTRING.") +(deftype string_cst lexical_cst () + "A single lexical string - a sequence of these gets concatenated to +form a string. The source form of the constant can be found in +CSTRING.") (deftype string expression (strings ddecl) "A list of STRINGS forming a single string constant. diff --git a/src/parser.h b/src/parser.h index ec1b33e..425ea7f 100644 --- a/src/parser.h +++ b/src/parser.h @@ -30,7 +30,7 @@ Boston, MA 02111-1307, USA. */ #include #include -#include "config.h" +#include "nconfig.h" #include "array.h" #include "utils.h" #include "AST.h" diff --git a/src/semantics.c b/src/semantics.c index 12b1963..2409543 100644 --- a/src/semantics.c +++ b/src/semantics.c @@ -22,7 +22,6 @@ Boston, MA 02111-1307, USA. */ #include "parser.h" #include "semantics.h" -#include "input.h" #include "flags.h" #include "c-parse.h" #include "c-lex.h" @@ -118,8 +117,8 @@ void init_data_declaration(data_declaration dd, declaration ast, dd->isparameter = FALSE; dd->islimbo = FALSE; dd->value = NULL; - dd->chars = NULL; - dd->chars_length = 0; + dd->schars.data = NULL; + dd->schars.length = 0; dd->id = 0; dd->defined = FALSE; dd->suppress_definition = FALSE; @@ -380,7 +379,7 @@ void shadow_tag_warned(type_element elements, int warned) } else { - if (!warned && ! input_file_stack->l.in_system_header) + if (!warned && ! current.lex.input->l.in_system_header) { warning("useless keyword or type name in empty declaration"); warned = 2; @@ -431,15 +430,6 @@ bool is_void_parms(declaration parms) is_rid(dd->modifiers) && CAST(rid, dd->modifiers)->id == RID_VOID; } -bool error_if_void_parms(declaration parms) -{ - bool vp; - - if ((vp = is_void_parms(parms))) - error("use (), not (void), for 0-argument functios"); - return vp; -} - /* At end of parameter list, warn about any struct, union or enum tags defined within. Do so because these types cannot ever become complete. */ static void parmlist_tags_warning(environment parm_env) @@ -718,7 +708,7 @@ void parse_declarator(type_element modifiers, declarator d, bool bitfield, "`long long long' is too long for GCC"); else { - if (pedantic && !input_file_stack->l.in_system_header) + if (pedantic && !current.lex.input->l.in_system_header) pedwarn_with_location(spec->location, "ANSI C does not support `long long'"); longlong = TRUE; @@ -935,7 +925,7 @@ void parse_declarator(type_element modifiers, declarator d, bool bitfield, } if (pedantic && type_function(t) && (type_const(t) || type_volatile(t)) && - !input_file_stack->l.in_system_header) + !current.lex.input->l.in_system_header) pedwarn_with_location(loc, "ANSI C forbids const or volatile function types"); /* Now figure out the structure of the declarator proper. @@ -1031,9 +1021,6 @@ void parse_declarator(type_element modifiers, declarator d, bool bitfield, /* Require new-style declarations */ if (current.language != l_c) { - if (error_if_void_parms(fd->parms)) - fd->parms = NULL; /* avoid 2nd error for tasks */ - newstyle = !fd->parms || !is_oldidentifier_decl(fd->parms); if (!newstyle) error("old-style parameter lists not supported"); @@ -1656,7 +1643,7 @@ void check_function(data_declaration dd, declaration fd, int class, /* XXX: Does this volatile/const stuff actually work with my imp ? */ if (pedantic && type_void(return_type) && (type_const(return_type) || type_volatile(return_type)) && - !input_file_stack->l.in_system_header) + !current.lex.input->l.in_system_header) pedwarn("ANSI C forbids const or volatile void function return type"); if (type_volatile(function_type) && !type_void(return_type)) @@ -1754,10 +1741,10 @@ void check_function(data_declaration dd, declaration fd, int class, } } -data_declaration declare_string(const char *name, bool wide, size_t length) +data_declaration declare_string(const char *name, cstring value, bool wide) { struct data_declaration tempdecl; - expression expr_l = build_uint_constant(parse_region, dummy_location, size_t_type, length + 1); + expression expr_l = build_uint_constant(parse_region, dummy_location, size_t_type, value.length + 1); type value_type = make_array_type(wide ? wchar_type : char_type, expr_l); init_data_declaration(&tempdecl, new_error_decl(parse_region, dummy_location), @@ -1766,24 +1753,14 @@ data_declaration declare_string(const char *name, bool wide, size_t length) tempdecl.needsmemory = TRUE; tempdecl.in_system_header = TRUE; tempdecl.vtype = variable_static; - - /* Save value. */ - tempdecl.chars_length = length; - tempdecl.chars = rarrayalloc(parse_region, length + 1, wchar_t); + tempdecl.schars = value; return declare(current.env, &tempdecl, TRUE); } static void declare_magic_string(const char *name, const char *value) { - int i, l = strlen(value); - data_declaration dd = declare_string(name, FALSE, l); - wchar_t *chars = (wchar_t *)dd->chars; - - /* Save value. */ - for (i = 0; i < l; i++) - chars[i] = value[i]; - chars[l] = 0; + declare_string(name, str2cstring(parse_region, value), FALSE); } bool builtin_declaration(data_declaration dd) @@ -3692,7 +3669,7 @@ void init_semantics(void) bad_decl->kind = decl_error; bad_decl->name = "undeclared"; bad_decl->type = error_type; - bad_decl->ast = new_error_decl(parse_region, last_location); + bad_decl->ast = new_error_decl(parse_region, dummy_location); dummy_function_declarator = new_function_declarator(parse_region, dummy_location, NULL, NULL, NULL, NULL, NULL); diff --git a/src/semantics.h b/src/semantics.h index f4f9844..3db7a5a 100644 --- a/src/semantics.h +++ b/src/semantics.h @@ -38,6 +38,7 @@ extern data_declaration builtin_constant_p; #include "cstring.h" #include "decls.h" +#include "c-lex-state.h" /* Print an error message now for a recent invalid struct, union or enum cross reference. @@ -167,7 +168,7 @@ data_declaration declare(environment env, data_declaration from, bool ignore_shadow); /* Build a declaration object for a string */ -data_declaration declare_string(const char *name, bool wide, size_t length); +data_declaration declare_string(const char *name, cstring value, bool wide); environment new_environment(region r, environment parent, bool global_level, bool parm_level); @@ -204,6 +205,7 @@ struct semantic_state atomic_stmt in_atomic; /* The lexically containing atomic statement (NULL for none) */ char *preprocessed_file; /* Temp file holding preprocessor output */ + struct lex_state lex; }; extern struct semantic_state current; diff --git a/src/toplev.c b/src/toplev.c index 945fdf9..1a00401 100644 --- a/src/toplev.c +++ b/src/toplev.c @@ -25,7 +25,6 @@ Boston, MA 02111-1307, USA. */ #include #include "parser.h" -#include "input.h" #include "c-parse.h" #include "unparse.h" #include "semantics.h" @@ -353,7 +352,7 @@ static void rcc_aborting(int s) signal(SIGABRT, 0); fprintf(stderr, "nesC: Internal error. Please send a bug report to the nesC bug mailing list\nat nescc-bugs@lists.sourceforge.net\n"); where = current_location(); - if (where) + if (where != dummy_location) fprintf(stderr, "Current location (guess): %s:%lu\n", where->filename, where->lineno); if (getenv("RCCDEBUG")) abort(); diff --git a/src/unparse.c b/src/unparse.c index 2fd0c7e..2e227c4 100644 --- a/src/unparse.c +++ b/src/unparse.c @@ -153,24 +153,27 @@ void output_quoted(const char *s) } -void output_quoted_wide(const wchar_t *s) +void output_quoted_cs(cstring s) { /* Output a string which may contain newlines, \ and " */ - while (*s) + int i; + + for (i = 0; i < s.length; i++) { - if (*s == '\n') /* don't confuse the line numbers */ + char c = s.data[i]; + + if (c == '\n') /* don't confuse the line numbers */ fputs("\\n", of); - else if ((unsigned char)*s == *s && isprint(*s)) + else if ((unsigned char)c == c && isprint(c)) { - if (*s == '\\' || *s == '"') + if (c == '\\' || c == '"') putc('\\', of); - putc(*s, of); + putc(c, of); } else /* The "" at the end avoids confusion if the next character is '0'-'9', 'a'-'f' or 'A'-'F' */ - output("\\x%lx\"\"", (unsigned long)*s); - s++; + output("\\x%lx\"\"", (unsigned long)c); } } @@ -334,7 +337,10 @@ void output_constant(known_cst c) assert(ddecl && ddecl->kind == decl_magic_string); output("\""); - output_quoted_wide(ddecl->chars); + /* FIXME we ignore wide char issues, just outputting the raw bytes - + this should be ok for now as we don't actually allow wide-char + strings as arguments to generics anyway */ + output_quoted_cs(ddecl->schars); output("\""); } else @@ -1766,10 +1772,10 @@ void prt_lexical_cst(lexical_cst e, int context_priority) void prt_string(string e, int context_priority) { - expression s; + lexical_cst s; - scan_expression (s, e->strings) - prt_expression(s, P_TOP); + scan_lexical_cst (s, CAST(lexical_cst, e->strings)) + prt_lexical_cst(s, P_TOP); } void prt_init_list(init_list e, int context_priority) diff --git a/src/unparse.h b/src/unparse.h index 0b8a507..6f2f294 100644 --- a/src/unparse.h +++ b/src/unparse.h @@ -50,7 +50,7 @@ void output_string(const char *s); void output_cstring(cstring s); void output_stripped_string(const char *s); void output_stripped_string_dollar(const char *s); -void output_quoted_wide(const wchar_t *s); +void output_quoted_cs(cstring cs); void copy_file_to_output(char *filename); void newline(void); void indent(void); diff --git a/src/utils.c b/src/utils.c index 0fb69ec..b5ea15a 100644 --- a/src/utils.c +++ b/src/utils.c @@ -4,6 +4,10 @@ This file is derived from the RC Compiler. It is thus Copyright (C) 2000-2001 The Regents of the University of California. Changes for nesC are Copyright (C) 2002 Intel Corporation +It also includes + Public domain code from Pat Rankin +and code from libiberty that is + Copyright (C) 2001, 2002 Free Software Foundation, Inc. The attached "nesC" software is provided to you under the terms and conditions of the GNU General Public License Version 2 as published by the @@ -44,6 +48,19 @@ void *xmalloc(size_t size) return x; } +void *xcalloc(size_t count, size_t size) +{ +#ifdef BWGC + void *x = GC_calloc(count, size); +#else + void *x = calloc(count, size); +#endif + + if (!x) abort(); + + return x; +} + void *xrealloc(void *p, size_t newsize) { #ifdef BWGC @@ -57,6 +74,53 @@ void *xrealloc(void *p, size_t newsize) return x; } +char *xstrdup(const char *s) +{ + char *t = strdup(s); + + if (!t) abort(); + + return t; +} + +void *xmemdup(const void *from, size_t s, size_t nsize) +{ + void *x = xcalloc(1, nsize); + + return memcpy(x, from, s); +} + +#define ERRSTR_FMT "undocumented error #%d" +static char xstrerror_buf[sizeof ERRSTR_FMT + 20]; + +/* Like strerror, but result is never a null pointer. */ +char *xstrerror (int errnum) +{ + char *errstr; +#ifdef VMS + char *(*vmslib_strerror) (int,...); + + /* Override any possibly-conflicting declaration from system header. */ + vmslib_strerror = (char *(*) (int,...)) strerror; + /* Second argument matters iff first is EVMSERR, but it's simpler to + pass it unconditionally. `vaxc$errno' is declared in + and maintained by the run-time library in parallel to `errno'. + We assume that `errnum' corresponds to the last value assigned to + errno by the run-time library, hence vaxc$errno will be relevant. */ + errstr = (*vmslib_strerror) (errnum, vaxc$errno); +#else + errstr = strerror (errnum); +#endif + + /* If `errnum' is out of range, result might be NULL. We'll fix that. */ + if (!errstr) + { + sprintf (xstrerror_buf, ERRSTR_FMT, errnum); + errstr = xstrerror_buf; + } + return errstr; +} + /* Make a new unintialised cstring of length l */ cstring alloc_cstring(region r, int l) { @@ -85,6 +149,17 @@ cstring str2cstring(region r, const char *s) return make_cstring(r, s, strlen(s)); } +/* Make a new C string with a copy of cstring s */ +char *cstring2str(region r, cstring s) +{ + int len = s.length + 1; + char *str = rstralloc(r, len); + + memcpy(str, s.data, len); + + return str; +} + unsigned long align_to(unsigned long n, unsigned long alignment) { int count = (n + alignment - 1) / alignment; @@ -128,7 +203,6 @@ int ilog2(largest_uint x) return v == x ? log2 : -1; } -DEFINE_ARRAY(wchar_array, wchar_t) DEFINE_ARRAY(char_array, char) #ifdef __CYGWIN32__