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"
22 #include "parrot/longopt.h"
24 /* HEADERIZER HFILE: include/parrot/longopt.h */
26 /* HEADERIZER BEGIN: static */
27 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
29 static int longopt_get_longopt(PARROT_INTERP
,
31 ARGIN(const char* argv
[]),
32 ARGIN(const struct longopt_opt_decl options
[]),
33 ARGMOD(struct longopt_opt_info
* info_buf
))
34 __attribute__nonnull__(1)
35 __attribute__nonnull__(3)
36 __attribute__nonnull__(4)
37 __attribute__nonnull__(5)
38 FUNC_MODIFIES(* info_buf
);
40 static int longopt_get_shortopt(PARROT_INTERP
,
42 ARGIN(const char* argv
[]),
43 ARGIN(const struct longopt_opt_decl options
[]),
44 ARGMOD(struct longopt_opt_info
* info_buf
))
45 __attribute__nonnull__(1)
46 __attribute__nonnull__(3)
47 __attribute__nonnull__(4)
48 __attribute__nonnull__(5)
49 FUNC_MODIFIES(* info_buf
);
51 #define ASSERT_ARGS_longopt_get_longopt __attribute__unused__ int _ASSERT_ARGS_CHECK = \
52 PARROT_ASSERT_ARG(interp) \
53 || PARROT_ASSERT_ARG(argv) \
54 || PARROT_ASSERT_ARG(options) \
55 || PARROT_ASSERT_ARG(info_buf)
56 #define ASSERT_ARGS_longopt_get_shortopt __attribute__unused__ int _ASSERT_ARGS_CHECK = \
57 PARROT_ASSERT_ARG(interp) \
58 || PARROT_ASSERT_ARG(argv) \
59 || PARROT_ASSERT_ARG(options) \
60 || PARROT_ASSERT_ARG(info_buf)
61 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
62 /* HEADERIZER END: static */
64 static char longopt_error_buffer
[512];
68 =item C<int longopt_get(PARROT_INTERP, int argc, const char* argv[], const
69 struct longopt_opt_decl options[], struct longopt_opt_info* info_buf)>
71 Gets long or short options, specified in C<options[]> (see
72 F<docs/dev/longopt.dev>).
74 Call it iteratively with the same C<info_buf> until it returns 0 or -1.
76 0 means you have reached the end of options.
78 -1 means a parse error, with error put in C<< info_buf->opt_error >>.
80 Any other value is a valid option identifier.
88 longopt_get(PARROT_INTERP
, int argc
, ARGIN(const char* argv
[]),
89 ARGIN(const struct longopt_opt_decl options
[]),
90 ARGMOD(struct longopt_opt_info
* info_buf
))
92 ASSERT_ARGS(longopt_get
)
93 const int dex
= info_buf
->opt_index
;
96 info_buf
->opt_arg
= info_buf
->opt_error
= NULL
;
98 if (dex
>= argc
|| argv
[dex
] == NULL
)
101 if (argv
[dex
][0] != '-' || argv
[dex
][1] == '\0')
104 if (info_buf
->_shortopt_pos
)
105 return longopt_get_shortopt(interp
, argc
, argv
, options
, info_buf
);
107 if (argv
[dex
][1] == '-') { /* Long option or -- */
108 if (argv
[dex
][2] == '\0') {
109 ++info_buf
->opt_index
;
112 else { /* Long option */
113 return longopt_get_longopt(interp
, argc
, argv
, options
, info_buf
);
116 else { /* Short option */
117 return longopt_get_shortopt(interp
, argc
, argv
, options
, info_buf
);
123 =item C<static int longopt_get_longopt(PARROT_INTERP, int argc, const char*
124 argv[], const struct longopt_opt_decl options[], struct longopt_opt_info*
127 Find the option identifier of a long option.
129 Fill C<info_buf> appropriately, and return the option identifier.
131 C<argv[info_buf->opt_index]> is guaranteed to have at least three
132 characters and start with C<-->.
139 longopt_get_longopt(PARROT_INTERP
, int argc
, ARGIN(const char* argv
[]),
140 ARGIN(const struct longopt_opt_decl options
[]),
141 ARGMOD(struct longopt_opt_info
* info_buf
))
143 ASSERT_ARGS(longopt_get_longopt
)
144 const int dex
= info_buf
->opt_index
;
146 const struct longopt_opt_decl
* dptr
;
148 while (argv
[dex
][optlen
] != '\0' && argv
[dex
][optlen
] != '=') {
152 for (dptr
= options
; dptr
->opt_id
; dptr
++) {
154 /* For each listed long option... */
155 for (sptr
= 0; dptr
->opt_long
[sptr
]; sptr
++) {
156 if (strncmp(dptr
->opt_long
[sptr
], argv
[dex
], optlen
) == 0
157 && dptr
->opt_long
[sptr
][optlen
] == '\0') {
159 info_buf
->opt_id
= dptr
->opt_id
;
160 ++info_buf
->opt_index
;
162 /* XXX: (LP) if a longopt is given an argument when it's
163 * not expecting one, it is just ignored. Bad. */
165 if (argv
[dex
][optlen
] == '=') {
166 if (dptr
->opt_flags
&
167 (OPTION_required_FLAG
| OPTION_optional_FLAG
)) {
168 info_buf
->opt_arg
= &argv
[dex
][optlen
+1];
171 Parrot_snprintf(interp
, longopt_error_buffer
,
172 sizeof (longopt_error_buffer
),
173 "Option %s does not expect an argument",
174 dptr
->opt_long
[sptr
]);
175 info_buf
->opt_error
= longopt_error_buffer
;
180 if (dptr
->opt_flags
& OPTION_required_FLAG
) {
182 info_buf
->opt_arg
= argv
[dex
+1];
183 ++info_buf
->opt_index
;
186 Parrot_snprintf(interp
, longopt_error_buffer
,
187 sizeof (longopt_error_buffer
),
188 "Option %s needs an argument",
189 dptr
->opt_long
[sptr
]);
190 info_buf
->opt_error
= longopt_error_buffer
;
194 else if (dptr
->opt_flags
& OPTION_optional_FLAG
) {
195 if (dex
+2 < argc
&& argv
[dex
+1][0] &&
196 argv
[dex
+1][0] != '-') {
197 info_buf
->opt_arg
= argv
[dex
+1];
198 ++info_buf
->opt_index
;
208 /* Couldn't find it. */
209 info_buf
->opt_id
= -1;
210 Parrot_snprintf(interp
, longopt_error_buffer
,
211 sizeof (longopt_error_buffer
),
212 "Option %s not known", argv
[dex
]);
213 info_buf
->opt_error
= longopt_error_buffer
;
219 =item C<static int longopt_get_shortopt(PARROT_INTERP, int argc, const char*
220 argv[], const struct longopt_opt_decl options[], struct longopt_opt_info*
223 Find the option identifier of the next short option.
225 This next short option may be in the middle of a bundle (C<-abcd>), and
226 C<< info_buf->_shortopt_pos >> maintains a pointer into that bundle.
228 C<< argv[info_buf->opt_index] >> is guaranteed to be at least two
229 characters long and start with a dash.
236 longopt_get_shortopt(PARROT_INTERP
, int argc
, ARGIN(const char* argv
[]),
237 ARGIN(const struct longopt_opt_decl options
[]),
238 ARGMOD(struct longopt_opt_info
* info_buf
))
240 ASSERT_ARGS(longopt_get_shortopt
)
241 const int dex
= info_buf
->opt_index
;
242 const struct longopt_opt_decl
* dptr
;
246 if (!info_buf
->_shortopt_pos
)
247 info_buf
->_shortopt_pos
= &argv
[dex
][1];
248 pos
= info_buf
->_shortopt_pos
;
250 for (dptr
= options
; dptr
->opt_id
; dptr
++) {
251 if (dptr
->opt_short
== *pos
) {
253 info_buf
->opt_id
= dptr
->opt_id
;
255 if (dptr
->opt_flags
& OPTION_required_FLAG
) {
257 info_buf
->opt_arg
= pos
+ 1;
261 info_buf
->opt_arg
= argv
[dex
+1];
262 ++info_buf
->opt_index
;
265 Parrot_snprintf(interp
, longopt_error_buffer
,
266 sizeof (longopt_error_buffer
),
267 "Option -%c expects an argument", *pos
);
268 info_buf
->opt_error
= longopt_error_buffer
;
272 info_buf
->_shortopt_pos
= NULL
;
273 ++info_buf
->opt_index
;
275 else if (dptr
->opt_flags
& OPTION_optional_FLAG
) {
277 info_buf
->opt_arg
= pos
+ 1;
279 else if (dex
+2 < argc
&& argv
[dex
+1][0] &&
280 argv
[dex
+1][0] != '-') {
281 info_buf
->opt_arg
= argv
[dex
+1];
282 ++info_buf
->opt_index
;
284 info_buf
->_shortopt_pos
= NULL
;
285 ++info_buf
->opt_index
;
287 else { /* No argument expected */
289 info_buf
->_shortopt_pos
= NULL
;
290 ++info_buf
->opt_index
;
293 ++info_buf
->_shortopt_pos
;
301 /* Couldn't find it in the table */
302 info_buf
->opt_id
= -1;
303 Parrot_snprintf(interp
, longopt_error_buffer
,
304 sizeof (longopt_error_buffer
),
305 "Option -%c not known", *pos
);
306 info_buf
->opt_error
= longopt_error_buffer
;
316 F<include/parrot/longopt.h> and F<docs/dev/longopt.dev>.
325 * c-file-style: "parrot"
327 * vim: expandtab shiftwidth=4: