From ecaed2c2b37b9b3c8508e2ee466eb8e4ddad7dbe Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Sun, 18 Sep 2011 09:41:26 +0000 Subject: [PATCH] added qse_sed_io_std_t and related code --- qse/cmd/sed/sed.c | 236 ++++++++++++----------- qse/include/qse/awk/awk.h | 5 +- qse/include/qse/cmn/sio.h | 22 +-- qse/include/qse/cut/cut.h | 1 + qse/include/qse/sed/sed.h | 3 +- qse/include/qse/sed/std.h | 43 ++++- qse/lib/awk/err.c | 5 +- qse/lib/cmn/sio.c | 8 +- qse/lib/cut/err.c | 1 + qse/lib/sed/err.c | 3 +- qse/lib/sed/sed.c | 27 +-- qse/lib/sed/sed.h | 4 +- qse/lib/sed/std.c | 392 +++++++++++++++++++++++++++++--------- 13 files changed, 513 insertions(+), 237 deletions(-) diff --git a/qse/cmd/sed/sed.c b/qse/cmd/sed/sed.c index 2d5f5757..e8822d82 100644 --- a/qse/cmd/sed/sed.c +++ b/qse/cmd/sed/sed.c @@ -18,7 +18,7 @@ License along with QSE. If not, see . */ -#include +#include #include #include #include @@ -31,8 +31,10 @@ static const qse_char_t* g_script_file = QSE_NULL; static qse_char_t* g_script = QSE_NULL; -static const qse_char_t* g_infile = QSE_NULL; +static qse_char_t* g_output_file = QSE_NULL; +static int g_infile_pos = 0; static int g_option = 0; +static int g_separate = 0; static qse_ulong_t g_memlimit = 0; static qse_mmgr_t xma_mmgr = @@ -43,91 +45,6 @@ static qse_mmgr_t xma_mmgr = QSE_NULL }; -static qse_ssize_t in ( - qse_sed_t* sed, qse_sed_io_cmd_t cmd, - qse_sed_io_arg_t* arg, qse_char_t* buf, qse_size_t size) -{ - switch (cmd) - { - case QSE_SED_IO_OPEN: - { - const qse_char_t* file; - - if (arg->path == QSE_NULL || arg->path[0] == QSE_T('\0')) - { - file = (g_infile == QSE_NULL)? QSE_NULL: g_infile; - } - else file = arg->path; - - - if (file == QSE_NULL) arg->handle = qse_sio_in; - else - { - arg->handle = qse_sio_open ( - qse_sed_getmmgr(sed), - 0, - file, - QSE_SIO_READ | QSE_SIO_IGNOREMBWCERR - ); - - if (arg->handle == QSE_NULL) return -1; - } - - return 1; - } - - case QSE_SED_IO_CLOSE: - if (arg->handle != qse_sio_in) qse_sio_close (arg->handle); - return 0; - - case QSE_SED_IO_READ: - return qse_sio_getsn (arg->handle, buf, size); - - default: - return -1; - } -} - -static qse_ssize_t out ( - qse_sed_t* sed, qse_sed_io_cmd_t cmd, - qse_sed_io_arg_t* arg, qse_char_t* data, qse_size_t len) -{ - switch (cmd) - { - case QSE_SED_IO_OPEN: - if (arg->path == QSE_NULL || arg->path[0] == QSE_T('\0')) - { - arg->handle = qse_sio_out; - } - else - { - arg->handle = qse_sio_open ( - qse_sed_getmmgr(sed), - 0, - arg->path, - QSE_SIO_WRITE | - QSE_SIO_CREATE | - QSE_SIO_TRUNCATE | - QSE_SIO_IGNOREMBWCERR - ); - - if (arg->handle == QSE_NULL) return -1; - } - return 1; - - case QSE_SED_IO_CLOSE: - qse_sio_flush (arg->handle); - if (arg->handle != qse_sio_out) qse_sio_close (arg->handle); - return 0; - - case QSE_SED_IO_WRITE: - return qse_sio_putsn (arg->handle, data, len); - - default: - return -1; - } -} - static void print_usage (QSE_FILE* out, int argc, qse_char_t* argv[]) { const qse_char_t* b = qse_basename (argv[0]); @@ -139,8 +56,10 @@ static void print_usage (QSE_FILE* out, int argc, qse_char_t* argv[]) qse_fprintf (out, QSE_T(" -h show this message\n")); qse_fprintf (out, QSE_T(" -n disable auto-print\n")); qse_fprintf (out, QSE_T(" -f file specify a script file\n")); + qse_fprintf (out, QSE_T(" -o file specify an output file\n")); qse_fprintf (out, QSE_T(" -r use the extended regular expression\n")); qse_fprintf (out, QSE_T(" -R enable non-standard extensions to the regular expression\n")); + qse_fprintf (out, QSE_T(" -s processes input files separately\n")); qse_fprintf (out, QSE_T(" -a perform strict address check\n")); 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")); @@ -152,7 +71,7 @@ static int handle_args (int argc, qse_char_t* argv[]) { static qse_opt_t opt = { - QSE_T("hnf:rRawxym:"), + QSE_T("hnf:o:rRsawxym:"), QSE_NULL }; qse_cint_t c; @@ -193,6 +112,10 @@ static int handle_args (int argc, qse_char_t* argv[]) g_script_file = opt.arg; break; + case QSE_T('o'): + g_output_file = opt.arg; + break; + case QSE_T('r'): g_option |= QSE_SED_EXTENDEDREX; break; @@ -201,6 +124,10 @@ static int handle_args (int argc, qse_char_t* argv[]) g_option |= QSE_SED_NONSTDEXTREX; break; + case QSE_T('s'): + g_separate = 1; + break; + case QSE_T('a'): g_option |= QSE_SED_STRICT; break; @@ -225,10 +152,9 @@ static int handle_args (int argc, qse_char_t* argv[]) if (opt.ind < argc && g_script_file == QSE_NULL) g_script = argv[opt.ind++]; - if (opt.ind < argc) g_infile = argv[opt.ind++]; + if (opt.ind < argc) g_infile_pos = opt.ind; - if ((g_script_file == QSE_NULL && g_script == QSE_NULL) || - opt.ind < argc) + if (g_script_file == QSE_NULL && g_script == QSE_NULL) { print_usage (QSE_STDERR, argc, argv); return -1; @@ -291,6 +217,27 @@ qse_char_t* load_script_file (qse_sed_t* sed, const qse_char_t* file) return xstr.ptr; } +void print_exec_error (qse_sed_t* sed) +{ + const qse_sed_loc_t* errloc = qse_sed_geterrloc(sed); + if (errloc->line > 0 || errloc->colm > 0) + { + qse_fprintf (QSE_STDERR, + QSE_T("cannot execute - %s at line %lu column %lu\n"), + qse_sed_geterrmsg(sed), + (unsigned long)errloc->line, + (unsigned long)errloc->colm + ); + } + else + { + qse_fprintf (QSE_STDERR, + QSE_T("cannot execute - %s\n"), + qse_sed_geterrmsg(sed) + ); + } +} + int sed_main (int argc, qse_char_t* argv[]) { qse_mmgr_t* mmgr = QSE_NULL; @@ -314,7 +261,7 @@ int sed_main (int argc, qse_char_t* argv[]) mmgr = &xma_mmgr; } - sed = qse_sed_open (mmgr, 0); + sed = qse_sed_openstdwithmmgr (mmgr, 0); if (sed == QSE_NULL) { qse_fprintf (QSE_STDERR, QSE_T("cannot open a stream editor\n")); @@ -331,7 +278,7 @@ int sed_main (int argc, qse_char_t* argv[]) if (g_script == QSE_NULL) goto oops; } - if (qse_sed_comp (sed, g_script, qse_strlen(g_script)) == -1) + if (qse_sed_compstd (sed, g_script) == -1) { const qse_sed_loc_t* errloc = qse_sed_geterrloc(sed); if (errloc->line > 0 || errloc->colm > 0) @@ -353,26 +300,101 @@ int sed_main (int argc, qse_char_t* argv[]) goto oops; } - if (qse_sed_exec (sed, in, out) == -1) + if (g_separate && g_infile_pos > 0) { - const qse_sed_loc_t* errloc = qse_sed_geterrloc(sed); - if (errloc->line > 0 || errloc->colm > 0) + qse_sed_iostd_t out; + qse_sed_iostd_t* output = QSE_NULL; + + if (g_output_file && + qse_strcmp (g_output_file, QSE_T("-")) != 0) { - qse_fprintf (QSE_STDERR, - QSE_T("cannot execute - %s at line %lu column %lu\n"), - qse_sed_geterrmsg(sed), - (unsigned long)errloc->line, - (unsigned long)errloc->colm + out.type = QSE_SED_IOSTD_SIO; + out.u.sio = qse_sio_open ( + qse_sed_getmmgr(sed), + 0, + g_output_file, + QSE_SIO_WRITE | + QSE_SIO_CREATE | + QSE_SIO_TRUNCATE | + QSE_SIO_IGNOREMBWCERR ); + if (out.u.sio == QSE_NULL) + { + qse_fprintf (QSE_STDERR, QSE_T("cannot open %s\n"), g_output_file); + goto oops; + } + + output = &out; } - else + + while (g_infile_pos < argc) { - qse_fprintf (QSE_STDERR, - QSE_T("cannot execute - %s\n"), - qse_sed_geterrmsg(sed) - ); + qse_sed_iostd_t in[2]; + + in[0].type = QSE_SED_IOSTD_FILE; + in[0].u.file = + (qse_strcmp (argv[g_infile_pos], QSE_T("-")) == 0)? + QSE_NULL: argv[g_infile_pos]; + in[1].type = QSE_SED_IOSTD_NULL; + + if (qse_sed_execstd (sed, in, output) <= -1) + { + if (output) qse_sio_close (output->u.sio); + print_exec_error (sed); + goto oops; + } + + g_infile_pos++; + } + + if (output) qse_sio_close (output->u.sio); + } + else + { + int xx; + qse_sed_iostd_t* in = QSE_NULL; + qse_sed_iostd_t out; + + if (g_infile_pos > 0) + { + int i, num_ins; + + num_ins = argc - g_infile_pos; + in = QSE_MMGR_ALLOC (qse_sed_getmmgr(sed), QSE_SIZEOF(*in) * (num_ins + 1)); + if (in == QSE_NULL) + { + qse_fprintf (QSE_STDERR, QSE_T("out of memory\n")); + goto oops; + } + + for (i = 0; i < num_ins; i++) + { + in[i].type = QSE_SED_IOSTD_FILE; + in[i].u.file = + (qse_strcmp (argv[g_infile_pos], QSE_T("-")) == 0)? + QSE_NULL: argv[g_infile_pos]; + g_infile_pos++; + } + + in[i].type = QSE_SED_IOSTD_NULL; + } + + if (g_output_file) + { + out.type = QSE_SED_IOSTD_FILE; + out.u.file = + (qse_strcmp (g_output_file, QSE_T("-")) == 0)? + QSE_NULL: g_output_file; + } + + xx = qse_sed_execstd (sed, in, (g_output_file? &out: QSE_NULL)); + if (in) QSE_MMGR_FREE (qse_sed_getmmgr(sed), in); + + if (xx <= -1) + { + print_exec_error (sed); + goto oops; } - goto oops; } ret = 0; diff --git a/qse/include/qse/awk/awk.h b/qse/include/qse/awk/awk.h index 79ff527a..41f0918d 100644 --- a/qse/include/qse/awk/awk.h +++ b/qse/include/qse/awk/awk.h @@ -1,5 +1,5 @@ /* - * $Id: awk.h 549 2011-08-14 09:07:31Z hyunghwan.chung $ + * $Id: awk.h 568 2011-09-17 15:41:26Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -827,11 +827,10 @@ typedef enum qse_awk_option_t qse_awk_option_t; enum qse_awk_errnum_t { QSE_AWK_ENOERR, /**< no error */ - QSE_AWK_EUNKNOWN,/**< unknown error */ /* common errors */ - QSE_AWK_EINVAL, /**< invalid parameter or data */ QSE_AWK_ENOMEM, /**< insufficient memory */ + QSE_AWK_EINVAL, /**< invalid parameter or data */ QSE_AWK_ENOSUP, /**< not supported */ QSE_AWK_ENOPER, /**< operation not allowed */ QSE_AWK_ENOENT, /**< '${0}' not found */ diff --git a/qse/include/qse/cmn/sio.h b/qse/include/qse/cmn/sio.h index 8cfc8fc1..f48a552c 100644 --- a/qse/include/qse/cmn/sio.h +++ b/qse/include/qse/cmn/sio.h @@ -1,5 +1,5 @@ /* - * $Id: sio.h 565 2011-09-11 02:48:21Z hyunghwan.chung $ + * $Id: sio.h 568 2011-09-17 15:41:26Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -32,20 +32,20 @@ enum qse_sio_open_flag_t { - QSE_SIO_HANDLE = QSE_FIO_HANDLE, + QSE_SIO_HANDLE = QSE_FIO_HANDLE, QSE_SIO_IGNOREMBWCERR = QSE_FIO_IGNOREMBWCERR, - QSE_SIO_READ = QSE_FIO_READ, - QSE_SIO_WRITE = QSE_FIO_WRITE, - QSE_SIO_APPEND = QSE_FIO_APPEND, + QSE_SIO_READ = QSE_FIO_READ, + QSE_SIO_WRITE = QSE_FIO_WRITE, + QSE_SIO_APPEND = QSE_FIO_APPEND, - QSE_SIO_CREATE = QSE_FIO_CREATE, - QSE_SIO_TRUNCATE = QSE_FIO_TRUNCATE, - QSE_SIO_EXCLUSIVE = QSE_FIO_EXCLUSIVE, - QSE_SIO_SYNC = QSE_FIO_SYNC, + QSE_SIO_CREATE = QSE_FIO_CREATE, + QSE_SIO_TRUNCATE = QSE_FIO_TRUNCATE, + QSE_SIO_EXCLUSIVE = QSE_FIO_EXCLUSIVE, + QSE_SIO_SYNC = QSE_FIO_SYNC, - QSE_SIO_NOSHRD = QSE_FIO_NOSHRD, - QSE_SIO_NOSHWR = QSE_FIO_NOSHWR + QSE_SIO_NOSHRD = QSE_FIO_NOSHRD, + QSE_SIO_NOSHWR = QSE_FIO_NOSHWR }; typedef qse_fio_off_t qse_sio_pos_t; diff --git a/qse/include/qse/cut/cut.h b/qse/include/qse/cut/cut.h index c18f212a..0ef9eb2b 100644 --- a/qse/include/qse/cut/cut.h +++ b/qse/include/qse/cut/cut.h @@ -49,6 +49,7 @@ enum qse_cut_errnum_t { QSE_CUT_ENOERR, /**< no error */ QSE_CUT_ENOMEM, /**< insufficient memory */ + QSE_CUT_EINVAL, /**< invalid parameter or data */ QSE_CUT_ESELNV, /**< selector not valid */ QSE_CUT_EIOFIL, /**< io error with file '${0}'*/ QSE_CUT_EIOUSR /**< error returned by user io handler */ diff --git a/qse/include/qse/sed/sed.h b/qse/include/qse/sed/sed.h index 75d67e47..4fc46e69 100644 --- a/qse/include/qse/sed/sed.h +++ b/qse/include/qse/sed/sed.h @@ -1,5 +1,5 @@ /* - * $Id: sed.h 563 2011-09-08 07:49:53Z hyunghwan.chung $ + * $Id: sed.h 568 2011-09-17 15:41:26Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -82,6 +82,7 @@ enum qse_sed_errnum_t { QSE_SED_ENOERR, /**< no error */ QSE_SED_ENOMEM, /**< insufficient memory */ + QSE_SED_EINVAL, /**< invalid parameter or data */ QSE_SED_ECMDNR, /**< command '${0}' not recognized */ QSE_SED_ECMDMS, /**< command code missing */ QSE_SED_ECMDIC, /**< command '${0}' incomplete */ diff --git a/qse/include/qse/sed/std.h b/qse/include/qse/sed/std.h index fbbe00ed..fc61a3b9 100644 --- a/qse/include/qse/sed/std.h +++ b/qse/include/qse/sed/std.h @@ -22,6 +22,7 @@ #define _QSE_SED_STD_H_ #include +#include /** @file * This file defines easier-to-use helper interface for a stream editor. @@ -35,6 +36,29 @@ * functions. */ +/** + * The qse_sed_iostd_t type defines standard I/O resources. + */ +typedef struct qse_sed_iostd_t qse_sed_iostd_t; + +struct qse_sed_iostd_t +{ + enum + { + QSE_SED_IOSTD_NULL, /** invalid resource */ + QSE_SED_IOSTD_SIO, + QSE_SED_IOSTD_FILE, + QSE_SED_IOSTD_MEM + } type; + + union + { + qse_sio_t* sio; + const qse_char_t* file; + qse_xstr_t mem; + } u; +}; + #ifdef __cplusplus extern "C" { #endif @@ -82,15 +106,22 @@ int qse_sed_compstd ( /** * The qse_sed_execstd() function executes the compiled script - * over an input file @a infile and an 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. + * 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. + * + * If @a in is #QSE_NULL, the standard console input is used. + * If @a out is #QSE_NULL, the standard console output is used. + * * @return 0 on success, -1 on failure */ int qse_sed_execstd ( - qse_sed_t* sed, /**< stream editor */ - const qse_char_t* infile, /**< input file */ - const qse_char_t* outfile /**< output file */ + qse_sed_t* sed, + qse_sed_iostd_t in[], + qse_sed_iostd_t* out ); #ifdef __cplusplus diff --git a/qse/lib/awk/err.c b/qse/lib/awk/err.c index 452c7a1c..7807120a 100644 --- a/qse/lib/awk/err.c +++ b/qse/lib/awk/err.c @@ -1,5 +1,5 @@ /* - * $Id: err.c 441 2011-04-22 14:28:43Z hyunghwan.chung $ + * $Id: err.c 568 2011-09-17 15:41:26Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -25,10 +25,9 @@ const qse_char_t* qse_awk_dflerrstr (qse_awk_t* awk, qse_awk_errnum_t errnum) static const qse_char_t* errstr[] = { QSE_T("no error"), - QSE_T("unknown error"), - QSE_T("invalid parameter or data"), QSE_T("insufficient memory"), + QSE_T("invalid parameter or data"), QSE_T("not supported"), QSE_T("operation not allowed"), QSE_T("'${0}' not found"), diff --git a/qse/lib/cmn/sio.c b/qse/lib/cmn/sio.c index b3e23597..90f695c4 100644 --- a/qse/lib/cmn/sio.c +++ b/qse/lib/cmn/sio.c @@ -1,5 +1,5 @@ /* - * $Id: sio.c 566 2011-09-11 12:44:56Z hyunghwan.chung $ + * $Id: sio.c 568 2011-09-17 15:41:26Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -39,6 +39,7 @@ static qse_sio_t __sio_in = { QSE_NULL, /* mmgr */ 0, /* errnum */ + #if defined(_WIN32) (HANDLE)STD_INPUT_HANDLE, /* handle */ #elif defined(__OS2__) @@ -48,6 +49,7 @@ static qse_sio_t __sio_in = #else 0, /* handle */ #endif + 0, /* flags */ QSE_NULL /* tio */ }, @@ -81,6 +83,7 @@ static qse_sio_t __sio_out = { QSE_NULL, 0, + #if defined(_WIN32) (HANDLE)STD_OUTPUT_HANDLE, #elif defined(__OS2__) @@ -90,6 +93,7 @@ static qse_sio_t __sio_out = #else 1, #endif + 0, QSE_NULL }, @@ -123,6 +127,7 @@ static qse_sio_t __sio_err = { QSE_NULL, 0, + #if defined(_WIN32) (HANDLE)STD_ERROR_HANDLE, #elif defined(__OS2__) @@ -132,6 +137,7 @@ static qse_sio_t __sio_err = #else 2, #endif + 0, QSE_NULL }, diff --git a/qse/lib/cut/err.c b/qse/lib/cut/err.c index 549b6211..856815ae 100644 --- a/qse/lib/cut/err.c +++ b/qse/lib/cut/err.c @@ -27,6 +27,7 @@ const qse_char_t* qse_cut_dflerrstr (qse_cut_t* cut, qse_cut_errnum_t errnum) { QSE_T("no error"), QSE_T("insufficient memory"), + QSE_T("invalid parameter or data"), QSE_T("selector not valid"), QSE_T("io error with file '${0}'"), QSE_T("error returned by user io handler") diff --git a/qse/lib/sed/err.c b/qse/lib/sed/err.c index de06956f..6774b4bb 100644 --- a/qse/lib/sed/err.c +++ b/qse/lib/sed/err.c @@ -1,5 +1,5 @@ /* - * $Id: err.c 562 2011-09-07 15:36:08Z hyunghwan.chung $ + * $Id: err.c 568 2011-09-17 15:41:26Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -27,6 +27,7 @@ const qse_char_t* qse_sed_dflerrstr (qse_sed_t* sed, qse_sed_errnum_t errnum) { QSE_T("no error"), QSE_T("insufficient memory"), + QSE_T("invalid parameter or data"), QSE_T("command '${0}' not recognized"), QSE_T("command code missing"), QSE_T("command '${0}' incomplete"), diff --git a/qse/lib/sed/sed.c b/qse/lib/sed/sed.c index 60b44db7..6cf838f4 100644 --- a/qse/lib/sed/sed.c +++ b/qse/lib/sed/sed.c @@ -1,5 +1,5 @@ /* - * $Id: sed.c 567 2011-09-14 15:48:08Z hyunghwan.chung $ + * $Id: sed.c 568 2011-09-17 15:41:26Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -103,7 +103,7 @@ int qse_sed_init (qse_sed_t* sed, qse_mmgr_t* mmgr) ); if (qse_str_init (&sed->e.txt.appended, mmgr, 256) <= -1) goto oops_5; - if (qse_str_init (&sed->e.txt.held, mmgr, 256) <= -1) goto oops_6; + if (qse_str_init (&sed->e.txt.hold, mmgr, 256) <= -1) goto oops_6; if (qse_str_init (&sed->e.txt.subst, mmgr, 256) <= -1) goto oops_7; /* on init, the last points to the first */ @@ -114,7 +114,7 @@ int qse_sed_init (qse_sed_t* sed, qse_mmgr_t* mmgr) return 0; oops_7: - qse_str_fini (&sed->e.txt.held); + qse_str_fini (&sed->e.txt.hold); oops_6: qse_str_fini (&sed->e.txt.appended); oops_5: @@ -133,7 +133,7 @@ void qse_sed_fini (qse_sed_t* sed) free_all_command_blocks (sed); qse_str_fini (&sed->e.txt.subst); - qse_str_fini (&sed->e.txt.held); + qse_str_fini (&sed->e.txt.hold); qse_str_fini (&sed->e.txt.appended); qse_map_fini (&sed->tmp.labs); @@ -1817,6 +1817,7 @@ static int flush (qse_sed_t* sed) while (sed->e.out.len > 0) { sed->errnum = QSE_SED_ENOERR; + n = sed->e.out.fun ( sed, QSE_SED_IO_WRITE, &sed->e.out.arg, &sed->e.out.buf[pos], sed->e.out.len); @@ -2694,7 +2695,7 @@ static qse_sed_cmd_t* exec_cmd (qse_sed_t* sed, qse_sed_cmd_t* cmd) case QSE_SED_CMD_HOLD: /* copy the pattern space to the hold space */ - if (qse_str_ncpy (&sed->e.txt.held, + if (qse_str_ncpy (&sed->e.txt.hold, QSE_STR_PTR(&sed->e.in.line), QSE_STR_LEN(&sed->e.in.line)) == (qse_size_t)-1) { @@ -2705,7 +2706,7 @@ static qse_sed_cmd_t* exec_cmd (qse_sed_t* sed, qse_sed_cmd_t* cmd) case QSE_SED_CMD_HOLD_APPEND: /* append the pattern space to the hold space */ - if (qse_str_ncat (&sed->e.txt.held, + if (qse_str_ncat (&sed->e.txt.hold, QSE_STR_PTR(&sed->e.in.line), QSE_STR_LEN(&sed->e.in.line)) == (qse_size_t)-1) { @@ -2717,8 +2718,8 @@ static qse_sed_cmd_t* exec_cmd (qse_sed_t* sed, qse_sed_cmd_t* cmd) case QSE_SED_CMD_RELEASE: /* copy the hold space to the pattern space */ if (qse_str_ncpy (&sed->e.in.line, - QSE_STR_PTR(&sed->e.txt.held), - QSE_STR_LEN(&sed->e.txt.held)) == (qse_size_t)-1) + QSE_STR_PTR(&sed->e.txt.hold), + QSE_STR_LEN(&sed->e.txt.hold)) == (qse_size_t)-1) { SETERR0 (sed, QSE_SED_ENOMEM, QSE_NULL); return QSE_NULL; @@ -2728,8 +2729,8 @@ static qse_sed_cmd_t* exec_cmd (qse_sed_t* sed, qse_sed_cmd_t* cmd) case QSE_SED_CMD_RELEASE_APPEND: /* append the hold space to the pattern space */ if (qse_str_ncat (&sed->e.in.line, - QSE_STR_PTR(&sed->e.txt.held), - QSE_STR_LEN(&sed->e.txt.held)) == (qse_size_t)-1) + QSE_STR_PTR(&sed->e.txt.hold), + QSE_STR_LEN(&sed->e.txt.hold)) == (qse_size_t)-1) { SETERR0 (sed, QSE_SED_ENOMEM, QSE_NULL); return QSE_NULL; @@ -2738,7 +2739,7 @@ static qse_sed_cmd_t* exec_cmd (qse_sed_t* sed, qse_sed_cmd_t* cmd) case QSE_SED_CMD_EXCHANGE: /* exchange the pattern space and the hold space */ - qse_str_swap (&sed->e.in.line, &sed->e.txt.held); + qse_str_swap (&sed->e.in.line, &sed->e.txt.hold); break; case QSE_SED_CMD_NEXT: @@ -3042,8 +3043,8 @@ int qse_sed_exec (qse_sed_t* sed, qse_sed_io_fun_t inf, qse_sed_io_fun_t outf) sed->e.subst_done = 0; qse_str_clear (&sed->e.txt.appended); qse_str_clear (&sed->e.txt.subst); - qse_str_clear (&sed->e.txt.held); - if (qse_str_ccat (&sed->e.txt.held, QSE_T('\n')) == (qse_size_t)-1) + qse_str_clear (&sed->e.txt.hold); + if (qse_str_ccat (&sed->e.txt.hold, QSE_T('\n')) == (qse_size_t)-1) { SETERR0 (sed, QSE_SED_ENOMEM, QSE_NULL); return -1; diff --git a/qse/lib/sed/sed.h b/qse/lib/sed/sed.h index e8fb257f..6914c138 100644 --- a/qse/lib/sed/sed.h +++ b/qse/lib/sed/sed.h @@ -1,5 +1,5 @@ /* - * $Id: sed.h 564 2011-09-10 16:14:38Z hyunghwan.chung $ + * $Id: sed.h 568 2011-09-17 15:41:26Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -262,7 +262,7 @@ struct qse_sed_t struct { qse_str_t appended; - qse_str_t held; + qse_str_t hold; /* hold space */ qse_str_t subst; } txt; diff --git a/qse/lib/sed/std.c b/qse/lib/sed/std.c index 9e2a44e5..3ec375ad 100644 --- a/qse/lib/sed/std.c +++ b/qse/lib/sed/std.c @@ -26,8 +26,15 @@ struct xtn_t { - const qse_char_t* infile; - const qse_char_t* outfile; + struct + { + qse_sed_iostd_t* in; + qse_sed_iostd_t* out; + + qse_sed_iostd_t* in_cur; + qse_size_t in_mempos; + qse_str_t* out_memstr; + } e; }; typedef struct xtn_t xtn_t; @@ -63,6 +70,166 @@ int qse_sed_compstd (qse_sed_t* sed, const qse_char_t* sptr) return qse_sed_comp (sed, sptr, qse_strlen(sptr)); } +static qse_sio_t* open_sio (qse_sed_t* sed, const qse_char_t* file, int flags) +{ + qse_sio_t* sio; + + sio = qse_sio_open (sed->mmgr, 0, file, flags); + if (sio == QSE_NULL) + { + qse_cstr_t ea; + ea.ptr = file; + ea.len = qse_strlen (file); + 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); + } +} + +static int open_main_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); + + QSE_ASSERT (io != QSE_NULL); + switch (io->type) + { + case QSE_SED_IOSTD_SIO: + arg->handle = io->u.sio; + 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; + } + break; + + case QSE_SED_IOSTD_MEM: + /* don't store anything to arg->handle */ + xtn->e.in_mempos = 0; + break; + } + + return 0; +} + +static int open_main_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); + + QSE_ASSERT (io != QSE_NULL); + switch (io->type) + { + case QSE_SED_IOSTD_SIO: + arg->handle = io->u.sio; + break; + + case QSE_SED_IOSTD_FILE: + if (io->u.file == QSE_NULL) + { + arg->handle = qse_sio_out; + } + else + { + qse_sio_t* sio; + 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 */ + xtn->e.out_memstr = qse_str_open (sed->mmgr, 0, 512); + if (xtn->e.out_memstr == QSE_NULL) + { + qse_sed_seterrnum (sed, QSE_SED_ENOMEM, QSE_NULL); + return -1; + } + break; + } + + return 0; +} + +static qse_ssize_t read_main_input_stream ( + qse_sed_t* sed, qse_sed_io_arg_t* arg, qse_char_t* buf, qse_size_t len) +{ + xtn_t* xtn = (xtn_t*) QSE_XTN (sed); + qse_sed_iostd_t* io, * next; + void* old, * new; + qse_ssize_t n = 0; + + if (len > QSE_TYPE_MAX(qse_ssize_t)) len = QSE_TYPE_MAX(qse_ssize_t); + + do + { + io = xtn->e.in_cur; + + QSE_ASSERT (io != QSE_NULL); + if (io->type == QSE_SED_IOSTD_MEM) + { + n = 0; + while (xtn->e.in_mempos < io->u.mem.len && n < len) + buf[n++] = io->u.mem.ptr[xtn->e.in_mempos++]; + } + else n = qse_sio_getsn (arg->handle, buf, len); + + if (n != 0) break; + + /* end of file on the current input stream */ + + next = xtn->e.in_cur + 1; + if (next->type == QSE_SED_IOSTD_NULL) + { + /* no next stream available - return 0 */ + break; + } + + old = arg->handle; + + /* try to open the next input stream */ + if (open_main_input_stream (sed, arg, next) <= -1) + { + /* failed to open the next input stream */ + n = -1; + break; + } + new = arg->handle; + + arg->handle = old; + close_main_stream (sed, arg, io); + + arg->handle = new; + xtn->e.in_cur++; + } + while (1); + + return n; +} + static qse_ssize_t xin ( qse_sed_t* sed, qse_sed_io_cmd_t cmd, qse_sed_io_arg_t* arg, qse_char_t* buf, qse_size_t len) @@ -77,67 +244,53 @@ static qse_ssize_t xin ( if (arg->path == QSE_NULL) { /* main data stream */ - if (xtn->infile == QSE_NULL) sio = qse_sio_in; + if (xtn->e.in == QSE_NULL) arg->handle = qse_sio_in; else { - sio = qse_sio_open ( - sed->mmgr, - 0, - xtn->infile, - QSE_SIO_READ | QSE_SIO_IGNOREMBWCERR - ); - 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 = xtn->infile; - ea.len = qse_strlen (xtn->infile); - qse_sed_seterrnum (sed,QSE_SED_EIOFIL, &ea); - return -1; - } + if (open_main_input_stream (sed, arg, xtn->e.in_cur) <= -1) return -1; } } else { - sio = qse_sio_open ( - sed->mmgr, - 0, - arg->path, - QSE_SIO_READ | QSE_SIO_IGNOREMBWCERR - ); + sio = open_sio (sed, arg->path, QSE_SIO_READ | QSE_SIO_IGNOREMBWCERR); + if (sio == QSE_NULL) return -1; + arg->handle = sio; } - if (sio == QSE_NULL) return -1; - arg->handle = sio; return 1; } case QSE_SED_IO_CLOSE: { - sio = (qse_sio_t*)arg->handle; - if (sio != qse_sio_in && sio != qse_sio_out && sio != qse_sio_err) - qse_sio_close (sio); + if (arg->path == QSE_NULL) + { + /* main data stream */ + if (xtn->e.in) 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); + } + return 0; } case QSE_SED_IO_READ: { - qse_ssize_t n = qse_sio_getsn (arg->handle, buf, len); - - if (n == -1) + if (arg->path == QSE_NULL) { - if (arg->path == QSE_NULL && xtn->infile != QSE_NULL) - { - qse_cstr_t ea; - ea.ptr = xtn->infile; - ea.len = qse_strlen (xtn->infile); - qse_sed_seterrnum (sed, QSE_SED_EIOFIL, &ea); - } + /* main data stream */ + if (xtn->e.in == QSE_NULL) + return qse_sio_getsn (arg->handle, buf, len); + else + return read_main_input_stream (sed, arg, buf, len); + } + else + { + return qse_sio_getsn (arg->handle, buf, len); } - - return n; } default: @@ -149,8 +302,8 @@ static qse_ssize_t xout ( qse_sed_t* sed, qse_sed_io_cmd_t cmd, qse_sed_io_arg_t* arg, qse_char_t* dat, qse_size_t len) { - qse_sio_t* sio; xtn_t* xtn = (xtn_t*) QSE_XTN (sed); + qse_sio_t* sio; switch (cmd) { @@ -158,74 +311,76 @@ static qse_ssize_t xout ( { if (arg->path == QSE_NULL) { - if (xtn->outfile == QSE_NULL) sio = qse_sio_out; + if (xtn->e.out == QSE_NULL) arg->handle = qse_sio_out; else { - sio = qse_sio_open ( - sed->mmgr, - 0, - xtn->outfile, - QSE_SIO_WRITE | - QSE_SIO_CREATE | - QSE_SIO_TRUNCATE | - QSE_SIO_IGNOREMBWCERR - ); - 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 = xtn->outfile; - ea.len = qse_strlen (xtn->outfile); - qse_sed_seterrnum (sed, QSE_SED_EIOFIL, &ea); - return -1; - } + if (open_main_output_stream (sed, arg, xtn->e.out) <= -1) return -1; } } else { - sio = qse_sio_open ( - sed->mmgr, - 0, - arg->path, + sio = open_sio ( + sed, arg->path, QSE_SIO_WRITE | QSE_SIO_CREATE | QSE_SIO_TRUNCATE | QSE_SIO_IGNOREMBWCERR ); + if (sio == QSE_NULL) return -1; + arg->handle = sio; } - if (sio == QSE_NULL) return -1; - arg->handle = sio; return 1; } case QSE_SED_IO_CLOSE: { - 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); + if (arg->path == QSE_NULL) + { + if (xtn->e.out) 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); + } return 0; } case QSE_SED_IO_WRITE: { - qse_ssize_t n = qse_sio_putsn (arg->handle, dat, len); - - if (n == -1) + if (arg->path == QSE_NULL) { - if (arg->path == QSE_NULL && xtn->infile != QSE_NULL) + /* main data stream */ + if (xtn->e.out == QSE_NULL) + return qse_sio_putsn (arg->handle, dat, len); + else { - qse_cstr_t ea; - ea.ptr = xtn->infile; - ea.len = qse_strlen (xtn->infile); - qse_sed_seterrnum (sed, QSE_SED_EIOFIL, &ea); + qse_sed_iostd_t* io = xtn->e.out; + if (io->type == QSE_SED_IOSTD_MEM) + { + if (len > QSE_TYPE_MAX(qse_ssize_t)) len = QSE_TYPE_MAX(qse_ssize_t); + + if (qse_str_ncat (xtn->e.out_memstr, dat, len) == (qse_size_t)-1) + { + qse_sed_seterrnum (sed, QSE_SED_ENOMEM, QSE_NULL); + return -1; + } + + return len; + } + else + { + return qse_sio_putsn (arg->handle, dat, len); + } } } - - return n; + else + { + return qse_sio_putsn (arg->handle, dat, len); + } } default: @@ -233,10 +388,69 @@ static qse_ssize_t xout ( } } -int qse_sed_execstd (qse_sed_t* sed, const qse_char_t* infile, const qse_char_t* outfile) +int qse_sed_execstd ( + qse_sed_t* sed, qse_sed_iostd_t in[], qse_sed_iostd_t* out) { + int n; xtn_t* xtn = (xtn_t*) QSE_XTN (sed); - xtn->infile = infile; - xtn->outfile = outfile; - return qse_sed_exec (sed, xin, xout); + + if (in) + { + qse_size_t i; + + if (in[0].type == QSE_SED_IOSTD_NULL) + { + /* if 'in' is specified, it must contains at least one + * valid entry */ + qse_sed_seterrnum (sed, QSE_SED_EINVAL, QSE_NULL); + return -1; + } + + for (i = 0; in[i].type != QSE_SED_IOSTD_NULL; i++) + { + if (in[i].type != QSE_SED_IOSTD_SIO && + in[i].type != QSE_SED_IOSTD_FILE && + in[i].type != QSE_SED_IOSTD_MEM) + { + qse_sed_seterrnum (sed, QSE_SED_EINVAL, QSE_NULL); + return -1; + } + } + } + + if (out) + { + if (out->type != QSE_SED_IOSTD_SIO && + out->type != QSE_SED_IOSTD_FILE && + out->type != QSE_SED_IOSTD_MEM) + { + qse_sed_seterrnum (sed, QSE_SED_EINVAL, QSE_NULL); + return -1; + } + } + + QSE_MEMSET (&xtn->e, 0, QSE_SIZEOF(xtn->e)); + xtn->e.in = in; + xtn->e.out = out; + xtn->e.in_cur = in; + + n = qse_sed_exec (sed, xin, xout); + + if (n >= 0 && out && out->type == QSE_SED_IOSTD_MEM) + { + QSE_ASSERT (xtn->e.out_memstr != QSE_NULL); + qse_str_yield (xtn->e.out_memstr, &out->u.mem, 0); + } + 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; } +