No empty .Rs/.Re
[netbsd-mini2440.git] / external / bsd / atf / dist / atf-c++ / application.cpp
blob8bdc3396197f2cb948c223720a60681b684235da
1 //
2 // Automated Testing Framework (atf)
3 //
4 // Copyright (c) 2007, 2008 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/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)
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 m_hflag(false),
112 m_argc(-1),
113 m_argv(NULL),
114 m_prog_name(NULL),
115 m_description(description),
116 m_manpage(manpage),
117 m_global_manpage(global_manpage)
119 atf_init_objects();
122 impl::app::~app(void)
126 bool
127 impl::app::inited(void)
129 return m_argc != -1;
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"));
137 return opts;
140 std::string
141 impl::app::specific_args(void)
142 const
144 return "";
147 impl::app::options_set
148 impl::app::specific_options(void)
149 const
151 return options_set();
154 void
155 impl::app::process_option(int ch, const char* arg)
159 void
160 impl::app::process_options(void)
162 PRE(inited());
164 std::string optstr;
165 #if defined(HAVE_GNU_GETOPT)
166 optstr += '+'; // Turn on POSIX behavior.
167 #endif
168 optstr += ':';
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())
177 optstr += ':';
181 int ch;
182 ::opterr = 0;
183 while ((ch = ::getopt(m_argc, m_argv, optstr.c_str())) != -1) {
184 switch (ch) {
185 case 'h':
186 m_hflag = true;
187 break;
189 case ':':
190 throw usage_error("Option -%c requires an argument.",
191 ::optopt);
193 case '?':
194 throw usage_error("Unknown option -%c.", ::optopt);
196 default:
197 process_option(ch, ::optarg);
200 m_argc -= ::optind;
201 m_argv += ::optind;
204 void
205 impl::app::usage(std::ostream& os)
207 PRE(inited());
209 std::string args = specific_args();
210 if (!args.empty())
211 args = " " + args;
212 os << ui::format_text_with_tag(std::string(m_prog_name) + " [options]" +
213 args, "Usage: ", false) << std::endl
214 << std::endl
215 << ui::format_text(m_description) << std::endl
216 << std::endl;
218 options_set opts = options();
219 INV(!opts.empty());
220 os << "Available options:" << std::endl;
221 size_t coldesc = 0;
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())
235 tag += " ";
236 else
237 tag += " " + opt.m_argument + " ";
238 os << ui::format_text_with_tag(opt.m_description, tag, false,
239 coldesc + 10)
240 << std::endl;
242 os << std::endl;
244 std::string gmp;
245 if (!m_global_manpage.empty())
246 gmp = " and " + m_global_manpage;
247 os << ui::format_text("For more details please see " + m_manpage +
248 gmp + ".")
249 << std::endl;
253 impl::app::run(int argc, char* const* argv)
255 PRE(argc > 0);
256 PRE(argv != NULL);
258 m_argc = argc;
259 m_argv = argv;
261 m_prog_name = std::strrchr(m_argv[0], '/');
262 if (m_prog_name == NULL)
263 m_prog_name = m_argv[0];
264 else
265 m_prog_name++;
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.";
273 int errcode;
274 try {
275 int oldargc = m_argc;
277 process_options();
279 if (m_hflag) {
280 if (oldargc != 2)
281 throw usage_error("-h must be given alone.");
283 usage(std::cout);
284 errcode = EXIT_SUCCESS;
285 } else
286 errcode = main();
287 } catch (const usage_error& e) {
288 std::cerr << ui::format_error(m_prog_name, e.what())
289 << std::endl
290 << ui::format_info(m_prog_name, std::string("Type `") +
291 m_prog_name + " -h' for more details.")
292 << std::endl;
293 errcode = EXIT_FAILURE;
294 } catch (const std::runtime_error& e) {
295 std::cerr << ui::format_error(m_prog_name, std::string(e.what()))
296 << std::endl;
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)
302 << std::endl;
303 errcode = EXIT_FAILURE;
304 } catch (...) {
305 std::cerr << ui::format_error(m_prog_name,
306 std::string("Caught unknown error\n") +
307 bug)
308 << std::endl;
309 errcode = EXIT_FAILURE;
311 return errcode;