1
0
mirror of https://github.com/stefanocasazza/ULib.git synced 2025-09-28 19:05:55 +08:00
ULib/include/ulib/command.h
2015-05-28 19:04:25 +02:00

332 lines
7.9 KiB
C++

// ============================================================================
//
// = LIBRARY
// ULib - c++ library
//
// = FILENAME
// command.h
//
// = AUTHOR
// Stefano Casazza
//
// ============================================================================
#ifndef ULIB_COMMAND_H
#define ULIB_COMMAND_H 1
#include <ulib/string.h>
#include <errno.h>
class UFile;
class UDialog;
class UFileConfig;
class UServer_Base;
class UProxyPlugIn;
class UNoCatPlugIn;
#define U_ADD_ARGS 100
#define U_MAX_ARGS 8192
class U_EXPORT UCommand {
public:
// Check for memory error
U_MEMORY_TEST
// Allocator e Deallocator
U_MEMORY_ALLOCATOR
U_MEMORY_DEALLOCATOR
// COSTRUTTORI
void zero()
{
envp = 0;
pathcmd = 0;
ncmd = nenv = nfile = 0;
flag_expand = U_NOT_FOUND;
argv_exec = envp_exec = 0;
}
void reset(const UString* penv);
UCommand()
{
U_TRACE_REGISTER_OBJECT(0, UCommand, "", 0)
zero();
}
UCommand(const UString& cmd, char** penv = 0) : command(cmd)
{
U_TRACE_REGISTER_OBJECT(0, UCommand, "%V,%p", cmd.rep, penv)
zero();
setCommand();
setEnvironment(penv);
}
UCommand(const UString& cmd, const UString* penv) : command(cmd)
{
U_TRACE_REGISTER_OBJECT(0, UCommand, "%V,%p", cmd.rep, penv)
zero();
setCommand();
setEnvironment(penv);
}
~UCommand()
{
U_TRACE_UNREGISTER_OBJECT(0, UCommand)
reset(0);
}
// MANAGE GENERIC ENVIRONMENT
void setEnvironment(char** penv)
{
U_TRACE(0, "UCommand::setEnvironment(%p)", penv)
envp = penv;
flag_expand = U_NOT_FOUND;
}
void setEnvironment(const UString* env);
// MANAGE GENERIC ARGUMENT
void delArgument()
{
U_TRACE(0, "UCommand::delArgument()")
U_INTERNAL_ASSERT_POINTER(argv_exec)
argv_exec[ncmd--] = 0;
U_INTERNAL_DUMP("ncmd = %d", ncmd)
U_INTERNAL_ASSERT_RANGE(1,ncmd,U_ADD_ARGS)
}
void addArgument(const char* argument)
{
U_TRACE(0, "UCommand::addArgument(%S)", argument)
U_INTERNAL_ASSERT_POINTER(argv_exec)
U_INTERNAL_ASSERT(u_isText((const unsigned char*)argument, u__strlen(argument, __PRETTY_FUNCTION__)))
argv_exec[++ncmd] = (char*) argument;
argv_exec[ncmd+1] = 0;
U_INTERNAL_DUMP("ncmd = %d", ncmd)
U_INTERNAL_ASSERT_RANGE(1,ncmd,U_ADD_ARGS)
}
void setArgument(int n, const char* argument)
{
U_TRACE(0, "UCommand::setArgument(%d,%S)", n, argument)
U_INTERNAL_ASSERT_RANGE(2,n,ncmd)
U_INTERNAL_ASSERT_POINTER(argv_exec)
U_INTERNAL_ASSERT(u_isText((const unsigned char*)argument, u__strlen(argument, __PRETTY_FUNCTION__)))
argv_exec[n] = (char*) argument;
}
void setLastArgument(const char* argument)
{
U_TRACE(0, "UCommand::setLastArgument(%S)", argument)
U_INTERNAL_ASSERT_POINTER(argv_exec)
U_INTERNAL_ASSERT_EQUALS(argv_exec[ncmd+1],0)
U_INTERNAL_ASSERT(u_isText((const unsigned char*)argument, u__strlen(argument, __PRETTY_FUNCTION__)))
argv_exec[ncmd] = (char*) argument;
}
void setNumArgument(int32_t n = 1, bool bfree = false);
// MANAGE FILE ARGUMENT
void setFileArgument();
void setFileArgument(const char* pathfile)
{
U_TRACE(0, "UCommand::setFileArgument(%S)", pathfile)
U_INTERNAL_ASSERT_POINTER(argv_exec)
U_INTERNAL_ASSERT(u_isText((const unsigned char*)pathfile, u__strlen(pathfile, __PRETTY_FUNCTION__)))
U_INTERNAL_DUMP("ncmd = %d", ncmd)
U_INTERNAL_ASSERT_RANGE(2,nfile,ncmd)
argv_exec[nfile] = (char*) pathfile;
}
// VARIE
int32_t getNumArgument() const { return ncmd; }
int32_t getNumFileArgument() const { return nfile; }
UString getStringCommand() { return command; }
UString getStringEnvironment() { return environment; }
void setCommand(const UString& cmd)
{
U_TRACE(0, "UCommand::setCommand(%V)", cmd.rep)
command = cmd;
setCommand();
}
void set(const UString& cmd, char** penv = 0)
{
U_TRACE(0, "UCommand::set(%V,%p)", cmd.rep, penv)
setCommand(cmd);
setEnvironment(penv);
}
void set(const UString& cmd, const UString* penv)
{
U_TRACE(0, "UCommand::set(%V,%p)", cmd.rep, penv)
setCommand(cmd);
setEnvironment(penv);
}
bool isShellScript() const __pure
{
U_TRACE(0, "UCommand::isShellScript()")
U_INTERNAL_ASSERT(command)
bool result = (strncmp(command.data(), U_CONSTANT_TO_PARAM(U_PATH_SHELL)) == 0);
U_RETURN(result);
}
char* getCommand() const __pure
{
U_TRACE(0, "UCommand::getCommand()")
char* result = (argv_exec ? argv_exec[(isShellScript() ? 2 : 0)] : 0);
U_INTERNAL_ASSERT(result == 0 || u_isText((const unsigned char*)result, u__strlen(result, __PRETTY_FUNCTION__)))
U_RETURN(result);
}
// SERVICES
static pid_t pid;
static int timeoutMS; // specified the timeout value, in milliseconds for read output. A negative value indicates no timeout, i.e. an infinite wait
static int exit_value, status;
static UCommand* loadConfigCommand(UFileConfig* cfg);
static void setTimeout(int seconds) { timeoutMS = (seconds * 1000); }
static int32_t setEnvironment(const UString& env, char**& envp);
static void freeEnvironment(char** _envp, int32_t n) { UMemoryPool::_free(_envp, n + 1, sizeof(char*)); } // NB: considera null terminator...
// run command
bool executeWithFileArgument(UString* output, UFile* file);
bool executeAndWait(UString* input = 0, int fd_stdin = -1, int fd_stderr = -1);
bool execute( UString* input = 0, UString* output = 0, int fd_stdin = -1, int fd_stderr = -1);
static UString outputCommand(const UString& cmd, char** envp = 0, int fd_stdin = -1, int fd_stderr = -1);
bool checkForExecute(int mode = R_OK | X_OK)
{
U_TRACE(1, "UCommand::checkForExecute(%d)", mode)
U_INTERNAL_ASSERT_POINTER(argv_exec)
bool result = (U_SYSCALL(access, "%S,%d", argv_exec[0], mode) == 0);
U_RETURN(result);
}
// MANAGE MESSAGE ERROR
static bool isStarted()
{
U_TRACE(0, "UCommand::isStarted()")
bool result = (pid > 0);
U_RETURN(result);
}
static bool isTimeout()
{
U_TRACE(0, "UCommand::isTimeout()")
bool result = (exit_value == -EAGAIN);
U_RETURN(result);
}
static void printMsgError()
{
U_TRACE(0, "UCommand::printMsgError()")
U_INTERNAL_ASSERT_MAJOR(u_buffer_len,0)
U_WARNING("%.*s", u_buffer_len, u_buffer);
u_buffer_len = 0;
}
static bool setMsgError(const char* cmd, bool only_if_error);
// DEBUG
#if defined(U_STDCPP_ENABLE) && defined(DEBUG)
const char* dump(bool reset) const;
#endif
protected:
char** envp;
char* pathcmd;
char** argv_exec;
char** envp_exec;
uint32_t flag_expand;
int32_t ncmd, nenv, nfile;
UString command, environment;
void setCommand();
void freeCommand();
void freeEnvironment();
static void outputCommandWithDialog(const UString& cmd, char** envp, UString* output, int fd_stdin, int fd_stderr, bool dialog);
private:
void setEnvironment(const UString& env) U_NO_EXPORT;
inline void execute(bool flag_stdin, bool flag_stdout, bool flag_stderr) U_NO_EXPORT;
static bool wait() U_NO_EXPORT;
static bool postCommand(UString* input, UString* output) U_NO_EXPORT; // NB: (void*)-1 is a special value...
static void setStdInOutErr(int fd_stdin, bool flag_stdin, bool flag_stdout, int fd_stderr) U_NO_EXPORT;
#ifdef U_COMPILER_DELETE_MEMBERS
UCommand& operator=(const UCommand&) = delete;
#else
UCommand& operator=(const UCommand&) { return *this; }
#endif
friend class UDialog;
friend class UServer_Base;
friend class UProxyPlugIn;
friend class UNoCatPlugIn;
};
#endif