-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathtm_dialog2.mm
149 lines (125 loc) · 3.39 KB
/
tm_dialog2.mm
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
//
// client.mm
// Created by Allan Odgaard on 2007-09-22.
//
#import "Dialog2.h"
static double const AppVersion = 2.0;
id connect ()
{
NSString* portName = kDialogServerConnectionName;
if(char const* var = getenv("DIALOG_PORT_NAME"))
portName = @(var);
id proxy = [NSConnection rootProxyForConnectionWithRegisteredName:portName host:nil];
[proxy setProtocolForProxy:@protocol(DialogServerProtocol)];
return proxy;
}
char const* create_pipe (char const* name)
{
char* filename;
asprintf(&filename, "%s/dialog_fifo_%d_%s", getenv("TMPDIR") ?: "/tmp", getpid(), name);
int res = mkfifo(filename, 0666);
if((res == -1) && (errno != EEXIST))
{
perror("Error creating the named pipe");
exit(EX_OSERR);
}
return filename;
}
int open_pipe (char const* name, int oflag)
{
int fd = open(name, oflag);
if(fd == -1)
{
perror("Error opening the named pipe");
exit(EX_IOERR);
}
return fd;
}
int main (int argc, char const* argv[])
{
if(argc == 2 && strcmp(argv[1], "--version") == 0)
{
fprintf(stderr, "%1$s %2$.1f (" __DATE__ ")\n", getprogname(), AppVersion);
return EX_OK;
}
// If the argument list starts with a switch then assume it’s meant for trunk dialog
// and pass it off
if(argc > 1 && *argv[1] == '-')
execv(getenv("DIALOG_1"), (char* const*)argv);
@autoreleasepool{
id<DialogServerProtocol> proxy = connect();
if(!proxy)
{
fprintf(stderr, "error reaching server\n");
exit(EX_UNAVAILABLE);
}
char const* stdinName = create_pipe("stdin");
char const* stdoutName = create_pipe("stdout");
char const* stderrName = create_pipe("stderr");
NSMutableArray* args = [NSMutableArray array];
for(size_t i = 0; i < argc; ++i)
[args addObject:@(argv[i])];
NSDictionary* dict = @{
@"stdin": @(stdinName),
@"stdout": @(stdoutName),
@"stderr": @(stderrName),
@"cwd": @(getcwd(NULL, 0)),
@"environment": [[NSProcessInfo processInfo] environment],
@"arguments": args,
};
[proxy connectFromClientWithOptions:dict];
int inputFd = open_pipe(stdinName, O_WRONLY);
int outputFd = open_pipe(stdoutName, O_RDONLY);
int errorFd = open_pipe(stderrName, O_RDONLY);
std::map<int, int> fdMap;
fdMap[STDIN_FILENO] = inputFd;
fdMap[outputFd] = STDOUT_FILENO;
fdMap[errorFd] = STDERR_FILENO;
if(isatty(STDIN_FILENO) != 0)
{
fdMap.erase(fdMap.find(STDIN_FILENO));
close(inputFd);
}
while(fdMap.size() > 1 || (fdMap.size() == 1 && fdMap.find(STDIN_FILENO) == fdMap.end()))
{
fd_set readfds, writefds;
FD_ZERO(&readfds); FD_ZERO(&writefds);
int fdCount = 0;
for(auto const& pair : fdMap)
{
FD_SET(pair.first, &readfds);
fdCount = std::max(fdCount, pair.first + 1);
}
int i = select(fdCount, &readfds, &writefds, NULL, NULL);
if(i == -1)
{
perror("Error from select");
continue;
}
std::vector<int> toRemove;
for(auto const& pair : fdMap)
{
if(FD_ISSET(pair.first, &readfds))
{
char buf[1024];
ssize_t len = read(pair.first, buf, sizeof(buf));
if(len == 0)
toRemove.push_back(pair.first); // we can’t remove as long as we need the iterator for the ++
else write(pair.second, buf, len);
}
}
for(int key : toRemove)
{
if(fdMap[key] == inputFd)
close(inputFd);
fdMap.erase(key);
}
}
close(outputFd);
close(errorFd);
unlink(stdinName);
unlink(stdoutName);
unlink(stderrName);
}
return EX_OK;
}