Commit 7a7064df4edd519b93de65b6cade23d60d4365d9
Committed by
Henry Schreiner
1 parent
eed23836
Adding optional, refactor single file
Showing
4 changed files
with
125 additions
and
53 deletions
include/CLI/CLI.hpp
include/CLI/Optional.hpp
0 → 100644
| 1 | +#pragma once | |
| 2 | + | |
| 3 | +// Distributed under the 3-Clause BSD License. See accompanying | |
| 4 | +// file LICENSE or https://github.com/CLIUtils/CLI11 for details. | |
| 5 | + | |
| 6 | +#include <sstream> | |
| 7 | + | |
| 8 | +#include "CLI/Macros.hpp" | |
| 9 | + | |
| 10 | +// [CLI11:verbatim] | |
| 11 | +#ifdef __has_include | |
| 12 | +#if defined(CLI11_CPP17) && __has_include(<optional>) | |
| 13 | +#include <optional> | |
| 14 | +#define CLI11_OPTIONAL | |
| 15 | +namespace CLI { | |
| 16 | +using std::experimental::optional; | |
| 17 | +} // namespace CLI | |
| 18 | +#elif defined(CPP11_CPP14) && __has_include(<experimental/optional>) | |
| 19 | +#include <experimental/optional> | |
| 20 | +#define CLI11_OPTIONAL | |
| 21 | +namespace CLI { | |
| 22 | +using std::optional; | |
| 23 | +} // namespace CLI | |
| 24 | +#endif | |
| 25 | +#endif | |
| 26 | +// [CLI11:verbatim] | |
| 27 | + | |
| 28 | +namespace CLI { | |
| 29 | + | |
| 30 | +#ifdef CLI11_OPTIONAL | |
| 31 | + | |
| 32 | +template <typename T> std::istream &operator>>(std::istream &in, optional<T> &val) { | |
| 33 | + T v; | |
| 34 | + in >> v; | |
| 35 | + val = v; | |
| 36 | + return in; | |
| 37 | +} | |
| 38 | + | |
| 39 | +#endif | |
| 40 | + | |
| 41 | +} // namespace CLI | ... | ... |
scripts/MakeSingleHeader.py
| ... | ... | @@ -5,60 +5,110 @@ from __future__ import print_function, unicode_literals |
| 5 | 5 | import os |
| 6 | 6 | import re |
| 7 | 7 | import argparse |
| 8 | +import operator | |
| 9 | +from copy import copy | |
| 8 | 10 | from subprocess import check_output, CalledProcessError |
| 11 | +from functools import reduce | |
| 9 | 12 | |
| 10 | 13 | includes_local = re.compile(r"""^#include "(.*)"$""", re.MULTILINE) |
| 11 | 14 | includes_system = re.compile(r"""^#include \<(.*)\>$""", re.MULTILINE) |
| 15 | +verbatim_tag_str = r""" | |
| 16 | +^ # Begin of line | |
| 17 | +[^\n^\[]+ # Some characters, not including [ or the end of a line | |
| 18 | +\[ # A literal [ | |
| 19 | +[^\]^\n]* # Anything except a closing ] | |
| 20 | +CLI11:verbatim # The tag | |
| 21 | +[^\]^\n]* # Anything except a closing ] | |
| 22 | +\] # A literal ] | |
| 23 | +[^\n]* # Up to end of line | |
| 24 | +$ # End of a line | |
| 25 | +""" | |
| 26 | +verbatim_all = re.compile(verbatim_tag_str + "(.*)" + verbatim_tag_str, | |
| 27 | + re.MULTILINE | re.DOTALL | re.VERBOSE) | |
| 28 | + | |
| 29 | +DIR = os.path.dirname(os.path.abspath(__file__)) | |
| 30 | + | |
| 31 | +class HeaderFile(object): | |
| 32 | + TAG = "Unknown git revision" | |
| 33 | + | |
| 34 | + def __init__(self, base, inc): | |
| 35 | + with open(os.path.join(base, inc)) as f: | |
| 36 | + inner = f.read() | |
| 12 | 37 | |
| 13 | -DIR = os.path.dirname(os.path.abspath(__file__)) # Path(__file__).resolve().parent | |
| 14 | -BDIR = os.path.join(os.path.dirname(DIR), 'include') # DIR.parent / 'include' | |
| 38 | + # add self.verbatim | |
| 39 | + if 'CLI11:verbatim' in inner: | |
| 40 | + self.verbatim = ["\n\n// Verbatim copy from {}".format(inc)] | |
| 41 | + self.verbatim += verbatim_all.findall(inner) | |
| 42 | + inner = verbatim_all.sub("", inner) | |
| 43 | + else: | |
| 44 | + self.verbatim = [] | |
| 15 | 45 | |
| 16 | -print("Git directory:", DIR) | |
| 46 | + self.headers = set(includes_system.findall(inner)) | |
| 17 | 47 | |
| 18 | -try: | |
| 19 | - TAG = check_output(['git', 'describe', '--tags', '--always'], cwd=str(DIR)).decode("utf-8") | |
| 20 | -except CalledProcessError: | |
| 21 | - TAG = "A non-git source" | |
| 48 | + self.body = '\n// From {}\n\n'.format(inc) + inner[inner.find('namespace'):] | |
| 22 | 49 | |
| 23 | -def MakeHeader(out): | |
| 24 | - main_header = os.path.join(BDIR, 'CLI', 'CLI.hpp') | |
| 25 | - with open(main_header) as f: | |
| 26 | - header = f.read() | |
| 50 | + def __add__(self, other): | |
| 51 | + out = copy(self) | |
| 52 | + out.headers |= other.headers | |
| 53 | + out.body += other.body | |
| 54 | + out.verbatim += other.verbatim | |
| 55 | + return out | |
| 27 | 56 | |
| 28 | - include_files = includes_local.findall(header) | |
| 57 | + @property | |
| 58 | + def header_str(self): | |
| 59 | + return '\n'.join('#include <'+h+'>' for h in sorted(self.headers)) | |
| 29 | 60 | |
| 30 | - headers = set() | |
| 31 | - output = '' | |
| 32 | - for inc in include_files: | |
| 33 | - with open(os.path.join(BDIR, inc)) as f: | |
| 34 | - inner = f.read() | |
| 35 | - headers |= set(includes_system.findall(inner)) | |
| 36 | - output += '\n// From {inc}\n\n'.format(inc=inc) | |
| 37 | - output += inner[inner.find('namespace'):] | |
| 61 | + @property | |
| 62 | + def verbatim_str(self): | |
| 63 | + return '\n'.join(self.verbatim) | |
| 38 | 64 | |
| 39 | - header_list = '\n'.join('#include <'+h+'>' for h in headers) | |
| 40 | - | |
| 41 | - output = '''\ | |
| 65 | + def __str__(self): | |
| 66 | + return '''\ | |
| 42 | 67 | #pragma once |
| 43 | 68 | |
| 44 | 69 | // Distributed under the 3-Clause BSD License. See accompanying |
| 45 | 70 | // file LICENSE or https://github.com/CLIUtils/CLI11 for details. |
| 46 | 71 | |
| 47 | 72 | // This file was generated using MakeSingleHeader.py in CLI11/scripts |
| 48 | -// from: {tag} | |
| 73 | +// from: {self.TAG} | |
| 49 | 74 | // This has the complete CLI library in one file. |
| 50 | 75 | |
| 51 | -{header_list} | |
| 52 | -{output}'''.format(header_list=header_list, output=output, tag=TAG) | |
| 76 | +{self.header_str} | |
| 77 | +{self.verbatim_str} | |
| 78 | +{self.body} | |
| 79 | +'''.format(self=self) | |
| 80 | + | |
| 53 | 81 | |
| 54 | - with open(out, 'w') as f: | |
| 55 | - f.write(output) | |
| 82 | +def MakeHeader(output, main_header, include_dir = '../include'): | |
| 83 | + # Set tag if possible to class variable | |
| 84 | + try: | |
| 85 | + HeaderFile.TAG = check_output(['git', 'describe', '--tags', '--always'], cwd=str(DIR)).decode("utf-8") | |
| 86 | + except CalledProcessError: | |
| 87 | + pass | |
| 56 | 88 | |
| 57 | - print("Created {out}".format(out=out)) | |
| 89 | + base_dir = os.path.abspath(os.path.join(DIR, include_dir)) | |
| 90 | + main_header = os.path.join(base_dir, main_header) | |
| 91 | + | |
| 92 | + with open(main_header) as f: | |
| 93 | + header = f.read() | |
| 94 | + | |
| 95 | + include_files = includes_local.findall(header) | |
| 96 | + | |
| 97 | + headers = [HeaderFile(base_dir, inc) for inc in include_files] | |
| 98 | + single_header = reduce(operator.add, headers) | |
| 99 | + | |
| 100 | + with open(output, 'w') as f: | |
| 101 | + f.write(str(single_header)) | |
| 102 | + | |
| 103 | + print("Created", output) | |
| 58 | 104 | |
| 59 | 105 | |
| 60 | 106 | if __name__ == '__main__': |
| 61 | 107 | parser = argparse.ArgumentParser() |
| 62 | - parser.add_argument("output", nargs='?', default=os.path.join(BDIR, 'CLI11.hpp')) | |
| 108 | + parser.add_argument("output", help="Single header file output") | |
| 109 | + parser.add_argument("--main", default='CLI/CLI.hpp', help="The main include file that defines the other files") | |
| 110 | + parser.add_argument("--include", default='../include') | |
| 63 | 111 | args = parser.parse_args() |
| 64 | - MakeHeader(args.output) | |
| 112 | + | |
| 113 | + MakeHeader(args.output, args.main, args.include) | |
| 114 | + | ... | ... |
tests/OptionalTest.cpp
| 1 | 1 | #include <cstdlib> |
| 2 | 2 | #include <iostream> |
| 3 | 3 | |
| 4 | -#ifdef __has_include | |
| 5 | -#if defined(CLI11_CPP17) && __has_include(<optional>) | |
| 6 | -#include <optional> | |
| 7 | -#define have_optional 1 | |
| 8 | -using std::experimental::optional; | |
| 9 | -#elif defined(CPP11_CPP14) && __has_include(<experimental/optional>) | |
| 10 | -#include <experimental/optional> | |
| 11 | -#define have_optional 1 | |
| 12 | -using std::optional; | |
| 13 | -#else | |
| 14 | -#define have_optional 0 | |
| 15 | -#endif | |
| 16 | -#endif | |
| 17 | - | |
| 18 | -#if have_optional | |
| 19 | - | |
| 20 | -template <typename T> std::istream &operator>>(std::istream &in, optional<T> &val) { | |
| 21 | - T v; | |
| 22 | - in >> v; | |
| 23 | - val = v; | |
| 24 | - return in; | |
| 25 | -} | |
| 4 | +#if CLI11_OPTIONAL | |
| 26 | 5 | |
| 27 | 6 | #include "app_helper.hpp" |
| 28 | 7 | ... | ... |