2 Copyright (C) 2001-2007, Parrot Foundation.
7 longopt.c - Command-line option parsing
11 This is used by C<parrot>.
21 #include "parrot/parrot.h"
23 /* HEADERIZER HFILE: include/parrot/longopt.h */
25 /* HEADERIZER BEGIN: static */
26 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
28 static int longopt_get_longopt(PARROT_INTERP
,
30 ARGIN(const char* argv
[]),
31 ARGIN(const struct longopt_opt_decl options
[]),
32 ARGMOD(struct longopt_opt_info
* info_buf
))
33 __attribute__nonnull__(1)
34 __attribute__nonnull__(3)
35 __attribute__nonnull__(4)
36 __attribute__nonnull__(5)
37 FUNC_MODIFIES(* info_buf
);
39 static int longopt_get_shortopt(PARROT_INTERP
,
41 ARGIN(const char* argv
[]),
42 ARGIN(const struct longopt_opt_decl options
[]),
43 ARGMOD(struct longopt_opt_info
* info_buf
))
44 __attribute__nonnull__(1)
45 __attribute__nonnull__(3)
46 __attribute__nonnull__(4)
47 __attribute__nonnull__(5)
48 FUNC_MODIFIES(* info_buf
);
50 #define ASSERT_ARGS_longopt_get_longopt __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
51 PARROT_ASSERT_ARG(interp) \
52 , PARROT_ASSERT_ARG(argv) \
53 , PARROT_ASSERT_ARG(options) \
54 , PARROT_ASSERT_ARG(info_buf))
55 #define ASSERT_ARGS_longopt_get_shortopt __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
56 PARROT_ASSERT_ARG(interp) \
57 , PARROT_ASSERT_ARG(argv) \
58 , PARROT_ASSERT_ARG(options) \
59 , PARROT_ASSERT_ARG(info_buf))
60 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
61 /* HEADERIZER END: static */
63 static char longopt_error_buffer
[512];
67 =item C<int longopt_get(PARROT_INTERP, int argc, const char* argv[], const
68 struct longopt_opt_decl options[], struct longopt_opt_info* info_buf)>
70 Gets long or short options, specified in C<options[]> (see
71 F<docs/dev/longopt.dev>).
73 Call it iteratively with the same C<info_buf> until it returns 0 or -1.
75 0 means you have reached the end of options.
77 -1 means a parse error, with error put in C<< info_buf->opt_error >>.
79 Any other value is a valid option identifier.
87 longopt_get(PARROT_INTERP
, int argc
, ARGIN(const char* argv
[]),
88 ARGIN(const struct longopt_opt_decl options
[]),
89 ARGMOD(struct longopt_opt_info
* info_buf
))
91 ASSERT_ARGS(longopt_get
)
92 const int dex
= info_buf
->opt_index
;
95 info_buf
->opt_arg
= info_buf
->opt_error
= NULL
;
97 if (dex
>= argc
|| argv
[dex
] == NULL
)
100 if (argv
[dex
][0] != '-' || argv
[dex
][1] == '\0')
103 if (info_buf
->_shortopt_pos
)
104 return longopt_get_shortopt(interp
, argc
, argv
, options
, info_buf
);
106 if (argv
[dex
][1] == '-') { /* Long option or -- */
107 if (argv
[dex
][2] == '\0') {
108 ++info_buf
->opt_index
;
111 else { /* Long option */
112 return longopt_get_longopt(interp
, argc
, argv
, options
, info_buf
);
115 else { /* Short option */
116 return longopt_get_shortopt(interp
, argc
, argv
, options
, info_buf
);
122 =item C<static int longopt_get_longopt(PARROT_INTERP, int argc, const char*
123 argv[], const struct longopt_opt_decl options[], struct longopt_opt_info*
126 Find the option identifier of a long option.
128 Fill C<info_buf> appropriately, and return the option identifier.
130 C<argv[info_buf->opt_index]> is guaranteed to have at least three
131 characters and start with C<-->.
138 longopt_get_longopt(PARROT_INTERP
, int argc
, ARGIN(const char* argv
[]),
139 ARGIN(const struct longopt_opt_decl options
[]),
140 ARGMOD(struct longopt_opt_info
* info_buf
))
142 ASSERT_ARGS(longopt_get_longopt
)
143 const int dex
= info_buf
->opt_index
;
145 const struct longopt_opt_decl
* dptr
;
147 while (argv
[dex
][optlen
] != '\0' && argv
[dex
][optlen
] != '=') {
151 for (dptr
= options
; dptr
->opt_id
; dptr
++) {
153 /* For each listed long option... */
154 for (sptr
= 0; dptr
->opt_long
[sptr
]; sptr
++) {
155 if (strncmp(dptr
->opt_long
[sptr
], argv
[dex
], optlen
) == 0
156 && dptr
->opt_long
[sptr
][optlen
] == '\0') {
158 info_buf
->opt_id
= dptr
->opt_id
;
159 ++info_buf
->opt_index
;
161 /* XXX: (LP) if a longopt is given an argument when it's
162 * not expecting one, it is just ignored. Bad. */
164 if (argv
[dex
][optlen
] == '=') {
165 if (dptr
->opt_flags
&
166 (OPTION_required_FLAG
| OPTION_optional_FLAG
)) {
167 info_buf
->opt_arg
= &argv
[dex
][optlen
+1];
170 Parrot_snprintf(interp
, longopt_error_buffer
,
171 sizeof (longopt_error_buffer
),
172 "Option %s does not expect an argument",
173 dptr
->opt_long
[sptr
]);
174 info_buf
->opt_error
= longopt_error_buffer
;
179 if (dptr
->opt_flags
& OPTION_required_FLAG
) {
181 info_buf
->opt_arg
= argv
[dex
+1];
182 ++info_buf
->opt_index
;
185 Parrot_snprintf(interp
, longopt_error_buffer
,
186 sizeof (longopt_error_buffer
),
187 "Option %s needs an argument",
188 dptr
->opt_long
[sptr
]);
189 info_buf
->opt_error
= longopt_error_buffer
;
193 else if (dptr
->opt_flags
& OPTION_optional_FLAG
) {
194 if (dex
+2 < argc
&& argv
[dex
+1][0] &&
195 argv
[dex
+1][0] != '-') {
196 info_buf
->opt_arg
= argv
[dex
+1];
197 ++info_buf
->opt_index
;
207 /* Couldn't find it. */
208 info_buf
->opt_id
= -1;
209 Parrot_snprintf(interp
, longopt_error_buffer
,
210 sizeof (longopt_error_buffer
),
211 "Option %s not known", argv
[dex
]);
212 info_buf
->opt_error
= longopt_error_buffer
;
218 =item C<static int longopt_get_shortopt(PARROT_INTERP, int argc, const char*
219 argv[], const struct longopt_opt_decl options[], struct longopt_opt_info*
222 Find the option identifier of the next short option.
224 This next short option may be in the middle of a bundle (C<-abcd>), and
225 C<< info_buf->_shortopt_pos >> maintains a pointer into that bundle.
227 C<< argv[info_buf->opt_index] >> is guaranteed to be at least two
228 characters long and start with a dash.
235 longopt_get_shortopt(PARROT_INTERP
, int argc
, ARGIN(const char* argv
[]),
236 ARGIN(const struct longopt_opt_decl options
[]),
237 ARGMOD(struct longopt_opt_info
* info_buf
))
239 ASSERT_ARGS(longopt_get_shortopt
)
240 const int dex
= info_buf
->opt_index
;
241 const struct longopt_opt_decl
* dptr
;
245 if (!info_buf
->_shortopt_pos
)
246 info_buf
->_shortopt_pos
= &argv
[dex
][1];
247 pos
= info_buf
->_shortopt_pos
;
249 for (dptr
= options
; dptr
->opt_id
; dptr
++) {
250 if (dptr
->opt_short
== *pos
) {
252 info_buf
->opt_id
= dptr
->opt_id
;
254 if (dptr
->opt_flags
& OPTION_required_FLAG
) {
256 info_buf
->opt_arg
= pos
+ 1;
260 info_buf
->opt_arg
= argv
[dex
+1];
261 ++info_buf
->opt_index
;
264 Parrot_snprintf(interp
, longopt_error_buffer
,
265 sizeof (longopt_error_buffer
),
266 "Option -%c expects an argument", *pos
);
267 info_buf
->opt_error
= longopt_error_buffer
;
271 info_buf
->_shortopt_pos
= NULL
;
272 ++info_buf
->opt_index
;
274 else if (dptr
->opt_flags
& OPTION_optional_FLAG
) {
276 info_buf
->opt_arg
= pos
+ 1;
278 else if (dex
+2 < argc
&& argv
[dex
+1][0] &&
279 argv
[dex
+1][0] != '-') {
280 info_buf
->opt_arg
= argv
[dex
+1];
281 ++info_buf
->opt_index
;
283 info_buf
->_shortopt_pos
= NULL
;
284 ++info_buf
->opt_index
;
286 else { /* No argument expected */
288 info_buf
->_shortopt_pos
= NULL
;
289 ++info_buf
->opt_index
;
292 ++info_buf
->_shortopt_pos
;
300 /* Couldn't find it in the table */
301 info_buf
->opt_id
= -1;
302 Parrot_snprintf(interp
, longopt_error_buffer
,
303 sizeof (longopt_error_buffer
),
304 "Option -%c not known", *pos
);
305 info_buf
->opt_error
= longopt_error_buffer
;
315 F<include/parrot/longopt.h> and F<docs/dev/longopt.dev>.
324 * c-file-style: "parrot"
326 * vim: expandtab shiftwidth=4: