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
This commit is contained in:
hyung-hwan 2009-01-15 03:58:27 +00:00
parent b1897b3b4d
commit 46e4ed5087
16 changed files with 1331 additions and 1145 deletions

View File

@ -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 pkgincludedir= $(includedir)/qse/cmn

View File

@ -172,7 +172,7 @@ sysconfdir = @sysconfdir@
target_alias = @target_alias@ target_alias = @target_alias@
top_builddir = @top_builddir@ top_builddir = @top_builddir@
top_srcdir = @top_srcdir@ 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 CLEANFILES = *dist
all: all-am all: all-am

321
qse/include/qse/cmn/pcp.h Normal file
View File

@ -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 <qse/types.h>
#include <qse/macros.h>
#include <qse/cmn/tio.h>
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
/* <winnt.h> => 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

View File

@ -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 <qse/types.h>
#include <qse/macros.h>
#include <qse/cmn/tio.h>
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
/* <winnt.h> => 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

View File

@ -85,7 +85,7 @@ typedef qse_ssize_t (*qse_tio_io_t) (
struct qse_tio_t struct qse_tio_t
{ {
qse_mmgr_t* mmgr; QSE_DEFINE_STD_FIELDS (tio)
qse_tio_err_t errnum; qse_tio_err_t errnum;
/* io functions */ /* io functions */
@ -108,6 +108,8 @@ struct qse_tio_t
extern "C" { extern "C" {
#endif #endif
QSE_DEFINE_STD_FUNCTIONS (tio)
/* /*
* FUNCTION: qse_tio_open * FUNCTION: qse_tio_open
*/ */
@ -132,26 +134,15 @@ int qse_tio_fini (
qse_tio_t* tio 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 /****f* qse.cmn.tio/qse_tio_geterrnum
* NAME * NAME
* qse_tio_geterrnum - get an error code * qse_tio_geterrnum - get an error code
* *
* SYNOPSIS * 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: * RETURNS:
* A pointer to a constant string describing the last error occurred * 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 * FUNCTION: qse_tio_attachin

View File

@ -154,4 +154,26 @@
# define QSE_END_NAMESPACE2(y,x) }} # define QSE_END_NAMESPACE2(y,x) }}
#endif #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 #endif

View File

@ -18,6 +18,7 @@
#include "awk.h" #include "awk.h"
#include <qse/cmn/sio.h> #include <qse/cmn/sio.h>
#include <qse/cmn/pcp.h>
#include <qse/cmn/str.h> #include <qse/cmn/str.h>
#include <qse/cmn/time.h> #include <qse/cmn/time.h>
#include <qse/utl/stdio.h> /* TODO: remove dependency on qse_vsprintf */ #include <qse/utl/stdio.h> /* TODO: remove dependency on qse_vsprintf */
@ -345,25 +346,30 @@ static qse_ssize_t awk_extio_pipe (
{ {
case QSE_AWK_IO_OPEN: case QSE_AWK_IO_OPEN:
{ {
qse_sio_t* handle; qse_pcp_t* handle;
int mode; int flags;
if (epa->mode == QSE_AWK_EXTIO_PIPE_READ) 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) else if (epa->mode == QSE_AWK_EXTIO_PIPE_WRITE)
{ {
mode = QSE_SIO_WRITE | flags = QSE_PCP_WRITEIN;
QSE_SIO_TRUNCATE |
QSE_SIO_CREATE;
} }
else return -1; /* TODO: any way to set the error number? */ 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);*/ /*dprint (QSE_T("opening %s of type %d (pipe)\n"), epa->name, epa->type);*/
/* TOOD: popen.... */ handle = qse_pcp_open (
handle = qse_sio_open (qse_awk_getrunmmgr(epa->run), 0, epa->name, mode); qse_awk_getrunmmgr(epa->run),
0,
epa->name,
flags|QSE_PCP_SHELL|QSE_PCP_TEXT
);
if (handle == QSE_NULL) return -1; if (handle == QSE_NULL) return -1;
epa->handle = (void*)handle; epa->handle = (void*)handle;
return 1; return 1;
@ -372,33 +378,35 @@ static qse_ssize_t awk_extio_pipe (
case QSE_AWK_IO_CLOSE: case QSE_AWK_IO_CLOSE:
{ {
/*dprint (QSE_T("closing %s of type (pipe) %d\n"), epa->name, epa->type);*/ /*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; epa->handle = QSE_NULL;
return 0; return 0;
} }
case QSE_AWK_IO_READ: case QSE_AWK_IO_READ:
{ {
return qse_sio_getsx ( return qse_pcp_read (
(qse_sio_t*)epa->handle, (qse_pcp_t*)epa->handle,
data, data,
size size,
QSE_PCP_OUT
); );
} }
case QSE_AWK_IO_WRITE: case QSE_AWK_IO_WRITE:
{ {
return qse_sio_putsx ( return qse_pcp_write (
(qse_sio_t*)epa->handle, (qse_pcp_t*)epa->handle,
data, data,
size size,
QSE_PCP_IN
); );
} }
case QSE_AWK_IO_FLUSH: case QSE_AWK_IO_FLUSH:
{ {
/*if (epa->mode == QSE_AWK_EXTIO_PIPE_READ) return -1;*/ /*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: case QSE_AWK_IO_NEXT:

View File

@ -6,7 +6,7 @@ lib_LTLIBRARIES = libqsecmn.la
libqsecmn_la_SOURCES = mem.h chr.h \ 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 \ 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 \ 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 \ time.c \
misc.c misc.c
libqsecmn_la_LDFLAGS = -version-info 1:0:0 -no-undefined libqsecmn_la_LDFLAGS = -version-info 1:0:0 -no-undefined

View File

@ -53,7 +53,7 @@ LTLIBRARIES = $(lib_LTLIBRARIES)
libqsecmn_la_DEPENDENCIES = libqsecmn_la_DEPENDENCIES =
am_libqsecmn_la_OBJECTS = mem.lo chr.lo chr_cnv.lo rex.lo str_bas.lo \ 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 \ 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 time.lo misc.lo
libqsecmn_la_OBJECTS = $(am_libqsecmn_la_OBJECTS) libqsecmn_la_OBJECTS = $(am_libqsecmn_la_OBJECTS)
libqsecmn_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ libqsecmn_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
@ -198,7 +198,7 @@ lib_LTLIBRARIES = libqsecmn.la
libqsecmn_la_SOURCES = mem.h chr.h \ 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 \ 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 \ 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 \ time.c \
misc.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)/mem.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misc.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)/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)/rex.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sio.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@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sll.Plo@am__quote@

696
qse/lib/cmn/pcp.c Normal file
View File

@ -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 <qse/cmn/pcp.h>
#include <qse/cmn/str.h>
#include "mem.h"
#ifdef _WIN32
# include <windows.h>
# include <tchar.h>
#else
# include "syscall.h"
# include <fcntl.h>
# include <errno.h>
# include <sys/wait.h>
#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;
}

View File

@ -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 <qse/cmn/pio.h>
#include <qse/cmn/str.h>
#include "mem.h"
#ifdef _WIN32
# include <windows.h>
# include <tchar.h>
#else
# include "syscall.h"
# include <fcntl.h>
# include <errno.h>
# include <sys/wait.h>
#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;
}

View File

@ -19,6 +19,8 @@
#include <qse/cmn/tio.h> #include <qse/cmn/tio.h>
#include "mem.h" #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* qse_tio_open (qse_mmgr_t* mmgr, qse_size_t ext)
{ {
qse_tio_t* tio; qse_tio_t* tio;
@ -83,21 +85,6 @@ int qse_tio_fini (qse_tio_t* tio)
return 0; 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) qse_tio_err_t qse_tio_geterrnum (qse_tio_t* tio)
{ {
return tio->errnum; return tio->errnum;

View File

@ -1,6 +1,6 @@
AM_CPPFLAGS = -I$(top_srcdir)/include 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 LDFLAGS = -L../../lib/cmn -L../../lib/utl
LDADD = -lqseutl -lqsecmn LDADD = -lqseutl -lqsecmn
@ -11,6 +11,6 @@ sll_SOURCES = sll.c
map_SOURCES = map.c map_SOURCES = map.c
lda_SOURCES = lda.c lda_SOURCES = lda.c
fio_SOURCES = fio.c fio_SOURCES = fio.c
pio_SOURCES = pio.c pcp_SOURCES = pcp.c
sio_SOURCES = sio.c sio_SOURCES = sio.c
time_SOURCES = time.c time_SOURCES = time.c

View File

@ -33,7 +33,7 @@ POST_UNINSTALL = :
build_triplet = @build@ build_triplet = @build@
host_triplet = @host@ host_triplet = @host@
bin_PROGRAMS = chr$(EXEEXT) str$(EXEEXT) sll$(EXEEXT) map$(EXEEXT) \ 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) time$(EXEEXT)
subdir = test/cmn subdir = test/cmn
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
@ -63,10 +63,10 @@ am_map_OBJECTS = map.$(OBJEXT)
map_OBJECTS = $(am_map_OBJECTS) map_OBJECTS = $(am_map_OBJECTS)
map_LDADD = $(LDADD) map_LDADD = $(LDADD)
map_DEPENDENCIES = map_DEPENDENCIES =
am_pio_OBJECTS = pio.$(OBJEXT) am_pcp_OBJECTS = pcp.$(OBJEXT)
pio_OBJECTS = $(am_pio_OBJECTS) pcp_OBJECTS = $(am_pcp_OBJECTS)
pio_LDADD = $(LDADD) pcp_LDADD = $(LDADD)
pio_DEPENDENCIES = pcp_DEPENDENCIES =
am_sio_OBJECTS = sio.$(OBJEXT) am_sio_OBJECTS = sio.$(OBJEXT)
sio_OBJECTS = $(am_sio_OBJECTS) sio_OBJECTS = $(am_sio_OBJECTS)
sio_LDADD = $(LDADD) sio_LDADD = $(LDADD)
@ -96,10 +96,10 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
$(LDFLAGS) -o $@ $(LDFLAGS) -o $@
SOURCES = $(chr_SOURCES) $(fio_SOURCES) $(lda_SOURCES) $(map_SOURCES) \ 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) $(time_SOURCES)
DIST_SOURCES = $(chr_SOURCES) $(fio_SOURCES) $(lda_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) $(str_SOURCES) $(time_SOURCES)
ETAGS = etags ETAGS = etags
CTAGS = ctags CTAGS = ctags
@ -228,7 +228,7 @@ sll_SOURCES = sll.c
map_SOURCES = map.c map_SOURCES = map.c
lda_SOURCES = lda.c lda_SOURCES = lda.c
fio_SOURCES = fio.c fio_SOURCES = fio.c
pio_SOURCES = pio.c pcp_SOURCES = pcp.c
sio_SOURCES = sio.c sio_SOURCES = sio.c
time_SOURCES = time.c time_SOURCES = time.c
all: all-am all: all-am
@ -304,9 +304,9 @@ lda$(EXEEXT): $(lda_OBJECTS) $(lda_DEPENDENCIES)
map$(EXEEXT): $(map_OBJECTS) $(map_DEPENDENCIES) map$(EXEEXT): $(map_OBJECTS) $(map_DEPENDENCIES)
@rm -f map$(EXEEXT) @rm -f map$(EXEEXT)
$(LINK) $(map_OBJECTS) $(map_LDADD) $(LIBS) $(LINK) $(map_OBJECTS) $(map_LDADD) $(LIBS)
pio$(EXEEXT): $(pio_OBJECTS) $(pio_DEPENDENCIES) pcp$(EXEEXT): $(pcp_OBJECTS) $(pcp_DEPENDENCIES)
@rm -f pio$(EXEEXT) @rm -f pcp$(EXEEXT)
$(LINK) $(pio_OBJECTS) $(pio_LDADD) $(LIBS) $(LINK) $(pcp_OBJECTS) $(pcp_LDADD) $(LIBS)
sio$(EXEEXT): $(sio_OBJECTS) $(sio_DEPENDENCIES) sio$(EXEEXT): $(sio_OBJECTS) $(sio_DEPENDENCIES)
@rm -f sio$(EXEEXT) @rm -f sio$(EXEEXT)
$(LINK) $(sio_OBJECTS) $(sio_LDADD) $(LIBS) $(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)/fio.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lda.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)/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)/sio.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sll.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@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str.Po@am__quote@

237
qse/test/cmn/pcp.c Normal file
View File

@ -0,0 +1,237 @@
#include <qse/cmn/pcp.h>
#include <qse/utl/stdio.h>
#include <string.h>
#include <locale.h>
#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;
}

View File

@ -1,111 +0,0 @@
#include <qse/cmn/pio.h>
#include <qse/utl/stdio.h>
#include <string.h>
#include <locale.h>
#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;
}