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. 15// 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. 28// 29 30#if defined(HAVE_CONFIG_H) 31#include "bconfig.h" 32#endif 33 34extern "C" { 35#include <unistd.h> 36} 37 38#include <cstdarg> 39#include <cstdio> 40#include <cstdlib> 41#include <cstring> 42#include <iostream> 43 44extern "C" { 45#include "atf-c/defs.h" 46} 47 48#include "application.hpp" 49#include "sanity.hpp" 50 51#if !defined(HAVE_VSNPRINTF_IN_STD) 52namespace std { 53using ::vsnprintf; 54} 55#endif // !defined(HAVE_VSNPRINTF_IN_STD) 56 57namespace impl = atf::application; 58#define IMPL_NAME "atf::application" 59 60// ------------------------------------------------------------------------ 61// The "usage_error" class. 62// ------------------------------------------------------------------------ 63 64impl::usage_error::usage_error(const char *fmt, ...) 65 throw() : 66 std::runtime_error("usage_error; message unformatted") 67{ 68 va_list ap; 69 70 va_start(ap, fmt); 71 std::vsnprintf(m_text, sizeof(m_text), fmt, ap); 72 va_end(ap); 73} 74 75impl::usage_error::~usage_error(void) 76 throw() 77{ 78} 79 80const char* 81impl::usage_error::what(void) 82 const throw() 83{ 84 return m_text; 85} 86 87// ------------------------------------------------------------------------ 88// The "application" class. 89// ------------------------------------------------------------------------ 90 91impl::option::option(char ch, 92 const std::string& a, 93 const std::string& desc) : 94 m_character(ch), 95 m_argument(a), 96 m_description(desc) 97{ 98} 99 100bool 101impl::option::operator<(const impl::option& o) 102 const 103{ 104 return m_character < o.m_character; 105} 106 107impl::app::app(const std::string& description, 108 const std::string& manpage) : 109 m_argc(-1), 110 m_argv(NULL), 111 m_prog_name(NULL), 112 m_description(description), 113 m_manpage(manpage) 114{ 115} 116 117impl::app::~app(void) 118{ 119} 120 121bool 122impl::app::inited(void) 123{ 124 return m_argc != -1; 125} 126 127impl::app::options_set 128impl::app::options(void) 129{ 130 return specific_options(); 131} 132 133std::string 134impl::app::specific_args(void) 135 const 136{ 137 return ""; 138} 139 140impl::app::options_set 141impl::app::specific_options(void) 142 const 143{ 144 return options_set(); 145} 146 147void 148impl::app::process_option(int ch ATF_DEFS_ATTRIBUTE_UNUSED, 149 const char* arg ATF_DEFS_ATTRIBUTE_UNUSED) 150{ 151} 152 153void 154impl::app::process_options(void) 155{ 156 PRE(inited()); 157 158 std::string optstr; 159#if defined(HAVE_GNU_GETOPT) 160 optstr += '+'; // Turn on POSIX behavior. 161#endif 162 optstr += ':'; 163 { 164 options_set opts = options(); 165 for (options_set::const_iterator iter = opts.begin(); 166 iter != opts.end(); iter++) { 167 const option& opt = (*iter); 168 169 optstr += opt.m_character; 170 if (!opt.m_argument.empty()) 171 optstr += ':'; 172 } 173 } 174 175 int ch; 176 const int old_opterr = ::opterr; 177 ::opterr = 0; 178 while ((ch = ::getopt(m_argc, m_argv, optstr.c_str())) != -1) { 179 switch (ch) { 180 case ':': 181 throw usage_error("Option -%c requires an argument.", 182 ::optopt); 183 184 case '?': 185 throw usage_error("Unknown option -%c.", ::optopt); 186 187 default: 188 process_option(ch, ::optarg); 189 } 190 } 191 m_argc -= ::optind; 192 m_argv += ::optind; 193 194 // Clear getopt state just in case the test wants to use it. 195 opterr = old_opterr; 196 optind = 1; 197#if defined(HAVE_OPTRESET) 198 optreset = 1; 199#endif 200} 201 202int 203impl::app::run(int argc, char* const* argv) 204{ 205 PRE(argc > 0); 206 PRE(argv != NULL); 207 208 m_argc = argc; 209 m_argv = argv; 210 211 m_argv0 = m_argv[0]; 212 213 m_prog_name = std::strrchr(m_argv[0], '/'); 214 if (m_prog_name == NULL) 215 m_prog_name = m_argv[0]; 216 else 217 m_prog_name++; 218 219 // Libtool workaround: if running from within the source tree (binaries 220 // that are not installed yet), skip the "lt-" prefix added to files in 221 // the ".libs" directory to show the real (not temporary) name. 222 if (std::strncmp(m_prog_name, "lt-", 3) == 0) 223 m_prog_name += 3; 224 225 const std::string bug = 226 std::string("This is probably a bug in ") + m_prog_name + 227 " or one of the libraries it uses. Please report this problem to " 228 PACKAGE_BUGREPORT " and provide as many details as possible " 229 "describing how you got to this condition."; 230 231 int errcode; 232 try { 233 process_options(); 234 errcode = main(); 235 } catch (const usage_error& e) { 236 std::cerr << m_prog_name << ": ERROR: " << e.what() << "\n"; 237 std::cerr << m_prog_name << ": See " << m_manpage << " for usage " 238 "details.\n"; 239 errcode = EXIT_FAILURE; 240 } catch (const std::runtime_error& e) { 241 std::cerr << m_prog_name << ": ERROR: " << e.what() << "\n"; 242 errcode = EXIT_FAILURE; 243 } catch (const std::exception& e) { 244 std::cerr << m_prog_name << ": ERROR: Caught unexpected error: " 245 << e.what() << "\n"; 246 errcode = EXIT_FAILURE; 247 } catch (...) { 248 std::cerr << m_prog_name << ": ERROR: Caught unknown error\n"; 249 errcode = EXIT_FAILURE; 250 } 251 return errcode; 252} 253