diff --git a/qse/include/qse/awk/awk.h b/qse/include/qse/awk/awk.h index 3e057b98..8686cbf4 100644 --- a/qse/include/qse/awk/awk.h +++ b/qse/include/qse/awk/awk.h @@ -1,5 +1,5 @@ /* - * $Id: awk.h 456 2011-05-12 14:55:53Z hyunghwan.chung $ + * $Id: awk.h 457 2011-05-12 16:16:57Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -53,6 +53,9 @@ * @example awk04.c * This programs shows how to qse_awk_rtx_call(). * + * @example awk10.c + * This programs shows how to manipuate a map using qse_awk_rtx_makemapval() + * and qse_awk_rtx_setmapvalfld(). */ /** @struct qse_awk_t @@ -1905,25 +1908,25 @@ qse_awk_val_t* qse_awk_rtx_makemapval ( * @return value @a v on success, #QSE_NULL on failure. */ qse_awk_val_t* qse_awk_rtx_setmapvalfld ( - qse_awk_rtx_t* rtx, - qse_awk_val_t* map, - qse_char_t* kptr, - qse_size_t klen, - qse_awk_val_t* v + qse_awk_rtx_t* rtx, + qse_awk_val_t* map, + const qse_char_t* kptr, + qse_size_t klen, + qse_awk_val_t* v ); /** * The qse_awk_rtx_setmapvalfld() function gets the field value in a map. * You must make sure that the type of @a map is #QSE_AWK_VAL_MAP. * If the field is not found, the function fails and sets the error number - * to #QSE_AWK_EINVAL. + * to #QSE_AWK_EINVAL. The function does not fail for other reasons. * @return field value on success, #QSE_NULL on failure. */ qse_awk_val_t* qse_awk_rtx_getmapvalfld ( - qse_awk_rtx_t* rtx, - qse_awk_val_t* map, - qse_char_t* kptr, - qse_size_t klen + qse_awk_rtx_t* rtx, + qse_awk_val_t* map, + const qse_char_t* kptr, + qse_size_t klen ); /** diff --git a/qse/lib/awk/Awk.cpp b/qse/lib/awk/Awk.cpp index 6e22c74a..9f6033f6 100644 --- a/qse/lib/awk/Awk.cpp +++ b/qse/lib/awk/Awk.cpp @@ -1,5 +1,5 @@ /* - * $Id: Awk.cpp 456 2011-05-12 14:55:53Z hyunghwan.chung $ + * $Id: Awk.cpp 457 2011-05-12 16:16:57Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -592,8 +592,8 @@ int Awk::Value::setIndexedVal (Run* r, const Index& idx, val_t* v) if (val->type != QSE_AWK_VAL_MAP) { - /* the previous value is not a map. - * a new map value needs to be created first */ + // the previous value is not a map. + // a new map value needs to be created first. val_t* map = qse_awk_rtx_makemapval (r->rtx); if (map == QSE_NULL) { @@ -602,24 +602,22 @@ int Awk::Value::setIndexedVal (Run* r, const Index& idx, val_t* v) } qse_awk_rtx_refupval (r->rtx, map); - qse_awk_rtx_refupval (r->rtx, v); -/* TODO: use qse_awk_rtx_setmapvalfld() */ - /* update the map with a given value */ - pair_t* pair = qse_htb_upsert ( - ((qse_awk_val_map_t*)map)->map, - (char_t*)idx.ptr, idx.len, v, 0); - if (pair == QSE_NULL) + // update the map with a given value + if (qse_awk_rtx_setmapvalfld ( + r->rtx, map, idx.ptr, idx.len, v) == QSE_NULL) { - qse_awk_rtx_refdownval (r->rtx, v); qse_awk_rtx_refdownval (r->rtx, map); - r->setError (QSE_AWK_ENOMEM); r->awk->retrieveError (r); return -1; } - if (run != QSE_NULL) - qse_awk_rtx_refdownval (run->rtx, val); + // increment the reference count of the value after + // it has been added to the map + qse_awk_rtx_refupval (r->rtx, v); + + // free the previous value + if (run) qse_awk_rtx_refdownval (run->rtx, val); run = r; val = map; @@ -639,19 +637,17 @@ int Awk::Value::setIndexedVal (Run* r, const Index& idx, val_t* v) return -1; } - qse_awk_rtx_refupval (r->rtx, v); - -/* TODO: use qse_awk_rtx_setmapvalfld() */ - pair_t* pair = qse_htb_upsert ( - ((qse_awk_val_map_t*)val)->map, - (char_t*)idx.ptr, idx.len, v, 0); - if (pair == QSE_NULL) + // update the map with a given value + if (qse_awk_rtx_setmapvalfld ( + r->rtx, val, idx.ptr, idx.len, v) == QSE_NULL) { - qse_awk_rtx_refdownval (r->rtx, v); - run->setError (QSE_AWK_ENOMEM); - run->awk->retrieveError (run); + r->awk->retrieveError (r); return -1; } + + // increment the reference count of the value after + // it has been added to the map + qse_awk_rtx_refupval (r->rtx, v); } return 0; @@ -665,8 +661,7 @@ int Awk::Value::setIndexedInt (const Index& idx, long_t v) int Awk::Value::setIndexedInt (Run* r, const Index& idx, long_t v) { - val_t* tmp; - tmp = qse_awk_rtx_makeintval (r->rtx, v); + val_t* tmp = qse_awk_rtx_makeintval (r->rtx, v); if (tmp == QSE_NULL) { r->awk->retrieveError (r); @@ -688,8 +683,7 @@ int Awk::Value::setIndexedReal (const Index& idx, real_t v) int Awk::Value::setIndexedReal (Run* r, const Index& idx, real_t v) { - val_t* tmp; - tmp = qse_awk_rtx_makerealval (r->rtx, v); + val_t* tmp = qse_awk_rtx_makerealval (r->rtx, v); if (tmp == QSE_NULL) { r->awk->retrieveError (r); @@ -768,7 +762,8 @@ int Awk::Value::getIndexed (const Index& idx, Value* v) const } // get the value from the map. - val_t* fv = qse_awk_rtx_getmapvalfld (val, idx.ptr, idx.len); + val_t* fv = qse_awk_rtx_getmapvalfld ( + run->rtx, val, (char_t*)idx.ptr, idx.len); // the key is not found. it is not an error. v is just nil if (fv == QSE_NULL) @@ -779,21 +774,6 @@ int Awk::Value::getIndexed (const Index& idx, Value* v) const // if v.set fails, it should return an error return v->setVal (run, fv); - -#if 0 - qse_awk_val_map_t* m = (qse_awk_val_map_t*)val; - pair_t* pair = qse_htb_search (m->map, idx.ptr, idx.len); - - // the key is not found. it is not an error. v is just nil - if (pair == QSE_NULL) - { - v->clear (); - return 0; - } - - // if v.set fails, it should return an error - return v->setVal (run, (val_t*)QSE_HTB_VPTR(pair)); -#endif } Awk::Value::IndexIterator Awk::Value::getFirstIndex (Index* idx) const @@ -834,57 +814,6 @@ Awk::Value::IndexIterator Awk::Value::getNextIndex ( return IndexIterator (pair, buckno); } -#if 0 -int Awk::Argument::getFirstIndex (Awk::Argument& val) const -{ - val.clear (); - - if (this->val == QSE_NULL) return -1; - if (this->val->type != QSE_AWK_VAL_MAP) return -1; - - qse_size_t buckno; - qse_awk_val_map_t* m = (qse_awk_val_map_t*)this->val; - pair_t* pair = qse_htb_getfirstpair (m->map, &buckno); - if (pair == QSE_NULL) return 0; // no more key - - if (val.init ( - (qse_char_t*)QSE_HTB_KPTR(pair), - QSE_HTB_KLEN(pair)) == -1) return -1; - - // reuse the string field as an interator. - this->str.ptr = (char_t*)pair; - this->str.len = buckno; - - return 1; -} - -int Awk::Argument::getNextIndex (Awk::Argument& val) const -{ - val.clear (); - - if (this->val == QSE_NULL) return -1; - if (this->val->type != QSE_AWK_VAL_MAP) return -1; - - qse_awk_val_map_t* m = (qse_awk_val_map_t*)this->val; - - pair_t* pair = (pair_t*)this->str.ptr; - qse_size_t buckno = this->str.len; - - pair = qse_htb_getnextpair (m->map, pair, &buckno); - if (pair == QSE_NULL) return 0; - - if (val.init ( - (qse_char_t*)QSE_HTB_KPTR(pair), - QSE_HTB_KLEN(pair)) == -1) return -1; - - // reuse the string field as an interator. - this->str.ptr = (char_t*)pair; - this->str.len = buckno; - return 1; -} - -#endif - ////////////////////////////////////////////////////////////////// // Awk::Run ////////////////////////////////////////////////////////////////// diff --git a/qse/lib/awk/val.c b/qse/lib/awk/val.c index cbe7e6ec..f10b5616 100644 --- a/qse/lib/awk/val.c +++ b/qse/lib/awk/val.c @@ -1,5 +1,5 @@ /* - * $Id: val.c 456 2011-05-12 14:55:53Z hyunghwan.chung $ + * $Id: val.c 457 2011-05-12 16:16:57Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -466,7 +466,7 @@ qse_awk_val_t* qse_awk_rtx_makemapval (qse_awk_rtx_t* rtx) qse_awk_val_t* qse_awk_rtx_setmapvalfld ( qse_awk_rtx_t* rtx, qse_awk_val_t* map, - qse_char_t* kptr, qse_size_t klen, qse_awk_val_t* v) + const qse_char_t* kptr, qse_size_t klen, qse_awk_val_t* v) { QSE_ASSERT (map->type == QSE_AWK_VAL_MAP); @@ -480,7 +480,7 @@ qse_awk_val_t* qse_awk_rtx_setmapvalfld ( if (qse_htb_upsert ( ((qse_awk_val_map_t*)map)->map, - kptr, klen, v, 0) == QSE_NULL) + (qse_char_t*)kptr, klen, v, 0) == QSE_NULL) { qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, QSE_NULL); return QSE_NULL; @@ -497,7 +497,7 @@ qse_awk_val_t* qse_awk_rtx_setmapvalfld ( qse_awk_val_t* qse_awk_rtx_getmapvalfld ( qse_awk_rtx_t* rtx, qse_awk_val_t* map, - qse_char_t* kptr, qse_size_t klen) + const qse_char_t* kptr, qse_size_t klen) { qse_htb_pair_t* pair; diff --git a/qse/samples/awk/Makefile.am b/qse/samples/awk/Makefile.am index 00a5c186..2b4d5bca 100644 --- a/qse/samples/awk/Makefile.am +++ b/qse/samples/awk/Makefile.am @@ -5,7 +5,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/include \ -I$(includedir) -bin_PROGRAMS = awk01 awk02 awk03 awk04 awk09 +bin_PROGRAMS = awk01 awk02 awk03 awk04 awk09 awk10 LDFLAGS = -L../../lib/cmn -L../../lib/awk LDADD = -lqseawk -lqsecmn $(LIBM) @@ -15,6 +15,7 @@ awk02_SOURCES = awk02.c awk03_SOURCES = awk03.c awk04_SOURCES = awk04.c awk09_SOURCES = awk09.c +awk10_SOURCES = awk10.c if ENABLE_CXX diff --git a/qse/samples/awk/Makefile.in b/qse/samples/awk/Makefile.in index 17ba1a5b..90eb232d 100644 --- a/qse/samples/awk/Makefile.in +++ b/qse/samples/awk/Makefile.in @@ -35,7 +35,7 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = awk01$(EXEEXT) awk02$(EXEEXT) awk03$(EXEEXT) \ - awk04$(EXEEXT) awk09$(EXEEXT) $(am__EXEEXT_1) + awk04$(EXEEXT) awk09$(EXEEXT) awk10$(EXEEXT) $(am__EXEEXT_1) @ENABLE_CXX_TRUE@am__append_1 = awk05 awk06 awk07 awk08 subdir = samples/awk DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in @@ -96,6 +96,10 @@ am_awk09_OBJECTS = awk09.$(OBJEXT) awk09_OBJECTS = $(am_awk09_OBJECTS) awk09_LDADD = $(LDADD) awk09_DEPENDENCIES = $(am__DEPENDENCIES_1) +am_awk10_OBJECTS = awk10.$(OBJEXT) +awk10_OBJECTS = $(am_awk10_OBJECTS) +awk10_LDADD = $(LDADD) +awk10_DEPENDENCIES = $(am__DEPENDENCIES_1) DEFAULT_INCLUDES = depcomp = $(SHELL) $(top_srcdir)/ac/depcomp am__depfiles_maybe = depfiles @@ -120,11 +124,12 @@ CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(awk01_SOURCES) $(awk02_SOURCES) $(awk03_SOURCES) \ $(awk04_SOURCES) $(awk05_SOURCES) $(awk06_SOURCES) \ - $(awk07_SOURCES) $(awk08_SOURCES) $(awk09_SOURCES) + $(awk07_SOURCES) $(awk08_SOURCES) $(awk09_SOURCES) \ + $(awk10_SOURCES) DIST_SOURCES = $(awk01_SOURCES) $(awk02_SOURCES) $(awk03_SOURCES) \ $(awk04_SOURCES) $(am__awk05_SOURCES_DIST) \ $(am__awk06_SOURCES_DIST) $(am__awk07_SOURCES_DIST) \ - $(am__awk08_SOURCES_DIST) $(awk09_SOURCES) + $(am__awk08_SOURCES_DIST) $(awk09_SOURCES) $(awk10_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -277,6 +282,7 @@ awk02_SOURCES = awk02.c awk03_SOURCES = awk03.c awk04_SOURCES = awk04.c awk09_SOURCES = awk09.c +awk10_SOURCES = awk10.c @ENABLE_CXX_TRUE@CXXLIB = -lqseawkxx -lqsecmnxx @ENABLE_CXX_TRUE@awk05_SOURCES = awk05.cpp @ENABLE_CXX_TRUE@awk06_SOURCES = awk06.cpp @@ -390,6 +396,9 @@ awk08$(EXEEXT): $(awk08_OBJECTS) $(awk08_DEPENDENCIES) awk09$(EXEEXT): $(awk09_OBJECTS) $(awk09_DEPENDENCIES) @rm -f awk09$(EXEEXT) $(LINK) $(awk09_OBJECTS) $(awk09_LDADD) $(LIBS) +awk10$(EXEEXT): $(awk10_OBJECTS) $(awk10_DEPENDENCIES) + @rm -f awk10$(EXEEXT) + $(LINK) $(awk10_OBJECTS) $(awk10_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) @@ -406,6 +415,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/awk07.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/awk08.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/awk09.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/awk10.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< diff --git a/qse/samples/awk/awk03.c b/qse/samples/awk/awk03.c index f0a22f0a..20131620 100644 --- a/qse/samples/awk/awk03.c +++ b/qse/samples/awk/awk03.c @@ -1,5 +1,5 @@ /* - * $Id: awk03.c 441 2011-04-22 14:28:43Z hyunghwan.chung $ + * $Id: awk03.c 457 2011-05-12 16:16:57Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -104,6 +104,8 @@ int main () { qse_fprintf (QSE_STDERR, QSE_T("error: %s\n"), qse_awk_rtx_geterrmsg(rtx)); + + qse_awk_rtx_refdownval (rtx, v); ret = -1; goto oops; } diff --git a/qse/samples/awk/awk04.c b/qse/samples/awk/awk04.c index 5746af5f..581320be 100644 --- a/qse/samples/awk/awk04.c +++ b/qse/samples/awk/awk04.c @@ -1,5 +1,5 @@ /* - * $Id: awk04.c 441 2011-04-22 14:28:43Z hyunghwan.chung $ + * $Id: awk04.c 457 2011-05-12 16:16:57Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -33,7 +33,7 @@ int main () qse_awk_parsestd_in_t psin; qse_char_t* str; qse_size_t len; - qse_awk_val_t* v; + qse_awk_val_t* rtv = QSE_NULL; qse_awk_val_t* arg[2] = { QSE_NULL, QSE_NULL }; int ret, i, opt; @@ -99,15 +99,15 @@ int main () } qse_awk_rtx_refupval (rtx, arg[1]); - v = qse_awk_rtx_call (rtx, QSE_T("pow"), arg, 2); - if (v == QSE_NULL) + rtv = qse_awk_rtx_call (rtx, QSE_T("pow"), arg, 2); + if (rtv == QSE_NULL) { qse_fprintf (QSE_STDERR, QSE_T("error: %s\n"), qse_awk_rtx_geterrmsg(rtx)); ret = -1; goto oops; } - str = qse_awk_rtx_valtocpldup (rtx, v, &len); + str = qse_awk_rtx_valtocpldup (rtx, rtv, &len); if (str == QSE_NULL) { qse_fprintf (QSE_STDERR, QSE_T("error: %s\n"), @@ -118,20 +118,19 @@ int main () qse_printf (QSE_T("[%.*s]\n"), (int)len, str); qse_awk_rtx_free (rtx, str); - /* clear the return value */ - qse_awk_rtx_refdownval (rtx, v); - oops: + /* clear the return value */ + if (rtv) qse_awk_rtx_refdownval (rtx, rtv); + /* dereference all arguments */ for (i = 0; i < QSE_COUNTOF(arg); i++) { - if (arg[i] != QSE_NULL) - qse_awk_rtx_refdownval (rtx, arg[i]); + if (arg[i]) qse_awk_rtx_refdownval (rtx, arg[i]); } /* destroy a runtime context */ - if (rtx != QSE_NULL) qse_awk_rtx_close (rtx); + if (rtx) qse_awk_rtx_close (rtx); /* destroy the processor */ - if (awk != QSE_NULL) qse_awk_close (awk); + if (awk) qse_awk_close (awk); return ret; } diff --git a/qse/samples/awk/awk10.c b/qse/samples/awk/awk10.c new file mode 100644 index 00000000..ce737d70 --- /dev/null +++ b/qse/samples/awk/awk10.c @@ -0,0 +1,170 @@ +/* + * $Id: awk04.c 441 2011-04-22 14:28:43Z hyunghwan.chung $ + * + Copyright 2006-2011 Chung, Hyung-Hwan. + This file is part of QSE. + + 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. + + 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. + + You should have received a copy of the GNU Lesser General Public + License along with QSE. If not, see . + */ + +#include +#include +#include + +static const qse_char_t* src = QSE_T( + "function dump(x) { for (k in x) print k \"=\" x[k]; x[\"f99\"]=\"os2\"; return x; }" +); + +int main () +{ + qse_awk_t* awk = QSE_NULL; + qse_awk_rtx_t* rtx = QSE_NULL; + qse_awk_parsestd_in_t psin; + qse_awk_val_t* rtv = QSE_NULL; + qse_awk_val_t* arg = QSE_NULL; + int ret, i, opt; + struct + { + const qse_char_t* kptr; + qse_size_t klen; + const qse_char_t* vptr; + } xxx[] = + { + { QSE_T("f0"), 2, QSE_T("linux") }, + { QSE_T("f1"), 2, QSE_T("openvms") }, + { QSE_T("f2"), 2, QSE_T("hpux") } + }; + + /* create a main processor */ + awk = qse_awk_openstd (0); + if (awk == QSE_NULL) + { + qse_fprintf (QSE_STDERR, QSE_T("error: cannot open awk\n")); + ret = -1; goto oops; + } + + opt = qse_awk_getoption(awk); + + /* don't allow BEGIN, END, pattern-action blocks */ + opt &= ~QSE_AWK_PABLOCK; + /* can assign a map to a variable */ + opt |= QSE_AWK_MAPTOVAR; + /* enable ** */ + opt |= QSE_AWK_EXTRAOPS; + + qse_awk_setoption (awk, opt); + + psin.type = QSE_AWK_PARSESTD_CP; + psin.u.cp = src; + + ret = qse_awk_parsestd (awk, &psin, QSE_NULL); + if (ret == -1) + { + qse_fprintf (QSE_STDERR, QSE_T("error: %s\n"), + qse_awk_geterrmsg(awk)); + goto oops; + } + + /* create a runtime context */ + rtx = qse_awk_rtx_openstd ( + awk, + 0, + QSE_T("awk10"), + QSE_NULL, /* stdin */ + QSE_NULL /* stdout */ + ); + if (rtx == QSE_NULL) + { + qse_fprintf (QSE_STDERR, QSE_T("error: %s\n"), + qse_awk_geterrmsg(awk)); + ret = -1; goto oops; + } + + /* prepare a argument to be a map */ + arg = qse_awk_rtx_makemapval (rtx); + if (arg == QSE_NULL) + { + qse_fprintf (QSE_STDERR, QSE_T("error: %s\n"), + qse_awk_rtx_geterrmsg(rtx)); + ret = -1; goto oops; + } + qse_awk_rtx_refupval (rtx, arg); + + /* insert some key/value pairs into the map */ + for (i = 0; i < QSE_COUNTOF(xxx); i++) + { + qse_awk_val_t* v, * fv; + + fv = qse_awk_rtx_makestrval0 (rtx, xxx[i].vptr); + if (fv == QSE_NULL) + { + qse_fprintf (QSE_STDERR, QSE_T("error: %s\n"), + qse_awk_rtx_geterrmsg(rtx)); + ret = -1; goto oops; + } + qse_awk_rtx_refupval (rtx, fv); + v = qse_awk_rtx_setmapvalfld (rtx, arg, xxx[i].kptr, xxx[i].klen, fv); + qse_awk_rtx_refdownval (rtx, fv); + if (v == QSE_NULL) + { + qse_fprintf (QSE_STDERR, QSE_T("error: %s\n"), + qse_awk_rtx_geterrmsg(rtx)); + ret = -1; goto oops; + } + } + + /* invoke the dump function */ + rtv = qse_awk_rtx_call (rtx, QSE_T("dump"), &arg, 1); + if (rtv == QSE_NULL) + { + qse_fprintf (QSE_STDERR, QSE_T("error: %s\n"), + qse_awk_rtx_geterrmsg(rtx)); + ret = -1; goto oops; + } + + /* print the return value */ + if (rtv->type == QSE_AWK_VAL_MAP) + { + qse_printf (QSE_T("ret [MAP]\n")); + } + else + { + qse_char_t* str; + qse_size_t len; + + str = qse_awk_rtx_valtocpldup (rtx, rtv, &len); + if (str == QSE_NULL) + { + qse_fprintf (QSE_STDERR, QSE_T("error: %s\n"), + qse_awk_rtx_geterrmsg(rtx)); + ret = -1; goto oops; + } + + qse_printf (QSE_T("ret [%.*s]\n"), (int)len, str); + qse_awk_rtx_free (rtx, str); + } + +oops: + /* clear the return value */ + if (rtv) qse_awk_rtx_refdownval (rtx, rtv); + + /* dereference the argument */ + if (arg) qse_awk_rtx_refdownval (rtx, arg); + + /* destroy a runtime context */ + if (rtx) qse_awk_rtx_close (rtx); + /* destroy the processor */ + if (awk) qse_awk_close (awk); + return ret; +}