From 50678c49734850356c2677c81f22eae44724b70f Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Sun, 5 Oct 2025 02:05:19 +0900 Subject: [PATCH] implemented a way for a console input handler to indicate medium switching --- lib/Hawk.hpp | 9 ++++++--- lib/Std.cpp | 49 ++++++++++++++++++++++++++-------------------- lib/hawk.h | 15 +++++++------- lib/rio.c | 25 ++++++++++++++++++++--- lib/std.c | 9 ++++++--- samples/hawk51.cpp | 2 +- 6 files changed, 71 insertions(+), 38 deletions(-) diff --git a/lib/Hawk.hpp b/lib/Hawk.hpp index cdfa361b..df2fcad2 100644 --- a/lib/Hawk.hpp +++ b/lib/Hawk.hpp @@ -621,8 +621,8 @@ public: const void* getHandle () const { return this->riod->handle; } void setHandle (void* handle) { this->riod->handle = handle; } - int getUflags () const { return this->riod->uflags; } - void setUflags (int uflags) { this->riod->uflags = uflags; } + hawk_uint16_t getUflags () const { return this->riod->uflags; } + void setUflags (hawk_uint16_t uflags) { this->riod->uflags = uflags; } operator Hawk* () const { return this->run->hawk; } operator hawk_t* () const @@ -775,7 +775,7 @@ public: /// The information set here is available in subsequent /// calls to other methods and are accessible with /// getHandle() and getUflags(). - virtual int open (Console& io) = 0; + virtual int open (Console& io) = 0; /// The close() function is called when the console /// is not needed any more. It must return 0 for success @@ -811,6 +811,9 @@ public: virtual int next (Console& io) = 0; }; + bool getSwitched() const { return this->riod->console_switched; } + void setSwitched(bool v) { this->riod->console_switched = v; } + protected: Console (Run* run, hawk_rio_arg_t* riod); ~Console (); diff --git a/lib/Std.cpp b/lib/Std.cpp index b739ad76..47093be9 100644 --- a/lib/Std.cpp +++ b/lib/Std.cpp @@ -258,8 +258,8 @@ int HawkStd::build_argcv (Run* run) if (argv.setIndexedStr(Value::IntIndex(i), this->runarg.ptr[i].ptr, this->runarg.ptr[i].len, true) <= -1) return -1; } - run->setGlobal (this->gbl_argc, (hawk_int_t)this->runarg.len); - run->setGlobal (this->gbl_argv, argv); + run->setGlobal(this->gbl_argc, (hawk_int_t)this->runarg.len); + run->setGlobal(this->gbl_argv, argv); return 0; } @@ -423,7 +423,7 @@ int HawkStd::setioattr ( hawk_find_oochar_in_oochars(ptr[1], l[1], '\0') || hawk_find_oochar_in_oochars(ptr[2], l[2], '\0')) { - return ret.setInt ((hawk_int_t)-1); + return ret.setInt((hawk_int_t)-1); } int tmout; @@ -451,7 +451,7 @@ int HawkStd::setioattr ( nsec = fv - ioattr->tmout[tmout].sec; ioattr->tmout[tmout].nsec = HAWK_SEC_TO_NSEC(nsec); } - return ret.setInt ((hawk_int_t)0); + return ret.setInt((hawk_int_t)0); } #if defined(HAWK_OOCH_IS_UCH) else if (hawk_comp_oocstr(ptr[1], HAWK_T("codepage"), 1) == 0 || @@ -464,7 +464,7 @@ int HawkStd::setioattr ( else { cmgr = hawk_get_cmgr_by_name(ptr[2]); - if (cmgr == HAWK_NULL) return ret.setInt ((hawk_int_t)-1); + if (cmgr == HAWK_NULL) return ret.setInt((hawk_int_t)-1); } ioattr = find_or_make_ioattr(ptr[0], l[0]); @@ -478,7 +478,7 @@ int HawkStd::setioattr ( else { // unknown attribute name - return ret.setInt ((hawk_int_t)-1); + return ret.setInt((hawk_int_t)-1); } } @@ -506,21 +506,21 @@ int HawkStd::getioattr ( if ((tmout = timeout_code(ptr[1])) >= 0) { if (ioattr->tmout[tmout].nsec == 0) - xx = args[2].setInt ((hawk_int_t)ioattr->tmout[tmout].sec); + xx = args[2].setInt((hawk_int_t)ioattr->tmout[tmout].sec); else - xx = args[2].setFlt ((hawk_flt_t)ioattr->tmout[tmout].sec + HAWK_NSEC_TO_SEC((hawk_flt_t)ioattr->tmout[tmout].nsec)); + xx = args[2].setFlt((hawk_flt_t)ioattr->tmout[tmout].sec + HAWK_NSEC_TO_SEC((hawk_flt_t)ioattr->tmout[tmout].nsec)); } #if defined(HAWK_OOCH_IS_UCH) else if (hawk_comp_oocstr(ptr[1], HAWK_T("codepage"), 1) == 0 || hawk_comp_oocstr(ptr[1], HAWK_T("encoding"), 1) == 0) { - xx = args[2].setStr (ioattr->cmgr_name); + xx = args[2].setStr(ioattr->cmgr_name); } #endif } // unknown attribute name or errors - return ret.setInt ((hawk_int_t)xx); + return ret.setInt((hawk_int_t)xx); } #if defined(ENABLE_NWIO) @@ -782,7 +782,7 @@ int HawkStd::openFile (File& io) int HawkStd::closeFile (File& io) { - hawk_sio_close ((hawk_sio_t*)io.getHandle()); + hawk_sio_close((hawk_sio_t*)io.getHandle()); return 0; } @@ -946,6 +946,11 @@ nextfile: pair = hawk_map_search(map, ibuf, ibuflen); if (!pair) { + if (this->runarg_count < i_argc) + { + this->runarg_index++; + goto nextfile; + } if (this->runarg_count <= 0) goto console_open_stdin; return 0; } @@ -1004,7 +1009,7 @@ nextfile: if (hawk_rtx_setfilenamewithoochars(rtx, file, hawk_count_oocstr(file)) <= -1) { - hawk_sio_close (sio); + hawk_sio_close(sio); hawk_rtx_freevaloocstr (rtx, v_pair, as.ptr); return -1; } @@ -1075,7 +1080,7 @@ int HawkStd::open_console_out (Console& io) if (hawk_rtx_setofilenamewithoochars(rtx, file, hawk_count_oocstr(file)) == -1) { - hawk_sio_close (sio); + hawk_sio_close(sio); return -1; } @@ -1110,7 +1115,7 @@ int HawkStd::openConsole (Console& io) int HawkStd::closeConsole (Console& io) { - hawk_sio_close ((hawk_sio_t*)io.getHandle()); + hawk_sio_close((hawk_sio_t*)io.getHandle()); return 0; } @@ -1132,8 +1137,9 @@ hawk_ooi_t HawkStd::readConsole (Console& io, hawk_ooch_t* data, hawk_oow_t size return 0; } - if (sio) hawk_sio_close (sio); - ((Run*)io)->setGlobal (HAWK_GBL_FNR, (hawk_int_t)0); + if (sio) hawk_sio_close(sio); + ((Run*)io)->setGlobal(HAWK_GBL_FNR, (hawk_int_t)0); + io.setSwitched(true); // indicates that the console medium switched } return nn; @@ -1157,8 +1163,9 @@ hawk_ooi_t HawkStd::readConsoleBytes (Console& io, hawk_bch_t* data, hawk_oow_t return 0; } - if (sio) hawk_sio_close (sio); - ((Run*)io)->setGlobal (HAWK_GBL_FNR, (hawk_int_t)0); + if (sio) hawk_sio_close(sio); + ((Run*)io)->setGlobal(HAWK_GBL_FNR, (hawk_int_t)0); + io.setSwitched(true); // indicates that the data comes from a new medium } return nn; @@ -1194,7 +1201,7 @@ int HawkStd::nextConsole (Console& io) return 0; } - if (sio) hawk_sio_close (sio); + if (sio) hawk_sio_close(sio); return n; } @@ -1376,7 +1383,7 @@ int HawkStd::SourceFile::close (Data& io) { hawk_sio_t* sio = (hawk_sio_t*)io.getHandle(); hawk_sio_flush (sio); - hawk_sio_close (sio); + hawk_sio_close(sio); return 0; } @@ -1520,7 +1527,7 @@ int HawkStd::SourceString::close (Data& io) } else { - hawk_sio_close ((hawk_sio_t*)io.getHandle()); + hawk_sio_close((hawk_sio_t*)io.getHandle()); } return 0; } diff --git a/lib/hawk.h b/lib/hawk.h index 9c4572f9..47fbbafa 100644 --- a/lib/hawk.h +++ b/lib/hawk.h @@ -755,8 +755,9 @@ struct hawk_rio_arg_t hawk_rio_rwcmode_t rwcmode; /**< closing mode for rwpipe */ /* read-write. a user handler can do whatever it likes to do with these. */ - void* handle; /**< I/O handle set by a handler */ - int uflags; /**< user-flags set by a handler */ + void* handle; /**< I/O handle set by a handler */ + hawk_uint16_t uflags; /**< user-flags set by a handler */ + hawk_uint16_t console_switched; /**< set by a console handler if it has opened a new underlying medium and continued reading */ /*-- from here down, internal use only --*/ int type; @@ -771,15 +772,15 @@ struct hawk_rio_arg_t } u; hawk_oow_t pos; hawk_oow_t len; - int eof; - int eos; - int mbs; + unsigned int eof: 2; + unsigned int eos: 2; + unsigned int mbs: 2; } in; struct { - int eof; - int eos; + unsigned int eof: 2; + unsigned int eos: 2; } out; struct hawk_rio_arg_t* next; diff --git a/lib/rio.c b/lib/rio.c index f26ff6b1..c2eb2437 100644 --- a/lib/rio.c +++ b/lib/rio.c @@ -165,7 +165,7 @@ static int find_rio_in ( p->in.eof = 0; p->in.eos = 0; */ - p->in.mbs = mbs_if_new; + p->in.mbs = !!mbs_if_new; /* request to open the stream */ x = handler(rtx, HAWK_RIO_CMD_OPEN, p, HAWK_NULL, 0); @@ -453,14 +453,16 @@ int hawk_rtx_readio (hawk_rtx_t* rtx, hawk_in_type_t in_type, const hawk_ooch_t* break; } + /* used for console only. but reset it regardless of the stream type. + * it must be faster than checking the type and resetting it */ + p->console_switched = 0; x = handler(rtx, HAWK_RIO_CMD_READ, p, p->in.u.buf, HAWK_COUNTOF(p->in.u.buf)); if (x <= -1) { ret = -1; break; } - - if (x == 0) + else if (x == 0) { /* EOF reached */ p->in.eof = 1; @@ -508,6 +510,18 @@ int hawk_rtx_readio (hawk_rtx_t* rtx, hawk_in_type_t in_type, const hawk_ooch_t* p->in.len = x; p->in.pos = 0; + + /* the new data is a chunk from a new underlying stream. + * let's end the record even if it didn't match RS yet. + * for example, `hawk -v RS=separator -f script f1.txt f2.txt` + * the console handler is invoked over all the specified files. + * if `separator` is not found when the end of `f1.txt` is reached, + * `f2.txt` is opened and read. When the handler returns the + * first part of the second file, it must indicate this special + * condition. if it's not indicated, it goes on without breaking + * the record at the end of the first file. + */ + if (p->console_switched) break; } if (rrs.ptr == HAWK_NULL) @@ -820,6 +834,7 @@ int hawk_rtx_readiobytes (hawk_rtx_t* rtx, hawk_in_type_t in_type, const hawk_oo break; } + p->console_switched = 0; x = handler(rtx, HAWK_RIO_CMD_READ_BYTES, p, p->in.u.bbuf, HAWK_COUNTOF(p->in.u.bbuf)); if (x <= -1) { @@ -875,6 +890,10 @@ int hawk_rtx_readiobytes (hawk_rtx_t* rtx, hawk_in_type_t in_type, const hawk_oo p->in.len = x; p->in.pos = 0; + + /* the new data is a chunk from a new underlying medium. + * let's end the record even if it didn't match RS yet. */ + if (p->console_switched) break; } if (rrs.ptr == HAWK_NULL) diff --git a/lib/std.c b/lib/std.c index e34746f7..962375a3 100644 --- a/lib/std.c +++ b/lib/std.c @@ -2621,6 +2621,7 @@ static hawk_ooi_t hawk_rio_console (hawk_rtx_t* rtx, hawk_rio_cmd_t cmd, hawk_ri /* reset FNR to 0 here since the caller doesn't know that the file has changed. */ hawk_rtx_setgbl(rtx, HAWK_GBL_FNR, hawk_rtx_makeintval(rtx, 0)); + riod->console_switched = 1; } if (nn <= -1) set_rio_error(rtx, HAWK_EREAD, HAWK_T("unable to read"), hawk_sio_getpath((hawk_sio_t*)riod->handle)); @@ -2646,7 +2647,9 @@ static hawk_ooi_t hawk_rio_console (hawk_rtx_t* rtx, hawk_rio_cmd_t cmd, hawk_ri } if (sio) hawk_sio_close(sio); + hawk_rtx_setgbl(rtx, HAWK_GBL_FNR, hawk_rtx_makeintval(rtx, 0)); + riod->console_switched = 1; } if (nn <= -1) set_rio_error(rtx, HAWK_EREAD, HAWK_T("unable to read"), hawk_sio_getpath((hawk_sio_t*)riod->handle)); @@ -2887,7 +2890,7 @@ static int build_environ (hawk_rtx_t* rtx, int gbl_id, env_char_t* envarr[]) kptr = hawk_rtx_dupbtoucstr(rtx, envarr[count], &klen, 1); vptr = hawk_rtx_dupbtoucstr(rtx, eq + 1, &vlen, 1); - if (HAWK_UNLIKELY(!kptr || !vptr)) + if (HAWK_UNLIKELY(!kptr) || HAWK_UNLIKELY(!vptr)) { if (kptr) hawk_rtx_freemem(rtx, kptr); if (vptr) hawk_rtx_freemem(rtx, vptr); @@ -2904,7 +2907,7 @@ static int build_environ (hawk_rtx_t* rtx, int gbl_id, env_char_t* envarr[]) kptr = hawk_rtx_duputobcstr(rtx, envarr[count], &klen); vptr = hawk_rtx_duputobcstr(rtx, eq + 1, &vlen); - if (HAWK_UNLIKELY(!kptr || !vptr)) + if (HAWK_UNLIKELY(!kptr) || HAWK_UNLIKELY(!vptr)) { if (kptr) hawk_rtx_freemem(rtx, kptr); if (vptr) hawk_rtx_freeme(rtx, vptr): @@ -2967,7 +2970,7 @@ static int build_environ (hawk_rtx_t* rtx, int gbl_id, env_char_t* envarr[]) } } - if (hawk_rtx_setgbl(rtx, gbl_id, v_env) == -1) + if (hawk_rtx_setgbl(rtx, gbl_id, v_env) <= -1) { hawk_rtx_refdownval(rtx, v_env); return -1; diff --git a/samples/hawk51.cpp b/samples/hawk51.cpp index fe5272e1..7406dd9f 100644 --- a/samples/hawk51.cpp +++ b/samples/hawk51.cpp @@ -481,11 +481,11 @@ static int hawk_main (MyHawk& hawk, int argc, hawk_bch_t* argv[]) if (hawk.exec(&ret, cmdline.argv, cmdline.argc) <= -1) { print_error(hawk); + free_args_for_exec(&cmdline); return -1; } free_args_for_exec(&cmdline); - return 0; }