touched up code a little

This commit is contained in:
hyung-hwan 2009-07-25 06:22:00 +00:00
parent 4496e29945
commit 1e7f2551e5
3 changed files with 245 additions and 244 deletions

View File

@ -1,5 +1,5 @@
/* /*
* $Id: pio.h 243 2009-07-24 04:11:07Z hyunghwan.chung $ * $Id: pio.h 244 2009-07-24 12:22:00Z hyunghwan.chung $
* *
Copyright 2006-2009 Chung, Hyung-Hwan. Copyright 2006-2009 Chung, Hyung-Hwan.
@ -24,22 +24,22 @@
#include <qse/cmn/tio.h> #include <qse/cmn/tio.h>
/** @file /** @file
* This file defines a piped interface to a child process. It provides more * This file defines a piped interface to a child process. You can execute
* advanced interface than popen() and pclose(). * a child process, read and write to its stdin, stdout, stderr, and terminate
* it. It provides more advanced interface than popen() and pclose().
* *
* @todo * @example pio.c
* - rename flags to option
*/ */
/** /**
* Open flags * The qse_pio_oflag_t defines enumerators to compose flags to qse_pio_open().
*/ */
enum qse_pio_open_flag_t enum qse_pio_oflag_t
{ {
/** enable text based IO. */ /** enable text based I/O. */
QSE_PIO_TEXT = (1 << 0), QSE_PIO_TEXT = (1 << 0),
/** invoke the command through a system shell /** execute the command via a system shell
* (/bin/sh on *nix, cmd.exe on windows) */ * (/bin/sh on *nix, cmd.exe on windows) */
QSE_PIO_SHELL = (1 << 1), QSE_PIO_SHELL = (1 << 1),
@ -50,9 +50,9 @@ enum qse_pio_open_flag_t
/** read stderr of a child process */ /** read stderr of a child process */
QSE_PIO_READERR = (1 << 10), QSE_PIO_READERR = (1 << 10),
/** redirect stderr to stdout(2>&1). require QSE_PIO_READOUT */ /** redirect stderr to stdout (2>&1, require QSE_PIO_READOUT) */
QSE_PIO_ERRTOOUT = (1 << 11), QSE_PIO_ERRTOOUT = (1 << 11),
/** redirect stdout to stderr(1>&2). require QSE_PIO_READERR */ /** redirect stdout to stderr (1>&2, require QSE_PIO_READERR) */
QSE_PIO_OUTTOERR = (1 << 12), QSE_PIO_OUTTOERR = (1 << 12),
/** redirect stdin to the null device (</dev/null, <NUL) */ /** redirect stdin to the null device (</dev/null, <NUL) */
@ -67,17 +67,26 @@ enum qse_pio_open_flag_t
/** drop stdout */ /** drop stdout */
QSE_PIO_DROPOUT = (1 << 17), QSE_PIO_DROPOUT = (1 << 17),
/** drop stderr */ /** drop stderr */
QSE_PIO_DROPERR = (1 << 18), QSE_PIO_DROPERR = (1 << 18)
}; };
/**
* The qse_pio_hid_t type defines pipe IDs established to a child process.
*/
enum qse_pio_hid_t enum qse_pio_hid_t
{ {
QSE_PIO_IN = 0, QSE_PIO_IN = 0, /**< stdin of a child process */
QSE_PIO_OUT = 1, QSE_PIO_OUT = 1, /**< stdout of a child process */
QSE_PIO_ERR = 2 QSE_PIO_ERR = 2 /**< stderr of a child process */
}; };
typedef enum qse_pio_hid_t qse_pio_hid_t;
enum qse_pio_io_flag_t /**
* The qse_pio_option_t type defines options to change the behavior of
* qse_pio_xxx functions.
*/
enum qse_pio_option_t
{ {
/*QSE_PIO_READ_NOBLOCK = (1 << 0),*/ /*QSE_PIO_READ_NOBLOCK = (1 << 0),*/
@ -89,12 +98,16 @@ enum qse_pio_io_flag_t
/** do not rewrite if write has been interrupted */ /** do not rewrite if write has been interrupted */
QSE_PIO_WRITE_NORETRY = (1 << 3), QSE_PIO_WRITE_NORETRY = (1 << 3),
/** return immediately from qse_pio_wait() if a child has not exited */
QSE_PIO_WAIT_NOBLOCK = (1 << 4), QSE_PIO_WAIT_NOBLOCK = (1 << 4),
/** do not wait again if waitpid has been interrupted */ /** do not wait again if waitpid has been interrupted */
QSE_PIO_WAIT_NORETRY = (1 << 5) QSE_PIO_WAIT_NORETRY = (1 << 5)
}; };
/**
* The qse_pio_errnum_t type defines error numbers.
*/
enum qse_pio_errnum_t enum qse_pio_errnum_t
{ {
QSE_PIO_ENOERR = 0, /**< no error */ QSE_PIO_ENOERR = 0, /**< no error */
@ -105,21 +118,19 @@ enum qse_pio_errnum_t
QSE_PIO_EPIPE, /**< broken pipe */ QSE_PIO_EPIPE, /**< broken pipe */
QSE_PIO_ESUBSYS /**< subsystem(system call) error */ QSE_PIO_ESUBSYS /**< subsystem(system call) error */
}; };
typedef enum qse_pio_hid_t qse_pio_hid_t;
typedef enum qse_pio_errnum_t qse_pio_errnum_t; typedef enum qse_pio_errnum_t qse_pio_errnum_t;
#ifdef _WIN32 #ifdef _WIN32
/* <winnt.h> => typedef PVOID HANDLE; */ /* <winnt.h> => typedef PVOID HANDLE; */
typedef void* qse_pio_hnd_t; typedef void* qse_pio_hnd_t; /**< defines a pipe handle type */
typedef void* qse_pio_pid_t; typedef void* qse_pio_pid_t; /**< defines a process handle type */
# define QSE_PIO_HND_NIL ((qse_pio_hnd_t)QSE_NULL) # define QSE_PIO_HND_NIL ((qse_pio_hnd_t)QSE_NULL)
# define QSE_PIO_PID_NIL ((qse_pio_pid_t)QSE_NULL) # define QSE_PIO_PID_NIL ((qse_pio_pid_t)QSE_NULL)
#else #else
typedef int qse_pio_hnd_t; typedef int qse_pio_hnd_t; /**< defines a pipe handle type */
typedef int qse_pio_pid_t; typedef int qse_pio_pid_t; /**< defines a process handle type */
# define QSE_PIO_HND_NIL ((qse_pio_hnd_t)-1) # define QSE_PIO_HND_NIL ((qse_pio_hnd_t)-1)
# define QSE_PIO_PID_NIL ((qse_pio_hnd_t)-1) # define QSE_PIO_PID_NIL ((qse_pio_pid_t)-1)
#endif #endif
typedef struct qse_pio_t qse_pio_t; typedef struct qse_pio_t qse_pio_t;
@ -133,21 +144,26 @@ struct qse_pio_pin_t
}; };
/** /**
* The qse_pio_t type defines a pipe I/O type * The qse_pio_t type defines a structure to store status for piped I/O
* to a child process. The qse_pio_xxx() funtions are written around this
* type. Do not change the value of each field directly.
*/ */
struct qse_pio_t struct qse_pio_t
{ {
QSE_DEFINE_COMMON_FIELDS(pio) QSE_DEFINE_COMMON_FIELDS(pio)
int option; /**< options */
int flags; qse_pio_errnum_t errnum; /**< error number */
qse_pio_errnum_t errnum; qse_pio_pid_t child; /**< handle to a child process */
qse_pio_pid_t child;
qse_pio_pin_t pin[3]; qse_pio_pin_t pin[3];
}; };
#define QSE_PIO_ERRNUM(pio) ((pio)->errnum) /** access the @a errnum field of the #qse_pio_t structure */
#define QSE_PIO_FLAGS(pio) ((pio)->flags) #define QSE_PIO_ERRNUM(pio) ((pio)->errnum)
#define QSE_PIO_CHILD(pio) ((pio)->child) /** access the @a option field of the #qse_pio_t structure */
#define QSE_PIO_OPTION(pio) ((pio)->option)
/** access the @a child field of the #qse_pio_t structure */
#define QSE_PIO_CHILD(pio) ((pio)->child)
/** get the native handle from the #qse_pio_t structure */
#define QSE_PIO_HANDLE(pio,hid) ((pio)->pin[hid].handle) #define QSE_PIO_HANDLE(pio,hid) ((pio)->pin[hid].handle)
#ifdef __cplusplus #ifdef __cplusplus
@ -157,188 +173,172 @@ extern "C" {
QSE_DEFINE_COMMON_FUNCTIONS (pio) QSE_DEFINE_COMMON_FUNCTIONS (pio)
/** /**
* The qse_pio_open() function opens pipes to a child process. * The qse_pio_open() function executes a command @cmd and establishes
* QSE_PIO_SHELL drives the function to execute the command via the default * pipes to it. #QSE_PIO_SHELL causes the function to execute @a cmd via
* shell of an underlying system: /bin/sh on *nix, cmd.exe on win32. * the default shell of an underlying system: /bin/sh on *nix, cmd.exe on win32.
* If @a flags is clear of QSE_PIO_SHELL, you should pass the full program path. * On *nix systems, a full path to the command is needed if it is not specified.
* @return #qse_pio_t object on success, #QSE_NULL on failure
*/ */
qse_pio_t* qse_pio_open ( qse_pio_t* qse_pio_open (
qse_mmgr_t* mmgr, /**< a memory manager */ qse_mmgr_t* mmgr, /**< memory manager */
qse_size_t ext, /**< extension size */ qse_size_t ext, /**< extension size */
const qse_char_t* cmd, /**< a command to execute */ const qse_char_t* cmd, /**< command to execute */
int flags /**< options */ int oflags /**< 0 or a number OR'ed of the
#qse_pio_oflag_t enumerators*/
); );
/** /**
* The qse_pio_close() function closes pipes to a child process. * The qse_pio_close() function closes pipes to a child process and waits for
* the child process to exit.
*/ */
void qse_pio_close ( void qse_pio_close (
qse_pio_t* pio qse_pio_t* pio /**< pio object */
); );
/** /**
* The qse_pio_init() function initializes pipes to a child process. * The qse_pio_init() functions performs the same task as the qse_pio_open()
* except that you need to allocate a #qse_pio_t structure and pass it to the
* function.
* @return @a pio on success, #QSE_NULL on failure
*/ */
qse_pio_t* qse_pio_init ( qse_pio_t* qse_pio_init (
qse_pio_t* pio, qse_pio_t* pio, /**< pio object */
qse_mmgr_t* mmgr, qse_mmgr_t* mmgr, /**< memory manager */
const qse_char_t* path, const qse_char_t* cmd, /**< command to execute */
int flags int oflags /**< 0 or a number OR'ed of the
#qse_pio_oflag_t enumerators*/
); );
/** /**
* The qse_pio_fini() function finalizes pipes to a child process. * The qse_pio_fini() function performs the same task as qse_pio_close()
* except that it does not destroy a #qse_pio_t structure pointed to by @a pio.
*/ */
void qse_pio_fini ( void qse_pio_fini (
qse_pio_t* pio qse_pio_t* pio /**< pio object */
); );
int qse_pio_getflags ( /**
qse_pio_t* pio * The qse_pio_getoption() function gets the current option.
* @return option number OR'ed of #qse_pio_option_t enumerators
*/
int qse_pio_getoption (
qse_pio_t* pio /**< pio object */
); );
void qse_pio_setflags ( /**
qse_pio_t* pio, * The qse_pio_setoption() function sets the option.
int flags, */
int opt void qse_pio_setoption (
qse_pio_t* pio, /**< pio object */
int opt /**< 0 or a number OR'ed of #qse_pio_option_t
enumerators */
); );
/****f* Common/qse_pio_geterrnum /**
* NAME * The qse_pio_geterrnum() function returns the number of the last error
* qse_pio_geterrnum - get an error code * occurred.
* * @return error number
* SYNOPSIS
*/ */
qse_pio_errnum_t qse_pio_geterrnum ( qse_pio_errnum_t qse_pio_geterrnum (
qse_pio_t* pio qse_pio_t* pio /**< pio object */
); );
/******/
/****f* Common/qse_pio_geterrmsg /**
* NAME * The qse_pio_geterrmsg() function returns the pointer to a constant string
* qse_pio_geterrmsg - transllate an error code to a string * describing the last error occurred.
* * @return error message
* DESCRIPTION
* The qse_pio_geterrmsg() function returns the pointer to a constant string
* describing the last error occurred.
*
* SYNOPSIS
*/ */
const qse_char_t* qse_pio_geterrmsg ( const qse_char_t* qse_pio_geterrmsg (
qse_pio_t* pio qse_pio_t* pio /**< pio object */
); );
/******/
/****f* Common/qse_pio_gethandle /**
* NAME * The qse_pio_gethandle() function gets a pipe handle.
* qse_pio_gethandle - get native handle * @return pipe handle
*
* SYNOPSIS
*/ */
qse_pio_hnd_t qse_pio_gethandle ( qse_pio_hnd_t qse_pio_gethandle (
qse_pio_t* pio, qse_pio_t* pio, /**< pio object */
qse_pio_hid_t hid qse_pio_hid_t hid /**< handle ID */
); );
/******/
/****f* Common/qse_pio_getchild /**
* NAME * The qse_pio_getchild() function gets a process handle.
* qse_pio_getchild - get the PID of a child process * @return process handle
*
* SYNOPSIS
*/ */
qse_pio_pid_t qse_pio_getchild ( qse_pio_pid_t qse_pio_getchild (
qse_pio_t* pio qse_pio_t* pio /**< pio object */
); );
/******/
/****f* Common/qse_pio_read /**
* NAME * The qse_pio_read() fucntion reads data.
* qse_pio_read - read data * @return -1 on failure, 0 on EOF, data length read on success
* SYNOPSIS
*/ */
qse_ssize_t qse_pio_read ( qse_ssize_t qse_pio_read (
qse_pio_t* pio, qse_pio_t* pio, /**< pio object */
void* buf, void* buf, /**< buffer to fill */
qse_size_t size, qse_size_t size, /**< buffer size */
qse_pio_hid_t hid qse_pio_hid_t hid /**< handle ID */
); );
/******/ /******/
/****f* Common/qse_pio_write /**
* NAME * The qse_pio_write() function writes data.
* qse_pio_write - write data * If @a size is zero, qse_pio_write() closes the the writing
* DESCRIPTION * stream causing the child process reach the end of the stream.
* If the parameter 'size' is zero, qse_pio_write() closes the the writing * @return -1 on failure, data length written on success
* stream causing the child process reach the end of the stream.
* SYNOPSIS
*/ */
qse_ssize_t qse_pio_write ( qse_ssize_t qse_pio_write (
qse_pio_t* pio, qse_pio_t* pio, /**< pio object */
const void* data, const void* data, /**< data to write */
qse_size_t size, qse_size_t size, /**< data size */
qse_pio_hid_t hid qse_pio_hid_t hid /**< handle ID */
); );
/******/ /******/
/****f* Common/qse_pio_flush /**
* NAME * The qse_pio_flush() flushes buffered data if #QSE_PIO_TEXT has been
* qse_pio_flush - flush data * specified to qse_pio_open() and qse_pio_init().
*
* SYNOPSIS
*/ */
qse_ssize_t qse_pio_flush ( qse_ssize_t qse_pio_flush (
qse_pio_t* pio, qse_pio_t* pio, /**< pio object */
qse_pio_hid_t hid qse_pio_hid_t hid /**< handle ID */
); );
/*****/
/****f* Common/qse_pio_end /**
* NAME * The qse_pio_end() function closes a pipe to a child process
* qse_pio_end - close native handle
*
* SYNOPSIS
*/ */
void qse_pio_end ( void qse_pio_end (
qse_pio_t* pio, qse_pio_t* pio, /**< pio object */
qse_pio_hid_t hid qse_pio_hid_t hid /**< handle ID */
); );
/******/
/****f* Common/qse_pio_wait /**
* NAME * The qse_pio_wait() function waits for a child process to terminate.
* qse_pio_wait - wait for a child process * #QSE_PIO_WAIT_NORETRY causes the function to return an error and set the
* DESCRIPTION * @a pio->errnum field to #QSE_PIO_EINTR if the underlying system call has
* QSE_PIO_WAIT_NORETRY causes the function to return an error and set the * been interrupted. If #QSE_PIO_WAIT_NOBLOCK is used, the return value of 256
* errnum field to QSE_PIO_EINTR if the underlying system call is interrupted. * indicates that the child process has not terminated. Otherwise, 256 is never
* returned.
* *
* When QSE_PIO_WAIT_NOBLOCK is used, the return value of 256 indicates that * @return
* the child process has not terminated. If the flag is not used, 256 is never * -1 on error, 256 if the child is alive and #QSE_PIO_WAIT_NOBLOCK is used,
* returned.
* RETURN
* -1 on error, 256 if the child is alive and QSE_PIO_NOBLOCK is used,
* a number between 0 and 255 inclusive if the child process ends normally, * a number between 0 and 255 inclusive if the child process ends normally,
* 256 + signal number if the child process is terminated by a signal. * 256 + signal number if the child process is terminated by a signal.
* SYNOPSIS
*/ */
int qse_pio_wait ( int qse_pio_wait (
qse_pio_t* pio qse_pio_t* pio /**< pio object */
); );
/******/
/****f* Common/qse_pio_kill /**
* NAME * The qse_pio_kill() function terminates a child process by force.
* qse_pio_kill - terminate the child process * You should know the danger of calling this function as the function can
* NOTES * kill a process that is not your child process if it has terminated but
* You should know the danger of calling this function as the function can * there is a new process with the same process handle.
* kill a process that is not your child process if it has terminated but * @return 0 on success, -1 on failure
* there is a new process with the same process handle.
* SYNOPSIS
*/ */
int qse_pio_kill ( int qse_pio_kill (
qse_pio_t* pio qse_pio_t* pio /**< pio object */
); );
/******/
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -1,5 +1,5 @@
/* /*
* $Id: pio.c 242 2009-07-23 13:01:52Z hyunghwan.chung $ * $Id: pio.c 244 2009-07-24 12:22:00Z hyunghwan.chung $
* *
Copyright 2006-2009 Chung, Hyung-Hwan. Copyright 2006-2009 Chung, Hyung-Hwan.
@ -35,8 +35,7 @@ static qse_ssize_t pio_input (int cmd, void* arg, void* buf, qse_size_t size);
static qse_ssize_t pio_output (int cmd, void* arg, void* buf, qse_size_t size); static qse_ssize_t pio_output (int cmd, void* arg, void* buf, qse_size_t size);
qse_pio_t* qse_pio_open ( qse_pio_t* qse_pio_open (
qse_mmgr_t* mmgr, qse_size_t ext, qse_mmgr_t* mmgr, qse_size_t ext, const qse_char_t* path, int oflags)
const qse_char_t* path, int flags)
{ {
qse_pio_t* pio; qse_pio_t* pio;
@ -53,7 +52,7 @@ qse_pio_t* qse_pio_open (
pio = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(qse_pio_t) + ext); pio = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(qse_pio_t) + ext);
if (pio == QSE_NULL) return QSE_NULL; if (pio == QSE_NULL) return QSE_NULL;
if (qse_pio_init (pio, mmgr, path, flags) == QSE_NULL) if (qse_pio_init (pio, mmgr, path, oflags) == QSE_NULL)
{ {
QSE_MMGR_FREE (mmgr, pio); QSE_MMGR_FREE (mmgr, pio);
return QSE_NULL; return QSE_NULL;
@ -69,7 +68,7 @@ void qse_pio_close (qse_pio_t* pio)
} }
qse_pio_t* qse_pio_init ( qse_pio_t* qse_pio_init (
qse_pio_t* pio, qse_mmgr_t* mmgr, const qse_char_t* cmd, int flags) qse_pio_t* pio, qse_mmgr_t* mmgr, const qse_char_t* cmd, int oflags)
{ {
qse_pio_hnd_t handle[6] = qse_pio_hnd_t handle[6] =
@ -112,7 +111,7 @@ qse_pio_t* qse_pio_init (
secattr.bInheritHandle = TRUE; secattr.bInheritHandle = TRUE;
secattr.lpSecurityDescriptor = QSE_NULL; secattr.lpSecurityDescriptor = QSE_NULL;
if (flags & QSE_PIO_WRITEIN) if (oflags & QSE_PIO_WRITEIN)
{ {
/* child reads, parent writes */ /* child reads, parent writes */
if (CreatePipe ( if (CreatePipe (
@ -126,7 +125,7 @@ qse_pio_t* qse_pio_init (
minidx = 0; maxidx = 1; minidx = 0; maxidx = 1;
} }
if (flags & QSE_PIO_READOUT) if (oflags & QSE_PIO_READOUT)
{ {
/* child writes, parent reads */ /* child writes, parent reads */
if (CreatePipe ( if (CreatePipe (
@ -141,7 +140,7 @@ qse_pio_t* qse_pio_init (
maxidx = 3; maxidx = 3;
} }
if (flags & QSE_PIO_READERR) if (oflags & QSE_PIO_READERR)
{ {
/* child writes, parent reads */ /* child writes, parent reads */
if (CreatePipe ( if (CreatePipe (
@ -156,9 +155,9 @@ qse_pio_t* qse_pio_init (
maxidx = 5; maxidx = 5;
} }
if ((flags & QSE_PIO_INTONUL) || if ((oflags & QSE_PIO_INTONUL) ||
(flags & QSE_PIO_OUTTONUL) || (oflags & QSE_PIO_OUTTONUL) ||
(flags & QSE_PIO_ERRTONUL)) (oflags & QSE_PIO_ERRTONUL))
{ {
windevnul = CreateFile( windevnul = CreateFile(
QSE_T("NUL"), GENERIC_READ | GENERIC_WRITE, QSE_T("NUL"), GENERIC_READ | GENERIC_WRITE,
@ -177,34 +176,34 @@ qse_pio_t* qse_pio_init (
startup.hStdOutput = INVALID_HANDLE_VALUE; startup.hStdOutput = INVALID_HANDLE_VALUE;
startup.hStdOutput = INVALID_HANDLE_VALUE; startup.hStdOutput = INVALID_HANDLE_VALUE;
if (flags & QSE_PIO_WRITEIN) startup.hStdInput = handle[0]; if (oflags & QSE_PIO_WRITEIN) startup.hStdInput = handle[0];
if (flags & QSE_PIO_READOUT) if (oflags & QSE_PIO_READOUT)
{ {
startup.hStdOutput = handle[3]; startup.hStdOutput = handle[3];
if (flags & QSE_PIO_ERRTOOUT) startup.hStdError = handle[3]; if (oflags & QSE_PIO_ERRTOOUT) startup.hStdError = handle[3];
} }
if (flags & QSE_PIO_READERR) if (oflags & QSE_PIO_READERR)
{ {
startup.hStdError = handle[5]; startup.hStdError = handle[5];
if (flags & QSE_PIO_OUTTOERR) startup.hStdOutput = handle[5]; if (oflags & QSE_PIO_OUTTOERR) startup.hStdOutput = handle[5];
} }
if (flags & QSE_PIO_INTONUL) startup.hStdOutput = windevnul; if (oflags & QSE_PIO_INTONUL) startup.hStdOutput = windevnul;
if (flags & QSE_PIO_OUTTONUL) startup.hStdOutput = windevnul; if (oflags & QSE_PIO_OUTTONUL) startup.hStdOutput = windevnul;
if (flags & QSE_PIO_ERRTONUL) startup.hStdError = windevnul; if (oflags & QSE_PIO_ERRTONUL) startup.hStdError = windevnul;
if (flags & QSE_PIO_DROPIN) startup.hStdInput = INVALID_HANDLE_VALUE; if (oflags & QSE_PIO_DROPIN) startup.hStdInput = INVALID_HANDLE_VALUE;
if (flags & QSE_PIO_DROPOUT) startup.hStdOutput = INVALID_HANDLE_VALUE; if (oflags & QSE_PIO_DROPOUT) startup.hStdOutput = INVALID_HANDLE_VALUE;
if (flags & QSE_PIO_DROPERR) startup.hStdError = INVALID_HANDLE_VALUE; if (oflags & QSE_PIO_DROPERR) startup.hStdError = INVALID_HANDLE_VALUE;
startup.dwFlags |= STARTF_USESTDHANDLES; startup.dwFlags |= STARTF_USESTDHANDLES;
/* there is nothing to do for QSE_PIO_SHELL as CreateProcess /* there is nothing to do for QSE_PIO_SHELL as CreateProcess
* takes the entire command line */ * takes the entire command line */
if (flags & QSE_PIO_SHELL) if (oflags & QSE_PIO_SHELL)
{ {
dup = QSE_MMGR_ALLOC ( dup = QSE_MMGR_ALLOC (
mmgr, (11+qse_strlen(cmd)+1 )*QSE_SIZEOF(qse_char_t)); mmgr, (11+qse_strlen(cmd)+1 )*QSE_SIZEOF(qse_char_t));
@ -237,17 +236,17 @@ qse_pio_t* qse_pio_init (
if (x == FALSE) goto oops; if (x == FALSE) goto oops;
if (flags & QSE_PIO_WRITEIN) if (oflags & QSE_PIO_WRITEIN)
{ {
CloseHandle (handle[0]); CloseHandle (handle[0]);
handle[0] = QSE_PIO_HND_NIL; handle[0] = QSE_PIO_HND_NIL;
} }
if (flags & QSE_PIO_READOUT) if (oflags & QSE_PIO_READOUT)
{ {
CloseHandle (handle[3]); CloseHandle (handle[3]);
handle[3] = QSE_PIO_HND_NIL; handle[3] = QSE_PIO_HND_NIL;
} }
if (flags & QSE_PIO_READERR) if (oflags & QSE_PIO_READERR)
{ {
CloseHandle (handle[5]); CloseHandle (handle[5]);
handle[5] = QSE_PIO_HND_NIL; handle[5] = QSE_PIO_HND_NIL;
@ -257,22 +256,22 @@ qse_pio_t* qse_pio_init (
pio->child = procinfo.hProcess; pio->child = procinfo.hProcess;
#else #else
if (flags & QSE_PIO_WRITEIN) if (oflags & QSE_PIO_WRITEIN)
{ {
if (QSE_PIPE(&handle[0]) == -1) goto oops; if (QSE_PIPE(&handle[0]) <= -1) goto oops;
minidx = 0; maxidx = 1; minidx = 0; maxidx = 1;
} }
if (flags & QSE_PIO_READOUT) if (oflags & QSE_PIO_READOUT)
{ {
if (QSE_PIPE(&handle[2]) == -1) goto oops; if (QSE_PIPE(&handle[2]) <= -1) goto oops;
if (minidx == -1) minidx = 2; if (minidx == -1) minidx = 2;
maxidx = 3; maxidx = 3;
} }
if (flags & QSE_PIO_READERR) if (oflags & QSE_PIO_READERR)
{ {
if (QSE_PIPE(&handle[4]) == -1) goto oops; if (QSE_PIPE(&handle[4]) <= -1) goto oops;
if (minidx == -1) minidx = 4; if (minidx == -1) minidx = 4;
maxidx = 5; maxidx = 5;
} }
@ -280,7 +279,7 @@ qse_pio_t* qse_pio_init (
if (maxidx == -1) goto oops; if (maxidx == -1) goto oops;
pid = QSE_FORK(); pid = QSE_FORK();
if (pid == -1) goto oops; if (pid <= -1) goto oops;
if (pid == 0) if (pid == 0)
{ {
@ -302,7 +301,7 @@ qse_pio_t* qse_pio_init (
struct rlimit rlim; struct rlimit rlim;
int fd; int fd;
if (QSE_GETRLIMIT (RLIMIT_NOFILE, &rlim) == -1 || if (QSE_GETRLIMIT (RLIMIT_NOFILE, &rlim) <= -1 ||
rlim.rlim_max == RLIM_INFINITY) rlim.rlim_max == RLIM_INFINITY)
{ {
#ifdef HAVE_SYSCONF #ifdef HAVE_SYSCONF
@ -323,77 +322,77 @@ qse_pio_t* qse_pio_init (
fd != handle[5]) QSE_CLOSE (fd); fd != handle[5]) QSE_CLOSE (fd);
} }
if (flags & QSE_PIO_WRITEIN) if (oflags & QSE_PIO_WRITEIN)
{ {
/* child should read */ /* child should read */
QSE_CLOSE (handle[1]); QSE_CLOSE (handle[1]);
handle[1] = QSE_PIO_HND_NIL; handle[1] = QSE_PIO_HND_NIL;
if (QSE_DUP2 (handle[0], 0) == -1) goto child_oops; if (QSE_DUP2 (handle[0], 0) <= -1) goto child_oops;
QSE_CLOSE (handle[0]); QSE_CLOSE (handle[0]);
handle[0] = QSE_PIO_HND_NIL; handle[0] = QSE_PIO_HND_NIL;
} }
if (flags & QSE_PIO_READOUT) if (oflags & QSE_PIO_READOUT)
{ {
/* child should write */ /* child should write */
QSE_CLOSE (handle[2]); QSE_CLOSE (handle[2]);
handle[2] = QSE_PIO_HND_NIL; handle[2] = QSE_PIO_HND_NIL;
if (QSE_DUP2 (handle[3], 1) == -1) goto child_oops; if (QSE_DUP2 (handle[3], 1) <= -1) goto child_oops;
if (flags & QSE_PIO_ERRTOOUT) if (oflags & QSE_PIO_ERRTOOUT)
{ {
if (QSE_DUP2 (handle[3], 2) == -1) goto child_oops; if (QSE_DUP2 (handle[3], 2) <= -1) goto child_oops;
} }
QSE_CLOSE (handle[3]); QSE_CLOSE (handle[3]);
handle[3] = QSE_PIO_HND_NIL; handle[3] = QSE_PIO_HND_NIL;
} }
if (flags & QSE_PIO_READERR) if (oflags & QSE_PIO_READERR)
{ {
/* child should write */ /* child should write */
QSE_CLOSE (handle[4]); QSE_CLOSE (handle[4]);
handle[4] = QSE_PIO_HND_NIL; handle[4] = QSE_PIO_HND_NIL;
if (QSE_DUP2 (handle[5], 2) == -1) goto child_oops; if (QSE_DUP2 (handle[5], 2) <= -1) goto child_oops;
if (flags & QSE_PIO_OUTTOERR) if (oflags & QSE_PIO_OUTTOERR)
{ {
if (QSE_DUP2 (handle[5], 1) == -1) goto child_oops; if (QSE_DUP2 (handle[5], 1) <= -1) goto child_oops;
} }
QSE_CLOSE (handle[5]); QSE_CLOSE (handle[5]);
handle[5] = QSE_PIO_HND_NIL; handle[5] = QSE_PIO_HND_NIL;
} }
if ((flags & QSE_PIO_INTONUL) || if ((oflags & QSE_PIO_INTONUL) ||
(flags & QSE_PIO_OUTTONUL) || (oflags & QSE_PIO_OUTTONUL) ||
(flags & QSE_PIO_ERRTONUL)) (oflags & QSE_PIO_ERRTONUL))
{ {
#ifdef O_LARGEFILE #ifdef O_LARGEFILE
devnull = QSE_OPEN ("/dev/null", O_RDWR|O_LARGEFILE, 0); devnull = QSE_OPEN ("/dev/null", O_RDWR|O_LARGEFILE, 0);
#else #else
devnull = QSE_OPEN ("/dev/null", O_RDWR, 0); devnull = QSE_OPEN ("/dev/null", O_RDWR, 0);
#endif #endif
if (devnull == -1) goto child_oops; if (devnull <= -1) goto child_oops;
} }
if ((flags & QSE_PIO_INTONUL) && if ((oflags & QSE_PIO_INTONUL) &&
QSE_DUP2(devnull,0) == -1) goto child_oops; QSE_DUP2(devnull,0) <= -1) goto child_oops;
if ((flags & QSE_PIO_OUTTONUL) && if ((oflags & QSE_PIO_OUTTONUL) &&
QSE_DUP2(devnull,1) == -1) goto child_oops; QSE_DUP2(devnull,1) <= -1) goto child_oops;
if ((flags & QSE_PIO_ERRTONUL) && if ((oflags & QSE_PIO_ERRTONUL) &&
QSE_DUP2(devnull,2) == -1) goto child_oops; QSE_DUP2(devnull,2) <= -1) goto child_oops;
if ((flags & QSE_PIO_INTONUL) || if ((oflags & QSE_PIO_INTONUL) ||
(flags & QSE_PIO_OUTTONUL) || (oflags & QSE_PIO_OUTTONUL) ||
(flags & QSE_PIO_ERRTONUL)) QSE_CLOSE (devnull); (oflags & QSE_PIO_ERRTONUL)) QSE_CLOSE (devnull);
if (flags & QSE_PIO_DROPIN) QSE_CLOSE(0); if (oflags & QSE_PIO_DROPIN) QSE_CLOSE(0);
if (flags & QSE_PIO_DROPOUT) QSE_CLOSE(1); if (oflags & QSE_PIO_DROPOUT) QSE_CLOSE(1);
if (flags & QSE_PIO_DROPERR) QSE_CLOSE(2); if (oflags & QSE_PIO_DROPERR) QSE_CLOSE(2);
#ifdef QSE_CHAR_IS_MCHAR #ifdef QSE_CHAR_IS_MCHAR
if (flags & QSE_PIO_SHELL) mcmd = (qse_char_t*)cmd; if (oflags & QSE_PIO_SHELL) mcmd = (qse_char_t*)cmd;
else else
{ {
mcmd = qse_strdup (cmd, pio->mmgr); mcmd = qse_strdup (cmd, pio->mmgr);
@ -408,7 +407,7 @@ qse_pio_t* qse_pio_init (
} }
} }
#else #else
if (flags & QSE_PIO_SHELL) if (oflags & QSE_PIO_SHELL)
{ {
n = qse_wcstombslen (cmd, &mn); n = qse_wcstombslen (cmd, &mn);
if (cmd[n] != QSE_WT('\0')) if (cmd[n] != QSE_WT('\0'))
@ -453,7 +452,7 @@ qse_pio_t* qse_pio_init (
if (mcmd == QSE_NULL) goto child_oops; if (mcmd == QSE_NULL) goto child_oops;
} }
if (flags & QSE_PIO_SHELL) if (oflags & QSE_PIO_SHELL)
{ {
/* qse_wcstombs() should succeed as /* qse_wcstombs() should succeed as
* qse_wcstombslen() was successful above */ * qse_wcstombslen() was successful above */
@ -471,7 +470,7 @@ qse_pio_t* qse_pio_init (
} }
#endif #endif
if (flags & QSE_PIO_SHELL) if (oflags & QSE_PIO_SHELL)
{ {
const qse_mchar_t* argv[4]; const qse_mchar_t* argv[4];
@ -508,7 +507,7 @@ qse_pio_t* qse_pio_init (
/* parent */ /* parent */
pio->child = pid; pio->child = pid;
if (flags & QSE_PIO_WRITEIN) if (oflags & QSE_PIO_WRITEIN)
{ {
/* /*
* 012345 * 012345
@ -519,7 +518,7 @@ qse_pio_t* qse_pio_init (
QSE_CLOSE (handle[0]); handle[0] = QSE_PIO_HND_NIL; QSE_CLOSE (handle[0]); handle[0] = QSE_PIO_HND_NIL;
} }
if (flags & QSE_PIO_READOUT) if (oflags & QSE_PIO_READOUT)
{ {
/* /*
* 012345 * 012345
@ -530,7 +529,7 @@ qse_pio_t* qse_pio_init (
QSE_CLOSE (handle[3]); handle[3] = QSE_PIO_HND_NIL; QSE_CLOSE (handle[3]); handle[3] = QSE_PIO_HND_NIL;
} }
if (flags & QSE_PIO_READERR) if (oflags & QSE_PIO_READERR)
{ {
/* /*
* 012345 * 012345
@ -553,7 +552,7 @@ qse_pio_t* qse_pio_init (
pio->pin[QSE_PIO_OUT].handle = handle[2]; pio->pin[QSE_PIO_OUT].handle = handle[2];
pio->pin[QSE_PIO_ERR].handle = handle[4]; pio->pin[QSE_PIO_ERR].handle = handle[4];
if (flags & QSE_PIO_TEXT) if (oflags & QSE_PIO_TEXT)
{ {
for (i = 0; i < QSE_COUNTOF(tio); i++) for (i = 0; i < QSE_COUNTOF(tio); i++)
{ {
@ -566,13 +565,13 @@ qse_pio_t* qse_pio_init (
qse_tio_attachout (tio[i], pio_output, &pio->pin[i]): qse_tio_attachout (tio[i], pio_output, &pio->pin[i]):
qse_tio_attachin (tio[i], pio_input, &pio->pin[i]); qse_tio_attachin (tio[i], pio_input, &pio->pin[i]);
if (r == -1) goto oops; if (r <= -1) goto oops;
pio->pin[i].tio = tio[i]; pio->pin[i].tio = tio[i];
} }
} }
pio->flags = 0; pio->option = 0;
return pio; return pio;
oops: oops:
@ -599,26 +598,19 @@ void qse_pio_fini (qse_pio_t* pio)
qse_pio_end (pio, QSE_PIO_OUT); qse_pio_end (pio, QSE_PIO_OUT);
qse_pio_end (pio, QSE_PIO_IN); qse_pio_end (pio, QSE_PIO_IN);
qse_pio_setflags (pio, QSE_PIO_WAIT_NOBLOCK|QSE_PIO_WAIT_NORETRY, -1); pio->option &= ~QSE_PIO_WAIT_NOBLOCK;
pio->option &= ~QSE_PIO_WAIT_NORETRY;
qse_pio_wait (pio); qse_pio_wait (pio);
} }
int qse_pio_getflags (qse_pio_t* pio) int qse_pio_getoption (qse_pio_t* pio)
{ {
return pio->flags; return pio->option;
} }
void qse_pio_setflags (qse_pio_t* pio, int flags, int op) void qse_pio_setoption (qse_pio_t* pio, int opt)
{ {
/* pio->option = opt;
op => set
op => off
op => on
*/
if (op == 0) pio->flags = flags;
else if (op > 0) pio->flags |= flags;
else /*if (op < 0)*/ pio->flags &= ~flags;
} }
qse_pio_errnum_t qse_pio_geterrnum (qse_pio_t* pio) qse_pio_errnum_t qse_pio_geterrnum (qse_pio_t* pio)
@ -626,8 +618,6 @@ qse_pio_errnum_t qse_pio_geterrnum (qse_pio_t* pio)
return pio->errnum; return pio->errnum;
} }
/* TODO: qse_pio_geterrmsg (qse_pio_t* pio) */
const qse_char_t* qse_pio_geterrmsg (qse_pio_t* pio) const qse_char_t* qse_pio_geterrmsg (qse_pio_t* pio)
{ {
static const qse_char_t* __errstr[] = static const qse_char_t* __errstr[] =
@ -694,7 +684,7 @@ reread:
{ {
if (errno == EINTR) if (errno == EINTR)
{ {
if (pio->flags & QSE_PIO_READ_NORETRY) if (pio->option & QSE_PIO_READ_NORETRY)
pio->errnum = QSE_PIO_EINTR; pio->errnum = QSE_PIO_EINTR;
else goto reread; else goto reread;
} }
@ -755,7 +745,7 @@ rewrite:
{ {
if (errno == EINTR) if (errno == EINTR)
{ {
if (pio->flags & QSE_PIO_WRITE_NORETRY) if (pio->option & QSE_PIO_WRITE_NORETRY)
pio->errnum = QSE_PIO_EINTR; pio->errnum = QSE_PIO_EINTR;
else goto rewrite; else goto rewrite;
} }
@ -820,7 +810,7 @@ int qse_pio_wait (qse_pio_t* pio)
} }
w = WaitForSingleObject (pio->child, w = WaitForSingleObject (pio->child,
((pio->flags & QSE_PIO_WAIT_NOBLOCK)? 0: INFINITE) ((pio->option & QSE_PIO_WAIT_NOBLOCK)? 0: INFINITE)
); );
if (w == WAIT_TIMEOUT) if (w == WAIT_TIMEOUT)
{ {
@ -871,14 +861,14 @@ int qse_pio_wait (qse_pio_t* pio)
return -1; return -1;
} }
if (pio->flags & QSE_PIO_WAIT_NOBLOCK) opt |= WNOHANG; if (pio->option & QSE_PIO_WAIT_NOBLOCK) opt |= WNOHANG;
while (1) while (1)
{ {
int status, n; int status, n;
n = QSE_WAITPID (pio->child, &status, opt); n = QSE_WAITPID (pio->child, &status, opt);
if (n == -1) if (n <= -1)
{ {
if (errno == ECHILD) if (errno == ECHILD)
{ {
@ -889,7 +879,7 @@ int qse_pio_wait (qse_pio_t* pio)
} }
else if (errno == EINTR) else if (errno == EINTR)
{ {
if (pio->flags & QSE_PIO_WAIT_NORETRY) if (pio->option & QSE_PIO_WAIT_NORETRY)
pio->errnum = QSE_PIO_EINTR; pio->errnum = QSE_PIO_EINTR;
else continue; else continue;
} }
@ -901,7 +891,7 @@ int qse_pio_wait (qse_pio_t* pio)
if (n == 0) if (n == 0)
{ {
/* when WNOHANG is not specified, 0 can't be returned */ /* when WNOHANG is not specified, 0 can't be returned */
QSE_ASSERT (pio->flags & QSE_PIO_WAIT_NOBLOCK); QSE_ASSERT (pio->option & QSE_PIO_WAIT_NOBLOCK);
ret = 255 + 1; ret = 255 + 1;
/* the child process is still alive */ /* the child process is still alive */
@ -963,7 +953,7 @@ int qse_pio_kill (qse_pio_t* pio)
return 0; return 0;
#else #else
n = QSE_KILL (pio->child, SIGKILL); n = QSE_KILL (pio->child, SIGKILL);
if (n == -1) pio->errnum = QSE_PIO_ESUBSYS; if (n <= -1) pio->errnum = QSE_PIO_ESUBSYS;
return n; return n;
#endif #endif
} }

View File

@ -6,6 +6,9 @@
#ifdef _WIN32 #ifdef _WIN32
# include <windows.h> # include <windows.h>
#else
# include <unistd.h>
# include <sys/wait.h>
#endif #endif
#define R(f) \ #define R(f) \
@ -41,7 +44,10 @@ static int pio1 (const qse_char_t* cmd, int oflags, qse_pio_hid_t rhid)
if (n == 0) break; if (n == 0) break;
if (n <= -1) if (n <= -1)
{ {
qse_printf (QSE_T("qse_pio_read() returned error - %s\n"), qse_pio_geterrmsg(pio)); qse_printf (
QSE_T("qse_pio_read() returned error - %s\n"),
qse_pio_geterrmsg(pio)
);
break; break;
} }
@ -61,7 +67,8 @@ static int pio1 (const qse_char_t* cmd, int oflags, qse_pio_hid_t rhid)
qse_printf (QSE_T("qse_pio_wait returns %d\n"), x); qse_printf (QSE_T("qse_pio_wait returns %d\n"), x);
if (x <= -1) if (x <= -1)
{ {
qse_printf (QSE_T("error code : %d, error string: %s\n"), (int)qse_pio_geterrnum(pio), qse_pio_geterrmsg(pio)); qse_printf (QSE_T("error code : %d, error string: %s\n"),
(int)qse_pio_geterrnum(pio), qse_pio_geterrmsg(pio));
} }
qse_pio_close (pio); qse_pio_close (pio);
@ -95,7 +102,10 @@ static int pio2 (const qse_char_t* cmd, int oflags, qse_pio_hid_t rhid)
if (n == 0) break; if (n == 0) break;
if (n < 0) if (n < 0)
{ {
qse_printf (QSE_T("qse_pio_read() returned error - %s\n"), qse_pio_geterrmsg(pio)); qse_printf (
QSE_T("qse_pio_read() returned error - %s\n"),
qse_pio_geterrmsg(pio)
);
break; break;
} }
@ -111,7 +121,8 @@ static int pio2 (const qse_char_t* cmd, int oflags, qse_pio_hid_t rhid)
qse_printf (QSE_T("qse_pio_wait returns %d\n"), x); qse_printf (QSE_T("qse_pio_wait returns %d\n"), x);
if (x <= -1) if (x <= -1)
{ {
qse_printf (QSE_T("error code : %d, error string: %s\n"), (int)qse_pio_geterrnum(pio), qse_pio_geterrmsg(pio)); qse_printf (QSE_T("error code : %d, error string: %s\n"),
(int)qse_pio_geterrnum(pio), qse_pio_geterrmsg(pio));
} }
qse_pio_close (pio); qse_pio_close (pio);
@ -216,9 +227,9 @@ static int test8 (void)
{ {
return pio1 ( return pio1 (
#ifdef _WIN32 #ifdef _WIN32
QSE_T("sll.exe"), QSE_T(".\\sll.exe"),
#else #else
QSE_T("ls -laF"), QSE_T("/bin/ls -laF"),
#endif #endif
QSE_PIO_READOUT|QSE_PIO_WRITEIN| QSE_PIO_READOUT|QSE_PIO_WRITEIN|
QSE_PIO_OUTTONUL|QSE_PIO_ERRTONUL|QSE_PIO_INTONUL, QSE_PIO_OUTTONUL|QSE_PIO_ERRTONUL|QSE_PIO_INTONUL,