1 /******************************************************************************* 
   2  * This file is part of the argtable3 library. 
   4  * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann 
   5  * <sheitmann@users.sourceforge.net> 
   8  * Redistribution and use in source and binary forms, with or without 
   9  * modification, are permitted provided that the following conditions are met: 
  10  *     * Redistributions of source code must retain the above copyright 
  11  *       notice, this list of conditions and the following disclaimer. 
  12  *     * Redistributions in binary form must reproduce the above copyright 
  13  *       notice, this list of conditions and the following disclaimer in the 
  14  *       documentation and/or other materials provided with the distribution. 
  15  *     * Neither the name of STEWART HEITMANN nor the  names of its contributors 
  16  *       may be used to endorse or promote products derived from this software 
  17  *       without specific prior written permission. 
  19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
  20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  22  * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, 
  23  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
  24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
  25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
  26  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
  27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
  28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
  29  ******************************************************************************/ 
  31 #include "argtable3.h" 
  33 #define ARG_AMALGAMATION 
  35 /******************************************************************************* 
  36  * argtable3_private: Declares private types, constants, and interfaces 
  38  * This file is part of the argtable3 library. 
  40  * Copyright (C) 2013-2019 Tom G. Huang 
  41  * <tomghuang@gmail.com> 
  42  * All rights reserved. 
  44  * Redistribution and use in source and binary forms, with or without 
  45  * modification, are permitted provided that the following conditions are met: 
  46  *     * Redistributions of source code must retain the above copyright 
  47  *       notice, this list of conditions and the following disclaimer. 
  48  *     * Redistributions in binary form must reproduce the above copyright 
  49  *       notice, this list of conditions and the following disclaimer in the 
  50  *       documentation and/or other materials provided with the distribution. 
  51  *     * Neither the name of STEWART HEITMANN nor the  names of its contributors 
  52  *       may be used to endorse or promote products derived from this software 
  53  *       without specific prior written permission. 
  55  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
  56  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  57  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  58  * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, 
  59  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
  60  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
  61  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
  62  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
  63  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
  64  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
  65  ******************************************************************************/ 
  72 #define ARG_ENABLE_TRACE 0 
  73 #define ARG_ENABLE_LOG 1 
  79 enum { ARG_ERR_MINCOUNT 
= 1, ARG_ERR_MAXCOUNT
, ARG_ERR_BADINT
, ARG_ERR_OVERFLOW
, ARG_ERR_BADDOUBLE
, ARG_ERR_BADDATE
, ARG_ERR_REGNOMATCH 
}; 
  81 typedef void(arg_panicfn
)(const char* fmt
, ...); 
  84 #define ARG_TRACE(x)                                               \ 
  85     __pragma(warning(push)) __pragma(warning(disable : 4127)) do { \ 
  86         if (ARG_ENABLE_TRACE)                                      \ 
  90     __pragma(warning(pop)) 
  93     __pragma(warning(push)) __pragma(warning(disable : 4127)) do { \ 
  98     __pragma(warning(pop)) 
 100 #define ARG_TRACE(x)          \ 
 102         if (ARG_ENABLE_TRACE) \ 
 108         if (ARG_ENABLE_LOG) \ 
 113 extern void dbg_printf(const char* fmt
, ...); 
 114 extern void arg_set_panic(arg_panicfn
* proc
); 
 115 extern void* xmalloc(size_t size
); 
 116 extern void* xcalloc(size_t count
, size_t size
); 
 117 extern void* xrealloc(void* ptr
, size_t size
); 
 118 extern void xfree(void* ptr
); 
 120 struct arg_hashtable_entry 
{ 
 123     struct arg_hashtable_entry
* next
; 
 126 typedef struct arg_hashtable 
{ 
 127     unsigned int tablelength
; 
 128     struct arg_hashtable_entry
** table
; 
 129     unsigned int entrycount
; 
 130     unsigned int loadlimit
; 
 131     unsigned int primeindex
; 
 132     unsigned int (*hashfn
)(const void* k
); 
 133     int (*eqfn
)(const void* k1
, const void* k2
); 
 137  * @brief Create a hash table. 
 139  * @param   minsize   minimum initial size of hash table 
 140  * @param   hashfn    function for hashing keys 
 141  * @param   eqfn      function for determining key equality 
 142  * @return            newly created hash table or NULL on failure 
 144 arg_hashtable_t
* arg_hashtable_create(unsigned int minsize
, unsigned int (*hashfn
)(const void*), int (*eqfn
)(const void*, const void*)); 
 147  * @brief This function will cause the table to expand if the insertion would take 
 148  * the ratio of entries to table size over the maximum load factor. 
 150  * This function does not check for repeated insertions with a duplicate key. 
 151  * The value returned when using a duplicate key is undefined -- when 
 152  * the hash table changes size, the order of retrieval of duplicate key 
 153  * entries is reversed. 
 154  * If in doubt, remove before insert. 
 156  * @param   h   the hash table to insert into 
 157  * @param   k   the key - hash table claims ownership and will free on removal 
 158  * @param   v   the value - does not claim ownership 
 159  * @return      non-zero for successful insertion 
 161 void arg_hashtable_insert(arg_hashtable_t
* h
, void* k
, void* v
); 
 163 #define ARG_DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \ 
 164     int fnname(arg_hashtable_t* h, keytype* k, valuetype* v) { return arg_hashtable_insert(h, k, v); } 
 167  * @brief Search the specified key in the hash table. 
 169  * @param   h   the hash table to search 
 170  * @param   k   the key to search for  - does not claim ownership 
 171  * @return      the value associated with the key, or NULL if none found 
 173 void* arg_hashtable_search(arg_hashtable_t
* h
, const void* k
); 
 175 #define ARG_DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \ 
 176     valuetype* fnname(arg_hashtable_t* h, keytype* k) { return (valuetype*)(arg_hashtable_search(h, k)); } 
 179  * @brief Remove the specified key from the hash table. 
 181  * @param   h   the hash table to remove the item from 
 182  * @param   k   the key to search for  - does not claim ownership 
 184 void arg_hashtable_remove(arg_hashtable_t
* h
, const void* k
); 
 186 #define ARG_DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \ 
 187     void fnname(arg_hashtable_t* h, keytype* k) { arg_hashtable_remove(h, k); } 
 190  * @brief Return the number of keys in the hash table. 
 192  * @param   h   the hash table 
 193  * @return      the number of items stored in the hash table 
 195 unsigned int arg_hashtable_count(arg_hashtable_t
* h
); 
 198  * @brief Change the value associated with the key. 
 200  * function to change the value associated with a key, where there already 
 201  * exists a value bound to the key in the hash table. 
 202  * Source due to Holger Schemel. 
 204  * @name        hashtable_change 
 205  * @param   h   the hash table 
 209 int arg_hashtable_change(arg_hashtable_t
* h
, void* k
, void* v
); 
 212  * @brief Free the hash table and the memory allocated for each key-value pair. 
 214  * @param   h            the hash table 
 215  * @param   free_values  whether to call 'free' on the remaining values 
 217 void arg_hashtable_destroy(arg_hashtable_t
* h
, int free_values
); 
 219 typedef struct arg_hashtable_itr 
{ 
 221     struct arg_hashtable_entry
* e
; 
 222     struct arg_hashtable_entry
* parent
; 
 224 } arg_hashtable_itr_t
; 
 226 arg_hashtable_itr_t
* arg_hashtable_itr_create(arg_hashtable_t
* h
); 
 228 void arg_hashtable_itr_destroy(arg_hashtable_itr_t
* itr
); 
 231  * @brief Return the value of the (key,value) pair at the current position. 
 233 extern void* arg_hashtable_itr_key(arg_hashtable_itr_t
* i
); 
 236  * @brief Return the value of the (key,value) pair at the current position. 
 238 extern void* arg_hashtable_itr_value(arg_hashtable_itr_t
* i
); 
 241  * @brief Advance the iterator to the next element. Returns zero if advanced to end of table. 
 243 int arg_hashtable_itr_advance(arg_hashtable_itr_t
* itr
); 
 246  * @brief Remove current element and advance the iterator to the next element. 
 248 int arg_hashtable_itr_remove(arg_hashtable_itr_t
* itr
); 
 251  * @brief Search and overwrite the supplied iterator, to point to the entry matching the supplied key. 
 253  * @return  Zero if not found. 
 255 int arg_hashtable_itr_search(arg_hashtable_itr_t
* itr
, arg_hashtable_t
* h
, void* k
); 
 257 #define ARG_DEFINE_HASHTABLE_ITERATOR_SEARCH(fnname, keytype) \ 
 258     int fnname(arg_hashtable_itr_t* i, arg_hashtable_t* h, keytype* k) { return (arg_hashtable_iterator_search(i, h, k)); } 
 265 /******************************************************************************* 
 266  * arg_utils: Implements memory, panic, and other utility functions 
 268  * This file is part of the argtable3 library. 
 270  * Copyright (C) 2013-2019 Tom G. Huang 
 271  * <tomghuang@gmail.com> 
 272  * All rights reserved. 
 274  * Redistribution and use in source and binary forms, with or without 
 275  * modification, are permitted provided that the following conditions are met: 
 276  *     * Redistributions of source code must retain the above copyright 
 277  *       notice, this list of conditions and the following disclaimer. 
 278  *     * Redistributions in binary form must reproduce the above copyright 
 279  *       notice, this list of conditions and the following disclaimer in the 
 280  *       documentation and/or other materials provided with the distribution. 
 281  *     * Neither the name of STEWART HEITMANN nor the  names of its contributors 
 282  *       may be used to endorse or promote products derived from this software 
 283  *       without specific prior written permission. 
 285  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 286  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 287  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 288  * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, 
 289  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 290  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 291  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
 292  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
 293  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 294  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 295  ******************************************************************************/ 
 297 #include "argtable3.h" 
 299 #ifndef ARG_AMALGAMATION 
 300 #include "argtable3_private.h" 
 308 static void panic(const char* fmt
, ...); 
 309 static arg_panicfn
* s_panic 
= panic
; 
 311 void dbg_printf(const char* fmt
, ...) { 
 314     vfprintf(stderr
, fmt
, args
); 
 318 static void panic(const char* fmt
, ...) { 
 323     vfprintf(stderr
, fmt
, args
); 
 326 #if defined(_MSC_VER) 
 327 #pragma warning(push) 
 328 #pragma warning(disable : 4996) 
 330     s 
= getenv("EF_DUMPCORE"); 
 331 #if defined(_MSC_VER) 
 335     if (s 
!= NULL 
&& *s 
!= '\0') { 
 342 void arg_set_panic(arg_panicfn
* proc
) { 
 346 void* xmalloc(size_t size
) { 
 347     void* ret 
= malloc(size
); 
 349         s_panic("Out of memory!\n"); 
 354 void* xcalloc(size_t count
, size_t size
) { 
 355     size_t allocated_count 
= count 
&& size 
? count 
: 1; 
 356     size_t allocated_size 
= count 
&& size 
? size 
: 1; 
 357     void* ret 
= calloc(allocated_count
, allocated_size
); 
 359         s_panic("Out of memory!\n"); 
 364 void* xrealloc(void* ptr
, size_t size
) { 
 365     size_t allocated_size 
= size 
? size 
: 1; 
 366     void* ret 
= realloc(ptr
, allocated_size
); 
 368         s_panic("Out of memory!\n"); 
 373 void xfree(void* ptr
) { 
 377 static void merge(void* data
, int esize
, int i
, int j
, int k
, arg_comparefn
* comparefn
) { 
 378     char* a 
= (char*)data
; 
 380     int ipos
, jpos
, mpos
; 
 382     /* Initialize the counters used in merging. */ 
 387     /* Allocate storage for the merged elements. */ 
 388     m 
= (char*)xmalloc(esize 
* ((k 
- i
) + 1)); 
 390     /* Continue while either division has elements to merge. */ 
 391     while (ipos 
<= j 
|| jpos 
<= k
) { 
 393             /* The left division has no more elements to merge. */ 
 395                 memcpy(&m
[mpos 
* esize
], &a
[jpos 
* esize
], esize
); 
 401         } else if (jpos 
> k
) { 
 402             /* The right division has no more elements to merge. */ 
 404                 memcpy(&m
[mpos 
* esize
], &a
[ipos 
* esize
], esize
); 
 412         /* Append the next ordered element to the merged elements. */ 
 413         if (comparefn(&a
[ipos 
* esize
], &a
[jpos 
* esize
]) < 0) { 
 414             memcpy(&m
[mpos 
* esize
], &a
[ipos 
* esize
], esize
); 
 418             memcpy(&m
[mpos 
* esize
], &a
[jpos 
* esize
], esize
); 
 424     /* Prepare to pass back the merged data. */ 
 425     memcpy(&a
[i 
* esize
], m
, esize 
* ((k 
- i
) + 1)); 
 429 void arg_mgsort(void* data
, int size
, int esize
, int i
, int k
, arg_comparefn
* comparefn
) { 
 432     /* Stop the recursion when no more divisions can be made. */ 
 434         /* Determine where to divide the elements. */ 
 435         j 
= (int)(((i 
+ k 
- 1)) / 2); 
 437         /* Recursively sort the two divisions. */ 
 438         arg_mgsort(data
, size
, esize
, i
, j
, comparefn
); 
 439         arg_mgsort(data
, size
, esize
, j 
+ 1, k
, comparefn
); 
 440         merge(data
, esize
, i
, j
, k
, comparefn
); 
 443 /******************************************************************************* 
 444  * arg_hashtable: Implements the hash table utilities 
 446  * This file is part of the argtable3 library. 
 448  * Copyright (C) 2013-2019 Tom G. Huang 
 449  * <tomghuang@gmail.com> 
 450  * All rights reserved. 
 452  * Redistribution and use in source and binary forms, with or without 
 453  * modification, are permitted provided that the following conditions are met: 
 454  *     * Redistributions of source code must retain the above copyright 
 455  *       notice, this list of conditions and the following disclaimer. 
 456  *     * Redistributions in binary form must reproduce the above copyright 
 457  *       notice, this list of conditions and the following disclaimer in the 
 458  *       documentation and/or other materials provided with the distribution. 
 459  *     * Neither the name of STEWART HEITMANN nor the  names of its contributors 
 460  *       may be used to endorse or promote products derived from this software 
 461  *       without specific prior written permission. 
 463  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 464  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 465  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 466  * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, 
 467  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 468  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 469  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
 470  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
 471  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 472  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 473  ******************************************************************************/ 
 475 #ifndef ARG_AMALGAMATION 
 476 #include "argtable3_private.h" 
 485  * This hash table module is adapted from the C hash table implementation by 
 486  * Christopher Clark. Here is the copyright notice from the library: 
 488  * Copyright (c) 2002, Christopher Clark 
 489  * All rights reserved. 
 491  * Redistribution and use in source and binary forms, with or without 
 492  * modification, are permitted provided that the following conditions 
 495  * * Redistributions of source code must retain the above copyright 
 496  * notice, this list of conditions and the following disclaimer. 
 498  * * Redistributions in binary form must reproduce the above copyright 
 499  * notice, this list of conditions and the following disclaimer in the 
 500  * documentation and/or other materials provided with the distribution. 
 502  * * Neither the name of the original author; nor the names of any contributors 
 503  * may be used to endorse or promote products derived from this software 
 504  * without specific prior written permission. 
 507  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 508  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 509  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
 510  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER 
 511  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 512  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 513  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
 514  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
 515  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
 516  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 517  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 521  * Credit for primes table: Aaron Krowne 
 522  * http://br.endernet.org/~akrowne/ 
 523  * http://planetmath.org/encyclopedia/GoodHashTablePrimes.html 
 525 static const unsigned int primes
[] = {53,       97,       193,      389,       769,       1543,      3079,      6151,      12289, 
 526                                       24593,    49157,    98317,    196613,    393241,    786433,    1572869,   3145739,   6291469, 
 527                                       12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741}; 
 528 const unsigned int prime_table_length 
= sizeof(primes
) / sizeof(primes
[0]); 
 529 const float max_load_factor 
= (float)0.65; 
 531 static unsigned int enhanced_hash(arg_hashtable_t
* h
, const void* k
) { 
 533      * Aim to protect against poor hash functions by adding logic here. 
 534      * The logic is taken from Java 1.4 hash table source. 
 536     unsigned int i 
= h
->hashfn(k
); 
 538     i 
^= ((i 
>> 14) | (i 
<< 18)); /* >>> */ 
 540     i 
^= ((i 
>> 10) | (i 
<< 22)); /* >>> */ 
 544 static unsigned int index_for(unsigned int tablelength
, unsigned int hashvalue
) { 
 545     return (hashvalue 
% tablelength
); 
 548 arg_hashtable_t
* arg_hashtable_create(unsigned int minsize
, unsigned int (*hashfn
)(const void*), int (*eqfn
)(const void*, const void*)) { 
 551     unsigned int size 
= primes
[0]; 
 553     /* Check requested hash table isn't too large */ 
 554     if (minsize 
> (1u << 30)) 
 558      * Enforce size as prime. The reason is to avoid clustering of values 
 559      * into a small number of buckets (yes, distribution). A more even 
 560      *  distributed hash table will perform more consistently. 
 562     for (pindex 
= 0; pindex 
< prime_table_length
; pindex
++) { 
 563         if (primes
[pindex
] > minsize
) { 
 564             size 
= primes
[pindex
]; 
 569     h 
= (arg_hashtable_t
*)xmalloc(sizeof(arg_hashtable_t
)); 
 570     h
->table 
= (struct arg_hashtable_entry
**)xmalloc(sizeof(struct arg_hashtable_entry
*) * size
); 
 571     memset(h
->table
, 0, size 
* sizeof(struct arg_hashtable_entry
*)); 
 572     h
->tablelength 
= size
; 
 573     h
->primeindex 
= pindex
; 
 577     h
->loadlimit 
= (unsigned int)ceil(size 
* max_load_factor
); 
 581 static int arg_hashtable_expand(arg_hashtable_t
* h
) { 
 582     /* Double the size of the table to accommodate more entries */ 
 583     struct arg_hashtable_entry
** newtable
; 
 584     struct arg_hashtable_entry
* e
; 
 585     unsigned int newsize
; 
 589     /* Check we're not hitting max capacity */ 
 590     if (h
->primeindex 
== (prime_table_length 
- 1)) 
 592     newsize 
= primes
[++(h
->primeindex
)]; 
 594     newtable 
= (struct arg_hashtable_entry
**)xmalloc(sizeof(struct arg_hashtable_entry
*) * newsize
); 
 595     memset(newtable
, 0, newsize 
* sizeof(struct arg_hashtable_entry
*)); 
 597      * This algorithm is not 'stable': it reverses the list 
 598      * when it transfers entries between the tables 
 600     for (i 
= 0; i 
< h
->tablelength
; i
++) { 
 601         while (NULL 
!= (e 
= h
->table
[i
])) { 
 602             h
->table
[i
] = e
->next
; 
 603             index 
= index_for(newsize
, e
->h
); 
 604             e
->next 
= newtable
[index
]; 
 611     h
->tablelength 
= newsize
; 
 612     h
->loadlimit 
= (unsigned int)ceil(newsize 
* max_load_factor
); 
 616 unsigned int arg_hashtable_count(arg_hashtable_t
* h
) { 
 617     return h
->entrycount
; 
 620 void arg_hashtable_insert(arg_hashtable_t
* h
, void* k
, void* v
) { 
 621     /* This method allows duplicate keys - but they shouldn't be used */ 
 623     struct arg_hashtable_entry
* e
; 
 624     if ((h
->entrycount 
+ 1) > h
->loadlimit
) { 
 626          * Ignore the return value. If expand fails, we should 
 627          * still try cramming just this value into the existing table 
 628          * -- we may not have memory for a larger table, but one more 
 629          * element may be ok. Next time we insert, we'll try expanding again. 
 631         arg_hashtable_expand(h
); 
 633     e 
= (struct arg_hashtable_entry
*)xmalloc(sizeof(struct arg_hashtable_entry
)); 
 634     e
->h 
= enhanced_hash(h
, k
); 
 635     index 
= index_for(h
->tablelength
, e
->h
); 
 638     e
->next 
= h
->table
[index
]; 
 643 void* arg_hashtable_search(arg_hashtable_t
* h
, const void* k
) { 
 644     struct arg_hashtable_entry
* e
; 
 645     unsigned int hashvalue
; 
 648     hashvalue 
= enhanced_hash(h
, k
); 
 649     index 
= index_for(h
->tablelength
, hashvalue
); 
 652         /* Check hash value to short circuit heavier comparison */ 
 653         if ((hashvalue 
== e
->h
) && (h
->eqfn(k
, e
->k
))) 
 660 void arg_hashtable_remove(arg_hashtable_t
* h
, const void* k
) { 
 662      * TODO: consider compacting the table when the load factor drops enough, 
 663      *       or provide a 'compact' method. 
 666     struct arg_hashtable_entry
* e
; 
 667     struct arg_hashtable_entry
** pE
; 
 668     unsigned int hashvalue
; 
 671     hashvalue 
= enhanced_hash(h
, k
); 
 672     index 
= index_for(h
->tablelength
, hashvalue
); 
 673     pE 
= &(h
->table
[index
]); 
 676         /* Check hash value to short circuit heavier comparison */ 
 677         if ((hashvalue 
== e
->h
) && (h
->eqfn(k
, e
->k
))) { 
 690 void arg_hashtable_destroy(arg_hashtable_t
* h
, int free_values
) { 
 692     struct arg_hashtable_entry 
*e
, *f
; 
 693     struct arg_hashtable_entry
** table 
= h
->table
; 
 695         for (i 
= 0; i 
< h
->tablelength
; i
++) { 
 706         for (i 
= 0; i 
< h
->tablelength
; i
++) { 
 720 arg_hashtable_itr_t
* arg_hashtable_itr_create(arg_hashtable_t
* h
) { 
 722     unsigned int tablelength
; 
 724     arg_hashtable_itr_t
* itr 
= (arg_hashtable_itr_t
*)xmalloc(sizeof(arg_hashtable_itr_t
)); 
 728     tablelength 
= h
->tablelength
; 
 729     itr
->index 
= tablelength
; 
 730     if (0 == h
->entrycount
) 
 733     for (i 
= 0; i 
< tablelength
; i
++) { 
 734         if (h
->table
[i
] != NULL
) { 
 735             itr
->e 
= h
->table
[i
]; 
 743 void arg_hashtable_itr_destroy(arg_hashtable_itr_t
* itr
) { 
 747 void* arg_hashtable_itr_key(arg_hashtable_itr_t
* i
) { 
 751 void* arg_hashtable_itr_value(arg_hashtable_itr_t
* i
) { 
 755 int arg_hashtable_itr_advance(arg_hashtable_itr_t
* itr
) { 
 757     unsigned int tablelength
; 
 758     struct arg_hashtable_entry
** table
; 
 759     struct arg_hashtable_entry
* next
; 
 762         return 0; /* stupidity check */ 
 766         itr
->parent 
= itr
->e
; 
 771     tablelength 
= itr
->h
->tablelength
; 
 773     if (tablelength 
<= (j 
= ++(itr
->index
))) { 
 778     table 
= itr
->h
->table
; 
 779     while (NULL 
== (next 
= table
[j
])) { 
 780         if (++j 
>= tablelength
) { 
 781             itr
->index 
= tablelength
; 
 792 int arg_hashtable_itr_remove(arg_hashtable_itr_t
* itr
) { 
 793     struct arg_hashtable_entry
* remember_e
; 
 794     struct arg_hashtable_entry
* remember_parent
; 
 798     if ((itr
->parent
) == NULL
) { 
 799         /* element is head of a chain */ 
 800         itr
->h
->table
[itr
->index
] = itr
->e
->next
; 
 802         /* element is mid-chain */ 
 803         itr
->parent
->next 
= itr
->e
->next
; 
 805     /* itr->e is now outside the hashtable */ 
 807     itr
->h
->entrycount
--; 
 808     xfree(remember_e
->k
); 
 809     xfree(remember_e
->v
); 
 811     /* Advance the iterator, correcting the parent */ 
 812     remember_parent 
= itr
->parent
; 
 813     ret 
= arg_hashtable_itr_advance(itr
); 
 814     if (itr
->parent 
== remember_e
) { 
 815         itr
->parent 
= remember_parent
; 
 821 int arg_hashtable_itr_search(arg_hashtable_itr_t
* itr
, arg_hashtable_t
* h
, void* k
) { 
 822     struct arg_hashtable_entry
* e
; 
 823     struct arg_hashtable_entry
* parent
; 
 824     unsigned int hashvalue
; 
 827     hashvalue 
= enhanced_hash(h
, k
); 
 828     index 
= index_for(h
->tablelength
, hashvalue
); 
 833         /* Check hash value to short circuit heavier comparison */ 
 834         if ((hashvalue 
== e
->h
) && (h
->eqfn(k
, e
->k
))) { 
 837             itr
->parent 
= parent
; 
 847 int arg_hashtable_change(arg_hashtable_t
* h
, void* k
, void* v
) { 
 848     struct arg_hashtable_entry
* e
; 
 849     unsigned int hashvalue
; 
 852     hashvalue 
= enhanced_hash(h
, k
); 
 853     index 
= index_for(h
->tablelength
, hashvalue
); 
 856         /* Check hash value to short circuit heavier comparison */ 
 857         if ((hashvalue 
== e
->h
) && (h
->eqfn(k
, e
->k
))) { 
 866 /******************************************************************************* 
 867  * arg_dstr: Implements the dynamic string utilities 
 869  * This file is part of the argtable3 library. 
 871  * Copyright (C) 2013-2019 Tom G. Huang 
 872  * <tomghuang@gmail.com> 
 873  * All rights reserved. 
 875  * Redistribution and use in source and binary forms, with or without 
 876  * modification, are permitted provided that the following conditions are met: 
 877  *     * Redistributions of source code must retain the above copyright 
 878  *       notice, this list of conditions and the following disclaimer. 
 879  *     * Redistributions in binary form must reproduce the above copyright 
 880  *       notice, this list of conditions and the following disclaimer in the 
 881  *       documentation and/or other materials provided with the distribution. 
 882  *     * Neither the name of STEWART HEITMANN nor the  names of its contributors 
 883  *       may be used to endorse or promote products derived from this software 
 884  *       without specific prior written permission. 
 886  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 887  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 888  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 889  * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, 
 890  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 891  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 892  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
 893  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
 894  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 895  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 896  ******************************************************************************/ 
 898 #include "argtable3.h" 
 900 #ifndef ARG_AMALGAMATION 
 901 #include "argtable3_private.h" 
 908 #if defined(_MSC_VER) 
 909 #pragma warning(push) 
 910 #pragma warning(disable : 4996) 
 913 #define START_VSNBUFF 16 
 916  * This dynamic string module is adapted from TclResult.c in the Tcl library. 
 917  * Here is the copyright notice from the library: 
 919  * This software is copyrighted by the Regents of the University of 
 920  * California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState 
 921  * Corporation and other parties.  The following terms apply to all files 
 922  * associated with the software unless explicitly disclaimed in 
 925  * The authors hereby grant permission to use, copy, modify, distribute, 
 926  * and license this software and its documentation for any purpose, provided 
 927  * that existing copyright notices are retained in all copies and that this 
 928  * notice is included verbatim in any distributions. No written agreement, 
 929  * license, or royalty fee is required for any of the authorized uses. 
 930  * Modifications to this software may be copyrighted by their authors 
 931  * and need not follow the licensing terms described here, provided that 
 932  * the new terms are clearly indicated on the first page of each file where 
 935  * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY 
 936  * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 
 937  * ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY 
 938  * DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE 
 939  * POSSIBILITY OF SUCH DAMAGE. 
 941  * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, 
 942  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, 
 943  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE 
 944  * IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE 
 945  * NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR 
 948  * GOVERNMENT USE: If you are acquiring this software on behalf of the 
 949  * U.S. government, the Government shall have only "Restricted Rights" 
 950  * in the software and related documentation as defined in the Federal 
 951  * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you 
 952  * are acquiring the software on behalf of the Department of Defense, the 
 953  * software shall be classified as "Commercial Computer Software" and the 
 954  * Government shall have only "Restricted Rights" as defined in Clause 
 955  * 252.227-7014 (b) (3) of DFARs.  Notwithstanding the foregoing, the 
 956  * authors grant the U.S. Government and others acting in its behalf 
 957  * permission to use and distribute the software in accordance with the 
 958  * terms specified in this license. 
 961 typedef struct _internal_arg_dstr 
{ 
 963     arg_dstr_freefn
* free_proc
; 
 964     char sbuf
[ARG_DSTR_SIZE 
+ 1]; 
 966     int append_data_size
; 
 968 } _internal_arg_dstr_t
; 
 970 static void setup_append_buf(arg_dstr_t res
, int newSpace
); 
 972 arg_dstr_t 
arg_dstr_create(void) { 
 973     _internal_arg_dstr_t
* h 
= (_internal_arg_dstr_t
*)xmalloc(sizeof(_internal_arg_dstr_t
)); 
 974     memset(h
, 0, sizeof(_internal_arg_dstr_t
)); 
 977     h
->free_proc 
= ARG_DSTR_STATIC
; 
 981 void arg_dstr_destroy(arg_dstr_t ds
) { 
 990 void arg_dstr_set(arg_dstr_t ds
, char* str
, arg_dstr_freefn
* free_proc
) { 
 992     register arg_dstr_freefn
* old_free_proc 
= ds
->free_proc
; 
 993     char* old_result 
= ds
->data
; 
 998         ds
->free_proc 
= ARG_DSTR_STATIC
; 
 999     } else if (free_proc 
== ARG_DSTR_VOLATILE
) { 
1000         length 
= (int)strlen(str
); 
1001         if (length 
> ARG_DSTR_SIZE
) { 
1002             ds
->data 
= (char*)xmalloc((unsigned)length 
+ 1); 
1003             ds
->free_proc 
= ARG_DSTR_DYNAMIC
; 
1005             ds
->data 
= ds
->sbuf
; 
1006             ds
->free_proc 
= ARG_DSTR_STATIC
; 
1008         strcpy(ds
->data
, str
); 
1011         ds
->free_proc 
= free_proc
; 
1015      * If the old result was dynamically-allocated, free it up. Do it here, 
1016      * rather than at the beginning, in case the new result value was part of 
1017      * the old result value. 
1020     if ((old_free_proc 
!= 0) && (old_result 
!= ds
->data
)) { 
1021         if (old_free_proc 
== ARG_DSTR_DYNAMIC
) { 
1024             (*old_free_proc
)(old_result
); 
1028     if ((ds
->append_data 
!= NULL
) && (ds
->append_data_size 
> 0)) { 
1029         xfree(ds
->append_data
); 
1030         ds
->append_data 
= NULL
; 
1031         ds
->append_data_size 
= 0; 
1035 char* arg_dstr_cstr(arg_dstr_t ds
) /* Interpreter whose result to return. */ 
1040 void arg_dstr_cat(arg_dstr_t ds
, const char* str
) { 
1041     setup_append_buf(ds
, (int)strlen(str
) + 1); 
1042     memcpy(ds
->data 
+ strlen(ds
->data
), str
, strlen(str
)); 
1045 void arg_dstr_catc(arg_dstr_t ds
, char c
) { 
1046     setup_append_buf(ds
, 2); 
1047     memcpy(ds
->data 
+ strlen(ds
->data
), &c
, 1); 
1051  * The logic of the `arg_dstr_catf` function is adapted from the `bformat` 
1052  * function in The Better String Library by Paul Hsieh. Here is the copyright 
1053  * notice from the library: 
1055  * Copyright (c) 2014, Paul Hsieh 
1056  * All rights reserved. 
1058  * Redistribution and use in source and binary forms, with or without 
1059  * modification, are permitted provided that the following conditions are met: 
1061  * * Redistributions of source code must retain the above copyright notice, this 
1062  *   list of conditions and the following disclaimer. 
1064  * * Redistributions in binary form must reproduce the above copyright notice, 
1065  *   this list of conditions and the following disclaimer in the documentation 
1066  *   and/or other materials provided with the distribution. 
1068  * * Neither the name of bstrlib nor the names of its 
1069  *   contributors may be used to endorse or promote products derived from 
1070  *   this software without specific prior written permission. 
1072  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
1073  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
1074  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
1075  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 
1076  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
1077  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
1078  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
1079  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
1080  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
1081  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
1083 void arg_dstr_catf(arg_dstr_t ds
, const char* fmt
, ...) { 
1092     /* Since the length is not determinable beforehand, a search is 
1093        performed using the truncating "vsnprintf" call (to avoid buffer 
1094        overflows) on increasing potential sizes for the output result. */ 
1096     if ((n 
= (int)(2 * strlen(fmt
))) < START_VSNBUFF
) 
1099     buff 
= (char*)xmalloc(n 
+ 2); 
1100     memset(buff
, 0, n 
+ 2); 
1103         va_start(arglist
, fmt
); 
1104         r 
= vsnprintf(buff
, n 
+ 1, fmt
, arglist
); 
1107         slen 
= strlen(buff
); 
1108         if (slen 
< (size_t)n
) 
1117         buff 
= (char*)xmalloc(n 
+ 2); 
1118         memset(buff
, 0, n 
+ 2); 
1121     arg_dstr_cat(ds
, buff
); 
1125 static void setup_append_buf(arg_dstr_t ds
, int new_space
) { 
1129      * Make the append buffer larger, if that's necessary, then copy the 
1130      * data into the append buffer and make the append buffer the official 
1133     if (ds
->data 
!= ds
->append_data
) { 
1135          * If the buffer is too big, then free it up so we go back to a 
1136          * smaller buffer. This avoids tying up memory forever after a large 
1139         if (ds
->append_data_size 
> 500) { 
1140             xfree(ds
->append_data
); 
1141             ds
->append_data 
= NULL
; 
1142             ds
->append_data_size 
= 0; 
1144         ds
->append_used 
= (int)strlen(ds
->data
); 
1145     } else if (ds
->data
[ds
->append_used
] != 0) { 
1147          * Most likely someone has modified a result created by 
1148          * arg_dstr_cat et al. so that it has a different size. Just 
1149          * recompute the size. 
1151         ds
->append_used 
= (int)strlen(ds
->data
); 
1154     total_space 
= new_space 
+ ds
->append_used
; 
1155     if (total_space 
>= ds
->append_data_size
) { 
1158         if (total_space 
< 100) { 
1163         newbuf 
= (char*)xmalloc((unsigned)total_space
); 
1164         memset(newbuf
, 0, total_space
); 
1165         strcpy(newbuf
, ds
->data
); 
1166         if (ds
->append_data 
!= NULL
) { 
1167             xfree(ds
->append_data
); 
1169         ds
->append_data 
= newbuf
; 
1170         ds
->append_data_size 
= total_space
; 
1171     } else if (ds
->data 
!= ds
->append_data
) { 
1172         strcpy(ds
->append_data
, ds
->data
); 
1176     ds
->data 
= ds
->append_data
; 
1179 void arg_dstr_free(arg_dstr_t ds
) { 
1180     if (ds
->free_proc 
!= NULL
) { 
1181         if (ds
->free_proc 
== ARG_DSTR_DYNAMIC
) { 
1184             (*ds
->free_proc
)(ds
->data
); 
1186         ds
->free_proc 
= NULL
; 
1190 void arg_dstr_reset(arg_dstr_t ds
) { 
1192     if ((ds
->append_data 
!= NULL
) && (ds
->append_data_size 
> 0)) { 
1193         xfree(ds
->append_data
); 
1194         ds
->append_data 
= NULL
; 
1195         ds
->append_data_size 
= 0; 
1198     ds
->data 
= ds
->sbuf
; 
1202 #if defined(_MSC_VER) 
1203 #pragma warning(pop) 
1205 /*      $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $    */ 
1209  * SPDX-License-Identifier: BSD-2-Clause-NetBSD 
1211  * Copyright (c) 2000 The NetBSD Foundation, Inc. 
1212  * All rights reserved. 
1214  * This code is derived from software contributed to The NetBSD Foundation 
1215  * by Dieter Baron and Thomas Klausner. 
1217  * Redistribution and use in source and binary forms, with or without 
1218  * modification, are permitted provided that the following conditions 
1220  * 1. Redistributions of source code must retain the above copyright 
1221  *    notice, this list of conditions and the following disclaimer. 
1222  * 2. Redistributions in binary form must reproduce the above copyright 
1223  *    notice, this list of conditions and the following disclaimer in the 
1224  *    documentation and/or other materials provided with the distribution. 
1226  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 
1227  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 
1228  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
1229  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 
1230  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
1231  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
1232  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
1233  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
1234  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
1235  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
1236  * POSSIBILITY OF SUCH DAMAGE. 
1239 #if ARG_REPLACE_GETOPT == 1 
1245  * GNU-like getopt_long()/getopt_long_only() with 4.4BSD optreset extension. 
1246  * getopt() is declared here too for GNU programs. 
1248 #define no_argument        0 
1249 #define required_argument  1 
1250 #define optional_argument  2 
1253         /* name of long option */ 
1256          * one of no_argument, required_argument, and optional_argument: 
1257          * whether option takes an argument 
1260         /* if not NULL, set *flag to val when option found */ 
1262         /* if flag not NULL, value to set *flag to; else return value */ 
1270 int     getopt_long(int, char * const *, const char *, 
1271         const struct option 
*, int *); 
1272 int     getopt_long_only(int, char * const *, const char *, 
1273         const struct option 
*, int *); 
1274 #ifndef _GETOPT_DECLARED 
1275 #define _GETOPT_DECLARED 
1276 int getopt(int, char * const [], const char *); 
1278 extern char *optarg
;                    /* getopt(3) external variables */ 
1279 extern int optind
, opterr
, optopt
; 
1281 #ifndef _OPTRESET_DECLARED 
1282 #define _OPTRESET_DECLARED 
1283 extern int optreset
;                    /* getopt(3) external variable */ 
1290 #endif /* !_GETOPT_H_ */ 
1292 #endif /* ARG_REPLACE_GETOPT == 1 */ 
1293 /*      $OpenBSD: getopt_long.c,v 1.26 2013/06/08 22:47:56 millert Exp $        */ 
1294 /*      $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $      */ 
1297  * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com> 
1299  * Permission to use, copy, modify, and distribute this software for any 
1300  * purpose with or without fee is hereby granted, provided that the above 
1301  * copyright notice and this permission notice appear in all copies. 
1303  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 
1304  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 
1305  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 
1306  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 
1307  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
1308  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
1309  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
1311  * Sponsored in part by the Defense Advanced Research Projects 
1312  * Agency (DARPA) and Air Force Research Laboratory, Air Force 
1313  * Materiel Command, USAF, under agreement number F39502-99-1-0512. 
1316  * Copyright (c) 2000 The NetBSD Foundation, Inc. 
1317  * All rights reserved. 
1319  * This code is derived from software contributed to The NetBSD Foundation 
1320  * by Dieter Baron and Thomas Klausner. 
1322  * Redistribution and use in source and binary forms, with or without 
1323  * modification, are permitted provided that the following conditions 
1325  * 1. Redistributions of source code must retain the above copyright 
1326  *    notice, this list of conditions and the following disclaimer. 
1327  * 2. Redistributions in binary form must reproduce the above copyright 
1328  *    notice, this list of conditions and the following disclaimer in the 
1329  *    documentation and/or other materials provided with the distribution. 
1331  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 
1332  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 
1333  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
1334  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 
1335  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
1336  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
1337  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
1338  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
1339  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
1340  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
1341  * POSSIBILITY OF SUCH DAMAGE. 
1344 #include "argtable3.h" 
1346 #if ARG_REPLACE_GETOPT == 1 
1348 #ifndef ARG_AMALGAMATION 
1349 #include "arg_getopt.h" 
1356 #define GNU_COMPATIBLE          /* Be more compatible, configure's use us! */ 
1358 int     opterr 
= 1;             /* if error message should be printed */ 
1359 int     optind 
= 1;             /* index into parent argv vector */ 
1360 int     optopt 
= '?';   /* character checked for validity */ 
1361 int     optreset
;               /* reset getopt */ 
1362 char *optarg
;           /* argument associated with option */ 
1364 #define PRINT_ERROR     ((opterr) && (*options != ':')) 
1366 #define FLAG_PERMUTE    0x01    /* permute non-options to the end of argv */ 
1367 #define FLAG_ALLARGS    0x02    /* treat non-options as args to option "-1" */ 
1368 #define FLAG_LONGONLY   0x04    /* operate as getopt_long_only */ 
1371 #define BADCH           (int)'?' 
1372 #define BADARG          ((*options == ':') ? (int)':' : (int)'?') 
1373 #define INORDER         (int)1 
1377 #ifdef GNU_COMPATIBLE 
1378 #define NO_PREFIX       (-1) 
1384 static int getopt_internal(int, char * const *, const char *, 
1385                            const struct option 
*, int *, int); 
1386 static int parse_long_options(char * const *, const char *, 
1387                               const struct option 
*, int *, int, int); 
1388 static int gcd(int, int); 
1389 static void permute_args(int, int, int, char * const *); 
1391 static char *place 
= EMSG
; /* option letter processing */ 
1393 /* XXX: set optreset to 1 rather than these two */ 
1394 static int nonopt_start 
= -1; /* first non option argument (for permute) */ 
1395 static int nonopt_end 
= -1;   /* first option after non options (for permute) */ 
1397 /* Error messages */ 
1398 static const char recargchar
[] = "option requires an argument -- %c"; 
1399 static const char illoptchar
[] = "illegal option -- %c"; /* From P1003.2 */ 
1400 #ifdef GNU_COMPATIBLE 
1401 static int dash_prefix 
= NO_PREFIX
; 
1402 static const char gnuoptchar
[] = "invalid option -- %c"; 
1404 static const char recargstring
[] = "option `%s%s' requires an argument"; 
1405 static const char ambig
[] = "option `%s%.*s' is ambiguous"; 
1406 static const char noarg
[] = "option `%s%.*s' doesn't allow an argument"; 
1407 static const char illoptstring
[] = "unrecognized option `%s%s'"; 
1409 static const char recargstring
[] = "option requires an argument -- %s"; 
1410 static const char ambig
[] = "ambiguous option -- %.*s"; 
1411 static const char noarg
[] = "option doesn't take an argument -- %.*s"; 
1412 static const char illoptstring
[] = "unknown option -- %s"; 
1418  * Windows needs warnx().  We change the definition though: 
1419  *  1. (another) global is defined, opterrmsg, which holds the error message 
1420  *  2. errors are always printed out on stderr w/o the program name 
1421  * Note that opterrmsg always gets set no matter what opterr is set to.  The 
1422  * error message will not be printed if opterr is 0 as usual. 
1428 #define MAX_OPTERRMSG_SIZE 128 
1430 extern char opterrmsg
[MAX_OPTERRMSG_SIZE
]; 
1431 char opterrmsg
[MAX_OPTERRMSG_SIZE
]; /* buffer for the last error message */ 
1433 static void warnx(const char* fmt
, ...) { 
1438      * Make sure opterrmsg is always zero-terminated despite the _vsnprintf() 
1439      * implementation specifics and manually suppress the warning. 
1441     memset(opterrmsg
, 0, sizeof(opterrmsg
)); 
1443 #if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__)) 
1444         _vsnprintf_s(opterrmsg
, sizeof(opterrmsg
), sizeof(opterrmsg
) - 1, fmt
, ap
); 
1446         _vsnprintf(opterrmsg
, sizeof(opterrmsg
) - 1, fmt
, ap
); 
1452 #pragma warning(suppress : 6053) 
1454     fprintf(stderr
, "%s\n", opterrmsg
); 
1461  * Compute the greatest common divisor of a and b. 
1479  * Exchange the block from nonopt_start to nonopt_end with the block 
1480  * from nonopt_end to opt_end (keeping the same order of arguments 
1484 permute_args(int panonopt_start
, int panonopt_end
, int opt_end
, 
1485         char * const *nargv
) 
1487         int cstart
, cyclelen
, i
, j
, ncycle
, nnonopts
, nopts
, pos
; 
1491          * compute lengths of blocks and number and size of cycles 
1493         nnonopts 
= panonopt_end 
- panonopt_start
; 
1494         nopts 
= opt_end 
- panonopt_end
; 
1495         ncycle 
= gcd(nnonopts
, nopts
); 
1496         cyclelen 
= (opt_end 
- panonopt_start
) / ncycle
; 
1498         for (i 
= 0; i 
< ncycle
; i
++) { 
1499                 cstart 
= panonopt_end
+i
; 
1501                 for (j 
= 0; j 
< cyclelen
; j
++) { 
1502                         if (pos 
>= panonopt_end
) 
1507                         /* LINTED const cast */ 
1508                         ((char **) nargv
)[pos
] = nargv
[cstart
]; 
1509                         /* LINTED const cast */ 
1510                         ((char **)nargv
)[cstart
] = swap
; 
1516  * parse_long_options -- 
1517  *      Parse long options in argc/argv argument vector. 
1518  * Returns -1 if short_too is set and the option does not match long_options. 
1521 parse_long_options(char * const *nargv
, const char *options
, 
1522         const struct option 
*long_options
, int *idx
, int short_too
, int flags
) 
1524         char *current_argv
, *has_equal
; 
1525 #ifdef GNU_COMPATIBLE 
1528         size_t current_argv_len
; 
1529         int i
, match
, exact_match
, second_partial_match
; 
1531         current_argv 
= place
; 
1532 #ifdef GNU_COMPATIBLE 
1533         switch (dash_prefix
) { 
1538                         current_dash 
= "--"; 
1541                         current_dash 
= "-W "; 
1550         second_partial_match 
= 0; 
1554         if ((has_equal 
= strchr(current_argv
, '=')) != NULL
) { 
1555                 /* argument found (--option=arg) */ 
1556                 current_argv_len 
= has_equal 
- current_argv
; 
1559                 current_argv_len 
= strlen(current_argv
); 
1561         for (i 
= 0; long_options
[i
].name
; i
++) { 
1562                 /* find matching long option */ 
1563                 if (strncmp(current_argv
, long_options
[i
].name
, 
1567                 if (strlen(long_options
[i
].name
) == current_argv_len
) { 
1574                  * If this is a known short option, don't allow 
1575                  * a partial match of a single character. 
1577                 if (short_too 
&& current_argv_len 
== 1) 
1580                 if (match 
== -1)        /* first partial match */ 
1582                 else if ((flags 
& FLAG_LONGONLY
) || 
1583                          long_options
[i
].has_arg 
!= 
1584                              long_options
[match
].has_arg 
|| 
1585                          long_options
[i
].flag 
!= long_options
[match
].flag 
|| 
1586                          long_options
[i
].val 
!= long_options
[match
].val
) 
1587                         second_partial_match 
= 1; 
1589         if (!exact_match 
&& second_partial_match
) { 
1590                 /* ambiguous abbreviation */ 
1593 #ifdef GNU_COMPATIBLE 
1596                              (int)current_argv_len
, 
1601         if (match 
!= -1) {              /* option found */ 
1602                 if (long_options
[match
].has_arg 
== no_argument
 
1606 #ifdef GNU_COMPATIBLE 
1609                                      (int)current_argv_len
, 
1612                          * XXX: GNU sets optopt to val regardless of flag 
1614                         if (long_options
[match
].flag 
== NULL
) 
1615                                 optopt 
= long_options
[match
].val
; 
1618 #ifdef GNU_COMPATIBLE 
1624                 if (long_options
[match
].has_arg 
== required_argument 
|| 
1625                     long_options
[match
].has_arg 
== optional_argument
) { 
1628                         else if (long_options
[match
].has_arg 
== 
1629                             required_argument
) { 
1631                                  * optional argument doesn't use next nargv 
1633                                 optarg 
= nargv
[optind
++]; 
1636                 if ((long_options
[match
].has_arg 
== required_argument
) 
1637                     && (optarg 
== NULL
)) { 
1639                          * Missing argument; leading ':' indicates no error 
1640                          * should be generated. 
1644 #ifdef GNU_COMPATIBLE 
1649                          * XXX: GNU sets optopt to val regardless of flag 
1651                         if (long_options
[match
].flag 
== NULL
) 
1652                                 optopt 
= long_options
[match
].val
; 
1658         } else {                        /* unknown option */ 
1665 #ifdef GNU_COMPATIBLE 
1674         if (long_options
[match
].flag
) { 
1675                 *long_options
[match
].flag 
= long_options
[match
].val
; 
1678                 return (long_options
[match
].val
); 
1682  * getopt_internal -- 
1683  *      Parse argc/argv argument vector.  Called by user level routines. 
1686 getopt_internal(int nargc
, char * const *nargv
, const char *options
, 
1687         const struct option 
*long_options
, int *idx
, int flags
) 
1689         char *oli
;                              /* option letter list index */ 
1690         int optchar
, short_too
; 
1691         static int posixly_correct 
= -1; 
1693         if (options 
== NULL
) 
1697          * XXX Some GNU programs (like cvs) set optind to 0 instead of 
1698          * XXX using optreset.  Work around this braindamage. 
1701                 optind 
= optreset 
= 1; 
1704          * Disable GNU extensions if POSIXLY_CORRECT is set or options 
1705          * string begins with a '+'. 
1707         if (posixly_correct 
== -1 || optreset
) { 
1709                 size_t requiredSize
; 
1710                 getenv_s(&requiredSize
, NULL
, 0, "POSIXLY_CORRECT"); 
1711                 posixly_correct 
= requiredSize 
!= 0; 
1713                 posixly_correct 
= (getenv("POSIXLY_CORRECT") != NULL
); 
1717         if (*options 
== '-') 
1718                 flags 
|= FLAG_ALLARGS
; 
1719         else if (posixly_correct 
|| *options 
== '+') 
1720                 flags 
&= ~FLAG_PERMUTE
; 
1721         if (*options 
== '+' || *options 
== '-') 
1726                 nonopt_start 
= nonopt_end 
= -1; 
1728         if (optreset 
|| !*place
) {              /* update scanning pointer */ 
1730                 if (optind 
>= nargc
) {          /* end of argument vector */ 
1732                         if (nonopt_end 
!= -1) { 
1733                                 /* do permutation, if we have to */ 
1734                                 permute_args(nonopt_start
, nonopt_end
, 
1736                                 optind 
-= nonopt_end 
- nonopt_start
; 
1738                         else if (nonopt_start 
!= -1) { 
1740                                  * If we skipped non-options, set optind 
1741                                  * to the first of them. 
1743                                 optind 
= nonopt_start
; 
1745                         nonopt_start 
= nonopt_end 
= -1; 
1748                 if (*(place 
= nargv
[optind
]) != '-' || 
1749 #ifdef GNU_COMPATIBLE 
1752                     (place
[1] == '\0' && strchr(options
, '-') == NULL
)) { 
1754                         place 
= EMSG
;           /* found non-option */ 
1755                         if (flags 
& FLAG_ALLARGS
) { 
1758                                  * return non-option as argument to option 1 
1760                                 optarg 
= nargv
[optind
++]; 
1763                         if (!(flags 
& FLAG_PERMUTE
)) { 
1765                                  * If no permutation wanted, stop parsing 
1766                                  * at first non-option. 
1770                         /* do permutation */ 
1771                         if (nonopt_start 
== -1) 
1772                                 nonopt_start 
= optind
; 
1773                         else if (nonopt_end 
!= -1) { 
1774                                 permute_args(nonopt_start
, nonopt_end
, 
1776                                 nonopt_start 
= optind 
- 
1777                                     (nonopt_end 
- nonopt_start
); 
1781                         /* process next argument */ 
1784                 if (nonopt_start 
!= -1 && nonopt_end 
== -1) 
1785                         nonopt_end 
= optind
; 
1788                  * If we have "-" do nothing, if "--" we are done. 
1790                 if (place
[1] != '\0' && *++place 
== '-' && place
[1] == '\0') { 
1794                          * We found an option (--), so if we skipped 
1795                          * non-options, we have to permute. 
1797                         if (nonopt_end 
!= -1) { 
1798                                 permute_args(nonopt_start
, nonopt_end
, 
1800                                 optind 
-= nonopt_end 
- nonopt_start
; 
1802                         nonopt_start 
= nonopt_end 
= -1; 
1808          * Check long options if: 
1809          *  1) we were passed some 
1810          *  2) the arg is not just "-" 
1811          *  3) either the arg starts with -- we are getopt_long_only() 
1813         if (long_options 
!= NULL 
&& place 
!= nargv
[optind
] && 
1814             (*place 
== '-' || (flags 
& FLAG_LONGONLY
))) { 
1816 #ifdef GNU_COMPATIBLE 
1817                 dash_prefix 
= D_PREFIX
; 
1819                 if (*place 
== '-') { 
1820                         place
++;                /* --foo long option */ 
1822                                 return (BADARG
);        /* malformed option */ 
1823 #ifdef GNU_COMPATIBLE 
1824                         dash_prefix 
= DD_PREFIX
; 
1826                 } else if (*place 
!= ':' && strchr(options
, *place
) != NULL
) 
1827                         short_too 
= 1;          /* could be short option too */ 
1829                 optchar 
= parse_long_options(nargv
, options
, long_options
, 
1830                     idx
, short_too
, flags
); 
1831                 if (optchar 
!= -1) { 
1837         if ((optchar 
= (int)*place
++) == (int)':' || 
1838             (optchar 
== (int)'-' && *place 
!= '\0') || 
1839             (oli 
= strchr(options
, optchar
)) == NULL
) { 
1841                  * If the user specified "-" and  '-' isn't listed in 
1842                  * options, return -1 (non-option) as per POSIX. 
1843                  * Otherwise, it is an unknown option character (or ':'). 
1845                 if (optchar 
== (int)'-' && *place 
== '\0') 
1849 #ifdef GNU_COMPATIBLE 
1851                         warnx(posixly_correct 
? illoptchar 
: gnuoptchar
, 
1855                         warnx(illoptchar
, optchar
); 
1860         if (long_options 
!= NULL 
&& optchar 
== 'W' && oli
[1] == ';') { 
1861                 /* -W long-option */ 
1862                 if (*place
)                     /* no space */ 
1864                 else if (++optind 
>= nargc
) {   /* no arg */ 
1867                                 warnx(recargchar
, optchar
); 
1870                 } else                          /* white space */ 
1871                         place 
= nargv
[optind
]; 
1872 #ifdef GNU_COMPATIBLE 
1873                 dash_prefix 
= W_PREFIX
; 
1875                 optchar 
= parse_long_options(nargv
, options
, long_options
, 
1880         if (*++oli 
!= ':') {                    /* doesn't take argument */ 
1883         } else {                                /* takes (optional) argument */ 
1885                 if (*place
)                     /* no white space */ 
1887                 else if (oli
[1] != ':') {       /* arg not optional */ 
1888                         if (++optind 
>= nargc
) {        /* no arg */ 
1891                                         warnx(recargchar
, optchar
); 
1895                                 optarg 
= nargv
[optind
]; 
1900         /* dump back option letter */ 
1906  *      Parse argc/argv argument vector. 
1908  * [eventually this will replace the BSD getopt] 
1911 getopt(int nargc
, char * const *nargv
, const char *options
) 
1915          * We don't pass FLAG_PERMUTE to getopt_internal() since 
1916          * the BSD getopt(3) (unlike GNU) has never done this. 
1918          * Furthermore, since many privileged programs call getopt() 
1919          * before dropping privileges it makes sense to keep things 
1920          * as simple (and bug-free) as possible. 
1922         return (getopt_internal(nargc
, nargv
, options
, NULL
, NULL
, 0)); 
1927  *      Parse argc/argv argument vector. 
1930 getopt_long(int nargc
, char * const *nargv
, const char *options
, 
1931         const struct option 
*long_options
, int *idx
) 
1934         return (getopt_internal(nargc
, nargv
, options
, long_options
, idx
, 
1939  * getopt_long_only -- 
1940  *      Parse argc/argv argument vector. 
1943 getopt_long_only(int nargc
, char * const *nargv
, const char *options
, 
1944         const struct option 
*long_options
, int *idx
) 
1947         return (getopt_internal(nargc
, nargv
, options
, long_options
, idx
, 
1948             FLAG_PERMUTE
|FLAG_LONGONLY
)); 
1951 #endif /* ARG_REPLACE_GETOPT == 1 */ 
1952 /******************************************************************************* 
1953  * arg_date: Implements the date command-line option 
1955  * This file is part of the argtable3 library. 
1957  * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann 
1958  * <sheitmann@users.sourceforge.net> 
1959  * All rights reserved. 
1961  * Redistribution and use in source and binary forms, with or without 
1962  * modification, are permitted provided that the following conditions are met: 
1963  *     * Redistributions of source code must retain the above copyright 
1964  *       notice, this list of conditions and the following disclaimer. 
1965  *     * Redistributions in binary form must reproduce the above copyright 
1966  *       notice, this list of conditions and the following disclaimer in the 
1967  *       documentation and/or other materials provided with the distribution. 
1968  *     * Neither the name of STEWART HEITMANN nor the  names of its contributors 
1969  *       may be used to endorse or promote products derived from this software 
1970  *       without specific prior written permission. 
1972  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
1973  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
1974  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
1975  * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, 
1976  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
1977  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
1978  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
1979  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
1980  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
1981  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
1982  ******************************************************************************/ 
1984 #include "argtable3.h" 
1986 #ifndef ARG_AMALGAMATION 
1987 #include "argtable3_private.h" 
1993 char* arg_strptime(const char* buf
, const char* fmt
, struct tm
* tm
); 
1995 static void arg_date_resetfn(struct arg_date
* parent
) { 
1996     ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
)); 
2000 static int arg_date_scanfn(struct arg_date
* parent
, const char* argval
) { 
2003     if (parent
->count 
== parent
->hdr
.maxcount
) { 
2004         errorcode 
= ARG_ERR_MAXCOUNT
; 
2005     } else if (!argval
) { 
2006         /* no argument value was given, leave parent->tmval[] unaltered but still count it */ 
2010         struct tm tm 
= parent
->tmval
[parent
->count
]; 
2012         /* parse the given argument value, store result in parent->tmval[] */ 
2013         pend 
= arg_strptime(argval
, parent
->format
, &tm
); 
2014         if (pend 
&& pend
[0] == '\0') 
2015             parent
->tmval
[parent
->count
++] = tm
; 
2017             errorcode 
= ARG_ERR_BADDATE
; 
2020     ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__
, parent
, errorcode
)); 
2024 static int arg_date_checkfn(struct arg_date
* parent
) { 
2025     int errorcode 
= (parent
->count 
< parent
->hdr
.mincount
) ? ARG_ERR_MINCOUNT 
: 0; 
2027     ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__
, parent
, errorcode
)); 
2031 static void arg_date_errorfn(struct arg_date
* parent
, arg_dstr_t ds
, int errorcode
, const char* argval
, const char* progname
) { 
2032     const char* shortopts 
= parent
->hdr
.shortopts
; 
2033     const char* longopts 
= parent
->hdr
.longopts
; 
2034     const char* datatype 
= parent
->hdr
.datatype
; 
2036     /* make argval NULL safe */ 
2037     argval 
= argval 
? argval 
: ""; 
2039     arg_dstr_catf(ds
, "%s: ", progname
); 
2040     switch (errorcode
) { 
2041         case ARG_ERR_MINCOUNT
: 
2042             arg_dstr_cat(ds
, "missing option "); 
2043             arg_print_option_ds(ds
, shortopts
, longopts
, datatype
, "\n"); 
2046         case ARG_ERR_MAXCOUNT
: 
2047             arg_dstr_cat(ds
, "excess option "); 
2048             arg_print_option_ds(ds
, shortopts
, longopts
, argval
, "\n"); 
2051         case ARG_ERR_BADDATE
: { 
2055             arg_dstr_catf(ds
, "illegal timestamp format \"%s\"\n", argval
); 
2056             memset(&tm
, 0, sizeof(tm
)); 
2057             arg_strptime("1999-12-31 23:59:59", "%F %H:%M:%S", &tm
); 
2058             strftime(buff
, sizeof(buff
), parent
->format
, &tm
); 
2059             arg_dstr_catf(ds
, "correct format is \"%s\"\n", buff
); 
2065 struct arg_date
* arg_date0(const char* shortopts
, const char* longopts
, const char* format
, const char* datatype
, const char* glossary
) { 
2066     return arg_daten(shortopts
, longopts
, format
, datatype
, 0, 1, glossary
); 
2069 struct arg_date
* arg_date1(const char* shortopts
, const char* longopts
, const char* format
, const char* datatype
, const char* glossary
) { 
2070     return arg_daten(shortopts
, longopts
, format
, datatype
, 1, 1, glossary
); 
2074 arg_daten(const char* shortopts
, const char* longopts
, const char* format
, const char* datatype
, int mincount
, int maxcount
, const char* glossary
) { 
2076     struct arg_date
* result
; 
2078     /* foolproof things by ensuring maxcount is not less than mincount */ 
2079     maxcount 
= (maxcount 
< mincount
) ? mincount 
: maxcount
; 
2081     /* default time format is the national date format for the locale */ 
2085     nbytes 
= sizeof(struct arg_date
)         /* storage for struct arg_date */ 
2086              + maxcount 
* sizeof(struct tm
); /* storage for tmval[maxcount] array */ 
2088     /* allocate storage for the arg_date struct + tmval[] array.    */ 
2089     /* we use calloc because we want the tmval[] array zero filled. */ 
2090     result 
= (struct arg_date
*)xcalloc(1, nbytes
); 
2092     /* init the arg_hdr struct */ 
2093     result
->hdr
.flag 
= ARG_HASVALUE
; 
2094     result
->hdr
.shortopts 
= shortopts
; 
2095     result
->hdr
.longopts 
= longopts
; 
2096     result
->hdr
.datatype 
= datatype 
? datatype 
: format
; 
2097     result
->hdr
.glossary 
= glossary
; 
2098     result
->hdr
.mincount 
= mincount
; 
2099     result
->hdr
.maxcount 
= maxcount
; 
2100     result
->hdr
.parent 
= result
; 
2101     result
->hdr
.resetfn 
= (arg_resetfn
*)arg_date_resetfn
; 
2102     result
->hdr
.scanfn 
= (arg_scanfn
*)arg_date_scanfn
; 
2103     result
->hdr
.checkfn 
= (arg_checkfn
*)arg_date_checkfn
; 
2104     result
->hdr
.errorfn 
= (arg_errorfn
*)arg_date_errorfn
; 
2106     /* store the tmval[maxcount] array immediately after the arg_date struct */ 
2107     result
->tmval 
= (struct tm
*)(result 
+ 1); 
2109     /* init the remaining arg_date member variables */ 
2111     result
->format 
= format
; 
2113     ARG_TRACE(("arg_daten() returns %p\n", result
)); 
2118  * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc. 
2119  * All rights reserved. 
2121  * This code was contributed to The NetBSD Foundation by Klaus Klein. 
2122  * Heavily optimised by David Laight 
2124  * Redistribution and use in source and binary forms, with or without 
2125  * modification, are permitted provided that the following conditions 
2127  * 1. Redistributions of source code must retain the above copyright 
2128  *    notice, this list of conditions and the following disclaimer. 
2129  * 2. Redistributions in binary form must reproduce the above copyright 
2130  *    notice, this list of conditions and the following disclaimer in the 
2131  *    documentation and/or other materials provided with the distribution. 
2133  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 
2134  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 
2135  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
2136  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 
2137  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
2138  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
2139  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
2140  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
2141  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
2142  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
2143  * POSSIBILITY OF SUCH DAMAGE. 
2151  * We do not implement alternate representations. However, we always 
2152  * check whether a given modifier is allowed for a certain conversion. 
2156 #define LEGAL_ALT(x)           \ 
2158         if (alt_format & ~(x)) \ 
2161 #define TM_YEAR_BASE (1900) 
2163 static int conv_num(const char**, int*, int, int); 
2165 static const char* day
[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; 
2167 static const char* abday
[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; 
2169 static const char* mon
[12] = {"January", "February", "March",     "April",   "May",      "June", 
2170                               "July",    "August",   "September", "October", "November", "December"}; 
2172 static const char* abmon
[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; 
2174 static const char* am_pm
[2] = {"AM", "PM"}; 
2176 static int arg_strcasecmp(const char* s1
, const char* s2
) { 
2177     const unsigned char* us1 
= (const unsigned char*)s1
; 
2178     const unsigned char* us2 
= (const unsigned char*)s2
; 
2179     while (tolower(*us1
) == tolower(*us2
++)) 
2183     return tolower(*us1
) - tolower(*--us2
); 
2186 static int arg_strncasecmp(const char* s1
, const char* s2
, size_t n
) { 
2188         const unsigned char* us1 
= (const unsigned char*)s1
; 
2189         const unsigned char* us2 
= (const unsigned char*)s2
; 
2191             if (tolower(*us1
) != tolower(*us2
++)) 
2192                 return tolower(*us1
) - tolower(*--us2
); 
2202 char* arg_strptime(const char* buf
, const char* fmt
, struct tm
* tm
) { 
2206     int alt_format
, i
, split_year 
= 0; 
2210     while ((c 
= *fmt
) != '\0') { 
2211         /* Clear `alternate' modifier prior to new conversion. */ 
2214         /* Eat up white-space. */ 
2216             while (isspace(*bp
)) 
2223         if ((c 
= *fmt
++) != '%') 
2227         switch (c 
= *fmt
++) { 
2228             case '%': /* "%%" is converted to "%". */ 
2235              * "Alternative" modifiers. Just set the appropriate flag 
2236              * and start over again. 
2238             case 'E': /* "%E?" alternative conversion modifier. */ 
2240                 alt_format 
|= ALT_E
; 
2243             case 'O': /* "%O?" alternative conversion modifier. */ 
2245                 alt_format 
|= ALT_O
; 
2249              * "Complex" conversion rules, implemented through recursion. 
2251             case 'c': /* Date and time, using the locale's format. */ 
2253                 bp 
= arg_strptime(bp
, "%x %X", tm
); 
2258             case 'D': /* The date as "%m/%d/%y". */ 
2260                 bp 
= arg_strptime(bp
, "%m/%d/%y", tm
); 
2265             case 'R': /* The time as "%H:%M". */ 
2267                 bp 
= arg_strptime(bp
, "%H:%M", tm
); 
2272             case 'r': /* The time in 12-hour clock representation. */ 
2274                 bp 
= arg_strptime(bp
, "%I:%M:%S %p", tm
); 
2279             case 'T': /* The time as "%H:%M:%S". */ 
2281                 bp 
= arg_strptime(bp
, "%H:%M:%S", tm
); 
2286             case 'X': /* The time, using the locale's format. */ 
2288                 bp 
= arg_strptime(bp
, "%H:%M:%S", tm
); 
2293             case 'x': /* The date, using the locale's format. */ 
2295                 bp 
= arg_strptime(bp
, "%m/%d/%y", tm
); 
2301              * "Elementary" conversion rules. 
2303             case 'A': /* The day of week, using the locale's form. */ 
2306                 for (i 
= 0; i 
< 7; i
++) { 
2308                     len 
= strlen(day
[i
]); 
2309                     if (arg_strncasecmp(day
[i
], bp
, len
) == 0) 
2312                     /* Abbreviated name. */ 
2313                     len 
= strlen(abday
[i
]); 
2314                     if (arg_strncasecmp(abday
[i
], bp
, len
) == 0) 
2318                 /* Nothing matched. */ 
2326             case 'B': /* The month, using the locale's form. */ 
2330                 for (i 
= 0; i 
< 12; i
++) { 
2332                     len 
= strlen(mon
[i
]); 
2333                     if (arg_strncasecmp(mon
[i
], bp
, len
) == 0) 
2336                     /* Abbreviated name. */ 
2337                     len 
= strlen(abmon
[i
]); 
2338                     if (arg_strncasecmp(abmon
[i
], bp
, len
) == 0) 
2342                 /* Nothing matched. */ 
2350             case 'C': /* The century number. */ 
2352                 if (!(conv_num(&bp
, &i
, 0, 99))) 
2356                     tm
->tm_year 
= (tm
->tm_year 
% 100) + (i 
* 100); 
2358                     tm
->tm_year 
= i 
* 100; 
2363             case 'd': /* The day of month. */ 
2366                 if (!(conv_num(&bp
, &tm
->tm_mday
, 1, 31))) 
2370             case 'k': /* The hour (24-hour clock representation). */ 
2375                 if (!(conv_num(&bp
, &tm
->tm_hour
, 0, 23))) 
2379             case 'l': /* The hour (12-hour clock representation). */ 
2384                 if (!(conv_num(&bp
, &tm
->tm_hour
, 1, 12))) 
2386                 if (tm
->tm_hour 
== 12) 
2390             case 'j': /* The day of year. */ 
2392                 if (!(conv_num(&bp
, &i
, 1, 366))) 
2394                 tm
->tm_yday 
= i 
- 1; 
2397             case 'M': /* The minute. */ 
2399                 if (!(conv_num(&bp
, &tm
->tm_min
, 0, 59))) 
2403             case 'm': /* The month. */ 
2405                 if (!(conv_num(&bp
, &i
, 1, 12))) 
2410             case 'p': /* The locale's equivalent of AM/PM. */ 
2413                 if (arg_strcasecmp(am_pm
[0], bp
) == 0) { 
2414                     if (tm
->tm_hour 
> 11) 
2417                     bp 
+= strlen(am_pm
[0]); 
2421                 else if (arg_strcasecmp(am_pm
[1], bp
) == 0) { 
2422                     if (tm
->tm_hour 
> 11) 
2426                     bp 
+= strlen(am_pm
[1]); 
2430                 /* Nothing matched. */ 
2433             case 'S': /* The seconds. */ 
2435                 if (!(conv_num(&bp
, &tm
->tm_sec
, 0, 61))) 
2439             case 'U': /* The week of year, beginning on sunday. */ 
2440             case 'W': /* The week of year, beginning on monday. */ 
2443                  * XXX This is bogus, as we can not assume any valid 
2444                  * information present in the tm structure at this 
2445                  * point to calculate a real value, so just check the 
2448                 if (!(conv_num(&bp
, &i
, 0, 53))) 
2452             case 'w': /* The day of week, beginning on sunday. */ 
2454                 if (!(conv_num(&bp
, &tm
->tm_wday
, 0, 6))) 
2458             case 'Y': /* The year. */ 
2460                 if (!(conv_num(&bp
, &i
, 0, 9999))) 
2463                 tm
->tm_year 
= i 
- TM_YEAR_BASE
; 
2466             case 'y': /* The year within 100 years of the epoch. */ 
2467                 LEGAL_ALT(ALT_E 
| ALT_O
); 
2468                 if (!(conv_num(&bp
, &i
, 0, 99))) 
2472                     tm
->tm_year 
= ((tm
->tm_year 
/ 100) * 100) + i
; 
2477                     tm
->tm_year 
= i 
+ 2000 - TM_YEAR_BASE
; 
2479                     tm
->tm_year 
= i 
+ 1900 - TM_YEAR_BASE
; 
2483              * Miscellaneous conversions. 
2485             case 'n': /* Any kind of white-space. */ 
2488                 while (isspace(*bp
)) 
2492             default: /* Unknown/unsupported conversion. */ 
2497     /* LINTED functional specification */ 
2501 static int conv_num(const char** buf
, int* dest
, int llim
, int ulim
) { 
2504     /* The limit also determines the number of valid digits. */ 
2507     if (**buf 
< '0' || **buf 
> '9') 
2512         result 
+= *(*buf
)++ - '0'; 
2514     } while ((result 
* 10 <= ulim
) && rulim 
&& **buf 
>= '0' && **buf 
<= '9'); 
2516     if (result 
< llim 
|| result 
> ulim
) 
2522 /******************************************************************************* 
2523  * arg_dbl: Implements the double command-line option 
2525  * This file is part of the argtable3 library. 
2527  * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann 
2528  * <sheitmann@users.sourceforge.net> 
2529  * All rights reserved. 
2531  * Redistribution and use in source and binary forms, with or without 
2532  * modification, are permitted provided that the following conditions are met: 
2533  *     * Redistributions of source code must retain the above copyright 
2534  *       notice, this list of conditions and the following disclaimer. 
2535  *     * Redistributions in binary form must reproduce the above copyright 
2536  *       notice, this list of conditions and the following disclaimer in the 
2537  *       documentation and/or other materials provided with the distribution. 
2538  *     * Neither the name of STEWART HEITMANN nor the  names of its contributors 
2539  *       may be used to endorse or promote products derived from this software 
2540  *       without specific prior written permission. 
2542  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
2543  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
2544  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
2545  * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, 
2546  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
2547  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
2548  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
2549  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
2550  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
2551  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
2552  ******************************************************************************/ 
2554 #include "argtable3.h" 
2556 #ifndef ARG_AMALGAMATION 
2557 #include "argtable3_private.h" 
2562 static void arg_dbl_resetfn(struct arg_dbl
* parent
) { 
2563     ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
)); 
2567 static int arg_dbl_scanfn(struct arg_dbl
* parent
, const char* argval
) { 
2570     if (parent
->count 
== parent
->hdr
.maxcount
) { 
2571         /* maximum number of arguments exceeded */ 
2572         errorcode 
= ARG_ERR_MAXCOUNT
; 
2573     } else if (!argval
) { 
2574         /* a valid argument with no argument value was given. */ 
2575         /* This happens when an optional argument value was invoked. */ 
2576         /* leave parent argument value unaltered but still count the argument. */ 
2582         /* extract double from argval into val */ 
2583         val 
= strtod(argval
, &end
); 
2585         /* if success then store result in parent->dval[] array otherwise return error*/ 
2587             parent
->dval
[parent
->count
++] = val
; 
2589             errorcode 
= ARG_ERR_BADDOUBLE
; 
2592     ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__
, parent
, errorcode
)); 
2596 static int arg_dbl_checkfn(struct arg_dbl
* parent
) { 
2597     int errorcode 
= (parent
->count 
< parent
->hdr
.mincount
) ? ARG_ERR_MINCOUNT 
: 0; 
2599     ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__
, parent
, errorcode
)); 
2603 static void arg_dbl_errorfn(struct arg_dbl
* parent
, arg_dstr_t ds
, int errorcode
, const char* argval
, const char* progname
) { 
2604     const char* shortopts 
= parent
->hdr
.shortopts
; 
2605     const char* longopts 
= parent
->hdr
.longopts
; 
2606     const char* datatype 
= parent
->hdr
.datatype
; 
2608     /* make argval NULL safe */ 
2609     argval 
= argval 
? argval 
: ""; 
2611     arg_dstr_catf(ds
, "%s: ", progname
); 
2612     switch (errorcode
) { 
2613         case ARG_ERR_MINCOUNT
: 
2614             arg_dstr_cat(ds
, "missing option "); 
2615             arg_print_option_ds(ds
, shortopts
, longopts
, datatype
, "\n"); 
2618         case ARG_ERR_MAXCOUNT
: 
2619             arg_dstr_cat(ds
, "excess option "); 
2620             arg_print_option_ds(ds
, shortopts
, longopts
, argval
, "\n"); 
2623         case ARG_ERR_BADDOUBLE
: 
2624             arg_dstr_catf(ds
, "invalid argument \"%s\" to option ", argval
); 
2625             arg_print_option_ds(ds
, shortopts
, longopts
, datatype
, "\n"); 
2630 struct arg_dbl
* arg_dbl0(const char* shortopts
, const char* longopts
, const char* datatype
, const char* glossary
) { 
2631     return arg_dbln(shortopts
, longopts
, datatype
, 0, 1, glossary
); 
2634 struct arg_dbl
* arg_dbl1(const char* shortopts
, const char* longopts
, const char* datatype
, const char* glossary
) { 
2635     return arg_dbln(shortopts
, longopts
, datatype
, 1, 1, glossary
); 
2638 struct arg_dbl
* arg_dbln(const char* shortopts
, const char* longopts
, const char* datatype
, int mincount
, int maxcount
, const char* glossary
) { 
2640     struct arg_dbl
* result
; 
2644     /* foolproof things by ensuring maxcount is not less than mincount */ 
2645     maxcount 
= (maxcount 
< mincount
) ? mincount 
: maxcount
; 
2647     nbytes 
= sizeof(struct arg_dbl
)             /* storage for struct arg_dbl */ 
2648              + (maxcount 
+ 1) * sizeof(double); /* storage for dval[maxcount] array plus one extra for padding to memory boundary */ 
2650     result 
= (struct arg_dbl
*)xmalloc(nbytes
); 
2652     /* init the arg_hdr struct */ 
2653     result
->hdr
.flag 
= ARG_HASVALUE
; 
2654     result
->hdr
.shortopts 
= shortopts
; 
2655     result
->hdr
.longopts 
= longopts
; 
2656     result
->hdr
.datatype 
= datatype 
? datatype 
: "<double>"; 
2657     result
->hdr
.glossary 
= glossary
; 
2658     result
->hdr
.mincount 
= mincount
; 
2659     result
->hdr
.maxcount 
= maxcount
; 
2660     result
->hdr
.parent 
= result
; 
2661     result
->hdr
.resetfn 
= (arg_resetfn
*)arg_dbl_resetfn
; 
2662     result
->hdr
.scanfn 
= (arg_scanfn
*)arg_dbl_scanfn
; 
2663     result
->hdr
.checkfn 
= (arg_checkfn
*)arg_dbl_checkfn
; 
2664     result
->hdr
.errorfn 
= (arg_errorfn
*)arg_dbl_errorfn
; 
2666     /* Store the dval[maxcount] array on the first double boundary that 
2667      * immediately follows the arg_dbl struct. We do the memory alignment 
2668      * purely for SPARC and Motorola systems. They require floats and 
2669      * doubles to be aligned on natural boundaries. 
2671     addr 
= (size_t)(result 
+ 1); 
2672     rem 
= addr 
% sizeof(double); 
2673     result
->dval 
= (double*)(addr 
+ sizeof(double) - rem
); 
2674     ARG_TRACE(("addr=%p, dval=%p, sizeof(double)=%d rem=%d\n", addr
, result
->dval
, (int)sizeof(double), (int)rem
)); 
2678     ARG_TRACE(("arg_dbln() returns %p\n", result
)); 
2681 /******************************************************************************* 
2682  * arg_end: Implements the error handling utilities 
2684  * This file is part of the argtable3 library. 
2686  * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann 
2687  * <sheitmann@users.sourceforge.net> 
2688  * All rights reserved. 
2690  * Redistribution and use in source and binary forms, with or without 
2691  * modification, are permitted provided that the following conditions are met: 
2692  *     * Redistributions of source code must retain the above copyright 
2693  *       notice, this list of conditions and the following disclaimer. 
2694  *     * Redistributions in binary form must reproduce the above copyright 
2695  *       notice, this list of conditions and the following disclaimer in the 
2696  *       documentation and/or other materials provided with the distribution. 
2697  *     * Neither the name of STEWART HEITMANN nor the  names of its contributors 
2698  *       may be used to endorse or promote products derived from this software 
2699  *       without specific prior written permission. 
2701  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
2702  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
2703  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
2704  * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, 
2705  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
2706  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
2707  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
2708  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
2709  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
2710  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
2711  ******************************************************************************/ 
2713 #include "argtable3.h" 
2715 #ifndef ARG_AMALGAMATION 
2716 #include "argtable3_private.h" 
2721 static void arg_end_resetfn(struct arg_end
* parent
) { 
2722     ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
)); 
2726 static void arg_end_errorfn(void* parent
, arg_dstr_t ds
, int error
, const char* argval
, const char* progname
) { 
2727     /* suppress unreferenced formal parameter warning */ 
2730     progname 
= progname 
? progname 
: ""; 
2731     argval 
= argval 
? argval 
: ""; 
2733     arg_dstr_catf(ds
, "%s: ", progname
); 
2736             arg_dstr_cat(ds
, "too many errors to display"); 
2739             arg_dstr_cat(ds
, "insufficient memory"); 
2742             arg_dstr_catf(ds
, "unexpected argument \"%s\"", argval
); 
2745             arg_dstr_catf(ds
, "option \"%s\" requires an argument", argval
); 
2748             arg_dstr_catf(ds
, "invalid option \"%s\"", argval
); 
2751             arg_dstr_catf(ds
, "invalid option \"-%c\"", error
); 
2755     arg_dstr_cat(ds
, "\n"); 
2758 struct arg_end
* arg_end(int maxcount
) { 
2760     struct arg_end
* result
; 
2762     nbytes 
= sizeof(struct arg_end
) + maxcount 
* sizeof(int) /* storage for int error[maxcount] array*/ 
2763              + maxcount 
* sizeof(void*)                      /* storage for void* parent[maxcount] array */ 
2764              + maxcount 
* sizeof(char*);                     /* storage for char* argval[maxcount] array */ 
2766     result 
= (struct arg_end
*)xmalloc(nbytes
); 
2768     /* init the arg_hdr struct */ 
2769     result
->hdr
.flag 
= ARG_TERMINATOR
; 
2770     result
->hdr
.shortopts 
= NULL
; 
2771     result
->hdr
.longopts 
= NULL
; 
2772     result
->hdr
.datatype 
= NULL
; 
2773     result
->hdr
.glossary 
= NULL
; 
2774     result
->hdr
.mincount 
= 1; 
2775     result
->hdr
.maxcount 
= maxcount
; 
2776     result
->hdr
.parent 
= result
; 
2777     result
->hdr
.resetfn 
= (arg_resetfn
*)arg_end_resetfn
; 
2778     result
->hdr
.scanfn 
= NULL
; 
2779     result
->hdr
.checkfn 
= NULL
; 
2780     result
->hdr
.errorfn 
= (arg_errorfn
*)arg_end_errorfn
; 
2782     /* store error[maxcount] array immediately after struct arg_end */ 
2783     result
->error 
= (int*)(result 
+ 1); 
2785     /* store parent[maxcount] array immediately after error[] array */ 
2786     result
->parent 
= (void**)(result
->error 
+ maxcount
); 
2788     /* store argval[maxcount] array immediately after parent[] array */ 
2789     result
->argval 
= (const char**)(result
->parent 
+ maxcount
); 
2791     ARG_TRACE(("arg_end(%d) returns %p\n", maxcount
, result
)); 
2795 void arg_print_errors_ds(arg_dstr_t ds
, struct arg_end
* end
, const char* progname
) { 
2797     ARG_TRACE(("arg_errors()\n")); 
2798     for (i 
= 0; i 
< end
->count
; i
++) { 
2799         struct arg_hdr
* errorparent 
= (struct arg_hdr
*)(end
->parent
[i
]); 
2800         if (errorparent
->errorfn
) 
2801             errorparent
->errorfn(end
->parent
[i
], ds
, end
->error
[i
], end
->argval
[i
], progname
); 
2805 void arg_print_errors(FILE* fp
, struct arg_end
* end
, const char* progname
) { 
2806     arg_dstr_t ds 
= arg_dstr_create(); 
2807     arg_print_errors_ds(ds
, end
, progname
); 
2808     fputs(arg_dstr_cstr(ds
), fp
); 
2809     arg_dstr_destroy(ds
); 
2811 /******************************************************************************* 
2812  * arg_file: Implements the file command-line option 
2814  * This file is part of the argtable3 library. 
2816  * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann 
2817  * <sheitmann@users.sourceforge.net> 
2818  * All rights reserved. 
2820  * Redistribution and use in source and binary forms, with or without 
2821  * modification, are permitted provided that the following conditions are met: 
2822  *     * Redistributions of source code must retain the above copyright 
2823  *       notice, this list of conditions and the following disclaimer. 
2824  *     * Redistributions in binary form must reproduce the above copyright 
2825  *       notice, this list of conditions and the following disclaimer in the 
2826  *       documentation and/or other materials provided with the distribution. 
2827  *     * Neither the name of STEWART HEITMANN nor the  names of its contributors 
2828  *       may be used to endorse or promote products derived from this software 
2829  *       without specific prior written permission. 
2831  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
2832  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
2833  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
2834  * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, 
2835  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
2836  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
2837  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
2838  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
2839  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
2840  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
2841  ******************************************************************************/ 
2843 #include "argtable3.h" 
2845 #ifndef ARG_AMALGAMATION 
2846 #include "argtable3_private.h" 
2853 #define FILESEPARATOR1 '\\' 
2854 #define FILESEPARATOR2 '/' 
2856 #define FILESEPARATOR1 '/' 
2857 #define FILESEPARATOR2 '/' 
2860 static void arg_file_resetfn(struct arg_file
* parent
) { 
2861     ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
)); 
2865 /* Returns ptr to the base filename within *filename */ 
2866 static const char* arg_basename(const char* filename
) { 
2867     const char *result 
= NULL
, *result1
, *result2
; 
2869     /* Find the last occurrence of eother file separator character. */ 
2870     /* Two alternative file separator chars are supported as legal  */ 
2871     /* file separators but not both together in the same filename.  */ 
2872     result1 
= (filename 
? strrchr(filename
, FILESEPARATOR1
) : NULL
); 
2873     result2 
= (filename 
? strrchr(filename
, FILESEPARATOR2
) : NULL
); 
2876         result 
= result2 
+ 1; /* using FILESEPARATOR2 (the alternative file separator) */ 
2879         result 
= result1 
+ 1; /* using FILESEPARATOR1 (the preferred file separator) */ 
2882         result 
= filename
; /* neither file separator was found so basename is the whole filename */ 
2884     /* special cases of "." and ".." are not considered basenames */ 
2885     if (result 
&& (strcmp(".", result
) == 0 || strcmp("..", result
) == 0)) 
2886         result 
= filename 
+ strlen(filename
); 
2891 /* Returns ptr to the file extension within *basename */ 
2892 static const char* arg_extension(const char* basename
) { 
2893     /* find the last occurrence of '.' in basename */ 
2894     const char* result 
= (basename 
? strrchr(basename
, '.') : NULL
); 
2896     /* if no '.' was found then return pointer to end of basename */ 
2897     if (basename 
&& !result
) 
2898         result 
= basename 
+ strlen(basename
); 
2900     /* special case: basenames with a single leading dot (eg ".foo") are not considered as true extensions */ 
2901     if (basename 
&& result 
== basename
) 
2902         result 
= basename 
+ strlen(basename
); 
2904     /* special case: empty extensions (eg "foo.","foo..") are not considered as true extensions */ 
2905     if (basename 
&& result 
&& strlen(result
) == 1) 
2906         result 
= basename 
+ strlen(basename
); 
2911 static int arg_file_scanfn(struct arg_file
* parent
, const char* argval
) { 
2914     if (parent
->count 
== parent
->hdr
.maxcount
) { 
2915         /* maximum number of arguments exceeded */ 
2916         errorcode 
= ARG_ERR_MAXCOUNT
; 
2917     } else if (!argval
) { 
2918         /* a valid argument with no argument value was given. */ 
2919         /* This happens when an optional argument value was invoked. */ 
2920         /* leave parent arguiment value unaltered but still count the argument. */ 
2923         parent
->filename
[parent
->count
] = argval
; 
2924         parent
->basename
[parent
->count
] = arg_basename(argval
); 
2925         parent
->extension
[parent
->count
] = 
2926                 arg_extension(parent
->basename
[parent
->count
]); /* only seek extensions within the basename (not the file path)*/ 
2930     ARG_TRACE(("%s4:scanfn(%p) returns %d\n", __FILE__
, parent
, errorcode
)); 
2934 static int arg_file_checkfn(struct arg_file
* parent
) { 
2935     int errorcode 
= (parent
->count 
< parent
->hdr
.mincount
) ? ARG_ERR_MINCOUNT 
: 0; 
2937     ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__
, parent
, errorcode
)); 
2941 static void arg_file_errorfn(struct arg_file
* parent
, arg_dstr_t ds
, int errorcode
, const char* argval
, const char* progname
) { 
2942     const char* shortopts 
= parent
->hdr
.shortopts
; 
2943     const char* longopts 
= parent
->hdr
.longopts
; 
2944     const char* datatype 
= parent
->hdr
.datatype
; 
2946     /* make argval NULL safe */ 
2947     argval 
= argval 
? argval 
: ""; 
2949     arg_dstr_catf(ds
, "%s: ", progname
); 
2950     switch (errorcode
) { 
2951         case ARG_ERR_MINCOUNT
: 
2952             arg_dstr_cat(ds
, "missing option "); 
2953             arg_print_option_ds(ds
, shortopts
, longopts
, datatype
, "\n"); 
2956         case ARG_ERR_MAXCOUNT
: 
2957             arg_dstr_cat(ds
, "excess option "); 
2958             arg_print_option_ds(ds
, shortopts
, longopts
, argval
, "\n"); 
2962             arg_dstr_catf(ds
, "unknown error at \"%s\"\n", argval
); 
2966 struct arg_file
* arg_file0(const char* shortopts
, const char* longopts
, const char* datatype
, const char* glossary
) { 
2967     return arg_filen(shortopts
, longopts
, datatype
, 0, 1, glossary
); 
2970 struct arg_file
* arg_file1(const char* shortopts
, const char* longopts
, const char* datatype
, const char* glossary
) { 
2971     return arg_filen(shortopts
, longopts
, datatype
, 1, 1, glossary
); 
2974 struct arg_file
* arg_filen(const char* shortopts
, const char* longopts
, const char* datatype
, int mincount
, int maxcount
, const char* glossary
) { 
2976     struct arg_file
* result
; 
2979     /* foolproof things by ensuring maxcount is not less than mincount */ 
2980     maxcount 
= (maxcount 
< mincount
) ? mincount 
: maxcount
; 
2982     nbytes 
= sizeof(struct arg_file
)     /* storage for struct arg_file */ 
2983              + sizeof(char*) * maxcount  
/* storage for filename[maxcount] array */ 
2984              + sizeof(char*) * maxcount  
/* storage for basename[maxcount] array */ 
2985              + sizeof(char*) * maxcount
; /* storage for extension[maxcount] array */ 
2987     result 
= (struct arg_file
*)xmalloc(nbytes
); 
2989     /* init the arg_hdr struct */ 
2990     result
->hdr
.flag 
= ARG_HASVALUE
; 
2991     result
->hdr
.shortopts 
= shortopts
; 
2992     result
->hdr
.longopts 
= longopts
; 
2993     result
->hdr
.glossary 
= glossary
; 
2994     result
->hdr
.datatype 
= datatype 
? datatype 
: "<file>"; 
2995     result
->hdr
.mincount 
= mincount
; 
2996     result
->hdr
.maxcount 
= maxcount
; 
2997     result
->hdr
.parent 
= result
; 
2998     result
->hdr
.resetfn 
= (arg_resetfn
*)arg_file_resetfn
; 
2999     result
->hdr
.scanfn 
= (arg_scanfn
*)arg_file_scanfn
; 
3000     result
->hdr
.checkfn 
= (arg_checkfn
*)arg_file_checkfn
; 
3001     result
->hdr
.errorfn 
= (arg_errorfn
*)arg_file_errorfn
; 
3003     /* store the filename,basename,extension arrays immediately after the arg_file struct */ 
3004     result
->filename 
= (const char**)(result 
+ 1); 
3005     result
->basename 
= result
->filename 
+ maxcount
; 
3006     result
->extension 
= result
->basename 
+ maxcount
; 
3009     /* foolproof the string pointers by initialising them with empty strings */ 
3010     for (i 
= 0; i 
< maxcount
; i
++) { 
3011         result
->filename
[i
] = ""; 
3012         result
->basename
[i
] = ""; 
3013         result
->extension
[i
] = ""; 
3016     ARG_TRACE(("arg_filen() returns %p\n", result
)); 
3019 /******************************************************************************* 
3020  * arg_int: Implements the int command-line option 
3022  * This file is part of the argtable3 library. 
3024  * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann 
3025  * <sheitmann@users.sourceforge.net> 
3026  * All rights reserved. 
3028  * Redistribution and use in source and binary forms, with or without 
3029  * modification, are permitted provided that the following conditions are met: 
3030  *     * Redistributions of source code must retain the above copyright 
3031  *       notice, this list of conditions and the following disclaimer. 
3032  *     * Redistributions in binary form must reproduce the above copyright 
3033  *       notice, this list of conditions and the following disclaimer in the 
3034  *       documentation and/or other materials provided with the distribution. 
3035  *     * Neither the name of STEWART HEITMANN nor the  names of its contributors 
3036  *       may be used to endorse or promote products derived from this software 
3037  *       without specific prior written permission. 
3039  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
3040  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
3041  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
3042  * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, 
3043  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
3044  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
3045  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
3046  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
3047  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
3048  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
3049  ******************************************************************************/ 
3051 #include "argtable3.h" 
3053 #ifndef ARG_AMALGAMATION 
3054 #include "argtable3_private.h" 
3061 static void arg_int_resetfn(struct arg_int
* parent
) { 
3062     ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
)); 
3066 /* strtol0x() is like strtol() except that the numeric string is    */ 
3067 /* expected to be prefixed by "0X" where X is a user supplied char. */ 
3068 /* The string may optionally be prefixed by white space and + or -  */ 
3069 /* as in +0X123 or -0X123.                                          */ 
3070 /* Once the prefix has been scanned, the remainder of the numeric   */ 
3071 /* string is converted using strtol() with the given base.          */ 
3072 /* eg: to parse hex str="-0X12324", specify X='X' and base=16.      */ 
3073 /* eg: to parse oct str="+0o12324", specify X='O' and base=8.       */ 
3074 /* eg: to parse bin str="-0B01010", specify X='B' and base=2.       */ 
3075 /* Failure of conversion is indicated by result where *endptr==str. */ 
3076 static long int strtol0X(const char* str
, const char** endptr
, char X
, int base
) { 
3077     long int val
;          /* stores result */ 
3078     int s 
= 1;             /* sign is +1 or -1 */ 
3079     const char* ptr 
= str
; /* ptr to current position in str */ 
3081     /* skip leading whitespace */ 
3082     while (isspace(*ptr
)) 
3084     /* printf("1) %s\n",ptr); */ 
3086     /* scan optional sign character */ 
3100     /* printf("2) %s\n",ptr); */ 
3103     if ((*ptr
++) != '0') { 
3104         /* printf("failed to detect '0'\n"); */ 
3108     /* printf("3) %s\n",ptr); */ 
3109     if (toupper(*ptr
++) != toupper(X
)) { 
3110         /* printf("failed to detect '%c'\n",X); */ 
3114     /* printf("4) %s\n",ptr); */ 
3116     /* attempt conversion on remainder of string using strtol() */ 
3117     val 
= strtol(ptr
, (char**)endptr
, base
); 
3118     if (*endptr 
== ptr
) { 
3119         /* conversion failed */ 
3128 /* Returns 1 if str matches suffix (case insensitive).    */ 
3129 /* Str may contain trailing whitespace, but nothing else. */ 
3130 static int detectsuffix(const char* str
, const char* suffix
) { 
3131     /* scan pairwise through strings until mismatch detected */ 
3132     while (toupper(*str
) == toupper(*suffix
)) { 
3133         /* printf("'%c' '%c'\n", *str, *suffix); */ 
3135         /* return 1 (success) if match persists until the string terminator */ 
3143     /* printf("'%c' '%c' mismatch\n", *str, *suffix); */ 
3145     /* return 0 (fail) if the matching did not consume the entire suffix */ 
3147         return 0; /* failed to consume entire suffix */ 
3149     /* skip any remaining whitespace in str */ 
3150     while (isspace(*str
)) 
3153     /* return 1 (success) if we have reached end of str else return 0 (fail) */ 
3154     return (*str 
== '\0') ? 1 : 0; 
3157 static int arg_int_scanfn(struct arg_int
* parent
, const char* argval
) { 
3160     if (parent
->count 
== parent
->hdr
.maxcount
) { 
3161         /* maximum number of arguments exceeded */ 
3162         errorcode 
= ARG_ERR_MAXCOUNT
; 
3163     } else if (!argval
) { 
3164         /* a valid argument with no argument value was given. */ 
3165         /* This happens when an optional argument value was invoked. */ 
3166         /* leave parent arguiment value unaltered but still count the argument. */ 
3172         /* attempt to extract hex integer (eg: +0x123) from argval into val conversion */ 
3173         val 
= strtol0X(argval
, &end
, 'X', 16); 
3174         if (end 
== argval
) { 
3175             /* hex failed, attempt octal conversion (eg +0o123) */ 
3176             val 
= strtol0X(argval
, &end
, 'O', 8); 
3177             if (end 
== argval
) { 
3178                 /* octal failed, attempt binary conversion (eg +0B101) */ 
3179                 val 
= strtol0X(argval
, &end
, 'B', 2); 
3180                 if (end 
== argval
) { 
3181                     /* binary failed, attempt decimal conversion with no prefix (eg 1234) */ 
3182                     val 
= strtol(argval
, (char**)&end
, 10); 
3183                     if (end 
== argval
) { 
3184                         /* all supported number formats failed */ 
3185                         return ARG_ERR_BADINT
; 
3191         /* Safety check for integer overflow. WARNING: this check    */ 
3192         /* achieves nothing on machines where size(int)==size(long). */ 
3193         if (val 
> INT_MAX 
|| val 
< INT_MIN
) 
3194             errorcode 
= ARG_ERR_OVERFLOW
; 
3196         /* Detect any suffixes (KB,MB,GB) and multiply argument value appropriately. */ 
3197         /* We need to be mindful of integer overflows when using such big numbers.   */ 
3198         if (detectsuffix(end
, "KB")) /* kilobytes */ 
3200             if (val 
> (INT_MAX 
/ 1024) || val 
< (INT_MIN 
/ 1024)) 
3201                 errorcode 
= ARG_ERR_OVERFLOW
; /* Overflow would occur if we proceed */ 
3203                 val 
*= 1024;                /* 1KB = 1024 */ 
3204         } else if (detectsuffix(end
, "MB")) /* megabytes */ 
3206             if (val 
> (INT_MAX 
/ 1048576) || val 
< (INT_MIN 
/ 1048576)) 
3207                 errorcode 
= ARG_ERR_OVERFLOW
; /* Overflow would occur if we proceed */ 
3209                 val 
*= 1048576;             /* 1MB = 1024*1024 */ 
3210         } else if (detectsuffix(end
, "GB")) /* gigabytes */ 
3212             if (val 
> (INT_MAX 
/ 1073741824) || val 
< (INT_MIN 
/ 1073741824)) 
3213                 errorcode 
= ARG_ERR_OVERFLOW
; /* Overflow would occur if we proceed */ 
3215                 val 
*= 1073741824; /* 1GB = 1024*1024*1024 */ 
3216         } else if (!detectsuffix(end
, "")) 
3217             errorcode 
= ARG_ERR_BADINT
; /* invalid suffix detected */ 
3219         /* if success then store result in parent->ival[] array */ 
3221             parent
->ival
[parent
->count
++] = (int)val
; 
3224     /* printf("%s:scanfn(%p,%p) returns %d\n",__FILE__,parent,argval,errorcode); */ 
3228 static int arg_int_checkfn(struct arg_int
* parent
) { 
3229     int errorcode 
= (parent
->count 
< parent
->hdr
.mincount
) ? ARG_ERR_MINCOUNT 
: 0; 
3230     /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/ 
3234 static void arg_int_errorfn(struct arg_int
* parent
, arg_dstr_t ds
, int errorcode
, const char* argval
, const char* progname
) { 
3235     const char* shortopts 
= parent
->hdr
.shortopts
; 
3236     const char* longopts 
= parent
->hdr
.longopts
; 
3237     const char* datatype 
= parent
->hdr
.datatype
; 
3239     /* make argval NULL safe */ 
3240     argval 
= argval 
? argval 
: ""; 
3242     arg_dstr_catf(ds
, "%s: ", progname
); 
3243     switch (errorcode
) { 
3244         case ARG_ERR_MINCOUNT
: 
3245             arg_dstr_cat(ds
, "missing option "); 
3246             arg_print_option_ds(ds
, shortopts
, longopts
, datatype
, "\n"); 
3249         case ARG_ERR_MAXCOUNT
: 
3250             arg_dstr_cat(ds
, "excess option "); 
3251             arg_print_option_ds(ds
, shortopts
, longopts
, argval
, "\n"); 
3254         case ARG_ERR_BADINT
: 
3255             arg_dstr_catf(ds
, "invalid argument \"%s\" to option ", argval
); 
3256             arg_print_option_ds(ds
, shortopts
, longopts
, datatype
, "\n"); 
3259         case ARG_ERR_OVERFLOW
: 
3260             arg_dstr_cat(ds
, "integer overflow at option "); 
3261             arg_print_option_ds(ds
, shortopts
, longopts
, datatype
, " "); 
3262             arg_dstr_catf(ds
, "(%s is too large)\n", argval
); 
3267 struct arg_int
* arg_int0(const char* shortopts
, const char* longopts
, const char* datatype
, const char* glossary
) { 
3268     return arg_intn(shortopts
, longopts
, datatype
, 0, 1, glossary
); 
3271 struct arg_int
* arg_int1(const char* shortopts
, const char* longopts
, const char* datatype
, const char* glossary
) { 
3272     return arg_intn(shortopts
, longopts
, datatype
, 1, 1, glossary
); 
3275 struct arg_int
* arg_intn(const char* shortopts
, const char* longopts
, const char* datatype
, int mincount
, int maxcount
, const char* glossary
) { 
3277     struct arg_int
* result
; 
3279     /* foolproof things by ensuring maxcount is not less than mincount */ 
3280     maxcount 
= (maxcount 
< mincount
) ? mincount 
: maxcount
; 
3282     nbytes 
= sizeof(struct arg_int
)    /* storage for struct arg_int */ 
3283              + maxcount 
* sizeof(int); /* storage for ival[maxcount] array */ 
3285     result 
= (struct arg_int
*)xmalloc(nbytes
); 
3287     /* init the arg_hdr struct */ 
3288     result
->hdr
.flag 
= ARG_HASVALUE
; 
3289     result
->hdr
.shortopts 
= shortopts
; 
3290     result
->hdr
.longopts 
= longopts
; 
3291     result
->hdr
.datatype 
= datatype 
? datatype 
: "<int>"; 
3292     result
->hdr
.glossary 
= glossary
; 
3293     result
->hdr
.mincount 
= mincount
; 
3294     result
->hdr
.maxcount 
= maxcount
; 
3295     result
->hdr
.parent 
= result
; 
3296     result
->hdr
.resetfn 
= (arg_resetfn
*)arg_int_resetfn
; 
3297     result
->hdr
.scanfn 
= (arg_scanfn
*)arg_int_scanfn
; 
3298     result
->hdr
.checkfn 
= (arg_checkfn
*)arg_int_checkfn
; 
3299     result
->hdr
.errorfn 
= (arg_errorfn
*)arg_int_errorfn
; 
3301     /* store the ival[maxcount] array immediately after the arg_int struct */ 
3302     result
->ival 
= (int*)(result 
+ 1); 
3305     ARG_TRACE(("arg_intn() returns %p\n", result
)); 
3308 /******************************************************************************* 
3309  * arg_lit: Implements the literature command-line option 
3311  * This file is part of the argtable3 library. 
3313  * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann 
3314  * <sheitmann@users.sourceforge.net> 
3315  * All rights reserved. 
3317  * Redistribution and use in source and binary forms, with or without 
3318  * modification, are permitted provided that the following conditions are met: 
3319  *     * Redistributions of source code must retain the above copyright 
3320  *       notice, this list of conditions and the following disclaimer. 
3321  *     * Redistributions in binary form must reproduce the above copyright 
3322  *       notice, this list of conditions and the following disclaimer in the 
3323  *       documentation and/or other materials provided with the distribution. 
3324  *     * Neither the name of STEWART HEITMANN nor the  names of its contributors 
3325  *       may be used to endorse or promote products derived from this software 
3326  *       without specific prior written permission. 
3328  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
3329  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
3330  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
3331  * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, 
3332  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
3333  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
3334  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
3335  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
3336  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
3337  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
3338  ******************************************************************************/ 
3340 #include "argtable3.h" 
3342 #ifndef ARG_AMALGAMATION 
3343 #include "argtable3_private.h" 
3348 static void arg_lit_resetfn(struct arg_lit
* parent
) { 
3349     ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
)); 
3353 static int arg_lit_scanfn(struct arg_lit
* parent
, const char* argval
) { 
3355     if (parent
->count 
< parent
->hdr
.maxcount
) 
3358         errorcode 
= ARG_ERR_MAXCOUNT
; 
3360     ARG_TRACE(("%s:scanfn(%p,%s) returns %d\n", __FILE__
, parent
, argval
, errorcode
)); 
3364 static int arg_lit_checkfn(struct arg_lit
* parent
) { 
3365     int errorcode 
= (parent
->count 
< parent
->hdr
.mincount
) ? ARG_ERR_MINCOUNT 
: 0; 
3366     ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__
, parent
, errorcode
)); 
3370 static void arg_lit_errorfn(struct arg_lit
* parent
, arg_dstr_t ds
, int errorcode
, const char* argval
, const char* progname
) { 
3371     const char* shortopts 
= parent
->hdr
.shortopts
; 
3372     const char* longopts 
= parent
->hdr
.longopts
; 
3373     const char* datatype 
= parent
->hdr
.datatype
; 
3375     switch (errorcode
) { 
3376         case ARG_ERR_MINCOUNT
: 
3377             arg_dstr_catf(ds
, "%s: missing option ", progname
); 
3378             arg_print_option_ds(ds
, shortopts
, longopts
, datatype
, "\n"); 
3379             arg_dstr_cat(ds
, "\n"); 
3382         case ARG_ERR_MAXCOUNT
: 
3383             arg_dstr_catf(ds
, "%s: extraneous option ", progname
); 
3384             arg_print_option_ds(ds
, shortopts
, longopts
, datatype
, "\n"); 
3388     ARG_TRACE(("%s:errorfn(%p, %p, %d, %s, %s)\n", __FILE__
, parent
, ds
, errorcode
, argval
, progname
)); 
3391 struct arg_lit
* arg_lit0(const char* shortopts
, const char* longopts
, const char* glossary
) { 
3392     return arg_litn(shortopts
, longopts
, 0, 1, glossary
); 
3395 struct arg_lit
* arg_lit1(const char* shortopts
, const char* longopts
, const char* glossary
) { 
3396     return arg_litn(shortopts
, longopts
, 1, 1, glossary
); 
3399 struct arg_lit
* arg_litn(const char* shortopts
, const char* longopts
, int mincount
, int maxcount
, const char* glossary
) { 
3400     struct arg_lit
* result
; 
3402     /* foolproof things by ensuring maxcount is not less than mincount */ 
3403     maxcount 
= (maxcount 
< mincount
) ? mincount 
: maxcount
; 
3405     result 
= (struct arg_lit
*)xmalloc(sizeof(struct arg_lit
)); 
3407     /* init the arg_hdr struct */ 
3408     result
->hdr
.flag 
= 0; 
3409     result
->hdr
.shortopts 
= shortopts
; 
3410     result
->hdr
.longopts 
= longopts
; 
3411     result
->hdr
.datatype 
= NULL
; 
3412     result
->hdr
.glossary 
= glossary
; 
3413     result
->hdr
.mincount 
= mincount
; 
3414     result
->hdr
.maxcount 
= maxcount
; 
3415     result
->hdr
.parent 
= result
; 
3416     result
->hdr
.resetfn 
= (arg_resetfn
*)arg_lit_resetfn
; 
3417     result
->hdr
.scanfn 
= (arg_scanfn
*)arg_lit_scanfn
; 
3418     result
->hdr
.checkfn 
= (arg_checkfn
*)arg_lit_checkfn
; 
3419     result
->hdr
.errorfn 
= (arg_errorfn
*)arg_lit_errorfn
; 
3421     /* init local variables */ 
3424     ARG_TRACE(("arg_litn() returns %p\n", result
)); 
3427 /******************************************************************************* 
3428  * arg_rem: Implements the rem command-line option 
3430  * This file is part of the argtable3 library. 
3432  * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann 
3433  * <sheitmann@users.sourceforge.net> 
3434  * All rights reserved. 
3436  * Redistribution and use in source and binary forms, with or without 
3437  * modification, are permitted provided that the following conditions are met: 
3438  *     * Redistributions of source code must retain the above copyright 
3439  *       notice, this list of conditions and the following disclaimer. 
3440  *     * Redistributions in binary form must reproduce the above copyright 
3441  *       notice, this list of conditions and the following disclaimer in the 
3442  *       documentation and/or other materials provided with the distribution. 
3443  *     * Neither the name of STEWART HEITMANN nor the  names of its contributors 
3444  *       may be used to endorse or promote products derived from this software 
3445  *       without specific prior written permission. 
3447  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
3448  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
3449  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
3450  * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, 
3451  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
3452  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
3453  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
3454  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
3455  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
3456  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
3457  ******************************************************************************/ 
3459 #include "argtable3.h" 
3461 #ifndef ARG_AMALGAMATION 
3462 #include "argtable3_private.h" 
3467 struct arg_rem
* arg_rem(const char* datatype
, const char* glossary
) { 
3468     struct arg_rem
* result 
= (struct arg_rem
*)xmalloc(sizeof(struct arg_rem
)); 
3470     result
->hdr
.flag 
= 0; 
3471     result
->hdr
.shortopts 
= NULL
; 
3472     result
->hdr
.longopts 
= NULL
; 
3473     result
->hdr
.datatype 
= datatype
; 
3474     result
->hdr
.glossary 
= glossary
; 
3475     result
->hdr
.mincount 
= 1; 
3476     result
->hdr
.maxcount 
= 1; 
3477     result
->hdr
.parent 
= result
; 
3478     result
->hdr
.resetfn 
= NULL
; 
3479     result
->hdr
.scanfn 
= NULL
; 
3480     result
->hdr
.checkfn 
= NULL
; 
3481     result
->hdr
.errorfn 
= NULL
; 
3483     ARG_TRACE(("arg_rem() returns %p\n", result
)); 
3486 /******************************************************************************* 
3487  * arg_rex: Implements the regex command-line option 
3489  * This file is part of the argtable3 library. 
3491  * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann 
3492  * <sheitmann@users.sourceforge.net> 
3493  * All rights reserved. 
3495  * Redistribution and use in source and binary forms, with or without 
3496  * modification, are permitted provided that the following conditions are met: 
3497  *     * Redistributions of source code must retain the above copyright 
3498  *       notice, this list of conditions and the following disclaimer. 
3499  *     * Redistributions in binary form must reproduce the above copyright 
3500  *       notice, this list of conditions and the following disclaimer in the 
3501  *       documentation and/or other materials provided with the distribution. 
3502  *     * Neither the name of STEWART HEITMANN nor the  names of its contributors 
3503  *       may be used to endorse or promote products derived from this software 
3504  *       without specific prior written permission. 
3506  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
3507  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
3508  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
3509  * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, 
3510  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
3511  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
3512  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
3513  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
3514  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
3515  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
3516  ******************************************************************************/ 
3518 #include "argtable3.h" 
3520 #ifndef ARG_AMALGAMATION 
3521 #include "argtable3_private.h" 
3531  * This module uses the T-Rex regular expression library to implement the regex 
3532  * logic. Here is the copyright notice of the library: 
3534  * Copyright (C) 2003-2006 Alberto Demichelis 
3536  * This software is provided 'as-is', without any express 
3537  * or implied warranty. In no event will the authors be held 
3538  * liable for any damages arising from the use of this software. 
3540  * Permission is granted to anyone to use this software for 
3541  * any purpose, including commercial applications, and to alter 
3542  * it and redistribute it freely, subject to the following restrictions: 
3544  *   1. The origin of this software must not be misrepresented; 
3545  *      you must not claim that you wrote the original software. 
3546  *      If you use this software in a product, an acknowledgment 
3547  *      in the product documentation would be appreciated but 
3550  *   2. Altered source versions must be plainly marked as such, 
3551  *      and must not be misrepresented as being the original software. 
3553  *   3. This notice may not be removed or altered from any 
3554  *      source distribution. 
3561 #define TRexChar char 
3562 #define MAX_CHAR 0xFF 
3563 #define _TREXC(c) (c) 
3564 #define trex_strlen strlen 
3565 #define trex_printf printf 
3568 #define TREX_API extern 
3572 #define TRex_False 0 
3574 #define TREX_ICASE ARG_REX_ICASE 
3576 typedef unsigned int TRexBool
; 
3577 typedef struct TRex TRex
; 
3580     const TRexChar
* begin
; 
3585 TREX_API TRex
* trex_compile(const TRexChar
* pattern
, const TRexChar
** error
, int flags
) __attribute__((optimize(0))); 
3587 TREX_API TRex
* trex_compile(const TRexChar
* pattern
, const TRexChar
** error
, int flags
); 
3589 TREX_API 
void trex_free(TRex
* exp
); 
3590 TREX_API TRexBool 
trex_match(TRex
* exp
, const TRexChar
* text
); 
3591 TREX_API TRexBool 
trex_search(TRex
* exp
, const TRexChar
* text
, const TRexChar
** out_begin
, const TRexChar
** out_end
); 
3593 trex_searchrange(TRex
* exp
, const TRexChar
* text_begin
, const TRexChar
* text_end
, const TRexChar
** out_begin
, const TRexChar
** out_end
); 
3594 TREX_API 
int trex_getsubexpcount(TRex
* exp
); 
3595 TREX_API TRexBool 
trex_getsubexp(TRex
* exp
, int n
, TRexMatch
* subexp
); 
3604     const char* pattern
; 
3608 static void arg_rex_resetfn(struct arg_rex
* parent
) { 
3609     ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
)); 
3613 static int arg_rex_scanfn(struct arg_rex
* parent
, const char* argval
) { 
3615     const TRexChar
* error 
= NULL
; 
3617     TRexBool is_match 
= TRex_False
; 
3619     if (parent
->count 
== parent
->hdr
.maxcount
) { 
3620         /* maximum number of arguments exceeded */ 
3621         errorcode 
= ARG_ERR_MAXCOUNT
; 
3622     } else if (!argval
) { 
3623         /* a valid argument with no argument value was given. */ 
3624         /* This happens when an optional argument value was invoked. */ 
3625         /* leave parent argument value unaltered but still count the argument. */ 
3628         struct privhdr
* priv 
= (struct privhdr
*)parent
->hdr
.priv
; 
3630         /* test the current argument value for a match with the regular expression */ 
3631         /* if a match is detected, record the argument value in the arg_rex struct */ 
3633         rex 
= trex_compile(priv
->pattern
, &error
, priv
->flags
); 
3634         is_match 
= trex_match(rex
, argval
); 
3636             errorcode 
= ARG_ERR_REGNOMATCH
; 
3638             parent
->sval
[parent
->count
++] = argval
; 
3643     ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__
, parent
, errorcode
)); 
3647 static int arg_rex_checkfn(struct arg_rex
* parent
) { 
3648     int errorcode 
= (parent
->count 
< parent
->hdr
.mincount
) ? ARG_ERR_MINCOUNT 
: 0; 
3650     struct privhdr 
*priv 
= (struct privhdr
*)parent
->hdr
.priv
; 
3652     /* free the regex "program" we constructed in resetfn */ 
3653     regfree(&(priv
->regex
)); 
3655     /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/ 
3660 static void arg_rex_errorfn(struct arg_rex
* parent
, arg_dstr_t ds
, int errorcode
, const char* argval
, const char* progname
) { 
3661     const char* shortopts 
= parent
->hdr
.shortopts
; 
3662     const char* longopts 
= parent
->hdr
.longopts
; 
3663     const char* datatype 
= parent
->hdr
.datatype
; 
3665     /* make argval NULL safe */ 
3666     argval 
= argval 
? argval 
: ""; 
3668     arg_dstr_catf(ds
, "%s: ", progname
); 
3669     switch (errorcode
) { 
3670         case ARG_ERR_MINCOUNT
: 
3671             arg_dstr_cat(ds
, "missing option "); 
3672             arg_print_option_ds(ds
, shortopts
, longopts
, datatype
, "\n"); 
3675         case ARG_ERR_MAXCOUNT
: 
3676             arg_dstr_cat(ds
, "excess option "); 
3677             arg_print_option_ds(ds
, shortopts
, longopts
, argval
, "\n"); 
3680         case ARG_ERR_REGNOMATCH
: 
3681             arg_dstr_cat(ds
, "illegal value  "); 
3682             arg_print_option_ds(ds
, shortopts
, longopts
, argval
, "\n"); 
3688             regerror(errorcode
, NULL
, errbuff
, sizeof(errbuff
)); 
3689             printf("%s\n", errbuff
); 
3695 struct arg_rex
* arg_rex0(const char* shortopts
, const char* longopts
, const char* pattern
, const char* datatype
, int flags
, const char* glossary
) { 
3696     return arg_rexn(shortopts
, longopts
, pattern
, datatype
, 0, 1, flags
, glossary
); 
3699 struct arg_rex
* arg_rex1(const char* shortopts
, const char* longopts
, const char* pattern
, const char* datatype
, int flags
, const char* glossary
) { 
3700     return arg_rexn(shortopts
, longopts
, pattern
, datatype
, 1, 1, flags
, glossary
); 
3703 struct arg_rex
* arg_rexn(const char* shortopts
, 
3704                          const char* longopts
, 
3705                          const char* pattern
, 
3706                          const char* datatype
, 
3710                          const char* glossary
) { 
3712     struct arg_rex
* result
; 
3713     struct privhdr
* priv
; 
3715     const TRexChar
* error 
= NULL
; 
3719         printf("argtable: ERROR - illegal regular expression pattern \"(NULL)\"\n"); 
3720         printf("argtable: Bad argument table.\n"); 
3724     /* foolproof things by ensuring maxcount is not less than mincount */ 
3725     maxcount 
= (maxcount 
< mincount
) ? mincount 
: maxcount
; 
3727     nbytes 
= sizeof(struct arg_rex
)      /* storage for struct arg_rex */ 
3728              + sizeof(struct privhdr
)    /* storage for private arg_rex data */ 
3729              + maxcount 
* sizeof(char*); /* storage for sval[maxcount] array */ 
3731     /* init the arg_hdr struct */ 
3732     result 
= (struct arg_rex
*)xmalloc(nbytes
); 
3733     result
->hdr
.flag 
= ARG_HASVALUE
; 
3734     result
->hdr
.shortopts 
= shortopts
; 
3735     result
->hdr
.longopts 
= longopts
; 
3736     result
->hdr
.datatype 
= datatype 
? datatype 
: pattern
; 
3737     result
->hdr
.glossary 
= glossary
; 
3738     result
->hdr
.mincount 
= mincount
; 
3739     result
->hdr
.maxcount 
= maxcount
; 
3740     result
->hdr
.parent 
= result
; 
3741     result
->hdr
.resetfn 
= (arg_resetfn
*)arg_rex_resetfn
; 
3742     result
->hdr
.scanfn 
= (arg_scanfn
*)arg_rex_scanfn
; 
3743     result
->hdr
.checkfn 
= (arg_checkfn
*)arg_rex_checkfn
; 
3744     result
->hdr
.errorfn 
= (arg_errorfn
*)arg_rex_errorfn
; 
3746     /* store the arg_rex_priv struct immediately after the arg_rex struct */ 
3747     result
->hdr
.priv 
= result 
+ 1; 
3748     priv 
= (struct privhdr
*)(result
->hdr
.priv
); 
3749     priv
->pattern 
= pattern
; 
3750     priv
->flags 
= flags
; 
3752     /* store the sval[maxcount] array immediately after the arg_rex_priv struct */ 
3753     result
->sval 
= (const char**)(priv 
+ 1); 
3756     /* foolproof the string pointers by initializing them to reference empty strings */ 
3757     for (i 
= 0; i 
< maxcount
; i
++) 
3758         result
->sval
[i
] = ""; 
3760     /* here we construct and destroy a regex representation of the regular 
3761      * expression for no other reason than to force any regex errors to be 
3762      * trapped now rather than later. If we don't, then errors may go undetected 
3763      * until an argument is actually parsed. 
3766     rex 
= trex_compile(priv
->pattern
, &error
, priv
->flags
); 
3768         ARG_LOG(("argtable: %s \"%s\"\n", error 
? error 
: _TREXC("undefined"), priv
->pattern
)); 
3769         ARG_LOG(("argtable: Bad argument table.\n")); 
3774     ARG_TRACE(("arg_rexn() returns %p\n", result
)); 
3778 /* see copyright notice in trex.h */ 
3785 #define scisprint iswprint 
3786 #define scstrlen wcslen 
3787 #define scprintf wprintf 
3790 #define scisprint isprint 
3791 #define scstrlen strlen 
3792 #define scprintf printf 
3796 #ifdef ARG_REX_DEBUG 
3799 static const TRexChar
* g_nnames
[] = {_SC("NONE"),    _SC("OP_GREEDY"), _SC("OP_OR"),     _SC("OP_EXPR"),   _SC("OP_NOCAPEXPR"), 
3800                                      _SC("OP_DOT"),  _SC("OP_CLASS"),  _SC("OP_CCLASS"), _SC("OP_NCLASS"), _SC("OP_RANGE"), 
3801                                      _SC("OP_CHAR"), _SC("OP_EOL"),    _SC("OP_BOL"),    _SC("OP_WB")}; 
3804 #define OP_GREEDY (MAX_CHAR + 1)  /*  * + ? {n} */ 
3805 #define OP_OR (MAX_CHAR + 2) 
3806 #define OP_EXPR (MAX_CHAR + 3)       /* parentesis () */ 
3807 #define OP_NOCAPEXPR (MAX_CHAR + 4)  /* parentesis (?:) */ 
3808 #define OP_DOT (MAX_CHAR + 5) 
3809 #define OP_CLASS (MAX_CHAR + 6) 
3810 #define OP_CCLASS (MAX_CHAR + 7) 
3811 #define OP_NCLASS (MAX_CHAR + 8)  /* negates class the [^ */ 
3812 #define OP_RANGE (MAX_CHAR + 9) 
3813 #define OP_CHAR (MAX_CHAR + 10) 
3814 #define OP_EOL (MAX_CHAR + 11) 
3815 #define OP_BOL (MAX_CHAR + 12) 
3816 #define OP_WB (MAX_CHAR + 13) 
3818 #define TREX_SYMBOL_ANY_CHAR ('.') 
3819 #define TREX_SYMBOL_GREEDY_ONE_OR_MORE ('+') 
3820 #define TREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*') 
3821 #define TREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?') 
3822 #define TREX_SYMBOL_BRANCH ('|') 
3823 #define TREX_SYMBOL_END_OF_STRING ('$') 
3824 #define TREX_SYMBOL_BEGINNING_OF_STRING ('^') 
3825 #define TREX_SYMBOL_ESCAPE_CHAR ('\\') 
3827 typedef int TRexNodeType
; 
3829 typedef struct tagTRexNode 
{ 
3837     const TRexChar
* _eol
; 
3838     const TRexChar
* _bol
; 
3846     TRexMatch
* _matches
; 
3849     const TRexChar
** _error
; 
3853 static int trex_list(TRex
* exp
); 
3855 static int trex_newnode(TRex
* exp
, TRexNodeType type
) { 
3859     n
.next 
= n
.right 
= n
.left 
= -1; 
3860     if (type 
== OP_EXPR
) 
3861         n
.right 
= exp
->_nsubexpr
++; 
3862     if (exp
->_nallocated 
< (exp
->_nsize 
+ 1)) { 
3863         exp
->_nallocated 
*= 2; 
3864         exp
->_nodes 
= (TRexNode
*)xrealloc(exp
->_nodes
, exp
->_nallocated 
* sizeof(TRexNode
)); 
3866     exp
->_nodes
[exp
->_nsize
++] = n
; 
3867     newid 
= exp
->_nsize 
- 1; 
3871 static void trex_error(TRex
* exp
, const TRexChar
* error
) { 
3873         *exp
->_error 
= error
; 
3874     longjmp(*((jmp_buf*)exp
->_jmpbuf
), -1); 
3877 static void trex_expect(TRex
* exp
, int n
) { 
3878     if ((*exp
->_p
) != n
) 
3879         trex_error(exp
, _SC("expected paren")); 
3883 static TRexChar 
trex_escapechar(TRex
* exp
) { 
3884     if (*exp
->_p 
== TREX_SYMBOL_ESCAPE_CHAR
) { 
3903                 return (*exp
->_p
++); 
3905     } else if (!scisprint(*exp
->_p
)) 
3906         trex_error(exp
, _SC("letter expected")); 
3907     return (*exp
->_p
++); 
3910 static int trex_charclass(TRex
* exp
, int classid
) { 
3911     int n 
= trex_newnode(exp
, OP_CCLASS
); 
3912     exp
->_nodes
[n
].left 
= classid
; 
3916 static int trex_charnode(TRex
* exp
, TRexBool isclass
) { 
3918     if (*exp
->_p 
== TREX_SYMBOL_ESCAPE_CHAR
) { 
3923                 return trex_newnode(exp
, '\n'); 
3926                 return trex_newnode(exp
, '\t'); 
3929                 return trex_newnode(exp
, '\r'); 
3932                 return trex_newnode(exp
, '\f'); 
3935                 return trex_newnode(exp
, '\v'); 
3954                 return trex_charclass(exp
, t
); 
3959                     int node 
= trex_newnode(exp
, OP_WB
); 
3960                     exp
->_nodes
[node
].left 
= *exp
->_p
; 
3968                 return trex_newnode(exp
, t
); 
3970     } else if (!scisprint(*exp
->_p
)) { 
3971         trex_error(exp
, _SC("letter expected")); 
3975     return trex_newnode(exp
, t
); 
3977 static int trex_class(TRex
* exp
) { 
3979     int first 
= -1, chain
; 
3980     if (*exp
->_p 
== TREX_SYMBOL_BEGINNING_OF_STRING
) { 
3981         ret 
= trex_newnode(exp
, OP_NCLASS
); 
3984         ret 
= trex_newnode(exp
, OP_CLASS
); 
3986     if (*exp
->_p 
== ']') 
3987         trex_error(exp
, _SC("empty class")); 
3989     while (*exp
->_p 
!= ']' && exp
->_p 
!= exp
->_eol
) { 
3990         if (*exp
->_p 
== '-' && first 
!= -1) { 
3992             if (*exp
->_p
++ == ']') 
3993                 trex_error(exp
, _SC("unfinished range")); 
3994             r 
= trex_newnode(exp
, OP_RANGE
); 
3995             if (first 
> *exp
->_p
) 
3996                 trex_error(exp
, _SC("invalid range")); 
3997             if (exp
->_nodes
[first
].type 
== OP_CCLASS
) 
3998                 trex_error(exp
, _SC("cannot use character classes in ranges")); 
3999             exp
->_nodes
[r
].left 
= exp
->_nodes
[first
].type
; 
4000             t 
= trex_escapechar(exp
); 
4001             exp
->_nodes
[r
].right 
= t
; 
4002             exp
->_nodes
[chain
].next 
= r
; 
4008                 exp
->_nodes
[chain
].next 
= c
; 
4010                 first 
= trex_charnode(exp
, TRex_True
); 
4012                 first 
= trex_charnode(exp
, TRex_True
); 
4018         exp
->_nodes
[chain
].next 
= c
; 
4023     exp
->_nodes
[ret
].left 
= exp
->_nodes
[ret
].next
; 
4024     exp
->_nodes
[ret
].next 
= -1; 
4028 static int trex_parsenumber(TRex
* exp
) { 
4029     int ret 
= *exp
->_p 
- '0'; 
4032     while (isdigit(*exp
->_p
)) { 
4033         ret 
= ret 
* 10 + (*exp
->_p
++ - '0'); 
4034         if (positions 
== 1000000000) 
4035             trex_error(exp
, _SC("overflow in numeric constant")); 
4041 static int trex_element(TRex
* exp
) { 
4048             if (*exp
->_p 
== '?') { 
4050                 trex_expect(exp
, ':'); 
4051                 expr 
= trex_newnode(exp
, OP_NOCAPEXPR
); 
4053                 expr 
= trex_newnode(exp
, OP_EXPR
); 
4054             newn 
= trex_list(exp
); 
4055             exp
->_nodes
[expr
].left 
= newn
; 
4057             trex_expect(exp
, ')'); 
4061             ret 
= trex_class(exp
); 
4062             trex_expect(exp
, ']'); 
4064         case TREX_SYMBOL_END_OF_STRING
: 
4066             ret 
= trex_newnode(exp
, OP_EOL
); 
4068         case TREX_SYMBOL_ANY_CHAR
: 
4070             ret 
= trex_newnode(exp
, OP_DOT
); 
4073             ret 
= trex_charnode(exp
, TRex_False
); 
4078         TRexBool isgreedy 
= TRex_False
; 
4079         unsigned short p0 
= 0, p1 
= 0; 
4081             case TREX_SYMBOL_GREEDY_ZERO_OR_MORE
: 
4085                 isgreedy 
= TRex_True
; 
4087             case TREX_SYMBOL_GREEDY_ONE_OR_MORE
: 
4091                 isgreedy 
= TRex_True
; 
4093             case TREX_SYMBOL_GREEDY_ZERO_OR_ONE
: 
4097                 isgreedy 
= TRex_True
; 
4101                 if (!isdigit(*exp
->_p
)) 
4102                     trex_error(exp
, _SC("number expected")); 
4103                 p0 
= (unsigned short)trex_parsenumber(exp
); 
4104                 /*******************************/ 
4113                         if (isdigit(*exp
->_p
)) { 
4114                             p1 
= (unsigned short)trex_parsenumber(exp
); 
4116                         trex_expect(exp
, '}'); 
4119                         trex_error(exp
, _SC(", or } expected")); 
4121                 /*******************************/ 
4122                 isgreedy 
= TRex_True
; 
4126             int nnode 
= trex_newnode(exp
, OP_GREEDY
); 
4127             exp
->_nodes
[nnode
].left 
= ret
; 
4128             exp
->_nodes
[nnode
].right 
= ((p0
) << 16) | p1
; 
4132     if ((*exp
->_p 
!= TREX_SYMBOL_BRANCH
) && (*exp
->_p 
!= ')') && (*exp
->_p 
!= TREX_SYMBOL_GREEDY_ZERO_OR_MORE
) && 
4133         (*exp
->_p 
!= TREX_SYMBOL_GREEDY_ONE_OR_MORE
) && (*exp
->_p 
!= '\0')) { 
4134         int nnode 
= trex_element(exp
); 
4135         exp
->_nodes
[ret
].next 
= nnode
; 
4141 static int trex_list(TRex
* exp
) { 
4143     if (*exp
->_p 
== TREX_SYMBOL_BEGINNING_OF_STRING
) { 
4145         ret 
= trex_newnode(exp
, OP_BOL
); 
4147     e 
= trex_element(exp
); 
4149         exp
->_nodes
[ret
].next 
= e
; 
4153     if (*exp
->_p 
== TREX_SYMBOL_BRANCH
) { 
4156         temp 
= trex_newnode(exp
, OP_OR
); 
4157         exp
->_nodes
[temp
].left 
= ret
; 
4158         tright 
= trex_list(exp
); 
4159         exp
->_nodes
[temp
].right 
= tright
; 
4165 static TRexBool 
trex_matchcclass(int cclass
, TRexChar c
) { 
4168             return isalpha(c
) ? TRex_True 
: TRex_False
; 
4170             return !isalpha(c
) ? TRex_True 
: TRex_False
; 
4172             return (isalnum(c
) || c 
== '_') ? TRex_True 
: TRex_False
; 
4174             return (!isalnum(c
) && c 
!= '_') ? TRex_True 
: TRex_False
; 
4176             return isspace(c
) ? TRex_True 
: TRex_False
; 
4178             return !isspace(c
) ? TRex_True 
: TRex_False
; 
4180             return isdigit(c
) ? TRex_True 
: TRex_False
; 
4182             return !isdigit(c
) ? TRex_True 
: TRex_False
; 
4184             return isxdigit(c
) ? TRex_True 
: TRex_False
; 
4186             return !isxdigit(c
) ? TRex_True 
: TRex_False
; 
4188             return iscntrl(c
) ? TRex_True 
: TRex_False
; 
4190             return !iscntrl(c
) ? TRex_True 
: TRex_False
; 
4192             return ispunct(c
) ? TRex_True 
: TRex_False
; 
4194             return !ispunct(c
) ? TRex_True 
: TRex_False
; 
4196             return islower(c
) ? TRex_True 
: TRex_False
; 
4198             return isupper(c
) ? TRex_True 
: TRex_False
; 
4200     return TRex_False
; /*cannot happen*/ 
4203 static TRexBool 
trex_matchclass(TRex
* exp
, TRexNode
* node
, TRexChar c
) { 
4205         switch (node
->type
) { 
4207                 if (exp
->_flags 
& TREX_ICASE
) { 
4208                     if (c 
>= toupper(node
->left
) && c 
<= toupper(node
->right
)) 
4210                     if (c 
>= tolower(node
->left
) && c 
<= tolower(node
->right
)) 
4213                     if (c 
>= node
->left 
&& c 
<= node
->right
) 
4218                 if (trex_matchcclass(node
->left
, c
)) 
4222                 if (exp
->_flags 
& TREX_ICASE
) { 
4223                     if (c 
== tolower(node
->type
) || c 
== toupper(node
->type
)) 
4226                     if (c 
== node
->type
) 
4230     } while ((node
->next 
!= -1) && ((node 
= &exp
->_nodes
[node
->next
]) != NULL
)); 
4234 static const TRexChar
* trex_matchnode(TRex
* exp
, TRexNode
* node
, const TRexChar
* str
, TRexNode
* next
) { 
4235     TRexNodeType type 
= node
->type
; 
4238             /* TRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL; */ 
4239             TRexNode
* greedystop 
= NULL
; 
4240             int p0 
= (node
->right 
>> 16) & 0x0000FFFF, p1 
= node
->right 
& 0x0000FFFF, nmaches 
= 0; 
4241             const TRexChar 
*s 
= str
, *good 
= str
; 
4243             if (node
->next 
!= -1) { 
4244                 greedystop 
= &exp
->_nodes
[node
->next
]; 
4249             while ((nmaches 
== 0xFFFF || nmaches 
< p1
)) { 
4250                 const TRexChar
* stop
; 
4251                 if ((s 
= trex_matchnode(exp
, &exp
->_nodes
[node
->left
], s
, greedystop
)) == NULL
) 
4256                     /* checks that 0 matches satisfy the expression(if so skips) */ 
4257                     /* if not would always stop(for instance if is a '?') */ 
4258                     if (greedystop
->type 
!= OP_GREEDY 
|| (greedystop
->type 
== OP_GREEDY 
&& ((greedystop
->right 
>> 16) & 0x0000FFFF) != 0)) { 
4259                         TRexNode
* gnext 
= NULL
; 
4260                         if (greedystop
->next 
!= -1) { 
4261                             gnext 
= &exp
->_nodes
[greedystop
->next
]; 
4262                         } else if (next 
&& next
->next 
!= -1) { 
4263                             gnext 
= &exp
->_nodes
[next
->next
]; 
4265                         stop 
= trex_matchnode(exp
, greedystop
, s
, gnext
); 
4267                             /* if satisfied stop it */ 
4268                             if (p0 
== p1 
&& p0 
== nmaches
) 
4270                             else if (nmaches 
>= p0 
&& p1 
== 0xFFFF) 
4272                             else if (nmaches 
>= p0 
&& nmaches 
<= p1
) 
4281             if (p0 
== p1 
&& p0 
== nmaches
) 
4283             else if (nmaches 
>= p0 
&& p1 
== 0xFFFF) 
4285             else if (nmaches 
>= p0 
&& nmaches 
<= p1
) 
4290             const TRexChar
* asd 
= str
; 
4291             TRexNode
* temp 
= &exp
->_nodes
[node
->left
]; 
4292             while ((asd 
= trex_matchnode(exp
, temp
, asd
, NULL
)) != NULL
) { 
4293                 if (temp
->next 
!= -1) 
4294                     temp 
= &exp
->_nodes
[temp
->next
]; 
4299             temp 
= &exp
->_nodes
[node
->right
]; 
4300             while ((asd 
= trex_matchnode(exp
, temp
, asd
, NULL
)) != NULL
) { 
4301                 if (temp
->next 
!= -1) 
4302                     temp 
= &exp
->_nodes
[temp
->next
]; 
4310         case OP_NOCAPEXPR
: { 
4311             TRexNode
* n 
= &exp
->_nodes
[node
->left
]; 
4312             const TRexChar
* cur 
= str
; 
4314             if (node
->type 
!= OP_NOCAPEXPR 
&& node
->right 
== exp
->_currsubexp
) { 
4315                 capture 
= exp
->_currsubexp
; 
4316                 exp
->_matches
[capture
].begin 
= cur
; 
4321                 TRexNode
* subnext 
= NULL
; 
4322                 if (n
->next 
!= -1) { 
4323                     subnext 
= &exp
->_nodes
[n
->next
]; 
4327                 if ((cur 
= trex_matchnode(exp
, n
, cur
, subnext
)) == NULL
) { 
4328                     if (capture 
!= -1) { 
4329                         exp
->_matches
[capture
].begin 
= 0; 
4330                         exp
->_matches
[capture
].len 
= 0; 
4334             } while ((n
->next 
!= -1) && ((n 
= &exp
->_nodes
[n
->next
]) != NULL
)); 
4337                 exp
->_matches
[capture
].len 
= (int)(cur 
- exp
->_matches
[capture
].begin
); 
4341             if ((str 
== exp
->_bol 
&& !isspace(*str
)) || (str 
== exp
->_eol 
&& !isspace(*(str 
- 1))) || (!isspace(*str
) && isspace(*(str 
+ 1))) || 
4342                 (isspace(*str
) && !isspace(*(str 
+ 1)))) { 
4343                 return (node
->left 
== 'b') ? str 
: NULL
; 
4345             return (node
->left 
== 'b') ? NULL 
: str
; 
4347             if (str 
== exp
->_bol
) 
4351             if (str 
== exp
->_eol
) 
4360             if (trex_matchclass(exp
, &exp
->_nodes
[node
->left
], *str
) ? (type 
== OP_CLASS 
? TRex_True 
: TRex_False
) 
4361                                                                      : (type 
== OP_NCLASS 
? TRex_True 
: TRex_False
)) { 
4367             if (trex_matchcclass(node
->left
, *str
)) { 
4373             if (exp
->_flags 
& TREX_ICASE
) { 
4374                 if (*str 
!= tolower(node
->type
) && *str 
!= toupper(node
->type
)) 
4377                 if (*str 
!= node
->type
) 
4386 TRex
* trex_compile(const TRexChar
* pattern
, const TRexChar
** error
, int flags
) { 
4387     TRex
* exp 
= (TRex
*)xmalloc(sizeof(TRex
)); 
4388     exp
->_eol 
= exp
->_bol 
= NULL
; 
4390     exp
->_nallocated 
= (int)scstrlen(pattern
) * sizeof(TRexChar
); 
4391     exp
->_nodes 
= (TRexNode
*)xmalloc(exp
->_nallocated 
* sizeof(TRexNode
)); 
4395     exp
->_first 
= trex_newnode(exp
, OP_EXPR
); 
4396     exp
->_error 
= error
; 
4397     exp
->_jmpbuf 
= xmalloc(sizeof(jmp_buf)); 
4398     exp
->_flags 
= flags
; 
4399     if (setjmp(*((jmp_buf*)exp
->_jmpbuf
)) == 0) { 
4400         int res 
= trex_list(exp
); 
4401         exp
->_nodes
[exp
->_first
].left 
= res
; 
4402         if (*exp
->_p 
!= '\0') 
4403             trex_error(exp
, _SC("unexpected character")); 
4404 #ifdef ARG_REX_DEBUG 
4407             nsize 
= exp
->_nsize
; 
4408             scprintf(_SC("\n")); 
4409             for (i 
= 0; i 
< nsize
; i
++) { 
4410                 if (exp
->_nodes
[i
].type 
> MAX_CHAR
) 
4411                     scprintf(_SC("[%02d] %10s "), i
, g_nnames
[exp
->_nodes
[i
].type 
- MAX_CHAR
]); 
4413                     scprintf(_SC("[%02d] %10c "), i
, exp
->_nodes
[i
].type
); 
4414                 scprintf(_SC("left %02d right %02d next %02d\n"), exp
->_nodes
[i
].left
, exp
->_nodes
[i
].right
, exp
->_nodes
[i
].next
); 
4416             scprintf(_SC("\n")); 
4419         exp
->_matches 
= (TRexMatch
*)xmalloc(exp
->_nsubexpr 
* sizeof(TRexMatch
)); 
4420         memset(exp
->_matches
, 0, exp
->_nsubexpr 
* sizeof(TRexMatch
)); 
4428 void trex_free(TRex
* exp
) { 
4431         xfree(exp
->_jmpbuf
); 
4432         xfree(exp
->_matches
); 
4437 TRexBool 
trex_match(TRex
* exp
, const TRexChar
* text
) { 
4438     const TRexChar
* res 
= NULL
; 
4440     exp
->_eol 
= text 
+ scstrlen(text
); 
4441     exp
->_currsubexp 
= 0; 
4442     res 
= trex_matchnode(exp
, exp
->_nodes
, text
, NULL
); 
4443     if (res 
== NULL 
|| res 
!= exp
->_eol
) 
4448 TRexBool 
trex_searchrange(TRex
* exp
, const TRexChar
* text_begin
, const TRexChar
* text_end
, const TRexChar
** out_begin
, const TRexChar
** out_end
) { 
4449     const TRexChar
* cur 
= NULL
; 
4450     int node 
= exp
->_first
; 
4451     if (text_begin 
>= text_end
) 
4453     exp
->_bol 
= text_begin
; 
4454     exp
->_eol 
= text_end
; 
4457         while (node 
!= -1) { 
4458             exp
->_currsubexp 
= 0; 
4459             cur 
= trex_matchnode(exp
, &exp
->_nodes
[node
], cur
, NULL
); 
4462             node 
= exp
->_nodes
[node
].next
; 
4465     } while (cur 
== NULL 
&& text_begin 
!= text_end
); 
4473         *out_begin 
= text_begin
; 
4479 TRexBool 
trex_search(TRex
* exp
, const TRexChar
* text
, const TRexChar
** out_begin
, const TRexChar
** out_end
) { 
4480     return trex_searchrange(exp
, text
, text 
+ scstrlen(text
), out_begin
, out_end
); 
4483 int trex_getsubexpcount(TRex
* exp
) { 
4484     return exp
->_nsubexpr
; 
4487 TRexBool 
trex_getsubexp(TRex
* exp
, int n
, TRexMatch
* subexp
) { 
4488     if (n 
< 0 || n 
>= exp
->_nsubexpr
) 
4490     *subexp 
= exp
->_matches
[n
]; 
4493 /******************************************************************************* 
4494  * arg_str: Implements the str command-line option 
4496  * This file is part of the argtable3 library. 
4498  * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann 
4499  * <sheitmann@users.sourceforge.net> 
4500  * All rights reserved. 
4502  * Redistribution and use in source and binary forms, with or without 
4503  * modification, are permitted provided that the following conditions are met: 
4504  *     * Redistributions of source code must retain the above copyright 
4505  *       notice, this list of conditions and the following disclaimer. 
4506  *     * Redistributions in binary form must reproduce the above copyright 
4507  *       notice, this list of conditions and the following disclaimer in the 
4508  *       documentation and/or other materials provided with the distribution. 
4509  *     * Neither the name of STEWART HEITMANN nor the  names of its contributors 
4510  *       may be used to endorse or promote products derived from this software 
4511  *       without specific prior written permission. 
4513  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
4514  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
4515  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
4516  * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, 
4517  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
4518  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
4519  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
4520  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
4521  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
4522  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
4523  ******************************************************************************/ 
4525 #include "argtable3.h" 
4527 #ifndef ARG_AMALGAMATION 
4528 #include "argtable3_private.h" 
4533 static void arg_str_resetfn(struct arg_str
* parent
) { 
4536     ARG_TRACE(("%s:resetfn(%p)\n", __FILE__
, parent
)); 
4537     for (i 
= 0; i 
< parent
->count
; i
++) { 
4538         parent
->sval
[i
] = ""; 
4543 static int arg_str_scanfn(struct arg_str
* parent
, const char* argval
) { 
4546     if (parent
->count 
== parent
->hdr
.maxcount
) { 
4547         /* maximum number of arguments exceeded */ 
4548         errorcode 
= ARG_ERR_MAXCOUNT
; 
4549     } else if (!argval
) { 
4550         /* a valid argument with no argument value was given. */ 
4551         /* This happens when an optional argument value was invoked. */ 
4552         /* leave parent argument value unaltered but still count the argument. */ 
4555         parent
->sval
[parent
->count
++] = argval
; 
4558     ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__
, parent
, errorcode
)); 
4562 static int arg_str_checkfn(struct arg_str
* parent
) { 
4563     int errorcode 
= (parent
->count 
< parent
->hdr
.mincount
) ? ARG_ERR_MINCOUNT 
: 0; 
4565     ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__
, parent
, errorcode
)); 
4569 static void arg_str_errorfn(struct arg_str
* parent
, arg_dstr_t ds
, int errorcode
, const char* argval
, const char* progname
) { 
4570     const char* shortopts 
= parent
->hdr
.shortopts
; 
4571     const char* longopts 
= parent
->hdr
.longopts
; 
4572     const char* datatype 
= parent
->hdr
.datatype
; 
4574     /* make argval NULL safe */ 
4575     argval 
= argval 
? argval 
: ""; 
4577     arg_dstr_catf(ds
, "%s: ", progname
); 
4578     switch (errorcode
) { 
4579         case ARG_ERR_MINCOUNT
: 
4580             arg_dstr_cat(ds
, "missing option "); 
4581             arg_print_option_ds(ds
, shortopts
, longopts
, datatype
, "\n"); 
4584         case ARG_ERR_MAXCOUNT
: 
4585             arg_dstr_cat(ds
, "excess option "); 
4586             arg_print_option_ds(ds
, shortopts
, longopts
, argval
, "\n"); 
4591 struct arg_str
* arg_str0(const char* shortopts
, const char* longopts
, const char* datatype
, const char* glossary
) { 
4592     return arg_strn(shortopts
, longopts
, datatype
, 0, 1, glossary
); 
4595 struct arg_str
* arg_str1(const char* shortopts
, const char* longopts
, const char* datatype
, const char* glossary
) { 
4596     return arg_strn(shortopts
, longopts
, datatype
, 1, 1, glossary
); 
4599 struct arg_str
* arg_strn(const char* shortopts
, const char* longopts
, const char* datatype
, int mincount
, int maxcount
, const char* glossary
) { 
4601     struct arg_str
* result
; 
4604     /* should not allow this stupid error */ 
4605     /* we should return an error code warning this logic error */ 
4606     /* foolproof things by ensuring maxcount is not less than mincount */ 
4607     maxcount 
= (maxcount 
< mincount
) ? mincount 
: maxcount
; 
4609     nbytes 
= sizeof(struct arg_str
)      /* storage for struct arg_str */ 
4610              + maxcount 
* sizeof(char*); /* storage for sval[maxcount] array */ 
4612     result 
= (struct arg_str
*)xmalloc(nbytes
); 
4614     /* init the arg_hdr struct */ 
4615     result
->hdr
.flag 
= ARG_HASVALUE
; 
4616     result
->hdr
.shortopts 
= shortopts
; 
4617     result
->hdr
.longopts 
= longopts
; 
4618     result
->hdr
.datatype 
= datatype 
? datatype 
: "<string>"; 
4619     result
->hdr
.glossary 
= glossary
; 
4620     result
->hdr
.mincount 
= mincount
; 
4621     result
->hdr
.maxcount 
= maxcount
; 
4622     result
->hdr
.parent 
= result
; 
4623     result
->hdr
.resetfn 
= (arg_resetfn
*)arg_str_resetfn
; 
4624     result
->hdr
.scanfn 
= (arg_scanfn
*)arg_str_scanfn
; 
4625     result
->hdr
.checkfn 
= (arg_checkfn
*)arg_str_checkfn
; 
4626     result
->hdr
.errorfn 
= (arg_errorfn
*)arg_str_errorfn
; 
4628     /* store the sval[maxcount] array immediately after the arg_str struct */ 
4629     result
->sval 
= (const char**)(result 
+ 1); 
4632     /* foolproof the string pointers by initializing them to reference empty strings */ 
4633     for (i 
= 0; i 
< maxcount
; i
++) 
4634         result
->sval
[i
] = ""; 
4636     ARG_TRACE(("arg_strn() returns %p\n", result
)); 
4639 /******************************************************************************* 
4640  * arg_cmd: Provides the sub-command mechanism 
4642  * This file is part of the argtable3 library. 
4644  * Copyright (C) 2013-2019 Tom G. Huang 
4645  * <tomghuang@gmail.com> 
4646  * All rights reserved. 
4648  * Redistribution and use in source and binary forms, with or without 
4649  * modification, are permitted provided that the following conditions are met: 
4650  *     * Redistributions of source code must retain the above copyright 
4651  *       notice, this list of conditions and the following disclaimer. 
4652  *     * Redistributions in binary form must reproduce the above copyright 
4653  *       notice, this list of conditions and the following disclaimer in the 
4654  *       documentation and/or other materials provided with the distribution. 
4655  *     * Neither the name of STEWART HEITMANN nor the  names of its contributors 
4656  *       may be used to endorse or promote products derived from this software 
4657  *       without specific prior written permission. 
4659  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
4660  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
4661  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
4662  * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, 
4663  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
4664  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
4665  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
4666  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
4667  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
4668  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
4669  ******************************************************************************/ 
4671 #include "argtable3.h" 
4673 #ifndef ARG_AMALGAMATION 
4674 #include "argtable3_private.h" 
4681 #define MAX_MODULE_VERSION_SIZE 128 
4683 static arg_hashtable_t
* s_hashtable 
= NULL
; 
4684 static char* s_module_name 
= NULL
; 
4685 static int s_mod_ver_major 
= 0; 
4686 static int s_mod_ver_minor 
= 0; 
4687 static int s_mod_ver_patch 
= 0; 
4688 static char* s_mod_ver_tag 
= NULL
; 
4689 static char* s_mod_ver 
= NULL
; 
4691 void arg_set_module_name(const char* name
) { 
4694     xfree(s_module_name
); 
4695     slen 
= strlen(name
); 
4696     s_module_name 
= (char*)xmalloc(slen 
+ 1); 
4697     memset(s_module_name
, 0, slen 
+ 1); 
4699 #if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__)) 
4700     strncpy_s(s_module_name
, slen 
+ 1, name
, slen
); 
4702     memcpy(s_module_name
, name
, slen
); 
4706 void arg_set_module_version(int major
, int minor
, int patch
, const char* tag
) { 
4707     size_t slen_tag
, slen_ds
; 
4710     s_mod_ver_major 
= major
; 
4711     s_mod_ver_minor 
= minor
; 
4712     s_mod_ver_patch 
= patch
; 
4714     xfree(s_mod_ver_tag
); 
4715     slen_tag 
= strlen(tag
); 
4716     s_mod_ver_tag 
= (char*)xmalloc(slen_tag 
+ 1); 
4717     memset(s_mod_ver_tag
, 0, slen_tag 
+ 1); 
4719 #if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__)) 
4720     strncpy_s(s_mod_ver_tag
, slen_tag 
+ 1, tag
, slen_tag
); 
4722     memcpy(s_mod_ver_tag
, tag
, slen_tag
); 
4725     ds 
= arg_dstr_create(); 
4726     arg_dstr_catf(ds
, "%d.", s_mod_ver_major
); 
4727     arg_dstr_catf(ds
, "%d.", s_mod_ver_minor
); 
4728     arg_dstr_catf(ds
, "%d.", s_mod_ver_patch
); 
4729     arg_dstr_cat(ds
, s_mod_ver_tag
); 
4732     slen_ds 
= strlen(arg_dstr_cstr(ds
)); 
4733     s_mod_ver 
= (char*)xmalloc(slen_ds 
+ 1); 
4734     memset(s_mod_ver
, 0, slen_ds 
+ 1); 
4736 #if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__)) 
4737     strncpy_s(s_mod_ver
, slen_ds 
+ 1, arg_dstr_cstr(ds
), slen_ds
); 
4739     memcpy(s_mod_ver
, arg_dstr_cstr(ds
), slen_ds
); 
4742     arg_dstr_destroy(ds
); 
4745 static unsigned int hash_key(const void* key
) { 
4746     const char* str 
= (const char*)key
; 
4748     unsigned int hash 
= 5381; 
4750     while ((c 
= *str
++) != 0) 
4751         hash 
= ((hash 
<< 5) + hash
) + c
; /* hash * 33 + c */ 
4756 static int equal_keys(const void* key1
, const void* key2
) { 
4757     char* k1 
= (char*)key1
; 
4758     char* k2 
= (char*)key2
; 
4759     return (0 == strcmp(k1
, k2
)); 
4762 void arg_cmd_init(void) { 
4763     s_hashtable 
= arg_hashtable_create(32, hash_key
, equal_keys
); 
4766 void arg_cmd_uninit(void) { 
4767     arg_hashtable_destroy(s_hashtable
, 1); 
4770 void arg_cmd_register(const char* name
, arg_cmdfn
* proc
, const char* description
) { 
4771     arg_cmd_info_t
* cmd_info
; 
4775     assert(strlen(name
) < ARG_CMD_NAME_LEN
); 
4776     assert(strlen(description
) < ARG_CMD_DESCRIPTION_LEN
); 
4778     /* Check if the command already exists. */ 
4779     /* If the command exists, replace the existing command. */ 
4780     /* If the command doesn't exist, insert the command. */ 
4781     cmd_info 
= (arg_cmd_info_t
*)arg_hashtable_search(s_hashtable
, name
); 
4783         arg_hashtable_remove(s_hashtable
, name
); 
4787     cmd_info 
= (arg_cmd_info_t
*)xmalloc(sizeof(arg_cmd_info_t
)); 
4788     memset(cmd_info
, 0, sizeof(arg_cmd_info_t
)); 
4790 #if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__)) 
4791     strncpy_s(cmd_info
->name
, ARG_CMD_NAME_LEN
, name
, strlen(name
)); 
4792     strncpy_s(cmd_info
->description
, ARG_CMD_DESCRIPTION_LEN
, description
, strlen(description
)); 
4794     memcpy(cmd_info
->name
, name
, strlen(name
)); 
4795     memcpy(cmd_info
->description
, description
, strlen(description
)); 
4798     cmd_info
->proc 
= proc
; 
4800     slen_name 
= strlen(name
); 
4801     k 
= xmalloc(slen_name 
+ 1); 
4802     memset(k
, 0, slen_name 
+ 1); 
4804 #if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__)) 
4805     strncpy_s((char*)k
, slen_name 
+ 1, name
, slen_name
); 
4807     memcpy((char*)k
, name
, slen_name
); 
4810     arg_hashtable_insert(s_hashtable
, k
, cmd_info
); 
4813 void arg_cmd_unregister(const char* name
) { 
4814     arg_hashtable_remove(s_hashtable
, name
); 
4817 int arg_cmd_dispatch(const char* name
, int argc
, char* argv
[], arg_dstr_t res
) { 
4818     arg_cmd_info_t
* cmd_info 
= arg_cmd_info(name
); 
4820     assert(cmd_info 
!= NULL
); 
4821     assert(cmd_info
->proc 
!= NULL
); 
4823     return cmd_info
->proc(argc
, argv
, res
); 
4826 arg_cmd_info_t
* arg_cmd_info(const char* name
) { 
4827     return (arg_cmd_info_t
*)arg_hashtable_search(s_hashtable
, name
); 
4830 unsigned int arg_cmd_count(void) { 
4831     return arg_hashtable_count(s_hashtable
); 
4834 arg_cmd_itr_t 
arg_cmd_itr_create(void) { 
4835     return (arg_cmd_itr_t
)arg_hashtable_itr_create(s_hashtable
); 
4838 int arg_cmd_itr_advance(arg_cmd_itr_t itr
) { 
4839     return arg_hashtable_itr_advance((arg_hashtable_itr_t
*)itr
); 
4842 char* arg_cmd_itr_key(arg_cmd_itr_t itr
) { 
4843     return (char*)arg_hashtable_itr_key((arg_hashtable_itr_t
*)itr
); 
4846 arg_cmd_info_t
* arg_cmd_itr_value(arg_cmd_itr_t itr
) { 
4847     return (arg_cmd_info_t
*)arg_hashtable_itr_value((arg_hashtable_itr_t
*)itr
); 
4850 void arg_cmd_itr_destroy(arg_cmd_itr_t itr
) { 
4851     arg_hashtable_itr_destroy((arg_hashtable_itr_t
*)itr
); 
4854 int arg_cmd_itr_search(arg_cmd_itr_t itr
, void* k
) { 
4855     return arg_hashtable_itr_search((arg_hashtable_itr_t
*)itr
, s_hashtable
, k
); 
4858 static const char* module_name(void) { 
4859     if (s_module_name 
== NULL 
|| strlen(s_module_name
) == 0) 
4862     return s_module_name
; 
4865 static const char* module_version(void) { 
4866     if (s_mod_ver 
== NULL 
|| strlen(s_mod_ver
) == 0) 
4872 void arg_make_get_help_msg(arg_dstr_t res
) { 
4873     arg_dstr_catf(res
, "%s v%s\n", module_name(), module_version()); 
4874     arg_dstr_catf(res
, "Please type '%s help' to get more information.\n", module_name()); 
4877 void arg_make_help_msg(arg_dstr_t ds
, char* cmd_name
, void** argtable
) { 
4878     arg_cmd_info_t
* cmd_info 
= (arg_cmd_info_t
*)arg_hashtable_search(s_hashtable
, cmd_name
); 
4880         arg_dstr_catf(ds
, "%s: %s\n", cmd_name
, cmd_info
->description
); 
4883     arg_dstr_cat(ds
, "Usage:\n"); 
4884     arg_dstr_catf(ds
, "  %s", module_name()); 
4886     arg_print_syntaxv_ds(ds
, argtable
, "\n \nAvailable options:\n"); 
4887     arg_print_glossary_ds(ds
, argtable
, "  %-23s %s\n"); 
4889     arg_dstr_cat(ds
, "\n"); 
4892 void arg_make_syntax_err_msg(arg_dstr_t ds
, void** argtable
, struct arg_end
* end
) { 
4893     arg_print_errors_ds(ds
, end
, module_name()); 
4894     arg_dstr_cat(ds
, "Usage: \n"); 
4895     arg_dstr_catf(ds
, "  %s", module_name()); 
4896     arg_print_syntaxv_ds(ds
, argtable
, "\n"); 
4897     arg_dstr_cat(ds
, "\n"); 
4900 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
) { 
4902      * note: '-h|--help' takes precedence over error reporting 
4905         arg_make_help_msg(ds
, name
, argtable
); 
4906         *exitcode 
= EXIT_SUCCESS
; 
4910     /* syntax error handling */ 
4912         arg_make_syntax_err_msg(ds
, argtable
, end
); 
4913         *exitcode 
= EXIT_FAILURE
; 
4919 /******************************************************************************* 
4920  * argtable3: Implements the main interfaces of the library 
4922  * This file is part of the argtable3 library. 
4924  * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann 
4925  * <sheitmann@users.sourceforge.net> 
4926  * All rights reserved. 
4928  * Redistribution and use in source and binary forms, with or without 
4929  * modification, are permitted provided that the following conditions are met: 
4930  *     * Redistributions of source code must retain the above copyright 
4931  *       notice, this list of conditions and the following disclaimer. 
4932  *     * Redistributions in binary form must reproduce the above copyright 
4933  *       notice, this list of conditions and the following disclaimer in the 
4934  *       documentation and/or other materials provided with the distribution. 
4935  *     * Neither the name of STEWART HEITMANN nor the  names of its contributors 
4936  *       may be used to endorse or promote products derived from this software 
4937  *       without specific prior written permission. 
4939  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
4940  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
4941  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
4942  * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, 
4943  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
4944  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
4945  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
4946  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
4947  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
4948  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
4949  ******************************************************************************/ 
4951 #include "argtable3.h" 
4953 #ifndef ARG_AMALGAMATION 
4954 #include "argtable3_private.h" 
4955 #if ARG_REPLACE_GETOPT == 1 
4956 #include "arg_getopt.h" 
4961 #if ARG_REPLACE_GETOPT == 0 
4967 #define WIN32_LEAN_AND_MEAN 
4968 #include <windows.h> 
4969 #undef WIN32_LEAN_AND_MEAN 
4978 static void arg_register_error(struct arg_end
* end
, void* parent
, int error
, const char* argval
) { 
4979     /* printf("arg_register_error(%p,%p,%d,%s)\n",end,parent,error,argval); */ 
4980     if (end
->count 
< end
->hdr
.maxcount
) { 
4981         end
->error
[end
->count
] = error
; 
4982         end
->parent
[end
->count
] = parent
; 
4983         end
->argval
[end
->count
] = argval
; 
4986         end
->error
[end
->hdr
.maxcount 
- 1] = ARG_ELIMIT
; 
4987         end
->parent
[end
->hdr
.maxcount 
- 1] = end
; 
4988         end
->argval
[end
->hdr
.maxcount 
- 1] = NULL
; 
4993  * Return index of first table entry with a matching short option 
4994  * or -1 if no match was found. 
4996 static int find_shortoption(struct arg_hdr
** table
, char shortopt
) { 
4998     for (tabindex 
= 0; !(table
[tabindex
]->flag 
& ARG_TERMINATOR
); tabindex
++) { 
4999         if (table
[tabindex
]->shortopts 
&& strchr(table
[tabindex
]->shortopts
, shortopt
)) 
5005 struct longoptions 
{ 
5008     struct option
* options
; 
5013 void dump_longoptions(struct longoptions 
* longoptions
) 
5016     printf("getoptval = %d\n", longoptions
->getoptval
); 
5017     printf("noptions  = %d\n", longoptions
->noptions
); 
5018     for (i 
= 0; i 
< longoptions
->noptions
; i
++) 
5020         printf("options[%d].name    = \"%s\"\n", 
5022                longoptions
->options
[i
].name
); 
5023         printf("options[%d].has_arg = %d\n", i
, longoptions
->options
[i
].has_arg
); 
5024         printf("options[%d].flag    = %p\n", i
, longoptions
->options
[i
].flag
); 
5025         printf("options[%d].val     = %d\n", i
, longoptions
->options
[i
].val
); 
5030 static struct longoptions
* alloc_longoptions(struct arg_hdr
** table
) { 
5031     struct longoptions
* result
; 
5034     size_t longoptlen 
= 0; 
5036     int option_index 
= 0; 
5040      * Determine the total number of option structs required 
5041      * by counting the number of comma separated long options 
5042      * in all table entries and return the count in noptions. 
5043      * note: noptions starts at 1 not 0 because we getoptlong 
5044      * requires a NULL option entry to terminate the option array. 
5045      * While we are at it, count the number of chars required 
5046      * to store private copies of all the longoption strings 
5047      * and return that count in logoptlen. 
5051         const char* longopts 
= table
[tabindex
]->longopts
; 
5052         longoptlen 
+= (longopts 
? strlen(longopts
) : 0) + 1; 
5055             longopts 
= strchr(longopts 
+ 1, ','); 
5057     } while (!(table
[tabindex
++]->flag 
& ARG_TERMINATOR
)); 
5058     /*printf("%d long options consuming %d chars in total\n",noptions,longoptlen);*/ 
5060     /* allocate storage for return data structure as: */ 
5061     /* (struct longoptions) + (struct options)[noptions] + char[longoptlen] */ 
5062     nbytes 
= sizeof(struct longoptions
) + sizeof(struct option
) * noptions 
+ longoptlen
; 
5063     result 
= (struct longoptions
*)xmalloc(nbytes
); 
5065     result
->getoptval 
= 0; 
5066     result
->noptions 
= noptions
; 
5067     result
->options 
= (struct option
*)(result 
+ 1); 
5068     store 
= (char*)(result
->options 
+ noptions
); 
5070     for (tabindex 
= 0; !(table
[tabindex
]->flag 
& ARG_TERMINATOR
); tabindex
++) { 
5071         const char* longopts 
= table
[tabindex
]->longopts
; 
5073         while (longopts 
&& *longopts
) { 
5074             char* storestart 
= store
; 
5076             /* copy progressive longopt strings into the store */ 
5077             while (*longopts 
!= 0 && *longopts 
!= ',') 
5078                 *store
++ = *longopts
++; 
5080             if (*longopts 
== ',') 
5082             /*fprintf(stderr,"storestart=\"%s\"\n",storestart);*/ 
5084             result
->options
[option_index
].name 
= storestart
; 
5085             result
->options
[option_index
].flag 
= &(result
->getoptval
); 
5086             result
->options
[option_index
].val 
= tabindex
; 
5087             if (table
[tabindex
]->flag 
& ARG_HASOPTVALUE
) 
5088                 result
->options
[option_index
].has_arg 
= 2; 
5089             else if (table
[tabindex
]->flag 
& ARG_HASVALUE
) 
5090                 result
->options
[option_index
].has_arg 
= 1; 
5092                 result
->options
[option_index
].has_arg 
= 0; 
5097     /* terminate the options array with a zero-filled entry */ 
5098     result
->options
[option_index
].name 
= 0; 
5099     result
->options
[option_index
].has_arg 
= 0; 
5100     result
->options
[option_index
].flag 
= 0; 
5101     result
->options
[option_index
].val 
= 0; 
5103     /*dump_longoptions(result);*/ 
5107 static char* alloc_shortoptions(struct arg_hdr
** table
) { 
5113     /* determine the total number of option chars required */ 
5114     for (tabindex 
= 0; !(table
[tabindex
]->flag 
& ARG_TERMINATOR
); tabindex
++) { 
5115         struct arg_hdr
* hdr 
= table
[tabindex
]; 
5116         len 
+= 3 * (hdr
->shortopts 
? strlen(hdr
->shortopts
) : 0); 
5119     result 
= xmalloc(len
); 
5123     /* add a leading ':' so getopt return codes distinguish    */ 
5124     /* unrecognised option and options missing argument values */ 
5127     for (tabindex 
= 0; !(table
[tabindex
]->flag 
& ARG_TERMINATOR
); tabindex
++) { 
5128         struct arg_hdr
* hdr 
= table
[tabindex
]; 
5129         const char* shortopts 
= hdr
->shortopts
; 
5130         while (shortopts 
&& *shortopts
) { 
5131             *res
++ = *shortopts
++; 
5132             if (hdr
->flag 
& ARG_HASVALUE
) 
5134             if (hdr
->flag 
& ARG_HASOPTVALUE
) 
5138     /* null terminate the string */ 
5141     /*printf("alloc_shortoptions() returns \"%s\"\n",(result?result:"NULL"));*/ 
5145 /* return index of the table terminator entry */ 
5146 static int arg_endindex(struct arg_hdr
** table
) { 
5148     while (!(table
[tabindex
]->flag 
& ARG_TERMINATOR
)) 
5153 static void arg_parse_tagged(int argc
, char** argv
, struct arg_hdr
** table
, struct arg_end
* endtable
) { 
5154     struct longoptions
* longoptions
; 
5158     /*printf("arg_parse_tagged(%d,%p,%p,%p)\n",argc,argv,table,endtable);*/ 
5160     /* allocate short and long option arrays for the given opttable[].   */ 
5161     /* if the allocs fail then put an error msg in the last table entry. */ 
5162     longoptions 
= alloc_longoptions(table
); 
5163     shortoptions 
= alloc_shortoptions(table
); 
5165     /*dump_longoptions(longoptions);*/ 
5167     /* reset getopts internal option-index to zero, and disable error reporting */ 
5171     /* fetch and process args using getopt_long */ 
5172 #ifdef ARG_LONG_ONLY 
5173     while ((copt 
= getopt_long_only(argc
, argv
, shortoptions
, longoptions
->options
, NULL
)) != -1) { 
5175     while ((copt 
= getopt_long(argc
, argv
, shortoptions
, longoptions
->options
, NULL
)) != -1) { 
5178            printf("optarg='%s'\n",optarg); 
5179            printf("optind=%d\n",optind); 
5180            printf("copt=%c\n",(char)copt); 
5181            printf("optopt=%c (%d)\n",optopt, (int)(optopt)); 
5185                 int tabindex 
= longoptions
->getoptval
; 
5186                 void* parent 
= table
[tabindex
]->parent
; 
5187                 /*printf("long option detected from argtable[%d]\n", tabindex);*/ 
5188                 if (optarg 
&& optarg
[0] == 0 && (table
[tabindex
]->flag 
& ARG_HASVALUE
)) { 
5189                     /* printf(": long option %s requires an argument\n",argv[optind-1]); */ 
5190                     arg_register_error(endtable
, endtable
, ARG_EMISSARG
, argv
[optind 
- 1]); 
5191                     /* continue to scan the (empty) argument value to enforce argument count checking */ 
5193                 if (table
[tabindex
]->scanfn
) { 
5194                     int errorcode 
= table
[tabindex
]->scanfn(parent
, optarg
); 
5196                         arg_register_error(endtable
, parent
, errorcode
, optarg
); 
5202                  * getopt_long() found an unrecognised short option. 
5203                  * if it was a short option its value is in optopt 
5204                  * if it was a long option then optopt=0 
5208                         /*printf("?0 unrecognised long option %s\n",argv[optind-1]);*/ 
5209                         arg_register_error(endtable
, endtable
, ARG_ELONGOPT
, argv
[optind 
- 1]); 
5212                         /*printf("?* unrecognised short option '%c'\n",optopt);*/ 
5213                         arg_register_error(endtable
, endtable
, optopt
, NULL
); 
5220                  * getopt_long() found an option with its argument missing. 
5222                 /*printf(": option %s requires an argument\n",argv[optind-1]); */ 
5223                 arg_register_error(endtable
, endtable
, ARG_EMISSARG
, argv
[optind 
- 1]); 
5227                 /* getopt_long() found a valid short option */ 
5228                 int tabindex 
= find_shortoption(table
, (char)copt
); 
5229                 /*printf("short option detected from argtable[%d]\n", tabindex);*/ 
5230                 if (tabindex 
== -1) { 
5231                     /* should never get here - but handle it just in case */ 
5232                     /*printf("unrecognised short option %d\n",copt);*/ 
5233                     arg_register_error(endtable
, endtable
, copt
, NULL
); 
5235                     if (table
[tabindex
]->scanfn
) { 
5236                         void* parent 
= table
[tabindex
]->parent
; 
5237                         int errorcode 
= table
[tabindex
]->scanfn(parent
, optarg
); 
5239                             arg_register_error(endtable
, parent
, errorcode
, optarg
); 
5247     xfree(shortoptions
); 
5251 static void arg_parse_untagged(int argc
, char** argv
, struct arg_hdr
** table
, struct arg_end
* endtable
) { 
5254     const char* optarglast 
= NULL
; 
5255     void* parentlast 
= NULL
; 
5257     /*printf("arg_parse_untagged(%d,%p,%p,%p)\n",argc,argv,table,endtable);*/ 
5258     while (!(table
[tabindex
]->flag 
& ARG_TERMINATOR
)) { 
5262         /* if we have exhausted our argv[optind] entries then we have finished */ 
5263         if (optind 
>= argc
) { 
5264             /*printf("arg_parse_untagged(): argv[] exhausted\n");*/ 
5268         /* skip table entries with non-null long or short options (they are not untagged entries) */ 
5269         if (table
[tabindex
]->longopts 
|| table
[tabindex
]->shortopts
) { 
5270             /*printf("arg_parse_untagged(): skipping argtable[%d] (tagged argument)\n",tabindex);*/ 
5275         /* skip table entries with NULL scanfn */ 
5276         if (!(table
[tabindex
]->scanfn
)) { 
5277             /*printf("arg_parse_untagged(): skipping argtable[%d] (NULL scanfn)\n",tabindex);*/ 
5282         /* attempt to scan the current argv[optind] with the current     */ 
5283         /* table[tabindex] entry. If it succeeds then keep it, otherwise */ 
5284         /* try again with the next table[] entry.                        */ 
5285         parent 
= table
[tabindex
]->parent
; 
5286         errorcode 
= table
[tabindex
]->scanfn(parent
, argv
[optind
]); 
5287         if (errorcode 
== 0) { 
5288             /* success, move onto next argv[optind] but stay with same table[tabindex] */ 
5289             /*printf("arg_parse_untagged(): argtable[%d] successfully matched\n",tabindex);*/ 
5292             /* clear the last tentative error */ 
5295             /* failure, try same argv[optind] with next table[tabindex] entry */ 
5296             /*printf("arg_parse_untagged(): argtable[%d] failed match\n",tabindex);*/ 
5299             /* remember this as a tentative error we may wish to reinstate later */ 
5300             errorlast 
= errorcode
; 
5301             optarglast 
= argv
[optind
]; 
5302             parentlast 
= parent
; 
5306     /* if a tenative error still remains at this point then register it as a proper error */ 
5308         arg_register_error(endtable
, parentlast
, errorlast
, optarglast
); 
5312     /* only get here when not all argv[] entries were consumed */ 
5313     /* register an error for each unused argv[] entry */ 
5314     while (optind 
< argc
) { 
5315         /*printf("arg_parse_untagged(): argv[%d]=\"%s\" not consumed\n",optind,argv[optind]);*/ 
5316         arg_register_error(endtable
, endtable
, ARG_ENOMATCH
, argv
[optind
++]); 
5322 static void arg_parse_check(struct arg_hdr
** table
, struct arg_end
* endtable
) { 
5324     /* printf("arg_parse_check()\n"); */ 
5326         if (table
[tabindex
]->checkfn
) { 
5327             void* parent 
= table
[tabindex
]->parent
; 
5328             int errorcode 
= table
[tabindex
]->checkfn(parent
); 
5330                 arg_register_error(endtable
, parent
, errorcode
, NULL
); 
5332     } while (!(table
[tabindex
++]->flag 
& ARG_TERMINATOR
)); 
5335 static void arg_reset(void** argtable
) { 
5336     struct arg_hdr
** table 
= (struct arg_hdr
**)argtable
; 
5338     /*printf("arg_reset(%p)\n",argtable);*/ 
5340         if (table
[tabindex
]->resetfn
) 
5341             table
[tabindex
]->resetfn(table
[tabindex
]->parent
); 
5342     } while (!(table
[tabindex
++]->flag 
& ARG_TERMINATOR
)); 
5345 int arg_parse(int argc
, char** argv
, void** argtable
) { 
5346     struct arg_hdr
** table 
= (struct arg_hdr
**)argtable
; 
5347     struct arg_end
* endtable
; 
5349     char** argvcopy 
= NULL
; 
5352     /*printf("arg_parse(%d,%p,%p)\n",argc,argv,argtable);*/ 
5354     /* reset any argtable data from previous invocations */ 
5355     arg_reset(argtable
); 
5357     /* locate the first end-of-table marker within the array */ 
5358     endindex 
= arg_endindex(table
); 
5359     endtable 
= (struct arg_end
*)table
[endindex
]; 
5361     /* Special case of argc==0.  This can occur on Texas Instruments DSP. */ 
5362     /* Failure to trap this case results in an unwanted NULL result from  */ 
5363     /* the malloc for argvcopy (next code block).                         */ 
5365         /* We must still perform post-parse checks despite the absence of command line arguments */ 
5366         arg_parse_check(table
, endtable
); 
5368         /* Now we are finished */ 
5369         return endtable
->count
; 
5372     argvcopy 
= (char**)xmalloc(sizeof(char*) * (argc 
+ 1)); 
5375         Fill in the local copy of argv[]. We need a local copy 
5376         because getopt rearranges argv[] which adversely affects 
5377         susbsequent parsing attempts. 
5379     for (i 
= 0; i 
< argc
; i
++) 
5380         argvcopy
[i
] = argv
[i
]; 
5382     argvcopy
[argc
] = NULL
; 
5384     /* parse the command line (local copy) for tagged options */ 
5385     arg_parse_tagged(argc
, argvcopy
, table
, endtable
); 
5387     /* parse the command line (local copy) for untagged options */ 
5388     arg_parse_untagged(argc
, argvcopy
, table
, endtable
); 
5390     /* if no errors so far then perform post-parse checks otherwise dont bother */ 
5391     if (endtable
->count 
== 0) 
5392         arg_parse_check(table
, endtable
); 
5394     /* release the local copt of argv[] */ 
5397     return endtable
->count
; 
5401  * Concatenate contents of src[] string onto *pdest[] string. 
5402  * The *pdest pointer is altered to point to the end of the 
5403  * target string and *pndest is decremented by the same number 
5405  * Does not append more than *pndest chars into *pdest[] 
5406  * so as to prevent buffer overruns. 
5407  * Its something like strncat() but more efficient for repeated 
5408  * calls on the same destination string. 
5410  *   char dest[30] = "good" 
5411  *   size_t ndest = sizeof(dest); 
5412  *   char *pdest = dest; 
5413  *   arg_char(&pdest,"bye ",&ndest); 
5414  *   arg_char(&pdest,"cruel ",&ndest); 
5415  *   arg_char(&pdest,"world!",&ndest); 
5417  *   dest[] == "goodbye cruel world!" 
5420 static void arg_cat(char** pdest
, const char* src
, size_t* pndest
) { 
5421     char* dest 
= *pdest
; 
5422     char* end 
= dest 
+ *pndest
; 
5424     /*locate null terminator of dest string */ 
5425     while (dest 
< end 
&& *dest 
!= 0) 
5428     /* concat src string to dest string */ 
5429     while (dest 
< end 
&& *src 
!= 0) 
5432     /* null terminate dest string */ 
5435     /* update *pdest and *pndest */ 
5436     *pndest 
= end 
- dest
; 
5440 static void arg_cat_option(char* dest
, size_t ndest
, const char* shortopts
, const char* longopts
, const char* datatype
, int optvalue
) { 
5444         /* note: option array[] is initialiazed dynamically here to satisfy   */ 
5445         /* a deficiency in the watcom compiler wrt static array initializers. */ 
5447         option
[1] = shortopts
[0]; 
5450         arg_cat(&dest
, option
, &ndest
); 
5452             arg_cat(&dest
, " ", &ndest
); 
5454                 arg_cat(&dest
, "[", &ndest
); 
5455                 arg_cat(&dest
, datatype
, &ndest
); 
5456                 arg_cat(&dest
, "]", &ndest
); 
5458                 arg_cat(&dest
, datatype
, &ndest
); 
5460     } else if (longopts
) { 
5463         /* add "--" tag prefix */ 
5464         arg_cat(&dest
, "--", &ndest
); 
5466         /* add comma separated option tag */ 
5467         ncspn 
= strcspn(longopts
, ","); 
5468 #if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__)) 
5469         strncat_s(dest
, ndest
, longopts
, (ncspn 
< ndest
) ? ncspn 
: ndest
); 
5471         strncat(dest
, longopts
, (ncspn 
< ndest
) ? ncspn 
: ndest
); 
5475             arg_cat(&dest
, "=", &ndest
); 
5477                 arg_cat(&dest
, "[", &ndest
); 
5478                 arg_cat(&dest
, datatype
, &ndest
); 
5479                 arg_cat(&dest
, "]", &ndest
); 
5481                 arg_cat(&dest
, datatype
, &ndest
); 
5483     } else if (datatype
) { 
5485             arg_cat(&dest
, "[", &ndest
); 
5486             arg_cat(&dest
, datatype
, &ndest
); 
5487             arg_cat(&dest
, "]", &ndest
); 
5489             arg_cat(&dest
, datatype
, &ndest
); 
5493 static void arg_cat_optionv(char* dest
, size_t ndest
, const char* shortopts
, const char* longopts
, const char* datatype
, int optvalue
, const char* separator
) { 
5494     separator 
= separator 
? separator 
: ""; 
5497         const char* c 
= shortopts
; 
5502             /* note: shortopt array[] is initialiazed dynamically here to satisfy */ 
5503             /* a deficiency in the watcom compiler wrt static array initializers. */ 
5508             arg_cat(&dest
, shortopt
, &ndest
); 
5510                 arg_cat(&dest
, separator
, &ndest
); 
5514     /* put separator between long opts and short opts */ 
5515     if (shortopts 
&& longopts
) 
5516         arg_cat(&dest
, separator
, &ndest
); 
5519         const char* c 
= longopts
; 
5523             /* add "--" tag prefix */ 
5524             arg_cat(&dest
, "--", &ndest
); 
5526             /* add comma separated option tag */ 
5527             ncspn 
= strcspn(c
, ","); 
5528 #if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__)) 
5529             strncat_s(dest
, ndest
, c
, (ncspn 
< ndest
) ? ncspn 
: ndest
); 
5531             strncat(dest
, c
, (ncspn 
< ndest
) ? ncspn 
: ndest
); 
5535             /* add given separator in place of comma */ 
5537                 arg_cat(&dest
, separator
, &ndest
); 
5545             arg_cat(&dest
, "=", &ndest
); 
5547             arg_cat(&dest
, " ", &ndest
); 
5550             arg_cat(&dest
, "[", &ndest
); 
5551             arg_cat(&dest
, datatype
, &ndest
); 
5552             arg_cat(&dest
, "]", &ndest
); 
5554             arg_cat(&dest
, datatype
, &ndest
); 
5558 void arg_print_option_ds(arg_dstr_t ds
, const char* shortopts
, const char* longopts
, const char* datatype
, const char* suffix
) { 
5559     char syntax
[200] = ""; 
5560     suffix 
= suffix 
? suffix 
: ""; 
5562     /* there is no way of passing the proper optvalue for optional argument values here, so we must ignore it */ 
5563     arg_cat_optionv(syntax
, sizeof(syntax
) - 1, shortopts
, longopts
, datatype
, 0, "|"); 
5565     arg_dstr_cat(ds
, syntax
); 
5566     arg_dstr_cat(ds
, (char*)suffix
); 
5569 /* this function should be deprecated because it doesn't consider optional argument values (ARG_HASOPTVALUE) */ 
5570 void arg_print_option(FILE* fp
, const char* shortopts
, const char* longopts
, const char* datatype
, const char* suffix
) { 
5571     arg_dstr_t ds 
= arg_dstr_create(); 
5572     arg_print_option_ds(ds
, shortopts
, longopts
, datatype
, suffix
); 
5573     fputs(arg_dstr_cstr(ds
), fp
); 
5574     arg_dstr_destroy(ds
); 
5578  * Print a GNU style [OPTION] string in which all short options that 
5579  * do not take argument values are presented in abbreviated form, as 
5580  * in: -xvfsd, or -xvf[sd], or [-xvsfd] 
5582 static void arg_print_gnuswitch_ds(arg_dstr_t ds
, struct arg_hdr
** table
) { 
5584     char* format1 
= " -%c"; 
5585     char* format2 
= " [-%c"; 
5588     /* print all mandatory switches that are without argument values */ 
5589     for (tabindex 
= 0; table
[tabindex
] && !(table
[tabindex
]->flag 
& ARG_TERMINATOR
); tabindex
++) { 
5590         /* skip optional options */ 
5591         if (table
[tabindex
]->mincount 
< 1) 
5594         /* skip non-short options */ 
5595         if (table
[tabindex
]->shortopts 
== NULL
) 
5598         /* skip options that take argument values */ 
5599         if (table
[tabindex
]->flag 
& ARG_HASVALUE
) 
5602         /* print the short option (only the first short option char, ignore multiple choices)*/ 
5603         arg_dstr_catf(ds
, format1
, table
[tabindex
]->shortopts
[0]); 
5608     /* print all optional switches that are without argument values */ 
5609     for (tabindex 
= 0; table
[tabindex
] && !(table
[tabindex
]->flag 
& ARG_TERMINATOR
); tabindex
++) { 
5610         /* skip mandatory args */ 
5611         if (table
[tabindex
]->mincount 
> 0) 
5614         /* skip args without short options */ 
5615         if (table
[tabindex
]->shortopts 
== NULL
) 
5618         /* skip args with values */ 
5619         if (table
[tabindex
]->flag 
& ARG_HASVALUE
) 
5622         /* print first short option */ 
5623         arg_dstr_catf(ds
, format2
, table
[tabindex
]->shortopts
[0]); 
5628     arg_dstr_catf(ds
, "%s", suffix
); 
5631 void arg_print_syntax_ds(arg_dstr_t ds
, void** argtable
, const char* suffix
) { 
5632     struct arg_hdr
** table 
= (struct arg_hdr
**)argtable
; 
5635     /* print GNU style [OPTION] string */ 
5636     arg_print_gnuswitch_ds(ds
, table
); 
5638     /* print remaining options in abbreviated style */ 
5639     for (tabindex 
= 0; table
[tabindex
] && !(table
[tabindex
]->flag 
& ARG_TERMINATOR
); tabindex
++) { 
5640         char syntax
[200] = ""; 
5641         const char *shortopts
, *longopts
, *datatype
; 
5643         /* skip short options without arg values (they were printed by arg_print_gnu_switch) */ 
5644         if (table
[tabindex
]->shortopts 
&& !(table
[tabindex
]->flag 
& ARG_HASVALUE
)) 
5647         shortopts 
= table
[tabindex
]->shortopts
; 
5648         longopts 
= table
[tabindex
]->longopts
; 
5649         datatype 
= table
[tabindex
]->datatype
; 
5650         arg_cat_option(syntax
, sizeof(syntax
) - 1, shortopts
, longopts
, datatype
, table
[tabindex
]->flag 
& ARG_HASOPTVALUE
); 
5652         if (strlen(syntax
) > 0) { 
5653             /* print mandatory instances of this option */ 
5654             for (i 
= 0; i 
< table
[tabindex
]->mincount
; i
++) { 
5655                 arg_dstr_cat(ds
, " "); 
5656                 arg_dstr_cat(ds
, syntax
); 
5659             /* print optional instances enclosed in "[..]" */ 
5660             switch (table
[tabindex
]->maxcount 
- table
[tabindex
]->mincount
) { 
5664                     arg_dstr_cat(ds
, " ["); 
5665                     arg_dstr_cat(ds
, syntax
); 
5666                     arg_dstr_cat(ds
, "]"); 
5669                     arg_dstr_cat(ds
, " ["); 
5670                     arg_dstr_cat(ds
, syntax
); 
5671                     arg_dstr_cat(ds
, "]"); 
5672                     arg_dstr_cat(ds
, " ["); 
5673                     arg_dstr_cat(ds
, syntax
); 
5674                     arg_dstr_cat(ds
, "]"); 
5677                     arg_dstr_cat(ds
, " ["); 
5678                     arg_dstr_cat(ds
, syntax
); 
5679                     arg_dstr_cat(ds
, "]..."); 
5686         arg_dstr_cat(ds
, (char*)suffix
); 
5690 void arg_print_syntax(FILE* fp
, void** argtable
, const char* suffix
) { 
5691     arg_dstr_t ds 
= arg_dstr_create(); 
5692     arg_print_syntax_ds(ds
, argtable
, suffix
); 
5693     fputs(arg_dstr_cstr(ds
), fp
); 
5694     arg_dstr_destroy(ds
); 
5697 void arg_print_syntaxv_ds(arg_dstr_t ds
, void** argtable
, const char* suffix
) { 
5698     struct arg_hdr
** table 
= (struct arg_hdr
**)argtable
; 
5701     /* print remaining options in abbreviated style */ 
5702     for (tabindex 
= 0; table
[tabindex
] && !(table
[tabindex
]->flag 
& ARG_TERMINATOR
); tabindex
++) { 
5703         char syntax
[200] = ""; 
5704         const char *shortopts
, *longopts
, *datatype
; 
5706         shortopts 
= table
[tabindex
]->shortopts
; 
5707         longopts 
= table
[tabindex
]->longopts
; 
5708         datatype 
= table
[tabindex
]->datatype
; 
5709         arg_cat_optionv(syntax
, sizeof(syntax
) - 1, shortopts
, longopts
, datatype
, table
[tabindex
]->flag 
& ARG_HASOPTVALUE
, "|"); 
5711         /* print mandatory options */ 
5712         for (i 
= 0; i 
< table
[tabindex
]->mincount
; i
++) { 
5713             arg_dstr_cat(ds
, " "); 
5714             arg_dstr_cat(ds
, syntax
); 
5717         /* print optional args enclosed in "[..]" */ 
5718         switch (table
[tabindex
]->maxcount 
- table
[tabindex
]->mincount
) { 
5722                 arg_dstr_cat(ds
, " ["); 
5723                 arg_dstr_cat(ds
, syntax
); 
5724                 arg_dstr_cat(ds
, "]"); 
5727                 arg_dstr_cat(ds
, " ["); 
5728                 arg_dstr_cat(ds
, syntax
); 
5729                 arg_dstr_cat(ds
, "]"); 
5730                 arg_dstr_cat(ds
, " ["); 
5731                 arg_dstr_cat(ds
, syntax
); 
5732                 arg_dstr_cat(ds
, "]"); 
5735                 arg_dstr_cat(ds
, " ["); 
5736                 arg_dstr_cat(ds
, syntax
); 
5737                 arg_dstr_cat(ds
, "]..."); 
5743         arg_dstr_cat(ds
, (char*)suffix
); 
5747 void arg_print_syntaxv(FILE* fp
, void** argtable
, const char* suffix
) { 
5748     arg_dstr_t ds 
= arg_dstr_create(); 
5749     arg_print_syntaxv_ds(ds
, argtable
, suffix
); 
5750     fputs(arg_dstr_cstr(ds
), fp
); 
5751     arg_dstr_destroy(ds
); 
5754 void arg_print_glossary_ds(arg_dstr_t ds
, void** argtable
, const char* format
) { 
5755     struct arg_hdr
** table 
= (struct arg_hdr
**)argtable
; 
5758     format 
= format 
? format 
: "  %-20s %s\n"; 
5759     for (tabindex 
= 0; !(table
[tabindex
]->flag 
& ARG_TERMINATOR
); tabindex
++) { 
5760         if (table
[tabindex
]->glossary
) { 
5761             char syntax
[200] = ""; 
5762             const char* shortopts 
= table
[tabindex
]->shortopts
; 
5763             const char* longopts 
= table
[tabindex
]->longopts
; 
5764             const char* datatype 
= table
[tabindex
]->datatype
; 
5765             const char* glossary 
= table
[tabindex
]->glossary
; 
5766             arg_cat_optionv(syntax
, sizeof(syntax
) - 1, shortopts
, longopts
, datatype
, table
[tabindex
]->flag 
& ARG_HASOPTVALUE
, ", "); 
5767             arg_dstr_catf(ds
, format
, syntax
, glossary
); 
5772 void arg_print_glossary(FILE* fp
, void** argtable
, const char* format
) { 
5773     arg_dstr_t ds 
= arg_dstr_create(); 
5774     arg_print_glossary_ds(ds
, argtable
, format
); 
5775     fputs(arg_dstr_cstr(ds
), fp
); 
5776     arg_dstr_destroy(ds
); 
5780  * Print a piece of text formatted, which means in a column with a 
5781  * left and a right margin. The lines are wrapped at whitspaces next 
5782  * to right margin. The function does not indent the first line, but 
5783  * only the following ones. 
5786  * arg_print_formatted( fp, 0, 5, "Some text that doesn't fit." ) 
5787  * will result in the following output: 
5795  * Too long lines will be wrapped in the middle of a word. 
5797  * arg_print_formatted( fp, 2, 7, "Some text that doesn't fit." ) 
5798  * will result in the following output: 
5806  * As you see, the first line is not indented. This enables output of 
5807  * lines, which start in a line where output already happened. 
5809  * Author: Uli Fouquet 
5811 static void arg_print_formatted_ds(arg_dstr_t ds
, const unsigned lmargin
, const unsigned rmargin
, const char* text
) { 
5812     const unsigned int textlen 
= (unsigned int)strlen(text
); 
5813     unsigned int line_start 
= 0; 
5814     unsigned int line_end 
= textlen
; 
5815     const unsigned int colwidth 
= (rmargin 
- lmargin
) + 1; 
5817     assert(strlen(text
) < UINT_MAX
); 
5819     /* Someone doesn't like us... */ 
5820     if (line_end 
< line_start
) { 
5821         arg_dstr_catf(ds
, "%s\n", text
); 
5824     while (line_end 
> line_start
) { 
5825         /* Eat leading white spaces. This is essential because while 
5826            wrapping lines, there will often be a whitespace at beginning 
5828         while (isspace(*(text 
+ line_start
))) { 
5832         /* Find last whitespace, that fits into line */ 
5833         if (line_end 
- line_start 
> colwidth
) { 
5834             line_end 
= line_start 
+ colwidth
; 
5836             while ((line_end 
> line_start
) && !isspace(*(text 
+ line_end
))) { 
5840             /* Consume trailing spaces */ 
5841             while ((line_end 
> line_start
) && isspace(*(text 
+ line_end
))) { 
5845             /* Restore the last non-space character */ 
5849         /* Output line of text */ 
5850         while (line_start 
< line_end
) { 
5851             char c 
= *(text 
+ line_start
); 
5852             arg_dstr_catc(ds
, c
); 
5855         arg_dstr_cat(ds
, "\n"); 
5857         /* Initialize another line */ 
5858         if (line_end 
< textlen
) { 
5861             for (i 
= 0; i 
< lmargin
; i
++) { 
5862                 arg_dstr_cat(ds
, " "); 
5867     } /* lines of text */ 
5871  * Prints the glossary in strict GNU format. 
5872  * Differences to arg_print_glossary() are: 
5873  *   - wraps lines after 80 chars 
5874  *   - indents lines without shortops 
5875  *   - does not accept formatstrings 
5877  * Contributed by Uli Fouquet 
5879 void arg_print_glossary_gnu_ds(arg_dstr_t ds
, void** argtable
) { 
5880     struct arg_hdr
** table 
= (struct arg_hdr
**)argtable
; 
5883     for (tabindex 
= 0; !(table
[tabindex
]->flag 
& ARG_TERMINATOR
); tabindex
++) { 
5884         if (table
[tabindex
]->glossary
) { 
5885             char syntax
[200] = ""; 
5886             const char* shortopts 
= table
[tabindex
]->shortopts
; 
5887             const char* longopts 
= table
[tabindex
]->longopts
; 
5888             const char* datatype 
= table
[tabindex
]->datatype
; 
5889             const char* glossary 
= table
[tabindex
]->glossary
; 
5891             if (!shortopts 
&& longopts
) { 
5892                 /* Indent trailing line by 4 spaces... */ 
5893                 memset(syntax
, ' ', 4); 
5894                 *(syntax 
+ 4) = '\0'; 
5897             arg_cat_optionv(syntax
, sizeof(syntax
) - 1, shortopts
, longopts
, datatype
, table
[tabindex
]->flag 
& ARG_HASOPTVALUE
, ", "); 
5899             /* If syntax fits not into column, print glossary in new line... */ 
5900             if (strlen(syntax
) > 25) { 
5901                 arg_dstr_catf(ds
, "  %-25s %s\n", syntax
, ""); 
5905             arg_dstr_catf(ds
, "  %-25s ", syntax
); 
5906             arg_print_formatted_ds(ds
, 28, 79, glossary
); 
5908     } /* for each table entry */ 
5910     arg_dstr_cat(ds
, "\n"); 
5913 void arg_print_glossary_gnu(FILE* fp
, void** argtable
) { 
5914     arg_dstr_t ds 
= arg_dstr_create(); 
5915     arg_print_glossary_gnu_ds(ds
, argtable
); 
5916     fputs(arg_dstr_cstr(ds
), fp
); 
5917     arg_dstr_destroy(ds
); 
5921  * Checks the argtable[] array for NULL entries and returns 1 
5922  * if any are found, zero otherwise. 
5924 int arg_nullcheck(void** argtable
) { 
5925     struct arg_hdr
** table 
= (struct arg_hdr
**)argtable
; 
5927     /*printf("arg_nullcheck(%p)\n",argtable);*/ 
5934         /*printf("argtable[%d]=%p\n",tabindex,argtable[tabindex]);*/ 
5935         if (!table
[tabindex
]) 
5937     } while (!(table
[tabindex
++]->flag 
& ARG_TERMINATOR
)); 
5943  * arg_free() is deprecated in favour of arg_freetable() due to a flaw in its design. 
5944  * The flaw results in memory leak in the (very rare) case that an intermediate 
5945  * entry in the argtable array failed its memory allocation while others following 
5946  * that entry were still allocated ok. Those subsequent allocations will not be 
5947  * deallocated by arg_free(). 
5948  * Despite the unlikeliness of the problem occurring, and the even unlikelier event 
5949  * that it has any deliterious effect, it is fixed regardless by replacing arg_free() 
5950  * with the newer arg_freetable() function. 
5951  * We still keep arg_free() for backwards compatibility. 
5953 void arg_free(void** argtable
) { 
5954     struct arg_hdr
** table 
= (struct arg_hdr
**)argtable
; 
5957     /*printf("arg_free(%p)\n",argtable);*/ 
5960            if we encounter a NULL entry then somewhat incorrectly we presume 
5961            we have come to the end of the array. It isnt strictly true because 
5962            an intermediate entry could be NULL with other non-NULL entries to follow. 
5963            The subsequent argtable entries would then not be freed as they should. 
5965         if (table
[tabindex
] == NULL
) 
5968         flag 
= table
[tabindex
]->flag
; 
5969         xfree(table
[tabindex
]); 
5970         table
[tabindex
++] = NULL
; 
5972     } while (!(flag 
& ARG_TERMINATOR
)); 
5975 /* frees each non-NULL element of argtable[], where n is the size of the number of entries in the array */ 
5976 void arg_freetable(void** argtable
, size_t n
) { 
5977     struct arg_hdr
** table 
= (struct arg_hdr
**)argtable
; 
5978     size_t tabindex 
= 0; 
5979     /*printf("arg_freetable(%p)\n",argtable);*/ 
5980     for (tabindex 
= 0; tabindex 
< n
; tabindex
++) { 
5981         if (table
[tabindex
] == NULL
) 
5984         xfree(table
[tabindex
]); 
5985         table
[tabindex
] = NULL
; 
5990 BOOL WINAPI 
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
) { 
5992     UNREFERENCED_PARAMETER(hinstDLL
); 
5993     UNREFERENCED_PARAMETER(fdwReason
); 
5994     UNREFERENCED_PARAMETER(lpvReserved
);