diff options
-rw-r--r-- | libbutl/fdstream.cxx | 39 | ||||
-rw-r--r-- | libbutl/fdstream.mxx | 18 | ||||
-rw-r--r-- | libbutl/path-io.mxx | 19 | ||||
-rw-r--r-- | libbutl/path.mxx | 52 |
4 files changed, 116 insertions, 12 deletions
diff --git a/libbutl/fdstream.cxx b/libbutl/fdstream.cxx index 50056a2..de91724 100644 --- a/libbutl/fdstream.cxx +++ b/libbutl/fdstream.cxx @@ -48,6 +48,7 @@ #include <new> // bad_alloc #include <limits> // numeric_limits #include <cstring> // memcpy(), memmove() +#include <iostream> // cin, cout #include <exception> // uncaught_exception[s]() #include <stdexcept> // invalid_argument #include <system_error> @@ -946,6 +947,44 @@ namespace butl : m | translate_mode (out))); } + istream& + open_file_or_stdin (path_name& pn, ifdstream& ifs) + { + assert (pn.path != nullptr); + + if (pn.path->string () != "-") + { + ifs.open (*pn.path); + return ifs; + } + else + { + cin.exceptions (ifs.exceptions ()); + if (!pn.name) + pn.name = "<stdin>"; + return cin; + } + } + + ostream& + open_file_or_stdout (path_name& pn, ofdstream& ofs) + { + assert (pn.path != nullptr); + + if (pn.path->string () != "-") + { + ofs.open (*pn.path); + return ofs; + } + else + { + cout.exceptions (ofs.exceptions ()); + if (!pn.name) + pn.name = "<stdout>"; + return cout; + } + } + // fd*() functions // diff --git a/libbutl/fdstream.mxx b/libbutl/fdstream.mxx index 49c5dae..cebbafa 100644 --- a/libbutl/fdstream.mxx +++ b/libbutl/fdstream.mxx @@ -645,6 +645,24 @@ LIBBUTL_MODEXPORT namespace butl bool is_open () const {return buf_.is_open ();} }; + // Open a file or, if the file name is `-`, stdin/stdout. + // + // In case of the stdin/stdout, these functions simply adjust the exception + // mask on std::cin/cout to match the i/ofdstreams argument. + // + // Return a reference to the opened i/ofdstream or cin/cout and, in the + // latter case, set the translated name in path_name to <stdin>/<stdout> + // (unless it is already present). + // + // Note that ofdstream::close() should be called explicitly unless stdout + // was opened (but harmless to call even if it was). + // + LIBBUTL_SYMEXPORT std::istream& + open_file_or_stdin (path_name&, ifdstream&); + + LIBBUTL_SYMEXPORT std::ostream& + open_file_or_stdout (path_name&, ofdstream&); + // The std::getline() replacement that provides a workaround for libstdc++'s // ios::failure ABI fiasco (#66145) by throwing ios::failure, as it is // defined at libbutl build time (new ABI on recent distributions) rather diff --git a/libbutl/path-io.mxx b/libbutl/path-io.mxx index 6c9f93b..54d884b 100644 --- a/libbutl/path-io.mxx +++ b/libbutl/path-io.mxx @@ -29,17 +29,22 @@ import butl.path; LIBBUTL_MODEXPORT namespace butl { - // This is the default path IO implementation. The reason it is - // separate is because one often wants a custom implementation. - // For example, we may want to print paths as relative to the - // working directory. Or we may want to print '~' for the home - // directory prefix. Or we may want to print dir_path with a - // trailing '/'. + // This is the default path IO implementation. It is separate to allo custom + // implementations. For example, we may want to print paths as relative to + // the working directory. Or we may want to print '~' for the home directory + // prefix. Or we may want to print dir_path with a trailing '/'. // template <typename C, typename K> inline std::basic_ostream<C>& - operator<< (std::basic_ostream<C>& os, basic_path<C, K> const& p) + operator<< (std::basic_ostream<C>& os, const basic_path<C, K>& p) { return os << p.string (); } + + template <typename C, typename P> + inline std::basic_ostream<C>& + operator<< (std::basic_ostream<C>& os, const basic_path_name<P>& pn) + { + return os << (pn.name ? *pn.name : pn.path->string ()); + } } diff --git a/libbutl/path.mxx b/libbutl/path.mxx index 114c25a..1d0ada9 100644 --- a/libbutl/path.mxx +++ b/libbutl/path.mxx @@ -29,11 +29,13 @@ export module butl.path; #ifdef __cpp_lib_modules_ts import std.core; #endif +import butl.optional; import butl.small_vector; #ifdef _WIN32 import butl.utility; #endif #else +#include <libbutl/optional.mxx> #include <libbutl/small-vector.mxx> #ifdef _WIN32 #include <libbutl/utility.mxx> // *case*() @@ -488,10 +490,10 @@ LIBBUTL_MODEXPORT namespace butl }; // This implementation of a filesystem path has two types: path, which can - // represent any path (file, directory, etc.) and dir_path, which is derived + // represent any path (file, directory, etc) and dir_path, which is derived // from path. The internal representation of directories maintains a - // trailing slash. However, it is ignored in path comparison, size, and - // string spelling. For example: + // trailing directory separator (slash). However, it is ignored in path + // comparison, size, and string spelling. For example: // // path p1 ("foo"); // File path. // path p2 ("bar/"); // Directory path. @@ -527,6 +529,22 @@ LIBBUTL_MODEXPORT namespace butl template <class P, class C, class K> P path_cast (const basic_path<C, K>&); template <class P, class C, class K> P path_cast (basic_path<C, K>&&); + // In certain cases we may need to translate a special path (e.g., `-`) to a + // name that may not be a valid path (e.g., `<stdin>` or `<stdout>`), for + // example, for diagnostics. In this case we can use path_name which + // contains the original path plus an optional translation as a string. Note + // that this is a view-like type with the original path shallow-referenced + // rather than copied. + // + // Note: we could also have a copying version that derives from the view + // (and thus can be passed down as a view). + // + template <typename P> + struct basic_path_name; + + using path_name = basic_path_name<path>; + using dir_path_name = basic_path_name<dir_path>; + // Low-level path data storage. It is also used by the implementation to // pass around initialized/valid paths. // @@ -555,6 +573,7 @@ LIBBUTL_MODEXPORT namespace butl // Notes: // - If path_ is empty, then tsep_ can only be 0. // - We could have used a much narrower integer for tsep_. + // - We could give the rest of tsep_ to the user to use as flags, etc. // string_type path_; difference_type tsep_; @@ -600,7 +619,6 @@ LIBBUTL_MODEXPORT namespace butl } }; - template <typename C> struct any_path_kind { @@ -1295,7 +1313,6 @@ LIBBUTL_MODEXPORT namespace butl return r; } - // Note that the result of (foo / "bar") is always a path, even if foo // is dir_path. An idiom to force it to dir_path is: // @@ -1319,6 +1336,31 @@ LIBBUTL_MODEXPORT namespace butl return r; } + template <typename P> + struct basic_path_name + { + using path_type = P; + using string_type = typename path_type::string_type; + + const path_type* path; + optional<string_type> name; + + explicit + basic_path_name (const path_type& p, optional<string_type> n = nullopt) + : path (&p), name (std::move (n)) {} + + explicit + basic_path_name (path_type&&, optional<string_type> = nullopt) = delete; + + explicit + basic_path_name (string_type n) + : path (nullptr), name (std::move (n)) {} + + explicit + basic_path_name (const path_type* p, optional<string_type> n = nullopt) + : path (p), name (std::move (n)) {} + }; + // For operator<< (ostream) see the path-io header. } |