Skip to content

Commit

Permalink
Merge branch 'master' into feature/20220816-125-update-ucg-to-=-c++20
Browse files Browse the repository at this point in the history
* master:
  Removed unnecessary static checks of dev_ino_pair properties.  Removed not-very-useful constexpr constructor of same.  Some comment improvements.
  Corrected some introduced code spacing issues.
  Some constexpr experimentation on PreDescriptors, commented out (sorry).
  push_back->emplace_back.
  File-scope static naming fixes, a nodiscard.
  Got HasLongAliases() constexpred.
  Some comments, "= default" cleanups.  SA cleanups.
  Some comments, "= default" cleanups.
  Fixing ordering of #includes.
  f_raw_options from vector to std::array.
  A bunch of constexpr added.  Some cleanup of file-scope static var names.  More cleanup of things missed during GNU argp removal.
  Create github-actions-demo.yml
  Added optionparser-1.7 files.
  Comment.
  Removed some obsolete GNU argp remnants.  Parameter name improvements.
  optionparser1.4->1.7.  Makefile.am adjustments to pick up the updated library.  Passes all tests.
  • Loading branch information
Gary R. Van Sickle committed May 27, 2023
2 parents b3d1c9a + f98b29c commit 5731fce
Show file tree
Hide file tree
Showing 25 changed files with 2,616 additions and 1,907 deletions.
17 changes: 17 additions & 0 deletions .github/workflows/github-actions-demo.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: GitHub Actions Demo
on: [push]
jobs:
Explore-GitHub-Actions:
runs-on: ubuntu-latest
steps:
- run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event."
- run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!"
- run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}."
- name: Check out repository code
uses: actions/checkout@v3
- run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
- name: List files in the repository
run: |
ls ${{ github.workspace }}
- run: echo "🍏 This job's status is ${{ job.status }}."
132 changes: 73 additions & 59 deletions src/ArgParse.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2015-2017 Gary R. Van Sickle ([email protected]).
* Copyright 2015-2022 Gary R. Van Sickle ([email protected]).
*
* This file is part of UniversalCodeGrep.
*
Expand Down Expand Up @@ -27,6 +27,7 @@

#include <libext/cpuidex.hpp>

// Std C++.
#include <locale>
#include <algorithm>
#include <vector>
Expand All @@ -37,9 +38,13 @@
#include <iostream>
#include <sstream>
#include <system_error>
#include <cstdlib>
#include <cstring>
#include <cstdio>


// Include "The Lean Mean C++ Option Parser".
// The namespaces here were originally to avoid clashes with "struct option" in argp.h during the transition,
// The namespaces here were originally to avoid clashes with "struct option" in argp.h during the transition away from it,
// but "option" is so common a name that we'll just leave this in place even though we've removed argp.
namespace lmcppop_int {
#include <optionparser.h>
Expand All @@ -52,9 +57,6 @@ namespace lmcppop = lmcppop_int::option;
#if HAVE_LIBPCRE2 == 1
#include <FileScannerPCRE2.h>
#endif
#include <cstdlib>
#include <cstring>
#include <cstdio>

#include <fcntl.h>
#include <sys/stat.h>
Expand All @@ -67,14 +69,14 @@ namespace lmcppop = lmcppop_int::option;
#include <libext/Logger.h>
#include <libext/Terminal.h>


// The sweet spot for the number of directory tree traversal threads seems to be 4 on Linux with the new DirTree implementation.
static constexpr size_t f_default_dirjobs = 4;


// Not static, argp.h externs this.
/// @TODO De-literalize the copyright dates.
const char *argp_program_version = PACKAGE_STRING "\n"
"Copyright (C) 2015-2017 Gary R. Van Sickle.\n"
static constexpr char f_program_version[] = PACKAGE_STRING "\n"
"Copyright (C) 2015-2022 Gary R. Van Sickle.\n"
"\n"
"This program is free software; you can redistribute it and/or modify\n"
"it under the terms of version 3 of the GNU General Public License as\n"
Expand All @@ -89,20 +91,18 @@ const char *argp_program_version = PACKAGE_STRING "\n"
"along with this program. If not, see http://www.gnu.org/licenses/."
;

// Not static, argp.h externs this.
/// No more argp?
constexpr char argp_program_bug_address[] = PACKAGE_BUGREPORT;
static constexpr char f_program_bug_address[] = PACKAGE_BUGREPORT;

/**
* The pre- and post-option help text.
*/
static constexpr char doc[] = "\nucg: the UniversalCodeGrep code search tool."
static constexpr char f_doc[] = "\nucg: the UniversalCodeGrep code search tool."
"\vExit status is 0 if any matches were found, 1 if no matches, 2 or greater on error.";

/**
* The "Usage:" text.
*/
static constexpr char args_doc[] = "PATTERN [FILES OR DIRECTORIES]";
static constexpr char f_args_doc[] = "PATTERN [FILES OR DIRECTORIES]";

/// Keys for options without short-options.
enum OPT
Expand Down Expand Up @@ -150,8 +150,6 @@ enum OPT
/// Ack returns 255 in this case, so we'll use that instead of BSD's EX_USAGE, which is 64.
#define STATUS_EX_USAGE 255

// Not static, argp.h externs this.
int argp_err_exit_status = STATUS_EX_USAGE;

/// Arg validity checkers.
struct Arg: public lmcppop::Arg
Expand All @@ -163,13 +161,13 @@ struct Arg: public lmcppop::Arg
fprintf(stderr, "%s", msg2);
}

static lmcppop::ArgStatus Unknown(const lmcppop::Option& option, bool msg)
static constexpr lmcppop::ArgStatus Unknown(const lmcppop::Option& option, bool msg)
{
if (msg) printError("ucg: unrecognized option '", option, "'\nTry `ucg --help\' or `ucg --usage\' for more information.\n");
return lmcppop::ARG_ILLEGAL;
}

static lmcppop::ArgStatus UnknownArgHook(const lmcppop::Option& option, bool msg)
static constexpr lmcppop::ArgStatus UnknownArgHook(const lmcppop::Option& option, bool msg)
{
if(option.name != nullptr)
{
Expand All @@ -180,7 +178,7 @@ struct Arg: public lmcppop::Arg
return lmcppop::ARG_ILLEGAL;
}

static lmcppop::ArgStatus Required(const lmcppop::Option& option, bool msg)
static constexpr lmcppop::ArgStatus Required(const lmcppop::Option& option, bool msg)
{
if (option.arg != nullptr)
return lmcppop::ARG_OK;
Expand All @@ -189,7 +187,7 @@ struct Arg: public lmcppop::Arg
return lmcppop::ARG_ILLEGAL;
}

static lmcppop::ArgStatus NonEmpty(const lmcppop::Option& option, bool msg)
static constexpr lmcppop::ArgStatus NonEmpty(const lmcppop::Option& option, bool msg)
{
if (option.arg != nullptr && option.arg[0] != 0)
return lmcppop::ARG_OK;
Expand All @@ -198,7 +196,7 @@ struct Arg: public lmcppop::Arg
return lmcppop::ARG_ILLEGAL;
}

static lmcppop::ArgStatus Numeric(const lmcppop::Option& option, bool msg)
static constexpr lmcppop::ArgStatus Numeric(const lmcppop::Option& option, bool msg)
{
char* endptr = nullptr;
if (option.arg != nullptr && strtol(option.arg, &endptr, 10)){};
Expand All @@ -210,7 +208,7 @@ struct Arg: public lmcppop::Arg
}

template <long limit>
static lmcppop::ArgStatus IntegerGreater(const lmcppop::Option& option, bool msg)
static constexpr lmcppop::ArgStatus IntegerGreater(const lmcppop::Option& option, bool msg)
{
if (option.arg != nullptr)
{
Expand Down Expand Up @@ -242,7 +240,8 @@ enum OptionType { UNSPECIFIED = 0, DISABLE = 0, ENABLE = 1,

static constexpr char m_opt_start_str[] {" \t"};
static constexpr char m_help_space_str[] {" \t"};
static std::vector<std::shared_ptr<std::string>> delete_us;

static std::vector<std::shared_ptr<std::string>> f_delete_us;

struct PreDescriptor
{
Expand All @@ -251,9 +250,15 @@ struct PreDescriptor
const int m_notype {0};
const char* const m_shortopts;
const char* const m_longopts;
const char *const m_argname;
const lmcppop::CheckArg m_check_arg;
const char* const m_argname;
const lmcppop::CheckArg m_check_arg {};
/// @note The use of std::string here is at least one problem with making the whole option parser description
/// constexpr. As of up to C++23, allocations can't escape the constexpr, so this can't be initialized in the
/// constructors. I *think* std::string simply can't work here for constexpr, regardless of any machinations we
/// might try.
const std::string m_help;
/// IGNORE ME - constexpr experimentation.
// const char* m_help;
const bool m_is_hidden { false };
const bool m_is_bracket_no { false };

Expand All @@ -262,10 +267,19 @@ struct PreDescriptor
struct arbtext_tag {};
struct hidden_tag {};

//// IGNORE ME - constexpr experimentation.
// constexpr const char* help_helper(const char* a) { return a; }; //const auto* retval = new std::string(a); return retval->c_str(); };

// constexpr explicit PreDescriptor() noexcept
// : m_index(1), m_type(1), m_shortopts(""), m_longopts(""), m_argname(""), m_check_arg(NULL), m_help(help_helper(""))
// {
//
// }

constexpr PreDescriptor(unsigned index, int type, const char *const shortopts, const char *const longopts,
const lmcppop::CheckArg c, const char *h) noexcept
: m_index(index), m_type(type), m_shortopts(shortopts), m_longopts(longopts), m_argname(""), m_check_arg(c), m_help(h)
const lmcppop::CheckArg check_arg, const char *help) noexcept
: m_index(index), m_type(type), m_shortopts(shortopts), m_longopts(longopts), m_argname(""), m_check_arg(
check_arg), m_help(help)
{
};

Expand Down Expand Up @@ -331,7 +345,7 @@ struct PreDescriptor
*
* @param section_header_name Text of the section header.
*/
constexpr PreDescriptor(const char *section_header_name, section_header_tag = section_header_tag()) noexcept
constexpr PreDescriptor(const char* section_header_name, section_header_tag = section_header_tag()) noexcept
: m_index(255), m_type(0), m_shortopts(""), m_longopts(""), m_argname(""), m_check_arg(Arg::None),
m_help(std::string("\n ") += section_header_name)
{
Expand All @@ -351,11 +365,10 @@ struct PreDescriptor

[[nodiscard]] constexpr bool IsHidden() const noexcept { return m_is_hidden; };
[[nodiscard]] constexpr bool IsBracketNo() const noexcept { return m_is_bracket_no; };
[[nodiscard]] bool HasLongAliases() const noexcept
[[nodiscard]] constexpr bool HasLongAliases() const noexcept
{
// constexpr std::string_view sv(m_longopts);
// return sv.rfind(',') != std::string_view::npos;
return std::strchr(m_longopts, ',') != nullptr;
std::string_view temp_sv(m_longopts);
return temp_sv.rfind(',') != std::string_view::npos;
};

/**
Expand Down Expand Up @@ -408,20 +421,20 @@ struct PreDescriptor
fmt_help = semi_fmt_help->c_str();

/// @todo We should control this lifetime in a lighter-weight way.
delete_us.push_back(semi_fmt_help);
f_delete_us.push_back(semi_fmt_help);
}
else if(!m_help.empty())
{
// It's a section header.
auto semi_fmt_help = std::make_shared<std::string>(m_help);
fmt_help = semi_fmt_help->c_str();
delete_us.push_back(semi_fmt_help);
f_delete_us.push_back(semi_fmt_help);
}
else if(m_help.empty())
{
auto semi_fmt_help = std::make_shared<std::string>("");
fmt_help = semi_fmt_help->c_str();
delete_us.push_back(semi_fmt_help);
f_delete_us.push_back(semi_fmt_help);
}
}

Expand All @@ -438,7 +451,7 @@ struct PreDescriptor
// Strip out the '[no]', this will be the 'yes' option.
desc_longopt->erase(0,4);
}
delete_us.push_back(desc_longopt);
f_delete_us.push_back(desc_longopt);
}

size_t bracket_no_offset {0};
Expand Down Expand Up @@ -466,12 +479,12 @@ struct PreDescriptor
long_alias->erase(0, 4);
auto no_opt_str = std::make_shared<std::string>("no-" + *long_alias);
auto noopt_str = std::make_shared<std::string>("no" + *long_alias);
delete_us.push_back(no_opt_str);
delete_us.push_back(noopt_str);
f_delete_us.push_back(no_opt_str);
f_delete_us.push_back(noopt_str);
usage_container->push_back(lmcppop::Descriptor{m_index, m_notype, "", no_opt_str->c_str(), m_check_arg, 0});
usage_container->push_back(lmcppop::Descriptor{m_index, m_notype, "", noopt_str->c_str(), m_check_arg, 0});
}
delete_us.push_back(long_alias);
f_delete_us.push_back(long_alias);
usage_container->push_back(lmcppop::Descriptor{m_index, m_type, "", long_alias->c_str(), m_check_arg, 0});
}
}
Expand All @@ -483,23 +496,28 @@ struct PreDescriptor
long_alias.erase(0, 4);
auto no_opt_str = std::make_shared<std::string>("no-" + long_alias);
auto noopt_str = std::make_shared<std::string>("no" + long_alias);
delete_us.push_back(no_opt_str);
delete_us.push_back(noopt_str);
f_delete_us.push_back(no_opt_str);
f_delete_us.push_back(noopt_str);
usage_container->push_back(lmcppop::Descriptor{m_index, m_notype, "", no_opt_str->c_str(), m_check_arg, 0});
usage_container->push_back(lmcppop::Descriptor{m_index, m_notype, "", noopt_str->c_str(), m_check_arg, 0});
}

static constexpr lmcppop::Descriptor NullEntry() noexcept { return lmcppop::Descriptor{0,0,0,0,0,0}; };
};

/// The vector of all command line options.
//// IGNORE ME - constexpr experimentation.
//static constexpr PreDescriptor p;
//static constexpr std::array fcx_raw_options = std::to_array<PreDescriptor>({p});

/// The array of all command line options.
/// @todo It should be possible to make this constexpr, moving a lot of startup work to compile-time.
static const std::vector<PreDescriptor> raw_options {
/// Currently one problem there is that even just a PreDescriptor of {"SomeString:"} isn't const enough.
static const std::array f_raw_options = std::to_array<PreDescriptor>({
// This first OPT_UNKNOWN entry picks up all unrecognized options.
{ OPT_UNKNOWN, 0, "", "", "", Arg::Unknown, "", PreDescriptor::hidden_tag() },
{ (std::string("Usage: ucg [OPTION...] ") += args_doc).c_str(), PreDescriptor::arbtext_tag() },
// This next one is pretty crazy just to keep the doc[] string in the same format as used by argp.
{ std::string(doc).substr(0, std::string(doc).find('\v')).c_str(), PreDescriptor::arbtext_tag() },
{ OPT_UNKNOWN, 0, "", "", "", Arg::Unknown, "", PreDescriptor::hidden_tag() },
{ (std::string("Usage: ucg [OPTION...] ") += f_args_doc).c_str(), PreDescriptor::arbtext_tag() },
// This next one is pretty crazy just to keep the f_doc[] string in the same format as used by argp.
{ std::string(f_doc).substr(0, std::string(f_doc).find('\v')).c_str(), PreDescriptor::arbtext_tag() },
{ "Searching:" },
{ OPT_HANDLE_CASE, SMART_CASE, NO_SMART_CASE, "", "[no]smart-case", "", Arg::None, "Ignore case if PATTERN is all lowercase (default: enabled)." },
{ OPT_HANDLE_CASE, IGNORE, "i", "ignore-case", Arg::None, "Ignore case distinctions in PATTERN." },
Expand Down Expand Up @@ -546,10 +564,10 @@ static const std::vector<PreDescriptor> raw_options {
{ OPT_TEST_USE_MMAP, 0, "", "test-use-mmap", "", Arg::None, "Use mmap() to access files being searched.", PreDescriptor::hidden_tag() },
// Epilogue Text.
{ "\n" "Mandatory or optional arguments to long options are also mandatory or optional for any corresponding short options." "\n", PreDescriptor::arbtext_tag() },
// Again, this folderol is to keep the doc[] string in the same format as used by argp.
{ (std::string(doc).substr(std::string(doc).find('\v')+1, std::string::npos) += "\n").c_str(), PreDescriptor::arbtext_tag() },
{ ((std::string("Report bugs to ") += argp_program_bug_address) += ".").c_str(), PreDescriptor::arbtext_tag() }
};
// Again, this folderol is to keep the f_doc[] string in the same format as used by argp.
{ (std::string(f_doc).substr(std::string(f_doc).find('\v')+1, std::string::npos) += "\n").c_str(), PreDescriptor::arbtext_tag() },
{ ((std::string("Report bugs to ") += f_program_bug_address) += ".").c_str(), PreDescriptor::arbtext_tag() }
});

/// Option descriptions for the "The Lean Mean C++ Option Parser" library.
static std::vector<lmcppop::Descriptor> dynamic_usage;
Expand All @@ -558,21 +576,21 @@ static std::vector<lmcppop::Descriptor> dynamic_usage;
ArgParse::ArgParse(TypeManager &type_manager)
: m_type_manager(type_manager)
{
for(auto& ro : raw_options)
for(auto& ro : f_raw_options)
{
/// @note We may want to only push hidden options below, since they break the help formatting into sections.
/// If we do, we need to make sure the OPT_UNKNOWN handler is the first one.
lmcppop::Descriptor d = ro;
dynamic_usage.push_back(d);
}
for(auto& ro : raw_options)
for(auto& ro : f_raw_options)
{
if(ro.HasLongAliases())
{
ro.PushAliasDescriptors<std::vector<lmcppop::Descriptor>>(&dynamic_usage);
}
}
for(auto& ro : raw_options)
for(auto& ro : f_raw_options)
{
if(ro.IsBracketNo())
{
Expand All @@ -593,10 +611,6 @@ ArgParse::ArgParse(TypeManager &type_manager)
dynamic_usage.push_back(PreDescriptor::NullEntry());
}

ArgParse::~ArgParse()
{
}


/**
* Why? There's a legitimate reason, honestly:
Expand Down Expand Up @@ -869,7 +883,7 @@ void ArgParse::Parse(int argc, char **argv)
void ArgParse::PrintVersionText(FILE* stream)
{
// Print the version string and copyright notice.
std::fputs(argp_program_version, stream);
std::fputs(f_program_version, stream);

// In addition, we want to print the compiler/version we were built with, the libpcre version and some other info on it,
// and any source control version info we can get.
Expand Down Expand Up @@ -991,7 +1005,7 @@ void ArgParse::PrintHelpTypes() const
std::cout << std::endl;
}

void ArgParse::FindAndParseConfigFiles(std::vector<char*> */*global_argv*/, std::vector<char*> *user_argv, std::vector<char*> *project_argv)
void ArgParse::FindAndParseConfigFiles(std::vector<char*> */*global_argv*/, std::vector<char*> *user_argv, std::vector<char*> *project_argv) const
{
// Find and parse the global config file.
/// @todo
Expand Down
Loading

0 comments on commit 5731fce

Please sign in to comment.