xref: /netbsd-src/external/bsd/atf/dist/atf-c++/detail/application.cpp (revision d780102efefa02003390cc43ea410dbd0ebb4a85)
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