Commit 7a7064df4edd519b93de65b6cade23d60d4365d9

Authored by Henry Fredrick Schreiner
Committed by Henry Schreiner
1 parent eed23836

Adding optional, refactor single file

include/CLI/CLI.hpp
... ... @@ -10,6 +10,8 @@
10 10  
11 11 #include "CLI/Macros.hpp"
12 12  
  13 +#include "CLI/Optional.hpp"
  14 +
13 15 #include "CLI/StringTools.hpp"
14 16  
15 17 #include "CLI/Error.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  
... ...