--- /dev/null
+# Klimbim Software collection, A bag full of things
+# Copyright (C) 2011-2023 Johannes 'Banana' Keßler
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+A selection of C tools and examples
\ No newline at end of file
--- /dev/null
+GNU GENERAL PUBLIC LICENSE\r
+ Version 3, 29 June 2007\r
+\r
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>\r
+ Everyone is permitted to copy and distribute verbatim copies\r
+ of this license document, but changing it is not allowed.\r
+\r
+ Preamble\r
+\r
+ The GNU General Public License is a free, copyleft license for\r
+software and other kinds of works.\r
+\r
+ The licenses for most software and other practical works are designed\r
+to take away your freedom to share and change the works. By contrast,\r
+the GNU General Public License is intended to guarantee your freedom to\r
+share and change all versions of a program--to make sure it remains free\r
+software for all its users. We, the Free Software Foundation, use the\r
+GNU General Public License for most of our software; it applies also to\r
+any other work released this way by its authors. You can apply it to\r
+your programs, too.\r
+\r
+ When we speak of free software, we are referring to freedom, not\r
+price. Our General Public Licenses are designed to make sure that you\r
+have the freedom to distribute copies of free software (and charge for\r
+them if you wish), that you receive source code or can get it if you\r
+want it, that you can change the software or use pieces of it in new\r
+free programs, and that you know you can do these things.\r
+\r
+ To protect your rights, we need to prevent others from denying you\r
+these rights or asking you to surrender the rights. Therefore, you have\r
+certain responsibilities if you distribute copies of the software, or if\r
+you modify it: responsibilities to respect the freedom of others.\r
+\r
+ For example, if you distribute copies of such a program, whether\r
+gratis or for a fee, you must pass on to the recipients the same\r
+freedoms that you received. You must make sure that they, too, receive\r
+or can get the source code. And you must show them these terms so they\r
+know their rights.\r
+\r
+ Developers that use the GNU GPL protect your rights with two steps:\r
+(1) assert copyright on the software, and (2) offer you this License\r
+giving you legal permission to copy, distribute and/or modify it.\r
+\r
+ For the developers' and authors' protection, the GPL clearly explains\r
+that there is no warranty for this free software. For both users' and\r
+authors' sake, the GPL requires that modified versions be marked as\r
+changed, so that their problems will not be attributed erroneously to\r
+authors of previous versions.\r
+\r
+ Some devices are designed to deny users access to install or run\r
+modified versions of the software inside them, although the manufacturer\r
+can do so. This is fundamentally incompatible with the aim of\r
+protecting users' freedom to change the software. The systematic\r
+pattern of such abuse occurs in the area of products for individuals to\r
+use, which is precisely where it is most unacceptable. Therefore, we\r
+have designed this version of the GPL to prohibit the practice for those\r
+products. If such problems arise substantially in other domains, we\r
+stand ready to extend this provision to those domains in future versions\r
+of the GPL, as needed to protect the freedom of users.\r
+\r
+ Finally, every program is threatened constantly by software patents.\r
+States should not allow patents to restrict development and use of\r
+software on general-purpose computers, but in those that do, we wish to\r
+avoid the special danger that patents applied to a free program could\r
+make it effectively proprietary. To prevent this, the GPL assures that\r
+patents cannot be used to render the program non-free.\r
+\r
+ The precise terms and conditions for copying, distribution and\r
+modification follow.\r
+\r
+ TERMS AND CONDITIONS\r
+\r
+ 0. Definitions.\r
+\r
+ "This License" refers to version 3 of the GNU General Public License.\r
+\r
+ "Copyright" also means copyright-like laws that apply to other kinds of\r
+works, such as semiconductor masks.\r
+\r
+ "The Program" refers to any copyrightable work licensed under this\r
+License. Each licensee is addressed as "you". "Licensees" and\r
+"recipients" may be individuals or organizations.\r
+\r
+ To "modify" a work means to copy from or adapt all or part of the work\r
+in a fashion requiring copyright permission, other than the making of an\r
+exact copy. The resulting work is called a "modified version" of the\r
+earlier work or a work "based on" the earlier work.\r
+\r
+ A "covered work" means either the unmodified Program or a work based\r
+on the Program.\r
+\r
+ To "propagate" a work means to do anything with it that, without\r
+permission, would make you directly or secondarily liable for\r
+infringement under applicable copyright law, except executing it on a\r
+computer or modifying a private copy. Propagation includes copying,\r
+distribution (with or without modification), making available to the\r
+public, and in some countries other activities as well.\r
+\r
+ To "convey" a work means any kind of propagation that enables other\r
+parties to make or receive copies. Mere interaction with a user through\r
+a computer network, with no transfer of a copy, is not conveying.\r
+\r
+ An interactive user interface displays "Appropriate Legal Notices"\r
+to the extent that it includes a convenient and prominently visible\r
+feature that (1) displays an appropriate copyright notice, and (2)\r
+tells the user that there is no warranty for the work (except to the\r
+extent that warranties are provided), that licensees may convey the\r
+work under this License, and how to view a copy of this License. If\r
+the interface presents a list of user commands or options, such as a\r
+menu, a prominent item in the list meets this criterion.\r
+\r
+ 1. Source Code.\r
+\r
+ The "source code" for a work means the preferred form of the work\r
+for making modifications to it. "Object code" means any non-source\r
+form of a work.\r
+\r
+ A "Standard Interface" means an interface that either is an official\r
+standard defined by a recognized standards body, or, in the case of\r
+interfaces specified for a particular programming language, one that\r
+is widely used among developers working in that language.\r
+\r
+ The "System Libraries" of an executable work include anything, other\r
+than the work as a whole, that (a) is included in the normal form of\r
+packaging a Major Component, but which is not part of that Major\r
+Component, and (b) serves only to enable use of the work with that\r
+Major Component, or to implement a Standard Interface for which an\r
+implementation is available to the public in source code form. A\r
+"Major Component", in this context, means a major essential component\r
+(kernel, window system, and so on) of the specific operating system\r
+(if any) on which the executable work runs, or a compiler used to\r
+produce the work, or an object code interpreter used to run it.\r
+\r
+ The "Corresponding Source" for a work in object code form means all\r
+the source code needed to generate, install, and (for an executable\r
+work) run the object code and to modify the work, including scripts to\r
+control those activities. However, it does not include the work's\r
+System Libraries, or general-purpose tools or generally available free\r
+programs which are used unmodified in performing those activities but\r
+which are not part of the work. For example, Corresponding Source\r
+includes interface definition files associated with source files for\r
+the work, and the source code for shared libraries and dynamically\r
+linked subprograms that the work is specifically designed to require,\r
+such as by intimate data communication or control flow between those\r
+subprograms and other parts of the work.\r
+\r
+ The Corresponding Source need not include anything that users\r
+can regenerate automatically from other parts of the Corresponding\r
+Source.\r
+\r
+ The Corresponding Source for a work in source code form is that\r
+same work.\r
+\r
+ 2. Basic Permissions.\r
+\r
+ All rights granted under this License are granted for the term of\r
+copyright on the Program, and are irrevocable provided the stated\r
+conditions are met. This License explicitly affirms your unlimited\r
+permission to run the unmodified Program. The output from running a\r
+covered work is covered by this License only if the output, given its\r
+content, constitutes a covered work. This License acknowledges your\r
+rights of fair use or other equivalent, as provided by copyright law.\r
+\r
+ You may make, run and propagate covered works that you do not\r
+convey, without conditions so long as your license otherwise remains\r
+in force. You may convey covered works to others for the sole purpose\r
+of having them make modifications exclusively for you, or provide you\r
+with facilities for running those works, provided that you comply with\r
+the terms of this License in conveying all material for which you do\r
+not control copyright. Those thus making or running the covered works\r
+for you must do so exclusively on your behalf, under your direction\r
+and control, on terms that prohibit them from making any copies of\r
+your copyrighted material outside their relationship with you.\r
+\r
+ Conveying under any other circumstances is permitted solely under\r
+the conditions stated below. Sublicensing is not allowed; section 10\r
+makes it unnecessary.\r
+\r
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.\r
+\r
+ No covered work shall be deemed part of an effective technological\r
+measure under any applicable law fulfilling obligations under article\r
+11 of the WIPO copyright treaty adopted on 20 December 1996, or\r
+similar laws prohibiting or restricting circumvention of such\r
+measures.\r
+\r
+ When you convey a covered work, you waive any legal power to forbid\r
+circumvention of technological measures to the extent such circumvention\r
+is effected by exercising rights under this License with respect to\r
+the covered work, and you disclaim any intention to limit operation or\r
+modification of the work as a means of enforcing, against the work's\r
+users, your or third parties' legal rights to forbid circumvention of\r
+technological measures.\r
+\r
+ 4. Conveying Verbatim Copies.\r
+\r
+ You may convey verbatim copies of the Program's source code as you\r
+receive it, in any medium, provided that you conspicuously and\r
+appropriately publish on each copy an appropriate copyright notice;\r
+keep intact all notices stating that this License and any\r
+non-permissive terms added in accord with section 7 apply to the code;\r
+keep intact all notices of the absence of any warranty; and give all\r
+recipients a copy of this License along with the Program.\r
+\r
+ You may charge any price or no price for each copy that you convey,\r
+and you may offer support or warranty protection for a fee.\r
+\r
+ 5. Conveying Modified Source Versions.\r
+\r
+ You may convey a work based on the Program, or the modifications to\r
+produce it from the Program, in the form of source code under the\r
+terms of section 4, provided that you also meet all of these conditions:\r
+\r
+ a) The work must carry prominent notices stating that you modified\r
+ it, and giving a relevant date.\r
+\r
+ b) The work must carry prominent notices stating that it is\r
+ released under this License and any conditions added under section\r
+ 7. This requirement modifies the requirement in section 4 to\r
+ "keep intact all notices".\r
+\r
+ c) You must license the entire work, as a whole, under this\r
+ License to anyone who comes into possession of a copy. This\r
+ License will therefore apply, along with any applicable section 7\r
+ additional terms, to the whole of the work, and all its parts,\r
+ regardless of how they are packaged. This License gives no\r
+ permission to license the work in any other way, but it does not\r
+ invalidate such permission if you have separately received it.\r
+\r
+ d) If the work has interactive user interfaces, each must display\r
+ Appropriate Legal Notices; however, if the Program has interactive\r
+ interfaces that do not display Appropriate Legal Notices, your\r
+ work need not make them do so.\r
+\r
+ A compilation of a covered work with other separate and independent\r
+works, which are not by their nature extensions of the covered work,\r
+and which are not combined with it such as to form a larger program,\r
+in or on a volume of a storage or distribution medium, is called an\r
+"aggregate" if the compilation and its resulting copyright are not\r
+used to limit the access or legal rights of the compilation's users\r
+beyond what the individual works permit. Inclusion of a covered work\r
+in an aggregate does not cause this License to apply to the other\r
+parts of the aggregate.\r
+\r
+ 6. Conveying Non-Source Forms.\r
+\r
+ You may convey a covered work in object code form under the terms\r
+of sections 4 and 5, provided that you also convey the\r
+machine-readable Corresponding Source under the terms of this License,\r
+in one of these ways:\r
+\r
+ a) Convey the object code in, or embodied in, a physical product\r
+ (including a physical distribution medium), accompanied by the\r
+ Corresponding Source fixed on a durable physical medium\r
+ customarily used for software interchange.\r
+\r
+ b) Convey the object code in, or embodied in, a physical product\r
+ (including a physical distribution medium), accompanied by a\r
+ written offer, valid for at least three years and valid for as\r
+ long as you offer spare parts or customer support for that product\r
+ model, to give anyone who possesses the object code either (1) a\r
+ copy of the Corresponding Source for all the software in the\r
+ product that is covered by this License, on a durable physical\r
+ medium customarily used for software interchange, for a price no\r
+ more than your reasonable cost of physically performing this\r
+ conveying of source, or (2) access to copy the\r
+ Corresponding Source from a network server at no charge.\r
+\r
+ c) Convey individual copies of the object code with a copy of the\r
+ written offer to provide the Corresponding Source. This\r
+ alternative is allowed only occasionally and noncommercially, and\r
+ only if you received the object code with such an offer, in accord\r
+ with subsection 6b.\r
+\r
+ d) Convey the object code by offering access from a designated\r
+ place (gratis or for a charge), and offer equivalent access to the\r
+ Corresponding Source in the same way through the same place at no\r
+ further charge. You need not require recipients to copy the\r
+ Corresponding Source along with the object code. If the place to\r
+ copy the object code is a network server, the Corresponding Source\r
+ may be on a different server (operated by you or a third party)\r
+ that supports equivalent copying facilities, provided you maintain\r
+ clear directions next to the object code saying where to find the\r
+ Corresponding Source. Regardless of what server hosts the\r
+ Corresponding Source, you remain obligated to ensure that it is\r
+ available for as long as needed to satisfy these requirements.\r
+\r
+ e) Convey the object code using peer-to-peer transmission, provided\r
+ you inform other peers where the object code and Corresponding\r
+ Source of the work are being offered to the general public at no\r
+ charge under subsection 6d.\r
+\r
+ A separable portion of the object code, whose source code is excluded\r
+from the Corresponding Source as a System Library, need not be\r
+included in conveying the object code work.\r
+\r
+ A "User Product" is either (1) a "consumer product", which means any\r
+tangible personal property which is normally used for personal, family,\r
+or household purposes, or (2) anything designed or sold for incorporation\r
+into a dwelling. In determining whether a product is a consumer product,\r
+doubtful cases shall be resolved in favor of coverage. For a particular\r
+product received by a particular user, "normally used" refers to a\r
+typical or common use of that class of product, regardless of the status\r
+of the particular user or of the way in which the particular user\r
+actually uses, or expects or is expected to use, the product. A product\r
+is a consumer product regardless of whether the product has substantial\r
+commercial, industrial or non-consumer uses, unless such uses represent\r
+the only significant mode of use of the product.\r
+\r
+ "Installation Information" for a User Product means any methods,\r
+procedures, authorization keys, or other information required to install\r
+and execute modified versions of a covered work in that User Product from\r
+a modified version of its Corresponding Source. The information must\r
+suffice to ensure that the continued functioning of the modified object\r
+code is in no case prevented or interfered with solely because\r
+modification has been made.\r
+\r
+ If you convey an object code work under this section in, or with, or\r
+specifically for use in, a User Product, and the conveying occurs as\r
+part of a transaction in which the right of possession and use of the\r
+User Product is transferred to the recipient in perpetuity or for a\r
+fixed term (regardless of how the transaction is characterized), the\r
+Corresponding Source conveyed under this section must be accompanied\r
+by the Installation Information. But this requirement does not apply\r
+if neither you nor any third party retains the ability to install\r
+modified object code on the User Product (for example, the work has\r
+been installed in ROM).\r
+\r
+ The requirement to provide Installation Information does not include a\r
+requirement to continue to provide support service, warranty, or updates\r
+for a work that has been modified or installed by the recipient, or for\r
+the User Product in which it has been modified or installed. Access to a\r
+network may be denied when the modification itself materially and\r
+adversely affects the operation of the network or violates the rules and\r
+protocols for communication across the network.\r
+\r
+ Corresponding Source conveyed, and Installation Information provided,\r
+in accord with this section must be in a format that is publicly\r
+documented (and with an implementation available to the public in\r
+source code form), and must require no special password or key for\r
+unpacking, reading or copying.\r
+\r
+ 7. Additional Terms.\r
+\r
+ "Additional permissions" are terms that supplement the terms of this\r
+License by making exceptions from one or more of its conditions.\r
+Additional permissions that are applicable to the entire Program shall\r
+be treated as though they were included in this License, to the extent\r
+that they are valid under applicable law. If additional permissions\r
+apply only to part of the Program, that part may be used separately\r
+under those permissions, but the entire Program remains governed by\r
+this License without regard to the additional permissions.\r
+\r
+ When you convey a copy of a covered work, you may at your option\r
+remove any additional permissions from that copy, or from any part of\r
+it. (Additional permissions may be written to require their own\r
+removal in certain cases when you modify the work.) You may place\r
+additional permissions on material, added by you to a covered work,\r
+for which you have or can give appropriate copyright permission.\r
+\r
+ Notwithstanding any other provision of this License, for material you\r
+add to a covered work, you may (if authorized by the copyright holders of\r
+that material) supplement the terms of this License with terms:\r
+\r
+ a) Disclaiming warranty or limiting liability differently from the\r
+ terms of sections 15 and 16 of this License; or\r
+\r
+ b) Requiring preservation of specified reasonable legal notices or\r
+ author attributions in that material or in the Appropriate Legal\r
+ Notices displayed by works containing it; or\r
+\r
+ c) Prohibiting misrepresentation of the origin of that material, or\r
+ requiring that modified versions of such material be marked in\r
+ reasonable ways as different from the original version; or\r
+\r
+ d) Limiting the use for publicity purposes of names of licensors or\r
+ authors of the material; or\r
+\r
+ e) Declining to grant rights under trademark law for use of some\r
+ trade names, trademarks, or service marks; or\r
+\r
+ f) Requiring indemnification of licensors and authors of that\r
+ material by anyone who conveys the material (or modified versions of\r
+ it) with contractual assumptions of liability to the recipient, for\r
+ any liability that these contractual assumptions directly impose on\r
+ those licensors and authors.\r
+\r
+ All other non-permissive additional terms are considered "further\r
+restrictions" within the meaning of section 10. If the Program as you\r
+received it, or any part of it, contains a notice stating that it is\r
+governed by this License along with a term that is a further\r
+restriction, you may remove that term. If a license document contains\r
+a further restriction but permits relicensing or conveying under this\r
+License, you may add to a covered work material governed by the terms\r
+of that license document, provided that the further restriction does\r
+not survive such relicensing or conveying.\r
+\r
+ If you add terms to a covered work in accord with this section, you\r
+must place, in the relevant source files, a statement of the\r
+additional terms that apply to those files, or a notice indicating\r
+where to find the applicable terms.\r
+\r
+ Additional terms, permissive or non-permissive, may be stated in the\r
+form of a separately written license, or stated as exceptions;\r
+the above requirements apply either way.\r
+\r
+ 8. Termination.\r
+\r
+ You may not propagate or modify a covered work except as expressly\r
+provided under this License. Any attempt otherwise to propagate or\r
+modify it is void, and will automatically terminate your rights under\r
+this License (including any patent licenses granted under the third\r
+paragraph of section 11).\r
+\r
+ However, if you cease all violation of this License, then your\r
+license from a particular copyright holder is reinstated (a)\r
+provisionally, unless and until the copyright holder explicitly and\r
+finally terminates your license, and (b) permanently, if the copyright\r
+holder fails to notify you of the violation by some reasonable means\r
+prior to 60 days after the cessation.\r
+\r
+ Moreover, your license from a particular copyright holder is\r
+reinstated permanently if the copyright holder notifies you of the\r
+violation by some reasonable means, this is the first time you have\r
+received notice of violation of this License (for any work) from that\r
+copyright holder, and you cure the violation prior to 30 days after\r
+your receipt of the notice.\r
+\r
+ Termination of your rights under this section does not terminate the\r
+licenses of parties who have received copies or rights from you under\r
+this License. If your rights have been terminated and not permanently\r
+reinstated, you do not qualify to receive new licenses for the same\r
+material under section 10.\r
+\r
+ 9. Acceptance Not Required for Having Copies.\r
+\r
+ You are not required to accept this License in order to receive or\r
+run a copy of the Program. Ancillary propagation of a covered work\r
+occurring solely as a consequence of using peer-to-peer transmission\r
+to receive a copy likewise does not require acceptance. However,\r
+nothing other than this License grants you permission to propagate or\r
+modify any covered work. These actions infringe copyright if you do\r
+not accept this License. Therefore, by modifying or propagating a\r
+covered work, you indicate your acceptance of this License to do so.\r
+\r
+ 10. Automatic Licensing of Downstream Recipients.\r
+\r
+ Each time you convey a covered work, the recipient automatically\r
+receives a license from the original licensors, to run, modify and\r
+propagate that work, subject to this License. You are not responsible\r
+for enforcing compliance by third parties with this License.\r
+\r
+ An "entity transaction" is a transaction transferring control of an\r
+organization, or substantially all assets of one, or subdividing an\r
+organization, or merging organizations. If propagation of a covered\r
+work results from an entity transaction, each party to that\r
+transaction who receives a copy of the work also receives whatever\r
+licenses to the work the party's predecessor in interest had or could\r
+give under the previous paragraph, plus a right to possession of the\r
+Corresponding Source of the work from the predecessor in interest, if\r
+the predecessor has it or can get it with reasonable efforts.\r
+\r
+ You may not impose any further restrictions on the exercise of the\r
+rights granted or affirmed under this License. For example, you may\r
+not impose a license fee, royalty, or other charge for exercise of\r
+rights granted under this License, and you may not initiate litigation\r
+(including a cross-claim or counterclaim in a lawsuit) alleging that\r
+any patent claim is infringed by making, using, selling, offering for\r
+sale, or importing the Program or any portion of it.\r
+\r
+ 11. Patents.\r
+\r
+ A "contributor" is a copyright holder who authorizes use under this\r
+License of the Program or a work on which the Program is based. The\r
+work thus licensed is called the contributor's "contributor version".\r
+\r
+ A contributor's "essential patent claims" are all patent claims\r
+owned or controlled by the contributor, whether already acquired or\r
+hereafter acquired, that would be infringed by some manner, permitted\r
+by this License, of making, using, or selling its contributor version,\r
+but do not include claims that would be infringed only as a\r
+consequence of further modification of the contributor version. For\r
+purposes of this definition, "control" includes the right to grant\r
+patent sublicenses in a manner consistent with the requirements of\r
+this License.\r
+\r
+ Each contributor grants you a non-exclusive, worldwide, royalty-free\r
+patent license under the contributor's essential patent claims, to\r
+make, use, sell, offer for sale, import and otherwise run, modify and\r
+propagate the contents of its contributor version.\r
+\r
+ In the following three paragraphs, a "patent license" is any express\r
+agreement or commitment, however denominated, not to enforce a patent\r
+(such as an express permission to practice a patent or covenant not to\r
+sue for patent infringement). To "grant" such a patent license to a\r
+party means to make such an agreement or commitment not to enforce a\r
+patent against the party.\r
+\r
+ If you convey a covered work, knowingly relying on a patent license,\r
+and the Corresponding Source of the work is not available for anyone\r
+to copy, free of charge and under the terms of this License, through a\r
+publicly available network server or other readily accessible means,\r
+then you must either (1) cause the Corresponding Source to be so\r
+available, or (2) arrange to deprive yourself of the benefit of the\r
+patent license for this particular work, or (3) arrange, in a manner\r
+consistent with the requirements of this License, to extend the patent\r
+license to downstream recipients. "Knowingly relying" means you have\r
+actual knowledge that, but for the patent license, your conveying the\r
+covered work in a country, or your recipient's use of the covered work\r
+in a country, would infringe one or more identifiable patents in that\r
+country that you have reason to believe are valid.\r
+\r
+ If, pursuant to or in connection with a single transaction or\r
+arrangement, you convey, or propagate by procuring conveyance of, a\r
+covered work, and grant a patent license to some of the parties\r
+receiving the covered work authorizing them to use, propagate, modify\r
+or convey a specific copy of the covered work, then the patent license\r
+you grant is automatically extended to all recipients of the covered\r
+work and works based on it.\r
+\r
+ A patent license is "discriminatory" if it does not include within\r
+the scope of its coverage, prohibits the exercise of, or is\r
+conditioned on the non-exercise of one or more of the rights that are\r
+specifically granted under this License. You may not convey a covered\r
+work if you are a party to an arrangement with a third party that is\r
+in the business of distributing software, under which you make payment\r
+to the third party based on the extent of your activity of conveying\r
+the work, and under which the third party grants, to any of the\r
+parties who would receive the covered work from you, a discriminatory\r
+patent license (a) in connection with copies of the covered work\r
+conveyed by you (or copies made from those copies), or (b) primarily\r
+for and in connection with specific products or compilations that\r
+contain the covered work, unless you entered into that arrangement,\r
+or that patent license was granted, prior to 28 March 2007.\r
+\r
+ Nothing in this License shall be construed as excluding or limiting\r
+any implied license or other defenses to infringement that may\r
+otherwise be available to you under applicable patent law.\r
+\r
+ 12. No Surrender of Others' Freedom.\r
+\r
+ If conditions are imposed on you (whether by court order, agreement or\r
+otherwise) that contradict the conditions of this License, they do not\r
+excuse you from the conditions of this License. If you cannot convey a\r
+covered work so as to satisfy simultaneously your obligations under this\r
+License and any other pertinent obligations, then as a consequence you may\r
+not convey it at all. For example, if you agree to terms that obligate you\r
+to collect a royalty for further conveying from those to whom you convey\r
+the Program, the only way you could satisfy both those terms and this\r
+License would be to refrain entirely from conveying the Program.\r
+\r
+ 13. Use with the GNU Affero General Public License.\r
+\r
+ Notwithstanding any other provision of this License, you have\r
+permission to link or combine any covered work with a work licensed\r
+under version 3 of the GNU Affero General Public License into a single\r
+combined work, and to convey the resulting work. The terms of this\r
+License will continue to apply to the part which is the covered work,\r
+but the special requirements of the GNU Affero General Public License,\r
+section 13, concerning interaction through a network will apply to the\r
+combination as such.\r
+\r
+ 14. Revised Versions of this License.\r
+\r
+ The Free Software Foundation may publish revised and/or new versions of\r
+the GNU General Public License from time to time. Such new versions will\r
+be similar in spirit to the present version, but may differ in detail to\r
+address new problems or concerns.\r
+\r
+ Each version is given a distinguishing version number. If the\r
+Program specifies that a certain numbered version of the GNU General\r
+Public License "or any later version" applies to it, you have the\r
+option of following the terms and conditions either of that numbered\r
+version or of any later version published by the Free Software\r
+Foundation. If the Program does not specify a version number of the\r
+GNU General Public License, you may choose any version ever published\r
+by the Free Software Foundation.\r
+\r
+ If the Program specifies that a proxy can decide which future\r
+versions of the GNU General Public License can be used, that proxy's\r
+public statement of acceptance of a version permanently authorizes you\r
+to choose that version for the Program.\r
+\r
+ Later license versions may give you additional or different\r
+permissions. However, no additional obligations are imposed on any\r
+author or copyright holder as a result of your choosing to follow a\r
+later version.\r
+\r
+ 15. Disclaimer of Warranty.\r
+\r
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\r
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\r
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY\r
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\r
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\r
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\r
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\r
+\r
+ 16. Limitation of Liability.\r
+\r
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\r
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\r
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\r
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\r
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\r
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\r
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\r
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\r
+SUCH DAMAGES.\r
+\r
+ 17. Interpretation of Sections 15 and 16.\r
+\r
+ If the disclaimer of warranty and limitation of liability provided\r
+above cannot be given local legal effect according to their terms,\r
+reviewing courts shall apply local law that most closely approximates\r
+an absolute waiver of all civil liability in connection with the\r
+Program, unless a warranty or assumption of liability accompanies a\r
+copy of the Program in return for a fee.\r
+\r
+ END OF TERMS AND CONDITIONS\r
+\r
+ How to Apply These Terms to Your New Programs\r
+\r
+ If you develop a new program, and you want it to be of the greatest\r
+possible use to the public, the best way to achieve this is to make it\r
+free software which everyone can redistribute and change under these terms.\r
+\r
+ To do so, attach the following notices to the program. It is safest\r
+to attach them to the start of each source file to most effectively\r
+state the exclusion of warranty; and each file should have at least\r
+the "copyright" line and a pointer to where the full notice is found.\r
+\r
+ <one line to give the program's name and a brief idea of what it does.>\r
+ Copyright (C) <year> <name of author>\r
+\r
+ This program is free software: you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation, either version 3 of the License, or\r
+ (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program. If not, see <https://www.gnu.org/licenses/>.\r
+\r
+Also add information on how to contact you by electronic and paper mail.\r
+\r
+ If the program does terminal interaction, make it output a short\r
+notice like this when it starts in an interactive mode:\r
+\r
+ <program> Copyright (C) <year> <name of author>\r
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\r
+ This is free software, and you are welcome to redistribute it\r
+ under certain conditions; type `show c' for details.\r
+\r
+The hypothetical commands `show w' and `show c' should show the appropriate\r
+parts of the General Public License. Of course, your program's commands\r
+might be different; for a GUI interface, you would use an "about box".\r
+\r
+ You should also get your employer (if you work as a programmer) or school,\r
+if any, to sign a "copyright disclaimer" for the program, if necessary.\r
+For more information on this, and how to apply and follow the GNU GPL, see\r
+<https://www.gnu.org/licenses/>.\r
+\r
+ The GNU General Public License does not permit incorporating your program\r
+into proprietary programs. If your program is a subroutine library, you\r
+may consider it more useful to permit linking proprietary applications with\r
+the library. If this is what you want to do, use the GNU Lesser General\r
+Public License instead of this License. But first, please read\r
+<https://www.gnu.org/licenses/why-not-lgpl.html>.
\ No newline at end of file
--- /dev/null
+CC=gcc
+CFLAGS=-O2 --machine-arch=native -pipe -Wall
+LIBS=
+
+# https://github.com/adamretter/utf8-validator-c
+CFLAGS+=-Isimdutf8check/
+
+all: utf8filenamecheck.c
+ $(CC) $(CFLAGS) -o bin/utf8filenamecheck utf8filenamecheck.c $(LIBS)
\ No newline at end of file
--- /dev/null
+# Klimbim Software collection, A bag full of things
+# Copyright (C) 2011-2023 Johannes 'Banana' Keßler
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# utf8filenamecheck
+Small windows C tool to check if paths in a folder are utf-8 formatted
\ No newline at end of file
--- /dev/null
+https://github.com/adamretter/utf8-validator-c
\ No newline at end of file
--- /dev/null
+#ifndef SIMDUTF8CHECK_H
+#define SIMDUTF8CHECK_H
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <x86intrin.h>
+/*
+ * legal utf-8 byte sequence
+ * http://www.unicode.org/versions/Unicode6.0.0/ch03.pdf - page 94
+ *
+ * Code Points 1st 2s 3s 4s
+ * U+0000..U+007F 00..7F
+ * U+0080..U+07FF C2..DF 80..BF
+ * U+0800..U+0FFF E0 A0..BF 80..BF
+ * U+1000..U+CFFF E1..EC 80..BF 80..BF
+ * U+D000..U+D7FF ED 80..9F 80..BF
+ * U+E000..U+FFFF EE..EF 80..BF 80..BF
+ * U+10000..U+3FFFF F0 90..BF 80..BF 80..BF
+ * U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF
+ * U+100000..U+10FFFF F4 80..8F 80..BF 80..BF
+ *
+ */
+
+// all byte values must be no larger than 0xF4
+static inline void checkSmallerThan0xF4(__m128i current_bytes,
+ __m128i *has_error) {
+ // unsigned, saturates to 0 below max
+ *has_error = _mm_or_si128(*has_error,
+ _mm_subs_epu8(current_bytes, _mm_set1_epi8(0xF4)));
+}
+
+static inline __m128i continuationLengths(__m128i high_nibbles) {
+ return _mm_shuffle_epi8(
+ _mm_setr_epi8(1, 1, 1, 1, 1, 1, 1, 1, // 0xxx (ASCII)
+ 0, 0, 0, 0, // 10xx (continuation)
+ 2, 2, // 110x
+ 3, // 1110
+ 4), // 1111, next should be 0 (not checked here)
+ high_nibbles);
+}
+
+static inline __m128i carryContinuations(__m128i initial_lengths,
+ __m128i previous_carries) {
+
+ __m128i right1 =
+ _mm_subs_epu8(_mm_alignr_epi8(initial_lengths, previous_carries, 16 - 1),
+ _mm_set1_epi8(1));
+ __m128i sum = _mm_add_epi8(initial_lengths, right1);
+
+ __m128i right2 = _mm_subs_epu8(_mm_alignr_epi8(sum, previous_carries, 16 - 2),
+ _mm_set1_epi8(2));
+ return _mm_add_epi8(sum, right2);
+}
+
+static inline void checkContinuations(__m128i initial_lengths, __m128i carries,
+ __m128i *has_error) {
+
+ // overlap || underlap
+ // carry > length && length > 0 || !(carry > length) && !(length > 0)
+ // (carries > length) == (lengths > 0)
+ __m128i overunder =
+ _mm_cmpeq_epi8(_mm_cmpgt_epi8(carries, initial_lengths),
+ _mm_cmpgt_epi8(initial_lengths, _mm_setzero_si128()));
+
+ *has_error = _mm_or_si128(*has_error, overunder);
+}
+
+// when 0xED is found, next byte must be no larger than 0x9F
+// when 0xF4 is found, next byte must be no larger than 0x8F
+// next byte must be continuation, ie sign bit is set, so signed < is ok
+static inline void checkFirstContinuationMax(__m128i current_bytes,
+ __m128i off1_current_bytes,
+ __m128i *has_error) {
+ __m128i maskED = _mm_cmpeq_epi8(off1_current_bytes, _mm_set1_epi8(0xED));
+ __m128i maskF4 = _mm_cmpeq_epi8(off1_current_bytes, _mm_set1_epi8(0xF4));
+
+ __m128i badfollowED =
+ _mm_and_si128(_mm_cmpgt_epi8(current_bytes, _mm_set1_epi8(0x9F)), maskED);
+ __m128i badfollowF4 =
+ _mm_and_si128(_mm_cmpgt_epi8(current_bytes, _mm_set1_epi8(0x8F)), maskF4);
+
+ *has_error = _mm_or_si128(*has_error, _mm_or_si128(badfollowED, badfollowF4));
+}
+
+// map off1_hibits => error condition
+// hibits off1 cur
+// C => < C2 && true
+// E => < E1 && < A0
+// F => < F1 && < 90
+// else false && false
+static inline void checkOverlong(__m128i current_bytes,
+ __m128i off1_current_bytes, __m128i hibits,
+ __m128i previous_hibits, __m128i *has_error) {
+ __m128i off1_hibits = _mm_alignr_epi8(hibits, previous_hibits, 16 - 1);
+ __m128i initial_mins = _mm_shuffle_epi8(
+ _mm_setr_epi8(-128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
+ -128, -128, // 10xx => false
+ 0xC2, -128, // 110x
+ 0xE1, // 1110
+ 0xF1),
+ off1_hibits);
+
+ __m128i initial_under = _mm_cmpgt_epi8(initial_mins, off1_current_bytes);
+
+ __m128i second_mins = _mm_shuffle_epi8(
+ _mm_setr_epi8(-128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
+ -128, -128, // 10xx => false
+ 127, 127, // 110x => true
+ 0xA0, // 1110
+ 0x90),
+ off1_hibits);
+ __m128i second_under = _mm_cmpgt_epi8(second_mins, current_bytes);
+ *has_error =
+ _mm_or_si128(*has_error, _mm_and_si128(initial_under, second_under));
+}
+
+struct processed_utf_bytes {
+ __m128i rawbytes;
+ __m128i high_nibbles;
+ __m128i carried_continuations;
+};
+
+static inline void count_nibbles(__m128i bytes,
+ struct processed_utf_bytes *answer) {
+ answer->rawbytes = bytes;
+ answer->high_nibbles =
+ _mm_and_si128(_mm_srli_epi16(bytes, 4), _mm_set1_epi8(0x0F));
+}
+
+// check whether the current bytes are valid UTF-8
+// at the end of the function, previous gets updated
+static struct processed_utf_bytes
+checkUTF8Bytes(__m128i current_bytes, struct processed_utf_bytes *previous,
+ __m128i *has_error) {
+ struct processed_utf_bytes pb;
+ count_nibbles(current_bytes, &pb);
+
+ checkSmallerThan0xF4(current_bytes, has_error);
+
+ __m128i initial_lengths = continuationLengths(pb.high_nibbles);
+
+ pb.carried_continuations =
+ carryContinuations(initial_lengths, previous->carried_continuations);
+
+ checkContinuations(initial_lengths, pb.carried_continuations, has_error);
+
+ __m128i off1_current_bytes =
+ _mm_alignr_epi8(pb.rawbytes, previous->rawbytes, 16 - 1);
+ checkFirstContinuationMax(current_bytes, off1_current_bytes, has_error);
+
+ checkOverlong(current_bytes, off1_current_bytes, pb.high_nibbles,
+ previous->high_nibbles, has_error);
+ return pb;
+}
+
+static bool validate_utf8_fast(const char *src, size_t len) {
+ size_t i = 0;
+ __m128i has_error = _mm_setzero_si128();
+ struct processed_utf_bytes previous = {.rawbytes = _mm_setzero_si128(),
+ .high_nibbles = _mm_setzero_si128(),
+ .carried_continuations =
+ _mm_setzero_si128()};
+ if (len >= 16) {
+ for (; i <= len - 16; i += 16) {
+ __m128i current_bytes = _mm_loadu_si128((const __m128i *)(src + i));
+ previous = checkUTF8Bytes(current_bytes, &previous, &has_error);
+ }
+ }
+
+ // last part
+ if (i < len) {
+ char buffer[16];
+ memset(buffer, 0, 16);
+ memcpy(buffer, src + i, len - i);
+ __m128i current_bytes = _mm_loadu_si128((const __m128i *)(buffer));
+ previous = checkUTF8Bytes(current_bytes, &previous, &has_error);
+ } else {
+ has_error =
+ _mm_or_si128(_mm_cmpgt_epi8(previous.carried_continuations,
+ _mm_setr_epi8(9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 1)),
+ has_error);
+ }
+
+ return _mm_testz_si128(has_error, has_error);
+}
+
+#ifdef __AVX2__
+
+/*****************************/
+static inline __m256i push_last_byte_of_a_to_b(__m256i a, __m256i b) {
+ return _mm256_alignr_epi8(b, _mm256_permute2x128_si256(a, b, 0x21), 15);
+}
+
+static inline __m256i push_last_2bytes_of_a_to_b(__m256i a, __m256i b) {
+ return _mm256_alignr_epi8(b, _mm256_permute2x128_si256(a, b, 0x21), 14);
+}
+
+// all byte values must be no larger than 0xF4
+static inline void avxcheckSmallerThan0xF4(__m256i current_bytes,
+ __m256i *has_error) {
+ // unsigned, saturates to 0 below max
+ *has_error = _mm256_or_si256(
+ *has_error, _mm256_subs_epu8(current_bytes, _mm256_set1_epi8(0xF4)));
+}
+
+static inline __m256i avxcontinuationLengths(__m256i high_nibbles) {
+ return _mm256_shuffle_epi8(
+ _mm256_setr_epi8(1, 1, 1, 1, 1, 1, 1, 1, // 0xxx (ASCII)
+ 0, 0, 0, 0, // 10xx (continuation)
+ 2, 2, // 110x
+ 3, // 1110
+ 4, // 1111, next should be 0 (not checked here)
+ 1, 1, 1, 1, 1, 1, 1, 1, // 0xxx (ASCII)
+ 0, 0, 0, 0, // 10xx (continuation)
+ 2, 2, // 110x
+ 3, // 1110
+ 4 // 1111, next should be 0 (not checked here)
+ ),
+ high_nibbles);
+}
+
+static inline __m256i avxcarryContinuations(__m256i initial_lengths,
+ __m256i previous_carries) {
+
+ __m256i right1 = _mm256_subs_epu8(
+ push_last_byte_of_a_to_b(previous_carries, initial_lengths),
+ _mm256_set1_epi8(1));
+ __m256i sum = _mm256_add_epi8(initial_lengths, right1);
+
+ __m256i right2 = _mm256_subs_epu8(
+ push_last_2bytes_of_a_to_b(previous_carries, sum), _mm256_set1_epi8(2));
+ return _mm256_add_epi8(sum, right2);
+}
+
+static inline void avxcheckContinuations(__m256i initial_lengths,
+ __m256i carries, __m256i *has_error) {
+
+ // overlap || underlap
+ // carry > length && length > 0 || !(carry > length) && !(length > 0)
+ // (carries > length) == (lengths > 0)
+ __m256i overunder = _mm256_cmpeq_epi8(
+ _mm256_cmpgt_epi8(carries, initial_lengths),
+ _mm256_cmpgt_epi8(initial_lengths, _mm256_setzero_si256()));
+
+ *has_error = _mm256_or_si256(*has_error, overunder);
+}
+
+// when 0xED is found, next byte must be no larger than 0x9F
+// when 0xF4 is found, next byte must be no larger than 0x8F
+// next byte must be continuation, ie sign bit is set, so signed < is ok
+static inline void avxcheckFirstContinuationMax(__m256i current_bytes,
+ __m256i off1_current_bytes,
+ __m256i *has_error) {
+ __m256i maskED =
+ _mm256_cmpeq_epi8(off1_current_bytes, _mm256_set1_epi8(0xED));
+ __m256i maskF4 =
+ _mm256_cmpeq_epi8(off1_current_bytes, _mm256_set1_epi8(0xF4));
+
+ __m256i badfollowED = _mm256_and_si256(
+ _mm256_cmpgt_epi8(current_bytes, _mm256_set1_epi8(0x9F)), maskED);
+ __m256i badfollowF4 = _mm256_and_si256(
+ _mm256_cmpgt_epi8(current_bytes, _mm256_set1_epi8(0x8F)), maskF4);
+
+ *has_error =
+ _mm256_or_si256(*has_error, _mm256_or_si256(badfollowED, badfollowF4));
+}
+
+// map off1_hibits => error condition
+// hibits off1 cur
+// C => < C2 && true
+// E => < E1 && < A0
+// F => < F1 && < 90
+// else false && false
+static inline void avxcheckOverlong(__m256i current_bytes,
+ __m256i off1_current_bytes, __m256i hibits,
+ __m256i previous_hibits,
+ __m256i *has_error) {
+ __m256i off1_hibits = push_last_byte_of_a_to_b(previous_hibits, hibits);
+ __m256i initial_mins = _mm256_shuffle_epi8(
+ _mm256_setr_epi8(-128, -128, -128, -128, -128, -128, -128, -128, -128,
+ -128, -128, -128, // 10xx => false
+ 0xC2, -128, // 110x
+ 0xE1, // 1110
+ 0xF1, -128, -128, -128, -128, -128, -128, -128, -128,
+ -128, -128, -128, -128, // 10xx => false
+ 0xC2, -128, // 110x
+ 0xE1, // 1110
+ 0xF1),
+ off1_hibits);
+
+ __m256i initial_under = _mm256_cmpgt_epi8(initial_mins, off1_current_bytes);
+
+ __m256i second_mins = _mm256_shuffle_epi8(
+ _mm256_setr_epi8(-128, -128, -128, -128, -128, -128, -128, -128, -128,
+ -128, -128, -128, // 10xx => false
+ 127, 127, // 110x => true
+ 0xA0, // 1110
+ 0x90, -128, -128, -128, -128, -128, -128, -128, -128,
+ -128, -128, -128, -128, // 10xx => false
+ 127, 127, // 110x => true
+ 0xA0, // 1110
+ 0x90),
+ off1_hibits);
+ __m256i second_under = _mm256_cmpgt_epi8(second_mins, current_bytes);
+ *has_error = _mm256_or_si256(*has_error,
+ _mm256_and_si256(initial_under, second_under));
+}
+
+struct avx_processed_utf_bytes {
+ __m256i rawbytes;
+ __m256i high_nibbles;
+ __m256i carried_continuations;
+};
+
+static inline void avx_count_nibbles(__m256i bytes,
+ struct avx_processed_utf_bytes *answer) {
+ answer->rawbytes = bytes;
+ answer->high_nibbles =
+ _mm256_and_si256(_mm256_srli_epi16(bytes, 4), _mm256_set1_epi8(0x0F));
+}
+
+// check whether the current bytes are valid UTF-8
+// at the end of the function, previous gets updated
+static struct avx_processed_utf_bytes
+avxcheckUTF8Bytes(__m256i current_bytes,
+ struct avx_processed_utf_bytes *previous,
+ __m256i *has_error) {
+ struct avx_processed_utf_bytes pb;
+ avx_count_nibbles(current_bytes, &pb);
+
+ avxcheckSmallerThan0xF4(current_bytes, has_error);
+
+ __m256i initial_lengths = avxcontinuationLengths(pb.high_nibbles);
+
+ pb.carried_continuations =
+ avxcarryContinuations(initial_lengths, previous->carried_continuations);
+
+ avxcheckContinuations(initial_lengths, pb.carried_continuations, has_error);
+
+ __m256i off1_current_bytes =
+ push_last_byte_of_a_to_b(previous->rawbytes, pb.rawbytes);
+ avxcheckFirstContinuationMax(current_bytes, off1_current_bytes, has_error);
+
+ avxcheckOverlong(current_bytes, off1_current_bytes, pb.high_nibbles,
+ previous->high_nibbles, has_error);
+ return pb;
+}
+
+// check whether the current bytes are valid UTF-8
+// at the end of the function, previous gets updated
+static struct avx_processed_utf_bytes
+avxcheckUTF8Bytes_asciipath(__m256i current_bytes,
+ struct avx_processed_utf_bytes *previous,
+ __m256i *has_error) {
+ if (_mm256_testz_si256(current_bytes,
+ _mm256_set1_epi8(0x80))) { // fast ascii path
+ *has_error = _mm256_or_si256(
+ _mm256_cmpgt_epi8(previous->carried_continuations,
+ _mm256_setr_epi8(9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 1)),
+ *has_error);
+ return *previous;
+ }
+
+ struct avx_processed_utf_bytes pb;
+ avx_count_nibbles(current_bytes, &pb);
+
+ avxcheckSmallerThan0xF4(current_bytes, has_error);
+
+ __m256i initial_lengths = avxcontinuationLengths(pb.high_nibbles);
+
+ pb.carried_continuations =
+ avxcarryContinuations(initial_lengths, previous->carried_continuations);
+
+ avxcheckContinuations(initial_lengths, pb.carried_continuations, has_error);
+
+ __m256i off1_current_bytes =
+ push_last_byte_of_a_to_b(previous->rawbytes, pb.rawbytes);
+ avxcheckFirstContinuationMax(current_bytes, off1_current_bytes, has_error);
+
+ avxcheckOverlong(current_bytes, off1_current_bytes, pb.high_nibbles,
+ previous->high_nibbles, has_error);
+ return pb;
+}
+
+static bool validate_utf8_fast_avx_asciipath(const char *src, size_t len) {
+ size_t i = 0;
+ __m256i has_error = _mm256_setzero_si256();
+ struct avx_processed_utf_bytes previous = {
+ .rawbytes = _mm256_setzero_si256(),
+ .high_nibbles = _mm256_setzero_si256(),
+ .carried_continuations = _mm256_setzero_si256()};
+ if (len >= 32) {
+ for (; i <= len - 32; i += 32) {
+ __m256i current_bytes = _mm256_loadu_si256((const __m256i *)(src + i));
+ previous =
+ avxcheckUTF8Bytes_asciipath(current_bytes, &previous, &has_error);
+ }
+ }
+
+ // last part
+ if (i < len) {
+ char buffer[32];
+ memset(buffer, 0, 32);
+ memcpy(buffer, src + i, len - i);
+ __m256i current_bytes = _mm256_loadu_si256((const __m256i *)(buffer));
+ previous = avxcheckUTF8Bytes(current_bytes, &previous, &has_error);
+ } else {
+ has_error = _mm256_or_si256(
+ _mm256_cmpgt_epi8(previous.carried_continuations,
+ _mm256_setr_epi8(9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 1)),
+ has_error);
+ }
+
+ return _mm256_testz_si256(has_error, has_error);
+}
+
+static bool validate_utf8_fast_avx(const char *src, size_t len) {
+ size_t i = 0;
+ __m256i has_error = _mm256_setzero_si256();
+ struct avx_processed_utf_bytes previous = {
+ .rawbytes = _mm256_setzero_si256(),
+ .high_nibbles = _mm256_setzero_si256(),
+ .carried_continuations = _mm256_setzero_si256()};
+ if (len >= 32) {
+ for (; i <= len - 32; i += 32) {
+ __m256i current_bytes = _mm256_loadu_si256((const __m256i *)(src + i));
+ previous = avxcheckUTF8Bytes(current_bytes, &previous, &has_error);
+ }
+ }
+
+ // last part
+ if (i < len) {
+ char buffer[32];
+ memset(buffer, 0, 32);
+ memcpy(buffer, src + i, len - i);
+ __m256i current_bytes = _mm256_loadu_si256((const __m256i *)(buffer));
+ previous = avxcheckUTF8Bytes(current_bytes, &previous, &has_error);
+ } else {
+ has_error = _mm256_or_si256(
+ _mm256_cmpgt_epi8(previous.carried_continuations,
+ _mm256_setr_epi8(9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 1)),
+ has_error);
+ }
+
+ return _mm256_testz_si256(has_error, has_error);
+}
+
+#endif // __AVX2__
+#endif
--- /dev/null
+/**
+ * utf8filenamecheck Check if all the filenames in a fiven folder are UTF-8
+ * Copyright (C) 2023 Johannes 'Banana' Keßler
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+/**
+ * 2023 Small linux C tool to check if paths in a folder are utf-8 formatted
+ * Linux version
+ */
+// https://linux.die.net/man/3/nftw
+#define _XOPEN_SOURCE 500
+#include <ftw.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <argp.h>
+
+// https://github.com/simdutf/simdutf
+#include <simdutf8check.h>
+
+/**
+ * Commandline arguments
+ * see: https://www.gnu.org/software/libc/manual/html_node/Argp-Example-3.html#Argp-Example-3
+ */
+const char *argp_program_version = "1.0";
+const char *argp_program_bug_address = "https://www.bananas-playground.net/";
+static char doc[] = "utf8filenamecheck. Small linux C tool to check if paths in a folder are utf-8 formatted.";
+static char args_doc[] = "folder";
+
+/* The options we understand. */
+static struct argp_option options[] = {
+ {"verbose",'v', 0, 0, "Produce verbose output" },
+ {"quiet",'q', 0, 0, "Produce verbose output" },
+ { 0 }
+};
+
+struct cmdArguments {
+ char *args[1];
+ int verbose, quiet;
+};
+
+/* Parse a single option. */
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state) {
+ struct cmdArguments *arguments = state->input;
+
+ switch (key) {
+ case 'v':
+ arguments->verbose = 1;
+ break;
+ case 'q':
+ arguments->quiet = 1;
+ break;
+
+ case ARGP_KEY_ARG:
+ if (state->arg_num >= 1)
+ // Too many arguments.
+ argp_usage (state);
+
+ arguments->args[state->arg_num] = arg;
+ break;
+
+ case ARGP_KEY_END:
+ if (state->arg_num < 1)
+ /* Not enough arguments. */
+ argp_usage (state);
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ return 0;
+}
+
+static struct argp argp = { options, parse_opt, args_doc, doc };
+struct cmdArguments arguments;
+
+/**
+ * the callback function for nftw
+ * https://linux.die.net/man/3/nftw
+ */
+static int nftw_callback(const char *fpath,
+ const struct stat *sb,
+ int tflag,
+ struct FTW *ftwbuf) {
+ if (strcmp(fpath, ".") == 0 || strcmp(fpath, "..") == 0) {
+ return 0;
+ }
+
+ if(tflag == FTW_DNR) {
+ if(!arguments.quiet) printf("Can not read %s", fpath);
+ }
+
+ bool result = validate_utf8_fast(fpath, strlen(fpath));
+ if(result) {
+ if(!arguments.quiet) printf("%s OK \n", fpath);
+ } else {
+ printf("%s FAILED \n", fpath);
+ }
+
+ // continue
+ return 0;
+}
+
+/**
+ * main routine
+ */
+int main(int argc, char *argv[]) {
+
+ /**
+ * command line argument parsing and default values
+ */
+ arguments.verbose = 0;
+ arguments.quiet = 0;
+
+ argp_parse (&argp, argc, argv, 0, 0, &arguments);
+
+ if(arguments.verbose) {
+ printf ("Folder = %s\n"
+ "Verbose = %s\n"
+ "Quiet = %s\n",
+ arguments.args[0],
+ arguments.verbose ? "yes" : "no",
+ arguments.quiet ? "yes" : "no"
+ );
+ }
+
+ if (nftw(arguments.args[0], nftw_callback, 15, FTW_PHYS)== -1) {
+ perror("Reading dir failed");
+ exit(EXIT_FAILURE);
+ }
+
+ exit(EXIT_SUCCESS);
+}
\ No newline at end of file
--- /dev/null
+GNU GENERAL PUBLIC LICENSE\r
+ Version 3, 29 June 2007\r
+\r
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>\r
+ Everyone is permitted to copy and distribute verbatim copies\r
+ of this license document, but changing it is not allowed.\r
+\r
+ Preamble\r
+\r
+ The GNU General Public License is a free, copyleft license for\r
+software and other kinds of works.\r
+\r
+ The licenses for most software and other practical works are designed\r
+to take away your freedom to share and change the works. By contrast,\r
+the GNU General Public License is intended to guarantee your freedom to\r
+share and change all versions of a program--to make sure it remains free\r
+software for all its users. We, the Free Software Foundation, use the\r
+GNU General Public License for most of our software; it applies also to\r
+any other work released this way by its authors. You can apply it to\r
+your programs, too.\r
+\r
+ When we speak of free software, we are referring to freedom, not\r
+price. Our General Public Licenses are designed to make sure that you\r
+have the freedom to distribute copies of free software (and charge for\r
+them if you wish), that you receive source code or can get it if you\r
+want it, that you can change the software or use pieces of it in new\r
+free programs, and that you know you can do these things.\r
+\r
+ To protect your rights, we need to prevent others from denying you\r
+these rights or asking you to surrender the rights. Therefore, you have\r
+certain responsibilities if you distribute copies of the software, or if\r
+you modify it: responsibilities to respect the freedom of others.\r
+\r
+ For example, if you distribute copies of such a program, whether\r
+gratis or for a fee, you must pass on to the recipients the same\r
+freedoms that you received. You must make sure that they, too, receive\r
+or can get the source code. And you must show them these terms so they\r
+know their rights.\r
+\r
+ Developers that use the GNU GPL protect your rights with two steps:\r
+(1) assert copyright on the software, and (2) offer you this License\r
+giving you legal permission to copy, distribute and/or modify it.\r
+\r
+ For the developers' and authors' protection, the GPL clearly explains\r
+that there is no warranty for this free software. For both users' and\r
+authors' sake, the GPL requires that modified versions be marked as\r
+changed, so that their problems will not be attributed erroneously to\r
+authors of previous versions.\r
+\r
+ Some devices are designed to deny users access to install or run\r
+modified versions of the software inside them, although the manufacturer\r
+can do so. This is fundamentally incompatible with the aim of\r
+protecting users' freedom to change the software. The systematic\r
+pattern of such abuse occurs in the area of products for individuals to\r
+use, which is precisely where it is most unacceptable. Therefore, we\r
+have designed this version of the GPL to prohibit the practice for those\r
+products. If such problems arise substantially in other domains, we\r
+stand ready to extend this provision to those domains in future versions\r
+of the GPL, as needed to protect the freedom of users.\r
+\r
+ Finally, every program is threatened constantly by software patents.\r
+States should not allow patents to restrict development and use of\r
+software on general-purpose computers, but in those that do, we wish to\r
+avoid the special danger that patents applied to a free program could\r
+make it effectively proprietary. To prevent this, the GPL assures that\r
+patents cannot be used to render the program non-free.\r
+\r
+ The precise terms and conditions for copying, distribution and\r
+modification follow.\r
+\r
+ TERMS AND CONDITIONS\r
+\r
+ 0. Definitions.\r
+\r
+ "This License" refers to version 3 of the GNU General Public License.\r
+\r
+ "Copyright" also means copyright-like laws that apply to other kinds of\r
+works, such as semiconductor masks.\r
+\r
+ "The Program" refers to any copyrightable work licensed under this\r
+License. Each licensee is addressed as "you". "Licensees" and\r
+"recipients" may be individuals or organizations.\r
+\r
+ To "modify" a work means to copy from or adapt all or part of the work\r
+in a fashion requiring copyright permission, other than the making of an\r
+exact copy. The resulting work is called a "modified version" of the\r
+earlier work or a work "based on" the earlier work.\r
+\r
+ A "covered work" means either the unmodified Program or a work based\r
+on the Program.\r
+\r
+ To "propagate" a work means to do anything with it that, without\r
+permission, would make you directly or secondarily liable for\r
+infringement under applicable copyright law, except executing it on a\r
+computer or modifying a private copy. Propagation includes copying,\r
+distribution (with or without modification), making available to the\r
+public, and in some countries other activities as well.\r
+\r
+ To "convey" a work means any kind of propagation that enables other\r
+parties to make or receive copies. Mere interaction with a user through\r
+a computer network, with no transfer of a copy, is not conveying.\r
+\r
+ An interactive user interface displays "Appropriate Legal Notices"\r
+to the extent that it includes a convenient and prominently visible\r
+feature that (1) displays an appropriate copyright notice, and (2)\r
+tells the user that there is no warranty for the work (except to the\r
+extent that warranties are provided), that licensees may convey the\r
+work under this License, and how to view a copy of this License. If\r
+the interface presents a list of user commands or options, such as a\r
+menu, a prominent item in the list meets this criterion.\r
+\r
+ 1. Source Code.\r
+\r
+ The "source code" for a work means the preferred form of the work\r
+for making modifications to it. "Object code" means any non-source\r
+form of a work.\r
+\r
+ A "Standard Interface" means an interface that either is an official\r
+standard defined by a recognized standards body, or, in the case of\r
+interfaces specified for a particular programming language, one that\r
+is widely used among developers working in that language.\r
+\r
+ The "System Libraries" of an executable work include anything, other\r
+than the work as a whole, that (a) is included in the normal form of\r
+packaging a Major Component, but which is not part of that Major\r
+Component, and (b) serves only to enable use of the work with that\r
+Major Component, or to implement a Standard Interface for which an\r
+implementation is available to the public in source code form. A\r
+"Major Component", in this context, means a major essential component\r
+(kernel, window system, and so on) of the specific operating system\r
+(if any) on which the executable work runs, or a compiler used to\r
+produce the work, or an object code interpreter used to run it.\r
+\r
+ The "Corresponding Source" for a work in object code form means all\r
+the source code needed to generate, install, and (for an executable\r
+work) run the object code and to modify the work, including scripts to\r
+control those activities. However, it does not include the work's\r
+System Libraries, or general-purpose tools or generally available free\r
+programs which are used unmodified in performing those activities but\r
+which are not part of the work. For example, Corresponding Source\r
+includes interface definition files associated with source files for\r
+the work, and the source code for shared libraries and dynamically\r
+linked subprograms that the work is specifically designed to require,\r
+such as by intimate data communication or control flow between those\r
+subprograms and other parts of the work.\r
+\r
+ The Corresponding Source need not include anything that users\r
+can regenerate automatically from other parts of the Corresponding\r
+Source.\r
+\r
+ The Corresponding Source for a work in source code form is that\r
+same work.\r
+\r
+ 2. Basic Permissions.\r
+\r
+ All rights granted under this License are granted for the term of\r
+copyright on the Program, and are irrevocable provided the stated\r
+conditions are met. This License explicitly affirms your unlimited\r
+permission to run the unmodified Program. The output from running a\r
+covered work is covered by this License only if the output, given its\r
+content, constitutes a covered work. This License acknowledges your\r
+rights of fair use or other equivalent, as provided by copyright law.\r
+\r
+ You may make, run and propagate covered works that you do not\r
+convey, without conditions so long as your license otherwise remains\r
+in force. You may convey covered works to others for the sole purpose\r
+of having them make modifications exclusively for you, or provide you\r
+with facilities for running those works, provided that you comply with\r
+the terms of this License in conveying all material for which you do\r
+not control copyright. Those thus making or running the covered works\r
+for you must do so exclusively on your behalf, under your direction\r
+and control, on terms that prohibit them from making any copies of\r
+your copyrighted material outside their relationship with you.\r
+\r
+ Conveying under any other circumstances is permitted solely under\r
+the conditions stated below. Sublicensing is not allowed; section 10\r
+makes it unnecessary.\r
+\r
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.\r
+\r
+ No covered work shall be deemed part of an effective technological\r
+measure under any applicable law fulfilling obligations under article\r
+11 of the WIPO copyright treaty adopted on 20 December 1996, or\r
+similar laws prohibiting or restricting circumvention of such\r
+measures.\r
+\r
+ When you convey a covered work, you waive any legal power to forbid\r
+circumvention of technological measures to the extent such circumvention\r
+is effected by exercising rights under this License with respect to\r
+the covered work, and you disclaim any intention to limit operation or\r
+modification of the work as a means of enforcing, against the work's\r
+users, your or third parties' legal rights to forbid circumvention of\r
+technological measures.\r
+\r
+ 4. Conveying Verbatim Copies.\r
+\r
+ You may convey verbatim copies of the Program's source code as you\r
+receive it, in any medium, provided that you conspicuously and\r
+appropriately publish on each copy an appropriate copyright notice;\r
+keep intact all notices stating that this License and any\r
+non-permissive terms added in accord with section 7 apply to the code;\r
+keep intact all notices of the absence of any warranty; and give all\r
+recipients a copy of this License along with the Program.\r
+\r
+ You may charge any price or no price for each copy that you convey,\r
+and you may offer support or warranty protection for a fee.\r
+\r
+ 5. Conveying Modified Source Versions.\r
+\r
+ You may convey a work based on the Program, or the modifications to\r
+produce it from the Program, in the form of source code under the\r
+terms of section 4, provided that you also meet all of these conditions:\r
+\r
+ a) The work must carry prominent notices stating that you modified\r
+ it, and giving a relevant date.\r
+\r
+ b) The work must carry prominent notices stating that it is\r
+ released under this License and any conditions added under section\r
+ 7. This requirement modifies the requirement in section 4 to\r
+ "keep intact all notices".\r
+\r
+ c) You must license the entire work, as a whole, under this\r
+ License to anyone who comes into possession of a copy. This\r
+ License will therefore apply, along with any applicable section 7\r
+ additional terms, to the whole of the work, and all its parts,\r
+ regardless of how they are packaged. This License gives no\r
+ permission to license the work in any other way, but it does not\r
+ invalidate such permission if you have separately received it.\r
+\r
+ d) If the work has interactive user interfaces, each must display\r
+ Appropriate Legal Notices; however, if the Program has interactive\r
+ interfaces that do not display Appropriate Legal Notices, your\r
+ work need not make them do so.\r
+\r
+ A compilation of a covered work with other separate and independent\r
+works, which are not by their nature extensions of the covered work,\r
+and which are not combined with it such as to form a larger program,\r
+in or on a volume of a storage or distribution medium, is called an\r
+"aggregate" if the compilation and its resulting copyright are not\r
+used to limit the access or legal rights of the compilation's users\r
+beyond what the individual works permit. Inclusion of a covered work\r
+in an aggregate does not cause this License to apply to the other\r
+parts of the aggregate.\r
+\r
+ 6. Conveying Non-Source Forms.\r
+\r
+ You may convey a covered work in object code form under the terms\r
+of sections 4 and 5, provided that you also convey the\r
+machine-readable Corresponding Source under the terms of this License,\r
+in one of these ways:\r
+\r
+ a) Convey the object code in, or embodied in, a physical product\r
+ (including a physical distribution medium), accompanied by the\r
+ Corresponding Source fixed on a durable physical medium\r
+ customarily used for software interchange.\r
+\r
+ b) Convey the object code in, or embodied in, a physical product\r
+ (including a physical distribution medium), accompanied by a\r
+ written offer, valid for at least three years and valid for as\r
+ long as you offer spare parts or customer support for that product\r
+ model, to give anyone who possesses the object code either (1) a\r
+ copy of the Corresponding Source for all the software in the\r
+ product that is covered by this License, on a durable physical\r
+ medium customarily used for software interchange, for a price no\r
+ more than your reasonable cost of physically performing this\r
+ conveying of source, or (2) access to copy the\r
+ Corresponding Source from a network server at no charge.\r
+\r
+ c) Convey individual copies of the object code with a copy of the\r
+ written offer to provide the Corresponding Source. This\r
+ alternative is allowed only occasionally and noncommercially, and\r
+ only if you received the object code with such an offer, in accord\r
+ with subsection 6b.\r
+\r
+ d) Convey the object code by offering access from a designated\r
+ place (gratis or for a charge), and offer equivalent access to the\r
+ Corresponding Source in the same way through the same place at no\r
+ further charge. You need not require recipients to copy the\r
+ Corresponding Source along with the object code. If the place to\r
+ copy the object code is a network server, the Corresponding Source\r
+ may be on a different server (operated by you or a third party)\r
+ that supports equivalent copying facilities, provided you maintain\r
+ clear directions next to the object code saying where to find the\r
+ Corresponding Source. Regardless of what server hosts the\r
+ Corresponding Source, you remain obligated to ensure that it is\r
+ available for as long as needed to satisfy these requirements.\r
+\r
+ e) Convey the object code using peer-to-peer transmission, provided\r
+ you inform other peers where the object code and Corresponding\r
+ Source of the work are being offered to the general public at no\r
+ charge under subsection 6d.\r
+\r
+ A separable portion of the object code, whose source code is excluded\r
+from the Corresponding Source as a System Library, need not be\r
+included in conveying the object code work.\r
+\r
+ A "User Product" is either (1) a "consumer product", which means any\r
+tangible personal property which is normally used for personal, family,\r
+or household purposes, or (2) anything designed or sold for incorporation\r
+into a dwelling. In determining whether a product is a consumer product,\r
+doubtful cases shall be resolved in favor of coverage. For a particular\r
+product received by a particular user, "normally used" refers to a\r
+typical or common use of that class of product, regardless of the status\r
+of the particular user or of the way in which the particular user\r
+actually uses, or expects or is expected to use, the product. A product\r
+is a consumer product regardless of whether the product has substantial\r
+commercial, industrial or non-consumer uses, unless such uses represent\r
+the only significant mode of use of the product.\r
+\r
+ "Installation Information" for a User Product means any methods,\r
+procedures, authorization keys, or other information required to install\r
+and execute modified versions of a covered work in that User Product from\r
+a modified version of its Corresponding Source. The information must\r
+suffice to ensure that the continued functioning of the modified object\r
+code is in no case prevented or interfered with solely because\r
+modification has been made.\r
+\r
+ If you convey an object code work under this section in, or with, or\r
+specifically for use in, a User Product, and the conveying occurs as\r
+part of a transaction in which the right of possession and use of the\r
+User Product is transferred to the recipient in perpetuity or for a\r
+fixed term (regardless of how the transaction is characterized), the\r
+Corresponding Source conveyed under this section must be accompanied\r
+by the Installation Information. But this requirement does not apply\r
+if neither you nor any third party retains the ability to install\r
+modified object code on the User Product (for example, the work has\r
+been installed in ROM).\r
+\r
+ The requirement to provide Installation Information does not include a\r
+requirement to continue to provide support service, warranty, or updates\r
+for a work that has been modified or installed by the recipient, or for\r
+the User Product in which it has been modified or installed. Access to a\r
+network may be denied when the modification itself materially and\r
+adversely affects the operation of the network or violates the rules and\r
+protocols for communication across the network.\r
+\r
+ Corresponding Source conveyed, and Installation Information provided,\r
+in accord with this section must be in a format that is publicly\r
+documented (and with an implementation available to the public in\r
+source code form), and must require no special password or key for\r
+unpacking, reading or copying.\r
+\r
+ 7. Additional Terms.\r
+\r
+ "Additional permissions" are terms that supplement the terms of this\r
+License by making exceptions from one or more of its conditions.\r
+Additional permissions that are applicable to the entire Program shall\r
+be treated as though they were included in this License, to the extent\r
+that they are valid under applicable law. If additional permissions\r
+apply only to part of the Program, that part may be used separately\r
+under those permissions, but the entire Program remains governed by\r
+this License without regard to the additional permissions.\r
+\r
+ When you convey a copy of a covered work, you may at your option\r
+remove any additional permissions from that copy, or from any part of\r
+it. (Additional permissions may be written to require their own\r
+removal in certain cases when you modify the work.) You may place\r
+additional permissions on material, added by you to a covered work,\r
+for which you have or can give appropriate copyright permission.\r
+\r
+ Notwithstanding any other provision of this License, for material you\r
+add to a covered work, you may (if authorized by the copyright holders of\r
+that material) supplement the terms of this License with terms:\r
+\r
+ a) Disclaiming warranty or limiting liability differently from the\r
+ terms of sections 15 and 16 of this License; or\r
+\r
+ b) Requiring preservation of specified reasonable legal notices or\r
+ author attributions in that material or in the Appropriate Legal\r
+ Notices displayed by works containing it; or\r
+\r
+ c) Prohibiting misrepresentation of the origin of that material, or\r
+ requiring that modified versions of such material be marked in\r
+ reasonable ways as different from the original version; or\r
+\r
+ d) Limiting the use for publicity purposes of names of licensors or\r
+ authors of the material; or\r
+\r
+ e) Declining to grant rights under trademark law for use of some\r
+ trade names, trademarks, or service marks; or\r
+\r
+ f) Requiring indemnification of licensors and authors of that\r
+ material by anyone who conveys the material (or modified versions of\r
+ it) with contractual assumptions of liability to the recipient, for\r
+ any liability that these contractual assumptions directly impose on\r
+ those licensors and authors.\r
+\r
+ All other non-permissive additional terms are considered "further\r
+restrictions" within the meaning of section 10. If the Program as you\r
+received it, or any part of it, contains a notice stating that it is\r
+governed by this License along with a term that is a further\r
+restriction, you may remove that term. If a license document contains\r
+a further restriction but permits relicensing or conveying under this\r
+License, you may add to a covered work material governed by the terms\r
+of that license document, provided that the further restriction does\r
+not survive such relicensing or conveying.\r
+\r
+ If you add terms to a covered work in accord with this section, you\r
+must place, in the relevant source files, a statement of the\r
+additional terms that apply to those files, or a notice indicating\r
+where to find the applicable terms.\r
+\r
+ Additional terms, permissive or non-permissive, may be stated in the\r
+form of a separately written license, or stated as exceptions;\r
+the above requirements apply either way.\r
+\r
+ 8. Termination.\r
+\r
+ You may not propagate or modify a covered work except as expressly\r
+provided under this License. Any attempt otherwise to propagate or\r
+modify it is void, and will automatically terminate your rights under\r
+this License (including any patent licenses granted under the third\r
+paragraph of section 11).\r
+\r
+ However, if you cease all violation of this License, then your\r
+license from a particular copyright holder is reinstated (a)\r
+provisionally, unless and until the copyright holder explicitly and\r
+finally terminates your license, and (b) permanently, if the copyright\r
+holder fails to notify you of the violation by some reasonable means\r
+prior to 60 days after the cessation.\r
+\r
+ Moreover, your license from a particular copyright holder is\r
+reinstated permanently if the copyright holder notifies you of the\r
+violation by some reasonable means, this is the first time you have\r
+received notice of violation of this License (for any work) from that\r
+copyright holder, and you cure the violation prior to 30 days after\r
+your receipt of the notice.\r
+\r
+ Termination of your rights under this section does not terminate the\r
+licenses of parties who have received copies or rights from you under\r
+this License. If your rights have been terminated and not permanently\r
+reinstated, you do not qualify to receive new licenses for the same\r
+material under section 10.\r
+\r
+ 9. Acceptance Not Required for Having Copies.\r
+\r
+ You are not required to accept this License in order to receive or\r
+run a copy of the Program. Ancillary propagation of a covered work\r
+occurring solely as a consequence of using peer-to-peer transmission\r
+to receive a copy likewise does not require acceptance. However,\r
+nothing other than this License grants you permission to propagate or\r
+modify any covered work. These actions infringe copyright if you do\r
+not accept this License. Therefore, by modifying or propagating a\r
+covered work, you indicate your acceptance of this License to do so.\r
+\r
+ 10. Automatic Licensing of Downstream Recipients.\r
+\r
+ Each time you convey a covered work, the recipient automatically\r
+receives a license from the original licensors, to run, modify and\r
+propagate that work, subject to this License. You are not responsible\r
+for enforcing compliance by third parties with this License.\r
+\r
+ An "entity transaction" is a transaction transferring control of an\r
+organization, or substantially all assets of one, or subdividing an\r
+organization, or merging organizations. If propagation of a covered\r
+work results from an entity transaction, each party to that\r
+transaction who receives a copy of the work also receives whatever\r
+licenses to the work the party's predecessor in interest had or could\r
+give under the previous paragraph, plus a right to possession of the\r
+Corresponding Source of the work from the predecessor in interest, if\r
+the predecessor has it or can get it with reasonable efforts.\r
+\r
+ You may not impose any further restrictions on the exercise of the\r
+rights granted or affirmed under this License. For example, you may\r
+not impose a license fee, royalty, or other charge for exercise of\r
+rights granted under this License, and you may not initiate litigation\r
+(including a cross-claim or counterclaim in a lawsuit) alleging that\r
+any patent claim is infringed by making, using, selling, offering for\r
+sale, or importing the Program or any portion of it.\r
+\r
+ 11. Patents.\r
+\r
+ A "contributor" is a copyright holder who authorizes use under this\r
+License of the Program or a work on which the Program is based. The\r
+work thus licensed is called the contributor's "contributor version".\r
+\r
+ A contributor's "essential patent claims" are all patent claims\r
+owned or controlled by the contributor, whether already acquired or\r
+hereafter acquired, that would be infringed by some manner, permitted\r
+by this License, of making, using, or selling its contributor version,\r
+but do not include claims that would be infringed only as a\r
+consequence of further modification of the contributor version. For\r
+purposes of this definition, "control" includes the right to grant\r
+patent sublicenses in a manner consistent with the requirements of\r
+this License.\r
+\r
+ Each contributor grants you a non-exclusive, worldwide, royalty-free\r
+patent license under the contributor's essential patent claims, to\r
+make, use, sell, offer for sale, import and otherwise run, modify and\r
+propagate the contents of its contributor version.\r
+\r
+ In the following three paragraphs, a "patent license" is any express\r
+agreement or commitment, however denominated, not to enforce a patent\r
+(such as an express permission to practice a patent or covenant not to\r
+sue for patent infringement). To "grant" such a patent license to a\r
+party means to make such an agreement or commitment not to enforce a\r
+patent against the party.\r
+\r
+ If you convey a covered work, knowingly relying on a patent license,\r
+and the Corresponding Source of the work is not available for anyone\r
+to copy, free of charge and under the terms of this License, through a\r
+publicly available network server or other readily accessible means,\r
+then you must either (1) cause the Corresponding Source to be so\r
+available, or (2) arrange to deprive yourself of the benefit of the\r
+patent license for this particular work, or (3) arrange, in a manner\r
+consistent with the requirements of this License, to extend the patent\r
+license to downstream recipients. "Knowingly relying" means you have\r
+actual knowledge that, but for the patent license, your conveying the\r
+covered work in a country, or your recipient's use of the covered work\r
+in a country, would infringe one or more identifiable patents in that\r
+country that you have reason to believe are valid.\r
+\r
+ If, pursuant to or in connection with a single transaction or\r
+arrangement, you convey, or propagate by procuring conveyance of, a\r
+covered work, and grant a patent license to some of the parties\r
+receiving the covered work authorizing them to use, propagate, modify\r
+or convey a specific copy of the covered work, then the patent license\r
+you grant is automatically extended to all recipients of the covered\r
+work and works based on it.\r
+\r
+ A patent license is "discriminatory" if it does not include within\r
+the scope of its coverage, prohibits the exercise of, or is\r
+conditioned on the non-exercise of one or more of the rights that are\r
+specifically granted under this License. You may not convey a covered\r
+work if you are a party to an arrangement with a third party that is\r
+in the business of distributing software, under which you make payment\r
+to the third party based on the extent of your activity of conveying\r
+the work, and under which the third party grants, to any of the\r
+parties who would receive the covered work from you, a discriminatory\r
+patent license (a) in connection with copies of the covered work\r
+conveyed by you (or copies made from those copies), or (b) primarily\r
+for and in connection with specific products or compilations that\r
+contain the covered work, unless you entered into that arrangement,\r
+or that patent license was granted, prior to 28 March 2007.\r
+\r
+ Nothing in this License shall be construed as excluding or limiting\r
+any implied license or other defenses to infringement that may\r
+otherwise be available to you under applicable patent law.\r
+\r
+ 12. No Surrender of Others' Freedom.\r
+\r
+ If conditions are imposed on you (whether by court order, agreement or\r
+otherwise) that contradict the conditions of this License, they do not\r
+excuse you from the conditions of this License. If you cannot convey a\r
+covered work so as to satisfy simultaneously your obligations under this\r
+License and any other pertinent obligations, then as a consequence you may\r
+not convey it at all. For example, if you agree to terms that obligate you\r
+to collect a royalty for further conveying from those to whom you convey\r
+the Program, the only way you could satisfy both those terms and this\r
+License would be to refrain entirely from conveying the Program.\r
+\r
+ 13. Use with the GNU Affero General Public License.\r
+\r
+ Notwithstanding any other provision of this License, you have\r
+permission to link or combine any covered work with a work licensed\r
+under version 3 of the GNU Affero General Public License into a single\r
+combined work, and to convey the resulting work. The terms of this\r
+License will continue to apply to the part which is the covered work,\r
+but the special requirements of the GNU Affero General Public License,\r
+section 13, concerning interaction through a network will apply to the\r
+combination as such.\r
+\r
+ 14. Revised Versions of this License.\r
+\r
+ The Free Software Foundation may publish revised and/or new versions of\r
+the GNU General Public License from time to time. Such new versions will\r
+be similar in spirit to the present version, but may differ in detail to\r
+address new problems or concerns.\r
+\r
+ Each version is given a distinguishing version number. If the\r
+Program specifies that a certain numbered version of the GNU General\r
+Public License "or any later version" applies to it, you have the\r
+option of following the terms and conditions either of that numbered\r
+version or of any later version published by the Free Software\r
+Foundation. If the Program does not specify a version number of the\r
+GNU General Public License, you may choose any version ever published\r
+by the Free Software Foundation.\r
+\r
+ If the Program specifies that a proxy can decide which future\r
+versions of the GNU General Public License can be used, that proxy's\r
+public statement of acceptance of a version permanently authorizes you\r
+to choose that version for the Program.\r
+\r
+ Later license versions may give you additional or different\r
+permissions. However, no additional obligations are imposed on any\r
+author or copyright holder as a result of your choosing to follow a\r
+later version.\r
+\r
+ 15. Disclaimer of Warranty.\r
+\r
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\r
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\r
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY\r
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\r
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\r
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\r
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\r
+\r
+ 16. Limitation of Liability.\r
+\r
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\r
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\r
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\r
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\r
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\r
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\r
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\r
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\r
+SUCH DAMAGES.\r
+\r
+ 17. Interpretation of Sections 15 and 16.\r
+\r
+ If the disclaimer of warranty and limitation of liability provided\r
+above cannot be given local legal effect according to their terms,\r
+reviewing courts shall apply local law that most closely approximates\r
+an absolute waiver of all civil liability in connection with the\r
+Program, unless a warranty or assumption of liability accompanies a\r
+copy of the Program in return for a fee.\r
+\r
+ END OF TERMS AND CONDITIONS\r
+\r
+ How to Apply These Terms to Your New Programs\r
+\r
+ If you develop a new program, and you want it to be of the greatest\r
+possible use to the public, the best way to achieve this is to make it\r
+free software which everyone can redistribute and change under these terms.\r
+\r
+ To do so, attach the following notices to the program. It is safest\r
+to attach them to the start of each source file to most effectively\r
+state the exclusion of warranty; and each file should have at least\r
+the "copyright" line and a pointer to where the full notice is found.\r
+\r
+ <one line to give the program's name and a brief idea of what it does.>\r
+ Copyright (C) <year> <name of author>\r
+\r
+ This program is free software: you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation, either version 3 of the License, or\r
+ (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program. If not, see <https://www.gnu.org/licenses/>.\r
+\r
+Also add information on how to contact you by electronic and paper mail.\r
+\r
+ If the program does terminal interaction, make it output a short\r
+notice like this when it starts in an interactive mode:\r
+\r
+ <program> Copyright (C) <year> <name of author>\r
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\r
+ This is free software, and you are welcome to redistribute it\r
+ under certain conditions; type `show c' for details.\r
+\r
+The hypothetical commands `show w' and `show c' should show the appropriate\r
+parts of the General Public License. Of course, your program's commands\r
+might be different; for a GUI interface, you would use an "about box".\r
+\r
+ You should also get your employer (if you work as a programmer) or school,\r
+if any, to sign a "copyright disclaimer" for the program, if necessary.\r
+For more information on this, and how to apply and follow the GNU GPL, see\r
+<https://www.gnu.org/licenses/>.\r
+\r
+ The GNU General Public License does not permit incorporating your program\r
+into proprietary programs. If your program is a subroutine library, you\r
+may consider it more useful to permit linking proprietary applications with\r
+the library. If this is what you want to do, use the GNU Lesser General\r
+Public License instead of this License. But first, please read\r
+<https://www.gnu.org/licenses/why-not-lgpl.html>.
\ No newline at end of file
--- /dev/null
+# Klimbim Software collection, A bag full of things\r
+# Copyright (C) 2011-2023 Johannes 'Banana' Keßler\r
+#\r
+# This program is free software: you can redistribute it and/or modify\r
+# it under the terms of the GNU General Public License as published by\r
+# the Free Software Foundation, either version 3 of the License, or\r
+# (at your option) any later version.\r
+#\r
+# This program is distributed in the hope that it will be useful,\r
+# but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+# GNU General Public License for more details.\r
+#\r
+# You should have received a copy of the GNU General Public License\r
+# along with this program. If not, see <https://www.gnu.org/licenses/>.\r
+\r
+# utf8filenamecheck\r
+Small windows C tool to check if paths in a folder are utf-8 formatted\r
+\r
+# Uses \r
+- https://www.argtable.org : Argument parsing (argtable-3.1.5-amalgamation)\r
+- https://github.com/adamretter/utf8-validator-c : Check if a string is utf-8\r
+\r
+# WARNING\r
+This is a very simple, with limited experience written, windows C program.\r
+Use at own risk and feel free to improve.\r
+\r
+# How to build\r
+- gcc from https://jmeubank.github.io/tdm-gcc/ (build with tdm64-gcc-9.2.0)\r
+Run the makefile.bat in a cmd terminal. \r
+Resulting utf8filenamecheck.exe is in bin/ directory.\r
+\r
+# How to use\r
+Run in a terminal `utf8filenamecheck.exe c:\some\dir`\r
+Run utf8filenamecheck.exe --help to see its options.
\ No newline at end of file
--- /dev/null
+https://www.argtable.org\r
+https://github.com/adamretter/utf8-validator-c
\ No newline at end of file
--- /dev/null
+Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
+<sheitmann@users.sourceforge.net>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * 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.
+ * Neither the name of STEWART HEITMANN 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN 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.
+
+
+NetBSD getopt library
+=====================
+
+Copyright (c) 2000 The NetBSD Foundation, Inc.
+All rights reserved.
+
+This code is derived from software contributed to The NetBSD Foundation
+by Dieter Baron and Thomas Klausner.
+
+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. All advertising materials mentioning features or use of this software
+ must display the following acknowledgement:
+ This product includes software developed by the NetBSD
+ Foundation, Inc. and its contributors.
+4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+
+
+Tcl library
+===========
+
+This software is copyrighted by the Regents of the University of
+California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState
+Corporation and other parties. The following terms apply to all files
+associated with the software unless explicitly disclaimed in
+individual files.
+
+The authors hereby grant permission to use, copy, modify, distribute,
+and license this software and its documentation for any purpose, provided
+that existing copyright notices are retained in all copies and that this
+notice is included verbatim in any distributions. No written agreement,
+license, or royalty fee is required for any of the authorized uses.
+Modifications to this software may be copyrighted by their authors
+and need not follow the licensing terms described here, provided that
+the new terms are clearly indicated on the first page of each file where
+they apply.
+
+IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
+FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
+DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
+IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
+NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+MODIFICATIONS.
+
+GOVERNMENT USE: If you are acquiring this software on behalf of the
+U.S. government, the Government shall have only "Restricted Rights"
+in the software and related documentation as defined in the Federal
+Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you
+are acquiring the software on behalf of the Department of Defense, the
+software shall be classified as "Commercial Computer Software" and the
+Government shall have only "Restricted Rights" as defined in Clause
+252.227-7014 (b) (3) of DFARs. Notwithstanding the foregoing, the
+authors grant the U.S. Government and others acting in its behalf
+permission to use and distribute the software in accordance with the
+terms specified in this license.
+
+
+C Hash Table library
+====================
+
+Copyright (c) 2002, Christopher Clark
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+* 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.
+
+* Neither the name of the original author; nor the names of any contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+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.
+
+
+The Better String library
+=========================
+
+Copyright (c) 2014, Paul Hsieh
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* 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.
+
+* Neither the name of bstrlib 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+
--- /dev/null
+[![Build Status](https://travis-ci.org/argtable/argtable3.svg?branch=master)](https://travis-ci.org/argtable/argtable3)\r
+\r
+\r
+Introduction of Argtable3\r
+=========================\r
+\r
+**Argtable3** is an open source ANSI C library that parses GNU-style\r
+command-line options. It simplifies command-line parsing by defining a\r
+declarative-style API that you can use to specify what your command-line syntax\r
+looks like. Argtable3 will automatically generate consistent error handling\r
+logic and textual descriptions of the command line syntax, which are essential\r
+but tedious to implement for a robust CLI program.\r
+\r
+\r
+Quick Start\r
+-----------\r
+\r
+> We no longer provide the amalgamation source code (`argtable3.c` and\r
+> `argtable3.h`) in the source code repository. You can get the amalgamation\r
+> distribution either from the release page (`argtable-3.x.x-amalgamation.zip`),\r
+> or generate the distribution yourself by using the generator under the `tools`\r
+> directory:\r
+> \r
+> 1. Navigate to the `tools` directory.\r
+> 2. Run `./build dist`, which will generate the distribution under the `<ROOT>/dist`\r
+> directory.\r
+\r
+\r
+Argtable3 is a single-file ANSI-C library. All you have to do is adding\r
+`argtable3.c` to your projects, and including `argtable3.h` in your source code.\r
+\r
+To build the library, examples, and unit tests, use CMake to generate\r
+out-of-source build:\r
+\r
+* If you use GCC (Linux, MacOSX, MinGW, Cygwin), run:\r
+\r
+ ```\r
+ $ mkdir build\r
+ $ cd build\r
+ $ cmake -DCMAKE_BUILD_TYPE=Debug ..\r
+ $ make\r
+ $ make test\r
+ ```\r
+\r
+ Makefile-based generators in CMake only support one configuration at a time,\r
+ so you need to specify `CMAKE_BUILD_TYPE` to `Debug`, `Release`, `MinSizeRel`,\r
+ or `RelWithDebInfo`. To build multiple configurations, you need to create a\r
+ build directory for each configuraiton.\r
+ \r
+ To cleanup, run `make clean` or remove the build directory:\r
+ \r
+ ```\r
+ $ rm -rf build\r
+ ```\r
+\r
+* If you use Microsoft Visual C++ compiler, run:\r
+\r
+ ```\r
+ $ mkdir build\r
+ $ cd build\r
+ $ cmake -G "Visual Studio 15 2017 Win64" ..\r
+ $ cmake --build . --config Debug\r
+ $ ctest -C Debug\r
+ ```\r
+\r
+ You can also use Visual Studio 2017 IDE to open the generated solution. To\r
+ cleanup, just remove the `build` directory.\r
+\r
+\r
+To build a tagged version, go to the project root directory, and use the\r
+`Makefile` in the project root folder to check out the specified version:\r
+\r
+ ```\r
+ $ make taglist\r
+ Available TAGs:\r
+ v3.1.1.432a160\r
+ $ make co TAG=v3.1.1.432a160\r
+ $ cd .tags/v3.1.1.432a160\r
+ $ mkdir build\r
+ $ cd build\r
+ $ cmake ..\r
+ $ make\r
+ $ make test\r
+ ```\r
+\r
+You will find the shared library (or Windows DLL), static library, and the\r
+amalgamation distribution under the build directory.\r
+\r
+\r
+Documentation and Examples\r
+--------------------------\r
+\r
+To learn how to use the Argtable3 API, you can see the documentation on the web\r
+site, or examples in the `examples` folder.\r
+\r
+\r
+Unit Tests\r
+----------\r
+\r
+Argtable3 is a BSD-licensed open source library, so you can modify the library\r
+anyway you want. However, before committing your code to your own repository or\r
+the Argtable3 official repository, please make sure your changes won't cause any\r
+compiler warning and can pass the unit tests included in the distribution.\r
+\r
+To build and test each configuration (`Debug`, `Release`, `MinSizeRel`,\r
+`RelWithDebInfo`), you can run CMake and CTest on all supported platforms:\r
+\r
+```\r
+$ mkdir build_debug && cd build_debug\r
+$ cmake -DCMAKE_BUILD_TYPE=Debug ..\r
+$ cmake --build . --config Debug\r
+$ ctest -C Debug\r
+\r
+$ cd .. && mkdir build_release && cd build_release\r
+$ cmake -DCMAKE_BUILD_TYPE=Release ..\r
+$ cmake --build . --config Release\r
+$ ctest -C Release\r
+\r
+$ cd .. && mkdir build_minsizerel && cd build_minsizerel\r
+$ cmake -DCMAKE_BUILD_TYPE=MinSizeRel ..\r
+$ cmake --build . --config MinSizeRel\r
+$ ctest -C MinSizeRel\r
+\r
+$ cd .. && mkdir build_relwithdebinfo && cd build_relwithdebinfo\r
+$ cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..\r
+$ cmake --build . --config RelWithDebInfo\r
+$ ctest -C RelWithDebInfo\r
+```\r
+\r
+\r
+Authors\r
+-------\r
+\r
+Argtable is Copyright (C) 1998-2001,2003-2011 Stewart Heitmann.\r
+Parts are Copyright (C) 1989-1994, 1996-1999, 2001, 2003\r
+ Free Software Foundation, Inc.\r
+\r
+Argtable was written by Stewart Heitmann <sheitmann@users.sourceforge.net>\r
+\r
+Argtable is now maintained by Tom G. Huang <tomghuang@gmail.com>\r
+The project homepage of argtable 3.x is http://www.argtable.org\r
+The project homepage of argtable 2.x is http://argtable.sourceforge.net/\r
+\r
+Here is a list of contributors who have helped to improve argtable:\r
+\r
+- **Nina Clemson**: Editing the original argtable-1.0 documentation.\r
+- **Livio Bertacco**: For bug fixes and the argtable-2.x Visual C++ Makefiles. \r
+- **Justin Dearing**: For bug fixes and Windows DLL support, plus code support for the Open Watcom compiler and help with the Mac OS X configuration.\r
+- **Asa Packer**: Contributing bug fixes and upgrades to the Visual C++ Makefiles.\r
+- **Danilo Cicerone**: For the Italian translation of "Introduction to Argtable-2x" on http://www.digitazero.org.\r
+- **Uli Fouquet**: For configuration patches and documentation related to cross-compiling argtable from Unix to Windows, as well as providing the arg_print_glossary_gnu function.\r
+- **Shachar Shemesh**: For Debian package integration and kick-starting the migration to automake/autoconf.\r
+- **Jasper Lievisse Adriaanse**: Maintaining the argtable package in OpenBSD ports.\r
+- **Ulrich Mohr**: For bug fixes relating to Texas Instrument DSP platforms.\r
+- **John Vickers**: For bug fixes relating to Solaris/Motorola platforms.\r
+- **Steve O'Neil**: For bug fixes relating to Solaris/Motorola platforms.\r
+- **Lori A. Pritchett-Sheats**: Fixing a makefile bug relating to "make dist".\r
+- **Paolo Bormida**: For instructions on building argtable with date and regex support on Windows.\r
+- **Michel Valin**: For bug fixes relating to the configure scripts on IBM AIX platforms and instructions on compiling the example code under AIX.\r
+- **Steve Christensen**: Providing prebuilt packages for SPARC/Solaris and x86/Solaris platforms on www.sunfreeware.com.\r
+- **Jess Portnoy**: Reworking the rpm package and integrating argtable into Fedora Linux.\r
+- **Michael Brown**: Incorporating support for pkg-config into the autoconf scripts.\r
+- **Alexander Lindert**: For extensions to the parser to support hex, octal and binary integer formats as well as KB/MB/GB suffixes.\r
+- **Rob Zaborowski**: Providing build configuration files for CMake.\r
+- **Moczik Gabor**: For bug fixes relating to the parsing of filepaths and filename extensions.\r
+\r
+Argtable 2.x uses `getopt` from GNU, which is LGPL licensed. In order to switch to BSD, we replaced GNU `getopt` with NetBSD `getopt`. We really appreciate this high quality library that lays the foundation of Argtable 3.x and here is its copyright notice:\r
+\r
+```\r
+Copyright (c) 2000 The NetBSD Foundation, Inc.\r
+All rights reserved.\r
+\r
+This code is derived from software contributed to The NetBSD Foundation\r
+by Dieter Baron and Thomas Klausner.\r
+\r
+Redistribution and use in source and binary forms, with or without\r
+modification, are permitted provided that the following conditions\r
+are met:\r
+1. Redistributions of source code must retain the above copyright\r
+ notice, this list of conditions and the following disclaimer.\r
+2. Redistributions in binary form must reproduce the above copyright\r
+ notice, this list of conditions and the following disclaimer in the\r
+ documentation and/or other materials provided with the distribution.\r
+3. All advertising materials mentioning features or use of this software\r
+ must display the following acknowledgement:\r
+ This product includes software developed by the NetBSD\r
+ Foundation, Inc. and its contributors.\r
+4. Neither the name of The NetBSD Foundation nor the names of its\r
+ contributors may be used to endorse or promote products derived\r
+ from this software without specific prior written permission.\r
+\r
+THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS\r
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\r
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
+PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS\r
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+POSSIBILITY OF SUCH DAMAGE.\r
+```\r
--- /dev/null
+/*******************************************************************************\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann\r
+ * <sheitmann@users.sourceforge.net>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ * * Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ * * Redistributions in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in the\r
+ * documentation and/or other materials provided with the distribution.\r
+ * * Neither the name of STEWART HEITMANN nor the names of its contributors\r
+ * may be used to endorse or promote products derived from this software\r
+ * without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#include "argtable3.h"\r
+\r
+#define ARG_AMALGAMATION\r
+\r
+/*******************************************************************************\r
+ * argtable3_private: Declares private types, constants, and interfaces\r
+ *\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 2013-2019 Tom G. Huang\r
+ * <tomghuang@gmail.com>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ * * Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ * * Redistributions in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in the\r
+ * documentation and/or other materials provided with the distribution.\r
+ * * Neither the name of STEWART HEITMANN nor the names of its contributors\r
+ * may be used to endorse or promote products derived from this software\r
+ * without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#ifndef ARG_UTILS_H\r
+#define ARG_UTILS_H\r
+\r
+#include <stdlib.h>\r
+\r
+#define ARG_ENABLE_TRACE 0\r
+#define ARG_ENABLE_LOG 1\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+enum { ARG_ERR_MINCOUNT = 1, ARG_ERR_MAXCOUNT, ARG_ERR_BADINT, ARG_ERR_OVERFLOW, ARG_ERR_BADDOUBLE, ARG_ERR_BADDATE, ARG_ERR_REGNOMATCH };\r
+\r
+typedef void(arg_panicfn)(const char* fmt, ...);\r
+\r
+#if defined(_MSC_VER)\r
+#define ARG_TRACE(x) \\r
+ __pragma(warning(push)) __pragma(warning(disable : 4127)) do { \\r
+ if (ARG_ENABLE_TRACE) \\r
+ dbg_printf x; \\r
+ } \\r
+ while (0) \\r
+ __pragma(warning(pop))\r
+\r
+#define ARG_LOG(x) \\r
+ __pragma(warning(push)) __pragma(warning(disable : 4127)) do { \\r
+ if (ARG_ENABLE_LOG) \\r
+ dbg_printf x; \\r
+ } \\r
+ while (0) \\r
+ __pragma(warning(pop))\r
+#else\r
+#define ARG_TRACE(x) \\r
+ do { \\r
+ if (ARG_ENABLE_TRACE) \\r
+ dbg_printf x; \\r
+ } while (0)\r
+\r
+#define ARG_LOG(x) \\r
+ do { \\r
+ if (ARG_ENABLE_LOG) \\r
+ dbg_printf x; \\r
+ } while (0)\r
+#endif\r
+\r
+extern void dbg_printf(const char* fmt, ...);\r
+extern void arg_set_panic(arg_panicfn* proc);\r
+extern void* xmalloc(size_t size);\r
+extern void* xcalloc(size_t count, size_t size);\r
+extern void* xrealloc(void* ptr, size_t size);\r
+extern void xfree(void* ptr);\r
+\r
+struct arg_hashtable_entry {\r
+ void *k, *v;\r
+ unsigned int h;\r
+ struct arg_hashtable_entry* next;\r
+};\r
+\r
+typedef struct arg_hashtable {\r
+ unsigned int tablelength;\r
+ struct arg_hashtable_entry** table;\r
+ unsigned int entrycount;\r
+ unsigned int loadlimit;\r
+ unsigned int primeindex;\r
+ unsigned int (*hashfn)(const void* k);\r
+ int (*eqfn)(const void* k1, const void* k2);\r
+} arg_hashtable_t;\r
+\r
+/**\r
+ * @brief Create a hash table.\r
+ *\r
+ * @param minsize minimum initial size of hash table\r
+ * @param hashfn function for hashing keys\r
+ * @param eqfn function for determining key equality\r
+ * @return newly created hash table or NULL on failure\r
+ */\r
+arg_hashtable_t* arg_hashtable_create(unsigned int minsize, unsigned int (*hashfn)(const void*), int (*eqfn)(const void*, const void*));\r
+\r
+/**\r
+ * @brief This function will cause the table to expand if the insertion would take\r
+ * the ratio of entries to table size over the maximum load factor.\r
+ *\r
+ * This function does not check for repeated insertions with a duplicate key.\r
+ * The value returned when using a duplicate key is undefined -- when\r
+ * the hash table changes size, the order of retrieval of duplicate key\r
+ * entries is reversed.\r
+ * If in doubt, remove before insert.\r
+ *\r
+ * @param h the hash table to insert into\r
+ * @param k the key - hash table claims ownership and will free on removal\r
+ * @param v the value - does not claim ownership\r
+ * @return non-zero for successful insertion\r
+ */\r
+void arg_hashtable_insert(arg_hashtable_t* h, void* k, void* v);\r
+\r
+#define ARG_DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \\r
+ int fnname(arg_hashtable_t* h, keytype* k, valuetype* v) { return arg_hashtable_insert(h, k, v); }\r
+\r
+/**\r
+ * @brief Search the specified key in the hash table.\r
+ *\r
+ * @param h the hash table to search\r
+ * @param k the key to search for - does not claim ownership\r
+ * @return the value associated with the key, or NULL if none found\r
+ */\r
+void* arg_hashtable_search(arg_hashtable_t* h, const void* k);\r
+\r
+#define ARG_DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \\r
+ valuetype* fnname(arg_hashtable_t* h, keytype* k) { return (valuetype*)(arg_hashtable_search(h, k)); }\r
+\r
+/**\r
+ * @brief Remove the specified key from the hash table.\r
+ *\r
+ * @param h the hash table to remove the item from\r
+ * @param k the key to search for - does not claim ownership\r
+ */\r
+void arg_hashtable_remove(arg_hashtable_t* h, const void* k);\r
+\r
+#define ARG_DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \\r
+ valuetype* fnname(arg_hashtable_t* h, keytype* k) { return (valuetype*)(arg_hashtable_remove(h, k)); }\r
+\r
+/**\r
+ * @brief Return the number of keys in the hash table.\r
+ *\r
+ * @param h the hash table\r
+ * @return the number of items stored in the hash table\r
+ */\r
+unsigned int arg_hashtable_count(arg_hashtable_t* h);\r
+\r
+/**\r
+ * @brief Change the value associated with the key.\r
+ *\r
+ * function to change the value associated with a key, where there already\r
+ * exists a value bound to the key in the hash table.\r
+ * Source due to Holger Schemel.\r
+ *\r
+ * @name hashtable_change\r
+ * @param h the hash table\r
+ * @param key\r
+ * @param value\r
+ */\r
+int arg_hashtable_change(arg_hashtable_t* h, void* k, void* v);\r
+\r
+/**\r
+ * @brief Free the hash table and the memory allocated for each key-value pair.\r
+ *\r
+ * @param h the hash table\r
+ * @param free_values whether to call 'free' on the remaining values\r
+ */\r
+void arg_hashtable_destroy(arg_hashtable_t* h, int free_values);\r
+\r
+typedef struct arg_hashtable_itr {\r
+ arg_hashtable_t* h;\r
+ struct arg_hashtable_entry* e;\r
+ struct arg_hashtable_entry* parent;\r
+ unsigned int index;\r
+} arg_hashtable_itr_t;\r
+\r
+arg_hashtable_itr_t* arg_hashtable_itr_create(arg_hashtable_t* h);\r
+\r
+void arg_hashtable_itr_destroy(arg_hashtable_itr_t* itr);\r
+\r
+/**\r
+ * @brief Return the value of the (key,value) pair at the current position.\r
+ */\r
+extern void* arg_hashtable_itr_key(arg_hashtable_itr_t* i);\r
+\r
+/**\r
+ * @brief Return the value of the (key,value) pair at the current position.\r
+ */\r
+extern void* arg_hashtable_itr_value(arg_hashtable_itr_t* i);\r
+\r
+/**\r
+ * @brief Advance the iterator to the next element. Returns zero if advanced to end of table.\r
+ */\r
+int arg_hashtable_itr_advance(arg_hashtable_itr_t* itr);\r
+\r
+/**\r
+ * @brief Remove current element and advance the iterator to the next element.\r
+ */\r
+int arg_hashtable_itr_remove(arg_hashtable_itr_t* itr);\r
+\r
+/**\r
+ * @brief Search and overwrite the supplied iterator, to point to the entry matching the supplied key.\r
+ *\r
+ * @return Zero if not found.\r
+ */\r
+int arg_hashtable_itr_search(arg_hashtable_itr_t* itr, arg_hashtable_t* h, void* k);\r
+\r
+#define ARG_DEFINE_HASHTABLE_ITERATOR_SEARCH(fnname, keytype) \\r
+ int fnname(arg_hashtable_itr_t* i, arg_hashtable_t* h, keytype* k) { return (arg_hashtable_iterator_search(i, h, k)); }\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif\r
+/*******************************************************************************\r
+ * arg_utils: Implements memory, panic, and other utility functions\r
+ *\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 2013-2019 Tom G. Huang\r
+ * <tomghuang@gmail.com>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ * * Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ * * Redistributions in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in the\r
+ * documentation and/or other materials provided with the distribution.\r
+ * * Neither the name of STEWART HEITMANN nor the names of its contributors\r
+ * may be used to endorse or promote products derived from this software\r
+ * without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#include "argtable3.h"\r
+\r
+#ifndef ARG_AMALGAMATION\r
+#include "argtable3_private.h"\r
+#endif\r
+\r
+#include <stdarg.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+static void panic(const char* fmt, ...);\r
+static arg_panicfn* s_panic = panic;\r
+\r
+void dbg_printf(const char* fmt, ...) {\r
+ va_list args;\r
+ va_start(args, fmt);\r
+ vfprintf(stderr, fmt, args);\r
+ va_end(args);\r
+}\r
+\r
+static void panic(const char* fmt, ...) {\r
+ va_list args;\r
+ char* s;\r
+\r
+ va_start(args, fmt);\r
+ vfprintf(stderr, fmt, args);\r
+ va_end(args);\r
+\r
+#if defined(_MSC_VER)\r
+#pragma warning(push)\r
+#pragma warning(disable : 4996)\r
+#endif\r
+ s = getenv("EF_DUMPCORE");\r
+#if defined(_MSC_VER)\r
+#pragma warning(pop)\r
+#endif\r
+\r
+ if (s != NULL && *s != '\0') {\r
+ abort();\r
+ } else {\r
+ exit(EXIT_FAILURE);\r
+ }\r
+}\r
+\r
+void arg_set_panic(arg_panicfn* proc) {\r
+ s_panic = proc;\r
+}\r
+\r
+void* xmalloc(size_t size) {\r
+ void* ret = malloc(size);\r
+ if (!ret) {\r
+ s_panic("Out of memory!\n");\r
+ }\r
+ return ret;\r
+}\r
+\r
+void* xcalloc(size_t count, size_t size) {\r
+ size_t allocated_count = count && size ? count : 1;\r
+ size_t allocated_size = count && size ? size : 1;\r
+ void* ret = calloc(allocated_count, allocated_size);\r
+ if (!ret) {\r
+ s_panic("Out of memory!\n");\r
+ }\r
+ return ret;\r
+}\r
+\r
+void* xrealloc(void* ptr, size_t size) {\r
+ size_t allocated_size = size ? size : 1;\r
+ void* ret = realloc(ptr, allocated_size);\r
+ if (!ret) {\r
+ s_panic("Out of memory!\n");\r
+ }\r
+ return ret;\r
+}\r
+\r
+void xfree(void* ptr) {\r
+ free(ptr);\r
+}\r
+\r
+static void merge(void* data, int esize, int i, int j, int k, arg_comparefn* comparefn) {\r
+ char* a = (char*)data;\r
+ char* m;\r
+ int ipos, jpos, mpos;\r
+\r
+ /* Initialize the counters used in merging. */\r
+ ipos = i;\r
+ jpos = j + 1;\r
+ mpos = 0;\r
+\r
+ /* Allocate storage for the merged elements. */\r
+ m = (char*)xmalloc(esize * ((k - i) + 1));\r
+\r
+ /* Continue while either division has elements to merge. */\r
+ while (ipos <= j || jpos <= k) {\r
+ if (ipos > j) {\r
+ /* The left division has no more elements to merge. */\r
+ while (jpos <= k) {\r
+ memcpy(&m[mpos * esize], &a[jpos * esize], esize);\r
+ jpos++;\r
+ mpos++;\r
+ }\r
+\r
+ continue;\r
+ } else if (jpos > k) {\r
+ /* The right division has no more elements to merge. */\r
+ while (ipos <= j) {\r
+ memcpy(&m[mpos * esize], &a[ipos * esize], esize);\r
+ ipos++;\r
+ mpos++;\r
+ }\r
+\r
+ continue;\r
+ }\r
+\r
+ /* Append the next ordered element to the merged elements. */\r
+ if (comparefn(&a[ipos * esize], &a[jpos * esize]) < 0) {\r
+ memcpy(&m[mpos * esize], &a[ipos * esize], esize);\r
+ ipos++;\r
+ mpos++;\r
+ } else {\r
+ memcpy(&m[mpos * esize], &a[jpos * esize], esize);\r
+ jpos++;\r
+ mpos++;\r
+ }\r
+ }\r
+\r
+ /* Prepare to pass back the merged data. */\r
+ memcpy(&a[i * esize], m, esize * ((k - i) + 1));\r
+ xfree(m);\r
+}\r
+\r
+void arg_mgsort(void* data, int size, int esize, int i, int k, arg_comparefn* comparefn) {\r
+ int j;\r
+\r
+ /* Stop the recursion when no more divisions can be made. */\r
+ if (i < k) {\r
+ /* Determine where to divide the elements. */\r
+ j = (int)(((i + k - 1)) / 2);\r
+\r
+ /* Recursively sort the two divisions. */\r
+ arg_mgsort(data, size, esize, i, j, comparefn);\r
+ arg_mgsort(data, size, esize, j + 1, k, comparefn);\r
+ merge(data, esize, i, j, k, comparefn);\r
+ }\r
+}\r
+/*******************************************************************************\r
+ * arg_hashtable: Implements the hash table utilities\r
+ *\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 2013-2019 Tom G. Huang\r
+ * <tomghuang@gmail.com>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ * * Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ * * Redistributions in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in the\r
+ * documentation and/or other materials provided with the distribution.\r
+ * * Neither the name of STEWART HEITMANN nor the names of its contributors\r
+ * may be used to endorse or promote products derived from this software\r
+ * without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#ifndef ARG_AMALGAMATION\r
+#include "argtable3_private.h"\r
+#endif\r
+\r
+#include <math.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+/*\r
+ * This hash table module is adapted from the C hash table implementation by\r
+ * Christopher Clark. Here is the copyright notice from the library:\r
+ *\r
+ * Copyright (c) 2002, Christopher Clark\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions\r
+ * are met:\r
+ *\r
+ * * Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ *\r
+ * * Redistributions in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in the\r
+ * documentation and/or other materials provided with the distribution.\r
+ *\r
+ * * Neither the name of the original author; nor the names of any contributors\r
+ * may be used to endorse or promote products derived from this software\r
+ * without specific prior written permission.\r
+ *\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER\r
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\r
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\r
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+\r
+/*\r
+ * Credit for primes table: Aaron Krowne\r
+ * http://br.endernet.org/~akrowne/\r
+ * http://planetmath.org/encyclopedia/GoodHashTablePrimes.html\r
+ */\r
+static const unsigned int primes[] = {53, 97, 193, 389, 769, 1543, 3079, 6151, 12289,\r
+ 24593, 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469,\r
+ 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741};\r
+const unsigned int prime_table_length = sizeof(primes) / sizeof(primes[0]);\r
+const float max_load_factor = (float)0.65;\r
+\r
+static unsigned int enhanced_hash(arg_hashtable_t* h, const void* k) {\r
+ /*\r
+ * Aim to protect against poor hash functions by adding logic here.\r
+ * The logic is taken from Java 1.4 hash table source.\r
+ */\r
+ unsigned int i = h->hashfn(k);\r
+ i += ~(i << 9);\r
+ i ^= ((i >> 14) | (i << 18)); /* >>> */\r
+ i += (i << 4);\r
+ i ^= ((i >> 10) | (i << 22)); /* >>> */\r
+ return i;\r
+}\r
+\r
+static unsigned int index_for(unsigned int tablelength, unsigned int hashvalue) {\r
+ return (hashvalue % tablelength);\r
+}\r
+\r
+arg_hashtable_t* arg_hashtable_create(unsigned int minsize, unsigned int (*hashfn)(const void*), int (*eqfn)(const void*, const void*)) {\r
+ arg_hashtable_t* h;\r
+ unsigned int pindex;\r
+ unsigned int size = primes[0];\r
+\r
+ /* Check requested hash table isn't too large */\r
+ if (minsize > (1u << 30))\r
+ return NULL;\r
+\r
+ /*\r
+ * Enforce size as prime. The reason is to avoid clustering of values\r
+ * into a small number of buckets (yes, distribution). A more even\r
+ * distributed hash table will perform more consistently.\r
+ */\r
+ for (pindex = 0; pindex < prime_table_length; pindex++) {\r
+ if (primes[pindex] > minsize) {\r
+ size = primes[pindex];\r
+ break;\r
+ }\r
+ }\r
+\r
+ h = (arg_hashtable_t*)xmalloc(sizeof(arg_hashtable_t));\r
+ h->table = (struct arg_hashtable_entry**)xmalloc(sizeof(struct arg_hashtable_entry*) * size);\r
+ memset(h->table, 0, size * sizeof(struct arg_hashtable_entry*));\r
+ h->tablelength = size;\r
+ h->primeindex = pindex;\r
+ h->entrycount = 0;\r
+ h->hashfn = hashfn;\r
+ h->eqfn = eqfn;\r
+ h->loadlimit = (unsigned int)ceil(size * max_load_factor);\r
+ return h;\r
+}\r
+\r
+static int arg_hashtable_expand(arg_hashtable_t* h) {\r
+ /* Double the size of the table to accommodate more entries */\r
+ struct arg_hashtable_entry** newtable;\r
+ struct arg_hashtable_entry* e;\r
+ unsigned int newsize;\r
+ unsigned int i;\r
+ unsigned int index;\r
+\r
+ /* Check we're not hitting max capacity */\r
+ if (h->primeindex == (prime_table_length - 1))\r
+ return 0;\r
+ newsize = primes[++(h->primeindex)];\r
+\r
+ newtable = (struct arg_hashtable_entry**)xmalloc(sizeof(struct arg_hashtable_entry*) * newsize);\r
+ memset(newtable, 0, newsize * sizeof(struct arg_hashtable_entry*));\r
+ /*\r
+ * This algorithm is not 'stable': it reverses the list\r
+ * when it transfers entries between the tables\r
+ */\r
+ for (i = 0; i < h->tablelength; i++) {\r
+ while (NULL != (e = h->table[i])) {\r
+ h->table[i] = e->next;\r
+ index = index_for(newsize, e->h);\r
+ e->next = newtable[index];\r
+ newtable[index] = e;\r
+ }\r
+ }\r
+\r
+ xfree(h->table);\r
+ h->table = newtable;\r
+ h->tablelength = newsize;\r
+ h->loadlimit = (unsigned int)ceil(newsize * max_load_factor);\r
+ return -1;\r
+}\r
+\r
+unsigned int arg_hashtable_count(arg_hashtable_t* h) {\r
+ return h->entrycount;\r
+}\r
+\r
+void arg_hashtable_insert(arg_hashtable_t* h, void* k, void* v) {\r
+ /* This method allows duplicate keys - but they shouldn't be used */\r
+ unsigned int index;\r
+ struct arg_hashtable_entry* e;\r
+ if ((h->entrycount + 1) > h->loadlimit) {\r
+ /*\r
+ * Ignore the return value. If expand fails, we should\r
+ * still try cramming just this value into the existing table\r
+ * -- we may not have memory for a larger table, but one more\r
+ * element may be ok. Next time we insert, we'll try expanding again.\r
+ */\r
+ arg_hashtable_expand(h);\r
+ }\r
+ e = (struct arg_hashtable_entry*)xmalloc(sizeof(struct arg_hashtable_entry));\r
+ e->h = enhanced_hash(h, k);\r
+ index = index_for(h->tablelength, e->h);\r
+ e->k = k;\r
+ e->v = v;\r
+ e->next = h->table[index];\r
+ h->table[index] = e;\r
+ h->entrycount++;\r
+}\r
+\r
+void* arg_hashtable_search(arg_hashtable_t* h, const void* k) {\r
+ struct arg_hashtable_entry* e;\r
+ unsigned int hashvalue;\r
+ unsigned int index;\r
+\r
+ hashvalue = enhanced_hash(h, k);\r
+ index = index_for(h->tablelength, hashvalue);\r
+ e = h->table[index];\r
+ while (e != NULL) {\r
+ /* Check hash value to short circuit heavier comparison */\r
+ if ((hashvalue == e->h) && (h->eqfn(k, e->k)))\r
+ return e->v;\r
+ e = e->next;\r
+ }\r
+ return NULL;\r
+}\r
+\r
+void arg_hashtable_remove(arg_hashtable_t* h, const void* k) {\r
+ /*\r
+ * TODO: consider compacting the table when the load factor drops enough,\r
+ * or provide a 'compact' method.\r
+ */\r
+\r
+ struct arg_hashtable_entry* e;\r
+ struct arg_hashtable_entry** pE;\r
+ unsigned int hashvalue;\r
+ unsigned int index;\r
+\r
+ hashvalue = enhanced_hash(h, k);\r
+ index = index_for(h->tablelength, hashvalue);\r
+ pE = &(h->table[index]);\r
+ e = *pE;\r
+ while (NULL != e) {\r
+ /* Check hash value to short circuit heavier comparison */\r
+ if ((hashvalue == e->h) && (h->eqfn(k, e->k))) {\r
+ *pE = e->next;\r
+ h->entrycount--;\r
+ xfree(e->k);\r
+ xfree(e->v);\r
+ xfree(e);\r
+ return;\r
+ }\r
+ pE = &(e->next);\r
+ e = e->next;\r
+ }\r
+}\r
+\r
+void arg_hashtable_destroy(arg_hashtable_t* h, int free_values) {\r
+ unsigned int i;\r
+ struct arg_hashtable_entry *e, *f;\r
+ struct arg_hashtable_entry** table = h->table;\r
+ if (free_values) {\r
+ for (i = 0; i < h->tablelength; i++) {\r
+ e = table[i];\r
+ while (NULL != e) {\r
+ f = e;\r
+ e = e->next;\r
+ xfree(f->k);\r
+ xfree(f->v);\r
+ xfree(f);\r
+ }\r
+ }\r
+ } else {\r
+ for (i = 0; i < h->tablelength; i++) {\r
+ e = table[i];\r
+ while (NULL != e) {\r
+ f = e;\r
+ e = e->next;\r
+ xfree(f->k);\r
+ xfree(f);\r
+ }\r
+ }\r
+ }\r
+ xfree(h->table);\r
+ xfree(h);\r
+}\r
+\r
+arg_hashtable_itr_t* arg_hashtable_itr_create(arg_hashtable_t* h) {\r
+ unsigned int i;\r
+ unsigned int tablelength;\r
+\r
+ arg_hashtable_itr_t* itr = (arg_hashtable_itr_t*)xmalloc(sizeof(arg_hashtable_itr_t));\r
+ itr->h = h;\r
+ itr->e = NULL;\r
+ itr->parent = NULL;\r
+ tablelength = h->tablelength;\r
+ itr->index = tablelength;\r
+ if (0 == h->entrycount)\r
+ return itr;\r
+\r
+ for (i = 0; i < tablelength; i++) {\r
+ if (h->table[i] != NULL) {\r
+ itr->e = h->table[i];\r
+ itr->index = i;\r
+ break;\r
+ }\r
+ }\r
+ return itr;\r
+}\r
+\r
+void arg_hashtable_itr_destroy(arg_hashtable_itr_t* itr) {\r
+ xfree(itr);\r
+}\r
+\r
+void* arg_hashtable_itr_key(arg_hashtable_itr_t* i) {\r
+ return i->e->k;\r
+}\r
+\r
+void* arg_hashtable_itr_value(arg_hashtable_itr_t* i) {\r
+ return i->e->v;\r
+}\r
+\r
+int arg_hashtable_itr_advance(arg_hashtable_itr_t* itr) {\r
+ unsigned int j;\r
+ unsigned int tablelength;\r
+ struct arg_hashtable_entry** table;\r
+ struct arg_hashtable_entry* next;\r
+\r
+ if (itr->e == NULL)\r
+ return 0; /* stupidity check */\r
+\r
+ next = itr->e->next;\r
+ if (NULL != next) {\r
+ itr->parent = itr->e;\r
+ itr->e = next;\r
+ return -1;\r
+ }\r
+\r
+ tablelength = itr->h->tablelength;\r
+ itr->parent = NULL;\r
+ if (tablelength <= (j = ++(itr->index))) {\r
+ itr->e = NULL;\r
+ return 0;\r
+ }\r
+\r
+ table = itr->h->table;\r
+ while (NULL == (next = table[j])) {\r
+ if (++j >= tablelength) {\r
+ itr->index = tablelength;\r
+ itr->e = NULL;\r
+ return 0;\r
+ }\r
+ }\r
+\r
+ itr->index = j;\r
+ itr->e = next;\r
+ return -1;\r
+}\r
+\r
+int arg_hashtable_itr_remove(arg_hashtable_itr_t* itr) {\r
+ struct arg_hashtable_entry* remember_e;\r
+ struct arg_hashtable_entry* remember_parent;\r
+ int ret;\r
+\r
+ /* Do the removal */\r
+ if ((itr->parent) == NULL) {\r
+ /* element is head of a chain */\r
+ itr->h->table[itr->index] = itr->e->next;\r
+ } else {\r
+ /* element is mid-chain */\r
+ itr->parent->next = itr->e->next;\r
+ }\r
+ /* itr->e is now outside the hashtable */\r
+ remember_e = itr->e;\r
+ itr->h->entrycount--;\r
+ xfree(remember_e->k);\r
+ xfree(remember_e->v);\r
+\r
+ /* Advance the iterator, correcting the parent */\r
+ remember_parent = itr->parent;\r
+ ret = arg_hashtable_itr_advance(itr);\r
+ if (itr->parent == remember_e) {\r
+ itr->parent = remember_parent;\r
+ }\r
+ xfree(remember_e);\r
+ return ret;\r
+}\r
+\r
+int arg_hashtable_itr_search(arg_hashtable_itr_t* itr, arg_hashtable_t* h, void* k) {\r
+ struct arg_hashtable_entry* e;\r
+ struct arg_hashtable_entry* parent;\r
+ unsigned int hashvalue;\r
+ unsigned int index;\r
+\r
+ hashvalue = enhanced_hash(h, k);\r
+ index = index_for(h->tablelength, hashvalue);\r
+\r
+ e = h->table[index];\r
+ parent = NULL;\r
+ while (e != NULL) {\r
+ /* Check hash value to short circuit heavier comparison */\r
+ if ((hashvalue == e->h) && (h->eqfn(k, e->k))) {\r
+ itr->index = index;\r
+ itr->e = e;\r
+ itr->parent = parent;\r
+ itr->h = h;\r
+ return -1;\r
+ }\r
+ parent = e;\r
+ e = e->next;\r
+ }\r
+ return 0;\r
+}\r
+\r
+int arg_hashtable_change(arg_hashtable_t* h, void* k, void* v) {\r
+ struct arg_hashtable_entry* e;\r
+ unsigned int hashvalue;\r
+ unsigned int index;\r
+\r
+ hashvalue = enhanced_hash(h, k);\r
+ index = index_for(h->tablelength, hashvalue);\r
+ e = h->table[index];\r
+ while (e != NULL) {\r
+ /* Check hash value to short circuit heavier comparison */\r
+ if ((hashvalue == e->h) && (h->eqfn(k, e->k))) {\r
+ xfree(e->v);\r
+ e->v = v;\r
+ return -1;\r
+ }\r
+ e = e->next;\r
+ }\r
+ return 0;\r
+}\r
+/*******************************************************************************\r
+ * arg_dstr: Implements the dynamic string utilities\r
+ *\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 2013-2019 Tom G. Huang\r
+ * <tomghuang@gmail.com>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ * * Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ * * Redistributions in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in the\r
+ * documentation and/or other materials provided with the distribution.\r
+ * * Neither the name of STEWART HEITMANN nor the names of its contributors\r
+ * may be used to endorse or promote products derived from this software\r
+ * without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#include "argtable3.h"\r
+\r
+#ifndef ARG_AMALGAMATION\r
+#include "argtable3_private.h"\r
+#endif\r
+\r
+#include <stdarg.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#if defined(_MSC_VER)\r
+#pragma warning(push)\r
+#pragma warning(disable : 4996)\r
+#endif\r
+\r
+#define START_VSNBUFF 16\r
+\r
+/*\r
+ * This dynamic string module is adapted from TclResult.c in the Tcl library.\r
+ * Here is the copyright notice from the library:\r
+ *\r
+ * This software is copyrighted by the Regents of the University of\r
+ * California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState\r
+ * Corporation and other parties. The following terms apply to all files\r
+ * associated with the software unless explicitly disclaimed in\r
+ * individual files.\r
+ *\r
+ * The authors hereby grant permission to use, copy, modify, distribute,\r
+ * and license this software and its documentation for any purpose, provided\r
+ * that existing copyright notices are retained in all copies and that this\r
+ * notice is included verbatim in any distributions. No written agreement,\r
+ * license, or royalty fee is required for any of the authorized uses.\r
+ * Modifications to this software may be copyrighted by their authors\r
+ * and need not follow the licensing terms described here, provided that\r
+ * the new terms are clearly indicated on the first page of each file where\r
+ * they apply.\r
+ *\r
+ * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY\r
+ * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES\r
+ * ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY\r
+ * DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE\r
+ * POSSIBILITY OF SUCH DAMAGE.\r
+ *\r
+ * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,\r
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,\r
+ * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE\r
+ * IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE\r
+ * NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR\r
+ * MODIFICATIONS.\r
+ *\r
+ * GOVERNMENT USE: If you are acquiring this software on behalf of the\r
+ * U.S. government, the Government shall have only "Restricted Rights"\r
+ * in the software and related documentation as defined in the Federal\r
+ * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you\r
+ * are acquiring the software on behalf of the Department of Defense, the\r
+ * software shall be classified as "Commercial Computer Software" and the\r
+ * Government shall have only "Restricted Rights" as defined in Clause\r
+ * 252.227-7014 (b) (3) of DFARs. Notwithstanding the foregoing, the\r
+ * authors grant the U.S. Government and others acting in its behalf\r
+ * permission to use and distribute the software in accordance with the\r
+ * terms specified in this license.\r
+ */\r
+\r
+typedef struct _internal_arg_dstr {\r
+ char* data;\r
+ arg_dstr_freefn* free_proc;\r
+ char sbuf[ARG_DSTR_SIZE + 1];\r
+ char* append_data;\r
+ int append_data_size;\r
+ int append_used;\r
+} _internal_arg_dstr_t;\r
+\r
+static void setup_append_buf(arg_dstr_t res, int newSpace);\r
+\r
+arg_dstr_t arg_dstr_create(void) {\r
+ _internal_arg_dstr_t* h = (_internal_arg_dstr_t*)xmalloc(sizeof(_internal_arg_dstr_t));\r
+ memset(h, 0, sizeof(_internal_arg_dstr_t));\r
+ h->sbuf[0] = 0;\r
+ h->data = h->sbuf;\r
+ h->free_proc = ARG_DSTR_STATIC;\r
+ return h;\r
+}\r
+\r
+void arg_dstr_destroy(arg_dstr_t ds) {\r
+ if (ds == NULL)\r
+ return;\r
+\r
+ arg_dstr_reset(ds);\r
+ xfree(ds);\r
+ return;\r
+}\r
+\r
+void arg_dstr_set(arg_dstr_t ds, char* str, arg_dstr_freefn* free_proc) {\r
+ int length;\r
+ register arg_dstr_freefn* old_free_proc = ds->free_proc;\r
+ char* old_result = ds->data;\r
+\r
+ if (str == NULL) {\r
+ ds->sbuf[0] = 0;\r
+ ds->data = ds->sbuf;\r
+ ds->free_proc = ARG_DSTR_STATIC;\r
+ } else if (free_proc == ARG_DSTR_VOLATILE) {\r
+ length = (int)strlen(str);\r
+ if (length > ARG_DSTR_SIZE) {\r
+ ds->data = (char*)xmalloc((unsigned)length + 1);\r
+ ds->free_proc = ARG_DSTR_DYNAMIC;\r
+ } else {\r
+ ds->data = ds->sbuf;\r
+ ds->free_proc = ARG_DSTR_STATIC;\r
+ }\r
+ strcpy(ds->data, str);\r
+ } else {\r
+ ds->data = str;\r
+ ds->free_proc = free_proc;\r
+ }\r
+\r
+ /*\r
+ * If the old result was dynamically-allocated, free it up. Do it here,\r
+ * rather than at the beginning, in case the new result value was part of\r
+ * the old result value.\r
+ */\r
+\r
+ if ((old_free_proc != 0) && (old_result != ds->data)) {\r
+ if (old_free_proc == ARG_DSTR_DYNAMIC) {\r
+ xfree(old_result);\r
+ } else {\r
+ (*old_free_proc)(old_result);\r
+ }\r
+ }\r
+\r
+ if ((ds->append_data != NULL) && (ds->append_data_size > 0)) {\r
+ xfree(ds->append_data);\r
+ ds->append_data = NULL;\r
+ ds->append_data_size = 0;\r
+ }\r
+}\r
+\r
+char* arg_dstr_cstr(arg_dstr_t ds) /* Interpreter whose result to return. */\r
+{\r
+ return ds->data;\r
+}\r
+\r
+void arg_dstr_cat(arg_dstr_t ds, const char* str) {\r
+ setup_append_buf(ds, (int)strlen(str) + 1);\r
+ memcpy(ds->data + strlen(ds->data), str, strlen(str));\r
+}\r
+\r
+void arg_dstr_catc(arg_dstr_t ds, char c) {\r
+ setup_append_buf(ds, 2);\r
+ memcpy(ds->data + strlen(ds->data), &c, 1);\r
+}\r
+\r
+/*\r
+ * The logic of the `arg_dstr_catf` function is adapted from the `bformat`\r
+ * function in The Better String Library by Paul Hsieh. Here is the copyright\r
+ * notice from the library:\r
+ *\r
+ * Copyright (c) 2014, Paul Hsieh\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ *\r
+ * * Redistributions of source code must retain the above copyright notice, this\r
+ * list of conditions and the following disclaimer.\r
+ *\r
+ * * Redistributions in binary form must reproduce the above copyright notice,\r
+ * this list of conditions and the following disclaimer in the documentation\r
+ * and/or other materials provided with the distribution.\r
+ *\r
+ * * Neither the name of bstrlib nor the names of its\r
+ * contributors may be used to endorse or promote products derived from\r
+ * this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\r
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\r
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+void arg_dstr_catf(arg_dstr_t ds, const char* fmt, ...) {\r
+ va_list arglist;\r
+ char* buff;\r
+ int n, r;\r
+ size_t slen;\r
+\r
+ if (fmt == NULL)\r
+ return;\r
+\r
+ /* Since the length is not determinable beforehand, a search is\r
+ performed using the truncating "vsnprintf" call (to avoid buffer\r
+ overflows) on increasing potential sizes for the output result. */\r
+\r
+ if ((n = (int)(2 * strlen(fmt))) < START_VSNBUFF)\r
+ n = START_VSNBUFF;\r
+\r
+ buff = (char*)xmalloc(n + 2);\r
+ memset(buff, 0, n + 2);\r
+\r
+ for (;;) {\r
+ va_start(arglist, fmt);\r
+ r = vsnprintf(buff, n + 1, fmt, arglist);\r
+ va_end(arglist);\r
+\r
+ slen = strlen(buff);\r
+ if (slen < (size_t)n)\r
+ break;\r
+\r
+ if (r > n)\r
+ n = r;\r
+ else\r
+ n += n;\r
+\r
+ xfree(buff);\r
+ buff = (char*)xmalloc(n + 2);\r
+ memset(buff, 0, n + 2);\r
+ }\r
+\r
+ arg_dstr_cat(ds, buff);\r
+ xfree(buff);\r
+}\r
+\r
+static void setup_append_buf(arg_dstr_t ds, int new_space) {\r
+ int total_space;\r
+\r
+ /*\r
+ * Make the append buffer larger, if that's necessary, then copy the\r
+ * data into the append buffer and make the append buffer the official\r
+ * data.\r
+ */\r
+ if (ds->data != ds->append_data) {\r
+ /*\r
+ * If the buffer is too big, then free it up so we go back to a\r
+ * smaller buffer. This avoids tying up memory forever after a large\r
+ * operation.\r
+ */\r
+ if (ds->append_data_size > 500) {\r
+ xfree(ds->append_data);\r
+ ds->append_data = NULL;\r
+ ds->append_data_size = 0;\r
+ }\r
+ ds->append_used = (int)strlen(ds->data);\r
+ } else if (ds->data[ds->append_used] != 0) {\r
+ /*\r
+ * Most likely someone has modified a result created by\r
+ * arg_dstr_cat et al. so that it has a different size. Just\r
+ * recompute the size.\r
+ */\r
+ ds->append_used = (int)strlen(ds->data);\r
+ }\r
+\r
+ total_space = new_space + ds->append_used;\r
+ if (total_space >= ds->append_data_size) {\r
+ char* newbuf;\r
+\r
+ if (total_space < 100) {\r
+ total_space = 200;\r
+ } else {\r
+ total_space *= 2;\r
+ }\r
+ newbuf = (char*)xmalloc((unsigned)total_space);\r
+ memset(newbuf, 0, total_space);\r
+ strcpy(newbuf, ds->data);\r
+ if (ds->append_data != NULL) {\r
+ xfree(ds->append_data);\r
+ }\r
+ ds->append_data = newbuf;\r
+ ds->append_data_size = total_space;\r
+ } else if (ds->data != ds->append_data) {\r
+ strcpy(ds->append_data, ds->data);\r
+ }\r
+\r
+ arg_dstr_free(ds);\r
+ ds->data = ds->append_data;\r
+}\r
+\r
+void arg_dstr_free(arg_dstr_t ds) {\r
+ if (ds->free_proc != NULL) {\r
+ if (ds->free_proc == ARG_DSTR_DYNAMIC) {\r
+ xfree(ds->data);\r
+ } else {\r
+ (*ds->free_proc)(ds->data);\r
+ }\r
+ ds->free_proc = NULL;\r
+ }\r
+}\r
+\r
+void arg_dstr_reset(arg_dstr_t ds) {\r
+ arg_dstr_free(ds);\r
+ if ((ds->append_data != NULL) && (ds->append_data_size > 0)) {\r
+ xfree(ds->append_data);\r
+ ds->append_data = NULL;\r
+ ds->append_data_size = 0;\r
+ }\r
+\r
+ ds->data = ds->sbuf;\r
+ ds->sbuf[0] = 0;\r
+}\r
+\r
+#if defined(_MSC_VER)\r
+#pragma warning(pop)\r
+#endif\r
+/* $Id: getopt.h,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $ */\r
+/* $OpenBSD: getopt.h,v 1.1 2002/12/03 20:24:29 millert Exp $ */\r
+/* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */\r
+\r
+/*\r
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.\r
+ * All rights reserved.\r
+ *\r
+ * This code is derived from software contributed to The NetBSD Foundation\r
+ * by Dieter Baron and Thomas Klausner.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions\r
+ * are met:\r
+ * 1. Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in the\r
+ * documentation and/or other materials provided with the distribution.\r
+ * 3. All advertising materials mentioning features or use of this software\r
+ * must display the following acknowledgment:\r
+ * This product includes software developed by the NetBSD\r
+ * Foundation, Inc. and its contributors.\r
+ * 4. Neither the name of The NetBSD Foundation nor the names of its\r
+ * contributors may be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS\r
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\r
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS\r
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+ * POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+\r
+#if ARG_REPLACE_GETOPT == 1\r
+\r
+#ifndef _GETOPT_H_\r
+#define _GETOPT_H_\r
+\r
+/*\r
+ * GNU-like getopt_long() and 4.4BSD getsubopt()/optreset extensions\r
+ */\r
+#define no_argument 0\r
+#define required_argument 1\r
+#define optional_argument 2\r
+\r
+struct option {\r
+ /* name of long option */\r
+ const char* name;\r
+ /*\r
+ * one of no_argument, required_argument, and optional_argument:\r
+ * whether option takes an argument\r
+ */\r
+ int has_arg;\r
+ /* if not NULL, set *flag to val when option found */\r
+ int* flag;\r
+ /* if flag not NULL, value to set *flag to; else return value */\r
+ int val;\r
+};\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+int getopt_long(int, char* const*, const char*, const struct option*, int*);\r
+int getopt_long_only(int, char* const*, const char*, const struct option*, int*);\r
+#ifndef _GETOPT_DEFINED\r
+#define _GETOPT_DEFINED\r
+int getopt(int, char* const*, const char*);\r
+int getsubopt(char**, char* const*, char**);\r
+\r
+extern char* optarg; /* getopt(3) external variables */\r
+extern int opterr;\r
+extern int optind;\r
+extern int optopt;\r
+extern int optreset;\r
+extern char* suboptarg; /* getsubopt(3) external variable */\r
+#endif /* _GETOPT_DEFINED */\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+#endif /* !_GETOPT_H_ */\r
+\r
+#else\r
+#include <getopt.h>\r
+#endif /* ARG_REPLACE_GETOPT */\r
+/* $Id: getopt_long.c,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $ */\r
+/* $OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl Exp $ */\r
+/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */\r
+\r
+/*\r
+ * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>\r
+ *\r
+ * Permission to use, copy, modify, and distribute this software for any\r
+ * purpose with or without fee is hereby granted, provided that the above\r
+ * copyright notice and this permission notice appear in all copies.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\r
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\r
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\r
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\r
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\r
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\r
+ *\r
+ * Sponsored in part by the Defense Advanced Research Projects\r
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force\r
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.\r
+ * All rights reserved.\r
+ *\r
+ * This code is derived from software contributed to The NetBSD Foundation\r
+ * by Dieter Baron and Thomas Klausner.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions\r
+ * are met:\r
+ * 1. Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in the\r
+ * documentation and/or other materials provided with the distribution.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS\r
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\r
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS\r
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+ * POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+\r
+#include "argtable3.h"\r
+\r
+#ifndef ARG_AMALGAMATION\r
+#include "getopt.h"\r
+#endif\r
+\r
+#include <errno.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#if ARG_REPLACE_GETOPT == 1\r
+int opterr = 1; /* if error message should be printed */\r
+int optind = 1; /* index into parent argv vector */\r
+int optopt = '?'; /* character checked for validity */\r
+int optreset; /* reset getopt */\r
+char* optarg; /* argument associated with option */\r
+#endif /* ARG_REPLACE_GETOPT */\r
+\r
+#define PRINT_ERROR ((opterr) && (*options != ':'))\r
+\r
+#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */\r
+#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */\r
+#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */\r
+\r
+/* return values */\r
+#define BADCH (int)'?'\r
+#define BADARG ((*options == ':') ? (int)':' : (int)'?')\r
+#define INORDER (int)1\r
+\r
+#define EMSG ""\r
+\r
+#if ARG_REPLACE_GETOPT == 1\r
+static int getopt_internal(int, char* const*, const char*, const struct option*, int*, int);\r
+#endif /* ARG_REPLACE_GETOPT */\r
+static int parse_long_options(char* const*, const char*, const struct option*, int*, int);\r
+static int gcd(int, int);\r
+static void permute_args(int, int, int, char* const*);\r
+\r
+static char* place = EMSG; /* option letter processing */\r
+\r
+/* XXX: set optreset to 1 rather than these two */\r
+static int nonopt_start = -1; /* first non option argument (for permute) */\r
+static int nonopt_end = -1; /* first option after non options (for permute) */\r
+\r
+/* Error messages */\r
+static const char recargchar[] = "option requires an argument -- %c";\r
+static const char recargstring[] = "option requires an argument -- %s";\r
+static const char ambig[] = "ambiguous option -- %.*s";\r
+static const char noarg[] = "option doesn't take an argument -- %.*s";\r
+static const char illoptchar[] = "unknown option -- %c";\r
+static const char illoptstring[] = "unknown option -- %s";\r
+\r
+#ifdef _WIN32\r
+\r
+/* \r
+ * Windows needs warnx(). We change the definition though:\r
+ * 1. (another) global is defined, opterrmsg, which holds the error message\r
+ * 2. errors are always printed out on stderr w/o the program name\r
+ * Note that opterrmsg always gets set no matter what opterr is set to. The\r
+ * error message will not be printed if opterr is 0 as usual.\r
+ */\r
+\r
+#include <stdarg.h>\r
+#include <stdio.h>\r
+\r
+#define MAX_OPTERRMSG_SIZE 128\r
+\r
+extern char opterrmsg[MAX_OPTERRMSG_SIZE];\r
+char opterrmsg[MAX_OPTERRMSG_SIZE]; /* buffer for the last error message */\r
+\r
+static void warnx(const char* fmt, ...) {\r
+ va_list ap;\r
+ va_start(ap, fmt);\r
+\r
+ /* \r
+ * Make sure opterrmsg is always zero-terminated despite the _vsnprintf()\r
+ * implementation specifics and manually suppress the warning.\r
+ */\r
+ memset(opterrmsg, 0, sizeof(opterrmsg));\r
+ if (fmt != NULL)\r
+#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__))\r
+ _vsnprintf_s(opterrmsg, sizeof(opterrmsg), sizeof(opterrmsg) - 1, fmt, ap);\r
+#else\r
+ _vsnprintf(opterrmsg, sizeof(opterrmsg) - 1, fmt, ap);\r
+#endif\r
+\r
+ va_end(ap);\r
+\r
+#ifdef _MSC_VER\r
+#pragma warning(suppress : 6053)\r
+#endif\r
+ fprintf(stderr, "%s\n", opterrmsg);\r
+}\r
+\r
+#else\r
+#include <err.h>\r
+#endif /*_WIN32*/\r
+\r
+/*\r
+ * Compute the greatest common divisor of a and b.\r
+ */\r
+static int gcd(int a, int b) {\r
+ int c;\r
+\r
+ c = a % b;\r
+ while (c != 0) {\r
+ a = b;\r
+ b = c;\r
+ c = a % b;\r
+ }\r
+\r
+ return (b);\r
+}\r
+\r
+/*\r
+ * Exchange the block from nonopt_start to nonopt_end with the block\r
+ * from nonopt_end to opt_end (keeping the same order of arguments\r
+ * in each block).\r
+ */\r
+static void permute_args(int panonopt_start, int panonopt_end, int opt_end, char* const* nargv) {\r
+ int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;\r
+ char* swap;\r
+\r
+ /*\r
+ * compute lengths of blocks and number and size of cycles\r
+ */\r
+ nnonopts = panonopt_end - panonopt_start;\r
+ nopts = opt_end - panonopt_end;\r
+ ncycle = gcd(nnonopts, nopts);\r
+ cyclelen = (opt_end - panonopt_start) / ncycle;\r
+\r
+ for (i = 0; i < ncycle; i++) {\r
+ cstart = panonopt_end + i;\r
+ pos = cstart;\r
+ for (j = 0; j < cyclelen; j++) {\r
+ if (pos >= panonopt_end)\r
+ pos -= nnonopts;\r
+ else\r
+ pos += nopts;\r
+ swap = nargv[pos];\r
+ /* LINTED const cast */\r
+ ((char**)nargv)[pos] = nargv[cstart];\r
+ /* LINTED const cast */\r
+ ((char**)nargv)[cstart] = swap;\r
+ }\r
+ }\r
+}\r
+\r
+/*\r
+ * parse_long_options --\r
+ * Parse long options in argc/argv argument vector.\r
+ * Returns -1 if short_too is set and the option does not match long_options.\r
+ */\r
+static int parse_long_options(char* const* nargv, const char* options, const struct option* long_options, int* idx, int short_too) {\r
+ char *current_argv, *has_equal;\r
+ size_t current_argv_len;\r
+ int i, match;\r
+\r
+ current_argv = place;\r
+ match = -1;\r
+\r
+ optind++;\r
+\r
+ if ((has_equal = strchr(current_argv, '=')) != NULL) {\r
+ /* argument found (--option=arg) */\r
+ current_argv_len = has_equal - current_argv;\r
+ has_equal++;\r
+ } else\r
+ current_argv_len = strlen(current_argv);\r
+\r
+ for (i = 0; long_options[i].name; i++) {\r
+ /* find matching long option */\r
+ if (strncmp(current_argv, long_options[i].name, current_argv_len))\r
+ continue;\r
+\r
+ if (strlen(long_options[i].name) == current_argv_len) {\r
+ /* exact match */\r
+ match = i;\r
+ break;\r
+ }\r
+ /*\r
+ * If this is a known short option, don't allow\r
+ * a partial match of a single character.\r
+ */\r
+ if (short_too && current_argv_len == 1)\r
+ continue;\r
+\r
+ if (match == -1) /* partial match */\r
+ match = i;\r
+ else {\r
+ /* ambiguous abbreviation */\r
+ if (PRINT_ERROR)\r
+ warnx(ambig, (int)current_argv_len, current_argv);\r
+ optopt = 0;\r
+ return (BADCH);\r
+ }\r
+ }\r
+ if (match != -1) { /* option found */\r
+ if (long_options[match].has_arg == no_argument && has_equal) {\r
+ if (PRINT_ERROR)\r
+ warnx(noarg, (int)current_argv_len, current_argv);\r
+ /*\r
+ * XXX: GNU sets optopt to val regardless of flag\r
+ */\r
+ if (long_options[match].flag == NULL)\r
+ optopt = long_options[match].val;\r
+ else\r
+ optopt = 0;\r
+ return (BADARG);\r
+ }\r
+ if (long_options[match].has_arg == required_argument || long_options[match].has_arg == optional_argument) {\r
+ if (has_equal)\r
+ optarg = has_equal;\r
+ else if (long_options[match].has_arg == required_argument) {\r
+ /*\r
+ * optional argument doesn't use next nargv\r
+ */\r
+ optarg = nargv[optind++];\r
+ }\r
+ }\r
+ if ((long_options[match].has_arg == required_argument) && (optarg == NULL)) {\r
+ /*\r
+ * Missing argument; leading ':' indicates no error\r
+ * should be generated.\r
+ */\r
+ if (PRINT_ERROR)\r
+ warnx(recargstring, current_argv);\r
+ /*\r
+ * XXX: GNU sets optopt to val regardless of flag\r
+ */\r
+ if (long_options[match].flag == NULL)\r
+ optopt = long_options[match].val;\r
+ else\r
+ optopt = 0;\r
+ --optind;\r
+ return (BADARG);\r
+ }\r
+ } else { /* unknown option */\r
+ if (short_too) {\r
+ --optind;\r
+ return (-1);\r
+ }\r
+ if (PRINT_ERROR)\r
+ warnx(illoptstring, current_argv);\r
+ optopt = 0;\r
+ return (BADCH);\r
+ }\r
+ if (idx)\r
+ *idx = match;\r
+ if (long_options[match].flag) {\r
+ *long_options[match].flag = long_options[match].val;\r
+ return (0);\r
+ } else\r
+ return (long_options[match].val);\r
+}\r
+\r
+#if ARG_REPLACE_GETOPT == 1\r
+/*\r
+ * getopt_internal --\r
+ * Parse argc/argv argument vector. Called by user level routines.\r
+ */\r
+static int getopt_internal(int nargc, char* const* nargv, const char* options, const struct option* long_options, int* idx, int flags) {\r
+ char* oli; /* option letter list index */\r
+ int optchar, short_too;\r
+ static int posixly_correct = -1;\r
+\r
+ if (options == NULL)\r
+ return (-1);\r
+\r
+ /*\r
+ * Disable GNU extensions if POSIXLY_CORRECT is set or options\r
+ * string begins with a '+'.\r
+ */\r
+ if (posixly_correct == -1)\r
+#if defined(_MSC_VER)\r
+#pragma warning(push)\r
+#pragma warning(disable : 4996)\r
+#endif\r
+ posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);\r
+#if defined(_MSC_VER)\r
+#pragma warning(pop)\r
+#endif\r
+ if (posixly_correct || *options == '+')\r
+ flags &= ~FLAG_PERMUTE;\r
+ else if (*options == '-')\r
+ flags |= FLAG_ALLARGS;\r
+ if (*options == '+' || *options == '-')\r
+ options++;\r
+\r
+ /*\r
+ * XXX Some GNU programs (like cvs) set optind to 0 instead of\r
+ * XXX using optreset. Work around this braindamage.\r
+ */\r
+ if (optind == 0)\r
+ optind = optreset = 1;\r
+\r
+ optarg = NULL;\r
+ if (optreset)\r
+ nonopt_start = nonopt_end = -1;\r
+start:\r
+ if (optreset || !*place) { /* update scanning pointer */\r
+ optreset = 0;\r
+ if (optind >= nargc) { /* end of argument vector */\r
+ place = EMSG;\r
+ if (nonopt_end != -1) {\r
+ /* do permutation, if we have to */\r
+ permute_args(nonopt_start, nonopt_end, optind, nargv);\r
+ optind -= nonopt_end - nonopt_start;\r
+ } else if (nonopt_start != -1) {\r
+ /*\r
+ * If we skipped non-options, set optind\r
+ * to the first of them.\r
+ */\r
+ optind = nonopt_start;\r
+ }\r
+ nonopt_start = nonopt_end = -1;\r
+ return (-1);\r
+ }\r
+ if (*(place = nargv[optind]) != '-' || (place[1] == '\0' && strchr(options, '-') == NULL)) {\r
+ place = EMSG; /* found non-option */\r
+ if (flags & FLAG_ALLARGS) {\r
+ /*\r
+ * GNU extension:\r
+ * return non-option as argument to option 1\r
+ */\r
+ optarg = nargv[optind++];\r
+ return (INORDER);\r
+ }\r
+ if (!(flags & FLAG_PERMUTE)) {\r
+ /*\r
+ * If no permutation wanted, stop parsing\r
+ * at first non-option.\r
+ */\r
+ return (-1);\r
+ }\r
+ /* do permutation */\r
+ if (nonopt_start == -1)\r
+ nonopt_start = optind;\r
+ else if (nonopt_end != -1) {\r
+ permute_args(nonopt_start, nonopt_end, optind, nargv);\r
+ nonopt_start = optind - (nonopt_end - nonopt_start);\r
+ nonopt_end = -1;\r
+ }\r
+ optind++;\r
+ /* process next argument */\r
+ goto start;\r
+ }\r
+ if (nonopt_start != -1 && nonopt_end == -1)\r
+ nonopt_end = optind;\r
+\r
+ /*\r
+ * If we have "-" do nothing, if "--" we are done.\r
+ */\r
+ if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {\r
+ optind++;\r
+ place = EMSG;\r
+ /*\r
+ * We found an option (--), so if we skipped\r
+ * non-options, we have to permute.\r
+ */\r
+ if (nonopt_end != -1) {\r
+ permute_args(nonopt_start, nonopt_end, optind, nargv);\r
+ optind -= nonopt_end - nonopt_start;\r
+ }\r
+ nonopt_start = nonopt_end = -1;\r
+ return (-1);\r
+ }\r
+ }\r
+\r
+ /*\r
+ * Check long options if:\r
+ * 1) we were passed some\r
+ * 2) the arg is not just "-"\r
+ * 3) either the arg starts with -- we are getopt_long_only()\r
+ */\r
+ if (long_options != NULL && place != nargv[optind] && (*place == '-' || (flags & FLAG_LONGONLY))) {\r
+ short_too = 0;\r
+ if (*place == '-')\r
+ place++; /* --foo long option */\r
+ else if (*place != ':' && strchr(options, *place) != NULL)\r
+ short_too = 1; /* could be short option too */\r
+\r
+ optchar = parse_long_options(nargv, options, long_options, idx, short_too);\r
+ if (optchar != -1) {\r
+ place = EMSG;\r
+ return (optchar);\r
+ }\r
+ }\r
+\r
+ if ((optchar = (int)*place++) == (int)':' || (optchar == (int)'-' && *place != '\0') || (oli = strchr(options, optchar)) == NULL) {\r
+ /*\r
+ * If the user specified "-" and '-' isn't listed in\r
+ * options, return -1 (non-option) as per POSIX.\r
+ * Otherwise, it is an unknown option character (or ':').\r
+ */\r
+ if (optchar == (int)'-' && *place == '\0')\r
+ return (-1);\r
+ if (!*place)\r
+ ++optind;\r
+ if (PRINT_ERROR)\r
+ warnx(illoptchar, optchar);\r
+ optopt = optchar;\r
+ return (BADCH);\r
+ }\r
+ if (long_options != NULL && optchar == 'W' && oli[1] == ';') {\r
+ /* -W long-option */\r
+ if (*place) /* no space */\r
+ /* NOTHING */;\r
+ else if (++optind >= nargc) { /* no arg */\r
+ place = EMSG;\r
+ if (PRINT_ERROR)\r
+ warnx(recargchar, optchar);\r
+ optopt = optchar;\r
+ return (BADARG);\r
+ } else /* white space */\r
+ place = nargv[optind];\r
+ optchar = parse_long_options(nargv, options, long_options, idx, 0);\r
+ place = EMSG;\r
+ return (optchar);\r
+ }\r
+ if (*++oli != ':') { /* doesn't take argument */\r
+ if (!*place)\r
+ ++optind;\r
+ } else { /* takes (optional) argument */\r
+ optarg = NULL;\r
+ if (*place) /* no white space */\r
+ optarg = place;\r
+ else if (oli[1] != ':') { /* arg not optional */\r
+ if (++optind >= nargc) { /* no arg */\r
+ place = EMSG;\r
+ if (PRINT_ERROR)\r
+ warnx(recargchar, optchar);\r
+ optopt = optchar;\r
+ return (BADARG);\r
+ } else\r
+ optarg = nargv[optind];\r
+ }\r
+ place = EMSG;\r
+ ++optind;\r
+ }\r
+ /* dump back option letter */\r
+ return (optchar);\r
+}\r
+\r
+/*\r
+ * getopt --\r
+ * Parse argc/argv argument vector.\r
+ *\r
+ * [eventually this will replace the BSD getopt]\r
+ */\r
+int getopt(int nargc, char* const* nargv, const char* options) {\r
+ /*\r
+ * We don't pass FLAG_PERMUTE to getopt_internal() since\r
+ * the BSD getopt(3) (unlike GNU) has never done this.\r
+ *\r
+ * Furthermore, since many privileged programs call getopt()\r
+ * before dropping privileges it makes sense to keep things\r
+ * as simple (and bug-free) as possible.\r
+ */\r
+ return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));\r
+}\r
+#endif /* ARG_REPLACE_GETOPT */\r
+\r
+/*\r
+ * getopt_long --\r
+ * Parse argc/argv argument vector.\r
+ */\r
+int getopt_long(int nargc, char* const* nargv, const char* options, const struct option* long_options, int* idx) {\r
+ return (getopt_internal(nargc, nargv, options, long_options, idx, FLAG_PERMUTE));\r
+}\r
+\r
+/*\r
+ * getopt_long_only --\r
+ * Parse argc/argv argument vector.\r
+ */\r
+int getopt_long_only(int nargc, char* const* nargv, const char* options, const struct option* long_options, int* idx) {\r
+ return (getopt_internal(nargc, nargv, options, long_options, idx, FLAG_PERMUTE | FLAG_LONGONLY));\r
+}\r
+/*******************************************************************************\r
+ * arg_date: Implements the date command-line option\r
+ *\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann\r
+ * <sheitmann@users.sourceforge.net>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ * * Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ * * Redistributions in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in the\r
+ * documentation and/or other materials provided with the distribution.\r
+ * * Neither the name of STEWART HEITMANN nor the names of its contributors\r
+ * may be used to endorse or promote products derived from this software\r
+ * without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#include "argtable3.h"\r
+\r
+#ifndef ARG_AMALGAMATION\r
+#include "argtable3_private.h"\r
+#endif\r
+\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+char* arg_strptime(const char* buf, const char* fmt, struct tm* tm);\r
+\r
+static void arg_date_resetfn(struct arg_date* parent) {\r
+ ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));\r
+ parent->count = 0;\r
+}\r
+\r
+static int arg_date_scanfn(struct arg_date* parent, const char* argval) {\r
+ int errorcode = 0;\r
+\r
+ if (parent->count == parent->hdr.maxcount) {\r
+ errorcode = ARG_ERR_MAXCOUNT;\r
+ } else if (!argval) {\r
+ /* no argument value was given, leave parent->tmval[] unaltered but still count it */\r
+ parent->count++;\r
+ } else {\r
+ const char* pend;\r
+ struct tm tm = parent->tmval[parent->count];\r
+\r
+ /* parse the given argument value, store result in parent->tmval[] */\r
+ pend = arg_strptime(argval, parent->format, &tm);\r
+ if (pend && pend[0] == '\0')\r
+ parent->tmval[parent->count++] = tm;\r
+ else\r
+ errorcode = ARG_ERR_BADDATE;\r
+ }\r
+\r
+ ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));\r
+ return errorcode;\r
+}\r
+\r
+static int arg_date_checkfn(struct arg_date* parent) {\r
+ int errorcode = (parent->count < parent->hdr.mincount) ? ARG_ERR_MINCOUNT : 0;\r
+\r
+ ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));\r
+ return errorcode;\r
+}\r
+\r
+static void arg_date_errorfn(struct arg_date* parent, arg_dstr_t ds, int errorcode, const char* argval, const char* progname) {\r
+ const char* shortopts = parent->hdr.shortopts;\r
+ const char* longopts = parent->hdr.longopts;\r
+ const char* datatype = parent->hdr.datatype;\r
+\r
+ /* make argval NULL safe */\r
+ argval = argval ? argval : "";\r
+\r
+ arg_dstr_catf(ds, "%s: ", progname);\r
+ switch (errorcode) {\r
+ case ARG_ERR_MINCOUNT:\r
+ arg_dstr_cat(ds, "missing option ");\r
+ arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");\r
+ break;\r
+\r
+ case ARG_ERR_MAXCOUNT:\r
+ arg_dstr_cat(ds, "excess option ");\r
+ arg_print_option_ds(ds, shortopts, longopts, argval, "\n");\r
+ break;\r
+\r
+ case ARG_ERR_BADDATE: {\r
+ struct tm tm;\r
+ char buff[200];\r
+\r
+ arg_dstr_catf(ds, "illegal timestamp format \"%s\"\n", argval);\r
+ memset(&tm, 0, sizeof(tm));\r
+ arg_strptime("1999-12-31 23:59:59", "%F %H:%M:%S", &tm);\r
+ strftime(buff, sizeof(buff), parent->format, &tm);\r
+ arg_dstr_catf(ds, "correct format is \"%s\"\n", buff);\r
+ break;\r
+ }\r
+ }\r
+}\r
+\r
+struct arg_date* arg_date0(const char* shortopts, const char* longopts, const char* format, const char* datatype, const char* glossary) {\r
+ return arg_daten(shortopts, longopts, format, datatype, 0, 1, glossary);\r
+}\r
+\r
+struct arg_date* arg_date1(const char* shortopts, const char* longopts, const char* format, const char* datatype, const char* glossary) {\r
+ return arg_daten(shortopts, longopts, format, datatype, 1, 1, glossary);\r
+}\r
+\r
+struct arg_date*\r
+arg_daten(const char* shortopts, const char* longopts, const char* format, const char* datatype, int mincount, int maxcount, const char* glossary) {\r
+ size_t nbytes;\r
+ struct arg_date* result;\r
+\r
+ /* foolproof things by ensuring maxcount is not less than mincount */\r
+ maxcount = (maxcount < mincount) ? mincount : maxcount;\r
+\r
+ /* default time format is the national date format for the locale */\r
+ if (!format)\r
+ format = "%x";\r
+\r
+ nbytes = sizeof(struct arg_date) /* storage for struct arg_date */\r
+ + maxcount * sizeof(struct tm); /* storage for tmval[maxcount] array */\r
+\r
+ /* allocate storage for the arg_date struct + tmval[] array. */\r
+ /* we use calloc because we want the tmval[] array zero filled. */\r
+ result = (struct arg_date*)xcalloc(1, nbytes);\r
+\r
+ /* init the arg_hdr struct */\r
+ result->hdr.flag = ARG_HASVALUE;\r
+ result->hdr.shortopts = shortopts;\r
+ result->hdr.longopts = longopts;\r
+ result->hdr.datatype = datatype ? datatype : format;\r
+ result->hdr.glossary = glossary;\r
+ result->hdr.mincount = mincount;\r
+ result->hdr.maxcount = maxcount;\r
+ result->hdr.parent = result;\r
+ result->hdr.resetfn = (arg_resetfn*)arg_date_resetfn;\r
+ result->hdr.scanfn = (arg_scanfn*)arg_date_scanfn;\r
+ result->hdr.checkfn = (arg_checkfn*)arg_date_checkfn;\r
+ result->hdr.errorfn = (arg_errorfn*)arg_date_errorfn;\r
+\r
+ /* store the tmval[maxcount] array immediately after the arg_date struct */\r
+ result->tmval = (struct tm*)(result + 1);\r
+\r
+ /* init the remaining arg_date member variables */\r
+ result->count = 0;\r
+ result->format = format;\r
+\r
+ ARG_TRACE(("arg_daten() returns %p\n", result));\r
+ return result;\r
+}\r
+\r
+/*-\r
+ * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc.\r
+ * All rights reserved.\r
+ *\r
+ * This code was contributed to The NetBSD Foundation by Klaus Klein.\r
+ * Heavily optimised by David Laight\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions\r
+ * are met:\r
+ * 1. Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in the\r
+ * documentation and/or other materials provided with the distribution.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS\r
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\r
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS\r
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+ * POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+\r
+#include <ctype.h>\r
+#include <string.h>\r
+#include <time.h>\r
+\r
+/*\r
+ * We do not implement alternate representations. However, we always\r
+ * check whether a given modifier is allowed for a certain conversion.\r
+ */\r
+#define ALT_E 0x01\r
+#define ALT_O 0x02\r
+#define LEGAL_ALT(x) \\r
+ { \\r
+ if (alt_format & ~(x)) \\r
+ return (0); \\r
+ }\r
+#define TM_YEAR_BASE (1900)\r
+\r
+static int conv_num(const char**, int*, int, int);\r
+\r
+static const char* day[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};\r
+\r
+static const char* abday[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};\r
+\r
+static const char* mon[12] = {"January", "February", "March", "April", "May", "June",\r
+ "July", "August", "September", "October", "November", "December"};\r
+\r
+static const char* abmon[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};\r
+\r
+static const char* am_pm[2] = {"AM", "PM"};\r
+\r
+static int arg_strcasecmp(const char* s1, const char* s2) {\r
+ const unsigned char* us1 = (const unsigned char*)s1;\r
+ const unsigned char* us2 = (const unsigned char*)s2;\r
+ while (tolower(*us1) == tolower(*us2++))\r
+ if (*us1++ == '\0')\r
+ return 0;\r
+\r
+ return tolower(*us1) - tolower(*--us2);\r
+}\r
+\r
+static int arg_strncasecmp(const char* s1, const char* s2, size_t n) {\r
+ if (n != 0) {\r
+ const unsigned char* us1 = (const unsigned char*)s1;\r
+ const unsigned char* us2 = (const unsigned char*)s2;\r
+ do {\r
+ if (tolower(*us1) != tolower(*us2++))\r
+ return tolower(*us1) - tolower(*--us2);\r
+\r
+ if (*us1++ == '\0')\r
+ break;\r
+ } while (--n != 0);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+char* arg_strptime(const char* buf, const char* fmt, struct tm* tm) {\r
+ char c;\r
+ const char* bp;\r
+ size_t len = 0;\r
+ int alt_format, i, split_year = 0;\r
+\r
+ bp = buf;\r
+\r
+ while ((c = *fmt) != '\0') {\r
+ /* Clear `alternate' modifier prior to new conversion. */\r
+ alt_format = 0;\r
+\r
+ /* Eat up white-space. */\r
+ if (isspace(c)) {\r
+ while (isspace(*bp))\r
+ bp++;\r
+\r
+ fmt++;\r
+ continue;\r
+ }\r
+\r
+ if ((c = *fmt++) != '%')\r
+ goto literal;\r
+\r
+ again:\r
+ switch (c = *fmt++) {\r
+ case '%': /* "%%" is converted to "%". */\r
+ literal:\r
+ if (c != *bp++)\r
+ return (0);\r
+ break;\r
+\r
+ /*\r
+ * "Alternative" modifiers. Just set the appropriate flag\r
+ * and start over again.\r
+ */\r
+ case 'E': /* "%E?" alternative conversion modifier. */\r
+ LEGAL_ALT(0);\r
+ alt_format |= ALT_E;\r
+ goto again;\r
+\r
+ case 'O': /* "%O?" alternative conversion modifier. */\r
+ LEGAL_ALT(0);\r
+ alt_format |= ALT_O;\r
+ goto again;\r
+\r
+ /*\r
+ * "Complex" conversion rules, implemented through recursion.\r
+ */\r
+ case 'c': /* Date and time, using the locale's format. */\r
+ LEGAL_ALT(ALT_E);\r
+ bp = arg_strptime(bp, "%x %X", tm);\r
+ if (!bp)\r
+ return (0);\r
+ break;\r
+\r
+ case 'D': /* The date as "%m/%d/%y". */\r
+ LEGAL_ALT(0);\r
+ bp = arg_strptime(bp, "%m/%d/%y", tm);\r
+ if (!bp)\r
+ return (0);\r
+ break;\r
+\r
+ case 'R': /* The time as "%H:%M". */\r
+ LEGAL_ALT(0);\r
+ bp = arg_strptime(bp, "%H:%M", tm);\r
+ if (!bp)\r
+ return (0);\r
+ break;\r
+\r
+ case 'r': /* The time in 12-hour clock representation. */\r
+ LEGAL_ALT(0);\r
+ bp = arg_strptime(bp, "%I:%M:%S %p", tm);\r
+ if (!bp)\r
+ return (0);\r
+ break;\r
+\r
+ case 'T': /* The time as "%H:%M:%S". */\r
+ LEGAL_ALT(0);\r
+ bp = arg_strptime(bp, "%H:%M:%S", tm);\r
+ if (!bp)\r
+ return (0);\r
+ break;\r
+\r
+ case 'X': /* The time, using the locale's format. */\r
+ LEGAL_ALT(ALT_E);\r
+ bp = arg_strptime(bp, "%H:%M:%S", tm);\r
+ if (!bp)\r
+ return (0);\r
+ break;\r
+\r
+ case 'x': /* The date, using the locale's format. */\r
+ LEGAL_ALT(ALT_E);\r
+ bp = arg_strptime(bp, "%m/%d/%y", tm);\r
+ if (!bp)\r
+ return (0);\r
+ break;\r
+\r
+ /*\r
+ * "Elementary" conversion rules.\r
+ */\r
+ case 'A': /* The day of week, using the locale's form. */\r
+ case 'a':\r
+ LEGAL_ALT(0);\r
+ for (i = 0; i < 7; i++) {\r
+ /* Full name. */\r
+ len = strlen(day[i]);\r
+ if (arg_strncasecmp(day[i], bp, len) == 0)\r
+ break;\r
+\r
+ /* Abbreviated name. */\r
+ len = strlen(abday[i]);\r
+ if (arg_strncasecmp(abday[i], bp, len) == 0)\r
+ break;\r
+ }\r
+\r
+ /* Nothing matched. */\r
+ if (i == 7)\r
+ return (0);\r
+\r
+ tm->tm_wday = i;\r
+ bp += len;\r
+ break;\r
+\r
+ case 'B': /* The month, using the locale's form. */\r
+ case 'b':\r
+ case 'h':\r
+ LEGAL_ALT(0);\r
+ for (i = 0; i < 12; i++) {\r
+ /* Full name. */\r
+ len = strlen(mon[i]);\r
+ if (arg_strncasecmp(mon[i], bp, len) == 0)\r
+ break;\r
+\r
+ /* Abbreviated name. */\r
+ len = strlen(abmon[i]);\r
+ if (arg_strncasecmp(abmon[i], bp, len) == 0)\r
+ break;\r
+ }\r
+\r
+ /* Nothing matched. */\r
+ if (i == 12)\r
+ return (0);\r
+\r
+ tm->tm_mon = i;\r
+ bp += len;\r
+ break;\r
+\r
+ case 'C': /* The century number. */\r
+ LEGAL_ALT(ALT_E);\r
+ if (!(conv_num(&bp, &i, 0, 99)))\r
+ return (0);\r
+\r
+ if (split_year) {\r
+ tm->tm_year = (tm->tm_year % 100) + (i * 100);\r
+ } else {\r
+ tm->tm_year = i * 100;\r
+ split_year = 1;\r
+ }\r
+ break;\r
+\r
+ case 'd': /* The day of month. */\r
+ case 'e':\r
+ LEGAL_ALT(ALT_O);\r
+ if (!(conv_num(&bp, &tm->tm_mday, 1, 31)))\r
+ return (0);\r
+ break;\r
+\r
+ case 'k': /* The hour (24-hour clock representation). */\r
+ LEGAL_ALT(0);\r
+ /* FALLTHROUGH */\r
+ case 'H':\r
+ LEGAL_ALT(ALT_O);\r
+ if (!(conv_num(&bp, &tm->tm_hour, 0, 23)))\r
+ return (0);\r
+ break;\r
+\r
+ case 'l': /* The hour (12-hour clock representation). */\r
+ LEGAL_ALT(0);\r
+ /* FALLTHROUGH */\r
+ case 'I':\r
+ LEGAL_ALT(ALT_O);\r
+ if (!(conv_num(&bp, &tm->tm_hour, 1, 12)))\r
+ return (0);\r
+ if (tm->tm_hour == 12)\r
+ tm->tm_hour = 0;\r
+ break;\r
+\r
+ case 'j': /* The day of year. */\r
+ LEGAL_ALT(0);\r
+ if (!(conv_num(&bp, &i, 1, 366)))\r
+ return (0);\r
+ tm->tm_yday = i - 1;\r
+ break;\r
+\r
+ case 'M': /* The minute. */\r
+ LEGAL_ALT(ALT_O);\r
+ if (!(conv_num(&bp, &tm->tm_min, 0, 59)))\r
+ return (0);\r
+ break;\r
+\r
+ case 'm': /* The month. */\r
+ LEGAL_ALT(ALT_O);\r
+ if (!(conv_num(&bp, &i, 1, 12)))\r
+ return (0);\r
+ tm->tm_mon = i - 1;\r
+ break;\r
+\r
+ case 'p': /* The locale's equivalent of AM/PM. */\r
+ LEGAL_ALT(0);\r
+ /* AM? */\r
+ if (arg_strcasecmp(am_pm[0], bp) == 0) {\r
+ if (tm->tm_hour > 11)\r
+ return (0);\r
+\r
+ bp += strlen(am_pm[0]);\r
+ break;\r
+ }\r
+ /* PM? */\r
+ else if (arg_strcasecmp(am_pm[1], bp) == 0) {\r
+ if (tm->tm_hour > 11)\r
+ return (0);\r
+\r
+ tm->tm_hour += 12;\r
+ bp += strlen(am_pm[1]);\r
+ break;\r
+ }\r
+\r
+ /* Nothing matched. */\r
+ return (0);\r
+\r
+ case 'S': /* The seconds. */\r
+ LEGAL_ALT(ALT_O);\r
+ if (!(conv_num(&bp, &tm->tm_sec, 0, 61)))\r
+ return (0);\r
+ break;\r
+\r
+ case 'U': /* The week of year, beginning on sunday. */\r
+ case 'W': /* The week of year, beginning on monday. */\r
+ LEGAL_ALT(ALT_O);\r
+ /*\r
+ * XXX This is bogus, as we can not assume any valid\r
+ * information present in the tm structure at this\r
+ * point to calculate a real value, so just check the\r
+ * range for now.\r
+ */\r
+ if (!(conv_num(&bp, &i, 0, 53)))\r
+ return (0);\r
+ break;\r
+\r
+ case 'w': /* The day of week, beginning on sunday. */\r
+ LEGAL_ALT(ALT_O);\r
+ if (!(conv_num(&bp, &tm->tm_wday, 0, 6)))\r
+ return (0);\r
+ break;\r
+\r
+ case 'Y': /* The year. */\r
+ LEGAL_ALT(ALT_E);\r
+ if (!(conv_num(&bp, &i, 0, 9999)))\r
+ return (0);\r
+\r
+ tm->tm_year = i - TM_YEAR_BASE;\r
+ break;\r
+\r
+ case 'y': /* The year within 100 years of the epoch. */\r
+ LEGAL_ALT(ALT_E | ALT_O);\r
+ if (!(conv_num(&bp, &i, 0, 99)))\r
+ return (0);\r
+\r
+ if (split_year) {\r
+ tm->tm_year = ((tm->tm_year / 100) * 100) + i;\r
+ break;\r
+ }\r
+ split_year = 1;\r
+ if (i <= 68)\r
+ tm->tm_year = i + 2000 - TM_YEAR_BASE;\r
+ else\r
+ tm->tm_year = i + 1900 - TM_YEAR_BASE;\r
+ break;\r
+\r
+ /*\r
+ * Miscellaneous conversions.\r
+ */\r
+ case 'n': /* Any kind of white-space. */\r
+ case 't':\r
+ LEGAL_ALT(0);\r
+ while (isspace(*bp))\r
+ bp++;\r
+ break;\r
+\r
+ default: /* Unknown/unsupported conversion. */\r
+ return (0);\r
+ }\r
+ }\r
+\r
+ /* LINTED functional specification */\r
+ return ((char*)bp);\r
+}\r
+\r
+static int conv_num(const char** buf, int* dest, int llim, int ulim) {\r
+ int result = 0;\r
+\r
+ /* The limit also determines the number of valid digits. */\r
+ int rulim = ulim;\r
+\r
+ if (**buf < '0' || **buf > '9')\r
+ return (0);\r
+\r
+ do {\r
+ result *= 10;\r
+ result += *(*buf)++ - '0';\r
+ rulim /= 10;\r
+ } while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9');\r
+\r
+ if (result < llim || result > ulim)\r
+ return (0);\r
+\r
+ *dest = result;\r
+ return (1);\r
+}\r
+/*******************************************************************************\r
+ * arg_dbl: Implements the double command-line option\r
+ *\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann\r
+ * <sheitmann@users.sourceforge.net>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ * * Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ * * Redistributions in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in the\r
+ * documentation and/or other materials provided with the distribution.\r
+ * * Neither the name of STEWART HEITMANN nor the names of its contributors\r
+ * may be used to endorse or promote products derived from this software\r
+ * without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#include "argtable3.h"\r
+\r
+#ifndef ARG_AMALGAMATION\r
+#include "argtable3_private.h"\r
+#endif\r
+\r
+#include <stdlib.h>\r
+\r
+static void arg_dbl_resetfn(struct arg_dbl* parent) {\r
+ ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));\r
+ parent->count = 0;\r
+}\r
+\r
+static int arg_dbl_scanfn(struct arg_dbl* parent, const char* argval) {\r
+ int errorcode = 0;\r
+\r
+ if (parent->count == parent->hdr.maxcount) {\r
+ /* maximum number of arguments exceeded */\r
+ errorcode = ARG_ERR_MAXCOUNT;\r
+ } else if (!argval) {\r
+ /* a valid argument with no argument value was given. */\r
+ /* This happens when an optional argument value was invoked. */\r
+ /* leave parent argument value unaltered but still count the argument. */\r
+ parent->count++;\r
+ } else {\r
+ double val;\r
+ char* end;\r
+\r
+ /* extract double from argval into val */\r
+ val = strtod(argval, &end);\r
+\r
+ /* if success then store result in parent->dval[] array otherwise return error*/\r
+ if (*end == 0)\r
+ parent->dval[parent->count++] = val;\r
+ else\r
+ errorcode = ARG_ERR_BADDOUBLE;\r
+ }\r
+\r
+ ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));\r
+ return errorcode;\r
+}\r
+\r
+static int arg_dbl_checkfn(struct arg_dbl* parent) {\r
+ int errorcode = (parent->count < parent->hdr.mincount) ? ARG_ERR_MINCOUNT : 0;\r
+\r
+ ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));\r
+ return errorcode;\r
+}\r
+\r
+static void arg_dbl_errorfn(struct arg_dbl* parent, arg_dstr_t ds, int errorcode, const char* argval, const char* progname) {\r
+ const char* shortopts = parent->hdr.shortopts;\r
+ const char* longopts = parent->hdr.longopts;\r
+ const char* datatype = parent->hdr.datatype;\r
+\r
+ /* make argval NULL safe */\r
+ argval = argval ? argval : "";\r
+\r
+ arg_dstr_catf(ds, "%s: ", progname);\r
+ switch (errorcode) {\r
+ case ARG_ERR_MINCOUNT:\r
+ arg_dstr_cat(ds, "missing option ");\r
+ arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");\r
+ break;\r
+\r
+ case ARG_ERR_MAXCOUNT:\r
+ arg_dstr_cat(ds, "excess option ");\r
+ arg_print_option_ds(ds, shortopts, longopts, argval, "\n");\r
+ break;\r
+\r
+ case ARG_ERR_BADDOUBLE:\r
+ arg_dstr_catf(ds, "invalid argument \"%s\" to option ", argval);\r
+ arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");\r
+ break;\r
+ }\r
+}\r
+\r
+struct arg_dbl* arg_dbl0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) {\r
+ return arg_dbln(shortopts, longopts, datatype, 0, 1, glossary);\r
+}\r
+\r
+struct arg_dbl* arg_dbl1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) {\r
+ return arg_dbln(shortopts, longopts, datatype, 1, 1, glossary);\r
+}\r
+\r
+struct arg_dbl* arg_dbln(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary) {\r
+ size_t nbytes;\r
+ struct arg_dbl* result;\r
+ size_t addr;\r
+ size_t rem;\r
+\r
+ /* foolproof things by ensuring maxcount is not less than mincount */\r
+ maxcount = (maxcount < mincount) ? mincount : maxcount;\r
+\r
+ nbytes = sizeof(struct arg_dbl) /* storage for struct arg_dbl */\r
+ + (maxcount + 1) * sizeof(double); /* storage for dval[maxcount] array plus one extra for padding to memory boundary */\r
+\r
+ result = (struct arg_dbl*)xmalloc(nbytes);\r
+\r
+ /* init the arg_hdr struct */\r
+ result->hdr.flag = ARG_HASVALUE;\r
+ result->hdr.shortopts = shortopts;\r
+ result->hdr.longopts = longopts;\r
+ result->hdr.datatype = datatype ? datatype : "<double>";\r
+ result->hdr.glossary = glossary;\r
+ result->hdr.mincount = mincount;\r
+ result->hdr.maxcount = maxcount;\r
+ result->hdr.parent = result;\r
+ result->hdr.resetfn = (arg_resetfn*)arg_dbl_resetfn;\r
+ result->hdr.scanfn = (arg_scanfn*)arg_dbl_scanfn;\r
+ result->hdr.checkfn = (arg_checkfn*)arg_dbl_checkfn;\r
+ result->hdr.errorfn = (arg_errorfn*)arg_dbl_errorfn;\r
+\r
+ /* Store the dval[maxcount] array on the first double boundary that\r
+ * immediately follows the arg_dbl struct. We do the memory alignment\r
+ * purely for SPARC and Motorola systems. They require floats and\r
+ * doubles to be aligned on natural boundaries.\r
+ */\r
+ addr = (size_t)(result + 1);\r
+ rem = addr % sizeof(double);\r
+ result->dval = (double*)(addr + sizeof(double) - rem);\r
+ ARG_TRACE(("addr=%p, dval=%p, sizeof(double)=%d rem=%d\n", addr, result->dval, (int)sizeof(double), (int)rem));\r
+\r
+ result->count = 0;\r
+\r
+ ARG_TRACE(("arg_dbln() returns %p\n", result));\r
+ return result;\r
+}\r
+/*******************************************************************************\r
+ * arg_end: Implements the error handling utilities\r
+ *\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann\r
+ * <sheitmann@users.sourceforge.net>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ * * Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ * * Redistributions in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in the\r
+ * documentation and/or other materials provided with the distribution.\r
+ * * Neither the name of STEWART HEITMANN nor the names of its contributors\r
+ * may be used to endorse or promote products derived from this software\r
+ * without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#include "argtable3.h"\r
+\r
+#ifndef ARG_AMALGAMATION\r
+#include "argtable3_private.h"\r
+#endif\r
+\r
+#include <stdlib.h>\r
+\r
+static void arg_end_resetfn(struct arg_end* parent) {\r
+ ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));\r
+ parent->count = 0;\r
+}\r
+\r
+static void arg_end_errorfn(void* parent, arg_dstr_t ds, int error, const char* argval, const char* progname) {\r
+ /* suppress unreferenced formal parameter warning */\r
+ (void)parent;\r
+\r
+ progname = progname ? progname : "";\r
+ argval = argval ? argval : "";\r
+\r
+ arg_dstr_catf(ds, "%s: ", progname);\r
+ switch (error) {\r
+ case ARG_ELIMIT:\r
+ arg_dstr_cat(ds, "too many errors to display");\r
+ break;\r
+ case ARG_EMALLOC:\r
+ arg_dstr_cat(ds, "insufficient memory");\r
+ break;\r
+ case ARG_ENOMATCH:\r
+ arg_dstr_catf(ds, "unexpected argument \"%s\"", argval);\r
+ break;\r
+ case ARG_EMISSARG:\r
+ arg_dstr_catf(ds, "option \"%s\" requires an argument", argval);\r
+ break;\r
+ case ARG_ELONGOPT:\r
+ arg_dstr_catf(ds, "invalid option \"%s\"", argval);\r
+ break;\r
+ default:\r
+ arg_dstr_catf(ds, "invalid option \"-%c\"", error);\r
+ break;\r
+ }\r
+\r
+ arg_dstr_cat(ds, "\n");\r
+}\r
+\r
+struct arg_end* arg_end(int maxcount) {\r
+ size_t nbytes;\r
+ struct arg_end* result;\r
+\r
+ nbytes = sizeof(struct arg_end) + maxcount * sizeof(int) /* storage for int error[maxcount] array*/\r
+ + maxcount * sizeof(void*) /* storage for void* parent[maxcount] array */\r
+ + maxcount * sizeof(char*); /* storage for char* argval[maxcount] array */\r
+\r
+ result = (struct arg_end*)xmalloc(nbytes);\r
+\r
+ /* init the arg_hdr struct */\r
+ result->hdr.flag = ARG_TERMINATOR;\r
+ result->hdr.shortopts = NULL;\r
+ result->hdr.longopts = NULL;\r
+ result->hdr.datatype = NULL;\r
+ result->hdr.glossary = NULL;\r
+ result->hdr.mincount = 1;\r
+ result->hdr.maxcount = maxcount;\r
+ result->hdr.parent = result;\r
+ result->hdr.resetfn = (arg_resetfn*)arg_end_resetfn;\r
+ result->hdr.scanfn = NULL;\r
+ result->hdr.checkfn = NULL;\r
+ result->hdr.errorfn = (arg_errorfn*)arg_end_errorfn;\r
+\r
+ /* store error[maxcount] array immediately after struct arg_end */\r
+ result->error = (int*)(result + 1);\r
+\r
+ /* store parent[maxcount] array immediately after error[] array */\r
+ result->parent = (void**)(result->error + maxcount);\r
+\r
+ /* store argval[maxcount] array immediately after parent[] array */\r
+ result->argval = (const char**)(result->parent + maxcount);\r
+\r
+ ARG_TRACE(("arg_end(%d) returns %p\n", maxcount, result));\r
+ return result;\r
+}\r
+\r
+void arg_print_errors_ds(arg_dstr_t ds, struct arg_end* end, const char* progname) {\r
+ int i;\r
+ ARG_TRACE(("arg_errors()\n"));\r
+ for (i = 0; i < end->count; i++) {\r
+ struct arg_hdr* errorparent = (struct arg_hdr*)(end->parent[i]);\r
+ if (errorparent->errorfn)\r
+ errorparent->errorfn(end->parent[i], ds, end->error[i], end->argval[i], progname);\r
+ }\r
+}\r
+\r
+void arg_print_errors(FILE* fp, struct arg_end* end, const char* progname) {\r
+ arg_dstr_t ds = arg_dstr_create();\r
+ arg_print_errors_ds(ds, end, progname);\r
+ fputs(arg_dstr_cstr(ds), fp);\r
+ arg_dstr_destroy(ds);\r
+}\r
+/*******************************************************************************\r
+ * arg_file: Implements the file command-line option\r
+ *\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann\r
+ * <sheitmann@users.sourceforge.net>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ * * Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ * * Redistributions in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in the\r
+ * documentation and/or other materials provided with the distribution.\r
+ * * Neither the name of STEWART HEITMANN nor the names of its contributors\r
+ * may be used to endorse or promote products derived from this software\r
+ * without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#include "argtable3.h"\r
+\r
+#ifndef ARG_AMALGAMATION\r
+#include "argtable3_private.h"\r
+#endif\r
+\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#ifdef WIN32\r
+#define FILESEPARATOR1 '\\'\r
+#define FILESEPARATOR2 '/'\r
+#else\r
+#define FILESEPARATOR1 '/'\r
+#define FILESEPARATOR2 '/'\r
+#endif\r
+\r
+static void arg_file_resetfn(struct arg_file* parent) {\r
+ ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));\r
+ parent->count = 0;\r
+}\r
+\r
+/* Returns ptr to the base filename within *filename */\r
+static const char* arg_basename(const char* filename) {\r
+ const char *result = NULL, *result1, *result2;\r
+\r
+ /* Find the last occurrence of eother file separator character. */\r
+ /* Two alternative file separator chars are supported as legal */\r
+ /* file separators but not both together in the same filename. */\r
+ result1 = (filename ? strrchr(filename, FILESEPARATOR1) : NULL);\r
+ result2 = (filename ? strrchr(filename, FILESEPARATOR2) : NULL);\r
+\r
+ if (result2)\r
+ result = result2 + 1; /* using FILESEPARATOR2 (the alternative file separator) */\r
+\r
+ if (result1)\r
+ result = result1 + 1; /* using FILESEPARATOR1 (the preferred file separator) */\r
+\r
+ if (!result)\r
+ result = filename; /* neither file separator was found so basename is the whole filename */\r
+\r
+ /* special cases of "." and ".." are not considered basenames */\r
+ if (result && (strcmp(".", result) == 0 || strcmp("..", result) == 0))\r
+ result = filename + strlen(filename);\r
+\r
+ return result;\r
+}\r
+\r
+/* Returns ptr to the file extension within *basename */\r
+static const char* arg_extension(const char* basename) {\r
+ /* find the last occurrence of '.' in basename */\r
+ const char* result = (basename ? strrchr(basename, '.') : NULL);\r
+\r
+ /* if no '.' was found then return pointer to end of basename */\r
+ if (basename && !result)\r
+ result = basename + strlen(basename);\r
+\r
+ /* special case: basenames with a single leading dot (eg ".foo") are not considered as true extensions */\r
+ if (basename && result == basename)\r
+ result = basename + strlen(basename);\r
+\r
+ /* special case: empty extensions (eg "foo.","foo..") are not considered as true extensions */\r
+ if (basename && result && result[1] == '\0')\r
+ result = basename + strlen(basename);\r
+\r
+ return result;\r
+}\r
+\r
+static int arg_file_scanfn(struct arg_file* parent, const char* argval) {\r
+ int errorcode = 0;\r
+\r
+ if (parent->count == parent->hdr.maxcount) {\r
+ /* maximum number of arguments exceeded */\r
+ errorcode = ARG_ERR_MAXCOUNT;\r
+ } else if (!argval) {\r
+ /* a valid argument with no argument value was given. */\r
+ /* This happens when an optional argument value was invoked. */\r
+ /* leave parent arguiment value unaltered but still count the argument. */\r
+ parent->count++;\r
+ } else {\r
+ parent->filename[parent->count] = argval;\r
+ parent->basename[parent->count] = arg_basename(argval);\r
+ parent->extension[parent->count] =\r
+ arg_extension(parent->basename[parent->count]); /* only seek extensions within the basename (not the file path)*/\r
+ parent->count++;\r
+ }\r
+\r
+ ARG_TRACE(("%s4:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));\r
+ return errorcode;\r
+}\r
+\r
+static int arg_file_checkfn(struct arg_file* parent) {\r
+ int errorcode = (parent->count < parent->hdr.mincount) ? ARG_ERR_MINCOUNT : 0;\r
+\r
+ ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));\r
+ return errorcode;\r
+}\r
+\r
+static void arg_file_errorfn(struct arg_file* parent, arg_dstr_t ds, int errorcode, const char* argval, const char* progname) {\r
+ const char* shortopts = parent->hdr.shortopts;\r
+ const char* longopts = parent->hdr.longopts;\r
+ const char* datatype = parent->hdr.datatype;\r
+\r
+ /* make argval NULL safe */\r
+ argval = argval ? argval : "";\r
+\r
+ arg_dstr_catf(ds, "%s: ", progname);\r
+ switch (errorcode) {\r
+ case ARG_ERR_MINCOUNT:\r
+ arg_dstr_cat(ds, "missing option ");\r
+ arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");\r
+ break;\r
+\r
+ case ARG_ERR_MAXCOUNT:\r
+ arg_dstr_cat(ds, "excess option ");\r
+ arg_print_option_ds(ds, shortopts, longopts, argval, "\n");\r
+ break;\r
+\r
+ default:\r
+ arg_dstr_catf(ds, "unknown error at \"%s\"\n", argval);\r
+ }\r
+}\r
+\r
+struct arg_file* arg_file0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) {\r
+ return arg_filen(shortopts, longopts, datatype, 0, 1, glossary);\r
+}\r
+\r
+struct arg_file* arg_file1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) {\r
+ return arg_filen(shortopts, longopts, datatype, 1, 1, glossary);\r
+}\r
+\r
+struct arg_file* arg_filen(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary) {\r
+ size_t nbytes;\r
+ struct arg_file* result;\r
+ int i;\r
+\r
+ /* foolproof things by ensuring maxcount is not less than mincount */\r
+ maxcount = (maxcount < mincount) ? mincount : maxcount;\r
+\r
+ nbytes = sizeof(struct arg_file) /* storage for struct arg_file */\r
+ + sizeof(char*) * maxcount /* storage for filename[maxcount] array */\r
+ + sizeof(char*) * maxcount /* storage for basename[maxcount] array */\r
+ + sizeof(char*) * maxcount; /* storage for extension[maxcount] array */\r
+\r
+ result = (struct arg_file*)xmalloc(nbytes);\r
+\r
+ /* init the arg_hdr struct */\r
+ result->hdr.flag = ARG_HASVALUE;\r
+ result->hdr.shortopts = shortopts;\r
+ result->hdr.longopts = longopts;\r
+ result->hdr.glossary = glossary;\r
+ result->hdr.datatype = datatype ? datatype : "<file>";\r
+ result->hdr.mincount = mincount;\r
+ result->hdr.maxcount = maxcount;\r
+ result->hdr.parent = result;\r
+ result->hdr.resetfn = (arg_resetfn*)arg_file_resetfn;\r
+ result->hdr.scanfn = (arg_scanfn*)arg_file_scanfn;\r
+ result->hdr.checkfn = (arg_checkfn*)arg_file_checkfn;\r
+ result->hdr.errorfn = (arg_errorfn*)arg_file_errorfn;\r
+\r
+ /* store the filename,basename,extension arrays immediately after the arg_file struct */\r
+ result->filename = (const char**)(result + 1);\r
+ result->basename = result->filename + maxcount;\r
+ result->extension = result->basename + maxcount;\r
+ result->count = 0;\r
+\r
+ /* foolproof the string pointers by initialising them with empty strings */\r
+ for (i = 0; i < maxcount; i++) {\r
+ result->filename[i] = "";\r
+ result->basename[i] = "";\r
+ result->extension[i] = "";\r
+ }\r
+\r
+ ARG_TRACE(("arg_filen() returns %p\n", result));\r
+ return result;\r
+}\r
+/*******************************************************************************\r
+ * arg_int: Implements the int command-line option\r
+ *\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann\r
+ * <sheitmann@users.sourceforge.net>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ * * Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ * * Redistributions in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in the\r
+ * documentation and/or other materials provided with the distribution.\r
+ * * Neither the name of STEWART HEITMANN nor the names of its contributors\r
+ * may be used to endorse or promote products derived from this software\r
+ * without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#include "argtable3.h"\r
+\r
+#ifndef ARG_AMALGAMATION\r
+#include "argtable3_private.h"\r
+#endif\r
+\r
+#include <ctype.h>\r
+#include <limits.h>\r
+#include <stdlib.h>\r
+\r
+static void arg_int_resetfn(struct arg_int* parent) {\r
+ ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));\r
+ parent->count = 0;\r
+}\r
+\r
+/* strtol0x() is like strtol() except that the numeric string is */\r
+/* expected to be prefixed by "0X" where X is a user supplied char. */\r
+/* The string may optionally be prefixed by white space and + or - */\r
+/* as in +0X123 or -0X123. */\r
+/* Once the prefix has been scanned, the remainder of the numeric */\r
+/* string is converted using strtol() with the given base. */\r
+/* eg: to parse hex str="-0X12324", specify X='X' and base=16. */\r
+/* eg: to parse oct str="+0o12324", specify X='O' and base=8. */\r
+/* eg: to parse bin str="-0B01010", specify X='B' and base=2. */\r
+/* Failure of conversion is indicated by result where *endptr==str. */\r
+static long int strtol0X(const char* str, const char** endptr, char X, int base) {\r
+ long int val; /* stores result */\r
+ int s = 1; /* sign is +1 or -1 */\r
+ const char* ptr = str; /* ptr to current position in str */\r
+\r
+ /* skip leading whitespace */\r
+ while (isspace(*ptr))\r
+ ptr++;\r
+ /* printf("1) %s\n",ptr); */\r
+\r
+ /* scan optional sign character */\r
+ switch (*ptr) {\r
+ case '+':\r
+ ptr++;\r
+ s = 1;\r
+ break;\r
+ case '-':\r
+ ptr++;\r
+ s = -1;\r
+ break;\r
+ default:\r
+ s = 1;\r
+ break;\r
+ }\r
+ /* printf("2) %s\n",ptr); */\r
+\r
+ /* '0X' prefix */\r
+ if ((*ptr++) != '0') {\r
+ /* printf("failed to detect '0'\n"); */\r
+ *endptr = str;\r
+ return 0;\r
+ }\r
+ /* printf("3) %s\n",ptr); */\r
+ if (toupper(*ptr++) != toupper(X)) {\r
+ /* printf("failed to detect '%c'\n",X); */\r
+ *endptr = str;\r
+ return 0;\r
+ }\r
+ /* printf("4) %s\n",ptr); */\r
+\r
+ /* attempt conversion on remainder of string using strtol() */\r
+ val = strtol(ptr, (char**)endptr, base);\r
+ if (*endptr == ptr) {\r
+ /* conversion failed */\r
+ *endptr = str;\r
+ return 0;\r
+ }\r
+\r
+ /* success */\r
+ return s * val;\r
+}\r
+\r
+/* Returns 1 if str matches suffix (case insensitive). */\r
+/* Str may contain trailing whitespace, but nothing else. */\r
+static int detectsuffix(const char* str, const char* suffix) {\r
+ /* scan pairwise through strings until mismatch detected */\r
+ while (toupper(*str) == toupper(*suffix)) {\r
+ /* printf("'%c' '%c'\n", *str, *suffix); */\r
+\r
+ /* return 1 (success) if match persists until the string terminator */\r
+ if (*str == '\0')\r
+ return 1;\r
+\r
+ /* next chars */\r
+ str++;\r
+ suffix++;\r
+ }\r
+ /* printf("'%c' '%c' mismatch\n", *str, *suffix); */\r
+\r
+ /* return 0 (fail) if the matching did not consume the entire suffix */\r
+ if (*suffix != 0)\r
+ return 0; /* failed to consume entire suffix */\r
+\r
+ /* skip any remaining whitespace in str */\r
+ while (isspace(*str))\r
+ str++;\r
+\r
+ /* return 1 (success) if we have reached end of str else return 0 (fail) */\r
+ return (*str == '\0') ? 1 : 0;\r
+}\r
+\r
+static int arg_int_scanfn(struct arg_int* parent, const char* argval) {\r
+ int errorcode = 0;\r
+\r
+ if (parent->count == parent->hdr.maxcount) {\r
+ /* maximum number of arguments exceeded */\r
+ errorcode = ARG_ERR_MAXCOUNT;\r
+ } else if (!argval) {\r
+ /* a valid argument with no argument value was given. */\r
+ /* This happens when an optional argument value was invoked. */\r
+ /* leave parent arguiment value unaltered but still count the argument. */\r
+ parent->count++;\r
+ } else {\r
+ long int val;\r
+ const char* end;\r
+\r
+ /* attempt to extract hex integer (eg: +0x123) from argval into val conversion */\r
+ val = strtol0X(argval, &end, 'X', 16);\r
+ if (end == argval) {\r
+ /* hex failed, attempt octal conversion (eg +0o123) */\r
+ val = strtol0X(argval, &end, 'O', 8);\r
+ if (end == argval) {\r
+ /* octal failed, attempt binary conversion (eg +0B101) */\r
+ val = strtol0X(argval, &end, 'B', 2);\r
+ if (end == argval) {\r
+ /* binary failed, attempt decimal conversion with no prefix (eg 1234) */\r
+ val = strtol(argval, (char**)&end, 10);\r
+ if (end == argval) {\r
+ /* all supported number formats failed */\r
+ return ARG_ERR_BADINT;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /* Safety check for integer overflow. WARNING: this check */\r
+ /* achieves nothing on machines where size(int)==size(long). */\r
+ if (val > INT_MAX || val < INT_MIN)\r
+ errorcode = ARG_ERR_OVERFLOW;\r
+\r
+ /* Detect any suffixes (KB,MB,GB) and multiply argument value appropriately. */\r
+ /* We need to be mindful of integer overflows when using such big numbers. */\r
+ if (detectsuffix(end, "KB")) /* kilobytes */\r
+ {\r
+ if (val > (INT_MAX / 1024) || val < (INT_MIN / 1024))\r
+ errorcode = ARG_ERR_OVERFLOW; /* Overflow would occur if we proceed */\r
+ else\r
+ val *= 1024; /* 1KB = 1024 */\r
+ } else if (detectsuffix(end, "MB")) /* megabytes */\r
+ {\r
+ if (val > (INT_MAX / 1048576) || val < (INT_MIN / 1048576))\r
+ errorcode = ARG_ERR_OVERFLOW; /* Overflow would occur if we proceed */\r
+ else\r
+ val *= 1048576; /* 1MB = 1024*1024 */\r
+ } else if (detectsuffix(end, "GB")) /* gigabytes */\r
+ {\r
+ if (val > (INT_MAX / 1073741824) || val < (INT_MIN / 1073741824))\r
+ errorcode = ARG_ERR_OVERFLOW; /* Overflow would occur if we proceed */\r
+ else\r
+ val *= 1073741824; /* 1GB = 1024*1024*1024 */\r
+ } else if (!detectsuffix(end, ""))\r
+ errorcode = ARG_ERR_BADINT; /* invalid suffix detected */\r
+\r
+ /* if success then store result in parent->ival[] array */\r
+ if (errorcode == 0)\r
+ parent->ival[parent->count++] = (int)val;\r
+ }\r
+\r
+ /* printf("%s:scanfn(%p,%p) returns %d\n",__FILE__,parent,argval,errorcode); */\r
+ return errorcode;\r
+}\r
+\r
+static int arg_int_checkfn(struct arg_int* parent) {\r
+ int errorcode = (parent->count < parent->hdr.mincount) ? ARG_ERR_MINCOUNT : 0;\r
+ /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/\r
+ return errorcode;\r
+}\r
+\r
+static void arg_int_errorfn(struct arg_int* parent, arg_dstr_t ds, int errorcode, const char* argval, const char* progname) {\r
+ const char* shortopts = parent->hdr.shortopts;\r
+ const char* longopts = parent->hdr.longopts;\r
+ const char* datatype = parent->hdr.datatype;\r
+\r
+ /* make argval NULL safe */\r
+ argval = argval ? argval : "";\r
+\r
+ arg_dstr_catf(ds, "%s: ", progname);\r
+ switch (errorcode) {\r
+ case ARG_ERR_MINCOUNT:\r
+ arg_dstr_cat(ds, "missing option ");\r
+ arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");\r
+ break;\r
+\r
+ case ARG_ERR_MAXCOUNT:\r
+ arg_dstr_cat(ds, "excess option ");\r
+ arg_print_option_ds(ds, shortopts, longopts, argval, "\n");\r
+ break;\r
+\r
+ case ARG_ERR_BADINT:\r
+ arg_dstr_catf(ds, "invalid argument \"%s\" to option ", argval);\r
+ arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");\r
+ break;\r
+\r
+ case ARG_ERR_OVERFLOW:\r
+ arg_dstr_cat(ds, "integer overflow at option ");\r
+ arg_print_option_ds(ds, shortopts, longopts, datatype, " ");\r
+ arg_dstr_catf(ds, "(%s is too large)\n", argval);\r
+ break;\r
+ }\r
+}\r
+\r
+struct arg_int* arg_int0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) {\r
+ return arg_intn(shortopts, longopts, datatype, 0, 1, glossary);\r
+}\r
+\r
+struct arg_int* arg_int1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) {\r
+ return arg_intn(shortopts, longopts, datatype, 1, 1, glossary);\r
+}\r
+\r
+struct arg_int* arg_intn(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary) {\r
+ size_t nbytes;\r
+ struct arg_int* result;\r
+\r
+ /* foolproof things by ensuring maxcount is not less than mincount */\r
+ maxcount = (maxcount < mincount) ? mincount : maxcount;\r
+\r
+ nbytes = sizeof(struct arg_int) /* storage for struct arg_int */\r
+ + maxcount * sizeof(int); /* storage for ival[maxcount] array */\r
+\r
+ result = (struct arg_int*)xmalloc(nbytes);\r
+\r
+ /* init the arg_hdr struct */\r
+ result->hdr.flag = ARG_HASVALUE;\r
+ result->hdr.shortopts = shortopts;\r
+ result->hdr.longopts = longopts;\r
+ result->hdr.datatype = datatype ? datatype : "<int>";\r
+ result->hdr.glossary = glossary;\r
+ result->hdr.mincount = mincount;\r
+ result->hdr.maxcount = maxcount;\r
+ result->hdr.parent = result;\r
+ result->hdr.resetfn = (arg_resetfn*)arg_int_resetfn;\r
+ result->hdr.scanfn = (arg_scanfn*)arg_int_scanfn;\r
+ result->hdr.checkfn = (arg_checkfn*)arg_int_checkfn;\r
+ result->hdr.errorfn = (arg_errorfn*)arg_int_errorfn;\r
+\r
+ /* store the ival[maxcount] array immediately after the arg_int struct */\r
+ result->ival = (int*)(result + 1);\r
+ result->count = 0;\r
+\r
+ ARG_TRACE(("arg_intn() returns %p\n", result));\r
+ return result;\r
+}\r
+/*******************************************************************************\r
+ * arg_lit: Implements the literature command-line option\r
+ *\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann\r
+ * <sheitmann@users.sourceforge.net>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ * * Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ * * Redistributions in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in the\r
+ * documentation and/or other materials provided with the distribution.\r
+ * * Neither the name of STEWART HEITMANN nor the names of its contributors\r
+ * may be used to endorse or promote products derived from this software\r
+ * without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#include "argtable3.h"\r
+\r
+#ifndef ARG_AMALGAMATION\r
+#include "argtable3_private.h"\r
+#endif\r
+\r
+#include <stdlib.h>\r
+\r
+static void arg_lit_resetfn(struct arg_lit* parent) {\r
+ ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));\r
+ parent->count = 0;\r
+}\r
+\r
+static int arg_lit_scanfn(struct arg_lit* parent, const char* argval) {\r
+ int errorcode = 0;\r
+ if (parent->count < parent->hdr.maxcount)\r
+ parent->count++;\r
+ else\r
+ errorcode = ARG_ERR_MAXCOUNT;\r
+\r
+ ARG_TRACE(("%s:scanfn(%p,%s) returns %d\n", __FILE__, parent, argval, errorcode));\r
+ return errorcode;\r
+}\r
+\r
+static int arg_lit_checkfn(struct arg_lit* parent) {\r
+ int errorcode = (parent->count < parent->hdr.mincount) ? ARG_ERR_MINCOUNT : 0;\r
+ ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));\r
+ return errorcode;\r
+}\r
+\r
+static void arg_lit_errorfn(struct arg_lit* parent, arg_dstr_t ds, int errorcode, const char* argval, const char* progname) {\r
+ const char* shortopts = parent->hdr.shortopts;\r
+ const char* longopts = parent->hdr.longopts;\r
+ const char* datatype = parent->hdr.datatype;\r
+\r
+ switch (errorcode) {\r
+ case ARG_ERR_MINCOUNT:\r
+ arg_dstr_catf(ds, "%s: missing option ", progname);\r
+ arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");\r
+ arg_dstr_cat(ds, "\n");\r
+ break;\r
+\r
+ case ARG_ERR_MAXCOUNT:\r
+ arg_dstr_catf(ds, "%s: extraneous option ", progname);\r
+ arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");\r
+ break;\r
+ }\r
+\r
+ ARG_TRACE(("%s:errorfn(%p, %p, %d, %s, %s)\n", __FILE__, parent, ds, errorcode, argval, progname));\r
+}\r
+\r
+struct arg_lit* arg_lit0(const char* shortopts, const char* longopts, const char* glossary) {\r
+ return arg_litn(shortopts, longopts, 0, 1, glossary);\r
+}\r
+\r
+struct arg_lit* arg_lit1(const char* shortopts, const char* longopts, const char* glossary) {\r
+ return arg_litn(shortopts, longopts, 1, 1, glossary);\r
+}\r
+\r
+struct arg_lit* arg_litn(const char* shortopts, const char* longopts, int mincount, int maxcount, const char* glossary) {\r
+ struct arg_lit* result;\r
+\r
+ /* foolproof things by ensuring maxcount is not less than mincount */\r
+ maxcount = (maxcount < mincount) ? mincount : maxcount;\r
+\r
+ result = (struct arg_lit*)xmalloc(sizeof(struct arg_lit));\r
+\r
+ /* init the arg_hdr struct */\r
+ result->hdr.flag = 0;\r
+ result->hdr.shortopts = shortopts;\r
+ result->hdr.longopts = longopts;\r
+ result->hdr.datatype = NULL;\r
+ result->hdr.glossary = glossary;\r
+ result->hdr.mincount = mincount;\r
+ result->hdr.maxcount = maxcount;\r
+ result->hdr.parent = result;\r
+ result->hdr.resetfn = (arg_resetfn*)arg_lit_resetfn;\r
+ result->hdr.scanfn = (arg_scanfn*)arg_lit_scanfn;\r
+ result->hdr.checkfn = (arg_checkfn*)arg_lit_checkfn;\r
+ result->hdr.errorfn = (arg_errorfn*)arg_lit_errorfn;\r
+\r
+ /* init local variables */\r
+ result->count = 0;\r
+\r
+ ARG_TRACE(("arg_litn() returns %p\n", result));\r
+ return result;\r
+}\r
+/*******************************************************************************\r
+ * arg_rem: Implements the rem command-line option\r
+ *\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann\r
+ * <sheitmann@users.sourceforge.net>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ * * Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ * * Redistributions in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in the\r
+ * documentation and/or other materials provided with the distribution.\r
+ * * Neither the name of STEWART HEITMANN nor the names of its contributors\r
+ * may be used to endorse or promote products derived from this software\r
+ * without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#include "argtable3.h"\r
+\r
+#ifndef ARG_AMALGAMATION\r
+#include "argtable3_private.h"\r
+#endif\r
+\r
+#include <stdlib.h>\r
+\r
+struct arg_rem* arg_rem(const char* datatype, const char* glossary) {\r
+ struct arg_rem* result = (struct arg_rem*)xmalloc(sizeof(struct arg_rem));\r
+\r
+ result->hdr.flag = 0;\r
+ result->hdr.shortopts = NULL;\r
+ result->hdr.longopts = NULL;\r
+ result->hdr.datatype = datatype;\r
+ result->hdr.glossary = glossary;\r
+ result->hdr.mincount = 1;\r
+ result->hdr.maxcount = 1;\r
+ result->hdr.parent = result;\r
+ result->hdr.resetfn = NULL;\r
+ result->hdr.scanfn = NULL;\r
+ result->hdr.checkfn = NULL;\r
+ result->hdr.errorfn = NULL;\r
+\r
+ ARG_TRACE(("arg_rem() returns %p\n", result));\r
+ return result;\r
+}\r
+/*******************************************************************************\r
+ * arg_rex: Implements the regex command-line option\r
+ *\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann\r
+ * <sheitmann@users.sourceforge.net>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ * * Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ * * Redistributions in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in the\r
+ * documentation and/or other materials provided with the distribution.\r
+ * * Neither the name of STEWART HEITMANN nor the names of its contributors\r
+ * may be used to endorse or promote products derived from this software\r
+ * without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#include "argtable3.h"\r
+\r
+#ifndef ARG_AMALGAMATION\r
+#include "argtable3_private.h"\r
+#endif\r
+\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#ifndef _TREX_H_\r
+#define _TREX_H_\r
+\r
+/*\r
+ * This module uses the T-Rex regular expression library to implement the regex\r
+ * logic. Here is the copyright notice of the library:\r
+ *\r
+ * Copyright (C) 2003-2006 Alberto Demichelis\r
+ *\r
+ * This software is provided 'as-is', without any express\r
+ * or implied warranty. In no event will the authors be held\r
+ * liable for any damages arising from the use of this software.\r
+ *\r
+ * Permission is granted to anyone to use this software for\r
+ * any purpose, including commercial applications, and to alter\r
+ * it and redistribute it freely, subject to the following restrictions:\r
+ *\r
+ * 1. The origin of this software must not be misrepresented;\r
+ * you must not claim that you wrote the original software.\r
+ * If you use this software in a product, an acknowledgment\r
+ * in the product documentation would be appreciated but\r
+ * is not required.\r
+ *\r
+ * 2. Altered source versions must be plainly marked as such,\r
+ * and must not be misrepresented as being the original software.\r
+ *\r
+ * 3. This notice may not be removed or altered from any\r
+ * source distribution.\r
+ */\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#define TRexChar char\r
+#define MAX_CHAR 0xFF\r
+#define _TREXC(c) (c)\r
+#define trex_strlen strlen\r
+#define trex_printf printf\r
+\r
+#ifndef TREX_API\r
+#define TREX_API extern\r
+#endif\r
+\r
+#define TRex_True 1\r
+#define TRex_False 0\r
+\r
+#define TREX_ICASE ARG_REX_ICASE\r
+\r
+typedef unsigned int TRexBool;\r
+typedef struct TRex TRex;\r
+\r
+typedef struct {\r
+ const TRexChar* begin;\r
+ int len;\r
+} TRexMatch;\r
+\r
+TREX_API TRex* trex_compile(const TRexChar* pattern, const TRexChar** error, int flags);\r
+TREX_API void trex_free(TRex* exp);\r
+TREX_API TRexBool trex_match(TRex* exp, const TRexChar* text);\r
+TREX_API TRexBool trex_search(TRex* exp, const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end);\r
+TREX_API TRexBool\r
+trex_searchrange(TRex* exp, const TRexChar* text_begin, const TRexChar* text_end, const TRexChar** out_begin, const TRexChar** out_end);\r
+TREX_API int trex_getsubexpcount(TRex* exp);\r
+TREX_API TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch* subexp);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif\r
+\r
+struct privhdr {\r
+ const char* pattern;\r
+ int flags;\r
+};\r
+\r
+static void arg_rex_resetfn(struct arg_rex* parent) {\r
+ ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));\r
+ parent->count = 0;\r
+}\r
+\r
+static int arg_rex_scanfn(struct arg_rex* parent, const char* argval) {\r
+ int errorcode = 0;\r
+ const TRexChar* error = NULL;\r
+ TRex* rex = NULL;\r
+ TRexBool is_match = TRex_False;\r
+\r
+ if (parent->count == parent->hdr.maxcount) {\r
+ /* maximum number of arguments exceeded */\r
+ errorcode = ARG_ERR_MAXCOUNT;\r
+ } else if (!argval) {\r
+ /* a valid argument with no argument value was given. */\r
+ /* This happens when an optional argument value was invoked. */\r
+ /* leave parent argument value unaltered but still count the argument. */\r
+ parent->count++;\r
+ } else {\r
+ struct privhdr* priv = (struct privhdr*)parent->hdr.priv;\r
+\r
+ /* test the current argument value for a match with the regular expression */\r
+ /* if a match is detected, record the argument value in the arg_rex struct */\r
+\r
+ rex = trex_compile(priv->pattern, &error, priv->flags);\r
+ is_match = trex_match(rex, argval);\r
+ if (!is_match)\r
+ errorcode = ARG_ERR_REGNOMATCH;\r
+ else\r
+ parent->sval[parent->count++] = argval;\r
+\r
+ trex_free(rex);\r
+ }\r
+\r
+ ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));\r
+ return errorcode;\r
+}\r
+\r
+static int arg_rex_checkfn(struct arg_rex* parent) {\r
+ int errorcode = (parent->count < parent->hdr.mincount) ? ARG_ERR_MINCOUNT : 0;\r
+#if 0\r
+ struct privhdr *priv = (struct privhdr*)parent->hdr.priv;\r
+\r
+ /* free the regex "program" we constructed in resetfn */\r
+ regfree(&(priv->regex));\r
+\r
+ /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/\r
+#endif\r
+ return errorcode;\r
+}\r
+\r
+static void arg_rex_errorfn(struct arg_rex* parent, arg_dstr_t ds, int errorcode, const char* argval, const char* progname) {\r
+ const char* shortopts = parent->hdr.shortopts;\r
+ const char* longopts = parent->hdr.longopts;\r
+ const char* datatype = parent->hdr.datatype;\r
+\r
+ /* make argval NULL safe */\r
+ argval = argval ? argval : "";\r
+\r
+ arg_dstr_catf(ds, "%s: ", progname);\r
+ switch (errorcode) {\r
+ case ARG_ERR_MINCOUNT:\r
+ arg_dstr_cat(ds, "missing option ");\r
+ arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");\r
+ break;\r
+\r
+ case ARG_ERR_MAXCOUNT:\r
+ arg_dstr_cat(ds, "excess option ");\r
+ arg_print_option_ds(ds, shortopts, longopts, argval, "\n");\r
+ break;\r
+\r
+ case ARG_ERR_REGNOMATCH:\r
+ arg_dstr_cat(ds, "illegal value ");\r
+ arg_print_option_ds(ds, shortopts, longopts, argval, "\n");\r
+ break;\r
+\r
+ default: {\r
+ #if 0\r
+ char errbuff[256];\r
+ regerror(errorcode, NULL, errbuff, sizeof(errbuff));\r
+ printf("%s\n", errbuff);\r
+ #endif\r
+ } break;\r
+ }\r
+}\r
+\r
+struct arg_rex* arg_rex0(const char* shortopts, const char* longopts, const char* pattern, const char* datatype, int flags, const char* glossary) {\r
+ return arg_rexn(shortopts, longopts, pattern, datatype, 0, 1, flags, glossary);\r
+}\r
+\r
+struct arg_rex* arg_rex1(const char* shortopts, const char* longopts, const char* pattern, const char* datatype, int flags, const char* glossary) {\r
+ return arg_rexn(shortopts, longopts, pattern, datatype, 1, 1, flags, glossary);\r
+}\r
+\r
+struct arg_rex* arg_rexn(const char* shortopts,\r
+ const char* longopts,\r
+ const char* pattern,\r
+ const char* datatype,\r
+ int mincount,\r
+ int maxcount,\r
+ int flags,\r
+ const char* glossary) {\r
+ size_t nbytes;\r
+ struct arg_rex* result;\r
+ struct privhdr* priv;\r
+ int i;\r
+ const TRexChar* error = NULL;\r
+ TRex* rex = NULL;\r
+\r
+ if (!pattern) {\r
+ printf("argtable: ERROR - illegal regular expression pattern \"(NULL)\"\n");\r
+ printf("argtable: Bad argument table.\n");\r
+ return NULL;\r
+ }\r
+\r
+ /* foolproof things by ensuring maxcount is not less than mincount */\r
+ maxcount = (maxcount < mincount) ? mincount : maxcount;\r
+\r
+ nbytes = sizeof(struct arg_rex) /* storage for struct arg_rex */\r
+ + sizeof(struct privhdr) /* storage for private arg_rex data */\r
+ + maxcount * sizeof(char*); /* storage for sval[maxcount] array */\r
+\r
+ /* init the arg_hdr struct */\r
+ result = (struct arg_rex*)xmalloc(nbytes);\r
+ result->hdr.flag = ARG_HASVALUE;\r
+ result->hdr.shortopts = shortopts;\r
+ result->hdr.longopts = longopts;\r
+ result->hdr.datatype = datatype ? datatype : pattern;\r
+ result->hdr.glossary = glossary;\r
+ result->hdr.mincount = mincount;\r
+ result->hdr.maxcount = maxcount;\r
+ result->hdr.parent = result;\r
+ result->hdr.resetfn = (arg_resetfn*)arg_rex_resetfn;\r
+ result->hdr.scanfn = (arg_scanfn*)arg_rex_scanfn;\r
+ result->hdr.checkfn = (arg_checkfn*)arg_rex_checkfn;\r
+ result->hdr.errorfn = (arg_errorfn*)arg_rex_errorfn;\r
+\r
+ /* store the arg_rex_priv struct immediately after the arg_rex struct */\r
+ result->hdr.priv = result + 1;\r
+ priv = (struct privhdr*)(result->hdr.priv);\r
+ priv->pattern = pattern;\r
+ priv->flags = flags;\r
+\r
+ /* store the sval[maxcount] array immediately after the arg_rex_priv struct */\r
+ result->sval = (const char**)(priv + 1);\r
+ result->count = 0;\r
+\r
+ /* foolproof the string pointers by initializing them to reference empty strings */\r
+ for (i = 0; i < maxcount; i++)\r
+ result->sval[i] = "";\r
+\r
+ /* here we construct and destroy a regex representation of the regular\r
+ * expression for no other reason than to force any regex errors to be\r
+ * trapped now rather than later. If we don't, then errors may go undetected\r
+ * until an argument is actually parsed.\r
+ */\r
+\r
+ rex = trex_compile(priv->pattern, &error, priv->flags);\r
+ if (rex == NULL) {\r
+ ARG_LOG(("argtable: %s \"%s\"\n", error ? error : _TREXC("undefined"), priv->pattern));\r
+ ARG_LOG(("argtable: Bad argument table.\n"));\r
+ }\r
+\r
+ trex_free(rex);\r
+\r
+ ARG_TRACE(("arg_rexn() returns %p\n", result));\r
+ return result;\r
+}\r
+\r
+/* see copyright notice in trex.h */\r
+#include <ctype.h>\r
+#include <setjmp.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#ifdef _UINCODE\r
+#define scisprint iswprint\r
+#define scstrlen wcslen\r
+#define scprintf wprintf\r
+#define _SC(x) L(x)\r
+#else\r
+#define scisprint isprint\r
+#define scstrlen strlen\r
+#define scprintf printf\r
+#define _SC(x) (x)\r
+#endif\r
+\r
+#ifdef _DEBUG\r
+#include <stdio.h>\r
+\r
+static const TRexChar* g_nnames[] = {_SC("NONE"), _SC("OP_GREEDY"), _SC("OP_OR"), _SC("OP_EXPR"), _SC("OP_NOCAPEXPR"),\r
+ _SC("OP_DOT"), _SC("OP_CLASS"), _SC("OP_CCLASS"), _SC("OP_NCLASS"), _SC("OP_RANGE"),\r
+ _SC("OP_CHAR"), _SC("OP_EOL"), _SC("OP_BOL"), _SC("OP_WB")};\r
+\r
+#endif\r
+#define OP_GREEDY (MAX_CHAR + 1) /* * + ? {n} */\r
+#define OP_OR (MAX_CHAR + 2)\r
+#define OP_EXPR (MAX_CHAR + 3) /* parentesis () */\r
+#define OP_NOCAPEXPR (MAX_CHAR + 4) /* parentesis (?:) */\r
+#define OP_DOT (MAX_CHAR + 5)\r
+#define OP_CLASS (MAX_CHAR + 6)\r
+#define OP_CCLASS (MAX_CHAR + 7)\r
+#define OP_NCLASS (MAX_CHAR + 8) /* negates class the [^ */\r
+#define OP_RANGE (MAX_CHAR + 9)\r
+#define OP_CHAR (MAX_CHAR + 10)\r
+#define OP_EOL (MAX_CHAR + 11)\r
+#define OP_BOL (MAX_CHAR + 12)\r
+#define OP_WB (MAX_CHAR + 13)\r
+\r
+#define TREX_SYMBOL_ANY_CHAR ('.')\r
+#define TREX_SYMBOL_GREEDY_ONE_OR_MORE ('+')\r
+#define TREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*')\r
+#define TREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?')\r
+#define TREX_SYMBOL_BRANCH ('|')\r
+#define TREX_SYMBOL_END_OF_STRING ('$')\r
+#define TREX_SYMBOL_BEGINNING_OF_STRING ('^')\r
+#define TREX_SYMBOL_ESCAPE_CHAR ('\\')\r
+\r
+typedef int TRexNodeType;\r
+\r
+typedef struct tagTRexNode {\r
+ TRexNodeType type;\r
+ int left;\r
+ int right;\r
+ int next;\r
+} TRexNode;\r
+\r
+struct TRex {\r
+ const TRexChar* _eol;\r
+ const TRexChar* _bol;\r
+ const TRexChar* _p;\r
+ int _first;\r
+ int _op;\r
+ TRexNode* _nodes;\r
+ int _nallocated;\r
+ int _nsize;\r
+ int _nsubexpr;\r
+ TRexMatch* _matches;\r
+ int _currsubexp;\r
+ void* _jmpbuf;\r
+ const TRexChar** _error;\r
+ int _flags;\r
+};\r
+\r
+static int trex_list(TRex* exp);\r
+\r
+static int trex_newnode(TRex* exp, TRexNodeType type) {\r
+ TRexNode n;\r
+ int newid;\r
+ n.type = type;\r
+ n.next = n.right = n.left = -1;\r
+ if (type == OP_EXPR)\r
+ n.right = exp->_nsubexpr++;\r
+ if (exp->_nallocated < (exp->_nsize + 1)) {\r
+ exp->_nallocated *= 2;\r
+ exp->_nodes = (TRexNode*)xrealloc(exp->_nodes, exp->_nallocated * sizeof(TRexNode));\r
+ }\r
+ exp->_nodes[exp->_nsize++] = n;\r
+ newid = exp->_nsize - 1;\r
+ return (int)newid;\r
+}\r
+\r
+static void trex_error(TRex* exp, const TRexChar* error) {\r
+ if (exp->_error)\r
+ *exp->_error = error;\r
+ longjmp(*((jmp_buf*)exp->_jmpbuf), -1);\r
+}\r
+\r
+static void trex_expect(TRex* exp, int n) {\r
+ if ((*exp->_p) != n)\r
+ trex_error(exp, _SC("expected paren"));\r
+ exp->_p++;\r
+}\r
+\r
+static TRexChar trex_escapechar(TRex* exp) {\r
+ if (*exp->_p == TREX_SYMBOL_ESCAPE_CHAR) {\r
+ exp->_p++;\r
+ switch (*exp->_p) {\r
+ case 'v':\r
+ exp->_p++;\r
+ return '\v';\r
+ case 'n':\r
+ exp->_p++;\r
+ return '\n';\r
+ case 't':\r
+ exp->_p++;\r
+ return '\t';\r
+ case 'r':\r
+ exp->_p++;\r
+ return '\r';\r
+ case 'f':\r
+ exp->_p++;\r
+ return '\f';\r
+ default:\r
+ return (*exp->_p++);\r
+ }\r
+ } else if (!scisprint(*exp->_p))\r
+ trex_error(exp, _SC("letter expected"));\r
+ return (*exp->_p++);\r
+}\r
+\r
+static int trex_charclass(TRex* exp, int classid) {\r
+ int n = trex_newnode(exp, OP_CCLASS);\r
+ exp->_nodes[n].left = classid;\r
+ return n;\r
+}\r
+\r
+static int trex_charnode(TRex* exp, TRexBool isclass) {\r
+ TRexChar t;\r
+ if (*exp->_p == TREX_SYMBOL_ESCAPE_CHAR) {\r
+ exp->_p++;\r
+ switch (*exp->_p) {\r
+ case 'n':\r
+ exp->_p++;\r
+ return trex_newnode(exp, '\n');\r
+ case 't':\r
+ exp->_p++;\r
+ return trex_newnode(exp, '\t');\r
+ case 'r':\r
+ exp->_p++;\r
+ return trex_newnode(exp, '\r');\r
+ case 'f':\r
+ exp->_p++;\r
+ return trex_newnode(exp, '\f');\r
+ case 'v':\r
+ exp->_p++;\r
+ return trex_newnode(exp, '\v');\r
+ case 'a':\r
+ case 'A':\r
+ case 'w':\r
+ case 'W':\r
+ case 's':\r
+ case 'S':\r
+ case 'd':\r
+ case 'D':\r
+ case 'x':\r
+ case 'X':\r
+ case 'c':\r
+ case 'C':\r
+ case 'p':\r
+ case 'P':\r
+ case 'l':\r
+ case 'u': {\r
+ t = *exp->_p;\r
+ exp->_p++;\r
+ return trex_charclass(exp, t);\r
+ }\r
+ case 'b':\r
+ case 'B':\r
+ if (!isclass) {\r
+ int node = trex_newnode(exp, OP_WB);\r
+ exp->_nodes[node].left = *exp->_p;\r
+ exp->_p++;\r
+ return node;\r
+ }\r
+ /* fall through */\r
+ default:\r
+ t = *exp->_p;\r
+ exp->_p++;\r
+ return trex_newnode(exp, t);\r
+ }\r
+ } else if (!scisprint(*exp->_p)) {\r
+ trex_error(exp, _SC("letter expected"));\r
+ }\r
+ t = *exp->_p;\r
+ exp->_p++;\r
+ return trex_newnode(exp, t);\r
+}\r
+static int trex_class(TRex* exp) {\r
+ int ret = -1;\r
+ int first = -1, chain;\r
+ if (*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING) {\r
+ ret = trex_newnode(exp, OP_NCLASS);\r
+ exp->_p++;\r
+ } else\r
+ ret = trex_newnode(exp, OP_CLASS);\r
+\r
+ if (*exp->_p == ']')\r
+ trex_error(exp, _SC("empty class"));\r
+ chain = ret;\r
+ while (*exp->_p != ']' && exp->_p != exp->_eol) {\r
+ if (*exp->_p == '-' && first != -1) {\r
+ int r, t;\r
+ if (*exp->_p++ == ']')\r
+ trex_error(exp, _SC("unfinished range"));\r
+ r = trex_newnode(exp, OP_RANGE);\r
+ if (first > *exp->_p)\r
+ trex_error(exp, _SC("invalid range"));\r
+ if (exp->_nodes[first].type == OP_CCLASS)\r
+ trex_error(exp, _SC("cannot use character classes in ranges"));\r
+ exp->_nodes[r].left = exp->_nodes[first].type;\r
+ t = trex_escapechar(exp);\r
+ exp->_nodes[r].right = t;\r
+ exp->_nodes[chain].next = r;\r
+ chain = r;\r
+ first = -1;\r
+ } else {\r
+ if (first != -1) {\r
+ int c = first;\r
+ exp->_nodes[chain].next = c;\r
+ chain = c;\r
+ first = trex_charnode(exp, TRex_True);\r
+ } else {\r
+ first = trex_charnode(exp, TRex_True);\r
+ }\r
+ }\r
+ }\r
+ if (first != -1) {\r
+ int c = first;\r
+ exp->_nodes[chain].next = c;\r
+ chain = c;\r
+ first = -1;\r
+ }\r
+ /* hack? */\r
+ exp->_nodes[ret].left = exp->_nodes[ret].next;\r
+ exp->_nodes[ret].next = -1;\r
+ return ret;\r
+}\r
+\r
+static int trex_parsenumber(TRex* exp) {\r
+ int ret = *exp->_p - '0';\r
+ int positions = 10;\r
+ exp->_p++;\r
+ while (isdigit(*exp->_p)) {\r
+ ret = ret * 10 + (*exp->_p++ - '0');\r
+ if (positions == 1000000000)\r
+ trex_error(exp, _SC("overflow in numeric constant"));\r
+ positions *= 10;\r
+ };\r
+ return ret;\r
+}\r
+\r
+static int trex_element(TRex* exp) {\r
+ int ret = -1;\r
+ switch (*exp->_p) {\r
+ case '(': {\r
+ int expr, newn;\r
+ exp->_p++;\r
+\r
+ if (*exp->_p == '?') {\r
+ exp->_p++;\r
+ trex_expect(exp, ':');\r
+ expr = trex_newnode(exp, OP_NOCAPEXPR);\r
+ } else\r
+ expr = trex_newnode(exp, OP_EXPR);\r
+ newn = trex_list(exp);\r
+ exp->_nodes[expr].left = newn;\r
+ ret = expr;\r
+ trex_expect(exp, ')');\r
+ } break;\r
+ case '[':\r
+ exp->_p++;\r
+ ret = trex_class(exp);\r
+ trex_expect(exp, ']');\r
+ break;\r
+ case TREX_SYMBOL_END_OF_STRING:\r
+ exp->_p++;\r
+ ret = trex_newnode(exp, OP_EOL);\r
+ break;\r
+ case TREX_SYMBOL_ANY_CHAR:\r
+ exp->_p++;\r
+ ret = trex_newnode(exp, OP_DOT);\r
+ break;\r
+ default:\r
+ ret = trex_charnode(exp, TRex_False);\r
+ break;\r
+ }\r
+\r
+ {\r
+ TRexBool isgreedy = TRex_False;\r
+ unsigned short p0 = 0, p1 = 0;\r
+ switch (*exp->_p) {\r
+ case TREX_SYMBOL_GREEDY_ZERO_OR_MORE:\r
+ p0 = 0;\r
+ p1 = 0xFFFF;\r
+ exp->_p++;\r
+ isgreedy = TRex_True;\r
+ break;\r
+ case TREX_SYMBOL_GREEDY_ONE_OR_MORE:\r
+ p0 = 1;\r
+ p1 = 0xFFFF;\r
+ exp->_p++;\r
+ isgreedy = TRex_True;\r
+ break;\r
+ case TREX_SYMBOL_GREEDY_ZERO_OR_ONE:\r
+ p0 = 0;\r
+ p1 = 1;\r
+ exp->_p++;\r
+ isgreedy = TRex_True;\r
+ break;\r
+ case '{':\r
+ exp->_p++;\r
+ if (!isdigit(*exp->_p))\r
+ trex_error(exp, _SC("number expected"));\r
+ p0 = (unsigned short)trex_parsenumber(exp);\r
+ /*******************************/\r
+ switch (*exp->_p) {\r
+ case '}':\r
+ p1 = p0;\r
+ exp->_p++;\r
+ break;\r
+ case ',':\r
+ exp->_p++;\r
+ p1 = 0xFFFF;\r
+ if (isdigit(*exp->_p)) {\r
+ p1 = (unsigned short)trex_parsenumber(exp);\r
+ }\r
+ trex_expect(exp, '}');\r
+ break;\r
+ default:\r
+ trex_error(exp, _SC(", or } expected"));\r
+ }\r
+ /*******************************/\r
+ isgreedy = TRex_True;\r
+ break;\r
+ }\r
+ if (isgreedy) {\r
+ int nnode = trex_newnode(exp, OP_GREEDY);\r
+ exp->_nodes[nnode].left = ret;\r
+ exp->_nodes[nnode].right = ((p0) << 16) | p1;\r
+ ret = nnode;\r
+ }\r
+ }\r
+ if ((*exp->_p != TREX_SYMBOL_BRANCH) && (*exp->_p != ')') && (*exp->_p != TREX_SYMBOL_GREEDY_ZERO_OR_MORE) &&\r
+ (*exp->_p != TREX_SYMBOL_GREEDY_ONE_OR_MORE) && (*exp->_p != '\0')) {\r
+ int nnode = trex_element(exp);\r
+ exp->_nodes[ret].next = nnode;\r
+ }\r
+\r
+ return ret;\r
+}\r
+\r
+static int trex_list(TRex* exp) {\r
+ int ret = -1, e;\r
+ if (*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING) {\r
+ exp->_p++;\r
+ ret = trex_newnode(exp, OP_BOL);\r
+ }\r
+ e = trex_element(exp);\r
+ if (ret != -1) {\r
+ exp->_nodes[ret].next = e;\r
+ } else\r
+ ret = e;\r
+\r
+ if (*exp->_p == TREX_SYMBOL_BRANCH) {\r
+ int temp, tright;\r
+ exp->_p++;\r
+ temp = trex_newnode(exp, OP_OR);\r
+ exp->_nodes[temp].left = ret;\r
+ tright = trex_list(exp);\r
+ exp->_nodes[temp].right = tright;\r
+ ret = temp;\r
+ }\r
+ return ret;\r
+}\r
+\r
+static TRexBool trex_matchcclass(int cclass, TRexChar c) {\r
+ switch (cclass) {\r
+ case 'a':\r
+ return isalpha(c) ? TRex_True : TRex_False;\r
+ case 'A':\r
+ return !isalpha(c) ? TRex_True : TRex_False;\r
+ case 'w':\r
+ return (isalnum(c) || c == '_') ? TRex_True : TRex_False;\r
+ case 'W':\r
+ return (!isalnum(c) && c != '_') ? TRex_True : TRex_False;\r
+ case 's':\r
+ return isspace(c) ? TRex_True : TRex_False;\r
+ case 'S':\r
+ return !isspace(c) ? TRex_True : TRex_False;\r
+ case 'd':\r
+ return isdigit(c) ? TRex_True : TRex_False;\r
+ case 'D':\r
+ return !isdigit(c) ? TRex_True : TRex_False;\r
+ case 'x':\r
+ return isxdigit(c) ? TRex_True : TRex_False;\r
+ case 'X':\r
+ return !isxdigit(c) ? TRex_True : TRex_False;\r
+ case 'c':\r
+ return iscntrl(c) ? TRex_True : TRex_False;\r
+ case 'C':\r
+ return !iscntrl(c) ? TRex_True : TRex_False;\r
+ case 'p':\r
+ return ispunct(c) ? TRex_True : TRex_False;\r
+ case 'P':\r
+ return !ispunct(c) ? TRex_True : TRex_False;\r
+ case 'l':\r
+ return islower(c) ? TRex_True : TRex_False;\r
+ case 'u':\r
+ return isupper(c) ? TRex_True : TRex_False;\r
+ }\r
+ return TRex_False; /*cannot happen*/\r
+}\r
+\r
+static TRexBool trex_matchclass(TRex* exp, TRexNode* node, TRexChar c) {\r
+ do {\r
+ switch (node->type) {\r
+ case OP_RANGE:\r
+ if (exp->_flags & TREX_ICASE) {\r
+ if (c >= toupper(node->left) && c <= toupper(node->right))\r
+ return TRex_True;\r
+ if (c >= tolower(node->left) && c <= tolower(node->right))\r
+ return TRex_True;\r
+ } else {\r
+ if (c >= node->left && c <= node->right)\r
+ return TRex_True;\r
+ }\r
+ break;\r
+ case OP_CCLASS:\r
+ if (trex_matchcclass(node->left, c))\r
+ return TRex_True;\r
+ break;\r
+ default:\r
+ if (exp->_flags & TREX_ICASE) {\r
+ if (c == tolower(node->type) || c == toupper(node->type))\r
+ return TRex_True;\r
+ } else {\r
+ if (c == node->type)\r
+ return TRex_True;\r
+ }\r
+ }\r
+ } while ((node->next != -1) && ((node = &exp->_nodes[node->next]) != NULL));\r
+ return TRex_False;\r
+}\r
+\r
+static const TRexChar* trex_matchnode(TRex* exp, TRexNode* node, const TRexChar* str, TRexNode* next) {\r
+ TRexNodeType type = node->type;\r
+ switch (type) {\r
+ case OP_GREEDY: {\r
+ /* TRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL; */\r
+ TRexNode* greedystop = NULL;\r
+ int p0 = (node->right >> 16) & 0x0000FFFF, p1 = node->right & 0x0000FFFF, nmaches = 0;\r
+ const TRexChar *s = str, *good = str;\r
+\r
+ if (node->next != -1) {\r
+ greedystop = &exp->_nodes[node->next];\r
+ } else {\r
+ greedystop = next;\r
+ }\r
+\r
+ while ((nmaches == 0xFFFF || nmaches < p1)) {\r
+ const TRexChar* stop;\r
+ if ((s = trex_matchnode(exp, &exp->_nodes[node->left], s, greedystop)) == NULL)\r
+ break;\r
+ nmaches++;\r
+ good = s;\r
+ if (greedystop) {\r
+ /* checks that 0 matches satisfy the expression(if so skips) */\r
+ /* if not would always stop(for instance if is a '?') */\r
+ if (greedystop->type != OP_GREEDY || (greedystop->type == OP_GREEDY && ((greedystop->right >> 16) & 0x0000FFFF) != 0)) {\r
+ TRexNode* gnext = NULL;\r
+ if (greedystop->next != -1) {\r
+ gnext = &exp->_nodes[greedystop->next];\r
+ } else if (next && next->next != -1) {\r
+ gnext = &exp->_nodes[next->next];\r
+ }\r
+ stop = trex_matchnode(exp, greedystop, s, gnext);\r
+ if (stop) {\r
+ /* if satisfied stop it */\r
+ if (p0 == p1 && p0 == nmaches)\r
+ break;\r
+ else if (nmaches >= p0 && p1 == 0xFFFF)\r
+ break;\r
+ else if (nmaches >= p0 && nmaches <= p1)\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (s >= exp->_eol)\r
+ break;\r
+ }\r
+ if (p0 == p1 && p0 == nmaches)\r
+ return good;\r
+ else if (nmaches >= p0 && p1 == 0xFFFF)\r
+ return good;\r
+ else if (nmaches >= p0 && nmaches <= p1)\r
+ return good;\r
+ return NULL;\r
+ }\r
+ case OP_OR: {\r
+ const TRexChar* asd = str;\r
+ TRexNode* temp = &exp->_nodes[node->left];\r
+ while ((asd = trex_matchnode(exp, temp, asd, NULL)) != NULL) {\r
+ if (temp->next != -1)\r
+ temp = &exp->_nodes[temp->next];\r
+ else\r
+ return asd;\r
+ }\r
+ asd = str;\r
+ temp = &exp->_nodes[node->right];\r
+ while ((asd = trex_matchnode(exp, temp, asd, NULL)) != NULL) {\r
+ if (temp->next != -1)\r
+ temp = &exp->_nodes[temp->next];\r
+ else\r
+ return asd;\r
+ }\r
+ return NULL;\r
+ break;\r
+ }\r
+ case OP_EXPR:\r
+ case OP_NOCAPEXPR: {\r
+ TRexNode* n = &exp->_nodes[node->left];\r
+ const TRexChar* cur = str;\r
+ int capture = -1;\r
+ if (node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) {\r
+ capture = exp->_currsubexp;\r
+ exp->_matches[capture].begin = cur;\r
+ exp->_currsubexp++;\r
+ }\r
+\r
+ do {\r
+ TRexNode* subnext = NULL;\r
+ if (n->next != -1) {\r
+ subnext = &exp->_nodes[n->next];\r
+ } else {\r
+ subnext = next;\r
+ }\r
+ if ((cur = trex_matchnode(exp, n, cur, subnext)) == NULL) {\r
+ if (capture != -1) {\r
+ exp->_matches[capture].begin = 0;\r
+ exp->_matches[capture].len = 0;\r
+ }\r
+ return NULL;\r
+ }\r
+ } while ((n->next != -1) && ((n = &exp->_nodes[n->next]) != NULL));\r
+\r
+ if (capture != -1)\r
+ exp->_matches[capture].len = (int)(cur - exp->_matches[capture].begin);\r
+ return cur;\r
+ }\r
+ case OP_WB:\r
+ if ((str == exp->_bol && !isspace(*str)) || (str == exp->_eol && !isspace(*(str - 1))) || (!isspace(*str) && isspace(*(str + 1))) ||\r
+ (isspace(*str) && !isspace(*(str + 1)))) {\r
+ return (node->left == 'b') ? str : NULL;\r
+ }\r
+ return (node->left == 'b') ? NULL : str;\r
+ case OP_BOL:\r
+ if (str == exp->_bol)\r
+ return str;\r
+ return NULL;\r
+ case OP_EOL:\r
+ if (str == exp->_eol)\r
+ return str;\r
+ return NULL;\r
+ case OP_DOT: {\r
+ str++;\r
+ }\r
+ return str;\r
+ case OP_NCLASS:\r
+ case OP_CLASS:\r
+ if (trex_matchclass(exp, &exp->_nodes[node->left], *str) ? (type == OP_CLASS ? TRex_True : TRex_False)\r
+ : (type == OP_NCLASS ? TRex_True : TRex_False)) {\r
+ str++;\r
+ return str;\r
+ }\r
+ return NULL;\r
+ case OP_CCLASS:\r
+ if (trex_matchcclass(node->left, *str)) {\r
+ str++;\r
+ return str;\r
+ }\r
+ return NULL;\r
+ default: /* char */\r
+ if (exp->_flags & TREX_ICASE) {\r
+ if (*str != tolower(node->type) && *str != toupper(node->type))\r
+ return NULL;\r
+ } else {\r
+ if (*str != node->type)\r
+ return NULL;\r
+ }\r
+ str++;\r
+ return str;\r
+ }\r
+}\r
+\r
+/* public api */\r
+TRex* trex_compile(const TRexChar* pattern, const TRexChar** error, int flags) {\r
+ TRex* exp = (TRex*)xmalloc(sizeof(TRex));\r
+ exp->_eol = exp->_bol = NULL;\r
+ exp->_p = pattern;\r
+ exp->_nallocated = (int)scstrlen(pattern) * sizeof(TRexChar);\r
+ exp->_nodes = (TRexNode*)xmalloc(exp->_nallocated * sizeof(TRexNode));\r
+ exp->_nsize = 0;\r
+ exp->_matches = 0;\r
+ exp->_nsubexpr = 0;\r
+ exp->_first = trex_newnode(exp, OP_EXPR);\r
+ exp->_error = error;\r
+ exp->_jmpbuf = xmalloc(sizeof(jmp_buf));\r
+ exp->_flags = flags;\r
+ if (setjmp(*((jmp_buf*)exp->_jmpbuf)) == 0) {\r
+ int res = trex_list(exp);\r
+ exp->_nodes[exp->_first].left = res;\r
+ if (*exp->_p != '\0')\r
+ trex_error(exp, _SC("unexpected character"));\r
+#ifdef _DEBUG\r
+ {\r
+ int nsize, i;\r
+ TRexNode* t;\r
+ nsize = exp->_nsize;\r
+ t = &exp->_nodes[0];\r
+ scprintf(_SC("\n"));\r
+ for (i = 0; i < nsize; i++) {\r
+ if (exp->_nodes[i].type > MAX_CHAR)\r
+ scprintf(_SC("[%02d] %10s "), i, g_nnames[exp->_nodes[i].type - MAX_CHAR]);\r
+ else\r
+ scprintf(_SC("[%02d] %10c "), i, exp->_nodes[i].type);\r
+ scprintf(_SC("left %02d right %02d next %02d\n"), exp->_nodes[i].left, exp->_nodes[i].right, exp->_nodes[i].next);\r
+ }\r
+ scprintf(_SC("\n"));\r
+ }\r
+#endif\r
+ exp->_matches = (TRexMatch*)xmalloc(exp->_nsubexpr * sizeof(TRexMatch));\r
+ memset(exp->_matches, 0, exp->_nsubexpr * sizeof(TRexMatch));\r
+ } else {\r
+ trex_free(exp);\r
+ return NULL;\r
+ }\r
+ return exp;\r
+}\r
+\r
+void trex_free(TRex* exp) {\r
+ if (exp) {\r
+ xfree(exp->_nodes);\r
+ xfree(exp->_jmpbuf);\r
+ xfree(exp->_matches);\r
+ xfree(exp);\r
+ }\r
+}\r
+\r
+TRexBool trex_match(TRex* exp, const TRexChar* text) {\r
+ const TRexChar* res = NULL;\r
+ exp->_bol = text;\r
+ exp->_eol = text + scstrlen(text);\r
+ exp->_currsubexp = 0;\r
+ res = trex_matchnode(exp, exp->_nodes, text, NULL);\r
+ if (res == NULL || res != exp->_eol)\r
+ return TRex_False;\r
+ return TRex_True;\r
+}\r
+\r
+TRexBool trex_searchrange(TRex* exp, const TRexChar* text_begin, const TRexChar* text_end, const TRexChar** out_begin, const TRexChar** out_end) {\r
+ const TRexChar* cur = NULL;\r
+ int node = exp->_first;\r
+ if (text_begin >= text_end)\r
+ return TRex_False;\r
+ exp->_bol = text_begin;\r
+ exp->_eol = text_end;\r
+ do {\r
+ cur = text_begin;\r
+ while (node != -1) {\r
+ exp->_currsubexp = 0;\r
+ cur = trex_matchnode(exp, &exp->_nodes[node], cur, NULL);\r
+ if (!cur)\r
+ break;\r
+ node = exp->_nodes[node].next;\r
+ }\r
+ text_begin++;\r
+ } while (cur == NULL && text_begin != text_end);\r
+\r
+ if (cur == NULL)\r
+ return TRex_False;\r
+\r
+ --text_begin;\r
+\r
+ if (out_begin)\r
+ *out_begin = text_begin;\r
+ if (out_end)\r
+ *out_end = cur;\r
+ return TRex_True;\r
+}\r
+\r
+TRexBool trex_search(TRex* exp, const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end) {\r
+ return trex_searchrange(exp, text, text + scstrlen(text), out_begin, out_end);\r
+}\r
+\r
+int trex_getsubexpcount(TRex* exp) {\r
+ return exp->_nsubexpr;\r
+}\r
+\r
+TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch* subexp) {\r
+ if (n < 0 || n >= exp->_nsubexpr)\r
+ return TRex_False;\r
+ *subexp = exp->_matches[n];\r
+ return TRex_True;\r
+}\r
+/*******************************************************************************\r
+ * arg_str: Implements the str command-line option\r
+ *\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann\r
+ * <sheitmann@users.sourceforge.net>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ * * Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ * * Redistributions in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in the\r
+ * documentation and/or other materials provided with the distribution.\r
+ * * Neither the name of STEWART HEITMANN nor the names of its contributors\r
+ * may be used to endorse or promote products derived from this software\r
+ * without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#include "argtable3.h"\r
+\r
+#ifndef ARG_AMALGAMATION\r
+#include "argtable3_private.h"\r
+#endif\r
+\r
+#include <stdlib.h>\r
+\r
+static void arg_str_resetfn(struct arg_str* parent) {\r
+ int i;\r
+ \r
+ ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));\r
+ for (i = 0; i < parent->count; i++) {\r
+ parent->sval[i] = "";\r
+ }\r
+ parent->count = 0;\r
+}\r
+\r
+static int arg_str_scanfn(struct arg_str* parent, const char* argval) {\r
+ int errorcode = 0;\r
+\r
+ if (parent->count == parent->hdr.maxcount) {\r
+ /* maximum number of arguments exceeded */\r
+ errorcode = ARG_ERR_MAXCOUNT;\r
+ } else if (!argval) {\r
+ /* a valid argument with no argument value was given. */\r
+ /* This happens when an optional argument value was invoked. */\r
+ /* leave parent argument value unaltered but still count the argument. */\r
+ parent->count++;\r
+ } else {\r
+ parent->sval[parent->count++] = argval;\r
+ }\r
+\r
+ ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));\r
+ return errorcode;\r
+}\r
+\r
+static int arg_str_checkfn(struct arg_str* parent) {\r
+ int errorcode = (parent->count < parent->hdr.mincount) ? ARG_ERR_MINCOUNT : 0;\r
+\r
+ ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));\r
+ return errorcode;\r
+}\r
+\r
+static void arg_str_errorfn(struct arg_str* parent, arg_dstr_t ds, int errorcode, const char* argval, const char* progname) {\r
+ const char* shortopts = parent->hdr.shortopts;\r
+ const char* longopts = parent->hdr.longopts;\r
+ const char* datatype = parent->hdr.datatype;\r
+\r
+ /* make argval NULL safe */\r
+ argval = argval ? argval : "";\r
+\r
+ arg_dstr_catf(ds, "%s: ", progname);\r
+ switch (errorcode) {\r
+ case ARG_ERR_MINCOUNT:\r
+ arg_dstr_cat(ds, "missing option ");\r
+ arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");\r
+ break;\r
+\r
+ case ARG_ERR_MAXCOUNT:\r
+ arg_dstr_cat(ds, "excess option ");\r
+ arg_print_option_ds(ds, shortopts, longopts, argval, "\n");\r
+ break;\r
+ }\r
+}\r
+\r
+struct arg_str* arg_str0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) {\r
+ return arg_strn(shortopts, longopts, datatype, 0, 1, glossary);\r
+}\r
+\r
+struct arg_str* arg_str1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) {\r
+ return arg_strn(shortopts, longopts, datatype, 1, 1, glossary);\r
+}\r
+\r
+struct arg_str* arg_strn(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary) {\r
+ size_t nbytes;\r
+ struct arg_str* result;\r
+ int i;\r
+\r
+ /* should not allow this stupid error */\r
+ /* we should return an error code warning this logic error */\r
+ /* foolproof things by ensuring maxcount is not less than mincount */\r
+ maxcount = (maxcount < mincount) ? mincount : maxcount;\r
+\r
+ nbytes = sizeof(struct arg_str) /* storage for struct arg_str */\r
+ + maxcount * sizeof(char*); /* storage for sval[maxcount] array */\r
+\r
+ result = (struct arg_str*)xmalloc(nbytes);\r
+\r
+ /* init the arg_hdr struct */\r
+ result->hdr.flag = ARG_HASVALUE;\r
+ result->hdr.shortopts = shortopts;\r
+ result->hdr.longopts = longopts;\r
+ result->hdr.datatype = datatype ? datatype : "<string>";\r
+ result->hdr.glossary = glossary;\r
+ result->hdr.mincount = mincount;\r
+ result->hdr.maxcount = maxcount;\r
+ result->hdr.parent = result;\r
+ result->hdr.resetfn = (arg_resetfn*)arg_str_resetfn;\r
+ result->hdr.scanfn = (arg_scanfn*)arg_str_scanfn;\r
+ result->hdr.checkfn = (arg_checkfn*)arg_str_checkfn;\r
+ result->hdr.errorfn = (arg_errorfn*)arg_str_errorfn;\r
+\r
+ /* store the sval[maxcount] array immediately after the arg_str struct */\r
+ result->sval = (const char**)(result + 1);\r
+ result->count = 0;\r
+\r
+ /* foolproof the string pointers by initializing them to reference empty strings */\r
+ for (i = 0; i < maxcount; i++)\r
+ result->sval[i] = "";\r
+\r
+ ARG_TRACE(("arg_strn() returns %p\n", result));\r
+ return result;\r
+}\r
+/*******************************************************************************\r
+ * arg_cmd: Provides the sub-command mechanism\r
+ *\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 2013-2019 Tom G. Huang\r
+ * <tomghuang@gmail.com>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ * * Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ * * Redistributions in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in the\r
+ * documentation and/or other materials provided with the distribution.\r
+ * * Neither the name of STEWART HEITMANN nor the names of its contributors\r
+ * may be used to endorse or promote products derived from this software\r
+ * without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#include "argtable3.h"\r
+\r
+#ifndef ARG_AMALGAMATION\r
+#include "argtable3_private.h"\r
+#endif\r
+\r
+#include <assert.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#define MAX_MODULE_VERSION_SIZE 128\r
+\r
+static arg_hashtable_t* s_hashtable = NULL;\r
+static char* s_module_name = NULL;\r
+static int s_mod_ver_major = 0;\r
+static int s_mod_ver_minor = 0;\r
+static int s_mod_ver_patch = 0;\r
+static char* s_mod_ver_tag = NULL;\r
+static char* s_mod_ver = NULL;\r
+\r
+void arg_set_module_name(const char* name) {\r
+ size_t slen;\r
+\r
+ xfree(s_module_name);\r
+ slen = strlen(name);\r
+ s_module_name = (char*)xmalloc(slen + 1);\r
+ memset(s_module_name, 0, slen + 1);\r
+\r
+#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__))\r
+ strncpy_s(s_module_name, slen + 1, name, slen);\r
+#else\r
+ memcpy(s_module_name, name, slen);\r
+#endif\r
+}\r
+\r
+void arg_set_module_version(int major, int minor, int patch, const char* tag) {\r
+ size_t slen_tag, slen_ds;\r
+ arg_dstr_t ds;\r
+\r
+ s_mod_ver_major = major;\r
+ s_mod_ver_minor = minor;\r
+ s_mod_ver_patch = patch;\r
+\r
+ xfree(s_mod_ver_tag);\r
+ slen_tag = strlen(tag);\r
+ s_mod_ver_tag = (char*)xmalloc(slen_tag + 1);\r
+ memset(s_mod_ver_tag, 0, slen_tag + 1);\r
+\r
+#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__))\r
+ strncpy_s(s_mod_ver_tag, slen_tag + 1, tag, slen_tag);\r
+#else\r
+ memcpy(s_mod_ver_tag, tag, slen_tag);\r
+#endif\r
+\r
+ ds = arg_dstr_create();\r
+ arg_dstr_catf(ds, "%d.", s_mod_ver_major);\r
+ arg_dstr_catf(ds, "%d.", s_mod_ver_minor);\r
+ arg_dstr_catf(ds, "%d.", s_mod_ver_patch);\r
+ arg_dstr_cat(ds, s_mod_ver_tag);\r
+\r
+ xfree(s_mod_ver);\r
+ slen_ds = strlen(arg_dstr_cstr(ds));\r
+ s_mod_ver = (char*)xmalloc(slen_ds + 1);\r
+ memset(s_mod_ver, 0, slen_ds + 1);\r
+\r
+#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__))\r
+ strncpy_s(s_mod_ver, slen_ds + 1, arg_dstr_cstr(ds), slen_ds);\r
+#else\r
+ memcpy(s_mod_ver, arg_dstr_cstr(ds), slen_ds);\r
+#endif\r
+\r
+ arg_dstr_destroy(ds);\r
+}\r
+\r
+static unsigned int hash_key(const void* key) {\r
+ const char* str = (const char*)key;\r
+ int c;\r
+ unsigned int hash = 5381;\r
+\r
+ while ((c = *str++) != 0)\r
+ hash = ((hash << 5) + hash) + c; /* hash * 33 + c */\r
+\r
+ return hash;\r
+}\r
+\r
+static int equal_keys(const void* key1, const void* key2) {\r
+ char* k1 = (char*)key1;\r
+ char* k2 = (char*)key2;\r
+ return (0 == strcmp(k1, k2));\r
+}\r
+\r
+void arg_cmd_init(void) {\r
+ s_hashtable = arg_hashtable_create(32, hash_key, equal_keys);\r
+}\r
+\r
+void arg_cmd_uninit(void) {\r
+ arg_hashtable_destroy(s_hashtable, 1);\r
+}\r
+\r
+void arg_cmd_register(const char* name, arg_cmdfn* proc, const char* description) {\r
+ arg_cmd_info_t* cmd_info;\r
+ size_t slen_name;\r
+ void* k;\r
+\r
+ assert(strlen(name) < ARG_CMD_NAME_LEN);\r
+ assert(strlen(description) < ARG_CMD_DESCRIPTION_LEN);\r
+\r
+ /* Check if the command already exists. */\r
+ /* If the command exists, replace the existing command. */\r
+ /* If the command doesn't exist, insert the command. */\r
+ cmd_info = (arg_cmd_info_t*)arg_hashtable_search(s_hashtable, name);\r
+ if (cmd_info) {\r
+ arg_hashtable_remove(s_hashtable, name);\r
+ cmd_info = NULL;\r
+ }\r
+\r
+ cmd_info = (arg_cmd_info_t*)xmalloc(sizeof(arg_cmd_info_t));\r
+ memset(cmd_info, 0, sizeof(arg_cmd_info_t));\r
+\r
+#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__))\r
+ strncpy_s(cmd_info->name, ARG_CMD_NAME_LEN, name, strlen(name));\r
+ strncpy_s(cmd_info->description, ARG_CMD_DESCRIPTION_LEN, description, strlen(description));\r
+#else\r
+ memcpy(cmd_info->name, name, strlen(name));\r
+ memcpy(cmd_info->description, description, strlen(description));\r
+#endif\r
+\r
+ cmd_info->proc = proc;\r
+\r
+ slen_name = strlen(name);\r
+ k = xmalloc(slen_name + 1);\r
+ memset(k, 0, slen_name + 1);\r
+\r
+#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__))\r
+ strncpy_s((char*)k, slen_name + 1, name, slen_name);\r
+#else\r
+ memcpy((char*)k, name, slen_name);\r
+#endif\r
+\r
+ arg_hashtable_insert(s_hashtable, k, cmd_info);\r
+}\r
+\r
+void arg_cmd_unregister(const char* name) {\r
+ arg_hashtable_remove(s_hashtable, name);\r
+}\r
+\r
+int arg_cmd_dispatch(const char* name, int argc, char* argv[], arg_dstr_t res) {\r
+ arg_cmd_info_t* cmd_info = arg_cmd_info(name);\r
+\r
+ assert(cmd_info != NULL);\r
+ assert(cmd_info->proc != NULL);\r
+\r
+ return cmd_info->proc(argc, argv, res);\r
+}\r
+\r
+arg_cmd_info_t* arg_cmd_info(const char* name) {\r
+ return (arg_cmd_info_t*)arg_hashtable_search(s_hashtable, name);\r
+}\r
+\r
+unsigned int arg_cmd_count(void) {\r
+ return arg_hashtable_count(s_hashtable);\r
+}\r
+\r
+arg_cmd_itr_t arg_cmd_itr_create(void) {\r
+ return (arg_cmd_itr_t)arg_hashtable_itr_create(s_hashtable);\r
+}\r
+\r
+int arg_cmd_itr_advance(arg_cmd_itr_t itr) {\r
+ return arg_hashtable_itr_advance((arg_hashtable_itr_t*)itr);\r
+}\r
+\r
+char* arg_cmd_itr_key(arg_cmd_itr_t itr) {\r
+ return (char*)arg_hashtable_itr_key((arg_hashtable_itr_t*)itr);\r
+}\r
+\r
+arg_cmd_info_t* arg_cmd_itr_value(arg_cmd_itr_t itr) {\r
+ return (arg_cmd_info_t*)arg_hashtable_itr_value((arg_hashtable_itr_t*)itr);\r
+}\r
+\r
+void arg_cmd_itr_destroy(arg_cmd_itr_t itr) {\r
+ arg_hashtable_itr_destroy((arg_hashtable_itr_t*)itr);\r
+}\r
+\r
+int arg_cmd_itr_search(arg_cmd_itr_t itr, void* k) {\r
+ return arg_hashtable_itr_search((arg_hashtable_itr_t*)itr, s_hashtable, k);\r
+}\r
+\r
+static const char* module_name(void) {\r
+ if (s_module_name == NULL || strlen(s_module_name) == 0)\r
+ return "<name>";\r
+\r
+ return s_module_name;\r
+}\r
+\r
+static const char* module_version(void) {\r
+ if (s_mod_ver == NULL || strlen(s_mod_ver) == 0)\r
+ return "0.0.0.0";\r
+\r
+ return s_mod_ver;\r
+}\r
+\r
+void arg_make_get_help_msg(arg_dstr_t res) {\r
+ arg_dstr_catf(res, "%s v%s\n", module_name(), module_version());\r
+ arg_dstr_catf(res, "Please type '%s help' to get more information.\n", module_name());\r
+}\r
+\r
+void arg_make_help_msg(arg_dstr_t ds, char* cmd_name, void** argtable) {\r
+ arg_cmd_info_t* cmd_info = (arg_cmd_info_t*)arg_hashtable_search(s_hashtable, cmd_name);\r
+ if (cmd_info) {\r
+ arg_dstr_catf(ds, "%s: %s\n", cmd_name, cmd_info->description);\r
+ }\r
+\r
+ arg_dstr_cat(ds, "Usage:\n");\r
+ arg_dstr_catf(ds, " %s", module_name());\r
+\r
+ arg_print_syntaxv_ds(ds, argtable, "\n \nAvailable options:\n");\r
+ arg_print_glossary_ds(ds, argtable, " %-23s %s\n");\r
+\r
+ arg_dstr_cat(ds, "\n");\r
+}\r
+\r
+void arg_make_syntax_err_msg(arg_dstr_t ds, void** argtable, struct arg_end* end) {\r
+ arg_print_errors_ds(ds, end, module_name());\r
+ arg_dstr_cat(ds, "Usage: \n");\r
+ arg_dstr_catf(ds, " %s", module_name());\r
+ arg_print_syntaxv_ds(ds, argtable, "\n");\r
+ arg_dstr_cat(ds, "\n");\r
+}\r
+\r
+int arg_make_syntax_err_help_msg(arg_dstr_t ds, char* name, int help, int nerrors, void** argtable, struct arg_end* end, int* exitcode) {\r
+ /* help handling\r
+ * note: '-h|--help' takes precedence over error reporting\r
+ */\r
+ if (help > 0) {\r
+ arg_make_help_msg(ds, name, argtable);\r
+ *exitcode = EXIT_SUCCESS;\r
+ return 1;\r
+ }\r
+\r
+ /* syntax error handling */\r
+ if (nerrors > 0) {\r
+ arg_make_syntax_err_msg(ds, argtable, end);\r
+ *exitcode = EXIT_FAILURE;\r
+ return 1;\r
+ }\r
+\r
+ return 0;\r
+}\r
+/*******************************************************************************\r
+ * argtable3: Implements the main interfaces of the library\r
+ *\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann\r
+ * <sheitmann@users.sourceforge.net>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ * * Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ * * Redistributions in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in the\r
+ * documentation and/or other materials provided with the distribution.\r
+ * * Neither the name of STEWART HEITMANN nor the names of its contributors\r
+ * may be used to endorse or promote products derived from this software\r
+ * without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#include "argtable3.h"\r
+\r
+#ifndef ARG_AMALGAMATION\r
+#include "argtable3_private.h"\r
+#include "getopt.h"\r
+#endif\r
+\r
+#ifdef _WIN32\r
+#define WIN32_LEAN_AND_MEAN\r
+#include <windows.h>\r
+#undef WIN32_LEAN_AND_MEAN\r
+#endif\r
+\r
+#include <assert.h>\r
+#include <ctype.h>\r
+#include <limits.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+static void arg_register_error(struct arg_end* end, void* parent, int error, const char* argval) {\r
+ /* printf("arg_register_error(%p,%p,%d,%s)\n",end,parent,error,argval); */\r
+ if (end->count < end->hdr.maxcount) {\r
+ end->error[end->count] = error;\r
+ end->parent[end->count] = parent;\r
+ end->argval[end->count] = argval;\r
+ end->count++;\r
+ } else {\r
+ end->error[end->hdr.maxcount - 1] = ARG_ELIMIT;\r
+ end->parent[end->hdr.maxcount - 1] = end;\r
+ end->argval[end->hdr.maxcount - 1] = NULL;\r
+ }\r
+}\r
+\r
+/*\r
+ * Return index of first table entry with a matching short option\r
+ * or -1 if no match was found.\r
+ */\r
+static int find_shortoption(struct arg_hdr** table, char shortopt) {\r
+ int tabindex;\r
+ for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) {\r
+ if (table[tabindex]->shortopts && strchr(table[tabindex]->shortopts, shortopt))\r
+ return tabindex;\r
+ }\r
+ return -1;\r
+}\r
+\r
+struct longoptions {\r
+ int getoptval;\r
+ int noptions;\r
+ struct option* options;\r
+};\r
+\r
+#if 0\r
+static\r
+void dump_longoptions(struct longoptions * longoptions)\r
+{\r
+ int i;\r
+ printf("getoptval = %d\n", longoptions->getoptval);\r
+ printf("noptions = %d\n", longoptions->noptions);\r
+ for (i = 0; i < longoptions->noptions; i++)\r
+ {\r
+ printf("options[%d].name = \"%s\"\n",\r
+ i,\r
+ longoptions->options[i].name);\r
+ printf("options[%d].has_arg = %d\n", i, longoptions->options[i].has_arg);\r
+ printf("options[%d].flag = %p\n", i, longoptions->options[i].flag);\r
+ printf("options[%d].val = %d\n", i, longoptions->options[i].val);\r
+ }\r
+}\r
+#endif\r
+\r
+static struct longoptions* alloc_longoptions(struct arg_hdr** table) {\r
+ struct longoptions* result;\r
+ size_t nbytes;\r
+ int noptions = 1;\r
+ size_t longoptlen = 0;\r
+ int tabindex;\r
+ int option_index = 0;\r
+ char* store;\r
+\r
+ /*\r
+ * Determine the total number of option structs required\r
+ * by counting the number of comma separated long options\r
+ * in all table entries and return the count in noptions.\r
+ * note: noptions starts at 1 not 0 because we getoptlong\r
+ * requires a NULL option entry to terminate the option array.\r
+ * While we are at it, count the number of chars required\r
+ * to store private copies of all the longoption strings\r
+ * and return that count in logoptlen.\r
+ */\r
+ tabindex = 0;\r
+ do {\r
+ const char* longopts = table[tabindex]->longopts;\r
+ longoptlen += (longopts ? strlen(longopts) : 0) + 1;\r
+ while (longopts) {\r
+ noptions++;\r
+ longopts = strchr(longopts + 1, ',');\r
+ }\r
+ } while (!(table[tabindex++]->flag & ARG_TERMINATOR));\r
+ /*printf("%d long options consuming %d chars in total\n",noptions,longoptlen);*/\r
+\r
+ /* allocate storage for return data structure as: */\r
+ /* (struct longoptions) + (struct options)[noptions] + char[longoptlen] */\r
+ nbytes = sizeof(struct longoptions) + sizeof(struct option) * noptions + longoptlen;\r
+ result = (struct longoptions*)xmalloc(nbytes);\r
+\r
+ result->getoptval = 0;\r
+ result->noptions = noptions;\r
+ result->options = (struct option*)(result + 1);\r
+ store = (char*)(result->options + noptions);\r
+\r
+ for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) {\r
+ const char* longopts = table[tabindex]->longopts;\r
+\r
+ while (longopts && *longopts) {\r
+ char* storestart = store;\r
+\r
+ /* copy progressive longopt strings into the store */\r
+ while (*longopts != 0 && *longopts != ',')\r
+ *store++ = *longopts++;\r
+ *store++ = 0;\r
+ if (*longopts == ',')\r
+ longopts++;\r
+ /*fprintf(stderr,"storestart=\"%s\"\n",storestart);*/\r
+\r
+ result->options[option_index].name = storestart;\r
+ result->options[option_index].flag = &(result->getoptval);\r
+ result->options[option_index].val = tabindex;\r
+ if (table[tabindex]->flag & ARG_HASOPTVALUE)\r
+ result->options[option_index].has_arg = 2;\r
+ else if (table[tabindex]->flag & ARG_HASVALUE)\r
+ result->options[option_index].has_arg = 1;\r
+ else\r
+ result->options[option_index].has_arg = 0;\r
+\r
+ option_index++;\r
+ }\r
+ }\r
+ /* terminate the options array with a zero-filled entry */\r
+ result->options[option_index].name = 0;\r
+ result->options[option_index].has_arg = 0;\r
+ result->options[option_index].flag = 0;\r
+ result->options[option_index].val = 0;\r
+\r
+ /*dump_longoptions(result);*/\r
+ return result;\r
+}\r
+\r
+static char* alloc_shortoptions(struct arg_hdr** table) {\r
+ char* result;\r
+ size_t len = 2;\r
+ int tabindex;\r
+ char* res;\r
+\r
+ /* determine the total number of option chars required */\r
+ for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) {\r
+ struct arg_hdr* hdr = table[tabindex];\r
+ len += 3 * (hdr->shortopts ? strlen(hdr->shortopts) : 0);\r
+ }\r
+\r
+ result = xmalloc(len);\r
+\r
+ res = result;\r
+\r
+ /* add a leading ':' so getopt return codes distinguish */\r
+ /* unrecognised option and options missing argument values */\r
+ *res++ = ':';\r
+\r
+ for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) {\r
+ struct arg_hdr* hdr = table[tabindex];\r
+ const char* shortopts = hdr->shortopts;\r
+ while (shortopts && *shortopts) {\r
+ *res++ = *shortopts++;\r
+ if (hdr->flag & ARG_HASVALUE)\r
+ *res++ = ':';\r
+ if (hdr->flag & ARG_HASOPTVALUE)\r
+ *res++ = ':';\r
+ }\r
+ }\r
+ /* null terminate the string */\r
+ *res = 0;\r
+\r
+ /*printf("alloc_shortoptions() returns \"%s\"\n",(result?result:"NULL"));*/\r
+ return result;\r
+}\r
+\r
+/* return index of the table terminator entry */\r
+static int arg_endindex(struct arg_hdr** table) {\r
+ int tabindex = 0;\r
+ while (!(table[tabindex]->flag & ARG_TERMINATOR))\r
+ tabindex++;\r
+ return tabindex;\r
+}\r
+\r
+static void arg_parse_tagged(int argc, char** argv, struct arg_hdr** table, struct arg_end* endtable) {\r
+ struct longoptions* longoptions;\r
+ char* shortoptions;\r
+ int copt;\r
+\r
+ /*printf("arg_parse_tagged(%d,%p,%p,%p)\n",argc,argv,table,endtable);*/\r
+\r
+ /* allocate short and long option arrays for the given opttable[]. */\r
+ /* if the allocs fail then put an error msg in the last table entry. */\r
+ longoptions = alloc_longoptions(table);\r
+ shortoptions = alloc_shortoptions(table);\r
+\r
+ /*dump_longoptions(longoptions);*/\r
+\r
+ /* reset getopts internal option-index to zero, and disable error reporting */\r
+ optind = 0;\r
+ opterr = 0;\r
+\r
+ /* fetch and process args using getopt_long */\r
+ while ((copt = getopt_long(argc, argv, shortoptions, longoptions->options, NULL)) != -1) {\r
+ /*\r
+ printf("optarg='%s'\n",optarg);\r
+ printf("optind=%d\n",optind);\r
+ printf("copt=%c\n",(char)copt);\r
+ printf("optopt=%c (%d)\n",optopt, (int)(optopt));\r
+ */\r
+ switch (copt) {\r
+ case 0: {\r
+ int tabindex = longoptions->getoptval;\r
+ void* parent = table[tabindex]->parent;\r
+ /*printf("long option detected from argtable[%d]\n", tabindex);*/\r
+ if (optarg && optarg[0] == 0 && (table[tabindex]->flag & ARG_HASVALUE)) {\r
+ /* printf(": long option %s requires an argument\n",argv[optind-1]); */\r
+ arg_register_error(endtable, endtable, ARG_EMISSARG, argv[optind - 1]);\r
+ /* continue to scan the (empty) argument value to enforce argument count checking */\r
+ }\r
+ if (table[tabindex]->scanfn) {\r
+ int errorcode = table[tabindex]->scanfn(parent, optarg);\r
+ if (errorcode != 0)\r
+ arg_register_error(endtable, parent, errorcode, optarg);\r
+ }\r
+ } break;\r
+\r
+ case '?':\r
+ /*\r
+ * getopt_long() found an unrecognised short option.\r
+ * if it was a short option its value is in optopt\r
+ * if it was a long option then optopt=0\r
+ */\r
+ switch (optopt) {\r
+ case 0:\r
+ /*printf("?0 unrecognised long option %s\n",argv[optind-1]);*/\r
+ arg_register_error(endtable, endtable, ARG_ELONGOPT, argv[optind - 1]);\r
+ break;\r
+ default:\r
+ /*printf("?* unrecognised short option '%c'\n",optopt);*/\r
+ arg_register_error(endtable, endtable, optopt, NULL);\r
+ break;\r
+ }\r
+ break;\r
+\r
+ case ':':\r
+ /*\r
+ * getopt_long() found an option with its argument missing.\r
+ */\r
+ /*printf(": option %s requires an argument\n",argv[optind-1]); */\r
+ arg_register_error(endtable, endtable, ARG_EMISSARG, argv[optind - 1]);\r
+ break;\r
+\r
+ default: {\r
+ /* getopt_long() found a valid short option */\r
+ int tabindex = find_shortoption(table, (char)copt);\r
+ /*printf("short option detected from argtable[%d]\n", tabindex);*/\r
+ if (tabindex == -1) {\r
+ /* should never get here - but handle it just in case */\r
+ /*printf("unrecognised short option %d\n",copt);*/\r
+ arg_register_error(endtable, endtable, copt, NULL);\r
+ } else {\r
+ if (table[tabindex]->scanfn) {\r
+ void* parent = table[tabindex]->parent;\r
+ int errorcode = table[tabindex]->scanfn(parent, optarg);\r
+ if (errorcode != 0)\r
+ arg_register_error(endtable, parent, errorcode, optarg);\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ xfree(shortoptions);\r
+ xfree(longoptions);\r
+}\r
+\r
+static void arg_parse_untagged(int argc, char** argv, struct arg_hdr** table, struct arg_end* endtable) {\r
+ int tabindex = 0;\r
+ int errorlast = 0;\r
+ const char* optarglast = NULL;\r
+ void* parentlast = NULL;\r
+\r
+ /*printf("arg_parse_untagged(%d,%p,%p,%p)\n",argc,argv,table,endtable);*/\r
+ while (!(table[tabindex]->flag & ARG_TERMINATOR)) {\r
+ void* parent;\r
+ int errorcode;\r
+\r
+ /* if we have exhausted our argv[optind] entries then we have finished */\r
+ if (optind >= argc) {\r
+ /*printf("arg_parse_untagged(): argv[] exhausted\n");*/\r
+ return;\r
+ }\r
+\r
+ /* skip table entries with non-null long or short options (they are not untagged entries) */\r
+ if (table[tabindex]->longopts || table[tabindex]->shortopts) {\r
+ /*printf("arg_parse_untagged(): skipping argtable[%d] (tagged argument)\n",tabindex);*/\r
+ tabindex++;\r
+ continue;\r
+ }\r
+\r
+ /* skip table entries with NULL scanfn */\r
+ if (!(table[tabindex]->scanfn)) {\r
+ /*printf("arg_parse_untagged(): skipping argtable[%d] (NULL scanfn)\n",tabindex);*/\r
+ tabindex++;\r
+ continue;\r
+ }\r
+\r
+ /* attempt to scan the current argv[optind] with the current */\r
+ /* table[tabindex] entry. If it succeeds then keep it, otherwise */\r
+ /* try again with the next table[] entry. */\r
+ parent = table[tabindex]->parent;\r
+ errorcode = table[tabindex]->scanfn(parent, argv[optind]);\r
+ if (errorcode == 0) {\r
+ /* success, move onto next argv[optind] but stay with same table[tabindex] */\r
+ /*printf("arg_parse_untagged(): argtable[%d] successfully matched\n",tabindex);*/\r
+ optind++;\r
+\r
+ /* clear the last tentative error */\r
+ errorlast = 0;\r
+ } else {\r
+ /* failure, try same argv[optind] with next table[tabindex] entry */\r
+ /*printf("arg_parse_untagged(): argtable[%d] failed match\n",tabindex);*/\r
+ tabindex++;\r
+\r
+ /* remember this as a tentative error we may wish to reinstate later */\r
+ errorlast = errorcode;\r
+ optarglast = argv[optind];\r
+ parentlast = parent;\r
+ }\r
+ }\r
+\r
+ /* if a tenative error still remains at this point then register it as a proper error */\r
+ if (errorlast) {\r
+ arg_register_error(endtable, parentlast, errorlast, optarglast);\r
+ optind++;\r
+ }\r
+\r
+ /* only get here when not all argv[] entries were consumed */\r
+ /* register an error for each unused argv[] entry */\r
+ while (optind < argc) {\r
+ /*printf("arg_parse_untagged(): argv[%d]=\"%s\" not consumed\n",optind,argv[optind]);*/\r
+ arg_register_error(endtable, endtable, ARG_ENOMATCH, argv[optind++]);\r
+ }\r
+\r
+ return;\r
+}\r
+\r
+static void arg_parse_check(struct arg_hdr** table, struct arg_end* endtable) {\r
+ int tabindex = 0;\r
+ /* printf("arg_parse_check()\n"); */\r
+ do {\r
+ if (table[tabindex]->checkfn) {\r
+ void* parent = table[tabindex]->parent;\r
+ int errorcode = table[tabindex]->checkfn(parent);\r
+ if (errorcode != 0)\r
+ arg_register_error(endtable, parent, errorcode, NULL);\r
+ }\r
+ } while (!(table[tabindex++]->flag & ARG_TERMINATOR));\r
+}\r
+\r
+static void arg_reset(void** argtable) {\r
+ struct arg_hdr** table = (struct arg_hdr**)argtable;\r
+ int tabindex = 0;\r
+ /*printf("arg_reset(%p)\n",argtable);*/\r
+ do {\r
+ if (table[tabindex]->resetfn)\r
+ table[tabindex]->resetfn(table[tabindex]->parent);\r
+ } while (!(table[tabindex++]->flag & ARG_TERMINATOR));\r
+}\r
+\r
+int arg_parse(int argc, char** argv, void** argtable) {\r
+ struct arg_hdr** table = (struct arg_hdr**)argtable;\r
+ struct arg_end* endtable;\r
+ int endindex;\r
+ char** argvcopy = NULL;\r
+ int i;\r
+\r
+ /*printf("arg_parse(%d,%p,%p)\n",argc,argv,argtable);*/\r
+\r
+ /* reset any argtable data from previous invocations */\r
+ arg_reset(argtable);\r
+\r
+ /* locate the first end-of-table marker within the array */\r
+ endindex = arg_endindex(table);\r
+ endtable = (struct arg_end*)table[endindex];\r
+\r
+ /* Special case of argc==0. This can occur on Texas Instruments DSP. */\r
+ /* Failure to trap this case results in an unwanted NULL result from */\r
+ /* the malloc for argvcopy (next code block). */\r
+ if (argc == 0) {\r
+ /* We must still perform post-parse checks despite the absence of command line arguments */\r
+ arg_parse_check(table, endtable);\r
+\r
+ /* Now we are finished */\r
+ return endtable->count;\r
+ }\r
+\r
+ argvcopy = (char**)xmalloc(sizeof(char*) * (argc + 1));\r
+\r
+ /*\r
+ Fill in the local copy of argv[]. We need a local copy\r
+ because getopt rearranges argv[] which adversely affects\r
+ susbsequent parsing attempts.\r
+ */\r
+ for (i = 0; i < argc; i++)\r
+ argvcopy[i] = argv[i];\r
+\r
+ argvcopy[argc] = NULL;\r
+\r
+ /* parse the command line (local copy) for tagged options */\r
+ arg_parse_tagged(argc, argvcopy, table, endtable);\r
+\r
+ /* parse the command line (local copy) for untagged options */\r
+ arg_parse_untagged(argc, argvcopy, table, endtable);\r
+\r
+ /* if no errors so far then perform post-parse checks otherwise dont bother */\r
+ if (endtable->count == 0)\r
+ arg_parse_check(table, endtable);\r
+\r
+ /* release the local copt of argv[] */\r
+ xfree(argvcopy);\r
+\r
+ return endtable->count;\r
+}\r
+\r
+/*\r
+ * Concatenate contents of src[] string onto *pdest[] string.\r
+ * The *pdest pointer is altered to point to the end of the\r
+ * target string and *pndest is decremented by the same number\r
+ * of chars.\r
+ * Does not append more than *pndest chars into *pdest[]\r
+ * so as to prevent buffer overruns.\r
+ * Its something like strncat() but more efficient for repeated\r
+ * calls on the same destination string.\r
+ * Example of use:\r
+ * char dest[30] = "good"\r
+ * size_t ndest = sizeof(dest);\r
+ * char *pdest = dest;\r
+ * arg_char(&pdest,"bye ",&ndest);\r
+ * arg_char(&pdest,"cruel ",&ndest);\r
+ * arg_char(&pdest,"world!",&ndest);\r
+ * Results in:\r
+ * dest[] == "goodbye cruel world!"\r
+ * ndest == 10\r
+ */\r
+static void arg_cat(char** pdest, const char* src, size_t* pndest) {\r
+ char* dest = *pdest;\r
+ char* end = dest + *pndest;\r
+\r
+ /*locate null terminator of dest string */\r
+ while (dest < end && *dest != 0)\r
+ dest++;\r
+\r
+ /* concat src string to dest string */\r
+ while (dest < end && *src != 0)\r
+ *dest++ = *src++;\r
+\r
+ /* null terminate dest string */\r
+ *dest = 0;\r
+\r
+ /* update *pdest and *pndest */\r
+ *pndest = end - dest;\r
+ *pdest = dest;\r
+}\r
+\r
+static void arg_cat_option(char* dest, size_t ndest, const char* shortopts, const char* longopts, const char* datatype, int optvalue) {\r
+ if (shortopts) {\r
+ char option[3];\r
+\r
+ /* note: option array[] is initialiazed dynamically here to satisfy */\r
+ /* a deficiency in the watcom compiler wrt static array initializers. */\r
+ option[0] = '-';\r
+ option[1] = shortopts[0];\r
+ option[2] = 0;\r
+\r
+ arg_cat(&dest, option, &ndest);\r
+ if (datatype) {\r
+ arg_cat(&dest, " ", &ndest);\r
+ if (optvalue) {\r
+ arg_cat(&dest, "[", &ndest);\r
+ arg_cat(&dest, datatype, &ndest);\r
+ arg_cat(&dest, "]", &ndest);\r
+ } else\r
+ arg_cat(&dest, datatype, &ndest);\r
+ }\r
+ } else if (longopts) {\r
+ size_t ncspn;\r
+\r
+ /* add "--" tag prefix */\r
+ arg_cat(&dest, "--", &ndest);\r
+\r
+ /* add comma separated option tag */\r
+ ncspn = strcspn(longopts, ",");\r
+#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__))\r
+ strncat_s(dest, ndest, longopts, (ncspn < ndest) ? ncspn : ndest);\r
+#else\r
+ strncat(dest, longopts, (ncspn < ndest) ? ncspn : ndest);\r
+#endif\r
+\r
+ if (datatype) {\r
+ arg_cat(&dest, "=", &ndest);\r
+ if (optvalue) {\r
+ arg_cat(&dest, "[", &ndest);\r
+ arg_cat(&dest, datatype, &ndest);\r
+ arg_cat(&dest, "]", &ndest);\r
+ } else\r
+ arg_cat(&dest, datatype, &ndest);\r
+ }\r
+ } else if (datatype) {\r
+ if (optvalue) {\r
+ arg_cat(&dest, "[", &ndest);\r
+ arg_cat(&dest, datatype, &ndest);\r
+ arg_cat(&dest, "]", &ndest);\r
+ } else\r
+ arg_cat(&dest, datatype, &ndest);\r
+ }\r
+}\r
+\r
+static void\r
+arg_cat_optionv(char* dest, size_t ndest, const char* shortopts, const char* longopts, const char* datatype, int optvalue, const char* separator) {\r
+ separator = separator ? separator : "";\r
+\r
+ if (shortopts) {\r
+ const char* c = shortopts;\r
+ while (*c) {\r
+ /* "-a|-b|-c" */\r
+ char shortopt[3];\r
+\r
+ /* note: shortopt array[] is initialiazed dynamically here to satisfy */\r
+ /* a deficiency in the watcom compiler wrt static array initializers. */\r
+ shortopt[0] = '-';\r
+ shortopt[1] = *c;\r
+ shortopt[2] = 0;\r
+\r
+ arg_cat(&dest, shortopt, &ndest);\r
+ if (*++c)\r
+ arg_cat(&dest, separator, &ndest);\r
+ }\r
+ }\r
+\r
+ /* put separator between long opts and short opts */\r
+ if (shortopts && longopts)\r
+ arg_cat(&dest, separator, &ndest);\r
+\r
+ if (longopts) {\r
+ const char* c = longopts;\r
+ while (*c) {\r
+ size_t ncspn;\r
+\r
+ /* add "--" tag prefix */\r
+ arg_cat(&dest, "--", &ndest);\r
+\r
+ /* add comma separated option tag */\r
+ ncspn = strcspn(c, ",");\r
+#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__))\r
+ strncat_s(dest, ndest, c, (ncspn < ndest) ? ncspn : ndest);\r
+#else\r
+ strncat(dest, c, (ncspn < ndest) ? ncspn : ndest);\r
+#endif\r
+ c += ncspn;\r
+\r
+ /* add given separator in place of comma */\r
+ if (*c == ',') {\r
+ arg_cat(&dest, separator, &ndest);\r
+ c++;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (datatype) {\r
+ if (longopts)\r
+ arg_cat(&dest, "=", &ndest);\r
+ else if (shortopts)\r
+ arg_cat(&dest, " ", &ndest);\r
+\r
+ if (optvalue) {\r
+ arg_cat(&dest, "[", &ndest);\r
+ arg_cat(&dest, datatype, &ndest);\r
+ arg_cat(&dest, "]", &ndest);\r
+ } else\r
+ arg_cat(&dest, datatype, &ndest);\r
+ }\r
+}\r
+\r
+void arg_print_option_ds(arg_dstr_t ds, const char* shortopts, const char* longopts, const char* datatype, const char* suffix) {\r
+ char syntax[200] = "";\r
+ suffix = suffix ? suffix : "";\r
+\r
+ /* there is no way of passing the proper optvalue for optional argument values here, so we must ignore it */\r
+ arg_cat_optionv(syntax, sizeof(syntax), shortopts, longopts, datatype, 0, "|");\r
+\r
+ arg_dstr_cat(ds, syntax);\r
+ arg_dstr_cat(ds, (char*)suffix);\r
+}\r
+\r
+/* this function should be deprecated because it doesn't consider optional argument values (ARG_HASOPTVALUE) */\r
+void arg_print_option(FILE* fp, const char* shortopts, const char* longopts, const char* datatype, const char* suffix) {\r
+ arg_dstr_t ds = arg_dstr_create();\r
+ arg_print_option_ds(ds, shortopts, longopts, datatype, suffix);\r
+ fputs(arg_dstr_cstr(ds), fp);\r
+ arg_dstr_destroy(ds);\r
+}\r
+\r
+/*\r
+ * Print a GNU style [OPTION] string in which all short options that\r
+ * do not take argument values are presented in abbreviated form, as\r
+ * in: -xvfsd, or -xvf[sd], or [-xvsfd]\r
+ */\r
+static void arg_print_gnuswitch_ds(arg_dstr_t ds, struct arg_hdr** table) {\r
+ int tabindex;\r
+ char* format1 = " -%c";\r
+ char* format2 = " [-%c";\r
+ char* suffix = "";\r
+\r
+ /* print all mandatory switches that are without argument values */\r
+ for (tabindex = 0; table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) {\r
+ /* skip optional options */\r
+ if (table[tabindex]->mincount < 1)\r
+ continue;\r
+\r
+ /* skip non-short options */\r
+ if (table[tabindex]->shortopts == NULL)\r
+ continue;\r
+\r
+ /* skip options that take argument values */\r
+ if (table[tabindex]->flag & ARG_HASVALUE)\r
+ continue;\r
+\r
+ /* print the short option (only the first short option char, ignore multiple choices)*/\r
+ arg_dstr_catf(ds, format1, table[tabindex]->shortopts[0]);\r
+ format1 = "%c";\r
+ format2 = "[%c";\r
+ }\r
+\r
+ /* print all optional switches that are without argument values */\r
+ for (tabindex = 0; table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) {\r
+ /* skip mandatory args */\r
+ if (table[tabindex]->mincount > 0)\r
+ continue;\r
+\r
+ /* skip args without short options */\r
+ if (table[tabindex]->shortopts == NULL)\r
+ continue;\r
+\r
+ /* skip args with values */\r
+ if (table[tabindex]->flag & ARG_HASVALUE)\r
+ continue;\r
+\r
+ /* print first short option */\r
+ arg_dstr_catf(ds, format2, table[tabindex]->shortopts[0]);\r
+ format2 = "%c";\r
+ suffix = "]";\r
+ }\r
+\r
+ arg_dstr_catf(ds, "%s", suffix);\r
+}\r
+\r
+void arg_print_syntax_ds(arg_dstr_t ds, void** argtable, const char* suffix) {\r
+ struct arg_hdr** table = (struct arg_hdr**)argtable;\r
+ int i, tabindex;\r
+\r
+ /* print GNU style [OPTION] string */\r
+ arg_print_gnuswitch_ds(ds, table);\r
+\r
+ /* print remaining options in abbreviated style */\r
+ for (tabindex = 0; table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) {\r
+ char syntax[200] = "";\r
+ const char *shortopts, *longopts, *datatype;\r
+\r
+ /* skip short options without arg values (they were printed by arg_print_gnu_switch) */\r
+ if (table[tabindex]->shortopts && !(table[tabindex]->flag & ARG_HASVALUE))\r
+ continue;\r
+\r
+ shortopts = table[tabindex]->shortopts;\r
+ longopts = table[tabindex]->longopts;\r
+ datatype = table[tabindex]->datatype;\r
+ arg_cat_option(syntax, sizeof(syntax), shortopts, longopts, datatype, table[tabindex]->flag & ARG_HASOPTVALUE);\r
+\r
+ if (strlen(syntax) > 0) {\r
+ /* print mandatory instances of this option */\r
+ for (i = 0; i < table[tabindex]->mincount; i++) {\r
+ arg_dstr_cat(ds, " ");\r
+ arg_dstr_cat(ds, syntax);\r
+ }\r
+\r
+ /* print optional instances enclosed in "[..]" */\r
+ switch (table[tabindex]->maxcount - table[tabindex]->mincount) {\r
+ case 0:\r
+ break;\r
+ case 1:\r
+ arg_dstr_cat(ds, " [");\r
+ arg_dstr_cat(ds, syntax);\r
+ arg_dstr_cat(ds, "]");\r
+ break;\r
+ case 2:\r
+ arg_dstr_cat(ds, " [");\r
+ arg_dstr_cat(ds, syntax);\r
+ arg_dstr_cat(ds, "]");\r
+ arg_dstr_cat(ds, " [");\r
+ arg_dstr_cat(ds, syntax);\r
+ arg_dstr_cat(ds, "]");\r
+ break;\r
+ default:\r
+ arg_dstr_cat(ds, " [");\r
+ arg_dstr_cat(ds, syntax);\r
+ arg_dstr_cat(ds, "]...");\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (suffix) {\r
+ arg_dstr_cat(ds, (char*)suffix);\r
+ }\r
+}\r
+\r
+void arg_print_syntax(FILE* fp, void** argtable, const char* suffix) {\r
+ arg_dstr_t ds = arg_dstr_create();\r
+ arg_print_syntax_ds(ds, argtable, suffix);\r
+ fputs(arg_dstr_cstr(ds), fp);\r
+ arg_dstr_destroy(ds);\r
+}\r
+\r
+void arg_print_syntaxv_ds(arg_dstr_t ds, void** argtable, const char* suffix) {\r
+ struct arg_hdr** table = (struct arg_hdr**)argtable;\r
+ int i, tabindex;\r
+\r
+ /* print remaining options in abbreviated style */\r
+ for (tabindex = 0; table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) {\r
+ char syntax[200] = "";\r
+ const char *shortopts, *longopts, *datatype;\r
+\r
+ shortopts = table[tabindex]->shortopts;\r
+ longopts = table[tabindex]->longopts;\r
+ datatype = table[tabindex]->datatype;\r
+ arg_cat_optionv(syntax, sizeof(syntax), shortopts, longopts, datatype, table[tabindex]->flag & ARG_HASOPTVALUE, "|");\r
+\r
+ /* print mandatory options */\r
+ for (i = 0; i < table[tabindex]->mincount; i++) {\r
+ arg_dstr_cat(ds, " ");\r
+ arg_dstr_cat(ds, syntax);\r
+ }\r
+\r
+ /* print optional args enclosed in "[..]" */\r
+ switch (table[tabindex]->maxcount - table[tabindex]->mincount) {\r
+ case 0:\r
+ break;\r
+ case 1:\r
+ arg_dstr_cat(ds, " [");\r
+ arg_dstr_cat(ds, syntax);\r
+ arg_dstr_cat(ds, "]");\r
+ break;\r
+ case 2:\r
+ arg_dstr_cat(ds, " [");\r
+ arg_dstr_cat(ds, syntax);\r
+ arg_dstr_cat(ds, "]");\r
+ arg_dstr_cat(ds, " [");\r
+ arg_dstr_cat(ds, syntax);\r
+ arg_dstr_cat(ds, "]");\r
+ break;\r
+ default:\r
+ arg_dstr_cat(ds, " [");\r
+ arg_dstr_cat(ds, syntax);\r
+ arg_dstr_cat(ds, "]...");\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (suffix) {\r
+ arg_dstr_cat(ds, (char*)suffix);\r
+ }\r
+}\r
+\r
+void arg_print_syntaxv(FILE* fp, void** argtable, const char* suffix) {\r
+ arg_dstr_t ds = arg_dstr_create();\r
+ arg_print_syntaxv_ds(ds, argtable, suffix);\r
+ fputs(arg_dstr_cstr(ds), fp);\r
+ arg_dstr_destroy(ds);\r
+}\r
+\r
+void arg_print_glossary_ds(arg_dstr_t ds, void** argtable, const char* format) {\r
+ struct arg_hdr** table = (struct arg_hdr**)argtable;\r
+ int tabindex;\r
+\r
+ format = format ? format : " %-20s %s\n";\r
+ for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) {\r
+ if (table[tabindex]->glossary) {\r
+ char syntax[200] = "";\r
+ const char* shortopts = table[tabindex]->shortopts;\r
+ const char* longopts = table[tabindex]->longopts;\r
+ const char* datatype = table[tabindex]->datatype;\r
+ const char* glossary = table[tabindex]->glossary;\r
+ arg_cat_optionv(syntax, sizeof(syntax), shortopts, longopts, datatype, table[tabindex]->flag & ARG_HASOPTVALUE, ", ");\r
+ arg_dstr_catf(ds, format, syntax, glossary);\r
+ }\r
+ }\r
+}\r
+\r
+void arg_print_glossary(FILE* fp, void** argtable, const char* format) {\r
+ arg_dstr_t ds = arg_dstr_create();\r
+ arg_print_glossary_ds(ds, argtable, format);\r
+ fputs(arg_dstr_cstr(ds), fp);\r
+ arg_dstr_destroy(ds);\r
+}\r
+\r
+/**\r
+ * Print a piece of text formatted, which means in a column with a\r
+ * left and a right margin. The lines are wrapped at whitspaces next\r
+ * to right margin. The function does not indent the first line, but\r
+ * only the following ones.\r
+ *\r
+ * Example:\r
+ * arg_print_formatted( fp, 0, 5, "Some text that doesn't fit." )\r
+ * will result in the following output:\r
+ *\r
+ * Some\r
+ * text\r
+ * that\r
+ * doesn'\r
+ * t fit.\r
+ *\r
+ * Too long lines will be wrapped in the middle of a word.\r
+ *\r
+ * arg_print_formatted( fp, 2, 7, "Some text that doesn't fit." )\r
+ * will result in the following output:\r
+ *\r
+ * Some\r
+ * text\r
+ * that\r
+ * doesn'\r
+ * t fit.\r
+ *\r
+ * As you see, the first line is not indented. This enables output of\r
+ * lines, which start in a line where output already happened.\r
+ *\r
+ * Author: Uli Fouquet\r
+ */\r
+static void arg_print_formatted_ds(arg_dstr_t ds, const unsigned lmargin, const unsigned rmargin, const char* text) {\r
+ const unsigned int textlen = (unsigned int)strlen(text);\r
+ unsigned int line_start = 0;\r
+ unsigned int line_end = textlen;\r
+ const unsigned int colwidth = (rmargin - lmargin) + 1;\r
+\r
+ assert(strlen(text) < UINT_MAX);\r
+\r
+ /* Someone doesn't like us... */\r
+ if (line_end < line_start) {\r
+ arg_dstr_catf(ds, "%s\n", text);\r
+ }\r
+\r
+ while (line_end > line_start) {\r
+ /* Eat leading white spaces. This is essential because while\r
+ wrapping lines, there will often be a whitespace at beginning\r
+ of line */\r
+ while (isspace(*(text + line_start))) {\r
+ line_start++;\r
+ }\r
+\r
+ /* Find last whitespace, that fits into line */\r
+ if (line_end - line_start > colwidth) {\r
+ line_end = line_start + colwidth;\r
+\r
+ while ((line_end > line_start) && !isspace(*(text + line_end))) {\r
+ line_end--;\r
+ }\r
+\r
+ /* Consume trailing spaces */\r
+ while ((line_end > line_start) && isspace(*(text + line_end))) {\r
+ line_end--;\r
+ }\r
+\r
+ /* Restore the last non-space character */\r
+ line_end++;\r
+ }\r
+\r
+ /* Output line of text */\r
+ while (line_start < line_end) {\r
+ char c = *(text + line_start);\r
+ arg_dstr_catc(ds, c);\r
+ line_start++;\r
+ }\r
+ arg_dstr_cat(ds, "\n");\r
+\r
+ /* Initialize another line */\r
+ if (line_end < textlen) {\r
+ unsigned i;\r
+\r
+ for (i = 0; i < lmargin; i++) {\r
+ arg_dstr_cat(ds, " ");\r
+ }\r
+\r
+ line_end = textlen;\r
+ }\r
+ } /* lines of text */\r
+}\r
+\r
+/**\r
+ * Prints the glossary in strict GNU format.\r
+ * Differences to arg_print_glossary() are:\r
+ * - wraps lines after 80 chars\r
+ * - indents lines without shortops\r
+ * - does not accept formatstrings\r
+ *\r
+ * Contributed by Uli Fouquet\r
+ */\r
+void arg_print_glossary_gnu_ds(arg_dstr_t ds, void** argtable) {\r
+ struct arg_hdr** table = (struct arg_hdr**)argtable;\r
+ int tabindex;\r
+\r
+ for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) {\r
+ if (table[tabindex]->glossary) {\r
+ char syntax[200] = "";\r
+ const char* shortopts = table[tabindex]->shortopts;\r
+ const char* longopts = table[tabindex]->longopts;\r
+ const char* datatype = table[tabindex]->datatype;\r
+ const char* glossary = table[tabindex]->glossary;\r
+\r
+ if (!shortopts && longopts) {\r
+ /* Indent trailing line by 4 spaces... */\r
+ memset(syntax, ' ', 4);\r
+ *(syntax + 4) = '\0';\r
+ }\r
+\r
+ arg_cat_optionv(syntax, sizeof(syntax), shortopts, longopts, datatype, table[tabindex]->flag & ARG_HASOPTVALUE, ", ");\r
+\r
+ /* If syntax fits not into column, print glossary in new line... */\r
+ if (strlen(syntax) > 25) {\r
+ arg_dstr_catf(ds, " %-25s %s\n", syntax, "");\r
+ *syntax = '\0';\r
+ }\r
+\r
+ arg_dstr_catf(ds, " %-25s ", syntax);\r
+ arg_print_formatted_ds(ds, 28, 79, glossary);\r
+ }\r
+ } /* for each table entry */\r
+\r
+ arg_dstr_cat(ds, "\n");\r
+}\r
+\r
+void arg_print_glossary_gnu(FILE* fp, void** argtable) {\r
+ arg_dstr_t ds = arg_dstr_create();\r
+ arg_print_glossary_gnu_ds(ds, argtable);\r
+ fputs(arg_dstr_cstr(ds), fp);\r
+ arg_dstr_destroy(ds);\r
+}\r
+\r
+/**\r
+ * Checks the argtable[] array for NULL entries and returns 1\r
+ * if any are found, zero otherwise.\r
+ */\r
+int arg_nullcheck(void** argtable) {\r
+ struct arg_hdr** table = (struct arg_hdr**)argtable;\r
+ int tabindex;\r
+ /*printf("arg_nullcheck(%p)\n",argtable);*/\r
+\r
+ if (!table)\r
+ return 1;\r
+\r
+ tabindex = 0;\r
+ do {\r
+ /*printf("argtable[%d]=%p\n",tabindex,argtable[tabindex]);*/\r
+ if (!table[tabindex])\r
+ return 1;\r
+ } while (!(table[tabindex++]->flag & ARG_TERMINATOR));\r
+\r
+ return 0;\r
+}\r
+\r
+/*\r
+ * arg_free() is deprecated in favour of arg_freetable() due to a flaw in its design.\r
+ * The flaw results in memory leak in the (very rare) case that an intermediate\r
+ * entry in the argtable array failed its memory allocation while others following\r
+ * that entry were still allocated ok. Those subsequent allocations will not be\r
+ * deallocated by arg_free().\r
+ * Despite the unlikeliness of the problem occurring, and the even unlikelier event\r
+ * that it has any deliterious effect, it is fixed regardless by replacing arg_free()\r
+ * with the newer arg_freetable() function.\r
+ * We still keep arg_free() for backwards compatibility.\r
+ */\r
+void arg_free(void** argtable) {\r
+ struct arg_hdr** table = (struct arg_hdr**)argtable;\r
+ int tabindex = 0;\r
+ int flag;\r
+ /*printf("arg_free(%p)\n",argtable);*/\r
+ do {\r
+ /*\r
+ if we encounter a NULL entry then somewhat incorrectly we presume\r
+ we have come to the end of the array. It isnt strictly true because\r
+ an intermediate entry could be NULL with other non-NULL entries to follow.\r
+ The subsequent argtable entries would then not be freed as they should.\r
+ */\r
+ if (table[tabindex] == NULL)\r
+ break;\r
+\r
+ flag = table[tabindex]->flag;\r
+ xfree(table[tabindex]);\r
+ table[tabindex++] = NULL;\r
+\r
+ } while (!(flag & ARG_TERMINATOR));\r
+}\r
+\r
+/* frees each non-NULL element of argtable[], where n is the size of the number of entries in the array */\r
+void arg_freetable(void** argtable, size_t n) {\r
+ struct arg_hdr** table = (struct arg_hdr**)argtable;\r
+ size_t tabindex = 0;\r
+ /*printf("arg_freetable(%p)\n",argtable);*/\r
+ for (tabindex = 0; tabindex < n; tabindex++) {\r
+ if (table[tabindex] == NULL)\r
+ continue;\r
+\r
+ xfree(table[tabindex]);\r
+ table[tabindex] = NULL;\r
+ };\r
+}\r
+\r
+#ifdef _WIN32\r
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {\r
+ return TRUE;\r
+ UNREFERENCED_PARAMETER(hinstDLL);\r
+ UNREFERENCED_PARAMETER(fdwReason);\r
+ UNREFERENCED_PARAMETER(lpvReserved);\r
+}\r
+#endif\r
--- /dev/null
+/*******************************************************************************
+ * argtable3: Declares the main interfaces of the library
+ *
+ * This file is part of the argtable3 library.
+ *
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
+ * <sheitmann@users.sourceforge.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of STEWART HEITMANN 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN 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.
+ ******************************************************************************/
+
+#ifndef ARGTABLE3
+#define ARGTABLE3
+
+#include <stdio.h> /* FILE */
+#include <time.h> /* struct tm */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ARG_REX_ICASE 1
+#define ARG_DSTR_SIZE 200
+#define ARG_CMD_NAME_LEN 100
+#define ARG_CMD_DESCRIPTION_LEN 256
+
+#ifndef ARG_REPLACE_GETOPT
+#define ARG_REPLACE_GETOPT 1 /* use the embedded getopt as the system getopt(3) */
+#endif /* ARG_REPLACE_GETOPT */
+
+/* bit masks for arg_hdr.flag */
+enum { ARG_TERMINATOR = 0x1, ARG_HASVALUE = 0x2, ARG_HASOPTVALUE = 0x4 };
+
+#if defined(_WIN32)
+ #if defined(argtable3_EXPORTS)
+ #define ARG_EXTERN __declspec(dllexport)
+ #elif defined(argtable3_IMPORTS)
+ #define ARG_EXTERN __declspec(dllimport)
+ #else
+ #define ARG_EXTERN
+ #endif
+#else
+ #define ARG_EXTERN
+#endif
+
+typedef struct _internal_arg_dstr* arg_dstr_t;
+typedef void* arg_cmd_itr_t;
+
+typedef void(arg_resetfn)(void* parent);
+typedef int(arg_scanfn)(void* parent, const char* argval);
+typedef int(arg_checkfn)(void* parent);
+typedef void(arg_errorfn)(void* parent, arg_dstr_t ds, int error, const char* argval, const char* progname);
+typedef void(arg_dstr_freefn)(char* buf);
+typedef int(arg_cmdfn)(int argc, char* argv[], arg_dstr_t res);
+typedef int(arg_comparefn)(const void* k1, const void* k2);
+
+/*
+ * The arg_hdr struct defines properties that are common to all arg_xxx structs.
+ * The argtable library requires each arg_xxx struct to have an arg_hdr
+ * struct as its first data member.
+ * The argtable library functions then use this data to identify the
+ * properties of the command line option, such as its option tags,
+ * datatype string, and glossary strings, and so on.
+ * Moreover, the arg_hdr struct contains pointers to custom functions that
+ * are provided by each arg_xxx struct which perform the tasks of parsing
+ * that particular arg_xxx arguments, performing post-parse checks, and
+ * reporting errors.
+ * These functions are private to the individual arg_xxx source code
+ * and are the pointer to them are initiliased by that arg_xxx struct's
+ * constructor function. The user could alter them after construction
+ * if desired, but the original intention is for them to be set by the
+ * constructor and left unaltered.
+ */
+struct arg_hdr {
+ char flag; /* Modifier flags: ARG_TERMINATOR, ARG_HASVALUE. */
+ const char* shortopts; /* String defining the short options */
+ const char* longopts; /* String defiing the long options */
+ const char* datatype; /* Description of the argument data type */
+ const char* glossary; /* Description of the option as shown by arg_print_glossary function */
+ int mincount; /* Minimum number of occurences of this option accepted */
+ int maxcount; /* Maximum number of occurences if this option accepted */
+ void* parent; /* Pointer to parent arg_xxx struct */
+ arg_resetfn* resetfn; /* Pointer to parent arg_xxx reset function */
+ arg_scanfn* scanfn; /* Pointer to parent arg_xxx scan function */
+ arg_checkfn* checkfn; /* Pointer to parent arg_xxx check function */
+ arg_errorfn* errorfn; /* Pointer to parent arg_xxx error function */
+ void* priv; /* Pointer to private header data for use by arg_xxx functions */
+};
+
+struct arg_rem {
+ struct arg_hdr hdr; /* The mandatory argtable header struct */
+};
+
+struct arg_lit {
+ struct arg_hdr hdr; /* The mandatory argtable header struct */
+ int count; /* Number of matching command line args */
+};
+
+struct arg_int {
+ struct arg_hdr hdr; /* The mandatory argtable header struct */
+ int count; /* Number of matching command line args */
+ int* ival; /* Array of parsed argument values */
+};
+
+struct arg_dbl {
+ struct arg_hdr hdr; /* The mandatory argtable header struct */
+ int count; /* Number of matching command line args */
+ double* dval; /* Array of parsed argument values */
+};
+
+struct arg_str {
+ struct arg_hdr hdr; /* The mandatory argtable header struct */
+ int count; /* Number of matching command line args */
+ const char** sval; /* Array of parsed argument values */
+};
+
+struct arg_rex {
+ struct arg_hdr hdr; /* The mandatory argtable header struct */
+ int count; /* Number of matching command line args */
+ const char** sval; /* Array of parsed argument values */
+};
+
+struct arg_file {
+ struct arg_hdr hdr; /* The mandatory argtable header struct */
+ int count; /* Number of matching command line args*/
+ const char** filename; /* Array of parsed filenames (eg: /home/foo.bar) */
+ const char** basename; /* Array of parsed basenames (eg: foo.bar) */
+ const char** extension; /* Array of parsed extensions (eg: .bar) */
+};
+
+struct arg_date {
+ struct arg_hdr hdr; /* The mandatory argtable header struct */
+ const char* format; /* strptime format string used to parse the date */
+ int count; /* Number of matching command line args */
+ struct tm* tmval; /* Array of parsed time values */
+};
+
+enum { ARG_ELIMIT = 1, ARG_EMALLOC, ARG_ENOMATCH, ARG_ELONGOPT, ARG_EMISSARG };
+struct arg_end {
+ struct arg_hdr hdr; /* The mandatory argtable header struct */
+ int count; /* Number of errors encountered */
+ int* error; /* Array of error codes */
+ void** parent; /* Array of pointers to offending arg_xxx struct */
+ const char** argval; /* Array of pointers to offending argv[] string */
+};
+
+typedef struct arg_cmd_info {
+ char name[ARG_CMD_NAME_LEN];
+ char description[ARG_CMD_DESCRIPTION_LEN];
+ arg_cmdfn* proc;
+} arg_cmd_info_t;
+
+/**** arg_xxx constructor functions *********************************/
+
+ARG_EXTERN struct arg_rem* arg_rem(const char* datatype, const char* glossary);
+
+ARG_EXTERN struct arg_lit* arg_lit0(const char* shortopts, const char* longopts, const char* glossary);
+ARG_EXTERN struct arg_lit* arg_lit1(const char* shortopts, const char* longopts, const char* glossary);
+ARG_EXTERN struct arg_lit* arg_litn(const char* shortopts, const char* longopts, int mincount, int maxcount, const char* glossary);
+
+ARG_EXTERN struct arg_key* arg_key0(const char* keyword, int flags, const char* glossary);
+ARG_EXTERN struct arg_key* arg_key1(const char* keyword, int flags, const char* glossary);
+ARG_EXTERN struct arg_key* arg_keyn(const char* keyword, int flags, int mincount, int maxcount, const char* glossary);
+
+ARG_EXTERN struct arg_int* arg_int0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary);
+ARG_EXTERN struct arg_int* arg_int1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary);
+ARG_EXTERN struct arg_int* arg_intn(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary);
+
+ARG_EXTERN struct arg_dbl* arg_dbl0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary);
+ARG_EXTERN struct arg_dbl* arg_dbl1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary);
+ARG_EXTERN struct arg_dbl* arg_dbln(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary);
+
+ARG_EXTERN struct arg_str* arg_str0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary);
+ARG_EXTERN struct arg_str* arg_str1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary);
+ARG_EXTERN struct arg_str* arg_strn(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary);
+
+ARG_EXTERN struct arg_rex* arg_rex0(const char* shortopts, const char* longopts, const char* pattern, const char* datatype, int flags, const char* glossary);
+ARG_EXTERN struct arg_rex* arg_rex1(const char* shortopts, const char* longopts, const char* pattern, const char* datatype, int flags, const char* glossary);
+ARG_EXTERN struct arg_rex* arg_rexn(const char* shortopts,
+ const char* longopts,
+ const char* pattern,
+ const char* datatype,
+ int mincount,
+ int maxcount,
+ int flags,
+ const char* glossary);
+
+ARG_EXTERN struct arg_file* arg_file0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary);
+ARG_EXTERN struct arg_file* arg_file1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary);
+ARG_EXTERN struct arg_file* arg_filen(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary);
+
+ARG_EXTERN struct arg_date* arg_date0(const char* shortopts, const char* longopts, const char* format, const char* datatype, const char* glossary);
+ARG_EXTERN struct arg_date* arg_date1(const char* shortopts, const char* longopts, const char* format, const char* datatype, const char* glossary);
+ARG_EXTERN struct arg_date* arg_daten(const char* shortopts, const char* longopts, const char* format, const char* datatype, int mincount, int maxcount, const char* glossary);
+
+ARG_EXTERN struct arg_end* arg_end(int maxerrors);
+
+#define ARG_DSTR_STATIC ((arg_dstr_freefn*)0)
+#define ARG_DSTR_VOLATILE ((arg_dstr_freefn*)1)
+#define ARG_DSTR_DYNAMIC ((arg_dstr_freefn*)3)
+
+/**** other functions *******************************************/
+ARG_EXTERN int arg_nullcheck(void** argtable);
+ARG_EXTERN int arg_parse(int argc, char** argv, void** argtable);
+ARG_EXTERN void arg_print_option(FILE* fp, const char* shortopts, const char* longopts, const char* datatype, const char* suffix);
+ARG_EXTERN void arg_print_syntax(FILE* fp, void** argtable, const char* suffix);
+ARG_EXTERN void arg_print_syntaxv(FILE* fp, void** argtable, const char* suffix);
+ARG_EXTERN void arg_print_glossary(FILE* fp, void** argtable, const char* format);
+ARG_EXTERN void arg_print_glossary_gnu(FILE* fp, void** argtable);
+ARG_EXTERN void arg_print_errors(FILE* fp, struct arg_end* end, const char* progname);
+ARG_EXTERN void arg_print_option_ds(arg_dstr_t ds, const char* shortopts, const char* longopts, const char* datatype, const char* suffix);
+ARG_EXTERN void arg_print_syntax_ds(arg_dstr_t ds, void** argtable, const char* suffix);
+ARG_EXTERN void arg_print_syntaxv_ds(arg_dstr_t ds, void** argtable, const char* suffix);
+ARG_EXTERN void arg_print_glossary_ds(arg_dstr_t ds, void** argtable, const char* format);
+ARG_EXTERN void arg_print_glossary_gnu_ds(arg_dstr_t ds, void** argtable);
+ARG_EXTERN void arg_print_errors_ds(arg_dstr_t ds, struct arg_end* end, const char* progname);
+ARG_EXTERN void arg_freetable(void** argtable, size_t n);
+
+ARG_EXTERN arg_dstr_t arg_dstr_create(void);
+ARG_EXTERN void arg_dstr_destroy(arg_dstr_t ds);
+ARG_EXTERN void arg_dstr_reset(arg_dstr_t ds);
+ARG_EXTERN void arg_dstr_free(arg_dstr_t ds);
+ARG_EXTERN void arg_dstr_set(arg_dstr_t ds, char* str, arg_dstr_freefn* free_proc);
+ARG_EXTERN void arg_dstr_cat(arg_dstr_t ds, const char* str);
+ARG_EXTERN void arg_dstr_catc(arg_dstr_t ds, char c);
+ARG_EXTERN void arg_dstr_catf(arg_dstr_t ds, const char* fmt, ...);
+ARG_EXTERN char* arg_dstr_cstr(arg_dstr_t ds);
+
+ARG_EXTERN void arg_cmd_init(void);
+ARG_EXTERN void arg_cmd_uninit(void);
+ARG_EXTERN void arg_cmd_register(const char* name, arg_cmdfn* proc, const char* description);
+ARG_EXTERN void arg_cmd_unregister(const char* name);
+ARG_EXTERN int arg_cmd_dispatch(const char* name, int argc, char* argv[], arg_dstr_t res);
+ARG_EXTERN unsigned int arg_cmd_count(void);
+ARG_EXTERN arg_cmd_info_t* arg_cmd_info(const char* name);
+ARG_EXTERN arg_cmd_itr_t arg_cmd_itr_create(void);
+ARG_EXTERN void arg_cmd_itr_destroy(arg_cmd_itr_t itr);
+ARG_EXTERN int arg_cmd_itr_advance(arg_cmd_itr_t itr);
+ARG_EXTERN char* arg_cmd_itr_key(arg_cmd_itr_t itr);
+ARG_EXTERN arg_cmd_info_t* arg_cmd_itr_value(arg_cmd_itr_t itr);
+ARG_EXTERN int arg_cmd_itr_search(arg_cmd_itr_t itr, void* k);
+ARG_EXTERN void arg_mgsort(void* data, int size, int esize, int i, int k, arg_comparefn* comparefn);
+ARG_EXTERN void arg_make_get_help_msg(arg_dstr_t res);
+ARG_EXTERN void arg_make_help_msg(arg_dstr_t ds, char* cmd_name, void** argtable);
+ARG_EXTERN void arg_make_syntax_err_msg(arg_dstr_t ds, void** argtable, struct arg_end* end);
+ARG_EXTERN int arg_make_syntax_err_help_msg(arg_dstr_t ds, char* name, int help, int nerrors, void** argtable, struct arg_end* end, int* exitcode);
+ARG_EXTERN void arg_set_module_name(const char* name);
+ARG_EXTERN void arg_set_module_version(int major, int minor, int patch, const char* tag);
+
+/**** deprecated functions, for back-compatibility only ********/
+ARG_EXTERN void arg_free(void** argtable);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
--- /dev/null
+################################################################################\r
+# This file is part of the argtable3 library.\r
+#\r
+# Copyright (C) 2016-2019 Tom G. Huang\r
+# <tomghuang@gmail.com>\r
+# All rights reserved.\r
+#\r
+# Redistribution and use in source and binary forms, with or without\r
+# modification, are permitted provided that the following conditions are met:\r
+# * Redistributions of source code must retain the above copyright\r
+# notice, this list of conditions and the following disclaimer.\r
+# * Redistributions in binary form must reproduce the above copyright\r
+# notice, this list of conditions and the following disclaimer in the\r
+# documentation and/or other materials provided with the distribution.\r
+# * Neither the name of STEWART HEITMANN nor the names of its contributors\r
+# may be used to endorse or promote products derived from this software\r
+# without specific prior written permission.\r
+#\r
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+# ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+################################################################################\r
+\r
+file(GLOB EXAMPLES_SOURCES RELATIVE ${PROJECT_SOURCE_DIR}/examples *.c)\r
+\r
+if(UNIX)\r
+ set(ARGTABLE3_EXTRA_LIBS m)\r
+endif()\r
+\r
+foreach(examples_src ${EXAMPLES_SOURCES})\r
+ string(REPLACE ".c" "" examplename ${examples_src})\r
+ add_executable(${examplename} ${PROJECT_SOURCE_DIR}/examples/${examples_src})\r
+ target_include_directories(${examplename} PRIVATE ${PROJECT_SOURCE_DIR}/src)\r
+ if(ARGTABLE3_BUILD_STATIC_EXAMPLES)\r
+ target_link_libraries(${examplename} argtable3_static ${ARGTABLE3_EXTRA_LIBS})\r
+ else()\r
+ target_link_libraries(${examplename} argtable3 ${ARGTABLE3_EXTRA_LIBS})\r
+ endif()\r
+endforeach()\r
--- /dev/null
+/*******************************************************************************
+ * Example source code for using the argtable3 library to implement:
+ *
+ * echo [-neE] [--help] [--version] [STRING]...
+ *
+ * This file is part of the argtable3 library.
+ *
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
+ * <sheitmann@users.sourceforge.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of STEWART HEITMANN 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN 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.
+ ******************************************************************************/
+
+#include "argtable3.h"
+
+/* Here we only approximate the echo functionality */
+void mymain(int n, int e, int E, const char** strings, int nstrings)
+ {
+ int j;
+
+ printf("option -n = %s\n", ((n)?"YES":"NO"));
+ printf("option -e = %s\n", ((e)?"YES":"NO"));
+ printf("option -E = %s\n", ((E)?"YES":"NO"));
+ for (j=0; j<nstrings; j++)
+ printf("%s ", strings[j]);
+ printf("\n");
+ }
+
+
+int main(int argc, char **argv)
+ {
+ /* Define the allowable command line options, collecting them in argtable[] */
+ struct arg_lit *n = arg_lit0("n", NULL, "do not output the trailing newline");
+ struct arg_lit *e = arg_lit0("e", NULL, "enable interpretation of the backslash-escaped characters listed below");
+ struct arg_lit *E = arg_lit0("E", NULL, "disable interpretation of those sequences in <string>s");
+ struct arg_lit *help = arg_lit0(NULL,"help", "print this help and exit");
+ struct arg_lit *vers = arg_lit0(NULL,"version", "print version information and exit");
+ struct arg_str *strs = arg_strn(NULL,NULL,"STRING",0,argc+2,NULL);
+ struct arg_end *end = arg_end(20);
+ void* argtable[] = {n,e,E,help,vers,strs,end};
+ const char* progname = "echo";
+ int exitcode=0;
+ int nerrors;
+
+ /* verify the argtable[] entries were allocated sucessfully */
+ if (arg_nullcheck(argtable) != 0)
+ {
+ /* NULL entries were detected, some allocations must have failed */
+ printf("%s: insufficient memory\n",progname);
+ exitcode=1;
+ goto exit;
+ }
+
+ /* Parse the command line as defined by argtable[] */
+ nerrors = arg_parse(argc,argv,argtable);
+
+ /* special case: '--help' takes precedence over error reporting */
+ if (help->count > 0)
+ {
+ printf("Usage: %s", progname);
+ arg_print_syntax(stdout,argtable,"\n");
+ printf("Echo the STRINGs to standard output.\n\n");
+ arg_print_glossary(stdout,argtable," %-10s %s\n");
+ printf("\nWithout -E, the following sequences are recognized and interpolated:\n\n"
+ " \\NNN the character whose ASCII code is NNN (octal)\n"
+ " \\\\ backslash\n"
+ " \\a alert (BEL)\n"
+ " \\b backspace\n"
+ " \\c suppress trailing newline\n"
+ " \\f form feed\n"
+ " \\n new line\n"
+ " \\r carriage return\n"
+ " \\t horizontal tab\n"
+ " \\v vertical tab\n\n"
+ "Report bugs to <foo@bar>.\n");
+ exitcode=0;
+ goto exit;
+ }
+
+ /* special case: '--version' takes precedence error reporting */
+ if (vers->count > 0)
+ {
+ printf("'%s' example program for the \"argtable\" command line argument parser.\n",progname);
+ printf("September 2003, Stewart Heitmann\n");
+ exitcode=0;
+ goto exit;
+ }
+
+ /* If the parser returned any errors then display them and exit */
+ if (nerrors > 0)
+ {
+ /* Display the error details contained in the arg_end struct.*/
+ arg_print_errors(stdout,end,progname);
+ printf("Try '%s --help' for more information.\n",progname);
+ exitcode=1;
+ goto exit;
+ }
+
+ /* Command line parsing is complete, do the main processing */
+ mymain(n->count, e->count, E->count, strs->sval, strs->count);
+
+ exit:
+ /* deallocate each non-null entry in argtable[] */
+ arg_freetable(argtable,sizeof(argtable)/sizeof(argtable[0]));
+
+ return exitcode;
+ }
--- /dev/null
+/*******************************************************************************
+ * Example source code for using the argtable3 library to implement:
+ *
+ * ls [-aAbBcCdDfFgGhHiklLmnNopqQrRsStuUvxX1] [--author]
+ * [--block-size=SIZE] [--color=[WHEN]] [--format=WORD] [--full-time]
+ * [--si] [--dereference-command-line-symlink-to-dir] [--indicator-style=WORD]
+ * [-I PATTERN] [--show-control-chars] [--quoting-style=WORD] [--sort=WORD]
+ * [--time=WORD] [--time-style=STYLE] [-T COLS] [-w COLS] [--help]
+ * [--version] [FILE]...
+ *
+ * This file is part of the argtable3 library.
+ *
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
+ * <sheitmann@users.sourceforge.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of STEWART HEITMANN 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN 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.
+ ******************************************************************************/
+
+#include "argtable3.h"
+
+/* These variables hold the values parsed from the comand line by arg_parse() */
+struct arg_lit *a, *A, *author, *b, *B, *c, *C, *d, *D, *f, *F, *fulltime;
+struct arg_lit *g, *G, *h, *H, *si, *deref, *i, *k, *l, *L, *m, *n, *N, *o, *p;
+struct arg_lit *q, *shcont, *Q, *r, *R, *s, *S, *t, *u, *U, *v, *x, *X, *one;
+struct arg_lit *help, *version;
+struct arg_int *blocksize, *T, *w;
+struct arg_str *color, *format, *indic, *I, *Qstyle, *sort, *Time, *timesty;
+struct arg_file *files;
+struct arg_end *end;
+
+/* Here we simply echo the command line option values as a demonstration. */
+/* In a real program, this is where we would perform the main processing. */
+int mymain(void)
+ {
+ int j;
+
+ if (a->count > 0)
+ printf("a=YES\n");
+ if (A->count > 0)
+ printf("A=YES\n");
+ if (author->count > 0)
+ printf("author=YES\n");
+ if (b->count > 0)
+ printf("b=YES\n");
+ if (blocksize->count > 0)
+ printf("blocksize=%d\n",blocksize->count);
+ if (B->count > 0)
+ printf("B=YES\n");
+ if (c->count > 0)
+ printf("c=YES\n");
+ if (C->count > 0)
+ printf("C=YES\n");
+ if (color->count > 0)
+ printf("color=%s\n",color->sval[0]);
+ if (d->count > 0)
+ printf("d=YES\n");
+ if (D->count > 0)
+ printf("D=YES\n");
+ if (f->count > 0)
+ printf("f=YES\n");
+ if (F->count > 0)
+ printf("F=YES\n");
+ if (format->count > 0)
+ printf("format=%s\n",format->sval[0]);
+ if (fulltime->count > 0)
+ printf("fulltime=YES\n");
+ if (g->count > 0)
+ printf("g=YES\n");
+ if (G->count > 0)
+ printf("G=YES\n");
+ if (h->count > 0)
+ printf("h=YES\n");
+ if (si->count > 0)
+ printf("si=YES\n");
+ if (H->count > 0)
+ printf("H=YES\n");
+ if (deref->count > 0)
+ printf("deref=YES\n");
+ if (indic->count > 0)
+ printf("indic=%s\n",indic->sval[0]);
+ if (i->count > 0)
+ printf("i=YES\n");
+ if (I->count > 0)
+ printf("I=%s\n",I->sval[0]);
+ if (k->count > 0)
+ printf("k=YES\n");
+ if (l->count > 0)
+ printf("l=YES\n");
+ if (L->count > 0)
+ printf("L=YES\n");
+ if (m->count > 0)
+ printf("m=YES\n");
+ if (n->count > 0)
+ printf("n=YES\n");
+ if (N->count > 0)
+ printf("N=YES\n");
+ if (o->count > 0)
+ printf("o=YES\n");
+ if (p->count > 0)
+ printf("p=YES\n");
+ if (q->count > 0)
+ printf("q=YES\n");
+ if (shcont->count > 0)
+ printf("shcont=YES\n");
+ if (Q->count > 0)
+ printf("Q=YES\n");
+ if (Qstyle->count > 0)
+ printf("Qstyle=%s\n",Qstyle->sval[0]);
+ if (r->count > 0)
+ printf("r=YES\n");
+ if (R->count > 0)
+ printf("R=YES\n");
+ if (s->count > 0)
+ printf("s=YES\n");
+ if (S->count > 0)
+ printf("S=YES\n");
+ if (sort->count > 0)
+ printf("sort=%s\n",sort->sval[0]);
+ if (Time->count > 0)
+ printf("time=%s\n",Time->sval[0]);
+ if (timesty->count > 0)
+ printf("timesty=%s\n",timesty->sval[0]);
+ if (t->count > 0)
+ printf("t=YES\n");
+ if (T->count > 0)
+ printf("T=%d\n",T->ival[0]);
+ if (u->count > 0)
+ printf("u=YES\n");
+ if (U->count > 0)
+ printf("U=YES\n");
+ if (v->count > 0)
+ printf("v=YES\n");
+ if (w->count > 0)
+ printf("w=%d\n",w->ival[0]);
+ if (x->count > 0)
+ printf("x=YES\n");
+ if (X->count > 0)
+ printf("X=YES\n");
+ if (one->count > 0)
+ printf("1=YES\n");
+
+ /* print the filenames */
+ for (j=0; j<files->count; j++)
+ printf("filename[%d] = \"%s\"\n", j, files->filename[j]);
+
+ return 0;
+ }
+
+
+int main(int argc, char **argv)
+ {
+ /* The argtable[] entries define the command line options */
+ void *argtable[] = {
+ a = arg_lit0("a", "all", "do not hide entries starting with ."),
+ A = arg_lit0("A", "almost-all", "do not list implied . and .."),
+ author = arg_lit0(NULL,"author", "print the author of each file"),
+ b = arg_lit0("b", "escape", "print octal escapes for nongraphic characters"),
+ blocksize = arg_int0(NULL,"block-size","SIZE", "use SIZE-byte blocks"),
+ B = arg_lit0("B", "ignore-backups", "do not list implied entries ending with ~"),
+ c = arg_lit0("c", NULL, "with -lt: sort by, and show, ctime (time of last"),
+ arg_rem(NULL, " modification of file status information)"),
+ arg_rem(NULL, " with -l: show ctime and sort by name"),
+ arg_rem(NULL, " otherwise: sort by ctime"),
+ C = arg_lit0("C", NULL, "list entries by columns"),
+ color = arg_str0(NULL,"color","WHEN", "control whether color is used to distinguish file"),
+ arg_rem(NULL, " types. WHEN may be `never', `always', or `auto'"),
+ d = arg_lit0("d", "directory", "list directory entries instead of contents,"),
+ arg_rem(NULL, " and do not dereference symbolic links"),
+ D = arg_lit0("D", "dired", "generate output designed for Emacs' dired mode"),
+ f = arg_lit0("f", NULL, "do not sort, enable -aU, disable -lst"),
+ F = arg_lit0("F", "classify", "append indicator (one of */=@|) to entries"),
+ format = arg_str0(NULL,"format","WORD", "across -x, commas -m, horizontal -x, long -l,"),
+ arg_rem (NULL, " single-column -1, verbose -l, vertical -C"),
+ fulltime = arg_lit0(NULL,"full-time", "like -l --time-style=full-iso"),
+ g = arg_lit0("g", NULL, "like -l, but do not list owner"),
+ G = arg_lit0("G", "no-group", "inhibit display of group information"),
+ h = arg_lit0("h", "human-readable", "print sizes in human readable format (e.g., 1K 234M 2G)"),
+ si = arg_lit0(NULL,"si", "likewise, but use powers of 1000 not 1024"),
+ H = arg_lit0("H", "dereference-command-line","follow symbolic links listed on the command line"),
+ deref = arg_lit0(NULL,"dereference-command-line-symlink-to-dir","follow each command line symbolic link"),
+ arg_rem(NULL, " that points to a directory"),
+ indic = arg_str0(NULL,"indicator-style","WORD","append indicator with style WORD to entry names:"),
+ arg_rem (NULL, " none (default), classify (-F), file-type (-p)"),
+ i = arg_lit0("i", "inode", "print index number of each file"),
+ I = arg_str0("I", "ignore","PATTERN", "do not list implied entries matching shell PATTERN"),
+ k = arg_lit0("k", NULL, "like --block-size=1K"),
+ l = arg_lit0("l", NULL, "use a long listing format"),
+ L = arg_lit0("L", "dereference", "when showing file information for a symbolic"),
+ arg_rem (NULL, " link, show information for the file the link"),
+ arg_rem (NULL, " references rather than for the link itself"),
+ m = arg_lit0("m", NULL, "fill width with a comma separated list of entries"),
+ n = arg_lit0("n", "numeric-uid-gid", "like -l, but list numeric UIDs and GIDs"),
+ N = arg_lit0("N", "literal", "print raw entry names (don't treat e.g. control"),
+ arg_rem (NULL, " characters specially)"),
+ o = arg_lit0("o", NULL, "like -l, but do not list group information"),
+ p = arg_lit0("p", "file-type", "append indicator (one of /=@|) to entries"),
+ q = arg_lit0("q", "hide-control-chars", "print ? instead of non graphic characters"),
+ shcont = arg_lit0(NULL,"show-control-chars", "show non graphic characters as-is (default"),
+ arg_rem (NULL, "unless program is `ls' and output is a terminal)"),
+ Q = arg_lit0("Q", "quote-name", "enclose entry names in double quotes"),
+ Qstyle = arg_str0(NULL,"quoting-style","WORD","use quoting style WORD for entry names:"),
+ arg_rem (NULL, " literal, locale, shell, shell-always, c, escape"),
+ r = arg_lit0("r", "reverse", "reverse order while sorting"),
+ R = arg_lit0("R", "recursive", "list subdirectories recursively"),
+ s = arg_lit0("s", "size", "print size of each file, in blocks"),
+ S = arg_lit0("S", NULL, "sort by file size"),
+ sort = arg_str0(NULL,"sort","WORD", "extension -X, none -U, size -S, time -t, version -v,"),
+ arg_rem (NULL, "status -c, time -t, atime -u, access -u, use -u"),
+ Time = arg_str0(NULL,"time","WORD", "show time as WORD instead of modification time:"),
+ arg_rem (NULL, " atime, access, use, ctime or status; use"),
+ arg_rem (NULL, " specified time as sort key if --sort=time"),
+ timesty = arg_str0(NULL, "time-style","STYLE", "show times using style STYLE:"),
+ arg_rem (NULL, " full-iso, long-iso, iso, locale, +FORMAT"),
+ arg_rem (NULL, "FORMAT is interpreted like `date'; if FORMAT is"),
+ arg_rem (NULL, "FORMAT1<newline>FORMAT2, FORMAT1 applies to"),
+ arg_rem (NULL, "non-recent files and FORMAT2 to recent files;"),
+ arg_rem (NULL, "if STYLE is prefixed with `posix-', STYLE"),
+ arg_rem (NULL, "takes effect only outside the POSIX locale"),
+ t = arg_lit0("t", NULL, "sort by modification time"),
+ T = arg_int0("T", "tabsize", "COLS", "assume tab stops at each COLS instead of 8"),
+ u = arg_lit0("u", NULL, "with -lt: sort by, and show, access time"),
+ arg_rem (NULL, " with -l: show access time and sort by name"),
+ arg_rem (NULL, " otherwise: sort by access time"),
+ U = arg_lit0("U", NULL, "do not sort; list entries in directory order"),
+ v = arg_lit0("v", NULL, "sort by version"),
+ w = arg_int0("w", "width", "COLS", "assume screen width instead of current value"),
+ x = arg_lit0("x", NULL, "list entries by lines instead of by columns"),
+ X = arg_lit0("X", NULL, "sort alphabetically by entry extension"),
+ one = arg_lit0("1", NULL, "list one file per line"),
+ help = arg_lit0(NULL,"help", "display this help and exit"),
+ version = arg_lit0(NULL,"version", "display version information and exit"),
+ files = arg_filen(NULL, NULL, "FILE", 0, argc+2, NULL),
+ end = arg_end(20),
+ };
+ const char *progname = "ls";
+ int exitcode=0;
+ int nerrors;
+
+ /* verify the argtable[] entries were allocated sucessfully */
+ if (arg_nullcheck(argtable) != 0)
+ {
+ /* NULL entries were detected, some allocations must have failed */
+ printf("%s: insufficient memory\n",progname);
+ exitcode=1;
+ goto exit;
+ }
+
+ /* allow optional argument values for --color */
+ /* and set the default value to "always" */
+ color->hdr.flag |= ARG_HASOPTVALUE;
+ color->sval[0] = "always";
+
+ /* Parse the command line as defined by argtable[] */
+ nerrors = arg_parse(argc,argv,argtable);
+
+ /* special case: '--help' takes precedence over error reporting */
+ if (help->count > 0)
+ {
+ printf("Usage: %s", progname);
+ arg_print_syntax(stdout,argtable,"\n");
+ printf("List information about the FILE(s) (the current directory by default).\n");
+ printf("Sort entries alphabetically if none of -cftuSUX nor --sort.\n\n");
+ arg_print_glossary(stdout,argtable," %-25s %s\n");
+ printf("\nSIZE may be (or may be an integer optionally followed by) one of following:\n"
+ "kB 1000, K 1024, MB 1,000,000, M 1,048,576, and so on for G, T, P, E, Z, Y.\n\n"
+ "By default, color is not used to distinguish types of files. That is\n"
+ "equivalent to using --color=none. Using the --color option without the\n"
+ "optional WHEN argument is equivalent to using --color=always. With\n"
+ "--color=auto, color codes are output only if standard output is connected\n"
+ "to a terminal (tty).\n\n"
+ "Report bugs to <foo@bar>.\n");
+ exitcode=0;
+ goto exit;
+ }
+
+ /* special case: '--version' takes precedence error reporting */
+ if (version->count > 0)
+ {
+ printf("'%s' example program for the \"argtable\" command line argument parser.\n",progname);
+ printf("September 2003, Stewart Heitmann\n");
+ exitcode=0;
+ goto exit;
+ }
+
+ /* If the parser returned any errors then display them and exit */
+ if (nerrors > 0)
+ {
+ /* Display the error details contained in the arg_end struct.*/
+ arg_print_errors(stdout,end,progname);
+ printf("Try '%s --help' for more information.\n",progname);
+ exitcode=1;
+ goto exit;
+ }
+
+ /* Command line parsing is complete, do the main processing */
+ exitcode = mymain();
+
+exit:
+ /* deallocate each non-null entry in argtable[] */
+ arg_freetable(argtable,sizeof(argtable)/sizeof(argtable[0]));
+
+ return exitcode;
+ }
+
+
--- /dev/null
+/*******************************************************************************
+ * Example source code for using the argtable3 library to implement
+ * a multi-syntax command line argument program
+ *
+ * usage 1: multisyntax [-nvR] insert <file> [<file>]... [-o <output>]
+ * usage 2: multisyntax [-nv] remove <file>
+ * usage 3: multisyntax [-v] search <pattern> [-o <output>]
+ * usage 4: multisyntax [--help] [--version]
+ *
+ * This file is part of the argtable3 library.
+ *
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
+ * <sheitmann@users.sourceforge.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of STEWART HEITMANN 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN 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.
+ ******************************************************************************/
+
+#include "argtable3.h"
+
+#define REG_EXTENDED 1
+#define REG_ICASE (REG_EXTENDED << 1)
+
+/* mymain1 implements the actions for syntax 1 */
+int mymain1(int n, int v, int R, const char *outfile,
+ const char **infiles, int ninfiles)
+ {
+ int i;
+ printf("syntax 1 matched OK:\n");
+ printf("n=%d\n", n);
+ printf("v=%d\n", v);
+ printf("R=%d\n", R);
+ printf("outfile=\"%s\"\n", outfile);
+ for (i=0; i<ninfiles; i++)
+ printf("infile[%d]=\"%s\"\n",i,infiles[i]);
+ return 0;
+ }
+
+
+/* mymain2 implements the actions for syntax 2 */
+int mymain2(int n, int v, const char *infile)
+ {
+ printf("syntax 2 matched OK:\n");
+ printf("n=%d\n", n);
+ printf("v=%d\n", v);
+ printf("infile=\"%s\"\n", infile);
+ return 0;
+ }
+
+
+/* mymain3 implements the actions for syntax 3 */
+int mymain3(int v, const char *pattern, const char *outfile)
+ {
+ printf("syntax 3 matched OK:\n");
+ printf("v=%d\n", v);
+ printf("pattern=\"%s\"\n", pattern);
+ printf("outfile=\"%s\"\n", outfile);
+ return 0;
+ }
+
+
+/* mymain4 implements the actions for syntax 4 */
+int mymain4(int help, int version, const char *progname,
+ void *argtable1, void *argtable2, void *argtable3, void *argtable4)
+ {
+ /* --help option */
+ if (help)
+ {
+ printf("Usage: %s", progname);
+ arg_print_syntax(stdout,argtable1,"\n");
+ printf(" %s", progname);
+ arg_print_syntax(stdout,argtable2,"\n");
+ printf(" %s", progname);
+ arg_print_syntax(stdout,argtable3,"\n");
+ printf(" %s", progname);
+ arg_print_syntax(stdout,argtable4,"\n");
+ printf("This program demonstrates the use of the argtable2 library\n");
+ printf("for parsing multiple command line syntaxes.\n");
+ arg_print_glossary(stdout,argtable1," %-20s %s\n");
+ arg_print_glossary(stdout,argtable2," %-20s %s\n");
+ arg_print_glossary(stdout,argtable3," %-20s %s\n");
+ arg_print_glossary(stdout,argtable4," %-20s %s\n");
+ return 0;
+ }
+
+ /* --version option */
+ if (version)
+ {
+ printf("'%s' example program for the \"argtable\" command line argument parser.\n",progname);
+ return 0;
+ }
+
+ /* no command line options at all */
+ printf("Try '%s --help' for more information.\n", progname);
+ return 0;
+ }
+
+
+int main(int argc, char **argv)
+ {
+ /* SYNTAX 1: insert [-nvR] <file> [file]... -o <file> */
+ struct arg_rex *cmd1 = arg_rex1(NULL, NULL, "insert", NULL, REG_ICASE, NULL);
+ struct arg_lit *noact1 = arg_lit0("n", NULL, "take no action");
+ struct arg_lit *verbose1 = arg_lit0("v", "verbose", "verbose messages");
+ struct arg_lit *recurse1 = arg_lit0("R", NULL, "recurse through subdirectories");
+ struct arg_file *infiles1 = arg_filen(NULL, NULL, NULL, 1,argc+2, "input file(s)");
+ struct arg_file *outfile1 = arg_file0("o", NULL, "<output>", "output file (default is \"-\")");
+ struct arg_end *end1 = arg_end(20);
+ void* argtable1[] = {cmd1,noact1,verbose1,recurse1,infiles1,outfile1,end1};
+ int nerrors1;
+
+ /* SYNTAX 2: remove [-nv] <file> */
+ struct arg_rex *cmd2 = arg_rex1(NULL, NULL, "remove", NULL, REG_ICASE, NULL);
+ struct arg_lit *noact2 = arg_lit0("n", NULL, NULL);
+ struct arg_lit *verbose2 = arg_lit0("v", "verbose", NULL);
+ struct arg_file *infiles2 = arg_file1(NULL, NULL, NULL, NULL);
+ struct arg_end *end2 = arg_end(20);
+ void* argtable2[] = {cmd2,noact2,verbose2,infiles2,end2};
+ int nerrors2;
+
+ /* SYNTAX 3: search [-v] <pattern> [-o <file>] [--help] [--version] */
+ struct arg_rex *cmd3 = arg_rex1(NULL, NULL, "search", NULL, REG_ICASE, NULL);
+ struct arg_lit *verbose3 = arg_lit0("v", "verbose", NULL);
+ struct arg_str *pattern3 = arg_str1(NULL, NULL, "<pattern>", "search string");
+ struct arg_file *outfile3 = arg_file0("o", NULL, "<output>", NULL);
+ struct arg_end *end3 = arg_end(20);
+ void* argtable3[] = {cmd3,verbose3,pattern3,outfile3,end3};
+ int nerrors3;
+
+ /* SYNTAX 4: [-help] [-version] */
+ struct arg_lit *help4 = arg_lit0(NULL,"help", "print this help and exit");
+ struct arg_lit *version4 = arg_lit0(NULL,"version", "print version information and exit");
+ struct arg_end *end4 = arg_end(20);
+ void* argtable4[] = {help4,version4,end4};
+ int nerrors4;
+
+ const char* progname = "multisyntax";
+ int exitcode=0;
+
+ /* verify all argtable[] entries were allocated sucessfully */
+ if (arg_nullcheck(argtable1)!=0 ||
+ arg_nullcheck(argtable2)!=0 ||
+ arg_nullcheck(argtable3)!=0 ||
+ arg_nullcheck(argtable4)!=0 )
+ {
+ /* NULL entries were detected, some allocations must have failed */
+ printf("%s: insufficient memory\n",progname);
+ exitcode=1;
+ goto exit;
+ }
+
+ /* set any command line default values prior to parsing */
+ outfile1->filename[0]="-";
+ outfile3->filename[0]="-";
+
+ /* Above we defined a separate argtable for each possible command line syntax */
+ /* and here we parse each one in turn to see if any of them are successful */
+ nerrors1 = arg_parse(argc,argv,argtable1);
+ nerrors2 = arg_parse(argc,argv,argtable2);
+ nerrors3 = arg_parse(argc,argv,argtable3);
+ nerrors4 = arg_parse(argc,argv,argtable4);
+
+ /* Execute the appropriate main<n> routine for the matching command line syntax */
+ /* In this example program our alternate command line syntaxes are mutually */
+ /* exclusive, so we know in advance that only one of them can be successful. */
+ if (nerrors1==0)
+ exitcode = mymain1(noact1->count, verbose1->count, recurse1->count,
+ outfile1->filename[0], infiles1->filename, infiles1->count);
+ else if (nerrors2==0)
+ exitcode = mymain2(noact2->count, verbose2->count, infiles2->filename[0]);
+ else if (nerrors3==0)
+ exitcode = mymain3(verbose3->count, pattern3->sval[0], outfile3->filename[0]);
+ else if (nerrors4==0)
+ exitcode = mymain4(help4->count, version4->count, progname,
+ argtable1, argtable2, argtable3, argtable4);
+ else
+ {
+ /* We get here if the command line matched none of the possible syntaxes */
+ if (cmd1->count > 0)
+ {
+ /* here the cmd1 argument was correct, so presume syntax 1 was intended target */
+ arg_print_errors(stdout,end1,progname);
+ printf("usage: %s ", progname);
+ arg_print_syntax(stdout,argtable1,"\n");
+ }
+ else if (cmd2->count > 0)
+ {
+ /* here the cmd2 argument was correct, so presume syntax 2 was intended target */
+ arg_print_errors(stdout,end2,progname);
+ printf("usage: %s ", progname);
+ arg_print_syntax(stdout,argtable2,"\n");
+ }
+ else if (cmd3->count > 0)
+ {
+ /* here the cmd3 argument was correct, so presume syntax 3 was intended target */
+ arg_print_errors(stdout,end3,progname);
+ printf("usage: %s ", progname);
+ arg_print_syntax(stdout,argtable3,"\n");
+ }
+ else
+ {
+ /* no correct cmd literals were given, so we cant presume which syntax was intended */
+ printf("%s: missing <insert|remove|search> command.\n",progname);
+ printf("usage 1: %s ", progname); arg_print_syntax(stdout,argtable1,"\n");
+ printf("usage 2: %s ", progname); arg_print_syntax(stdout,argtable2,"\n");
+ printf("usage 3: %s ", progname); arg_print_syntax(stdout,argtable3,"\n");
+ printf("usage 4: %s", progname); arg_print_syntax(stdout,argtable4,"\n");
+ }
+ }
+
+exit:
+ /* deallocate each non-null entry in each argtable */
+ arg_freetable(argtable1,sizeof(argtable1)/sizeof(argtable1[0]));
+ arg_freetable(argtable2,sizeof(argtable2)/sizeof(argtable2[0]));
+ arg_freetable(argtable3,sizeof(argtable3)/sizeof(argtable3[0]));
+ arg_freetable(argtable4,sizeof(argtable4)/sizeof(argtable4[0]));
+
+ return exitcode;
+ }
--- /dev/null
+/*******************************************************************************
+ * Example source code for using the argtable3 library to implement:
+ *
+ * mv [-bfiuv] [--backup=[CONTROL]] [--reply={yes,no,query}]
+ * [--strip-trailing-slashes] [-S SUFFIX] [--target-directory=DIRECTORY]
+ * [--help] [--version] SOURCE [SOURCE]... DEST|DIRECTORY
+ *
+ * This file is part of the argtable3 library.
+ *
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
+ * <sheitmann@users.sourceforge.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of STEWART HEITMANN 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN 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.
+ ******************************************************************************/
+
+#include "argtable3.h"
+
+int mymain(const char *backup_control,
+ int backup,
+ int force,
+ int interactive,
+ const char *reply,
+ int strip_trailing_slashes,
+ const char *suffix,
+ const char *targetdir,
+ int update,
+ int verbose,
+ const char **files,
+ int nfiles)
+ {
+ int j;
+
+ /* if verbose option was given then display all option settings */
+ if (verbose)
+ {
+ printf("backup = %s\n", ((backup)?"YES":"NO"));
+ printf("backup CONTROL = %s\n", backup_control);
+ printf("force = %s\n", ((force)?"YES":"NO"));
+ printf("interactive mode = %s\n", ((interactive)?"YES":"NO"));
+ printf("reply = %s\n", reply);
+ printf("strip-trailing-slashes = %s\n", ((strip_trailing_slashes)?"YES":"NO"));
+ printf("suffix = %s\n", suffix);
+ printf("target-directory = %s\n", targetdir);
+ printf("update = %s\n", ((update)?"YES":"NO"));
+ printf("verbose = %s\n", ((verbose)?"YES":"NO"));
+ }
+
+ /* print the source filenames */
+ for (j=0; j<nfiles; j++)
+ printf("file[%d] = \"%s\"\n", j, files[j]);
+
+ return 0;
+ }
+
+
+int main(int argc, char **argv)
+ {
+ const char *progname = "mv";
+ struct arg_str *backupc = arg_str0(NULL, "backup", "[CONTROL]", "make a backup of each existing destination file");
+ struct arg_lit *backup = arg_lit0("b", NULL, "like --backup but does not accept an argument");
+ struct arg_lit *force = arg_lit0("f", "force", "do not prompt before overwriting");
+ struct arg_rem *force1 = arg_rem (NULL, " equivalent to --reply=yes");
+ struct arg_lit *interact = arg_lit0("i", "interactive", "Prompt before overwriting");
+ struct arg_rem *interact1= arg_rem (NULL, " equivalent to --reply=yes");
+ struct arg_str *reply = arg_str0(NULL,"reply", "{yes,no,query}", "specify how to handle the prompt about an");
+ struct arg_rem *reply1 = arg_rem (NULL, " existing destination file");
+ struct arg_lit *strpslsh = arg_lit0(NULL,"strip-trailing-slashes", "remove any trailing slashes from each SOURCE argument");
+ struct arg_str *suffix = arg_str0("S", "suffix", "SUFFIX", "override the usual backup suffix");
+ struct arg_str *targetd = arg_str0(NULL,"target-directory", "DIRECTORY", "move all SOURCE arguments into DIRECTORY");
+ struct arg_lit *update = arg_lit0("u", "update", "copy only when the SOURCE file is newer");
+ struct arg_rem *update1 = arg_rem (NULL, " than the destination file or when the");
+ struct arg_rem *update2 = arg_rem (NULL, " destination file is missing");
+ struct arg_lit *verbose = arg_lit0("v", "verbose", "explain what is being done");
+ struct arg_lit *help = arg_lit0(NULL,"help", "display this help and exit");
+ struct arg_lit *version = arg_lit0(NULL,"version", "display version information and exit");
+ struct arg_file *files = arg_filen(NULL, NULL, "SOURCE", 1, argc+2, NULL);
+ struct arg_rem *dest = arg_rem ("DEST|DIRECTORY", NULL);
+ struct arg_end *end = arg_end(20);
+ void* argtable[] = {backupc,backup,force,force1,interact,interact1,reply,reply1,strpslsh,suffix,targetd,update,update1,update2,verbose,help,version,files,dest,end};
+ int exitcode=0;
+ int nerrors;
+
+ /* verify the argtable[] entries were allocated sucessfully */
+ if (arg_nullcheck(argtable) != 0)
+ {
+ /* NULL entries were detected, some allocations must have failed */
+ printf("%s: insufficient memory\n",progname);
+ exitcode=1;
+ goto exit;
+ }
+
+ /* Set default argument values prior to parsing */
+ backupc->sval[0] = "existing"; /* --backup={none,off,numbered,t,existing,nil,simple,never} */
+ suffix->sval[0] = "~"; /* --suffix=~ */
+ reply->sval[0] = "query"; /* --reply={yes,no,query} */
+ targetd->sval[0] = NULL;
+
+ /* Parse the command line as defined by argtable[] */
+ nerrors = arg_parse(argc,argv,argtable);
+
+ /* special case: '--help' takes precedence over error reporting */
+ if (help->count > 0)
+ {
+ printf("Usage: %s", progname);
+ arg_print_syntax(stdout,argtable,"\n");
+ printf("Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.\n\n");
+ arg_print_glossary(stdout,argtable," %-30s %s\n");
+ printf("\nThe backup suffix is \"~\", unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n"
+ "The version control method may be selected via the --backup option or through\n"
+ "the VERSION_CONTROL environment variable. Here are the values:\n\n"
+ " none, off never make backups (even if --backup is given)\n"
+ " numbered, t make numbered backups\n"
+ " existing, nil numbered if numbered backups exist, simple otherwise\n"
+ " simple, never always make simple backups\n\n"
+ "Report bugs to <foo@bar>.\n");
+ exitcode=0;
+ goto exit;
+ }
+
+ /* special case: '--version' takes precedence error reporting */
+ if (version->count > 0)
+ {
+ printf("'%s' example program for the \"argtable\" command line argument parser.\n",progname);
+ printf("September 2003, Stewart Heitmann\n");
+ exitcode=0;
+ goto exit;
+ }
+
+ /* If the parser returned any errors then display them and exit */
+ if (nerrors > 0)
+ {
+ /* Display the error details contained in the arg_end struct.*/
+ arg_print_errors(stdout,end,progname);
+ printf("Try '%s --help' for more information.\n",progname);
+ exitcode=1;
+ goto exit;
+ }
+
+ /* Command line parsing is complete, do the main processing */
+ exitcode = mymain(backupc->sval[0],
+ backup->count,
+ force->count,
+ interact->count,
+ reply->sval[0],
+ strpslsh->count,
+ suffix->sval[0],
+ targetd->sval[0],
+ update->count,
+ verbose->count,
+ files->filename,
+ files->count);
+
+exit:
+ /* deallocate each non-null entry in argtable[] */
+ arg_freetable(argtable,sizeof(argtable)/sizeof(argtable[0]));
+
+ return exitcode;
+ }
--- /dev/null
+/*******************************************************************************
+ * Example source code for using the argtable3 library to implement:
+ *
+ * myprog [-lRv] [-k <int>] [-D MACRO]... [-o <output>] [--help]
+ * [--version] <file> [<file>]...
+ *
+ * This file is part of the argtable3 library.
+ *
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
+ * <sheitmann@users.sourceforge.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of STEWART HEITMANN 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN 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.
+ ******************************************************************************/
+
+#include <argtable3.h>
+
+int mymain(int l, int R, int k,
+ const char **defines, int ndefines,
+ const char *outfile,
+ int v,
+ const char **infiles, int ninfiles)
+ {
+ int i;
+
+ if (l>0) printf("list files (-l)\n");
+ if (R>0) printf("recurse through directories (-R)\n");
+ if (v>0) printf("verbose is enabled (-v)\n");
+ printf("scalar k=%d\n",k);
+ printf("output is \"%s\"\n", outfile);
+
+ for (i=0; i<ndefines; i++)
+ printf("user defined macro \"%s\"\n",defines[i]);
+
+ for (i=0; i<ninfiles; i++)
+ printf("infile[%d]=\"%s\"\n",i,infiles[i]);
+
+ return 0;
+ }
+
+
+int main(int argc, char **argv)
+ {
+ struct arg_lit *list = arg_lit0("lL",NULL, "list files");
+ struct arg_lit *recurse = arg_lit0("R",NULL, "recurse through subdirectories");
+ struct arg_int *repeat = arg_int0("k","scalar",NULL, "define scalar value k (default is 3)");
+ struct arg_str *defines = arg_strn("D","define","MACRO",0,argc+2, "macro definitions");
+ struct arg_file *outfile = arg_file0("o",NULL,"<output>", "output file (default is \"-\")");
+ struct arg_lit *verbose = arg_lit0("v","verbose,debug", "verbose messages");
+ struct arg_lit *help = arg_lit0(NULL,"help", "print this help and exit");
+ struct arg_lit *version = arg_lit0(NULL,"version", "print version information and exit");
+ struct arg_file *infiles = arg_filen(NULL,NULL,NULL,1,argc+2, "input file(s)");
+ struct arg_end *end = arg_end(20);
+ void* argtable[] = {list,recurse,repeat,defines,outfile,verbose,help,version,infiles,end};
+ const char* progname = "myprog";
+ int nerrors;
+ int exitcode=0;
+
+ /* verify the argtable[] entries were allocated sucessfully */
+ if (arg_nullcheck(argtable) != 0)
+ {
+ /* NULL entries were detected, some allocations must have failed */
+ printf("%s: insufficient memory\n",progname);
+ exitcode=1;
+ goto exit;
+ }
+
+ /* set any command line default values prior to parsing */
+ repeat->ival[0]=3;
+ outfile->filename[0]="-";
+
+ /* Parse the command line as defined by argtable[] */
+ nerrors = arg_parse(argc,argv,argtable);
+
+ /* special case: '--help' takes precedence over error reporting */
+ if (help->count > 0)
+ {
+ printf("Usage: %s", progname);
+ arg_print_syntax(stdout,argtable,"\n");
+ printf("This program demonstrates the use of the argtable2 library\n");
+ printf("for parsing command line arguments. Argtable accepts integers\n");
+ printf("in decimal (123), hexadecimal (0xff), octal (0o123) and binary\n");
+ printf("(0b101101) formats. Suffixes KB, MB and GB are also accepted.\n");
+ arg_print_glossary(stdout,argtable," %-25s %s\n");
+ exitcode=0;
+ goto exit;
+ }
+
+ /* special case: '--version' takes precedence error reporting */
+ if (version->count > 0)
+ {
+ printf("'%s' example program for the \"argtable\" command line argument parser.\n",progname);
+ printf("September 2003, Stewart Heitmann\n");
+ exitcode=0;
+ goto exit;
+ }
+
+ /* If the parser returned any errors then display them and exit */
+ if (nerrors > 0)
+ {
+ /* Display the error details contained in the arg_end struct.*/
+ arg_print_errors(stdout,end,progname);
+ printf("Try '%s --help' for more information.\n",progname);
+ exitcode=1;
+ goto exit;
+ }
+
+ /* special case: uname with no command line options induces brief help */
+ if (argc==1)
+ {
+ printf("Try '%s --help' for more information.\n",progname);
+ exitcode=0;
+ goto exit;
+ }
+
+ /* normal case: take the command line options at face value */
+ exitcode = mymain(list->count, recurse->count, repeat->ival[0],
+ defines->sval, defines->count,
+ outfile->filename[0], verbose->count,
+ infiles->filename, infiles->count);
+
+ exit:
+ /* deallocate each non-null entry in argtable[] */
+ arg_freetable(argtable,sizeof(argtable)/sizeof(argtable[0]));
+
+ return exitcode;
+ }
--- /dev/null
+/*******************************************************************************
+ * This example source code is an alternate version of myprog.c
+ * that adheres to ansi C89 standards rather than ansi C99.
+ * The only difference being that C89 does not permit the argtable array
+ * to be statically initialized with the contents of variables set at
+ * runtime whereas C99 does.
+ * Hence we cannot declare and initialize the argtable array in one declaration
+ * as
+ * void* argtable[] = {list, recurse, repeat, defines, outfile, verbose,
+ * help, version, infiles, end};
+ * Instead, we must declare
+ * void* argtable[10];
+ * and initialize the contents of the array separately.
+ *
+ * This file is part of the argtable3 library.
+ *
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
+ * <sheitmann@users.sourceforge.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of STEWART HEITMANN 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN 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.
+ ******************************************************************************/
+
+#include "argtable3.h"
+
+int mymain(int l, int R, int k,
+ const char **defines, int ndefines,
+ const char *outfile,
+ int v,
+ const char **infiles, int ninfiles)
+ {
+ int i;
+
+ if (l>0) printf("list files (-l)\n");
+ if (R>0) printf("recurse through directories (-R)\n");
+ if (v>0) printf("verbose is enabled (-v)\n");
+ printf("scalar k=%d\n",k);
+ printf("output is \"%s\"\n", outfile);
+
+ for (i=0; i<ndefines; i++)
+ printf("user defined macro \"%s\"\n",defines[i]);
+
+ for (i=0; i<ninfiles; i++)
+ printf("infile[%d]=\"%s\"\n",i,infiles[i]);
+
+ return 0;
+ }
+
+
+int main(int argc, char **argv)
+ {
+ struct arg_lit *list = arg_lit0("lL",NULL, "list files");
+ struct arg_lit *recurse = arg_lit0("R",NULL, "recurse through subdirectories");
+ struct arg_int *repeat = arg_int0("k","scalar",NULL, "define scalar value k (default is 3)");
+ struct arg_str *defines = arg_strn("D","define","MACRO",0,argc+2, "macro definitions");
+ struct arg_file *outfile = arg_file0("o",NULL,"<output>", "output file (default is \"-\")");
+ struct arg_lit *verbose = arg_lit0("v","verbose,debug", "verbose messages");
+ struct arg_lit *help = arg_lit0(NULL,"help", "print this help and exit");
+ struct arg_lit *version = arg_lit0(NULL,"version", "print version information and exit");
+ struct arg_file *infiles = arg_filen(NULL,NULL,NULL,1,argc+2, "input file(s)");
+ struct arg_end *end = arg_end(20);
+ void* argtable[10];
+ const char* progname = "myprog_C89";
+ int nerrors;
+ int exitcode=0;
+
+ /* initialize the argtable array with ptrs to the arg_xxx structures constructed above */
+ argtable[0] = list;
+ argtable[1] = recurse;
+ argtable[2] = repeat;
+ argtable[3] = defines;
+ argtable[4] = outfile;
+ argtable[5] = verbose;
+ argtable[6] = help;
+ argtable[7] = version;
+ argtable[8] = infiles;
+ argtable[9] = end;
+
+ /* verify the argtable[] entries were allocated sucessfully */
+ if (arg_nullcheck(argtable) != 0)
+ {
+ /* NULL entries were detected, some allocations must have failed */
+ printf("%s: insufficient memory\n",progname);
+ exitcode=1;
+ goto exit;
+ }
+
+ /* set any command line default values prior to parsing */
+ repeat->ival[0]=3;
+ outfile->filename[0]="-";
+
+ /* Parse the command line as defined by argtable[] */
+ nerrors = arg_parse(argc,argv,argtable);
+
+ /* special case: '--help' takes precedence over error reporting */
+ if (help->count > 0)
+ {
+ printf("Usage: %s", progname);
+ arg_print_syntax(stdout,argtable,"\n");
+ printf("This program demonstrates the use of the argtable2 library\n");
+ printf("for parsing command line arguments.\n");
+ arg_print_glossary(stdout,argtable," %-25s %s\n");
+ exitcode=0;
+ goto exit;
+ }
+
+ /* special case: '--version' takes precedence error reporting */
+ if (version->count > 0)
+ {
+ printf("'%s' example program for the \"argtable\" command line argument parser.\n",progname);
+ printf("September 2003, Stewart Heitmann\n");
+ exitcode=0;
+ goto exit;
+ }
+
+ /* If the parser returned any errors then display them and exit */
+ if (nerrors > 0)
+ {
+ /* Display the error details contained in the arg_end struct.*/
+ arg_print_errors(stdout,end,progname);
+ printf("Try '%s --help' for more information.\n",progname);
+ exitcode=1;
+ goto exit;
+ }
+
+ /* special case: uname with no command line options induces brief help */
+ if (argc==1)
+ {
+ printf("Try '%s --help' for more information.\n",progname);
+ exitcode=0;
+ goto exit;
+ }
+
+ /* normal case: take the command line options at face value */
+ exitcode = mymain(list->count, recurse->count, repeat->ival[0],
+ defines->sval, defines->count,
+ outfile->filename[0], verbose->count,
+ infiles->filename, infiles->count);
+
+ exit:
+ /* deallocate each non-null entry in argtable[] */
+ arg_freetable(argtable,sizeof(argtable)/sizeof(argtable[0]));
+
+ return exitcode;
+ }
--- /dev/null
+#include "argtable3.h"
+
+/* global arg_xxx structs */
+struct arg_lit *a, *b, *c, *verb, *help, *version;
+struct arg_int *scal;
+struct arg_file *o, *file;
+struct arg_end *end;
+
+int main(int argc, char *argv[])
+{
+ /* the global arg_xxx structs are initialised within the argtable */
+ void *argtable[] = {
+ help = arg_lit0(NULL, "help", "display this help and exit"),
+ version = arg_lit0(NULL, "version", "display version info and exit"),
+ a = arg_lit0("a", NULL,"the -a option"),
+ b = arg_lit0("b", NULL, "the -b option"),
+ c = arg_lit0("c", NULL, "the -c option"),
+ scal = arg_int0(NULL, "scalar", "<n>", "foo value"),
+ verb = arg_lit0("v", "verbose", "verbose output"),
+ o = arg_file0("o", NULL, "myfile", "output file"),
+ file = arg_filen(NULL, NULL, "<file>", 1, 100, "input files"),
+ end = arg_end(20),
+ };
+
+ int exitcode = 0;
+ char progname[] = "testargtable2.exe";
+
+ int nerrors;
+ nerrors = arg_parse(argc,argv,argtable);
+
+ /* special case: '--help' takes precedence over error reporting */
+ if (help->count > 0)
+ {
+ printf("Usage: %s", progname);
+ arg_print_syntax(stdout, argtable, "\n");
+ printf("List information about the FILE(s) "
+ "(the current directory by default).\n\n");
+ arg_print_glossary(stdout, argtable, " %-25s %s\n");
+ exitcode = 0;
+ goto exit;
+ }
+
+ /* If the parser returned any errors then display them and exit */
+ if (nerrors > 0)
+ {
+ /* Display the error details contained in the arg_end struct.*/
+ arg_print_errors(stdout, end, progname);
+ printf("Try '%s --help' for more information.\n", progname);
+ exitcode = 1;
+ goto exit;
+ }
+
+exit:
+ /* deallocate each non-null entry in argtable[] */
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+ return exitcode;
+}
+
--- /dev/null
+/*******************************************************************************
+ * Example source code for using the argtable3 library to implement:
+ *
+ * uname [-asnrvmpio] [--help] [--version]
+ *
+ * This file is part of the argtable3 library.
+ *
+ * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
+ * <sheitmann@users.sourceforge.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of STEWART HEITMANN 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN 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.
+ ******************************************************************************/
+
+#include "argtable3.h"
+
+/* Here we simulate the uname functionality */
+int mymain(int kname, int nname, int krel, int kver, int mach, int proc, int hard, int opsys)
+ {
+ if (kname) printf("Linux ");
+ if (nname) printf("localhost.localdomain ");
+ if (krel) printf("2.4.19-16 ");
+ if (kver) printf("#1 Fri Sep 20 18:15:05 CEST 2002 ");
+ if (mach) printf("i686 ");
+ if (proc) printf("Intel ");
+ if (hard) printf("unknown ");
+ if (opsys) printf("GNU/Linux ");
+ printf("\n");
+ return 0;
+ }
+
+
+int main(int argc, char **argv)
+ {
+ const char* progname = "uname";
+ struct arg_lit *all = arg_lit0("a", "all", "print all information, in the following order:");
+ struct arg_lit *kname = arg_lit0("s", "kernel-name", "print the kernel name");
+ struct arg_lit *nname = arg_lit0("n", "nodename", "print the node name");
+ struct arg_lit *krel = arg_lit0("r", "kernel-release", "print the kernel release");
+ struct arg_lit *kver = arg_lit0("v", "kernel-version", "print the kernel version");
+ struct arg_lit *mach = arg_lit0("m", "machine", "print the machine hardware name");
+ struct arg_lit *proc = arg_lit0("p", "processor", "print the processor type");
+ struct arg_lit *hard = arg_lit0("i", "hardware-platform","print the hardware platform");
+ struct arg_lit *opsys = arg_lit0("o", "operating-system", "print the operating system");
+ struct arg_lit *help = arg_lit0(NULL,"help", "print this help and exit");
+ struct arg_lit *vers = arg_lit0(NULL,"version", "print version information and exit");
+ struct arg_end *end = arg_end(20);
+ void* argtable[] = {all,kname,nname,krel,kver,mach,proc,hard,opsys,help,vers,end};
+ int nerrors;
+ int exitcode=0;
+
+ /* verify the argtable[] entries were allocated sucessfully */
+ if (arg_nullcheck(argtable) != 0)
+ {
+ /* NULL entries were detected, some allocations must have failed */
+ printf("%s: insufficient memory\n",progname);
+ exitcode=1;
+ goto exit;
+ }
+
+ /* Parse the command line as defined by argtable[] */
+ nerrors = arg_parse(argc,argv,argtable);
+
+ /* special case: '--help' takes precedence over error reporting */
+ if (help->count > 0)
+ {
+ printf("Usage: %s", progname);
+ arg_print_syntax(stdout,argtable,"\n");
+ printf("Print certain system information. With no options, same as -s.\n\n");
+ arg_print_glossary(stdout,argtable," %-25s %s\n");
+ printf("\nReport bugs to <foo@bar>.\n");
+ exitcode=0;
+ goto exit;
+ }
+
+ /* special case: '--version' takes precedence error reporting */
+ if (vers->count > 0)
+ {
+ printf("'%s' example program for the \"argtable\" command line argument parser.\n",progname);
+ printf("September 2003, Stewart Heitmann\n");
+ exitcode=0;
+ goto exit;
+ }
+
+ /* If the parser returned any errors then display them and exit */
+ if (nerrors > 0)
+ {
+ /* Display the error details contained in the arg_end struct.*/
+ arg_print_errors(stdout,end,progname);
+ printf("Try '%s --help' for more information.\n",progname);
+ exitcode=1;
+ goto exit;
+ }
+
+ /* special case: uname with no command line options is equivalent to "uname -s" */
+ if (argc==1)
+ {
+ exitcode = mymain(0,1,0,0,0,0,0,0);
+ goto exit;
+ }
+
+ /* special case: "uname -a" is equivalent to "uname -snrvmpi" */
+ if (all->count>0)
+ {
+ exitcode = mymain(1,1,1,1,1,1,1,1);
+ goto exit;
+ }
+
+ /* normal case: take the command line options at face value */
+ exitcode = mymain(kname->count, nname->count, krel->count, kver->count, mach->count, proc->count, hard->count, opsys->count);
+
+ exit:
+ /* deallocate each non-null entry in argtable[] */
+ arg_freetable(argtable,sizeof(argtable)/sizeof(argtable[0]));
+
+ return exitcode;
+ }
--- /dev/null
+################################################################################
+# This file is part of the argtable3 library.
+#
+# Copyright (C) 2016-2019 Tom G. Huang
+# <tomghuang@gmail.com>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of STEWART HEITMANN 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN 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.
+################################################################################
+
+set(TEST_PUBLIC_SRC_FILES
+ testall.c
+ testarglit.c
+ testargstr.c
+ testargint.c
+ testargdate.c
+ testargdbl.c
+ testargfile.c
+ testargrex.c
+ testargdstr.c
+ testargcmd.c
+ CuTest.c
+)
+
+set(TEST_SRC_FILES
+ ${TEST_PUBLIC_SRC_FILES}
+ testarghashtable.c
+)
+
+if(UNIX)
+ set(ARGTABLE3_EXTRA_LIBS m)
+endif()
+
+add_executable(test_shared ${TEST_PUBLIC_SRC_FILES})
+target_compile_definitions(test_shared PRIVATE -DARGTABLE3_TEST_PUBLIC_ONLY)
+target_include_directories(test_shared PRIVATE ${PROJECT_SOURCE_DIR}/src)
+target_link_libraries(test_shared argtable3 ${ARGTABLE3_EXTRA_LIBS})
+add_custom_command(TARGET test_shared POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ "$<TARGET_FILE:argtable3>"
+ "$<TARGET_FILE_DIR:test_shared>"
+)
+
+add_executable(test_static ${TEST_SRC_FILES})
+target_compile_definitions(test_static PRIVATE -DARGTABLE3_TEST_PUBLIC_ONLY)
+target_include_directories(test_static PRIVATE ${PROJECT_SOURCE_DIR}/src)
+target_link_libraries(test_static argtable3_static ${ARGTABLE3_EXTRA_LIBS})
+
+add_executable(test_src ${TEST_SRC_FILES} ${ARGTABLE3_SRC_FILES})
+target_include_directories(test_src PRIVATE ${PROJECT_SOURCE_DIR}/src)
+target_link_libraries(test_src ${ARGTABLE3_EXTRA_LIBS})
+
+add_custom_command(OUTPUT ${ARGTABLE3_AMALGAMATION_SRC_FILE}
+ COMMAND "${PROJECT_SOURCE_DIR}/tools/build" dist
+ WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/tools"
+)
+
+add_executable(test_amalgamation ${TEST_SRC_FILES} ${ARGTABLE3_AMALGAMATION_SRC_FILE})
+target_include_directories(test_amalgamation PRIVATE ${PROJECT_SOURCE_DIR}/src)
+target_link_libraries(test_amalgamation ${ARGTABLE3_EXTRA_LIBS})
+add_custom_command(TARGET test_amalgamation PRE_BUILD
+ COMMAND "${PROJECT_SOURCE_DIR}/tools/build" dist
+ WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/tools"
+)
+
+add_test(NAME test_shared COMMAND "$<TARGET_FILE:test_shared>")
+add_test(NAME test_static COMMAND "$<TARGET_FILE:test_static>")
+add_test(NAME test_src COMMAND "$<TARGET_FILE:test_src>")
+add_test(NAME test_amalgamation COMMAND "$<TARGET_FILE:test_amalgamation>")
--- /dev/null
+#include <assert.h>
+#include <math.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "CuTest.h"
+
+/*-------------------------------------------------------------------------*
+ * CuStr
+ *-------------------------------------------------------------------------*/
+
+char* CuStrAlloc(size_t size) {
+ char* newStr = (char*)malloc(sizeof(char) * (size));
+ return newStr;
+}
+
+char* CuStrCopy(const char* old) {
+ size_t len = strlen(old);
+ char* newStr = CuStrAlloc(len + 1);
+#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__))
+ strcpy_s(newStr, len + 1, old);
+#else
+ strcpy(newStr, old);
+#endif
+
+ return newStr;
+}
+
+/*-------------------------------------------------------------------------*
+ * CuString
+ *-------------------------------------------------------------------------*/
+
+void CuStringInit(CuString* str) {
+ str->length = 0;
+ str->size = STRING_MAX;
+ str->buffer = (char*)malloc(sizeof(char) * str->size);
+ str->buffer[0] = '\0';
+}
+
+CuString* CuStringNew(void) {
+ CuString* str = (CuString*)malloc(sizeof(CuString));
+ str->length = 0;
+ str->size = STRING_MAX;
+ str->buffer = (char*)malloc(sizeof(char) * str->size);
+ str->buffer[0] = '\0';
+ return str;
+}
+
+void CuStringDelete(CuString* str) {
+ if (!str)
+ return;
+ free(str->buffer);
+ free(str);
+}
+
+void CuStringResize(CuString* str, size_t newSize) {
+ str->buffer = (char*)realloc(str->buffer, sizeof(char) * newSize);
+ str->size = newSize;
+}
+
+void CuStringAppend(CuString* str, const char* text) {
+ size_t length;
+
+ if (text == NULL) {
+ text = "NULL";
+ }
+
+ length = strlen(text);
+ if (str->length + length + 1 >= str->size)
+ CuStringResize(str, str->length + length + 1 + STRING_INC);
+ str->length += length;
+#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__))
+ strcat_s(str->buffer, str->size, text);
+#else
+ strcat(str->buffer, text);
+#endif
+}
+
+void CuStringAppendChar(CuString* str, char ch) {
+ char text[2];
+ text[0] = ch;
+ text[1] = '\0';
+ CuStringAppend(str, text);
+}
+
+void CuStringAppendFormat(CuString* str, const char* format, ...) {
+ va_list argp;
+ char buf[HUGE_STRING_LEN];
+ va_start(argp, format);
+#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__))
+ vsprintf_s(buf, sizeof(buf), format, argp);
+#else
+ vsprintf(buf, format, argp);
+#endif
+
+ va_end(argp);
+ CuStringAppend(str, buf);
+}
+
+void CuStringInsert(CuString* str, const char* text, int pos) {
+ size_t length = strlen(text);
+ if ((size_t)pos > str->length)
+ pos = (int)str->length;
+ if (str->length + length + 1 >= str->size)
+ CuStringResize(str, str->length + length + 1 + STRING_INC);
+ memmove(str->buffer + pos + length, str->buffer + pos, (str->length - pos) + 1);
+ str->length += length;
+ memcpy(str->buffer + pos, text, length);
+}
+
+/*-------------------------------------------------------------------------*
+ * CuTest
+ *-------------------------------------------------------------------------*/
+
+void CuTestInit(CuTest* t, const char* name, TestFunction function) {
+ t->name = CuStrCopy(name);
+ t->failed = 0;
+ t->ran = 0;
+ t->message = NULL;
+ t->function = function;
+ t->jumpBuf = NULL;
+}
+
+CuTest* CuTestNew(const char* name, TestFunction function) {
+ CuTest* tc = CU_ALLOC(CuTest);
+ CuTestInit(tc, name, function);
+ return tc;
+}
+
+void CuTestDelete(CuTest* t) {
+ if (!t)
+ return;
+ free(t->name);
+ free(t);
+}
+
+void CuTestRun(CuTest* tc) {
+ jmp_buf buf;
+ tc->jumpBuf = &buf;
+ if (setjmp(buf) == 0) {
+ tc->ran = 1;
+ (tc->function)(tc);
+ }
+ tc->jumpBuf = 0;
+}
+
+static void CuFailInternal(CuTest* tc, const char* file, int line, CuString* string) {
+ char buf[HUGE_STRING_LEN];
+
+#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__))
+ sprintf_s(buf, sizeof(buf), "%s:%d: ", file, line);
+#else
+ sprintf(buf, "%s:%d: ", file, line);
+#endif
+ CuStringInsert(string, buf, 0);
+
+ tc->failed = 1;
+ tc->message = string->buffer;
+ if (tc->jumpBuf != 0)
+ longjmp(*(tc->jumpBuf), 0);
+}
+
+void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message) {
+ CuString string;
+
+ CuStringInit(&string);
+ if (message2 != NULL) {
+ CuStringAppend(&string, message2);
+ CuStringAppend(&string, ": ");
+ }
+ CuStringAppend(&string, message);
+ CuFailInternal(tc, file, line, &string);
+}
+
+void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition) {
+ if (condition)
+ return;
+ CuFail_Line(tc, file, line, NULL, message);
+}
+
+void CuAssertStrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, const char* expected, const char* actual) {
+ CuString string;
+ if ((expected == NULL && actual == NULL) || (expected != NULL && actual != NULL && strcmp(expected, actual) == 0)) {
+ return;
+ }
+
+ CuStringInit(&string);
+ if (message != NULL) {
+ CuStringAppend(&string, message);
+ CuStringAppend(&string, ": ");
+ }
+ CuStringAppend(&string, "expected <");
+ CuStringAppend(&string, expected);
+ CuStringAppend(&string, "> but was <");
+ CuStringAppend(&string, actual);
+ CuStringAppend(&string, ">");
+ CuFailInternal(tc, file, line, &string);
+}
+
+void CuAssertIntEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, int expected, int actual) {
+ char buf[STRING_MAX];
+ if (expected == actual)
+ return;
+#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__))
+ sprintf_s(buf, sizeof(buf), "expected <%d> but was <%d>", expected, actual);
+#else
+ sprintf(buf, "expected <%d> but was <%d>", expected, actual);
+#endif
+ CuFail_Line(tc, file, line, message, buf);
+}
+
+void CuAssertDblEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, double expected, double actual, double delta) {
+ char buf[STRING_MAX];
+ if (fabs(expected - actual) <= delta)
+ return;
+#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__))
+ sprintf_s(buf, sizeof(buf), "expected <%f> but was <%f>", expected, actual);
+#else
+ sprintf(buf, "expected <%f> but was <%f>", expected, actual);
+#endif
+ CuFail_Line(tc, file, line, message, buf);
+}
+
+void CuAssertPtrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, void* expected, void* actual) {
+ char buf[STRING_MAX];
+ if (expected == actual)
+ return;
+#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__))
+ sprintf_s(buf, sizeof(buf), "expected pointer <0x%p> but was <0x%p>", expected, actual);
+#else
+ sprintf(buf, "expected pointer <0x%p> but was <0x%p>", expected, actual);
+#endif
+ CuFail_Line(tc, file, line, message, buf);
+}
+
+/*-------------------------------------------------------------------------*
+ * CuSuite
+ *-------------------------------------------------------------------------*/
+
+void CuSuiteInit(CuSuite* testSuite) {
+ testSuite->count = 0;
+ testSuite->failCount = 0;
+ memset(testSuite->list, 0, sizeof(testSuite->list));
+}
+
+CuSuite* CuSuiteNew(void) {
+ CuSuite* testSuite = CU_ALLOC(CuSuite);
+ CuSuiteInit(testSuite);
+ return testSuite;
+}
+
+void CuSuiteDelete(CuSuite* testSuite) {
+ unsigned int n;
+ for (n = 0; n < MAX_TEST_CASES; n++) {
+ if (testSuite->list[n]) {
+ CuTestDelete(testSuite->list[n]);
+ }
+ }
+ free(testSuite);
+}
+
+void CuSuiteAdd(CuSuite* testSuite, CuTest* testCase) {
+ assert(testSuite->count < MAX_TEST_CASES);
+ testSuite->list[testSuite->count] = testCase;
+ testSuite->count++;
+}
+
+void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2) {
+ int i;
+ for (i = 0; i < testSuite2->count; ++i) {
+ CuTest* testCase = testSuite2->list[i];
+ CuSuiteAdd(testSuite, testCase);
+ }
+}
+
+void CuSuiteRun(CuSuite* testSuite) {
+ int i;
+ for (i = 0; i < testSuite->count; ++i) {
+ CuTest* testCase = testSuite->list[i];
+ CuTestRun(testCase);
+ if (testCase->failed) {
+ testSuite->failCount += 1;
+ }
+ }
+}
+
+void CuSuiteSummary(CuSuite* testSuite, CuString* summary) {
+ int i;
+ for (i = 0; i < testSuite->count; ++i) {
+ CuTest* testCase = testSuite->list[i];
+ CuStringAppend(summary, testCase->failed ? "F" : ".");
+ }
+ CuStringAppend(summary, "\n\n");
+}
+
+void CuSuiteDetails(CuSuite* testSuite, CuString* details) {
+ int i;
+ int failCount = 0;
+
+ if (testSuite->failCount == 0) {
+ int passCount = testSuite->count - testSuite->failCount;
+ const char* testWord = passCount == 1 ? "test" : "tests";
+ CuStringAppendFormat(details, "OK (%d %s)\n", passCount, testWord);
+ } else {
+ if (testSuite->failCount == 1)
+ CuStringAppend(details, "There was 1 failure:\n");
+ else
+ CuStringAppendFormat(details, "There were %d failures:\n", testSuite->failCount);
+
+ for (i = 0; i < testSuite->count; ++i) {
+ CuTest* testCase = testSuite->list[i];
+ if (testCase->failed) {
+ failCount++;
+ CuStringAppendFormat(details, "%d) %s: %s\n", failCount, testCase->name, testCase->message);
+ }
+ }
+ CuStringAppend(details, "\n!!!FAILURES!!!\n");
+
+ CuStringAppendFormat(details, "Runs: %d ", testSuite->count);
+ CuStringAppendFormat(details, "Passes: %d ", testSuite->count - testSuite->failCount);
+ CuStringAppendFormat(details, "Fails: %d\n", testSuite->failCount);
+ }
+}
--- /dev/null
+#ifndef CU_TEST_H
+#define CU_TEST_H
+
+#include <setjmp.h>
+#include <stdarg.h>
+
+#define CUTEST_VERSION "CuTest 1.5"
+
+/* CuString */
+
+char* CuStrAlloc(size_t size);
+char* CuStrCopy(const char* old);
+
+#define CU_ALLOC(TYPE) ((TYPE*)malloc(sizeof(TYPE)))
+
+#define HUGE_STRING_LEN 8192
+#define STRING_MAX 256
+#define STRING_INC 256
+
+typedef struct {
+ size_t length;
+ size_t size;
+ char* buffer;
+} CuString;
+
+void CuStringInit(CuString* str);
+CuString* CuStringNew(void);
+void CuStringRead(CuString* str, const char* path);
+void CuStringAppend(CuString* str, const char* text);
+void CuStringAppendChar(CuString* str, char ch);
+void CuStringAppendFormat(CuString* str, const char* format, ...);
+void CuStringInsert(CuString* str, const char* text, int pos);
+void CuStringResize(CuString* str, size_t newSize);
+void CuStringDelete(CuString* str);
+
+/* CuTest */
+
+typedef struct CuTest CuTest;
+
+typedef void (*TestFunction)(CuTest*);
+
+struct CuTest {
+ char* name;
+ TestFunction function;
+ int failed;
+ int ran;
+ const char* message;
+ jmp_buf* jumpBuf;
+};
+
+void CuTestInit(CuTest* t, const char* name, TestFunction function);
+CuTest* CuTestNew(const char* name, TestFunction function);
+void CuTestRun(CuTest* tc);
+void CuTestDelete(CuTest* t);
+
+/* Internal versions of assert functions -- use the public versions */
+void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message);
+void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition);
+void CuAssertStrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, const char* expected, const char* actual);
+void CuAssertIntEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, int expected, int actual);
+void CuAssertDblEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, double expected, double actual, double delta);
+void CuAssertPtrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, void* expected, void* actual);
+
+/* public assert functions */
+
+#define CuFail(tc, ms) CuFail_Line((tc), __FILE__, __LINE__, NULL, (ms))
+#define CuAssert(tc, ms, cond) CuAssert_Line((tc), __FILE__, __LINE__, (ms), (cond))
+#define CuAssertTrue(tc, cond) CuAssert_Line((tc), __FILE__, __LINE__, "assert failed", (cond))
+
+#define CuAssertStrEquals(tc, ex, ac) CuAssertStrEquals_LineMsg((tc), __FILE__, __LINE__, NULL, (ex), (ac))
+#define CuAssertStrEquals_Msg(tc, ms, ex, ac) CuAssertStrEquals_LineMsg((tc), __FILE__, __LINE__, (ms), (ex), (ac))
+#define CuAssertIntEquals(tc, ex, ac) CuAssertIntEquals_LineMsg((tc), __FILE__, __LINE__, NULL, (ex), (ac))
+#define CuAssertIntEquals_Msg(tc, ms, ex, ac) CuAssertIntEquals_LineMsg((tc), __FILE__, __LINE__, (ms), (ex), (ac))
+#define CuAssertDblEquals(tc, ex, ac, dl) CuAssertDblEquals_LineMsg((tc), __FILE__, __LINE__, NULL, (ex), (ac), (dl))
+#define CuAssertDblEquals_Msg(tc, ms, ex, ac, dl) CuAssertDblEquals_LineMsg((tc), __FILE__, __LINE__, (ms), (ex), (ac), (dl))
+#define CuAssertPtrEquals(tc, ex, ac) CuAssertPtrEquals_LineMsg((tc), __FILE__, __LINE__, NULL, (ex), (ac))
+#define CuAssertPtrEquals_Msg(tc, ms, ex, ac) CuAssertPtrEquals_LineMsg((tc), __FILE__, __LINE__, (ms), (ex), (ac))
+
+#define CuAssertPtrNotNull(tc, p) CuAssert_Line((tc), __FILE__, __LINE__, "null pointer unexpected", (p != NULL))
+#define CuAssertPtrNotNullMsg(tc, msg, p) CuAssert_Line((tc), __FILE__, __LINE__, (msg), (p != NULL))
+
+/* CuSuite */
+
+#define MAX_TEST_CASES 1024
+
+#define SUITE_ADD_TEST(SUITE, TEST) CuSuiteAdd(SUITE, CuTestNew(#TEST, TEST))
+
+typedef struct {
+ int count;
+ CuTest* list[MAX_TEST_CASES];
+ int failCount;
+
+} CuSuite;
+
+void CuSuiteInit(CuSuite* testSuite);
+CuSuite* CuSuiteNew(void);
+void CuSuiteDelete(CuSuite* testSuite);
+void CuSuiteAdd(CuSuite* testSuite, CuTest* testCase);
+void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2);
+void CuSuiteRun(CuSuite* testSuite);
+void CuSuiteSummary(CuSuite* testSuite, CuString* summary);
+void CuSuiteDetails(CuSuite* testSuite, CuString* details);
+
+#endif /* CU_TEST_H */
--- /dev/null
+/*******************************************************************************
+ * argtable3_private: Declares private types, constants, and interfaces
+ *
+ * This file is part of the argtable3 library.
+ *
+ * Copyright (C) 2013-2019 Tom G. Huang
+ * <tomghuang@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of STEWART HEITMANN 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN 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.
+ ******************************************************************************/
+
+#ifndef ARG_UTILS_H
+#define ARG_UTILS_H
+
+#include <stdlib.h>
+
+#define ARG_ENABLE_TRACE 0
+#define ARG_ENABLE_LOG 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum { ARG_ERR_MINCOUNT = 1, ARG_ERR_MAXCOUNT, ARG_ERR_BADINT, ARG_ERR_OVERFLOW, ARG_ERR_BADDOUBLE, ARG_ERR_BADDATE, ARG_ERR_REGNOMATCH };
+
+typedef void(arg_panicfn)(const char* fmt, ...);
+
+#if defined(_MSC_VER)
+#define ARG_TRACE(x) \
+ __pragma(warning(push)) __pragma(warning(disable : 4127)) do { \
+ if (ARG_ENABLE_TRACE) \
+ dbg_printf x; \
+ } \
+ while (0) \
+ __pragma(warning(pop))
+
+#define ARG_LOG(x) \
+ __pragma(warning(push)) __pragma(warning(disable : 4127)) do { \
+ if (ARG_ENABLE_LOG) \
+ dbg_printf x; \
+ } \
+ while (0) \
+ __pragma(warning(pop))
+#else
+#define ARG_TRACE(x) \
+ do { \
+ if (ARG_ENABLE_TRACE) \
+ dbg_printf x; \
+ } while (0)
+
+#define ARG_LOG(x) \
+ do { \
+ if (ARG_ENABLE_LOG) \
+ dbg_printf x; \
+ } while (0)
+#endif
+
+extern void dbg_printf(const char* fmt, ...);
+extern void arg_set_panic(arg_panicfn* proc);
+extern void* xmalloc(size_t size);
+extern void* xcalloc(size_t count, size_t size);
+extern void* xrealloc(void* ptr, size_t size);
+extern void xfree(void* ptr);
+
+struct arg_hashtable_entry {
+ void *k, *v;
+ unsigned int h;
+ struct arg_hashtable_entry* next;
+};
+
+typedef struct arg_hashtable {
+ unsigned int tablelength;
+ struct arg_hashtable_entry** table;
+ unsigned int entrycount;
+ unsigned int loadlimit;
+ unsigned int primeindex;
+ unsigned int (*hashfn)(const void* k);
+ int (*eqfn)(const void* k1, const void* k2);
+} arg_hashtable_t;
+
+/**
+ * @brief Create a hash table.
+ *
+ * @param minsize minimum initial size of hash table
+ * @param hashfn function for hashing keys
+ * @param eqfn function for determining key equality
+ * @return newly created hash table or NULL on failure
+ */
+arg_hashtable_t* arg_hashtable_create(unsigned int minsize, unsigned int (*hashfn)(const void*), int (*eqfn)(const void*, const void*));
+
+/**
+ * @brief This function will cause the table to expand if the insertion would take
+ * the ratio of entries to table size over the maximum load factor.
+ *
+ * This function does not check for repeated insertions with a duplicate key.
+ * The value returned when using a duplicate key is undefined -- when
+ * the hash table changes size, the order of retrieval of duplicate key
+ * entries is reversed.
+ * If in doubt, remove before insert.
+ *
+ * @param h the hash table to insert into
+ * @param k the key - hash table claims ownership and will free on removal
+ * @param v the value - does not claim ownership
+ * @return non-zero for successful insertion
+ */
+void arg_hashtable_insert(arg_hashtable_t* h, void* k, void* v);
+
+#define ARG_DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \
+ int fnname(arg_hashtable_t* h, keytype* k, valuetype* v) { return arg_hashtable_insert(h, k, v); }
+
+/**
+ * @brief Search the specified key in the hash table.
+ *
+ * @param h the hash table to search
+ * @param k the key to search for - does not claim ownership
+ * @return the value associated with the key, or NULL if none found
+ */
+void* arg_hashtable_search(arg_hashtable_t* h, const void* k);
+
+#define ARG_DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \
+ valuetype* fnname(arg_hashtable_t* h, keytype* k) { return (valuetype*)(arg_hashtable_search(h, k)); }
+
+/**
+ * @brief Remove the specified key from the hash table.
+ *
+ * @param h the hash table to remove the item from
+ * @param k the key to search for - does not claim ownership
+ */
+void arg_hashtable_remove(arg_hashtable_t* h, const void* k);
+
+#define ARG_DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \
+ valuetype* fnname(arg_hashtable_t* h, keytype* k) { return (valuetype*)(arg_hashtable_remove(h, k)); }
+
+/**
+ * @brief Return the number of keys in the hash table.
+ *
+ * @param h the hash table
+ * @return the number of items stored in the hash table
+ */
+unsigned int arg_hashtable_count(arg_hashtable_t* h);
+
+/**
+ * @brief Change the value associated with the key.
+ *
+ * function to change the value associated with a key, where there already
+ * exists a value bound to the key in the hash table.
+ * Source due to Holger Schemel.
+ *
+ * @name hashtable_change
+ * @param h the hash table
+ * @param key
+ * @param value
+ */
+int arg_hashtable_change(arg_hashtable_t* h, void* k, void* v);
+
+/**
+ * @brief Free the hash table and the memory allocated for each key-value pair.
+ *
+ * @param h the hash table
+ * @param free_values whether to call 'free' on the remaining values
+ */
+void arg_hashtable_destroy(arg_hashtable_t* h, int free_values);
+
+typedef struct arg_hashtable_itr {
+ arg_hashtable_t* h;
+ struct arg_hashtable_entry* e;
+ struct arg_hashtable_entry* parent;
+ unsigned int index;
+} arg_hashtable_itr_t;
+
+arg_hashtable_itr_t* arg_hashtable_itr_create(arg_hashtable_t* h);
+
+void arg_hashtable_itr_destroy(arg_hashtable_itr_t* itr);
+
+/**
+ * @brief Return the value of the (key,value) pair at the current position.
+ */
+extern void* arg_hashtable_itr_key(arg_hashtable_itr_t* i);
+
+/**
+ * @brief Return the value of the (key,value) pair at the current position.
+ */
+extern void* arg_hashtable_itr_value(arg_hashtable_itr_t* i);
+
+/**
+ * @brief Advance the iterator to the next element. Returns zero if advanced to end of table.
+ */
+int arg_hashtable_itr_advance(arg_hashtable_itr_t* itr);
+
+/**
+ * @brief Remove current element and advance the iterator to the next element.
+ */
+int arg_hashtable_itr_remove(arg_hashtable_itr_t* itr);
+
+/**
+ * @brief Search and overwrite the supplied iterator, to point to the entry matching the supplied key.
+ *
+ * @return Zero if not found.
+ */
+int arg_hashtable_itr_search(arg_hashtable_itr_t* itr, arg_hashtable_t* h, void* k);
+
+#define ARG_DEFINE_HASHTABLE_ITERATOR_SEARCH(fnname, keytype) \
+ int fnname(arg_hashtable_itr_t* i, arg_hashtable_t* h, keytype* k) { return (arg_hashtable_iterator_search(i, h, k)); }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/*******************************************************************************
+ * This file is part of the argtable3 library.
+ *
+ * Copyright (C) 2013-2019 Tom G. Huang
+ * <tomghuang@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of STEWART HEITMANN 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN 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.
+ ******************************************************************************/
+
+#include <stdio.h>
+
+#include "CuTest.h"
+
+CuSuite* get_arglit_testsuite();
+CuSuite* get_argstr_testsuite();
+CuSuite* get_argint_testsuite();
+CuSuite* get_argdate_testsuite();
+CuSuite* get_argdbl_testsuite();
+CuSuite* get_argfile_testsuite();
+CuSuite* get_argrex_testsuite();
+CuSuite* get_argdstr_testsuite();
+CuSuite* get_argcmd_testsuite();
+
+#ifndef ARGTABLE3_TEST_PUBLIC_ONLY
+CuSuite* get_arghashtable_testsuite();
+#endif
+
+int RunAllTests(void) {
+ CuString* output = CuStringNew();
+ CuSuite* suite = CuSuiteNew();
+
+ CuSuiteAddSuite(suite, get_arglit_testsuite());
+ CuSuiteAddSuite(suite, get_argstr_testsuite());
+ CuSuiteAddSuite(suite, get_argint_testsuite());
+ CuSuiteAddSuite(suite, get_argdate_testsuite());
+ CuSuiteAddSuite(suite, get_argdbl_testsuite());
+ CuSuiteAddSuite(suite, get_argfile_testsuite());
+ CuSuiteAddSuite(suite, get_argrex_testsuite());
+ CuSuiteAddSuite(suite, get_argdstr_testsuite());
+ CuSuiteAddSuite(suite, get_argcmd_testsuite());
+#ifndef ARGTABLE3_TEST_PUBLIC_ONLY
+ CuSuiteAddSuite(suite, get_arghashtable_testsuite());
+#endif
+
+ CuSuiteRun(suite);
+ CuSuiteSummary(suite, output);
+ CuSuiteDetails(suite, output);
+ printf("%s\n", output->buffer);
+
+ return suite->failCount;
+}
+
+int main(void) {
+ return RunAllTests();
+}
--- /dev/null
+/*******************************************************************************
+ * This file is part of the argtable3 library.
+ *
+ * Copyright (C) 2013-2019 Tom G. Huang
+ * <tomghuang@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of STEWART HEITMANN 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN 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.
+ ******************************************************************************/
+
+#include <string.h>
+#include <time.h>
+
+#include <stdio.h>
+
+#include "CuTest.h"
+#include "argtable3.h"
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4204)
+#endif
+
+int cmd1_proc(int argc, char* argv[], arg_dstr_t res) {
+ if (argc == 0) {
+ arg_dstr_catf(res, "cmd1 fail");
+ return 1;
+ }
+
+ arg_dstr_catf(res, "%d %s", argc, argv[0]);
+ return 0;
+}
+
+void test_argcmd_basic_001(CuTest* tc) {
+ arg_cmd_init();
+ CuAssertIntEquals(tc, 0, arg_cmd_count());
+
+ arg_cmd_register("cmd1", cmd1_proc, "description of cmd1");
+ CuAssertIntEquals(tc, 1, arg_cmd_count());
+
+ char* argv[] = {
+ "cmd1",
+ "-o",
+ "file1",
+ };
+ int argc = 3;
+ CuAssertTrue(tc, strcmp(argv[0], "cmd1") == 0);
+ CuAssertTrue(tc, strcmp(argv[1], "-o") == 0);
+ CuAssertTrue(tc, strcmp(argv[2], "file1") == 0);
+
+ arg_dstr_t res = arg_dstr_create();
+ int err = arg_cmd_dispatch("cmd1", argc, argv, res);
+ CuAssertIntEquals(tc, 0, err);
+ CuAssertTrue(tc, strcmp(arg_dstr_cstr(res), "3 cmd1") == 0);
+
+ arg_dstr_reset(res);
+ err = arg_cmd_dispatch("cmd1", 0, NULL, res);
+ CuAssertIntEquals(tc, 1, err);
+ CuAssertTrue(tc, strcmp(arg_dstr_cstr(res), "cmd1 fail") == 0);
+
+ arg_cmd_uninit();
+}
+
+CuSuite* get_argcmd_testsuite() {
+ CuSuite* suite = CuSuiteNew();
+ SUITE_ADD_TEST(suite, test_argcmd_basic_001);
+ return suite;
+}
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
--- /dev/null
+/*******************************************************************************
+ * This file is part of the argtable3 library.
+ *
+ * Copyright (C) 2013-2019 Tom G. Huang
+ * <tomghuang@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of STEWART HEITMANN 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN 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.
+ ******************************************************************************/
+
+#include <string.h>
+#include <time.h>
+
+#include "CuTest.h"
+#include "argtable3.h"
+
+/*
+ printf("tm_sec = %d\n", c->tmval->tm_sec);
+ printf("tm_min = %d\n", c->tmval->tm_min);
+ printf("tm_hour = %d\n", c->tmval->tm_hour);
+ printf("tm_mday = %d\n", c->tmval->tm_mday);
+ printf("tm_mon = %d\n", c->tmval->tm_mon);
+ printf("tm_year = %d\n", c->tmval->tm_year);
+ printf("tm_wday = %d\n", c->tmval->tm_wday);
+ printf("tm_yday = %d\n", c->tmval->tm_yday);
+ printf("tm_isdst = %d\n", c->tmval->tm_isdst);
+
+*/
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4204)
+#endif
+
+void test_argdate_basic_001(CuTest* tc) {
+ struct arg_date* a = arg_date1(NULL, NULL, "%H:%M", NULL, "time 23:59");
+ struct arg_date* b = arg_date0("b", NULL, "%Y-%m-%d", NULL, "date YYYY-MM-DD");
+ struct arg_date* c = arg_daten(NULL, "date", "%D", NULL, 1, 2, "MM/DD/YY");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, end};
+ int nerrors;
+
+ char* argv[] = {"program", "23:59", "--date", "12/31/04", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertIntEquals(tc, a->tmval->tm_sec, 0);
+ CuAssertIntEquals(tc, a->tmval->tm_min, 59);
+ CuAssertIntEquals(tc, a->tmval->tm_hour, 23);
+ CuAssertIntEquals(tc, a->tmval->tm_mday, 0);
+ CuAssertIntEquals(tc, a->tmval->tm_mon, 0);
+ CuAssertIntEquals(tc, a->tmval->tm_year, 0);
+ CuAssertIntEquals(tc, a->tmval->tm_wday, 0);
+ CuAssertIntEquals(tc, a->tmval->tm_yday, 0);
+ CuAssertIntEquals(tc, a->tmval->tm_isdst, 0);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertIntEquals(tc, c->tmval->tm_sec, 0);
+ CuAssertIntEquals(tc, c->tmval->tm_min, 0);
+ CuAssertIntEquals(tc, c->tmval->tm_hour, 0);
+ CuAssertIntEquals(tc, c->tmval->tm_mday, 31);
+ CuAssertIntEquals(tc, c->tmval->tm_mon, 11);
+ CuAssertIntEquals(tc, c->tmval->tm_year, 104);
+ CuAssertIntEquals(tc, c->tmval->tm_wday, 0);
+ CuAssertIntEquals(tc, c->tmval->tm_yday, 0);
+ CuAssertIntEquals(tc, c->tmval->tm_isdst, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argdate_basic_002(CuTest* tc) {
+ struct arg_date* a = arg_date1(NULL, NULL, "%H:%M", NULL, "time 23:59");
+ struct arg_date* b = arg_date0("b", NULL, "%Y-%m-%d", NULL, "date YYYY-MM-DD");
+ struct arg_date* c = arg_daten(NULL, "date", "%D", NULL, 1, 2, "MM/DD/YY");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, end};
+ int nerrors;
+
+ char* argv[] = {"program", "--date", "12/31/04", "20:15", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertIntEquals(tc, a->tmval->tm_sec, 0);
+ CuAssertIntEquals(tc, a->tmval->tm_min, 15);
+ CuAssertIntEquals(tc, a->tmval->tm_hour, 20);
+ CuAssertIntEquals(tc, a->tmval->tm_mday, 0);
+ CuAssertIntEquals(tc, a->tmval->tm_mon, 0);
+ CuAssertIntEquals(tc, a->tmval->tm_year, 0);
+ CuAssertIntEquals(tc, a->tmval->tm_wday, 0);
+ CuAssertIntEquals(tc, a->tmval->tm_yday, 0);
+ CuAssertIntEquals(tc, a->tmval->tm_isdst, 0);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertIntEquals(tc, c->tmval->tm_sec, 0);
+ CuAssertIntEquals(tc, c->tmval->tm_min, 0);
+ CuAssertIntEquals(tc, c->tmval->tm_hour, 0);
+ CuAssertIntEquals(tc, c->tmval->tm_mday, 31);
+ CuAssertIntEquals(tc, c->tmval->tm_mon, 11);
+ CuAssertIntEquals(tc, c->tmval->tm_year, 104);
+ CuAssertIntEquals(tc, c->tmval->tm_wday, 0);
+ CuAssertIntEquals(tc, c->tmval->tm_yday, 0);
+ CuAssertIntEquals(tc, c->tmval->tm_isdst, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argdate_basic_003(CuTest* tc) {
+ struct arg_date* a = arg_date1(NULL, NULL, "%H:%M", NULL, "time 23:59");
+ struct arg_date* b = arg_date0("b", NULL, "%Y-%m-%d", NULL, "date YYYY-MM-DD");
+ struct arg_date* c = arg_daten(NULL, "date", "%D", NULL, 1, 2, "MM/DD/YY");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, end};
+ int nerrors;
+
+ char* argv[] = {"program", "--date", "12/31/04", "20:15", "--date", "06/07/84", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertIntEquals(tc, a->tmval->tm_sec, 0);
+ CuAssertIntEquals(tc, a->tmval->tm_min, 15);
+ CuAssertIntEquals(tc, a->tmval->tm_hour, 20);
+ CuAssertIntEquals(tc, a->tmval->tm_mday, 0);
+ CuAssertIntEquals(tc, a->tmval->tm_mon, 0);
+ CuAssertIntEquals(tc, a->tmval->tm_year, 0);
+ CuAssertIntEquals(tc, a->tmval->tm_wday, 0);
+ CuAssertIntEquals(tc, a->tmval->tm_yday, 0);
+ CuAssertIntEquals(tc, a->tmval->tm_isdst, 0);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 2);
+ CuAssertIntEquals(tc, c->tmval->tm_sec, 0);
+ CuAssertIntEquals(tc, c->tmval->tm_min, 0);
+ CuAssertIntEquals(tc, c->tmval->tm_hour, 0);
+ CuAssertIntEquals(tc, c->tmval->tm_mday, 31);
+ CuAssertIntEquals(tc, c->tmval->tm_mon, 11);
+ CuAssertIntEquals(tc, c->tmval->tm_year, 104);
+ CuAssertIntEquals(tc, c->tmval->tm_wday, 0);
+ CuAssertIntEquals(tc, c->tmval->tm_yday, 0);
+ CuAssertIntEquals(tc, c->tmval->tm_isdst, 0);
+ CuAssertIntEquals(tc, (c->tmval + 1)->tm_sec, 0);
+ CuAssertIntEquals(tc, (c->tmval + 1)->tm_min, 0);
+ CuAssertIntEquals(tc, (c->tmval + 1)->tm_hour, 0);
+ CuAssertIntEquals(tc, (c->tmval + 1)->tm_mday, 7);
+ CuAssertIntEquals(tc, (c->tmval + 1)->tm_mon, 5);
+ CuAssertIntEquals(tc, (c->tmval + 1)->tm_year, 84);
+ CuAssertIntEquals(tc, (c->tmval + 1)->tm_wday, 0);
+ CuAssertIntEquals(tc, (c->tmval + 1)->tm_yday, 0);
+ CuAssertIntEquals(tc, (c->tmval + 1)->tm_isdst, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argdate_basic_004(CuTest* tc) {
+ struct arg_date* a = arg_date1(NULL, NULL, "%H:%M", NULL, "time 23:59");
+ struct arg_date* b = arg_date0("b", NULL, "%Y-%m-%d", NULL, "date YYYY-MM-DD");
+ struct arg_date* c = arg_daten(NULL, "date", "%D", NULL, 1, 2, "MM/DD/YY");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, end};
+ int nerrors;
+
+ char* argv[] = {"program", "--date", "12/31/04", "20:15", "-b", "1982-11-28", "--date", "06/07/84", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertIntEquals(tc, a->tmval->tm_sec, 0);
+ CuAssertIntEquals(tc, a->tmval->tm_min, 15);
+ CuAssertIntEquals(tc, a->tmval->tm_hour, 20);
+ CuAssertIntEquals(tc, a->tmval->tm_mday, 0);
+ CuAssertIntEquals(tc, a->tmval->tm_mon, 0);
+ CuAssertIntEquals(tc, a->tmval->tm_year, 0);
+ CuAssertIntEquals(tc, a->tmval->tm_wday, 0);
+ CuAssertIntEquals(tc, a->tmval->tm_yday, 0);
+ CuAssertIntEquals(tc, a->tmval->tm_isdst, 0);
+ CuAssertTrue(tc, b->count == 1);
+ CuAssertIntEquals(tc, b->tmval->tm_sec, 0);
+ CuAssertIntEquals(tc, b->tmval->tm_min, 0);
+ CuAssertIntEquals(tc, b->tmval->tm_hour, 0);
+ CuAssertIntEquals(tc, b->tmval->tm_mday, 28);
+ CuAssertIntEquals(tc, b->tmval->tm_mon, 10);
+ CuAssertIntEquals(tc, b->tmval->tm_year, 82);
+ CuAssertIntEquals(tc, b->tmval->tm_wday, 0);
+ CuAssertIntEquals(tc, b->tmval->tm_yday, 0);
+ CuAssertIntEquals(tc, b->tmval->tm_isdst, 0);
+ CuAssertTrue(tc, c->count == 2);
+ CuAssertIntEquals(tc, c->tmval->tm_sec, 0);
+ CuAssertIntEquals(tc, c->tmval->tm_min, 0);
+ CuAssertIntEquals(tc, c->tmval->tm_hour, 0);
+ CuAssertIntEquals(tc, c->tmval->tm_mday, 31);
+ CuAssertIntEquals(tc, c->tmval->tm_mon, 11);
+ CuAssertIntEquals(tc, c->tmval->tm_year, 104);
+ CuAssertIntEquals(tc, c->tmval->tm_wday, 0);
+ CuAssertIntEquals(tc, c->tmval->tm_yday, 0);
+ CuAssertIntEquals(tc, c->tmval->tm_isdst, 0);
+ CuAssertIntEquals(tc, (c->tmval + 1)->tm_sec, 0);
+ CuAssertIntEquals(tc, (c->tmval + 1)->tm_min, 0);
+ CuAssertIntEquals(tc, (c->tmval + 1)->tm_hour, 0);
+ CuAssertIntEquals(tc, (c->tmval + 1)->tm_mday, 7);
+ CuAssertIntEquals(tc, (c->tmval + 1)->tm_mon, 5);
+ CuAssertIntEquals(tc, (c->tmval + 1)->tm_year, 84);
+ CuAssertIntEquals(tc, (c->tmval + 1)->tm_wday, 0);
+ CuAssertIntEquals(tc, (c->tmval + 1)->tm_yday, 0);
+ CuAssertIntEquals(tc, (c->tmval + 1)->tm_isdst, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argdate_basic_005(CuTest* tc) {
+ struct arg_date* a = arg_date1(NULL, NULL, "%H:%M", NULL, "time 23:59");
+ struct arg_date* b = arg_date0("b", NULL, "%Y-%m-%d", NULL, "date YYYY-MM-DD");
+ struct arg_date* c = arg_daten(NULL, "date", "%D", NULL, 1, 2, "MM/DD/YY");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, end};
+ int nerrors;
+
+ char* argv[] = {"program", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 2);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argdate_basic_006(CuTest* tc) {
+ struct arg_date* a = arg_date1(NULL, NULL, "%H:%M", NULL, "time 23:59");
+ struct arg_date* b = arg_date0("b", NULL, "%Y-%m-%d", NULL, "date YYYY-MM-DD");
+ struct arg_date* c = arg_daten(NULL, "date", "%D", NULL, 1, 2, "MM/DD/YY");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, end};
+ int nerrors;
+
+ char* argv[] = {"program", "25:59", "--date", "12/31/04", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 1);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argdate_basic_007(CuTest* tc) {
+ struct arg_date* a = arg_date1(NULL, NULL, "%H:%M", NULL, "time 23:59");
+ struct arg_date* b = arg_date0("b", NULL, "%Y-%m-%d", NULL, "date YYYY-MM-DD");
+ struct arg_date* c = arg_daten(NULL, "date", "%D", NULL, 1, 2, "MM/DD/YY");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, end};
+ int nerrors;
+
+ char* argv[] = {"program", "23:59", "--date", "12/32/04", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 1);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argdate_basic_008(CuTest* tc) {
+ struct arg_date* a = arg_date1(NULL, NULL, "%H:%M", NULL, "time 23:59");
+ struct arg_date* b = arg_date0("b", NULL, "%Y-%m-%d", NULL, "date YYYY-MM-DD");
+ struct arg_date* c = arg_daten(NULL, "date", "%D", NULL, 1, 2, "MM/DD/YY");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, end};
+ int nerrors;
+
+ char* argv[] = {"program", "23:59", "--date", "12/31/04", "22:58", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 1);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argdate_basic_009(CuTest* tc) {
+ struct arg_date* a = arg_date1(NULL, NULL, "%H:%M", NULL, "time 23:59");
+ struct arg_date* b = arg_date0("b", NULL, "%Y-%m-%d", NULL, "date YYYY-MM-DD");
+ struct arg_date* c = arg_daten(NULL, "date", "%D", NULL, 1, 2, "MM/DD/YY");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, end};
+ int nerrors;
+
+ char* argv[] = {"program", "--date", "12/31/04", "20:15", "--date", "26/07/84", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 1);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argdate_basic_010(CuTest* tc) {
+ struct arg_date* a = arg_date1(NULL, NULL, "%H:%M", NULL, "time 23:59");
+ struct arg_date* b = arg_date0("b", NULL, "%Y-%m-%d", NULL, "date YYYY-MM-DD");
+ struct arg_date* c = arg_daten(NULL, "date", "%D", NULL, 1, 2, "MM/DD/YY");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-b", "1982-11-28", "-b", "1976-11-11", "--date", "12/07/84", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 1);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+CuSuite* get_argdate_testsuite() {
+ CuSuite* suite = CuSuiteNew();
+ SUITE_ADD_TEST(suite, test_argdate_basic_001);
+ SUITE_ADD_TEST(suite, test_argdate_basic_002);
+ SUITE_ADD_TEST(suite, test_argdate_basic_003);
+ SUITE_ADD_TEST(suite, test_argdate_basic_004);
+ SUITE_ADD_TEST(suite, test_argdate_basic_005);
+ SUITE_ADD_TEST(suite, test_argdate_basic_006);
+ SUITE_ADD_TEST(suite, test_argdate_basic_007);
+ SUITE_ADD_TEST(suite, test_argdate_basic_008);
+ SUITE_ADD_TEST(suite, test_argdate_basic_009);
+ SUITE_ADD_TEST(suite, test_argdate_basic_010);
+ return suite;
+}
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
--- /dev/null
+/*******************************************************************************
+ * This file is part of the argtable3 library.
+ *
+ * Copyright (C) 2013-2019 Tom G. Huang
+ * <tomghuang@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of STEWART HEITMANN 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN 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.
+ ******************************************************************************/
+
+#include <float.h>
+#include <string.h>
+
+#include "CuTest.h"
+#include "argtable3.h"
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4204)
+#endif
+
+void test_argdbl_basic_001(CuTest* tc) {
+ struct arg_dbl* a = arg_dbl1(NULL, NULL, "a", "a is <double>");
+ struct arg_dbl* b = arg_dbl0(NULL, NULL, "b", "b is <double>");
+ struct arg_dbl* c = arg_dbl0(NULL, NULL, "c", "c is <double>");
+ struct arg_dbl* d = arg_dbln("dD", "delta", "<double>", 0, 3, "d can occur 0..3 times");
+ struct arg_dbl* e = arg_dbl0(NULL, "eps,eqn", "<double>", "eps is optional");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, end};
+ int nerrors;
+
+ char* argv[] = {"program", "0", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 0);
+
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertDblEquals(tc, a->dval[0], 0, DBL_EPSILON);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 0);
+ CuAssertTrue(tc, d->count == 0);
+ CuAssertTrue(tc, e->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argdbl_basic_002(CuTest* tc) {
+ struct arg_dbl* a = arg_dbl1(NULL, NULL, "a", "a is <double>");
+ struct arg_dbl* b = arg_dbl0(NULL, NULL, "b", "b is <double>");
+ struct arg_dbl* c = arg_dbl0(NULL, NULL, "c", "c is <double>");
+ struct arg_dbl* d = arg_dbln("dD", "delta", "<double>", 0, 3, "d can occur 0..3 times");
+ struct arg_dbl* e = arg_dbl0(NULL, "eps,eqn", "<double>", "eps is optional");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, end};
+ int nerrors;
+
+ char* argv[] = {"program", "1.234", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 0);
+
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertDblEquals(tc, a->dval[0], 1.234, DBL_EPSILON);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 0);
+ CuAssertTrue(tc, d->count == 0);
+ CuAssertTrue(tc, e->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argdbl_basic_003(CuTest* tc) {
+ struct arg_dbl* a = arg_dbl1(NULL, NULL, "a", "a is <double>");
+ struct arg_dbl* b = arg_dbl0(NULL, NULL, "b", "b is <double>");
+ struct arg_dbl* c = arg_dbl0(NULL, NULL, "c", "c is <double>");
+ struct arg_dbl* d = arg_dbln("dD", "delta", "<double>", 0, 3, "d can occur 0..3 times");
+ struct arg_dbl* e = arg_dbl0(NULL, "eps,eqn", "<double>", "eps is optional");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, end};
+ int nerrors;
+
+ char* argv[] = {"program", "1.8", "2.3", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 0);
+
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertDblEquals(tc, a->dval[0], 1.8, DBL_EPSILON);
+ CuAssertTrue(tc, b->count == 1);
+ CuAssertDblEquals(tc, b->dval[0], 2.3, DBL_EPSILON);
+ CuAssertTrue(tc, c->count == 0);
+ CuAssertTrue(tc, d->count == 0);
+ CuAssertTrue(tc, e->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argdbl_basic_004(CuTest* tc) {
+ struct arg_dbl* a = arg_dbl1(NULL, NULL, "a", "a is <double>");
+ struct arg_dbl* b = arg_dbl0(NULL, NULL, "b", "b is <double>");
+ struct arg_dbl* c = arg_dbl0(NULL, NULL, "c", "c is <double>");
+ struct arg_dbl* d = arg_dbln("dD", "delta", "<double>", 0, 3, "d can occur 0..3 times");
+ struct arg_dbl* e = arg_dbl0(NULL, "eps,eqn", "<double>", "eps is optional");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, end};
+ int nerrors;
+
+ char* argv[] = {"program", "5", "7", "9", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 0);
+
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertDblEquals(tc, a->dval[0], 5, DBL_EPSILON);
+ CuAssertTrue(tc, b->count == 1);
+ CuAssertDblEquals(tc, b->dval[0], 7, DBL_EPSILON);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertDblEquals(tc, c->dval[0], 9, DBL_EPSILON);
+ CuAssertTrue(tc, d->count == 0);
+ CuAssertTrue(tc, e->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argdbl_basic_005(CuTest* tc) {
+ struct arg_dbl* a = arg_dbl1(NULL, NULL, "a", "a is <double>");
+ struct arg_dbl* b = arg_dbl0(NULL, NULL, "b", "b is <double>");
+ struct arg_dbl* c = arg_dbl0(NULL, NULL, "c", "c is <double>");
+ struct arg_dbl* d = arg_dbln("dD", "delta", "<double>", 0, 3, "d can occur 0..3 times");
+ struct arg_dbl* e = arg_dbl0(NULL, "eps,eqn", "<double>", "eps is optional");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, end};
+ int nerrors;
+
+ char* argv[] = {"program", "1.9998", "-d", "13e-1", "-D", "17e-1", "--delta", "36e-1", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 0);
+
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertDblEquals(tc, a->dval[0], 1.9998, DBL_EPSILON);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 0);
+ CuAssertTrue(tc, d->count == 3);
+ CuAssertDblEquals(tc, d->dval[0], 13e-1, DBL_EPSILON);
+ CuAssertDblEquals(tc, d->dval[1], 17e-1, DBL_EPSILON);
+ CuAssertDblEquals(tc, d->dval[2], 36e-1, DBL_EPSILON);
+ CuAssertTrue(tc, e->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argdbl_basic_006(CuTest* tc) {
+ struct arg_dbl* a = arg_dbl1(NULL, NULL, "a", "a is <double>");
+ struct arg_dbl* b = arg_dbl0(NULL, NULL, "b", "b is <double>");
+ struct arg_dbl* c = arg_dbl0(NULL, NULL, "c", "c is <double>");
+ struct arg_dbl* d = arg_dbln("dD", "delta", "<double>", 0, 3, "d can occur 0..3 times");
+ struct arg_dbl* e = arg_dbl0(NULL, "eps,eqn", "<double>", "eps is optional");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, end};
+ int nerrors;
+
+ char* argv[] = {"program", "1.2", "2.3", "4.5", "--eps", "8.3456789", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 0);
+
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertDblEquals(tc, a->dval[0], 1.2, DBL_EPSILON);
+ CuAssertTrue(tc, b->count == 1);
+ CuAssertDblEquals(tc, b->dval[0], 2.3, DBL_EPSILON);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertDblEquals(tc, c->dval[0], 4.5, DBL_EPSILON);
+ CuAssertTrue(tc, d->count == 0);
+ CuAssertTrue(tc, e->count == 1);
+ CuAssertDblEquals(tc, e->dval[0], 8.3456789, DBL_EPSILON);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argdbl_basic_007(CuTest* tc) {
+ struct arg_dbl* a = arg_dbl1(NULL, NULL, "a", "a is <double>");
+ struct arg_dbl* b = arg_dbl0(NULL, NULL, "b", "b is <double>");
+ struct arg_dbl* c = arg_dbl0(NULL, NULL, "c", "c is <double>");
+ struct arg_dbl* d = arg_dbln("dD", "delta", "<double>", 0, 3, "d can occur 0..3 times");
+ struct arg_dbl* e = arg_dbl0(NULL, "eps,eqn", "<double>", "eps is optional");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, end};
+ int nerrors;
+
+ char* argv[] = {"program", "1.2", "2.3", "4.5", "--eqn", "8.3456789", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 0);
+
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertDblEquals(tc, a->dval[0], 1.2, DBL_EPSILON);
+ CuAssertTrue(tc, b->count == 1);
+ CuAssertDblEquals(tc, b->dval[0], 2.3, DBL_EPSILON);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertDblEquals(tc, c->dval[0], 4.5, DBL_EPSILON);
+ CuAssertTrue(tc, d->count == 0);
+ CuAssertTrue(tc, e->count == 1);
+ CuAssertDblEquals(tc, e->dval[0], 8.3456789, DBL_EPSILON);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argdbl_basic_008(CuTest* tc) {
+ struct arg_dbl* a = arg_dbl1(NULL, NULL, "a", "a is <double>");
+ struct arg_dbl* b = arg_dbl0(NULL, NULL, "b", "b is <double>");
+ struct arg_dbl* c = arg_dbl0(NULL, NULL, "c", "c is <double>");
+ struct arg_dbl* d = arg_dbln("dD", "delta", "<double>", 0, 3, "d can occur 0..3 times");
+ struct arg_dbl* e = arg_dbl0(NULL, "eps,eqn", "<double>", "eps is optional");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, end};
+ int nerrors;
+
+ char* argv[] = {"program", "1.2", "2.3", "4.5", "--eqn", "8.345", "-D", "0.234", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 0);
+
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertDblEquals(tc, a->dval[0], 1.2, DBL_EPSILON);
+ CuAssertTrue(tc, b->count == 1);
+ CuAssertDblEquals(tc, b->dval[0], 2.3, DBL_EPSILON);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertDblEquals(tc, c->dval[0], 4.5, DBL_EPSILON);
+ CuAssertTrue(tc, d->count == 1);
+ CuAssertDblEquals(tc, d->dval[0], 0.234, DBL_EPSILON);
+ CuAssertTrue(tc, e->count == 1);
+ CuAssertDblEquals(tc, e->dval[0], 8.345, DBL_EPSILON);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argdbl_basic_009(CuTest* tc) {
+ struct arg_dbl* a = arg_dbl1(NULL, NULL, "a", "a is <double>");
+ struct arg_dbl* b = arg_dbl0(NULL, NULL, "b", "b is <double>");
+ struct arg_dbl* c = arg_dbl0(NULL, NULL, "c", "c is <double>");
+ struct arg_dbl* d = arg_dbln("dD", "delta", "<double>", 0, 3, "d can occur 0..3 times");
+ struct arg_dbl* e = arg_dbl0(NULL, "eps,eqn", "<double>", "eps is optional");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, end};
+ int nerrors;
+
+ char* argv[] = {"program", "1", "2", "3", "4", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 1);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argdbl_basic_010(CuTest* tc) {
+ struct arg_dbl* a = arg_dbl1(NULL, NULL, "a", "a is <double>");
+ struct arg_dbl* b = arg_dbl0(NULL, NULL, "b", "b is <double>");
+ struct arg_dbl* c = arg_dbl0(NULL, NULL, "c", "c is <double>");
+ struct arg_dbl* d = arg_dbln("dD", "delta", "<double>", 0, 3, "d can occur 0..3 times");
+ struct arg_dbl* e = arg_dbl0(NULL, "eps,eqn", "<double>", "eps is optional");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, end};
+ int nerrors;
+
+ char* argv[] = {"program", "1", "2", "3", "4", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 1);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argdbl_basic_011(CuTest* tc) {
+ struct arg_dbl* a = arg_dbl1(NULL, NULL, "a", "a is <double>");
+ struct arg_dbl* b = arg_dbl0(NULL, NULL, "b", "b is <double>");
+ struct arg_dbl* c = arg_dbl0(NULL, NULL, "c", "c is <double>");
+ struct arg_dbl* d = arg_dbln("dD", "delta", "<double>", 0, 3, "d can occur 0..3 times");
+ struct arg_dbl* e = arg_dbl0(NULL, "eps,eqn", "<double>", "eps is optional");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, end};
+ int nerrors;
+
+ char* argv[] = {"program", "1", "2", "3", "-d1", "-d2", "-d3", "-d4", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 1);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argdbl_basic_012(CuTest* tc) {
+ struct arg_dbl* a = arg_dbl1(NULL, NULL, "a", "a is <double>");
+ struct arg_dbl* b = arg_dbl0(NULL, NULL, "b", "b is <double>");
+ struct arg_dbl* c = arg_dbl0(NULL, NULL, "c", "c is <double>");
+ struct arg_dbl* d = arg_dbln("dD", "delta", "<double>", 0, 3, "d can occur 0..3 times");
+ struct arg_dbl* e = arg_dbl0(NULL, "eps,eqn", "<double>", "eps is optional");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, end};
+ int nerrors;
+
+ char* argv[] = {"program", "1", "2", "3", "--eps", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 1);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argdbl_basic_013(CuTest* tc) {
+ struct arg_dbl* a = arg_dbl1(NULL, NULL, "a", "a is <double>");
+ struct arg_dbl* b = arg_dbl0(NULL, NULL, "b", "b is <double>");
+ struct arg_dbl* c = arg_dbl0(NULL, NULL, "c", "c is <double>");
+ struct arg_dbl* d = arg_dbln("dD", "delta", "<double>", 0, 3, "d can occur 0..3 times");
+ struct arg_dbl* e = arg_dbl0(NULL, "eps,eqn", "<double>", "eps is optional");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, end};
+ int nerrors;
+
+ char* argv[] = {"program", "1", "2", "3", "--eps", "3", "--eqn", "6", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 1);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argdbl_basic_014(CuTest* tc) {
+ struct arg_dbl* a = arg_dbl1(NULL, NULL, "a", "a is <double>");
+ struct arg_dbl* b = arg_dbl0(NULL, NULL, "b", "b is <double>");
+ struct arg_dbl* c = arg_dbl0(NULL, NULL, "c", "c is <double>");
+ struct arg_dbl* d = arg_dbln("dD", "delta", "<double>", 0, 3, "d can occur 0..3 times");
+ struct arg_dbl* e = arg_dbl0(NULL, "eps,eqn", "<double>", "eps is optional");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, end};
+ int nerrors;
+
+ char* argv[] = {"program", "hello", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 1);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argdbl_basic_015(CuTest* tc) {
+ struct arg_dbl* a = arg_dbl1(NULL, NULL, "a", "a is <double>");
+ struct arg_dbl* b = arg_dbl0(NULL, NULL, "b", "b is <double>");
+ struct arg_dbl* c = arg_dbl0(NULL, NULL, "c", "c is <double>");
+ struct arg_dbl* d = arg_dbln("dD", "delta", "<double>", 0, 3, "d can occur 0..3 times");
+ struct arg_dbl* e = arg_dbl0(NULL, "eps,eqn", "<double>", "eps is optional");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, end};
+ int nerrors;
+
+ char* argv[] = {"program", "4", "hello", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 1);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+CuSuite* get_argdbl_testsuite() {
+ CuSuite* suite = CuSuiteNew();
+ SUITE_ADD_TEST(suite, test_argdbl_basic_001);
+ SUITE_ADD_TEST(suite, test_argdbl_basic_002);
+ SUITE_ADD_TEST(suite, test_argdbl_basic_003);
+ SUITE_ADD_TEST(suite, test_argdbl_basic_004);
+ SUITE_ADD_TEST(suite, test_argdbl_basic_005);
+ SUITE_ADD_TEST(suite, test_argdbl_basic_006);
+ SUITE_ADD_TEST(suite, test_argdbl_basic_007);
+ SUITE_ADD_TEST(suite, test_argdbl_basic_008);
+ SUITE_ADD_TEST(suite, test_argdbl_basic_009);
+ SUITE_ADD_TEST(suite, test_argdbl_basic_010);
+ SUITE_ADD_TEST(suite, test_argdbl_basic_011);
+ SUITE_ADD_TEST(suite, test_argdbl_basic_012);
+ SUITE_ADD_TEST(suite, test_argdbl_basic_013);
+ SUITE_ADD_TEST(suite, test_argdbl_basic_014);
+ SUITE_ADD_TEST(suite, test_argdbl_basic_015);
+ return suite;
+}
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
--- /dev/null
+/*******************************************************************************
+ * This file is part of the argtable3 library.
+ *
+ * Copyright (C) 2013-2019 Tom G. Huang
+ * <tomghuang@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of STEWART HEITMANN 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN 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.
+ ******************************************************************************/
+
+#include <string.h>
+#include <time.h>
+
+#include <stdio.h>
+
+#include "CuTest.h"
+#include "argtable3.h"
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4204)
+#endif
+
+void test_argdstr_basic_001(CuTest* tc) {
+ arg_dstr_t ds = arg_dstr_create();
+
+ arg_dstr_set(ds, "hello ", ARG_DSTR_VOLATILE);
+ CuAssertTrue(tc, strcmp(arg_dstr_cstr(ds), "hello ") == 0);
+
+ arg_dstr_cat(ds, "world");
+ CuAssertTrue(tc, strcmp(arg_dstr_cstr(ds), "hello world") == 0);
+
+ arg_dstr_destroy(ds);
+}
+
+void test_argdstr_basic_002(CuTest* tc) {
+ arg_dstr_t ds = arg_dstr_create();
+
+ arg_dstr_set(ds, "hello world", ARG_DSTR_VOLATILE);
+ CuAssertTrue(tc, strcmp(arg_dstr_cstr(ds), "hello world") == 0);
+
+ arg_dstr_reset(ds);
+ CuAssertTrue(tc, strcmp(arg_dstr_cstr(ds), "") == 0);
+
+ arg_dstr_set(ds, "good", ARG_DSTR_VOLATILE);
+ CuAssertTrue(tc, strcmp(arg_dstr_cstr(ds), "good") == 0);
+
+ arg_dstr_destroy(ds);
+}
+
+void test_argdstr_basic_003(CuTest* tc) {
+ arg_dstr_t ds = arg_dstr_create();
+ arg_dstr_cat(ds, "hello world");
+ CuAssertTrue(tc, strcmp(arg_dstr_cstr(ds), "hello world") == 0);
+
+ arg_dstr_destroy(ds);
+}
+
+void test_argdstr_basic_004(CuTest* tc) {
+ arg_dstr_t ds = arg_dstr_create();
+ arg_dstr_catf(ds, "%s %d", "hello world", 1);
+ CuAssertTrue(tc, strcmp(arg_dstr_cstr(ds), "hello world 1") == 0);
+
+ arg_dstr_destroy(ds);
+}
+
+void test_argdstr_basic_005(CuTest* tc) {
+ arg_dstr_t ds = arg_dstr_create();
+ arg_dstr_catf(ds, "%d.", 1);
+ arg_dstr_catf(ds, "%d.", 2);
+ arg_dstr_catf(ds, "%d.", 3);
+ arg_dstr_cat(ds, "456");
+ CuAssertTrue(tc, strcmp(arg_dstr_cstr(ds), "1.2.3.456") == 0);
+
+ arg_dstr_destroy(ds);
+}
+
+void test_argdstr_basic_006(CuTest* tc) {
+ int i;
+
+ arg_dstr_t ds = arg_dstr_create();
+ for (i = 0; i < 100000; i++) {
+ arg_dstr_catf(ds, "%s", "1234567890");
+ }
+ CuAssertTrue(tc, strlen(arg_dstr_cstr(ds)) == 1000000);
+
+ arg_dstr_destroy(ds);
+}
+
+CuSuite* get_argdstr_testsuite() {
+ CuSuite* suite = CuSuiteNew();
+ SUITE_ADD_TEST(suite, test_argdstr_basic_001);
+ SUITE_ADD_TEST(suite, test_argdstr_basic_002);
+ SUITE_ADD_TEST(suite, test_argdstr_basic_003);
+ SUITE_ADD_TEST(suite, test_argdstr_basic_004);
+ SUITE_ADD_TEST(suite, test_argdstr_basic_005);
+ SUITE_ADD_TEST(suite, test_argdstr_basic_006);
+ return suite;
+}
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
--- /dev/null
+/*******************************************************************************
+ * This file is part of the argtable3 library.
+ *
+ * Copyright (C) 2013-2019 Tom G. Huang
+ * <tomghuang@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of STEWART HEITMANN 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN 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.
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "CuTest.h"
+#include "argtable3.h"
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4204)
+#endif
+
+void test_argfile_basic_001(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "foo.bar", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "foo.bar");
+ CuAssertStrEquals(tc, a->basename[0], "foo.bar");
+ CuAssertStrEquals(tc, a->extension[0], ".bar");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_002(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "/foo.bar", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "/foo.bar");
+ CuAssertStrEquals(tc, a->basename[0], "foo.bar");
+ CuAssertStrEquals(tc, a->extension[0], ".bar");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_003(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "./foo.bar", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "./foo.bar");
+ CuAssertStrEquals(tc, a->basename[0], "foo.bar");
+ CuAssertStrEquals(tc, a->extension[0], ".bar");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_004(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "././foo.bar", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "././foo.bar");
+ CuAssertStrEquals(tc, a->basename[0], "foo.bar");
+ CuAssertStrEquals(tc, a->extension[0], ".bar");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_005(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "./././foo.bar", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "./././foo.bar");
+ CuAssertStrEquals(tc, a->basename[0], "foo.bar");
+ CuAssertStrEquals(tc, a->extension[0], ".bar");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_006(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "../foo.bar", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "../foo.bar");
+ CuAssertStrEquals(tc, a->basename[0], "foo.bar");
+ CuAssertStrEquals(tc, a->extension[0], ".bar");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_007(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "../../foo.bar", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "../../foo.bar");
+ CuAssertStrEquals(tc, a->basename[0], "foo.bar");
+ CuAssertStrEquals(tc, a->extension[0], ".bar");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_008(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "foo", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "foo");
+ CuAssertStrEquals(tc, a->basename[0], "foo");
+ CuAssertStrEquals(tc, a->extension[0], "");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_009(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "/foo", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "/foo");
+ CuAssertStrEquals(tc, a->basename[0], "foo");
+ CuAssertStrEquals(tc, a->extension[0], "");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_010(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "./foo", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "./foo");
+ CuAssertStrEquals(tc, a->basename[0], "foo");
+ CuAssertStrEquals(tc, a->extension[0], "");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_011(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "././foo", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "././foo");
+ CuAssertStrEquals(tc, a->basename[0], "foo");
+ CuAssertStrEquals(tc, a->extension[0], "");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_012(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "./././foo", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "./././foo");
+ CuAssertStrEquals(tc, a->basename[0], "foo");
+ CuAssertStrEquals(tc, a->extension[0], "");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_013(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "../foo", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "../foo");
+ CuAssertStrEquals(tc, a->basename[0], "foo");
+ CuAssertStrEquals(tc, a->extension[0], "");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_014(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "../../foo", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "../../foo");
+ CuAssertStrEquals(tc, a->basename[0], "foo");
+ CuAssertStrEquals(tc, a->extension[0], "");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_015(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", ".foo", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], ".foo");
+ CuAssertStrEquals(tc, a->basename[0], ".foo");
+ CuAssertStrEquals(tc, a->extension[0], "");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_016(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "/.foo", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "/.foo");
+ CuAssertStrEquals(tc, a->basename[0], ".foo");
+ CuAssertStrEquals(tc, a->extension[0], "");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_017(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "./.foo", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "./.foo");
+ CuAssertStrEquals(tc, a->basename[0], ".foo");
+ CuAssertStrEquals(tc, a->extension[0], "");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_018(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "../.foo", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "../.foo");
+ CuAssertStrEquals(tc, a->basename[0], ".foo");
+ CuAssertStrEquals(tc, a->extension[0], "");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_019(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "foo.", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "foo.");
+ CuAssertStrEquals(tc, a->basename[0], "foo.");
+ CuAssertStrEquals(tc, a->extension[0], "");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_020(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "/foo.", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "/foo.");
+ CuAssertStrEquals(tc, a->basename[0], "foo.");
+ CuAssertStrEquals(tc, a->extension[0], "");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_021(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "./foo.", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "./foo.");
+ CuAssertStrEquals(tc, a->basename[0], "foo.");
+ CuAssertStrEquals(tc, a->extension[0], "");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_022(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "../foo.", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "../foo.");
+ CuAssertStrEquals(tc, a->basename[0], "foo.");
+ CuAssertStrEquals(tc, a->extension[0], "");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_023(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "/.foo.", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "/.foo.");
+ CuAssertStrEquals(tc, a->basename[0], ".foo.");
+ CuAssertStrEquals(tc, a->extension[0], "");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_024(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "/.foo.c", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "/.foo.c");
+ CuAssertStrEquals(tc, a->basename[0], ".foo.c");
+ CuAssertStrEquals(tc, a->extension[0], ".c");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_025(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "/.foo..b.c", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "/.foo..b.c");
+ CuAssertStrEquals(tc, a->basename[0], ".foo..b.c");
+ CuAssertStrEquals(tc, a->extension[0], ".c");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_026(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "/", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "/");
+ CuAssertStrEquals(tc, a->basename[0], "");
+ CuAssertStrEquals(tc, a->extension[0], "");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_027(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", ".", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], ".");
+ CuAssertStrEquals(tc, a->basename[0], "");
+ CuAssertStrEquals(tc, a->extension[0], "");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_028(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "..", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "..");
+ CuAssertStrEquals(tc, a->basename[0], "");
+ CuAssertStrEquals(tc, a->extension[0], "");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_029(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "/.", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "/.");
+ CuAssertStrEquals(tc, a->basename[0], "");
+ CuAssertStrEquals(tc, a->extension[0], "");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_030(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "/..", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "/..");
+ CuAssertStrEquals(tc, a->basename[0], "");
+ CuAssertStrEquals(tc, a->extension[0], "");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_031(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "./", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "./");
+ CuAssertStrEquals(tc, a->basename[0], "");
+ CuAssertStrEquals(tc, a->extension[0], "");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argfile_basic_032(CuTest* tc) {
+ struct arg_file* a = arg_file1(NULL, NULL, "<file>", "filename to test");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, end};
+ int nerrors;
+
+ char* argv[] = {"program", "../", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->filename[0], "../");
+ CuAssertStrEquals(tc, a->basename[0], "");
+ CuAssertStrEquals(tc, a->extension[0], "");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+CuSuite* get_argfile_testsuite() {
+ CuSuite* suite = CuSuiteNew();
+ SUITE_ADD_TEST(suite, test_argfile_basic_001);
+ SUITE_ADD_TEST(suite, test_argfile_basic_002);
+ SUITE_ADD_TEST(suite, test_argfile_basic_003);
+ SUITE_ADD_TEST(suite, test_argfile_basic_004);
+ SUITE_ADD_TEST(suite, test_argfile_basic_005);
+ SUITE_ADD_TEST(suite, test_argfile_basic_006);
+ SUITE_ADD_TEST(suite, test_argfile_basic_007);
+ SUITE_ADD_TEST(suite, test_argfile_basic_008);
+ SUITE_ADD_TEST(suite, test_argfile_basic_009);
+ SUITE_ADD_TEST(suite, test_argfile_basic_010);
+ SUITE_ADD_TEST(suite, test_argfile_basic_011);
+ SUITE_ADD_TEST(suite, test_argfile_basic_012);
+ SUITE_ADD_TEST(suite, test_argfile_basic_013);
+ SUITE_ADD_TEST(suite, test_argfile_basic_014);
+ SUITE_ADD_TEST(suite, test_argfile_basic_015);
+ SUITE_ADD_TEST(suite, test_argfile_basic_016);
+ SUITE_ADD_TEST(suite, test_argfile_basic_017);
+ SUITE_ADD_TEST(suite, test_argfile_basic_018);
+ SUITE_ADD_TEST(suite, test_argfile_basic_019);
+ SUITE_ADD_TEST(suite, test_argfile_basic_020);
+ SUITE_ADD_TEST(suite, test_argfile_basic_021);
+ SUITE_ADD_TEST(suite, test_argfile_basic_022);
+ SUITE_ADD_TEST(suite, test_argfile_basic_023);
+ SUITE_ADD_TEST(suite, test_argfile_basic_024);
+ SUITE_ADD_TEST(suite, test_argfile_basic_025);
+ SUITE_ADD_TEST(suite, test_argfile_basic_026);
+ SUITE_ADD_TEST(suite, test_argfile_basic_027);
+ SUITE_ADD_TEST(suite, test_argfile_basic_028);
+ SUITE_ADD_TEST(suite, test_argfile_basic_029);
+ SUITE_ADD_TEST(suite, test_argfile_basic_030);
+ SUITE_ADD_TEST(suite, test_argfile_basic_031);
+ SUITE_ADD_TEST(suite, test_argfile_basic_032);
+ return suite;
+}
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
--- /dev/null
+/*******************************************************************************\r
+ * This file is part of the argtable3 library.\r
+ *\r
+ * Copyright (C) 2013-2019 Tom G. Huang\r
+ * <tomghuang@gmail.com>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ * * Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ * * Redistributions in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in the\r
+ * documentation and/or other materials provided with the distribution.\r
+ * * Neither the name of STEWART HEITMANN nor the names of its contributors\r
+ * may be used to endorse or promote products derived from this software\r
+ * without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ ******************************************************************************/\r
+\r
+#include <string.h>\r
+#include <time.h>\r
+\r
+#include <stdio.h>\r
+\r
+#include "CuTest.h"\r
+#include "argtable3_private.h"\r
+\r
+#if defined(_MSC_VER)\r
+#pragma warning(push)\r
+#pragma warning(disable : 4204)\r
+#pragma warning(disable : 4996)\r
+#endif\r
+\r
+static unsigned int hash_key(const void* key) {\r
+ char* str = (char*)key;\r
+ int c;\r
+ unsigned int hash = 5381;\r
+\r
+ while ((c = *str++) != 0)\r
+ hash = ((hash << 5) + hash) + c; /* hash * 33 + c */\r
+\r
+ return hash;\r
+}\r
+\r
+static int equal_keys(const void* key1, const void* key2) {\r
+ char* k1 = (char*)key1;\r
+ char* k2 = (char*)key2;\r
+ return (0 == strcmp(k1, k2));\r
+}\r
+\r
+void test_arghashtable_basic_001(CuTest* tc) {\r
+ arg_hashtable_t* h = arg_hashtable_create(32, hash_key, equal_keys);\r
+ CuAssertTrue(tc, h != 0);\r
+ CuAssertIntEquals(tc, arg_hashtable_count(h), 0);\r
+\r
+ arg_hashtable_destroy(h, 1);\r
+}\r
+\r
+void test_arghashtable_basic_002(CuTest* tc) {\r
+ arg_hashtable_t* h = arg_hashtable_create(32, hash_key, equal_keys);\r
+ CuAssertTrue(tc, h != 0);\r
+ CuAssertIntEquals(tc, arg_hashtable_count(h), 0);\r
+\r
+ char* key_1 = "k1";\r
+ char* k_1 = (char*)malloc(strlen(key_1) + 1);\r
+ memset(k_1, 0, strlen(key_1) + 1);\r
+ strncpy(k_1, key_1, strlen(key_1));\r
+\r
+ char* value_1 = "v1";\r
+ char* v_1 = (char*)malloc(strlen(value_1) + 1);\r
+ memset(v_1, 0, strlen(value_1) + 1);\r
+ strncpy(v_1, value_1, strlen(value_1));\r
+\r
+ arg_hashtable_insert(h, k_1, v_1);\r
+ CuAssertIntEquals(tc, 1, arg_hashtable_count(h));\r
+\r
+ arg_hashtable_itr_t* itr = arg_hashtable_itr_create(h);\r
+ CuAssertTrue(tc, itr != 0);\r
+ CuAssertPtrEquals(tc, k_1, arg_hashtable_itr_key(itr));\r
+ CuAssertTrue(tc, strcmp((char*)arg_hashtable_itr_key(itr), key_1) == 0);\r
+ CuAssertPtrEquals(tc, v_1, arg_hashtable_itr_value(itr));\r
+ CuAssertTrue(tc, strcmp((char*)arg_hashtable_itr_value(itr), value_1) == 0);\r
+\r
+ arg_hashtable_itr_destroy(itr);\r
+ arg_hashtable_destroy(h, 1);\r
+}\r
+\r
+void test_arghashtable_basic_003(CuTest* tc) {\r
+ arg_hashtable_t* h = arg_hashtable_create(32, hash_key, equal_keys);\r
+ CuAssertTrue(tc, h != 0);\r
+ CuAssertIntEquals(tc, arg_hashtable_count(h), 0);\r
+\r
+ char* key_1 = "k1";\r
+ char* k_1 = (char*)malloc(strlen(key_1) + 1);\r
+ memset(k_1, 0, strlen(key_1) + 1);\r
+ strncpy(k_1, key_1, strlen(key_1));\r
+\r
+ char* value_1 = "v1";\r
+ char* v_1 = (char*)malloc(strlen(value_1) + 1);\r
+ memset(v_1, 0, strlen(value_1) + 1);\r
+ strncpy(v_1, value_1, strlen(value_1));\r
+\r
+ arg_hashtable_insert(h, k_1, v_1);\r
+ CuAssertIntEquals(tc, 1, arg_hashtable_count(h));\r
+\r
+ char* key_2 = "k2";\r
+ char* k_2 = (char*)malloc(strlen(key_2) + 1);\r
+ memset(k_2, 0, strlen(key_2) + 1);\r
+ strncpy(k_2, key_2, strlen(key_2));\r
+\r
+ char* value_2 = "v2";\r
+ char* v_2 = (char*)malloc(strlen(value_2) + 1);\r
+ memset(v_2, 0, strlen(value_2) + 1);\r
+ strncpy(v_2, value_2, strlen(value_2));\r
+\r
+ arg_hashtable_insert(h, k_2, v_2);\r
+ CuAssertIntEquals(tc, 2, arg_hashtable_count(h));\r
+\r
+ arg_hashtable_itr_t* itr = arg_hashtable_itr_create(h);\r
+ CuAssertTrue(tc, itr != 0);\r
+\r
+ int ret = arg_hashtable_itr_advance(itr);\r
+ CuAssertTrue(tc, ret != 0);\r
+\r
+ ret = arg_hashtable_itr_advance(itr);\r
+ CuAssertTrue(tc, ret == 0);\r
+\r
+ arg_hashtable_itr_destroy(itr);\r
+ arg_hashtable_destroy(h, 1);\r
+}\r
+\r
+void test_arghashtable_basic_004(CuTest* tc) {\r
+ arg_hashtable_t* h = arg_hashtable_create(32, hash_key, equal_keys);\r
+ CuAssertTrue(tc, h != 0);\r
+ CuAssertIntEquals(tc, arg_hashtable_count(h), 0);\r
+\r
+ char* key_1 = "k1";\r
+ char* k_1 = (char*)malloc(strlen(key_1) + 1);\r
+ memset(k_1, 0, strlen(key_1) + 1);\r
+ strncpy(k_1, key_1, strlen(key_1));\r
+\r
+ char* value_1 = "v1";\r
+ char* v_1 = (char*)malloc(strlen(value_1) + 1);\r
+ memset(v_1, 0, strlen(value_1) + 1);\r
+ strncpy(v_1, value_1, strlen(value_1));\r
+\r
+ arg_hashtable_insert(h, k_1, v_1);\r
+ CuAssertTrue(tc, h != 0);\r
+ CuAssertIntEquals(tc, 1, arg_hashtable_count(h));\r
+\r
+ arg_hashtable_itr_t* itr = arg_hashtable_itr_create(h);\r
+ int ret = arg_hashtable_itr_remove(itr);\r
+ CuAssertTrue(tc, ret == 0);\r
+ CuAssertIntEquals(tc, 0, arg_hashtable_count(h));\r
+\r
+ arg_hashtable_itr_destroy(itr);\r
+ arg_hashtable_destroy(h, 1);\r
+}\r
+\r
+void test_arghashtable_basic_005(CuTest* tc) {\r
+ arg_hashtable_t* h = arg_hashtable_create(3, hash_key, equal_keys);\r
+ CuAssertTrue(tc, h != 0);\r
+ CuAssertIntEquals(tc, arg_hashtable_count(h), 0);\r
+\r
+ char* key_1 = "k1";\r
+ char* k_1 = (char*)malloc(strlen(key_1) + 1);\r
+ memset(k_1, 0, strlen(key_1) + 1);\r
+ strncpy(k_1, key_1, strlen(key_1));\r
+\r
+ char* value_1 = "v1";\r
+ char* v_1 = (char*)malloc(strlen(value_1) + 1);\r
+ memset(v_1, 0, strlen(value_1) + 1);\r
+ strncpy(v_1, value_1, strlen(value_1));\r
+\r
+ arg_hashtable_insert(h, k_1, v_1);\r
+ CuAssertTrue(tc, h != 0);\r
+ CuAssertIntEquals(tc, 1, arg_hashtable_count(h));\r
+\r
+ arg_hashtable_remove(h, k_1);\r
+ CuAssertIntEquals(tc, 0, arg_hashtable_count(h));\r
+\r
+ arg_hashtable_destroy(h, 1);\r
+}\r
+\r
+void test_arghashtable_basic_006(CuTest* tc) {\r
+ arg_hashtable_t* h = arg_hashtable_create(32, hash_key, equal_keys);\r
+ CuAssertTrue(tc, h != 0);\r
+ CuAssertIntEquals(tc, arg_hashtable_count(h), 0);\r
+\r
+ char* key_1 = "k1";\r
+ char* k_1 = (char*)malloc(strlen(key_1) + 1);\r
+ memset(k_1, 0, strlen(key_1) + 1);\r
+ strncpy(k_1, key_1, strlen(key_1));\r
+\r
+ char* value_1 = "v1";\r
+ char* v_1 = (char*)malloc(strlen(value_1) + 1);\r
+ memset(v_1, 0, strlen(value_1) + 1);\r
+ strncpy(v_1, value_1, strlen(value_1));\r
+\r
+ arg_hashtable_insert(h, k_1, v_1);\r
+ CuAssertTrue(tc, arg_hashtable_count(h) == 1);\r
+\r
+ char* vv = (char*)arg_hashtable_search(h, k_1);\r
+ CuAssertTrue(tc, strcmp(vv, v_1) == 0);\r
+\r
+ arg_hashtable_destroy(h, 1);\r
+}\r
+\r
+void test_arghashtable_basic_007(CuTest* tc) {\r
+ arg_hashtable_t* h = arg_hashtable_create(32, hash_key, equal_keys);\r
+ CuAssertTrue(tc, h != 0);\r
+ CuAssertIntEquals(tc, arg_hashtable_count(h), 0);\r
+\r
+ char* key_1 = "k1";\r
+ char* k_1 = (char*)malloc(strlen(key_1) + 1);\r
+ memset(k_1, 0, strlen(key_1) + 1);\r
+ strncpy(k_1, key_1, strlen(key_1));\r
+\r
+ char* value_1 = "v1";\r
+ char* v_1 = (char*)malloc(strlen(value_1) + 1);\r
+ memset(v_1, 0, strlen(value_1) + 1);\r
+ strncpy(v_1, value_1, strlen(value_1));\r
+\r
+ arg_hashtable_insert(h, k_1, v_1);\r
+ CuAssertIntEquals(tc, 1, arg_hashtable_count(h));\r
+\r
+ char* key_2 = "k2";\r
+ char* k_2 = (char*)malloc(strlen(key_2) + 1);\r
+ memset(k_2, 0, strlen(key_2) + 1);\r
+ strncpy(k_2, key_2, strlen(key_2));\r
+\r
+ char* value_2 = "v2";\r
+ char* v_2 = (char*)malloc(strlen(value_2) + 1);\r
+ memset(v_2, 0, strlen(value_2) + 1);\r
+ strncpy(v_2, value_2, strlen(value_2));\r
+\r
+ arg_hashtable_insert(h, k_2, v_2);\r
+ CuAssertIntEquals(tc, 2, arg_hashtable_count(h));\r
+\r
+ arg_hashtable_itr_t itr;\r
+ int ret = arg_hashtable_itr_search(&itr, h, k_1);\r
+ CuAssertTrue(tc, ret != 0);\r
+ CuAssertPtrEquals(tc, k_1, arg_hashtable_itr_key(&itr));\r
+ CuAssertPtrEquals(tc, v_1, arg_hashtable_itr_value(&itr));\r
+ CuAssertTrue(tc, strcmp((char*)arg_hashtable_itr_key(&itr), k_1) == 0);\r
+ CuAssertTrue(tc, strcmp((char*)arg_hashtable_itr_value(&itr), v_1) == 0);\r
+\r
+ arg_hashtable_destroy(h, 1);\r
+}\r
+\r
+CuSuite* get_arghashtable_testsuite() {\r
+ CuSuite* suite = CuSuiteNew();\r
+ SUITE_ADD_TEST(suite, test_arghashtable_basic_001);\r
+ SUITE_ADD_TEST(suite, test_arghashtable_basic_002);\r
+ SUITE_ADD_TEST(suite, test_arghashtable_basic_003);\r
+ SUITE_ADD_TEST(suite, test_arghashtable_basic_004);\r
+ SUITE_ADD_TEST(suite, test_arghashtable_basic_005);\r
+ SUITE_ADD_TEST(suite, test_arghashtable_basic_006);\r
+ SUITE_ADD_TEST(suite, test_arghashtable_basic_007);\r
+ return suite;\r
+}\r
+\r
+#if defined(_MSC_VER)\r
+#pragma warning(pop)\r
+#endif\r
--- /dev/null
+/*******************************************************************************
+ * This file is part of the argtable3 library.
+ *
+ * Copyright (C) 2013-2019 Tom G. Huang
+ * <tomghuang@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of STEWART HEITMANN 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN 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.
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "CuTest.h"
+#include "argtable3.h"
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4204)
+#endif
+
+void test_argint_basic_001(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+
+ char* argv[] = {"program", "0", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertIntEquals(tc, a->ival[0], 0);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 0);
+ CuAssertTrue(tc, d->count == 0);
+ CuAssertTrue(tc, e->count == 0);
+ CuAssertTrue(tc, f->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_002(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+
+ char* argv[] = {"program", "1", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertIntEquals(tc, a->ival[0], 1);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 0);
+ CuAssertTrue(tc, d->count == 0);
+ CuAssertTrue(tc, e->count == 0);
+ CuAssertTrue(tc, f->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_003(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+
+ char* argv[] = {"program", "1", "2", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertIntEquals(tc, a->ival[0], 1);
+ CuAssertTrue(tc, b->count == 1);
+ CuAssertIntEquals(tc, b->ival[0], 2);
+ CuAssertTrue(tc, c->count == 0);
+ CuAssertTrue(tc, d->count == 0);
+ CuAssertTrue(tc, e->count == 0);
+ CuAssertTrue(tc, f->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_004(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+
+ char* argv[] = {"program", "5", "7", "9", "-d", "-21", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertIntEquals(tc, a->ival[0], 5);
+ CuAssertTrue(tc, b->count == 1);
+ CuAssertIntEquals(tc, b->ival[0], 7);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertIntEquals(tc, c->ival[0], 9);
+ CuAssertTrue(tc, d->count == 1);
+ CuAssertIntEquals(tc, d->ival[0], -21);
+ CuAssertTrue(tc, e->count == 0);
+ CuAssertTrue(tc, f->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_005(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-d", "1", "-D2", "--delta", "3", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 1);
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 0);
+ CuAssertTrue(tc, d->count == 3);
+ CuAssertIntEquals(tc, d->ival[0], 1);
+ CuAssertIntEquals(tc, d->ival[1], 2);
+ CuAssertIntEquals(tc, d->ival[2], 3);
+ CuAssertTrue(tc, e->count == 0);
+ CuAssertTrue(tc, f->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_006(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+
+ char* argv[] = {"program", "1", "2", "4", "--eps", "-7", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertIntEquals(tc, a->ival[0], 1);
+ CuAssertTrue(tc, b->count == 1);
+ CuAssertIntEquals(tc, b->ival[0], 2);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertIntEquals(tc, c->ival[0], 4);
+ CuAssertTrue(tc, d->count == 0);
+ CuAssertTrue(tc, e->count == 1);
+ CuAssertIntEquals(tc, e->ival[0], -7);
+ CuAssertTrue(tc, f->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_007(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+
+ char* argv[] = {"program", "1", "2", "4", "--eqn", "-7", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertIntEquals(tc, a->ival[0], 1);
+ CuAssertTrue(tc, b->count == 1);
+ CuAssertIntEquals(tc, b->ival[0], 2);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertIntEquals(tc, c->ival[0], 4);
+ CuAssertTrue(tc, d->count == 0);
+ CuAssertTrue(tc, e->count == 1);
+ CuAssertIntEquals(tc, e->ival[0], -7);
+ CuAssertTrue(tc, f->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_008(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+
+ char* argv[] = {"program", "1", "2", "3", "-D4", "--eps", "-10", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertIntEquals(tc, a->ival[0], 1);
+ CuAssertTrue(tc, b->count == 1);
+ CuAssertIntEquals(tc, b->ival[0], 2);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertIntEquals(tc, c->ival[0], 3);
+ CuAssertTrue(tc, d->count == 1);
+ CuAssertIntEquals(tc, d->ival[0], 4);
+ CuAssertTrue(tc, e->count == 1);
+ CuAssertIntEquals(tc, e->ival[0], -10);
+ CuAssertTrue(tc, f->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_009(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "1", "-f", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 0);
+ CuAssertTrue(tc, d->count == 0);
+ CuAssertTrue(tc, e->count == 0);
+ CuAssertTrue(tc, f->count == 1);
+ CuAssertIntEquals(tc, f->ival[0], -1);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_010(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "-f", "1", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 0);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 1);
+ CuAssertIntEquals(tc, b->count, 0);
+ CuAssertIntEquals(tc, c->count, 0);
+ CuAssertIntEquals(tc, d->count, 0);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 1);
+ CuAssertIntEquals(tc, f->ival[0], -1);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_011(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "-f", "2", "--filler", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 0);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 2);
+ CuAssertIntEquals(tc, b->count, 0);
+ CuAssertIntEquals(tc, c->count, 0);
+ CuAssertIntEquals(tc, d->count, 0);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 2);
+ CuAssertIntEquals(tc, f->ival[0], -1);
+ CuAssertIntEquals(tc, f->ival[1], -1);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_012(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "-f", "1", "--filler=2", "-f", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 0);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 1);
+ CuAssertIntEquals(tc, b->count, 0);
+ CuAssertIntEquals(tc, c->count, 0);
+ CuAssertIntEquals(tc, d->count, 0);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 3);
+ CuAssertIntEquals(tc, f->ival[0], -1);
+ CuAssertIntEquals(tc, f->ival[1], 2);
+ CuAssertIntEquals(tc, f->ival[0], -1);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_013(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "0x0", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 0);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 0x0);
+ CuAssertIntEquals(tc, b->count, 0);
+ CuAssertIntEquals(tc, c->count, 0);
+ CuAssertIntEquals(tc, d->count, 0);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_014(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "0x0", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 0);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 0x0);
+ CuAssertIntEquals(tc, b->count, 0);
+ CuAssertIntEquals(tc, c->count, 0);
+ CuAssertIntEquals(tc, d->count, 0);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_015(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "0x10", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 0);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 0x10);
+ CuAssertIntEquals(tc, b->count, 0);
+ CuAssertIntEquals(tc, c->count, 0);
+ CuAssertIntEquals(tc, d->count, 0);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_016(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "0x10", "0x32", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 0);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 0x10);
+ CuAssertIntEquals(tc, b->count, 1);
+ CuAssertIntEquals(tc, b->ival[0], 0x32);
+ CuAssertIntEquals(tc, c->count, 0);
+ CuAssertIntEquals(tc, d->count, 0);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_017(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "0x5", "0xA", "0xF", "-d", "-0x1E", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 0);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 0x5);
+ CuAssertIntEquals(tc, b->count, 1);
+ CuAssertIntEquals(tc, b->ival[0], 0xA);
+ CuAssertIntEquals(tc, c->count, 1);
+ CuAssertIntEquals(tc, c->ival[0], 0xF);
+ CuAssertIntEquals(tc, d->count, 1);
+ CuAssertIntEquals(tc, d->ival[0], -0x1E);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_018(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "-d", "0xab", "-D0x09", "--delta", "0x02e", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 1);
+ CuAssertIntEquals(tc, a->count, 0);
+ CuAssertIntEquals(tc, b->count, 0);
+ CuAssertIntEquals(tc, c->count, 0);
+ CuAssertIntEquals(tc, d->count, 3);
+ CuAssertIntEquals(tc, d->ival[0], 0xab);
+ CuAssertIntEquals(tc, d->ival[1], 0x09);
+ CuAssertIntEquals(tc, d->ival[2], 0x02e);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_019(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "0o0", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 0);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 0);
+ CuAssertIntEquals(tc, b->count, 0);
+ CuAssertIntEquals(tc, c->count, 0);
+ CuAssertIntEquals(tc, d->count, 0);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_020(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "0o10", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 0);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 010);
+ CuAssertIntEquals(tc, b->count, 0);
+ CuAssertIntEquals(tc, c->count, 0);
+ CuAssertIntEquals(tc, d->count, 0);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_021(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "0o67", "0O23", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 0);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 067);
+ CuAssertIntEquals(tc, b->count, 1);
+ CuAssertIntEquals(tc, b->ival[0], 023);
+ CuAssertIntEquals(tc, c->count, 0);
+ CuAssertIntEquals(tc, d->count, 0);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_022(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "0o5", "0O0", "0x1", "-d", "-0o6", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 0);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 05);
+ CuAssertIntEquals(tc, b->count, 1);
+ CuAssertIntEquals(tc, b->ival[0], 0);
+ CuAssertIntEquals(tc, c->count, 1);
+ CuAssertIntEquals(tc, c->ival[0], 0x1);
+ CuAssertIntEquals(tc, d->count, 1);
+ CuAssertIntEquals(tc, d->ival[0], -06);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_023(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "-d", "0o012", "-D0o0777", "--delta", "0o56", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 1);
+ CuAssertIntEquals(tc, a->count, 0);
+ CuAssertIntEquals(tc, b->count, 0);
+ CuAssertIntEquals(tc, c->count, 0);
+ CuAssertIntEquals(tc, d->count, 3);
+ CuAssertIntEquals(tc, d->ival[0], 012);
+ CuAssertIntEquals(tc, d->ival[1], 0777);
+ CuAssertIntEquals(tc, d->ival[2], 056);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_024(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "0B0", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 0);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 0);
+ CuAssertIntEquals(tc, b->count, 0);
+ CuAssertIntEquals(tc, c->count, 0);
+ CuAssertIntEquals(tc, d->count, 0);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_025(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "0B0", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 0);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 0);
+ CuAssertIntEquals(tc, b->count, 0);
+ CuAssertIntEquals(tc, c->count, 0);
+ CuAssertIntEquals(tc, d->count, 0);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_026(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "0b10", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 0);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 2);
+ CuAssertIntEquals(tc, b->count, 0);
+ CuAssertIntEquals(tc, c->count, 0);
+ CuAssertIntEquals(tc, d->count, 0);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_027(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "0B10110", "0b111001", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 0);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 22);
+ CuAssertIntEquals(tc, b->count, 1);
+ CuAssertIntEquals(tc, b->ival[0], 57);
+ CuAssertIntEquals(tc, c->count, 0);
+ CuAssertIntEquals(tc, d->count, 0);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_028(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "0B10110", "0b111001", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 0);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 22);
+ CuAssertIntEquals(tc, b->count, 1);
+ CuAssertIntEquals(tc, b->ival[0], 57);
+ CuAssertIntEquals(tc, c->count, 0);
+ CuAssertIntEquals(tc, d->count, 0);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_029(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "0b101001", "0b101", "0b00101010101", "-d", "0B110000011", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 0);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 41);
+ CuAssertIntEquals(tc, b->count, 1);
+ CuAssertIntEquals(tc, b->ival[0], 5);
+ CuAssertIntEquals(tc, c->count, 1);
+ CuAssertIntEquals(tc, c->ival[0], 341);
+ CuAssertIntEquals(tc, d->count, 1);
+ CuAssertIntEquals(tc, d->ival[0], 387);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_030(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "-d", "0b101", "-D0B11", "--delta", "0b11011", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 1);
+ CuAssertIntEquals(tc, a->count, 0);
+ CuAssertIntEquals(tc, b->count, 0);
+ CuAssertIntEquals(tc, c->count, 0);
+ CuAssertIntEquals(tc, d->count, 3);
+ CuAssertIntEquals(tc, d->ival[0], 5);
+ CuAssertIntEquals(tc, d->ival[1], 3);
+ CuAssertIntEquals(tc, d->ival[2], 27);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_031(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "11", "0x11", "0o11", "-D0b11", "--eps", "-0o50", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 0);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 11);
+ CuAssertIntEquals(tc, b->count, 1);
+ CuAssertIntEquals(tc, b->ival[0], 0x11);
+ CuAssertIntEquals(tc, c->count, 1);
+ CuAssertIntEquals(tc, c->ival[0], 011);
+ CuAssertIntEquals(tc, d->count, 1);
+ CuAssertIntEquals(tc, d->ival[0], 3);
+ CuAssertIntEquals(tc, e->count, 1);
+ CuAssertIntEquals(tc, e->ival[0], -050);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_032(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "1KB", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 0);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 1024);
+ CuAssertIntEquals(tc, b->count, 0);
+ CuAssertIntEquals(tc, c->count, 0);
+ CuAssertIntEquals(tc, d->count, 0);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_033(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "1MB", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 0);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 1024 * 1024);
+ CuAssertIntEquals(tc, b->count, 0);
+ CuAssertIntEquals(tc, c->count, 0);
+ CuAssertIntEquals(tc, d->count, 0);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_034(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "1GB", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 0);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 1024 * 1024 * 1024);
+ CuAssertIntEquals(tc, b->count, 0);
+ CuAssertIntEquals(tc, c->count, 0);
+ CuAssertIntEquals(tc, d->count, 0);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_035(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "0x5KB", "0xAMB", "0x1GB", "-d", "-0x40A01400", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 0);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 0x5 * 1024);
+ CuAssertIntEquals(tc, b->count, 1);
+ CuAssertIntEquals(tc, b->ival[0], 0xA * 1024 * 1024);
+ CuAssertIntEquals(tc, c->count, 1);
+ CuAssertIntEquals(tc, c->ival[0], 0x1 * 1024 * 1024 * 1024);
+ CuAssertIntEquals(tc, d->count, 1);
+ CuAssertIntEquals(tc, d->ival[0], -0x40A01400);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_036(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 1);
+ CuAssertIntEquals(tc, a->count, 0);
+ CuAssertIntEquals(tc, b->count, 0);
+ CuAssertIntEquals(tc, c->count, 0);
+ CuAssertIntEquals(tc, d->count, 0);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_037(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "1", "2", "3", "4", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 1);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 1);
+ CuAssertIntEquals(tc, b->count, 1);
+ CuAssertIntEquals(tc, b->ival[0], 2);
+ CuAssertIntEquals(tc, c->count, 1);
+ CuAssertIntEquals(tc, c->ival[0], 3);
+ CuAssertIntEquals(tc, d->count, 0);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_038(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "1", "2", "3", "-d1", "-d2", "-d3", "-d4", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 1);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 1);
+ CuAssertIntEquals(tc, b->count, 1);
+ CuAssertIntEquals(tc, b->ival[0], 2);
+ CuAssertIntEquals(tc, c->count, 1);
+ CuAssertIntEquals(tc, c->ival[0], 3);
+ CuAssertIntEquals(tc, d->count, 3);
+ CuAssertIntEquals(tc, d->ival[0], 1);
+ CuAssertIntEquals(tc, d->ival[1], 2);
+ CuAssertIntEquals(tc, d->ival[2], 3);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_039(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "1", "2", "3", "-d1", "-d2", "-d3", "-d", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 1);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 1);
+ CuAssertIntEquals(tc, b->count, 1);
+ CuAssertIntEquals(tc, b->ival[0], 2);
+ CuAssertIntEquals(tc, c->count, 1);
+ CuAssertIntEquals(tc, c->ival[0], 3);
+ CuAssertIntEquals(tc, d->count, 3);
+ CuAssertIntEquals(tc, d->ival[0], 1);
+ CuAssertIntEquals(tc, d->ival[1], 2);
+ CuAssertIntEquals(tc, d->ival[2], 3);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_040(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "1", "2", "3", "-d1", "-d2", "-d", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 1);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 1);
+ CuAssertIntEquals(tc, b->count, 1);
+ CuAssertIntEquals(tc, b->ival[0], 2);
+ CuAssertIntEquals(tc, c->count, 1);
+ CuAssertIntEquals(tc, c->ival[0], 3);
+ CuAssertIntEquals(tc, d->count, 2);
+ CuAssertIntEquals(tc, d->ival[0], 1);
+ CuAssertIntEquals(tc, d->ival[1], 2);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_041(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "1", "2", "3", "-d1", "-d", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 1);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 1);
+ CuAssertIntEquals(tc, b->count, 1);
+ CuAssertIntEquals(tc, b->ival[0], 2);
+ CuAssertIntEquals(tc, c->count, 1);
+ CuAssertIntEquals(tc, c->ival[0], 3);
+ CuAssertIntEquals(tc, d->count, 1);
+ CuAssertIntEquals(tc, d->ival[0], 1);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_042(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "1", "2", "3", "-d", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 1);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 1);
+ CuAssertIntEquals(tc, b->count, 1);
+ CuAssertIntEquals(tc, b->ival[0], 2);
+ CuAssertIntEquals(tc, c->count, 1);
+ CuAssertIntEquals(tc, c->ival[0], 3);
+ CuAssertIntEquals(tc, d->count, 0);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_043(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "1", "2", "3", "--eps", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 1);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_044(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "1", "2", "3", "--eps", "3", "--eqn", "6", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 1);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 1);
+ CuAssertIntEquals(tc, b->count, 1);
+ CuAssertIntEquals(tc, b->ival[0], 2);
+ CuAssertIntEquals(tc, c->count, 1);
+ CuAssertIntEquals(tc, c->ival[0], 3);
+ CuAssertIntEquals(tc, d->count, 0);
+ CuAssertIntEquals(tc, e->count, 1);
+ CuAssertIntEquals(tc, e->ival[0], 3);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_045(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "hello", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 1);
+ CuAssertIntEquals(tc, a->count, 0);
+ CuAssertIntEquals(tc, b->count, 0);
+ CuAssertIntEquals(tc, c->count, 0);
+ CuAssertIntEquals(tc, d->count, 0);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_046(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "1.234", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 1);
+ CuAssertIntEquals(tc, a->count, 0);
+ CuAssertIntEquals(tc, b->count, 0);
+ CuAssertIntEquals(tc, c->count, 0);
+ CuAssertIntEquals(tc, d->count, 0);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_047(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "4", "hello", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 1);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 4);
+ CuAssertIntEquals(tc, b->count, 0);
+ CuAssertIntEquals(tc, c->count, 0);
+ CuAssertIntEquals(tc, d->count, 0);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_048(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "5", "1.234", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 1);
+ CuAssertIntEquals(tc, a->count, 1);
+ CuAssertIntEquals(tc, a->ival[0], 5);
+ CuAssertIntEquals(tc, b->count, 0);
+ CuAssertIntEquals(tc, c->count, 0);
+ CuAssertIntEquals(tc, d->count, 0);
+ CuAssertIntEquals(tc, e->count, 0);
+ CuAssertIntEquals(tc, f->count, 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_049(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "-f", "2", "--filler=", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 2);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_050(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "0x0g", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 1);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_051(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "0o08", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 1);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_052(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "0b02", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 1);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_053(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "1000GB", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 1);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argint_basic_054(CuTest* tc) {
+ struct arg_int* a = arg_int1(NULL, NULL, "a", "a is <int>");
+ struct arg_int* b = arg_int0(NULL, NULL, "b", "b is <int>");
+ struct arg_int* c = arg_int0(NULL, NULL, "c", "c is <int>");
+ struct arg_int* d = arg_intn("dD", "delta", "<int>", 0, 3, "d can occur 0..3 times");
+ struct arg_int* e = arg_int0(NULL, "eps,eqn", "<int>", "eps is optional");
+ struct arg_int* f = arg_intn("fF", "filler", "<int>", 0, 3, "f can occur 0..3 times");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, e, f, end};
+ int nerrors;
+ int i;
+
+ char* argv[] = {"program", "1GBH", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ /* allow missing argument values for the f argument, and set defaults to -1 */
+ f->hdr.flag |= ARG_HASOPTVALUE;
+ for (i = 0; i < f->hdr.maxcount; i++)
+ f->ival[i] = -1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertIntEquals(tc, nerrors, 1);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+CuSuite* get_argint_testsuite() {
+ CuSuite* suite = CuSuiteNew();
+ SUITE_ADD_TEST(suite, test_argint_basic_001);
+ SUITE_ADD_TEST(suite, test_argint_basic_002);
+ SUITE_ADD_TEST(suite, test_argint_basic_003);
+ SUITE_ADD_TEST(suite, test_argint_basic_004);
+ SUITE_ADD_TEST(suite, test_argint_basic_005);
+ SUITE_ADD_TEST(suite, test_argint_basic_006);
+ SUITE_ADD_TEST(suite, test_argint_basic_007);
+ SUITE_ADD_TEST(suite, test_argint_basic_008);
+ SUITE_ADD_TEST(suite, test_argint_basic_009);
+ SUITE_ADD_TEST(suite, test_argint_basic_010);
+ SUITE_ADD_TEST(suite, test_argint_basic_011);
+ SUITE_ADD_TEST(suite, test_argint_basic_012);
+ SUITE_ADD_TEST(suite, test_argint_basic_013);
+ SUITE_ADD_TEST(suite, test_argint_basic_014);
+ SUITE_ADD_TEST(suite, test_argint_basic_015);
+ SUITE_ADD_TEST(suite, test_argint_basic_016);
+ SUITE_ADD_TEST(suite, test_argint_basic_017);
+ SUITE_ADD_TEST(suite, test_argint_basic_018);
+ SUITE_ADD_TEST(suite, test_argint_basic_019);
+ SUITE_ADD_TEST(suite, test_argint_basic_020);
+ SUITE_ADD_TEST(suite, test_argint_basic_021);
+ SUITE_ADD_TEST(suite, test_argint_basic_022);
+ SUITE_ADD_TEST(suite, test_argint_basic_023);
+ SUITE_ADD_TEST(suite, test_argint_basic_024);
+ SUITE_ADD_TEST(suite, test_argint_basic_025);
+ SUITE_ADD_TEST(suite, test_argint_basic_026);
+ SUITE_ADD_TEST(suite, test_argint_basic_027);
+ SUITE_ADD_TEST(suite, test_argint_basic_028);
+ SUITE_ADD_TEST(suite, test_argint_basic_029);
+ SUITE_ADD_TEST(suite, test_argint_basic_030);
+ SUITE_ADD_TEST(suite, test_argint_basic_031);
+ SUITE_ADD_TEST(suite, test_argint_basic_032);
+ SUITE_ADD_TEST(suite, test_argint_basic_033);
+ SUITE_ADD_TEST(suite, test_argint_basic_034);
+ SUITE_ADD_TEST(suite, test_argint_basic_035);
+ SUITE_ADD_TEST(suite, test_argint_basic_036);
+ SUITE_ADD_TEST(suite, test_argint_basic_037);
+ SUITE_ADD_TEST(suite, test_argint_basic_038);
+ SUITE_ADD_TEST(suite, test_argint_basic_039);
+ SUITE_ADD_TEST(suite, test_argint_basic_040);
+ SUITE_ADD_TEST(suite, test_argint_basic_041);
+ SUITE_ADD_TEST(suite, test_argint_basic_042);
+ SUITE_ADD_TEST(suite, test_argint_basic_043);
+ SUITE_ADD_TEST(suite, test_argint_basic_044);
+ SUITE_ADD_TEST(suite, test_argint_basic_045);
+ SUITE_ADD_TEST(suite, test_argint_basic_046);
+ SUITE_ADD_TEST(suite, test_argint_basic_047);
+ SUITE_ADD_TEST(suite, test_argint_basic_048);
+ SUITE_ADD_TEST(suite, test_argint_basic_049);
+ SUITE_ADD_TEST(suite, test_argint_basic_050);
+ SUITE_ADD_TEST(suite, test_argint_basic_051);
+ SUITE_ADD_TEST(suite, test_argint_basic_052);
+ SUITE_ADD_TEST(suite, test_argint_basic_053);
+ SUITE_ADD_TEST(suite, test_argint_basic_054);
+ return suite;
+}
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
--- /dev/null
+/*******************************************************************************
+ * This file is part of the argtable3 library.
+ *
+ * Copyright (C) 2013-2019 Tom G. Huang
+ * <tomghuang@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of STEWART HEITMANN 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN 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.
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "CuTest.h"
+#include "argtable3.h"
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4204)
+#endif
+
+void test_arglit_basic_001(CuTest* tc) {
+ struct arg_lit* a = arg_lit0(NULL, "hello,world", "either --hello or --world or none");
+ struct arg_lit* b = arg_lit0("bB", NULL, "either -b or -B or none");
+ struct arg_lit* c = arg_lit1("cC", NULL, "either -c or -C");
+ struct arg_lit* d = arg_litn("dD", "delta", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_lit* help = arg_lit0(NULL, "help", "print this help and exit");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, help, end};
+ int nerrors;
+
+ char* argv[] = {"program", "--help", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 2);
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 0);
+ CuAssertTrue(tc, d->count == 0);
+ CuAssertTrue(tc, help->count == 1);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_arglit_basic_002(CuTest* tc) {
+ struct arg_lit* a = arg_lit0(NULL, "hello,world", "either --hello or --world or none");
+ struct arg_lit* b = arg_lit0("bB", NULL, "either -b or -B or none");
+ struct arg_lit* c = arg_lit1("cC", NULL, "either -c or -C");
+ struct arg_lit* d = arg_litn("dD", "delta", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_lit* help = arg_lit0(NULL, "help", "print this help and exit");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, help, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-cDd", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ if (nerrors > 0)
+ arg_print_errors(stdout, end, argv[0]);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertTrue(tc, d->count == 2);
+ CuAssertTrue(tc, help->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_arglit_basic_003(CuTest* tc) {
+ struct arg_lit* a = arg_lit0(NULL, "hello,world", "either --hello or --world or none");
+ struct arg_lit* b = arg_lit0("bB", NULL, "either -b or -B or none");
+ struct arg_lit* c = arg_lit1("cC", NULL, "either -c or -C");
+ struct arg_lit* d = arg_litn("dD", "delta", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_lit* help = arg_lit0(NULL, "help", "print this help and exit");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, help, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-cdDd", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ if (nerrors > 0)
+ arg_print_errors(stdout, end, argv[0]);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertTrue(tc, d->count == 3);
+ CuAssertTrue(tc, help->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_arglit_basic_004(CuTest* tc) {
+ struct arg_lit* a = arg_lit0(NULL, "hello,world", "either --hello or --world or none");
+ struct arg_lit* b = arg_lit0("bB", NULL, "either -b or -B or none");
+ struct arg_lit* c = arg_lit1("cC", NULL, "either -c or -C");
+ struct arg_lit* d = arg_litn("dD", "delta", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_lit* help = arg_lit0(NULL, "help", "print this help and exit");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, help, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-CDd", "--delta", "--delta", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ if (nerrors > 0)
+ arg_print_errors(stdout, end, argv[0]);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertTrue(tc, d->count == 4);
+ CuAssertTrue(tc, help->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_arglit_basic_005(CuTest* tc) {
+ struct arg_lit* a = arg_lit0(NULL, "hello,world", "either --hello or --world or none");
+ struct arg_lit* b = arg_lit0("bB", NULL, "either -b or -B or none");
+ struct arg_lit* c = arg_lit1("cC", NULL, "either -c or -C");
+ struct arg_lit* d = arg_litn("dD", "delta", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_lit* help = arg_lit0(NULL, "help", "print this help and exit");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, help, end};
+ int nerrors;
+
+ char* argv[] = {"program", "--delta", "-cD", "-b", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ if (nerrors > 0)
+ arg_print_errors(stdout, end, argv[0]);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 1);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertTrue(tc, d->count == 2);
+ CuAssertTrue(tc, help->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_arglit_basic_006(CuTest* tc) {
+ struct arg_lit* a = arg_lit0(NULL, "hello,world", "either --hello or --world or none");
+ struct arg_lit* b = arg_lit0("bB", NULL, "either -b or -B or none");
+ struct arg_lit* c = arg_lit1("cC", NULL, "either -c or -C");
+ struct arg_lit* d = arg_litn("dD", "delta", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_lit* help = arg_lit0(NULL, "help", "print this help and exit");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, help, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-D", "-B", "--delta", "-C", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ if (nerrors > 0)
+ arg_print_errors(stdout, end, argv[0]);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 1);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertTrue(tc, d->count == 2);
+ CuAssertTrue(tc, help->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_arglit_basic_007(CuTest* tc) {
+ struct arg_lit* a = arg_lit0(NULL, "hello,world", "either --hello or --world or none");
+ struct arg_lit* b = arg_lit0("bB", NULL, "either -b or -B or none");
+ struct arg_lit* c = arg_lit1("cC", NULL, "either -c or -C");
+ struct arg_lit* d = arg_litn("dD", "delta", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_lit* help = arg_lit0(NULL, "help", "print this help and exit");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, help, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-D", "-B", "--delta", "-C", "--hello", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ if (nerrors > 0)
+ arg_print_errors(stdout, end, argv[0]);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertTrue(tc, b->count == 1);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertTrue(tc, d->count == 2);
+ CuAssertTrue(tc, help->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_arglit_basic_008(CuTest* tc) {
+ struct arg_lit* a = arg_lit0(NULL, "hello,world", "either --hello or --world or none");
+ struct arg_lit* b = arg_lit0("bB", NULL, "either -b or -B or none");
+ struct arg_lit* c = arg_lit1("cC", NULL, "either -c or -C");
+ struct arg_lit* d = arg_litn("dD", "delta", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_lit* help = arg_lit0(NULL, "help", "print this help and exit");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, help, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-D", "-B", "--delta", "-C", "--world", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ if (nerrors > 0)
+ arg_print_errors(stdout, end, argv[0]);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertTrue(tc, b->count == 1);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertTrue(tc, d->count == 2);
+ CuAssertTrue(tc, help->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_arglit_basic_009(CuTest* tc) {
+ struct arg_lit* a = arg_lit0(NULL, "hello,world", "either --hello or --world or none");
+ struct arg_lit* b = arg_lit0("bB", NULL, "either -b or -B or none");
+ struct arg_lit* c = arg_lit1("cC", NULL, "either -c or -C");
+ struct arg_lit* d = arg_litn("dD", "delta", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_lit* help = arg_lit0(NULL, "help", "print this help and exit");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, help, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-c", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 1);
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertTrue(tc, d->count == 0);
+ CuAssertTrue(tc, help->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_arglit_basic_010(CuTest* tc) {
+ struct arg_lit* a = arg_lit0(NULL, "hello,world", "either --hello or --world or none");
+ struct arg_lit* b = arg_lit0("bB", NULL, "either -b or -B or none");
+ struct arg_lit* c = arg_lit1("cC", NULL, "either -c or -C");
+ struct arg_lit* d = arg_litn("dD", "delta", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_lit* help = arg_lit0(NULL, "help", "print this help and exit");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, help, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-D", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 2);
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 0);
+ CuAssertTrue(tc, d->count == 1);
+ CuAssertTrue(tc, help->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_arglit_basic_011(CuTest* tc) {
+ struct arg_lit* a = arg_lit0(NULL, "hello,world", "either --hello or --world or none");
+ struct arg_lit* b = arg_lit0("bB", NULL, "either -b or -B or none");
+ struct arg_lit* c = arg_lit1("cC", NULL, "either -c or -C");
+ struct arg_lit* d = arg_litn("dD", "delta", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_lit* help = arg_lit0(NULL, "help", "print this help and exit");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, help, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-CD", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 1);
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertTrue(tc, d->count == 1);
+ CuAssertTrue(tc, help->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_arglit_basic_012(CuTest* tc) {
+ struct arg_lit* a = arg_lit0(NULL, "hello,world", "either --hello or --world or none");
+ struct arg_lit* b = arg_lit0("bB", NULL, "either -b or -B or none");
+ struct arg_lit* c = arg_lit1("cC", NULL, "either -c or -C");
+ struct arg_lit* d = arg_litn("dD", "delta", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_lit* help = arg_lit0(NULL, "help", "print this help and exit");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, help, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-Dd", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 1);
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 0);
+ CuAssertTrue(tc, d->count == 2);
+ CuAssertTrue(tc, help->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_arglit_basic_013(CuTest* tc) {
+ struct arg_lit* a = arg_lit0(NULL, "hello,world", "either --hello or --world or none");
+ struct arg_lit* b = arg_lit0("bB", NULL, "either -b or -B or none");
+ struct arg_lit* c = arg_lit1("cC", NULL, "either -c or -C");
+ struct arg_lit* d = arg_litn("dD", "delta", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_lit* help = arg_lit0(NULL, "help", "print this help and exit");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, help, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-cddddd", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 1);
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertTrue(tc, d->count == 4);
+ CuAssertTrue(tc, help->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_arglit_basic_014(CuTest* tc) {
+ struct arg_lit* a = arg_lit0(NULL, "hello,world", "either --hello or --world or none");
+ struct arg_lit* b = arg_lit0("bB", NULL, "either -b or -B or none");
+ struct arg_lit* c = arg_lit1("cC", NULL, "either -c or -C");
+ struct arg_lit* d = arg_litn("dD", "delta", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_lit* help = arg_lit0(NULL, "help", "print this help and exit");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, help, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-ccddd", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 1);
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertTrue(tc, d->count == 3);
+ CuAssertTrue(tc, help->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_arglit_basic_015(CuTest* tc) {
+ struct arg_lit* a = arg_lit0(NULL, "hello,world", "either --hello or --world or none");
+ struct arg_lit* b = arg_lit0("bB", NULL, "either -b or -B or none");
+ struct arg_lit* c = arg_lit1("cC", NULL, "either -c or -C");
+ struct arg_lit* d = arg_litn("dD", "delta", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_lit* help = arg_lit0(NULL, "help", "print this help and exit");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, help, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-C", "-d", "-D", "--delta", "-b", "-B", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 1);
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 1);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertTrue(tc, d->count == 3);
+ CuAssertTrue(tc, help->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_arglit_basic_016(CuTest* tc) {
+ struct arg_lit* a = arg_lit0(NULL, "hello,world", "either --hello or --world or none");
+ struct arg_lit* b = arg_lit0("bB", NULL, "either -b or -B or none");
+ struct arg_lit* c = arg_lit1("cC", NULL, "either -c or -C");
+ struct arg_lit* d = arg_litn("dD", "delta", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_lit* help = arg_lit0(NULL, "help", "print this help and exit");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, help, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-C", "-d", "-D", "--delta", "--hello", "--world", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 1);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertTrue(tc, d->count == 3);
+ CuAssertTrue(tc, help->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_arglit_basic_017(CuTest* tc) {
+ struct arg_lit* a = arg_lit0(NULL, "hello,world", "either --hello or --world or none");
+ struct arg_lit* b = arg_lit0("bB", NULL, "either -b or -B or none");
+ struct arg_lit* c = arg_lit1("cC", NULL, "either -c or -C");
+ struct arg_lit* d = arg_litn("dD", "delta", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_lit* help = arg_lit0(NULL, "help", "print this help and exit");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, help, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-C", "-d", "-D", "--delta", "--hello", "X", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 1);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertTrue(tc, d->count == 3);
+ CuAssertTrue(tc, help->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+CuSuite* get_arglit_testsuite() {
+ CuSuite* suite = CuSuiteNew();
+ SUITE_ADD_TEST(suite, test_arglit_basic_001);
+ SUITE_ADD_TEST(suite, test_arglit_basic_002);
+ SUITE_ADD_TEST(suite, test_arglit_basic_003);
+ SUITE_ADD_TEST(suite, test_arglit_basic_004);
+ SUITE_ADD_TEST(suite, test_arglit_basic_005);
+ SUITE_ADD_TEST(suite, test_arglit_basic_006);
+ SUITE_ADD_TEST(suite, test_arglit_basic_007);
+ SUITE_ADD_TEST(suite, test_arglit_basic_008);
+ SUITE_ADD_TEST(suite, test_arglit_basic_009);
+ SUITE_ADD_TEST(suite, test_arglit_basic_010);
+ SUITE_ADD_TEST(suite, test_arglit_basic_011);
+ SUITE_ADD_TEST(suite, test_arglit_basic_012);
+ SUITE_ADD_TEST(suite, test_arglit_basic_013);
+ SUITE_ADD_TEST(suite, test_arglit_basic_014);
+ SUITE_ADD_TEST(suite, test_arglit_basic_015);
+ SUITE_ADD_TEST(suite, test_arglit_basic_016);
+ SUITE_ADD_TEST(suite, test_arglit_basic_017);
+ return suite;
+}
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
--- /dev/null
+/*******************************************************************************
+ * This file is part of the argtable3 library.
+ *
+ * Copyright (C) 2013-2019 Tom G. Huang
+ * <tomghuang@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of STEWART HEITMANN 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN 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.
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "CuTest.h"
+#include "argtable3.h"
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4204)
+#endif
+
+void test_argrex_basic_001(CuTest* tc) {
+ struct arg_rex* a = arg_rex0("a", NULL, "hello", NULL, 0, "blah blah");
+ struct arg_rex* b = arg_rex1(NULL, "beta", "[Ww]orld", NULL, 0, "blah blah");
+ struct arg_rex* c = arg_rexn(NULL, NULL, "goodbye", NULL, 1, 5, ARG_REX_ICASE, "blah blah");
+ struct arg_rex* d = arg_rex0(NULL, NULL, "any.*", NULL, ARG_REX_ICASE, "blah blah");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, end};
+ int nerrors;
+
+ char* argv[] = {"program", "--beta", "world", "goodbye", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 0);
+
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 1);
+ CuAssertStrEquals(tc, b->sval[0], "world");
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertStrEquals(tc, c->sval[0], "goodbye");
+ CuAssertTrue(tc, d->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argrex_basic_002(CuTest* tc) {
+ struct arg_rex* a = arg_rex0("a", NULL, "hello", NULL, 0, "blah blah");
+ struct arg_rex* b = arg_rex1(NULL, "beta", "[Ww]orld", NULL, 0, "blah blah");
+ struct arg_rex* c = arg_rexn(NULL, NULL, "goodbye", NULL, 1, 5, ARG_REX_ICASE, "blah blah");
+ struct arg_rex* d = arg_rex0(NULL, NULL, "any.*", NULL, ARG_REX_ICASE, "blah blah");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, end};
+ int nerrors;
+
+ char* argv[] = {"program", "GoodBye", "--beta", "World", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 0);
+
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 1);
+ CuAssertStrEquals(tc, b->sval[0], "World");
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertStrEquals(tc, c->sval[0], "GoodBye");
+ CuAssertTrue(tc, d->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argrex_basic_003(CuTest* tc) {
+ struct arg_rex* a = arg_rex0("a", NULL, "hello", NULL, 0, "blah blah");
+ struct arg_rex* b = arg_rex1(NULL, "beta", "[Ww]orld", NULL, 0, "blah blah");
+ struct arg_rex* c = arg_rexn(NULL, NULL, "goodbye", NULL, 1, 5, ARG_REX_ICASE, "blah blah");
+ struct arg_rex* d = arg_rex0(NULL, NULL, "any.*", NULL, ARG_REX_ICASE, "blah blah");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, end};
+ int nerrors;
+
+ char* argv[] = {"program", "--beta", "world", "GOODBYE", "GoodBye", "gOoDbyE", "Anything", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 0);
+
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 1);
+ CuAssertStrEquals(tc, b->sval[0], "world");
+ CuAssertTrue(tc, c->count == 3);
+ CuAssertStrEquals(tc, c->sval[0], "GOODBYE");
+ CuAssertStrEquals(tc, c->sval[1], "GoodBye");
+ CuAssertStrEquals(tc, c->sval[2], "gOoDbyE");
+ CuAssertTrue(tc, d->count == 1);
+ CuAssertStrEquals(tc, d->sval[0], "Anything");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argrex_basic_004(CuTest* tc) {
+ struct arg_rex* a = arg_rex0("a", NULL, "hello", NULL, 0, "blah blah");
+ struct arg_rex* b = arg_rex1(NULL, "beta", "[Ww]orld", NULL, 0, "blah blah");
+ struct arg_rex* c = arg_rexn(NULL, NULL, "goodbye", NULL, 1, 5, ARG_REX_ICASE, "blah blah");
+ struct arg_rex* d = arg_rex0(NULL, NULL, "any.*", NULL, ARG_REX_ICASE, "blah blah");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, end};
+ int nerrors;
+
+ char* argv[] = {"program", "--beta", "world", "GOODBYE", "AnyHow", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 0);
+
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 1);
+ CuAssertStrEquals(tc, b->sval[0], "world");
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertStrEquals(tc, c->sval[0], "GOODBYE");
+ CuAssertTrue(tc, d->count == 1);
+ CuAssertStrEquals(tc, d->sval[0], "AnyHow");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argrex_basic_005(CuTest* tc) {
+ struct arg_rex* a = arg_rex0("a", NULL, "hello", NULL, 0, "blah blah");
+ struct arg_rex* b = arg_rex1(NULL, "beta", "[Ww]orld", NULL, 0, "blah blah");
+ struct arg_rex* c = arg_rexn(NULL, NULL, "goodbye", NULL, 1, 5, ARG_REX_ICASE, "blah blah");
+ struct arg_rex* d = arg_rex0(NULL, NULL, "any.*", NULL, ARG_REX_ICASE, "blah blah");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-a", "hello", "--beta", "world", "GOODBYE", "AnyHow", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 0);
+
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->sval[0], "hello");
+ CuAssertTrue(tc, b->count == 1);
+ CuAssertStrEquals(tc, b->sval[0], "world");
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertStrEquals(tc, c->sval[0], "GOODBYE");
+ CuAssertTrue(tc, d->count == 1);
+ CuAssertStrEquals(tc, d->sval[0], "AnyHow");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argrex_basic_006(CuTest* tc) {
+ struct arg_rex* a = arg_rex0("a", NULL, "hello", NULL, 0, "blah blah");
+ struct arg_rex* b = arg_rex1(NULL, "beta", "[Ww]orld", NULL, 0, "blah blah");
+ struct arg_rex* c = arg_rexn(NULL, NULL, "goodbye", NULL, 1, 5, ARG_REX_ICASE, "blah blah");
+ struct arg_rex* d = arg_rex0(NULL, NULL, "any.*", NULL, ARG_REX_ICASE, "blah blah");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, end};
+ int nerrors;
+
+ char* argv[] = {"program", "--beta", "WORLD", "goodbye", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 1);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argrex_basic_007(CuTest* tc) {
+ struct arg_rex* a = arg_rex0("a", NULL, "hello", NULL, 0, "blah blah");
+ struct arg_rex* b = arg_rex1(NULL, "beta", "[Ww]orld", NULL, 0, "blah blah");
+ struct arg_rex* c = arg_rexn(NULL, NULL, "goodbye", NULL, 1, 5, ARG_REX_ICASE, "blah blah");
+ struct arg_rex* d = arg_rex0(NULL, NULL, "any.*", NULL, ARG_REX_ICASE, "blah blah");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, end};
+ int nerrors;
+
+ char* argv[] = {"program", "--beta", "World", "goodby", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 1);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argrex_basic_008(CuTest* tc) {
+ struct arg_rex* a = arg_rex0("a", NULL, "hello", NULL, 0, "blah blah");
+ struct arg_rex* b = arg_rex1(NULL, "beta", "[Ww]orld", NULL, 0, "blah blah");
+ struct arg_rex* c = arg_rexn(NULL, NULL, "goodbye", NULL, 1, 5, ARG_REX_ICASE, "blah blah");
+ struct arg_rex* d = arg_rex0(NULL, NULL, "any.*", NULL, ARG_REX_ICASE, "blah blah");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, end};
+ int nerrors;
+
+ char* argv[] = {"program", "--beta", "world", "GoodBye", "Goodbye", "gOoDbyE", "Anything", "goodbye", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 1);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argrex_basic_009(CuTest* tc) {
+ struct arg_rex* a = arg_rex0("a", NULL, "hello", NULL, 0, "blah blah");
+ struct arg_rex* b = arg_rex1(NULL, "beta", "[Ww]orld", NULL, 0, "blah blah");
+ struct arg_rex* c = arg_rexn(NULL, NULL, "goodbye", NULL, 1, 5, ARG_REX_ICASE, "blah blah");
+ struct arg_rex* d = arg_rex0(NULL, NULL, "any.*", NULL, ARG_REX_ICASE, "blah blah");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, end};
+ int nerrors;
+
+ char* argv[] = {"program", "--beta", "world", "GoodBye", "Goodbye", "gOoDbyE", "Anything", "Anytime", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 1);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argrex_basic_010(CuTest* tc) {
+ struct arg_rex* a = arg_rex0("a", NULL, "hello", NULL, 0, "blah blah");
+ struct arg_rex* b = arg_rex1(NULL, "beta", "[Ww]orld", NULL, 0, "blah blah");
+ struct arg_rex* c = arg_rexn(NULL, NULL, "goodbye", NULL, 1, 5, ARG_REX_ICASE, "blah blah");
+ struct arg_rex* d = arg_rex0(NULL, NULL, "any.*", NULL, ARG_REX_ICASE, "blah blah");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, end};
+ int nerrors;
+
+ char* argv[] = {"program", "--beta", "world", "GoodBye", "Goodbye", "Anything", "-a", "Hello", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ CuAssertTrue(tc, nerrors == 1);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+CuSuite* get_argrex_testsuite() {
+ CuSuite* suite = CuSuiteNew();
+ SUITE_ADD_TEST(suite, test_argrex_basic_001);
+ SUITE_ADD_TEST(suite, test_argrex_basic_002);
+ SUITE_ADD_TEST(suite, test_argrex_basic_003);
+ SUITE_ADD_TEST(suite, test_argrex_basic_004);
+ SUITE_ADD_TEST(suite, test_argrex_basic_005);
+ SUITE_ADD_TEST(suite, test_argrex_basic_006);
+ SUITE_ADD_TEST(suite, test_argrex_basic_007);
+ SUITE_ADD_TEST(suite, test_argrex_basic_008);
+ SUITE_ADD_TEST(suite, test_argrex_basic_009);
+ SUITE_ADD_TEST(suite, test_argrex_basic_010);
+ return suite;
+}
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
--- /dev/null
+/*******************************************************************************
+ * This file is part of the argtable3 library.
+ *
+ * Copyright (C) 2013-2019 Tom G. Huang
+ * <tomghuang@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of STEWART HEITMANN 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN 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.
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "CuTest.h"
+#include "argtable3.h"
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4204)
+#endif
+
+void test_argstr_basic_001(CuTest* tc) {
+ struct arg_str* a = arg_str0(NULL, "hello,world", "STRVAL", "either --hello or --world or none");
+ struct arg_str* b = arg_str0("bB", NULL, "STRVAL", "either -b or -B or none");
+ struct arg_str* c = arg_str1("cC", NULL, "STRVAL", "either -c or -C");
+ struct arg_str* d = arg_strn("dD", "delta", "STRVAL", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, end};
+ int nerrors;
+
+ char* argv[] = {"program", "--hello=string1", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 2);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->sval[0], "string1");
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 0);
+ CuAssertTrue(tc, d->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argstr_basic_002(CuTest* tc) {
+ struct arg_str* a = arg_str0(NULL, "hello,world", "STRVAL", "either --hello or --world or none");
+ struct arg_str* b = arg_str0("bB", NULL, "STRVAL", "either -b or -B or none");
+ struct arg_str* c = arg_str1("cC", NULL, "STRVAL", "either -c or -C");
+ struct arg_str* d = arg_strn("dD", "delta", "STRVAL", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-cstring1", "-Dstring2", "-dstring3", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ if (nerrors > 0)
+ arg_print_errors(stdout, end, argv[0]);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertStrEquals(tc, c->sval[0], "string1");
+ CuAssertTrue(tc, d->count == 2);
+ CuAssertStrEquals(tc, d->sval[0], "string2");
+ CuAssertStrEquals(tc, d->sval[1], "string3");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argstr_basic_003(CuTest* tc) {
+ struct arg_str* a = arg_str0(NULL, "hello,world", "STRVAL", "either --hello or --world or none");
+ struct arg_str* b = arg_str0("bB", NULL, "STRVAL", "either -b or -B or none");
+ struct arg_str* c = arg_str1("cC", NULL, "STRVAL", "either -c or -C");
+ struct arg_str* d = arg_strn("dD", "delta", "STRVAL", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-Cstring1", "--delta=string2", "--delta=string3", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ if (nerrors > 0)
+ arg_print_errors(stdout, end, argv[0]);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertStrEquals(tc, c->sval[0], "string1");
+ CuAssertTrue(tc, d->count == 2);
+ CuAssertStrEquals(tc, d->sval[0], "string2");
+ CuAssertStrEquals(tc, d->sval[1], "string3");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argstr_basic_004(CuTest* tc) {
+ struct arg_str* a = arg_str0(NULL, "hello,world", "STRVAL", "either --hello or --world or none");
+ struct arg_str* b = arg_str0("bB", NULL, "STRVAL", "either -b or -B or none");
+ struct arg_str* c = arg_str1("cC", NULL, "STRVAL", "either -c or -C");
+ struct arg_str* d = arg_strn("dD", "delta", "STRVAL", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, end};
+ int nerrors;
+
+ char* argv[] = {"program", "--delta=string1", "-cstring2", "-Dstring3", "-bstring4", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ if (nerrors > 0)
+ arg_print_errors(stdout, end, argv[0]);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 1);
+ CuAssertStrEquals(tc, b->sval[0], "string4");
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertStrEquals(tc, c->sval[0], "string2");
+ CuAssertTrue(tc, d->count == 2);
+ CuAssertStrEquals(tc, d->sval[0], "string1");
+ CuAssertStrEquals(tc, d->sval[1], "string3");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argstr_basic_005(CuTest* tc) {
+ struct arg_str* a = arg_str0(NULL, "hello,world", "STRVAL", "either --hello or --world or none");
+ struct arg_str* b = arg_str0("bB", NULL, "STRVAL", "either -b or -B or none");
+ struct arg_str* c = arg_str1("cC", NULL, "STRVAL", "either -c or -C");
+ struct arg_str* d = arg_strn("dD", "delta", "STRVAL", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-Dstring1", "-Bstring2", "--delta=string3", "-Cstring4", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ if (nerrors > 0)
+ arg_print_errors(stdout, end, argv[0]);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 1);
+ CuAssertStrEquals(tc, b->sval[0], "string2");
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertStrEquals(tc, c->sval[0], "string4");
+ CuAssertTrue(tc, d->count == 2);
+ CuAssertStrEquals(tc, d->sval[0], "string1");
+ CuAssertStrEquals(tc, d->sval[1], "string3");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argstr_basic_006(CuTest* tc) {
+ struct arg_str* a = arg_str0(NULL, "hello,world", "STRVAL", "either --hello or --world or none");
+ struct arg_str* b = arg_str0("bB", NULL, "STRVAL", "either -b or -B or none");
+ struct arg_str* c = arg_str1("cC", NULL, "STRVAL", "either -c or -C");
+ struct arg_str* d = arg_strn("dD", "delta", "STRVAL", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-Dstring1", "-Bstring2", "--delta=string3", "-Cstring4", "--hello=string5", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ if (nerrors > 0)
+ arg_print_errors(stdout, end, argv[0]);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->sval[0], "string5");
+ CuAssertTrue(tc, b->count == 1);
+ CuAssertStrEquals(tc, b->sval[0], "string2");
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertStrEquals(tc, c->sval[0], "string4");
+ CuAssertTrue(tc, d->count == 2);
+ CuAssertStrEquals(tc, d->sval[0], "string1");
+ CuAssertStrEquals(tc, d->sval[1], "string3");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argstr_basic_007(CuTest* tc) {
+ struct arg_str* a = arg_str0(NULL, "hello,world", "STRVAL", "either --hello or --world or none");
+ struct arg_str* b = arg_str0("bB", NULL, "STRVAL", "either -b or -B or none");
+ struct arg_str* c = arg_str1("cC", NULL, "STRVAL", "either -c or -C");
+ struct arg_str* d = arg_strn("dD", "delta", "STRVAL", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-Dstring1", "-Bstring2", "--delta=string3", "-Cstring4", "--world=string5", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+ if (nerrors > 0)
+ arg_print_errors(stdout, end, argv[0]);
+
+ CuAssertTrue(tc, nerrors == 0);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->sval[0], "string5");
+ CuAssertTrue(tc, b->count == 1);
+ CuAssertStrEquals(tc, b->sval[0], "string2");
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertStrEquals(tc, c->sval[0], "string4");
+ CuAssertTrue(tc, d->count == 2);
+ CuAssertStrEquals(tc, d->sval[0], "string1");
+ CuAssertStrEquals(tc, d->sval[1], "string3");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argstr_basic_008(CuTest* tc) {
+ struct arg_str* a = arg_str0(NULL, "hello,world", "STRVAL", "either --hello or --world or none");
+ struct arg_str* b = arg_str0("bB", NULL, "STRVAL", "either -b or -B or none");
+ struct arg_str* c = arg_str1("cC", NULL, "STRVAL", "either -c or -C");
+ struct arg_str* d = arg_strn("dD", "delta", "STRVAL", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-cstring1", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 1);
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertStrEquals(tc, c->sval[0], "string1");
+ CuAssertTrue(tc, d->count == 0);
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argstr_basic_009(CuTest* tc) {
+ struct arg_str* a = arg_str0(NULL, "hello,world", "STRVAL", "either --hello or --world or none");
+ struct arg_str* b = arg_str0("bB", NULL, "STRVAL", "either -b or -B or none");
+ struct arg_str* c = arg_str1("cC", NULL, "STRVAL", "either -c or -C");
+ struct arg_str* d = arg_strn("dD", "delta", "STRVAL", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-Dstring1", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 2);
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 0);
+ CuAssertTrue(tc, d->count == 1);
+ CuAssertStrEquals(tc, d->sval[0], "string1");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argstr_basic_010(CuTest* tc) {
+ struct arg_str* a = arg_str0(NULL, "hello,world", "STRVAL", "either --hello or --world or none");
+ struct arg_str* b = arg_str0("bB", NULL, "STRVAL", "either -b or -B or none");
+ struct arg_str* c = arg_str1("cC", NULL, "STRVAL", "either -c or -C");
+ struct arg_str* d = arg_strn("dD", "delta", "STRVAL", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-Cstring1", "-Dstring2", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 1);
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertStrEquals(tc, c->sval[0], "string1");
+ CuAssertTrue(tc, d->count == 1);
+ CuAssertStrEquals(tc, d->sval[0], "string2");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argstr_basic_011(CuTest* tc) {
+ struct arg_str* a = arg_str0(NULL, "hello,world", "STRVAL", "either --hello or --world or none");
+ struct arg_str* b = arg_str0("bB", NULL, "STRVAL", "either -b or -B or none");
+ struct arg_str* c = arg_str1("cC", NULL, "STRVAL", "either -c or -C");
+ struct arg_str* d = arg_strn("dD", "delta", "STRVAL", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-Dstring1", "-dstring2", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 1);
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 0);
+ CuAssertTrue(tc, d->count == 2);
+ CuAssertStrEquals(tc, d->sval[0], "string1");
+ CuAssertStrEquals(tc, d->sval[1], "string2");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argstr_basic_012(CuTest* tc) {
+ struct arg_str* a = arg_str0(NULL, "hello,world", "STRVAL", "either --hello or --world or none");
+ struct arg_str* b = arg_str0("bB", NULL, "STRVAL", "either -b or -B or none");
+ struct arg_str* c = arg_str1("cC", NULL, "STRVAL", "either -c or -C");
+ struct arg_str* d = arg_strn("dD", "delta", "STRVAL", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-cs1", "-ds2", "-ds3", "-ds4", "-ds5", "-ds6", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 1);
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertStrEquals(tc, c->sval[0], "s1");
+ CuAssertTrue(tc, d->count == 4);
+ CuAssertStrEquals(tc, d->sval[0], "s2");
+ CuAssertStrEquals(tc, d->sval[1], "s3");
+ CuAssertStrEquals(tc, d->sval[2], "s4");
+ CuAssertStrEquals(tc, d->sval[3], "s5");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argstr_basic_013(CuTest* tc) {
+ struct arg_str* a = arg_str0(NULL, "hello,world", "STRVAL", "either --hello or --world or none");
+ struct arg_str* b = arg_str0("bB", NULL, "STRVAL", "either -b or -B or none");
+ struct arg_str* c = arg_str1("cC", NULL, "STRVAL", "either -c or -C");
+ struct arg_str* d = arg_strn("dD", "delta", "STRVAL", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-cs1", "-cs2", "-ds3", "-ds4", "-ds5", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 1);
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertStrEquals(tc, c->sval[0], "s1");
+ CuAssertTrue(tc, d->count == 3);
+ CuAssertStrEquals(tc, d->sval[0], "s3");
+ CuAssertStrEquals(tc, d->sval[1], "s4");
+ CuAssertStrEquals(tc, d->sval[2], "s5");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argstr_basic_014(CuTest* tc) {
+ struct arg_str* a = arg_str0(NULL, "hello,world", "STRVAL", "either --hello or --world or none");
+ struct arg_str* b = arg_str0("bB", NULL, "STRVAL", "either -b or -B or none");
+ struct arg_str* c = arg_str1("cC", NULL, "STRVAL", "either -c or -C");
+ struct arg_str* d = arg_strn("dD", "delta", "STRVAL", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-Cs1", "-ds2", "-Ds3", "--delta=s4", "-bs5", "-Bs6", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 1);
+ CuAssertTrue(tc, a->count == 0);
+ CuAssertTrue(tc, b->count == 1);
+ CuAssertStrEquals(tc, b->sval[0], "s5");
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertStrEquals(tc, c->sval[0], "s1");
+ CuAssertTrue(tc, d->count == 3);
+ CuAssertStrEquals(tc, d->sval[0], "s2");
+ CuAssertStrEquals(tc, d->sval[1], "s3");
+ CuAssertStrEquals(tc, d->sval[2], "s4");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argstr_basic_015(CuTest* tc) {
+ struct arg_str* a = arg_str0(NULL, "hello,world", "STRVAL", "either --hello or --world or none");
+ struct arg_str* b = arg_str0("bB", NULL, "STRVAL", "either -b or -B or none");
+ struct arg_str* c = arg_str1("cC", NULL, "STRVAL", "either -c or -C");
+ struct arg_str* d = arg_strn("dD", "delta", "STRVAL", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-Cs1", "-ds2", "-Ds3", "--delta=s4", "--hello=s5", "--world=s6", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 1);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->sval[0], "s5");
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertStrEquals(tc, c->sval[0], "s1");
+ CuAssertTrue(tc, d->count == 3);
+ CuAssertStrEquals(tc, d->sval[0], "s2");
+ CuAssertStrEquals(tc, d->sval[1], "s3");
+ CuAssertStrEquals(tc, d->sval[2], "s4");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+void test_argstr_basic_016(CuTest* tc) {
+ struct arg_str* a = arg_str0(NULL, "hello,world", "STRVAL", "either --hello or --world or none");
+ struct arg_str* b = arg_str0("bB", NULL, "STRVAL", "either -b or -B or none");
+ struct arg_str* c = arg_str1("cC", NULL, "STRVAL", "either -c or -C");
+ struct arg_str* d = arg_strn("dD", "delta", "STRVAL", 2, 4, "-d|-D|--delta 2..4 occurences");
+ struct arg_end* end = arg_end(20);
+ void* argtable[] = {a, b, c, d, end};
+ int nerrors;
+
+ char* argv[] = {"program", "-Cs1", "-ds2", "-Ds3", "--delta=s4", "--hello=s5", "X", NULL};
+ int argc = sizeof(argv) / sizeof(char*) - 1;
+
+ CuAssertTrue(tc, arg_nullcheck(argtable) == 0);
+
+ nerrors = arg_parse(argc, argv, argtable);
+
+ CuAssertTrue(tc, nerrors == 1);
+ CuAssertTrue(tc, a->count == 1);
+ CuAssertStrEquals(tc, a->sval[0], "s5");
+ CuAssertTrue(tc, b->count == 0);
+ CuAssertTrue(tc, c->count == 1);
+ CuAssertStrEquals(tc, c->sval[0], "s1");
+ CuAssertTrue(tc, d->count == 3);
+ CuAssertStrEquals(tc, d->sval[0], "s2");
+ CuAssertStrEquals(tc, d->sval[1], "s3");
+ CuAssertStrEquals(tc, d->sval[2], "s4");
+
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
+}
+
+CuSuite* get_argstr_testsuite() {
+ CuSuite* suite = CuSuiteNew();
+ SUITE_ADD_TEST(suite, test_argstr_basic_001);
+ SUITE_ADD_TEST(suite, test_argstr_basic_002);
+ SUITE_ADD_TEST(suite, test_argstr_basic_003);
+ SUITE_ADD_TEST(suite, test_argstr_basic_004);
+ SUITE_ADD_TEST(suite, test_argstr_basic_005);
+ SUITE_ADD_TEST(suite, test_argstr_basic_006);
+ SUITE_ADD_TEST(suite, test_argstr_basic_007);
+ SUITE_ADD_TEST(suite, test_argstr_basic_008);
+ SUITE_ADD_TEST(suite, test_argstr_basic_009);
+ SUITE_ADD_TEST(suite, test_argstr_basic_010);
+ SUITE_ADD_TEST(suite, test_argstr_basic_011);
+ SUITE_ADD_TEST(suite, test_argstr_basic_012);
+ SUITE_ADD_TEST(suite, test_argstr_basic_013);
+ SUITE_ADD_TEST(suite, test_argstr_basic_014);
+ SUITE_ADD_TEST(suite, test_argstr_basic_015);
+ SUITE_ADD_TEST(suite, test_argstr_basic_016);
+ return suite;
+}
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
--- /dev/null
+:: utf8filenamecheck Check if all the filenames in a fiven folder are UTF-8\r
+:: Copyright (C) 2023 Johannes 'Banana' Keßler\r
+:: \r
+:: This program is free software: you can redistribute it and/or modify\r
+:: it under the terms of the GNU General Public License as published by\r
+:: the Free Software Foundation, either version 3 of the License, or\r
+:: (at your option) any later version.\r
+:: \r
+:: This program is distributed in the hope that it will be useful,\r
+:: but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+:: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+:: GNU General Public License for more details.\r
+:: \r
+:: You should have received a copy of the GNU General Public License\r
+:: along with this program. If not, see <https://www.gnu.org/licenses/>.\r
+@echo off\r
+cls\r
+gcc -std=c99 -march=native -O3 -Wall -Iargtable/ -Isimdutf8check/ utf8filenamecheck.c argtable/argtable3.c -o bin/utf8filenamecheck.exe
\ No newline at end of file
--- /dev/null
+https://github.com/adamretter/utf8-validator-c\r
+https://stackoverflow.com/questions/1301402/example-invalid-utf8-string\r
+\r
+https://codeforwin.org/c-programming/c-program-to-list-all-files-in-a-directory-recursively\r
+https://man7.org/linux/man-pages/man3/nftw.3.html
\ No newline at end of file
--- /dev/null
+#ifndef SIMDUTF8CHECK_H
+#define SIMDUTF8CHECK_H
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <x86intrin.h>
+/*
+ * legal utf-8 byte sequence
+ * http://www.unicode.org/versions/Unicode6.0.0/ch03.pdf - page 94
+ *
+ * Code Points 1st 2s 3s 4s
+ * U+0000..U+007F 00..7F
+ * U+0080..U+07FF C2..DF 80..BF
+ * U+0800..U+0FFF E0 A0..BF 80..BF
+ * U+1000..U+CFFF E1..EC 80..BF 80..BF
+ * U+D000..U+D7FF ED 80..9F 80..BF
+ * U+E000..U+FFFF EE..EF 80..BF 80..BF
+ * U+10000..U+3FFFF F0 90..BF 80..BF 80..BF
+ * U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF
+ * U+100000..U+10FFFF F4 80..8F 80..BF 80..BF
+ *
+ */
+
+// all byte values must be no larger than 0xF4
+static inline void checkSmallerThan0xF4(__m128i current_bytes,
+ __m128i *has_error) {
+ // unsigned, saturates to 0 below max
+ *has_error = _mm_or_si128(*has_error,
+ _mm_subs_epu8(current_bytes, _mm_set1_epi8(0xF4)));
+}
+
+static inline __m128i continuationLengths(__m128i high_nibbles) {
+ return _mm_shuffle_epi8(
+ _mm_setr_epi8(1, 1, 1, 1, 1, 1, 1, 1, // 0xxx (ASCII)
+ 0, 0, 0, 0, // 10xx (continuation)
+ 2, 2, // 110x
+ 3, // 1110
+ 4), // 1111, next should be 0 (not checked here)
+ high_nibbles);
+}
+
+static inline __m128i carryContinuations(__m128i initial_lengths,
+ __m128i previous_carries) {
+
+ __m128i right1 =
+ _mm_subs_epu8(_mm_alignr_epi8(initial_lengths, previous_carries, 16 - 1),
+ _mm_set1_epi8(1));
+ __m128i sum = _mm_add_epi8(initial_lengths, right1);
+
+ __m128i right2 = _mm_subs_epu8(_mm_alignr_epi8(sum, previous_carries, 16 - 2),
+ _mm_set1_epi8(2));
+ return _mm_add_epi8(sum, right2);
+}
+
+static inline void checkContinuations(__m128i initial_lengths, __m128i carries,
+ __m128i *has_error) {
+
+ // overlap || underlap
+ // carry > length && length > 0 || !(carry > length) && !(length > 0)
+ // (carries > length) == (lengths > 0)
+ __m128i overunder =
+ _mm_cmpeq_epi8(_mm_cmpgt_epi8(carries, initial_lengths),
+ _mm_cmpgt_epi8(initial_lengths, _mm_setzero_si128()));
+
+ *has_error = _mm_or_si128(*has_error, overunder);
+}
+
+// when 0xED is found, next byte must be no larger than 0x9F
+// when 0xF4 is found, next byte must be no larger than 0x8F
+// next byte must be continuation, ie sign bit is set, so signed < is ok
+static inline void checkFirstContinuationMax(__m128i current_bytes,
+ __m128i off1_current_bytes,
+ __m128i *has_error) {
+ __m128i maskED = _mm_cmpeq_epi8(off1_current_bytes, _mm_set1_epi8(0xED));
+ __m128i maskF4 = _mm_cmpeq_epi8(off1_current_bytes, _mm_set1_epi8(0xF4));
+
+ __m128i badfollowED =
+ _mm_and_si128(_mm_cmpgt_epi8(current_bytes, _mm_set1_epi8(0x9F)), maskED);
+ __m128i badfollowF4 =
+ _mm_and_si128(_mm_cmpgt_epi8(current_bytes, _mm_set1_epi8(0x8F)), maskF4);
+
+ *has_error = _mm_or_si128(*has_error, _mm_or_si128(badfollowED, badfollowF4));
+}
+
+// map off1_hibits => error condition
+// hibits off1 cur
+// C => < C2 && true
+// E => < E1 && < A0
+// F => < F1 && < 90
+// else false && false
+static inline void checkOverlong(__m128i current_bytes,
+ __m128i off1_current_bytes, __m128i hibits,
+ __m128i previous_hibits, __m128i *has_error) {
+ __m128i off1_hibits = _mm_alignr_epi8(hibits, previous_hibits, 16 - 1);
+ __m128i initial_mins = _mm_shuffle_epi8(
+ _mm_setr_epi8(-128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
+ -128, -128, // 10xx => false
+ 0xC2, -128, // 110x
+ 0xE1, // 1110
+ 0xF1),
+ off1_hibits);
+
+ __m128i initial_under = _mm_cmpgt_epi8(initial_mins, off1_current_bytes);
+
+ __m128i second_mins = _mm_shuffle_epi8(
+ _mm_setr_epi8(-128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
+ -128, -128, // 10xx => false
+ 127, 127, // 110x => true
+ 0xA0, // 1110
+ 0x90),
+ off1_hibits);
+ __m128i second_under = _mm_cmpgt_epi8(second_mins, current_bytes);
+ *has_error =
+ _mm_or_si128(*has_error, _mm_and_si128(initial_under, second_under));
+}
+
+struct processed_utf_bytes {
+ __m128i rawbytes;
+ __m128i high_nibbles;
+ __m128i carried_continuations;
+};
+
+static inline void count_nibbles(__m128i bytes,
+ struct processed_utf_bytes *answer) {
+ answer->rawbytes = bytes;
+ answer->high_nibbles =
+ _mm_and_si128(_mm_srli_epi16(bytes, 4), _mm_set1_epi8(0x0F));
+}
+
+// check whether the current bytes are valid UTF-8
+// at the end of the function, previous gets updated
+static struct processed_utf_bytes
+checkUTF8Bytes(__m128i current_bytes, struct processed_utf_bytes *previous,
+ __m128i *has_error) {
+ struct processed_utf_bytes pb;
+ count_nibbles(current_bytes, &pb);
+
+ checkSmallerThan0xF4(current_bytes, has_error);
+
+ __m128i initial_lengths = continuationLengths(pb.high_nibbles);
+
+ pb.carried_continuations =
+ carryContinuations(initial_lengths, previous->carried_continuations);
+
+ checkContinuations(initial_lengths, pb.carried_continuations, has_error);
+
+ __m128i off1_current_bytes =
+ _mm_alignr_epi8(pb.rawbytes, previous->rawbytes, 16 - 1);
+ checkFirstContinuationMax(current_bytes, off1_current_bytes, has_error);
+
+ checkOverlong(current_bytes, off1_current_bytes, pb.high_nibbles,
+ previous->high_nibbles, has_error);
+ return pb;
+}
+
+static bool validate_utf8_fast(const char *src, size_t len) {
+ size_t i = 0;
+ __m128i has_error = _mm_setzero_si128();
+ struct processed_utf_bytes previous = {.rawbytes = _mm_setzero_si128(),
+ .high_nibbles = _mm_setzero_si128(),
+ .carried_continuations =
+ _mm_setzero_si128()};
+ if (len >= 16) {
+ for (; i <= len - 16; i += 16) {
+ __m128i current_bytes = _mm_loadu_si128((const __m128i *)(src + i));
+ previous = checkUTF8Bytes(current_bytes, &previous, &has_error);
+ }
+ }
+
+ // last part
+ if (i < len) {
+ char buffer[16];
+ memset(buffer, 0, 16);
+ memcpy(buffer, src + i, len - i);
+ __m128i current_bytes = _mm_loadu_si128((const __m128i *)(buffer));
+ previous = checkUTF8Bytes(current_bytes, &previous, &has_error);
+ } else {
+ has_error =
+ _mm_or_si128(_mm_cmpgt_epi8(previous.carried_continuations,
+ _mm_setr_epi8(9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 1)),
+ has_error);
+ }
+
+ return _mm_testz_si128(has_error, has_error);
+}
+
+#ifdef __AVX2__
+
+/*****************************/
+static inline __m256i push_last_byte_of_a_to_b(__m256i a, __m256i b) {
+ return _mm256_alignr_epi8(b, _mm256_permute2x128_si256(a, b, 0x21), 15);
+}
+
+static inline __m256i push_last_2bytes_of_a_to_b(__m256i a, __m256i b) {
+ return _mm256_alignr_epi8(b, _mm256_permute2x128_si256(a, b, 0x21), 14);
+}
+
+// all byte values must be no larger than 0xF4
+static inline void avxcheckSmallerThan0xF4(__m256i current_bytes,
+ __m256i *has_error) {
+ // unsigned, saturates to 0 below max
+ *has_error = _mm256_or_si256(
+ *has_error, _mm256_subs_epu8(current_bytes, _mm256_set1_epi8(0xF4)));
+}
+
+static inline __m256i avxcontinuationLengths(__m256i high_nibbles) {
+ return _mm256_shuffle_epi8(
+ _mm256_setr_epi8(1, 1, 1, 1, 1, 1, 1, 1, // 0xxx (ASCII)
+ 0, 0, 0, 0, // 10xx (continuation)
+ 2, 2, // 110x
+ 3, // 1110
+ 4, // 1111, next should be 0 (not checked here)
+ 1, 1, 1, 1, 1, 1, 1, 1, // 0xxx (ASCII)
+ 0, 0, 0, 0, // 10xx (continuation)
+ 2, 2, // 110x
+ 3, // 1110
+ 4 // 1111, next should be 0 (not checked here)
+ ),
+ high_nibbles);
+}
+
+static inline __m256i avxcarryContinuations(__m256i initial_lengths,
+ __m256i previous_carries) {
+
+ __m256i right1 = _mm256_subs_epu8(
+ push_last_byte_of_a_to_b(previous_carries, initial_lengths),
+ _mm256_set1_epi8(1));
+ __m256i sum = _mm256_add_epi8(initial_lengths, right1);
+
+ __m256i right2 = _mm256_subs_epu8(
+ push_last_2bytes_of_a_to_b(previous_carries, sum), _mm256_set1_epi8(2));
+ return _mm256_add_epi8(sum, right2);
+}
+
+static inline void avxcheckContinuations(__m256i initial_lengths,
+ __m256i carries, __m256i *has_error) {
+
+ // overlap || underlap
+ // carry > length && length > 0 || !(carry > length) && !(length > 0)
+ // (carries > length) == (lengths > 0)
+ __m256i overunder = _mm256_cmpeq_epi8(
+ _mm256_cmpgt_epi8(carries, initial_lengths),
+ _mm256_cmpgt_epi8(initial_lengths, _mm256_setzero_si256()));
+
+ *has_error = _mm256_or_si256(*has_error, overunder);
+}
+
+// when 0xED is found, next byte must be no larger than 0x9F
+// when 0xF4 is found, next byte must be no larger than 0x8F
+// next byte must be continuation, ie sign bit is set, so signed < is ok
+static inline void avxcheckFirstContinuationMax(__m256i current_bytes,
+ __m256i off1_current_bytes,
+ __m256i *has_error) {
+ __m256i maskED =
+ _mm256_cmpeq_epi8(off1_current_bytes, _mm256_set1_epi8(0xED));
+ __m256i maskF4 =
+ _mm256_cmpeq_epi8(off1_current_bytes, _mm256_set1_epi8(0xF4));
+
+ __m256i badfollowED = _mm256_and_si256(
+ _mm256_cmpgt_epi8(current_bytes, _mm256_set1_epi8(0x9F)), maskED);
+ __m256i badfollowF4 = _mm256_and_si256(
+ _mm256_cmpgt_epi8(current_bytes, _mm256_set1_epi8(0x8F)), maskF4);
+
+ *has_error =
+ _mm256_or_si256(*has_error, _mm256_or_si256(badfollowED, badfollowF4));
+}
+
+// map off1_hibits => error condition
+// hibits off1 cur
+// C => < C2 && true
+// E => < E1 && < A0
+// F => < F1 && < 90
+// else false && false
+static inline void avxcheckOverlong(__m256i current_bytes,
+ __m256i off1_current_bytes, __m256i hibits,
+ __m256i previous_hibits,
+ __m256i *has_error) {
+ __m256i off1_hibits = push_last_byte_of_a_to_b(previous_hibits, hibits);
+ __m256i initial_mins = _mm256_shuffle_epi8(
+ _mm256_setr_epi8(-128, -128, -128, -128, -128, -128, -128, -128, -128,
+ -128, -128, -128, // 10xx => false
+ 0xC2, -128, // 110x
+ 0xE1, // 1110
+ 0xF1, -128, -128, -128, -128, -128, -128, -128, -128,
+ -128, -128, -128, -128, // 10xx => false
+ 0xC2, -128, // 110x
+ 0xE1, // 1110
+ 0xF1),
+ off1_hibits);
+
+ __m256i initial_under = _mm256_cmpgt_epi8(initial_mins, off1_current_bytes);
+
+ __m256i second_mins = _mm256_shuffle_epi8(
+ _mm256_setr_epi8(-128, -128, -128, -128, -128, -128, -128, -128, -128,
+ -128, -128, -128, // 10xx => false
+ 127, 127, // 110x => true
+ 0xA0, // 1110
+ 0x90, -128, -128, -128, -128, -128, -128, -128, -128,
+ -128, -128, -128, -128, // 10xx => false
+ 127, 127, // 110x => true
+ 0xA0, // 1110
+ 0x90),
+ off1_hibits);
+ __m256i second_under = _mm256_cmpgt_epi8(second_mins, current_bytes);
+ *has_error = _mm256_or_si256(*has_error,
+ _mm256_and_si256(initial_under, second_under));
+}
+
+struct avx_processed_utf_bytes {
+ __m256i rawbytes;
+ __m256i high_nibbles;
+ __m256i carried_continuations;
+};
+
+static inline void avx_count_nibbles(__m256i bytes,
+ struct avx_processed_utf_bytes *answer) {
+ answer->rawbytes = bytes;
+ answer->high_nibbles =
+ _mm256_and_si256(_mm256_srli_epi16(bytes, 4), _mm256_set1_epi8(0x0F));
+}
+
+// check whether the current bytes are valid UTF-8
+// at the end of the function, previous gets updated
+static struct avx_processed_utf_bytes
+avxcheckUTF8Bytes(__m256i current_bytes,
+ struct avx_processed_utf_bytes *previous,
+ __m256i *has_error) {
+ struct avx_processed_utf_bytes pb;
+ avx_count_nibbles(current_bytes, &pb);
+
+ avxcheckSmallerThan0xF4(current_bytes, has_error);
+
+ __m256i initial_lengths = avxcontinuationLengths(pb.high_nibbles);
+
+ pb.carried_continuations =
+ avxcarryContinuations(initial_lengths, previous->carried_continuations);
+
+ avxcheckContinuations(initial_lengths, pb.carried_continuations, has_error);
+
+ __m256i off1_current_bytes =
+ push_last_byte_of_a_to_b(previous->rawbytes, pb.rawbytes);
+ avxcheckFirstContinuationMax(current_bytes, off1_current_bytes, has_error);
+
+ avxcheckOverlong(current_bytes, off1_current_bytes, pb.high_nibbles,
+ previous->high_nibbles, has_error);
+ return pb;
+}
+
+// check whether the current bytes are valid UTF-8
+// at the end of the function, previous gets updated
+static struct avx_processed_utf_bytes
+avxcheckUTF8Bytes_asciipath(__m256i current_bytes,
+ struct avx_processed_utf_bytes *previous,
+ __m256i *has_error) {
+ if (_mm256_testz_si256(current_bytes,
+ _mm256_set1_epi8(0x80))) { // fast ascii path
+ *has_error = _mm256_or_si256(
+ _mm256_cmpgt_epi8(previous->carried_continuations,
+ _mm256_setr_epi8(9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 1)),
+ *has_error);
+ return *previous;
+ }
+
+ struct avx_processed_utf_bytes pb;
+ avx_count_nibbles(current_bytes, &pb);
+
+ avxcheckSmallerThan0xF4(current_bytes, has_error);
+
+ __m256i initial_lengths = avxcontinuationLengths(pb.high_nibbles);
+
+ pb.carried_continuations =
+ avxcarryContinuations(initial_lengths, previous->carried_continuations);
+
+ avxcheckContinuations(initial_lengths, pb.carried_continuations, has_error);
+
+ __m256i off1_current_bytes =
+ push_last_byte_of_a_to_b(previous->rawbytes, pb.rawbytes);
+ avxcheckFirstContinuationMax(current_bytes, off1_current_bytes, has_error);
+
+ avxcheckOverlong(current_bytes, off1_current_bytes, pb.high_nibbles,
+ previous->high_nibbles, has_error);
+ return pb;
+}
+
+static bool validate_utf8_fast_avx_asciipath(const char *src, size_t len) {
+ size_t i = 0;
+ __m256i has_error = _mm256_setzero_si256();
+ struct avx_processed_utf_bytes previous = {
+ .rawbytes = _mm256_setzero_si256(),
+ .high_nibbles = _mm256_setzero_si256(),
+ .carried_continuations = _mm256_setzero_si256()};
+ if (len >= 32) {
+ for (; i <= len - 32; i += 32) {
+ __m256i current_bytes = _mm256_loadu_si256((const __m256i *)(src + i));
+ previous =
+ avxcheckUTF8Bytes_asciipath(current_bytes, &previous, &has_error);
+ }
+ }
+
+ // last part
+ if (i < len) {
+ char buffer[32];
+ memset(buffer, 0, 32);
+ memcpy(buffer, src + i, len - i);
+ __m256i current_bytes = _mm256_loadu_si256((const __m256i *)(buffer));
+ previous = avxcheckUTF8Bytes(current_bytes, &previous, &has_error);
+ } else {
+ has_error = _mm256_or_si256(
+ _mm256_cmpgt_epi8(previous.carried_continuations,
+ _mm256_setr_epi8(9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 1)),
+ has_error);
+ }
+
+ return _mm256_testz_si256(has_error, has_error);
+}
+
+static bool validate_utf8_fast_avx(const char *src, size_t len) {
+ size_t i = 0;
+ __m256i has_error = _mm256_setzero_si256();
+ struct avx_processed_utf_bytes previous = {
+ .rawbytes = _mm256_setzero_si256(),
+ .high_nibbles = _mm256_setzero_si256(),
+ .carried_continuations = _mm256_setzero_si256()};
+ if (len >= 32) {
+ for (; i <= len - 32; i += 32) {
+ __m256i current_bytes = _mm256_loadu_si256((const __m256i *)(src + i));
+ previous = avxcheckUTF8Bytes(current_bytes, &previous, &has_error);
+ }
+ }
+
+ // last part
+ if (i < len) {
+ char buffer[32];
+ memset(buffer, 0, 32);
+ memcpy(buffer, src + i, len - i);
+ __m256i current_bytes = _mm256_loadu_si256((const __m256i *)(buffer));
+ previous = avxcheckUTF8Bytes(current_bytes, &previous, &has_error);
+ } else {
+ has_error = _mm256_or_si256(
+ _mm256_cmpgt_epi8(previous.carried_continuations,
+ _mm256_setr_epi8(9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 1)),
+ has_error);
+ }
+
+ return _mm256_testz_si256(has_error, has_error);
+}
+
+#endif // __AVX2__
+#endif
--- /dev/null
+/**\r
+ * utf8filenamecheck Check if all the filenames in a fiven folder are UTF-8\r
+ * Copyright (C) 2023 Johannes 'Banana' Keßler\r
+ *\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.\r
+ */\r
+\r
+/**\r
+ * 2023 Small windows C tool to check if paths in a folder are utf-8 formatted\r
+ * This is the windows version\r
+ */\r
+ \r
+#include <stdint.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+// https://linux.die.net/man/3/nftw\r
+#define _XOPEN_SOURCE 500\r
+#include <ftw.h>\r
+\r
+// https://www.argtable.org\r
+#include <argtable3.h>\r
+\r
+// https://github.com/simdutf/simdutf\r
+#include <simdutf8check.h>\r
+\r
+/**\r
+ * global arg_xxx structs\r
+ * https://www.argtable.org/\r
+ */\r
+struct arg_lit *verbose, *quiet, *help;\r
+struct arg_file *folderToRead;\r
+struct arg_end *end;\r
+const char *program_version = "1.0";\r
+const char *program_bug_address = "https://://www.bananas-playground.net";\r
+\r
+struct cmdArguments {\r
+ int quiet, verbose;\r
+ char *folder_to_read;\r
+};\r
+\r
+struct cmdArguments arguments;\r
+\r
+/**\r
+ * the callback function for nftw\r
+ * https://linux.die.net/man/3/nftw\r
+ */\r
+static int nftw_callback(const char *fpath, \r
+ const struct stat *sb,\r
+ int tflag, \r
+ struct FTW *ftwbuf) {\r
+ if (strcmp(fpath, ".") == 0 || strcmp(fpath, "..") == 0) {\r
+ return 0;\r
+ }\r
+ \r
+ if(tflag == FTW_DNR) {\r
+ if(!arguments.quiet) printf("Can not read %s", fpath);\r
+ }\r
+ \r
+ bool result = validate_utf8_fast(fpath, strlen(fpath));\r
+ if(result) {\r
+ if(!arguments.quiet) printf("%s Valid OK \n", fpath);\r
+ } else {\r
+ printf("%s Valid FAILED \n", fpath);\r
+ }\r
+ \r
+ // continue\r
+ return 0;\r
+}\r
+\r
+/**\r
+ * the main stuff\r
+ */\r
+int main(int argc, char *argv[]) {\r
+ \r
+ /**\r
+ * command line argument default values\r
+ */\r
+ arguments.quiet = 0;\r
+ arguments.verbose = 0;\r
+ arguments.folder_to_read = ".";\r
+ \r
+ /**\r
+ * https://www.argtable.org/\r
+ */\r
+ void *argtable[] = {\r
+ help = arg_litn(NULL, "help", 0, 1, "Display this help and exit"),\r
+ quiet = arg_litn("q", "quiet", 0, 1, "Display only false ones"),\r
+ verbose = arg_litn("v", "verbose", 0, 1, "Verbose additional output"),\r
+ folderToRead = arg_filen(NULL, NULL, "<folder>", 1, 1, "Folder to read"),\r
+ end = arg_end(20),\r
+ };\r
+ /* argtable parsing */\r
+ int nerrors;\r
+ nerrors = arg_parse(argc,argv,argtable);\r
+ /* special case: '--help' takes precedence over error reporting */\r
+ if (help->count > 0) {\r
+ printf("Usage: utf8check.exe");\r
+ arg_print_syntax(stdout, argtable, "\n");\r
+ arg_print_glossary(stdout, argtable, " %-25s %s\n");\r
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));\r
+ return(1);\r
+ }\r
+ /* If the parser returned any errors then display them and exit */\r
+ if (nerrors > 0) {\r
+ /* Display the error details contained in the arg_end struct.*/\r
+ arg_print_errors(stdout, end, "utf8check.exe");\r
+ printf("Try '%s --help' for more information.\n", "utf8check.exe");\r
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));\r
+ return(1);\r
+ }\r
+ else {\r
+ arguments.quiet = quiet->count;\r
+ arguments.verbose = verbose->count;\r
+ arguments.folder_to_read = folderToRead->filename[0];\r
+ }\r
+\r
+ if(arguments.verbose) {\r
+ printf ("Folder = %s\n"\r
+ "Verbose = %s\n"\r
+ "Quiet = %s\n\n",\r
+ arguments.folder_to_read,\r
+ arguments.verbose ? "yes" : "no",\r
+ arguments.quiet ? "yes" : "no"\r
+ );\r
+ }\r
+\r
+ if (nftw(arguments.folder_to_read, nftw_callback, 15, FTW_PHYS)== -1) {\r
+ perror("Reading dir failed");\r
+ exit(EXIT_FAILURE);\r
+ }\r
+\r
+ arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));\r
+ exit(EXIT_SUCCESS);\r
+}
\ No newline at end of file