aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2019-11-07 11:11:45 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2019-11-07 11:11:45 +0200
commit23d4deb111bfff9c282c20989573c4b0775e4c16 (patch)
tree9763c7e2cbce36581673eb69b652f67e2f7cfa6f
parentb2ac741e2b806f4565beeef34b12c95b6b3fdd41 (diff)
Add path_name struct, open_file_or{stdin,stdout}() functions
-rw-r--r--libbutl/fdstream.cxx39
-rw-r--r--libbutl/fdstream.mxx18
-rw-r--r--libbutl/path-io.mxx19
-rw-r--r--libbutl/path.mxx52
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.
}