qse/qse/lib/awk/eio.c

980 lines
22 KiB
C
Raw Normal View History

/*
* $Id: eio.c 466 2008-12-09 09:50:40Z baconevi $
*
2008-12-27 04:35:14 +00:00
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.
*/
2008-08-21 03:17:25 +00:00
#include "awk.h"
enum
{
MASK_READ = 0x0100,
MASK_WRITE = 0x0200,
MASK_RDWR = 0x0400,
MASK_CLEAR = 0x00FF
};
static int in_type_map[] =
{
/* the order should match the order of the
2008-12-21 21:35:07 +00:00
* QSE_AWK_IN_XXX values in tree.h */
QSE_AWK_EIO_PIPE,
QSE_AWK_EIO_PIPE,
QSE_AWK_EIO_FILE,
QSE_AWK_EIO_CONSOLE
};
static int in_mode_map[] =
{
/* the order should match the order of the
2008-12-21 21:35:07 +00:00
* QSE_AWK_IN_XXX values in tree.h */
QSE_AWK_EIO_PIPE_READ,
QSE_AWK_EIO_PIPE_RW,
QSE_AWK_EIO_FILE_READ,
QSE_AWK_EIO_CONSOLE_READ
};
static int in_mask_map[] =
{
MASK_READ,
MASK_RDWR,
MASK_READ,
MASK_READ
};
static int out_type_map[] =
{
/* the order should match the order of the
2008-12-21 21:35:07 +00:00
* QSE_AWK_OUT_XXX values in tree.h */
QSE_AWK_EIO_PIPE,
QSE_AWK_EIO_PIPE,
QSE_AWK_EIO_FILE,
QSE_AWK_EIO_FILE,
QSE_AWK_EIO_CONSOLE
};
static int out_mode_map[] =
{
/* the order should match the order of the
2008-12-21 21:35:07 +00:00
* QSE_AWK_OUT_XXX values in tree.h */
QSE_AWK_EIO_PIPE_WRITE,
QSE_AWK_EIO_PIPE_RW,
QSE_AWK_EIO_FILE_WRITE,
QSE_AWK_EIO_FILE_APPEND,
QSE_AWK_EIO_CONSOLE_WRITE
};
static int out_mask_map[] =
{
MASK_WRITE,
MASK_RDWR,
MASK_WRITE,
MASK_WRITE,
MASK_WRITE
};
int qse_awk_readeio (
qse_awk_rtx_t* run, int in_type,
2008-12-21 21:35:07 +00:00
const qse_char_t* name, qse_str_t* buf)
{
qse_awk_eio_t* p = run->eio.chain;
2008-12-21 21:35:07 +00:00
qse_awk_io_t handler;
int eio_type, eio_mode, eio_mask, ret, n;
2008-12-21 21:35:07 +00:00
qse_ssize_t x;
qse_awk_val_t* rs;
qse_char_t* rs_ptr;
qse_size_t rs_len;
qse_size_t line_len = 0;
qse_char_t c = QSE_T('\0'), pc;
2008-12-21 21:35:07 +00:00
QSE_ASSERT (in_type >= 0 && in_type <= QSE_COUNTOF(in_type_map));
QSE_ASSERT (in_type >= 0 && in_type <= QSE_COUNTOF(in_mode_map));
QSE_ASSERT (in_type >= 0 && in_type <= QSE_COUNTOF(in_mask_map));
/* translate the in_type into the relevant eio type and mode */
eio_type = in_type_map[in_type];
eio_mode = in_mode_map[in_type];
eio_mask = in_mask_map[in_type];
/* get the io handler provided by a user */
handler = run->eio.handler[eio_type];
2008-12-21 21:35:07 +00:00
if (handler == QSE_NULL)
{
/* no io handler provided */
qse_awk_rtx_seterrnum (run, QSE_AWK_EIOUSER);
return -1;
}
/* search the chain for exiting an existing io name */
2008-12-21 21:35:07 +00:00
while (p != QSE_NULL)
{
if (p->type == (eio_type | eio_mask) &&
2008-12-21 21:35:07 +00:00
qse_strcmp (p->name,name) == 0) break;
p = p->next;
}
2008-12-21 21:35:07 +00:00
if (p == QSE_NULL)
{
/* if the name doesn't exist in the chain, create an entry
* to the chain */
p = (qse_awk_eio_t*) QSE_AWK_ALLOC (
run->awk, QSE_SIZEOF(qse_awk_eio_t));
2008-12-21 21:35:07 +00:00
if (p == QSE_NULL)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM);
return -1;
}
2008-12-21 21:35:07 +00:00
p->name = QSE_AWK_STRDUP (run->awk, name);
if (p->name == QSE_NULL)
{
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, p);
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM);
return -1;
}
p->rtx = run;
p->type = (eio_type | eio_mask);
p->mode = eio_mode;
2008-12-21 21:35:07 +00:00
p->handle = QSE_NULL;
p->next = QSE_NULL;
p->data = run->eio.data;
2008-12-21 21:35:07 +00:00
p->in.buf[0] = QSE_T('\0');
p->in.pos = 0;
p->in.len = 0;
2008-12-21 21:35:07 +00:00
p->in.eof = QSE_FALSE;
p->in.eos = QSE_FALSE;
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOERR);
/* request to open the stream */
2008-12-21 21:35:07 +00:00
x = handler (QSE_AWK_IO_OPEN, p, QSE_NULL, 0);
if (x <= -1)
{
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, p->name);
QSE_AWK_FREE (run->awk, p);
2008-12-21 21:35:07 +00:00
if (run->errnum == QSE_AWK_ENOERR)
{
/* if the error number has not been
* set by the user handler */
qse_awk_rtx_seterrnum (run, QSE_AWK_EIOIMPL);
}
return -1;
}
/* chain it */
p->next = run->eio.chain;
run->eio.chain = p;
/* usually, x == 0 indicates that it has reached the end
* of the input. the user io 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 exeuction. */
if (x == 0)
{
2008-12-21 21:35:07 +00:00
p->in.eos = QSE_TRUE;
return 0;
}
}
if (p->in.eos)
{
/* no more streams. */
return 0;
}
/* ready to read a line. clear the line buffer */
2008-12-21 21:35:07 +00:00
qse_str_clear (buf);
/* get the record separator */
rs = qse_awk_rtx_getglobal (run, QSE_AWK_GLOBAL_RS);
qse_awk_rtx_refupval (run, rs);
2008-12-21 21:35:07 +00:00
if (rs->type == QSE_AWK_VAL_NIL)
{
2008-12-21 21:35:07 +00:00
rs_ptr = QSE_NULL;
rs_len = 0;
}
2008-12-21 21:35:07 +00:00
else if (rs->type == QSE_AWK_VAL_STR)
{
rs_ptr = ((qse_awk_val_str_t*)rs)->ptr;
2008-12-21 21:35:07 +00:00
rs_len = ((qse_awk_val_str_t*)rs)->len;
}
else
{
rs_ptr = qse_awk_rtx_valtostr (
2008-12-21 21:35:07 +00:00
run, rs, QSE_AWK_VALTOSTR_CLEAR, QSE_NULL, &rs_len);
if (rs_ptr == QSE_NULL)
{
qse_awk_rtx_refdownval (run, rs);
return -1;
}
}
ret = 1;
/* call the io handler */
while (1)
{
if (p->in.pos >= p->in.len)
{
2008-12-21 21:35:07 +00:00
qse_ssize_t n;
if (p->in.eof)
{
2008-12-21 21:35:07 +00:00
if (QSE_STR_LEN(buf) == 0) ret = 0;
break;
}
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOERR);
n = handler (QSE_AWK_IO_READ,
2008-12-21 21:35:07 +00:00
p, p->in.buf, QSE_COUNTOF(p->in.buf));
if (n <= -1)
{
2008-12-21 21:35:07 +00:00
if (run->errnum == QSE_AWK_ENOERR)
{
/* if the error number has not been
* set by the user handler */
qse_awk_rtx_seterrnum (run, QSE_AWK_EIOIMPL);
}
ret = -1;
break;
}
if (n == 0)
{
2008-12-21 21:35:07 +00:00
p->in.eof = QSE_TRUE;
2008-12-21 21:35:07 +00:00
if (QSE_STR_LEN(buf) == 0) ret = 0;
else if (rs_len >= 2)
{
/* when RS is multiple characters, it needs to check
* for the match at the end of the input stream as
* the buffer has been appened with the last character
* after the previous matchrex has failed */
2008-12-21 21:35:07 +00:00
const qse_char_t* match_ptr;
qse_size_t match_len;
2008-12-21 21:35:07 +00:00
QSE_ASSERT (run->global.rs != QSE_NULL);
2008-12-21 21:35:07 +00:00
n = QSE_AWK_MATCHREX (
run->awk, run->global.rs,
2008-12-21 21:35:07 +00:00
((run->global.ignorecase)? QSE_REX_IGNORECASE: 0),
QSE_STR_PTR(buf), QSE_STR_LEN(buf),
&match_ptr, &match_len, &run->errnum);
if (n == -1)
{
ret = -1;
break;
}
if (n == 1)
{
/* the match should be found at the end of
* the current buffer */
2008-12-21 21:35:07 +00:00
QSE_ASSERT (
QSE_STR_PTR(buf) + QSE_STR_LEN(buf) ==
match_ptr + match_len);
2008-12-21 21:35:07 +00:00
QSE_STR_LEN(buf) -= match_len;
break;
}
}
break;
}
p->in.len = n;
p->in.pos = 0;
}
pc = c;
c = p->in.buf[p->in.pos++];
2008-12-21 21:35:07 +00:00
if (rs_ptr == QSE_NULL)
{
/* separate by a new line */
2008-12-21 21:35:07 +00:00
if (c == QSE_T('\n'))
{
2008-12-21 21:35:07 +00:00
if (pc == QSE_T('\r') &&
QSE_STR_LEN(buf) > 0)
{
2008-12-21 21:35:07 +00:00
QSE_STR_LEN(buf) -= 1;
}
break;
}
}
else if (rs_len == 0)
{
/* separate by a blank line */
2008-12-21 21:35:07 +00:00
if (c == QSE_T('\n'))
{
2008-12-21 21:35:07 +00:00
if (pc == QSE_T('\r') &&
QSE_STR_LEN(buf) > 0)
{
2008-12-21 21:35:07 +00:00
QSE_STR_LEN(buf) -= 1;
}
}
2008-12-21 21:35:07 +00:00
if (line_len == 0 && c == QSE_T('\n'))
{
2008-12-21 21:35:07 +00:00
if (QSE_STR_LEN(buf) <= 0)
{
/* if the record is empty when a blank
* line is encountered, the line
* terminator should not be added to
* the record */
continue;
}
/* when a blank line is encountered,
* it needs to snip off the line
* terminator of the previous line */
2008-12-21 21:35:07 +00:00
QSE_STR_LEN(buf) -= 1;
break;
}
}
else if (rs_len == 1)
{
if (c == rs_ptr[0]) break;
}
else
{
2008-12-21 21:35:07 +00:00
const qse_char_t* match_ptr;
qse_size_t match_len;
2008-12-21 21:35:07 +00:00
QSE_ASSERT (run->global.rs != QSE_NULL);
2008-12-21 21:35:07 +00:00
n = QSE_AWK_MATCHREX (
run->awk, run->global.rs,
2008-12-21 21:35:07 +00:00
((run->global.ignorecase)? QSE_REX_IGNORECASE: 0),
QSE_STR_PTR(buf), QSE_STR_LEN(buf),
&match_ptr, &match_len, &run->errnum);
if (n == -1)
{
ret = -1;
p->in.pos--; /* unread the character in c */
break;
}
if (n == 1)
{
/* the match should be found at the end of
* the current buffer */
2008-12-21 21:35:07 +00:00
QSE_ASSERT (
QSE_STR_PTR(buf) + QSE_STR_LEN(buf) ==
match_ptr + match_len);
2008-12-21 21:35:07 +00:00
QSE_STR_LEN(buf) -= match_len;
p->in.pos--; /* unread the character in c */
break;
}
}
2008-12-21 21:35:07 +00:00
if (qse_str_ccat (buf, c) == (qse_size_t)-1)
{
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ENOMEM, 0, QSE_NULL, 0);
ret = -1;
break;
}
/* TODO: handle different line terminator like \r\n */
2008-12-21 21:35:07 +00:00
if (c == QSE_T('\n')) line_len = 0;
else line_len = line_len + 1;
}
2008-12-21 21:35:07 +00:00
if (rs_ptr != QSE_NULL &&
rs->type != QSE_AWK_VAL_STR) QSE_AWK_FREE (run->awk, rs_ptr);
qse_awk_rtx_refdownval (run, rs);
return ret;
}
int qse_awk_writeeio_val (
qse_awk_rtx_t* run, int out_type,
2008-12-21 21:35:07 +00:00
const qse_char_t* name, qse_awk_val_t* v)
{
2008-12-21 21:35:07 +00:00
qse_char_t* str;
qse_size_t len;
int n;
2008-12-21 21:35:07 +00:00
if (v->type == QSE_AWK_VAL_STR)
{
str = ((qse_awk_val_str_t*)v)->ptr;
2008-12-21 21:35:07 +00:00
len = ((qse_awk_val_str_t*)v)->len;
}
else
{
str = qse_awk_rtx_valtostr (
run, v,
2008-12-21 21:35:07 +00:00
QSE_AWK_VALTOSTR_CLEAR | QSE_AWK_VALTOSTR_PRINT,
QSE_NULL, &len);
if (str == QSE_NULL) return -1;
}
n = qse_awk_writeeio_str (run, out_type, name, str, len);
2008-12-21 21:35:07 +00:00
if (v->type != QSE_AWK_VAL_STR) QSE_AWK_FREE (run->awk, str);
return n;
}
int qse_awk_writeeio_str (
qse_awk_rtx_t* run, int out_type,
2008-12-21 21:35:07 +00:00
const qse_char_t* name, qse_char_t* str, qse_size_t len)
{
qse_awk_eio_t* p = run->eio.chain;
2008-12-21 21:35:07 +00:00
qse_awk_io_t handler;
int eio_type, eio_mode, eio_mask;
2008-12-21 21:35:07 +00:00
qse_ssize_t n;
2008-12-21 21:35:07 +00:00
QSE_ASSERT (out_type >= 0 && out_type <= QSE_COUNTOF(out_type_map));
QSE_ASSERT (out_type >= 0 && out_type <= QSE_COUNTOF(out_mode_map));
QSE_ASSERT (out_type >= 0 && out_type <= QSE_COUNTOF(out_mask_map));
/* translate the out_type into the relevant eio type and mode */
eio_type = out_type_map[out_type];
eio_mode = out_mode_map[out_type];
eio_mask = out_mask_map[out_type];
handler = run->eio.handler[eio_type];
2008-12-21 21:35:07 +00:00
if (handler == QSE_NULL)
{
/* no io handler provided */
qse_awk_rtx_seterrnum (run, QSE_AWK_EIOUSER);
return -1;
}
/* look for the corresponding eio for name */
2008-12-21 21:35:07 +00:00
while (p != QSE_NULL)
{
/* the file "1.tmp", in the following code snippets,
* would be opened by the first print statement, but not by
* the second print statement. this is because
* both QSE_AWK_OUT_FILE and QSE_AWK_OUT_APFILE are
* translated to QSE_AWK_EIO_FILE and it is used to
* keep track of file handles..
*
* print "1111" >> "1.tmp"
* print "1111" > "1.tmp"
*/
if (p->type == (eio_type | eio_mask) &&
2008-12-21 21:35:07 +00:00
qse_strcmp (p->name, name) == 0) break;
p = p->next;
}
/* if there is not corresponding eio for name, create one */
2008-12-21 21:35:07 +00:00
if (p == QSE_NULL)
{
p = (qse_awk_eio_t*) QSE_AWK_ALLOC (
run->awk, QSE_SIZEOF(qse_awk_eio_t));
2008-12-21 21:35:07 +00:00
if (p == QSE_NULL)
{
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ENOMEM, 0, QSE_NULL, 0);
return -1;
}
2008-12-21 21:35:07 +00:00
p->name = QSE_AWK_STRDUP (run->awk, name);
if (p->name == QSE_NULL)
{
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, p);
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ENOMEM, 0, QSE_NULL, 0);
return -1;
}
p->rtx = run;
p->type = (eio_type | eio_mask);
p->mode = eio_mode;
2008-12-21 21:35:07 +00:00
p->handle = QSE_NULL;
p->next = QSE_NULL;
p->data = run->eio.data;
2008-12-21 21:35:07 +00:00
p->out.eof = QSE_FALSE;
p->out.eos = QSE_FALSE;
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOERR);
2008-12-21 21:35:07 +00:00
n = handler (QSE_AWK_IO_OPEN, p, QSE_NULL, 0);
if (n <= -1)
{
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, p->name);
QSE_AWK_FREE (run->awk, p);
2008-12-21 21:35:07 +00:00
if (run->errnum == QSE_AWK_ENOERR)
qse_awk_rtx_seterrnum (run, QSE_AWK_EIOIMPL);
return -1;
}
/* chain it */
p->next = run->eio.chain;
run->eio.chain = p;
/* usually, n == 0 indicates that it has reached the end
* of the input. the user io 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 exeuction. */
if (n == 0)
{
2008-12-21 21:35:07 +00:00
p->out.eos = QSE_TRUE;
return 0;
}
}
if (p->out.eos)
{
/* no more streams */
return 0;
}
if (p->out.eof)
{
/* it has reached the end of the stream but this function
* has been recalled */
return 0;
}
while (len > 0)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOERR);
2008-12-21 21:35:07 +00:00
n = handler (QSE_AWK_IO_WRITE, p, str, len);
if (n <= -1)
{
2008-12-21 21:35:07 +00:00
if (run->errnum == QSE_AWK_ENOERR)
qse_awk_rtx_seterrnum (run, QSE_AWK_EIOIMPL);
return -1;
}
if (n == 0)
{
2008-12-21 21:35:07 +00:00
p->out.eof = QSE_TRUE;
return 0;
}
len -= n;
str += n;
}
return 1;
}
int qse_awk_flusheio (
qse_awk_rtx_t* run, int out_type, const qse_char_t* name)
{
qse_awk_eio_t* p = run->eio.chain;
2008-12-21 21:35:07 +00:00
qse_awk_io_t handler;
int eio_type, /*eio_mode,*/ eio_mask;
2008-12-21 21:35:07 +00:00
qse_ssize_t n;
qse_bool_t ok = QSE_FALSE;
2008-12-21 21:35:07 +00:00
QSE_ASSERT (out_type >= 0 && out_type <= QSE_COUNTOF(out_type_map));
QSE_ASSERT (out_type >= 0 && out_type <= QSE_COUNTOF(out_mode_map));
QSE_ASSERT (out_type >= 0 && out_type <= QSE_COUNTOF(out_mask_map));
/* translate the out_type into the relevant eio type and mode */
eio_type = out_type_map[out_type];
/*eio_mode = out_mode_map[out_type];*/
eio_mask = out_mask_map[out_type];
handler = run->eio.handler[eio_type];
2008-12-21 21:35:07 +00:00
if (handler == QSE_NULL)
{
/* no io handler provided */
qse_awk_rtx_seterrnum (run, QSE_AWK_EIOUSER);
return -1;
}
/* look for the corresponding eio for name */
2008-12-21 21:35:07 +00:00
while (p != QSE_NULL)
{
if (p->type == (eio_type | eio_mask) &&
2008-12-21 21:35:07 +00:00
(name == QSE_NULL || qse_strcmp(p->name,name) == 0))
{
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOERR);
2008-12-21 21:35:07 +00:00
n = handler (QSE_AWK_IO_FLUSH, p, QSE_NULL, 0);
if (n <= -1)
{
2008-12-21 21:35:07 +00:00
if (run->errnum == QSE_AWK_ENOERR)
qse_awk_rtx_seterrnum (run, QSE_AWK_EIOIMPL);
return -1;
}
2008-12-21 21:35:07 +00:00
ok = QSE_TRUE;
}
p = p->next;
}
if (ok) return 0;
/* there is no corresponding eio for name */
qse_awk_rtx_seterrnum (run, QSE_AWK_EIONONE);
return -1;
}
int qse_awk_nexteio_read (
qse_awk_rtx_t* run, int in_type, const qse_char_t* name)
{
qse_awk_eio_t* p = run->eio.chain;
2008-12-21 21:35:07 +00:00
qse_awk_io_t handler;
int eio_type, /*eio_mode,*/ eio_mask;
2008-12-21 21:35:07 +00:00
qse_ssize_t n;
2008-12-21 21:35:07 +00:00
QSE_ASSERT (in_type >= 0 && in_type <= QSE_COUNTOF(in_type_map));
QSE_ASSERT (in_type >= 0 && in_type <= QSE_COUNTOF(in_mode_map));
QSE_ASSERT (in_type >= 0 && in_type <= QSE_COUNTOF(in_mask_map));
/* translate the in_type into the relevant eio type and mode */
eio_type = in_type_map[in_type];
/*eio_mode = in_mode_map[in_type];*/
eio_mask = in_mask_map[in_type];
handler = run->eio.handler[eio_type];
2008-12-21 21:35:07 +00:00
if (handler == QSE_NULL)
{
/* no io handler provided */
qse_awk_rtx_seterrnum (run, QSE_AWK_EIOUSER);
return -1;
}
2008-12-21 21:35:07 +00:00
while (p != QSE_NULL)
{
if (p->type == (eio_type | eio_mask) &&
2008-12-21 21:35:07 +00:00
qse_strcmp (p->name,name) == 0) break;
p = p->next;
}
2008-12-21 21:35:07 +00:00
if (p == QSE_NULL)
{
/* something is totally wrong */
2008-12-21 21:35:07 +00:00
QSE_ASSERT (
!"should never happen - cannot find the relevant eio entry");
qse_awk_rtx_seterror (run, QSE_AWK_EINTERN, 0, QSE_NULL, 0);
return -1;
}
if (p->in.eos)
{
/* no more streams. */
return 0;
}
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOERR);
2008-12-21 21:35:07 +00:00
n = handler (QSE_AWK_IO_NEXT, p, QSE_NULL, 0);
if (n <= -1)
{
2008-12-21 21:35:07 +00:00
if (run->errnum == QSE_AWK_ENOERR)
qse_awk_rtx_seterrnum (run, QSE_AWK_EIOIMPL);
return -1;
}
if (n == 0)
{
/* the next stream cannot be opened.
* set the eos flags so that the next call to nexteio_read
* will return 0 without executing the handler */
2008-12-21 21:35:07 +00:00
p->in.eos = QSE_TRUE;
return 0;
}
else
{
/* as the next stream has been opened successfully,
* the eof flag should be cleared if set */
2008-12-21 21:35:07 +00:00
p->in.eof = QSE_FALSE;
/* also the previous input buffer must be reset */
p->in.pos = 0;
p->in.len = 0;
return 1;
}
}
int qse_awk_nexteio_write (
qse_awk_rtx_t* run, int out_type, const qse_char_t* name)
{
qse_awk_eio_t* p = run->eio.chain;
2008-12-21 21:35:07 +00:00
qse_awk_io_t handler;
int eio_type, /*eio_mode,*/ eio_mask;
2008-12-21 21:35:07 +00:00
qse_ssize_t n;
2008-12-21 21:35:07 +00:00
QSE_ASSERT (out_type >= 0 && out_type <= QSE_COUNTOF(out_type_map));
QSE_ASSERT (out_type >= 0 && out_type <= QSE_COUNTOF(out_mode_map));
QSE_ASSERT (out_type >= 0 && out_type <= QSE_COUNTOF(out_mask_map));
/* translate the out_type into the relevant eio type and mode */
eio_type = out_type_map[out_type];
/*eio_mode = out_mode_map[out_type];*/
eio_mask = out_mask_map[out_type];
handler = run->eio.handler[eio_type];
2008-12-21 21:35:07 +00:00
if (handler == QSE_NULL)
{
/* no io handler provided */
qse_awk_rtx_seterrnum (run, QSE_AWK_EIOUSER);
return -1;
}
2008-12-21 21:35:07 +00:00
while (p != QSE_NULL)
{
if (p->type == (eio_type | eio_mask) &&
2008-12-21 21:35:07 +00:00
qse_strcmp (p->name,name) == 0) break;
p = p->next;
}
2008-12-21 21:35:07 +00:00
if (p == QSE_NULL)
{
/* something is totally wrong */
QSE_ASSERT (!"should never happen - cannot find the relevant eio entry");
qse_awk_rtx_seterror (run, QSE_AWK_EINTERN, 0, QSE_NULL, 0);
return -1;
}
if (p->out.eos)
{
/* no more streams. */
return 0;
}
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOERR);
2008-12-21 21:35:07 +00:00
n = handler (QSE_AWK_IO_NEXT, p, QSE_NULL, 0);
if (n <= -1)
{
2008-12-21 21:35:07 +00:00
if (run->errnum == QSE_AWK_ENOERR)
qse_awk_rtx_seterrnum (run, QSE_AWK_EIOIMPL);
return -1;
}
if (n == 0)
{
/* the next stream cannot be opened.
* set the eos flags so that the next call to nexteio_write
* will return 0 without executing the handler */
2008-12-21 21:35:07 +00:00
p->out.eos = QSE_TRUE;
return 0;
}
else
{
/* as the next stream has been opened successfully,
* the eof flag should be cleared if set */
2008-12-21 21:35:07 +00:00
p->out.eof = QSE_FALSE;
return 1;
}
}
int qse_awk_closeeio_read (
qse_awk_rtx_t* run, int in_type, const qse_char_t* name)
{
qse_awk_eio_t* p = run->eio.chain, * px = QSE_NULL;
2008-12-21 21:35:07 +00:00
qse_awk_io_t handler;
int eio_type, /*eio_mode,*/ eio_mask;
2008-12-21 21:35:07 +00:00
QSE_ASSERT (in_type >= 0 && in_type <= QSE_COUNTOF(in_type_map));
QSE_ASSERT (in_type >= 0 && in_type <= QSE_COUNTOF(in_mode_map));
QSE_ASSERT (in_type >= 0 && in_type <= QSE_COUNTOF(in_mask_map));
/* translate the in_type into the relevant eio type and mode */
eio_type = in_type_map[in_type];
/*eio_mode = in_mode_map[in_type];*/
eio_mask = in_mask_map[in_type];
handler = run->eio.handler[eio_type];
2008-12-21 21:35:07 +00:00
if (handler == QSE_NULL)
{
/* no io handler provided */
qse_awk_rtx_seterrnum (run, QSE_AWK_EIOUSER);
return -1;
}
2008-12-21 21:35:07 +00:00
while (p != QSE_NULL)
{
if (p->type == (eio_type | eio_mask) &&
2008-12-21 21:35:07 +00:00
qse_strcmp (p->name, name) == 0)
{
2008-12-21 21:35:07 +00:00
qse_awk_io_t handler;
handler = run->eio.handler[p->type & MASK_CLEAR];
2008-12-21 21:35:07 +00:00
if (handler != QSE_NULL)
{
2008-12-21 21:35:07 +00:00
if (handler (QSE_AWK_IO_CLOSE, p, QSE_NULL, 0) <= -1)
{
/* this is not a run-time error.*/
qse_awk_rtx_seterror (run, QSE_AWK_EIOIMPL, 0, QSE_NULL, 0);
return -1;
}
}
2008-12-21 21:35:07 +00:00
if (px != QSE_NULL) px->next = p->next;
else run->eio.chain = p->next;
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, p->name);
QSE_AWK_FREE (run->awk, p);
return 0;
}
px = p;
p = p->next;
}
/* the name given is not found */
qse_awk_rtx_seterrnum (run, QSE_AWK_EIONONE);
return -1;
}
int qse_awk_closeeio_write (
qse_awk_rtx_t* run, int out_type, const qse_char_t* name)
{
qse_awk_eio_t* p = run->eio.chain, * px = QSE_NULL;
2008-12-21 21:35:07 +00:00
qse_awk_io_t handler;
int eio_type, /*eio_mode,*/ eio_mask;
2008-12-21 21:35:07 +00:00
QSE_ASSERT (out_type >= 0 && out_type <= QSE_COUNTOF(out_type_map));
QSE_ASSERT (out_type >= 0 && out_type <= QSE_COUNTOF(out_mode_map));
QSE_ASSERT (out_type >= 0 && out_type <= QSE_COUNTOF(out_mask_map));
/* translate the out_type into the relevant eio type and mode */
eio_type = out_type_map[out_type];
/*eio_mode = out_mode_map[out_type];*/
eio_mask = out_mask_map[out_type];
handler = run->eio.handler[eio_type];
2008-12-21 21:35:07 +00:00
if (handler == QSE_NULL)
{
/* no io handler provided */
qse_awk_rtx_seterror (run, QSE_AWK_EIOUSER, 0, QSE_NULL, 0);
return -1;
}
2008-12-21 21:35:07 +00:00
while (p != QSE_NULL)
{
if (p->type == (eio_type | eio_mask) &&
2008-12-21 21:35:07 +00:00
qse_strcmp (p->name, name) == 0)
{
2008-12-21 21:35:07 +00:00
qse_awk_io_t handler;
handler = run->eio.handler[p->type & MASK_CLEAR];
2008-12-21 21:35:07 +00:00
if (handler != QSE_NULL)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOERR);
2008-12-21 21:35:07 +00:00
if (handler (QSE_AWK_IO_CLOSE, p, QSE_NULL, 0) <= -1)
{
2008-12-21 21:35:07 +00:00
if (run->errnum == QSE_AWK_ENOERR)
qse_awk_rtx_seterrnum (run, QSE_AWK_EIOIMPL);
return -1;
}
}
2008-12-21 21:35:07 +00:00
if (px != QSE_NULL) px->next = p->next;
else run->eio.chain = p->next;
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, p->name);
QSE_AWK_FREE (run->awk, p);
return 0;
}
px = p;
p = p->next;
}
qse_awk_rtx_seterrnum (run, QSE_AWK_EIONONE);
return -1;
}
int qse_awk_closeeio (qse_awk_rtx_t* run, const qse_char_t* name)
{
qse_awk_eio_t* p = run->eio.chain, * px = QSE_NULL;
2008-12-21 21:35:07 +00:00
while (p != QSE_NULL)
{
/* it handles the first that matches the given name
* regardless of the eio type */
2008-12-21 21:35:07 +00:00
if (qse_strcmp (p->name, name) == 0)
{
2008-12-21 21:35:07 +00:00
qse_awk_io_t handler;
handler = run->eio.handler[p->type & MASK_CLEAR];
2008-12-21 21:35:07 +00:00
if (handler != QSE_NULL)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOERR);
2008-12-21 21:35:07 +00:00
if (handler (QSE_AWK_IO_CLOSE, p, QSE_NULL, 0) <= -1)
{
/* this is not a run-time error.*/
2008-12-21 21:35:07 +00:00
if (run->errnum == QSE_AWK_ENOERR)
qse_awk_rtx_seterrnum (run, QSE_AWK_EIOIMPL);
return -1;
}
}
2008-12-21 21:35:07 +00:00
if (px != QSE_NULL) px->next = p->next;
else run->eio.chain = p->next;
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, p->name);
QSE_AWK_FREE (run->awk, p);
return 0;
}
px = p;
p = p->next;
}
qse_awk_rtx_seterrnum (run, QSE_AWK_EIONONE);
return -1;
}
void qse_awk_cleareio (qse_awk_rtx_t* run)
{
qse_awk_eio_t* next;
2008-12-21 21:35:07 +00:00
qse_awk_io_t handler;
qse_ssize_t n;
while (run->eio.chain != QSE_NULL)
{
handler = run->eio.handler[
run->eio.chain->type & MASK_CLEAR];
next = run->eio.chain->next;
2008-12-21 21:35:07 +00:00
if (handler != QSE_NULL)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOERR);
n = handler (QSE_AWK_IO_CLOSE, run->eio.chain, QSE_NULL, 0);
if (n <= -1)
{
2008-12-21 21:35:07 +00:00
if (run->errnum == QSE_AWK_ENOERR)
qse_awk_rtx_seterrnum (run, QSE_AWK_EIOIMPL);
/* TODO: some warnings need to be shown??? */
}
}
QSE_AWK_FREE (run->awk, run->eio.chain->name);
QSE_AWK_FREE (run->awk, run->eio.chain);
run->eio.chain = next;
}
}