qse/qse/lib/awk/rec.c

560 lines
13 KiB
C
Raw Normal View History

/*
2009-09-22 07:28:18 +00:00
* $Id: rec.c 291 2009-09-21 13:28:18Z hyunghwan.chung $
*
2009-09-16 04:01:02 +00:00
Copyright 2006-2009 Chung, Hyung-Hwan.
This file is part of QSE.
2008-12-27 04:35:14 +00:00
2009-09-16 04:01:02 +00:00
QSE is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
2008-12-27 04:35:14 +00:00
2009-09-16 04:01:02 +00:00
QSE is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
2008-12-27 04:35:14 +00:00
2009-09-16 04:01:02 +00:00
You should have received a copy of the GNU Lesser General Public
License along with QSE. If not, see <http://www.gnu.org/licenses/>.
*/
2008-08-21 03:17:25 +00:00
#include "awk.h"
static int split_record (qse_awk_rtx_t* run);
2008-02-13 01:39:56 +00:00
static int recomp_record_fields (
qse_awk_rtx_t* run, qse_size_t lv,
2008-12-21 21:35:07 +00:00
const qse_char_t* str, qse_size_t len);
int qse_awk_rtx_setrec (
qse_awk_rtx_t* run, qse_size_t idx,
2008-12-21 21:35:07 +00:00
const qse_char_t* str, qse_size_t len)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* v;
if (idx == 0)
{
2008-12-21 21:35:07 +00:00
if (str == QSE_STR_PTR(&run->inrec.line) &&
len == QSE_STR_LEN(&run->inrec.line))
{
if (qse_awk_rtx_clrrec (run, QSE_TRUE) == -1) return -1;
}
else
{
if (qse_awk_rtx_clrrec (run, QSE_FALSE) == -1) return -1;
2008-12-21 21:35:07 +00:00
if (qse_str_ncpy (&run->inrec.line, str, len) == (qse_size_t)-1)
{
qse_awk_rtx_clrrec (run, QSE_FALSE);
2009-08-17 02:08:58 +00:00
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM, QSE_NULL);
return -1;
}
}
2009-06-21 06:47:34 +00:00
v = qse_awk_rtx_makenstrval (run, str, len);
2008-12-21 21:35:07 +00:00
if (v == QSE_NULL)
{
qse_awk_rtx_clrrec (run, QSE_FALSE);
return -1;
}
2008-12-21 21:35:07 +00:00
QSE_ASSERT (run->inrec.d0->type == QSE_AWK_VAL_NIL);
/* d0 should be cleared before the next line is reached
* as it doesn't call qse_awk_rtx_refdownval on run->inrec.d0 */
run->inrec.d0 = v;
qse_awk_rtx_refupval (run, v);
2008-02-13 01:39:56 +00:00
if (split_record (run) == -1)
{
qse_awk_rtx_clrrec (run, QSE_FALSE);
return -1;
}
}
else
{
2008-02-13 01:39:56 +00:00
if (recomp_record_fields (run, idx, str, len) == -1)
{
qse_awk_rtx_clrrec (run, QSE_FALSE);
return -1;
}
/* recompose $0 */
v = qse_awk_rtx_makestrval (run,
2008-12-21 21:35:07 +00:00
QSE_STR_PTR(&run->inrec.line),
QSE_STR_LEN(&run->inrec.line));
if (v == QSE_NULL)
{
qse_awk_rtx_clrrec (run, QSE_FALSE);
return -1;
}
qse_awk_rtx_refdownval (run, run->inrec.d0);
run->inrec.d0 = v;
qse_awk_rtx_refupval (run, v);
}
return 0;
}
2009-09-22 07:28:18 +00:00
static int split_record (qse_awk_rtx_t* rtx)
{
2008-12-21 21:35:07 +00:00
qse_char_t* p, * tok;
qse_size_t len, tok_len, nflds;
qse_awk_val_t* v, * fs;
qse_char_t* fs_ptr, * fs_free;
qse_size_t fs_len;
qse_awk_errnum_t errnum;
2009-09-22 07:28:18 +00:00
int how;
2008-02-13 01:39:56 +00:00
/* inrec should be cleared before split_record is called */
2009-09-22 07:28:18 +00:00
QSE_ASSERT (rtx->inrec.nflds == 0);
/* get FS */
2009-09-22 07:28:18 +00:00
fs = qse_awk_rtx_getgbl (rtx, QSE_AWK_GBL_FS);
2008-12-21 21:35:07 +00:00
if (fs->type == QSE_AWK_VAL_NIL)
{
2008-12-21 21:35:07 +00:00
fs_ptr = QSE_T(" ");
fs_len = 1;
2008-12-21 21:35:07 +00:00
fs_free = QSE_NULL;
}
2008-12-21 21:35:07 +00:00
else if (fs->type == QSE_AWK_VAL_STR)
{
fs_ptr = ((qse_awk_val_str_t*)fs)->ptr;
2008-12-21 21:35:07 +00:00
fs_len = ((qse_awk_val_str_t*)fs)->len;
fs_free = QSE_NULL;
}
else
{
qse_awk_rtx_valtostr_out_t out;
out.type = QSE_AWK_RTX_VALTOSTR_CPLDUP;
2009-09-22 07:28:18 +00:00
if (qse_awk_rtx_valtostr (rtx, fs, &out) == QSE_NULL) return -1;
fs_ptr = out.u.cpldup.ptr;
fs_len = out.u.cpldup.len;
fs_free = fs_ptr;
}
/* scan the input record to count the fields */
2009-09-22 07:28:18 +00:00
len = QSE_STR_LEN(&rtx->inrec.line);
if (fs_len == 5 && fs_ptr[0] == QSE_T('?'))
{
2009-09-22 07:28:18 +00:00
if (qse_str_ncpy (
&rtx->inrec.linew,
QSE_STR_PTR(&rtx->inrec.line),
QSE_STR_LEN(&rtx->inrec.line)) == (qse_size_t)-1)
{
2009-09-22 07:28:18 +00:00
if (fs_free != QSE_NULL)
QSE_AWK_FREE (rtx->awk, fs_free);
qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, QSE_NULL);
return -1;
}
2009-09-22 07:28:18 +00:00
p = QSE_STR_PTR(&rtx->inrec.linew);
how = 1;
}
else
{
p = QSE_STR_PTR(&rtx->inrec.line);
how = (fs_len <= 1)? 0: 2;
}
#if 0
nflds = 0;
while (p != QSE_NULL)
{
switch (how)
{
2009-09-22 07:28:18 +00:00
case 0:
p = qse_awk_rtx_strxntok (rtx,
p, len, fs_ptr, fs_len, &tok, &tok_len);
break;
case 1:
break;
default:
p = qse_awk_rtx_strxntokbyrex (
rtx,
QSE_STR_PTR(&rtx->inrec.line),
QSE_STR_LEN(&rtx->inrec.line),
p, len,
rtx->gbl.fs, &tok, &tok_len, &errnum
);
if (p == QSE_NULL && errnum != QSE_AWK_ENOERR)
{
if (fs_free != QSE_NULL)
QSE_AWK_FREE (rtx->awk, fs_free);
qse_awk_rtx_seterrnum (rtx, errnum, QSE_NULL);
return -1;
}
}
2008-12-21 21:35:07 +00:00
if (nflds == 0 && p == QSE_NULL && tok_len == 0)
{
/* there are no fields. it can just return here
* as qse_awk_rtx_clrrec has been called before this */
2009-09-22 07:28:18 +00:00
if (fs_free != QSE_NULL) QSE_AWK_FREE (rtx->awk, fs_free);
return 0;
}
2008-12-21 21:35:07 +00:00
QSE_ASSERT ((tok != QSE_NULL && tok_len > 0) || tok_len == 0);
nflds++;
2009-09-22 07:28:18 +00:00
len = QSE_STR_LEN(&rtx->inrec.line) -
(p - QSE_STR_PTR(&rtx->inrec.line));
}
/* allocate space */
2009-09-22 07:28:18 +00:00
if (nflds > rtx->inrec.maxflds)
{
2008-12-21 21:35:07 +00:00
void* tmp = QSE_AWK_ALLOC (
2009-09-22 07:28:18 +00:00
rtx->awk, QSE_SIZEOF(*rtx->inrec.flds) * nflds);
2008-12-21 21:35:07 +00:00
if (tmp == QSE_NULL)
{
2009-09-22 07:28:18 +00:00
if (fs_free != QSE_NULL) QSE_AWK_FREE (rtx->awk, fs_free);
qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, QSE_NULL);
return -1;
}
2009-09-22 07:28:18 +00:00
if (rtx->inrec.flds != QSE_NULL)
QSE_AWK_FREE (rtx->awk, rtx->inrec.flds);
rtx->inrec.flds = tmp;
rtx->inrec.maxflds = nflds;
}
/* scan again and split it */
2009-09-22 07:28:18 +00:00
if (how == 1)
{
if (qse_str_ncpy (
&rtx->inrec.linew,
QSE_STR_PTR(&rtx->inrec.line),
QSE_STR_LEN(&rtx->inrec.line)) == (qse_size_t)-1)
{
if (fs_free != QSE_NULL)
QSE_AWK_FREE (rtx->awk, fs_free);
qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, QSE_NULL);
return -1;
}
p = QSE_STR_PTR(&rtx->inrec.linew):
}
else
{
p = QSE_STR_PTR(&rtx->inrec.line);
}
len = QSE_STR_LEN(&rtx->inrec.line);
#endif
2008-12-21 21:35:07 +00:00
while (p != QSE_NULL)
{
2009-09-22 07:28:18 +00:00
switch (how)
{
2009-09-22 07:28:18 +00:00
case 0:
p = qse_awk_rtx_strxntok (
rtx, p, len, fs_ptr, fs_len,
&tok, &tok_len);
break;
case 1:
p = qse_awk_rtx_strxnfld (
rtx, p, len,
fs_ptr[1], fs_ptr[2],
fs_ptr[3], fs_ptr[4],
&tok, &tok_len);
break;
default:
p = qse_awk_rtx_strxntokbyrex (
rtx,
QSE_STR_PTR(&rtx->inrec.line),
QSE_STR_LEN(&rtx->inrec.line),
p, len,
rtx->gbl.fs, &tok, &tok_len, &errnum
);
if (p == QSE_NULL && errnum != QSE_AWK_ENOERR)
{
if (fs_free != QSE_NULL)
QSE_AWK_FREE (rtx->awk, fs_free);
qse_awk_rtx_seterrnum (rtx, errnum, QSE_NULL);
return -1;
}
}
2009-09-22 07:28:18 +00:00
#if 1
if (rtx->inrec.nflds == 0 && p == QSE_NULL && tok_len == 0)
{
/* there are no fields. it can just return here
* as qse_awk_rtx_clrrec has been called before this */
if (fs_free != QSE_NULL) QSE_AWK_FREE (rtx->awk, fs_free);
return 0;
}
#endif
QSE_ASSERT ((tok != QSE_NULL && tok_len > 0) || tok_len == 0);
#if 1
if (rtx->inrec.nflds >= rtx->inrec.maxflds)
{
2009-09-22 07:28:18 +00:00
if (rtx->inrec.nflds < 16) nflds = 32;
else nflds = rtx->inrec.nflds * 2;
void* tmp = QSE_AWK_ALLOC (
rtx->awk, QSE_SIZEOF(*rtx->inrec.flds) * nflds);
if (tmp == QSE_NULL)
{
2009-09-22 07:28:18 +00:00
if (fs_free != QSE_NULL) QSE_AWK_FREE (rtx->awk, fs_free);
qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, QSE_NULL);
return -1;
}
2009-09-22 07:28:18 +00:00
if (rtx->inrec.flds != QSE_NULL)
{
QSE_MEMCPY (tmp, rtx->inrec.flds,
QSE_SIZEOF(*rtx->inrec.flds) * rtx->inrec.nflds);
QSE_AWK_FREE (rtx->awk, rtx->inrec.flds);
}
rtx->inrec.flds = tmp;
rtx->inrec.maxflds = nflds;
}
#endif
2009-09-22 07:28:18 +00:00
rtx->inrec.flds[rtx->inrec.nflds].ptr = tok;
rtx->inrec.flds[rtx->inrec.nflds].len = tok_len;
2009-09-22 07:28:18 +00:00
rtx->inrec.flds[rtx->inrec.nflds].val =
qse_awk_rtx_makenstrval (rtx, tok, tok_len);
2009-09-22 07:28:18 +00:00
if (rtx->inrec.flds[rtx->inrec.nflds].val == QSE_NULL)
{
2009-06-21 06:47:34 +00:00
if (fs_free != QSE_NULL)
2009-09-22 07:28:18 +00:00
QSE_AWK_FREE (rtx->awk, fs_free);
return -1;
}
2009-06-21 06:47:34 +00:00
qse_awk_rtx_refupval (
2009-09-22 07:28:18 +00:00
rtx, rtx->inrec.flds[rtx->inrec.nflds].val);
rtx->inrec.nflds++;
2009-09-22 07:28:18 +00:00
len = QSE_STR_LEN(&rtx->inrec.line) -
(p - QSE_STR_PTR(&rtx->inrec.line));
}
2009-09-22 07:28:18 +00:00
if (fs_free != QSE_NULL) QSE_AWK_FREE (rtx->awk, fs_free);
/* set the number of fields */
2009-09-22 07:28:18 +00:00
v = qse_awk_rtx_makeintval (rtx, (qse_long_t)rtx->inrec.nflds);
2008-12-21 21:35:07 +00:00
if (v == QSE_NULL) return -1;
2009-09-22 07:28:18 +00:00
qse_awk_rtx_refupval (rtx, v);
if (qse_awk_rtx_setgbl (rtx, QSE_AWK_GBL_NF, v) == -1)
{
2009-09-22 07:28:18 +00:00
qse_awk_rtx_refdownval (rtx, v);
return -1;
}
2009-09-22 07:28:18 +00:00
qse_awk_rtx_refdownval (rtx, v);
return 0;
}
int qse_awk_rtx_clrrec (qse_awk_rtx_t* run, qse_bool_t skip_inrec_line)
{
2008-12-21 21:35:07 +00:00
qse_size_t i;
int n = 0;
2008-12-21 21:35:07 +00:00
if (run->inrec.d0 != qse_awk_val_nil)
{
qse_awk_rtx_refdownval (run, run->inrec.d0);
2008-12-21 21:35:07 +00:00
run->inrec.d0 = qse_awk_val_nil;
}
if (run->inrec.nflds > 0)
{
2008-12-21 21:35:07 +00:00
QSE_ASSERT (run->inrec.flds != QSE_NULL);
for (i = 0; i < run->inrec.nflds; i++)
{
2008-12-21 21:35:07 +00:00
QSE_ASSERT (run->inrec.flds[i].val != QSE_NULL);
qse_awk_rtx_refdownval (run, run->inrec.flds[i].val);
}
run->inrec.nflds = 0;
if (qse_awk_rtx_setgbl (
run, QSE_AWK_GBL_NF, qse_awk_val_zero) == -1)
{
/* first of all, this should never happen.
* if it happened, it would return an error
* after all the clearance tasks */
n = -1;
}
}
2008-12-21 21:35:07 +00:00
QSE_ASSERT (run->inrec.nflds == 0);
if (!skip_inrec_line) qse_str_clear (&run->inrec.line);
return n;
}
2008-02-13 01:39:56 +00:00
static int recomp_record_fields (
qse_awk_rtx_t* run, qse_size_t lv,
2008-12-21 21:35:07 +00:00
const qse_char_t* str, qse_size_t len)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* v;
qse_size_t max, i, nflds;
/* recomposes the record and the fields when $N has been assigned
* a new value and recomputes NF accordingly */
2008-12-21 21:35:07 +00:00
QSE_ASSERT (lv > 0);
max = (lv > run->inrec.nflds)? lv: run->inrec.nflds;
nflds = run->inrec.nflds;
if (max > run->inrec.maxflds)
{
void* tmp;
/* if the given field number is greater than the maximum
* number of fields that the current record can hold,
* the field spaces are resized */
2008-12-21 21:35:07 +00:00
if (run->awk->mmgr->realloc != QSE_NULL)
{
2008-12-21 21:35:07 +00:00
tmp = QSE_AWK_REALLOC (
run->awk, run->inrec.flds,
2008-12-21 21:35:07 +00:00
QSE_SIZEOF(*run->inrec.flds) * max);
if (tmp == QSE_NULL)
{
2009-08-17 02:08:58 +00:00
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM, QSE_NULL);
return -1;
}
}
else
{
2008-12-21 21:35:07 +00:00
tmp = QSE_AWK_ALLOC (
run->awk, QSE_SIZEOF(*run->inrec.flds) * max);
if (tmp == QSE_NULL)
{
2009-08-17 02:08:58 +00:00
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM, QSE_NULL);
return -1;
}
2008-12-21 21:35:07 +00:00
if (run->inrec.flds != QSE_NULL)
{
2008-12-21 21:35:07 +00:00
QSE_MEMCPY (tmp, run->inrec.flds,
QSE_SIZEOF(*run->inrec.flds)*run->inrec.maxflds);
QSE_AWK_FREE (run->awk, run->inrec.flds);
}
}
run->inrec.flds = tmp;
run->inrec.maxflds = max;
}
lv = lv - 1; /* adjust the value to 0-based index */
2008-12-21 21:35:07 +00:00
qse_str_clear (&run->inrec.line);
for (i = 0; i < max; i++)
{
if (i > 0)
{
2008-12-21 21:35:07 +00:00
if (qse_str_ncat (
&run->inrec.line,
run->gbl.ofs.ptr,
run->gbl.ofs.len) == (qse_size_t)-1)
{
2009-08-17 02:08:58 +00:00
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM, QSE_NULL);
return -1;
}
}
if (i == lv)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* tmp;
run->inrec.flds[i].ptr =
2008-12-21 21:35:07 +00:00
QSE_STR_PTR(&run->inrec.line) +
QSE_STR_LEN(&run->inrec.line);
run->inrec.flds[i].len = len;
2008-12-21 21:35:07 +00:00
if (qse_str_ncat (
&run->inrec.line, str, len) == (qse_size_t)-1)
{
2009-08-17 02:08:58 +00:00
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM, QSE_NULL);
return -1;
}
tmp = qse_awk_rtx_makestrval (run, str,len);
2008-12-21 21:35:07 +00:00
if (tmp == QSE_NULL) return -1;
if (i < nflds)
qse_awk_rtx_refdownval (run, run->inrec.flds[i].val);
else run->inrec.nflds++;
run->inrec.flds[i].val = tmp;
qse_awk_rtx_refupval (run, tmp);
}
else if (i >= nflds)
{
run->inrec.flds[i].ptr =
2008-12-21 21:35:07 +00:00
QSE_STR_PTR(&run->inrec.line) +
QSE_STR_LEN(&run->inrec.line);
run->inrec.flds[i].len = 0;
2008-12-21 21:35:07 +00:00
if (qse_str_cat (
&run->inrec.line, QSE_T("")) == (qse_size_t)-1)
{
2009-08-17 02:08:58 +00:00
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM, QSE_NULL);
return -1;
}
/* qse_awk_rtx_refdownval should not be called over
* run->inrec.flds[i].val as it is not initialized
* to any valid values */
/*qse_awk_rtx_refdownval (run, run->inrec.flds[i].val);*/
2008-12-21 21:35:07 +00:00
run->inrec.flds[i].val = qse_awk_val_zls;
qse_awk_rtx_refupval (run, qse_awk_val_zls);
run->inrec.nflds++;
}
else
{
2008-12-21 21:35:07 +00:00
qse_awk_val_str_t* tmp;
2008-12-21 21:35:07 +00:00
tmp = (qse_awk_val_str_t*)run->inrec.flds[i].val;
run->inrec.flds[i].ptr =
2008-12-21 21:35:07 +00:00
QSE_STR_PTR(&run->inrec.line) +
QSE_STR_LEN(&run->inrec.line);
run->inrec.flds[i].len = tmp->len;
2008-12-21 21:35:07 +00:00
if (qse_str_ncat (&run->inrec.line,
tmp->ptr, tmp->len) == (qse_size_t)-1)
{
2009-08-17 02:08:58 +00:00
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM, QSE_NULL);
return -1;
}
}
}
v = qse_awk_rtx_getgbl (run, QSE_AWK_GBL_NF);
2008-12-21 21:35:07 +00:00
QSE_ASSERT (v->type == QSE_AWK_VAL_INT);
2008-12-21 21:35:07 +00:00
if (((qse_awk_val_int_t*)v)->val != max)
{
v = qse_awk_rtx_makeintval (run, (qse_long_t)max);
2008-12-21 21:35:07 +00:00
if (v == QSE_NULL) return -1;
qse_awk_rtx_refupval (run, v);
if (qse_awk_rtx_setgbl (run, QSE_AWK_GBL_NF, v) == -1)
{
qse_awk_rtx_refdownval (run, v);
return -1;
}
qse_awk_rtx_refdownval (run, v);
}
return 0;
}