2 Copyright (C) 2001-2010, 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 PARROT_WARN_UNUSED_RESULT
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 PARROT_WARN_UNUSED_RESULT
41 static int longopt_get_shortopt(PARROT_INTERP
,
43 ARGIN(const char* argv
[]),
44 ARGIN(const struct longopt_opt_decl options
[]),
45 ARGMOD(struct longopt_opt_info
* info_buf
))
46 __attribute__nonnull__(1)
47 __attribute__nonnull__(3)
48 __attribute__nonnull__(4)
49 __attribute__nonnull__(5)
50 FUNC_MODIFIES(* info_buf
);
52 #define ASSERT_ARGS_longopt_get_longopt __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
53 PARROT_ASSERT_ARG(interp) \
54 , PARROT_ASSERT_ARG(argv) \
55 , PARROT_ASSERT_ARG(options) \
56 , PARROT_ASSERT_ARG(info_buf))
57 #define ASSERT_ARGS_longopt_get_shortopt __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
58 PARROT_ASSERT_ARG(interp) \
59 , PARROT_ASSERT_ARG(argv) \
60 , PARROT_ASSERT_ARG(options) \
61 , PARROT_ASSERT_ARG(info_buf))
62 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
63 /* HEADERIZER END: static */
65 static char longopt_error_buffer
[512];
69 =item C<const struct longopt_opt_decl * Parrot_cmd_options(void)>
71 Set up the const struct declaration for cmd_options
78 PARROT_CANNOT_RETURN_NULL
80 const struct longopt_opt_decl
*
81 Parrot_cmd_options(void)
83 ASSERT_ARGS(Parrot_cmd_options
)
84 static const struct longopt_opt_decl cmd_options
[] = {
85 { '.', '.', (OPTION_flags
)0, { "--wait" } },
86 { 'D', 'D', OPTION_optional_FLAG
, { "--parrot-debug" } },
87 { 'E', 'E', (OPTION_flags
)0, { "--pre-process-only" } },
88 { 'G', 'G', (OPTION_flags
)0, { "--no-gc" } },
89 { '\0', OPT_HASH_SEED
, OPTION_required_FLAG
, { "--hash-seed" } },
90 { 'I', 'I', OPTION_required_FLAG
, { "--include" } },
91 { 'L', 'L', OPTION_required_FLAG
, { "--library" } },
92 { 'O', 'O', OPTION_optional_FLAG
, { "--optimize" } },
93 { 'R', 'R', OPTION_required_FLAG
, { "--runcore" } },
94 { 'g', 'g', OPTION_required_FLAG
, { "--gc" } },
95 { 'V', 'V', (OPTION_flags
)0, { "--version" } },
96 { 'X', 'X', OPTION_required_FLAG
, { "--dynext" } },
97 { '\0', OPT_DESTROY_FLAG
, (OPTION_flags
)0,
98 { "--leak-test", "--destroy-at-end" } },
99 { '\0', OPT_GC_DEBUG
, (OPTION_flags
)0, { "--gc-debug" } },
100 { 'a', 'a', (OPTION_flags
)0, { "--pasm" } },
101 { 'c', 'c', (OPTION_flags
)0, { "--pbc" } },
102 { 'd', 'd', OPTION_optional_FLAG
, { "--imcc-debug" } },
103 { '\0', OPT_HELP_DEBUG
, (OPTION_flags
)0, { "--help-debug" } },
104 { 'h', 'h', (OPTION_flags
)0, { "--help" } },
105 { 'o', 'o', OPTION_required_FLAG
, { "--output" } },
106 { '\0', OPT_PBC_OUTPUT
, (OPTION_flags
)0, { "--output-pbc" } },
107 { 'r', 'r', (OPTION_flags
)0, { "--run-pbc" } },
108 { '\0', OPT_RUNTIME_PREFIX
, (OPTION_flags
)0, { "--runtime-prefix" } },
109 { 't', 't', OPTION_optional_FLAG
, { "--trace" } },
110 { 'v', 'v', (OPTION_flags
)0, { "--verbose" } },
111 { 'w', 'w', (OPTION_flags
)0, { "--warnings" } },
112 { 'y', 'y', (OPTION_flags
)0, { "--yydebug" } },
113 { 0, 0, (OPTION_flags
)0, { NULL
} }
120 =item C<int longopt_get(PARROT_INTERP, int argc, const char* argv[], const
121 struct longopt_opt_decl options[], struct longopt_opt_info* info_buf)>
123 Gets long or short options, specified in C<options[]> (see
124 F<docs/dev/longopt.dev>).
126 Call it iteratively with the same C<info_buf> until it returns 0 or -1.
128 0 means you have reached the end of options.
130 -1 means a parse error, with error put in C<< info_buf->opt_error >>.
132 Any other value is a valid option identifier.
139 PARROT_WARN_UNUSED_RESULT
141 longopt_get(PARROT_INTERP
, int argc
, ARGIN(const char* argv
[]),
142 ARGIN(const struct longopt_opt_decl options
[]),
143 ARGMOD(struct longopt_opt_info
* info_buf
))
145 ASSERT_ARGS(longopt_get
)
146 const int dex
= info_buf
->opt_index
;
148 info_buf
->opt_id
= 0;
149 info_buf
->opt_arg
= info_buf
->opt_error
= NULL
;
151 if (dex
>= argc
|| argv
[dex
] == NULL
)
154 if (argv
[dex
][0] != '-' || argv
[dex
][1] == '\0')
157 if (info_buf
->_shortopt_pos
)
158 return longopt_get_shortopt(interp
, argc
, argv
, options
, info_buf
);
160 if (argv
[dex
][1] == '-') { /* Long option or -- */
161 if (argv
[dex
][2] == '\0') {
162 ++info_buf
->opt_index
;
165 else { /* Long option */
166 return longopt_get_longopt(interp
, argc
, argv
, options
, info_buf
);
169 else { /* Short option */
170 return longopt_get_shortopt(interp
, argc
, argv
, options
, info_buf
);
176 =item C<static int longopt_get_longopt(PARROT_INTERP, int argc, const char*
177 argv[], const struct longopt_opt_decl options[], struct longopt_opt_info*
180 Find the option identifier of a long option.
182 Fill C<info_buf> appropriately, and return the option identifier.
184 C<argv[info_buf->opt_index]> is guaranteed to have at least three
185 characters and start with C<-->.
191 PARROT_WARN_UNUSED_RESULT
193 longopt_get_longopt(PARROT_INTERP
, int argc
, ARGIN(const char* argv
[]),
194 ARGIN(const struct longopt_opt_decl options
[]),
195 ARGMOD(struct longopt_opt_info
* info_buf
))
197 ASSERT_ARGS(longopt_get_longopt
)
198 const int dex
= info_buf
->opt_index
;
200 const struct longopt_opt_decl
* dptr
;
202 while (argv
[dex
][optlen
] != '\0' && argv
[dex
][optlen
] != '=') {
206 for (dptr
= options
; dptr
->opt_id
; ++dptr
) {
208 /* For each listed long option... */
209 for (sptr
= 0; dptr
->opt_long
[sptr
]; ++sptr
) {
210 if (strncmp(dptr
->opt_long
[sptr
], argv
[dex
], optlen
) == 0
211 && dptr
->opt_long
[sptr
][optlen
] == '\0') {
213 info_buf
->opt_id
= dptr
->opt_id
;
214 ++info_buf
->opt_index
;
216 /* XXX: (LP) if a longopt is given an argument when it's
217 * not expecting one, it is just ignored. Bad. */
219 if (argv
[dex
][optlen
] == '=') {
220 if (dptr
->opt_flags
&
221 (OPTION_required_FLAG
| OPTION_optional_FLAG
)) {
222 info_buf
->opt_arg
= &argv
[dex
][optlen
+1];
225 Parrot_snprintf(interp
, longopt_error_buffer
,
226 sizeof (longopt_error_buffer
),
227 "Option %s does not expect an argument",
228 dptr
->opt_long
[sptr
]);
229 info_buf
->opt_error
= longopt_error_buffer
;
234 if (dptr
->opt_flags
& OPTION_required_FLAG
) {
236 info_buf
->opt_arg
= argv
[dex
+1];
237 ++info_buf
->opt_index
;
240 Parrot_snprintf(interp
, longopt_error_buffer
,
241 sizeof (longopt_error_buffer
),
242 "Option %s needs an argument",
243 dptr
->opt_long
[sptr
]);
244 info_buf
->opt_error
= longopt_error_buffer
;
248 else if (dptr
->opt_flags
& OPTION_optional_FLAG
) {
249 if (dex
+2 < argc
&& argv
[dex
+1][0] &&
250 argv
[dex
+1][0] != '-') {
251 info_buf
->opt_arg
= argv
[dex
+1];
252 ++info_buf
->opt_index
;
262 /* Couldn't find it. */
263 info_buf
->opt_id
= -1;
264 Parrot_snprintf(interp
, longopt_error_buffer
,
265 sizeof (longopt_error_buffer
),
266 "Option %s not known", argv
[dex
]);
267 info_buf
->opt_error
= longopt_error_buffer
;
273 =item C<static int longopt_get_shortopt(PARROT_INTERP, int argc, const char*
274 argv[], const struct longopt_opt_decl options[], struct longopt_opt_info*
277 Find the option identifier of the next short option.
279 This next short option may be in the middle of a bundle (C<-abcd>), and
280 C<< info_buf->_shortopt_pos >> maintains a pointer into that bundle.
282 C<< argv[info_buf->opt_index] >> is guaranteed to be at least two
283 characters long and start with a dash.
289 PARROT_WARN_UNUSED_RESULT
291 longopt_get_shortopt(PARROT_INTERP
, int argc
, ARGIN(const char* argv
[]),
292 ARGIN(const struct longopt_opt_decl options
[]),
293 ARGMOD(struct longopt_opt_info
* info_buf
))
295 ASSERT_ARGS(longopt_get_shortopt
)
296 const int dex
= info_buf
->opt_index
;
297 const struct longopt_opt_decl
* dptr
;
301 if (!info_buf
->_shortopt_pos
)
302 info_buf
->_shortopt_pos
= &argv
[dex
][1];
303 pos
= info_buf
->_shortopt_pos
;
305 for (dptr
= options
; dptr
->opt_id
; ++dptr
) {
306 if (dptr
->opt_short
== *pos
) {
308 info_buf
->opt_id
= dptr
->opt_id
;
310 if (dptr
->opt_flags
& OPTION_required_FLAG
) {
312 info_buf
->opt_arg
= pos
+ 1;
316 info_buf
->opt_arg
= argv
[dex
+1];
317 ++info_buf
->opt_index
;
320 Parrot_snprintf(interp
, longopt_error_buffer
,
321 sizeof (longopt_error_buffer
),
322 "Option -%c expects an argument", *pos
);
323 info_buf
->opt_error
= longopt_error_buffer
;
327 info_buf
->_shortopt_pos
= NULL
;
328 ++info_buf
->opt_index
;
330 else if (dptr
->opt_flags
& OPTION_optional_FLAG
) {
332 info_buf
->opt_arg
= pos
+ 1;
334 else if (dex
+2 < argc
&& argv
[dex
+1][0] &&
335 argv
[dex
+1][0] != '-') {
336 info_buf
->opt_arg
= argv
[dex
+1];
337 ++info_buf
->opt_index
;
339 info_buf
->_shortopt_pos
= NULL
;
340 ++info_buf
->opt_index
;
342 else { /* No argument expected */
344 info_buf
->_shortopt_pos
= NULL
;
345 ++info_buf
->opt_index
;
348 ++info_buf
->_shortopt_pos
;
356 /* Couldn't find it in the table */
357 info_buf
->opt_id
= -1;
358 Parrot_snprintf(interp
, longopt_error_buffer
,
359 sizeof (longopt_error_buffer
),
360 "Option -%c not known", *pos
);
361 info_buf
->opt_error
= longopt_error_buffer
;
371 F<include/parrot/longopt.h> and F<docs/dev/longopt.dev>.
380 * c-file-style: "parrot"
382 * vim: expandtab shiftwidth=4: