diff --git a/Lua/Makefile b/Lua/Makefile index fc1ba14..3c9a745 100644 --- a/Lua/Makefile +++ b/Lua/Makefile @@ -26,9 +26,9 @@ O=-O3 ALL_FLAGS=$(CFLAGS) $(OSFLAGS) $(INCS) $(EXTRA) $(CWARN) $(G) $(O) ifeq ($(shell uname -s),Darwin) - MAKESO= $(CC) -bundle -undefined dynamic_lookup + MAKESO= $(CC) -bundle -undefined dynamic_lookup $(CFLAGS) $(OSFLAGS) $(EXTRA) $(CWARN) $(G) $(O) else - MAKESO= $(CC) -shared + MAKESO= $(CC) -shared $(CFLAGS) $(OSFLAGS) $(EXTRA) $(CWARN) $(G) $(O) endif all: bp.so diff --git a/Lua/lbp.c b/Lua/lbp.c index c1c3f61..7c5db3e 100644 --- a/Lua/lbp.c +++ b/Lua/lbp.c @@ -33,10 +33,8 @@ static void push_match(lua_State *L, match_t *m, const char *start); lua_State *cur_state = NULL; -static void match_error(pat_t *pat, const char *msg) +static void match_error(const char *msg) { - (void)pat; - recycle_all_matches(); lua_pushstring(cur_state, msg); lua_error(cur_state); } @@ -170,11 +168,13 @@ static int Lmatch(lua_State *L) match_t *m = NULL; int ret = 0; cur_state = L; - if (next_match_safe(&m, text+index-1, &text[textlen], pat, builtins, NULL, false, match_error)) { + bp_errhand_t old = bp_set_error_handler(match_error); + if (next_match(&m, text+index-1, &text[textlen], pat, builtins, NULL, false)) { push_match(L, m, text); stop_matching(&m); ret = 1; } + bp_set_error_handler(old); return ret; } @@ -209,12 +209,14 @@ static int Lreplace(lua_State *L) const char *prev = text; pat_t *rep_pat = maybe_replacement.value.pat; cur_state = L; - for (match_t *m = NULL; next_match_safe(&m, text, &text[textlen], rep_pat, builtins, NULL, false, match_error); ) { + bp_errhand_t old = bp_set_error_handler(match_error); + for (match_t *m = NULL; next_match(&m, text, &text[textlen], rep_pat, builtins, NULL, false); ) { fwrite(prev, sizeof(char), (size_t)(m->start - prev), out); fprint_match(out, text, m, NULL); prev = m->end; ++replacements; } + bp_set_error_handler(old); fwrite(prev, sizeof(char), (size_t)(&text[textlen] - prev), out); fflush(out); lua_pushlstring(L, buf, size); diff --git a/Lua/test.lua b/Lua/test.lua index d812009..48a2ffa 100644 --- a/Lua/test.lua +++ b/Lua/test.lua @@ -38,7 +38,7 @@ print("Testing parse errors:") local ok, msg = pcall(function() bp.match(".;//;;; wtf", "xxx") end) -if not ok then print(("\x1B[41;30mParse error:\x1B[0;1;31m %s\x1B[m\n"):format(msg)) end +if not ok then print(("Successfully got parse error: \"%s\"\n"):format(msg)) end print("Testing builtins:") print(bp.match("parens", "...(foo())...")) diff --git a/match.c b/match.c index 7e88a3c..a7b9799 100644 --- a/match.c +++ b/match.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,7 @@ typedef struct match_ctx_s { pat_t *defs; cache_t *cache; const char *start, *end; + jmp_buf error_jump; bool ignorecase; } match_ctx_t; @@ -49,13 +51,19 @@ typedef struct match_ctx_s { static match_t *unused_matches = NULL; static match_t *in_use_matches = NULL; -static void default_error_handler(pat_t *pat, const char *msg) { - (void)pat; +static void default_error_handler(const char *msg) { errx(EXIT_FAILURE, "%s", msg); } static bp_errhand_t error_handler = default_error_handler; +bp_errhand_t bp_set_error_handler(bp_errhand_t new_handler) +{ + bp_errhand_t old_handler = error_handler; + error_handler = new_handler; + return old_handler; +} + #define MATCHES(...) (match_t*[]){__VA_ARGS__, NULL} __attribute__((hot, nonnull(1,2,3))) @@ -63,16 +71,17 @@ static match_t *match(match_ctx_t *ctx, const char *str, pat_t *pat); __attribute__((returns_nonnull)) static match_t *new_match(pat_t *pat, const char *start, const char *end, match_t *children[]); +char *error_message = NULL; + __attribute__((format(printf,2,3))) -static inline void match_error(pat_t *pat, const char *fmt, ...) +static inline void match_error(match_ctx_t *ctx, const char *fmt, ...) { va_list args; va_start(args, fmt); - char buf[256]; - vsnprintf(buf, sizeof(buf)-1, fmt, args); + if (error_message) free(error_message); + vasprintf(&error_message, fmt, args); va_end(args); - if (error_handler) - error_handler(pat, buf); + longjmp(ctx->error_jump, 1); } static match_t *clone_match(match_t *m) @@ -214,11 +223,11 @@ void cache_destroy(match_ctx_t *ctx) // Look up a pattern definition by name from a definition pattern. // __attribute__((nonnull(2))) -static pat_t *_lookup_def(pat_t *defs, const char *name, size_t namelen) +static pat_t *_lookup_def(match_ctx_t *ctx, pat_t *defs, const char *name, size_t namelen) { while (defs) { if (defs->type == BP_CHAIN) { - pat_t *second = _lookup_def(defs->args.multiple.second, name, namelen); + pat_t *second = _lookup_def(ctx, defs->args.multiple.second, name, namelen); if (second) return second; defs = defs->args.multiple.first; } else if (defs->type == BP_DEFINITIONS) { @@ -226,7 +235,7 @@ static pat_t *_lookup_def(pat_t *defs, const char *name, size_t namelen) return defs->args.def.meaning; defs = defs->args.def.next_def; } else { - match_error(defs, "Invalid pattern type in definitions"); + match_error(ctx, "Invalid pattern type in definitions"); return NULL; } } @@ -240,7 +249,7 @@ __attribute__((nonnull)) pat_t *lookup_ctx(match_ctx_t *ctx, const char *name, size_t namelen) { for (; ctx; ctx = ctx->parent_ctx) { - pat_t *def = _lookup_def(ctx->defs, name, namelen); + pat_t *def = _lookup_def(ctx, ctx->defs, name, namelen); if (def) return def; } return NULL; @@ -667,7 +676,7 @@ static match_t *match(match_ctx_t *ctx, const char *str, pat_t *pat) pat_t *ref = lookup_ctx(ctx, pat->args.ref.name, pat->args.ref.len); if (ref == NULL) { - match_error(pat, "Unknown pattern: '%.*s'", (int)pat->args.ref.len, pat->args.ref.name); + match_error(ctx, "Unknown pattern: '%.*s'", (int)pat->args.ref.len, pat->args.ref.name); return NULL; } @@ -754,7 +763,7 @@ static match_t *match(match_ctx_t *ctx, const char *str, pat_t *pat) return new_match(pat, str, str, NULL); } default: { - match_error(pat, "Unknown pattern type: %u", pat->type); + match_error(ctx, "Unknown pattern type: %u", pat->type); return NULL; } } @@ -864,20 +873,22 @@ bool next_match(match_t **m, const char *start, const char *end, pat_t *pat, pat .ignorecase = ignorecase, .defs = defs, }; - *m = (pos <= end) ? _next_match(&ctx, pos, pat, skip) : NULL; - cache_destroy(&ctx); - return *m != NULL; -} + if (setjmp(ctx.error_jump) == 0) { + *m = (pos <= end) ? _next_match(&ctx, pos, pat, skip) : NULL; + cache_destroy(&ctx); + } else { + recycle_all_matches(); + cache_destroy(&ctx); + *m = NULL; + if (error_handler) + error_handler(error_message); -// -// Wrapper for next_match() that sets an error handler -// -bool next_match_safe(match_t **m, const char *start, const char *end, pat_t *pat, pat_t *defs, pat_t *skip, bool ignorecase, bp_errhand_t errhand) -{ - error_handler = errhand; - bool ret = next_match(m, start, end, pat, defs, skip, ignorecase); - error_handler = default_error_handler; - return ret; + if (error_message) { + free(error_message); + error_message = NULL; + } + } + return *m != NULL; } // diff --git a/match.h b/match.h index cf4f977..9ead032 100644 --- a/match.h +++ b/match.h @@ -25,7 +25,7 @@ typedef struct match_s { struct match_s *_children[3]; } match_t; -typedef void (*bp_errhand_t)(pat_t *pat, const char *err_msg); +typedef void (*bp_errhand_t)(const char *err_msg); __attribute__((nonnull)) void recycle_match(match_t **at_m); @@ -33,7 +33,7 @@ size_t free_all_matches(void); size_t recycle_all_matches(void); bool next_match(match_t **m, const char *start, const char *end, pat_t *pat, pat_t *defs, pat_t *skip, bool ignorecase); #define stop_matching(m) next_match(m, NULL, NULL, NULL, NULL, NULL, 0) -bool next_match_safe(match_t **m, const char *start, const char *end, pat_t *pat, pat_t *defs, pat_t *skip, bool ignorecase, bp_errhand_t errhand); +bp_errhand_t bp_set_error_handler(bp_errhand_t handler); __attribute__((nonnull)) match_t *get_numbered_capture(match_t *m, int n); __attribute__((nonnull, pure))