diff --git a/qse/cmd/sed/sed.c b/qse/cmd/sed/sed.c index 3b23d838..63e236be 100644 --- a/qse/cmd/sed/sed.c +++ b/qse/cmd/sed/sed.c @@ -463,11 +463,17 @@ static void trace_exec (qse_sed_t* sed, qse_sed_exec_op_t op, const qse_sed_cmd_ break; #endif case QSE_SED_EXEC_MATCH: - qse_printf (QSE_T("matching address for [%c] at line %lu\n"), cmd->type, (unsigned long)cmd->loc.line); + qse_printf (QSE_T("matching address for [%c] in %s at line %lu\n"), + cmd->type, + (cmd->lid? cmd->lid: QSE_T("<>")), + (unsigned long)cmd->loc.line); break; case QSE_SED_EXEC_EXEC: - qse_printf (QSE_T("executing [%c] at line %lu\n"), cmd->type, (unsigned long)cmd->loc.line); + qse_printf (QSE_T("executing [%c] in %s at line %lu\n"), + cmd->type, + (cmd->lid? cmd->lid: QSE_T("<>")), + (unsigned long)cmd->loc.line); break; } } diff --git a/qse/include/qse/sed/Sed.hpp b/qse/include/qse/sed/Sed.hpp index 22f0c965..d6d49f07 100644 --- a/qse/include/qse/sed/Sed.hpp +++ b/qse/include/qse/sed/Sed.hpp @@ -267,6 +267,12 @@ public: const loc_t* loc = QSE_NULL ///< error location ); + const char_t* getCompileId () const; + + const char_t* setCompileId ( + const char_t* id + ); + /// /// The getConsoleLine() function returns the current line /// number from an input console. diff --git a/qse/include/qse/sed/sed.h b/qse/include/qse/sed/sed.h index 9853bb8c..45cdc8d8 100644 --- a/qse/include/qse/sed/sed.h +++ b/qse/include/qse/sed/sed.h @@ -130,7 +130,9 @@ struct qse_sed_adr_t struct qse_sed_cmd_t { qse_char_t type; - qse_sed_loc_t loc; + + const qse_char_t* lid; + qse_sed_loc_t loc; int negated; @@ -521,18 +523,40 @@ void qse_sed_setlformatter ( qse_sed_lformatter_t lformatter /**< text formatter */ ); +/** + * The qse_sed_getcompid() function returns the latest + * identifier successfully set with qse_sed_setcompid(). + */ +const qse_char_t* qse_sed_getcompid ( + qse_sed_t* sed +); + +/** + * The qse_sed_setcompid() functions duplicates a string + * pointed to by @a id and stores it internally to identify + * the script currently being compiled. The lid field of the + * current command being compiled in the script is set to the + * lastest identifer successfully set with this function. + * If this function fails, the location set in the command + * may be wrong. + */ +const qse_char_t* qse_sed_setcompid ( + qse_sed_t* sed, + const qse_char_t* id +); + /** * The qse_sed_getlinnum() function gets the current input line number. * @return current input line number */ -qse_size_t qse_sed_getlinnum ( +qse_size_t qse_sed_getlinenum ( qse_sed_t* sed /**< stream editor */ ); /** - * The qse_sed_setlinnum() function changes the current input line number. + * The qse_sed_setlinenum() function changes the current input line number. */ -void qse_sed_setlinnum ( +void qse_sed_setlinenum ( qse_sed_t* sed, /**< stream editor */ qse_size_t num /**< a line number */ ); diff --git a/qse/lib/sed/Sed.cpp b/qse/lib/sed/Sed.cpp index 7c925650..0535787f 100644 --- a/qse/lib/sed/Sed.cpp +++ b/qse/lib/sed/Sed.cpp @@ -112,7 +112,8 @@ Sed::loc_t Sed::getErrorLocation () const if (sed == QSE_NULL) { loc_t loc; - loc.line = 0; loc.colm = 0; + loc.line = 0; + loc.colm = 0; return loc; } return *qse_sed_geterrloc (sed); @@ -129,16 +130,26 @@ void Sed::setError (errnum_t err, const cstr_t* args, const loc_t* loc) qse_sed_seterror (sed, err, args, loc); } +const Sed::char_t* Sed::getCompileId () const +{ + return qse_sed_getcompid (this->sed); +} + +const Sed::char_t* Sed::setCompileId (const char_t* id) +{ + return qse_sed_setcompid (this->sed, id); +} + Sed::size_t Sed::getConsoleLine () { QSE_ASSERT (sed != QSE_NULL); - return qse_sed_getlinnum (sed); + return qse_sed_getlinenum (this->sed); } void Sed::setConsoleLine (size_t num) { QSE_ASSERT (sed != QSE_NULL); - qse_sed_setlinnum (sed, num); + qse_sed_setlinenum (this->sed, num); } Sed::ssize_t Sed::sin ( diff --git a/qse/lib/sed/sed.c b/qse/lib/sed/sed.c index c70edca6..8e7609f9 100644 --- a/qse/lib/sed/sed.c +++ b/qse/lib/sed/sed.c @@ -38,6 +38,7 @@ QSE_IMPLEMENT_COMMON_FUNCTIONS (sed) static void free_command (qse_sed_t* sed, qse_sed_cmd_t* cmd); static void free_all_command_blocks (qse_sed_t* sed); +static void free_all_cids (qse_sed_t* sed); static void free_appends (qse_sed_t* sed); static int emit_output (qse_sed_t* sed, int skipline); @@ -130,6 +131,7 @@ oops_1: void qse_sed_fini (qse_sed_t* sed) { free_all_command_blocks (sed); + free_all_cids (sed); qse_str_fini (&sed->e.txt.subst); qse_str_fini (&sed->e.txt.hold); @@ -582,6 +584,15 @@ static void free_command (qse_sed_t* sed, qse_sed_cmd_t* cmd) } } +static void free_all_cids (qse_sed_t* sed) +{ + while (sed->src.cid) + { + qse_sed_cid_t* next = sed->src.cid->next; + QSE_MMGR_FREE (sed->mmgr, sed->src.cid); + sed->src.cid = next; + } +} static QSE_INLINE int xdigit_to_num (qse_cint_t c) { @@ -1501,6 +1512,7 @@ static int get_command (qse_sed_t* sed, qse_sed_cmd_t* cmd) qse_cint_t c; c = CURSC (sed); + cmd->lid = sed->src.cid? ((const qse_char_t*)(sed->src.cid + 1)): QSE_NULL; cmd->loc = sed->src.loc; switch (c) { @@ -1739,20 +1751,13 @@ int qse_sed_comp (qse_sed_t* sed, qse_sed_io_fun_t inf) return -1; } - /* store the source code pointers */ - sed->src.fun = inf; - if (open_script_stream (sed) <= -1) return -1; - - sed->src.loc.line = 1; - sed->src.loc.colm = 0; - sed->src.cc = QSE_CHAR_EOF; - - NXTSC_GOTO (sed, c, oops); - /* free all the commands previously compiled */ free_all_command_blocks (sed); QSE_ASSERT (sed->cmd.lb == &sed->cmd.fb && sed->cmd.lb->len == 0); + /* free all the compilation identifiers */ + free_all_cids (sed); + /* clear the label table */ qse_map_clear (&sed->tmp.labs); @@ -1760,6 +1765,11 @@ int qse_sed_comp (qse_sed_t* sed, qse_sed_io_fun_t inf) sed->tmp.grp.level = 0; qse_str_clear (&sed->tmp.rex); + /* open script */ + sed->src.fun = inf; + if (open_script_stream (sed) <= -1) return -1; + NXTSC_GOTO (sed, c, oops); + while (1) { int n; @@ -3615,12 +3625,33 @@ void qse_sed_setlformatter (qse_sed_t* sed, qse_sed_lformatter_t lf) sed->lformatter = lf; } -qse_size_t qse_sed_getlinnum (qse_sed_t* sed) +const qse_char_t* qse_sed_getcompid (qse_sed_t* sed) +{ + return sed->src.cid? ((const qse_char_t*)(sed->src.cid + 1)): QSE_NULL; +} + +const qse_char_t* qse_sed_setcompid (qse_sed_t* sed, const qse_char_t* id) +{ + qse_sed_cid_t* cid; + qse_size_t len; + + len = qse_strlen (id); + cid = QSE_MMGR_ALLOC (sed->mmgr, QSE_SIZEOF(*cid) + ((len + 1) * QSE_SIZEOF(*id))); + if (cid == QSE_NULL) return QSE_NULL; + + cid->next = sed->src.cid; + sed->src.cid = cid; + qse_strcpy ((qse_char_t*)(cid + 1), id); + + return (const qse_char_t*)(cid + 1); +} + +qse_size_t qse_sed_getlinenum (qse_sed_t* sed) { return sed->e.in.num; } -void qse_sed_setlinnum (qse_sed_t* sed, qse_size_t num) +void qse_sed_setlinenum (qse_sed_t* sed, qse_size_t num) { sed->e.in.num = num; } @@ -3634,3 +3665,4 @@ void qse_sed_setexectracer (qse_sed_t* sed, qse_sed_exec_tracer_t tracer) { sed->e.tracer = tracer; } + diff --git a/qse/lib/sed/sed.h b/qse/lib/sed/sed.h index 0f6e4051..8227b0fa 100644 --- a/qse/lib/sed/sed.h +++ b/qse/lib/sed/sed.h @@ -55,6 +55,12 @@ struct qse_sed_cmd_blk_t qse_sed_cmd_blk_t* next; }; +typedef struct qse_sed_cid_t qse_sed_cid_t; +struct qse_sed_cid_t +{ + qse_sed_cid_t* next; +}; + /** * The qse_sed_t type defines a stream editor */ @@ -88,6 +94,7 @@ struct qse_sed_t qse_char_t buf[1024]; int eof; + qse_sed_cid_t* cid; qse_sed_loc_t loc; /**< location */ qse_cint_t cc; /**< last character read */ const qse_char_t* ptr; /**< beginning of the source text */ diff --git a/qse/lib/sed/std.c b/qse/lib/sed/std.c index 8f8b5b0d..f168bfec 100644 --- a/qse/lib/sed/std.c +++ b/qse/lib/sed/std.c @@ -45,6 +45,8 @@ struct xtn_t struct { xtn_in_t in; + qse_char_t last; + int newline_squeezed; } s; struct { @@ -54,6 +56,44 @@ struct xtn_t }; +static int int_to_str (qse_size_t val, qse_char_t* buf, qse_size_t buflen) +{ + qse_size_t t; + qse_size_t rlen = 0; + + t = val; + if (t == 0) rlen++; + else + { + /* non-zero values */ + if (t < 0) { t = -t; rlen++; } + while (t > 0) { rlen++; t /= 10; } + } + + if (rlen >= buflen) return -1; /* buffer too small */ + + buf[rlen] = QSE_T('\0'); + + t = val; + if (t == 0) buf[0] = QSE_T('0'); + else + { + if (t < 0) t = -t; + + /* fill in the buffer with digits */ + while (t > 0) + { + buf[--rlen] = (qse_char_t)(t % 10) + QSE_T('0'); + t /= 10; + } + + /* insert the negative sign if necessary */ + if (val < 0) buf[--rlen] = QSE_T('-'); + } + + return 0; +} + qse_sed_t* qse_sed_openstd (qse_size_t xtnsize) { return qse_sed_openstdwithmmgr (QSE_MMGR_GETDFL(), xtnsize); @@ -151,7 +191,7 @@ static void close_main_stream ( static int open_input_stream ( qse_sed_t* sed, qse_sed_io_arg_t* arg, qse_sed_iostd_t* io, xtn_in_t* base) { - /*xtn_t* xtn = (xtn_t*) QSE_XTN (sed);*/ + xtn_t* xtn = (xtn_t*) QSE_XTN (sed); QSE_ASSERT (io != QSE_NULL); switch (io->type) @@ -185,6 +225,25 @@ static int open_input_stream ( return -1; } + + if (base == &xtn->s.in) + { + /* reset script location */ + if (io->type == QSE_SED_IOSTD_FILE) + { + qse_sed_setcompid (sed, io->u.file); + } + else + { + qse_char_t buf[64]; + buf[0] = (io->type == QSE_SED_IOSTD_MEM)? QSE_T('M'): QSE_T('S'); + buf[1] = QSE_T('#'); + if (int_to_str (io - xtn->s.in.ptr, &buf[2], QSE_COUNTOF(buf) - 2) >= 0) + qse_sed_setcompid (sed, buf); + } + sed->src.loc.line = 1; + sed->src.loc.colm = 1; + } return 0; } @@ -257,7 +316,6 @@ static qse_ssize_t read_input_stream ( qse_sed_iostd_t* io, * next; void* old, * new; qse_ssize_t n = 0; - int newline_forced = 0; if (len > QSE_TYPE_MAX(qse_ssize_t)) len = QSE_TYPE_MAX(qse_ssize_t); @@ -265,7 +323,14 @@ static qse_ssize_t read_input_stream ( { io = base->cur; + if (base == &xtn->s.in && xtn->s.newline_squeezed) + { + xtn->s.newline_squeezed = 0; + goto open_next; + } + QSE_ASSERT (io != QSE_NULL); + if (io->type == QSE_SED_IOSTD_MEM) { n = 0; @@ -285,15 +350,9 @@ static qse_ssize_t read_input_stream ( qse_sed_seterrnum (sed, QSE_SED_EIOFIL, &ea); } } - else if (newline_forced) + else if (base == &xtn->s.in) { - /* set the line number to 0 for the newline - * squeezed in. see the getnextsc() in sed.c - * to know how line and column numbers are - * incremented */ - sed->src.loc.line = 0; - sed->src.loc.colm = 0; - n += newline_forced; + xtn->s.last = buf[n-1]; } break; @@ -303,6 +362,16 @@ static qse_ssize_t read_input_stream ( /* == end of file on the current input stream == */ /* ============================================= */ + if (base == &xtn->s.in && xtn->s.last != QSE_T('\n')) + { + /* TODO: different line termination convension */ + buf[0] = QSE_T('\n'); + n = 1; + xtn->s.newline_squeezed = 1; + break; + } + + open_next: next = base->cur + 1; if (next->type == QSE_SED_IOSTD_NULL) { @@ -327,25 +396,18 @@ static qse_ssize_t read_input_stream ( n = -1; break; } + + /* successfuly opened the next input stream */ new = arg->handle; arg->handle = old; + + /* close the previous stream */ close_main_stream (sed, arg, io); arg->handle = new; + base->cur++; - - if (base == &xtn->s.in && !newline_forced) - { - /* == ONLY FOR A SCRIPT STREAM == - * squeeze in a new line in case the previous script - * stream doesn't end with a line terminator.*/ - - /* TODO: support different line terminator */ - buf[0] = QSE_T('\n'); - buf++; len--; - newline_forced = 1; - } } while (1);