tools/llvm: Do not build with symbols
[minix3.git] / external / bsd / atf / dist / atf-c++ / detail / application.cpp
blob878b010bcde8770adf6e1b3b8a530ce944e258a0
1 //
2 // Automated Testing Framework (atf)
3 //
4 // Copyright (c) 2007 The NetBSD Foundation, Inc.
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
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)
31 #include "bconfig.h"
32 #endif
34 extern "C" {
35 #include <unistd.h>
38 #include <cstdarg>
39 #include <cstdio>
40 #include <cstdlib>
41 #include <cstring>
42 #include <iostream>
44 extern "C" {
45 #include "atf-c/defs.h"
48 #include "application.hpp"
49 #include "sanity.hpp"
50 #include "ui.hpp"
52 #if !defined(HAVE_VSNPRINTF_IN_STD)
53 namespace std {
54 using ::vsnprintf;
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, ...)
66 throw() :
67 std::runtime_error("usage_error; message unformatted")
69 va_list ap;
71 va_start(ap, fmt);
72 std::vsnprintf(m_text, sizeof(m_text), fmt, ap);
73 va_end(ap);
76 impl::usage_error::~usage_error(void)
77 throw()
81 const char*
82 impl::usage_error::what(void)
83 const throw()
85 return m_text;
88 // ------------------------------------------------------------------------
89 // The "application" class.
90 // ------------------------------------------------------------------------
92 impl::option::option(char ch,
93 const std::string& a,
94 const std::string& desc) :
95 m_character(ch),
96 m_argument(a),
97 m_description(desc)
101 bool
102 impl::option::operator<(const impl::option& o)
103 const
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,
111 const bool use_ui) :
112 m_hflag(false),
113 m_argc(-1),
114 m_argv(NULL),
115 m_prog_name(NULL),
116 m_description(description),
117 m_manpage(manpage),
118 m_global_manpage(global_manpage),
119 m_use_ui(use_ui)
123 impl::app::~app(void)
127 bool
128 impl::app::inited(void)
130 return m_argc != -1;
133 impl::app::options_set
134 impl::app::options(void)
136 options_set opts = specific_options();
137 if (m_use_ui) {
138 opts.insert(option('h', "", "Shows this help message"));
140 return opts;
143 std::string
144 impl::app::specific_args(void)
145 const
147 return "";
150 impl::app::options_set
151 impl::app::specific_options(void)
152 const
154 return options_set();
157 void
158 impl::app::process_option(int ch ATF_DEFS_ATTRIBUTE_UNUSED,
159 const char* arg ATF_DEFS_ATTRIBUTE_UNUSED)
163 void
164 impl::app::process_options(void)
166 PRE(inited());
168 std::string optstr;
169 #if defined(HAVE_GNU_GETOPT)
170 optstr += '+'; // Turn on POSIX behavior.
171 #endif
172 optstr += ':';
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())
181 optstr += ':';
185 int ch;
186 const int old_opterr = ::opterr;
187 ::opterr = 0;
188 while ((ch = ::getopt(m_argc, m_argv, optstr.c_str())) != -1) {
189 switch (ch) {
190 case 'h':
191 INV(m_use_ui);
192 m_hflag = true;
193 break;
195 case ':':
196 throw usage_error("Option -%c requires an argument.",
197 ::optopt);
199 case '?':
200 throw usage_error("Unknown option -%c.", ::optopt);
202 default:
203 process_option(ch, ::optarg);
206 m_argc -= ::optind;
207 m_argv += ::optind;
209 // Clear getopt state just in case the test wants to use it.
210 opterr = old_opterr;
211 optind = 1;
212 #if defined(HAVE_OPTRESET)
213 optreset = 1;
214 #endif
217 void
218 impl::app::usage(std::ostream& os)
220 PRE(inited());
222 std::string args = specific_args();
223 if (!args.empty())
224 args = " " + 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();
230 INV(!opts.empty());
231 os << "Available options:\n";
232 size_t coldesc = 0;
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())
246 tag += " ";
247 else
248 tag += " " + opt.m_argument + " ";
249 os << ui::format_text_with_tag(opt.m_description, tag, false,
250 coldesc + 10) << "\n";
252 os << "\n";
254 std::string gmp;
255 if (!m_global_manpage.empty())
256 gmp = " and " + m_global_manpage;
257 os << ui::format_text("For more details please see " + m_manpage +
258 gmp + ".")
259 << "\n";
263 impl::app::run(int argc, char* const* argv)
265 PRE(argc > 0);
266 PRE(argv != NULL);
268 m_argc = argc;
269 m_argv = argv;
271 m_argv0 = m_argv[0];
273 m_prog_name = std::strrchr(m_argv[0], '/');
274 if (m_prog_name == NULL)
275 m_prog_name = m_argv[0];
276 else
277 m_prog_name++;
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)
283 m_prog_name += 3;
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.";
291 int errcode;
292 try {
293 int oldargc = m_argc;
295 process_options();
297 if (m_hflag) {
298 INV(m_use_ui);
299 if (oldargc != 2)
300 throw usage_error("-h must be given alone.");
302 usage(std::cout);
303 errcode = EXIT_SUCCESS;
304 } else
305 errcode = main();
306 } catch (const usage_error& e) {
307 if (m_use_ui) {
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.")
311 << "\n";
312 } else {
313 std::cerr << m_prog_name << ": ERROR: " << e.what() << "\n";
314 std::cerr << m_prog_name << ": See " << m_manpage << " for usage "
315 "details.\n";
317 errcode = EXIT_FAILURE;
318 } catch (const std::runtime_error& e) {
319 if (m_use_ui) {
320 std::cerr << ui::format_error(m_prog_name, std::string(e.what()))
321 << "\n";
322 } else {
323 std::cerr << m_prog_name << ": ERROR: " << e.what() << "\n";
325 errcode = EXIT_FAILURE;
326 } catch (const std::exception& e) {
327 if (m_use_ui) {
328 std::cerr << ui::format_error(m_prog_name, std::string("Caught "
329 "unexpected error: ") + e.what() + "\n" + bug) << "\n";
330 } else {
331 std::cerr << m_prog_name << ": ERROR: Caught unexpected error: "
332 << e.what() << "\n";
334 errcode = EXIT_FAILURE;
335 } catch (...) {
336 if (m_use_ui) {
337 std::cerr << ui::format_error(m_prog_name, std::string("Caught "
338 "unknown error\n") + bug) << "\n";
339 } else {
340 std::cerr << m_prog_name << ": ERROR: Caught unknown error\n";
342 errcode = EXIT_FAILURE;
344 return errcode;