4 #include <string.h> /* for strchr() and strncmp() */
6 #define ko_no_argument 0
7 #define ko_required_argument 1
8 #define ko_optional_argument 2
11 int ind
; /* equivalent to optind */
12 int opt
; /* equivalent to optopt */
13 char *arg
; /* equivalent to optarg */
14 int longidx
; /* index of a long option; or -1 if short */
15 /* private variables not intended for external uses */
25 static ketopt_t KETOPT_INIT
= { 1, 0, 0, -1, 1, 0, 0 };
27 static void ketopt_permute(char *argv
[], int j
, int n
) /* move argv[j] over n elements to the left */
31 for (k
= 0; k
< n
; ++k
)
32 argv
[j
- k
] = argv
[j
- k
- 1];
37 * Parse command-line options and arguments
39 * This fuction has a similar interface to GNU's getopt_long(). Each call
40 * parses one option and returns the option name. s->arg points to the option
41 * argument if present. The function returns -1 when all command-line arguments
42 * are parsed. In this case, s->ind is the index of the first non-option
45 * @param s status; shall be initialized to KETOPT_INIT on the first call
46 * @param argc length of argv[]
47 * @param argv list of command-line arguments; argv[0] is ignored
48 * @param permute non-zero to move options ahead of non-option arguments
49 * @param ostr option string
50 * @param longopts long options
52 * @return ASCII for a short option; ko_longopt_t::val for a long option; -1 if
53 * argv[] is fully processed; '?' for an unknown option or an ambiguous
54 * long option; ':' if an option argument is missing
56 static int ketopt(ketopt_t
*s
, int argc
, char *argv
[], int permute
, const char *ostr
, const ko_longopt_t
*longopts
)
60 while (s
->i
< argc
&& (argv
[s
->i
][0] != '-' || argv
[s
->i
][1] == '\0'))
63 s
->arg
= 0, s
->longidx
= -1, i0
= s
->i
;
64 if (s
->i
>= argc
|| argv
[s
->i
][0] != '-' || argv
[s
->i
][1] == '\0') {
65 s
->ind
= s
->i
- s
->n_args
;
68 if (argv
[s
->i
][0] == '-' && argv
[s
->i
][1] == '-') { /* "--" or a long option */
69 if (argv
[s
->i
][2] == '\0') { /* a bare "--" */
70 ketopt_permute(argv
, s
->i
, s
->n_args
);
71 ++s
->i
, s
->ind
= s
->i
- s
->n_args
;
74 s
->opt
= 0, opt
= '?', s
->pos
= -1;
75 if (longopts
) { /* parse long options */
76 int k
, n_exact
= 0, n_partial
= 0;
77 const ko_longopt_t
*o
= 0, *o_exact
= 0, *o_partial
= 0;
78 for (j
= 2; argv
[s
->i
][j
] != '\0' && argv
[s
->i
][j
] != '='; ++j
) {} /* find the end of the option name */
79 for (k
= 0; longopts
[k
].name
!= 0; ++k
)
80 if (strncmp(&argv
[s
->i
][2], longopts
[k
].name
, j
- 2) == 0) {
81 if (longopts
[k
].name
[j
- 2] == 0) ++n_exact
, o_exact
= &longopts
[k
];
82 else ++n_partial
, o_partial
= &longopts
[k
];
84 if (n_exact
> 1 || (n_exact
== 0 && n_partial
> 1)) return '?';
85 o
= n_exact
== 1? o_exact
: n_partial
== 1? o_partial
: 0;
87 s
->opt
= opt
= o
->val
, s
->longidx
= o
- longopts
;
88 if (argv
[s
->i
][j
] == '=') s
->arg
= &argv
[s
->i
][j
+ 1];
89 if (o
->has_arg
== 1 && argv
[s
->i
][j
] == '\0') {
90 if (s
->i
< argc
- 1) s
->arg
= argv
[++s
->i
];
91 else opt
= ':'; /* missing option argument */
95 } else { /* a short option */
97 if (s
->pos
== 0) s
->pos
= 1;
98 opt
= s
->opt
= argv
[s
->i
][s
->pos
++];
99 p
= strchr((char*)ostr
, opt
);
101 opt
= '?'; /* unknown option */
102 } else if (p
[1] == ':') {
103 if (argv
[s
->i
][s
->pos
] == 0) {
104 if (s
->i
< argc
- 1) s
->arg
= argv
[++s
->i
];
105 else opt
= ':'; /* missing option argument */
106 } else s
->arg
= &argv
[s
->i
][s
->pos
];
110 if (s
->pos
< 0 || argv
[s
->i
][s
->pos
] == 0) {
112 if (s
->n_args
> 0) /* permute */
113 for (j
= i0
; j
< s
->i
; ++j
)
114 ketopt_permute(argv
, j
, s
->n_args
);
116 s
->ind
= s
->i
- s
->n_args
;