1895f502bSjmmv //
2895f502bSjmmv // Automated Testing Framework (atf)
3895f502bSjmmv //
4a551a20fSjmmv // Copyright (c) 2007 The NetBSD Foundation, Inc.
5895f502bSjmmv // All rights reserved.
6895f502bSjmmv //
7895f502bSjmmv // Redistribution and use in source and binary forms, with or without
8895f502bSjmmv // modification, are permitted provided that the following conditions
9895f502bSjmmv // are met:
10895f502bSjmmv // 1. Redistributions of source code must retain the above copyright
11895f502bSjmmv // notice, this list of conditions and the following disclaimer.
12895f502bSjmmv // 2. Redistributions in binary form must reproduce the above copyright
13895f502bSjmmv // notice, this list of conditions and the following disclaimer in the
14895f502bSjmmv // documentation and/or other materials provided with the distribution.
15895f502bSjmmv //
16895f502bSjmmv // THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17895f502bSjmmv // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18895f502bSjmmv // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19895f502bSjmmv // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20895f502bSjmmv // IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21895f502bSjmmv // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22895f502bSjmmv // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23895f502bSjmmv // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24895f502bSjmmv // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25895f502bSjmmv // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26895f502bSjmmv // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27895f502bSjmmv // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28895f502bSjmmv //
29895f502bSjmmv
30895f502bSjmmv #if defined(HAVE_CONFIG_H)
31895f502bSjmmv #include "bconfig.h"
32895f502bSjmmv #endif
33895f502bSjmmv
34895f502bSjmmv extern "C" {
35895f502bSjmmv #include <unistd.h>
36895f502bSjmmv }
37895f502bSjmmv
38895f502bSjmmv #include <cstdarg>
39895f502bSjmmv #include <cstdio>
40895f502bSjmmv #include <cstdlib>
41895f502bSjmmv #include <cstring>
42895f502bSjmmv #include <iostream>
43895f502bSjmmv
44a551a20fSjmmv extern "C" {
45a551a20fSjmmv #include "atf-c/defs.h"
46a551a20fSjmmv }
47a551a20fSjmmv
48895f502bSjmmv #include "application.hpp"
49895f502bSjmmv #include "sanity.hpp"
50895f502bSjmmv
51895f502bSjmmv #if !defined(HAVE_VSNPRINTF_IN_STD)
52895f502bSjmmv namespace std {
53895f502bSjmmv using ::vsnprintf;
54895f502bSjmmv }
55895f502bSjmmv #endif // !defined(HAVE_VSNPRINTF_IN_STD)
56895f502bSjmmv
57895f502bSjmmv namespace impl = atf::application;
58895f502bSjmmv #define IMPL_NAME "atf::application"
59895f502bSjmmv
60895f502bSjmmv // ------------------------------------------------------------------------
61895f502bSjmmv // The "usage_error" class.
62895f502bSjmmv // ------------------------------------------------------------------------
63895f502bSjmmv
usage_error(const char * fmt,...)64895f502bSjmmv impl::usage_error::usage_error(const char *fmt, ...)
65895f502bSjmmv throw() :
66895f502bSjmmv std::runtime_error("usage_error; message unformatted")
67895f502bSjmmv {
68895f502bSjmmv va_list ap;
69895f502bSjmmv
70895f502bSjmmv va_start(ap, fmt);
71895f502bSjmmv std::vsnprintf(m_text, sizeof(m_text), fmt, ap);
72895f502bSjmmv va_end(ap);
73895f502bSjmmv }
74895f502bSjmmv
~usage_error(void)75895f502bSjmmv impl::usage_error::~usage_error(void)
76895f502bSjmmv throw()
77895f502bSjmmv {
78895f502bSjmmv }
79895f502bSjmmv
80895f502bSjmmv const char*
what(void) const81895f502bSjmmv impl::usage_error::what(void)
82895f502bSjmmv const throw()
83895f502bSjmmv {
84895f502bSjmmv return m_text;
85895f502bSjmmv }
86895f502bSjmmv
87895f502bSjmmv // ------------------------------------------------------------------------
88895f502bSjmmv // The "application" class.
89895f502bSjmmv // ------------------------------------------------------------------------
90895f502bSjmmv
option(char ch,const std::string & a,const std::string & desc)91895f502bSjmmv impl::option::option(char ch,
92895f502bSjmmv const std::string& a,
93895f502bSjmmv const std::string& desc) :
94895f502bSjmmv m_character(ch),
95895f502bSjmmv m_argument(a),
96895f502bSjmmv m_description(desc)
97895f502bSjmmv {
98895f502bSjmmv }
99895f502bSjmmv
100895f502bSjmmv bool
operator <(const impl::option & o) const101895f502bSjmmv impl::option::operator<(const impl::option& o)
102895f502bSjmmv const
103895f502bSjmmv {
104895f502bSjmmv return m_character < o.m_character;
105895f502bSjmmv }
106895f502bSjmmv
app(const std::string & description,const std::string & manpage)107895f502bSjmmv impl::app::app(const std::string& description,
108*d780102eSjmmv const std::string& manpage) :
109895f502bSjmmv m_argc(-1),
110895f502bSjmmv m_argv(NULL),
111895f502bSjmmv m_prog_name(NULL),
112895f502bSjmmv m_description(description),
113*d780102eSjmmv m_manpage(manpage)
114895f502bSjmmv {
115895f502bSjmmv }
116895f502bSjmmv
~app(void)117895f502bSjmmv impl::app::~app(void)
118895f502bSjmmv {
119895f502bSjmmv }
120895f502bSjmmv
121895f502bSjmmv bool
inited(void)122895f502bSjmmv impl::app::inited(void)
123895f502bSjmmv {
124895f502bSjmmv return m_argc != -1;
125895f502bSjmmv }
126895f502bSjmmv
127895f502bSjmmv impl::app::options_set
options(void)128895f502bSjmmv impl::app::options(void)
129895f502bSjmmv {
130*d780102eSjmmv return specific_options();
131895f502bSjmmv }
132895f502bSjmmv
133895f502bSjmmv std::string
specific_args(void) const134895f502bSjmmv impl::app::specific_args(void)
135895f502bSjmmv const
136895f502bSjmmv {
137895f502bSjmmv return "";
138895f502bSjmmv }
139895f502bSjmmv
140895f502bSjmmv impl::app::options_set
specific_options(void) const141895f502bSjmmv impl::app::specific_options(void)
142895f502bSjmmv const
143895f502bSjmmv {
144895f502bSjmmv return options_set();
145895f502bSjmmv }
146895f502bSjmmv
147895f502bSjmmv void
process_option(int ch ATF_DEFS_ATTRIBUTE_UNUSED,const char * arg ATF_DEFS_ATTRIBUTE_UNUSED)148a551a20fSjmmv impl::app::process_option(int ch ATF_DEFS_ATTRIBUTE_UNUSED,
149a551a20fSjmmv const char* arg ATF_DEFS_ATTRIBUTE_UNUSED)
150895f502bSjmmv {
151895f502bSjmmv }
152895f502bSjmmv
153895f502bSjmmv void
process_options(void)154895f502bSjmmv impl::app::process_options(void)
155895f502bSjmmv {
156895f502bSjmmv PRE(inited());
157895f502bSjmmv
158895f502bSjmmv std::string optstr;
159895f502bSjmmv #if defined(HAVE_GNU_GETOPT)
160895f502bSjmmv optstr += '+'; // Turn on POSIX behavior.
161895f502bSjmmv #endif
162895f502bSjmmv optstr += ':';
163895f502bSjmmv {
164895f502bSjmmv options_set opts = options();
165895f502bSjmmv for (options_set::const_iterator iter = opts.begin();
166895f502bSjmmv iter != opts.end(); iter++) {
167895f502bSjmmv const option& opt = (*iter);
168895f502bSjmmv
169895f502bSjmmv optstr += opt.m_character;
170895f502bSjmmv if (!opt.m_argument.empty())
171895f502bSjmmv optstr += ':';
172895f502bSjmmv }
173895f502bSjmmv }
174895f502bSjmmv
175895f502bSjmmv int ch;
176eb215e31Sjmmv const int old_opterr = ::opterr;
177895f502bSjmmv ::opterr = 0;
178895f502bSjmmv while ((ch = ::getopt(m_argc, m_argv, optstr.c_str())) != -1) {
179895f502bSjmmv switch (ch) {
180895f502bSjmmv case ':':
181895f502bSjmmv throw usage_error("Option -%c requires an argument.",
182895f502bSjmmv ::optopt);
183895f502bSjmmv
184895f502bSjmmv case '?':
185895f502bSjmmv throw usage_error("Unknown option -%c.", ::optopt);
186895f502bSjmmv
187895f502bSjmmv default:
188895f502bSjmmv process_option(ch, ::optarg);
189895f502bSjmmv }
190895f502bSjmmv }
191895f502bSjmmv m_argc -= ::optind;
192895f502bSjmmv m_argv += ::optind;
193895f502bSjmmv
194895f502bSjmmv // Clear getopt state just in case the test wants to use it.
195eb215e31Sjmmv opterr = old_opterr;
196895f502bSjmmv optind = 1;
197895f502bSjmmv #if defined(HAVE_OPTRESET)
198895f502bSjmmv optreset = 1;
199895f502bSjmmv #endif
200895f502bSjmmv }
201895f502bSjmmv
202895f502bSjmmv int
run(int argc,char * const * argv)203895f502bSjmmv impl::app::run(int argc, char* const* argv)
204895f502bSjmmv {
205895f502bSjmmv PRE(argc > 0);
206895f502bSjmmv PRE(argv != NULL);
207895f502bSjmmv
208895f502bSjmmv m_argc = argc;
209895f502bSjmmv m_argv = argv;
210895f502bSjmmv
211895f502bSjmmv m_argv0 = m_argv[0];
212895f502bSjmmv
213895f502bSjmmv m_prog_name = std::strrchr(m_argv[0], '/');
214895f502bSjmmv if (m_prog_name == NULL)
215895f502bSjmmv m_prog_name = m_argv[0];
216895f502bSjmmv else
217895f502bSjmmv m_prog_name++;
218895f502bSjmmv
219895f502bSjmmv // Libtool workaround: if running from within the source tree (binaries
220895f502bSjmmv // that are not installed yet), skip the "lt-" prefix added to files in
221895f502bSjmmv // the ".libs" directory to show the real (not temporary) name.
222895f502bSjmmv if (std::strncmp(m_prog_name, "lt-", 3) == 0)
223895f502bSjmmv m_prog_name += 3;
224895f502bSjmmv
225895f502bSjmmv const std::string bug =
226895f502bSjmmv std::string("This is probably a bug in ") + m_prog_name +
227895f502bSjmmv " or one of the libraries it uses. Please report this problem to "
228895f502bSjmmv PACKAGE_BUGREPORT " and provide as many details as possible "
229895f502bSjmmv "describing how you got to this condition.";
230895f502bSjmmv
231895f502bSjmmv int errcode;
232895f502bSjmmv try {
233895f502bSjmmv process_options();
234895f502bSjmmv errcode = main();
235895f502bSjmmv } catch (const usage_error& e) {
236895f502bSjmmv std::cerr << m_prog_name << ": ERROR: " << e.what() << "\n";
237895f502bSjmmv std::cerr << m_prog_name << ": See " << m_manpage << " for usage "
238895f502bSjmmv "details.\n";
239895f502bSjmmv errcode = EXIT_FAILURE;
240895f502bSjmmv } catch (const std::runtime_error& e) {
241895f502bSjmmv std::cerr << m_prog_name << ": ERROR: " << e.what() << "\n";
242895f502bSjmmv errcode = EXIT_FAILURE;
243895f502bSjmmv } catch (const std::exception& e) {
244895f502bSjmmv std::cerr << m_prog_name << ": ERROR: Caught unexpected error: "
245895f502bSjmmv << e.what() << "\n";
246895f502bSjmmv errcode = EXIT_FAILURE;
247895f502bSjmmv } catch (...) {
248895f502bSjmmv std::cerr << m_prog_name << ": ERROR: Caught unknown error\n";
249895f502bSjmmv errcode = EXIT_FAILURE;
250895f502bSjmmv }
251895f502bSjmmv return errcode;
252895f502bSjmmv }
253