8 typedef unsigned int uint
;
11 static int countopts(const struct opttype
*opts
) {
15 /* longname and short name are both 0, OR */
16 !(((opts
[i
].longname
== NULL
) && (opts
[i
].shortname
== '\0')) ||
17 /* output type was unspecified OR */
18 ((opts
[i
].type
== 0) || (opts
[i
].type
> OPTTYPE_STRING
)) ||
19 /* nowhere to output data */
20 (opts
[i
].outdata
== NULL
));
27 static int get_option_index_short(char opt
, const struct opttype
*potentialopts
, uint len
) {
30 for (i
= 0; i
< len
; i
++) {
31 if (!potentialopts
[i
].shortname
) {
33 } else if (potentialopts
[i
].shortname
== opt
) {
40 static int get_option_index_long(const char *opt
, const struct opttype
*potentialopts
, uint len
) {
43 for (i
= 0; i
< len
; i
++) {
44 if (!potentialopts
[i
].longname
) {
46 } else if (!strcmp(potentialopts
[i
].longname
, opt
)) {
54 void fetchopts(int *argc
, char ***argv
, struct opttype
*opts
) {
55 uint numopts
= countopts(opts
);
60 struct opttype
*wasinarg
= NULL
;
63 /* start at 1 because index 0 is the executable name */
64 for (argindex
= 1; argindex
< *argc
; argindex
++) {
65 if ((curropt
= (*argv
)[argindex
]) == NULL
) continue;
67 /* Last argument was an option, now we're setting the actual value of that option */
68 if (wasinarg
!= NULL
) {
69 char *format_specifier
;
71 switch (wasinarg
->type
) {
72 /* We set the format specifier here then make
73 * one sscanf call with it. We don't even need
74 * to cast it because it's already a pointer
75 * unless the user fucked something up which is
78 case OPTTYPE_CHAR
: format_specifier
= "%c"; break;
79 case OPTTYPE_SHORT
: format_specifier
= "%hi"; break;
80 case OPTTYPE_USHORT
: format_specifier
= "%hu"; break;
81 case OPTTYPE_INT
: format_specifier
= "%d"; break;
82 case OPTTYPE_UINT
: format_specifier
= "%u"; break;
83 case OPTTYPE_LONG
: format_specifier
= "%ld"; break;
84 case OPTTYPE_ULONG
: format_specifier
= "%lu"; break;
86 case OPTTYPE_LONGLONG
: format_specifier
= "%l64d"; break;
87 case OPTTYPE_ULONGLONG
: format_specifier
= "%l64u"; break;
89 case OPTTYPE_LONGLONG
: format_specifier
= "%lld"; break;
90 case OPTTYPE_ULONGLONG
: format_specifier
= "%llu"; break;
92 case OPTTYPE_FLOAT
: format_specifier
= "%f"; break;
93 case OPTTYPE_DOUBLE
: format_specifier
= "%lf"; break;
94 case OPTTYPE_LONGDOUBLE
: format_specifier
= "%Lf"; break;
97 *(char**)(wasinarg
->outdata
) = curropt
;
99 format_specifier
= NULL
;
101 /* OPTTYPE_BOOL already handled */
103 sscanf(curropt
, format_specifier
, wasinarg
->outdata
);
105 format_specifier
= NULL
;
107 /* Has the user manually demanded that the option-parsing end now? */
108 if (!strcmp(curropt
, "--")) {
114 /* in an option, getting warmer */
115 if (curropt
[0] == '-') {
116 int option_index
= -1;
117 unsigned char oneoffset
;
119 /* was it a --foo or just a -foo? */
120 if (curropt
[1] == '-') {
126 /* is it a short opt (e.g. -f) or a long one (e.g. -foo)? */
127 if (strlen(curropt
+oneoffset
) == 1) {
128 option_index
= get_option_index_short(curropt
[oneoffset
], opts
, numopts
);
131 /* long opt OR nothing matched for short opt ('f' is a valid longname) */
132 if (strlen(curropt
+oneoffset
) > 1 || option_index
== -1) {
133 option_index
= get_option_index_long(curropt
+oneoffset
, opts
, numopts
);
137 if (option_index
== -1) {
138 (*argv
)[newargc
++] = curropt
;
141 /* it's a boolean option, so the next loop doesn't want to know about it */
142 if ((opts
[option_index
]).type
== OPTTYPE_BOOL
) {
143 *(bool*)opts
[option_index
].outdata
= 1;
144 /* let the next loop iteration get the value */
146 wasinarg
= &opts
[option_index
];
150 (*argv
)[newargc
++] = curropt
;
159 for (i
= argindex
; i
< *argc
; i
++) {
160 /* -1, because argv starts at 1 (with 0 as program name), but newargv starts at 0 */
161 (*argv
)[newargc
++] = (*argv
)[i
];