diff --git a/qse/cmd/sed/sed.c b/qse/cmd/sed/sed.c index e8822d82..d8c492ff 100644 --- a/qse/cmd/sed/sed.c +++ b/qse/cmd/sed/sed.c @@ -37,6 +37,39 @@ static int g_option = 0; static int g_separate = 0; static qse_ulong_t g_memlimit = 0; +#if defined(QSE_BUILD_DEBUG) +#include +static qse_ulong_t g_failmalloc; +static qse_ulong_t debug_mmgr_count = 0; + +static void* debug_mmgr_alloc (void* ctx, qse_size_t size) +{ + debug_mmgr_count++; + if (debug_mmgr_count % g_failmalloc == 0) return QSE_NULL; + return malloc (size); +} + +static void* debug_mmgr_realloc (void* ctx, void* ptr, qse_size_t size) +{ + debug_mmgr_count++; + if (debug_mmgr_count % g_failmalloc == 0) return QSE_NULL; + return realloc (ptr, size); +} + +static void debug_mmgr_free (void* ctx, void* ptr) +{ + free (ptr); +} + +static qse_mmgr_t debug_mmgr = +{ + debug_mmgr_alloc, + debug_mmgr_realloc, + debug_mmgr_free, + QSE_NULL +}; +#endif + static qse_mmgr_t xma_mmgr = { (qse_mmgr_alloc_t)qse_xma_alloc, @@ -64,14 +97,22 @@ static void print_usage (QSE_FILE* out, int argc, qse_char_t* argv[]) qse_fprintf (out, QSE_T(" -w allow address format of start~step\n")); qse_fprintf (out, QSE_T(" -x allow text on the same line as c, a, i\n")); qse_fprintf (out, QSE_T(" -y ensure a newline at text end\n")); + qse_fprintf (out, QSE_T(" -z allow 0,/regex/ address\n")); qse_fprintf (out, QSE_T(" -m number specify the maximum amount of memory to use in bytes\n")); +#if defined(QSE_BUILD_DEBUG) + qse_fprintf (out, QSE_T(" -X number fail the number'th memory allocation\n")); +#endif } static int handle_args (int argc, qse_char_t* argv[]) { static qse_opt_t opt = { - QSE_T("hnf:o:rRsawxym:"), +#if defined(QSE_BUILD_DEBUG) + QSE_T("hnf:o:rRsawxyzm:X:"), +#else + QSE_T("hnf:o:rRsawxyzm:"), +#endif QSE_NULL }; qse_cint_t c; @@ -144,9 +185,19 @@ static int handle_args (int argc, qse_char_t* argv[]) g_option |= QSE_SED_ENSURENL; break; + case QSE_T('z'): + g_option |= QSE_SED_ZEROA1; + break; + case QSE_T('m'): g_memlimit = qse_strtoulong (opt.arg); break; + +#if defined(QSE_BUILD_DEBUG) + case QSE_T('X'): + g_failmalloc = qse_strtoulong (opt.arg); + break; +#endif } } @@ -250,6 +301,14 @@ int sed_main (int argc, qse_char_t* argv[]) ret = -1; +#if defined(QSE_BUILD_DEBUG) + if (g_failmalloc > 0) + { + debug_mmgr.ctx = QSE_NULL; + mmgr = &debug_mmgr; + } + else +#endif if (g_memlimit > 0) { xma_mmgr.ctx = qse_xma_open (QSE_NULL, 0, g_memlimit); diff --git a/qse/include/qse/cmn/fio.h b/qse/include/qse/cmn/fio.h index 5dc66ec4..848d1c78 100644 --- a/qse/include/qse/cmn/fio.h +++ b/qse/include/qse/cmn/fio.h @@ -1,5 +1,5 @@ /* - * $Id: fio.h 565 2011-09-11 02:48:21Z hyunghwan.chung $ + * $Id: fio.h 569 2011-09-19 06:51:02Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -55,6 +55,14 @@ enum qse_fio_open_flag_t QSE_FIO_SEQUENTIAL = (1 << 27) /* hint that access is sequential */ }; +enum qse_fio_std_t +{ + QSE_FIO_STDIN = 0, + QSE_FIO_STDOUT = 1, + QSE_FIO_STDERR = 2 +}; +typedef enum qse_fio_std_t qse_fio_std_t; + /* seek origin */ enum qse_fio_ori_t { @@ -62,6 +70,8 @@ enum qse_fio_ori_t QSE_FIO_CURRENT = 1, QSE_FIO_END = 2 }; +/* file origin for seek */ +typedef enum qse_fio_ori_t qse_fio_ori_t; enum qse_fio_mode_t { @@ -95,9 +105,6 @@ enum qse_fio_mode_t /* file offset */ typedef qse_foff_t qse_fio_off_t; -/* file origin for seek */ -typedef enum qse_fio_ori_t qse_fio_ori_t; - typedef struct qse_fio_t qse_fio_t; typedef struct qse_fio_lck_t qse_fio_lck_t; @@ -143,14 +150,14 @@ qse_fio_t* qse_fio_open ( int mode ); -/*** +/** * The qse_fio_close() function closes a file. */ void qse_fio_close ( qse_fio_t* fio ); -/*** +/** * The qse_fio_close() function opens a file into @a fio. */ int qse_fio_init ( @@ -161,7 +168,7 @@ int qse_fio_init ( int mode ); -/*** +/** * The qse_fio_close() function finalizes a file by closing the handle * stored in @a fio. */ @@ -169,6 +176,7 @@ void qse_fio_fini ( qse_fio_t* fio ); + /** * The qse_fio_gethandle() function returns the native file handle. */ @@ -271,6 +279,12 @@ int qse_fio_unlock ( int flags ); + +int qse_getstdfiohandle ( + qse_fio_std_t std, + qse_fio_hnd_t* hnd +); + #ifdef __cplusplus } #endif diff --git a/qse/include/qse/cmn/sio.h b/qse/include/qse/cmn/sio.h index f48a552c..d005b138 100644 --- a/qse/include/qse/cmn/sio.h +++ b/qse/include/qse/cmn/sio.h @@ -1,5 +1,5 @@ /* - * $Id: sio.h 568 2011-09-17 15:41:26Z hyunghwan.chung $ + * $Id: sio.h 569 2011-09-19 06:51:02Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -50,6 +50,11 @@ enum qse_sio_open_flag_t typedef qse_fio_off_t qse_sio_pos_t; typedef qse_fio_hnd_t qse_sio_hnd_t; +typedef qse_fio_std_t qse_sio_std_t; + +#define QSE_SIO_STDIN QSE_FIO_STDIN +#define QSE_SIO_STDOUT QSE_FIO_STDOUT +#define QSE_SIO_STDER QSE_FIO_STDERR /** * The qse_sio_t type defines a simple text stream over a file. It also @@ -86,6 +91,13 @@ qse_sio_t* qse_sio_open ( int flags /**< number OR'ed of #qse_sio_open_flag_t */ ); +qse_sio_t* qse_sio_openstd ( + qse_mmgr_t* mmgr, /**< memory manager */ + qse_size_t xtnsize, /**< extension size in bytes */ + qse_sio_std_t std, /**< standard I/O identifier */ + int flags /**< number OR'ed of #qse_sio_open_flag_t */ +); + /** * The qse_sio_close() function destroys a stream object. */ @@ -100,6 +112,13 @@ int qse_sio_init ( int flags ); +int qse_sio_initstd ( + qse_sio_t* sio, + qse_mmgr_t* mmgr, + qse_sio_std_t std, + int flags +); + void qse_sio_fini ( qse_sio_t* sio ); diff --git a/qse/include/qse/sed/sed.h b/qse/include/qse/sed/sed.h index 4fc46e69..d2551039 100644 --- a/qse/include/qse/sed/sed.h +++ b/qse/include/qse/sed/sed.h @@ -1,5 +1,5 @@ /* - * $Id: sed.h 568 2011-09-17 15:41:26Z hyunghwan.chung $ + * $Id: sed.h 569 2011-09-19 06:51:02Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -140,9 +140,10 @@ enum qse_sed_option_t QSE_SED_QUIET = (1 << 3), /**< do not print pattern space */ QSE_SED_STRICT = (1 << 4), /**< do strict address check */ QSE_SED_STARTSTEP = (1 << 5), /**< allow start~step */ - QSE_SED_EXTENDEDREX = (1 << 6), /**< use extended regex */ - QSE_SED_NONSTDEXTREX = (1 << 7), /**< enable non-standard extensions to regex */ - QSE_SED_SAMELINE = (1 << 8), /**< allow text on the same line as c, a, i */ + QSE_SED_ZEROA1 = (1 << 6), /**< allow 0,/regex/ */ + QSE_SED_SAMELINE = (1 << 7), /**< allow text on the same line as c, a, i */ + QSE_SED_EXTENDEDREX = (1 << 8), /**< use extended regex */ + QSE_SED_NONSTDEXTREX = (1 << 9) /**< enable non-standard extensions to regex */ }; typedef enum qse_sed_option_t qse_sed_option_t; diff --git a/qse/include/qse/sed/std.h b/qse/include/qse/sed/std.h index fc61a3b9..73823ec7 100644 --- a/qse/include/qse/sed/std.h +++ b/qse/include/qse/sed/std.h @@ -105,13 +105,13 @@ int qse_sed_compstd ( ); /** - * The qse_sed_execstd() function executes the compiled script + * The qse_sed_execstd() function executes a compiled script * over input streams @a in and an output stream @a out. * * If @a in is not #QSE_NULL, it must point to a null-terminated array - * of standard I/O resources. if in[0] is QSE_NULL, this function - * returns failure, requiring at least 1 valid resource to be included - * in the array. + * of standard I/O resources. if in[0].type is QSE_SED_IOSTD_NULL, this + * function returns failure, requiring at least 1 valid resource to be + * included in the array. * * If @a in is #QSE_NULL, the standard console input is used. * If @a out is #QSE_NULL, the standard console output is used. @@ -124,6 +124,21 @@ int qse_sed_execstd ( qse_sed_iostd_t* out ); +/** + * The qse_sed_execstdfile() function executes a compiled script + * a single input file @a infile and a single output file @a outfile. + * + * If @a infile is #QSE_NULL, the standard console input is used. + * If @a outfile is #QSE_NULL, the standard console output is used. + * + * @return 0 on success, -1 on failure + */ +int qse_sed_execstdfile ( + qse_sed_t* sed, + const qse_char_t* infile, + const qse_char_t* outfile +); + #ifdef __cplusplus } #endif diff --git a/qse/lib/cmn/fio.c b/qse/lib/cmn/fio.c index 29340321..3639e20c 100644 --- a/qse/lib/cmn/fio.c +++ b/qse/lib/cmn/fio.c @@ -1,5 +1,5 @@ /* - * $Id: fio.c 565 2011-09-11 02:48:21Z hyunghwan.chung $ + * $Id: fio.c 569 2011-09-19 06:51:02Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -45,8 +45,10 @@ QSE_IMPLEMENT_COMMON_FUNCTIONS (fio) -static qse_ssize_t fio_input (qse_tio_cmd_t cmd, void* arg, void* buf, qse_size_t size); -static qse_ssize_t fio_output (qse_tio_cmd_t cmd, void* arg, void* buf, qse_size_t size); +static qse_ssize_t fio_input ( + qse_tio_cmd_t cmd, void* arg, void* buf, qse_size_t size); +static qse_ssize_t fio_output ( + qse_tio_cmd_t cmd, void* arg, void* buf, qse_size_t size); qse_fio_t* qse_fio_open ( qse_mmgr_t* mmgr, qse_size_t ext, @@ -851,3 +853,34 @@ static qse_ssize_t fio_output (qse_tio_cmd_t cmd, void* arg, void* buf, qse_size * by fio */ return 0; } + +int qse_getstdfiohandle (qse_fio_std_t std, qse_fio_hnd_t* hnd) +{ + qse_fio_hnd_t tab[] = + { +#if defined(_WIN32) + (HANDLE)STD_INPUT_HANDLE, + (HANDLE)STD_OUTPUT_HANDLE, + (HANDLE)STD_ERROR_HANDLE +#elif defined(__OS2__) + (HFILE)0, (HFILE)1, (HFILE)2 +#elif defined(__DOS__) + 0, 1, 2 +#else + 0, 1, 2 +#endif + }; + + if (std < 0 || std >= QSE_COUNTOF(tab)) return -1; + +#if defined(_WIN32) + { + HANDLE tmp = GetStdHandle (tab[std]); + if (tmp == INVALID_HANDLE_VALUE) return -1; + *hnd = tmp; + } +#else + *hnd = tab[std]; +#endif + return 0; +} diff --git a/qse/lib/cmn/sio.c b/qse/lib/cmn/sio.c index 90f695c4..b8304be0 100644 --- a/qse/lib/cmn/sio.c +++ b/qse/lib/cmn/sio.c @@ -1,5 +1,5 @@ /* - * $Id: sio.c 568 2011-09-17 15:41:26Z hyunghwan.chung $ + * $Id: sio.c 569 2011-09-19 06:51:02Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -194,6 +194,14 @@ qse_sio_t* qse_sio_open ( return sio; } +qse_sio_t* qse_sio_openstd ( + qse_mmgr_t* mmgr, qse_size_t xtnsize, qse_sio_std_t std, int flags) +{ + qse_fio_hnd_t hnd; + if (qse_getstdfiohandle (std, &hnd) <= -1) return QSE_NULL; + return qse_sio_open (mmgr, xtnsize, &hnd, flags | QSE_SIO_HANDLE); +} + void qse_sio_close (qse_sio_t* sio) { qse_sio_fini (sio); @@ -235,6 +243,14 @@ int qse_sio_init ( return 0; } +int qse_sio_initstd ( + qse_sio_t* sio, qse_mmgr_t* mmgr, qse_sio_std_t std, int flags) +{ + qse_fio_hnd_t hnd; + if (qse_getstdfiohandle (std, &hnd) <= -1) return -1; + return qse_sio_init (sio, mmgr, &hnd, flags | QSE_SIO_HANDLE); +} + void qse_sio_fini (qse_sio_t* sio) { /*if (qse_sio_flush (sio) == -1) return -1;*/ diff --git a/qse/lib/sed/StdSed.cpp b/qse/lib/sed/StdSed.cpp index 5c784a44..49ba4e10 100644 --- a/qse/lib/sed/StdSed.cpp +++ b/qse/lib/sed/StdSed.cpp @@ -1,5 +1,5 @@ /* - * $Id: StdSed.cpp 556 2011-08-31 15:43:46Z hyunghwan.chung $ + * $Id: StdSed.cpp 569 2011-09-19 06:51:02Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -28,68 +28,69 @@ QSE_BEGIN_NAMESPACE(QSE) ///////////////////////////////// +static qse_sio_t* open_sio (StdSed::Stream::Data& io, const qse_char_t* file, int flags) +{ + qse_sio_t* sio; + + sio = qse_sio_open (((StdSed::sed_t*)io)->mmgr, 0, file, flags); + if (sio == QSE_NULL) + { + qse_cstr_t ea; + ea.ptr = file; + ea.len = qse_strlen (file); + ((StdSed::Sed*)io)->setError (QSE_SED_EIOFIL, &ea); + } + return sio; +} + +static qse_sio_t* open_sio_std (StdSed::Stream::Data& io, qse_sio_std_t std, int flags) +{ + qse_sio_t* sio; + static const qse_char_t* std_names[] = + { + QSE_T("stdin"), + QSE_T("stdout"), + QSE_T("stderr"), + }; + + sio = qse_sio_openstd (((StdSed::sed_t*)io)->mmgr, 0, std, flags); + if (sio == QSE_NULL) + { + qse_cstr_t ea; + ea.ptr = std_names[std]; + ea.len = qse_strlen (std_names[std]); + ((StdSed::Sed*)io)->setError (QSE_SED_EIOFIL, &ea); + } + return sio; +} + int StdSed::FileStream::open (Data& io) { qse_sio_t* sio; const char_t* ioname = io.getName(); + int oflags; + + if (io.getMode() == READ) + oflags = QSE_SIO_READ | QSE_SIO_IGNOREMBWCERR; + else + oflags = QSE_SIO_WRITE | QSE_SIO_CREATE | QSE_SIO_TRUNCATE | QSE_SIO_IGNOREMBWCERR; if (ioname == QSE_NULL) { // // a normal console is indicated by a null name // - if (io.getMode() == READ) { - if (infile == QSE_NULL) sio = qse_sio_in; - else - { - sio = qse_sio_open ( - ((sed_t*)io)->mmgr, - 0, - infile, - QSE_SIO_READ - ); - if (sio == QSE_NULL) - { - // set the error message explicitly - // as the file name is different from - // the standard console name (NULL) - qse_cstr_t ea; - ea.ptr = infile; - ea.len = qse_strlen (infile); - ((Sed*)io)->setError ( - QSE_SED_EIOFIL, &ea); - return -1; - } - } + sio = (infile == QSE_NULL)? + open_sio_std (io, QSE_SIO_STDIN, oflags): + open_sio (io, infile, oflags); } else { - if (outfile == QSE_NULL) sio = qse_sio_out; - else - { - sio = qse_sio_open ( - ((sed_t*)io)->mmgr, - 0, - outfile, - QSE_SIO_WRITE | - QSE_SIO_CREATE | - QSE_SIO_TRUNCATE - ); - if (sio == QSE_NULL) - { - // set the error message explicitly - // as the file name is different from - // the standard console name (NULL) - qse_cstr_t ea; - ea.ptr = outfile; - ea.len = qse_strlen (outfile); - ((Sed*)io)->setError ( - QSE_SED_EIOFIL, &ea); - return -1; - } - } + sio = (outfile == QSE_NULL)? + open_sio_std (io, QSE_SIO_STDOUT, oflags): + open_sio (io, outfile, oflags); } } else @@ -97,18 +98,9 @@ int StdSed::FileStream::open (Data& io) // // if ioname is not empty, it is a file name // - - sio = qse_sio_open ( - ((sed_t*)io)->mmgr, - 0, - ioname, - (io.getMode() == READ? - QSE_SIO_READ: - (QSE_SIO_WRITE|QSE_SIO_CREATE|QSE_SIO_TRUNCATE)) - ); - - if (sio == QSE_NULL) return -1; + sio = open_sio (io, ioname, oflags); } + if (sio == QSE_NULL) return -1; io.setHandle (sio); return 1; @@ -116,12 +108,7 @@ int StdSed::FileStream::open (Data& io) int StdSed::FileStream::close (Data& io) { - qse_sio_t* sio = (qse_sio_t*)io.getHandle(); - - qse_sio_flush (sio); - if (sio != qse_sio_in && sio != qse_sio_out && sio != qse_sio_err) - qse_sio_close (sio); - + qse_sio_close ((qse_sio_t*)io.getHandle()); return 0; } diff --git a/qse/lib/sed/sed.c b/qse/lib/sed/sed.c index 6cf838f4..0d3eb57e 100644 --- a/qse/lib/sed/sed.c +++ b/qse/lib/sed/sed.c @@ -1,5 +1,5 @@ /* - * $Id: sed.c 568 2011-09-17 15:41:26Z hyunghwan.chung $ + * $Id: sed.c 569 2011-09-19 06:51:02Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -1389,6 +1389,14 @@ static int get_command (qse_sed_t* sed, qse_sed_cmd_t* cmd) if (c != QSE_T('\\')) { + if ((sed->option & QSE_SED_SAMELINE) && + c != QSE_CHAR_EOF && c != QSE_T('\n')) + { + /* allow text without a starting backslash + * on the same line as a command */ + goto sameline_ok; + } + SETERR0 (sed, QSE_SED_EBSEXP, &sed->src.loc); return -1; } @@ -1399,7 +1407,11 @@ static int get_command (qse_sed_t* sed, qse_sed_cmd_t* cmd) if (c != QSE_CHAR_EOF && c != QSE_T('\n')) { if (sed->option & QSE_SED_SAMELINE) + { + /* allow text with a starting backslash + * on the same line as a command */ goto sameline_ok; + } SETERR0 (sed, QSE_SED_EGBABS, &sed->src.loc); return -1; @@ -1592,9 +1604,14 @@ int qse_sed_comp (qse_sed_t* sed, const qse_char_t* sptr, qse_size_t slen) cmd->a1.type == QSE_SED_ADR_LINE && cmd->a1.u.lno <= 0) { - /* 0 is not allowed as a normal line number */ - SETERR0 (sed, QSE_SED_EA1MOI, &sed->src.loc); - goto oops; + if (!(sed->option & QSE_SED_ZEROA1) || + cmd->a2.type != QSE_SED_ADR_REX) + { + /* 0 is not allowed as a normal line number. + * 0,/regex/ is allowed */ + SETERR0 (sed, QSE_SED_EA1MOI, &sed->src.loc); + goto oops; + } } /* skip white spaces */ @@ -2891,6 +2908,18 @@ static int init_command_block_for_exec (qse_sed_t* sed, qse_sed_cmd_blk_t* b) /* clear states */ c->state.a1_matched = 0; + + if (sed->option & QSE_SED_ZEROA1) + { + if (c->a2.type == QSE_SED_ADR_REX && + c->a1.type == QSE_SED_ADR_LINE && + c->a1.u.lno <= 0) + { + /* special handling for 0,/regex/ */ + c->state.a1_matched = 1; + } + } + c->state.c_ready = 0; /* let c point to the next command */ diff --git a/qse/lib/sed/std.c b/qse/lib/sed/std.c index 3ec375ad..63d32cff 100644 --- a/qse/lib/sed/std.c +++ b/qse/lib/sed/std.c @@ -85,18 +85,34 @@ static qse_sio_t* open_sio (qse_sed_t* sed, const qse_char_t* file, int flags) return sio; } +static qse_sio_t* open_sio_std (qse_sed_t* sed, qse_sio_std_t std, int flags) +{ + qse_sio_t* sio; + static const qse_char_t* std_names[] = + { + QSE_T("stdin"), + QSE_T("stdout"), + QSE_T("stderr"), + }; + + sio = qse_sio_openstd (sed->mmgr, 0, std, flags); + if (sio == QSE_NULL) + { + qse_cstr_t ea; + ea.ptr = std_names[std]; + ea.len = qse_strlen (std_names[std]); + qse_sed_seterrnum (sed, QSE_SED_EIOFIL, &ea); + } + return sio; +} + static void close_main_stream ( qse_sed_t* sed, qse_sed_io_arg_t* arg, qse_sed_iostd_t* io) { - if (io->type == QSE_SED_IOSTD_FILE) - { - qse_sio_t* sio = (qse_sio_t*)arg->handle; - if (sio != qse_sio_in && sio != qse_sio_out && sio != qse_sio_err) - qse_sio_close (sio); - } + if (io->type == QSE_SED_IOSTD_FILE) qse_sio_close (arg->handle); } -static int open_main_input_stream (qse_sed_t* sed, qse_sed_io_arg_t* arg, qse_sed_iostd_t* io) +static int open_console_input_stream (qse_sed_t* sed, qse_sed_io_arg_t* arg, qse_sed_iostd_t* io) { xtn_t* xtn = (xtn_t*) QSE_XTN (sed); @@ -108,18 +124,15 @@ static int open_main_input_stream (qse_sed_t* sed, qse_sed_io_arg_t* arg, qse_se break; case QSE_SED_IOSTD_FILE: - if (io->u.file == QSE_NULL) - { - arg->handle = qse_sio_in; - } - else - { - qse_sio_t* sio; - sio = open_sio (sed, io->u.file, QSE_SIO_READ | QSE_SIO_IGNOREMBWCERR); - if (sio == QSE_NULL) return -1; - arg->handle = sio; - } + { + qse_sio_t* sio; + sio = (io->u.file == QSE_NULL)? + open_sio_std (sed, QSE_SIO_STDIN, QSE_SIO_READ | QSE_SIO_IGNOREMBWCERR): + open_sio (sed, io->u.file, QSE_SIO_READ | QSE_SIO_IGNOREMBWCERR); + if (sio == QSE_NULL) return -1; + arg->handle = sio; break; + } case QSE_SED_IOSTD_MEM: /* don't store anything to arg->handle */ @@ -130,7 +143,7 @@ static int open_main_input_stream (qse_sed_t* sed, qse_sed_io_arg_t* arg, qse_se return 0; } -static int open_main_output_stream (qse_sed_t* sed, qse_sed_io_arg_t* arg, qse_sed_iostd_t* io) +static int open_console_output_stream (qse_sed_t* sed, qse_sed_io_arg_t* arg, qse_sed_iostd_t* io) { xtn_t* xtn = (xtn_t*) QSE_XTN (sed); @@ -142,23 +155,32 @@ static int open_main_output_stream (qse_sed_t* sed, qse_sed_io_arg_t* arg, qse_s break; case QSE_SED_IOSTD_FILE: + { + qse_sio_t* sio; if (io->u.file == QSE_NULL) { - arg->handle = qse_sio_out; - } - else - { - qse_sio_t* sio; - sio = open_sio (sed, io->u.file, + sio = open_sio_std ( + sed, QSE_SIO_STDOUT, QSE_SIO_WRITE | QSE_SIO_CREATE | QSE_SIO_TRUNCATE | QSE_SIO_IGNOREMBWCERR ); - if (sio == QSE_NULL) return -1; - arg->handle = sio; } + else + { + sio = open_sio ( + sed, io->u.file, + QSE_SIO_WRITE | + QSE_SIO_CREATE | + QSE_SIO_TRUNCATE | + QSE_SIO_IGNOREMBWCERR + ); + } + if (sio == QSE_NULL) return -1; + arg->handle = sio; break; + } case QSE_SED_IOSTD_MEM: /* don't store anything to arg->handle */ @@ -211,7 +233,7 @@ static qse_ssize_t read_main_input_stream ( old = arg->handle; /* try to open the next input stream */ - if (open_main_input_stream (sed, arg, next) <= -1) + if (open_console_input_stream (sed, arg, next) <= -1) { /* failed to open the next input stream */ n = -1; @@ -243,11 +265,17 @@ static qse_ssize_t xin ( { if (arg->path == QSE_NULL) { - /* main data stream */ - if (xtn->e.in == QSE_NULL) arg->handle = qse_sio_in; + /* not file specified. console stream */ + if (xtn->e.in == QSE_NULL) + { + sio = open_sio_std ( + sed, QSE_SIO_STDIN, QSE_SIO_READ | QSE_SIO_IGNOREMBWCERR); + if (sio == QSE_NULL) return -1; + arg->handle = sio; + } else { - if (open_main_input_stream (sed, arg, xtn->e.in_cur) <= -1) return -1; + if (open_console_input_stream (sed, arg, xtn->e.in_cur) <= -1) return -1; } } else @@ -265,13 +293,14 @@ static qse_ssize_t xin ( if (arg->path == QSE_NULL) { /* main data stream */ - if (xtn->e.in) close_main_stream (sed, arg, xtn->e.in_cur); + if (xtn->e.in == QSE_NULL) + qse_sio_close (arg->handle); + else + close_main_stream (sed, arg, xtn->e.in_cur); } else { - sio = (qse_sio_t*)arg->handle; - if (sio != qse_sio_in && sio != qse_sio_out && sio != qse_sio_err) - qse_sio_close (sio); + qse_sio_close (arg->handle); } return 0; @@ -311,10 +340,21 @@ static qse_ssize_t xout ( { if (arg->path == QSE_NULL) { - if (xtn->e.out == QSE_NULL) arg->handle = qse_sio_out; + if (xtn->e.out == QSE_NULL) + { + sio = open_sio_std ( + sed, QSE_SIO_STDOUT, + QSE_SIO_WRITE | + QSE_SIO_CREATE | + QSE_SIO_TRUNCATE | + QSE_SIO_IGNOREMBWCERR + ); + if (sio == QSE_NULL) return -1; + arg->handle = sio; + } else { - if (open_main_output_stream (sed, arg, xtn->e.out) <= -1) return -1; + if (open_console_output_stream (sed, arg, xtn->e.out) <= -1) return -1; } } else @@ -337,14 +377,14 @@ static qse_ssize_t xout ( { if (arg->path == QSE_NULL) { - if (xtn->e.out) close_main_stream (sed, arg, xtn->e.out); + if (xtn->e.out == QSE_NULL) + qse_sio_close (arg->handle); + else + close_main_stream (sed, arg, xtn->e.out); } else { - sio = (qse_sio_t*)arg->handle; - qse_sio_flush (sio); - if (sio != qse_sio_in && sio != qse_sio_out && sio != qse_sio_err) - qse_sio_close (sio); + qse_sio_close (arg->handle); } return 0; } @@ -355,7 +395,9 @@ static qse_ssize_t xout ( { /* main data stream */ if (xtn->e.out == QSE_NULL) + { return qse_sio_putsn (arg->handle, dat, len); + } else { qse_sed_iostd_t* io = xtn->e.out; @@ -443,14 +485,30 @@ int qse_sed_execstd ( } if (xtn->e.out_memstr) qse_str_close (xtn->e.out_memstr); - /* if some output without a newline is emitted before - * last flush, they can be lost because qse_sio_out - * is not explicitly closed() with qse_sio_close() - * which in turn calls qse_sio_flush(). let's call it - * here directly. I don't care whether some other - * threads could have written to this. */ - qse_sio_flush (qse_sio_out); - return n; } +int qse_sed_execstdfile ( + qse_sed_t* sed, const qse_char_t* infile, const qse_char_t* outfile) +{ + qse_sed_iostd_t in[2]; + qse_sed_iostd_t out; + qse_sed_iostd_t* pin = QSE_NULL, * pout = QSE_NULL; + + if (infile) + { + in[0].type = QSE_SED_IOSTD_FILE; + in[0].u.file = infile; + in[1].type = QSE_SED_IOSTD_NULL; + pin = in; + } + + if (outfile) + { + out.type = QSE_SED_IOSTD_FILE; + out.u.file = outfile; + pout = &out; + } + + return qse_sed_execstd (sed, pin, pout); +} diff --git a/qse/samples/sed/sed01.c b/qse/samples/sed/sed01.c index 077a1d3c..0aaf1286 100644 --- a/qse/samples/sed/sed01.c +++ b/qse/samples/sed/sed01.c @@ -51,7 +51,7 @@ int sed_main (int argc, qse_char_t* argv[]) infile = (argc >= 3)? argv[2]: QSE_NULL; outfile = (argc >= 4)? argv[3]: QSE_NULL; - if (qse_sed_execstd (sed, infile, outfile) <= -1) + if (qse_sed_execstdfile (sed, infile, outfile) <= -1) { qse_fprintf (QSE_STDERR, QSE_T("ERROR: %s\n"), qse_sed_geterrmsg(sed)); goto oops;