[TT# 1592][t] Improve test for open opcode delegation. All tests in the file pass...
[parrot.git] / src / longopt.c
blob943192bc55a9df438c5f213d893e75c5d3bdec7c
1 /*
2 Copyright (C) 2001-2007, 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 static int longopt_get_longopt(PARROT_INTERP,
29 int argc,
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,
40 int argc,
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.
81 =cut
85 PARROT_EXPORT
86 int
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;
94 info_buf->opt_id = 0;
95 info_buf->opt_arg = info_buf->opt_error = NULL;
97 if (dex >= argc || argv[dex] == NULL)
98 return 0;
100 if (argv[dex][0] != '-' || argv[dex][1] == '\0')
101 return 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;
109 return 0;
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*
124 info_buf)>
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<-->.
133 =cut
137 static int
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;
144 int optlen = 0;
145 const struct longopt_opt_decl* dptr;
147 while (argv[dex][optlen] != '\0' && argv[dex][optlen] != '=') {
148 optlen++;
151 for (dptr = options; dptr->opt_id; dptr++) {
152 int sptr;
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') {
157 /* Found it */
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];
169 else {
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;
175 return -1;
178 else {
179 if (dptr->opt_flags & OPTION_required_FLAG) {
180 if (dex+1 < argc) {
181 info_buf->opt_arg = argv[dex+1];
182 ++info_buf->opt_index;
184 else {
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;
190 return -1;
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;
202 return dptr->opt_id;
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;
213 return -1;
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*
220 info_buf)>
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.
230 =cut
234 static int
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;
242 const char* pos;
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) {
251 /* Found it */
252 info_buf->opt_id = dptr->opt_id;
254 if (dptr->opt_flags & OPTION_required_FLAG) {
255 if (*(pos + 1)) {
256 info_buf->opt_arg = pos + 1;
258 else {
259 if (dex+1 < argc) {
260 info_buf->opt_arg = argv[dex+1];
261 ++info_buf->opt_index;
263 else {
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;
268 return -1;
271 info_buf->_shortopt_pos = NULL;
272 ++info_buf->opt_index;
274 else if (dptr->opt_flags & OPTION_optional_FLAG) {
275 if (*(pos + 1)) {
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 */
287 if (! *(pos + 1)) {
288 info_buf->_shortopt_pos = NULL;
289 ++info_buf->opt_index;
291 else {
292 ++info_buf->_shortopt_pos;
296 return dptr->opt_id;
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;
306 return -1;
311 =back
313 =head1 SEE ALSO
315 F<include/parrot/longopt.h> and F<docs/dev/longopt.dev>.
317 =cut
323 * Local variables:
324 * c-file-style: "parrot"
325 * End:
326 * vim: expandtab shiftwidth=4: