2 // Automated Testing Framework (atf)
4 // Copyright (c) 2007 The NetBSD Foundation, Inc.
5 // All rights reserved.
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
10 // 1. Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 // 2. Redistributions in binary form must reproduce the above copyright
13 // notice, this list of conditions and the following disclaimer in the
14 // documentation and/or other materials provided with the distribution.
16 // THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17 // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18 // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 // IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #if defined(HAVE_CONFIG_H)
45 #include "atf-c/defs.h"
48 #include "application.hpp"
52 #if !defined(HAVE_VSNPRINTF_IN_STD)
56 #endif // !defined(HAVE_VSNPRINTF_IN_STD)
58 namespace impl
= atf::application
;
59 #define IMPL_NAME "atf::application"
61 // ------------------------------------------------------------------------
62 // The "usage_error" class.
63 // ------------------------------------------------------------------------
65 impl::usage_error::usage_error(const char *fmt
, ...)
67 std::runtime_error("usage_error; message unformatted")
72 std::vsnprintf(m_text
, sizeof(m_text
), fmt
, ap
);
76 impl::usage_error::~usage_error(void)
82 impl::usage_error::what(void)
88 // ------------------------------------------------------------------------
89 // The "application" class.
90 // ------------------------------------------------------------------------
92 impl::option::option(char ch
,
94 const std::string
& desc
) :
102 impl::option::operator<(const impl::option
& o
)
105 return m_character
< o
.m_character
;
108 impl::app::app(const std::string
& description
,
109 const std::string
& manpage
,
110 const std::string
& global_manpage
,
116 m_description(description
),
118 m_global_manpage(global_manpage
),
123 impl::app::~app(void)
128 impl::app::inited(void)
133 impl::app::options_set
134 impl::app::options(void)
136 options_set opts
= specific_options();
138 opts
.insert(option('h', "", "Shows this help message"));
144 impl::app::specific_args(void)
150 impl::app::options_set
151 impl::app::specific_options(void)
154 return options_set();
158 impl::app::process_option(int ch ATF_DEFS_ATTRIBUTE_UNUSED
,
159 const char* arg ATF_DEFS_ATTRIBUTE_UNUSED
)
164 impl::app::process_options(void)
169 #if defined(HAVE_GNU_GETOPT)
170 optstr
+= '+'; // Turn on POSIX behavior.
174 options_set opts
= options();
175 for (options_set::const_iterator iter
= opts
.begin();
176 iter
!= opts
.end(); iter
++) {
177 const option
& opt
= (*iter
);
179 optstr
+= opt
.m_character
;
180 if (!opt
.m_argument
.empty())
186 const int old_opterr
= ::opterr
;
188 while ((ch
= ::getopt(m_argc
, m_argv
, optstr
.c_str())) != -1) {
196 throw usage_error("Option -%c requires an argument.",
200 throw usage_error("Unknown option -%c.", ::optopt
);
203 process_option(ch
, ::optarg
);
209 // Clear getopt state just in case the test wants to use it.
212 #if defined(HAVE_OPTRESET)
218 impl::app::usage(std::ostream
& os
)
222 std::string args
= specific_args();
225 os
<< ui::format_text_with_tag(std::string(m_prog_name
) + " [options]" +
226 args
, "Usage: ", false) << "\n\n"
227 << ui::format_text(m_description
) << "\n\n";
229 options_set opts
= options();
231 os
<< "Available options:\n";
233 for (options_set::const_iterator iter
= opts
.begin();
234 iter
!= opts
.end(); iter
++) {
235 const option
& opt
= (*iter
);
237 if (opt
.m_argument
.length() + 1 > coldesc
)
238 coldesc
= opt
.m_argument
.length() + 1;
240 for (options_set::const_iterator iter
= opts
.begin();
241 iter
!= opts
.end(); iter
++) {
242 const option
& opt
= (*iter
);
244 std::string tag
= std::string(" -") + opt
.m_character
;
245 if (opt
.m_argument
.empty())
248 tag
+= " " + opt
.m_argument
+ " ";
249 os
<< ui::format_text_with_tag(opt
.m_description
, tag
, false,
250 coldesc
+ 10) << "\n";
255 if (!m_global_manpage
.empty())
256 gmp
= " and " + m_global_manpage
;
257 os
<< ui::format_text("For more details please see " + m_manpage
+
263 impl::app::run(int argc
, char* const* argv
)
273 m_prog_name
= std::strrchr(m_argv
[0], '/');
274 if (m_prog_name
== NULL
)
275 m_prog_name
= m_argv
[0];
279 // Libtool workaround: if running from within the source tree (binaries
280 // that are not installed yet), skip the "lt-" prefix added to files in
281 // the ".libs" directory to show the real (not temporary) name.
282 if (std::strncmp(m_prog_name
, "lt-", 3) == 0)
285 const std::string bug
=
286 std::string("This is probably a bug in ") + m_prog_name
+
287 " or one of the libraries it uses. Please report this problem to "
288 PACKAGE_BUGREPORT
" and provide as many details as possible "
289 "describing how you got to this condition.";
293 int oldargc
= m_argc
;
300 throw usage_error("-h must be given alone.");
303 errcode
= EXIT_SUCCESS
;
306 } catch (const usage_error
& e
) {
308 std::cerr
<< ui::format_error(m_prog_name
, e
.what()) << "\n"
309 << ui::format_info(m_prog_name
, std::string("Type `") +
310 m_prog_name
+ " -h' for more details.")
313 std::cerr
<< m_prog_name
<< ": ERROR: " << e
.what() << "\n";
314 std::cerr
<< m_prog_name
<< ": See " << m_manpage
<< " for usage "
317 errcode
= EXIT_FAILURE
;
318 } catch (const std::runtime_error
& e
) {
320 std::cerr
<< ui::format_error(m_prog_name
, std::string(e
.what()))
323 std::cerr
<< m_prog_name
<< ": ERROR: " << e
.what() << "\n";
325 errcode
= EXIT_FAILURE
;
326 } catch (const std::exception
& e
) {
328 std::cerr
<< ui::format_error(m_prog_name
, std::string("Caught "
329 "unexpected error: ") + e
.what() + "\n" + bug
) << "\n";
331 std::cerr
<< m_prog_name
<< ": ERROR: Caught unexpected error: "
334 errcode
= EXIT_FAILURE
;
337 std::cerr
<< ui::format_error(m_prog_name
, std::string("Caught "
338 "unknown error\n") + bug
) << "\n";
340 std::cerr
<< m_prog_name
<< ": ERROR: Caught unknown error\n";
342 errcode
= EXIT_FAILURE
;