1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
|
#ifndef FISH_IO_H
#define FISH_IO_H
#include <vector>
#include <tr1/memory>
using std::tr1::shared_ptr;
/**
Describes what type of IO operation an io_data_t represents
*/
enum io_mode
{
IO_FILE, IO_PIPE, IO_FD, IO_BUFFER, IO_CLOSE
};
/** Represents an FD redirection */
class io_data_t
{
private:
/** buffer to save output in for IO_BUFFER. Note that in the original fish, the buffer was a pointer to a buffer_t stored in the param2 union down below, and when an io_data_t was duplicated the pointer was copied so that two io_data_ts referenced the same buffer. It's not clear to me how this was ever cleaned up correctly. But it's important that they share the same buffer for reasons I don't yet understand either. We can get correct sharing and cleanup with shared_ptr. */
shared_ptr<std::vector<char> > out_buffer;
/* No assignment allowed */
void operator=(const io_data_t &rhs);
public:
/** Type of redirect */
int io_mode;
/** FD to redirect */
int fd;
/**
Type-specific parameter for redirection
*/
union
{
/** Fds for IO_PIPE and for IO_BUFFER */
int pipe_fd[2];
/** fd to redirect specified fd to, for IO_FD */
int old_fd;
} param1;
/** Second type-specific paramter for redirection */
union
{
/** file creation flags to send to open for IO_FILE */
int flags;
/** Whether to close old_fd for IO_FD */
int close_old;
} param2;
/** Filename IO_FILE. malloc'd. This needs to be used after fork, so don't use wcstring here. */
const char *filename_cstr;
/** Convenience to set filename_cstr via wcstring */
void set_filename(const wcstring &str) {
free((void *)filename_cstr);
filename_cstr = wcs2str(str.c_str());
}
/** Function to create the output buffer */
void out_buffer_create() {
out_buffer.reset(new std::vector<char>);
}
/** Function to append to the buffer */
void out_buffer_append(const char *ptr, size_t count) {
assert(out_buffer.get() != NULL);
out_buffer->insert(out_buffer->end(), ptr, ptr + count);
}
/** Function to get a pointer to the buffer */
char *out_buffer_ptr(void) {
assert(out_buffer.get() != NULL);
return out_buffer->empty() ? NULL : &out_buffer->at(0);
}
const char *out_buffer_ptr(void) const {
assert(out_buffer.get() != NULL);
return out_buffer->empty() ? NULL : &out_buffer->at(0);
}
/** Function to get the size of the buffer */
size_t out_buffer_size(void) const {
assert(out_buffer.get() != NULL);
return out_buffer->size();
}
/** Set to true if this is an input io redirection */
bool is_input;
io_data_t() :
out_buffer(),
io_mode(0),
fd(0),
param1(),
param2(),
filename_cstr(NULL),
is_input(0)
{
}
io_data_t(const io_data_t &rhs) :
out_buffer(rhs.out_buffer),
io_mode(rhs.io_mode),
fd(rhs.fd),
param1(rhs.param1),
param2(rhs.param2),
filename_cstr(rhs.filename_cstr ? strdup(rhs.filename_cstr) : NULL),
is_input(rhs.is_input)
{
}
~io_data_t() {
free((void *)filename_cstr);
}
};
class io_chain_t : public std::vector<io_data_t *> {
public:
io_chain_t();
io_chain_t(io_data_t *);
void remove(const io_data_t *element);
io_chain_t duplicate() const;
void duplicate_prepend(const io_chain_t &src);
void destroy();
const io_data_t *get_io_for_fd(int fd) const;
io_data_t *get_io_for_fd(int fd);
};
/**
Remove the specified io redirection from the chain
*/
void io_remove(io_chain_t &list, const io_data_t *element);
/** Make a copy of the specified chain of redirections. Uses operator new. */
io_chain_t io_duplicate(const io_chain_t &chain);
/** Return a shallow copy of the specified chain of redirections that contains only the applicable redirections. That is, if there's multiple redirections for the same fd, only the second one is included. */
io_chain_t io_unique(const io_chain_t &chain);
/** Prepends a copy of the specified 'src' chain of redirections to 'dst.' Uses operator new. */
void io_duplicate_prepend( const io_chain_t &src, io_chain_t &dst );
/** Destroys an io_chain */
void io_chain_destroy(io_chain_t &chain);
/**
Return the last io redirection in the chain for the specified file descriptor.
*/
const io_data_t *io_chain_get(const io_chain_t &src, int fd);
io_data_t *io_chain_get(io_chain_t &src, int fd);
/**
Free all resources used by a IO_BUFFER type io redirection.
*/
void io_buffer_destroy( io_data_t *io_buffer );
/**
Create a IO_BUFFER type io redirection, complete with a pipe and a
vector<char> for output. The default file descriptor used is 1 for
output buffering and 0 for input buffering.
\param is_input set this parameter to zero if the buffer should be
used to buffer the output of a command, or non-zero to buffer the
input to a command.
*/
io_data_t *io_buffer_create( bool is_input );
/**
Close output pipe, and read from input pipe until eof.
*/
void io_buffer_read( io_data_t *d );
/** Print debug information about the specified IO redirection chain to stderr. */
void io_print( const io_chain_t &chain );
#endif
|