2 // Automated Testing Framework (atf)
4 // Copyright (c) 2007, 2008 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/object.h"
48 #include "atf-c++/application.hpp"
49 #include "atf-c++/sanity.hpp"
50 #include "atf-c++/ui.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
) :
115 m_description(description
),
117 m_global_manpage(global_manpage
)
122 impl::app::~app(void)
127 impl::app::inited(void)
132 impl::app::options_set
133 impl::app::options(void)
135 options_set opts
= specific_options();
136 opts
.insert(option('h', "", "Shows this help message"));
141 impl::app::specific_args(void)
147 impl::app::options_set
148 impl::app::specific_options(void)
151 return options_set();
155 impl::app::process_option(int ch
, const char* arg
)
160 impl::app::process_options(void)
165 #if defined(HAVE_GNU_GETOPT)
166 optstr
+= '+'; // Turn on POSIX behavior.
170 options_set opts
= options();
171 for (options_set::const_iterator iter
= opts
.begin();
172 iter
!= opts
.end(); iter
++) {
173 const option
& opt
= (*iter
);
175 optstr
+= opt
.m_character
;
176 if (!opt
.m_argument
.empty())
183 while ((ch
= ::getopt(m_argc
, m_argv
, optstr
.c_str())) != -1) {
190 throw usage_error("Option -%c requires an argument.",
194 throw usage_error("Unknown option -%c.", ::optopt
);
197 process_option(ch
, ::optarg
);
205 impl::app::usage(std::ostream
& os
)
209 std::string args
= specific_args();
212 os
<< ui::format_text_with_tag(std::string(m_prog_name
) + " [options]" +
213 args
, "Usage: ", false) << std::endl
215 << ui::format_text(m_description
) << std::endl
218 options_set opts
= options();
220 os
<< "Available options:" << std::endl
;
222 for (options_set::const_iterator iter
= opts
.begin();
223 iter
!= opts
.end(); iter
++) {
224 const option
& opt
= (*iter
);
226 if (opt
.m_argument
.length() + 1 > coldesc
)
227 coldesc
= opt
.m_argument
.length() + 1;
229 for (options_set::const_iterator iter
= opts
.begin();
230 iter
!= opts
.end(); iter
++) {
231 const option
& opt
= (*iter
);
233 std::string tag
= std::string(" -") + opt
.m_character
;
234 if (opt
.m_argument
.empty())
237 tag
+= " " + opt
.m_argument
+ " ";
238 os
<< ui::format_text_with_tag(opt
.m_description
, tag
, false,
245 if (!m_global_manpage
.empty())
246 gmp
= " and " + m_global_manpage
;
247 os
<< ui::format_text("For more details please see " + m_manpage
+
253 impl::app::run(int argc
, char* const* argv
)
261 m_prog_name
= std::strrchr(m_argv
[0], '/');
262 if (m_prog_name
== NULL
)
263 m_prog_name
= m_argv
[0];
267 const std::string bug
=
268 std::string("This is probably a bug in ") + m_prog_name
+
269 " or one of the libraries it uses. Please report this problem to "
270 PACKAGE_BUGREPORT
" and provide as many details as possible "
271 "describing how you got to this condition.";
275 int oldargc
= m_argc
;
281 throw usage_error("-h must be given alone.");
284 errcode
= EXIT_SUCCESS
;
287 } catch (const usage_error
& e
) {
288 std::cerr
<< ui::format_error(m_prog_name
, e
.what())
290 << ui::format_info(m_prog_name
, std::string("Type `") +
291 m_prog_name
+ " -h' for more details.")
293 errcode
= EXIT_FAILURE
;
294 } catch (const std::runtime_error
& e
) {
295 std::cerr
<< ui::format_error(m_prog_name
, std::string(e
.what()))
297 errcode
= EXIT_FAILURE
;
298 } catch (const std::exception
& e
) {
299 std::cerr
<< ui::format_error(m_prog_name
,
300 std::string("Caught unexpected error: ")
301 + e
.what() + "\n" + bug
)
303 errcode
= EXIT_FAILURE
;
305 std::cerr
<< ui::format_error(m_prog_name
,
306 std::string("Caught unknown error\n") +
309 errcode
= EXIT_FAILURE
;