2019-12-13 04:29:58 +00:00
|
|
|
/*
|
2020-04-16 03:42:30 +00:00
|
|
|
Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved.
|
2019-12-13 04:29:58 +00:00
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
|
|
modification, are permitted provided that the following conditions
|
|
|
|
are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright
|
|
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
notice, this list of conditions and the following disclaimer in the
|
|
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
|
|
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
|
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
|
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _HAWK_PIO_H_
|
|
|
|
#define _HAWK_PIO_H_
|
|
|
|
|
|
|
|
#include <hawk-cmn.h>
|
|
|
|
#include <hawk-tio.h>
|
|
|
|
|
|
|
|
/** \file
|
|
|
|
* This file defines a piped interface to a child process. You can execute
|
|
|
|
* a child process, read and write to its stdin, stdout, stderr, and terminate
|
|
|
|
* it. It provides more advanced interface than popen() and pclose().
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The hawk_pio_flag_t defines enumerators to compose flags to hawk_pio_open().
|
|
|
|
*/
|
|
|
|
enum hawk_pio_flag_t
|
|
|
|
{
|
|
|
|
/** enable text based I/O. */
|
|
|
|
HAWK_PIO_TEXT = (1 << 0),
|
|
|
|
HAWK_PIO_IGNOREECERR = (1 << 1),
|
|
|
|
HAWK_PIO_NOAUTOFLUSH = (1 << 2),
|
|
|
|
|
|
|
|
/** execute the command via a system shell
|
|
|
|
* (/bin/sh on unix/linux, cmd.exe on windows and os2) */
|
|
|
|
HAWK_PIO_SHELL = (1 << 3),
|
|
|
|
|
|
|
|
/** indicate that the command to hawk_pio_open() is a multi-byte string.
|
|
|
|
* it is useful if #HAWK_OOCH_IS_UCH is defined. */
|
2019-12-18 08:16:34 +00:00
|
|
|
HAWK_PIO_BCSTRCMD = (1 << 4),
|
2019-12-13 04:29:58 +00:00
|
|
|
|
|
|
|
/** don't attempt to close open file descriptors unknown to pio.
|
|
|
|
* it is useful only on a unix-like systems where file descriptors
|
|
|
|
* not set with FD_CLOEXEC are inherited by a child process.
|
|
|
|
* you're advised to set this option if all normal file descriptors
|
|
|
|
* in your application are open with FD_CLOEXEC set. it can skip
|
|
|
|
* checking a bunch of file descriptors and arranging to close
|
|
|
|
* them to prevent inheritance. */
|
|
|
|
HAWK_PIO_NOCLOEXEC = (1 << 5),
|
|
|
|
|
|
|
|
/** indidate that the command to hawk_pio_open()/hawk_pio_init() is
|
|
|
|
* a pointer to a #hawk_pio_fnc_t structure. supported on unix/linux
|
|
|
|
* only */
|
|
|
|
HAWK_PIO_FNCCMD = (1 << 6),
|
|
|
|
|
|
|
|
/** write to stdin of a child process */
|
|
|
|
HAWK_PIO_WRITEIN = (1 << 8),
|
|
|
|
/** read stdout of a child process */
|
|
|
|
HAWK_PIO_READOUT = (1 << 9),
|
|
|
|
/** read stderr of a child process */
|
|
|
|
HAWK_PIO_READERR = (1 << 10),
|
|
|
|
|
|
|
|
/** redirect stderr to stdout (2>&1, require #HAWK_PIO_READOUT) */
|
|
|
|
HAWK_PIO_ERRTOOUT = (1 << 11),
|
|
|
|
/** redirect stdout to stderr (1>&2, require #HAWK_PIO_READERR) */
|
|
|
|
HAWK_PIO_OUTTOERR = (1 << 12),
|
|
|
|
|
|
|
|
/** redirect stdin to the null device (</dev/null, <NUL) */
|
|
|
|
HAWK_PIO_INTONUL = (1 << 13),
|
|
|
|
/** redirect stdin to the null device (>/dev/null, >NUL) */
|
|
|
|
HAWK_PIO_ERRTONUL = (1 << 14),
|
|
|
|
/** redirect stderr to the null device (2>/dev/null, 2>NUL) */
|
|
|
|
HAWK_PIO_OUTTONUL = (1 << 15),
|
|
|
|
|
|
|
|
/** drop stdin */
|
|
|
|
HAWK_PIO_DROPIN = (1 << 16),
|
|
|
|
/** drop stdout */
|
|
|
|
HAWK_PIO_DROPOUT = (1 << 17),
|
|
|
|
/** drop stderr */
|
|
|
|
HAWK_PIO_DROPERR = (1 << 18),
|
|
|
|
|
|
|
|
/** do not reread if read has been interrupted */
|
|
|
|
HAWK_PIO_READNORETRY = (1 << 21),
|
|
|
|
/** do not rewrite if write has been interrupted */
|
|
|
|
HAWK_PIO_WRITENORETRY = (1 << 22),
|
|
|
|
/** return immediately from hawk_pio_wait() if a child has not exited */
|
|
|
|
HAWK_PIO_WAITNOBLOCK = (1 << 23),
|
|
|
|
/** do not wait again if waitpid has been interrupted */
|
|
|
|
HAWK_PIO_WAITNORETRY = (1 << 24),
|
|
|
|
|
|
|
|
/** put stdin to non-blocking mode (only on supported platforms) */
|
|
|
|
HAWK_PIO_INNOBLOCK = (1 << 25),
|
|
|
|
/** put stdout to non-blocking mode (only on supported platforms)*/
|
|
|
|
HAWK_PIO_OUTNOBLOCK = (1 << 26),
|
|
|
|
/** put stderr to non-blocking mode (only on supported platforms) */
|
|
|
|
HAWK_PIO_ERRNOBLOCK = (1 << 27)
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The hawk_pio_hid_t type defines pipe IDs established to a child process.
|
|
|
|
*/
|
|
|
|
enum hawk_pio_hid_t
|
|
|
|
{
|
|
|
|
HAWK_PIO_IN = 0, /**< stdin of a child process */
|
|
|
|
HAWK_PIO_OUT = 1, /**< stdout of a child process */
|
|
|
|
HAWK_PIO_ERR = 2 /**< stderr of a child process */
|
|
|
|
};
|
|
|
|
typedef enum hawk_pio_hid_t hawk_pio_hid_t;
|
|
|
|
|
|
|
|
|
|
|
|
typedef int (*hawk_pio_fncptr_t) (void* ctx);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The hawk_pio_fnc_t type defines a structure to point to the function
|
|
|
|
* executed in a child process when #HAWK_PIO_FNCCMD is specified.
|
|
|
|
*/
|
|
|
|
typedef struct hawk_pio_fnc_t hawk_pio_fnc_t;
|
|
|
|
struct hawk_pio_fnc_t
|
|
|
|
{
|
|
|
|
hawk_pio_fncptr_t ptr;
|
|
|
|
void* ctx;
|
|
|
|
};
|
|
|
|
|
|
|
|
#if defined(_WIN32)
|
|
|
|
/* <winnt.h> => typedef PVOID HANDLE; */
|
|
|
|
typedef void* hawk_pio_hnd_t; /**< defines a pipe handle type */
|
|
|
|
typedef void* hawk_pio_pid_t; /**< defines a process handle type */
|
|
|
|
# define HAWK_PIO_HND_NIL ((hawk_pio_hnd_t)HAWK_NULL)
|
|
|
|
# define HAWK_PIO_PID_NIL ((hawk_pio_pid_t)HAWK_NULL)
|
|
|
|
#elif defined(__OS2__)
|
|
|
|
/* <os2def.h> => typedef LHANDLE HFILE;
|
|
|
|
typedef LHANDLE PID;
|
|
|
|
typedef unsigned long LHANDLE; */
|
|
|
|
typedef unsigned long hawk_pio_hnd_t; /**< defines a pipe handle type */
|
|
|
|
typedef unsigned long hawk_pio_pid_t; /**< defined a process handle type */
|
|
|
|
# define HAWK_PIO_HND_NIL ((hawk_pio_hnd_t)-1)
|
|
|
|
# define HAWK_PIO_PID_NIL ((hawk_pio_pid_t)-1)
|
|
|
|
#elif defined(__DOS__)
|
|
|
|
typedef int hawk_pio_hnd_t; /**< defines a pipe handle type */
|
|
|
|
typedef int hawk_pio_pid_t; /**< defines a process handle type */
|
|
|
|
# define HAWK_PIO_HND_NIL ((hawk_pio_hnd_t)-1)
|
|
|
|
# define HAWK_PIO_PID_NIL ((hawk_pio_pid_t)-1)
|
|
|
|
#else
|
|
|
|
typedef int hawk_pio_hnd_t; /**< defines a pipe handle type */
|
|
|
|
typedef int hawk_pio_pid_t; /**< defines a process handle type */
|
|
|
|
# define HAWK_PIO_HND_NIL ((hawk_pio_hnd_t)-1)
|
|
|
|
# define HAWK_PIO_PID_NIL ((hawk_pio_pid_t)-1)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
typedef struct hawk_pio_t hawk_pio_t;
|
|
|
|
typedef struct hawk_pio_pin_t hawk_pio_pin_t;
|
|
|
|
|
|
|
|
struct hawk_pio_pin_t
|
|
|
|
{
|
|
|
|
hawk_pio_hnd_t handle;
|
|
|
|
hawk_tio_t* tio;
|
|
|
|
hawk_pio_t* self;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The hawk_pio_t type defines a structure to store status for piped I/O
|
|
|
|
* to a child process. The hawk_pio_xxx() funtions are written around this
|
|
|
|
* type. Do not change the value of each field directly.
|
|
|
|
*/
|
|
|
|
struct hawk_pio_t
|
|
|
|
{
|
2019-12-18 05:15:03 +00:00
|
|
|
hawk_gem_t* gem;
|
2019-12-13 04:29:58 +00:00
|
|
|
int flags; /**< options */
|
|
|
|
hawk_pio_pid_t child; /**< handle to a child process */
|
|
|
|
hawk_pio_pin_t pin[3];
|
|
|
|
};
|
|
|
|
|
|
|
|
/** access the \a child field of the #hawk_pio_t structure */
|
|
|
|
#define HAWK_PIO_CHILD(pio) ((pio)->child)
|
|
|
|
/** get the native handle from the #hawk_pio_t structure */
|
|
|
|
#define HAWK_PIO_HANDLE(pio,hid) ((pio)->pin[hid].handle)
|
|
|
|
|
|
|
|
#if defined(__cplusplus)
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The hawk_pio_open() function executes a command \a cmd and establishes
|
|
|
|
* pipes to it. #HAWK_PIO_SHELL causes the function to execute \a cmd via
|
|
|
|
* the default shell of an underlying system: /bin/sh on *nix, cmd.exe on win32.
|
|
|
|
* On *nix systems, a full path to the command is needed if it is not specified.
|
|
|
|
* If \a env is #HAWK_NULL, the environment of \a cmd inherits that of the
|
|
|
|
* calling process. If you want to pass an empty environment, you can pass
|
2019-12-18 08:16:34 +00:00
|
|
|
* an empty \a env object with no items inserted. If #HAWK_PIO_BCSTRCMD is
|
2019-12-13 04:29:58 +00:00
|
|
|
* specified in \a flags, \a cmd is treated as a multi-byte string whose
|
|
|
|
* character type is #hawk_bch_t.
|
|
|
|
* \return #hawk_pio_t object on success, #HAWK_NULL on failure
|
|
|
|
*/
|
|
|
|
HAWK_EXPORT hawk_pio_t* hawk_pio_open (
|
2019-12-18 08:34:44 +00:00
|
|
|
hawk_gem_t* gem, /**< gem */
|
2019-12-13 04:29:58 +00:00
|
|
|
hawk_oow_t ext, /**< extension size */
|
|
|
|
const hawk_ooch_t* cmd, /**< command to execute */
|
2019-12-18 08:34:44 +00:00
|
|
|
int flags /**< 0 or a number OR'ed of the #hawk_pio_flag_t enumerators*/
|
2019-12-13 04:29:58 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The hawk_pio_close() function closes pipes to a child process and waits for
|
|
|
|
* the child process to exit.
|
|
|
|
*/
|
|
|
|
HAWK_EXPORT void hawk_pio_close (
|
|
|
|
hawk_pio_t* pio /**< pio object */
|
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The hawk_pio_init() functions performs the same task as the hawk_pio_open()
|
|
|
|
* except that you need to allocate a #hawk_pio_t structure and pass it to the
|
|
|
|
* function.
|
|
|
|
* \return 0 on success, -1 on failure
|
|
|
|
*/
|
|
|
|
HAWK_EXPORT int hawk_pio_init (
|
|
|
|
hawk_pio_t* pio, /**< pio object */
|
2019-12-18 08:34:44 +00:00
|
|
|
hawk_gem_t* gem, /**< gem */
|
2019-12-13 04:29:58 +00:00
|
|
|
const hawk_ooch_t* cmd, /**< command to execute */
|
2019-12-18 08:34:44 +00:00
|
|
|
int flags /**< 0 or a number OR'ed of the #hawk_pio_flag_t enumerators*/
|
2019-12-13 04:29:58 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The hawk_pio_fini() function performs the same task as hawk_pio_close()
|
|
|
|
* except that it does not destroy a #hawk_pio_t structure pointed to by \a pio.
|
|
|
|
*/
|
|
|
|
HAWK_EXPORT void hawk_pio_fini (
|
|
|
|
hawk_pio_t* pio /**< pio object */
|
|
|
|
);
|
|
|
|
|
|
|
|
#if defined(HAWK_HAVE_INLINE)
|
|
|
|
static HAWK_INLINE void* hawk_pio_getxtn (hawk_pio_t* pio) { return (void*)(pio + 1); }
|
|
|
|
#else
|
2020-04-13 06:15:03 +00:00
|
|
|
#define hawk_pio_getxtn(pio) ((void*)((hawk_pio_t*)(pio) + 1))
|
2019-12-13 04:29:58 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The hawk_pio_getcmgr() function returns the current character manager.
|
|
|
|
* It returns #HAWK_NULL is \a pio is not opened with #HAWK_PIO_TEXT.
|
|
|
|
*/
|
|
|
|
HAWK_EXPORT hawk_cmgr_t* hawk_pio_getcmgr (
|
|
|
|
hawk_pio_t* pio,
|
|
|
|
hawk_pio_hid_t hid
|
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The hawk_pio_setcmgr() function changes the character manager to \a cmgr.
|
|
|
|
* The character manager is used only if \a pio is opened with #HAWK_PIO_TEXT.
|
|
|
|
*/
|
|
|
|
HAWK_EXPORT void hawk_pio_setcmgr (
|
|
|
|
hawk_pio_t* pio,
|
|
|
|
hawk_pio_hid_t hid,
|
|
|
|
hawk_cmgr_t* cmgr
|
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The hawk_pio_gethnd() function gets a pipe handle.
|
|
|
|
* \return pipe handle
|
|
|
|
*/
|
|
|
|
HAWK_EXPORT hawk_pio_hnd_t hawk_pio_gethnd (
|
|
|
|
const hawk_pio_t* pio, /**< pio object */
|
|
|
|
hawk_pio_hid_t hid /**< handle ID */
|
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The hawk_pio_getchild() function gets a process handle.
|
|
|
|
* \return process handle
|
|
|
|
*/
|
|
|
|
HAWK_EXPORT hawk_pio_pid_t hawk_pio_getchild (
|
|
|
|
const hawk_pio_t* pio /**< pio object */
|
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The hawk_pio_read() fucntion reads at most \a size bytes/characters
|
|
|
|
* and stores them to the buffer pointed to by \a buf.
|
|
|
|
* \return -1 on failure, 0 on EOF, data length read on success
|
|
|
|
*/
|
|
|
|
HAWK_EXPORT hawk_ooi_t hawk_pio_read (
|
|
|
|
hawk_pio_t* pio, /**< pio object */
|
|
|
|
hawk_pio_hid_t hid, /**< handle ID */
|
2020-01-14 09:10:47 +00:00
|
|
|
void* buf, /**< buffer to fill */
|
|
|
|
hawk_oow_t size /**< buffer size */
|
2019-12-13 04:29:58 +00:00
|
|
|
);
|
|
|
|
|
2020-01-14 09:10:47 +00:00
|
|
|
HAWK_EXPORT hawk_ooi_t hawk_pio_readbytes (
|
|
|
|
hawk_pio_t* pio, /**< pio object */
|
|
|
|
hawk_pio_hid_t hid, /**< handle ID */
|
|
|
|
void* buf, /**< buffer to fill */
|
|
|
|
hawk_oow_t size /**< buffer size */
|
|
|
|
);
|
|
|
|
|
|
|
|
|
2019-12-13 04:29:58 +00:00
|
|
|
/**
|
|
|
|
* The hawk_pio_write() function writes up \a size bytes/characters
|
|
|
|
* from the buffer pointed to by \a data. If #HAWK_PIO_TEXT is used
|
|
|
|
* and the \a size parameter is (hawk_oow_t)-1, the function treats
|
|
|
|
* the \a data parameter as a pointer to a null-terminated string.
|
|
|
|
* (hawk_oow_t)-1 into \a size is not treated specially if #HAWK_PIO_TEXT
|
|
|
|
* is not set.
|
|
|
|
*
|
|
|
|
* \return -1 on failure, data length written on success
|
|
|
|
*/
|
|
|
|
HAWK_EXPORT hawk_ooi_t hawk_pio_write (
|
|
|
|
hawk_pio_t* pio, /**< pio object */
|
|
|
|
hawk_pio_hid_t hid, /**< handle ID */
|
2019-12-18 05:15:03 +00:00
|
|
|
const void* data, /**< data to write */
|
|
|
|
hawk_oow_t size /**< data size */
|
2019-12-13 04:29:58 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
HAWK_EXPORT hawk_ooi_t hawk_pio_writebytes (
|
|
|
|
hawk_pio_t* pio, /**< pio object */
|
|
|
|
hawk_pio_hid_t hid, /**< handle ID */
|
2019-12-18 05:15:03 +00:00
|
|
|
const void* data, /**< data to write */
|
|
|
|
hawk_oow_t size /**< data size */
|
2019-12-13 04:29:58 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The hawk_pio_flush() flushes buffered data if #HAWK_PIO_TEXT has been
|
|
|
|
* specified to hawk_pio_open() and hawk_pio_init().
|
|
|
|
*/
|
|
|
|
HAWK_EXPORT hawk_ooi_t hawk_pio_flush (
|
|
|
|
hawk_pio_t* pio, /**< pio object */
|
|
|
|
hawk_pio_hid_t hid /**< handle ID */
|
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The hawk_pio_drain() drops unflushed input and output data in the
|
|
|
|
* buffer.
|
|
|
|
*/
|
|
|
|
HAWK_EXPORT void hawk_pio_drain (
|
|
|
|
hawk_pio_t* pio, /**< pio object */
|
|
|
|
hawk_pio_hid_t hid /**< handle ID */
|
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The hawk_pio_end() function closes a pipe to a child process
|
|
|
|
*/
|
|
|
|
HAWK_EXPORT void hawk_pio_end (
|
|
|
|
hawk_pio_t* pio, /**< pio object */
|
|
|
|
hawk_pio_hid_t hid /**< handle ID */
|
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The hawk_pio_wait() function waits for a child process to terminate.
|
|
|
|
* #HAWK_PIO_WAIT_NORETRY causes the function to return an error and set the
|
|
|
|
* \a pio->errnum field to #HAWK_PIO_EINTR if the underlying system call has
|
|
|
|
* been interrupted. If #HAWK_PIO_WAIT_NOBLOCK is used, the return value of 256
|
|
|
|
* indicates that the child process has not terminated. Otherwise, 256 is never
|
|
|
|
* returned.
|
|
|
|
*
|
|
|
|
* \return
|
|
|
|
* -1 on error, 256 if the child is alive and #HAWK_PIO_WAIT_NOBLOCK is used,
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
HAWK_EXPORT int hawk_pio_wait (
|
|
|
|
hawk_pio_t* pio /**< pio object */
|
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The hawk_pio_kill() function terminates a child process by force.
|
|
|
|
* You should know the danger of calling this function as the function can
|
|
|
|
* kill a process that is not your child process if it has terminated but
|
|
|
|
* there is a new process with the same process handle.
|
|
|
|
* \return 0 on success, -1 on failure
|
|
|
|
*/
|
|
|
|
HAWK_EXPORT int hawk_pio_kill (
|
|
|
|
hawk_pio_t* pio /**< pio object */
|
|
|
|
);
|
|
|
|
|
|
|
|
#if defined(__cplusplus)
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif
|