[t] Refactor some namespace pmc tests to use throws_like
[parrot.git] / src / longopt.c
blob603f97e67329898152b4f29d7dd325f9b26807c9
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"
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,
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 static int longopt_get_shortopt(PARROT_INTERP,
41 int argc,
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.
82 =cut
86 PARROT_EXPORT
87 int
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;
95 info_buf->opt_id = 0;
96 info_buf->opt_arg = info_buf->opt_error = NULL;
98 if (dex >= argc || argv[dex] == NULL)
99 return 0;
101 if (argv[dex][0] != '-' || argv[dex][1] == '\0')
102 return 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;
110 return 0;
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*
125 info_buf)>
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<-->.
134 =cut
138 static int
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;
145 int optlen = 0;
146 const struct longopt_opt_decl* dptr;
148 while (argv[dex][optlen] != '\0' && argv[dex][optlen] != '=') {
149 optlen++;
152 for (dptr = options; dptr->opt_id; dptr++) {
153 int sptr;
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') {
158 /* Found it */
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];
170 else {
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;
176 return -1;
179 else {
180 if (dptr->opt_flags & OPTION_required_FLAG) {
181 if (dex+1 < argc) {
182 info_buf->opt_arg = argv[dex+1];
183 ++info_buf->opt_index;
185 else {
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;
191 return -1;
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;
203 return dptr->opt_id;
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;
214 return -1;
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*
221 info_buf)>
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.
231 =cut
235 static int
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;
243 const char* pos;
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) {
252 /* Found it */
253 info_buf->opt_id = dptr->opt_id;
255 if (dptr->opt_flags & OPTION_required_FLAG) {
256 if (*(pos + 1)) {
257 info_buf->opt_arg = pos + 1;
259 else {
260 if (dex+1 < argc) {
261 info_buf->opt_arg = argv[dex+1];
262 ++info_buf->opt_index;
264 else {
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;
269 return -1;
272 info_buf->_shortopt_pos = NULL;
273 ++info_buf->opt_index;
275 else if (dptr->opt_flags & OPTION_optional_FLAG) {
276 if (*(pos + 1)) {
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 */
288 if (! *(pos + 1)) {
289 info_buf->_shortopt_pos = NULL;
290 ++info_buf->opt_index;
292 else {
293 ++info_buf->_shortopt_pos;
297 return dptr->opt_id;
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;
307 return -1;
312 =back
314 =head1 SEE ALSO
316 F<include/parrot/longopt.h> and F<docs/dev/longopt.dev>.
318 =cut
324 * Local variables:
325 * c-file-style: "parrot"
326 * End:
327 * vim: expandtab shiftwidth=4: