fix codetest failure - ASSERT_ARGS does not have a ; after and
[parrot.git] / src / longopt.c
blobfa26cf1b698c8a75196f765b19bee1670c671ac2
1 /*
2 Copyright (C) 2001-2010, Parrot Foundation.
3 $Id$
5 =head1 NAME
7 longopt.c - Command-line option parsing
9 =head1 DESCRIPTION
11 This is used by C<parrot>.
13 =head2 Functions
15 =over 4
17 =cut
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,
30 int argc,
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,
42 int argc,
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
73 =cut
77 PARROT_EXPORT
78 PARROT_CANNOT_RETURN_NULL
79 PARROT_CONST_FUNCTION
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 } }
115 return cmd_options;
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.
134 =cut
138 PARROT_EXPORT
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)
152 return 0;
154 if (argv[dex][0] != '-' || argv[dex][1] == '\0')
155 return 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;
163 return 0;
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*
178 info_buf)>
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<-->.
187 =cut
191 PARROT_WARN_UNUSED_RESULT
192 static int
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;
199 int optlen = 0;
200 const struct longopt_opt_decl* dptr;
202 while (argv[dex][optlen] != '\0' && argv[dex][optlen] != '=') {
203 ++optlen;
206 for (dptr = options; dptr->opt_id; ++dptr) {
207 int sptr;
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') {
212 /* Found it */
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];
224 else {
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;
230 return -1;
233 else {
234 if (dptr->opt_flags & OPTION_required_FLAG) {
235 if (dex+1 < argc) {
236 info_buf->opt_arg = argv[dex+1];
237 ++info_buf->opt_index;
239 else {
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;
245 return -1;
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;
257 return dptr->opt_id;
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;
268 return -1;
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*
275 info_buf)>
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.
285 =cut
289 PARROT_WARN_UNUSED_RESULT
290 static int
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;
298 const char* pos;
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) {
307 /* Found it */
308 info_buf->opt_id = dptr->opt_id;
310 if (dptr->opt_flags & OPTION_required_FLAG) {
311 if (*(pos + 1)) {
312 info_buf->opt_arg = pos + 1;
314 else {
315 if (dex+1 < argc) {
316 info_buf->opt_arg = argv[dex+1];
317 ++info_buf->opt_index;
319 else {
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;
324 return -1;
327 info_buf->_shortopt_pos = NULL;
328 ++info_buf->opt_index;
330 else if (dptr->opt_flags & OPTION_optional_FLAG) {
331 if (*(pos + 1)) {
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 */
343 if (! *(pos + 1)) {
344 info_buf->_shortopt_pos = NULL;
345 ++info_buf->opt_index;
347 else {
348 ++info_buf->_shortopt_pos;
352 return dptr->opt_id;
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;
362 return -1;
367 =back
369 =head1 SEE ALSO
371 F<include/parrot/longopt.h> and F<docs/dev/longopt.dev>.
373 =cut
379 * Local variables:
380 * c-file-style: "parrot"
381 * End:
382 * vim: expandtab shiftwidth=4: