1+ // From https://github.com/attractivechaos/klib
2+ // Under MIT/X11 license.
3+
4+ #ifndef KETOPT_H
5+ #define KETOPT_H
6+
7+ #include <string.h> /* for strchr() and strncmp() */
8+
9+ #define ko_no_argument 0
10+ #define ko_required_argument 1
11+ #define ko_optional_argument 2
12+
13+ typedef struct {
14+ int ind ; /* equivalent to optind */
15+ int opt ; /* equivalent to optopt */
16+ char * arg ; /* equivalent to optarg */
17+ int longidx ; /* index of a long option; or -1 if short */
18+ /* private variables not intended for external uses */
19+ int i , pos , n_args ;
20+ } ketopt_t ;
21+
22+ typedef struct {
23+ char * name ;
24+ int has_arg ;
25+ int val ;
26+ } ko_longopt_t ;
27+
28+ ketopt_t KETOPT_INIT = { 1 , 0 , 0 , -1 , 1 , 0 , 0 };
29+
30+ static void ketopt_permute (char * argv [], int j , int n ) /* move argv[j] over n elements to the left */
31+ {
32+ int k ;
33+ char * p = argv [j ];
34+ for (k = 0 ; k < n ; ++ k )
35+ argv [j - k ] = argv [j - k - 1 ];
36+ argv [j - k ] = p ;
37+ }
38+
39+ /**
40+ * Parse command-line options and arguments
41+ *
42+ * This fuction has a similar interface to GNU's getopt_long(). Each call
43+ * parses one option and returns the option name. s->arg points to the option
44+ * argument if present. The function returns -1 when all command-line arguments
45+ * are parsed. In this case, s->ind is the index of the first non-option
46+ * argument.
47+ *
48+ * @param s status; shall be initialized to KETOPT_INIT on the first call
49+ * @param argc length of argv[]
50+ * @param argv list of command-line arguments; argv[0] is ignored
51+ * @param permute non-zero to move options ahead of non-option arguments
52+ * @param ostr option string
53+ * @param longopts long options
54+ *
55+ * @return ASCII for a short option; ko_longopt_t::val for a long option; -1 if
56+ * argv[] is fully processed; '?' for an unknown option or an ambiguous
57+ * long option; ':' if an option argument is missing
58+ */
59+ int ketopt (ketopt_t * s , int argc , char * argv [], int permute , const char * ostr , const ko_longopt_t * longopts )
60+ {
61+ int opt = -1 , i0 , j ;
62+ if (permute ) {
63+ while (s -> i < argc && (argv [s -> i ][0 ] != '-' || argv [s -> i ][1 ] == '\0' ))
64+ ++ s -> i , ++ s -> n_args ;
65+ }
66+ s -> arg = 0 , s -> longidx = -1 , i0 = s -> i ;
67+ if (s -> i >= argc || argv [s -> i ][0 ] != '-' || argv [s -> i ][1 ] == '\0' ) {
68+ s -> ind = s -> i - s -> n_args ;
69+ return -1 ;
70+ }
71+ if (argv [s -> i ][0 ] == '-' && argv [s -> i ][1 ] == '-' ) { /* "--" or a long option */
72+ if (argv [s -> i ][2 ] == '\0' ) { /* a bare "--" */
73+ ketopt_permute (argv , s -> i , s -> n_args );
74+ ++ s -> i , s -> ind = s -> i - s -> n_args ;
75+ return -1 ;
76+ }
77+ s -> opt = 0 , opt = '?' , s -> pos = -1 ;
78+ if (longopts ) { /* parse long options */
79+ int k , n_exact = 0 , n_partial = 0 ;
80+ const ko_longopt_t * o = 0 , * o_exact = 0 , * o_partial = 0 ;
81+ for (j = 2 ; argv [s -> i ][j ] != '\0' && argv [s -> i ][j ] != '=' ; ++ j ) {} /* find the end of the option name */
82+ for (k = 0 ; longopts [k ].name != 0 ; ++ k )
83+ if (strncmp (& argv [s -> i ][2 ], longopts [k ].name , j - 2 ) == 0 ) {
84+ if (longopts [k ].name [j - 2 ] == 0 ) ++ n_exact , o_exact = & longopts [k ];
85+ else ++ n_partial , o_partial = & longopts [k ];
86+ }
87+ if (n_exact > 1 || (n_exact == 0 && n_partial > 1 )) return '?' ;
88+ o = n_exact == 1 ? o_exact : n_partial == 1 ? o_partial : 0 ;
89+ if (o ) {
90+ s -> opt = opt = o -> val , s -> longidx = o - longopts ;
91+ if (argv [s -> i ][j ] == '=' ) s -> arg = & argv [s -> i ][j + 1 ];
92+ if (o -> has_arg == 1 && argv [s -> i ][j ] == '\0' ) {
93+ if (s -> i < argc - 1 ) s -> arg = argv [++ s -> i ];
94+ else opt = ':' ; /* missing option argument */
95+ }
96+ }
97+ }
98+ } else { /* a short option */
99+ const char * p ;
100+ if (s -> pos == 0 ) s -> pos = 1 ;
101+ opt = s -> opt = argv [s -> i ][s -> pos ++ ];
102+ p = strchr ((char * )ostr , opt );
103+ if (p == 0 ) {
104+ opt = '?' ; /* unknown option */
105+ } else if (p [1 ] == ':' ) {
106+ if (argv [s -> i ][s -> pos ] == 0 ) {
107+ if (s -> i < argc - 1 ) s -> arg = argv [++ s -> i ];
108+ else opt = ':' ; /* missing option argument */
109+ } else s -> arg = & argv [s -> i ][s -> pos ];
110+ s -> pos = -1 ;
111+ }
112+ }
113+ if (s -> pos < 0 || argv [s -> i ][s -> pos ] == 0 ) {
114+ ++ s -> i , s -> pos = 0 ;
115+ if (s -> n_args > 0 ) /* permute */
116+ for (j = i0 ; j < s -> i ; ++ j )
117+ ketopt_permute (argv , j , s -> n_args );
118+ }
119+ s -> ind = s -> i - s -> n_args ;
120+ return opt ;
121+ }
122+
123+ #endif
0 commit comments