]> 91.132.146.200 Git - klimbim.git/commitdiff
adding utf8filenamecheck to the c tools
authorBanana <mail@bananas-playground.net>
Sun, 6 Aug 2023 20:06:39 +0000 (22:06 +0200)
committerBanana <mail@bananas-playground.net>
Sun, 6 Aug 2023 20:06:39 +0000 (22:06 +0200)
44 files changed:
c/README [new file with mode: 0644]
c/utf8filenamecheck/linux/COPYING [new file with mode: 0644]
c/utf8filenamecheck/linux/Makefile [new file with mode: 0644]
c/utf8filenamecheck/linux/README [new file with mode: 0644]
c/utf8filenamecheck/linux/USES [new file with mode: 0644]
c/utf8filenamecheck/linux/bin/utf8filenamecheck [new file with mode: 0755]
c/utf8filenamecheck/linux/simdutf8check/simdutf8check.h [new file with mode: 0644]
c/utf8filenamecheck/linux/utf8filenamecheck.c [new file with mode: 0644]
c/utf8filenamecheck/windows/COPYING [new file with mode: 0644]
c/utf8filenamecheck/windows/README [new file with mode: 0644]
c/utf8filenamecheck/windows/USES [new file with mode: 0644]
c/utf8filenamecheck/windows/argtable/LICENSE [new file with mode: 0644]
c/utf8filenamecheck/windows/argtable/README.md [new file with mode: 0644]
c/utf8filenamecheck/windows/argtable/argtable3.c [new file with mode: 0644]
c/utf8filenamecheck/windows/argtable/argtable3.h [new file with mode: 0644]
c/utf8filenamecheck/windows/argtable/examples/CMakeLists.txt [new file with mode: 0644]
c/utf8filenamecheck/windows/argtable/examples/echo.c [new file with mode: 0644]
c/utf8filenamecheck/windows/argtable/examples/ls.c [new file with mode: 0644]
c/utf8filenamecheck/windows/argtable/examples/multisyntax.c [new file with mode: 0644]
c/utf8filenamecheck/windows/argtable/examples/mv.c [new file with mode: 0644]
c/utf8filenamecheck/windows/argtable/examples/myprog.c [new file with mode: 0644]
c/utf8filenamecheck/windows/argtable/examples/myprog_C89.c [new file with mode: 0644]
c/utf8filenamecheck/windows/argtable/examples/testargtable3.c [new file with mode: 0644]
c/utf8filenamecheck/windows/argtable/examples/uname.c [new file with mode: 0644]
c/utf8filenamecheck/windows/argtable/tests/CMakeLists.txt [new file with mode: 0644]
c/utf8filenamecheck/windows/argtable/tests/CuTest.c [new file with mode: 0644]
c/utf8filenamecheck/windows/argtable/tests/CuTest.h [new file with mode: 0644]
c/utf8filenamecheck/windows/argtable/tests/argtable3_private.h [new file with mode: 0644]
c/utf8filenamecheck/windows/argtable/tests/testall.c [new file with mode: 0644]
c/utf8filenamecheck/windows/argtable/tests/testargcmd.c [new file with mode: 0644]
c/utf8filenamecheck/windows/argtable/tests/testargdate.c [new file with mode: 0644]
c/utf8filenamecheck/windows/argtable/tests/testargdbl.c [new file with mode: 0644]
c/utf8filenamecheck/windows/argtable/tests/testargdstr.c [new file with mode: 0644]
c/utf8filenamecheck/windows/argtable/tests/testargfile.c [new file with mode: 0644]
c/utf8filenamecheck/windows/argtable/tests/testarghashtable.c [new file with mode: 0644]
c/utf8filenamecheck/windows/argtable/tests/testargint.c [new file with mode: 0644]
c/utf8filenamecheck/windows/argtable/tests/testarglit.c [new file with mode: 0644]
c/utf8filenamecheck/windows/argtable/tests/testargrex.c [new file with mode: 0644]
c/utf8filenamecheck/windows/argtable/tests/testargstr.c [new file with mode: 0644]
c/utf8filenamecheck/windows/bin/utf8filenamecheck.exe [new file with mode: 0644]
c/utf8filenamecheck/windows/makefile.bat [new file with mode: 0644]
c/utf8filenamecheck/windows/notes.txt [new file with mode: 0644]
c/utf8filenamecheck/windows/simdutf8check/simdutf8check.h [new file with mode: 0644]
c/utf8filenamecheck/windows/utf8filenamecheck.c [new file with mode: 0644]

diff --git a/c/README b/c/README
new file mode 100644 (file)
index 0000000..3e80216
--- /dev/null
+++ b/c/README
@@ -0,0 +1,17 @@
+# 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
diff --git a/c/utf8filenamecheck/linux/COPYING b/c/utf8filenamecheck/linux/COPYING
new file mode 100644 (file)
index 0000000..80e659d
--- /dev/null
@@ -0,0 +1,674 @@
+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
diff --git a/c/utf8filenamecheck/linux/Makefile b/c/utf8filenamecheck/linux/Makefile
new file mode 100644 (file)
index 0000000..a1f91c7
--- /dev/null
@@ -0,0 +1,9 @@
+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
diff --git a/c/utf8filenamecheck/linux/README b/c/utf8filenamecheck/linux/README
new file mode 100644 (file)
index 0000000..5cacc7d
--- /dev/null
@@ -0,0 +1,18 @@
+# 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
diff --git a/c/utf8filenamecheck/linux/USES b/c/utf8filenamecheck/linux/USES
new file mode 100644 (file)
index 0000000..6aebec2
--- /dev/null
@@ -0,0 +1 @@
+https://github.com/adamretter/utf8-validator-c
\ No newline at end of file
diff --git a/c/utf8filenamecheck/linux/bin/utf8filenamecheck b/c/utf8filenamecheck/linux/bin/utf8filenamecheck
new file mode 100755 (executable)
index 0000000..8abae88
Binary files /dev/null and b/c/utf8filenamecheck/linux/bin/utf8filenamecheck differ
diff --git a/c/utf8filenamecheck/linux/simdutf8check/simdutf8check.h b/c/utf8filenamecheck/linux/simdutf8check/simdutf8check.h
new file mode 100644 (file)
index 0000000..7644bfa
--- /dev/null
@@ -0,0 +1,457 @@
+#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
diff --git a/c/utf8filenamecheck/linux/utf8filenamecheck.c b/c/utf8filenamecheck/linux/utf8filenamecheck.c
new file mode 100644 (file)
index 0000000..1a98014
--- /dev/null
@@ -0,0 +1,148 @@
+/**
+ * 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
diff --git a/c/utf8filenamecheck/windows/COPYING b/c/utf8filenamecheck/windows/COPYING
new file mode 100644 (file)
index 0000000..80e659d
--- /dev/null
@@ -0,0 +1,674 @@
+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
diff --git a/c/utf8filenamecheck/windows/README b/c/utf8filenamecheck/windows/README
new file mode 100644 (file)
index 0000000..39abb8d
--- /dev/null
@@ -0,0 +1,35 @@
+# 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
diff --git a/c/utf8filenamecheck/windows/USES b/c/utf8filenamecheck/windows/USES
new file mode 100644 (file)
index 0000000..84ddd54
--- /dev/null
@@ -0,0 +1,2 @@
+https://www.argtable.org\r
+https://github.com/adamretter/utf8-validator-c
\ No newline at end of file
diff --git a/c/utf8filenamecheck/windows/argtable/LICENSE b/c/utf8filenamecheck/windows/argtable/LICENSE
new file mode 100644 (file)
index 0000000..b7853f1
--- /dev/null
@@ -0,0 +1,175 @@
+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.
+
diff --git a/c/utf8filenamecheck/windows/argtable/README.md b/c/utf8filenamecheck/windows/argtable/README.md
new file mode 100644 (file)
index 0000000..8a71ba8
--- /dev/null
@@ -0,0 +1,203 @@
+[![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
diff --git a/c/utf8filenamecheck/windows/argtable/argtable3.c b/c/utf8filenamecheck/windows/argtable/argtable3.c
new file mode 100644 (file)
index 0000000..e0ab1c5
--- /dev/null
@@ -0,0 +1,5860 @@
+/*******************************************************************************\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
diff --git a/c/utf8filenamecheck/windows/argtable/argtable3.h b/c/utf8filenamecheck/windows/argtable/argtable3.h
new file mode 100644 (file)
index 0000000..2042538
--- /dev/null
@@ -0,0 +1,277 @@
+/*******************************************************************************
+ * 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
diff --git a/c/utf8filenamecheck/windows/argtable/examples/CMakeLists.txt b/c/utf8filenamecheck/windows/argtable/examples/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9e0be34
--- /dev/null
@@ -0,0 +1,46 @@
+################################################################################\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
diff --git a/c/utf8filenamecheck/windows/argtable/examples/echo.c b/c/utf8filenamecheck/windows/argtable/examples/echo.c
new file mode 100644 (file)
index 0000000..584db02
--- /dev/null
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * 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;
+    }
diff --git a/c/utf8filenamecheck/windows/argtable/examples/ls.c b/c/utf8filenamecheck/windows/argtable/examples/ls.c
new file mode 100644 (file)
index 0000000..345eb38
--- /dev/null
@@ -0,0 +1,326 @@
+/*******************************************************************************
+ * 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;
+    }
+
+
diff --git a/c/utf8filenamecheck/windows/argtable/examples/multisyntax.c b/c/utf8filenamecheck/windows/argtable/examples/multisyntax.c
new file mode 100644 (file)
index 0000000..b5b7853
--- /dev/null
@@ -0,0 +1,239 @@
+/*******************************************************************************
+ * 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;
+    }
diff --git a/c/utf8filenamecheck/windows/argtable/examples/mv.c b/c/utf8filenamecheck/windows/argtable/examples/mv.c
new file mode 100644 (file)
index 0000000..1381adf
--- /dev/null
@@ -0,0 +1,179 @@
+/*******************************************************************************
+ * 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;
+    }
diff --git a/c/utf8filenamecheck/windows/argtable/examples/myprog.c b/c/utf8filenamecheck/windows/argtable/examples/myprog.c
new file mode 100644 (file)
index 0000000..5a152ba
--- /dev/null
@@ -0,0 +1,147 @@
+/*******************************************************************************
+ * 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;
+    }
diff --git a/c/utf8filenamecheck/windows/argtable/examples/myprog_C89.c b/c/utf8filenamecheck/windows/argtable/examples/myprog_C89.c
new file mode 100644 (file)
index 0000000..b88d278
--- /dev/null
@@ -0,0 +1,165 @@
+/*******************************************************************************
+ * 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;
+    }
diff --git a/c/utf8filenamecheck/windows/argtable/examples/testargtable3.c b/c/utf8filenamecheck/windows/argtable/examples/testargtable3.c
new file mode 100644 (file)
index 0000000..be19f3c
--- /dev/null
@@ -0,0 +1,58 @@
+#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;
+}
+
diff --git a/c/utf8filenamecheck/windows/argtable/examples/uname.c b/c/utf8filenamecheck/windows/argtable/examples/uname.c
new file mode 100644 (file)
index 0000000..ac3e40c
--- /dev/null
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * 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;
+    }
diff --git a/c/utf8filenamecheck/windows/argtable/tests/CMakeLists.txt b/c/utf8filenamecheck/windows/argtable/tests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e4a553c
--- /dev/null
@@ -0,0 +1,89 @@
+################################################################################
+# 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>")
diff --git a/c/utf8filenamecheck/windows/argtable/tests/CuTest.c b/c/utf8filenamecheck/windows/argtable/tests/CuTest.c
new file mode 100644 (file)
index 0000000..9d885a7
--- /dev/null
@@ -0,0 +1,325 @@
+#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);
+    }
+}
diff --git a/c/utf8filenamecheck/windows/argtable/tests/CuTest.h b/c/utf8filenamecheck/windows/argtable/tests/CuTest.h
new file mode 100644 (file)
index 0000000..671cbcf
--- /dev/null
@@ -0,0 +1,104 @@
+#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 */
diff --git a/c/utf8filenamecheck/windows/argtable/tests/argtable3_private.h b/c/utf8filenamecheck/windows/argtable/tests/argtable3_private.h
new file mode 100644 (file)
index 0000000..ad61cfa
--- /dev/null
@@ -0,0 +1,230 @@
+/*******************************************************************************
+ * 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
diff --git a/c/utf8filenamecheck/windows/argtable/tests/testall.c b/c/utf8filenamecheck/windows/argtable/tests/testall.c
new file mode 100644 (file)
index 0000000..8f4ed6f
--- /dev/null
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * 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();
+}
diff --git a/c/utf8filenamecheck/windows/argtable/tests/testargcmd.c b/c/utf8filenamecheck/windows/argtable/tests/testargcmd.c
new file mode 100644 (file)
index 0000000..5ec0836
--- /dev/null
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * 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
diff --git a/c/utf8filenamecheck/windows/argtable/tests/testargdate.c b/c/utf8filenamecheck/windows/argtable/tests/testargdate.c
new file mode 100644 (file)
index 0000000..3b4f5a0
--- /dev/null
@@ -0,0 +1,377 @@
+/*******************************************************************************
+ * 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
diff --git a/c/utf8filenamecheck/windows/argtable/tests/testargdbl.c b/c/utf8filenamecheck/windows/argtable/tests/testargdbl.c
new file mode 100644 (file)
index 0000000..9271cae
--- /dev/null
@@ -0,0 +1,451 @@
+/*******************************************************************************
+ * 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
diff --git a/c/utf8filenamecheck/windows/argtable/tests/testargdstr.c b/c/utf8filenamecheck/windows/argtable/tests/testargdstr.c
new file mode 100644 (file)
index 0000000..4c8aff0
--- /dev/null
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * 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
diff --git a/c/utf8filenamecheck/windows/argtable/tests/testargfile.c b/c/utf8filenamecheck/windows/argtable/tests/testargfile.c
new file mode 100644 (file)
index 0000000..4ae5e9d
--- /dev/null
@@ -0,0 +1,752 @@
+/*******************************************************************************
+ * 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
diff --git a/c/utf8filenamecheck/windows/argtable/tests/testarghashtable.c b/c/utf8filenamecheck/windows/argtable/tests/testarghashtable.c
new file mode 100644 (file)
index 0000000..36e4a7d
--- /dev/null
@@ -0,0 +1,276 @@
+/*******************************************************************************\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
diff --git a/c/utf8filenamecheck/windows/argtable/tests/testargint.c b/c/utf8filenamecheck/windows/argtable/tests/testargint.c
new file mode 100644 (file)
index 0000000..a474430
--- /dev/null
@@ -0,0 +1,2018 @@
+/*******************************************************************************
+ * 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
diff --git a/c/utf8filenamecheck/windows/argtable/tests/testarglit.c b/c/utf8filenamecheck/windows/argtable/tests/testarglit.c
new file mode 100644 (file)
index 0000000..8109f87
--- /dev/null
@@ -0,0 +1,538 @@
+/*******************************************************************************
+ * 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
diff --git a/c/utf8filenamecheck/windows/argtable/tests/testargrex.c b/c/utf8filenamecheck/windows/argtable/tests/testargrex.c
new file mode 100644 (file)
index 0000000..8d846b7
--- /dev/null
@@ -0,0 +1,299 @@
+/*******************************************************************************
+ * 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
diff --git a/c/utf8filenamecheck/windows/argtable/tests/testargstr.c b/c/utf8filenamecheck/windows/argtable/tests/testargstr.c
new file mode 100644 (file)
index 0000000..ac2e088
--- /dev/null
@@ -0,0 +1,531 @@
+/*******************************************************************************
+ * 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
diff --git a/c/utf8filenamecheck/windows/bin/utf8filenamecheck.exe b/c/utf8filenamecheck/windows/bin/utf8filenamecheck.exe
new file mode 100644 (file)
index 0000000..fa2ab2e
Binary files /dev/null and b/c/utf8filenamecheck/windows/bin/utf8filenamecheck.exe differ
diff --git a/c/utf8filenamecheck/windows/makefile.bat b/c/utf8filenamecheck/windows/makefile.bat
new file mode 100644 (file)
index 0000000..a67a3c8
--- /dev/null
@@ -0,0 +1,18 @@
+:: 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
diff --git a/c/utf8filenamecheck/windows/notes.txt b/c/utf8filenamecheck/windows/notes.txt
new file mode 100644 (file)
index 0000000..6304e04
--- /dev/null
@@ -0,0 +1,5 @@
+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
diff --git a/c/utf8filenamecheck/windows/simdutf8check/simdutf8check.h b/c/utf8filenamecheck/windows/simdutf8check/simdutf8check.h
new file mode 100644 (file)
index 0000000..7644bfa
--- /dev/null
@@ -0,0 +1,457 @@
+#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
diff --git a/c/utf8filenamecheck/windows/utf8filenamecheck.c b/c/utf8filenamecheck/windows/utf8filenamecheck.c
new file mode 100644 (file)
index 0000000..764cc09
--- /dev/null
@@ -0,0 +1,147 @@
+/**\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