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.
41 #include "application.hpp"
48 namespace impl
= tools::application
;
49 #define IMPL_NAME "tools::application"
51 // ------------------------------------------------------------------------
52 // The "usage_error" class.
53 // ------------------------------------------------------------------------
55 impl::usage_error::usage_error(const char *fmt
, ...)
57 std::runtime_error("usage_error; message unformatted")
62 std::vsnprintf(m_text
, sizeof(m_text
), fmt
, ap
);
66 impl::usage_error::~usage_error(void)
72 impl::usage_error::what(void)
78 // ------------------------------------------------------------------------
79 // The "application" class.
80 // ------------------------------------------------------------------------
82 impl::option::option(char ch
,
84 const std::string
& desc
) :
92 impl::option::operator<(const impl::option
& o
)
95 return m_character
< o
.m_character
;
98 impl::app::app(const std::string
& description
,
99 const std::string
& manpage
,
100 const std::string
& global_manpage
) :
105 m_description(description
),
107 m_global_manpage(global_manpage
)
111 impl::app::~app(void)
116 impl::app::inited(void)
121 impl::app::options_set
122 impl::app::options(void)
124 options_set opts
= specific_options();
125 opts
.insert(option('h', "", "Shows this help message"));
130 impl::app::specific_args(void)
136 impl::app::options_set
137 impl::app::specific_options(void)
140 return options_set();
144 impl::app::process_option(int ch
__attribute__((__unused__
)),
145 const char* arg
__attribute__((__unused__
)))
150 impl::app::process_options(void)
154 std::string optstr
= ":";
156 options_set opts
= options();
157 for (options_set::const_iterator iter
= opts
.begin();
158 iter
!= opts
.end(); iter
++) {
159 const option
& opt
= (*iter
);
161 optstr
+= opt
.m_character
;
162 if (!opt
.m_argument
.empty())
168 const int old_opterr
= ::opterr
;
170 while ((ch
= ::getopt(m_argc
, m_argv
, optstr
.c_str())) != -1) {
177 throw usage_error("Option -%c requires an argument.",
181 throw usage_error("Unknown option -%c.", ::optopt
);
184 process_option(ch
, ::optarg
);
190 // Clear getopt state just in case the test wants to use it.
197 impl::app::usage(std::ostream
& os
)
201 std::string args
= specific_args();
204 os
<< ui::format_text_with_tag(std::string(m_prog_name
) + " [options]" +
205 args
, "Usage: ", false) << "\n\n"
206 << ui::format_text(m_description
) << "\n\n";
208 options_set opts
= options();
209 assert(!opts
.empty());
210 os
<< "Available options:\n";
212 for (options_set::const_iterator iter
= opts
.begin();
213 iter
!= opts
.end(); iter
++) {
214 const option
& opt
= (*iter
);
216 if (opt
.m_argument
.length() + 1 > coldesc
)
217 coldesc
= opt
.m_argument
.length() + 1;
219 for (options_set::const_iterator iter
= opts
.begin();
220 iter
!= opts
.end(); iter
++) {
221 const option
& opt
= (*iter
);
223 std::string tag
= std::string(" -") + opt
.m_character
;
224 if (opt
.m_argument
.empty())
227 tag
+= " " + opt
.m_argument
+ " ";
228 os
<< ui::format_text_with_tag(opt
.m_description
, tag
, false,
229 coldesc
+ 10) << "\n";
234 if (!m_global_manpage
.empty())
235 gmp
= " and " + m_global_manpage
;
236 os
<< ui::format_text("For more details please see " + m_manpage
+
242 impl::app::run(int argc
, char* const* argv
)
245 assert(argv
!= NULL
);
252 m_prog_name
= std::strrchr(m_argv
[0], '/');
253 if (m_prog_name
== NULL
)
254 m_prog_name
= m_argv
[0];
258 // Libtool workaround: if running from within the source tree (binaries
259 // that are not installed yet), skip the "lt-" prefix added to files in
260 // the ".libs" directory to show the real (not temporary) name.
261 if (std::strncmp(m_prog_name
, "lt-", 3) == 0)
264 const std::string bug
=
265 std::string("This is probably a bug in ") + m_prog_name
+
266 " Please use send-pr(1) to report this issue and provide as many"
267 " details as possible describing how you got to this condition.";
271 int oldargc
= m_argc
;
277 throw usage_error("-h must be given alone.");
280 errcode
= EXIT_SUCCESS
;
283 } catch (const usage_error
& e
) {
284 std::cerr
<< ui::format_error(m_prog_name
, e
.what()) << "\n"
285 << ui::format_info(m_prog_name
, std::string("Type `") +
286 m_prog_name
+ " -h' for more details.")
288 errcode
= EXIT_FAILURE
;
289 } catch (const std::runtime_error
& e
) {
290 std::cerr
<< ui::format_error(m_prog_name
, std::string(e
.what()))
292 errcode
= EXIT_FAILURE
;
293 } catch (const std::exception
& e
) {
294 std::cerr
<< ui::format_error(m_prog_name
, std::string("Caught "
295 "unexpected error: ") + e
.what() + "\n" + bug
) << "\n";
296 errcode
= EXIT_FAILURE
;
298 std::cerr
<< ui::format_error(m_prog_name
, std::string("Caught "
299 "unknown error\n") + bug
) << "\n";
300 errcode
= EXIT_FAILURE
;