btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / kits / shared / CommandPipe.cpp
blobe1a3ba2d587b54bb79c59c9a9dd3d4f44d440200
1 /*
2 * Copyright 2007 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Ramshankar, v.ramshankar@gmail.com
7 * Stephan Aßmus <superstippi@gmx.de>
8 */
10 //! BCommandPipe class to handle reading shell output
11 // (stdout/stderr) of other programs into memory.
12 #include "CommandPipe.h"
14 #include <stdlib.h>
15 #include <unistd.h>
17 #include <image.h>
18 #include <Message.h>
19 #include <Messenger.h>
20 #include <String.h>
23 BCommandPipe::BCommandPipe()
25 fStdOutOpen(false),
26 fStdErrOpen(false)
31 BCommandPipe::~BCommandPipe()
33 FlushArgs();
37 status_t
38 BCommandPipe::AddArg(const char* arg)
40 if (arg == NULL || arg[0] == '\0')
41 return B_BAD_VALUE;
43 char* argCopy = strdup(arg);
44 if (argCopy == NULL)
45 return B_NO_MEMORY;
47 if (!fArgList.AddItem(reinterpret_cast<void*>(argCopy))) {
48 free(argCopy);
49 return B_NO_MEMORY;
52 return B_OK;
56 void
57 BCommandPipe::PrintToStream() const
59 for (int32 i = 0L; i < fArgList.CountItems(); i++)
60 printf("%s ", reinterpret_cast<char*>(fArgList.ItemAtFast(i)));
62 printf("\n");
66 void
67 BCommandPipe::FlushArgs()
69 // Delete all arguments from the list
70 for (int32 i = fArgList.CountItems() - 1; i >= 0; i--)
71 free(fArgList.ItemAtFast(i));
72 fArgList.MakeEmpty();
74 Close();
78 void
79 BCommandPipe::Close()
81 if (fStdErrOpen) {
82 close(fStdErr[0]);
83 fStdErrOpen = false;
86 if (fStdOutOpen) {
87 close(fStdOut[0]);
88 fStdOutOpen = false;
93 const char**
94 BCommandPipe::Argv(int32& argc) const
96 // NOTE: Freeing is left to caller as indicated in the header!
97 argc = fArgList.CountItems();
98 const char** argv = reinterpret_cast<const char**>(
99 malloc((argc + 1) * sizeof(char*)));
100 for (int32 i = 0; i < argc; i++)
101 argv[i] = reinterpret_cast<const char*>(fArgList.ItemAtFast(i));
103 argv[argc] = NULL;
104 return argv;
108 // #pragma mark -
111 thread_id
112 BCommandPipe::PipeAll(int* stdOutAndErr) const
114 // This function pipes both stdout and stderr to the same filedescriptor
115 // (stdOut)
116 int oldStdOut;
117 int oldStdErr;
118 pipe(stdOutAndErr);
119 oldStdOut = dup(STDOUT_FILENO);
120 oldStdErr = dup(STDERR_FILENO);
121 close(STDOUT_FILENO);
122 close(STDERR_FILENO);
123 // TODO: This looks broken, using "stdOutAndErr[1]" twice!
124 dup2(stdOutAndErr[1], STDOUT_FILENO);
125 dup2(stdOutAndErr[1], STDERR_FILENO);
127 // Construct the argv vector
128 int32 argc;
129 const char** argv = Argv(argc);
131 // Load the app image... and pass the args
132 thread_id appThread = load_image((int)argc, argv,
133 const_cast<const char**>(environ));
135 dup2(oldStdOut, STDOUT_FILENO);
136 dup2(oldStdErr, STDERR_FILENO);
137 close(oldStdOut);
138 close(oldStdErr);
140 free(argv);
142 return appThread;
146 thread_id
147 BCommandPipe::Pipe(int* stdOut, int* stdErr) const
149 int oldStdOut;
150 int oldStdErr;
151 pipe(stdOut);
152 pipe(stdErr);
153 oldStdOut = dup(STDOUT_FILENO);
154 oldStdErr = dup(STDERR_FILENO);
155 close(STDOUT_FILENO);
156 close(STDERR_FILENO);
157 dup2(stdOut[1], STDOUT_FILENO);
158 dup2(stdErr[1], STDERR_FILENO);
160 // Construct the argv vector
161 int32 argc;
162 const char** argv = Argv(argc);
164 // Load the app image... and pass the args
165 thread_id appThread = load_image((int)argc, argv, const_cast<
166 const char**>(environ));
168 dup2(oldStdOut, STDOUT_FILENO);
169 dup2(oldStdErr, STDERR_FILENO);
170 close(oldStdOut);
171 close(oldStdErr);
173 free(argv);
175 return appThread;
179 thread_id
180 BCommandPipe::Pipe(int* stdOut) const
182 // Redirects only output (stdout) to caller, stderr is closed
183 int stdErr[2];
184 thread_id tid = Pipe(stdOut, stdErr);
185 close(stdErr[0]);
186 close(stdErr[1]);
187 return tid;
191 thread_id
192 BCommandPipe::PipeInto(FILE** _out, FILE** _err)
194 Close();
196 thread_id tid = Pipe(fStdOut, fStdErr);
197 if (tid >= 0)
198 resume_thread(tid);
200 close(fStdErr[1]);
201 close(fStdOut[1]);
203 fStdOutOpen = true;
204 fStdErrOpen = true;
206 *_out = fdopen(fStdOut[0], "r");
207 *_err = fdopen(fStdErr[0], "r");
209 return tid;
213 thread_id
214 BCommandPipe::PipeInto(FILE** _outAndErr)
216 Close();
218 thread_id tid = PipeAll(fStdOut);
219 if (tid >= 0)
220 resume_thread(tid);
222 close(fStdOut[1]);
223 fStdOutOpen = true;
225 *_outAndErr = fdopen(fStdOut[0], "r");
226 return tid;
230 // #pragma mark -
233 void
234 BCommandPipe::Run()
236 // Runs the command without bothering to redirect streams, this is similar
237 // to system() but uses pipes and wait_for_thread.... Synchronous.
238 int stdOut[2], stdErr[2];
239 status_t exitCode;
240 wait_for_thread(Pipe(stdOut, stdErr), &exitCode);
242 close(stdOut[0]);
243 close(stdErr[0]);
244 close(stdOut[1]);
245 close(stdErr[1]);
249 void
250 BCommandPipe::RunAsync()
252 // Runs the command without bothering to redirect streams, this is similar
253 // to system() but uses pipes.... Asynchronous.
254 Close();
255 FILE* f = NULL;
256 PipeInto(&f);
257 fclose(f);
261 // #pragma mark -
264 status_t
265 BCommandPipe::ReadLines(FILE* file, LineReader* lineReader)
267 // Reads output of file, line by line. Each line is passed to lineReader
268 // for inspection, and the IsCanceled() method is repeatedly called.
270 if (file == NULL || lineReader == NULL)
271 return B_BAD_VALUE;
273 BString line;
275 while (!feof(file)) {
276 if (lineReader->IsCanceled())
277 return B_CANCELED;
279 unsigned char c = fgetc(file);
280 // TODO: fgetc() blocks, is there a way to make it timeout?
282 if (c != 255)
283 line << (char)c;
285 if (c == '\n') {
286 status_t ret = lineReader->ReadLine(line);
287 if (ret != B_OK)
288 return ret;
289 line = "";
293 return B_OK;
297 BString
298 BCommandPipe::ReadLines(FILE* file)
300 class AllLinesReader : public LineReader {
301 public:
302 AllLinesReader()
304 fResult("")
308 virtual bool IsCanceled()
310 return false;
313 virtual status_t ReadLine(const BString& line)
315 int lineLength = line.Length();
316 int resultLength = fResult.Length();
317 fResult << line;
318 if (fResult.Length() != lineLength + resultLength)
319 return B_NO_MEMORY;
320 return B_OK;
323 BString Result() const
325 return fResult;
328 private:
329 BString fResult;
330 } lineReader;
332 ReadLines(file, &lineReader);
334 return lineReader.Result();
338 // #pragma mark -
341 BCommandPipe&
342 BCommandPipe::operator<<(const char* arg)
344 AddArg(arg);
345 return *this;
349 BCommandPipe&
350 BCommandPipe::operator<<(const BString& arg)
352 AddArg(arg.String());
353 return *this;
357 BCommandPipe&
358 BCommandPipe::operator<<(const BCommandPipe& arg)
360 int32 argc;
361 const char** argv = arg.Argv(argc);
362 for (int32 i = 0; i < argc; i++)
363 AddArg(argv[i]);
365 free(argv);
366 return *this;