etc/services - sync with NetBSD-8
[minix.git] / external / bsd / atf / dist / tools / application.cpp
blobf0324ab971314c122ddccf6fa85df72e67f55440
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 extern "C" {
31 #include <unistd.h>
34 #include <cassert>
35 #include <cstdarg>
36 #include <cstdio>
37 #include <cstdlib>
38 #include <cstring>
39 #include <iostream>
41 #include "application.hpp"
42 #include "ui.hpp"
44 namespace std {
45 using ::vsnprintf;
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, ...)
56 throw() :
57 std::runtime_error("usage_error; message unformatted")
59 va_list ap;
61 va_start(ap, fmt);
62 std::vsnprintf(m_text, sizeof(m_text), fmt, ap);
63 va_end(ap);
66 impl::usage_error::~usage_error(void)
67 throw()
71 const char*
72 impl::usage_error::what(void)
73 const throw()
75 return m_text;
78 // ------------------------------------------------------------------------
79 // The "application" class.
80 // ------------------------------------------------------------------------
82 impl::option::option(char ch,
83 const std::string& a,
84 const std::string& desc) :
85 m_character(ch),
86 m_argument(a),
87 m_description(desc)
91 bool
92 impl::option::operator<(const impl::option& o)
93 const
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) :
101 m_hflag(false),
102 m_argc(-1),
103 m_argv(NULL),
104 m_prog_name(NULL),
105 m_description(description),
106 m_manpage(manpage),
107 m_global_manpage(global_manpage)
111 impl::app::~app(void)
115 bool
116 impl::app::inited(void)
118 return m_argc != -1;
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"));
126 return opts;
129 std::string
130 impl::app::specific_args(void)
131 const
133 return "";
136 impl::app::options_set
137 impl::app::specific_options(void)
138 const
140 return options_set();
143 void
144 impl::app::process_option(int ch __attribute__((__unused__)),
145 const char* arg __attribute__((__unused__)))
149 void
150 impl::app::process_options(void)
152 assert(inited());
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())
163 optstr += ':';
167 int ch;
168 const int old_opterr = ::opterr;
169 ::opterr = 0;
170 while ((ch = ::getopt(m_argc, m_argv, optstr.c_str())) != -1) {
171 switch (ch) {
172 case 'h':
173 m_hflag = true;
174 break;
176 case ':':
177 throw usage_error("Option -%c requires an argument.",
178 ::optopt);
180 case '?':
181 throw usage_error("Unknown option -%c.", ::optopt);
183 default:
184 process_option(ch, ::optarg);
187 m_argc -= ::optind;
188 m_argv += ::optind;
190 // Clear getopt state just in case the test wants to use it.
191 opterr = old_opterr;
192 optind = 1;
193 optreset = 1;
196 void
197 impl::app::usage(std::ostream& os)
199 assert(inited());
201 std::string args = specific_args();
202 if (!args.empty())
203 args = " " + 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";
211 size_t coldesc = 0;
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())
225 tag += " ";
226 else
227 tag += " " + opt.m_argument + " ";
228 os << ui::format_text_with_tag(opt.m_description, tag, false,
229 coldesc + 10) << "\n";
231 os << "\n";
233 std::string gmp;
234 if (!m_global_manpage.empty())
235 gmp = " and " + m_global_manpage;
236 os << ui::format_text("For more details please see " + m_manpage +
237 gmp + ".")
238 << "\n";
242 impl::app::run(int argc, char* const* argv)
244 assert(argc > 0);
245 assert(argv != NULL);
247 m_argc = argc;
248 m_argv = argv;
250 m_argv0 = m_argv[0];
252 m_prog_name = std::strrchr(m_argv[0], '/');
253 if (m_prog_name == NULL)
254 m_prog_name = m_argv[0];
255 else
256 m_prog_name++;
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)
262 m_prog_name += 3;
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.";
269 int errcode;
270 try {
271 int oldargc = m_argc;
273 process_options();
275 if (m_hflag) {
276 if (oldargc != 2)
277 throw usage_error("-h must be given alone.");
279 usage(std::cout);
280 errcode = EXIT_SUCCESS;
281 } else
282 errcode = main();
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.")
287 << "\n";
288 errcode = EXIT_FAILURE;
289 } catch (const std::runtime_error& e) {
290 std::cerr << ui::format_error(m_prog_name, std::string(e.what()))
291 << "\n";
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;
297 } catch (...) {
298 std::cerr << ui::format_error(m_prog_name, std::string("Caught "
299 "unknown error\n") + bug) << "\n";
300 errcode = EXIT_FAILURE;
302 return errcode;