1 #include "ace/Get_Opt.h"
3 #if !defined (__ACE_INLINE__)
4 #include "ace/Get_Opt.inl"
5 #endif /* __ACE_INLINE__ */
8 #include "ace/Log_Category.h"
9 #include "ace/SString.h"
10 #include "ace/OS_Memory.h"
11 #include "ace/OS_NS_string.h"
12 #include "ace/OS_NS_ctype.h"
13 #include "ace/OS_NS_stdlib.h"
16 * Copyright (c) 1987, 1993, 1994
17 * The Regents of the University of California. All rights reserved.
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions
22 * 1. Redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer.
24 * 2. Redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in the
26 * documentation and/or other materials provided with the distribution.
27 * 3. All advertising materials mentioning features or use of this software
28 * must display the following acknowledgement:
29 * This product includes software developed by the University of
30 * California, Berkeley and its contributors.
31 * 4. Neither the name of the University nor the names of its contributors
32 * may be used to endorse or promote products derived from this software
33 * without specific prior written permission.
35 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
36 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
39 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
49 * Copyright (c) 2000 The NetBSD Foundation, Inc.
50 * All rights reserved.
52 * This code is derived from software contributed to The NetBSD Foundation
53 * by Dieter Baron and Thomas Klausner.
55 * Redistribution and use in source and binary forms, with or without
56 * modification, are permitted provided that the following conditions
58 * 1. Redistributions of source code must retain the above copyright
59 * notice, this list of conditions and the following disclaimer.
60 * 2. Redistributions in binary form must reproduce the above copyright
61 * notice, this list of conditions and the following disclaimer in the
62 * documentation and/or other materials provided with the distribution.
63 * 3. All advertising materials mentioning features or use of this software
64 * must display the following acknowledgement:
65 * This product includes software developed by the NetBSD
66 * Foundation, Inc. and its contributors.
67 * 4. Neither the name of The NetBSD Foundation nor the names of its
68 * contributors may be used to endorse or promote products derived
69 * from this software without specific prior written permission.
71 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
72 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
73 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
74 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
75 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
76 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
77 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
78 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
79 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
80 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
81 * POSSIBILITY OF SUCH DAMAGE.
84 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
86 ACE_ALLOC_HOOK_DEFINE(ACE_Get_Opt
)
89 void ACE_Get_Opt::ACE_Get_Opt_Init (const ACE_TCHAR
*optstring
)
91 ACE_Get_Opt::ACE_Get_Opt (int argc
,
93 const ACE_TCHAR
*optstring
,
101 opterr (report_errors
),
104 long_only_ (long_only
),
109 ordering_ (ordering
),
110 nonopt_start_ (optind
),
111 nonopt_end_ (optind
),
115 ACE_TRACE ("ACE_Get_Opt::ACE_Get_Opt");
117 ACE_NEW (this->optstring_
, ACE_TString (optstring
));
118 ACE_NEW (this->last_option_
, ACE_TString (ACE_TEXT ("")));
120 // First check to see if POSIXLY_CORRECT was set.
121 // Win32 is the only platform capable of wide-char env var.
122 #if defined (ACE_WIN32)
123 const ACE_TCHAR
*env_check
= ACE_TEXT ("POSIXLY_CORRECT");
125 const char *env_check
= "POSIXLY_CORRECT";
127 if (ACE_OS::getenv (env_check
) != 0)
128 this->ordering_
= REQUIRE_ORDER
;
130 // Now, check to see if any or the following were passed at
131 // the beginning of optstring: '+' same as POSIXLY_CORRECT;
132 // '-' turns off POSIXLY_CORRECT; or ':' which signifies we
133 // should return ':' if a parameter is missing for an option.
134 // We use a loop here, since a combination of "{+|-}:" in any
135 // order should be legal.
140 switch (optstring
[offset
++])
143 this->ordering_
= REQUIRE_ORDER
;
146 this->ordering_
= RETURN_IN_ORDER
;
149 this->has_colon_
= 1;
152 // Quit as soon as we see something else...
159 ACE_Get_Opt::~ACE_Get_Opt ()
161 ACE_TRACE ("ACE_Get_Opt::~ACE_Get_Opt");
164 size_t size
= this->long_opts_
.size ();
165 ACE_Get_Opt_Long_Option
*option
= 0;
166 for (i
= 0; i
< size
; ++i
)
168 int retval
= this->long_opts_
.get (option
, i
);
171 // Should never happen.
181 delete this->optstring_
;
182 delete this->last_option_
;
186 ACE_Get_Opt::nextchar_i ()
188 ACE_TRACE ("ACE_Get_Opt::nextchar_i");
190 if (this->ordering_
== PERMUTE_ARGS
)
191 if (this->permute () == EOF
)
194 // Update scanning pointer.
195 if (this->optind
>= this->argc_
)
201 else if (*(this->nextchar_
= this->argv_
[this->optind
]) != '-'
202 || this->nextchar_
[1] == '\0')
204 // We didn't get an option.
206 if (this->ordering_
== REQUIRE_ORDER
207 || this->ordering_
== PERMUTE_ARGS
)
208 // If we permuted or require the options to be in order, we're done.
211 // It must be RETURN_IN_ORDER...
212 this->optarg
= this->argv_
[this->optind
++];
216 else if (this->nextchar_
[1] != 0
217 && *++this->nextchar_
== '-'
218 && this->nextchar_
[1] == 0)
220 // Found "--" so we're done...
226 // If it's a long option, and we allow long options advance nextchar_.
227 if (*this->nextchar_
== '-' && this->long_opts_
.size () != 0)
234 ACE_Get_Opt::long_option_i ()
236 ACE_TRACE ("ACE_Get_Opt::long_option_i");
238 ACE_Get_Opt_Long_Option
*p
;
239 ACE_TCHAR
*s
= this->nextchar_
;
242 ACE_Get_Opt_Long_Option
*pfound
= 0;
245 // Advance to the end of the long option name so we can use
246 // it to get the length for a string compare.
247 while (*s
&& *s
!= '=')
250 size_t len
= s
- this->nextchar_
;
251 // set last_option_ to nextchar_, up to the '='.
252 this->last_option (ACE_TString (this->nextchar_
, len
));
254 size_t size
= this->long_opts_
.size ();
255 u_int option_index
= 0;
256 for (option_index
= 0; option_index
< size
; option_index
++)
258 p
= this->long_opts_
[option_index
];
261 if (!ACE_OS::strncmp (p
->name_
, this->nextchar_
, len
))
263 // Got at least a partial match.
265 indfound
= option_index
;
267 if (len
== ACE_OS::strlen(p
->name_
))
269 // And in fact, it's an exact match, so let's use it.
276 if ((hits
> 1) && !exact
)
278 // Great, we found a match, but unfortunately we found more than
279 // one and it wasn't exact.
281 ACELIB_ERROR ((LM_ERROR
,
282 ACE_TEXT ("%s: option `%s' is ambiguous\n"),
283 this->argv_
[0], this->argv_
[this->optind
]));
291 // Okay, we found a good one (either a single hit or an exact match).
292 option_index
= indfound
;
296 // s must point to '=' which means there's an argument (well
298 if (pfound
->has_arg_
!= NO_ARG
)
299 // Good, we want an argument and here it is.
303 // Whoops, we've got what looks like an argument, but we
308 ACE_TEXT ("%s: long option `--%s' doesn't allow ")
309 ACE_TEXT ("an argument\n"),
310 this->argv_
[0], pfound
->name_
));
311 // The spec doesn't cover this, so we keep going and the program
312 // doesn't know we ignored an argument if opt_err is off!!!
315 else if (pfound
->has_arg_
== ARG_REQUIRED
)
317 // s didn't help us, but we need an argument. Note that
318 // optional arguments for long options must use the "=" syntax,
319 // so we won't get here in that case.
320 if (this->optind
< this->argc_
)
321 // We still have some elements left, so use the next one.
322 this->optarg
= this->argv_
[this->optind
++];
325 // All out of elements, so we have to punt...
327 ACELIB_ERROR ((LM_ERROR
,
328 ACE_TEXT ("%s: long option '--%s' requires ")
329 ACE_TEXT ("an argument\n"),
330 this->argv_
[0], pfound
->name_
));
332 this->optopt_
= pfound
->val_
; // Remember matching short equiv
333 return this->has_colon_
? ':' : '?';
337 this->long_option_
= pfound
;
338 // Since val_ has to be either a valid short option or 0, this works
339 // great. If the user really wants to know if a long option was passed.
340 this->optopt_
= pfound
->val_
;
343 if (!this->long_only_
|| this->argv_
[this->optind
][1] == '-'
344 || this->optstring_
->find (*this->nextchar_
) == ACE_TString::npos
)
346 // Okay, we couldn't find a long option. If it isn't long_only (which
347 // means try the long first, and if not found try the short) or a long
348 // signature was passed, e.g. "--", or it's not a short (not sure when
349 // this could happen) it's an error.
351 ACELIB_ERROR ((LM_ERROR
,
352 ACE_TEXT ("%s: illegal long option '--%s'\n"),
353 this->argv_
[0], this->nextchar_
));
358 return this->short_option_i ();
362 ACE_Get_Opt::short_option_i ()
364 ACE_TRACE ("ACE_Get_Opt::short_option_i");
366 /* Look at and handle the next option-character. */
367 ACE_TCHAR opt
= *this->nextchar_
++;
368 // Set last_option_ to opt
369 this->last_option (opt
);
373 const_cast<ACE_TCHAR
*> (ACE_OS::strchr (this->optstring_
->c_str (), opt
));
375 /* Increment `optind' when we start to process its last character. */
376 if (*this->nextchar_
== '\0')
379 if (oli
== 0 || opt
== ':')
382 ACELIB_ERROR ((LM_ERROR
,
383 ACE_TEXT ("%s: illegal short option -- %c\n"),
384 this->argv_
[0], opt
));
387 if (opt
== 'W' && oli
[1] == ';')
389 if (this->nextchar_
[0] == 0)
390 this->nextchar_
= this->argv_
[this->optind
];
391 return long_option_i ();
393 this->optopt_
= oli
[0]; // Remember the option that matched
398 // Takes an optional argument, and since short option args must
399 // must follow directly in the same argument, a NULL nextchar_
400 // means we didn't get one.
401 if (*this->nextchar_
!= '\0')
403 this->optarg
= this->nextchar_
;
412 // Takes a required argument.
413 if (*this->nextchar_
!= '\0')
415 // Found argument in same argv-element.
416 this->optarg
= this->nextchar_
;
419 else if (this->optind
== this->argc_
)
421 // Ran out of arguments before finding required argument.
423 ACELIB_ERROR ((LM_ERROR
,
424 ACE_TEXT ("%s: short option requires ")
425 ACE_TEXT ("an argument -- %c\n"),
426 this->argv_
[0], opt
));
427 opt
= this->has_colon_
? ':' : '?';
430 // Use the next argv-element as the argument.
431 this->optarg
= this->argv_
[this->optind
++];
439 ACE_Get_Opt::operator () ()
441 ACE_TRACE ("ACE_Get_Opt_Long::operator");
443 // First of all, make sure we reinitialize any pointers..
445 this->long_option_
= 0;
447 if (this->argv_
== 0)
449 // It can happen, e.g., on VxWorks.
454 // We check this because we can string short options together if the
455 // preceding one doesn't take an argument.
456 if (this->nextchar_
== 0 || *this->nextchar_
== '\0')
458 int retval
= this->nextchar_i ();
463 if (((this->argv_
[this->optind
][0] == '-')
464 && (this->argv_
[this->optind
][1] == '-')) || this->long_only_
)
465 return this->long_option_i ();
467 return this->short_option_i ();
471 ACE_Get_Opt::long_option (const ACE_TCHAR
*name
,
472 OPTION_ARG_MODE has_arg
)
474 ACE_TRACE ("ACE_Get_Opt::long_option (const ACE_TCHAR *name, OPTION_ARG_MODE has_arg)");
475 return this->long_option (name
, 0, has_arg
);
479 ACE_Get_Opt::long_option (const ACE_TCHAR
*name
,
481 OPTION_ARG_MODE has_arg
)
483 ACE_TRACE ("ACE_Get_Opt::long_option (const ACE_TCHAR *name, int short_option, OPTION_ARG_MODE has_arg)");
485 // We only allow valid alpha-numeric characters as short options.
486 // If short_options is not a valid alpha-numeric, we can still return it
487 // when the long option is found, but won't allow the caller to pass it on
488 // the command line (how could they?). The special case is 0, but since
489 // we always return it, we let the caller worry about that.
490 if (ACE_OS::ace_isalnum (short_option
) != 0)
492 // If the short_option already exists, make sure it matches, otherwise
495 if ((s
= const_cast<ACE_TCHAR
*> (
496 ACE_OS::strchr (this->optstring_
->c_str (),
497 short_option
))) != 0)
499 // Short option exists, so verify the argument options
504 if (has_arg
!= ARG_OPTIONAL
)
509 ACE_TEXT ("Existing short option '%c' takes ")
510 ACE_TEXT ("optional argument; adding %s ")
511 ACE_TEXT ("requires ARG_OPTIONAL\n"),
512 short_option
, name
));
517 if (has_arg
!= ARG_REQUIRED
)
522 ACE_TEXT ("Existing short option '%c' requires ")
523 ACE_TEXT ("an argument; adding %s ")
524 ACE_TEXT ("requires ARG_REQUIRED\n"),
525 short_option
, name
));
529 else if (has_arg
!= NO_ARG
)
534 ACE_TEXT ("Existing short option '%c' does not ")
535 ACE_TEXT ("accept an argument; adding %s ")
536 ACE_TEXT ("requires NO_ARG\n"),
537 short_option
, name
));
543 // Didn't find short option, so add it...
544 *this->optstring_
+= (ACE_TCHAR
) short_option
;
545 if (has_arg
== ARG_REQUIRED
)
546 *this->optstring_
+= ACE_TEXT (":");
547 else if (has_arg
== ARG_OPTIONAL
)
548 *this->optstring_
+= ACE_TEXT ("::");
552 ACE_Get_Opt_Long_Option
*option
=
553 new ACE_Get_Opt_Long_Option (name
, has_arg
, short_option
);
559 size_t size
= this->long_opts_
.size ();
560 if (this->long_opts_
.size (size
+ 1) != 0
561 || this->long_opts_
.set (option
, size
) != 0)
565 ((LM_ERROR
, ACE_TEXT ("Could not add long option to array.\n")),
572 ACE_Get_Opt::long_option () const
574 ACE_TRACE ("ACE_Get_Opt::long_option (void)");
575 if (this->long_option_
)
576 return this->long_option_
->name_
;
581 ACE_Get_Opt::last_option () const
583 return this->last_option_
->c_str ();
587 ACE_Get_Opt::last_option (const ACE_TString
&last_option
)
589 *this->last_option_
= last_option
;
593 ACE_Get_Opt::dump () const
595 #if defined (ACE_HAS_DUMP)
596 ACE_TRACE ("ACE_Get_Opt::dump");
598 ACELIB_DEBUG ((LM_DEBUG
, ACE_BEGIN_DUMP
, this));
599 ACELIB_DEBUG ((LM_DEBUG
, ACE_TEXT ("\n")
600 ACE_TEXT ("opstring_ = %s\n")
601 ACE_TEXT ("long_only_ = %d\n")
602 ACE_TEXT ("has_colon_ = %d\n")
603 ACE_TEXT ("last_option_ = %s\n")
604 ACE_TEXT ("nextchar_ = %s\n")
605 ACE_TEXT ("optopt_ = %c\n")
606 ACE_TEXT ("ordering_ = %d\n"),
607 this->optstring_
->c_str (),
610 this->last_option_
->c_str (),
615 // now loop through the
616 size_t size
= this->long_opts_
.size ();
617 for (u_int i
= 0; i
< size
; ++i
)
619 ACELIB_DEBUG ((LM_DEBUG
, ACE_TEXT ("\n")
620 ACE_TEXT ("long_option name_ = %s\n")
621 ACE_TEXT ("has_arg_ = %d\n")
622 ACE_TEXT ("val_ = %d\n"),
623 this->long_opts_
[i
]->name_
,
624 this->long_opts_
[i
]->has_arg_
,
625 this->long_opts_
[i
]->val_
));
627 ACELIB_DEBUG ((LM_DEBUG
, ACE_END_DUMP
));
628 #endif /* ACE_HAS_DUMP */
632 ACE_Get_Opt::permute_args ()
634 ACE_TRACE ("ACE_Get_Opt::permute_args");
636 u_long cyclelen
, i
, j
, ncycle
, nnonopts
, nopts
;
637 u_long opt_end
= this->optind
;
641 nnonopts
= this->nonopt_end_
- this->nonopt_start_
;
642 nopts
= opt_end
- this->nonopt_end_
;
643 ncycle
= ACE::gcd (nnonopts
, nopts
);
644 cyclelen
= (opt_end
- this->nonopt_start_
) / ncycle
;
646 this->optind
= this->optind
- nnonopts
;
648 for (i
= 0; i
< ncycle
; i
++)
650 cstart
= this->nonopt_end_
+ i
;
652 for (j
= 0; j
< cyclelen
; j
++)
654 if (pos
>= this->nonopt_end_
)
658 swap
= this->argv_
[pos
];
660 ((ACE_TCHAR
**)this->argv_
)[pos
] = argv_
[cstart
];
662 ((ACE_TCHAR
**)this->argv_
)[cstart
] = swap
;
668 ACE_Get_Opt::permute ()
670 ACE_TRACE ("ACE_Get_Opt::permute");
672 if (this->nonopt_start_
!= this->nonopt_end_
673 && this->nonopt_start_
!= this->optind
)
674 this->permute_args ();
676 this->nonopt_start_
= this->optind
;
678 // Skip over args untill we find the next option.
679 while (this->optind
< this->argc_
680 && (this->argv_
[this->optind
][0] != '-'
681 || this->argv_
[this->optind
][1] == '\0'))
684 // Got an option, so mark this as the end of the non options.
685 this->nonopt_end_
= this->optind
;
687 if (this->optind
!= this->argc_
688 && ACE_OS::strcmp (this->argv_
[this->optind
],
689 ACE_TEXT ("--")) == 0)
691 // We found the marker for the end of the options.
694 if (this->nonopt_start_
!= this->nonopt_end_
695 && this->nonopt_end_
!= this->optind
)
696 this->permute_args ();
699 if (this->optind
== this->argc_
)
701 if (this->nonopt_start_
!= this->nonopt_end_
)
702 this->optind
= this->nonopt_start_
;
709 ACE_Get_Opt::optstring () const
711 return this->optstring_
->c_str ();
714 ACE_Get_Opt::ACE_Get_Opt_Long_Option::ACE_Get_Opt_Long_Option (
715 const ACE_TCHAR
*name
,
718 : name_ (ACE::strnew (name
)),
723 ACE_Get_Opt::ACE_Get_Opt_Long_Option::~ACE_Get_Opt_Long_Option ()
725 #if defined (ACE_HAS_ALLOC_HOOKS)
726 ACE_Allocator::instance()->free(const_cast<ACE_TCHAR
*>(this->name_
));
728 delete [] this->name_
;
729 #endif /* ACE_HAS_ALLOC_HOOKS */
732 ACE_ALLOC_HOOK_DEFINE(ACE_Get_Opt::ACE_Get_Opt_Long_Option
);
734 ACE_END_VERSIONED_NAMESPACE_DECL