aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--README.md2
-rw-r--r--bp.c2
-rw-r--r--explain.h13
-rw-r--r--match.c87
-rw-r--r--match.h9
-rw-r--r--printmatch.c (renamed from explain.c)92
-rw-r--r--printmatch.h22
8 files changed, 116 insertions, 113 deletions
diff --git a/Makefile b/Makefile
index f54e8af..abbdb19 100644
--- a/Makefile
+++ b/Makefile
@@ -22,7 +22,7 @@ G=
O=-O3
ALL_FLAGS=$(CFLAGS) $(OSFLAGS) -DBP_NAME="\"$(NAME)\"" $(EXTRA) $(CWARN) $(G) $(O)
-CFILES=pattern.c utils.c match.c files.c explain.c json.c utf8.c
+CFILES=pattern.c utils.c match.c files.c printmatch.c json.c utf8.c
OBJFILES=$(CFILES:.c=.o)
all: $(NAME) bp.1
diff --git a/README.md b/README.md
index fb8d39b..20ee2ad 100644
--- a/README.md
+++ b/README.md
@@ -140,11 +140,11 @@ so use at your own risk! These grammar files are only approximations of syntax.
File | Description
-------------------------------|-----------------------------------------------------
[bp.c](bp.c) | The main program.
-[explain.c](explain.c) | Printing a visual explanation of a match.
[files.c](files.c) | Loading files into memory.
[json.c](json.c) | JSON output of matches.
[match.c](match.c) | Pattern matching code (find occurrences of a bp pattern within an input string).
[pattern.c](pattern.c) | Pattern compiling code (compile a bp pattern from an input string).
+[printmatch.c](printmatch.c) | Printing a visual explanation of a match.
[utf8.c](utf8.c) | UTF-8 helper code.
[utils.c](utils.c) | Miscellaneous helper functions.
diff --git a/bp.c b/bp.c
index 5146d5a..dbd72bd 100644
--- a/bp.c
+++ b/bp.c
@@ -20,11 +20,11 @@
#include <sys/wait.h>
#include <unistd.h>
-#include "explain.h"
#include "files.h"
#include "json.h"
#include "match.h"
#include "pattern.h"
+#include "printmatch.h"
#include "utils.h"
#ifndef BP_NAME
diff --git a/explain.h b/explain.h
deleted file mode 100644
index fbb2abf..0000000
--- a/explain.h
+++ /dev/null
@@ -1,13 +0,0 @@
-//
-// Debug visualization of matches
-//
-#ifndef EXPLAIN__H
-#define EXPLAIN__H
-
-#include "match.h"
-
-__attribute__((nonnull))
-void explain_match(match_t *m);
-
-#endif
-// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/match.c b/match.c
index 461148d..80296e9 100644
--- a/match.c
+++ b/match.c
@@ -857,91 +857,4 @@ match_t *get_named_capture(match_t *m, const char *name, size_t namelen)
return NULL;
}
-static inline void fputc_safe(FILE *out, char c, print_options_t *opts)
-{
- (void)fputc(c, out);
- if (c == '\n' && opts && opts->on_nl) {
- opts->on_nl(out);
- if (opts->replace_color) fprintf(out, "%s", opts->replace_color);
- }
-}
-
-void fprint_match(FILE *out, const char *file_start, match_t *m, print_options_t *opts)
-{
- if (m->pat->type == BP_REPLACE) {
- const char *text = m->pat->args.replace.text;
- const char *end = &text[m->pat->args.replace.len];
- if (opts && opts->replace_color) fprintf(out, "%s", opts->replace_color);
-
- // TODO: clean up the line numbering code
- for (const char *r = text; r < end; ) {
- // Capture substitution
- if (*r == '@' && r+1 < end && r[1] != '@') {
- const char *next = r+1;
- // Retrieve the capture value:
- match_t *cap = NULL;
- if (isdigit(*next)) {
- int n = (int)strtol(next, (char**)&next, 10);
- cap = get_numbered_capture(m->children[0], n);
- } else {
- const char *name = next, *name_end = after_name(next, end);
- if (name_end) {
- cap = get_named_capture(m->children[0], name, (size_t)(name_end - name));
- next = name_end;
- if (next < m->end && *next == ';') ++next;
- }
- }
-
- if (cap != NULL) {
- fprint_match(out, file_start, cap, opts);
- if (opts && opts->replace_color) fprintf(out, "%s", opts->replace_color);
- r = next;
- continue;
- }
- }
-
- if (*r == '\\') {
- ++r;
- if (*r == 'N') { // \N (nodent)
- ++r;
- // Mildly hacky: nodents here are based on the *first line*
- // of the match. If the match spans multiple lines, or if
- // the replacement text contains newlines, this may get weird.
- const char *line_start = m->start;
- while (line_start > file_start && line_start[-1] != '\n') --line_start;
- fputc_safe(out, '\n', opts);
- for (const char *p = line_start; p < m->start && (*p == ' ' || *p == '\t'); ++p)
- fputc(*p, out);
- continue;
- }
- fputc_safe(out, unescapechar(r, &r, end), opts);
- } else {
- fputc_safe(out, *r, opts);
- ++r;
- }
- }
- } else {
- if (opts && opts->match_color) fprintf(out, "%s", opts->match_color);
- const char *prev = m->start;
- for (int i = 0; m->children && m->children[i]; i++) {
- match_t *child = m->children[i];
- // Skip children from e.g. zero-width matches like >@foo
- if (!(prev <= child->start && child->start <= m->end &&
- prev <= child->end && child->end <= m->end))
- continue;
- if (child->start > prev) {
- if (opts && opts->fprint_between) opts->fprint_between(out, prev, child->start, opts->match_color);
- else fwrite(prev, sizeof(char), (size_t)(child->start - prev), out);
- }
- fprint_match(out, file_start, child, opts);
- if (opts && opts->match_color) fprintf(out, "%s", opts->match_color);
- prev = child->end;
- }
- if (m->end > prev) {
- if (opts && opts->fprint_between) opts->fprint_between(out, prev, m->end, opts->match_color);
- else fwrite(prev, sizeof(char), (size_t)(m->end - prev), out);
- }
- }
-}
-
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/match.h b/match.h
index 93f2ade..7439b27 100644
--- a/match.h
+++ b/match.h
@@ -24,12 +24,6 @@ typedef struct match_s {
struct match_s *_children[3];
} match_t;
-typedef struct {
- const char *normal_color, *match_color, *replace_color;
- void (*fprint_between)(FILE *out, const char *start, const char *end, const char *normal_color);
- void (*on_nl)(FILE *out);
-} print_options_t;
-
__attribute__((nonnull))
void recycle_match(match_t **at_m);
size_t free_all_matches(void);
@@ -40,9 +34,6 @@ __attribute__((nonnull))
match_t *get_numbered_capture(match_t *m, int n);
__attribute__((nonnull, pure))
match_t *get_named_capture(match_t *m, const char *name, size_t namelen);
-__attribute__((nonnull(1,2,3)))
-//void fprint_match(FILE *out, const char *file_start, match_t *m, const char *colors[3]);
-void fprint_match(FILE *out, const char *file_start, match_t *m, print_options_t *opts);
#endif
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/explain.c b/printmatch.c
index 41939c3..5b7e6e7 100644
--- a/explain.c
+++ b/printmatch.c
@@ -1,11 +1,13 @@
//
-// explain.c - Debug visualization of pattern matches.
+// printmatch.c - Debug visualization of pattern matches.
//
#include <stdio.h>
#include <string.h>
+#include <ctype.h>
#include "match.h"
+#include "printmatch.h"
#include "utils.h"
typedef struct match_node_s {
@@ -170,4 +172,92 @@ void explain_match(match_t *m)
printf("\033[?7h"); // Re-enable line wrapping
}
+static inline void fputc_safe(FILE *out, char c, print_options_t *opts)
+{
+ (void)fputc(c, out);
+ if (c == '\n' && opts && opts->on_nl) {
+ opts->on_nl(out);
+ if (opts->replace_color) fprintf(out, "%s", opts->replace_color);
+ }
+}
+
+void fprint_match(FILE *out, const char *file_start, match_t *m, print_options_t *opts)
+{
+ if (m->pat->type == BP_REPLACE) {
+ const char *text = m->pat->args.replace.text;
+ const char *end = &text[m->pat->args.replace.len];
+ if (opts && opts->replace_color) fprintf(out, "%s", opts->replace_color);
+
+ // TODO: clean up the line numbering code
+ for (const char *r = text; r < end; ) {
+ // Capture substitution
+ if (*r == '@' && r+1 < end && r[1] != '@') {
+ const char *next = r+1;
+ // Retrieve the capture value:
+ match_t *cap = NULL;
+ if (isdigit(*next)) {
+ int n = (int)strtol(next, (char**)&next, 10);
+ cap = get_numbered_capture(m->children[0], n);
+ } else {
+ const char *name = next, *name_end = after_name(next, end);
+ if (name_end) {
+ cap = get_named_capture(m->children[0], name, (size_t)(name_end - name));
+ next = name_end;
+ if (next < m->end && *next == ';') ++next;
+ }
+ }
+
+ if (cap != NULL) {
+ fprint_match(out, file_start, cap, opts);
+ if (opts && opts->replace_color) fprintf(out, "%s", opts->replace_color);
+ r = next;
+ continue;
+ }
+ }
+
+ if (*r == '\\') {
+ ++r;
+ if (*r == 'N') { // \N (nodent)
+ ++r;
+ // Mildly hacky: nodents here are based on the *first line*
+ // of the match. If the match spans multiple lines, or if
+ // the replacement text contains newlines, this may get weird.
+ const char *line_start = m->start;
+ while (line_start > file_start && line_start[-1] != '\n') --line_start;
+ fputc_safe(out, '\n', opts);
+ for (const char *p = line_start; p < m->start && (*p == ' ' || *p == '\t'); ++p)
+ fputc(*p, out);
+ continue;
+ }
+ fputc_safe(out, unescapechar(r, &r, end), opts);
+ } else {
+ fputc_safe(out, *r, opts);
+ ++r;
+ }
+ }
+ } else {
+ if (opts && opts->match_color) fprintf(out, "%s", opts->match_color);
+ const char *prev = m->start;
+ for (int i = 0; m->children && m->children[i]; i++) {
+ match_t *child = m->children[i];
+ // Skip children from e.g. zero-width matches like >@foo
+ if (!(prev <= child->start && child->start <= m->end &&
+ prev <= child->end && child->end <= m->end))
+ continue;
+ if (child->start > prev) {
+ if (opts && opts->fprint_between) opts->fprint_between(out, prev, child->start, opts->match_color);
+ else fwrite(prev, sizeof(char), (size_t)(child->start - prev), out);
+ }
+ fprint_match(out, file_start, child, opts);
+ if (opts && opts->match_color) fprintf(out, "%s", opts->match_color);
+ prev = child->end;
+ }
+ if (m->end > prev) {
+ if (opts && opts->fprint_between) opts->fprint_between(out, prev, m->end, opts->match_color);
+ else fwrite(prev, sizeof(char), (size_t)(m->end - prev), out);
+ }
+ }
+}
+
+
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/printmatch.h b/printmatch.h
new file mode 100644
index 0000000..f6a894d
--- /dev/null
+++ b/printmatch.h
@@ -0,0 +1,22 @@
+//
+// Debug visualization of matches
+//
+#ifndef EXPLAIN__H
+#define EXPLAIN__H
+
+#include "match.h"
+
+typedef struct {
+ const char *normal_color, *match_color, *replace_color;
+ void (*fprint_between)(FILE *out, const char *start, const char *end, const char *normal_color);
+ void (*on_nl)(FILE *out);
+} print_options_t;
+__attribute__((nonnull(1,2,3)))
+//void fprint_match(FILE *out, const char *file_start, match_t *m, const char *colors[3]);
+void fprint_match(FILE *out, const char *file_start, match_t *m, print_options_t *opts);
+
+__attribute__((nonnull))
+void explain_match(match_t *m);
+
+#endif
+// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0