389 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			389 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|     Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved.
 | |
| 
 | |
|     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. */
 | |
| 	HAWK_PIO_BCSTRCMD        = (1 << 4),
 | |
| 
 | |
| 	/** 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
 | |
| {
 | |
| 	hawk_gem_t*       gem;
 | |
| 	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
 | |
|  * an empty \a env object with no items inserted. If #HAWK_PIO_BCSTRCMD is
 | |
|  * 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 (
 | |
| 	hawk_gem_t*        gem,    /**< gem */
 | |
| 	hawk_oow_t         ext,    /**< extension size */
 | |
| 	const hawk_ooch_t* cmd,    /**< command to execute */
 | |
| 	int                flags   /**< 0 or a number OR'ed of the #hawk_pio_flag_t enumerators*/
 | |
| );
 | |
| 
 | |
| /**
 | |
|  * 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 */
 | |
| 	hawk_gem_t*        gem,    /**< gem */
 | |
| 	const hawk_ooch_t* cmd,    /**< command to execute */
 | |
| 	int                flags   /**< 0 or a number OR'ed of the #hawk_pio_flag_t enumerators*/
 | |
| );
 | |
| 
 | |
| /**
 | |
|  * 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
 | |
| #define hawk_pio_getxtn(pio) ((void*)((hawk_pio_t*)(pio) + 1))
 | |
| #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 */
 | |
| 	void*          buf,  /**< buffer to fill */
 | |
| 	hawk_oow_t     size  /**< buffer size */
 | |
| );
 | |
| 
 | |
| 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 */
 | |
| );
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * 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 */
 | |
| 	const void*    data,  /**< data to write */
 | |
| 	hawk_oow_t     size   /**< data size */
 | |
| );
 | |
| 
 | |
| HAWK_EXPORT hawk_ooi_t hawk_pio_writebytes (
 | |
| 	hawk_pio_t*    pio,   /**< pio object */
 | |
| 	hawk_pio_hid_t hid,   /**< handle ID */
 | |
| 	const void*    data,  /**< data to write */
 | |
| 	hawk_oow_t     size   /**< data size */
 | |
| );
 | |
| 
 | |
| /**
 | |
|  * 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
 |