make @word to be always on

simplified the return value of I/O handler's open function by eliminating the concept of EOF on opening.
enhanced qse_awk_parsestd() to accept an array of qse_awk_parsestd_t for input streams.
enhanced cmd/awk/awk.c to handle multiple -f's properly
This commit is contained in:
2012-11-25 16:16:44 +00:00
parent 1ad89afa99
commit f1f3080ab3
8 changed files with 248 additions and 266 deletions

View File

@ -496,12 +496,19 @@ static int fnc_length (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
else
{
v = qse_awk_rtx_getarg (rtx, 0);
if (v->type == QSE_AWK_VAL_STR)
if (v->type == QSE_AWK_VAL_MAP)
{
/* map size */
len = QSE_HTB_SIZE(((qse_awk_val_map_t*)v)->map);
}
else if (v->type == QSE_AWK_VAL_STR)
{
/* string length */
len = ((qse_awk_val_str_t*)v)->val.len;
}
else
{
/* convert to string and get length */
str = qse_awk_rtx_valtostrdup (rtx, v, &len);
if (str == QSE_NULL) return -1;
QSE_AWK_FREE (rtx->awk, str);

View File

@ -255,11 +255,11 @@ static kwent_t kwtab[] =
{
/* keep this table in sync with the kw_t enums in <parse.h>.
* also keep it sorted by the first field for binary search */
{ { QSE_T("@abort"), 6 }, TOK_XABORT, QSE_AWK_EXTRAKWS },
{ { QSE_T("@global"), 7 }, TOK_XGLOBAL, QSE_AWK_EXTRAKWS },
{ { QSE_T("@include"), 8 }, TOK_XINCLUDE, QSE_AWK_EXTRAKWS },
{ { QSE_T("@local"), 6 }, TOK_XLOCAL, QSE_AWK_EXTRAKWS },
{ { QSE_T("@reset"), 6 }, TOK_XRESET, QSE_AWK_EXTRAKWS },
{ { QSE_T("@abort"), 6 }, TOK_XABORT, 0 },
{ { QSE_T("@global"), 7 }, TOK_XGLOBAL, 0 },
{ { QSE_T("@include"), 8 }, TOK_XINCLUDE, 0 },
{ { QSE_T("@local"), 6 }, TOK_XLOCAL, 0 },
{ { QSE_T("@reset"), 6 }, TOK_XRESET, 0 },
{ { QSE_T("BEGIN"), 5 }, TOK_BEGIN, QSE_AWK_PABLOCK },
{ { QSE_T("END"), 3 }, TOK_END, QSE_AWK_PABLOCK },
{ { QSE_T("break"), 5 }, TOK_BREAK, 0 },
@ -522,60 +522,53 @@ static int parse (qse_awk_t* awk)
adjust_static_globals (awk);
/* the user io handler for the source code input returns 0 when
* it doesn't have any files to open. this is the same condition
* as the source code file is empty. so it will perform the parsing
* when op is positive, which means there are something to parse */
if (op > 0)
/* get the first character and the first token */
if (get_char (awk) <= -1 || get_token (awk)) goto oops;
while (1)
{
/* get the first character and the first token */
if (get_char (awk) <= -1 || get_token (awk)) goto oops;
while (1)
while (MATCH(awk,TOK_NEWLINE))
{
while (MATCH(awk,TOK_NEWLINE))
{
if (get_token (awk) <= -1) goto oops;
}
if (MATCH(awk,TOK_EOF)) break;
if (parse_progunit (awk) <= -1) goto oops;
if (get_token (awk) <= -1) goto oops;
}
if (MATCH(awk,TOK_EOF)) break;
if (!(awk->opt.trait & QSE_AWK_IMPLICIT))
if (parse_progunit (awk) <= -1) goto oops;
}
if (!(awk->opt.trait & QSE_AWK_IMPLICIT))
{
/* ensure that all functions called are defined
* in the EXPLICIT-only mode */
qse_htb_pair_t* p;
qse_size_t buckno;
p = qse_htb_getfirstpair (awk->parse.funs, &buckno);
while (p != QSE_NULL)
{
/* ensure that all functions called are defined
* in the EXPLICIT-only mode */
qse_htb_pair_t* p;
qse_size_t buckno;
p = qse_htb_getfirstpair (awk->parse.funs, &buckno);
while (p != QSE_NULL)
if (qse_htb_search (awk->tree.funs,
QSE_HTB_KPTR(p), QSE_HTB_KLEN(p)) == QSE_NULL)
{
if (qse_htb_search (awk->tree.funs,
QSE_HTB_KPTR(p), QSE_HTB_KLEN(p)) == QSE_NULL)
{
qse_awk_nde_t* nde;
qse_awk_nde_t* nde;
/* see parse_fncall() for what is
* stored into awk->tree.funs */
nde = (qse_awk_nde_t*)QSE_HTB_VPTR(p);
/* see parse_fncall() for what is
* stored into awk->tree.funs */
nde = (qse_awk_nde_t*)QSE_HTB_VPTR(p);
SETERR_ARG_LOC (
awk,
QSE_AWK_EFUNNF,
QSE_HTB_KPTR(p),
QSE_HTB_KLEN(p),
&nde->loc
);
SETERR_ARG_LOC (
awk,
QSE_AWK_EFUNNF,
QSE_HTB_KPTR(p),
QSE_HTB_KLEN(p),
&nde->loc
);
goto oops;
}
p = qse_htb_getnextpair (awk->parse.funs, p, &buckno);
goto oops;
}
p = qse_htb_getnextpair (awk->parse.funs, p, &buckno);
}
}
@ -759,18 +752,6 @@ static int begin_include (qse_awk_t* awk)
goto oops;
}
if (op == 0)
{
CLRERR (awk);
op = awk->sio.inf (awk, QSE_AWK_SIO_CLOSE, arg, QSE_NULL, 0);
if (op != 0)
{
if (ISNOERR(awk)) SETERR_TOK (awk, QSE_AWK_ECLOSE);
else awk->errinf.loc = awk->tok.loc;
goto oops;
}
}
arg->next = awk->sio.inp;
awk->sio.inp = arg;
awk->parse.depth.incl++;
@ -6109,23 +6090,6 @@ static int deparse (qse_awk_t* awk)
return -1;
}
if (op == 0)
{
/* the result of the open operation indicates that the
* file has been open but reached the end. so it has to
* skip the entire deparsing procedure as it can't write
* any single characters on such an io handler. but note
* that this is not really an error for the parse and deparser.
*
* in fact, there are two ways to skip deparsing.
* 1. set awk->sio.inf to NULL.
* 2. set awk->sio.inf to a normal handler but
* make it return 0 on the OPEN request.
*/
n = 0;
goto exit_deparse;
}
#define EXIT_DEPARSE() do { n = -1; goto exit_deparse; } while(0)
if (awk->tree.ngbls > awk->tree.ngbls_base)

View File

@ -182,13 +182,6 @@ static int find_rio_in (
/* chain it */
p->next = run->rio.chain;
run->rio.chain = p;
/* usually, x == 0 indicates that it has reached the end
* of the input. the user I/O handler can return 0 for the
* open request if it doesn't have any files to open. One
* advantage of doing this would be that you can skip the
* entire pattern-block matching and execution. */
if (x == 0) p->in.eos = 1;
}
*rio = p;
@ -761,17 +754,6 @@ int qse_awk_rtx_writeio_str (
/* chain it */
p->next = run->rio.chain;
run->rio.chain = p;
/* usually, n == 0 indicates that it has reached the end
* of the input. the user I/O handler can return 0 for the
* open request if it doesn't have any files to open. One
* advantage of doing this would be that you can skip the
* entire pattern-block matching and execution. */
if (n == 0)
{
p->out.eos = 1;
return 0;
}
}
if (p->out.eos)

View File

@ -80,6 +80,8 @@ typedef struct xtn_t
struct
{
qse_awk_parsestd_t* x;
qse_size_t xindex;
union
{
struct
@ -649,58 +651,84 @@ static qse_sio_t* open_sio_std_rtx (qse_awk_rtx_t* rtx, qse_sio_std_t std, int f
}
/*** PARSESTD ***/
static int open_parsestd (qse_awk_t* awk, xtn_t* xtn, qse_size_t index)
{
qse_awk_parsestd_t* psin = &xtn->s.in.x[index];
switch (psin->type)
{
/* normal source files */
case QSE_AWK_PARSESTD_FILE:
if (psin->u.file.path == QSE_NULL ||
(psin->u.file.path[0] == QSE_T('-') &&
psin->u.file.path[1] == QSE_T('\0')))
{
/* special file name '-' */
qse_sio_t* tmp;
tmp = open_sio_std (awk, QSE_SIO_STDIN, QSE_SIO_READ | QSE_SIO_IGNOREMBWCERR);
if (tmp == QSE_NULL) return -1;
if (index >= 1 && xtn->s.in.x[index-1].type == QSE_AWK_PARSESTD_FILE)
qse_sio_close (xtn->s.in.u.file.sio);
xtn->s.in.u.file.sio = tmp;
}
else
{
qse_sio_t* tmp;
const qse_char_t* base;
tmp = open_sio (awk, psin->u.file.path, QSE_SIO_READ | QSE_SIO_IGNOREMBWCERR);
if (tmp == QSE_NULL) return -1;
if (index >= 1 && xtn->s.in.x[index-1].type == QSE_AWK_PARSESTD_FILE)
qse_sio_close (xtn->s.in.u.file.sio);
xtn->s.in.u.file.sio = tmp;
base = qse_basename (psin->u.file.path);
if (base != psin->u.file.path)
{
xtn->s.in.u.file.dir.ptr = psin->u.file.path;
xtn->s.in.u.file.dir.len = base - psin->u.file.path;
}
}
if (psin->cmgr) qse_sio_setcmgr (xtn->s.in.u.file.sio, psin->cmgr);
return 0;
case QSE_AWK_PARSESTD_STR:
if (index >= 1 && xtn->s.in.x[index-1].type == QSE_AWK_PARSESTD_FILE)
qse_sio_close (xtn->s.in.u.file.sio);
xtn->s.in.u.str.ptr = psin->u.str.ptr;
xtn->s.in.u.str.end = psin->u.str.ptr + psin->u.str.len;
return 0;
default:
qse_awk_seterrnum (awk, QSE_AWK_EINTERN, QSE_NULL);
return -1;
}
}
static qse_ssize_t sf_in_open (
qse_awk_t* awk, qse_awk_sio_arg_t* arg, xtn_t* xtn)
{
if (arg == QSE_NULL || arg->name == QSE_NULL)
{
switch (xtn->s.in.x->type)
{
case QSE_AWK_PARSESTD_FILE:
if (xtn->s.in.x->u.file.path == QSE_NULL ||
(xtn->s.in.x->u.file.path[0] == QSE_T('-') &&
xtn->s.in.x->u.file.path[1] == QSE_T('\0')))
{
/* special file name '-' */
xtn->s.in.u.file.sio = open_sio_std (
awk, QSE_SIO_STDIN, QSE_SIO_READ | QSE_SIO_IGNOREMBWCERR);
if (xtn->s.in.u.file.sio == QSE_NULL) return -1;
}
else
{
const qse_char_t* base;
xtn->s.in.u.file.sio = open_sio (
awk, xtn->s.in.x->u.file.path,
QSE_SIO_READ | QSE_SIO_IGNOREMBWCERR
);
if (xtn->s.in.u.file.sio == QSE_NULL) return -1;
base = qse_basename (xtn->s.in.x->u.file.path);
if (base != xtn->s.in.x->u.file.path)
{
xtn->s.in.u.file.dir.ptr = xtn->s.in.x->u.file.path;
xtn->s.in.u.file.dir.len = base - xtn->s.in.x->u.file.path;
}
}
if (xtn->s.in.x->u.file.cmgr)
qse_sio_setcmgr (xtn->s.in.u.file.sio, xtn->s.in.x->u.file.cmgr);
return 1;
case QSE_AWK_PARSESTD_STR:
xtn->s.in.u.str.ptr = xtn->s.in.x->u.str.ptr;
xtn->s.in.u.str.end = xtn->s.in.x->u.str.ptr + xtn->s.in.x->u.str.len;
return 1;
default:
/* this should never happen */
qse_awk_seterrnum (awk, QSE_AWK_EINTERN, QSE_NULL);
return -1;
}
/* handle normal source input streams specified
* to qse_awk_parsestd() */
qse_ssize_t x;
x = open_parsestd (awk, xtn, 0);
if (x >= 0) xtn->s.in.xindex = 0; /* update the current stream index */
return x;
}
else
{
/* handle the included source file - @include */
const qse_char_t* file = arg->name;
qse_char_t fbuf[64];
qse_char_t* dbuf = QSE_NULL;
@ -733,7 +761,7 @@ static qse_ssize_t sf_in_open (
awk->mmgr, 0, file, QSE_SIO_READ | QSE_SIO_IGNOREMBWCERR
);
if (dbuf != QSE_NULL) QSE_MMGR_FREE (awk->mmgr, dbuf);
if (dbuf) QSE_MMGR_FREE (awk->mmgr, dbuf);
if (arg->handle == QSE_NULL)
{
qse_cstr_t ea;
@ -743,7 +771,7 @@ static qse_ssize_t sf_in_open (
return -1;
}
return 1;
return 0;
}
}
@ -752,12 +780,12 @@ static qse_ssize_t sf_in_close (
{
if (arg == QSE_NULL || arg->name == QSE_NULL)
{
switch (xtn->s.in.x->type)
switch (xtn->s.in.x[xtn->s.in.xindex].type)
{
case QSE_AWK_PARSESTD_FILE:
qse_sio_close (xtn->s.in.u.file.sio);
break;
case QSE_AWK_PARSESTD_STR:
/* nothing to close */
break;
@ -769,6 +797,7 @@ static qse_ssize_t sf_in_close (
}
else
{
/* handle the included source file - @include */
QSE_ASSERT (arg->handle != QSE_NULL);
qse_sio_close (arg->handle);
}
@ -780,22 +809,23 @@ static qse_ssize_t sf_in_read (
qse_awk_t* awk, qse_awk_sio_arg_t* arg,
qse_char_t* data, qse_size_t size, xtn_t* xtn)
{
if (arg == QSE_NULL || arg->name == QSE_NULL)
{
switch (xtn->s.in.x->type)
qse_ssize_t n;
again:
switch (xtn->s.in.x[xtn->s.in.xindex].type)
{
case QSE_AWK_PARSESTD_FILE:
{
qse_ssize_t n;
QSE_ASSERT (xtn->s.in.u.file.sio != QSE_NULL);
n = qse_sio_getstrn (xtn->s.in.u.file.sio, data, size);
if (n <= -1)
{
qse_cstr_t ea;
if (xtn->s.in.x->u.file.path)
if (xtn->s.in.x[xtn->s.in.xindex].u.file.path)
{
ea.ptr = xtn->s.in.x->u.file.path;
ea.ptr = xtn->s.in.x[xtn->s.in.xindex].u.file.path;
ea.len = qse_strlen(ea.ptr);
}
else
@ -805,28 +835,45 @@ static qse_ssize_t sf_in_read (
}
qse_awk_seterrnum (awk, QSE_AWK_EREAD, &ea);
}
return n;
}
break;
case QSE_AWK_PARSESTD_STR:
{
qse_size_t n = 0;
n = 0;
while (n < size && xtn->s.in.u.str.ptr < xtn->s.in.u.str.end)
{
data[n++] = *xtn->s.in.u.str.ptr++;
}
return n;
}
break;
default:
/* this should never happen */
qse_awk_seterrnum (awk, QSE_AWK_EINTERN, QSE_NULL);
return -1;
n = -1;
break;
}
if (n == 0)
{
/* reached end of the current stream. */
qse_size_t next = xtn->s.in.xindex + 1;
if (xtn->s.in.x[next].type != QSE_AWK_PARSESTD_NULL)
{
/* open the next stream if available. */
if (open_parsestd (awk, xtn, next) <= -1) n = -1;
else
{
/* if successful, close the current stream */
xtn->s.in.xindex = next; /* update the next to the current */
goto again;
}
}
}
return n;
}
else
{
/* handle the included source file - @include */
qse_ssize_t n;
QSE_ASSERT (arg->handle != QSE_NULL);
@ -899,8 +946,8 @@ static qse_ssize_t sf_out (
if (xtn->s.out.u.file.sio == QSE_NULL) return -1;
}
if (xtn->s.out.x->u.file.cmgr)
qse_sio_setcmgr (xtn->s.out.u.file.sio, xtn->s.out.x->u.file.cmgr);
if (xtn->s.out.x->cmgr)
qse_sio_setcmgr (xtn->s.out.u.file.sio, xtn->s.out.x->cmgr);
return 1;
case QSE_AWK_PARSESTD_STR:
@ -988,25 +1035,20 @@ static qse_ssize_t sf_out (
}
int qse_awk_parsestd (
qse_awk_t* awk, qse_awk_parsestd_t* in, qse_awk_parsestd_t* out)
qse_awk_t* awk, qse_awk_parsestd_t in[], qse_awk_parsestd_t* out)
{
qse_awk_sio_t sio;
xtn_t* xtn = (xtn_t*) QSE_XTN (awk);
int n;
if (in == QSE_NULL)
if (in == QSE_NULL || (in[0].type != QSE_AWK_PARSESTD_FILE &&
in[0].type != QSE_AWK_PARSESTD_STR))
{
/* the input is a must */
qse_awk_seterrnum (awk, QSE_AWK_EINVAL, QSE_NULL);
return -1;
}
if (in->type != QSE_AWK_PARSESTD_FILE &&
in->type != QSE_AWK_PARSESTD_STR)
{
qse_awk_seterrnum (awk, QSE_AWK_EINVAL, QSE_NULL);
return -1;
}
sio.in = sf_in;
xtn->s.in.x = in;

View File

@ -234,7 +234,7 @@ int qse_tio_attachout (
}
tio->errnum = QSE_TIO_ENOERR;
if (output (tio, QSE_TIO_OPEN, QSE_NULL, 0) == -1)
if (output (tio, QSE_TIO_OPEN, QSE_NULL, 0) <= -1)
{
if (tio->errnum == QSE_TIO_ENOERR) tio->errnum = QSE_TIO_EOTHER;
if (xbufptr != bufptr) QSE_MMGR_FREE (tio->mmgr, xbufptr);

View File

@ -383,16 +383,8 @@ static int open_script_stream (qse_sed_t* sed)
sed->src.loc.line = 1;
sed->src.loc.colm = 0;
if (n == 0)
{
sed->src.eof = 1;
return 0; /* end of file */
}
else
{
sed->src.eof = 0;
return 1;
}
sed->src.eof = 0;
return 0;
}
static int close_script_stream (qse_sed_t* sed)
@ -2516,16 +2508,6 @@ static int write_str_to_file (
else sed->errloc = cmd->loc;
return -1;
}
if (n == 0)
{
/* EOF is returned upon opening a write stream.
* it is also an error as it can't write
* a requested string */
sed->e.out.fun (sed, QSE_SED_IO_CLOSE, ap, QSE_NULL, 0);
ap->handle = QSE_NULL;
SETERR1 (sed, QSE_SED_EIOFIL, path, plen, &cmd->loc);
return -1;
}
}
while (len > 0)
@ -2582,12 +2564,6 @@ static int write_file (
/* it is ok if it is not able to open a file */
return 0;
}
if (n == 0)
{
/* EOF - no data */
sed->e.in.fun (sed, QSE_SED_IO_CLOSE, &arg, QSE_NULL, 0);
return 0;
}
while (1)
{
@ -3983,12 +3959,6 @@ int qse_sed_exec (qse_sed_t* sed, qse_sed_io_impl_t inf, qse_sed_io_impl_t outf)
SETERR0 (sed, QSE_SED_EIOUSR, QSE_NULL);
goto done3;
}
if (n == 0)
{
/* EOF reached upon opening an input stream.
* no data to process. this is success */
goto done2;
}
sed->errnum = QSE_SED_ENOERR;
sed->e.out.arg.path = QSE_NULL;
@ -4000,12 +3970,6 @@ int qse_sed_exec (qse_sed_t* sed, qse_sed_io_impl_t inf, qse_sed_io_impl_t outf)
SETERR0 (sed, QSE_SED_EIOUSR, QSE_NULL);
goto done2;
}
if (n == 0)
{
/* still don't know if we will write something.
* just mark EOF on the output stream and continue */
sed->e.out.eof = 1;
}
if (init_all_commands_for_exec (sed) <= -1)
{