mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-04 17:18:45 +00:00
14d2a6d8ff
Let's hope this doesn't causes build failures for e.g. musl: I just know it's good on macOS and our Linux CI. It's been a long time. One fix this brings, is I discovered we #include assert.h or cassert in a lot of places. If those ever happen to be in a file that doesn't include common.h, or we are before common.h gets included, we're unawaringly working with the system 'assert' macro again, which may get disabled for debug builds or at least has different behavior on crash. We undef 'assert' and redefine it in common.h. Those were all eliminated, except in one catch-22 spot for maybe.h: it can't include common.h. A fix might be to make a fish_assert.h that *usually* common.h exports.
101 lines
3.4 KiB
C++
101 lines
3.4 KiB
C++
#ifndef FISH_REDIRECTION_H
|
|
#define FISH_REDIRECTION_H
|
|
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "common.h"
|
|
#include "maybe.h"
|
|
|
|
/// This file supports specifying and applying redirections.
|
|
|
|
enum class redirection_mode_t {
|
|
overwrite, // normal redirection: > file.txt
|
|
append, // appending redirection: >> file.txt
|
|
input, // input redirection: < file.txt
|
|
fd, // fd redirection: 2>&1
|
|
noclob // noclobber redirection: >? file.txt
|
|
};
|
|
|
|
class io_chain_t;
|
|
|
|
/// A struct which represents a redirection specification from the user.
|
|
/// Here the file descriptors don't represent open files - it's purely textual.
|
|
struct redirection_spec_t {
|
|
/// The redirected fd, or -1 on overflow.
|
|
/// In the common case of a pipe, this is 1 (STDOUT_FILENO).
|
|
/// For example, in the case of "3>&1" this will be 3.
|
|
int fd{-1};
|
|
|
|
/// The redirection mode.
|
|
redirection_mode_t mode{redirection_mode_t::overwrite};
|
|
|
|
/// The target of the redirection.
|
|
/// For example in "3>&1", this will be "1".
|
|
/// In "< file.txt" this will be "file.txt".
|
|
wcstring target{};
|
|
|
|
/// \return if this is a close-type redirection.
|
|
bool is_close() const { return mode == redirection_mode_t::fd && target == L"-"; }
|
|
|
|
/// Attempt to parse target as an fd. Return the fd, or none() if none.
|
|
maybe_t<int> get_target_as_fd() const;
|
|
|
|
/// \return the open flags for this redirection.
|
|
int oflags() const;
|
|
|
|
redirection_spec_t(int fd, redirection_mode_t mode, wcstring target)
|
|
: fd(fd), mode(mode), target(std::move(target)) {}
|
|
};
|
|
using redirection_spec_list_t = std::vector<redirection_spec_t>;
|
|
|
|
/// A class representing a sequence of basic redirections.
|
|
class dup2_list_t : noncopyable_t {
|
|
public:
|
|
/// A type that represents the action dup2(src, target).
|
|
/// If target is negative, this represents close(src).
|
|
/// Note none of the fds here are considered 'owned'.
|
|
struct action_t {
|
|
int src;
|
|
int target;
|
|
};
|
|
|
|
dup2_list_t() = default;
|
|
dup2_list_t(dup2_list_t &&) = default;
|
|
dup2_list_t &operator=(dup2_list_t &&) = default;
|
|
~dup2_list_t();
|
|
|
|
/// \return the list of dup2 actions.
|
|
const std::vector<action_t> &get_actions() const { return actions_; }
|
|
|
|
/// Produce a dup_fd_list_t from an io_chain. This may not be called before fork().
|
|
/// The result contains the list of fd actions (dup2 and close), as well as the list
|
|
/// of fds opened.
|
|
static dup2_list_t resolve_chain(const io_chain_t &);
|
|
|
|
/// \return the fd ultimately dup'd to a target fd, or -1 if the target is closed.
|
|
/// For example, if target fd is 1, and we have a dup2 chain 5->3 and 3->1, then we will
|
|
/// return 5. If the target is not referenced in the chain, returns target.
|
|
int fd_for_target_fd(int target) const;
|
|
|
|
private:
|
|
/// The list of actions.
|
|
std::vector<action_t> actions_;
|
|
|
|
/// Append a dup2 action.
|
|
void add_dup2(int src, int target) {
|
|
assert(src >= 0 && target >= 0 && "Invalid fd in add_dup2");
|
|
// Note: record these even if src and target is the same.
|
|
// This is a note that we must clear the CLO_EXEC bit.
|
|
actions_.push_back(action_t{src, target});
|
|
}
|
|
|
|
/// Append a close action.
|
|
void add_close(int fd) {
|
|
assert(fd >= 0 && "Invalid fd in add_close");
|
|
actions_.push_back(action_t{fd, -1});
|
|
}
|
|
};
|
|
|
|
#endif
|