Cleaned up and simplified global state setting stuff (e.g. --verbose)
This commit is contained in:
parent
8ff80b09cc
commit
b29060f38b
154
bp.c
154
bp.c
@ -39,10 +39,21 @@ static const char *usage = (
|
||||
" -c --context <context> set number of lines of context to print (all: the whole file, 0: only the match, 1: the line, N: N lines of context)\n"
|
||||
" -g --grammar <grammar file> use the specified file as a grammar\n");
|
||||
|
||||
// Flag-configurable options:
|
||||
#define USE_DEFAULT_CONTEXT -2
|
||||
#define ALL_CONTEXT -1
|
||||
static int print_color = 0;
|
||||
static int print_line_numbers = 0;
|
||||
static int context_lines = USE_DEFAULT_CONTEXT;
|
||||
static unsigned int print_color = 0;
|
||||
static unsigned int print_line_numbers = 0;
|
||||
static unsigned int ignorecase = 0;
|
||||
static unsigned int verbose = 0;
|
||||
static enum {
|
||||
MODE_NORMAL,
|
||||
MODE_LISTFILES,
|
||||
MODE_INPLACE,
|
||||
MODE_JSON,
|
||||
MODE_EXPLAIN,
|
||||
} mode = MODE_NORMAL;
|
||||
|
||||
__attribute__((nonnull))
|
||||
static char *getflag(const char *flag, char *argv[], int *i);
|
||||
@ -91,16 +102,16 @@ static int is_text_file(const char *filename)
|
||||
//
|
||||
// Print matches in JSON format.
|
||||
//
|
||||
static int print_matches_as_json(def_t *defs, file_t *f, vm_op_t *pattern, unsigned int flags)
|
||||
static int print_matches_as_json(def_t *defs, file_t *f, vm_op_t *pattern)
|
||||
{
|
||||
int matches = 0;
|
||||
for (match_t *m = NULL; (m = next_match(defs, f, m, pattern, flags)); ) {
|
||||
for (match_t *m = NULL; (m = next_match(defs, f, m, pattern, ignorecase)); ) {
|
||||
if (++matches > 1)
|
||||
printf(",\n");
|
||||
printf("{\"filename\":\"%s\",", f->filename ? f->filename : "-");
|
||||
printf("{\"filename\":\"%s\",", f->filename);
|
||||
printf("\"tree\":{\"rule\":\"text\",\"start\":%d,\"end\":%ld,\"children\":[",
|
||||
0, f->end - f->contents);
|
||||
json_match(f->contents, m, (flags & BP_VERBOSE) ? 1 : 0);
|
||||
json_match(f->contents, m, verbose);
|
||||
printf("]}}\n");
|
||||
}
|
||||
return matches;
|
||||
@ -109,10 +120,10 @@ static int print_matches_as_json(def_t *defs, file_t *f, vm_op_t *pattern, unsig
|
||||
//
|
||||
// Print matches in a visual explanation style
|
||||
//
|
||||
static int explain_matches(def_t *defs, file_t *f, vm_op_t *pattern, unsigned int flags)
|
||||
static int explain_matches(def_t *defs, file_t *f, vm_op_t *pattern)
|
||||
{
|
||||
int matches = 0;
|
||||
for (match_t *m = NULL; (m = next_match(defs, f, m, pattern, flags)); ) {
|
||||
for (match_t *m = NULL; (m = next_match(defs, f, m, pattern, ignorecase)); ) {
|
||||
if (++matches == 1) {
|
||||
if (print_color)
|
||||
printf("\033[0;1;4;33m%s\033[0m\n", f->filename);
|
||||
@ -130,21 +141,21 @@ static int explain_matches(def_t *defs, file_t *f, vm_op_t *pattern, unsigned in
|
||||
// Replace a file's contents with the text version of a match.
|
||||
// (Useful for replacements)
|
||||
//
|
||||
static int inplace_modify_file(def_t *defs, file_t *f, vm_op_t *pattern, int context, unsigned int flags)
|
||||
static int inplace_modify_file(def_t *defs, file_t *f, vm_op_t *pattern)
|
||||
{
|
||||
// Need to do this before matching:
|
||||
intern_file(f);
|
||||
|
||||
printer_t pr = {
|
||||
.file = f,
|
||||
.context_lines = context,
|
||||
.context_lines = context_lines,
|
||||
.use_color = 0,
|
||||
.print_line_numbers = 0,
|
||||
};
|
||||
|
||||
FILE *inplace_file = NULL; // Lazy-open this on the first match
|
||||
int matches = 0;
|
||||
for (match_t *m = NULL; (m = next_match(defs, f, m, pattern, flags)); ) {
|
||||
for (match_t *m = NULL; (m = next_match(defs, f, m, pattern, ignorecase)); ) {
|
||||
++matches;
|
||||
if (print_errors(&pr, m) > 0)
|
||||
exit(1);
|
||||
@ -166,18 +177,18 @@ static int inplace_modify_file(def_t *defs, file_t *f, vm_op_t *pattern, int con
|
||||
//
|
||||
// Print all the matches in a file.
|
||||
//
|
||||
static int print_matches(def_t *defs, file_t *f, vm_op_t *pattern, int context, unsigned int flags)
|
||||
static int print_matches(def_t *defs, file_t *f, vm_op_t *pattern)
|
||||
{
|
||||
static int printed_filenames = 0;
|
||||
int matches = 0;
|
||||
printer_t pr = {
|
||||
.file = f,
|
||||
.context_lines = context,
|
||||
.context_lines = context_lines,
|
||||
.use_color = print_color,
|
||||
.print_line_numbers = print_line_numbers,
|
||||
};
|
||||
|
||||
for (match_t *m = NULL; (m = next_match(defs, f, m, pattern, flags)); ) {
|
||||
for (match_t *m = NULL; (m = next_match(defs, f, m, pattern, ignorecase)); ) {
|
||||
if (print_errors(&pr, m) > 0)
|
||||
exit(1);
|
||||
|
||||
@ -205,27 +216,27 @@ static int print_matches(def_t *defs, file_t *f, vm_op_t *pattern, int context,
|
||||
// For a given filename, open the file and attempt to match the given pattern
|
||||
// against it, printing any results according to the flags.
|
||||
//
|
||||
static int process_file(def_t *defs, const char *filename, vm_op_t *pattern, int context, unsigned int flags)
|
||||
static int process_file(def_t *defs, const char *filename, vm_op_t *pattern)
|
||||
{
|
||||
file_t *f = load_file(NULL, filename);
|
||||
check(f, "Could not open file: %s", filename);
|
||||
|
||||
int matches = 0;
|
||||
if (flags & BP_EXPLAIN) {
|
||||
matches += explain_matches(defs, f, pattern, flags);
|
||||
} else if (flags & BP_LISTFILES) {
|
||||
match_t *m = next_match(defs, f, NULL, pattern, flags);
|
||||
if (mode == MODE_EXPLAIN) {
|
||||
matches += explain_matches(defs, f, pattern);
|
||||
} else if (mode == MODE_LISTFILES) {
|
||||
match_t *m = next_match(defs, f, NULL, pattern, ignorecase);
|
||||
if (m) {
|
||||
recycle_if_unused(&m);
|
||||
printf("%s\n", f->filename);
|
||||
matches += 1;
|
||||
}
|
||||
} else if (flags & BP_JSON) {
|
||||
matches += print_matches_as_json(defs, f, pattern, flags);
|
||||
} else if (flags & BP_INPLACE) {
|
||||
matches += inplace_modify_file(defs, f, pattern, context, flags);
|
||||
} else if (mode == MODE_JSON) {
|
||||
matches += print_matches_as_json(defs, f, pattern);
|
||||
} else if (mode == MODE_INPLACE) {
|
||||
matches += inplace_modify_file(defs, f, pattern);
|
||||
} else {
|
||||
matches += print_matches(defs, f, pattern, context, flags);
|
||||
matches += print_matches(defs, f, pattern);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_HEAP
|
||||
@ -240,33 +251,24 @@ static int process_file(def_t *defs, const char *filename, vm_op_t *pattern, int
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
unsigned int flags = 0;
|
||||
int context = USE_DEFAULT_CONTEXT;
|
||||
char *flag = NULL;
|
||||
char path[PATH_MAX] = {0};
|
||||
|
||||
def_t *defs = NULL;
|
||||
|
||||
file_t *loaded_files = NULL;
|
||||
|
||||
// Define an opcode that is just a reference to the rule `pattern`
|
||||
file_t *pat_file = spoof_file(&loaded_files, "<pattern>", "pattern");
|
||||
vm_op_t *pattern = bp_pattern(pat_file, pat_file->contents);
|
||||
vm_op_t *pattern = bp_pattern(loaded_files, pat_file->contents);
|
||||
|
||||
// Define an opcode that is just a reference to the rule `replacement`
|
||||
file_t *rep_file = spoof_file(&loaded_files, "<replacement>", "replacement");
|
||||
vm_op_t *replacement = bp_pattern(rep_file, rep_file->contents);
|
||||
|
||||
// Load builtins:
|
||||
if (access("/etc/xdg/bp/builtins.bp", R_OK) != -1) {
|
||||
file_t *f = load_file(&loaded_files, "/etc/xdg/bp/builtins.bp");
|
||||
defs = load_grammar(defs, f);
|
||||
}
|
||||
sprintf(path, "%s/.config/bp/builtins.bp", getenv("HOME"));
|
||||
if (access(path, R_OK) != -1) {
|
||||
file_t *f = load_file(&loaded_files, path);
|
||||
defs = load_grammar(defs, f);
|
||||
}
|
||||
file_t *xdg_file = load_file(&loaded_files, "/etc/xdg/bp/builtins.bp");
|
||||
if (xdg_file) defs = load_grammar(defs, xdg_file);
|
||||
file_t *local_file = load_file(&loaded_files, "%s/.config/bp/builtins.bp", getenv("HOME"));
|
||||
if (local_file) defs = load_grammar(defs, local_file);
|
||||
|
||||
int i, npatterns = 0;
|
||||
check(argc > 1, "%s", usage);
|
||||
@ -279,18 +281,18 @@ int main(int argc, char *argv[])
|
||||
printf("%s\n", usage);
|
||||
return 0;
|
||||
} else if (streq(argv[i], "--verbose")) {
|
||||
flags |= BP_VERBOSE;
|
||||
verbose = 1;
|
||||
} else if (streq(argv[i], "--explain")) {
|
||||
flags |= BP_EXPLAIN;
|
||||
mode = MODE_EXPLAIN;
|
||||
} else if (streq(argv[i], "--json")) {
|
||||
flags |= BP_JSON;
|
||||
mode = MODE_JSON;
|
||||
} else if (streq(argv[i], "--inplace")) {
|
||||
flags |= BP_INPLACE;
|
||||
context = ALL_CONTEXT;
|
||||
mode = MODE_INPLACE;
|
||||
context_lines = ALL_CONTEXT;
|
||||
} else if (streq(argv[i], "--ignore-case")) {
|
||||
flags |= BP_IGNORECASE;
|
||||
ignorecase = 1;
|
||||
} else if (streq(argv[i], "--list-files")) {
|
||||
flags |= BP_LISTFILES;
|
||||
mode = MODE_LISTFILES;
|
||||
} else if (FLAG("--replace") || FLAG("-r")) {
|
||||
// TODO: spoof file as sprintf("pattern => '%s'", flag)
|
||||
// except that would require handling edge cases like quotation marks etc.
|
||||
@ -299,17 +301,14 @@ int main(int argc, char *argv[])
|
||||
check(rep, "Replacement failed to compile: %s", flag);
|
||||
defs = with_def(defs, replace_file, strlen("replacement"), "replacement", rep);
|
||||
pattern = replacement;
|
||||
if (context == USE_DEFAULT_CONTEXT) context = 1;
|
||||
if (context_lines == USE_DEFAULT_CONTEXT)
|
||||
context_lines = ALL_CONTEXT;
|
||||
} else if (FLAG("--grammar") || FLAG("-g")) {
|
||||
file_t *f = load_file(&loaded_files, flag);
|
||||
if (f == NULL) {
|
||||
sprintf(path, "%s/.config/bp/%s.bp", getenv("HOME"), flag);
|
||||
f = load_file(&loaded_files, path);
|
||||
}
|
||||
if (f == NULL) {
|
||||
sprintf(path, "/etc/xdg/bp/%s.bp", flag);
|
||||
f = load_file(&loaded_files, path);
|
||||
}
|
||||
if (f == NULL)
|
||||
f = load_file(&loaded_files, "%s/.config/bp/%s.bp", getenv("HOME"), flag);
|
||||
if (f == NULL)
|
||||
f = load_file(&loaded_files, "/etc/xdg/bp/%s.bp", flag);
|
||||
check(f != NULL, "Couldn't find grammar: %s", flag);
|
||||
defs = load_grammar(defs, f); // Keep in memory for debug output
|
||||
} else if (FLAG("--define") || FLAG("-d")) {
|
||||
@ -347,19 +346,21 @@ int main(int argc, char *argv[])
|
||||
++npatterns;
|
||||
} else if (FLAG("--context") || FLAG("-c")) {
|
||||
if (streq(flag, "all"))
|
||||
context = ALL_CONTEXT;
|
||||
context_lines = ALL_CONTEXT;
|
||||
else if (streq(flag, "none"))
|
||||
context_lines = 0;
|
||||
else
|
||||
context = (int)strtol(flag, NULL, 10);
|
||||
context_lines = (int)strtol(flag, NULL, 10);
|
||||
} else if (argv[i][0] == '-' && argv[i][1] && argv[i][1] != '-') { // single-char flags
|
||||
for (char *c = &argv[i][1]; *c; ++c) {
|
||||
switch (*c) {
|
||||
case 'h': goto flag_help; // -h
|
||||
case 'v': flags |= BP_VERBOSE; break; // -v
|
||||
case 'e': flags |= BP_EXPLAIN; break; // -e
|
||||
case 'j': flags |= BP_JSON; break; // -j
|
||||
case 'I': flags |= BP_INPLACE; context = ALL_CONTEXT; break; // -I
|
||||
case 'i': flags |= BP_IGNORECASE; break; // -i
|
||||
case 'l': flags |= BP_LISTFILES; break; // -l
|
||||
case 'v': verbose = 1; break; // -v
|
||||
case 'e': mode = MODE_EXPLAIN; break; // -e
|
||||
case 'j': mode = MODE_JSON; break; // -j
|
||||
case 'I': mode = MODE_INPLACE; break; // -I
|
||||
case 'i': ignorecase = 1; break; // -i
|
||||
case 'l': mode = MODE_LISTFILES; break; // -l
|
||||
default:
|
||||
printf("Unrecognized flag: -%c\n\n%s\n", *c, usage);
|
||||
return 1;
|
||||
@ -379,22 +380,9 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (((flags & BP_JSON) != 0) + ((flags & BP_EXPLAIN) != 0) + ((flags & BP_LISTFILES) != 0) > 1) {
|
||||
printf("Please choose no more than one of the flags: -j/--json, -e/--explain, and -l/--list-files.\n"
|
||||
"They are mutually contradictory.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (context < 0) {
|
||||
if (context == USE_DEFAULT_CONTEXT) context = 1;
|
||||
else if (context != ALL_CONTEXT) context = 0;
|
||||
}
|
||||
|
||||
if (flags & BP_INPLACE && context != ALL_CONTEXT) {
|
||||
printf("--inplace and --context are mutually exclusive.\n"
|
||||
"Please drop one of the two arguments and try again.\n");
|
||||
return 1;
|
||||
}
|
||||
if (mode == MODE_INPLACE) context_lines = ALL_CONTEXT;
|
||||
if (context_lines == USE_DEFAULT_CONTEXT) context_lines = 1;
|
||||
if (context_lines < 0 && context_lines != ALL_CONTEXT) context_lines = 0;
|
||||
|
||||
if (isatty(STDOUT_FILENO)) {
|
||||
print_color = 1;
|
||||
@ -402,11 +390,11 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
int found = 0;
|
||||
if (flags & BP_JSON) printf("[");
|
||||
if (mode == MODE_JSON) printf("[");
|
||||
if (i < argc) {
|
||||
// Files pass in as command line args:
|
||||
for (int nfiles = 0; i < argc; nfiles++, i++) {
|
||||
found += process_file(defs, argv[i], pattern, context, flags);
|
||||
found += process_file(defs, argv[i], pattern);
|
||||
}
|
||||
} else if (isatty(STDIN_FILENO)) {
|
||||
// No files, no piped in input, so use * **/*:
|
||||
@ -415,14 +403,14 @@ int main(int argc, char *argv[])
|
||||
glob("**/*", GLOB_APPEND, NULL, &globbuf);
|
||||
for (size_t i = 0; i < globbuf.gl_pathc; i++) {
|
||||
if (is_text_file(globbuf.gl_pathv[i]))
|
||||
found += process_file(defs, globbuf.gl_pathv[i], pattern, context, flags);
|
||||
found += process_file(defs, globbuf.gl_pathv[i], pattern);
|
||||
}
|
||||
globfree(&globbuf);
|
||||
} else {
|
||||
// Piped in input:
|
||||
found += process_file(defs, NULL, pattern, context, flags);
|
||||
found += process_file(defs, NULL, pattern);
|
||||
}
|
||||
if (flags & BP_JSON) printf("]\n");
|
||||
if (mode == MODE_JSON) printf("]\n");
|
||||
|
||||
#ifdef DEBUG_HEAP
|
||||
// This code frees up all residual heap-allocated memory. Since the program
|
||||
|
@ -42,10 +42,16 @@ static void populate_lines(file_t *f)
|
||||
//
|
||||
// Read an entire file into memory.
|
||||
//
|
||||
file_t *load_file(file_t **files, const char *filename)
|
||||
file_t *load_file(file_t **files, const char *fmt, ...)
|
||||
{
|
||||
if (filename == NULL) filename = "-";
|
||||
int fd = streq(filename, "-") ? STDIN_FILENO : open(filename, O_RDONLY);
|
||||
char filename[PATH_MAX+1] = {0};
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
check(vsnprintf(filename, PATH_MAX, fmt, args) <= PATH_MAX,
|
||||
"File name is too large");
|
||||
va_end(args);
|
||||
|
||||
int fd = filename[0] == '\0' ? STDIN_FILENO : open(filename, O_RDONLY);
|
||||
if (fd < 0) return NULL;
|
||||
size_t length;
|
||||
file_t *f = new(file_t);
|
||||
|
@ -17,7 +17,8 @@ typedef struct file_s {
|
||||
unsigned int mmapped:1;
|
||||
} file_t;
|
||||
|
||||
file_t *load_file(file_t **files, const char *filename);
|
||||
__attribute__((format(printf,2,3)))
|
||||
file_t *load_file(file_t **files, const char *fmt, ...);
|
||||
__attribute__((nonnull(3), returns_nonnull))
|
||||
file_t *spoof_file(file_t **files, const char *filename, const char *text);
|
||||
__attribute__((nonnull))
|
||||
@ -30,7 +31,7 @@ __attribute__((pure, nonnull))
|
||||
size_t get_char_number(file_t *f, const char *p);
|
||||
__attribute__((pure, nonnull))
|
||||
const char *get_line(file_t *f, size_t line_number);
|
||||
__attribute__((nonnull(1,2,3), format(printf, 5, 6)))
|
||||
__attribute__((nonnull(1,2,3), format(printf,5,6)))
|
||||
void fprint_line(FILE *dest, file_t *f, const char *start, const char *end, const char *fmt, ...);
|
||||
|
||||
#endif
|
||||
|
6
json.c
6
json.c
@ -7,14 +7,14 @@
|
||||
#include "types.h"
|
||||
|
||||
__attribute__((nonnull))
|
||||
static int _json_match(const char *text, match_t *m, int comma, int verbose);
|
||||
static int _json_match(const char *text, match_t *m, int comma, unsigned int verbose);
|
||||
|
||||
//
|
||||
// Helper function for json_match().
|
||||
// `comma` is used to track whether a comma will need to be printed before the
|
||||
// next object or not.
|
||||
//
|
||||
static int _json_match(const char *text, match_t *m, int comma, int verbose)
|
||||
static int _json_match(const char *text, match_t *m, int comma, unsigned int verbose)
|
||||
{
|
||||
if (!verbose) {
|
||||
if (m->op->type != VM_REF) {
|
||||
@ -49,7 +49,7 @@ static int _json_match(const char *text, match_t *m, int comma, int verbose)
|
||||
//
|
||||
// Print a match object as a JSON object.
|
||||
//
|
||||
void json_match(const char *text, match_t *m, int verbose)
|
||||
void json_match(const char *text, match_t *m, unsigned int verbose)
|
||||
{
|
||||
_json_match(text, m, 0, verbose);
|
||||
}
|
||||
|
2
json.h
2
json.h
@ -5,7 +5,7 @@
|
||||
#define JSON__H
|
||||
|
||||
__attribute__((nonnull))
|
||||
void json_match(const char *text, match_t *m, int verbose);
|
||||
void json_match(const char *text, match_t *m, unsigned int verbose);
|
||||
|
||||
#endif
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1
|
||||
|
9
types.h
9
types.h
@ -8,15 +8,6 @@
|
||||
|
||||
#include "file_loader.h"
|
||||
|
||||
enum BPFlag {
|
||||
BP_VERBOSE = 1 << 0,
|
||||
BP_IGNORECASE = 1 << 1,
|
||||
BP_EXPLAIN = 1 << 2,
|
||||
BP_JSON = 1 << 3,
|
||||
BP_LISTFILES = 1 << 4,
|
||||
BP_INPLACE = 1 << 5,
|
||||
};
|
||||
|
||||
//
|
||||
// BP virtual machine opcodes (these must be kept in sync with the names in vm.c)
|
||||
//
|
||||
|
64
vm.c
64
vm.c
@ -36,7 +36,7 @@ static match_t *in_use_matches = NULL;
|
||||
__attribute__((nonnull, pure))
|
||||
static inline const char *next_char(file_t *f, const char *str);
|
||||
__attribute__((nonnull))
|
||||
static const char *match_backref(const char *str, vm_op_t *op, match_t *cap, unsigned int flags);
|
||||
static const char *match_backref(const char *str, vm_op_t *op, match_t *cap, unsigned int ignorecase);
|
||||
__attribute__((nonnull))
|
||||
static match_t *get_capture_by_num(match_t *m, int *n);
|
||||
__attribute__((nonnull, pure))
|
||||
@ -66,7 +66,7 @@ static inline const char *next_char(file_t *f, const char *str)
|
||||
// Attempt to match text against a previously captured value.
|
||||
// Return the character position after the backref has matched, or NULL if no match has occurred.
|
||||
//
|
||||
static const char *match_backref(const char *str, vm_op_t *op, match_t *cap, unsigned int flags)
|
||||
static const char *match_backref(const char *str, vm_op_t *op, match_t *cap, unsigned int ignorecase)
|
||||
{
|
||||
check(op->type == VM_BACKREF, "Attempt to match backref against something that's not a backref");
|
||||
if (cap->op->type == VM_REPLACE) {
|
||||
@ -87,7 +87,7 @@ static const char *match_backref(const char *str, vm_op_t *op, match_t *cap, uns
|
||||
++r;
|
||||
match_t *value = get_capture(cap, &r);
|
||||
if (value != NULL) {
|
||||
str = match_backref(str, op, value, flags);
|
||||
str = match_backref(str, op, value, ignorecase);
|
||||
if (str == NULL) return NULL;
|
||||
}
|
||||
}
|
||||
@ -96,22 +96,22 @@ static const char *match_backref(const char *str, vm_op_t *op, match_t *cap, uns
|
||||
for (match_t *child = cap->child; child; child = child->nextsibling) {
|
||||
if (child->start > prev) {
|
||||
size_t len = (size_t)(child->start - prev);
|
||||
if ((flags & BP_IGNORECASE) ? memicmp(str, prev, len) != 0
|
||||
: memcmp(str, prev, len) != 0) {
|
||||
if (ignorecase ? memicmp(str, prev, len) != 0
|
||||
: memcmp(str, prev, len) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
str += len;
|
||||
prev = child->start;
|
||||
}
|
||||
if (child->start < prev) continue;
|
||||
str = match_backref(str, op, child, flags);
|
||||
str = match_backref(str, op, child, ignorecase);
|
||||
if (str == NULL) return NULL;
|
||||
prev = child->end;
|
||||
}
|
||||
if (cap->end > prev) {
|
||||
size_t len = (size_t)(cap->end - prev);
|
||||
if ((flags & BP_IGNORECASE) ? memicmp(str, prev, len) != 0
|
||||
: memcmp(str, prev, len) != 0) {
|
||||
if (ignorecase ? memicmp(str, prev, len) != 0
|
||||
: memcmp(str, prev, len) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
str += len;
|
||||
@ -124,7 +124,7 @@ static const char *match_backref(const char *str, vm_op_t *op, match_t *cap, uns
|
||||
//
|
||||
// Find the next match after prev (or the first match if prev is NULL)
|
||||
//
|
||||
match_t *next_match(def_t *defs, file_t *f, match_t *prev, vm_op_t *op, unsigned int flags)
|
||||
match_t *next_match(def_t *defs, file_t *f, match_t *prev, vm_op_t *op, unsigned int ignorecase)
|
||||
{
|
||||
const char *str;
|
||||
if (prev) {
|
||||
@ -134,7 +134,7 @@ match_t *next_match(def_t *defs, file_t *f, match_t *prev, vm_op_t *op, unsigned
|
||||
str = f->contents;
|
||||
}
|
||||
for (; str < f->end; ++str) {
|
||||
match_t *m = match(defs, f, str, op, flags);
|
||||
match_t *m = match(defs, f, str, op, ignorecase);
|
||||
if (m) return m;
|
||||
}
|
||||
return NULL;
|
||||
@ -145,7 +145,7 @@ match_t *next_match(def_t *defs, file_t *f, match_t *prev, vm_op_t *op, unsigned
|
||||
// a match struct, or NULL if no match is found.
|
||||
// The returned value should be free()'d to avoid memory leaking.
|
||||
//
|
||||
match_t *match(def_t *defs, file_t *f, const char *str, vm_op_t *op, unsigned int flags)
|
||||
match_t *match(def_t *defs, file_t *f, const char *str, vm_op_t *op, unsigned int ignorecase)
|
||||
{
|
||||
switch (op->type) {
|
||||
case VM_LEFTRECURSION: {
|
||||
@ -158,7 +158,7 @@ match_t *match(def_t *defs, file_t *f, const char *str, vm_op_t *op, unsigned in
|
||||
++op->args.leftrec.visits;
|
||||
return op->args.leftrec.match;
|
||||
} else {
|
||||
return match(defs, f, str, op->args.leftrec.fallback, flags);
|
||||
return match(defs, f, str, op->args.leftrec.fallback, ignorecase);
|
||||
}
|
||||
}
|
||||
case VM_ANYCHAR: {
|
||||
@ -172,8 +172,8 @@ match_t *match(def_t *defs, file_t *f, const char *str, vm_op_t *op, unsigned in
|
||||
}
|
||||
case VM_STRING: {
|
||||
if (&str[op->len] > f->end) return NULL;
|
||||
if ((flags & BP_IGNORECASE) ? memicmp(str, op->args.s, (size_t)op->len) != 0
|
||||
: memcmp(str, op->args.s, (size_t)op->len) != 0)
|
||||
if (ignorecase ? memicmp(str, op->args.s, (size_t)op->len) != 0
|
||||
: memcmp(str, op->args.s, (size_t)op->len) != 0)
|
||||
return NULL;
|
||||
match_t *m = new_match();
|
||||
m->op = op;
|
||||
@ -192,7 +192,7 @@ match_t *match(def_t *defs, file_t *f, const char *str, vm_op_t *op, unsigned in
|
||||
return m;
|
||||
}
|
||||
case VM_NOT: {
|
||||
match_t *m = match(defs, f, str, op->args.pat, flags);
|
||||
match_t *m = match(defs, f, str, op->args.pat, ignorecase);
|
||||
if (m != NULL) {
|
||||
recycle_if_unused(&m);
|
||||
return NULL;
|
||||
@ -219,7 +219,7 @@ match_t *match(def_t *defs, file_t *f, const char *str, vm_op_t *op, unsigned in
|
||||
for (const char *prev = NULL; prev < str; ) {
|
||||
prev = str;
|
||||
if (pat) {
|
||||
match_t *p = match(defs, f, str, pat, flags);
|
||||
match_t *p = match(defs, f, str, pat, ignorecase);
|
||||
if (p != NULL) {
|
||||
ADD_OWNER(*dest, p);
|
||||
m->end = p->end;
|
||||
@ -230,7 +230,7 @@ match_t *match(def_t *defs, file_t *f, const char *str, vm_op_t *op, unsigned in
|
||||
return m;
|
||||
}
|
||||
if (skip) {
|
||||
match_t *s = match(defs, f, str, skip, flags);
|
||||
match_t *s = match(defs, f, str, skip, ignorecase);
|
||||
if (s != NULL) {
|
||||
ADD_OWNER(*dest, s);
|
||||
dest = &s->nextsibling;
|
||||
@ -261,11 +261,11 @@ match_t *match(def_t *defs, file_t *f, const char *str, vm_op_t *op, unsigned in
|
||||
// Separator
|
||||
match_t *sep = NULL;
|
||||
if (op->args.repetitions.sep != NULL && reps > 0) {
|
||||
sep = match(defs, f, str, op->args.repetitions.sep, flags);
|
||||
sep = match(defs, f, str, op->args.repetitions.sep, ignorecase);
|
||||
if (sep == NULL) break;
|
||||
str = sep->end;
|
||||
}
|
||||
match_t *p = match(defs, f, str, op->args.repetitions.repeat_pat, flags);
|
||||
match_t *p = match(defs, f, str, op->args.repetitions.repeat_pat, ignorecase);
|
||||
if (p == NULL) {
|
||||
str = start;
|
||||
recycle_if_unused(&sep);
|
||||
@ -306,7 +306,7 @@ match_t *match(def_t *defs, file_t *f, const char *str, vm_op_t *op, unsigned in
|
||||
ssize_t backtrack = op->args.pat->len;
|
||||
check(backtrack != -1, "'<' is only allowed for fixed-length operations");
|
||||
if (str - backtrack < f->contents) return NULL;
|
||||
match_t *before = match(defs, f, str - backtrack, op->args.pat, flags);
|
||||
match_t *before = match(defs, f, str - backtrack, op->args.pat, ignorecase);
|
||||
if (before == NULL) return NULL;
|
||||
match_t *m = new_match();
|
||||
m->start = str;
|
||||
@ -316,7 +316,7 @@ match_t *match(def_t *defs, file_t *f, const char *str, vm_op_t *op, unsigned in
|
||||
return m;
|
||||
}
|
||||
case VM_BEFORE: {
|
||||
match_t *after = match(defs, f, str, op->args.pat, flags);
|
||||
match_t *after = match(defs, f, str, op->args.pat, ignorecase);
|
||||
if (after == NULL) return NULL;
|
||||
match_t *m = new_match();
|
||||
m->start = str;
|
||||
@ -326,7 +326,7 @@ match_t *match(def_t *defs, file_t *f, const char *str, vm_op_t *op, unsigned in
|
||||
return m;
|
||||
}
|
||||
case VM_CAPTURE: {
|
||||
match_t *p = match(defs, f, str, op->args.pat, flags);
|
||||
match_t *p = match(defs, f, str, op->args.pat, ignorecase);
|
||||
if (p == NULL) return NULL;
|
||||
match_t *m = new_match();
|
||||
m->start = str;
|
||||
@ -336,18 +336,18 @@ match_t *match(def_t *defs, file_t *f, const char *str, vm_op_t *op, unsigned in
|
||||
return m;
|
||||
}
|
||||
case VM_OTHERWISE: {
|
||||
match_t *m = match(defs, f, str, op->args.multiple.first, flags);
|
||||
if (m == NULL) m = match(defs, f, str, op->args.multiple.second, flags);
|
||||
match_t *m = match(defs, f, str, op->args.multiple.first, ignorecase);
|
||||
if (m == NULL) m = match(defs, f, str, op->args.multiple.second, ignorecase);
|
||||
return m;
|
||||
}
|
||||
case VM_CHAIN: {
|
||||
match_t *m1 = match(defs, f, str, op->args.multiple.first, flags);
|
||||
match_t *m1 = match(defs, f, str, op->args.multiple.first, ignorecase);
|
||||
if (m1 == NULL) return NULL;
|
||||
|
||||
match_t *m2;
|
||||
{ // Push backrefs and run matching, then cleanup
|
||||
def_t *defs2 = with_backrefs(defs, f, m1);
|
||||
m2 = match(defs2, f, m1->end, op->args.multiple.second, flags);
|
||||
m2 = match(defs2, f, m1->end, op->args.multiple.second, ignorecase);
|
||||
free_defs(&defs2, defs);
|
||||
}
|
||||
|
||||
@ -364,7 +364,7 @@ match_t *match(def_t *defs, file_t *f, const char *str, vm_op_t *op, unsigned in
|
||||
return m;
|
||||
}
|
||||
case VM_EQUAL: case VM_NOT_EQUAL: {
|
||||
match_t *m1 = match(defs, f, str, op->args.multiple.first, flags);
|
||||
match_t *m1 = match(defs, f, str, op->args.multiple.first, ignorecase);
|
||||
if (m1 == NULL) return NULL;
|
||||
|
||||
// <p1>==<p2> matches iff the text of <p1> matches <p2>
|
||||
@ -376,7 +376,7 @@ match_t *match(def_t *defs, file_t *f, const char *str, vm_op_t *op, unsigned in
|
||||
.nlines=1 + get_line_number(f, m1->end)-get_line_number(f, m1->start),
|
||||
.mmapped=f->mmapped,
|
||||
};
|
||||
match_t *m2 = match(defs, &inner, str, op->args.multiple.second, flags);
|
||||
match_t *m2 = match(defs, &inner, str, op->args.multiple.second, ignorecase);
|
||||
if ((m2 == NULL) == (op->type == VM_EQUAL)) {
|
||||
recycle_if_unused(&m1);
|
||||
if (m2 != NULL) recycle_if_unused(&m2);
|
||||
@ -397,7 +397,7 @@ match_t *match(def_t *defs, file_t *f, const char *str, vm_op_t *op, unsigned in
|
||||
case VM_REPLACE: {
|
||||
match_t *p = NULL;
|
||||
if (op->args.replace.pat) {
|
||||
p = match(defs, f, str, op->args.replace.pat, flags);
|
||||
p = match(defs, f, str, op->args.replace.pat, ignorecase);
|
||||
if (p == NULL) return NULL;
|
||||
}
|
||||
match_t *m = new_match();
|
||||
@ -437,7 +437,7 @@ match_t *match(def_t *defs, file_t *f, const char *str, vm_op_t *op, unsigned in
|
||||
};
|
||||
|
||||
const char *prev = str;
|
||||
match_t *m = match(&defs2, f, str, ref, flags);
|
||||
match_t *m = match(&defs2, f, str, ref, ignorecase);
|
||||
if (m == NULL) return NULL;
|
||||
|
||||
while (rec_op.args.leftrec.visits > 0) {
|
||||
@ -445,7 +445,7 @@ match_t *match(def_t *defs, file_t *f, const char *str, vm_op_t *op, unsigned in
|
||||
REMOVE_OWNERSHIP(rec_op.args.leftrec.match);
|
||||
ADD_OWNER(rec_op.args.leftrec.match, m);
|
||||
prev = m->end;
|
||||
match_t *m2 = match(&defs2, f, str, ref, flags);
|
||||
match_t *m2 = match(&defs2, f, str, ref, ignorecase);
|
||||
if (m2 == NULL) break;
|
||||
if (m2->end <= prev) {
|
||||
recycle_if_unused(&m2);
|
||||
@ -465,7 +465,7 @@ match_t *match(def_t *defs, file_t *f, const char *str, vm_op_t *op, unsigned in
|
||||
return m;
|
||||
}
|
||||
case VM_BACKREF: {
|
||||
const char *end = match_backref(str, op, op->args.backref, flags);
|
||||
const char *end = match_backref(str, op, op->args.backref, ignorecase);
|
||||
if (end == NULL) return NULL;
|
||||
match_t *m = new_match();
|
||||
m->op = op;
|
||||
|
Loading…
Reference in New Issue
Block a user