1240116Smarcel// Copyright (c) 2007 The NetBSD Foundation, Inc. 2240116Smarcel// All rights reserved. 3240116Smarcel// 4240116Smarcel// Redistribution and use in source and binary forms, with or without 5240116Smarcel// modification, are permitted provided that the following conditions 6240116Smarcel// are met: 7240116Smarcel// 1. Redistributions of source code must retain the above copyright 8240116Smarcel// notice, this list of conditions and the following disclaimer. 9240116Smarcel// 2. Redistributions in binary form must reproduce the above copyright 10240116Smarcel// notice, this list of conditions and the following disclaimer in the 11240116Smarcel// documentation and/or other materials provided with the distribution. 12240116Smarcel// 13240116Smarcel// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 14240116Smarcel// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 15240116Smarcel// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 16240116Smarcel// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17240116Smarcel// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 18240116Smarcel// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19240116Smarcel// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 20240116Smarcel// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21240116Smarcel// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 22240116Smarcel// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23240116Smarcel// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 24240116Smarcel// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25240116Smarcel 26273929Sjmmv#include "atf-c++/detail/application.hpp" 27273929Sjmmv 28240116Smarcel#if defined(HAVE_CONFIG_H) 29273929Sjmmv#include "config.h" 30240116Smarcel#endif 31240116Smarcel 32240116Smarcelextern "C" { 33240116Smarcel#include <unistd.h> 34240116Smarcel} 35240116Smarcel 36240116Smarcel#include <cstdarg> 37240116Smarcel#include <cstdio> 38240116Smarcel#include <cstdlib> 39240116Smarcel#include <cstring> 40240116Smarcel#include <iostream> 41240116Smarcel 42240116Smarcelextern "C" { 43240116Smarcel#include "atf-c/defs.h" 44240116Smarcel} 45240116Smarcel 46273929Sjmmv#include "atf-c++/detail/sanity.hpp" 47240116Smarcel 48240116Smarcel#if !defined(HAVE_VSNPRINTF_IN_STD) 49240116Smarcelnamespace std { 50240116Smarcelusing ::vsnprintf; 51240116Smarcel} 52240116Smarcel#endif // !defined(HAVE_VSNPRINTF_IN_STD) 53240116Smarcel 54240116Smarcelnamespace impl = atf::application; 55240116Smarcel#define IMPL_NAME "atf::application" 56240116Smarcel 57240116Smarcel// ------------------------------------------------------------------------ 58240116Smarcel// The "usage_error" class. 59240116Smarcel// ------------------------------------------------------------------------ 60240116Smarcel 61240116Smarcelimpl::usage_error::usage_error(const char *fmt, ...) 62240116Smarcel throw() : 63240116Smarcel std::runtime_error("usage_error; message unformatted") 64240116Smarcel{ 65240116Smarcel va_list ap; 66240116Smarcel 67240116Smarcel va_start(ap, fmt); 68240116Smarcel std::vsnprintf(m_text, sizeof(m_text), fmt, ap); 69240116Smarcel va_end(ap); 70240116Smarcel} 71240116Smarcel 72240116Smarcelimpl::usage_error::~usage_error(void) 73240116Smarcel throw() 74240116Smarcel{ 75240116Smarcel} 76240116Smarcel 77240116Smarcelconst char* 78240116Smarcelimpl::usage_error::what(void) 79240116Smarcel const throw() 80240116Smarcel{ 81240116Smarcel return m_text; 82240116Smarcel} 83240116Smarcel 84240116Smarcel// ------------------------------------------------------------------------ 85240116Smarcel// The "application" class. 86240116Smarcel// ------------------------------------------------------------------------ 87240116Smarcel 88240116Smarcelimpl::option::option(char ch, 89240116Smarcel const std::string& a, 90240116Smarcel const std::string& desc) : 91240116Smarcel m_character(ch), 92240116Smarcel m_argument(a), 93240116Smarcel m_description(desc) 94240116Smarcel{ 95240116Smarcel} 96240116Smarcel 97240116Smarcelbool 98240116Smarcelimpl::option::operator<(const impl::option& o) 99240116Smarcel const 100240116Smarcel{ 101240116Smarcel return m_character < o.m_character; 102240116Smarcel} 103240116Smarcel 104240116Smarcelimpl::app::app(const std::string& description, 105261897Sjmmv const std::string& manpage) : 106240116Smarcel m_argc(-1), 107240116Smarcel m_argv(NULL), 108240116Smarcel m_prog_name(NULL), 109240116Smarcel m_description(description), 110261897Sjmmv m_manpage(manpage) 111240116Smarcel{ 112240116Smarcel} 113240116Smarcel 114240116Smarcelimpl::app::~app(void) 115240116Smarcel{ 116240116Smarcel} 117240116Smarcel 118240116Smarcelbool 119240116Smarcelimpl::app::inited(void) 120240116Smarcel{ 121240116Smarcel return m_argc != -1; 122240116Smarcel} 123240116Smarcel 124240116Smarcelimpl::app::options_set 125240116Smarcelimpl::app::options(void) 126240116Smarcel{ 127261897Sjmmv return specific_options(); 128240116Smarcel} 129240116Smarcel 130240116Smarcelstd::string 131240116Smarcelimpl::app::specific_args(void) 132240116Smarcel const 133240116Smarcel{ 134240116Smarcel return ""; 135240116Smarcel} 136240116Smarcel 137240116Smarcelimpl::app::options_set 138240116Smarcelimpl::app::specific_options(void) 139240116Smarcel const 140240116Smarcel{ 141240116Smarcel return options_set(); 142240116Smarcel} 143240116Smarcel 144240116Smarcelvoid 145240116Smarcelimpl::app::process_option(int ch ATF_DEFS_ATTRIBUTE_UNUSED, 146240116Smarcel const char* arg ATF_DEFS_ATTRIBUTE_UNUSED) 147240116Smarcel{ 148240116Smarcel} 149240116Smarcel 150240116Smarcelvoid 151240116Smarcelimpl::app::process_options(void) 152240116Smarcel{ 153240116Smarcel PRE(inited()); 154240116Smarcel 155240116Smarcel std::string optstr; 156240116Smarcel#if defined(HAVE_GNU_GETOPT) 157240116Smarcel optstr += '+'; // Turn on POSIX behavior. 158240116Smarcel#endif 159240116Smarcel optstr += ':'; 160240116Smarcel { 161240116Smarcel options_set opts = options(); 162240116Smarcel for (options_set::const_iterator iter = opts.begin(); 163240116Smarcel iter != opts.end(); iter++) { 164240116Smarcel const option& opt = (*iter); 165240116Smarcel 166240116Smarcel optstr += opt.m_character; 167240116Smarcel if (!opt.m_argument.empty()) 168240116Smarcel optstr += ':'; 169240116Smarcel } 170240116Smarcel } 171240116Smarcel 172240116Smarcel int ch; 173240116Smarcel const int old_opterr = ::opterr; 174240116Smarcel ::opterr = 0; 175240116Smarcel while ((ch = ::getopt(m_argc, m_argv, optstr.c_str())) != -1) { 176240116Smarcel switch (ch) { 177240116Smarcel case ':': 178240116Smarcel throw usage_error("Option -%c requires an argument.", 179240116Smarcel ::optopt); 180240116Smarcel 181240116Smarcel case '?': 182240116Smarcel throw usage_error("Unknown option -%c.", ::optopt); 183240116Smarcel 184240116Smarcel default: 185240116Smarcel process_option(ch, ::optarg); 186240116Smarcel } 187240116Smarcel } 188240116Smarcel m_argc -= ::optind; 189240116Smarcel m_argv += ::optind; 190240116Smarcel 191240116Smarcel // Clear getopt state just in case the test wants to use it. 192240116Smarcel opterr = old_opterr; 193240116Smarcel optind = 1; 194240116Smarcel#if defined(HAVE_OPTRESET) 195240116Smarcel optreset = 1; 196240116Smarcel#endif 197240116Smarcel} 198240116Smarcel 199240116Smarcelint 200240116Smarcelimpl::app::run(int argc, char* const* argv) 201240116Smarcel{ 202240116Smarcel PRE(argc > 0); 203240116Smarcel PRE(argv != NULL); 204240116Smarcel 205240116Smarcel m_argc = argc; 206240116Smarcel m_argv = argv; 207240116Smarcel 208240116Smarcel m_argv0 = m_argv[0]; 209240116Smarcel 210240116Smarcel m_prog_name = std::strrchr(m_argv[0], '/'); 211240116Smarcel if (m_prog_name == NULL) 212240116Smarcel m_prog_name = m_argv[0]; 213240116Smarcel else 214240116Smarcel m_prog_name++; 215240116Smarcel 216240116Smarcel // Libtool workaround: if running from within the source tree (binaries 217240116Smarcel // that are not installed yet), skip the "lt-" prefix added to files in 218240116Smarcel // the ".libs" directory to show the real (not temporary) name. 219240116Smarcel if (std::strncmp(m_prog_name, "lt-", 3) == 0) 220240116Smarcel m_prog_name += 3; 221240116Smarcel 222240116Smarcel const std::string bug = 223240116Smarcel std::string("This is probably a bug in ") + m_prog_name + 224240116Smarcel " or one of the libraries it uses. Please report this problem to " 225240116Smarcel PACKAGE_BUGREPORT " and provide as many details as possible " 226240116Smarcel "describing how you got to this condition."; 227240116Smarcel 228240116Smarcel int errcode; 229240116Smarcel try { 230240116Smarcel process_options(); 231261897Sjmmv errcode = main(); 232240116Smarcel } catch (const usage_error& e) { 233261897Sjmmv std::cerr << m_prog_name << ": ERROR: " << e.what() << "\n"; 234261897Sjmmv std::cerr << m_prog_name << ": See " << m_manpage << " for usage " 235261897Sjmmv "details.\n"; 236240116Smarcel errcode = EXIT_FAILURE; 237240116Smarcel } catch (const std::runtime_error& e) { 238261897Sjmmv std::cerr << m_prog_name << ": ERROR: " << e.what() << "\n"; 239240116Smarcel errcode = EXIT_FAILURE; 240240116Smarcel } catch (const std::exception& e) { 241261897Sjmmv std::cerr << m_prog_name << ": ERROR: Caught unexpected error: " 242261897Sjmmv << e.what() << "\n"; 243240116Smarcel errcode = EXIT_FAILURE; 244240116Smarcel } catch (...) { 245261897Sjmmv std::cerr << m_prog_name << ": ERROR: Caught unknown error\n"; 246240116Smarcel errcode = EXIT_FAILURE; 247240116Smarcel } 248240116Smarcel return errcode; 249240116Smarcel} 250