WIP implementation of setjmp/longjmp recovery

This commit is contained in:
Bruce Hill 2021-09-23 13:38:20 -07:00
parent 55ff8ec663
commit cf99abb852
4 changed files with 45 additions and 12 deletions

2
bp.c
View File

@ -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")) {

View File

@ -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
View File

@ -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) {

View File

@ -92,6 +92,9 @@ typedef struct pat_s {
const char *at;
struct pat_s *fallback;
} leftrec;
struct {
const char *start, *end, *msg;
} error;
struct pat_s *pat;
} args;
size_t id;