* added BCommandPipe class (currently private API) kindly provided by

Ramshankar
* adopted to Haiku coding style


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21463 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2007-06-19 12:38:29 +00:00
parent 687e327bac
commit 45f929b494
2 changed files with 412 additions and 0 deletions
+88
View File
@@ -0,0 +1,88 @@
/*
* Copyright 2007 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Ramshankar, [email protected]
*/
#ifndef _COMMAND_PIPE_H
#define _COMMAND_PIPE_H
#include <stdio.h>
#include <List.h>
#include <OS.h>
class BMessage;
class BMessenger;
class BString;
namespace BPrivate {
class BCommandPipe {
public:
BCommandPipe();
virtual ~BCommandPipe();
status_t AddArg(const char* argv);
void PrintToStream() const;
// FlushArgs() deletes the commands while Close() explicity closes all
// pending pipe-ends
// Note: Internally FlushArgs() calls Close()
void FlushArgs();
void Close();
// If you use these, you must explicitly call "close" for the parameters
// (outdes/errdes) when you are done with them!
thread_id Pipe(int* outdes, int* errdes) const;
thread_id Pipe(int* outdes) const;
thread_id PipeAll(int* outAndErrDes) const;
// If you use these, you need NOT call "fclose" for the parameters
// (out/err) when you are done with them, also you need not do any
// allocation for these FILE* pointers, just use FILE* out = NULL
// and pass &out and so on...
thread_id PipeInto(FILE** _out, FILE** _err);
thread_id PipeInto(FILE** _outAndErr);
// Run() is a synchronous call, and waits till the command has finished
// executing RunAsync() is an asynchronous call that returns immediately
// after launching the command Neither of these bother about redirecting
// pipes for you to use
void Run();
void RunAsync();
// This function reads line-by-line from "file", cancels its reading
// when "*cancel" is true. It reports each line it has read to "target"
// using the supplied "_message" and string field name. "cancel" can be
// NULL
BString ReadLines(FILE* file, bool* cancel,
BMessenger& target, const BMessage& message,
const BString& stringFieldName);
// You need NOT free/delete the return array of strings
const char** Argv(int32& _argc) const;
// Stardard append operators, if you use pointers to a BCommandPipe,
// you must use *pipe << "command"; and not pipe << "command" (as it
// will not compile that way)
BCommandPipe& operator<<(const char *arg);
BCommandPipe& operator<<(const BString& arg);
BCommandPipe& operator<<(const BCommandPipe& arg);
protected:
BList fArgList;
int fOutDes[2];
int fErrDes[2];
bool fOutDesOpen;
bool fErrDesOpen;
};
} // namespace BPrivate
using BPrivate::BCommandPipe;
#endif // _COMMAND_PIPE_H
+324
View File
@@ -0,0 +1,324 @@
/*
* Copyright 2007 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Ramshankar, [email protected]
*/
//! BCommandPipe class to handle reading shell output
// (stdout/stderr) of other programs into memory.
#include "CommandPipe.h"
#include <stdlib.h>
#include <unistd.h>
#include <image.h>
#include <Message.h>
#include <Messenger.h>
#include <String.h>
BCommandPipe::BCommandPipe()
: fOutDesOpen(false)
, fErrDesOpen(false)
{
}
BCommandPipe::~BCommandPipe()
{
FlushArgs();
}
status_t
BCommandPipe::AddArg(const char* arg)
{
return (fArgList.AddItem(reinterpret_cast<void*>(strdup(arg))) == true ?
B_OK : B_ERROR);
}
void
BCommandPipe::PrintToStream() const
{
for (int32 i = 0L; i < fArgList.CountItems(); i++)
printf("%s ", (char*)fArgList.ItemAtFast(i));
printf("\n");
}
void
BCommandPipe::FlushArgs()
{
// Delete all arguments from the list
for(int32 i = 0; i < fArgList.CountItems(); i++)
free(fArgList.RemoveItem(0L));
fArgList.MakeEmpty();
Close();
}
void
BCommandPipe::Close()
{
if (fErrDesOpen) {
close(fErrDes[0]);
fErrDesOpen = false;
}
if (fOutDesOpen) {
close(fOutDes[0]);
fOutDesOpen = false;
}
}
const char**
BCommandPipe::Argv(int32& _argc) const
{
// *** Warning *** Freeing is left to caller!! Indicated in Header
int32 argc = fArgList.CountItems();
const char **argv = (const char**)malloc((argc + 1) * sizeof(char*));
for (int32 i = 0; i < argc; i++)
argv[i] = (const char*)fArgList.ItemAtFast(i);
argv[argc] = NULL;
_argc = argc;
return argv;
}
// #pragma mark -
thread_id
BCommandPipe::PipeAll(int* outAndErrDes) const
{
// This function pipes both stdout and stderr to the same filedescriptor
// (outdes)
int oldstdout;
int oldstderr;
pipe(outAndErrDes);
oldstdout = dup(STDOUT_FILENO);
oldstderr = dup(STDERR_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
dup2(outAndErrDes[1], STDOUT_FILENO);
dup2(outAndErrDes[1], STDERR_FILENO);
// Construct the argv vector
int32 argc = fArgList.CountItems();
const char **argv = (const char**)malloc((argc + 1) * sizeof(char*));
for (int32 i = 0; i < argc; i++)
argv[i] = (const char*)fArgList.ItemAtFast(i);
argv[argc] = NULL;
// Load the app image... and pass the args
thread_id appThread = load_image((int)argc, argv, const_cast<
const char**>(environ));
dup2(oldstdout, STDOUT_FILENO);
dup2(oldstderr, STDERR_FILENO);
close(oldstdout);
close(oldstderr);
delete[] argv;
return appThread;
}
thread_id
BCommandPipe::Pipe(int* outdes, int* errdes) const
{
int oldstdout;
int oldstderr;
pipe(outdes);
pipe(errdes);
oldstdout = dup(STDOUT_FILENO);
oldstderr = dup(STDERR_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
dup2(outdes[1], STDOUT_FILENO);
dup2(errdes[1], STDERR_FILENO);
// Construct the argv vector
int32 argc = fArgList.CountItems();
const char **argv = (const char**)malloc((argc + 1) * sizeof(char*));
for (int32 i = 0; i < argc; i++)
argv[i] = (const char*)fArgList.ItemAtFast(i);
argv[argc] = NULL;
// Load the app image... and pass the args
thread_id appThread = load_image((int)argc, argv, const_cast<
const char**>(environ));
dup2(oldstdout, STDOUT_FILENO);
dup2(oldstderr, STDERR_FILENO);
close(oldstdout);
close(oldstderr);
delete[] argv;
return appThread;
}
thread_id
BCommandPipe::Pipe(int* outdes) const
{
// Redirects only output (stdout) to caller, stderr is closed
int errdes[2];
thread_id tid = Pipe(outdes, errdes);
close(errdes[0]);
close(errdes[1]);
return tid;
}
thread_id
BCommandPipe::PipeInto(FILE** _out, FILE** _err)
{
Close();
thread_id tid = Pipe(fOutDes, fErrDes);
resume_thread(tid);
close(fErrDes[1]);
close(fOutDes[1]);
fOutDesOpen = true;
fErrDesOpen = true;
*_out = fdopen(fOutDes[0], "r");
*_err = fdopen(fErrDes[0], "r");
return tid;
}
thread_id
BCommandPipe::PipeInto(FILE** _outAndErr)
{
Close();
thread_id tid = PipeAll(fOutDes);
if (tid == B_ERROR || tid == B_NO_MEMORY)
return tid;
resume_thread(tid);
close(fOutDes[1]);
fOutDesOpen = true;
*_outAndErr = fdopen(fOutDes[0], "r");
return tid;
}
// #pragma mark -
void
BCommandPipe::Run()
{
// Runs the command without bothering to redirect streams, this is similar
// to system() but uses pipes and wait_for_thread.... Synchronous.
int outdes[2], errdes[2];
status_t exitCode;
wait_for_thread(Pipe(outdes, errdes), &exitCode);
close(outdes[0]);
close(errdes[0]);
close(outdes[1]);
close(errdes[1]);
}
void
BCommandPipe::RunAsync()
{
// Runs the command without bothering to redirect streams, this is similar
// to system() but uses pipes.... Asynchronous.
Close();
FILE* f = NULL;
PipeInto(&f);
fclose(f);
}
// #pragma mark -
BString
BCommandPipe::ReadLines(FILE* file, bool* cancel, BMessenger& target,
const BMessage& message, const BString& stringFieldName)
{
// Reads output of file, line by line. The entire output is returned
// and as each line is being read "target" (if any) is informed,
// with "message" i.e. AddString (stringFieldName, <line read from pipe>)
// "cancel" cancels the reading process, when it becomes true (unless its
// waiting on fgetc()) and I don't know how to cancel the waiting fgetc()
// call.
BString result;
BString line;
BMessage updateMsg(message);
while (!feof(file)) {
if (cancel != NULL && *cancel == true)
break;
unsigned char c = fgetc(file);
if (c != 255) {
line << (char)c;
result << (char)c;
}
if (c == '\n') {
updateMsg.RemoveName(stringFieldName.String());
updateMsg.AddString(stringFieldName.String(), line);
target.SendMessage(&updateMsg);
line = "";
}
}
return result;
}
BCommandPipe&
BCommandPipe::operator<<(const char* _arg)
{
AddArg(_arg);
return *this;
}
BCommandPipe&
BCommandPipe::operator<<(const BString& _arg)
{
AddArg(_arg.String());
return *this;
}
BCommandPipe&
BCommandPipe::operator<<(const BCommandPipe& _arg)
{
int32 argc;
const char** argv = _arg.Argv(argc);
for (int32 i = 0; i < argc; i++)
AddArg(argv[i]);
return *this;
}