Path: blob/main/contrib/atf/atf-c++/detail/application.cpp
39563 views
// Copyright (c) 2007 The NetBSD Foundation, Inc.1// All rights reserved.2//3// Redistribution and use in source and binary forms, with or without4// modification, are permitted provided that the following conditions5// are met:6// 1. Redistributions of source code must retain the above copyright7// notice, this list of conditions and the following disclaimer.8// 2. Redistributions in binary form must reproduce the above copyright9// notice, this list of conditions and the following disclaimer in the10// documentation and/or other materials provided with the distribution.11//12// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND13// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,14// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF15// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.16// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY17// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE19// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS20// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER21// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR22// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN23// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.2425#include "atf-c++/detail/application.hpp"2627#if defined(HAVE_CONFIG_H)28#include "config.h"29#endif3031extern "C" {32#include <unistd.h>33}3435#include <cstdarg>36#include <cstdio>37#include <cstdlib>38#include <cstring>39#include <iostream>4041extern "C" {42#include "atf-c/defs.h"43}4445#include "atf-c++/detail/sanity.hpp"4647#if !defined(HAVE_VSNPRINTF_IN_STD)48namespace std {49using ::vsnprintf;50}51#endif // !defined(HAVE_VSNPRINTF_IN_STD)5253namespace impl = atf::application;54#define IMPL_NAME "atf::application"5556// ------------------------------------------------------------------------57// The "usage_error" class.58// ------------------------------------------------------------------------5960impl::usage_error::usage_error(const char *fmt, ...)61throw() :62std::runtime_error("usage_error; message unformatted")63{64va_list ap;6566va_start(ap, fmt);67std::vsnprintf(m_text, sizeof(m_text), fmt, ap);68va_end(ap);69}7071impl::usage_error::~usage_error(void)72throw()73{74}7576const char*77impl::usage_error::what(void)78const throw()79{80return m_text;81}8283// ------------------------------------------------------------------------84// The "application" class.85// ------------------------------------------------------------------------8687impl::option::option(char ch,88const std::string& a,89const std::string& desc) :90m_character(ch),91m_argument(a),92m_description(desc)93{94}9596bool97impl::option::operator<(const impl::option& o)98const99{100return m_character < o.m_character;101}102103impl::app::app(const std::string& description,104const std::string& manpage) :105m_argc(-1),106m_argv(NULL),107m_prog_name(NULL),108m_description(description),109m_manpage(manpage)110{111}112113impl::app::~app(void)114{115}116117bool118impl::app::inited(void)119{120return m_argc != -1;121}122123impl::app::options_set124impl::app::options(void)125{126return specific_options();127}128129std::string130impl::app::specific_args(void)131const132{133return "";134}135136impl::app::options_set137impl::app::specific_options(void)138const139{140return options_set();141}142143void144impl::app::process_option(int ch ATF_DEFS_ATTRIBUTE_UNUSED,145const char* arg ATF_DEFS_ATTRIBUTE_UNUSED)146{147}148149void150impl::app::process_options(void)151{152PRE(inited());153154std::string optstr;155#if defined(HAVE_GNU_GETOPT)156optstr += '+'; // Turn on POSIX behavior.157#endif158optstr += ':';159{160options_set opts = options();161for (options_set::const_iterator iter = opts.begin();162iter != opts.end(); iter++) {163const option& opt = (*iter);164165optstr += opt.m_character;166if (!opt.m_argument.empty())167optstr += ':';168}169}170171int ch;172const int old_opterr = ::opterr;173::opterr = 0;174while ((ch = ::getopt(m_argc, m_argv, optstr.c_str())) != -1) {175switch (ch) {176case ':':177throw usage_error("Option -%c requires an argument.",178::optopt);179180case '?':181throw usage_error("Unknown option -%c.", ::optopt);182183default:184process_option(ch, ::optarg);185}186}187m_argc -= ::optind;188m_argv += ::optind;189190// Clear getopt state just in case the test wants to use it.191opterr = old_opterr;192optind = 1;193#if defined(HAVE_OPTRESET)194optreset = 1;195#endif196}197198int199impl::app::run(int argc, char* const* argv)200{201PRE(argc > 0);202PRE(argv != NULL);203204m_argc = argc;205m_argv = argv;206207m_argv0 = m_argv[0];208209m_prog_name = std::strrchr(m_argv[0], '/');210if (m_prog_name == NULL)211m_prog_name = m_argv[0];212else213m_prog_name++;214215// Libtool workaround: if running from within the source tree (binaries216// that are not installed yet), skip the "lt-" prefix added to files in217// the ".libs" directory to show the real (not temporary) name.218if (std::strncmp(m_prog_name, "lt-", 3) == 0)219m_prog_name += 3;220221const std::string bug =222std::string("This is probably a bug in ") + m_prog_name +223" or one of the libraries it uses. Please report this problem to "224PACKAGE_BUGREPORT " and provide as many details as possible "225"describing how you got to this condition.";226227int errcode;228try {229process_options();230errcode = main();231} catch (const usage_error& e) {232std::cerr << m_prog_name << ": ERROR: " << e.what() << "\n";233std::cerr << m_prog_name << ": See " << m_manpage << " for usage "234"details.\n";235errcode = EXIT_FAILURE;236} catch (const std::runtime_error& e) {237std::cerr << m_prog_name << ": ERROR: " << e.what() << "\n";238errcode = EXIT_FAILURE;239} catch (const std::exception& e) {240std::cerr << m_prog_name << ": ERROR: Caught unexpected error: "241<< e.what() << "\n";242errcode = EXIT_FAILURE;243} catch (...) {244std::cerr << m_prog_name << ": ERROR: Caught unknown error\n";245errcode = EXIT_FAILURE;246}247return errcode;248}249250251