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
);