aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md1
-rw-r--r--bp.14
-rw-r--r--bpeg.c14
-rw-r--r--file_loader.c18
-rw-r--r--file_loader.h2
-rw-r--r--types.h1
-rw-r--r--vm.c39
-rw-r--r--vm.h4
8 files changed, 61 insertions, 22 deletions
diff --git a/README.md b/README.md
index 1bc1d8f..784296a 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,7 @@ It's written in pure C with no dependencies.
* `-h` `--help` print the usage and quit
* `-v` `--verbose` print verbose debugging info
* `-i` `--ignore-case` perform a case-insensitive match
+* `-I` `--inplace` perform replacements or filtering in-place on files
* `-e` `--explain` print an explanation of the matches
* `-j` `--json` print matches as JSON objects
* `-l` `--list-files` print only filenames containing matches
diff --git a/bp.1 b/bp.1
index 11429e2..2af9967 100644
--- a/bp.1
+++ b/bp.1
@@ -11,6 +11,7 @@ bp \- Bruce's Parsing Expression Grammar tool
[\fI-j\fR|\fI--json\fR]
[\fI-l\fR|\fI--list-files\fR]
[\fI-i\fR|\fI--ignore-case\fR \fI<pattern>\fR]
+[\fI-I\fR|\fI--inplace\fR]
[\fI-p\fR|\fI--pattern\fR \fI<pattern>\fR]
[\fI-P\fR|\fI--pattern-string\fR \fI<string-pattern>\fR]
[\fI-d\fR|\fI--define\fR \fI<name>\fR:\fI<pattern>\fR]
@@ -38,6 +39,9 @@ Print only the names of files containing matches instead of the matches themselv
.B \-i\fR, \fB--ignore-case
Perform pattern matching case-insensitively.
+.B \-I\fR, \fB--inplace
+Perform filtering or replacement in-place (i.e. overwrite files with new content).
+
.B \-d\fR, \fB--define \fI<name>\fR:\fI<pattern>\fR
Define a grammar rule using a bp pattern.
diff --git a/bpeg.c b/bpeg.c
index 530857a..69b49ef 100644
--- a/bpeg.c
+++ b/bpeg.c
@@ -28,6 +28,7 @@ static const char *usage = (
" -v --verbose print verbose debugging info\n"
" -e --explain explain the matches\n"
" -j --json print matches as a list of JSON objects\n"
+ " -I --inplace modify a file in-place\n"
" -i --ignore-case preform matching case-insensitively\n"
" -l --list-files list filenames only\n"
" -d --define <name>:<def> define a grammar rule\n"
@@ -61,7 +62,7 @@ static int print_errors(file_t *f, match_t *m)
int ret = 0;
if (m->op->op == VM_CAPTURE && m->op->args.capture.name && streq(m->op->args.capture.name, "!")) {
printf("\033[31;1m");
- print_match(f, m, print_options);
+ print_match(stdout, f, m, print_options);
printf("\033[0m\n");
fprint_line(stdout, f, m->start, m->end, " ");
return 1;
@@ -76,6 +77,8 @@ static int run_match(grammar_t *g, const char *filename, vm_op_t *pattern, unsig
static int printed_matches = 0;
file_t *f = load_file(filename);
check(f, "Could not open file: %s", filename);
+ if (flags & BPEG_INPLACE) // Need to do this before matching
+ intern_file(f);
match_t *m = match(g, f, f->contents, pattern, flags);
if (m && print_errors(f, m) > 0)
_exit(1);
@@ -96,6 +99,10 @@ static int run_match(grammar_t *g, const char *filename, vm_op_t *pattern, unsig
0, f->end - f->contents);
json_match(f->contents, m, (flags & BPEG_VERBOSE) ? 1 : 0);
printf("]}}\n");
+ } else if (flags & BPEG_INPLACE) {
+ FILE *out = fopen(filename, "w");
+ print_match(out, f, m, 0);
+ fclose(out);
} else {
if (printed_matches > 1)
fputc('\n', stdout);
@@ -105,7 +112,7 @@ static int run_match(grammar_t *g, const char *filename, vm_op_t *pattern, unsig
else
printf("%s:\n", filename);
}
- print_match(f, m, print_options);
+ print_match(stdout, f, m, print_options);
}
destroy_file(&f);
return 0;
@@ -149,6 +156,8 @@ int main(int argc, char *argv[])
flags |= BPEG_EXPLAIN;
} else if (streq(argv[i], "--json")) {
flags |= BPEG_JSON;
+ } else if (streq(argv[i], "--inplace")) {
+ flags |= BPEG_INPLACE;
} else if (streq(argv[i], "--ignore-case")) {
flags |= BPEG_IGNORECASE;
} else if (streq(argv[i], "--list-files")) {
@@ -215,6 +224,7 @@ int main(int argc, char *argv[])
case 'v': flags |= BPEG_VERBOSE; break; // -v
case 'e': flags |= BPEG_EXPLAIN; break; // -e
case 'j': flags |= BPEG_JSON; break; // -j
+ case 'I': flags |= BPEG_INPLACE; break; // -I
case 'i': flags |= BPEG_IGNORECASE; break; // -i
case 'l': flags |= BPEG_LISTFILES; break; // -l
default:
diff --git a/file_loader.c b/file_loader.c
index 72cea72..1f61953 100644
--- a/file_loader.c
+++ b/file_loader.c
@@ -89,6 +89,24 @@ file_t *spoof_file(const char *filename, char *text)
return f;
}
+/*
+ * Ensure that the file's contents are held in memory, rather than being memory
+ * mapped IO.
+ */
+void intern_file(file_t *f)
+{
+ if (!f->mmapped) return;
+ size_t size = (size_t)(f->end - f->contents);
+ char *buf = xcalloc(sizeof(char), size + 1);
+ memcpy(buf, f->contents, size);
+ munmap(f->contents, size);
+ f->contents = buf;
+ f->end = buf + size;
+ f->mmapped = 0;
+ free(f->lines);
+ populate_lines(f);
+}
+
void destroy_file(file_t **f)
{
if ((*f)->filename) {
diff --git a/file_loader.h b/file_loader.h
index d6d305a..28a6281 100644
--- a/file_loader.h
+++ b/file_loader.h
@@ -16,6 +16,8 @@ typedef struct {
file_t *load_file(const char *filename);
file_t *spoof_file(const char *filename, char *text);
__attribute__((nonnull))
+void intern_file(file_t *f);
+__attribute__((nonnull))
void destroy_file(file_t **f);
__attribute__((pure, nonnull))
size_t get_line_number(file_t *f, const char *p);
diff --git a/types.h b/types.h
index 38c14bb..0cbcc93 100644
--- a/types.h
+++ b/types.h
@@ -14,6 +14,7 @@ enum BPEGFlag {
BPEG_EXPLAIN = 1 << 2,
BPEG_JSON = 1 << 3,
BPEG_LISTFILES = 1 << 4,
+ BPEG_INPLACE = 1 << 5,
};
/*
diff --git a/vm.c b/vm.c
index f88b532..40c783b 100644
--- a/vm.c
+++ b/vm.c
@@ -3,6 +3,7 @@
*/
#include <ctype.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -489,20 +490,20 @@ typedef struct {
const char *color;
} print_state_t;
-static void print_line_number(print_state_t *state, print_options_t options)
+static void print_line_number(FILE *out, print_state_t *state, print_options_t options)
{
state->printed_line = state->line;
if (!(options & PRINT_LINE_NUMBERS)) return;
if (options & PRINT_COLOR)
- printf("\033[0;2m% 5ld\033(0\x78\033(B%s", state->line, state->color);
+ fprintf(out, "\033[0;2m% 5ld\033(0\x78\033(B%s", state->line, state->color);
else
- printf("% 5ld|", state->line);
+ fprintf(out, "% 5ld|", state->line);
}
/*
* Print a match with replacements and highlighting.
*/
-static void _print_match(file_t *f, match_t *m, print_state_t *state, print_options_t options)
+static void _print_match(FILE *out, file_t *f, match_t *m, print_state_t *state, print_options_t options)
{
static const char *hl = "\033[0;31;1m";
const char *old_color = state->color;
@@ -514,7 +515,7 @@ static void _print_match(file_t *f, match_t *m, print_state_t *state, print_opti
} else if (m->op->op == VM_REPLACE) {
if (options & PRINT_COLOR && state->color != hl) {
state->color = hl;
- printf("%s", state->color);
+ fprintf(out, "%s", state->color);
}
const char *text = m->op->args.replace.text;
const char *end = &text[m->op->args.replace.len];
@@ -523,7 +524,7 @@ static void _print_match(file_t *f, match_t *m, print_state_t *state, print_opti
++r;
match_t *cap = get_cap(m, &r);
if (cap != NULL) {
- _print_match(f, cap, state, options);
+ _print_match(out, f, cap, state, options);
continue;
} else {
--r;
@@ -531,21 +532,21 @@ static void _print_match(file_t *f, match_t *m, print_state_t *state, print_opti
}
if (state->printed_line != state->line)
- print_line_number(state, options);
+ print_line_number(out, state, options);
if (*r == '\\') {
++r;
unsigned char c = unescapechar(r, &r);
- fputc(c, stdout);
+ fputc(c, out);
if (c == '\n') ++state->line;
continue;
} else if (*r == '\n') {
- fputc('\n', stdout);
+ fputc('\n', out);
++state->line;
++r;
continue;
} else {
- fputc(*r, stdout);
+ fputc(*r, out);
++r;
continue;
}
@@ -554,7 +555,7 @@ static void _print_match(file_t *f, match_t *m, print_state_t *state, print_opti
if (m->op->op == VM_CAPTURE) {
if (options & PRINT_COLOR && state->color != hl) {
state->color = hl;
- printf("%s", state->color);
+ fprintf(out, "%s", state->color);
}
}
@@ -567,33 +568,33 @@ static void _print_match(file_t *f, match_t *m, print_state_t *state, print_opti
if (child->start > prev) {
for (const char *p = prev; p < child->start; ++p) {
if (state->printed_line != state->line)
- print_line_number(state, options);
- fputc(*p, stdout);
+ print_line_number(out, state, options);
+ fputc(*p, out);
if (*p == '\n') ++state->line;
}
}
- _print_match(f, child, state, options);
+ _print_match(out, f, child, state, options);
prev = child->end;
}
if (m->end > prev) {
for (const char *p = prev; p < m->end; ++p) {
if (state->printed_line != state->line)
- print_line_number(state, options);
- fputc(*p, stdout);
+ print_line_number(out, state, options);
+ fputc(*p, out);
if (*p == '\n') ++state->line;
}
}
}
if (options & PRINT_COLOR && old_color != state->color) {
- printf("%s", old_color);
+ fprintf(out, "%s", old_color);
state->color = old_color;
}
}
-void print_match(file_t *f, match_t *m, print_options_t options)
+void print_match(FILE *out, file_t *f, match_t *m, print_options_t options)
{
print_state_t state = {.line = 1, .color = "\033[0m"};
- _print_match(f, m, &state, options);
+ _print_match(out, f, m, &state, options);
}
static match_t *match_backref(const char *str, vm_op_t *op, match_t *cap, unsigned int flags)
diff --git a/vm.h b/vm.h
index 3470e9c..842b782 100644
--- a/vm.h
+++ b/vm.h
@@ -4,6 +4,8 @@
#ifndef VM__H
#define VM__H
+#include <stdio.h>
+
#include "types.h"
typedef enum {
@@ -17,7 +19,7 @@ match_t *match(grammar_t *g, file_t *f, const char *str, vm_op_t *op, unsigned i
__attribute__((nonnull))
void destroy_match(match_t **m);
__attribute__((nonnull))
-void print_match(file_t *f, match_t *m, print_options_t options);
+void print_match(FILE *out, file_t *f, match_t *m, print_options_t options);
#endif
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1