WIP implementation of setjmp/longjmp recovery
This commit is contained in:
parent
55ff8ec663
commit
cf99abb852
2
bp.c
2
bp.c
@ -463,6 +463,8 @@ int main(int argc, char *argv[])
|
||||
file_t *arg_file = spoof_file(&loaded_files, "<pattern argument>", flag, -1);
|
||||
pat_t *p = bp_pattern(arg_file, arg_file->start);
|
||||
if (!p) file_err(arg_file, arg_file->start, arg_file->end, "Failed to compile this part of the argument");
|
||||
if (p->type == BP_ERROR)
|
||||
file_err(arg_file, p->args.error.start, p->args.error.end, p->args.error.msg);
|
||||
if (after_spaces(p->end, true) < arg_file->end) file_err(arg_file, p->end, arg_file->end, "Failed to compile this part of the argument");
|
||||
pattern = chain_together(arg_file, pattern, p);
|
||||
} else if (FLAG("-w") || FLAG("--word")) {
|
||||
|
42
pattern.c
42
pattern.c
@ -7,6 +7,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include "files.h"
|
||||
#include "pattern.h"
|
||||
@ -18,6 +19,29 @@ static pat_t *bp_pattern_nl(file_t *f, const char *str, bool allow_nl);
|
||||
__attribute__((nonnull))
|
||||
static pat_t *bp_simplepattern(file_t *f, const char *str);
|
||||
|
||||
// For error-handling purposes, use setjmp/longjmp to break out of deeply
|
||||
// recursive function calls when a parse error occurs.
|
||||
bool is_in_try_catch = false;
|
||||
static jmp_buf err_jmp;
|
||||
pat_t *err_pat = NULL;
|
||||
|
||||
#define __TRY_PATTERN__ bool was_in_try_catch = is_in_try_catch; \
|
||||
if (!is_in_try_catch) { is_in_try_catch = true; if (setjmp(err_jmp)) return err_pat; }
|
||||
#define __END_TRY_PATTERN__ if (!was_in_try_catch) is_in_try_catch = false;
|
||||
|
||||
static inline void parse_err(file_t *f, const char *start, const char *end, const char *msg)
|
||||
{
|
||||
if (!is_in_try_catch) {
|
||||
fprintf(stderr, "Parse error: %s\n%.*s\n", msg, (int)(end-start), start);
|
||||
exit(1);
|
||||
}
|
||||
err_pat = new_pat(f, start, end, 0, 0, BP_ERROR);
|
||||
err_pat->args.error.start = start;
|
||||
err_pat->args.error.end = end;
|
||||
err_pat->args.error.msg = msg;
|
||||
longjmp(err_jmp, 1);
|
||||
}
|
||||
|
||||
//
|
||||
// Allocate a new pattern for this file (ensuring it will be automatically
|
||||
// freed when the file is freed)
|
||||
@ -67,9 +91,6 @@ static pat_t *expand_chain(file_t *f, pat_t *first, bool allow_nl)
|
||||
pat_t *second = bp_simplepattern(f, str);
|
||||
if (second == NULL) return first;
|
||||
second = expand_chain(f, second, allow_nl);
|
||||
if (second->end <= first->end)
|
||||
file_err(f, second->end, second->end,
|
||||
"This chain is not parsing properly");
|
||||
return chain_together(f, first, second);
|
||||
}
|
||||
|
||||
@ -90,7 +111,7 @@ static pat_t *expand_replacements(file_t *f, pat_t *replace_pat, bool allow_nl)
|
||||
for (; str < f->end && *str != closequote; str = next_char(str, f->end)) {
|
||||
if (*str == '\\') {
|
||||
if (!str[1] || str[1] == '\n')
|
||||
file_err(f, str, str+1,
|
||||
parse_err(f, str, str+1,
|
||||
"There should be an escape sequence after this backslash.");
|
||||
str = next_char(str, f->end);
|
||||
}
|
||||
@ -130,7 +151,7 @@ static pat_t *expand_choices(file_t *f, pat_t *first, bool allow_nl)
|
||||
if (matchstr(&str, "=>", allow_nl))
|
||||
second = expand_replacements(f, second ? second : new_pat(f, str-2, str-2, 0, 0, BP_STRING), allow_nl);
|
||||
if (!second)
|
||||
file_err(f, str, str, "There should be a pattern here after a '/'");
|
||||
parse_err(f, str, str, "There should be a pattern here after a '/'");
|
||||
second = expand_choices(f, second, allow_nl);
|
||||
return either_pat(f, first, second);
|
||||
}
|
||||
@ -221,7 +242,7 @@ static pat_t *_bp_simplepattern(file_t *f, const char *str)
|
||||
pat_t *all = NULL;
|
||||
do { // Comma-separated items:
|
||||
if (str >= f->end || !*str || *str == '\n')
|
||||
file_err(f, str, str, "There should be a character here after the '`'");
|
||||
parse_err(f, str, str, "There should be a character here after the '`'");
|
||||
|
||||
const char *c1_loc = str;
|
||||
str = next_char(c1_loc, f->end);
|
||||
@ -490,6 +511,7 @@ static pat_t *_bp_simplepattern(file_t *f, const char *str)
|
||||
//
|
||||
pat_t *bp_stringpattern(file_t *f, const char *str)
|
||||
{
|
||||
__TRY_PATTERN__
|
||||
pat_t *ret = NULL;
|
||||
while (str < f->end) {
|
||||
char *start = (char*)str;
|
||||
@ -518,6 +540,7 @@ pat_t *bp_stringpattern(file_t *f, const char *str)
|
||||
(void)matchchar(&str, ';', false);
|
||||
}
|
||||
}
|
||||
__END_TRY_PATTERN__
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -562,6 +585,7 @@ pat_t *bp_replacement(file_t *f, pat_t *replacepat, const char *replacement)
|
||||
pat_t *pat = new_pat(f, replacepat->start, replacepat->end, replacepat->min_matchlen, replacepat->max_matchlen, BP_REPLACE);
|
||||
pat->args.replace.pat = replacepat;
|
||||
const char *p = replacement;
|
||||
__TRY_PATTERN__
|
||||
for (; p < f->end; p++) {
|
||||
if (*p == '\\') {
|
||||
if (!p[1] || p[1] == '\n')
|
||||
@ -569,6 +593,7 @@ pat_t *bp_replacement(file_t *f, pat_t *replacepat, const char *replacement)
|
||||
++p;
|
||||
}
|
||||
}
|
||||
__END_TRY_PATTERN__
|
||||
size_t rlen = (size_t)(p-replacement);
|
||||
char *rcpy = new(char[rlen + 1]);
|
||||
memcpy(rcpy, replacement, rlen);
|
||||
@ -592,7 +617,10 @@ static pat_t *bp_pattern_nl(file_t *f, const char *str, bool allow_nl)
|
||||
//
|
||||
pat_t *bp_pattern(file_t *f, const char *str)
|
||||
{
|
||||
return bp_pattern_nl(f, str, false);
|
||||
__TRY_PATTERN__
|
||||
pat_t *ret = bp_pattern_nl(f, str, false);
|
||||
__END_TRY_PATTERN__
|
||||
return ret;
|
||||
}
|
||||
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|
||||
|
10
print.c
10
print.c
@ -56,9 +56,9 @@ static void print_between(FILE *out, printer_t *pr, const char *start, const cha
|
||||
{
|
||||
file_t *f = pr->file;
|
||||
while (start < end) {
|
||||
size_t line_num = get_line_number(f, start);
|
||||
size_t line_num = f ? get_line_number(f, start) : 0;
|
||||
print_line_number(out, pr, line_num, color, 0);
|
||||
const char *eol = get_line(pr->file, line_num + 1);
|
||||
const char *eol = f ? get_line(f, line_num + 1) : end;
|
||||
if (!eol || eol > end) eol = end;
|
||||
if (color && color != current_color) {
|
||||
fprintf(out, "%s", color);
|
||||
@ -118,8 +118,8 @@ static void _print_match(FILE *out, printer_t *pr, match_t *m)
|
||||
{
|
||||
pr->pos = m->start;
|
||||
if (m->pat->type == BP_REPLACE) {
|
||||
size_t line = get_line_number(pr->file, m->start);
|
||||
size_t line_end = get_line_number(pr->file, m->end);
|
||||
size_t line = pr->file ? get_line_number(pr->file, m->start) : 0;
|
||||
size_t line_end = pr->file ? get_line_number(pr->file, m->end) : 0;
|
||||
|
||||
if (pr->use_color && current_color != color_replace) {
|
||||
fprintf(out, "%s", color_replace);
|
||||
@ -232,7 +232,7 @@ void print_match(FILE *out, printer_t *pr, match_t *m)
|
||||
current_color = color_normal;
|
||||
bool first = (pr->pos == NULL);
|
||||
if (first) { // First match printed:
|
||||
pr->pos = pr->file->start;
|
||||
pr->pos = pr->file ? pr->file->start : m->start;
|
||||
pr->needs_line_number = 1;
|
||||
}
|
||||
if (m) {
|
||||
|
Loading…
Reference in New Issue
Block a user