diff --git a/lib/rio.c b/lib/rio.c index 7fc96093..f26ff6b1 100644 --- a/lib/rio.c +++ b/lib/rio.c @@ -123,7 +123,7 @@ static int find_rio_in ( if (handler == HAWK_NULL) { /* no I/O handler provided */ - hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EIOUSER); + hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EIOUSER); return -1; } @@ -388,9 +388,9 @@ int hawk_rtx_readio (hawk_rtx_t* rtx, hawk_in_type_t in_type, const hawk_ooch_t* if (p->in.mbs) { if (name[0] == '\0') - hawk_rtx_seterrfmt (rtx, HAWK_NULL, HAWK_EPERM, HAWK_T("disallowed mixed mode input")); + hawk_rtx_seterrfmt(rtx, HAWK_NULL, HAWK_EPERM, HAWK_T("disallowed mixed mode input")); else - hawk_rtx_seterrfmt (rtx, HAWK_NULL, HAWK_EPERM, HAWK_T("disallowed mixed mode input on %js"), name); + hawk_rtx_seterrfmt(rtx, HAWK_NULL, HAWK_EPERM, HAWK_T("disallowed mixed mode input on %js"), name); return -1; } @@ -737,10 +737,16 @@ int hawk_rtx_readiobytes (hawk_rtx_t* rtx, hawk_in_type_t in_type, const hawk_oo hawk_rio_arg_t* p; hawk_rio_impl_t handler; int ret; + int esc_lq_rq; + int quoted; + hawk_bch_t esc, lq, rq; hawk_val_t* brs; hawk_bcs_t rrs; + hawk_val_t* bfs; + hawk_bcs_t ffs; + hawk_oow_t line_len = 0; hawk_bch_t c = '\0', pc; @@ -749,9 +755,9 @@ int hawk_rtx_readiobytes (hawk_rtx_t* rtx, hawk_in_type_t in_type, const hawk_oo if (!p->in.mbs) { if (name[0] == '\0') - hawk_rtx_seterrfmt (rtx, HAWK_NULL, HAWK_EPERM, HAWK_T("disallowed mixed mode input")); + hawk_rtx_seterrfmt(rtx, HAWK_NULL, HAWK_EPERM, HAWK_T("disallowed mixed mode input")); else - hawk_rtx_seterrfmt (rtx, HAWK_NULL, HAWK_EPERM, HAWK_T("disallowed mixed mode input on %js"), name); + hawk_rtx_seterrfmt(rtx, HAWK_NULL, HAWK_EPERM, HAWK_T("disallowed mixed mode input on %js"), name); return -1; } @@ -762,12 +768,35 @@ int hawk_rtx_readiobytes (hawk_rtx_t* rtx, hawk_in_type_t in_type, const hawk_oo brs = hawk_rtx_getgbl(rtx, HAWK_GBL_RS); hawk_rtx_refupval(rtx, brs); + bfs = hawk_rtx_getgbl(rtx, HAWK_GBL_FS); + hawk_rtx_refupval(rtx, bfs); + if (resolve_brs(rtx, brs, &rrs) <= -1) { hawk_rtx_refdownval(rtx, brs); return -1; } + if (resolve_brs(rtx, bfs, &ffs) <= -1) + { + hawk_rtx_refdownval(rtx, bfs); + hawk_rtx_refdownval(rtx, brs); + return -1; + } + + /* RS set to @nil, FS set to a special string starting with ?, followed by esc lq rq */ + esc_lq_rq = 0; + quoted = 0; + if (ffs.len == 5 && ffs.ptr[0] == '?' && !rrs.ptr) + { + esc = ffs.ptr[2]; + lq = ffs.ptr[3]; + rq = ffs.ptr[4]; + + esc_lq_rq = 1; + esc_lq_rq += (esc == lq && esc == rq); + } + ret = 1; /* call the I/O handler */ @@ -859,6 +888,27 @@ int hawk_rtx_readiobytes (hawk_rtx_t* rtx, hawk_in_type_t in_type, const hawk_oo c = p->in.u.bbuf[p->in.pos++]; end_pos = p->in.pos; + if (esc_lq_rq == 2) + { + /* if FS is something like [?,"""] and RS is @nil, + * it supports multi-line quoted vlaues. */ + if (quoted == 2) + { + quoted = (c == rq); + /* no continue here as c could be a new line */ + } + else if (quoted == 1) + { + if (c == rq) quoted = 2; + continue; + } + else if (c == lq) + { + quoted = 1; + continue; + } + } + /* TODO: handle different line terminator */ /* separate by a new line */ if (c == '\n') @@ -1044,6 +1094,7 @@ int hawk_rtx_readiobytes (hawk_rtx_t* rtx, hawk_in_type_t in_type, const hawk_oo } if (rrs.ptr && HAWK_RTX_GETVALTYPE(rtx, brs) != HAWK_VAL_MBS) hawk_rtx_freemem(rtx, rrs.ptr); + hawk_rtx_refdownval(rtx, bfs); hawk_rtx_refdownval(rtx, brs); return ret; @@ -1117,7 +1168,7 @@ static int prepare_for_write_io_data (hawk_rtx_t* rtx, hawk_out_type_t out_type, if (HAWK_UNLIKELY(!handler)) { /* no I/O handler provided */ - hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EIOUSER); + hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EIOUSER); return -1; } @@ -1261,7 +1312,7 @@ int hawk_rtx_flushio (hawk_rtx_t* rtx, hawk_out_type_t out_type, const hawk_ooch if (!handler) { /* no I/O handler provided */ - hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EIOUSER); + hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EIOUSER); return -1; } @@ -1286,7 +1337,7 @@ int hawk_rtx_flushio (hawk_rtx_t* rtx, hawk_out_type_t out_type, const hawk_ooch if (ok) return 0; /* there is no corresponding rio for name */ - hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EIONMNF); + hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EIONMNF); return -1; } @@ -1310,7 +1361,7 @@ int hawk_rtx_nextio_read (hawk_rtx_t* rtx, hawk_in_type_t in_type, const hawk_oo if (!handler) { /* no I/O handler provided */ - hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EIOUSER); + hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EIOUSER); return -1; } @@ -1324,7 +1375,7 @@ int hawk_rtx_nextio_read (hawk_rtx_t* rtx, hawk_in_type_t in_type, const hawk_oo { /* something is totally wrong */ HAWK_ASSERT(!"should never happen - cannot find the relevant rio entry"); - hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EINTERN); + hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EINTERN); return -1; } @@ -1379,7 +1430,7 @@ int hawk_rtx_nextio_write (hawk_rtx_t* rtx, hawk_out_type_t out_type, const hawk if (!handler) { /* no I/O handler provided */ - hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EIOUSER); + hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EIOUSER); return -1; } @@ -1394,7 +1445,7 @@ int hawk_rtx_nextio_write (hawk_rtx_t* rtx, hawk_out_type_t out_type, const hawk /* something is totally wrong */ HAWK_ASSERT(!"should never happen - cannot find the relevant rio entry"); - hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EINTERN); + hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EINTERN); return -1; } @@ -1443,7 +1494,7 @@ int hawk_rtx_closio_read (hawk_rtx_t* rtx, hawk_in_type_t in_type, const hawk_oo if (!handler) { /* no I/O handler provided */ - hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EIOUSER); + hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EIOUSER); return -1; } @@ -1459,7 +1510,7 @@ int hawk_rtx_closio_read (hawk_rtx_t* rtx, hawk_in_type_t in_type, const hawk_oo if (handler (rtx, HAWK_RIO_CMD_CLOSE, p, HAWK_NULL, 0) <= -1) { /* this is not a rtx-time error.*/ - hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EIOIMPL); + hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EIOIMPL); return -1; } } @@ -1477,7 +1528,7 @@ int hawk_rtx_closio_read (hawk_rtx_t* rtx, hawk_in_type_t in_type, const hawk_oo } /* the name given is not found */ - hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EIONMNF); + hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EIONMNF); return -1; } @@ -1500,7 +1551,7 @@ int hawk_rtx_closio_write (hawk_rtx_t* rtx, hawk_out_type_t out_type, const hawk if (HAWK_UNLIKELY(!handler)) { /* no io handler provided */ - hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EIOUSER); + hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EIOUSER); return -1; } @@ -1525,7 +1576,7 @@ int hawk_rtx_closio_write (hawk_rtx_t* rtx, hawk_out_type_t out_type, const hawk p = p->next; } - hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EIONMNF); + hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EIONMNF); return -1; } @@ -1614,7 +1665,7 @@ int hawk_rtx_closeio (hawk_rtx_t* rtx, const hawk_ooch_t* name, const hawk_ooch_ p = p->next; } - hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EIONMNF); + hawk_rtx_seterrnum(rtx, HAWK_NULL, HAWK_EIONMNF); return -1; } diff --git a/t/Makefile.am b/t/Makefile.am index 70bbc899..fb717f74 100644 --- a/t/Makefile.am +++ b/t/Makefile.am @@ -24,7 +24,8 @@ check_ERRORS = e-001.err ##noinst_SCRIPTS = $(check_SCRIPTS) EXTRA_DIST = $(check_SCRIPTS) $(check_ERRORS) tap.inc err.sh \ journal-toc.hawk journal-toc.in journal-toc.out journal-toc-html.out \ - bibtex-to-html.hawk bibtex-to-html.out + bibtex-to-html.hawk bibtex-to-html.out \ + fs-test.hawk fs-test.in fs-test.out check_PROGRAMS = t-001 t-002 t-003 t-004 t-005 t-006 t-007 t-008 t-009 diff --git a/t/Makefile.in b/t/Makefile.in index 20ff1d8f..3ae0c674 100644 --- a/t/Makefile.in +++ b/t/Makefile.in @@ -648,7 +648,8 @@ check_SCRIPTS = $(am__append_1) h-003.hawk h-004.hawk h-009.hawk check_ERRORS = e-001.err EXTRA_DIST = $(check_SCRIPTS) $(check_ERRORS) tap.inc err.sh \ journal-toc.hawk journal-toc.in journal-toc.out journal-toc-html.out \ - bibtex-to-html.hawk bibtex-to-html.out + bibtex-to-html.hawk bibtex-to-html.out \ + fs-test.hawk fs-test.in fs-test.out t_001_SOURCES = t-001.c tap.h t_001_CPPFLAGS = $(CPPFLAGS_COMMON) diff --git a/t/fs-test.hawk b/t/fs-test.hawk new file mode 100644 index 00000000..62f1df06 --- /dev/null +++ b/t/fs-test.hawk @@ -0,0 +1,9 @@ +BEGIN { + ## `FS` with a question mark(`?`) followed by four characters. the last three are equal. + FS="?,\"\"\""; +} + +{ + for (i = 0; i <= NF; i++) print i, "[" $i "]"; +} + diff --git a/t/fs-test.in b/t/fs-test.in new file mode 100644 index 00000000..225778e4 --- /dev/null +++ b/t/fs-test.in @@ -0,0 +1,8 @@ +"Product ID","Product Name","Description","Price","Available Sizes","Notes" +101,"Deluxe Widget","A versatile widget for various applications. Features include: +- Enhanced durability +- Multi-functional design +- Easy to use",29.99,"Small,Medium,Large","Customer feedback suggests excellent performance." +102,"Super Gadget","The ultimate gadget for tech enthusiasts.",49.99,"One Size","Limited stock, order soon!" +103,"Basic Tool Set","A comprehensive set of essential tools, including a hammer, screwdriver, and wrench. +Perfect for home DIY projects.",35.50,"N/A","Tools are made from high-quality steel." diff --git a/t/fs-test.out b/t/fs-test.out new file mode 100644 index 00000000..d4aae4db --- /dev/null +++ b/t/fs-test.out @@ -0,0 +1,36 @@ +0 ["Product ID","Product Name","Description","Price","Available Sizes","Notes"] +1 [Product ID] +2 [Product Name] +3 [Description] +4 [Price] +5 [Available Sizes] +6 [Notes] +0 [101,"Deluxe Widget","A versatile widget for various applications. Features include: +- Enhanced durability +- Multi-functional design +- Easy to use",29.99,"Small,Medium,Large","Customer feedback suggests excellent performance."] +1 [101] +2 [Deluxe Widget] +3 [A versatile widget for various applications. Features include: +- Enhanced durability +- Multi-functional design +- Easy to use] +4 [29.99] +5 [Small,Medium,Large] +6 [Customer feedback suggests excellent performance.] +0 [102,"Super Gadget","The ultimate gadget for tech enthusiasts.",49.99,"One Size","Limited stock, order soon!"] +1 [102] +2 [Super Gadget] +3 [The ultimate gadget for tech enthusiasts.] +4 [49.99] +5 [One Size] +6 [Limited stock, order soon!] +0 [103,"Basic Tool Set","A comprehensive set of essential tools, including a hammer, screwdriver, and wrench. +Perfect for home DIY projects.",35.50,"N/A","Tools are made from high-quality steel."] +1 [103] +2 [Basic Tool Set] +3 [A comprehensive set of essential tools, including a hammer, screwdriver, and wrench. +Perfect for home DIY projects.] +4 [35.50] +5 [N/A] +6 [Tools are made from high-quality steel.] diff --git a/t/h-003.hawk b/t/h-003.hawk index c1816e0e..b681ea2d 100644 --- a/t/h-003.hawk +++ b/t/h-003.hawk @@ -10,7 +10,7 @@ function are_files_identical(a, b) f1 = sys::open(a, sys::O_RDONLY); if (f1 <= -1) { - printf ("ERROR: unable to open %s\n", a); + printf("ERROR: unable to open %s\n", a); return -1; } @@ -18,7 +18,7 @@ function are_files_identical(a, b) if (f2 <= -1) { sys::close (a); - printf ("ERROR: unable to open %s\n", b); + printf("ERROR: unable to open %s\n", b); return -1; } @@ -34,8 +34,8 @@ function are_files_identical(a, b) if (sys::read(f2, y, 1) > 0) diff = 1; - sys::close (f2); - sys::close (f1); + sys::close(f2); + sys::close(f1); return !diff; } @@ -66,20 +66,21 @@ function run_test (x, more_opts, in_name, set_out_name, out_name) if (same <= 0) { ## don't delete the output file for review. - tap_fail (sprintf("%s[%d] %s - %s and %s differ", @SCRIPTNAME, @SCRIPTLINE, x, expf, outf)); + tap_fail(sprintf("%s[%d] %s - %s and %s differ", @SCRIPTNAME, @SCRIPTLINE, x, expf, outf)); } else { - tap_ok (sprintf("%s[%d]", @SCRIPTNAME, @SCRIPTLINE)); - sys::unlink (outf); + tap_ok(sprintf("%s[%d]", @SCRIPTNAME, @SCRIPTLINE)); + sys::unlink(outf); } } function main() { - run_test ("journal-toc", "", @nil, 0, @nil); - run_test ("journal-toc", "-vHTML=1", "journal-toc", 0, "journal-toc-html"); - run_test ("bibtex-to-html", "", "journal-toc", 1, "bibtex-to-html"); + run_test("journal-toc", "", @nil, 0, @nil); + run_test("journal-toc", "-vHTML=1", "journal-toc", 0, "journal-toc-html"); + run_test("bibtex-to-html", "", "journal-toc", 1, "bibtex-to-html"); + run_test("fs-test", "", "fs-test", 0, "fs-test"); tap_end (); }