From 46e4ed50870e907d8cd2b6cfd12abe8afd2aafe9 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Thu, 15 Jan 2009 03:58:27 +0000 Subject: [PATCH] implemented the pipe to the child process and integrated it into awk - renamed pio to pcp - finished the first version of pcp for unix - integrated pcp into awk - yet to finish pcp for win32 --- qse/include/qse/cmn/Makefile.am | 2 +- qse/include/qse/cmn/Makefile.in | 2 +- qse/include/qse/cmn/pcp.h | 321 +++++++++++++++ qse/include/qse/cmn/pio.h | 323 --------------- qse/include/qse/cmn/tio.h | 25 +- qse/include/qse/macros.h | 22 + qse/lib/awk/std.c | 40 +- qse/lib/cmn/Makefile.am | 2 +- qse/lib/cmn/Makefile.in | 6 +- qse/lib/cmn/pcp.c | 696 ++++++++++++++++++++++++++++++++ qse/lib/cmn/pio.c | 644 ----------------------------- qse/lib/cmn/tio.c | 17 +- qse/test/cmn/Makefile.am | 4 +- qse/test/cmn/Makefile.in | 24 +- qse/test/cmn/pcp.c | 237 +++++++++++ qse/test/cmn/pio.c | 111 ----- 16 files changed, 1331 insertions(+), 1145 deletions(-) create mode 100644 qse/include/qse/cmn/pcp.h delete mode 100644 qse/include/qse/cmn/pio.h create mode 100644 qse/lib/cmn/pcp.c delete mode 100644 qse/lib/cmn/pio.c create mode 100644 qse/test/cmn/pcp.c delete mode 100644 qse/test/cmn/pio.c diff --git a/qse/include/qse/cmn/Makefile.am b/qse/include/qse/cmn/Makefile.am index a523ad2b..cddf3392 100644 --- a/qse/include/qse/cmn/Makefile.am +++ b/qse/include/qse/cmn/Makefile.am @@ -1,5 +1,5 @@ -pkginclude_HEADERS = mem.h chr.h str.h lda.h map.h rex.h sll.h dll.h opt.h fio.h pio.h tio.h sio.h time.h +pkginclude_HEADERS = mem.h chr.h str.h lda.h map.h rex.h sll.h dll.h opt.h fio.h pcp.h tio.h sio.h time.h pkgincludedir= $(includedir)/qse/cmn diff --git a/qse/include/qse/cmn/Makefile.in b/qse/include/qse/cmn/Makefile.in index 71d4ef07..84aace72 100644 --- a/qse/include/qse/cmn/Makefile.in +++ b/qse/include/qse/cmn/Makefile.in @@ -172,7 +172,7 @@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -pkginclude_HEADERS = mem.h chr.h str.h lda.h map.h rex.h sll.h dll.h opt.h fio.h pio.h tio.h sio.h time.h +pkginclude_HEADERS = mem.h chr.h str.h lda.h map.h rex.h sll.h dll.h opt.h fio.h pcp.h tio.h sio.h time.h CLEANFILES = *dist all: all-am diff --git a/qse/include/qse/cmn/pcp.h b/qse/include/qse/cmn/pcp.h new file mode 100644 index 00000000..495b7cab --- /dev/null +++ b/qse/include/qse/cmn/pcp.h @@ -0,0 +1,321 @@ +/* + * $Id$ + * + Copyright 2006-2008 Chung, Hyung-Hwan. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitapcpns under the License. + */ + +#ifndef _QSE_CMN_PCP_H_ +#define _QSE_CMN_PCP_H_ + +/* (P)ipe to a (C)hild (P)rocess */ + +#include +#include +#include + +enum qse_pcp_open_flag_t +{ + QSE_PCP_WRITEIN = (1 << 0), + QSE_PCP_READOUT = (1 << 1), + QSE_PCP_READERR = (1 << 2), + + QSE_PCP_ERRTOOUT = (1 << 3), + QSE_PCP_OUTTOERR = (1 << 4), + + QSE_PCP_INTONUL = (1 << 5), + QSE_PCP_ERRTONUL = (1 << 6), + QSE_PCP_OUTTONUL = (1 << 7), + + QSE_PCP_DROPIN = (1 << 8), + QSE_PCP_DROPOUT = (1 << 9), + QSE_PCP_DROPERR = (1 << 10), + + /* invoke the command through a default system shell */ + QSE_PCP_SHELL = (1 << 11), + + /* enable ase_char_t based IO */ + QSE_PCP_TEXT = (1 << 12) +}; + +enum qse_pcp_wait_flag_t +{ + QSE_PCP_NOHANG = (1 << 0), + QSE_PCP_IGNINTR = (1 << 1) +}; + +enum qse_pcp_hid_t +{ + QSE_PCP_IN = 0, + QSE_PCP_OUT = 1, + QSE_PCP_ERR = 2 +}; + +enum qse_pcp_err_t +{ + QSE_PCP_ENOERR = 0, + QSE_PCP_ENOMEM, /* out of memory */ + QSE_PCP_ENOHND, /* no handle available */ + QSE_PCP_ECHILD, /* the child is not valid */ + QSE_PCP_EINTR, /* interrupted */ + QSE_PCP_ESYSCALL /* system call error */ +}; + +typedef enum qse_pcp_hid_t qse_pcp_hid_t; +typedef enum qse_pcp_err_t qse_pcp_err_t; + +#ifdef _WIN32 + /* => typedef PVOID HANDLE; */ + typedef void* qse_pcp_hnd_t; + typedef void* qse_pcp_pid_t; +# define QSE_PCP_HND_NIL ((qse_pcp_hnd_t)QSE_NULL) +# define QSE_PCP_PID_NIL ((qse_pcp_pid_t)QSE_NULL) +#else + typedef int qse_pcp_hnd_t; + typedef int qse_pcp_pid_t; +# define QSE_PCP_HND_NIL ((qse_pcp_hnd_t)-1) +# define QSE_PCP_PID_NIL ((qse_pcp_hnd_t)-1) +#endif + +typedef struct qse_pcp_t qse_pcp_t; +typedef struct qse_pcp_pip_t qse_pcp_pip_t; + +struct qse_pcp_pip_t +{ + qse_pcp_hnd_t handle; + qse_tio_t* tio; + qse_pcp_t* self; +}; + +struct qse_pcp_t +{ + QSE_DEFINE_STD_FIELDS(pcp) + + qse_pcp_err_t errnum; + qse_pcp_pid_t child; + qse_pcp_pip_t pip[3]; +}; + +#define QSE_PCP_MMGR(pcp) ((pcp)->mmgr) +#define QSE_PCP_XTN(pcp) ((void*)(((qse_pcp_t*)pcp) + 1)) +#define QSE_PCP_HANDLE(pcp,hid) ((pcp)->pip[3].handle) +#define QSE_PCP_CHILD(pcp) ((pcp)->child) +#define QSE_PCP_ERRNUM(pcp) ((pcp)->errnum) + +#ifdef __cplusplus +extern "C" { +#endif + +QSE_DEFINE_STD_FUNCTIONS (pcp) + +/****f* qse.cmn.pcp/qse_pcp_open + * NAME + * qse_pcp_open - open pipes to a child process + * + * DESCRIPTION + * QSE_PCP_SHELL drives the funcpcpn to execute the command via /bin/sh. + * If flags is clear of QSE_PCP_SHELL, you should pass the full program path. + * + * SYNOPSIS + */ +qse_pcp_t* qse_pcp_open ( + qse_mmgr_t* mmgr, + qse_size_t ext, + const qse_char_t* cmd, + int flags +); +/******/ + +/****f* qse.cmn.pcp/qse_pcp_close + * NAME + * qse_pcp_close - close pipes to a child process + * + * SYNOPSIS + */ +void qse_pcp_close ( + qse_pcp_t* pcp +); +/******/ + +/****f* qse.cmn/pcp/qse_pcp_init + * NAME + * qse_pcp_init - initialize pipes to a child process + * + * SYNOPSIS + */ +qse_pcp_t* qse_pcp_init ( + qse_pcp_t* pcp, + qse_mmgr_t* mmgr, + const qse_char_t* path, + int flags +); +/******/ + +/****f* qse.cmn/pcp/qse_pcp_fini + * NAME + * qse_pcp_fini - finalize pipes to a child process + * + * SYNOPSIS + */ +void qse_pcp_fini ( + qse_pcp_t* pcp +); +/******/ + +/****f* qse.cmn.pcp/qse_pcp_geterrnum + * NAME + * qse_pcp_geterrnum - get an error code + * + * SYNOPSIS + */ +qse_pcp_err_t qse_pcp_geterrnum (qse_pcp_t* pcp); +/******/ + +/****f* qse.cmn.pcp/qse_pcp_geterrstr + * NAME + * qse_pcp_geterrstr - transllate an error code to a string + * + * DESCRIPTION + * The qse_pcp_geterrstr() funcpcpn returns the pointer to a constant string + * describing the last error occurred. + * + * SYNOPSIS + */ +const qse_char_t* qse_pcp_geterrstr (qse_pcp_t* pcp); +/******/ + +/****f* qse.cmn.pcp/qse_pcp_gethandle + * NAME + * qse_pcp_gethandle - get native handle + * + * SYNOPSIS + */ +qse_pcp_hnd_t qse_pcp_gethandle ( + qse_pcp_t* pcp, + qse_pcp_hid_t hid +); +/******/ + +/****f* qse.cmn.pcp/qse_pcp_getchild + * NAME + * qse_pcp_getchild - get the PID of a child process + * + * SYNOPSIS + */ +qse_pcp_pid_t qse_pcp_getchild ( + qse_pcp_t* pcp +); +/******/ + +/****f* qse.cmn.pcp/qse_pcp_read + * NAME + * qse_pcp_read - read data + * + * SYNOPSIS + */ +qse_ssize_t qse_pcp_read ( + qse_pcp_t* pcp, + void* buf, + qse_size_t size, + qse_pcp_hid_t hid +); +/******/ + +/****f* qse.cmn.pcp/qse_pcp_write + * NAME + * qse_pcp_write - write data + * + * DESCRIPTION + * If the parameter 'size' is zero, qse_pcp_write() closes the the writing + * stream causing the child process reach the end of the stream. + * + * SYNOPSIS + */ +qse_ssize_t qse_pcp_write ( + qse_pcp_t* pcp, + const void* data, + qse_size_t size, + qse_pcp_hid_t hid +); +/******/ + +/****f* qse.cmn.pcp/qse_pcp_flush + * NAME + * qse_pcp_flush - flush data + * + * SYNOPSIS + */ +qse_ssize_t qse_pcp_flush ( + qse_pcp_t* pcp, + qse_pcp_hid_t hid +); +/*****/ + +/****f* qse.cmn.pcp/qse_pcp_end + * NAME + * qse_pcp_end - close native handle + * + * SYNOPSIS + */ +void qse_pcp_end ( + qse_pcp_t* pcp, + qse_pcp_hid_t hid +); +/******/ + +/****f* qse.cmn.pcp/qse_pcp_wait + * NAME + * qse_pcp_wait - wait for a child process + * + * DESCRIPTION + * QSE_PCP_IGNINTR causes the function to retry when the underlying system + * call is interrupted. + * When you specify QSE_PCP_NOHANG, the return value of 256 indicates that the + * child process has not terminated. If the flag is not specified, 256 will + * never be returned. + * + * RETURN + * -1 on error, 256 if the child is alive and QSE_PCP_NOHANG is specified, + * 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. + * + * SYNOPSIS + */ +int qse_pcp_wait ( + qse_pcp_t* pcp, + int flags +); +/******/ + +/****f* qse.cmn.pcp/qse_pcp_kill + * NAME + * qse_pcp_kill - terminate the child process + * + * NOTES + * 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. + * + * SYNOPSIS + */ +int qse_pcp_kill ( + qse_pcp_t* pcp +); +/******/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/qse/include/qse/cmn/pio.h b/qse/include/qse/cmn/pio.h deleted file mode 100644 index 871db0da..00000000 --- a/qse/include/qse/cmn/pio.h +++ /dev/null @@ -1,323 +0,0 @@ -/* - * $Id$ - * - Copyright 2006-2008 Chung, Hyung-Hwan. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitapions under the License. - */ - -#ifndef _QSE_CMN_PIO_H_ -#define _QSE_CMN_PIO_H_ - -#include -#include -#include - -enum qse_pio_open_flag_t -{ - QSE_PIO_WRITEIN = (1 << 0), - QSE_PIO_READOUT = (1 << 1), - QSE_PIO_READERR = (1 << 2), - - QSE_PIO_ERRTOOUT = (1 << 3), - QSE_PIO_OUTTOERR = (1 << 4), - - QSE_PIO_INTONUL = (1 << 5), - QSE_PIO_ERRTONUL = (1 << 6), - QSE_PIO_OUTTONUL = (1 << 7), - - QSE_PIO_DROPIN = (1 << 8), - QSE_PIO_DROPOUT = (1 << 9), - QSE_PIO_DROPERR = (1 << 10), - - /* invoke the command through a default system shell */ - QSE_PIO_SHELL = (1 << 11), - - /* enable ase_char_t based IO */ - QSE_PIO_TEXT = (1 << 12) -}; - -enum qse_pio_wait_flag_t -{ - QSE_PIO_NOHANG = (1 << 0), - QSE_PIO_IGNINTR = (1 << 1) -}; - -enum qse_pio_hid_t -{ - QSE_PIO_IN = 0, - QSE_PIO_OUT = 1, - QSE_PIO_ERR = 2 -}; - -enum qse_pio_err_t -{ - QSE_PIO_ENOERR = 0, - QSE_PIO_ENOMEM, /* out of memory */ - QSE_PIO_ENOHND, /* no handle available */ - QSE_PIO_ECHILD, /* the child is not valid */ - QSE_PIO_EINTR, /* interrupted */ - QSE_PIO_ESYSCALL /* system call error */ -}; - -typedef enum qse_pio_hid_t qse_pio_hid_t; -typedef enum qse_pio_err_t qse_pio_err_t; - -#ifdef _WIN32 - /* => typedef PVOID HANDLE; */ - typedef void* qse_pio_hnd_t; - typedef void* qse_pio_pid_t; -# define QSE_PIO_HND_NIL ((qse_pio_hnd_t)QSE_NULL) -# define QSE_PIO_PID_NIL ((qse_pio_pid_t)QSE_NULL) -#else - typedef int qse_pio_hnd_t; - typedef int qse_pio_pid_t; -# define QSE_PIO_HND_NIL ((qse_pio_hnd_t)-1) -# define QSE_PIO_PID_NIL ((qse_pio_hnd_t)-1) -#endif - -typedef struct qse_pio_t qse_pio_t; - -struct qse_pio_t -{ - qse_mmgr_t* mmgr; - qse_pio_err_t errnum; - qse_pio_pid_t child; - - qse_pio_hnd_t handle[3]; - qse_tio_t* tio[3]; -}; - -#define QSE_PIO_MMGR(pio) ((pio)->mmgr) -#define QSE_PIO_XTN(pio) ((void*)(((qse_pio_t*)pio) + 1)) -#define QSE_PIO_HANDLE(pio,hid) ((pio)->handle[hid]) -#define QSE_PIO_CHILD(pio) ((pio)->child) - -#ifdef __cplusplus -extern "C" { -#endif - -/****f* qse.cmn.pio/qse_pio_open - * NAME - * qse_pio_open - open pipes to a child process - * - * DESCRIPTION - * QSE_PIO_SHELL drives the funcpion to execute the command via /bin/sh. - * If flags is clear of QSE_PIO_SHELL, you should pass the full program path. - * - * SYNOPSIS - */ -qse_pio_t* qse_pio_open ( - qse_mmgr_t* mmgr, - qse_size_t ext, - const qse_char_t* cmd, - int flags -); -/******/ - -/****f* qse.cmn.pio/qse_pio_close - * NAME - * qse_pio_close - close pipes to a child process - * - * SYNOPSIS - */ -void qse_pio_close ( - qse_pio_t* pio -); -/******/ - -/****f* qse.cmn/pio/qse_pio_init - * NAME - * qse_pio_init - initialize pipes to a child process - * - * SYNOPSIS - */ -qse_pio_t* qse_pio_init ( - qse_pio_t* pio, - qse_mmgr_t* mmgr, - const qse_char_t* path, - int flags -); -/******/ - -/****f* qse.cmn/pio/qse_pio_fini - * NAME - * qse_pio_fini - finalize pipes to a child process - * - * SYNOPSIS - */ -void qse_pio_fini ( - qse_pio_t* pio -); -/******/ - - -void* qse_pio_getxtn ( - qse_pio_t* pio -); - -qse_mmgr_t* qse_pio_getmmgr ( - qse_pio_t* pio -); - -void qse_pio_setmmgr ( - qse_pio_t* pio, - qse_mmgr_t* mmgr -); - -/* TODO: -QSE_OBJECT_DEFINE_BASIC_MACROS(pio) -QSE_OBJEcT_DEFINE_BASIC_FIELDS(pio) -QSE_OBJECT_DEFINE_BASIC_FUNCTION(pio) -QSE_OBJECT_IMPLEMENT_BASIC_FUNCTION(pio) -*/ - -/****f* qse.cmn.pio/qse_pio_geterrnum - * NAME - * qse_pio_geterrnum - get an error code - * - * SYNOPSIS - */ -qse_pio_err_t qse_pio_geterrnum (qse_pio_t* pio); -/******/ - -/****f* qse.cmn.pio/qse_pio_geterrstr - * NAME - * qse_pio_geterrstr - transllate an error code to a string - * - * DESCRIPTION - * The qse_pio_geterrstr() funcpion returns the pointer to a constant string - * describing the last error occurred. - * - * SYNOPSIS - */ -const qse_char_t* qse_pio_geterrstr (qse_pio_t* pio); -/******/ - -/****f* qse.cmn.pio/qse_pio_gethandle - * NAME - * qse_pio_gethandle - get native handle - * - * SYNOPSIS - */ -qse_pio_hnd_t qse_pio_gethandle ( - qse_pio_t* pio, - qse_pio_hid_t hid -); -/******/ - -/****f* qse.cmn.pio/qse_pio_getchild - * NAME - * qse_pio_getchild - get the PID of a child process - * - * SYNOPSIS - */ -qse_pio_pid_t qse_pio_getchild ( - qse_pio_t* pio -); -/******/ - -/****f* qse.cmn.pio/qse_pio_read - * NAME - * qse_pio_read - read data - * - * SYNOPSIS - */ -qse_ssize_t qse_pio_read ( - qse_pio_t* pio, - void* buf, - qse_size_t size, - qse_pio_hid_t hid -); -/******/ - -/****f* qse.cmn.pio/qse_pio_write - * NAME - * qse_pio_write - write data - * - * DESCRIPTION - * If the parameter 'size' is zero, qse_pio_write() closes the the writing - * stream causing the child process reach the end of the stream. - * - * SYNOPSIS - */ -qse_ssize_t qse_pio_write ( - qse_pio_t* pio, - const void* data, - qse_size_t size, - qse_pio_hid_t hid -); -/******/ - -void qse_pio_flush ( - qse_pio_t* pio, - qse_pio_hid_t hid -); - -/****f* qse.cmn.pio/qse_pio_end - * NAME - * qse_pio_end - * - * SYNOPSIS - */ -void qse_pio_end ( - qse_pio_t* pio, - qse_pio_hid_t hid -); -/******/ - -/****f* qse.cmn.pio/qse_pio_wait - * NAME - * qse_pio_wait - wait for a child process - * - * DESCRIPTION - * QSE_PIO_IGNINTR causes the function to retry when the underlying system - * call is interrupted. - * When you specify QSE_PIO_NOHANG, the return value of 256 indicates that the - * child process has not terminated. If the flag is not specified, 256 will - * never be returned. - * - * RETURN - * -1 on error, 256 if the child is still alive and QSE_PIO_NOHANG is specified, - * a number between 0 and 255 inclusive if the child process terminates normally, - * 256 + signal number if the child process is terminated by a signal. - * - * SYNOPSIS - */ -int qse_pio_wait ( - qse_pio_t* pio, - int flags -); -/******/ - -/****f* qse.cmn.pio/qse_pio_kill - * NAME - * qse_pio_kill - terminate the child process - * - * NOTES - * 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. - * - * SYNOPSIS - */ -int qse_pio_kill ( - qse_pio_t* pio -); -/******/ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/qse/include/qse/cmn/tio.h b/qse/include/qse/cmn/tio.h index 15291cdd..4d3e94b8 100644 --- a/qse/include/qse/cmn/tio.h +++ b/qse/include/qse/cmn/tio.h @@ -85,7 +85,7 @@ typedef qse_ssize_t (*qse_tio_io_t) ( struct qse_tio_t { - qse_mmgr_t* mmgr; + QSE_DEFINE_STD_FIELDS (tio) qse_tio_err_t errnum; /* io functions */ @@ -108,6 +108,8 @@ struct qse_tio_t extern "C" { #endif +QSE_DEFINE_STD_FUNCTIONS (tio) + /* * FUNCTION: qse_tio_open */ @@ -132,26 +134,15 @@ int qse_tio_fini ( qse_tio_t* tio ); -void* qse_tio_getxtn ( - qse_tio_t* tio -); - -qse_mmgr_t* qse_tio_getmmgr ( - qse_tio_t* tio -); - -void qse_tio_setmmgr ( - qse_tio_t* tio, - qse_mmgr_t* mmgr -); - /****f* qse.cmn.tio/qse_tio_geterrnum * NAME * qse_tio_geterrnum - get an error code * * SYNOPSIS */ -qse_tio_err_t qse_tio_geterrnum (qse_tio_t* tio); +qse_tio_err_t qse_tio_geterrnum ( + qse_tio_t* tio +); /******/ /* @@ -164,7 +155,9 @@ qse_tio_err_t qse_tio_geterrnum (qse_tio_t* tio); * RETURNS: * A pointer to a constant string describing the last error occurred */ -const qse_char_t* qse_tio_geterrstr (qse_tio_t* tio); +const qse_char_t* qse_tio_geterrstr ( + qse_tio_t* tio +); /* * FUNCTION: qse_tio_attachin diff --git a/qse/include/qse/macros.h b/qse/include/qse/macros.h index 62acc18f..a6a7a1e5 100644 --- a/qse/include/qse/macros.h +++ b/qse/include/qse/macros.h @@ -154,4 +154,26 @@ # define QSE_END_NAMESPACE2(y,x) }} #endif +#define QSE_DEFINE_STD_FIELDS(name) \ + qse_mmgr_t* mmgr; + +#define QSE_DEFINE_STD_FUNCTIONS(name) \ +qse_##name##_t qse_##name##_setmmgr (qse_##name##_t* name, qse_mmgr_t* mmgr); \ +qse_mmgr_t* qse_##name##_getmmgr (qse_##name##_t* name); \ +void* qse_##name##_getxtn (qse_##name##_t* name); + +#define QSE_IMPLEMENT_STD_FUNCTIONS(name) \ +qse_##name##_t qse_##name##_setmmgr (qse_##name##_t* name, qse_mmgr_t* mmgr) \ +{ \ + name->mmgr = mmgr; \ +} \ +qse_mmgr_t* qse_##name##_getmmgr (qse_##name##_t* name) \ +{ \ + return name->mmgr; \ +} \ +void* qse_##name##_getxtn (qse_##name##_t* name) \ +{ \ + return (void*)(name + 1); \ +} + #endif diff --git a/qse/lib/awk/std.c b/qse/lib/awk/std.c index 334545bd..b55e2cc6 100644 --- a/qse/lib/awk/std.c +++ b/qse/lib/awk/std.c @@ -18,6 +18,7 @@ #include "awk.h" #include +#include #include #include #include /* TODO: remove dependency on qse_vsprintf */ @@ -345,25 +346,30 @@ static qse_ssize_t awk_extio_pipe ( { case QSE_AWK_IO_OPEN: { - qse_sio_t* handle; - int mode; + qse_pcp_t* handle; + int flags; if (epa->mode == QSE_AWK_EXTIO_PIPE_READ) { - mode = QSE_SIO_READ; + /* TODO: should specify ERRTOOUT */ + flags = QSE_PCP_READOUT | + QSE_PCP_ERRTOOUT; } else if (epa->mode == QSE_AWK_EXTIO_PIPE_WRITE) { - mode = QSE_SIO_WRITE | - QSE_SIO_TRUNCATE | - QSE_SIO_CREATE; + flags = QSE_PCP_WRITEIN; } else return -1; /* TODO: any way to set the error number? */ /*dprint (QSE_T("opening %s of type %d (pipe)\n"), epa->name, epa->type);*/ - /* TOOD: popen.... */ - handle = qse_sio_open (qse_awk_getrunmmgr(epa->run), 0, epa->name, mode); + handle = qse_pcp_open ( + qse_awk_getrunmmgr(epa->run), + 0, + epa->name, + flags|QSE_PCP_SHELL|QSE_PCP_TEXT + ); + if (handle == QSE_NULL) return -1; epa->handle = (void*)handle; return 1; @@ -372,33 +378,35 @@ static qse_ssize_t awk_extio_pipe ( case QSE_AWK_IO_CLOSE: { /*dprint (QSE_T("closing %s of type (pipe) %d\n"), epa->name, epa->type);*/ - qse_sio_close ((qse_sio_t*)epa->handle); + qse_pcp_close ((qse_pcp_t*)epa->handle); epa->handle = QSE_NULL; return 0; } case QSE_AWK_IO_READ: { - return qse_sio_getsx ( - (qse_sio_t*)epa->handle, + return qse_pcp_read ( + (qse_pcp_t*)epa->handle, data, - size + size, + QSE_PCP_OUT ); } case QSE_AWK_IO_WRITE: { - return qse_sio_putsx ( - (qse_sio_t*)epa->handle, + return qse_pcp_write ( + (qse_pcp_t*)epa->handle, data, - size + size, + QSE_PCP_IN ); } case QSE_AWK_IO_FLUSH: { /*if (epa->mode == QSE_AWK_EXTIO_PIPE_READ) return -1;*/ - return qse_sio_flush ((qse_sio_t*)epa->handle); + return qse_pcp_flush ((qse_pcp_t*)epa->handle, QSE_PCP_IN); } case QSE_AWK_IO_NEXT: diff --git a/qse/lib/cmn/Makefile.am b/qse/lib/cmn/Makefile.am index 27aaeac9..576741e4 100644 --- a/qse/lib/cmn/Makefile.am +++ b/qse/lib/cmn/Makefile.am @@ -6,7 +6,7 @@ lib_LTLIBRARIES = libqsecmn.la libqsecmn_la_SOURCES = mem.h chr.h \ mem.c chr.c chr_cnv.c rex.c str_bas.c str_cnv.c str_dyn.c str_utl.c \ lda.c map.c sll.c dll.c opt.c \ - fio.c pio.c sio.c tio.c tio_get.c tio_put.c \ + fio.c pcp.c sio.c tio.c tio_get.c tio_put.c \ time.c \ misc.c libqsecmn_la_LDFLAGS = -version-info 1:0:0 -no-undefined diff --git a/qse/lib/cmn/Makefile.in b/qse/lib/cmn/Makefile.in index 1085b1ce..694904b0 100644 --- a/qse/lib/cmn/Makefile.in +++ b/qse/lib/cmn/Makefile.in @@ -53,7 +53,7 @@ LTLIBRARIES = $(lib_LTLIBRARIES) libqsecmn_la_DEPENDENCIES = am_libqsecmn_la_OBJECTS = mem.lo chr.lo chr_cnv.lo rex.lo str_bas.lo \ str_cnv.lo str_dyn.lo str_utl.lo lda.lo map.lo sll.lo dll.lo \ - opt.lo fio.lo pio.lo sio.lo tio.lo tio_get.lo tio_put.lo \ + opt.lo fio.lo pcp.lo sio.lo tio.lo tio_get.lo tio_put.lo \ time.lo misc.lo libqsecmn_la_OBJECTS = $(am_libqsecmn_la_OBJECTS) libqsecmn_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @@ -198,7 +198,7 @@ lib_LTLIBRARIES = libqsecmn.la libqsecmn_la_SOURCES = mem.h chr.h \ mem.c chr.c chr_cnv.c rex.c str_bas.c str_cnv.c str_dyn.c str_utl.c \ lda.c map.c sll.c dll.c opt.c \ - fio.c pio.c sio.c tio.c tio_get.c tio_put.c \ + fio.c pcp.c sio.c tio.c tio_get.c tio_put.c \ time.c \ misc.c @@ -282,7 +282,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/opt.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pio.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcp.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rex.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sio.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sll.Plo@am__quote@ diff --git a/qse/lib/cmn/pcp.c b/qse/lib/cmn/pcp.c new file mode 100644 index 00000000..4277025c --- /dev/null +++ b/qse/lib/cmn/pcp.c @@ -0,0 +1,696 @@ +/* + * $Id: pcp.c,v 1.23 2006/06/30 04:18:47 bacon Exp $ + * + Copyright 2006-2008 Chung, Hyung-Hwan. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include +#include +#include "mem.h" + +#ifdef _WIN32 +# include +# include +#else +# include "syscall.h" +# include +# include +# include +#endif + +QSE_IMPLEMENT_STD_FUNCTIONS (pcp) + +static qse_ssize_t pcp_read ( + qse_pcp_t* pcp, void* buf, qse_size_t size, qse_pcp_hnd_t hnd); +static qse_ssize_t pcp_write ( + qse_pcp_t* pcp, const void* data, qse_size_t size, qse_pcp_hnd_t hnd); + +static qse_ssize_t pcp_input (int cmd, void* arg, void* buf, qse_size_t size); +static qse_ssize_t pcp_output (int cmd, void* arg, void* buf, qse_size_t size); + +qse_pcp_t* qse_pcp_open ( + qse_mmgr_t* mmgr, qse_size_t ext, + const qse_char_t* path, int flags) +{ + qse_pcp_t* pcp; + + if (mmgr == QSE_NULL) + { + mmgr = QSE_MMGR_GETDFL(); + + QSE_ASSERTX (mmgr != QSE_NULL, + "Set the memory manager with QSE_MMGR_SETDFL()"); + + if (mmgr == QSE_NULL) return QSE_NULL; + } + + pcp = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(qse_pcp_t) + ext); + if (pcp == QSE_NULL) return QSE_NULL; + + if (qse_pcp_init (pcp, mmgr, path, flags) == QSE_NULL) + { + QSE_MMGR_FREE (mmgr, pcp); + return QSE_NULL; + } + + return pcp; +} + +void qse_pcp_close (qse_pcp_t* pcp) +{ + qse_pcp_fini (pcp); + QSE_MMGR_FREE (pcp->mmgr, pcp); +} + +qse_pcp_t* qse_pcp_init ( + qse_pcp_t* pcp, qse_mmgr_t* mmgr, const qse_char_t* cmd, int flags) +{ + qse_pcp_pid_t pid; + qse_pcp_hnd_t handle[6] = + { + QSE_PCP_HND_NIL, + QSE_PCP_HND_NIL, + QSE_PCP_HND_NIL, + QSE_PCP_HND_NIL, + QSE_PCP_HND_NIL, + QSE_PCP_HND_NIL + }; + qse_tio_t* tio[3] = + { + QSE_NULL, + QSE_NULL, + QSE_NULL + }; + int i, minidx = -1, maxidx = -1; + + QSE_ASSERT (QSE_COUNTOF(pcp->hanlde) == QSE_COUNTOF(handle)); + + QSE_MEMSET (pcp, 0, QSE_SIZEOF(*pcp)); + pcp->mmgr = mmgr; + +#ifdef _WIN32 + /* TODO: XXXXXXXXXXXXXXXXX */ +http://msdn.microsoft.com/en-us/library/ms682499(VS.85).aspx +#else + + if (flags & QSE_PCP_WRITEIN) + { + if (QSE_PIPE(&handle[0]) == -1) goto oops; + minidx = 0; maxidx = 1; + } + + if (flags & QSE_PCP_READOUT) + { + if (QSE_PIPE(&handle[2]) == -1) goto oops; + if (minidx == -1) minidx = 2; + maxidx = 3; + } + + if (flags & QSE_PCP_READERR) + { + if (QSE_PIPE(&handle[4]) == -1) goto oops; + if (minidx == -1) minidx = 4; + maxidx = 5; + } + + if (maxidx == -1) goto oops; + + pid = QSE_FORK(); + if (pid == -1) goto oops; + + if (pid == 0) + { + /* child */ + qse_pcp_hnd_t devnull; + qse_mchar_t* mcmd; + extern char** environ; + int fcnt = 0; + #ifndef QSE_CHAR_IS_MCHAR + qse_size_t n, mn, wl; + qse_char_t* wcmd = QSE_NULL; + qse_mchar_t buf[64]; + #endif + + if (flags & QSE_PCP_WRITEIN) + { + /* child should read */ + QSE_CLOSE (handle[1]); + if (QSE_DUP2 (handle[0], 0) == -1) goto child_oops; + QSE_CLOSE (handle[0]); + } + + if (flags & QSE_PCP_READOUT) + { + /* child should write */ + QSE_CLOSE (handle[2]); + if (QSE_DUP2 (handle[3], 1) == -1) goto child_oops; + + if (flags & QSE_PCP_ERRTOOUT) + { + if (QSE_DUP2 (handle[3], 2) == -1) goto child_oops; + } + + QSE_CLOSE (handle[3]); + } + + if (flags & QSE_PCP_READERR) + { + /* child should write */ + QSE_CLOSE (handle[4]); + if (QSE_DUP2 (handle[5], 2) == -1) goto child_oops; + + if (flags & QSE_PCP_OUTTOERR) + { + if (QSE_DUP2 (handle[5], 1) == -1) goto child_oops; + } + + QSE_CLOSE (handle[5]); + } + + if ((flags & QSE_PCP_INTONUL) || + (flags & QSE_PCP_OUTTONUL) || + (flags & QSE_PCP_ERRTONUL)) + { + #ifdef O_LARGEFILE + devnull = QSE_OPEN ("/dev/null", O_RDWR|O_LARGEFILE, 0); + #else + devnull = QSE_OPEN ("/dev/null", O_RDWR, 0); + #endif + if (devnull == -1) goto oops; + } + + if ((flags & QSE_PCP_INTONUL) && + QSE_DUP2(devnull,0) == -1) goto child_oops; + if ((flags & QSE_PCP_OUTTONUL) && + QSE_DUP2(devnull,1) == -1) goto child_oops; + if ((flags & QSE_PCP_ERRTONUL) && + QSE_DUP2(devnull,2) == -1) goto child_oops; + + if ((flags & QSE_PCP_INTONUL) || + (flags & QSE_PCP_OUTTONUL) || + (flags & QSE_PCP_ERRTONUL)) QSE_CLOSE (devnull); + + if (flags & QSE_PCP_DROPIN) QSE_CLOSE(0); + if (flags & QSE_PCP_DROPOUT) QSE_CLOSE(1); + if (flags & QSE_PCP_DROPERR) QSE_CLOSE(2); + + #ifdef QSE_CHAR_IS_MCHAR + if (flags & QSE_PCP_SHELL) mcmd = (qse_char_t*)cmd; + else + { + mcmd = qse_strdup (cmd, pcp->mmgr); + if (mcmd == QSE_NULL) goto child_oops; + + fcnt = qse_strspl (mcmd, QSE_T(""), + QSE_T('\"'), QSE_T('\"'), QSE_T('\'')); + if (fcnt <= 0) + { + /* no field or an error */ + goto child_oops; + } + } + #else + if (flags & QSE_PCP_SHELL) + { + n = qse_wcstombslen (cmd, &mn); + if (cmd[n] != QSE_WT('\0')) + { + /* cmd has illegal sequence */ + goto child_oops; + } + } + else + { + wcmd = qse_strdup (cmd, pcp->mmgr); + if (wcmd == QSE_NULL) goto child_oops; + + fcnt = qse_strspl (wcmd, QSE_T(""), + QSE_T('\"'), QSE_T('\"'), QSE_T('\'')); + if (fcnt <= 0) + { + /* no field or an error */ + goto child_oops; + } + + for (wl = 0, n = fcnt; n > 0; ) + { + if (wcmd[wl++] == QSE_T('\0')) n--; + } + + n = qse_wcsntombsnlen (wcmd, wl, &mn); + if (n != wl) goto child_oops; + } + + mn = mn + 1; + + if (mn <= QSE_COUNTOF(buf)) + { + mcmd = buf; + mn = QSE_COUNTOF(buf); + } + else + { + mcmd = QSE_MMGR_ALLOC ( + pcp->mmgr, mn*QSE_SIZEOF(*mcmd)); + if (mcmd == QSE_NULL) goto child_oops; + } + + if (flags & QSE_PCP_SHELL) + { + /* qse_wcstombs() should succeed as + * qse_wcstombslen() was successful above */ + qse_wcstombs (cmd, mcmd, &mn); + /* qse_wcstombs() null-terminate mcmd */ + } + else + { + QSE_ASSERT (wcmd != QSE_NULL); + /* qse_wcsntombsn() should succeed as + * qse_wcsntombsnlen() was successful above */ + qse_wcsntombsn (wcmd, wl, mcmd, &mn); + /* qse_wcsntombsn() doesn't null-terminate mcmd */ + mcmd[mn] = QSE_MT('\0'); + } + #endif + + if (flags & QSE_PCP_SHELL) + { + const qse_mchar_t* argv[4]; + + argv[0] = QSE_MT("/bin/sh"); + argv[1] = QSE_MT("-c"); + argv[2] = mcmd; + argv[3] = QSE_NULL; + + QSE_EXECVE (QSE_MT("/bin/sh"), argv, environ); + } + else + { + int i; + qse_mchar_t** argv; + + argv = QSE_MMGR_ALLOC (pcp->mmgr, (fcnt+1)*QSE_SIZEOF(argv[0])); + if (argv == QSE_NULL) goto child_oops; + + for (i = 0; i < fcnt; i++) + { + argv[i] = mcmd; + while (*mcmd != QSE_MT('\0')) mcmd++; + mcmd++; + } + argv[i] = QSE_NULL; + + QSE_EXECVE (argv[0], argv, environ); + } + + child_oops: + QSE_EXIT (128); + } + + /* parent */ + pcp->child = pid; + + if (flags & QSE_PCP_WRITEIN) + { + /* + * 012345 + * rw---- + * X + * WRITE => 1 + */ + QSE_CLOSE (handle[0]); handle[0] = QSE_PCP_HND_NIL; + } + + if (flags & QSE_PCP_READOUT) + { + /* + * 012345 + * --rw-- + * X + * READ => 2 + */ + QSE_CLOSE (handle[3]); handle[3] = QSE_PCP_HND_NIL; + } + + if (flags & QSE_PCP_READERR) + { + /* + * 012345 + * ----rw + * X + * READ => 4 + */ + QSE_CLOSE (handle[5]); handle[5] = QSE_PCP_HND_NIL; + } + +#endif + + /* store back references */ + pcp->pip[QSE_PCP_IN].self = pcp; + pcp->pip[QSE_PCP_OUT].self = pcp; + pcp->pip[QSE_PCP_ERR].self = pcp; + + /* store actual pipe handles */ + pcp->pip[QSE_PCP_IN].handle = handle[1]; + pcp->pip[QSE_PCP_OUT].handle = handle[2]; + pcp->pip[QSE_PCP_ERR].handle = handle[4]; + + if (flags & QSE_PCP_TEXT) + { + for (i = 0; i < QSE_COUNTOF(tio); i++) + { + int r; + + tio[i] = qse_tio_open (pcp->mmgr, 0); + if (tio[i] == QSE_NULL) goto oops; + + r = (i == QSE_PCP_IN)? + qse_tio_attachout (tio[i], pcp_output, &pcp->pip[i]): + qse_tio_attachin (tio[i], pcp_input, &pcp->pip[i]); + + if (r == -1) goto oops; + + pcp->pip[i].tio = tio[i]; + } + } + + return pcp; + +oops: + for (i = 0; i < QSE_COUNTOF(tio); i++) qse_tio_close (tio[i]); + for (i = minidx; i < maxidx; i++) QSE_CLOSE (handle[i]); + return QSE_NULL; +} + +void qse_pcp_fini (qse_pcp_t* pcp) +{ + qse_pcp_end (pcp, QSE_PCP_IN); + qse_pcp_end (pcp, QSE_PCP_OUT); + qse_pcp_end (pcp, QSE_PCP_ERR); + qse_pcp_wait (pcp, QSE_PCP_IGNINTR); +} + +qse_pcp_err_t qse_pcp_geterrnum (qse_pcp_t* pcp) +{ + return pcp->errnum; +} + +const qse_char_t* qse_pcp_geterrstr (qse_pcp_t* pcp) +{ + static const qse_char_t* __errstr[] = + { + QSE_T("no error"), + QSE_T("out of memory"), + QSE_T("no handle available"), + QSE_T("child process not valid"), + QSE_T("interruped"), + QSE_T("systeam call error"), + QSE_T("unknown error") + }; + + return __errstr[ + (pcp->errnum < 0 || pcp->errnum >= QSE_COUNTOF(__errstr))? + QSE_COUNTOF(__errstr) - 1: pcp->errnum]; +} + +qse_pcp_hnd_t qse_pcp_gethandle (qse_pcp_t* pcp, qse_pcp_hid_t hid) +{ + return pcp->pip[hid].handle; +} + +qse_pcp_pid_t qse_pcp_getchild (qse_pcp_t* pcp) +{ + return pcp->child; +} + +qse_ssize_t qse_pcp_read ( + qse_pcp_t* pcp, void* buf, qse_size_t size, qse_pcp_hid_t hid) +{ + if (pcp->pip[hid].tio == QSE_NULL) + return pcp_read (pcp, buf, size, pcp->pip[hid].handle); + else + return qse_tio_getsx (pcp->pip[hid].tio, buf, size); +} + +qse_ssize_t qse_pcp_write ( + qse_pcp_t* pcp, const void* data, qse_size_t size, qse_pcp_hid_t hid) +{ + if (pcp->pip[hid].tio == QSE_NULL) + return pcp_write (pcp, data, size, pcp->pip[hid].handle); + else + return qse_tio_putsx (pcp->pip[hid].tio, data, size); +} + +qse_ssize_t qse_pcp_flush (qse_pcp_t* pcp, qse_pcp_hid_t hid) +{ + if (pcp->pip[hid].tio == QSE_NULL) return 0; + return qse_tio_flush (pcp->pip[hid].tio); +} + +static qse_ssize_t pcp_read ( + qse_pcp_t* pcp, void* buf, qse_size_t size, qse_pcp_hnd_t hnd) +{ +#ifdef _WIN32 + DWORD count; +#else + qse_ssize_t n; +#endif + + if (hnd == QSE_PCP_HND_NIL) + { + /* the stream is already closed */ + pcp->errnum = QSE_PCP_ENOHND; + return (qse_ssize_t)-1; + } + +#ifdef _WIN32 + if (size > QSE_TYPE_MAX(DWORD)) size = QSE_TYPE_MAX(DWORD); + if (ReadFile(hnd, buf, size, &count, QSE_NULL) == FALSE) return -1; + return (qse_ssize_t)count; +#else + + if (size > QSE_TYPE_MAX(size_t)) size = QSE_TYPE_MAX(size_t); + n = QSE_READ (hnd, buf, size); + if (n == -1) + { + pcp->errnum = (errno == EINTR)? + QSE_PCP_EINTR: QSE_PCP_ESYSCALL; + } + + return n; +#endif +} + +static qse_ssize_t pcp_write ( + qse_pcp_t* pcp, const void* data, qse_size_t size, qse_pcp_hnd_t hnd) +{ +#ifdef _WIN32 + DWORD count; +#else + qse_ssize_t n; +#endif + + if (hnd == QSE_PCP_HND_NIL) + { + /* the stream is already closed */ + pcp->errnum = QSE_PCP_ENOHND; + return (qse_ssize_t)-1; + } + +#ifdef _WIN32 + if (size > QSE_TYPE_MAX(DWORD)) size = QSE_TYPE_MAX(DWORD); + if (WriteFile (hnd, data, size, &count, QSE_NULL) == FALSE) return -1; + return (qse_ssize_t)count; +#else + if (size > QSE_TYPE_MAX(size_t)) size = QSE_TYPE_MAX(size_t); + n = QSE_WRITE (hnd, data, size); + if (n == -1) + { + pcp->errnum = (errno == EINTR)? + QSE_PCP_EINTR: QSE_PCP_ESYSCALL; + } + return n; +#endif +} + +void qse_pcp_end (qse_pcp_t* pcp, qse_pcp_hid_t hid) +{ + if (pcp->pip[hid].tio != QSE_NULL) + { + qse_tio_close (pcp->pip[hid].tio); + pcp->pip[hid].tio = QSE_NULL; + } + + if (pcp->pip[hid].handle != QSE_PCP_HND_NIL) + { + QSE_CLOSE (pcp->pip[hid].handle); + pcp->pip[hid].handle = QSE_PCP_HND_NIL; + } +} + +int qse_pcp_wait (qse_pcp_t* pcp, int flags) +{ +#ifdef _WIN32 + DWORD ec; + + if (pcp->child == QSE_PCP_PID_NIL) + { + + pcp->errnum = QSE_PCP_ECHILD; + return -1; + } + + WaitForSingleObject (pcp->child, -1); + if (GetExitCodeProcess (pcp->child, &ec) == -1) + /* close handle here to emulate waitpid() as much as possible. */ + CloseHandle (pcp->child); + pcp->child = QSE_PCP_PID_NIL; + +#else + int opt = 0; + int ret = -1; + + if (pcp->child == QSE_PCP_PID_NIL) + { + pcp->errnum = QSE_PCP_ECHILD; + return -1; + } + + if (flags & QSE_PCP_NOHANG) opt |= WNOHANG; + + while (1) + { + int status, n; + + n = QSE_WAITPID (pcp->child, &status, opt); + + if (n == -1) + { + if (errno == ECHILD) + { + /* most likely, the process has already been + * waitpid()ed on. */ + pcp->child = QSE_PCP_PID_NIL; + pcp->errnum = QSE_PCP_ECHILD; + } + else if (errno == EINTR) + { + if (flags & QSE_PCP_IGNINTR) continue; + pcp->errnum = QSE_PCP_EINTR; + } + else pcp->errnum = QSE_PCP_ESYSCALL; + + break; + } + + if (n == 0) + { + /* when WNOHANG is not specified, 0 can't be returned */ + QSE_ASSERT (flags & QSE_PCP_NOHANG); + + ret = 255 + 1; + /* the child process is still alive */ + break; + } + + if (n == pcp->child) + { + if (WIFEXITED(status)) + { + /* the child process ended normally */ + ret = WEXITSTATUS(status); + } + else if (WIFSIGNALED(status)) + { + /* the child process was killed by a signal */ + ret = 255 + 1 + WTERMSIG (status); + } + else + { + /* not interested in WIFSTOPPED & WIFCONTINUED. + * in fact, this else block should not be reached + * as WIFEXITED or WIFSIGNALED must be true. + * anyhow, just set the return value to 0. */ + ret = 0; + } + + pcp->child = QSE_PCP_PID_NIL; + break; + } + } + + return ret; +#endif +} + +int qse_pcp_kill (qse_pcp_t* pcp) +{ +#ifdef _WIN32 + DWORD n; +#else + int n; +#endif + + if (pcp->child == QSE_PCP_PID_NIL) + { + pcp->errnum = QSE_PCP_ECHILD; + return -1; + } + +#ifdef _WIN32 + /* 9 was chosen below to treat TerminateProcess as kill -KILL. */ + n = TerminateProcess (pcp->child, 255 + 1 + 9); + if (n == FALSE) + { + pcp->errnum = QSE_PCP_SYSCALL; + return -1; + } + return 0; +#else + n = QSE_KILL (pcp->child, SIGKILL); + if (n == -1) pcp->errnum = QSE_PCP_ESYSCALL; + return n; +#endif +} + +static qse_ssize_t pcp_input (int cmd, void* arg, void* buf, qse_size_t size) +{ + qse_pcp_pip_t* pip = (qse_pcp_pip_t*)arg; + QSE_ASSERT (pip != QSE_NULL); + if (cmd == QSE_TIO_IO_DATA) + { + QSE_ASSERT (pip->self != QSE_NULL); + return pcp_read (pip->self, buf, size, pip->handle); + } + + /* take no actions for OPEN and CLOSE as they are handled + * by pcp */ + return 0; +} + +static qse_ssize_t pcp_output (int cmd, void* arg, void* buf, qse_size_t size) +{ + qse_pcp_pip_t* pip = (qse_pcp_pip_t*)arg; + QSE_ASSERT (pip != QSE_NULL); + if (cmd == QSE_TIO_IO_DATA) + { + QSE_ASSERT (pip->self != QSE_NULL); + return pcp_write (pip->self, buf, size, pip->handle); + } + + /* take no actions for OPEN and CLOSE as they are handled + * by pcp */ + return 0; +} diff --git a/qse/lib/cmn/pio.c b/qse/lib/cmn/pio.c deleted file mode 100644 index dbfd0e61..00000000 --- a/qse/lib/cmn/pio.c +++ /dev/null @@ -1,644 +0,0 @@ -/* - * $Id: pio.c,v 1.23 2006/06/30 04:18:47 bacon Exp $ - * - Copyright 2006-2008 Chung, Hyung-Hwan. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - -#include -#include -#include "mem.h" - -#ifdef _WIN32 -# include -# include -#else -# include "syscall.h" -# include -# include -# include -#endif - -#define CHILD_EXIT_CODE 128 - -static qse_ssize_t pio_read ( - qse_pio_t* pio, void* buf, qse_size_t size, qse_pio_hid_t hid); -static qse_ssize_t pio_write ( - qse_pio_t* pio, const void* data, qse_size_t size, qse_pio_hid_t hid)a; - -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); - -qse_pio_t* qse_pio_open ( - qse_mmgr_t* mmgr, qse_size_t ext, - const qse_char_t* path, int flags) -{ - qse_pio_t* pio; - - if (mmgr == QSE_NULL) - { - mmgr = QSE_MMGR_GETDFL(); - - QSE_ASSERTX (mmgr != QSE_NULL, - "Set the memory manager with QSE_MMGR_SETDFL()"); - - if (mmgr == QSE_NULL) return QSE_NULL; - } - - pio = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(qse_pio_t) + ext); - if (pio == QSE_NULL) return QSE_NULL; - - if (qse_pio_init (pio, mmgr, path, flags) == QSE_NULL) - { - QSE_MMGR_FREE (mmgr, pio); - return QSE_NULL; - } - - return pio; -} - -void qse_pio_close (qse_pio_t* pio) -{ - qse_pio_fini (pio); - QSE_MMGR_FREE (pio->mmgr, pio); -} - - -qse_pio_t* qse_pio_init ( - qse_pio_t* pio, qse_mmgr_t* mmgr, const qse_char_t* cmd, int flags) -{ - qse_pio_pid_t pid; - qse_pio_hnd_t handle[6] = - { - QSE_PIO_HND_NIL, - QSE_PIO_HND_NIL, - QSE_PIO_HND_NIL, - QSE_PIO_HND_NIL, - QSE_PIO_HND_NIL, - QSE_PIO_HND_NIL - }; - int i, minidx = -1, maxidx = -1; - - QSE_ASSERT (QSE_COUNTOF(pio->hanlde) == QSE_COUNTOF(handle)); - - QSE_MEMSET (pio, 0, QSE_SIZEOF(*pio)); - pio->mmgr = mmgr; - -#ifdef _WIN32 - /* TODO: XXXXXXXXXXXXXXXXX */ -http://msdn.microsoft.com/en-us/library/ms682499(VS.85).aspx -#else - - if (flags & QSE_PIO_WRITEIN) - { - if (QSE_PIPE(&handle[0]) == -1) goto oops; - minidx = 0; maxidx = 1; - } - - if (flags & QSE_PIO_READOUT) - { - if (QSE_PIPE(&handle[2]) == -1) goto oops; - if (minidx == -1) minidx = 2; - maxidx = 3; - } - - if (flags & QSE_PIO_READERR) - { - if (QSE_PIPE(&handle[4]) == -1) goto oops; - if (minidx == -1) minidx = 4; - maxidx = 5; - } - - if (maxidx == -1) goto oops; - - pid = QSE_FORK(); - if (pid == -1) goto oops; - - if (pid == 0) - { - /* child */ - qse_pio_hnd_t devnull; - qse_mchar_t* mcmd; - extern char** environ; - int fcnt = 0; - #ifndef QSE_CHAR_IS_MCHAR - qse_size_t n, mn, wl; - qse_char_t* wcmd = QSE_NULL; - qse_mchar_t buf[64]; - #endif - - if (flags & QSE_PIO_WRITEIN) - { - /* child should read */ - QSE_CLOSE (handle[1]); - if (QSE_DUP2 (handle[0], 0) == -1) goto child_oops; - QSE_CLOSE (handle[0]); - } - - if (flags & QSE_PIO_READOUT) - { - /* child should write */ - QSE_CLOSE (handle[2]); - if (QSE_DUP2 (handle[3], 1) == -1) goto child_oops; - - if (flags & QSE_PIO_ERRTOOUT) - { - if (QSE_DUP2 (handle[3], 2) == -1) goto child_oops; - } - - QSE_CLOSE (handle[3]); - } - - if (flags & QSE_PIO_READERR) - { - /* child should write */ - QSE_CLOSE (handle[4]); - if (QSE_DUP2 (handle[5], 2) == -1) goto child_oops; - - if (flags & QSE_PIO_OUTTOERR) - { - if (QSE_DUP2 (handle[5], 1) == -1) goto child_oops; - } - - QSE_CLOSE (handle[5]); - } - - if ((flags & QSE_PIO_INTONUL) || - (flags & QSE_PIO_OUTTONUL) || - (flags & QSE_PIO_ERRTONUL)) - { - #ifdef O_LARGEFILE - devnull = QSE_OPEN ("/dev/null", O_RDWR|O_LARGEFILE, 0); - #else - devnull = QSE_OPEN ("/dev/null", O_RDWR, 0); - #endif - if (devnull == -1) goto oops; - } - - if ((flags & QSE_PIO_INTONUL) && - QSE_DUP2(devnull,0) == -1) goto child_oops; - if ((flags & QSE_PIO_OUTTONUL) && - QSE_DUP2(devnull,1) == -1) goto child_oops; - if ((flags & QSE_PIO_ERRTONUL) && - QSE_DUP2(devnull,2) == -1) goto child_oops; - - if ((flags & QSE_PIO_INTONUL) || - (flags & QSE_PIO_OUTTONUL) || - (flags & QSE_PIO_ERRTONUL)) QSE_CLOSE (devnull); - - if (flags & QSE_PIO_DROPIN) QSE_CLOSE(0); - if (flags & QSE_PIO_DROPOUT) QSE_CLOSE(1); - if (flags & QSE_PIO_DROPERR) QSE_CLOSE(2); - - #ifdef QSE_CHAR_IS_MCHAR - if (flags & QSE_PIO_SHELL) mcmd = (qse_char_t*)cmd; - else - { - mcmd = qse_strdup (cmd, pio->mmgr); - if (mcmd == QSE_NULL) goto child_oops; - - fcnt = qse_strspl (mcmd, QSE_T(""), - QSE_T('\"'), QSE_T('\"'), QSE_T('\'')); - if (fcnt <= 0) - { - /* no field or an error */ - goto child_oops; - } - } - #else - if (flags & QSE_PIO_SHELL) - { - n = qse_wcstombslen (cmd, &mn); - if (cmd[n] != QSE_WT('\0')) - { - /* cmd has illegal sequence */ - goto child_oops; - } - } - else - { - wcmd = qse_strdup (cmd, pio->mmgr); - if (wcmd == QSE_NULL) goto child_oops; - - fcnt = qse_strspl (wcmd, QSE_T(""), - QSE_T('\"'), QSE_T('\"'), QSE_T('\'')); - if (fcnt <= 0) - { - /* no field or an error */ - goto child_oops; - } - - for (wl = 0, n = fcnt; n > 0; ) - { - if (wcmd[wl++] == QSE_T('\0')) n--; - } - - n = qse_wcsntombsnlen (wcmd, wl, &mn); - if (n != wl) goto child_oops; - } - - mn = mn + 1; - - if (mn <= QSE_COUNTOF(buf)) - { - mcmd = buf; - mn = QSE_COUNTOF(buf); - } - else - { - mcmd = QSE_MMGR_ALLOC ( - pio->mmgr, mn*QSE_SIZEOF(*mcmd)); - if (mcmd == QSE_NULL) goto child_oops; - } - - if (flags & QSE_PIO_SHELL) - { - /* qse_wcstombs() should succeed as - * qse_wcstombslen() was successful above */ - qse_wcstombs (cmd, mcmd, &mn); - /* qse_wcstombs() null-terminate mcmd */ - } - else - { - QSE_ASSERT (wcmd != QSE_NULL); - /* qse_wcsntombsn() should succeed as - * qse_wcsntombsnlen() was successful above */ - qse_wcsntombsn (wcmd, wl, mcmd, &mn); - /* qse_wcsntombsn() doesn't null-terminate mcmd */ - mcmd[mn] = QSE_MT('\0'); - } - #endif - - if (flags & QSE_PIO_SHELL) - { - const qse_mchar_t* argv[4]; - - argv[0] = QSE_MT("/bin/sh"); - argv[1] = QSE_MT("-c"); - argv[2] = mcmd; - argv[3] = QSE_NULL; - - QSE_EXECVE (QSE_MT("/bin/sh"), argv, environ); - } - else - { - int i; - qse_mchar_t** argv; - - argv = QSE_MMGR_ALLOC (pio->mmgr, (fcnt+1)*QSE_SIZEOF(argv[0])); - if (argv == QSE_NULL) goto child_oops; - - for (i = 0; i < fcnt; i++) - { - argv[i] = mcmd; - while (*mcmd != QSE_MT('\0')) mcmd++; - mcmd++; - } - argv[i] = QSE_NULL; - - QSE_EXECVE (argv[0], argv, environ); - } - - child_oops: - QSE_EXIT (CHILD_EXIT_CODE); - } - - /* parent */ - pio->child = pid; - - if (flags & QSE_PIO_WRITEIN) - { - /* - * 012345 - * rw---- - * X - * WRITE => 1 - */ - QSE_CLOSE (handle[0]); handle[0] = QSE_PIO_HND_NIL; - } - - if (flags & QSE_PIO_READOUT) - { - /* - * 012345 - * --rw-- - * X - * READ => 2 - */ - QSE_CLOSE (handle[3]); handle[3] = QSE_PIO_HND_NIL; - } - - if (flags & QSE_PIO_READERR) - { - /* - * 012345 - * ----rw - * X - * READ => 4 - */ - QSE_CLOSE (handle[5]); handle[5] = QSE_PIO_HND_NIL; - } - -#endif - if (flags & QSE_PIO_TEXT) - { - qse_tio_t* tio[3]; - - tio[0] = qse_tio_open (pio->mmgr, 0); - tio[1] = qse_tio_open (pio->mmgr, 0); - tio[2] = qse_tio_open (pio->mmgr, 0); - - qse_tio_attachout (tio[0], pio_output, &handle[1]); - qse_tio_attachin (tio[1], pio_input, &handle[2]); - qse_tio_attachin (tio[2], pio_input, &handle[4]); - } - - /* store back references */ - pio->p[QSE_PIO_IN].self = pio; - pio->p[QSE_PIO_OUT].self = pio; - pio->p[QSE_PIO_ERR].self = pio; - - /* store actual pipe handles */ - pio->p[QSE_PIO_IN].handle = handle[1]; - pio->p[QSE_PIO_OUT].handle = handle[2]; - pio->p[QSE_PIO_ERR].handle = handle[4]; -/* - pio->handle[QSE_PIO_IN] = handle[1]; - pio->handle[QSE_PIO_OUT] = handle[2]; - pio->handle[QSE_PIO_ERR] = handle[4]; -*/ - - return pio; - -oops: - for (i = minidx; i < maxidx; i++) QSE_CLOSE (handle[i]); - return QSE_NULL; -} - -void qse_pio_fini (qse_pio_t* pio) -{ - qse_pio_end (pio, QSE_PIO_IN); - qse_pio_end (pio, QSE_PIO_OUT); - qse_pio_end (pio, QSE_PIO_ERR); - qse_pio_wait (pio, QSE_PIO_IGNINTR); -} - -qse_pio_hnd_t qse_pio_gethandle (qse_pio_t* pio, qse_pio_hid_t hid) -{ - return pio->handle[hid]; -} - -qse_pio_pid_t qse_pio_getchild (qse_pio_t* pio) -{ - return pio->child; -} - -qse_ssize_t qse_pio_read ( - qse_pio_t* pio, void* buf, qse_size_t size, qse_pio_hid_t hid) -{ - if (pio->p[hid].tio == QSE_NULL) - return pio_read (pio, buf, size, hid); - else - return qse_tio_read (pio->p[hid].tio, buf, size); -} - -qse_ssize_t qse_pio_write ( - qse_pio_t* pio, const void* data, qse_size_t size, qse_pio_hid_t hid) -{ - if (pio->p[hid].tio == QSE_NULL) - return pio_write (pio, buf, size, hid); - else - return qse_tio_write (pio->p[hid].tio, buf, size); -} - -static qse_ssize_t pio_read ( - qse_pio_t* pio, void* buf, qse_size_t size, qse_pio_hid_t hid) -{ -#ifdef _WIN32 - DWORD count; -#else - qse_ssize_t n; -#endif - - if (pio->handle[hid] == QSE_PIO_HND_NIL) - { - /* the stream is already closed */ - pio->errnum = QSE_PIO_ENOHND; - return (qse_ssize_t)-1; - } - -#ifdef _WIN32 - if (size > QSE_TYPE_MAX(DWORD)) size = QSE_TYPE_MAX(DWORD); - if (ReadFile(pio->handle, buf, size, &count, QSE_NULL) == FALSE) return -1; - return (qse_ssize_t)count; -#else - - if (size > QSE_TYPE_MAX(size_t)) size = QSE_TYPE_MAX(size_t); - n = QSE_READ (pio->handle[hid], buf, size); - if (n == -1) - { - pio->errnum = (errno == EINTR)? - QSE_PIO_EINTR: QSE_PIO_ESYSCALL; - } - return n; -#endif -} - -static qse_ssize_t pio_write ( - qse_pio_t* pio, const void* data, qse_size_t size, qse_pio_hid_t hid) -{ -#ifdef _WIN32 - DWORD count; -#else - qse_ssize_t n; -#endif - - if (pio->handle[hid] == QSE_PIO_HND_NIL) - { - /* the stream is already closed */ - pio->errnum = QSE_PIO_ENOHND; - return (qse_ssize_t)-1; - } - -#ifdef _WIN32 - if (size > QSE_TYPE_MAX(DWORD)) size = QSE_TYPE_MAX(DWORD); - if (WriteFile(pio->handle, data, size, &count, QSE_NULL) == FALSE) return -1; - return (qse_ssize_t)count; -#else - if (pio->handle[hid] == QSE_PIO_HND_NIL) - { - /* the stream is already closed */ - return (qse_ssize_t)-1; - } - - if (size > QSE_TYPE_MAX(size_t)) size = QSE_TYPE_MAX(size_t); - n = QSE_WRITE (pio->handle[hid], data, size); - if (n == -1) - { - pio->errnum = (errno == EINTR)? - QSE_PIO_EINTR: QSE_PIO_ESYSCALL; - } - return n; -#endif -} - -void qse_pio_end (qse_pio_t* pio, qse_pio_hid_t hid) -{ - if (pio->handle[hid] != QSE_PIO_HND_NIL) - { - QSE_CLOSE (pio->handle[hid]); - pio->handle[hid] = QSE_PIO_HND_NIL; - } -} - -int qse_pio_wait (qse_pio_t* pio, int flags) -{ -#ifdef _WIN32 - DWORD ec; - - if (pio->child == QSE_PIO_PID_NIL) - { - - pio->errnum = QSE_PIO_ECHILD; - return -1; - } - - WaitForSingleObject (pio->child, -1); - if (GetExitCodeProcess (pio->child, &ec) == -1) - /* close handle here to emulate waitpid() as much as possible. */ - CloseHandle (pio->child); - pio->child = QSE_PIO_PID_NIL; - -#else - int opt = 0; - int ret = -1; - - if (pio->child == QSE_PIO_PID_NIL) - { - pio->errnum = QSE_PIO_ECHILD; - return -1; - } - - if (flags & QSE_PIO_NOHANG) opt |= WNOHANG; - - while (1) - { - int status, n; - - n = QSE_WAITPID (pio->child, &status, opt); - - if (n == -1) - { - if (errno == ECHILD) - { - /* most likely, the process has already been - * waitpid()ed on. */ - pio->child = QSE_PIO_PID_NIL; - pio->errnum = QSE_PIO_ECHILD; - } - else if (errno == EINTR) - { - if (flags & QSE_PIO_IGNINTR) continue; - pio->errnum = QSE_PIO_EINTR; - } - else pio->errnum = QSE_PIO_ESYSCALL; - - break; - } - - if (n == 0) - { - /* when WNOHANG is not specified, 0 can't be returned */ - QSE_ASSERT (flags & QSE_PIO_NOHANG); - - ret = 255 + 1; - /* the child process is still alive */ - break; - } - - if (n == pio->child) - { - if (WIFEXITED(status)) - { - /* the child process ended normally */ - ret = WEXITSTATUS(status); - } - else if (WIFSIGNALED(status)) - { - /* the child process was killed by a signal */ - ret = 255 + 1 + WTERMSIG (status); - } - else - { - /* not interested in WIFSTOPPED & WIFCONTINUED. - * in fact, this else block should not be reached - * as WIFEXITED or WIFSIGNALED must be true. - * anyhow, just set the return value to 0. */ - ret = 0; - } - - pio->child = QSE_PIO_PID_NIL; - break; - } - } - - return ret; -#endif -} - -int qse_pio_kill (qse_pio_t* pio) -{ -#ifdef _WIN32 - DWORD n; -#else - int n; -#endif - - if (pio->child == QSE_PIO_PID_NIL) - { - pio->errnum = QSE_PIO_ECHILD; - return -1; - } - -#ifdef _WIN32 - /* 9 was chosen below to treat TerminateProcess as kill -KILL. */ - n = TerminateProcess (pio->child, 255 + 1 + 9); - if (n == FALSE) - { - pio->errnum = QSE_PIO_SYSCALL; - return -1; - } - return 0; -#else - n = QSE_KILL (pio->child, SIGKILL); - if (n == -1) pio->errnum = QSE_PIO_ESYSCALL; - return n; -#endif -} - -static qse_ssize_t pio_input (int cmd, void* arg, void* buf, qse_size_t size) -{ - qse_pio_t* pio = (qse_pio_t*)arg; - QSE_ASSERT (pio != QSE_NULL); - if (cmd == QSE_TIO_IO_DATA) return pio_read (pio, buf, size, hid); - return 0; -} - -static qse_ssize_t pio_output (int cmd, void* arg, void* buf, qse_size_t size) -{ - qse_pio_t* pio = (qse_pio_t*)arg; - QSE_ASSERT (pio != QSE_NULL); - if (cmd == QSE_TIO_IO_DATA) return pio_write (pio, buf, size, hid); - return 0; -} diff --git a/qse/lib/cmn/tio.c b/qse/lib/cmn/tio.c index b1122b68..cc4ffa78 100644 --- a/qse/lib/cmn/tio.c +++ b/qse/lib/cmn/tio.c @@ -19,6 +19,8 @@ #include #include "mem.h" +QSE_IMPLEMENT_STD_FUNCTIONS (tio) + qse_tio_t* qse_tio_open (qse_mmgr_t* mmgr, qse_size_t ext) { qse_tio_t* tio; @@ -83,21 +85,6 @@ int qse_tio_fini (qse_tio_t* tio) return 0; } -void* qse_tio_getxtn (qse_tio_t* tio) -{ - return tio + 1; -} - -qse_mmgr_t* qse_tio_getmmgr (qse_tio_t* tio) -{ - return tio->mmgr; -} - -void qse_tio_setmmgr (qse_tio_t* tio, qse_mmgr_t* mmgr) -{ - tio->mmgr = mmgr; -} - qse_tio_err_t qse_tio_geterrnum (qse_tio_t* tio) { return tio->errnum; diff --git a/qse/test/cmn/Makefile.am b/qse/test/cmn/Makefile.am index 26bad0ce..736a43ea 100644 --- a/qse/test/cmn/Makefile.am +++ b/qse/test/cmn/Makefile.am @@ -1,6 +1,6 @@ AM_CPPFLAGS = -I$(top_srcdir)/include -bin_PROGRAMS = chr str sll map lda fio pio sio time +bin_PROGRAMS = chr str sll map lda fio pcp sio time LDFLAGS = -L../../lib/cmn -L../../lib/utl LDADD = -lqseutl -lqsecmn @@ -11,6 +11,6 @@ sll_SOURCES = sll.c map_SOURCES = map.c lda_SOURCES = lda.c fio_SOURCES = fio.c -pio_SOURCES = pio.c +pcp_SOURCES = pcp.c sio_SOURCES = sio.c time_SOURCES = time.c diff --git a/qse/test/cmn/Makefile.in b/qse/test/cmn/Makefile.in index 2caadb2c..217ec422 100644 --- a/qse/test/cmn/Makefile.in +++ b/qse/test/cmn/Makefile.in @@ -33,7 +33,7 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = chr$(EXEEXT) str$(EXEEXT) sll$(EXEEXT) map$(EXEEXT) \ - lda$(EXEEXT) fio$(EXEEXT) pio$(EXEEXT) sio$(EXEEXT) \ + lda$(EXEEXT) fio$(EXEEXT) pcp$(EXEEXT) sio$(EXEEXT) \ time$(EXEEXT) subdir = test/cmn DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in @@ -63,10 +63,10 @@ am_map_OBJECTS = map.$(OBJEXT) map_OBJECTS = $(am_map_OBJECTS) map_LDADD = $(LDADD) map_DEPENDENCIES = -am_pio_OBJECTS = pio.$(OBJEXT) -pio_OBJECTS = $(am_pio_OBJECTS) -pio_LDADD = $(LDADD) -pio_DEPENDENCIES = +am_pcp_OBJECTS = pcp.$(OBJEXT) +pcp_OBJECTS = $(am_pcp_OBJECTS) +pcp_LDADD = $(LDADD) +pcp_DEPENDENCIES = am_sio_OBJECTS = sio.$(OBJEXT) sio_OBJECTS = $(am_sio_OBJECTS) sio_LDADD = $(LDADD) @@ -96,10 +96,10 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(chr_SOURCES) $(fio_SOURCES) $(lda_SOURCES) $(map_SOURCES) \ - $(pio_SOURCES) $(sio_SOURCES) $(sll_SOURCES) $(str_SOURCES) \ + $(pcp_SOURCES) $(sio_SOURCES) $(sll_SOURCES) $(str_SOURCES) \ $(time_SOURCES) DIST_SOURCES = $(chr_SOURCES) $(fio_SOURCES) $(lda_SOURCES) \ - $(map_SOURCES) $(pio_SOURCES) $(sio_SOURCES) $(sll_SOURCES) \ + $(map_SOURCES) $(pcp_SOURCES) $(sio_SOURCES) $(sll_SOURCES) \ $(str_SOURCES) $(time_SOURCES) ETAGS = etags CTAGS = ctags @@ -228,7 +228,7 @@ sll_SOURCES = sll.c map_SOURCES = map.c lda_SOURCES = lda.c fio_SOURCES = fio.c -pio_SOURCES = pio.c +pcp_SOURCES = pcp.c sio_SOURCES = sio.c time_SOURCES = time.c all: all-am @@ -304,9 +304,9 @@ lda$(EXEEXT): $(lda_OBJECTS) $(lda_DEPENDENCIES) map$(EXEEXT): $(map_OBJECTS) $(map_DEPENDENCIES) @rm -f map$(EXEEXT) $(LINK) $(map_OBJECTS) $(map_LDADD) $(LIBS) -pio$(EXEEXT): $(pio_OBJECTS) $(pio_DEPENDENCIES) - @rm -f pio$(EXEEXT) - $(LINK) $(pio_OBJECTS) $(pio_LDADD) $(LIBS) +pcp$(EXEEXT): $(pcp_OBJECTS) $(pcp_DEPENDENCIES) + @rm -f pcp$(EXEEXT) + $(LINK) $(pcp_OBJECTS) $(pcp_LDADD) $(LIBS) sio$(EXEEXT): $(sio_OBJECTS) $(sio_DEPENDENCIES) @rm -f sio$(EXEEXT) $(LINK) $(sio_OBJECTS) $(sio_LDADD) $(LIBS) @@ -330,7 +330,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fio.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lda.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/map.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pio.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sio.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sll.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str.Po@am__quote@ diff --git a/qse/test/cmn/pcp.c b/qse/test/cmn/pcp.c new file mode 100644 index 00000000..176fa47d --- /dev/null +++ b/qse/test/cmn/pcp.c @@ -0,0 +1,237 @@ +#include +#include + +#include +#include + +#define R(f) \ + do { \ + qse_printf (QSE_T("== %s ==\n"), QSE_T(#f)); \ + if (f() == -1) return -1; \ + } while (0) + +static int pcp1 (const qse_char_t* cmd, int oflags, qse_pcp_hid_t rhid) +{ + qse_pcp_t* pcp; + int x; + + pcp = qse_pcp_open ( + QSE_NULL, + 0, + cmd, + oflags + ); + if (pcp == QSE_NULL) + { + qse_printf (QSE_T("cannot open program through pipe\n")); + return -1; + } + + while (1) + { + qse_byte_t buf[128]; + + /*qse_pcp_canread (pcp, QSE_PCP_ERR, 1000)*/ + qse_ssize_t n = qse_pcp_read (pcp, buf, sizeof(buf), rhid); + if (n == 0) break; + if (n < 0) + { + qse_printf (QSE_T("qse_pcp_read() returned error - %s\n"), qse_pcp_geterrstr(pcp)); + break; + } + + qse_printf (QSE_T("N===> %d\n"), (int)n); + #ifdef QSE_CHAR_IS_MCHAR + qse_printf (QSE_T("buf => [%.*s]\n"), (int)n, buf); + #else + qse_printf (QSE_T("buf => [%.*S]\n"), (int)n, buf); + #endif + + } + + x = qse_pcp_wait (pcp, 0); + qse_printf (QSE_T("qse_pcp_wait returns %d\n"), x); + if (x == -1) + { + qse_printf (QSE_T("error code : %d, error string: %s\n"), (int)qse_pcp_geterrnum(pcp), qse_pcp_geterrstr(pcp)); + } + + qse_pcp_close (pcp); + + return 0; +} + +static int pcp2 (const qse_char_t* cmd, int oflags, qse_pcp_hid_t rhid) +{ + qse_pcp_t* pcp; + int x; + + pcp = qse_pcp_open ( + QSE_NULL, + 0, + cmd, + oflags | QSE_PCP_TEXT + ); + if (pcp == QSE_NULL) + { + qse_printf (QSE_T("cannot open program through pipe\n")); + return -1; + } + + while (1) + { + qse_char_t buf[128]; + + qse_ssize_t n = qse_pcp_read (pcp, buf, QSE_COUNTOF(buf), rhid); + if (n == 0) break; + if (n < 0) + { + qse_printf (QSE_T("qse_pcp_read() returned error - %s\n"), qse_pcp_geterrstr(pcp)); + break; + } + + qse_printf (QSE_T("N===> %d\n"), (int)n); + qse_printf (QSE_T("buf => [%.*s]\n"), (int)n, buf); + } + + x = qse_pcp_wait (pcp, 0); + qse_printf (QSE_T("qse_pcp_wait returns %d\n"), x); + if (x == -1) + { + qse_printf (QSE_T("error code : %d, error string: %s\n"), (int)qse_pcp_geterrnum(pcp), qse_pcp_geterrstr(pcp)); + } + + qse_pcp_close (pcp); + + return 0; +} + + +static int test1 (void) +{ + return pcp1 (QSE_T("ls -laF"), QSE_PCP_READOUT|QSE_PCP_WRITEIN|QSE_PCP_SHELL, QSE_PCP_OUT); +} + +static int test2 (void) +{ + return pcp1 (QSE_T("ls -laF"), QSE_PCP_READERR|QSE_PCP_OUTTOERR|QSE_PCP_WRITEIN|QSE_PCP_SHELL, QSE_PCP_ERR); +} + +static int test3 (void) +{ + return pcp1 (QSE_T("/bin/ls -laF"), QSE_PCP_READERR|QSE_PCP_OUTTOERR|QSE_PCP_WRITEIN, QSE_PCP_ERR); +} + +static int test4 (void) +{ + return pcp2 (QSE_T("ls -laF"), QSE_PCP_READOUT|QSE_PCP_WRITEIN|QSE_PCP_SHELL, QSE_PCP_OUT); +} + +static int test5 (void) +{ + return pcp2 (QSE_T("ls -laF"), QSE_PCP_READERR|QSE_PCP_OUTTOERR|QSE_PCP_WRITEIN|QSE_PCP_SHELL, QSE_PCP_ERR); +} + +static int test6 (void) +{ + return pcp2 (QSE_T("/bin/ls -laF"), QSE_PCP_READERR|QSE_PCP_OUTTOERR|QSE_PCP_WRITEIN, QSE_PCP_ERR); +} + +static int test7 (void) +{ + qse_pcp_t* pcp; + int x; + + pcp = qse_pcp_open ( + QSE_NULL, + 0, + QSE_T("/bin/ls -laF"), + QSE_PCP_READOUT|QSE_PCP_ERRTOOUT|QSE_PCP_WRITEIN + ); + if (pcp == QSE_NULL) + { + qse_printf (QSE_T("cannot open program through pipe\n")); + return -1; + } + + while (1) + { + qse_byte_t buf[128]; + + /*qse_pcp_canread (pcp, QSE_PCP_ERR, 1000)*/ + qse_ssize_t n = qse_pcp_read (pcp, buf, sizeof(buf), QSE_PCP_OUT); + if (n == 0) break; + if (n < 0) + { + qse_printf (QSE_T("qse_pcp_read() returned error - %s\n"), qse_pcp_geterrstr(pcp)); + break; + } + } + + x = qse_pcp_wait (pcp, 0); + qse_printf (QSE_T("qse_pcp_wait returns %d\n"), x); + if (x == -1) + { + qse_printf (QSE_T("error code : %d, error string: %s\n"), (int)QSE_PCP_ERRNUM(pcp), qse_pcp_geterrstr(pcp)); + } + + qse_pcp_close (pcp); + return 0; +} + +static int test8 (void) +{ + qse_pcp_t* pcp; + int x; + + pcp = qse_pcp_open ( + QSE_NULL, + 0, + QSE_T("/bin/ls -laF"), + QSE_PCP_READOUT|QSE_PCP_READERR|QSE_PCP_WRITEIN + ); + if (pcp == QSE_NULL) + { + qse_printf (QSE_T("cannot open program through pipe\n")); + return -1; + } + + { + int status; + int n = 5; + + qse_printf (QSE_T("sleeping for %d seconds\n"), n); + sleep (n); + qse_printf (QSE_T("waitpid...%d\n"), (int)waitpid (-1, &status, 0)); + } + + x = qse_pcp_wait (pcp, 0); + qse_printf (QSE_T("qse_pcp_wait returns %d\n"), x); + if (x == -1) + { + qse_printf (QSE_T("error code : %d, error string: %s\n"), (int)QSE_PCP_ERRNUM(pcp), qse_pcp_geterrstr(pcp)); + } + + qse_pcp_close (pcp); + return 0; +} + +int main () +{ + setlocale (LC_ALL, ""); + + qse_printf (QSE_T("--------------------------------------------------------------------------------\n")); + qse_printf (QSE_T("Set the environment LANG to a Unicode locale such as UTF-8 if you see the illegal XXXXX errors. If you see such errors in Unicode locales, this program might be buggy. It is normal to see such messages in non-Unicode locales as it uses Unicode data\n")); + qse_printf (QSE_T("--------------------------------------------------------------------------------\n")); + + R (test1); + R (test2); + R (test3); + R (test4); + R (test5); + R (test6); + R (test7); + R (test8); + + return 0; +} diff --git a/qse/test/cmn/pio.c b/qse/test/cmn/pio.c deleted file mode 100644 index 2f792128..00000000 --- a/qse/test/cmn/pio.c +++ /dev/null @@ -1,111 +0,0 @@ -#include -#include - -#include -#include - -#define R(f) \ - do { \ - qse_printf (QSE_T("== %s ==\n"), QSE_T(#f)); \ - if (f() == -1) return -1; \ - } while (0) - -static int pio1 (const qse_char_t* cmd, int oflags, qse_pio_hid_t rhid) -{ - qse_pio_t* pio; - - pio = qse_pio_open ( - QSE_NULL, - 0, - cmd, - oflags - ); - if (pio == QSE_NULL) - { - qse_printf (QSE_T("cannot open program through pipe\n")); - return -1; - } - - while (1) - { - qse_byte_t buf[128]; - - /*qse_pio_canread (pio, QSE_PIO_ERR, 1000)*/ - qse_ssize_t n = qse_pio_read (pio, buf, sizeof(buf), rhid); - if (n == 0) break; - if (n < 0) - { - qse_printf (QSE_T("qse_pio_read() returned error\n")); - break; - } - - qse_printf (QSE_T("N===> %d\n"), (int)n); - #ifdef QSE_CHAR_IS_MCHAR - qse_printf (QSE_T("buf => [%.*s]\n"), (int)n, buf); - #else - qse_printf (QSE_T("buf => [%.*S]\n"), (int)n, buf); - #endif - - } - - qse_pio_close (pio); - - return 0; -} - - -static int test1 (void) -{ - return pio1 (QSE_T("ls -laF"), QSE_PIO_READOUT|QSE_PIO_WRITEIN|QSE_PIO_SHELL, QSE_PIO_OUT); -} - -static int test2 (void) -{ - return pio1 (QSE_T("ls -laF"), QSE_PIO_READERR|QSE_PIO_OUTTOERR|QSE_PIO_WRITEIN|QSE_PIO_SHELL, QSE_PIO_ERR); -} - -static int test3 (void) -{ - return pio1 (QSE_T("/bin/ls -laF"), QSE_PIO_READERR|QSE_PIO_OUTTOERR|QSE_PIO_WRITEIN, QSE_PIO_ERR); -} - -static int test4 (void) -{ - qse_pio_t* pio; - - pio = qse_pio_open ( - QSE_NULL, - 0, - "ls -laF", - QSE_PIO_READOUT|QSE_PIO_READERR|QSE_PIO_WRITEIN - ); - if (pio == QSE_NULL) - { - qse_printf (QSE_T("cannot open program through pipe\n")); - return -1; - } - - { - int status; - sleep (5); - qse_printf (QSE_T("waitpid...%d\n"), (int)waitpid (-1, &status, 0)); - } - - qse_pio_close (pio); -} - -int main () -{ - setlocale (LC_ALL, ""); - - qse_printf (QSE_T("--------------------------------------------------------------------------------\n")); - qse_printf (QSE_T("Set the environment LANG to a Unicode locale such as UTF-8 if you see the illegal XXXXX errors. If you see such errors in Unicode locales, this program might be buggy. It is normal to see such messages in non-Unicode locales as it uses Unicode data\n")); - qse_printf (QSE_T("--------------------------------------------------------------------------------\n")); - - R (test1); - R (test2); - R (test3); - R (test4); - - return 0; -}