Go back to Richel Bilderbeek's homepage.

Go back to Richel Bilderbeek's C++ page.

 

 

 

 

 

(C++) Help

 

STLQt CreatorLubuntu

 

Help is a class to display help information in a command-line application.

Technical facts

 

 

 

 

 

 

./CppHelp/CppHelp.pri

 

INCLUDEPATH += \
    ../../Classes/CppHelp

SOURCES += \
    ../../Classes/CppHelp/help.cpp

HEADERS  += \
    ../../Classes/CppHelp/help.h

OTHER_FILES += \
    ../../Classes/CppHelp/Licence.txt

 

 

 

 

 

./CppHelp/help.h

 

//---------------------------------------------------------------------------
/*
Help, class for a program its help information
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppHelp.htm
//---------------------------------------------------------------------------
#ifndef RIBI_HELP_H
#define RIBI_HELP_H

#include <iosfwd>
#include <string>
#include <vector>

namespace ribi {

///Help is used to manage a help screen its info
///Help always has some default options, as used by each MenuDialog
struct Help
{
  //Help options
  struct Option
  {
    explicit Option(
      const char option_short,
      const std::string& option_long,
      const std::string& option_description);
    char m_short;              // a
    std::string m_long;        // about
    std::string m_description; // displays the about information
  };
  explicit Help(
    const std::string& program_name,
    const std::string& program_description,
    const std::vector<Option>& options,
    const std::vector<std::string> example_uses
  );

  const std::vector<std::string>& GetExampleUses() const noexcept { return m_example_uses; }
  const std::vector<Option>& GetOptions() const noexcept { return  m_options; }
  const std::string& GetProgramDescription() const noexcept { return  m_program_description; }
  const std::string& GetProgramName() const noexcept { return  m_program_name; }

  static std::string GetVersion() noexcept;
  static std::vector<std::string> GetVersionHistory() noexcept;

  #ifndef NDEBUG
  static void Test() noexcept;
  #endif

  private:

  // { "ProjectRichelBilderbeek --about", "ProjectRichelBilderbeek ToolHometrainer Exercise.txt" }
  const std::vector<std::string> m_example_uses;
  const std::vector<Option> m_options;

  //RichelBilderbeek's work
  const std::string m_program_description;

  //ProjectRichelBilderbeek
  const std::string m_program_name;

  static const std::vector<Option> AddDefaultOptions(const std::vector<Option>& options);

};

std::ostream& operator<<(std::ostream& os, const Help& help);

} //~namespace ribi

#endif // RIBI_HELP_H

 

 

 

 

 

./CppHelp/help.cpp

 

//---------------------------------------------------------------------------
/*
Help, class for a program its help information
Copyright (C) 2013-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppHelp.htm
//---------------------------------------------------------------------------
#include "help.h"

#include <algorithm>
#include <cassert>
#include <iostream>

#include "testtimer.h"
#include "trace.h"

ribi::Help::Option::Option(
  const char option_short,
  const std::string& option_long,
  const std::string& option_description)
  : m_short(option_short),
    m_long(option_long),
    m_description(option_description)
{
  #ifndef NDEBUG
  const int max_chars_per_line = 80;
  const int chars_for_padding = 7;
  const int max_chars = max_chars_per_line - chars_for_padding;
  const int chars_used = static_cast<int>(1 + m_long.size() + m_description.size());
  if (chars_used > max_chars)
  {
    TRACE("ERROR");
    TRACE(chars_used);
    TRACE(max_chars);
    TRACE(option_short);
    TRACE(option_long);
    TRACE(option_description);
  }
  assert(chars_used <= max_chars && "Options must be kept short to fit on a line");
  //os << "-" << p.m_short << ", --" << p.m_long << "  " << p.m_description << '\n';
  #endif
}


ribi::Help::Help(
  const std::string& program_name,
  const std::string& program_description,
  const std::vector<Option>& options,
  const std::vector<std::string> example_uses)
  : m_example_uses(example_uses),
    m_options(AddDefaultOptions(options)),
    m_program_description(program_description),
    m_program_name(program_name)
{
  #ifndef NDEBUG
  Test();

  //checks if there are no short or long option occurring twice
  const std::size_t sz = m_options.size();
  for (std::size_t i=0; i!=sz-1; ++i)
  {
    const Option& a { m_options[i] };
    for (std::size_t j=i+1; j!=sz; ++j)
    {
      assert(j < m_options.size());
      const Option& b { m_options[j] };
      if (a.m_short == b.m_short
        || a.m_long == b.m_long)
      {
        TRACE(a.m_short);
        TRACE(a.m_long);
        TRACE(a.m_description);
        TRACE(b.m_short);
        TRACE(b.m_long);
        TRACE(b.m_description);
      }
      assert(a.m_short != b.m_short
        && "Every short option must be unique");
      assert(a.m_long != b.m_long
        && "Every long option must be unique");
    }
  }
  #endif
}

const std::vector<ribi::Help::Option> ribi::Help::AddDefaultOptions(const std::vector<Option>& options)
{
  //v: unpadded Options
  std::vector<Option> v { options };
  v.push_back(Option('a',"about","display about message"));
  v.push_back(Option('h',"help","display this help message"));
  v.push_back(Option('i',"history","display version history"));
  v.push_back(Option('l',"licence","display licence"));
  v.push_back(Option('v',"version","display version"));

  //Find the longest long option, for padding
  const int max_length {
    static_cast<int>(
      std::max_element(
        v.begin(), v.end(),
        [](const Option& lhs, const Option& rhs)
        {
          return lhs.m_long.size() < rhs.m_long.size();
        }
      )->m_long.size()
    )
  };
  //w: padded options
  std::vector<Option> w;
  for (Option& p: v)
  {
    const int sz = static_cast<int>(p.m_long.size());
    assert(max_length >= sz);
    const int n_spaces = max_length - sz;
    assert(n_spaces >= 0);
    const std::string s = p.m_long
      + (n_spaces > 0 ? std::string(n_spaces,' '): std::string());
    assert(max_length == static_cast<int>(s.size()));
    const Option q(p.m_short,s,p.m_description);
    w.push_back(q);
  }

  //Sorts by short option
  //Also checks if there are no short or long option occurring twice
  std::sort(
    w.begin(),w.end(),
    [](const Option& lhs, const Option& rhs)
      {
        #ifndef NDEBUG
        if (lhs.m_short == rhs.m_short
          || lhs.m_long == rhs.m_long)
        {
          TRACE(lhs.m_short);
          TRACE(lhs.m_long);
          TRACE(lhs.m_description);
          TRACE(rhs.m_short);
          TRACE(rhs.m_long);
          TRACE(rhs.m_description);
        }
        #endif
        assert(lhs.m_short != rhs.m_short
          && "Every short option must be unique");
        assert(lhs.m_long != rhs.m_long
          && "Every long option must be unique");
        return lhs.m_short < rhs.m_short;
      }
    );

  return w;
}

std::string ribi::Help::GetVersion() noexcept
{
  return "1.1";
}

std::vector<std::string> ribi::Help::GetVersionHistory() noexcept
{
  return {
    "201x-xx-xx: Version 1.0: initial version",
    "2014-02-27: Version 1.1: started versioning"
  };
}

#ifndef NDEBUG
void ribi::Help::Test() noexcept
{
  {
    static bool is_tested{false};
    if (is_tested) return;
    is_tested = true;
  }
  const TestTimer test_timer(__func__,__FILE__,1.0);
}
#endif

std::ostream& ribi::operator<<(std::ostream& os, const Help& help)
{
  os
    << help.GetProgramName() << " help menu\n"
    << "\n"
    << help.GetProgramDescription() << "\n"
    << "\n"
    << "Allowed options for " << help.GetProgramName() << ":\n";
  for (const Help::Option& p: help.GetOptions())
  {
    os << "-" << p.m_short << ", --" << p.m_long << "  " << p.m_description << '\n';
  }
  os
    << "\n"
    << "Example uses:\n";
  for (const std::string& s: help.GetExampleUses())
  {
    os << "  " << s << '\n';
  }
  return os;
}

 

 

 

 

 

Go back to Richel Bilderbeek's C++ page.

Go back to Richel Bilderbeek's homepage.

 

Valid XHTML 1.0 Strict

This page has been created by the tool CodeToHtml