From 7a7064df4edd519b93de65b6cade23d60d4365d9 Mon Sep 17 00:00:00 2001 From: Henry Fredrick Schreiner Date: Tue, 3 Apr 2018 21:37:40 +0200 Subject: [PATCH] Adding optional, refactor single file --- include/CLI/CLI.hpp | 2 + include/CLI/Optional.hpp | 41 +++++++++++++ scripts/MakeSingleHeader.py | 114 ++++++++++++++++++++++++++---------- tests/OptionalTest.cpp | 23 +------- 4 files changed, 126 insertions(+), 54 deletions(-) create mode 100644 include/CLI/Optional.hpp diff --git a/include/CLI/CLI.hpp b/include/CLI/CLI.hpp index c8210c20..662e833d 100644 --- a/include/CLI/CLI.hpp +++ b/include/CLI/CLI.hpp @@ -10,6 +10,8 @@ #include "CLI/Macros.hpp" +#include "CLI/Optional.hpp" + #include "CLI/StringTools.hpp" #include "CLI/Error.hpp" diff --git a/include/CLI/Optional.hpp b/include/CLI/Optional.hpp new file mode 100644 index 00000000..dc1fad3a --- /dev/null +++ b/include/CLI/Optional.hpp @@ -0,0 +1,41 @@ +#pragma once + +// Distributed under the 3-Clause BSD License. See accompanying +// file LICENSE or https://github.com/CLIUtils/CLI11 for details. + +#include + +#include "CLI/Macros.hpp" + +// [CLI11:verbatim] +#ifdef __has_include +#if defined(CLI11_CPP17) && __has_include() +#include +#define CLI11_OPTIONAL +namespace CLI { +using std::experimental::optional; +} // namespace CLI +#elif defined(CPP11_CPP14) && __has_include() +#include +#define CLI11_OPTIONAL +namespace CLI { +using std::optional; +} // namespace CLI +#endif +#endif +// [CLI11:verbatim] + +namespace CLI { + +#ifdef CLI11_OPTIONAL + +template std::istream &operator>>(std::istream &in, optional &val) { + T v; + in >> v; + val = v; + return in; +} + +#endif + +} // namespace CLI diff --git a/scripts/MakeSingleHeader.py b/scripts/MakeSingleHeader.py index 39d227f4..d260ab95 100755 --- a/scripts/MakeSingleHeader.py +++ b/scripts/MakeSingleHeader.py @@ -5,60 +5,110 @@ from __future__ import print_function, unicode_literals import os import re import argparse +import operator +from copy import copy from subprocess import check_output, CalledProcessError +from functools import reduce includes_local = re.compile(r"""^#include "(.*)"$""", re.MULTILINE) includes_system = re.compile(r"""^#include \<(.*)\>$""", re.MULTILINE) +verbatim_tag_str = r""" +^ # Begin of line +[^\n^\[]+ # Some characters, not including [ or the end of a line +\[ # A literal [ +[^\]^\n]* # Anything except a closing ] +CLI11:verbatim # The tag +[^\]^\n]* # Anything except a closing ] +\] # A literal ] +[^\n]* # Up to end of line +$ # End of a line +""" +verbatim_all = re.compile(verbatim_tag_str + "(.*)" + verbatim_tag_str, + re.MULTILINE | re.DOTALL | re.VERBOSE) -DIR = os.path.dirname(os.path.abspath(__file__)) # Path(__file__).resolve().parent -BDIR = os.path.join(os.path.dirname(DIR), 'include') # DIR.parent / 'include' +DIR = os.path.dirname(os.path.abspath(__file__)) -print("Git directory:", DIR) +class HeaderFile(object): + TAG = "Unknown git revision" -try: - TAG = check_output(['git', 'describe', '--tags', '--always'], cwd=str(DIR)).decode("utf-8") -except CalledProcessError: - TAG = "A non-git source" - -def MakeHeader(out): - main_header = os.path.join(BDIR, 'CLI', 'CLI.hpp') - with open(main_header) as f: - header = f.read() - - include_files = includes_local.findall(header) - - headers = set() - output = '' - for inc in include_files: - with open(os.path.join(BDIR, inc)) as f: + def __init__(self, base, inc): + with open(os.path.join(base, inc)) as f: inner = f.read() - headers |= set(includes_system.findall(inner)) - output += '\n// From {inc}\n\n'.format(inc=inc) - output += inner[inner.find('namespace'):] - header_list = '\n'.join('#include <'+h+'>' for h in headers) + # add self.verbatim + if 'CLI11:verbatim' in inner: + self.verbatim = ["\n\n// Verbatim copy from {}".format(inc)] + self.verbatim += verbatim_all.findall(inner) + inner = verbatim_all.sub("", inner) + else: + self.verbatim = [] - output = '''\ + self.headers = set(includes_system.findall(inner)) + + self.body = '\n// From {}\n\n'.format(inc) + inner[inner.find('namespace'):] + + def __add__(self, other): + out = copy(self) + out.headers |= other.headers + out.body += other.body + out.verbatim += other.verbatim + return out + + @property + def header_str(self): + return '\n'.join('#include <'+h+'>' for h in sorted(self.headers)) + + @property + def verbatim_str(self): + return '\n'.join(self.verbatim) + + def __str__(self): + return '''\ #pragma once // Distributed under the 3-Clause BSD License. See accompanying // file LICENSE or https://github.com/CLIUtils/CLI11 for details. // This file was generated using MakeSingleHeader.py in CLI11/scripts -// from: {tag} +// from: {self.TAG} // This has the complete CLI library in one file. -{header_list} -{output}'''.format(header_list=header_list, output=output, tag=TAG) +{self.header_str} +{self.verbatim_str} +{self.body} +'''.format(self=self) - with open(out, 'w') as f: - f.write(output) - print("Created {out}".format(out=out)) +def MakeHeader(output, main_header, include_dir = '../include'): + # Set tag if possible to class variable + try: + HeaderFile.TAG = check_output(['git', 'describe', '--tags', '--always'], cwd=str(DIR)).decode("utf-8") + except CalledProcessError: + pass + + base_dir = os.path.abspath(os.path.join(DIR, include_dir)) + main_header = os.path.join(base_dir, main_header) + + with open(main_header) as f: + header = f.read() + + include_files = includes_local.findall(header) + + headers = [HeaderFile(base_dir, inc) for inc in include_files] + single_header = reduce(operator.add, headers) + + with open(output, 'w') as f: + f.write(str(single_header)) + + print("Created", output) if __name__ == '__main__': parser = argparse.ArgumentParser() - parser.add_argument("output", nargs='?', default=os.path.join(BDIR, 'CLI11.hpp')) + parser.add_argument("output", help="Single header file output") + parser.add_argument("--main", default='CLI/CLI.hpp', help="The main include file that defines the other files") + parser.add_argument("--include", default='../include') args = parser.parse_args() - MakeHeader(args.output) + + MakeHeader(args.output, args.main, args.include) + diff --git a/tests/OptionalTest.cpp b/tests/OptionalTest.cpp index d1a26c27..a863f239 100644 --- a/tests/OptionalTest.cpp +++ b/tests/OptionalTest.cpp @@ -1,28 +1,7 @@ #include #include -#ifdef __has_include -#if defined(CLI11_CPP17) && __has_include() -#include -#define have_optional 1 -using std::experimental::optional; -#elif defined(CPP11_CPP14) && __has_include() -#include -#define have_optional 1 -using std::optional; -#else -#define have_optional 0 -#endif -#endif - -#if have_optional - -template std::istream &operator>>(std::istream &in, optional &val) { - T v; - in >> v; - val = v; - return in; -} +#if CLI11_OPTIONAL #include "app_helper.hpp"