forked from OctaForge/libostd
remove c++ std::filesystem stuff
This commit is contained in:
parent
307675731c
commit
9aa03b8a9f
17
README.md
17
README.md
|
@ -36,23 +36,6 @@ c++ build.cc -o build -std=c++1z -I. -pthread -stdlib=libc++
|
|||
CXXFLAGS="-stdlib=libc++" ./build
|
||||
~~~
|
||||
|
||||
If you get undefined references about filesystem, you will need to add
|
||||
extra linkage.
|
||||
|
||||
For libstdc++:
|
||||
|
||||
~~~
|
||||
c++ build.cc -o build -std=c++1z -I. -pthread -lstdc++fs
|
||||
LDFLAGS="-lstdc++fs" ./build
|
||||
~~~
|
||||
|
||||
For libc++:
|
||||
|
||||
~~~
|
||||
c++ build.cc -o build -std=c++1z -I. -pthread -stdlib=libc++ -lc++experimental
|
||||
CXXFLAGS="-stdlib=libc++" LDFLAGS="-lc++experimental" ./build
|
||||
~~~
|
||||
|
||||
You can skip `-pthread` on Windows.
|
||||
|
||||
Using the tool should be straightforward. The `./build --help` command lists
|
||||
|
|
115
build.cc
115
build.cc
|
@ -18,18 +18,17 @@
|
|||
#include "ostd/format.hh"
|
||||
#include "ostd/string.hh"
|
||||
#include "ostd/path.hh"
|
||||
#include "ostd/filesystem.hh"
|
||||
#include "ostd/thread_pool.hh"
|
||||
#include "ostd/channel.hh"
|
||||
#include "ostd/argparse.hh"
|
||||
|
||||
namespace fs = ostd::filesystem;
|
||||
namespace fs = ostd::fs;
|
||||
using path = ostd::path;
|
||||
|
||||
/* ugly, but do not explicitly compile */
|
||||
#include "src/io.cc"
|
||||
#include "src/process.cc"
|
||||
#include "src/path.cc"
|
||||
#include "src/filesystem.cc"
|
||||
#include "src/thread_pool.cc"
|
||||
#include "src/channel.cc"
|
||||
#include "src/string.cc"
|
||||
|
@ -39,31 +38,31 @@ namespace fs = ostd::filesystem;
|
|||
#include "gen_unicode.cc"
|
||||
|
||||
using strvec = std::vector<std::string>;
|
||||
using pathvec = std::vector<fs::path>;
|
||||
using pathvec = std::vector<path>;
|
||||
|
||||
/* THESE VARIABLES CAN BE ALTERED */
|
||||
|
||||
/* all examples in the directory are built */
|
||||
static fs::path EXAMPLES_DIR = "examples";
|
||||
static path EXAMPLES_DIR = "examples";
|
||||
|
||||
static fs::path ASM_SOURCE_DIR = fs::path{"src"} / "asm";
|
||||
static path ASM_SOURCE_DIR = path{"src"} / "asm";
|
||||
static pathvec ASM_SOURCES = {
|
||||
"jump_all_gas", "make_all_gas", "ontop_all_gas"
|
||||
};
|
||||
|
||||
/* all sources in the directory are built */
|
||||
static fs::path CXX_SOURCE_DIR = "src";
|
||||
static path CXX_SOURCE_DIR = "src";
|
||||
|
||||
static fs::path TEST_DIR = "tests";
|
||||
static path TEST_DIR = "tests";
|
||||
static pathvec TEST_CASES = {
|
||||
"algorithm", "range"
|
||||
};
|
||||
|
||||
static fs::path OSTD_UNICODE_DATA = "data/UnicodeData-10.0.txt";
|
||||
static fs::path OSTD_UNICODE_SRC = CXX_SOURCE_DIR / "string_utf.hh";
|
||||
static path OSTD_UNICODE_DATA = "data/UnicodeData-10.0.txt";
|
||||
static path OSTD_UNICODE_SRC = CXX_SOURCE_DIR / "string_utf.hh";
|
||||
|
||||
static fs::path OSTD_SHARED_LIB = "libostd.so";
|
||||
static fs::path OSTD_STATIC_LIB = "libostd.a";
|
||||
static path OSTD_SHARED_LIB = "libostd.so";
|
||||
static path OSTD_STATIC_LIB = "libostd.a";
|
||||
|
||||
static std::string DEFAULT_CXXFLAGS = "-std=c++1z -I. -O2 -Wall -Wextra "
|
||||
"-Wshadow -Wold-style-cast -fPIC "
|
||||
|
@ -129,20 +128,14 @@ static void add_args(strvec &args, std::string const &cmdl) {
|
|||
}, cmdl);
|
||||
}
|
||||
|
||||
static fs::path path_with_ext(fs::path const &p, fs::path const &ext) {
|
||||
fs::path rp = p;
|
||||
rp.replace_extension(ext);
|
||||
return rp;
|
||||
}
|
||||
|
||||
static void try_remove(fs::path const &path, bool all = false) {
|
||||
try {
|
||||
static void try_remove(path const &path, bool all = false) {
|
||||
//try {
|
||||
if (all) {
|
||||
fs::remove_all(path);
|
||||
} else {
|
||||
fs::remove(path);
|
||||
}
|
||||
} catch (fs::filesystem_error const &) {}
|
||||
//} catch (fs::fs_error const &) {}
|
||||
}
|
||||
|
||||
static bool verbose = false;
|
||||
|
@ -213,9 +206,9 @@ int main(int argc, char **argv) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
std::string default_lib = OSTD_SHARED_LIB.string();
|
||||
auto default_lib = std::string{OSTD_SHARED_LIB.string()};
|
||||
if (build_static) {
|
||||
default_lib = OSTD_STATIC_LIB.string();
|
||||
default_lib = std::string{OSTD_STATIC_LIB.string()};
|
||||
}
|
||||
|
||||
auto strip = from_env_or("STRIP", "strip");
|
||||
|
@ -242,15 +235,15 @@ int main(int argc, char **argv) {
|
|||
add_env(asflags, "ASFLAGS");
|
||||
|
||||
auto examples = ostd::appender<pathvec>();
|
||||
ostd::glob_match(examples, EXAMPLES_DIR / "*.cc");
|
||||
fs::glob_match(examples, EXAMPLES_DIR / "*.cc");
|
||||
for (auto &ex: examples.get()) {
|
||||
ex.replace_extension();
|
||||
ex.replace_suffix();
|
||||
}
|
||||
|
||||
auto cxx_sources = ostd::appender<pathvec>();
|
||||
ostd::glob_match(cxx_sources, CXX_SOURCE_DIR / "*.cc");
|
||||
fs::glob_match(cxx_sources, CXX_SOURCE_DIR / "*.cc");
|
||||
for (auto &cc: cxx_sources.get()) {
|
||||
cc.replace_extension();
|
||||
cc.replace_suffix();
|
||||
}
|
||||
|
||||
if (clean) {
|
||||
|
@ -259,19 +252,19 @@ int main(int argc, char **argv) {
|
|||
for (auto &ex: examples.get()) {
|
||||
auto rp = ex;
|
||||
try_remove(rp);
|
||||
rp.replace_extension(".o");
|
||||
rp.replace_suffix(".o");
|
||||
try_remove(rp);
|
||||
}
|
||||
for (auto &aso: ASM_SOURCES) {
|
||||
auto rp = path_with_ext(ASM_SOURCE_DIR / aso, ".o");
|
||||
auto rp = (ASM_SOURCE_DIR / aso).with_suffix(".o");
|
||||
try_remove(rp);
|
||||
rp.replace_filename(aso.string() + "_dyn.o");
|
||||
rp.replace_name((aso + "_dyn.o").string());
|
||||
try_remove(rp);
|
||||
}
|
||||
for (auto &cso: cxx_sources.get()) {
|
||||
auto rp = path_with_ext(cso, ".o");
|
||||
auto rp = cso.with_suffix(".o");
|
||||
try_remove(rp);
|
||||
rp.replace_filename(cso.string() + "_dyn.o");
|
||||
rp.replace_name((cso + "_dyn.o").string());
|
||||
try_remove(rp);
|
||||
}
|
||||
try_remove(OSTD_UNICODE_SRC);
|
||||
|
@ -316,7 +309,7 @@ int main(int argc, char **argv) {
|
|||
};
|
||||
|
||||
auto call_cxx = [&](
|
||||
fs::path const &input, fs::path const &output, bool lib, bool shared
|
||||
path const &input, path const &output, bool lib, bool shared
|
||||
) {
|
||||
strvec args = { cxx };
|
||||
add_args(args, cxxflags);
|
||||
|
@ -325,7 +318,7 @@ int main(int argc, char **argv) {
|
|||
auto outp = output;
|
||||
|
||||
if (shared) {
|
||||
outp.replace_extension();
|
||||
outp.replace_suffix();
|
||||
outp += "_dyn.o";
|
||||
echo_q("CXX (shared): %s", ifs);
|
||||
add_args(args, SHARED_CXXFLAGS);
|
||||
|
@ -342,8 +335,8 @@ int main(int argc, char **argv) {
|
|||
|
||||
args.push_back("-c");
|
||||
args.push_back("-o");
|
||||
args.push_back(outp.string());
|
||||
args.push_back(ifs);
|
||||
args.push_back(std::string{outp.string()});
|
||||
args.push_back(std::string{ifs});
|
||||
|
||||
exec_v(args);
|
||||
|
||||
|
@ -354,7 +347,7 @@ int main(int argc, char **argv) {
|
|||
* the files may check for __PIC__ (at least mips32 does)
|
||||
*/
|
||||
auto call_as = [&](
|
||||
fs::path const &input, fs::path const &output, bool, bool shared
|
||||
path const &input, path const &output, bool, bool shared
|
||||
) {
|
||||
strvec args = { as };
|
||||
add_args(args, asflags);
|
||||
|
@ -363,7 +356,7 @@ int main(int argc, char **argv) {
|
|||
auto outp = output;
|
||||
|
||||
if (shared) {
|
||||
outp.replace_extension();
|
||||
outp.replace_suffix();
|
||||
outp += "_dyn.o";
|
||||
echo_q("AS (shared): %s", ifs);
|
||||
add_args(args, SHARED_ASFLAGS);
|
||||
|
@ -373,8 +366,8 @@ int main(int argc, char **argv) {
|
|||
|
||||
args.push_back("-c");
|
||||
args.push_back("-o");
|
||||
args.push_back(outp.string());
|
||||
args.push_back(ifs);
|
||||
args.push_back(std::string{outp.string()});
|
||||
args.push_back(std::string{ifs});
|
||||
|
||||
exec_v(args);
|
||||
|
||||
|
@ -382,7 +375,7 @@ int main(int argc, char **argv) {
|
|||
};
|
||||
|
||||
auto call_ld = [&](
|
||||
fs::path const &output, pathvec const &files, strvec const &flags
|
||||
path const &output, pathvec const &files, strvec const &flags
|
||||
) {
|
||||
echo_q("LD: %s", output);
|
||||
|
||||
|
@ -390,9 +383,9 @@ int main(int argc, char **argv) {
|
|||
add_args(args, cxxflags);
|
||||
|
||||
args.push_back("-o");
|
||||
args.push_back(output.string());
|
||||
args.push_back(std::string{output.string()});
|
||||
for (auto &p: files) {
|
||||
args.push_back(p.string());
|
||||
args.push_back(std::string{p.string()});
|
||||
}
|
||||
args.insert(args.cend(), flags.begin(), flags.end());
|
||||
|
||||
|
@ -403,13 +396,13 @@ int main(int argc, char **argv) {
|
|||
if (build_cfg == "release") {
|
||||
args.clear();
|
||||
args.push_back(strip);
|
||||
args.push_back(output.string());
|
||||
args.push_back(std::string{output.string()});
|
||||
exec_v(args);
|
||||
}
|
||||
};
|
||||
|
||||
auto call_ldlib = [&](
|
||||
fs::path const &output, pathvec const &files, bool shared
|
||||
path const &output, pathvec const &files, bool shared
|
||||
) {
|
||||
if (shared) {
|
||||
strvec flags;
|
||||
|
@ -421,19 +414,19 @@ int main(int argc, char **argv) {
|
|||
echo_q("AR: %s", output);
|
||||
|
||||
args.push_back("rcs");
|
||||
args.push_back(output.string());
|
||||
args.push_back(std::string{output.string()});
|
||||
for (auto &p: files) {
|
||||
args.push_back(p.string());
|
||||
args.push_back(std::string{p.string()});
|
||||
}
|
||||
|
||||
exec_v(args);
|
||||
}
|
||||
};
|
||||
|
||||
auto build_example = [&](fs::path const &name) {
|
||||
auto build_example = [&](path const &name) {
|
||||
auto base = name;
|
||||
auto ccf = path_with_ext(base, ".cc");
|
||||
auto obf = path_with_ext(base, ".o");
|
||||
auto ccf = base.with_suffix(".cc");
|
||||
auto obf = base.with_suffix(".o");
|
||||
|
||||
call_cxx(ccf, obf, false, false);
|
||||
call_ld(base, { obf }, { default_lib });
|
||||
|
@ -441,10 +434,10 @@ int main(int argc, char **argv) {
|
|||
try_remove(obf);
|
||||
};
|
||||
|
||||
auto build_test = [&](fs::path const &name) {
|
||||
auto build_test = [&](path const &name) {
|
||||
auto base = TEST_DIR / name;
|
||||
auto ccf = path_with_ext(base, ".cc");
|
||||
auto obf = path_with_ext(base, ".o");
|
||||
auto ccf = base.with_suffix(".cc");
|
||||
auto obf = base.with_suffix(".o");
|
||||
|
||||
try_remove(ccf);
|
||||
ostd::file_stream f{ccf.string(), ostd::stream_mode::WRITE};
|
||||
|
@ -483,16 +476,16 @@ int main(int argc, char **argv) {
|
|||
ostd::thread_pool tp{};
|
||||
tp.start();
|
||||
|
||||
std::queue<std::future<fs::path>> future_obj, future_dynobj;
|
||||
std::queue<std::future<path>> future_obj, future_dynobj;
|
||||
|
||||
/* build object files in static and shared (PIC) variants */
|
||||
auto build_all = [&](
|
||||
pathvec const &list, fs::path const &spath,
|
||||
fs::path const &sext, auto &buildf
|
||||
pathvec const &list, path const &spath,
|
||||
path const &sext, auto &buildf
|
||||
) {
|
||||
auto build_obj = [&](fs::path const &fpath, bool shared) {
|
||||
auto srcf = path_with_ext(fpath, sext);
|
||||
auto srco = path_with_ext(srcf, ".o");
|
||||
auto build_obj = [&](path const &fpath, bool shared) {
|
||||
auto srcf = fpath.with_suffix(sext.string());
|
||||
auto srco = srcf.with_suffix(".o");
|
||||
auto &fq = (shared ? future_dynobj : future_obj);
|
||||
fq.push(tp.push([&buildf, srcf, srco, shared]() {
|
||||
return buildf(srcf, srco, true, shared);
|
||||
|
@ -516,7 +509,7 @@ int main(int argc, char **argv) {
|
|||
|
||||
echo_q("Building the library...");
|
||||
build_all(ASM_SOURCES, ASM_SOURCE_DIR, ".S", call_as);
|
||||
build_all(cxx_sources.get(), fs::path{}, ".cc", call_cxx);
|
||||
build_all(cxx_sources.get(), path{}, ".cc", call_cxx);
|
||||
|
||||
if (build_static) {
|
||||
pathvec objs;
|
||||
|
@ -569,7 +562,7 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
if (build_testsuite) {
|
||||
exec_v({ "./test_runner", TEST_DIR.string() });
|
||||
exec_v({ "./test_runner", std::string{TEST_DIR.string()} });
|
||||
}
|
||||
|
||||
io_msgs.close();
|
||||
|
|
|
@ -1,204 +0,0 @@
|
|||
/** @addtogroup Utilities
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @file filesystem.hh
|
||||
*
|
||||
* @brief Filesystem abstraction module.
|
||||
*
|
||||
* This module defines the namespace ostd::filesystem, which is either
|
||||
* std::experimental::filesystem or std::filesystem depending on which
|
||||
* is available. For portable applications, only use the subset of the
|
||||
* module covered by both versions.
|
||||
*
|
||||
* It also provides range integration for directory iterators and
|
||||
* ostd::format_traits specialization for std::filesystem::path.
|
||||
*
|
||||
* Additionally, it implements glob matching following POSIX with its
|
||||
* own extensions (mainly recursive glob matching via `**`).
|
||||
*
|
||||
* @include glob.cc
|
||||
* @include listdir.cc
|
||||
*
|
||||
* @copyright See COPYING.md in the project tree for further information.
|
||||
*/
|
||||
|
||||
#ifndef OSTD_FILESYSTEM_HH
|
||||
#define OSTD_FILESYSTEM_HH
|
||||
|
||||
#if __has_include(<filesystem>)
|
||||
# include <filesystem>
|
||||
namespace ostd {
|
||||
namespace filesystem = std::filesystem;
|
||||
}
|
||||
#elif __has_include(<experimental/filesystem>)
|
||||
# include <experimental/filesystem>
|
||||
namespace ostd {
|
||||
namespace filesystem = std::experimental::filesystem;
|
||||
}
|
||||
#else
|
||||
# error "Unsupported platform"
|
||||
#endif
|
||||
|
||||
#include <ostd/platform.hh>
|
||||
#include <ostd/range.hh>
|
||||
#include <ostd/format.hh>
|
||||
|
||||
namespace ostd {
|
||||
|
||||
/** @addtogroup Utilities
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief Range integration for std::filesystem::directory_iterator.
|
||||
*
|
||||
* Allows directory iterators to be made into ranges via ostd::iter().
|
||||
*
|
||||
* @see ostd::ranged_traits<filesystem::recursive_directory_iterator>
|
||||
*/
|
||||
template<>
|
||||
struct ranged_traits<filesystem::directory_iterator> {
|
||||
/** @brief The range type for the iterator. */
|
||||
using range = iterator_range<filesystem::directory_iterator>;
|
||||
|
||||
/** @brief Creates a range for the iterator. */
|
||||
static range iter(filesystem::directory_iterator const &r) {
|
||||
return range{filesystem::begin(r), filesystem::end(r)};
|
||||
}
|
||||
};
|
||||
|
||||
/** @brief Range integration for std::filesystem::recursive_directory_iterator.
|
||||
*
|
||||
* Allows recursive directory iterators to be made into ranges via ostd::iter().
|
||||
*
|
||||
* @see ostd::ranged_traits<filesystem::directory_iterator>
|
||||
*/
|
||||
template<>
|
||||
struct ranged_traits<filesystem::recursive_directory_iterator> {
|
||||
/** @brief The range type for the iterator. */
|
||||
using range = iterator_range<filesystem::recursive_directory_iterator>;
|
||||
|
||||
/** @brief Creates a range for the iterator. */
|
||||
static range iter(filesystem::recursive_directory_iterator const &r) {
|
||||
return range{filesystem::begin(r), filesystem::end(r)};
|
||||
}
|
||||
};
|
||||
|
||||
/** @brief ostd::format_traits specialization for std::filesystem::path.
|
||||
*
|
||||
* This allows paths to be formatted as strings. The value is formatted
|
||||
* as if `path.string()` was formatted, using the exact ostd::format_spec.
|
||||
*/
|
||||
template<>
|
||||
struct format_traits<filesystem::path> {
|
||||
/** @brief Formats the path's string value.
|
||||
*
|
||||
* This calls exactly
|
||||
*
|
||||
* ~~~{.cc}
|
||||
* fs.format_value(writer, p.string());
|
||||
* ~~~
|
||||
*/
|
||||
template<typename R>
|
||||
static void to_format(
|
||||
filesystem::path const &p, R &writer, format_spec const &fs
|
||||
) {
|
||||
fs.format_value(writer, p.string());
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
OSTD_EXPORT bool glob_match_filename_impl(
|
||||
typename filesystem::path::value_type const *fname,
|
||||
typename filesystem::path::value_type const *wname
|
||||
) noexcept;
|
||||
|
||||
OSTD_EXPORT void glob_match_impl(
|
||||
void (*out)(filesystem::path const &, void *),
|
||||
typename filesystem::path::iterator beg,
|
||||
typename filesystem::path::iterator &end,
|
||||
filesystem::path pre, void *data
|
||||
);
|
||||
} /* namespace detail */
|
||||
|
||||
/** @brief Checks if the given path matches the given glob pattern.
|
||||
*
|
||||
* This matches the given filename against POSIX-style glob patterns.
|
||||
* The following patterns are supported:
|
||||
*
|
||||
* | Pattern | Description |
|
||||
* |---------|----------------------------------------------------|
|
||||
* | * | 0 or more characters |
|
||||
* | ? | any single character |
|
||||
* | [abc] | one character in the brackets |
|
||||
* | [a-z] | one character within the range in the brackets |
|
||||
* | [!abc] | one character not in the brackets |
|
||||
* | [!a-z] | one character not within the range in the brackets |
|
||||
*
|
||||
* The behavior is the same as in POSIX. You can combine ranges and
|
||||
* individual characters in the `[]` pattern together as well as define
|
||||
* multiple ranges in one (e.g. `[a-zA-Z_?]` matching alphabetics,
|
||||
* an underscore and a question mark). The behavior of the range varies
|
||||
* by locale. If the second character in the range is lower in value
|
||||
* than the first one, a match will never happen. To match the `]`
|
||||
* character in the brackets, make it the first one. To match the
|
||||
* dash character, make it the first or the last.
|
||||
*
|
||||
* You can also use the brackets to escape metacharacters. So to
|
||||
* match a literal `*`, use `[*]`.
|
||||
*
|
||||
* Keep in mind that an invalid bracket syntax (unterminated) will
|
||||
* always cause this to return `false`.
|
||||
*
|
||||
* This function is used in ostd::glob_match().
|
||||
*/
|
||||
inline bool glob_match_filename(
|
||||
filesystem::path const &filename, filesystem::path const &pattern
|
||||
) noexcept {
|
||||
return detail::glob_match_filename_impl(filename.c_str(), pattern.c_str());
|
||||
}
|
||||
|
||||
/** @brief Expands a path with glob patterns.
|
||||
*
|
||||
* Individual expanded paths are put in `out` and are of the standard
|
||||
* std::filesystem::path type. It supports standard patterns as defined
|
||||
* in ostd::glob_match_filename().
|
||||
*
|
||||
* So for example, `*.cc` will expand to `one.cc`, `two.cc` and so on.
|
||||
* A pattern like `foo/[cb]at.txt` will match `foo/cat.txt` and `foo/bat.txt`
|
||||
* but not `foo/Cat.txt`. The `foo/?at.txt` will match `foo/cat.txt`,
|
||||
* `foo/Cat.txt`, `foo/pat.txt`, `foo/vat.txt` or any other character
|
||||
* in the place.
|
||||
*
|
||||
* Additionally, a special `**` pattern is also supported which is not
|
||||
* matched by ostd::glob_match_filename(). It's only allowed if the entire
|
||||
* filename or directory name is `**`. When used as a directory name, it
|
||||
* will expand to all directories in the location and all subdirectories
|
||||
* of those directories. If used as a filename (at the end of the path),
|
||||
* then it expands to directories and subdirectories aswell as all files
|
||||
* in the location and in the directories or subdirectories. Keep in mind
|
||||
* that it is not a regular pattern and a `**` when found in a regular
|
||||
* context (i.e. not as entire filename/directory name) will be treated
|
||||
* as two regular `*` patterns.
|
||||
*
|
||||
* @throws std::filesystem_error if a filesystem error occurs.
|
||||
* @returns The forwarded `out`.
|
||||
*/
|
||||
template<typename OutputRange>
|
||||
inline OutputRange &&glob_match(
|
||||
OutputRange &&out, filesystem::path const &path
|
||||
) {
|
||||
auto pend = path.end();
|
||||
detail::glob_match_impl([](filesystem::path const &p, void *outp) {
|
||||
static_cast<std::remove_reference_t<OutputRange> *>(outp)->put(p);
|
||||
}, path.begin(), pend, filesystem::path{}, &out);
|
||||
return std::forward<OutputRange>(out);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
} /* namespace ostd */
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
10
ostd/path.hh
10
ostd/path.hh
|
@ -296,13 +296,13 @@ struct path {
|
|||
return *this;
|
||||
}
|
||||
|
||||
path with_name(string_range name) {
|
||||
path with_name(string_range name) const {
|
||||
path ret{*this};
|
||||
ret.replace_name(name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
path &replace_suffix(string_range sfx) {
|
||||
path &replace_suffix(string_range sfx = string_range{}) {
|
||||
auto osfx = suffix();
|
||||
if (!osfx.empty()) {
|
||||
p_path.erase(p_path.size() - osfx.size(), osfx.size());
|
||||
|
@ -311,7 +311,7 @@ struct path {
|
|||
return *this;
|
||||
}
|
||||
|
||||
path &replace_suffixes(string_range sfx) {
|
||||
path &replace_suffixes(string_range sfx = string_range{}) {
|
||||
auto sfxs = suffixes();
|
||||
if (!sfxs.empty()) {
|
||||
p_path.erase(p_path.size() - sfxs.size(), sfxs.size());
|
||||
|
@ -320,13 +320,13 @@ struct path {
|
|||
return *this;
|
||||
}
|
||||
|
||||
path with_suffix(string_range sfx) {
|
||||
path with_suffix(string_range sfx = string_range{}) const {
|
||||
path ret{*this};
|
||||
ret.replace_suffix(sfx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
path with_suffixes(string_range sfx) {
|
||||
path with_suffixes(string_range sfx = string_range{}) const {
|
||||
path ret{*this};
|
||||
ret.replace_suffixes(sfx);
|
||||
return ret;
|
||||
|
|
|
@ -1,199 +0,0 @@
|
|||
/* Filesystem implementation bits.
|
||||
*
|
||||
* This file is part of libostd. See COPYING.md for futher information.
|
||||
*/
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "ostd/filesystem.hh"
|
||||
|
||||
namespace ostd {
|
||||
namespace detail {
|
||||
|
||||
inline typename filesystem::path::value_type const *glob_match_brackets(
|
||||
typename filesystem::path::value_type match,
|
||||
typename filesystem::path::value_type const *wp
|
||||
) noexcept {
|
||||
bool neg = (*wp == '!');
|
||||
if (neg) {
|
||||
++wp;
|
||||
}
|
||||
|
||||
/* grab the first character as it can be ] */
|
||||
auto c = *wp++;
|
||||
if (!c) {
|
||||
/* unterminated */
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* make sure it's terminated somewhere */
|
||||
auto *eb = wp;
|
||||
for (; *eb != ']'; ++eb) {
|
||||
if (!*eb) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
++eb;
|
||||
|
||||
/* no need to worry about \0 from now on */
|
||||
do {
|
||||
/* character range */
|
||||
if ((*wp == '-') && (*(wp + 1) != ']')) {
|
||||
auto lc = *(wp + 1);
|
||||
wp += 2;
|
||||
if ((match >= c) && (match <= lc)) {
|
||||
return neg ? nullptr : eb;
|
||||
}
|
||||
c = *wp++;
|
||||
continue;
|
||||
}
|
||||
/* single-char match */
|
||||
if (match == c) {
|
||||
return neg ? nullptr : eb;
|
||||
}
|
||||
c = *wp++;
|
||||
} while (c != ']');
|
||||
|
||||
/* loop ended, so no match */
|
||||
return neg ? eb : nullptr;
|
||||
}
|
||||
|
||||
OSTD_EXPORT bool glob_match_filename_impl(
|
||||
typename filesystem::path::value_type const *fname,
|
||||
typename filesystem::path::value_type const *wname
|
||||
) noexcept {
|
||||
/* skip any matching prefix if present */
|
||||
while (*wname && (*wname != '*')) {
|
||||
if (!*wname || (*wname == '*')) {
|
||||
break;
|
||||
}
|
||||
if (*fname) {
|
||||
/* ? wildcard matches any character */
|
||||
if (*wname == '?') {
|
||||
++wname;
|
||||
++fname;
|
||||
continue;
|
||||
}
|
||||
/* [...] wildcard */
|
||||
if (*wname == '[') {
|
||||
wname = glob_match_brackets(*fname, wname + 1);
|
||||
if (!wname) {
|
||||
return false;
|
||||
}
|
||||
++fname;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ((*wname == '?') && *fname) {
|
||||
++wname;
|
||||
++fname;
|
||||
continue;
|
||||
}
|
||||
if (*fname++ != *wname++) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/* skip * wildcards; a wildcard matches 0 or more */
|
||||
if (*wname == '*') {
|
||||
while (*wname == '*') {
|
||||
++wname;
|
||||
}
|
||||
/* was trailing so everything matches */
|
||||
if (!*wname) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/* prefix skipping matched entire filename */
|
||||
if (!*fname) {
|
||||
return true;
|
||||
}
|
||||
/* empty pattern and non-empty filename */
|
||||
if (!*wname) {
|
||||
return false;
|
||||
}
|
||||
/* keep incrementing filename until it matches */
|
||||
while (*fname) {
|
||||
if (glob_match_filename_impl(fname, wname)) {
|
||||
return true;
|
||||
}
|
||||
++fname;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
OSTD_EXPORT void glob_match_impl(
|
||||
void (*out)(filesystem::path const &, void *),
|
||||
typename filesystem::path::iterator beg,
|
||||
typename filesystem::path::iterator &end,
|
||||
filesystem::path pre, void *data
|
||||
) {
|
||||
while (beg != end) {
|
||||
auto cur = *beg;
|
||||
auto *cs = cur.c_str();
|
||||
/* this part of the path might contain wildcards */
|
||||
for (auto c = *cs; c; c = *++cs) {
|
||||
/* ** as a name does recursive expansion */
|
||||
if ((c == '*') && (*(cs + 1) == '*') && !*(cs + 2)) {
|
||||
++beg;
|
||||
auto ip = pre.empty() ? "." : pre;
|
||||
if (!filesystem::is_directory(ip)) {
|
||||
return;
|
||||
}
|
||||
filesystem::recursive_directory_iterator it{ip};
|
||||
/* include "current" dir in the match */
|
||||
if (beg != end) {
|
||||
glob_match_impl(out, beg, end, pre, data);
|
||||
}
|
||||
for (auto &de: it) {
|
||||
/* followed by more path, only consider dirs */
|
||||
auto dp = de.path();
|
||||
if ((beg != end) && !filesystem::is_directory(dp)) {
|
||||
continue;
|
||||
}
|
||||
/* otherwise also match files */
|
||||
if (pre.empty()) {
|
||||
/* avoid ugly formatting, sadly we have to do
|
||||
* with experimental fs api so no better way...
|
||||
*/
|
||||
auto dpb = dp.begin(), dpe = dp.end();
|
||||
if (*dpb == ".") {
|
||||
++dpb;
|
||||
}
|
||||
filesystem::path ap;
|
||||
while (dpb != dpe) {
|
||||
ap /= *dpb;
|
||||
++dpb;
|
||||
}
|
||||
glob_match_impl(out, beg, end, ap, data);
|
||||
} else {
|
||||
glob_match_impl(out, beg, end, dp, data);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
/* wildcards *, ?, [...] */
|
||||
if ((c == '*') || (c == '?') || (c == '[')) {
|
||||
++beg;
|
||||
auto ip = pre.empty() ? "." : pre;
|
||||
if (!filesystem::is_directory(ip)) {
|
||||
return;
|
||||
}
|
||||
filesystem::directory_iterator it{ip};
|
||||
for (auto &de: it) {
|
||||
auto p = de.path().filename();
|
||||
if (!glob_match_filename(p, cur)) {
|
||||
continue;
|
||||
}
|
||||
glob_match_impl(out, beg, end, pre / p, data);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
pre /= cur;
|
||||
++beg;
|
||||
}
|
||||
out(pre, data);
|
||||
}
|
||||
|
||||
} /* namespace detail */
|
||||
} /* namespace ostd */
|
|
@ -6,7 +6,7 @@
|
|||
#include <ostd/format.hh>
|
||||
#include <ostd/io.hh>
|
||||
#include <ostd/string.hh>
|
||||
#include <ostd/filesystem.hh>
|
||||
#include <ostd/path.hh>
|
||||
|
||||
using namespace ostd;
|
||||
|
||||
|
@ -52,21 +52,21 @@ int main(int argc, char **argv) {
|
|||
++nfailed;
|
||||
};
|
||||
|
||||
filesystem::directory_iterator ds{testdir};
|
||||
for (auto &v: ds) {
|
||||
auto p = filesystem::path{v};
|
||||
if (!filesystem::is_regular_file(p)) {
|
||||
fs::directory_range dr{testdir};
|
||||
for (auto &v: dr) {
|
||||
if (!v.is_regular_file()) {
|
||||
continue;
|
||||
}
|
||||
auto p = v.path();
|
||||
#ifdef OSTD_PLATFORM_WIN32
|
||||
if (p.extension().string() != ".exe")
|
||||
if (p.suffix().string() != ".exe")
|
||||
#else
|
||||
if (p.extension().string() != "")
|
||||
if (p.has_suffix())
|
||||
#endif
|
||||
{
|
||||
continue;
|
||||
}
|
||||
auto modname = p.stem().string();
|
||||
auto modname = p.stem();
|
||||
auto exepath = p.string();
|
||||
|
||||
auto rf = popen(exepath.data(), "r");
|
||||
|
|
Loading…
Reference in a new issue